1. bbarry

    21.04.2008

    0 ↑
    0 ↓
    Sorry about the English, I don't know Russian at all:

    I added some functionality to highlight.js to give it alternating rows and row numbers. In order to activate it, you can either:
    add:
    hljs.addAlternatingRows();
    hljs.addLineNumbers();
    to your document headers or:
    class='startAt1 alternating-rows'
    to the code tag (you can start at other numbers as well: startAt# is the syntax).

    If you happen to have turned it on via javascript, you can turn it off by:
    hljs.noAlternatingRows();
    hljs.noLineNumbers();
    in javascript or by adding:
    class='no-linenumbers no-alternating-rows'
    to the code tag.

    Both features work independently of each other and the css classes will override the javascript settings. I tried adding reasonable styling to each of the css files as well and I added some tests as well as modifying the export.html file to support this. Also, it defaults to the current functionality.
    === modified file 'export.html'
    --- export.html 2008-04-21 13:12:25 +0000
    +++ export.html 2008-04-21 15:41:42 +0000
    @@ -34,11 +34,19 @@
    var t2 = document.getElementById("t2");
    var selector = document.getElementById("langSelector");
    var selectedLang = selector.options[selector.selectedIndex].value.toLowerCase();
    - if(selectedLang) {
    - viewDiv.innerHTML = '<pre><code class="'+selectedLang+'">'+t1.value.escape()+"</code></pre>";
    - } else { // try auto
    - viewDiv.innerHTML = '<pre><code>' + t1.value.escape() + "</code></pre>";
    + var linenumbers = document.getElementById("lineNumber");
    + var startAt = linenumbers.value;
    + if(startAt != '') startAt = 'startAt'+startAt;
    + var alternateRows = document.getElementById("alternateRows").checked;
    + var classinsert = '';
    + if(selectedLang || startAt != '' || alternateRows) {
    + classinsert = ' class="';
    + if(selectedLang) classinsert = classinsert+selectedLang+' ';
    + if(startAt != '') classinsert = classinsert+startAt+' ';
    + if(alternateRows) classinsert = classinsert+'alternating-rows';
    + classinsert = classinsert+'"';
    }
    + viewDiv.innerHTML = '<pre><code'+classinsert+'>' + t1.value.escape() + "</code></pre>";
    hljs.highlightBlock(viewDiv.firstChild.firstChild);
    t2.value = viewDiv.innerHTML;
    }
    @@ -64,6 +72,8 @@
    langSelectorHtml += '</select></label>';
    document.write(langSelectorHtml);
    </script>
    + <br/><label>Starting Line Number: <input id="lineNumber"></label>
    + <br/><label>Alternate Rows: <input type="checkbox" id="alternateRows"></label>
    <table width="100%">
    <tr>
    <td><textarea rows="20" cols="50" id="t1"></textarea></td>

    === modified file 'highlight.js'
    --- highlight.js 2008-04-21 13:12:25 +0000
    +++ highlight.js 2008-04-21 15:41:42 +0000
    @@ -300,11 +300,41 @@
    }
    }
    }
    +
    + function getStartingLineNumber(block) {
    + var classes = block.className.split(/\s+/);
    + for (var i = 0; i < classes.length; i++) {
    + if (classes == 'no-linenumbers') {
    + return -1;
    + }
    + if (classes.match("startAt") != null) {
    + //nearest I can tell there are some wierd things happenning with numbers; hence the "/ 1" part
    + return classes.match(/\d+/) / 1;
    + }
    + }
    + if(lineNumbers) return 1;
    + return -1;
    + }

    + function getAlternatingRowsOn(block) {
    + var classes = block.className.split(/\s+/);
    + for (var i = 0; i < classes.length; i++) {
    + if (classes == 'no-alternating-rows') {
    + return false;
    + }
    + if (classes == 'alternating-rows') {
    + return true;
    + }
    + }
    + return alternatingRows;
    + }
    +
    function highlightBlock(block) {
    try {
    var text = blockText(block);
    var language = blockLanguage(block);
    + var startAt = getStartingLineNumber(block);
    + var alternatingRows = getAlternatingRowsOn(block);
    } catch (e) {
    if (e == 'No highlight')
    return;
    @@ -327,6 +357,9 @@
    }

    if (result) {
    + if(startAt != -1 || alternatingRows)
    + result = insertLines(result, startAt, alternatingRows);
    +
    var className = block.className;
    if (!className.match(language)) {
    className += ' ' + language;
    @@ -339,6 +372,61 @@
    }
    }

    + function insertLines(highlightedText, startAt, alternatingRows) {
    + var counter = startAt + 1 - 1; //make sure it is a number; otherwise Math.log doesn't work right
    + var result = "";
    + //IE does wierd stuff when splitting blank lines, so insert a space
    + highlightedText = highlightedText.replace(/(\r\n|\r|\n)(\r\n|\r|\n)/g, "$1 $2");
    + var lines = highlightedText.split(/\r\n|\r|\n/);
    + var spaces = Math.ceil(Math.log(lines.length) / Math.log(10));
    + var newline = "";
    + var line;
    + var i;
    + var tokenArray = new Array();
    + if(spaces < 6)
    + spaces = 6;
    + for (line = 0; line < lines.length - 1; ++line) {
    + newline = "";
    + if(alternatingRows) {
    + newline = "<span class=\"";
    + if(line%2 == 0)
    + newline = newline + "row";
    + else
    + newline = newline + "alternaterow";
    + newline = newline + "\">";
    + }
    + if(startAt != -1) {
    + newline = newline + "<span class=\"rownumber\">";
    + for (i = 0; i < (spaces - (Math.ceil(Math.log(counter + 1) / Math.log(10)))); ++i)
    + newline = newline + " ";
    + newline = newline + counter + " </span>";
    + }
    + for(var restartTokenCt = 0; restartTokenCt < tokenArray.length; ++restartTokenCt) {
    + newline = newline + tokenArray[restartTokenCt];
    + }
    + var tokens = lines[line].match(/(<span class="\w+">)|(<\/span>)|(.*?)/g);
    + for (var tokenct = 0;tokenct<tokens.length;++tokenct) {
    + if (tokens[tokenct].match(/(<span class="\w+">)/)) {
    + tokenArray.push(tokens[tokenct]);
    + } else if (tokens[tokenct].match(/(<\/span>)/)) {
    + tokenArray.pop();
    + }
    + }
    + newline = newline + lines[line];
    + for(var restartTokenCt = 0; restartTokenCt < tokenArray.length; ++restartTokenCt) {
    + newline = newline + "</span>";
    + }
    +
    + newline = newline + "\n";
    + if(alternatingRows) {
    + newline = newline + "</span>";
    + }
    + counter++;
    + result = result + newline;
    + }
    + return result;
    + }
    +
    function langRe(language, value, global) {
    var mode = 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '');
    return new RegExp(value, mode);
    @@ -445,6 +533,14 @@
    this.initHighlightingOnLoad = initHighlightingOnLoad;
    this.highlightBlock = highlightBlock;

    + var lineNumbers = false
    + this.noLineNumbers = function() { lineNumbers = false; }
    + this.addLineNumbers = function() { lineNumbers = true; }
    +
    + var alternatingRows = false;
    + this.noAlternatingRows = function() { alternatingRows=false; }
    + this.addAlternatingRows = function() { alternatingRows=true; }
    +
    // Common regexps
    this.IDENT_RE = '[a-zA-Z][a-zA-Z0-9_]*';
    this.UNDERSCORE_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9_]*';

    === modified file 'styles/ascetic.css'
    --- styles/ascetic.css 2008-04-21 13:12:25 +0000
    +++ styles/ascetic.css 2008-04-21 15:41:42 +0000
    @@ -1,4 +1,4 @@
    -?/*
    +/*

    Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>

    @@ -34,4 +34,16 @@
    .winutils,
    .flow {
    font-weight: bold;
    -}
    \ No newline at end of file
    +}
    +
    +.rownumber {
    + border-right: 2px solid #AAA;
    + margin-right: 4px;
    + background-color: #EEE;
    +}
    +
    +.alternaterow {
    + width: 100%;
    + display: block;
    + background-color: #F9F9F9;
    +}

    === modified file 'styles/dark.css'
    --- styles/dark.css 2008-04-21 13:12:25 +0000
    +++ styles/dark.css 2008-04-21 15:41:42 +0000
    @@ -1,4 +1,4 @@
    -?/*
    +/*

    Dark style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>

    @@ -90,4 +90,16 @@
    .html .css,
    .html .javascript {
    opacity: 0.5;
    -}
    \ No newline at end of file
    +}
    +
    +.rownumber {
    + border-right: 1px solid #888;
    + margin-right: 2px;
    + background-color: #484848;
    +}
    +
    +.alternaterow {
    + width: 100%;
    + display: block;
    + background-color: #505050;
    +}

    === modified file 'styles/default.css'
    --- styles/default.css 2008-04-21 13:12:25 +0000
    +++ styles/default.css 2008-04-21 15:41:42 +0000
    @@ -1,4 +1,4 @@
    -?/*
    +/*

    Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>

    @@ -93,3 +93,15 @@
    .html .javascript {
    opacity: 0.5;
    }
    +
    +.rownumber {
    + border-right: 2px solid #666;
    + margin-right: 4px;
    + background-color: #EEE;
    +}
    +
    +.alternaterow {
    + width: 100%;
    + display: block;
    + background-color: #F9F9F9;
    +}

    === modified file 'styles/far.css'
    --- styles/far.css 2008-04-21 13:12:25 +0000
    +++ styles/far.css 2008-04-21 15:41:42 +0000
    @@ -91,4 +91,17 @@
    .flow {
    color: #FFF;
    font-weight: bold;
    -}
    \ No newline at end of file
    +}
    +
    +.rownumber {
    + border-right: 2px solid #CCC;
    + margin-right: 4px;
    + color: #0F0;
    + font-weight: bold;
    +}
    +
    +.alternaterow {
    + width: 100%;
    + display: block;
    + background-color: #007;
    +}

    === modified file 'styles/idea.css'
    --- styles/idea.css 2008-04-21 13:12:25 +0000
    +++ styles/idea.css 2008-04-21 15:41:42 +0000
    @@ -72,4 +72,17 @@

    .diff .change {
    background: #bccff9;
    -}
    \ No newline at end of file
    +}
    +
    +.rownumber {
    + border-right: 2px solid #666;
    + margin-right: 4px;
    + background-color: #EEE;
    + font-weight: bold;
    +}
    +
    +.alternaterow {
    + width: 100%;
    + display: block;
    + background-color: #F9F9F9;
    +}

    === modified file 'styles/sunburst.css'
    --- styles/sunburst.css 2008-04-21 13:12:25 +0000
    +++ styles/sunburst.css 2008-04-21 15:41:42 +0000
    @@ -105,4 +105,19 @@
    .deletion {
    background-color: #420E09;
    color: #F8F8F8;
    -}
    \ No newline at end of file
    +}
    +
    +.rownumber {
    + margin:0 4px;
    + color: #8996A8;
    + display:-moz-inline-stack; /* ff2 */
    + display: inline-block;
    + white-space: normal;
    + width: 60px;
    +}
    +
    +.alternaterow {
    + width: 100%;
    + display: block;
    + background-color: #111;
    +}

    === modified file 'styles/zenburn.css'
    --- styles/zenburn.css 2008-04-21 13:12:25 +0000
    +++ styles/zenburn.css 2008-04-21 15:41:42 +0000
    @@ -105,3 +105,8 @@
    opacity: 0.5;
    }

    +.alternaterow {
    + width: 100%;
    + display: block;
    + background-color:#303030;
    +}

    === modified file 'test.html'
    --- test.html 2008-04-21 13:12:25 +0000
    +++ test.html 2008-04-21 15:41:42 +0000
    @@ -34,6 +34,10 @@
    <script type="text/javascript" src="highlight.js"></script>
    <script type="text/javascript">
    hljs.initHighlightingOnLoad.apply(null, hljs.ALL_LANGUAGES);
    + //hljs.addAlternatingRows();
    + //hljs.noAlternatingRows();
    + //hljs.addLineNumbers();
    + //hljs.noLineNumbers();
    </script>

    <body>
    @@ -711,4 +715,73 @@
    &lt;/div&gt;
    </code></pre>

    + <tr>
    + <th>Line numbers
    + <td>
    +<pre><code class="startAt1">@requires_authorization
    +def somefunc(param1, param2):
    + '''A docstring'''
    + if param1 > param2:
    + # interesting
    + print 'Gre\'ater'
    + print ''
    + return (param2 - param1 + 1) or None
    +
    +class SomeClass:<br> pass
    +</code></pre>
    +
    + <tr>
    + <th>Line numbers can start somewhere other than 1
    + <td>
    +<pre><code class="startAt53 cpp"> for (unsigned i = 0; i &lt; 0xFFFF; i++)
    + cout &lt;&lt; "Hello, World!" &lt;&lt; endl;
    +</code></pre>
    +
    + <tr>
    + <th>Alternating Rows
    + <td>
    +<pre><code class="alternating-rows">@requires_authorization
    +def somefunc(param1, param2):
    + '''A docstring'''
    + if param1 > param2:
    + # interesting
    + print 'Gre\'ater'
    + print ''
    + return (param2 - param1 + 1) or None
    +
    +class SomeClass:<br> pass
    +</code></pre>
    +
    + <tr>
    + <th>Explicitly No Alternating Rows
    + <td>
    +<pre><code class="no-alternating-rows">@requires_authorization
    +def somefunc(param1, param2):
    + '''A docstring'''
    + if param1 > param2:
    + # interesting
    + print 'Gre\'ater'
    + print ''
    + return (param2 - param1 + 1) or None
    +
    +class SomeClass:<br> pass
    +</code></pre>
    +
    + <tr>
    + <th>Alternating rows and <br>Line numbers
    + <td>
    +<pre><code class="alternating-rows startAt53 java"> protected static final Logger _log = Logger.getLogger(L2Character.class.getName());
    +
    + public static final Short ABNORMAL_EFFECT_BLEEDING = 0x0001; // not sure
    + public static final Short ABNORMAL_EFFECT_POISON = 0x0002;
    +
    + public void detachAI() {
    + _ai = null;
    + //jbf = null;
    + if (1 > 5) {
    + return;
    + }
    + }
    +</code></pre>
    +
    </table>
    I am emailing this to Maniac (Ivan Sagalaev, Иван Сагалаев, I think?). Is that right?
  2. Ivan Sagalaev

    21.04.2008

    0 ↑
    0 ↓
    Sorry about the English, I don't know Russian at all
    This is perfectly OK, don't worry :-)

    I've read your patch and it seems to be really good (except for may be calculating logarithms in a loop which might be slow, though I didn't test).

    But... The thing is that I don't want to cross the line where useful highlighting becomes distracting eye-candy. In my opinion line numbers and alternate row colors are beyond the line. The former is useful in an editor where you sometimes want to search a line by its number from an error message. But I can't invent a usecase for a code snippet in a blog post. And the latter is not used anywhere except other highlighters many of which, in my opinion, just can't stop adding new features :-).

    Please don't take it personally. It's just my own feeling of what should and should not be in highlight.js. However if you think that this may be useful to others you can make your own variant of highlight.js distribution or may be package your patch as an additional script. I'll happily link to it from http://softwaremaniacs.org/soft/highlight/en/addons/. And in this case I think you might find useful a link to the repository: svn://softwaremaniacs.org/highlight/
  3. bbarry

    22.04.2008

    0 ↑
    0 ↓
    No problem; I figured I like this library better than http://code.google.com/p/syntaxhighlighter/ but I do find the line numbers useful there.

    The main use case for the numbers is when you want to refer to the lines individually, but I was actually considering this for a syntax highlighter in the web front end for mercurial (highlighting stuff like this: http://hg.mozilla.org/index.cgi/actionmonkey/file/66a5c7bce7ee/browser/fuel/src/fuelApplication.js). I feel that it could simplify the server side code as well (in some other places too, like diffs) as provide a highlighting solution for many of the files under source control. On the other hand I am also considering converting this library to python to not rely on client side javascript (but still provide more powerful functionality than is there now, as well as consolidating the current formatting functions).

    I agree with you on the alternating row colors; it is rather pointless. The only reason I added it was because I figured it was pretty easy to do (and it is already done in the mercurial pages).

    I was also thinking about trying my hand at a Thunderbird extension to highlight the code in rss feeds. I would have to create highlighters for C#, VB.NET, Perl and Boo first though. At the moment these are just ideas. I'll keep you posted and I will send you the highlighters when I make them. I do plan on using this on my blog (at http://16randombytes.blogspot.com, replacing the copy source as html addon for visual studio; it will be mostly C# though).
  4. Ivan Sagalaev

    22.04.2008

    0 ↑
    0 ↓
    The main use case for the numbers is when you want to refer to the lines individually, but I was actually considering this for a syntax highlighter in the web front end for mercurial
    Ah.. I see. Looks like it's really out of scope of highlight.js then. Or may be I should think more deeply if it can handle such usecase too. I'll think about it :-)
    On the other hand I am also considering converting this library to python to not rely on client side javascript
    Why not use http://pygments.org/ ? I believe it's pretty advanced library.
    I would have to create highlighters for C#, VB.NET, Perl and Boo first though
    Now *this* would be very useful for highlight.js :-). It really lacks mainstream Microsoft languages currently...

    Thanks!
  5. Josefina

    18.02.2009

    0 ↑
    0 ↓
    Hi,
    I would need to show line numbers too, where can I download these files? otherwise I will try to update them manually..
    Thanks,josefina
  6. Ivan Sagalaev

    18.02.2009

    0 ↑
    0 ↓

    Josefina, I believe that bbarry doesn't track this thread (given it's almost a year old). I think it makes sense to contact him on his blog that he mentioned (http://16randombytes.blogspot.com)

  7. alex

    27.06.2011

    0 ↑
    0 ↓
    хочется встроенного нумератора строк, не мешающего копировать код ^_^
    вот есть коротенькое решение
    http://mrer.org.ua/?article=show%5Bbe_careful_guru%5D%5Bhighlight_js_with_row_numbers%5D%5Ben%5D
    не хочеш встроить?

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.