Edgewall Software

Opened 12 years ago

Last modified 9 years ago

#10834 closed enhancement

Option to add line numbers to code blocks — at Version 32

Reported by: Ryan J Ollos <ryan.j.ollos@…> Owned by: Ryan J Ollos
Priority: normal Milestone: 1.1.2
Component: wiki system Version:
Severity: normal Keywords: wikimacros
Cc: ethan.jucovy@…, leho@… Branch:
Release Notes:

Line numbers and row highlighting can be specified for WikiProcessor code blocks.

API Changes:

The WikiProcessor argument parser supports supports dashes in the argument value.

Internal Changes:

Description

Inspired by th:LinenoMacro, the attached patch adds an option annotations=lineno that adds line numbers to code blocks.

{{{#!python annotations=lineno
}}}

The unit test is failing. I'm hoping someone can give me some guidance on that.

Change History (37)

by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

Attachment: t10834-r11295-1.patch added

Patch against r11295 of trunk.

comment:1 by Remy Blank, 12 years ago

I'm not familiar with annotations in the mimeview renderers, but it looks like this would generate duplicate element IDs if there are two such blocks on the same page.

comment:2 by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

Yeah, your are right, it does generate duplicate element IDs. It seems like the easiest thing to do would be to just drop the element IDs from the line numbers. This was actually the approach taken by the th:LinenoMacro before I changed it to use trac.mimeview.api.LineNumberAnnotator.

by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

Attachment: t10834-r11295-2.patch added

Second revision of patch against r11295 of trunk.d

comment:3 by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

I'm not sure that modifying LineNumberAnnotator is the best way to accomplish this, but that is what t10834-r11295-2.patch does to try and fix the issue. It might be better to add another implementation of IHTMLPreviewAnnotator.

comment:4 by Christian Boos, 12 years ago

Good suggestion with this ticket! However I'd prefer something like lineno=n (then start numbering at n). And if we pass id=something, then we could also have the #somethingLn links.

comment:5 by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

I didn't like the verboseness of annotations=lineno anyway, so lineno=n sounds like a good alternative. So do you think I should take the route of implementing a new IHTMLPreviewAnnotator?

in reply to:  4 ; comment:6 by Remy Blank, 12 years ago

Replying to cboos:

And if we pass id=something, then we could also have the #somethingLn links.

Users shouldn't have to worry about Trac generating well-formed and validated XHTML. We should implement an auto-numbering scheme like we do for heading anchors. The id= attribute could still be useful, in the same way as we can override the heading anchors, but we should do the right thing automatically by default.

in reply to:  6 comment:7 by Christian Boos, 12 years ago

For a code block, if you just autonumber it, the links will break as soon as you're prepending another block. Having to specify id= explicitly for having anchors makes it less likely to shoot yourself in the foot. But OK, as the links would probably be placed just next to the code snippet anyway, this will not be very consequential.

comment:8 by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

I've attempted to implement the unique autonumbered ids for the th:LinenoMacro. The ids are of the form a\d-L\d (th:browser:/linenomacro/trunk/lineno/LinenoMacro.py@11954). When the id attribute is specified, the anchor id would be %s-L\d % id. Does that seem like an okay scheme?

comment:9 by Remy Blank, 12 years ago

Yes, looks good.

The auto-numbering of anchors ensures that our XHTML always validates, and it's fine for the cases where the anchors are not actually used, or when there's only one code snippet. When there's more and you break your links, it's easy to fix with id=.

by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

Attachment: t10834-r11295-3.patch added

Patch against r11295 of trunk.

comment:10 by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

t10834-r11295-3.patch implements the proposed feature.

  • If id is not specified, the first unique anchor id prefix is chosen, starting with a1 and incrementing the digit.
  • Line numbers are only added to the code block if the lineno option is specified. Specifying the id option without specifying lineno has no effect.

Also:

  • Removed an unnecessary inline import from trac.mimeview.api import Mimeview.
  • Fixed an obsolete comment.
  • Added a new Formatter class member function _unique_anchor.

