jgm / skylighting

A Haskell syntax highlighting library with tokenizers derived from KDE syntax highlighting descriptions
194 stars 62 forks source link

Demarcating source lines in html output #13

Closed dbaynard closed 7 years ago

dbaynard commented 7 years ago

The issue raised in jgm/pandoc#3838 :

misaligned

corresponds to this library.

(from that linked issue:)

The fundamental issue is the markdown is converted to the following html

<body>
<div class="sourceCode"><table class="sourceCode haskell numberLines"><tr class="sourceCode"><td class="lineNumbers"><pre>1
2
3
4
5
</pre></td>
<td class="sourceCode"><pre><code class="sourceCode haskell">
<span class="ot">extraLongFunctionWithVeryLongNames ::</span> a <span class="ot">-&gt;</span> a
extraLongFunctionWithVeryLongNames <span class="fu">=</span> whenTheLineGetsTooLong <span class="fu">.</span> itWraps <span class="fu">.</span> whenPrinted <span class="fu">.</span> ifTheCSSOption <span class="st">&quot;white-space&quot;</span> <span class="fu">.</span> isSetTo <span class="st">&quot;pre-wrap&quot;</span>

<span class="ot">whenTheLineGetsTooLong ::</span> a <span class="ot">-&gt;</span> a
whenTheLineGetsTooLong <span class="fu">=</span> id
</code></pre></td>
</tr></table></div>
</body>

With numberLines the code is inserted into a one row, two column table, with the left column a simple list of newline-separated line numbers. Without numberLines there is no indication what code corresponds to a line, in the html output — indeed, in the native AST line breaks are represented as \n but this information is lost on conversion to html.

I suspect the fix for this would be to rewrite the html writer so that numberLines wraps each line in a div, say (this could then be prefixed with a line number using css) or something more similar to github, where the code is presented in a table but each line has its own row.

Any solution must preserve behaviour of copy-paste: line numbers must not be copied.


Wrapping each line in a div.sourceLine is trivial; the question concerns the remaining behaviour. Options are:

  1. Add numbers using pseudo-elements (div.sourceLine::before) in custom css inserted into each file.
  2. Hard code the line numbers, and just add css to display them.

For the former case, a fairly minimal css required looks like:

div.sourceLine {
    text-indent: -1em;
}
div.sourceLine::before {
    content: counter(line);
    counter-increment: line;
    position: relative;
    left: -1em;
    text-align: right;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    padding: 0 4px;
}

pre.sourceCode {
    margin-left: 3em;
    border-left: 1px solid #a0a0a0;
    padding-left: 4px;
}
}

code.sourceCode {
    counter-reset: line 0;
    white-space: pre-wrap;
}

.sourceCode {
    overflow: visible;
}

and produces

with-line-numbers

dbaynard commented 7 years ago

TODO

dbaynard commented 7 years ago

Just thinking about that list of tasks; wrapping each line of code in its own div could be a standalone change (the first two tasks) that would be very useful beyond this issue. Any change will break code relying on css selectors like code > span; I don't know how important that might be.

jgm commented 7 years ago

Any change will break code relying on css selectors like code > span; I don't know how important that might be.

It might be fairly important, because people may be using templates that hard-code CSS for highlighting, and the default CSS has always used code > span. So there's a potential for breaking existing documents.

dbaynard commented 7 years ago

~I can just add extra selectors for the css to cover both cases! (Turns out it's an easy solution...)~ I'll discuss in the PR