Created
June 8, 2025 17:08
-
-
Save Zetaphor/de8f4a540dc849f935f33e8f335aa9a4 to your computer and use it in GitHub Desktop.
Fish history deleter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# function hdel | |
# | |
# Interactively search and delete entries from fish shell history. | |
# Requires 'fzf' to be installed. | |
# | |
function hdel --description "Interactively delete items from Fish history" | |
# 1. Dependency Check: Ensure fzf is installed. | |
if not command -q fzf | |
echo (set_color red)"Error: This function requires 'fzf' (fuzzy finder)."(set_color normal) | |
echo "Please install it to continue. (e.g., 'sudo apt install fzf' or 'brew install fzf')" | |
return 1 | |
end | |
# 2. Get the history file path (backwards-compatible). | |
set -l histfile | |
if command -q fish_config && fish_config path history >/dev/null 2>&1 | |
set histfile (fish_config path history) | |
else | |
set histfile "$HOME/.local/share/fish/fish_history" | |
if not test -f "$histfile"; set histfile "$HOME/.fish_history"; end | |
end | |
if not test -f "$histfile" | |
echo (set_color red)"History file could not be found."(set_color normal) | |
return 1 | |
end | |
# 3. Present the history to the user via fzf for selection. | |
# - We extract only the command text for a clean list. | |
# - The user can select multiple lines with the Tab key. | |
# - A preview window shows the timestamp for context. | |
set -l to_delete ( | |
grep '^- cmd: ' "$histfile" | | |
sed 's/^- cmd: //' | | |
fzf --multi --height=80% --reverse \ | |
--header="[ Fuzzy search history. Press TAB to mark for deletion, ENTER to confirm ]" \ | |
--preview='echo "Timestamp:"; grep -B 1 -F -- " {}" "$histfile" | head -n 1 | sed "s/ when: //"' | |
) | |
# 4. Check if the user cancelled (e.g., pressed Esc) or selected nothing. | |
if test (count $to_delete) -eq 0 | |
echo "No commands selected. Aborting." | |
return 0 | |
end | |
# 5. Confirmation Step: Show what will be deleted and ask for confirmation. | |
echo (set_color yellow)"The following (count(string trim $to_delete)) commands are marked for permanent deletion:"(set_color normal) | |
for cmd in $to_delete | |
echo " - "(set_color red)$cmd(set_color normal) | |
end | |
echo | |
read --prompt-str="Are you sure you want to proceed? (y/N) " confirm | |
if test "$confirm" != "y" -a "$confirm" != "Y" | |
echo "Aborted by user." | |
return 0 | |
end | |
# 6. Safety First: Create a backup before modifying anything. | |
set -l backup_file "$histfile.bak."(date +%F-%T) | |
cp -p "$histfile" "$backup_file" | |
echo "↪ Safety backup created at:" (set_color blue)$backup_file(set_color normal) | |
# 7. Core Deletion Logic using AWK. | |
# This is robust and correctly handles the 2-line structure of fish history. | |
set -l temp_file (mktemp) | |
# Build an awk script that knows which commands to delete. | |
# We pass the commands from our fish list into an awk associative array. | |
set -l awk_script 'BEGIN {' | |
for cmd in $to_delete | |
# Escape backslashes and double-quotes for the awk string literal | |
set -l escaped_cmd (string escape --style=c $cmd) | |
set awk_script "$awk_script to_delete[\"$escaped_cmd\"] = 1;" | |
end | |
# The main awk logic that filters the file. | |
set awk_script "$awk_script" ' | |
} | |
# For every line in the history file... | |
{ | |
# Is it a command line? | |
if (match($0, /^- cmd: (.*)/, m)) { | |
# Is the extracted command text (m[1]) in our to_delete list? | |
if (m[1] in to_delete) { | |
# Yes. So we do nothing. This effectively deletes both | |
# this line and the "when:" line we saved just before it. | |
} else { | |
# No. This is a command to keep. Print its saved "when:" | |
# line, and then print the command line itself. | |
print saved_line | |
print $0 | |
} | |
} else { | |
# It must be a "when:" line. Save it for the next iteration. | |
saved_line = $0 | |
} | |
} | |
' | |
# Execute the awk script. | |
awk "$awk_script" "$histfile" > "$temp_file" | |
# 8. Replace the original history file and reload the session. | |
mv "$temp_file" "$histfile" | |
history clear-session | |
history merge | |
echo (set_color green)"✅ Successfully deleted (count $to_delete) history entries."(set_color normal) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment