Adds sub-command clear-session to history command.

Issue #5791
This clears all history for the current session. Documentation and
autocompletion for the new subcommand is added.
This commit is contained in:
Erik Serrander 2021-10-17 19:27:46 -07:00 committed by ridiculousfish
parent 87b2c2fdec
commit 049104e8df
8 changed files with 95 additions and 11 deletions

View file

@ -13,6 +13,7 @@ Synopsis
history merge history merge
history save history save
history clear history clear
history clear-session
history ( -h | --help ) history ( -h | --help )
Description Description
@ -32,6 +33,8 @@ The following operations (sub-commands) are available:
- ``clear`` clears the history file. A prompt is displayed before the history is erased asking you to confirm you really want to clear all history unless ``builtin history`` is used. - ``clear`` clears the history file. A prompt is displayed before the history is erased asking you to confirm you really want to clear all history unless ``builtin history`` is used.
- ``clear-session`` clears the history file from all activity of the current session. Note: If ``history merge`` or ``builtin history merge`` is run in a session only the history after this will be erased.
The following options are available: The following options are available:
These flags can appear before or immediately after one of the sub-commands listed above. These flags can appear before or immediately after one of the sub-commands listed above.

View file

@ -1,5 +1,5 @@
# Note that when a completion file is sourced a new block scope is created so `set -l` works. # Note that when a completion file is sourced a new block scope is created so `set -l` works.
set -l __fish_history_all_commands search delete save merge clear set -l __fish_history_all_commands search delete save merge clear clear-session
complete -c history -s h -l help -d "Display help and exit" complete -c history -s h -l help -d "Display help and exit"
@ -33,3 +33,5 @@ complete -f -c history -n "not __fish_seen_subcommand_from $__fish_history_all_c
-a merge -d "Incorporate history changes from other sessions" -a merge -d "Incorporate history changes from other sessions"
complete -f -c history -n "not __fish_seen_subcommand_from $__fish_history_all_commands" \ complete -f -c history -n "not __fish_seen_subcommand_from $__fish_history_all_commands" \
-a clear -d "Clears history file" -a clear -d "Clears history file"
complete -f -c history -n "not __fish_seen_subcommand_from $__fish_history_all_commands" \
-a clear-session -d "Clears all history from the current session"

View file

@ -62,13 +62,15 @@ function history --description "display or manipulate interactive command histor
set hist_cmd search set hist_cmd search
else if set -q _flag_merge else if set -q _flag_merge
set hist_cmd merge set hist_cmd merge
else if set -q _flag_clear-session
set hist_cmd clear-session
end end
# If a history command has not already been specified check the first non-flag argument for a # If a history command has not already been specified check the first non-flag argument for a
# command. This allows the flags to appear before or after the subcommand. # command. This allows the flags to appear before or after the subcommand.
if not set -q hist_cmd[1] if not set -q hist_cmd[1]
and set -q argv[1] and set -q argv[1]
if contains $argv[1] search delete merge save clear if contains $argv[1] search delete merge save clear clear-session
set hist_cmd $argv[1] set hist_cmd $argv[1]
set -e argv[1] set -e argv[1]
end end
@ -190,7 +192,12 @@ function history --description "display or manipulate interactive command histor
else else
printf (_ "You did not say 'yes' so I will not clear your command history\n") printf (_ "You did not say 'yes' so I will not clear your command history\n")
end end
case clear-session # clears only session
__fish_unexpected_hist_args $argv
and return 1
builtin history clear-session -- $argv
printf (_ "Command history for session cleared!\n")
case '*' case '*'
printf "%ls: unexpected subcommand '%ls'\n" $cmd $hist_cmd printf "%ls: unexpected subcommand '%ls'\n" $cmd $hist_cmd
return 2 return 2

View file

