Skip to content

fix code() failing with "line number not found in file stdio" on pasted input#4358

Draft
d-torrance wants to merge 1 commit into
Macaulay2:developmentfrom
d-torrance:history
Draft

fix code() failing with "line number not found in file stdio" on pasted input#4358
d-torrance wants to merge 1 commit into
Macaulay2:developmentfrom
d-torrance:history

Conversation

@d-torrance
Copy link
Copy Markdown
Member

readline 8+ enables bracketed paste mode by default. When the user pastes multiple lines at once, readline() can return a single string containing embedded newlines (e.g. "expr1\nexpr2") rather than one line per readline() call.

The old code called add_history() on the entire returned string, so the whole paste was stored as one history entry. Meanwhile M2's parser incremented lineNumber for every '\n' it saw, creating a mismatch: after a two-line paste the session line counter was 2 but only one new history entry existed.

code.m2 maps M2 line numbers to history entries via
getHistory(lineNumber + historyOffset)
so getHistory(2 + historyOffset) would call history_get() with an out-of-range index, return NULL, and ultimately produce:

error: line number 1 not found in file stdio

Fix: instead of a single add_history(p), split p at each embedded '\n' and add each segment as its own history entry (save/restore the '\n' in-place). For single-line input (the common case) this is identical to the previous behaviour.

Fixes: #4356

AI Disclosure

This was 100% Claude Code

…ed input

readline 8+ enables bracketed paste mode by default.  When the user
pastes multiple lines at once, readline() can return a single string
containing embedded newlines (e.g. "expr1\nexpr2") rather than one
line per readline() call.

The old code called add_history() on the entire returned string, so
the whole paste was stored as one history entry.  Meanwhile M2's
parser incremented lineNumber for every '\n' it saw, creating a
mismatch: after a two-line paste the session line counter was 2 but
only one new history entry existed.

code.m2 maps M2 line numbers to history entries via
    getHistory(lineNumber + historyOffset)
so getHistory(2 + historyOffset) would call history_get() with an
out-of-range index, return NULL, and ultimately produce:

    error: line number 1 not found in file stdio

Fix: instead of a single add_history(p), split p at each embedded '\n'
and add each segment as its own history entry (save/restore the '\n'
in-place).  For single-line input (the common case) this is identical
to the previous behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mahrud
Copy link
Copy Markdown
Member

mahrud commented May 23, 2026

I don't think Claude identified the correct solution. We don't want to split user's input into several lines. It is a feature that if I paste multiple lines, then want to redo the same thing, I can go up until I get to the full multiline input and enter it again.

I'm not even sure Claude identified the correct problem. e.g. this works fine:

i1 : g = () -> (
    L = {};
    for i to 4000 do (
        L = append(L, i)
        )
    )

o1 = g

o1 : FunctionClosure

i2 : code g

o2 = stdio:1:4-6:5: --source code:
     g = () -> (
         L = {};
         for i to 4000 do (
             L = append(L, i)
             )
         )

Which indicates that lines 1 through 6 were correctly retrieved from history.

@d-torrance d-torrance marked this pull request as draft May 23, 2026 14:05
@pzinn
Copy link
Copy Markdown
Contributor

pzinn commented May 26, 2026

I'm a little confused what this has to do with readline -- neither emacs nor WebApp mode use readline, and I've definitely encountered some version of this bug.

@d-torrance
Copy link
Copy Markdown
Member Author

They do use readline a bit -- in particular for grabbing the code of things defined in stdio

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants