Skip to content

Commit

Permalink
function scope all variables to reduce side effects
Browse files Browse the repository at this point in the history
Without passing -f (--function), set commands in functions will clobber same-name shell variables that were already set. For example, if you do 'set commands_selected 1' and then execute _fzf_search_history, commands_selected will change value.

I chose -f over -l or a combination of the two to emulate Python's variable scopes, in which all variables declared within a function are function scoped. This makes reasoning about variables easier and more intuitive.
  • Loading branch information
PatrickF1 committed May 20, 2023
1 parent 63c8f8e commit cab67cc
Show file tree
Hide file tree
Showing 11 changed files with 37 additions and 37 deletions.
10 changes: 5 additions & 5 deletions functions/_fzf_preview_changed_file.fish
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ function _fzf_preview_changed_file --argument-names path_status --description "S
# remove quotes because they'll be interpreted literally by git diff
# no need to requote when referencing $path because fish does not perform word splitting
# https://fishshell.com/docs/current/fish_for_bash_users.html
set -l path (string unescape (string sub --start 4 $path_status))
set -f path (string unescape (string sub --start 4 $path_status))
# first letter of short format shows index, second letter shows working tree
# https://git-scm.com/docs/git-status/2.35.0#_short_format
set -l index_status (string sub --length 1 $path_status)
set -l working_tree_status (string sub --start 2 --length 1 $path_status)
set -f index_status (string sub --length 1 $path_status)
set -f working_tree_status (string sub --start 2 --length 1 $path_status)

set diff_opts --color=always
set -f diff_opts --color=always

if test $index_status = '?'
_fzf_report_diff_type Untracked
Expand All @@ -32,7 +32,7 @@ function _fzf_preview_changed_file --argument-names path_status --description "S
# https://stackoverflow.com/questions/73954214
if test $index_status = R
# diff the post-rename path with the original path, otherwise the diff will show the entire file as being added
set orig_and_new_path (string split --max 1 -- ' -> ' $path)
set -f orig_and_new_path (string split --max 1 -- ' -> ' $path)
git diff --staged $diff_opts -- $orig_and_new_path[1] $orig_and_new_path[2]
# path currently has the form of "original -> current", so we need to correct it before it's used below
set path $orig_and_new_path[2]
Expand Down
2 changes: 1 addition & 1 deletion functions/_fzf_preview_file.fish
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
function _fzf_preview_file --description "Print a preview for the given file based on its file type."
# because there's no way to guarantee that _fzf_search_directory passes the path to _fzf_preview_file
# as one argument, we collect all the arguments into one single variable and treat that as the path
set file_path $argv
set -f file_path $argv

if test -L "$file_path" # symlink
# notify user and recurse on the target of the symlink, which can be any of these file types
Expand Down
8 changes: 4 additions & 4 deletions functions/_fzf_report_diff_type.fish
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
# ╰────────╯
function _fzf_report_diff_type --argument-names diff_type --description "Print a distinct colored header meant to preface a git patch."
# number of "-" to draw is the length of the string to box + 2 for padding
set repeat_count (math 2 + (string length $diff_type))
set line (string repeat --count $repeat_count ─)
set top_border ╭$line
set btm_border ╰$line
set -f repeat_count (math 2 + (string length $diff_type))
set -f line (string repeat --count $repeat_count ─)
set -f top_border ╭$line
set -f btm_border ╰$line

set_color yellow
echo $top_border
Expand Down
16 changes: 8 additions & 8 deletions functions/_fzf_search_directory.fish
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@ function _fzf_search_directory --description "Search the current directory. Repl
# Directly use fd binary to avoid output buffering delay caused by a fd alias, if any.
# Debian-based distros install fd as fdfind and the fd package is something else, so
# check for fdfind first. Fall back to "fd" for a clear error message.
set fd_cmd (command -v fdfind || command -v fd || echo "fd")
set --append fd_cmd --color=always $fzf_fd_opts
set -f fd_cmd (command -v fdfind || command -v fd || echo "fd")
set -f --append fd_cmd --color=always $fzf_fd_opts

# $fzf_dir_opts is the deprecated version of $fzf_directory_opts
set fzf_arguments --multi --ansi $fzf_dir_opts $fzf_directory_opts
set token (commandline --current-token)
set -f fzf_arguments --multi --ansi $fzf_dir_opts $fzf_directory_opts
set -f token (commandline --current-token)
# expand any variables or leading tilde (~) in the token
set expanded_token (eval echo -- $token)
set -f expanded_token (eval echo -- $token)
# unescape token because it's already quoted so backslashes will mess up the path
set unescaped_exp_token (string unescape -- $expanded_token)
set -f unescaped_exp_token (string unescape -- $expanded_token)

