Skip to content

Commit f7cc174

Browse files
authored
Allow deciding if a command should be saved to history (fish-shell#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 fish-shell#9298
1 parent d91ad29 commit f7cc174

File tree

3 files changed

+102
-3
lines changed

3 files changed

+102
-3
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
.. _cmd-fish_should_add_to_history:
2+
3+
fish_should_add_to_history - decide whether a command should be added to the history
4+
=================================================================================
5+
6+
Synopsis
7+
--------
8+
9+
.. synopsis::
10+
11+
fish_should_add_to_history
12+
13+
::
14+
15+
function fish_should_add_to_history
16+
...
17+
end
18+
19+
20+
Description
21+
-----------
22+
23+
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.
24+
25+
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.
26+
27+
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.
28+
29+
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.
30+
31+
Example
32+
-------
33+
34+
A simple example:
35+
36+
::
37+
38+
function fish_should_add_to_history
39+
for cmd in vault mysql ls
40+
string match -qr "^$cmd" -- $argv; and return 1
41+
end
42+
return 0
43+
end
44+
45+
This refuses to store any immediate "vault", "mysql" or "ls" calls. Commands starting with space would be stored.
46+
47+
::
48+
49+
function fish_should_add_to_history
50+
# I don't want `git pull`s in my history when I'm in a specific repository
51+
if string match -qr '^git pull'
52+
and string match -qr "^/home/me/my-secret-project/" -- (pwd -P)
53+
return 1
54+
end
55+
56+
return 0
57+
end

src/reader.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4674,6 +4674,25 @@ impl ReaderData {
46744674
}
46754675
}
46764676

4677+
fn should_add_to_history(&mut self, text: &wstr) -> bool {
4678+
let parser = self.parser();
4679+
if !function::exists(L!("fish_should_add_to_history"), parser) {
4680+
// Historical behavior, if the command starts with a space we don't save it.
4681+
return text.as_char_slice()[0] != ' ';
4682+
}
4683+
4684+
let mut cmd: WString = L!("fish_should_add_to_history ").into();
4685+
cmd.push_utfstr(&escape(text));
4686+
let _not_interactive = scoped_push_replacer(
4687+
|new_value| std::mem::replace(&mut parser.libdata_mut().pods.is_interactive, new_value),
4688+
false,
4689+
);
4690+
4691+
let ret = exec_subshell(&cmd, parser, None, /*apply_exit_status=*/ false);
4692+
4693+
ret == STATUS_CMD_OK.unwrap()
4694+
}
4695+
46774696
// Add the current command line contents to history.
46784697
fn add_to_history(&mut self) {
46794698
if self.conf.in_silent_mode {
@@ -4692,9 +4711,8 @@ impl ReaderData {
46924711
self.history.remove_ephemeral_items();
46934712

46944713
if !text.is_empty() {
4695-
// Mark this item as ephemeral if there is a leading space (#615).
4696-
let mode = if text.as_char_slice()[0] == ' ' {
4697-
// Leading spaces are ephemeral (#615).
4714+
// Mark this item as ephemeral if should_add_to_history says no (#615).
4715+
let mode = if !self.should_add_to_history(&text) {
46984716
PersistenceMode::Ephemeral
46994717
} else if in_private_mode(self.vars()) {
47004718
PersistenceMode::Memory

tests/pexpects/history.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,27 @@
178178
expect_prompt()
179179
sendline("history search --exact 'echo after' | cat")
180180
expect_prompt("\r\n")
181+
182+
# Check history filtering
183+
# We store anything that starts with "echo ephemeral".
184+
sendline("function fish_should_add_to_history; string match -q 'echo ephemeral*' -- $argv; and return 2; return 0; end")
185+
expect_prompt("")
186+
# Check that matching the line works
187+
# (fish_should_add_to_history is itself stored in history so we match "ephemeral!" to avoid it)
188+
sendline("echo ephemeral! line")
189+
expect_prompt("ephemeral! line")
190+
sendline("echo nonephemeral! line")
191+
expect_prompt("nonephemeral! line")
192+
sendline("true")
193+
expect_prompt()
194+
sendline("echo a; history search '*ephemeral!*' | cat; echo b")
195+
expect_prompt("a\r\necho nonephemeral! line\r\nb\r\n")
196+
197+
# If fish_should_add_to_history exists, it will completely take over,
198+
# so even lines with spaces are stored
199+
sendline(" echo spaced")
200+
expect_prompt("spaced")
201+
sendline("true")
202+
expect_prompt()
203+
sendline("echo a; history search '*spaced*' | cat; echo b")
204+
expect_prompt("a\r\n echo spaced\r\nb\r\n")

0 commit comments

Comments
 (0)