prompt-toolkit / prompt-toolkit/python-prompt-toolkit
vi mode: `d` deletes something other than the selected characters (block select)
Open
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 10.6k
- Forks
- 815
- PR merge metrics
- No merged PRs in 30d
Description
Hi, thanks for this library, it's handy.
I have written three tests to demonstrate this bug
test_vi_delblockpasses. This test runsvito check my assumption thatdshould indeed delete a block selection.test_example_delblockfails. This is the problematic behavior. If you select the first character of all three lines and pressd, you should still have the remaining characters on all three lines. Instead you lose every character on the first two lines, and the last line remains untouchedtest_example_cutblockpasses. This shows prompt toolkit doing the right thing and deleting only the first character on each line. However, it should do this for bothxandd, not just forx
import pexpect
import pyte, os
from textwrap import dedent
ROWS, COLS = 15, 40
screen = pyte.Screen(COLS, ROWS)
stream = pyte.Stream(screen)
def spawn_process(cmd):
env = os.environ.copy()
env.update({'LINES': str(ROWS), 'COLUMNS': str(COLS)})
return pexpect.spawn(cmd, echo=False, encoding='utf-8', dimensions=(ROWS, COLS), env=env)
def emulate_ansi_terminal(raw_output):
stream.feed(raw_output)
lines = screen.display
screen.reset()
return '\n'.join(lines)
def test_vi_delblock():
"you can use 'd' to delete a block selection in vi"
p = spawn_process('vi')
p.send("iabc\ndef\nghi") # some text to edit
p.sendcontrol("[") # press esc
p.send("0") # beginning of line
p.sendcontrol("v") # block select
p.send("kkd") # this and two lines above, then delete
p.expect(pexpect.TIMEOUT, timeout=2)
output = emulate_ansi_terminal(p.before)
print(output)
assert '\n'.join(output.split()[0:3]) == dedent(
"""
bc
ef
hi
"""
).strip()
def test_example_delblock():
"but prompt toolkit ignores the block select when 'd' is pressed"
p = spawn_process('sh -c "python $HOME/src/python-prompt-toolkit/examples/prompts/switch-between-vi-emacs.py"')
p.send("abc\ndef\nghi") # type something
p.send(chr(27) + chr(79) + chr(83)) # switch to vi mode (F4, accoring to https://stackoverflow.com/a/73355658/1054322)
p.sendcontrol("[") # press esc
p.send("0") # beginning of line
p.sendcontrol("v") # block select
p.send("kkd") # this and two lines above, then delete
p.expect(pexpect.TIMEOUT, timeout=2)
output = emulate_ansi_terminal(p.before)
print(output)
# lines 1 & 2 say: WARNING: your terminal doesn't support cursor position requests (CPR)
assert '\n'.join(map(lambda x: x.strip(), output.split("\n")[2:5])) == dedent(
"""
> bc
ef
hi
"""
).strip()
# fails, instead output has:
#
#
# ghi
# which is *almost* what would have happened if this had been `v` instead of `ctrl + v`
def test_example_cutblock():
"you do, however, get the desired behavior for 'd' if you use 'x' instead"
p = spawn_process('sh -c "python $HOME/src/python-prompt-toolkit/examples/prompts/switch-between-vi-emacs.py"')
p.send("abc\ndef\nghi") # type something
p.send(chr(27) + chr(79) + chr(83)) # switch to vi mode (F4, accoring to https://stackoverflow.com/a/73355658/1054322)
p.sendcontrol("[") # press esc
p.send("0") # beginning of line
p.sendcontrol("v") # block select
p.send("kkx") # this and two lines above, then cut
p.expect(pexpect.TIMEOUT, timeout=2)
output = emulate_ansi_terminal(p.before)
print(output)
assert '\n'.join(map(lambda x: x.strip(), output.split("\n")[2:5])) == dedent(
"""
> bc
ef
hi
"""
).strip()
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the reported test_example_delblock scenario against examples/prompts/switch-between-vi-emacs.py, then compare it with test_example_cutblock and test_vi_delblock. Trace the vi block-selection handling for d and x; done means d leaves bc, ef, and hi, matching the block behavior demonstrated by x.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100