# If the current token is a directory and has a trailing slash,
# then use it as fd's base directory.
if string match --quiet -- "*/" $unescaped_exp_token && test -d "$unescaped_exp_token"
set --append fd_cmd --base-directory=$unescaped_exp_token
# use the directory name as fzf's prompt to indicate the search is limited to that directory
set --prepend fzf_arguments --prompt="Search Directory $unescaped_exp_token> " --preview="_fzf_preview_file $expanded_token{}"
set file_paths_selected $unescaped_exp_token($fd_cmd 2>/dev/null | _fzf_wrapper $fzf_arguments)
set -f file_paths_selected $unescaped_exp_token($fd_cmd 2>/dev/null | _fzf_wrapper $fzf_arguments)
else
set --prepend fzf_arguments --prompt="Search Directory> " --query="$unescaped_exp_token" --preview='_fzf_preview_file {}'
set file_paths_selected ($fd_cmd 2>/dev/null | _fzf_wrapper $fzf_arguments)
set -f file_paths_selected ($fd_cmd 2>/dev/null | _fzf_wrapper $fzf_arguments)
end


Expand Down
10 changes: 5 additions & 5 deletions functions/_fzf_search_git_log.fish
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ function _fzf_search_git_log --description "Search the output of git log and pre
else
if not set --query fzf_git_log_format
# %h gives you the abbreviated commit hash, which is useful for saving screen space, but we will have to expand it later below
set fzf_git_log_format '%C(bold blue)%h%C(reset) - %C(cyan)%ad%C(reset) %C(yellow)%d%C(reset) %C(normal)%s%C(reset) %C(dim normal)[%an]%C(reset)'
set -f fzf_git_log_format '%C(bold blue)%h%C(reset) - %C(cyan)%ad%C(reset) %C(yellow)%d%C(reset) %C(normal)%s%C(reset) %C(dim normal)[%an]%C(reset)'
end
set selected_log_lines (
set -f selected_log_lines (
git log --no-show-signature --color=always --format=format:$fzf_git_log_format --date=short | \
_fzf_wrapper --ansi \
--multi \
Expand All @@ -18,9 +18,9 @@ function _fzf_search_git_log --description "Search the output of git log and pre
)
if test $status -eq 0
for line in $selected_log_lines
set abbreviated_commit_hash (string split --field 1 " " $line)
set full_commit_hash (git rev-parse $abbreviated_commit_hash)
set --append commit_hashes $full_commit_hash
set -f abbreviated_commit_hash (string split --field 1 " " $line)
set -f full_commit_hash (git rev-parse $abbreviated_commit_hash)
set -f --append commit_hashes $full_commit_hash
end
commandline --current-token --replace (string join ' ' $commit_hashes)
end
Expand Down
4 changes: 2 additions & 2 deletions functions/_fzf_search_git_status.fish
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ function _fzf_search_git_status --description "Search the output of git status.
if not git rev-parse --git-dir >/dev/null 2>&1
echo '_fzf_search_git_status: Not in a git repository.' >&2
else
set selected_paths (
set -f selected_paths (
# Pass configuration color.status=always to force status to use colors even though output is sent to a pipe
git -c color.status=always status --short |
_fzf_wrapper --ansi \
Expand All @@ -16,7 +16,7 @@ function _fzf_search_git_status --description "Search the output of git status.
if test $status -eq 0
# git status --short automatically escapes the paths of most files for us so not going to bother trying to handle
# the few edges cases of weird file names that should be extremely rare (e.g. "this;needs;escaping")
set cleaned_paths
set -f cleaned_paths

for path in $selected_paths
if test (string sub --length 1 $path) = R
Expand Down
2 changes: 1 addition & 1 deletion functions/_fzf_search_history.fish
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ function _fzf_search_history --description "Search command history. Replace the
end

# Delinate commands throughout pipeline using null rather than newlines because commands can be multi-line
set commands_selected (
set -f commands_selected (
# Reference https://devhints.io/strftime to understand strftime format symbols
builtin history --null --show-time="%m-%d %H:%M:%S │ " |
_fzf_wrapper --read0 \
Expand Down
6 changes: 3 additions & 3 deletions functions/_fzf_search_processes.fish
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
function _fzf_search_processes --description "Search all running processes. Replace the current token with the pid of the selected process."
# use all caps to be consistent with ps default format
# snake_case because ps doesn't seem to allow spaces in the field names
set ps_preview_fmt (string join ',' 'pid' 'ppid=PARENT' 'user' '%cpu' 'rss=RSS_IN_KB' 'start=START_TIME' 'command')
set processes_selected (
set -f ps_preview_fmt (string join ',' 'pid' 'ppid=PARENT' 'user' '%cpu' 'rss=RSS_IN_KB' 'start=START_TIME' 'command')
set -f processes_selected (
ps -A -opid,command | \
_fzf_wrapper --multi \
--prompt="Search Processes> " \
Expand All @@ -18,7 +18,7 @@ function _fzf_search_processes --description "Search all running processes. Repl

if test $status -eq 0
for process in $processes_selected
set --append pids_selected (string split --no-empty --field=1 -- " " $process)
set -f --append pids_selected (string split --no-empty --field=1 -- " " $process)
end

# string join to replace the newlines outputted by string split with spaces
Expand Down
8 changes: 4 additions & 4 deletions functions/_fzf_search_variables.fish
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ function _fzf_search_variables --argument-names set_show_output set_names_output
# 1. it's not included in $set_names_output
# 2. it tends to be a very large value => increases computation time
# 3._fzf_search_history is a much better way to examine history anyway
set all_variable_names (string match --invert history <$set_names_output)
set -f all_variable_names (string match --invert history <$set_names_output)

set current_token (commandline --current-token)
set -f current_token (commandline --current-token)
# Use the current token to pre-populate fzf's query. If the current token begins
# with a $, remove it from the query so that it will better match the variable names
set cleaned_curr_token (string replace -- '$' '' $current_token)
set -f cleaned_curr_token (string replace -- '$' '' $current_token)

set variable_names_selected (
set -f variable_names_selected (
printf '%s\n' $all_variable_names |
_fzf_wrapper --preview "_fzf_extract_var_info {} $set_show_output" \
--prompt="Search Variables> " \
Expand Down
4 changes: 2 additions & 2 deletions functions/_fzf_wrapper.fish
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
function _fzf_wrapper --description "Prepares some environment variables before executing fzf."
# Make sure fzf uses fish to execute preview commands, some of which
# are autoloaded fish functions so don't exist in other shells.
# Use --local so that it doesn't clobber SHELL outside of this function.
set --local --export SHELL (command --search fish)
# Use --function so that it doesn't clobber SHELL outside this function.
set -f --export SHELL (command --search fish)

# If FZF_DEFAULT_OPTS is not set, then set some sane defaults.
# See https://github.com/junegunn/fzf#environment-variables
Expand Down
4 changes: 2 additions & 2 deletions functions/fzf_configure_bindings.fish
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ function fzf_configure_bindings --description "Installs the default key bindings
# no need to install bindings if not in interactive mode or running tests
status is-interactive || test "$CI" = true; or return

set options_spec h/help 'directory=?' 'git_log=?' 'git_status=?' 'history=?' 'processes=?' 'variables=?'
set -f options_spec h/help 'directory=?' 'git_log=?' 'git_status=?' 'history=?' 'processes=?' 'variables=?'
argparse --max-args=0 --ignore-unknown $options_spec -- $argv 2>/dev/null
if test $status -ne 0
echo "Invalid option or a positional argument was provided." >&2
Expand All @@ -16,7 +16,7 @@ function fzf_configure_bindings --description "Installs the default key bindings
else
# Initialize with default key sequences and then override or disable them based on flags
# index 1 = directory, 2 = git_log, 3 = git_status, 4 = history, 5 = processes, 6 = variables
set key_sequences \e\cf \e\cl \e\cs \cr \e\cp \cv # \c = control, \e = escape
set -f key_sequences \e\cf \e\cl \e\cs \cr \e\cp \cv # \c = control, \e = escape
set --query _flag_directory && set key_sequences[1] "$_flag_directory"
set --query _flag_git_log && set key_sequences[2] "$_flag_git_log"
set --query _flag_git_status && set key_sequences[3] "$_flag_git_status"
Expand Down

2 comments on commit cab67cc

@oscarsiles
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to increase the minimum fish version to 3.4, as set -f is not recognized in 3.3 or lower.

@PatrickF1
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, I'll bump up the minimum version of fish. I hope you are able to upgrade.

Please sign in to comment.