mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-10 15:14:44 +00:00
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:
parent
87b2c2fdec
commit
049104e8df
8 changed files with 95 additions and 11 deletions
|
@ -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.
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in a new issue