fish-shell/tests/pexpects/history.py
Johannes Altmanninger 610338cc70 On undo after execute, restore the cursor position
Ever since 149594f974 (Initial revision, 2005-09-20), we move the
cursor to the end of the commandline just before executing it.

This is so we can move the cursor to the line below the command line,
so moving the cursor is relevant if one presses enter on say, the
first line of a multi-line commandline.

As mentioned in #10838 and others, it can be useful to restore the
cursor position when recalling commandline from history. Make undo
restore the position where enter was pressed, instead of implicitly
moving the cursor to the end. This allows to quickly correct small
mistakes in large commandlines that failed recently.

This requires a new way of moving the cursor below the command line.
Test changes include unrelated cleanup of history.py.
2024-12-21 13:10:34 +01:00

205 lines
6.8 KiB
Python

#!/usr/bin/env python3
# This is a very fragile test. Sorry about that. But interactively entering
# commands and verifying they are recorded correctly in the interactive
# history and that history can be manipulated is inherently difficult.
#
# This is meant to verify just a few of the most basic behaviors of the
# interactive history to hopefully keep regressions from happening. It is not
# meant to be a comprehensive test of the history subsystem. Those types of
# tests belong in the src/fish_tests.cpp module.
#
# 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
import os
os.environ["PAGER"] = "cat"
sp = SpawnedProc(env=os.environ.copy())
send, sendline, sleep, expect_prompt, expect_re, expect_str = (
sp.send,
sp.sendline,
sp.sleep,
sp.expect_prompt,
sp.expect_re,
sp.expect_str,
)
expect_prompt()
# ==========
# Start by ensuring we're not affected by earlier tests. Clear the history.
sendline("builtin history clear")
expect_prompt()
# ==========
# The following tests verify the behavior of the history builtin.
# ==========
# ==========
# List our history which should be empty after just clearing it.
sendline("echo start1; builtin history; echo end1")
expect_prompt("start1\r\nend1\r\n")
# Our history should now contain the previous command and nothing else.
sendline("echo start2; builtin history; echo end2")
expect_prompt("start2\r\necho start1; builtin history; echo end1\r\nend2\r\n")
# ==========
# The following tests verify the behavior of the history function.
# ==========
# ==========
# Verify explicit searching for the first two commands in the previous tests
# returns the expected results.
sendline("history search --reverse 'echo start' | cat")
expect_prompt("echo start1;.*\r\necho start2;")
# ==========
# Verify searching is the implicit action.
sendline("history -p 'echo start'")
expect_prompt("echo start2.*\r\necho start1")
# ==========
# Verify searching with a request for timestamps includes the timestamps.
sendline("history search --show-time='# %F %T%n' --prefix 'echo start'")
expect_prompt(
"# \\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d\r\necho start2; .*\r\n# \\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d\r\necho start1;"
)
# ==========
# Verify explicit searching for an exact command returns just that command.
# returns the expected results.
sendline("echo hello")
expect_prompt()
sendline("echo goodbye")
expect_prompt()
sendline("echo hello again")
expect_prompt()
sendline("echo hello AGAIN")
expect_prompt()
sendline("history search --exact 'echo goodbye' | cat")
expect_prompt("echo goodbye\r\n")
sendline("history search --exact 'echo hello' | cat")
expect_prompt("echo hello\r\n")
# This is slightly subtle in that it shouldn't actually match anything between
# the command we sent and the next prompt.
sendline("history search --exact 'echo hell' | cat")
expect_prompt("history search --exact 'echo hell' | cat\r\n")
# Verify that glob searching works.
sendline("history search --prefix 'echo start*echo end' | cat")
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)
sendline("echo count hello (history search -e -C 'echo hello' | wc -l | string trim)")
expect_prompt("count hello 0\r\n")
# ==========
# Interactively delete one of multiple matched commands. This verifies that we
# 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("Delete which entries\? ")
sendline("1")
expect_prompt('Deleting history entry 1: "echo hello AGAIN"\r\n')
# Verify that the deleted history entry is gone and the other one that matched
# the prefix search above is still there.
sendline(
"echo count AGAIN (history search -e -C 'echo hello AGAIN' | wc -l | string trim)"
)
expect_prompt("count AGAIN 0\r\n")
sendline(
"echo count again (history search -e -C 'echo hello again' | wc -l | string trim)"
)
expect_prompt("count again 1\r\n")
# Verify that the $history var has the expected content.
sendline("echo history2=$history\[2\]")
expect_prompt("history2=echo count AGAIN .*\r\n")
# Verify that history search is case-insensitive by default
sendline("echo term")
expect_prompt("term")
sendline("echo TERM")
expect_prompt("TERM")
sendline("echo banana")
expect_prompt("banana")
send("ter\x1b[A") # up-arrow
expect_re("echo TERM")
sendline("")
expect_prompt("TERM")
# Check that leading space makes an ephemeral item
sendline(" echo ephemeral")
expect_prompt("ephemeral")
send("\x1b[A") # up-arrow
expect_re(" echo ephemeral")
sendline("")
expect_prompt("ephemeral")
sendline(" ")
expect_prompt()
send("\x1b[A")
expect_re("echo TERM") # not ephemeral!
# Verify that clear-session works as expected
# Note: This test depends on that history merge resets the session from history clear-sessions point of view.
sendline("builtin history clear")
expect_prompt()
# create before history
sendline("echo before1")
expect_prompt()
sendline("echo before2")
expect_prompt()
# "reset" session with history merge
sendline("history merge")
expect_prompt()
# create after history
sendline("echo after")
expect_prompt()
# clear session
sendline("history clear-session")
expect_prompt()
sendline("history search --exact 'echo after' | cat")
expect_prompt()
# Check history filtering
# We store anything that starts with "echo ephemeral".
sendline("function fish_should_add_to_history; string match -q 'echo ephemeral*' -- $argv; and return 2; return 0; end")
expect_prompt("")
# Check that matching the line works
# (fish_should_add_to_history is itself stored in history so we match "ephemeral!" to avoid it)
sendline("echo ephemeral! line")
expect_prompt("ephemeral! line")
sendline("echo nonephemeral! line")
expect_prompt("nonephemeral! line")
sendline("true")
expect_prompt()
sendline("echo a; history search '*ephemeral!*' | cat; echo b")
expect_prompt(r"a\r\n.*echo nonephemeral! line\r\nb\r\n")
# If fish_should_add_to_history exists, it will completely take over,
# so even lines with spaces are stored
sendline(" echo spaced")
expect_prompt("spaced")
sendline("true")
expect_prompt()
sendline("echo a; history search '*spaced*' | cat; echo b")
expect_prompt("a\r\n.* echo spaced\r\nb\r\n")