diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index f74cf83..cceb38c 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -18,7 +18,7 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/crate-ci/typos
- rev: v1.16.25
+ rev: v1.17.0
hooks:
- id: typos
args: [--format, brief, --write-changes]
diff --git a/gh-find-code b/gh-find-code
index e0c61af..059d33b 100755
--- a/gh-find-code
+++ b/gh-find-code
@@ -13,15 +13,14 @@ set -o allexport -o errexit -o nounset -o pipefail
# --jq '[.data.__type.enumValues[].name] | join(", ")'
# TODO: add tests
-# TODO: experiment with 'parallel' to speed things up
+# TODO: replace python with a more typical bash solution
# ====================== set variables =======================
-
debug_mode=false
open_in_editor=false
open_in_pager=false
fzf_prompt="❮❯ Code: "
-FZF_API_KEY="$(head -c 32 /dev/urandom | base64)"
+FZF_API_KEY="$(command head -c 32 /dev/urandom | command base64)"
BAT_THEME=${BAT_THEME:-Monokai Extended}
# bash is needed to use exported functions when the default shellis not bash
SHELL=bash
@@ -35,8 +34,8 @@ gh_accept_json="Accept: application/vnd.github+json"
gh_accept_raw="Accept: application/vnd.github.raw"
gh_accept_text_match="Accept: application/vnd.github.text-match+json"
gh_rest_api_version="X-GitHub-Api-Version:2022-11-28"
-# see https://github.com/junegunn/fzf/blob/master/CHANGELOG.md 'preview-border' option
-min_fzf_version="0.43.0"
+# see https://github.com/junegunn/fzf/blob/master/CHANGELOG.md longform '{fzf:query}' option
+min_fzf_version="0.45.0"
# a bug with 'gh-browse' with relative paths was fixed
# https://github.com/cli/cli/issues/7674
min_gh_version="2.37.0"
@@ -61,22 +60,38 @@ DARK_GRAY='\033[0;90m'
cleanup() {
$debug_mode && printf "%bDebug mode was ON, the following files weren't deleted.%b\n" "$YELLOW_NORMAL" "$COLOR_RESET"
- rm -rf "$scratch_directory" 2>/dev/null
+ if [ -s "$store_ppid" ]; then
+ while read -r ppid; do
+ if command kill -0 "$ppid" 2>/dev/null; then
+ command kill "$ppid" 2>/dev/null
+ fi
+ done <"$store_ppid"
+ fi
+ if [ -s "$store_pids" ]; then
+ command awk '!x[$0]++' "$store_pids" | while read -r pid; do
+ if command kill -0 "$pid" 2>/dev/null; then
+ command kill "$pid" 2>/dev/null
+ fi
+ done
+ : >"$store_pids"
+ fi
+ command rm -rf "$scratch_directory" 2>/dev/null
if ! $debug_mode; then
- rm -rf "$debug_directory" 2>/dev/null
+ command rm -rf "$debug_directory" 2>/dev/null
else
find "${debug_directory}/"* 2>/dev/null | while read -r matching_file; do
if [[ ! -s $matching_file ]]; then
- rm -f "$matching_file"
+ command rm -f "$matching_file"
else
- printf "\t%s\n" "$matching_file"
+ command printf "\t%s\n" "$matching_file"
fi
done
fi
+
# In case of duplicates, only the most recent entry is preserved. Instead of 'tail -r', 'tac'
# can be used, but it requires 'coreutils'.
- [[ -f $gh_find_code_history ]] && tail -r "$gh_find_code_history" |
- awk '!x[$0]++' | tail -r | tee "$gh_find_code_history" >/dev/null
+ [[ -f $gh_find_code_history ]] && command tail -r "$gh_find_code_history" |
+ command awk '!x[$0]++' | command tail -r | command tee "$gh_find_code_history" >/dev/null
}
die() {
@@ -99,6 +114,8 @@ store_fzf_port="${scratch_directory}/fzf_port"
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"
# Debug directory
debug_directory=$(mktemp -dt "$date_prefix.gh_find_code.debug") || die "Can't create debug directory."
@@ -112,7 +129,9 @@ check_version() {
local tool=$1 threshold=$2 on_error=${3:-die}
local user_version
declare -a ver_parts threshold_parts
- user_version=$($tool --version 2>&1 | grep -Eo '[0-9]+(\.[0-9]+)*' | sed q)
+ user_version=$(command $tool --version 2>&1 |
+ command grep --color=never --extended-regexp --only-matching --regexp='[0-9]+(\.[0-9]+)*' |
+ command sed q)
IFS='.' read -ra ver_parts <<<"$user_version"
IFS='.' read -ra threshold_parts <<<"$threshold"
@@ -146,7 +165,7 @@ ${WHITE_BOLD}Hotkeys${COLOR_RESET}
${GREEN_NORMAL}ctrl-n${COLOR_RESET} next history command
${GREEN_NORMAL}ctrl-o${COLOR_RESET} open the file content in the editor
${GREEN_NORMAL}ctrl-p${COLOR_RESET} previous history command
- ${GREEN_NORMAL}ctrl-r${COLOR_RESET} reload with 100 results
+ ${GREEN_NORMAL}ctrl-r${COLOR_RESET} reload with up to 100 results
${GREEN_NORMAL}ctrl-t${COLOR_RESET} open the search query in the browser
${GREEN_NORMAL}enter ${COLOR_RESET} open the file in the pager
${GREEN_NORMAL}tab ${COLOR_RESET} toggle the file preview
@@ -192,7 +211,7 @@ shift "$((OPTIND - 1))"
# ====================== check requirements =======================
for tool in bat column curl fzf gh python; do
- if ! type -p $tool >/dev/null; then
+ if ! command -v $tool >/dev/null; then
die "'$tool' was not found."
fi
done
@@ -211,7 +230,7 @@ check_version python "$min_python_version"
# https://github.com/util-linux/util-linux/issues/1699#issuecomment-1140972918
# https://man7.org/linux/man-pages/man1/column.1.html
-if [[ $(column -t <<<"A Z" 2>/dev/null) != *" "* ]]; then
+if [[ $(command column -t <<<"A Z" 2>/dev/null) != *" "* ]]; then
die "Your 'column' command does not separate columns with at least two spaces. Please report this issue, stating your operating system and 'column' version."
fi
@@ -227,23 +246,23 @@ curl_custom() {
sanitize_input() {
if [[ -n ${2-} ]]; then
# replace spaces with '+' and special characters with percent-encoded values
- python -c "import urllib.parse; print(urllib.parse.quote_plus('''$1'''))"
+ command python -c "import urllib.parse; print(urllib.parse.quote_plus('''$1'''))"
else
# replaces spaces with '%20' and special characters with percent-encoded values
- python -c "import urllib.parse; print(urllib.parse.quote('''$1'''))"
+ command python -c "import urllib.parse; print(urllib.parse.quote('''$1'''))"
fi
}
play_notification_sound() {
# natively installed audio player for macOS, or fall back to the ASCII bell character
- afplay /System/Library/Sounds/Basso.aiff 2>/dev/null || echo -e "\a"
+ command afplay /System/Library/Sounds/Basso.aiff 2>/dev/null || echo -e "\a"
}
open_query_in_browser() {
local sanitized_query
sanitized_query=$(sanitize_input "$1" true)
if [ -n "$sanitized_query" ]; then
- python -m webbrowser "https://github.com/search?q=${sanitized_query}&type=code"
+ command python -m webbrowser "https://github.com/search?q=${sanitized_query}&type=code"
else
play_notification_sound
fi
@@ -256,7 +275,21 @@ gh_query() {
local file_extension sanitized_patterns sanitized_owner_repo_name sanitized_file_path
local matched_line error_encountered redirect_location index_color
declare -a line_numbers
- if data=$(gh api search/code \
+ if [ -z "$input" ]; then
+ curl_custom "transform-header:printf '%b? help · esc quit\nPlease enter a search query.%b' '$DARK_GRAY' '$COLOR_RESET'"
+ return
+ fi
+ # Ensure all background jobs are terminated before starting a new one.
+ if [ -s "$store_pids" ]; then
+ command awk '!x[$0]++' "$store_pids" | while read -r pid; do
+ if command kill -0 "$pid" 2>/dev/null; then
+ command kill "$pid" 2>/dev/null
+ fi
+ done
+ : >"$store_pids"
+ fi
+ curl_custom "transform-header:printf '%bSearching…%b' '$DARK_GRAY' '$COLOR_RESET'"
+ if ! data=$(command gh api search/code \
--method GET \
--cache "$gh_default_cache_time" \
--header "$gh_accept_json" \
@@ -275,7 +308,49 @@ gh_query() {
# extended grep
patterns: ([.value.text_matches[] | .. | .text? | select(type=="string")] as $patterns_array |
if $patterns_array == [] then "__NoPatternFound__" else $patterns_array | unique | join("|") end)
- } | [.index, .owner_repo_name, .file_name, .file_path, .patterns] | @tsv)' 2>"$store_gh_search_debug"); then
+ } | [.index, .owner_repo_name, .file_name, .file_path, .patterns] | @tsv)' \
+ 2>"$store_gh_search_debug") || [[ -z $data ]]; then
+ curl_custom "transform-header:printf '%bFailed to get the search results!\n\t- Check query syntax\n\t- Check internet connection%b' \
+ '$RED_NORMAL' '$COLOR_RESET'"
+ return
+ else
+ ({
+ # first line
+ IFS=' ' read -r items total_count
+
+ while IFS=$'\t' read -r index owner_repo_name file_name file_path patterns; do
+ # https://github.com/junegunn/fzf/issues/398
+ # Tested with 'sudo opensnoop -n bash', without a break check it keeps going through
+ # the data list. Check if the parent process is still running or kill the loop
+ ! command kill -0 "$PPID" 2>/dev/null && break
+ # These sanitizations are necessary because file paths may contain special
+ # characters, such as hashtags (#).
+ sanitized_owner_repo_name=$(sanitize_input "$owner_repo_name")
+ sanitized_file_path=$(sanitize_input "$file_path")
+ command cp "$store_file_contents" "${store_file_contents}_${index}"
+ command cp "$store_file_contents" "${store_file_contents}_${index}_line_numbers"
+ (
+ if command gh api "repos/${sanitized_owner_repo_name}/contents/${sanitized_file_path}" \
+ --cache "$gh_default_cache_time" \
+ --header "$gh_accept_raw" \
+ --header "$gh_rest_api_version" \
+ >"${store_file_contents}_${index}" \
+ 2>"$store_gh_content_debug"; then
+ :
+ elif command gh api "https://raw.githubusercontent.com/${sanitized_owner_repo_name}/HEAD/${sanitized_file_path}" \
+ --cache "$gh_default_cache_time" \
+ --header "$gh_accept_raw" \
+ --header "$gh_rest_api_version" \
+ >"${store_file_contents}_${index}" \
+ 2>"$store_gh_content_debug"; then
+ :
+ fi
+ ) &
+ # save process ID of the most recently invoked background job
+ echo $! >>"$store_pids"
+ done
+ } <<<"$data") &
+ echo $! >>"$store_pids"
{
error_encountered=false
skip_count=0
@@ -286,15 +361,9 @@ gh_query() {
: >"$store_skip_count"
# first line
IFS=' ' read -r items total_count
-
# listed items
while IFS=$'\t' read -r index owner_repo_name file_name file_path patterns; do
- # https://github.com/junegunn/fzf/issues/398
- # TODO: Improve the solution for terminating this while loop, when the script is exited.
- # Tested with 'sudo opensnoop -n bash', without a break check it
- # keeps going through the data list.
- # Check if the parent process is still running or kill the loop
- ! kill -0 "$PPID" 2>/dev/null && break
+ ! command kill -0 "$PPID" 2>/dev/null && break
index_color="$WHITE_NORMAL"
file_extension="null"
# Check if the file has a file extension and assign it.
@@ -303,59 +372,48 @@ gh_query() {
fi
# This covers special cases where syntax highlighting requires a leading
# dot, such as filenames like 'zshrc', '.zshrc' or 'macos.zshrc'
- if bat --list-languages --color=never | grep --quiet --word-regexp "\.${file_extension}"; then
+ if command bat --list-languages --color=never |
+ command grep --quiet --word-regexp "\.${file_extension}"; then
file_extension=".${file_extension}"
- elif bat --list-languages --color=never | grep --quiet --word-regexp "\.${file_name}"; then
+ elif command bat --list-languages --color=never |
+ command grep --quiet --word-regexp "\.${file_name}"; then
file_extension=".${file_name}"
fi
- # These sanitizations are necessary because file paths may contain special
- # characters, such as hashtags (#).
- sanitized_owner_repo_name=$(sanitize_input "$owner_repo_name")
- sanitized_file_path=$(sanitize_input "$file_path")
- cp "$store_file_contents" "${store_file_contents}_${index}"
- cp "$store_file_contents" "${store_file_contents}_${index}_line_numbers"
-
# Escape special charters before using the string in extended 'grep'.
# However, the "|" character should be left unescaped.
- # shellcheck disable=SC2001
- sanitized_patterns=$(sed -e 's/[][?*+.\/$^(){}]/\\&/g' <<<"$patterns")
-
- if gh api "repos/${sanitized_owner_repo_name}/contents/${sanitized_file_path}" \
- --cache "$gh_default_cache_time" \
- --header "$gh_accept_raw" \
- --header "$gh_rest_api_version" \
- >"${store_file_contents}_${index}" \
- 2>"$store_gh_content_debug"; then
- # The first attempt is the typical way and is usually successful.
- :
- elif gh api "https://raw.githubusercontent.com/${sanitized_owner_repo_name}/HEAD/${sanitized_file_path}" \
- --cache "$gh_default_cache_time" \
- --header "$gh_accept_raw" \
- --header "$gh_rest_api_version" \
- >"${store_file_contents}_${index}" \
- 2>"$store_gh_content_debug"; then
- # This case covers 'symlinked' files, for example:
- # 'repo:model-checking/kani in:path macos'.
- :
- else
- # There could be several reasons why pulling content might fail. One
- # reason could be outdated cached search results from GitHub. For
- # example, a user might have deleted their account, but their content
- # is still in the search index.
- echo "$index" >>"$store_skip_count"
- if $debug_mode; then
- error_encountered=true
- else
- {
- cat "$store_gh_content_debug"
- printf "\n[%s] SKIPPED: The contents of this file couldn't be fetched.\n\n" "$(date -u +%Y-%m-%dT%H-%M-%S)"
- } >>"${store_file_contents}_${index}"
+ sanitized_patterns=$(command sed -e 's/[][?*+.\/$^(){}]/\\&/g' <<<"$patterns")
+ SECONDS=0
+ while :; do
+ ! command kill -0 "$PPID" 2>/dev/null && break
+ if [ -s "${store_file_contents}_${index}" ]; then
+ cp "${store_file_contents}_${index}" "${store_file_contents}_${index}_fetched"
+ : >"${store_file_contents}_${index}"
+ break
fi
- index_color="$RED_NORMAL"
- patterns="__NoPatternFound__"
+ command sleep 0.1
+ if ((SECONDS >= 2)); then
+ # There could be several reasons why pulling content might fail. One
+ # reason could be outdated cached search results from GitHub. For
+ # example, a user might have deleted their account, but their content
+ # is still in the search index.
+ echo "$index" >>"$store_skip_count"
+ if $debug_mode; then
+ error_encountered=true
+ else
+ {
+ command cat "$store_gh_content_debug"
+ printf "\n[%s] SKIPPED: The contents of this file couldn't be fetched.\n\n" "$(date -u +%Y-%m-%dT%H-%M-%S)"
+ } >>"${store_file_contents}_${index}"
+ fi
+ index_color="$RED_NORMAL"
+ patterns="__NoPatternFound__"
+ break
+ fi
+ done
+ if command grep --quiet --word-regexp "$index" "$store_skip_count"; then
+ continue
fi
-
curl_custom "transform-header:printf '%b%s/%s of %s collected...%b' '$DARK_GRAY' \
'$index' '$((total_count > gh_user_limit ? gh_user_limit : total_count))' \
'$total_count' '$COLOR_RESET'"
@@ -378,9 +436,12 @@ gh_query() {
# Use the '--text' flag, as grep will simply print 'Binary file … matches' if
# the file contains binary characters. It won't even throw an error.
# https://unix.stackexchange.com/questions/19907
- done < <(grep --extended-regexp --line-number --text \
- --regexp="$sanitized_patterns" -- \
- "${store_file_contents}_${index}" 2>"${redirect_location}" | cut -d: -f1)
+ # I compared the performance of grep and rg, finding grep to be slightly faster,
+ # even with large files (~2000 lines). I may need to investigate further, but
+ # for now, I'm opting to use grep.
+ done < <(command grep --color=never --line-number --text \
+ --extended-regexp --regexp="$sanitized_patterns" -- \
+ "${store_file_contents}_${index}_fetched" 2>"${redirect_location}" | cut -d: -f1)
# Save additional information only if an error is encountered by grep
if $debug_mode && [[ -s ${store_grep_extended_debug}_${index} ]]; then
{
@@ -403,13 +464,13 @@ gh_query() {
fi
done
# Format the input list into a structured table.
- column -ts $'\t' <"$store_tee_append" >"$store_input_list"
+ command column -ts $'\t' <"$store_tee_append" >"$store_input_list"
skip_count="$(sed -n '$=' "$store_skip_count")"
if $error_encountered; then
{
echo
- gh api rate_limit \
+ command gh api rate_limit \
--header "$gh_accept_json" \
--header "$gh_rest_api_version" \
--jq \
@@ -419,8 +480,8 @@ gh_query() {
used_limit: "\(.value.used)/\(.value.limit)",
reset: "\(.value.reset | strflocaltime("%H:%M:%S %Z") ) (\((.value.reset - now) | (./60|ceil))m)"
} | [.name, .used_limit, .reset]) | @tsv' |
- column -ts $'\t' |
- bat --plain --language COMMIT_EDITMSG
+ command column -ts $'\t' |
+ command bat --color=always --plain --language COMMIT_EDITMSG
} >>"$store_gh_content_debug"
curl_custom "transform-header(printf '%bAPI failed for repos/%s/contents/%s%b' \
'$RED_NORMAL' '$owner_repo_name' '$file_path' '$COLOR_RESET')+change-preview:cat '$store_gh_content_debug'"
@@ -435,14 +496,7 @@ gh_query() {
fi
} <<<"$data"
-
- else
- if [ -z "$input" ]; then
- curl_custom "transform-header:printf '%b? help · esc quit\nPlease enter a search query.%b' '$DARK_GRAY' '$COLOR_RESET'"
- else
- curl_custom "transform-header:printf '%bFailed to get the search results, check the query syntax.%b' \
- '$RED_NORMAL' '$COLOR_RESET'"
- fi
+ return
fi
}
@@ -463,7 +517,7 @@ view_contents() {
"--color=always"
)
- [[ $file_extension != "null" ]] && if bat --language "$file_extension" <<<"test" >/dev/null 2>&1; then
+ [[ $file_extension != "null" ]] && if command bat --language "$file_extension" <<<"test" >/dev/null 2>&1; then
bat_args+=("--language=${file_extension}")
fi
IFS=' ' read -ra line_numbers <"${store_file_contents}_${index}_line_numbers"
@@ -482,7 +536,7 @@ view_contents() {
if $open_in_editor; then
tempfile_with_ext="${store_file_contents}_${index}_${file_name}"
- cp "${store_file_contents}_${index}" "$tempfile_with_ext"
+ cp "${store_file_contents}_${index}_fetched" "$tempfile_with_ext"
case $(basename "${EDITOR-}") in
code | codium)
editor_args=(--reuse-window --goto "${tempfile_with_ext}:${line_numbers:-1}")
@@ -502,10 +556,10 @@ view_contents() {
if $debug_mode; then
{
echo -n "bat version: "
- bat --version
+ command bat --version
echo -n "config file: "
- bat --config-file
- cat "$(bat --config-file)"
+ command bat --config-file
+ command cat "$(command bat --config-file)"
for value in BAT_PAGER BAT_CONFIG_PATH BAT_STYLE BAT_THEME BAT_TABS PAGER; do
echo "$value = '${!value}'"
done
@@ -516,30 +570,16 @@ view_contents() {
bat_args+=("--paging=always")
# The 'less' pager can move to a specific line.
if [[ $(basename "${PAGER-}") =~ ^(bat|less)$ ]]; then
- # If the user has assigned the environment variable LESS with the
- # '-F/--quit-if-one-screen' option, and explicitly set the '--pager' to 'less',
- # the screen will not remain open for small text files that fit on the entire
- # screen. The simplest solution is to unset the 'LESS' variable and define
- # custom settings. Replace "${LESS-}" with an empty string when 'LESS' is
- # already unset to avoid an error from 'set -o nounset'.
- [[ -n ${LESS-} ]] && unset LESS
- # Account for an offset of 3 lines for the bat header.
+ # The long option (--+…) for resetting the option to its default setting is broken in
+ # less version 643, so only use the short version.
+ # Ref: https://github.com/gwsw/less/issues/452
less_move_to_line=$((${line_numbers:-1} + 3))
less_args=(
- "--LONG-PROMPT" # Long prompts ("Line X of Y")
- "--hilite-search" # Highlight results when searching with slash key (/)
- "--jump-target=.3" # percent on the screen for the target line
- "--quiet" # be more quiet
- "--quit-on-intr" # quit less immediately with ^C
- "--RAW-CONTROL-CHARS" # colors will not work without it
- "--tilde" # don't show '~' symbols on lines after EOF
+ "--clear-screen" # to be painted from the top line down
+ "-+F" # disable exiting if the entire file can be displayed on the first screen
+ "-+X" # disable screen clearing prevention
"+${less_move_to_line}" # as the variable name suggests
)
- if [[ -z $(check_version less 550 echo) ]]; then
- # https://www.greenwoodsoftware.com/less/old.html
- # mouse input came with version 550
- less_args+=("--mouse")
- fi
# https://github.com/sharkdp/bat#using-a-different-pager
bat_args+=("--pager='less ${less_args[*]}'")
fi
@@ -547,7 +587,7 @@ view_contents() {
# Not needed in the pager, as these environment variables aren't expanded there.
bat_args+=("--terminal-width=${FZF_PREVIEW_COLUMNS:-$COLUMNS}")
fi
- eval bat "${bat_args[*]}" "${store_file_contents}_${index}"
+ eval command bat "${bat_args[*]}" "${store_file_contents}_${index}_fetched"
}
get_history_count() {
@@ -557,7 +597,7 @@ get_history_count() {
# the gh_find_code_history.txt file.
echo 0
else
- cat "$store_history_counter"
+ command cat "$store_history_counter"
fi
}
@@ -582,7 +622,7 @@ view_history_commands() {
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")")
- bat --color=always \
+ command bat --color=always \
--highlight-line="$counter" \
--terminal-width="${FZF_PREVIEW_COLUMNS:-$COLUMNS}" \
--file-name="$header_info" \
@@ -594,22 +634,29 @@ view_history_commands() {
# ===================== lets begin ========================
-: | fzf \
+# Switching with the new 'transform' action in 0.45.0 can be challenging because the 'echo' command
+# does not preserve the search query's quotation marks ("). For instance, in this query:
+# '"zsh -c"', the quotation marks will not be saved to the '/tmp/rg-fzf-r' file.
+#
+# --bind "ctrl-t:transform:[[ ! {fzf:prompt} =~ Fuzzy ]] &&
+# echo 'unbind(change)+change-prompt(Fuzzy search > )+enable-search+transform-query:echo {fzf:query} > /tmp/rg-fzf-r; cat /tmp/rg-fzf-f' ||
+# echo 'rebind(change)+change-prompt($fzf_prompt)+disable-search+transform-query:echo {fzf:query} > /tmp/rg-fzf-f; cat /tmp/rg-fzf-r'" \
+: | command fzf \
--ansi \
- --bind $'start:execute-silent(echo $FZF_PORT > $store_fzf_port)+reload:gh_query {q}' \
- --bind "change:first+reload:sleep 0.65; gh_query {q} || true" \
+ --bind $'start:execute-silent(echo ${PPID-} > $store_ppid ;echo $FZF_PORT > $store_fzf_port)+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-h:change-preview(view_history_commands)+change-preview-window:~0:+1" \
--bind "ctrl-n:execute-silent(next)+refresh-preview+next-history" \
--bind "ctrl-p:execute-silent(previous)+refresh-preview+prev-history" \
- --bind 'ctrl-o:execute:[[ -n {q} && -n {} ]] && open_in_editor=true view_contents {}' \
- --bind 'ctrl-r:reload:gh_user_limit=100;gh_query {q} || true' \
- --bind 'ctrl-t:execute-silent:open_query_in_browser {q}' \
- --bind 'enter:execute:[[ -n {q} && -n {} ]] && open_in_pager=true view_contents {}' \
+ --bind 'ctrl-o:execute:[[ -n {fzf:query} && -n {} ]] && open_in_editor=true view_contents {}' \
+ --bind 'ctrl-r:reload:gh_user_limit=100;gh_query {fzf:query}' \
+ --bind 'ctrl-t:execute-silent:open_query_in_browser {fzf:query}' \
+ --bind 'enter:execute:[[ -n {fzf:query} && -n {} ]] && open_in_pager=true view_contents {}' \
--bind 'esc:become:' \
--bind '?:change-preview(print_help_text)+change-preview-window:~0:+1' \
--bind 'scroll-up:offset-up,scroll-down:offset-down' \
- --bind 'tab:change-preview([[ -n {q} && -n {} ]] && view_contents {})+change-preview-window:hidden:<70(hidden)|+{1}+3/3' \
+ --bind 'tab:change-preview([[ -n {fzf:query} && -n {} ]] && view_contents {})+change-preview-window:hidden:<70(hidden)|+{1}+3/3' \
--border block \
--color 'bg+:233,bg:235,gutter:235,border:238,scrollbar:235' \
--color 'preview-bg:234,preview-border:236,preview-scrollbar:237' \
@@ -628,7 +675,7 @@ view_history_commands() {
--listen \
--no-multi \
--pointer '▶' \
- --preview "[[ -n {q} && -n {} ]] && view_contents {}" \
+ --preview "[[ -n {fzf:query} && -n {} ]] && view_contents {}" \
--preview-window 'border-block:~3:+{1}+3/3:nohidden:right:nowrap:65%:<70(bottom:75%)' \
--prompt "$fzf_prompt" \
--query "$*" \
diff --git a/readme.md b/readme.md
index 5dc83f8..84cda38 100644
--- a/readme.md
+++ b/readme.md
@@ -56,7 +56,7 @@ gh find-code [Flags] [Search query]
| ctrln | next history command |
| ctrlo | open the file content in the editor |
| ctrlp | previous history command |
-| ctrlr | reload |
+| ctrlr | reload with up to 100 results |
| ctrlt | open the search query in the browser |
| enter | open the file in the pager |
| tab | toggle the file preview |