diff --git a/_config.yml b/_config.yml index 20bf8a1..aca049e 100644 --- a/_config.yml +++ b/_config.yml @@ -99,6 +99,11 @@ ga_tracking_anonymize_ip: true # Use GDPR compliant Google Analytics settings (t plugins: - jekyll-seo-tag +kramdown: + syntax_highlighter_opts: + block: + line_numbers: false + compress_html: clippings: all comments: all @@ -106,3 +111,5 @@ compress_html: startings: [] blanklines: false profile: false + # ignore: + # envs: all diff --git a/_includes/fix_linenos.html b/_includes/fix_linenos.html new file mode 100644 index 0000000..6243fb0 --- /dev/null +++ b/_includes/fix_linenos.html @@ -0,0 +1,65 @@ +{%- comment -%} +This file can be used to fix the HTML produced by Jekyll for highlighted +code with line numbers. + +It works with `{% highlight some_language linenos %}...{% endhighlight %}` +and with the Kramdown option to add line numbers to fenced code. + +The implementation was derived from the workaround provided by +Dmitry Hrabrov (DeXP) at +https://github.com/penibelst/jekyll-compress-html/issues/71#issuecomment-188144901 + +EXPLANATION + +The HTML produced by Rouge highlighting with lie numbers is of the form +`code table`. Jekyll (<= 4.1.1) always wraps the highlighted HTML +with `pre`. This wrapping is not only unnecessary, but also transforms +the conforming HTML produced by Rouge to non-conforming HTML, which +results in HTML validation error reports. + +The fix removes the outer `pre` tags whenever they contain the pattern +``. + +Apart from avoiding HTML validation errors, the fix allows the use of +the [Jekyll layout for compressing HTML](http://jch.penibelst.de), +which relies on `pre` tags not being nested, according to +https://github.com/penibelst/jekyll-compress-html/issues/71#issuecomment-172069842 + +USAGE + +(Any names can be used for `some_var` and `some_language`.) + +{% capture some_var %} +{% highlight some_language linenos %} +Some code +{% endhighlight %} +{% endcapture %} +{% include fix_linenos.html code=some_var %} + +For code fences: + +{% capture some_var %} +```some_language +Some code +``` +{% endcapture %} +{% assign some_var = some_var | markdownify %} +{% include fix_linenos.html code=some_var %} + +CAVEATS + +The above does not work when `Some code` happens to contain the matched string +`
`. + +The use of this file overwrites the variable `fix_linenos_code` with `nil`. + +{%- endcomment -%} + +{% assign fix_linenos_code = include.code %} +{% if fix_linenos_code contains '
' %} + {% assign fix_linenos_code = fix_linenos_code | replace: '
', '
' %}
+  {% assign fix_linenos_code = fix_linenos_code | replace: "
", "" %} +{% endif %} +{{ fix_linenos_code }} +{% assign fix_linenos_code = nil %} diff --git a/_sass/code.scss b/_sass/code.scss index affc8aa..ead2c5f 100644 --- a/_sass/code.scss +++ b/_sass/code.scss @@ -11,23 +11,96 @@ code { border-radius: $border-radius; } -pre.highlight, -figure.highlight { +// Content structure for highlighted code blocks using fences or Liquid +// +// ```[LANG]...```, no kramdown line_numbers: +// div.[language-LANG.]highlighter-rouge > div.highlight > pre.highlight > code +// +// ```[LANG]...```, kramdown line_numbers = true: +// div.[language-LANG.]highlighter-rouge > div.highlight > pre.highlight > code +// > div.table-wrapper > table.rouge-table > tbody > tr +// > td.rouge-gutter.gl > pre.lineno +// | td.rouge-code > pre +// +// {% highlight LANG %}...{% endhighlight %}: +// figure.highlight > pre > code.language-LANG +// +// {% highlight LANG linenos %}...{% endhighlight %}: +// figure.highlight > pre > code.language-LANG +// > div.table-wrapper > table.rouge-table > tbody > tr +// > td.gutter.gl > pre.lineno +// | td.code > pre +// +// fix_linenos removes the outermost pre when it encloses table.rouge-table +// +// See docs/index-test.md for some tests. +// +// No kramdown line_numbers: fences and Liquid highlighting look the same. +// Kramdown line_numbers = true: fences have a wider gutter than with Liquid? + +// ```[LANG]...``` +div.highlighter-rouge { padding: $sp-3; margin-top: 0; - margin-bottom: 0; + margin-bottom: $sp-3; background-color: $code-background-color; border-radius: $border-radius; + box-shadow: none; -webkit-overflow-scrolling: touch; + div.highlight, + pre.highlight, code { padding: 0; + margin: 0; border: 0; } } -.highlighter-rouge { +// {% highlight LANG %}...{% endhighlight %}, +// {% highlight LANG linenos %}...{% endhighlight %}: +figure.highlight { + padding: $sp-3; + margin-top: 0; margin-bottom: $sp-3; + background-color: $code-background-color; + border-radius: $border-radius; + box-shadow: none; + -webkit-overflow-scrolling: touch; + + pre, + code { + padding: 0; + margin: 0; + border: 0; + } +} + +// ```[LANG]...```, kramdown line_numbers = true, +// {% highlight LANG linenos %}...{% endhighlight %}: +.highlight .table-wrapper { + padding: 0; + margin: 0; + border: 0; + box-shadow: none; + + td, + pre { + @include fs-2; + min-width: 0; + padding: 0; + background-color: $code-background-color; + border: 0; + } + + td.gl { + padding-right: $sp-3; + } + + pre { + margin: 0; + line-height: 2; + } } .highlight .c { diff --git a/docs/ui-components/code.md b/docs/ui-components/code.md index e53a90d..b8136a3 100644 --- a/docs/ui-components/code.md +++ b/docs/ui-components/code.md @@ -2,6 +2,7 @@ layout: default title: Code parent: UI Components +has_children: true nav_order: 6 --- diff --git a/docs/ui-components/linenos.md b/docs/ui-components/linenos.md new file mode 100644 index 0000000..b13e6c9 --- /dev/null +++ b/docs/ui-components/linenos.md @@ -0,0 +1,124 @@ +--- +layout: default +title: Code with line numbers +parent: Code +grand_parent: UI Components +--- + +# Configuration options + +The default settings for HTML compression are incompatible with the HTML +produced by Jekyll (4.1.1 or earlier) for line numbers from highlighted code +-- both when using Kramdown code fences and when using Liquid highlight tags. + +To avoid non-conforming HTML and unsatisfactory layout, HTML compression +can be turned off by using the following configuration option: + +{% highlight yaml %} +compress_html: + ignore: + envs: all +{% endhighlight %} + +When using Kramdown code fences, line numbers are turned on globally by the +following configuration option: + +{% highlight yaml %} +kramdown: + syntax_highlighter_opts: + block: + line_numbers: false +{% endhighlight %} + +Line numbers can then be suppressed locally using Liquid tags (_without_ the +`linenos` option) instead of fences: + +{% highlight yaml %} +{% raw %}{% highlight some_language %} +Some code +{% endhighlight %}{% endraw %} +{% endhighlight %} + +# Workarounds + +To use HTML compression together with line numbers, all highlighted code +needs to be wrapped using one of the following workarounds. +(The variable name `some_var` can be changed to avoid clashes; it can also +be replaced by `code` -- but note that `code=code` cannot be removed). + +## Code fences + +{% highlight default %} +{% raw %}{% capture some_var %} +```some_language +Some code +``` +{% endcapture %} +{% assign some_var = some_var | markdownify %} +{% include fix_linenos.html code=some_var %}{% endraw %} +{% endhighlight %} + +## Liquid highlighting + +{% highlight default %} +{% raw %}{% capture some_var %} +{% highlight some_language linenos %} +Some code +{% endhighlight %} +{% endcapture %} +{% include fix_linenos.html code=some_var %}{% endraw %} +{% endhighlight %} + +_Credit:_ The original version of the above workaround was suggested by +Dmitry Hrabrov at +. + +# Examples + +``` +Some unknown code in fences +``` + +```js +// Javascript code with syntax highlighting in fences +var fun = function lang(l) { + dateformat.i18n = require('./lang/' + l) + return true; +} +``` + +```ruby +# Ruby code with syntax highlighting in fences +GitHubPages::Dependencies.gems.each do |gem, version| + s.add_dependency(gem, "= #{version}") +end +``` + +{% highlight ruby %} +# Ruby code with syntax highlighting using Liquid +GitHubPages::Dependencies.gems.each do |gem, version| + s.add_dependency(gem, "= #{version}") +end +{% endhighlight %} + +{% capture code %} +{% highlight ruby linenos %} +# Ruby code with syntax highlighting and fixed line numbers using Liquid +GitHubPages::Dependencies.gems.each do |gem, version| + s.add_dependency(gem, "= #{version}") +end +{% endhighlight %} +{% endcapture %} +{% include fix_linenos.html code=code %} +{% assign code = nil %} + +With the default configuration options, the following example illustrates +the incorrect formatting arising from the incompatibility of HTML compression +and the non-conforming HTML produced by Jekyll for line numbers: + +{% highlight ruby linenos %} +# Ruby code with syntax highlighting and unfixed line numbers using Liquid +GitHubPages::Dependencies.gems.each do |gem, version| + s.add_dependency(gem, "= #{version}") +end +{% endhighlight %}