Skip to content

Fix interactive prompt: keep reverse-video escape inside readline non-printing markers - #900

Open
tkossak wants to merge 1 commit into
jarun:masterfrom
tkossak:fix/prompt-readline-markers
Open

Fix interactive prompt: keep reverse-video escape inside readline non-printing markers#900
tkossak wants to merge 1 commit into
jarun:masterfrom
tkossak:fix/prompt-readline-markers

Conversation

@tkossak

@tkossak tkossak commented Jul 8, 2026

Copy link
Copy Markdown

Description

In the interactive prompt, after typing characters and pressing Backspace repeatedly, the first typed character cannot be deleted (the cursor/redisplay is off by one column).

The colored prompt brackets its ANSI escapes with readline's non-printing markers \001 (RL_PROMPT_START_IGNORE) and \002 (RL_PROMPT_END_IGNORE) so they aren't counted toward the prompt width. But in the reverse-video open sequence, \002 is placed before the terminating m of \x1b[7m, leaving the m outside the ignore region:

# before
PROMPTMSG = '\001\x1b[7\002mbuku (? for help)\001\x1b[0m\002 '
#                    ^^^^ \002 closes before the terminating `m`

The terminal still consumes \x1b[7m as an invisible SGR toggle, but readline counts the leftover m as one visible column. So readline computes the prompt as 19 columns wide when it renders as 18 — an off-by-one that shifts readline's idea of where input begins, so Backspace stops one column early. The reset code \001\x1b[0m\002 is already wrapped correctly, which is why the error is exactly one column.

Fix — move \002 to after the m, so the whole \x1b[7m is inside the markers:

# after
PROMPTMSG = '\001\x1b[7m\002buku (? for help)\001\x1b[0m\002 '

Two occurrences are affected: PROMPTMSG (main reverse-video prompt) and the per-DB prompt suffix ([{bdb.dbname}]).

Design notes

Purely a correction of the readline non-printing markers around the reverse-video SGR opener; no logic, API, or option changes. The closing \x1b[0m was already correctly bracketed and is left unchanged.

Side effects

None expected. The change is inert when color is disabled (--nc / NO_COLOR), since that path uses the plain, escape-free PROMPTMSG. Not OS-specific — it's a readline redisplay issue reproducible wherever GNU readline is used.

Test cases

Minimal repro (no buku needed) — before the fix, type a word then Backspace to the start; the first char can't be removed:

import readline  # noqa: F401
prompt = '\001\x1b[7\002mbuku (? for help)\001\x1b[0m\002 '
input(prompt)

Manual verification with buku:

buku              # type "hello", hold Backspace -> clears fully, incl. first char
buku --db testdb  # exercises the [testdb] reverse-video suffix; backspace behaves too

Linting (per PR guidelines) — both clean on the change:

python3 -m flake8 buku.py
python3 -m pylint buku.py --rc-file tests/.pylintrc

…kers

The colored prompt brackets its ANSI escapes with RL_PROMPT_START_IGNORE
(\001) and RL_PROMPT_END_IGNORE (\002) so readline does not count them toward
the prompt width. In the reverse-video opener, \002 was placed before the
terminating 'm' of \x1b[7m, leaving 'm' outside the ignore region. readline
counted it as a visible column, making the prompt one column wider than it
renders. That off-by-one shifted readline's input-start position, so Backspace
could not delete the first typed character.

Move \002 to after the 'm' so the whole \x1b[7m sits inside the markers. This
fixes both PROMPTMSG (reverse-video prompt) and the per-DB prompt suffix.
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.

1 participant