diff --git a/gh-find-code b/gh-find-code index 785e441..d0ca9d4 100755 --- a/gh-find-code +++ b/gh-find-code @@ -70,12 +70,11 @@ store_input_list="${scratch_directory}/input_list" store_tee_append="${scratch_directory}/tee_append" store_file_contents="${scratch_directory}/file_content" store_skip_count="${scratch_directory}/skip_count" -store_history_counter="${scratch_directory}/history_counter" store_ppid="${scratch_directory}/ppid" store_pids="${scratch_directory}/pids" store_fuzzy_search_string="${scratch_directory}/fuzzy_search_string" store_search_string="${scratch_directory}/search_string" -store_gh_find_code_history_tmp="${scratch_directory}/gh_find_code_history" +store_gh_find_code_history_tmp="${scratch_directory}/gh_find_code_history_tmp" # Debug directory debug_directory=$(mktemp -dt "$date_prefix.gh_find_code.debug") || die "Can't create debug directory." @@ -87,7 +86,6 @@ store_gh_content_debug="${debug_directory}/gh_content_debug" # =========================== basics ============================ cleanup() { - $debug_mode && printf "%bDebug mode was ON, the following files weren't deleted.%b\n" "$YELLOW_NORMAL" "$COLOR_RESET" if [ -s "$store_ppid" ]; then while read -r ppid; do if command kill -0 "$ppid" 2>/dev/null; then @@ -109,10 +107,21 @@ cleanup() { # in the same pipeline - https://shellcheck.net/wiki/SC2094. This could lead to a race # condition, resulting in the file being erased. It's crucial to run the process before # deleting the scratch_directory. - [[ -f $gh_find_code_history ]] && command tail -r "$gh_find_code_history" | - command awk '!x[$0]++' | command tail -r >"$store_gh_find_code_history_tmp" && - command mv "$store_gh_find_code_history_tmp" "$gh_find_code_history" + # Check if the file exists before proceeding + if [[ -f $gh_find_code_history ]]; then + command tail -r "$gh_find_code_history" | command awk '!x[$0]++' | command tail -r >"$store_gh_find_code_history_tmp" + + # Check if the temporary file was created successfully + if [[ -f $store_gh_find_code_history_tmp ]]; then + command mv "$store_gh_find_code_history_tmp" "$gh_find_code_history" + else + $debug_mode && echo "Error: Failed to create temporary file." + fi + else + $debug_mode && echo "Error: File '$gh_find_code_history' not found." + fi + $debug_mode && printf "%bDebug mode was ON, the following files weren't deleted.%b\n" "$YELLOW_NORMAL" "$COLOR_RESET" command rm -rf "$scratch_directory" 2>/dev/null if ! $debug_mode; then command rm -rf "$debug_directory" 2>/dev/null @@ -387,9 +396,7 @@ gh_query() { # A way to shorten large numbers using SI prefixes. # https://www.bipm.org/en/measurement-units/si-prefixes total_count_si_format=$( - if ((total_count >= 1000000000)); then - printf "%dG" $((total_count / 1000000000)) - elif ((total_count >= 1000000)); then + if ((total_count >= 1000000)); then printf "%dM" $((total_count / 1000000)) elif ((total_count >= 1000)); then printf "%dk" $((total_count / 1000)) @@ -506,8 +513,8 @@ gh_query() { else base_name="…${file_path: -30}" fi - printf "%s\t%s\t%s\t%b%-3d%b\t%b%s%b/%b%s%b\t%b%s/%b%s%b\n" \ - "${line_numbers:-1}" "$(get_history_count)" "$file_extension" "$index_color" \ + printf "%s\t%s\t%b%-3d%b\t%b%s%b/%b%s%b\t%b%s/%b%s%b\n" \ + "${line_numbers:-1}" "$file_extension" "$index_color" \ "$index" "$COLOR_RESET" "$CYAN_NORMAL" "${owner_repo_name%/*}" "$COLOR_RESET" \ "$CYAN_BOLD" "${owner_repo_name#*/}" "$COLOR_RESET" "$MAGENTA_NORMAL" \ "$dir_name" "$MAGENTA_BOLD" "$base_name" "$COLOR_RESET" | @@ -559,7 +566,7 @@ view_contents() { declare -a line_numbers bat_args editor_args less_args local file_extension index file_path local file_name tempfile_with_ext less_move_to_line - IFS=$'\t' read -r _ _ file_extension index _ file_path < <(sed -E $'s/[[:space:]]{2,}/\t/g' <<<"$@") + IFS=$'\t' read -r _ file_extension index _ file_path < <(sed -E $'s/[[:space:]]{2,}/\t/g' <<<"$@") # Remove trailing whitespace that was caused by the '%-3d' placeholder in 'printf'. index=$(tr -d '[:space:]' <<<"$index") @@ -644,103 +651,104 @@ view_contents() { eval command bat "${bat_args[*]}" "${store_file_contents}_${index}_fetched" } -get_history_count() { - if [ ! -s "$store_history_counter" ]; then - # Initialization is set to zero to prevent any highlighting. Highlighting only starts when - # 'ctrl-p' or 'ctrl-n' are pressed and are within the range of 1 and the total line count of - # the gh_find_code_history.txt file. - echo 0 - else - command cat "$store_history_counter" - fi -} - -next() { - counter=$(get_history_count) - if [[ $counter -gt 0 ]]; then - ((counter--)) - echo "$counter" >"$store_history_counter" - fi -} - -previous() { - counter=$(get_history_count) - if [[ $counter -lt $(sed -n '$=' "$gh_find_code_history") ]]; then - ((counter++)) - echo "$counter" >"$store_history_counter" - fi +fzf_basic_style() { + # Useful tool: https://vitormv.github.io/fzf-themes/ + # IMPORTANT: anything after "$@" will overwrite options in the actual command + command fzf -- \ + --ansi \ + --bind 'scroll-up:offset-up,scroll-down:offset-down' \ + --border block \ + --color 'bg+:233,bg:235,gutter:235,border:238,scrollbar:235' \ + --color 'preview-bg:234,preview-border:236,preview-scrollbar:237' \ + --color 'fg+:255,fg:regular:250,hl:40,hl+:40' \ + --color 'pointer:9,spinner:92,marker:46' \ + --color 'prompt:14,info:40,header:255:regular,label:bold' \ + --ellipsis '' \ + --height=100% \ + --header-lines 0 \ + --no-multi \ + --info hidden \ + --layout reverse \ + --scroll-off 3 \ + --scrollbar '│▐' \ + --separator '' \ + --unicode \ + "$@" } view_history_commands() { - counter=$(get_history_count) - if [ -s "$gh_find_code_history" ]; then - header_info=$(printf "%s (%s/%s) │ sort desc (↓) │ ^n (next) / ^p (previous)" \ - "${gh_find_code_history##*/}" "$counter" "$(sed -n '$=' "$gh_find_code_history")") - command bat --color=always \ - --highlight-line="$counter" \ - --terminal-width="${FZF_PREVIEW_COLUMNS:-$COLUMNS}" \ - --file-name="$header_info" \ - --style=numbers,header-filename,grid <<<"$(tail -r "$gh_find_code_history")" + local selection header_string header_color + if [[ ! -s $gh_find_code_history ]]; then + header_color="yellow" + header_string="No history entries yet. Check back on your next run. Press 'esc' to exit." + fi + selection=$(command tail -r "$gh_find_code_history" | command nl -n ln -w 3 -s $'\t' | + fzf_basic_style \ + --bind 'ctrl-h:abort' \ + --bind 'esc:abort' \ + --color "header:${header_color:--1}" \ + --preview-window 'hidden' \ + --prompt 'Select a History Entry > ' \ + --header "${header_string:-"enter select · esc quit"}") || true + if [[ -n $selection ]]; then + # to eliminate the first field and any leading whitespace + main "$(command awk '{$1=""; sub(/^[ \t]+/, ""); print $0}' <<<"$selection")" else - echo 'No history entries yet. Check back on your next run.' + main "$1" fi } -# ===================== lets begin ======================== - -# https://github.com/junegunn/fzf/issues/3353 -# NOTE: The 'change-preview-window' action in 'transform' should precede 'change-preview'. -# NOTE: In the transform action, placeholders and functions using placeholders as arguments must be -# escaped, e.g. '\view_contents \{}' - -: | command fzf \ - --ansi \ - --bind $'start:execute-silent(echo ${PPID-} > $store_ppid)+reload:gh_query {fzf:query}' \ - --bind "change:first+reload:sleep 0.5; gh_query {fzf:query}" \ - --bind 'ctrl-b:execute-silent:gh browse --repo {5} {6}:{1}' \ - --bind "ctrl-h:transform:[[ ! \$FZF_PROMPT =~ History ]] && - echo 'change-prompt(History: )+change-preview-window(+\{2}+3/3)+change-preview:view_history_commands' || - echo 'change-prompt($fzf_prompt)+change-preview-window(+\{1}+3/3)+change-preview:\view_contents \{}'" \ - --bind "ctrl-n:execute-silent(next)+refresh-preview+next-history+beginning-of-line" \ - --bind "ctrl-p:execute-silent(previous)+refresh-preview+prev-history+beginning-of-line" \ - --bind $'ctrl-o:execute:[[ $FZF_MATCH_COUNT -ge 1 ]] && open_in_editor=true view_contents {}' \ - --bind 'ctrl-r:reload:gh_user_limit=100;gh_query {fzf:query}' \ - --bind "ctrl-t:transform:[[ ! \$FZF_PROMPT == \"$fzf_prompt\" ]] && +main() { + local output_selection + output_selection=$( + # https://github.com/junegunn/fzf/issues/3353 + # NOTE: The 'change-preview-window' action in 'transform' should precede 'change-preview'. + # NOTE: In the transform action, placeholders and functions using placeholders as arguments must be + # escaped, e.g. '\view_contents \{}' + : | fzf_basic_style \ + --bind $'start:execute-silent(echo ${PPID-} > $store_ppid)+reload:gh_query {fzf:query}' \ + --bind "change:first+reload:sleep 0.5; gh_query {fzf:query}" \ + --bind 'ctrl-b:execute-silent:gh browse --repo {4} {5}:{1}' \ + --bind $'ctrl-o:execute:[[ $FZF_MATCH_COUNT -ge 1 ]] && open_in_editor=true view_contents {}' \ + --bind 'ctrl-r:reload:gh_user_limit=100;gh_query {fzf:query}' \ + --bind "ctrl-t:transform:[[ ! \$FZF_PROMPT == \"$fzf_prompt\" ]] && echo 'rebind(change)+change-prompt($fzf_prompt)+disable-search+transform-query:echo \{fzf:query} > $store_fuzzy_search_string; cat $store_search_string' || echo 'unbind(change)+change-prompt($fzf_prompt_fuzzy)+enable-search+transform-query:echo \{fzf:query} > $store_search_string; cat $store_fuzzy_search_string'" \ - --bind 'ctrl-x:execute-silent:open_query_in_browser {fzf:query}' \ - --bind $'enter:execute:[[ $FZF_MATCH_COUNT -ge 1 ]] && view_contents {}' \ - --bind 'esc:become:' \ - --bind 'scroll-up:offset-up,scroll-down:offset-down' \ - --bind "tab:change-prompt($fzf_prompt)+change-preview(view_contents {})+change-preview-window:hidden:<70(hidden)|+{1}+3/3" \ - --bind "?:transform:[[ ! \$FZF_PROMPT =~ Help ]] && + --bind 'ctrl-x:execute-silent:open_query_in_browser {fzf:query}' \ + --bind $'enter:execute:[[ $FZF_MATCH_COUNT -ge 1 ]] && view_contents {} >/dev/tty' \ + --bind 'esc:become:' \ + --bind "tab:change-prompt($fzf_prompt)+change-preview(view_contents {})+change-preview-window:hidden:<70(hidden)|+{1}+3/3" \ + --bind "?:transform:[[ ! \$FZF_PROMPT =~ Help ]] && echo 'change-prompt(Help: )+change-preview-window(~0:+1)+change-preview:print_help_text' || echo 'change-prompt($fzf_prompt)+change-preview-window(+\{1}+3/3)+change-preview:\view_contents \{}'" \ - --border block \ - --color 'bg+:233,bg:235,gutter:235,border:238,scrollbar:235' \ - --color 'preview-bg:234,preview-border:236,preview-scrollbar:237' \ - --color 'fg+:255,fg:regular:250,hl:40,hl+:40' \ - --color 'pointer:9,spinner:92,marker:46' \ - --color 'prompt:14,info:40,header:255:regular,label:bold' \ - --delimiter '\t|\s\s+' \ - --disabled \ - --ellipsis '' \ - --height=100% \ - --header-lines 0 \ - --history "$gh_find_code_history" \ - --history-size 100 \ - --info hidden \ - --layout reverse \ - --listen \ - --no-multi \ - --nth=2..,.. \ - --pointer '▶' \ - --preview 'view_contents {}' \ - --preview-window 'border-block:~3:+{1}+3/3:nohidden:right:nowrap:65%:<70(bottom:75%)' \ - --prompt "$fzf_prompt" \ - --query "$*" \ - --scroll-off 3 \ - --scrollbar '│▐' \ - --separator '' \ - --unicode \ - --with-nth=4.. + --delimiter '\t|\s\s+' \ + --disabled \ + --history "$gh_find_code_history" \ + --history-size 250 \ + --listen \ + --nth=2..,.. \ + --pointer '▶' \ + --preview 'view_contents {}' \ + --preview-window 'border-block:~3:+{1}+3/3:nohidden:right:nowrap:65%:<70(bottom:75%)' \ + --prompt "$fzf_prompt" \ + --query "$*" \ + --with-nth=3.. \ + --print-query \ + --expect "ctrl-h" + ) || true + + printed_query="$(sed 1q <<<"$output_selection")" + output_selection="$(sed '1d;3d' <<<"$output_selection")" + case "$output_selection" in + ctrl-h) + # Using the '--expect' flag is working, but I would send the update of the new query + # back with curl, but I run into /dev/tty too often. I need to write a minimal + # reproducible small script to file a bug report or ask 'junegunn' about it. + view_history_commands "$printed_query" + ;; + esac +} + +# ===================== lets begin ======================== + +main "$@" diff --git a/readme.md b/readme.md index 6171d5e..0642109 100644 --- a/readme.md +++ b/readme.md @@ -143,7 +143,7 @@ export FZF_DEFAULT_OPTS=" using the shortcut keys ⌃ Control + N (next) and ⌃ Control + P (previous). All commands can be viewed with ⌃ Control + H. In case of duplicates, only the most recent entry is preserved. The maximum number of command entries - stored is 100. + stored is 250. ### Pager - If the `PAGER` environment variable is set to `less` or `bat`, when opening the destination file,