Skip to content

Better lineno in needs JSON#1692

Open
sebastiansetzer wants to merge 4 commits intouseblocks:masterfrom
sebastiansetzer:lineno_experiments
Open

Better lineno in needs JSON#1692
sebastiansetzer wants to merge 4 commits intouseblocks:masterfrom
sebastiansetzer:lineno_experiments

Conversation

@sebastiansetzer
Copy link
Copy Markdown

This should fix #1349.

The fix for the include and rst-prolog use cases is simple.

I just wonder if anyone relies on having unique line numbers for one "docname" and docname being a full rst document, not an include file. If that's the case, maybe instead of fixing the lineno attribute, we should add a new attribute (maybe call it "source position"?)
On the other hand, the only reason I can think of why you would not want include file names as "source" attribute is if you had one that you included in multiple places. And if you do that, you won't have needs in there, because those would then get duplicated.

The fix for the list2need use case is abusing the "source" string to pass line number information from the list2needs directive to the generated needs directives.
I considered passing this information through a generated "option", but when I declare this in needs_extra_options, it shows up for all needs (as "None" when unused) in the JSON, so that's a bit ugly.

I guess the best solution would be to refactor the list2need directive to create the needs objects directly, instead of generating rst text which is then injected back into the parser. This would avoid the need to pass line numbers, and it would even avoid calling state_machine.insert_input, so it wouldn't corrupt line numbers for subsequent needs.
Of course, corrupted line numbers of subsequent needs are already fixed by using state_machine.get_source_and_line, and you'd want to keep this for the include and rst-prolog use cases, so the important reason for the refactoring is just avoiding to encode line numbers in the source string.

Before attempting to do this refactoring, I would like to understand why the current solution with state_machine.insert_input was chosen. Directly creating the needs objects seems more obvious, so I wonder if I'm missing the reason for Chesterton's fence here.

My test setup is attached - not integrated into the sphinx-needs test suite so far.
rst-lineno-bug-tests.zip

sebastiansetzer and others added 4 commits April 6, 2026 11:25
This function converts the "virtual" lineno into a real line number
as it appears in the source file, even in the presence of code
injected with state_machine.insert_input.
The injected code has line numbers starting from 1 again,
and the returned "source" name is the name of an include file,
if that's where the injected code is from.
It is not used anymore, and the next commit will turn the commented out
line unusable because you need to iterate over each line to get
line numbers.
In the case of list2need, the injected text is not coming from
an include file, it is needs directives generated from a list2need
directive.
So the line number info returned by state_machine.get_source_and_line
is not useful: The source is still the original document, but the
linenumber is the offset within the generated text.

In the list2needs directive, compute the line number of the list item
defining the need, by starting from self.content_offset+1, which is
the virtual lineno of the directive content, turning it into a real
lineno through get_source_and_line, and adding the relative line number
inside the contents.

Encode this information in the "source" parameter passed to
state_machine.insert_input, so that it can be later retrieved
when the need is created.
You need separate state_machine.insert_input invocations in order to
get different source for each need. Don't combine them into one
overall_text anymore.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lineno gets shifted if rst_prolog is present

1 participant