Some undesirable behavior exists. If there is a space added between the key/value pair, for example id = b, then the arguments become id=True, b=True, and the anchor id prefix becomes True. This behavior effects any key/value pairs passed to WikiProcessors, and it looks like WikiProcessors#UsingProcessors is fairly clear about the syntax, but we may want to improve on this in the future and strip whitespace around the = character.

comment:11 by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

I wasn't sure whether passing data through the hints member variable was the right thing to do here, but I didn't see another way to pass data to the IHTMLPreviewAnnotator within the existing structure. I'll modify the patch if someone points me in another direction.

comment:12 by Christian Boos, 12 years ago

It's fine, it's just that the term hints is a bit over-restrictive here. I meant to try out the patches soon (or the patch, it's just t10834-r11295-3.patch, right?).

in reply to:  12 ; comment:13 by Christian Boos, 12 years ago

As a side-note:

t10834-r11295-3.patch, right?).

Oops, [attachment:t10834-r11295-3.patch​]/t10834-r11295-3.patch vs. [attachment:t10834-r11295-3.patch]/t10834-r11295-3.patch (i.e. without the trailing ZWSP) …

I thought we fixed that…

in reply to:  12 comment:14 by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

Replying to cboos:

It's fine, it's just that the term hints is a bit over-restrictive here. I meant to try out the patches soon (or the patch, it's just t10834-r11295-3.patch, right?).

Yes, just t10834-r11295-3.patch. It supersedes the other patches.

in reply to:  13 ; comment:15 by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

Replying to cboos:

I thought we fixed that…

Jun fixed a similar case for the Image macro (#10668). I had been wondering whether the same problem could come about with attachment TracLinks, but hadn't been able to reproduce what you've just shown. I could put together a fix similar to [11074], if no one wants to beat me to it. I guess a new ticket is in order.

in reply to:  15 comment:16 by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

Replying to Ryan J Ollos <ryan.j.ollos@…>:

Jun fixed a similar case for the Image macro (#10668). I had been wondering whether the same problem could come about with attachment TracLinks, but hadn't been able to reproduce what you've just shown. I could put together a fix similar to [11074], if no one wants to beat me to it. I guess a new ticket is in order.

#10865

comment:17 by Christian Boos, 12 years ago

Btw, I just noticed we had a ticket for that already, #3275. Some interesting ideas there, for example the link to Sphinx.

comment:18 by Christian Boos, 12 years ago

Milestone: next-dev-1.1.x

in reply to:  17 ; comment:19 by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

Replying to cboos:

Btw, I just noticed we had a ticket for that already, #3275. Some interesting ideas there, for example the link to Sphinx.

Are you hinting that we should utilize Pygments, or did you like some of the other options offered by Sphinx such as emphasize-lines?

I have some time to do more work on the patch over the weekend. Maybe I can figure out what is wrong with the unit test.

in reply to:  19 ; comment:20 by Christian Boos, 12 years ago

Replying to Ryan J Ollos <ryan.j.ollos@…>:

Replying to cboos:

Btw, I just noticed we had a ticket for that already, #3275. Some interesting ideas there, for example the link to Sphinx.

Are you hinting that we should utilize Pygments, or did you like some of the other options offered by Sphinx such as emphasize-lines?

The latter, of course. An equivalent to emphasize-lines could be achieved with mark=120,123-125 and reuse the marking mechanism we already have.

I have some time to do more work on the patch over the weekend. Maybe I can figure out what is wrong with the unit test.

Well, the unit-test wasn't refreshed since the first patch it seems, so it doesn't have lineno or lineno=12 (two or more tests, also with id=explicit-id, would be even better).

But the patch looks good to me.

in reply to:  20 ; comment:21 by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

Replying to cboos:

The latter, of course. An equivalent to emphasize-lines could be achieved with mark=120,123-125 and reuse the marking mechanism we already have.

I've added the marks option to the revised patch. One ugly and probably error-prone aspect of this is that it seems to be necessary to quote the values, for example: marks="120,123-125". One first glance, it looks like some changes to trac.wiki.parse.parse_processor_args would be required to change this behavior.

I'll add some tests in the next iteration of the patch, but just wanted to post the latest changes for review, in case there is anything obvious that can be spotted.

by Ryan J Ollos <ryan.j.ollos@…>, 12 years ago

Attachment: t10834-r11421-1.patch added

Patch against r11421 of the trunk.

in reply to:  21 ; comment:22 by Ryan J Ollos <ryan.j.ollos@…>, 11 years ago

Replying to Ryan J Ollos <ryan.j.ollos@…>:

I've added the marks option to the revised patch. One ugly and probably error-prone aspect of this is that it seems to be necessary to quote the values, for example: marks="120,123-125". One first glance, it looks like some changes to trac.wiki.parse.parse_processor_args would be required to change this behavior.

Rather than providing another patch, I pushed the latest changes to a branch of my fork in 936367a44adf4c08ecd4391f699fb16e3fe5f260. Please bear with me while I learn how to use Git, and I appreciate any hints on how to do this better.

I propose the follow change to parse_processor_args:

-PROCESSOR_PARAM = r'''(?P<proc_pname>\w+)=(?P<proc_pval>".*?"|'.*?'|\w+)'''
+PROCESSOR_PARAM = r'''(?P<proc_pname>\w+)=(?P<proc_pval>".*?"|'.*?'|[-,\w]+)'''

Here is the before/after output:

>>> parse_processor_args('ab=c de -f gh="ij klmn" p=q-r')
{'ab': 'c', 'f': False, 'de': True, 'p': 'q', 'r': False, 'gh': 'ij klmn'}

>>> parse_processor_args('ab=c de -f gh="ij klmn" p=q-r')
{'p': 'q-r', 'de': True, 'ab': 'c', 'f': False, 'gh': 'ij klmn'}

and p=q-r,s yields the dictionary entry 'p': 'q-r,s'.

This would allow the marks=120,123-125 syntax to be accepted by the processor. I implemented this in 84ba753c5185c2182f3eb59957c5f4c30fe080e5.

Test cases have been added. There were a two issues that could probably be improved on:

  • The .replace(u'\\xa0',u'\xa0') was a workaround for not knowing how to deal with the unicode escape sequence being escaped on read.
  • There is no line break after the table, so I couldn't allow a line break between the expected output and the 30 character test case delimiter.

Other than that, the patch is ready in my opinion, though I'll do more work on it if I get feedback.

in reply to:  22 ; comment:23 by Christian Boos, 11 years ago

Replying to Ryan J Ollos <ryan.j.ollos@…>:

Rather than providing another patch, I pushed the latest changes to a branch of my fork in 936367a4. Please bear with me while I learn how to use Git, and I appreciate any hints on how to do this better.

Great! First tip: 8 digits for referring to commits are (more than) enough.

Second tip, there are basically two ways to work on topic branches:

  1. cumulative: add new changesets to integrate feedback; the end result will get committed back in the main branch (or svn, for us) as a whole anyway, so the precise content of each changeset doesn't matter that much
  2. iterative: rework each changeset until each change is "perfect"; the end result might be committed 1 to 1 to the main branch, as a way to better document the changes

Choose whichever style you prefer or is appropriate to the nature of the feature. The "cumulative" style is certainly easier and the "iterative" style is really great if you like to work that way (it's very similar to working with MQ, in Mercurial), but is a bit harder to get used to (rebase -i is your friend!). And there is the advice: if you choose this way, never reuse the same branch name for a rebased branch, but start by making a copy (.2 suffix), then rebase that copy. See for example #10717. That advice also applies if for some reason you feel you need to rebase your branch on top of the latest changes from upstream.

I propose the follow change to parse_processor_args: […] and p=q-r,s yields the dictionary entry 'p': 'q-r,s'.

After thinking a bit about it, I wasn't able to find a counter example for the comma, so I think I'm fine with this.

Test cases have been added. There were a two issues that could probably be improved on:

  • The .replace(u'\\xa0',u'\xa0') was a workaround for not knowing how to deal with the unicode escape sequence being escaped on read.

Just insert a plain unicode "NO-BREAK SPACE" character in the .txt file instead. (Hint: C-x 8 RET a0, or copy/paste from the French translation file which is full of these little things if you don't use the One True Editor)

  • There is no line break after the table, so I couldn't allow a line break between the expected output and the 30 character test case delimiter.

Add "Paragraph" after the block. That way the generated content will end with:

...</table><p>
Paragraph
</p>

It's a trick we use for a lot of other tests there.

Other than that, the patch is ready in my opinion, though I'll do more work on it if I get feedback.

A part from improving the tests, I also think it's (nearly) good to go (I said nearly as I just added a few inline comments about TracDev/CodingStyle, on the changesets themselves on GitHub). I'm quite pleased with the result, great job!

Note: you can "assign" the ticket to yourself, it will then show up in the assigned group in the milestone progress bar (in yellow), which is helpful for showing work-in-progress tickets.

by Ryan J Ollos <ryan.j.ollos@…>, 11 years ago

Attachment: WorkflowActionBox.png added

in reply to:  23 comment:24 by Ryan J Ollos <ryan.j.ollos@…>, 11 years ago

Owner: set to anonymous
Status: newassigned

Replying to cboos:

[…] A part from improving the tests, I also think it's (nearly) good to go (I said nearly as I just added a few inline comments about TracDev/CodingStyle, on the changesets themselves on GitHub). I'm quite pleased with the result, great job!

Thanks for the review and feedback. I think I've captured these changes in 8343e40d.

Note: you can "assign" the ticket to yourself, it will then show up in the assigned group in the milestone progress bar (in yellow), which is helpful for showing work-in-progress tickets.

I'll give this a try, but even though I have my username and email set in the session data, it is showing that the owner will be changed to anonymous:

comment:25 by Ryan J Ollos <ryan.j.ollos@…>, 11 years ago

Owner: changed from anonymous to Ryan J Ollos <ryan.j.ollos@…>

It looks like I can change ownership to now, but I'll have to manually input my username and email.

comment:26 by Ryan J Ollos <ryan.j.ollos@…>, 11 years ago

Would it be okay to target this one to 1.1.2 since it has a patch that has been reviewed?

comment:27 by Christian Boos, 11 years ago

Keywords: wikimacros added
Milestone: next-dev-1.1.x1.1.2

Yep.

comment:28 by ethan.jucovy@…, 11 years ago

Cc: ethan.jucovy@… added

comment:29 by Ryan J Ollos, 11 years ago

Owner: changed from Ryan J Ollos <ryan.j.ollos@…> to Ryan J Ollos

comment:30 by Ryan J Ollos, 11 years ago

Unrelated changes from t10834 on GitHub committed to 1.0-stable in [12111] and merged to trunk in [12112].

comment:31 by Ryan J Ollos, 11 years ago

There is a problem with the patch, which I'll propose a fix for shortly, though I'm not certain that my fix is the right way to go yet. I'll be hoping to get some feedback. The problem is exhibited with the following markup:

{{{#!python lineno=3 id=b marks=4-5
print 'this is a python sample'
a = b+3
z = "this is a string"
print 'this is the end of the python sample'
}}}

[[BR]]

{{{#!python lineno=3 id=d
print 'this is a python sample'
a = b+3
z = "this is a string"
print 'this is the end of the python sample'
}}}

which renders as:

Line
3print 'this is a python sample'
4a = b+3
5z = "this is a string"
6print 'this is the end of the python sample'


Line
3print 'this is a python sample'
4a = b+3
5z = "this is a string"
6print 'this is the end of the python sample'

Note that the second WikiProcessor call doesn't have the marks argument, but still highlights the rows.

comment:32 by Ryan J Ollos, 11 years ago

API Changes: modified (diff)
Release Notes: modified (diff)

Proposed changes can be found in repos:rjollos.git:t10834. To deal with the issues described in comment:31:

  • A child RenderingContext is created in _mimeview_processor before adding the hints.
  • The hilite class is no longer added in _render_source when marks have been specified as request arguments. The hilite class is added by LineNumberAnnotator. This appears to work just fine for rendering in the source browser as well.
Note: See TracTickets for help on using tickets.