Revert "On undo after execute, restore the cursor position"

This reverts commit 815bc054e7.

This is too ambitious for a patch release, given that it affects how every
typed-in command runs.
This commit is contained in:
Peter Ammon
2025-03-05 15:54:20 -08:00
parent 4a35c48ce5
commit c9f1979b05
9 changed files with 57 additions and 70 deletions

View File

@@ -129,10 +129,6 @@ class Message(object):
"""Return a output message with the given text."""
return Message(Message.DIR_OUTPUT, text, when)
# Sequences for moving the cursor below the commandline. This happens before executing.
MOVE_TO_END: str = r"(?:\r\n|\x1b\[2 q)"
TO_END: str = MOVE_TO_END + r"[^\n]*"
TO_END_SUFFIX: str = r"[^\n]*" + MOVE_TO_END
class SpawnedProc(object):
"""A process, talking to our ptty. This wraps pexpect.spawn.

View File

@@ -1988,9 +1988,7 @@ fn readline(&mut self, nchars: Option<NonZeroUsize>) -> Option<WString> {
// Redraw the command line. This is what ensures the autosuggestion is hidden, etc. after the
// user presses enter.
if zelf.is_repaint_needed(None)
|| zelf.screen.scrolled()
|| zelf.conf.inputfd != STDIN_FILENO
if zelf.is_repaint_needed(None) || zelf.screen.scrolled || zelf.conf.inputfd != STDIN_FILENO
{
zelf.layout_and_repaint_before_execution();
}
@@ -2000,8 +1998,11 @@ fn readline(&mut self, nchars: Option<NonZeroUsize>) -> Option<WString> {
zelf.finish_highlighting_before_exec();
}
// Move the cursor so that output is on the line after the command.
zelf.screen.move_to_end();
// Emit a newline so that the output is on the line after the command.
// But do not emit a newline if the cursor has wrapped onto a new line all its own - see #6826.
if !zelf.screen.cursor_is_wrapped_to_own_line() {
let _ = write_to_fd(b"\n", STDOUT_FILENO);
}
// HACK: If stdin isn't the same terminal as stdout, we just moved the cursor.
// For now, just reset it to the beginning of the line.
@@ -3643,6 +3644,7 @@ fn handle_execute(&mut self) -> bool {
self.add_to_history();
self.rls_mut().finished = true;
self.update_buff_pos(elt, Some(self.command_line_len()));
true
}

View File

@@ -177,9 +177,8 @@ pub fn is_empty(&self) -> bool {
pub struct Screen {
/// Whether the last-drawn autosuggestion (if any) is truncated, or hidden entirely.
pub autosuggestion_is_truncated: bool,
/// If the last rendering was so large we could only display part of the command line,
/// this is the number of lines that were pushed to scrollback.
pub scroll_amount: usize,
/// True if the last rendering was so large we could only display part of the command line.
pub scrolled: bool,
/// Receiver for our output.
outp: &'static RefCell<Outputter>,
@@ -216,7 +215,7 @@ pub fn new() -> Self {
Self {
outp: Outputter::stdoutput(),
autosuggestion_is_truncated: Default::default(),
scroll_amount: Default::default(),
scrolled: Default::default(),
desired: Default::default(),
actual: Default::default(),
actual_left_prompt: Default::default(),
@@ -230,10 +229,6 @@ pub fn new() -> Self {
}
}
pub fn scrolled(&self) -> bool {
self.scroll_amount != 0
}
/// This is the main function for the screen output library. It is used to define the desired
/// contents of the screen. The screen command will use its knowledge of the current contents of
/// the screen in order to render the desired output using as few terminal commands as possible.
@@ -438,7 +433,7 @@ struct ScrolledCursor {
// Append pager_data (none if empty).
self.desired.append_lines(&page_rendering.screen_data);
self.scroll_amount = scrolled_cursor.scroll_amount;
self.scrolled = scrolled_cursor.scroll_amount != 0;
self.update(
vars,
@@ -478,10 +473,6 @@ pub fn reset_line(&mut self, repaint_prompt: bool /* = false */) {
self.save_status();
}
pub fn move_to_end(&mut self) {
self.r#move(0, self.actual.line_count() - self.scroll_amount);
}
/// Resets the screen buffer's internal knowledge about the contents of the screen,
/// abandoning the current line and going to the next line.
/// If clear_to_eos is set,
@@ -930,15 +921,14 @@ fn update(
let term = term.as_ref();
// Output the left prompt if it has changed.
if zelf.scrolled() && !is_final_rendering {
if zelf.scrolled && !is_final_rendering {
zelf.r#move(0, 0);
zelf.outp
.borrow_mut()
.tputs_if_some(&term.and_then(|term| term.clr_eol.as_ref()));
zelf.actual_left_prompt.clear();
zelf.actual.cursor.x = 0;
} else if left_prompt != zelf.actual_left_prompt || (zelf.scrolled() && is_final_rendering)
{
} else if left_prompt != zelf.actual_left_prompt || (zelf.scrolled && is_final_rendering) {
zelf.r#move(0, 0);
let mut start = 0;
let osc_133_prompt_start =
@@ -988,7 +978,7 @@ fn s_line(zelf: &Screen, i: usize) -> &Line {
// Note that skip_remaining is a width, not a character count.
let mut skip_remaining = start_pos;
let shared_prefix = if zelf.scrolled() {
let shared_prefix = if zelf.scrolled {
0
} else {
line_shared_prefix(o_line(&zelf, i), s_line(&zelf, i))

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
from pexpect_helper import SpawnedProc, TO_END
from pexpect_helper import SpawnedProc
import os
import platform
import sys
@@ -42,7 +42,7 @@ expect_prompt("")
# Start by testing with no delay. This should transpose the words.
send("echo abc def")
send("\033t\r")
expect_prompt(TO_END + "def abc\r\n") # emacs transpose words, default timeout: no delay
expect_prompt("\r\n.*def abc\r\n") # emacs transpose words, default timeout: no delay
# Now test with a delay > 0 and < the escape timeout. This should transpose
# the words.
@@ -51,7 +51,7 @@ send("\033")
sleep(0.010)
send("t\r")
# emacs transpose words, default timeout: short delay
expect_prompt(TO_END + "jkl ghi\r\n")
expect_prompt("\r\n.*jkl ghi\r\n")
# Now test with a delay > the escape timeout. The transposition should not
# occur and the "t" should become part of the text that is echoed.
@@ -60,11 +60,11 @@ send("\033")
sleep(0.250)
send("t\r")
# emacs transpose words, default timeout: long delay
expect_prompt(TO_END + "mno pqrt\r\n")
expect_prompt("\r\n.*mno pqrt\r\n")
# Now test that exactly the expected bind modes are defined
sendline("bind --list-modes")
expect_prompt(TO_END + "default", unmatched="Unexpected bind modes")
expect_prompt("\r\n.*default", unmatched="Unexpected bind modes")
# Test vi key bindings.
# This should leave vi mode in the insert state.
@@ -74,7 +74,7 @@ expect_prompt()
# Go through a prompt cycle to let fish catch up, it may be slow due to ASAN
sendline("echo success: default escape timeout")
expect_prompt(
TO_END + "success: default escape timeout", unmatched="prime vi mode, default timeout"
"\r\n.*success: default escape timeout", unmatched="prime vi mode, default timeout"
)
send("echo fail: default escape timeout")
@@ -88,7 +88,7 @@ sleep(0.250)
send("ddi")
sendline("echo success: default escape timeout")
expect_prompt(
TO_END + "success: default escape timeout\r\n",
"\r\n.*success: default escape timeout\r\n",
unmatched="vi replace line, default timeout: long delay",
)
@@ -103,7 +103,7 @@ send("\033")
sleep(0.400)
send("hhrAi\r")
expect_prompt(
TO_END + "TAXT\r\n", unmatched="vi mode replace char, default timeout: long delay"
"\r\n.*TAXT\r\n", unmatched="vi mode replace char, default timeout: long delay"
)
# Test deleting characters with 'x'.
@@ -115,7 +115,7 @@ send("xxxxx\r")
# vi mode delete char, default timeout: long delay
expect_prompt(
TO_END + "MORE\r\n", unmatched="vi mode delete char, default timeout: long delay"
"\r\n.*MORE\r\n", unmatched="vi mode delete char, default timeout: long delay"
)
# Test jumping forward til before a character with t
@@ -127,7 +127,7 @@ send("0tTD\r")
# vi mode forward-jump-till character, default timeout: long delay
expect_prompt(
TO_END + "MORE\r\n",
"\r\n.*MORE\r\n",
unmatched="vi mode forward-jump-till character, default timeout: long delay",
)
@@ -140,7 +140,7 @@ expect_prompt(
# send("TSD\r")
# # vi mode backward-jump-till character, default timeout: long delay
# expect_prompt(
# TO_END + "MORE-TEXT-IS\r\n",
# "\r\n.*MORE-TEXT-IS\r\n",
# unmatched="vi mode backward-jump-till character, default timeout: long delay",
# )
@@ -152,7 +152,7 @@ sleep(0.250)
send("F-;D\r")
# vi mode backward-jump-to character and repeat, default timeout: long delay
expect_prompt(
TO_END + "MORE-TEXT\r\n",
"\r\n.*MORE-TEXT\r\n",
unmatched="vi mode backward-jump-to character and repeat, default timeout: long delay",
)
@@ -164,7 +164,7 @@ sleep(0.250)
send("F-F-,D\r")
# vi mode backward-jump-to character, and reverse, default timeout: long delay
expect_prompt(
TO_END + "MORE-TEXT-IS\r\n",
"\r\n.*MORE-TEXT-IS\r\n",
unmatched="vi mode backward-jump-to character, and reverse, default timeout: long delay",
)
@@ -179,7 +179,7 @@ send("ddi")
sleep(0.25)
send("echo success: lengthened escape timeout\r")
expect_prompt(
TO_END + "success: lengthened escape timeout\r\n",
"\r\n.*success: lengthened escape timeout\r\n",
unmatched="vi replace line, 100ms timeout: long delay",
)
@@ -191,7 +191,7 @@ sleep(0.010)
send("ddi")
send("inserted\r")
expect_prompt(
TO_END + "fail: no normal modediinserted\r\n",
"\r\n.*fail: no normal modediinserted\r\n",
unmatched="vi replace line, 100ms timeout: short delay",
)
@@ -208,7 +208,7 @@ expect_str("echo TEXT")
send("\033")
sleep(0.200)
send("hhtTrN\r")
expect_prompt(TO_END + "TENT\r\n", unmatched="Couldn't find expected output 'TENT'")
expect_prompt("\r\n.*TENT\r\n", unmatched="Couldn't find expected output 'TENT'")
# Test sequence key delay
send("set -g fish_sequence_key_delay_ms 200\r")
@@ -239,7 +239,7 @@ expect_prompt("foo")
# send("echo some TExT\033")
# sleep(0.300)
# send("hh~~bbve~\r")
# expect_prompt(TO_END + "SOME TeXT\r\n", unmatched="Couldn't find expected output 'SOME TeXT")
# expect_prompt("\r\n.*SOME TeXT\r\n", unmatched="Couldn't find expected output 'SOME TeXT")
send("echo echo")
send("\033")
@@ -261,7 +261,7 @@ expect_prompt()
# Verify the custom escape timeout set earlier is still in effect.
sendline("echo fish_escape_delay_ms=$fish_escape_delay_ms")
expect_prompt(
TO_END + "fish_escape_delay_ms=50\r\n",
"\r\n.*fish_escape_delay_ms=50\r\n",
unmatched="default-mode custom timeout not set correctly",
)
@@ -276,7 +276,7 @@ send("echo abc def")
send("\033")
send("t\r")
expect_prompt(
TO_END + "def abc\r\n", unmatched="emacs transpose words fail, 200ms timeout: no delay"
"\r\n.*def abc\r\n", unmatched="emacs transpose words fail, 200ms timeout: no delay"
)
# Verify special characters, such as \cV, are not intercepted by the kernel
@@ -307,7 +307,7 @@ expect_prompt()
send("foo ")
expect_str("echo foonanana")
send(" banana\r")
expect_str(" banana")
expect_str(" banana\r")
expect_prompt("foonanana banana")
# Ensure that nul can be bound properly (#3189).
@@ -335,7 +335,7 @@ expect_prompt()
send("a b c d\x01") # ctrl-a, move back to the beginning of the line
send("\x07") # ctrl-g, kill bigword
sendline("echo")
expect_prompt(TO_END + "b c d")
expect_prompt("\n.*b c d")
# Test that overriding the escape binding works
# and does not inhibit other escape sequences (up-arrow in this case).
@@ -351,7 +351,7 @@ expect_prompt()
send(" a b c d\x01") # ctrl-a, move back to the beginning of the line
send("\x07") # ctrl-g, kill bigword
sendline("echo")
expect_prompt(TO_END + "b c d")
expect_prompt("\n.*b c d")
# Check that ctrl-z can be bound
sendline('bind ctrl-z "echo bound ctrl-z"')

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
from pexpect_helper import SpawnedProc, TO_END
from pexpect_helper import SpawnedProc
import os
import sys
import signal
@@ -16,7 +16,7 @@ send("set -g fish_key_bindings fish_vi_key_bindings\r")
expect_prompt()
send("echo ready to go\r")
expect_prompt(TO_END + f"ready to go\r\n")
expect_prompt(f"\r\n.*ready to go\r\n")
send(
"function add_change --on-variable fish_bind_mode ; set -g MODE_CHANGES $MODE_CHANGES $fish_bind_mode ; end\r"
)
@@ -42,7 +42,7 @@ send("i")
sleep(10 if "CI" in os.environ else 1)
send("echo mode changes: $MODE_CHANGES\r")
expect_prompt(TO_END + "mode changes: default insert default insert\r\n")
expect_prompt("\r\n.*mode changes: default insert default insert\r\n")
# Regression test for #8125.
# Control-C should return us to insert mode.
@@ -70,4 +70,4 @@ sleep(timeout)
# We should be back in insert mode now.
send("echo mode changes: $MODE_CHANGES\r")
expect_prompt(TO_END + "mode changes: default insert\r\n")
expect_prompt("\r\n.*mode changes: default insert\r\n")

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
from pexpect_helper import SpawnedProc, TO_END
from pexpect_helper import SpawnedProc
sp = SpawnedProc()
send, sendline, sleep, expect_prompt, expect_re, expect_str = (
@@ -75,6 +75,6 @@ send("echo fo\t")
expect_re("foooo")
send("\x07")
sendline("echo bar")
expect_re(TO_END + "bar")
expect_re("\n.*bar")
sendline("echo fo\t")
expect_re("foooo")

View File

@@ -11,7 +11,7 @@
# The history function might pipe output through the user's pager. We don't
# want something like `less` to complicate matters so force the use of `cat`.
from pexpect_helper import SpawnedProc, TO_END, TO_END_SUFFIX
from pexpect_helper import SpawnedProc
import os
os.environ["PAGER"] = "cat"
@@ -98,7 +98,7 @@ expect_prompt("echo start1; builtin history; echo end1\r\n")
# ==========
# Delete a single command we recently ran.
sendline("history delete -e -C 'echo hello'")
expect_prompt("history delete -e -C 'echo hello'" + TO_END_SUFFIX)
expect_prompt("history delete -e -C 'echo hello'\r\n")
sendline("echo count hello (history search -e -C 'echo hello' | wc -l | string trim)")
expect_prompt("count hello 0\r\n")
@@ -107,13 +107,12 @@ expect_prompt("count hello 0\r\n")
# delete the first entry matched by the prefix search (the most recent command
# sent above that matches).
sendline("history delete -p 'echo hello'")
expect_re("history delete -p 'echo hello'" + TO_END_SUFFIX)
expect_re("\[1\] echo hello AGAIN" + TO_END_SUFFIX)
expect_re("\[2\] echo hello again" + TO_END_SUFFIX)
expect_re("Enter nothing to cancel the delete, or\r\n")
expect_re("Enter one or more of the entry IDs or ranges like '5..12', separated by a space.\r\n")
expect_re("For example '7 10..15 35 788..812'.\r\n")
expect_re("Enter 'all' to delete all the matching entries.\r\n")
expect_re("history delete -p 'echo hello'\r\n")
expect_re("\[1\] echo hello AGAIN\r\n")
expect_re("\[2\] echo hello again\r\n\r\n")
expect_re(
"Enter nothing to cancel the delete, or\r\nEnter one or more of the entry IDs or ranges like '5..12', separated by a space.\r\nFor example '7 10..15 35 788..812'.\r\nEnter 'all' to delete all the matching entries.\r\n"
)
expect_re("Delete which entries\? ")
sendline("1")
expect_prompt('Deleting history entry 1: "echo hello AGAIN"\r\n')
@@ -178,7 +177,7 @@ expect_prompt()
sendline("history clear-session")
expect_prompt()
sendline("history search --exact 'echo after' | cat")
expect_prompt()
expect_prompt("\r\n")
# Check history filtering
# We store anything that starts with "echo ephemeral".

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
from pexpect_helper import SpawnedProc, TO_END
from pexpect_helper import SpawnedProc
sp = SpawnedProc()
send, sendline, sleep, expect_prompt, expect_re, expect_str = (
@@ -17,7 +17,7 @@ def expect_read_prompt():
def expect_marker(text):
expect_prompt(TO_END + "@MARKER:" + str(text) + "@\\r\\n")
expect_prompt("\r\n.*@MARKER:" + str(text) + "@\\r\\n")
def print_var_contents(varname, expected):

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
from pexpect_helper import SpawnedProc, TO_END
from pexpect_helper import SpawnedProc
sp = SpawnedProc()
send, sendline, sleep, expect_prompt, expect_re, expect_str = (
@@ -22,11 +22,11 @@ expect_prompt("")
# Validate standalone behavior
sendline("status current-commandline")
expect_prompt(TO_END + "status current-commandline\r\n")
expect_prompt("\r\n.*status current-commandline\r\n")
# Validate behavior as part of a command chain
sendline("true 7 && status current-commandline")
expect_prompt(TO_END + "true 7 && status current-commandline\r\n")
expect_prompt("\r\n.*true 7 && status current-commandline\r\n")
# Validate behavior when used in a function
sendline("function report; set -g last_cmdline (status current-commandline); end")
@@ -34,7 +34,7 @@ expect_prompt("")
sendline("report 27")
expect_prompt("")
sendline("echo $last_cmdline")
expect_prompt(TO_END + "report 27\r\n")
expect_prompt("\r\n.*report 27\r\n")
# Exit
send("\x04") # <c-d>