Allow deciding if a command should be saved to history (#10302)

Call fish_should_add_to_history to see if a command should be saved

If it returns 0, it will be saved, if it returns anything else, it
will be ephemeral.

It gets the right-trimmed text as the argument.

If it doesn't exist, we do the historical behavior of checking for a
leading space.

That means you can now turn that off by defining a
`fish_should_add_to_history` that just doesn't check it.

documentation based on #9298
This commit is contained in:
Fabian Boehm 2024-03-09 12:04:16 +01:00 committed by GitHub
parent d91ad2976c
commit f7cc1743c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 102 additions and 3 deletions

View File

@ -0,0 +1,57 @@
.. _cmd-fish_should_add_to_history:
fish_should_add_to_history - decide whether a command should be added to the history
=================================================================================
Synopsis
--------
.. synopsis::
fish_should_add_to_history
::
function fish_should_add_to_history
...
end
Description
-----------
The ``fish_should_add_to_history`` function is executed before fish adds a command to history, and its return status decides whether that is done.
If it returns 0, the command is stored in history, when it returns anything else, it is not. In the latter case the command can still be recalled for one command.
The first argument to ``fish_should_add_to_history`` is the commandline. History is added *before* a command is run, so e.g. :envvar:`status` can't be checked. This is so commands that don't finish like :doc:`exec` and long-running commands are available in new sessions immediately.
If ``fish_should_add_to_history`` doesn't exist, fish will save a command to history unless it starts with a space. If it does exist, this function takes over all of the duties, so commands starting with space are saved unless ``fish_should_add_to_history`` says otherwise.
Example
-------
A simple example:
::
function fish_should_add_to_history
for cmd in vault mysql ls
string match -qr "^$cmd" -- $argv; and return 1
end
return 0
end
This refuses to store any immediate "vault", "mysql" or "ls" calls. Commands starting with space would be stored.
::
function fish_should_add_to_history
# I don't want `git pull`s in my history when I'm in a specific repository
if string match -qr '^git pull'
and string match -qr "^/home/me/my-secret-project/" -- (pwd -P)
return 1
end
return 0
end

View File

@ -4674,6 +4674,25 @@ impl ReaderData {
}
}
fn should_add_to_history(&mut self, text: &wstr) -> bool {
let parser = self.parser();
if !function::exists(L!("fish_should_add_to_history"), parser) {
// Historical behavior, if the command starts with a space we don't save it.
return text.as_char_slice()[0] != ' ';
}
let mut cmd: WString = L!("fish_should_add_to_history ").into();
cmd.push_utfstr(&escape(text));
let _not_interactive = scoped_push_replacer(
|new_value| std::mem::replace(&mut parser.libdata_mut().pods.is_interactive, new_value),
false,
);
let ret = exec_subshell(&cmd, parser, None, /*apply_exit_status=*/ false);
ret == STATUS_CMD_OK.unwrap()
}
// Add the current command line contents to history.
fn add_to_history(&mut self) {
if self.conf.in_silent_mode {
@ -4692,9 +4711,8 @@ impl ReaderData {
self.history.remove_ephemeral_items();
if !text.is_empty() {
// Mark this item as ephemeral if there is a leading space (#615).
let mode = if text.as_char_slice()[0] == ' ' {
// Leading spaces are ephemeral (#615).
// Mark this item as ephemeral if should_add_to_history says no (#615).
let mode = if !self.should_add_to_history(&text) {
PersistenceMode::Ephemeral
} else if in_private_mode(self.vars()) {
PersistenceMode::Memory

View File

@ -178,3 +178,27 @@ sendline("history clear-session")
expect_prompt()
sendline("history search --exact 'echo after' | cat")
expect_prompt("\r\n")
# 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("a\r\necho 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")