@ -21,12 +21,15 @@
#include "wgetopt.h" #include "wgetopt.h"
#include "wutil.h" // IWYU pragma: keep #include "wutil.h" // IWYU pragma: keep
enum hist_cmd_t { HIST_SEARCH = 1, HIST_DELETE, HIST_CLEAR, HIST_MERGE, HIST_SAVE, HIST_UNDEF }; enum hist_cmd_t { HIST_SEARCH = 1, HIST_DELETE, HIST_CLEAR, HIST_MERGE, HIST_SAVE, HIST_UNDEF,
HIST_CLEAR_SESSION };
// Must be sorted by string, not enum or random. // Must be sorted by string, not enum or random.
static const enum_map<hist_cmd_t> hist_enum_map[] = { static const enum_map<hist_cmd_t> hist_enum_map[] = {
{HIST_CLEAR, L"clear"}, {HIST_DELETE, L"delete"}, {HIST_MERGE, L"merge"}, {HIST_CLEAR, L"clear"}, {HIST_CLEAR_SESSION, L"clear-session"},
{HIST_SAVE, L"save"}, {HIST_SEARCH, L"search"}, {HIST_UNDEF, nullptr}}; {HIST_DELETE, L"delete"}, {HIST_MERGE, L"merge"},
{HIST_SAVE, L"save"}, {HIST_SEARCH, L"search"},
{HIST_UNDEF, nullptr}, };
struct history_cmd_opts_t { struct history_cmd_opts_t {
hist_cmd_t hist_cmd = HIST_UNDEF; hist_cmd_t hist_cmd = HIST_UNDEF;
@ -287,6 +290,15 @@ maybe_t<int> builtin_history(parser_t &parser, io_streams_t &streams, const wcha
history->save(); history->save();
break; break;
} }
case HIST_CLEAR_SESSION: {
if (check_for_unexpected_hist_args(opts, cmd, args, streams)) {
status = STATUS_INVALID_ARGS;
break;
}
history->clear_session();
history->save();
break;
}
case HIST_MERGE: { case HIST_MERGE: {
if (check_for_unexpected_hist_args(opts, cmd, args, streams)) { if (check_for_unexpected_hist_args(opts, cmd, args, streams)) {
status = STATUS_INVALID_ARGS; status = STATUS_INVALID_ARGS;

View file

@ -240,7 +240,9 @@ struct history_impl_t {
uint32_t disable_automatic_save_counter{0}; uint32_t disable_automatic_save_counter{0};
// Deleted item contents. // Deleted item contents.
std::unordered_set<wcstring> deleted_items{}; // Boolean describes if it should be deleted only in this session or in all
// (used in deduplication).
std::unordered_map<wcstring, bool> deleted_items{};
// The buffer containing the history file contents. // The buffer containing the history file contents.
std::unique_ptr<history_file_contents_t> file_contents{}; std::unique_ptr<history_file_contents_t> file_contents{};
@ -332,6 +334,9 @@ struct history_impl_t {
// Irreversibly clears history. // Irreversibly clears history.
void clear(); void clear();
// Clears only session.
void clear_session();
// Populates from older location ()in config path, rather than data path). // Populates from older location ()in config path, rather than data path).
void populate_from_config_path(); void populate_from_config_path();
@ -453,7 +458,7 @@ void history_impl_t::save_unless_disabled() {
// case-sensitive, matches. // case-sensitive, matches.
void history_impl_t::remove(const wcstring &str_to_remove) { void history_impl_t::remove(const wcstring &str_to_remove) {
// Add to our list of deleted items. // Add to our list of deleted items.
deleted_items.insert(str_to_remove); deleted_items.insert(std::pair<wcstring, bool>(str_to_remove, false));
size_t idx = new_items.size(); size_t idx = new_items.size();
while (idx--) { while (idx--) {
@ -721,13 +726,24 @@ bool history_impl_t::rewrite_to_temporary_file(int existing_fd, int dst_fd) cons
// Try decoding an old item. // Try decoding an old item.
history_item_t old_item = local_file->decode_item(*offset); history_item_t old_item = local_file->decode_item(*offset);
// If old item is newer than session always erase if in deleted.
if (old_item.timestamp() > boundary_timestamp) {
if (old_item.empty() || deleted_items.count(old_item.str()) > 0) { if (old_item.empty() || deleted_items.count(old_item.str()) > 0) {
continue; continue;
} }
lru.add_item(std::move(old_item));
} else {
// If old item is older and in deleted items don't erase if added by
// clear_session.
if (old_item.empty() || (deleted_items.count(old_item.str()) > 0 &&
!deleted_items.at(old_item.str()))) {
continue;
}
// Add this old item. // Add this old item.
lru.add_item(std::move(old_item)); lru.add_item(std::move(old_item));
} }
} }
}
// Insert any unwritten new items // Insert any unwritten new items
for (auto iter = new_items.cbegin() + this->first_unwritten_new_item_index; for (auto iter = new_items.cbegin() + this->first_unwritten_new_item_index;
@ -1073,6 +1089,15 @@ void history_impl_t::clear() {
this->clear_file_state(); this->clear_file_state();
} }
void history_impl_t::clear_session() {
for (const auto &item : new_items) {
deleted_items.insert(std::pair<wcstring,bool>(item.str(), true));
}
new_items.clear();
first_unwritten_new_item_index = 0;
}
bool history_impl_t::is_default() const { return name == DFLT_FISH_HISTORY_SESSION_ID; } bool history_impl_t::is_default() const { return name == DFLT_FISH_HISTORY_SESSION_ID; }
bool history_impl_t::is_empty() { bool history_impl_t::is_empty() {
@ -1491,6 +1516,8 @@ bool history_t::search(history_search_type_t search_type, const wcstring_list_t
void history_t::clear() { impl()->clear(); } void history_t::clear() { impl()->clear(); }
void history_t::clear_session() { impl()->clear_session(); }
void history_t::populate_from_config_path() { impl()->populate_from_config_path(); } void history_t::populate_from_config_path() { impl()->populate_from_config_path(); }
void history_t::populate_from_bash(FILE *f) { impl()->populate_from_bash(f); } void history_t::populate_from_bash(FILE *f) { impl()->populate_from_bash(f); }

View file

@ -193,6 +193,9 @@ class history_t : noncopyable_t, nonmovable_t {
// Irreversibly clears history. // Irreversibly clears history.
void clear(); void clear();
// Irreversibly clears history for the current session.
void clear_session();
// Populates from older location (in config path, rather than data path). // Populates from older location (in config path, rather than data path).
void populate_from_config_path(); void populate_from_config_path();

View file

@ -30,12 +30,16 @@ builtin history --clear abc def
# First with the history function. # First with the history function.
history clear --contains history clear --contains
#CHECKERR: history: you cannot use any options with the clear command #CHECKERR: history: you cannot use any options with the clear command
history clear-session --contains
#CHECKERR: history: you cannot use any options with the clear-session command
history merge -t history merge -t
#CHECKERR: history: you cannot use any options with the merge command #CHECKERR: history: you cannot use any options with the merge command
history save xyz history save xyz
#CHECKERR: history: save expected 0 args, got 1 #CHECKERR: history: save expected 0 args, got 1
history --prefix clear history --prefix clear
#CHECKERR: history: you cannot use any options with the clear command #CHECKERR: history: you cannot use any options with the clear command
history --prefix clear-session
#CHECKERR: history: you cannot use any options with the clear-session command
history --show-time merge history --show-time merge
#CHECKERR: history: you cannot use any options with the merge command #CHECKERR: history: you cannot use any options with the merge command
@ -47,10 +51,14 @@ builtin history save --prefix
#CHECKERR: history: you cannot use any options with the save command #CHECKERR: history: you cannot use any options with the save command
builtin history clear --show-time builtin history clear --show-time
#CHECKERR: history: you cannot use any options with the clear command #CHECKERR: history: you cannot use any options with the clear command
builtin history clear-session --show-time
#CHECKERR: history: you cannot use any options with the clear-session command
builtin history merge xyz builtin history merge xyz
#CHECKERR: history merge: Expected 0 args, got 1 #CHECKERR: history merge: Expected 0 args, got 1
builtin history clear abc def builtin history clear abc def
#CHECKERR: history clear: Expected 0 args, got 2 #CHECKERR: history clear: Expected 0 args, got 2
builtin history clear-session abc def
#CHECKERR: history clear-session: Expected 0 args, got 2
builtin history --contains save builtin history --contains save
#CHECKERR: history: you cannot use any options with the save command #CHECKERR: history: you cannot use any options with the save command
builtin history -t merge builtin history -t merge

View file

@ -156,3 +156,25 @@ sendline(" ")
expect_prompt() expect_prompt()
send("\x1b[A") send("\x1b[A")
expect_re("echo TERM") # not ephemeral! 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("\r\n")