Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(issue,pr)!: add live query mode using github search syntax #32

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
601fbe1
feat(issue): add live search mode using github syntax
benelan Jul 11, 2024
af8dc37
feat(ui): change fzf border style to use less screen space
benelan Jul 11, 2024
795a429
fix(issue): use border label to store search mode state
benelan Jul 11, 2024
3413f78
refactor: add additional mode indicator
benelan Jul 11, 2024
9c8c39d
feat(issue): improve filter keybind behavior during live search
benelan Jul 12, 2024
83dbcbd
Merge remote-tracking branch 'origin/main' into live-search
benelan Jul 12, 2024
2abc217
feat(issue): make `ctrl-r` keybind reset the live search state
benelan Jul 12, 2024
51070ae
fix(issue): use the same trailing character for the prompt
benelan Jul 12, 2024
a14c97f
chore: cleanup
benelan Jul 12, 2024
71a1f51
Merge remote-tracking branch 'origin/main' into live-search
benelan Jul 12, 2024
6cd96b6
style(issue): lowercase command-specific variables
benelan Jul 13, 2024
c117642
fix(issue) add state filter to query in gh mode
benelan Jul 13, 2024
7be8388
fix(issue): resolve invalid transform action syntax
benelan Jul 13, 2024
fcdd29a
feat(pr): add mode to live query via github search syntax
benelan Jul 13, 2024
3de9126
refactor!: add fzf version check
benelan Jul 14, 2024
58c0473
feat(issue): get milestone filter working with gh search mode
benelan Jul 14, 2024
7c58b21
chore: cleanup
benelan Jul 14, 2024
7720223
Merge remote-tracking branch 'origin/main' into live-search
benelan Jul 14, 2024
3f82f64
Merge remote-tracking branch 'origin/main' into live-search
benelan Jul 22, 2024
ec984e8
Merge remote-tracking branch 'origin/main' into live-search
benelan Jul 30, 2024
a445bb8
Merge remote-tracking branch 'origin/main' into live-search
benelan Sep 26, 2024
05dc5c8
Merge remote-tracking branch 'origin/main' into live-search
benelan Nov 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 182 additions & 36 deletions gh-fzf
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ set -e

GH_FZF_VERSION="v0.14.1" # x-release-please-version

# USAGE INFO AND LOGS {{{1
FZF_USER_VERSION="$(fzf --version | awk '{print $1}')"

# USAGE INFO AND INTERNAL FUNCTIONS {{{1

has() { command -v "$1" >/dev/null 2>&1; }

Expand Down Expand Up @@ -58,6 +60,12 @@ version_number() {
echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'
}

requires_version() {
if [ "$(version_number "$1")" -gt "$(version_number "$FZF_USER_VERSION")" ]; then
error "the minimum fzf version is $1 (found $FZF_USER_VERSION)"
fi
}

error() {
if [ -n "$1" ]; then
printf "Error: " >&2
Expand Down Expand Up @@ -200,6 +208,9 @@ default_cmd() {
# COMMAND > ISSUE {{{1

issue_cmd() {
# make sure state from the previous execution is destroyed
rm -f /tmp/gh-fzf-issue-*

# GO TEMPLATE {{{2
issue_template='\
--json "number,title,author,assignees,state,milestone,labels,updatedAt" \
Expand Down Expand Up @@ -243,14 +254,35 @@ $global_binds

"

# INITIAL STATE {{{2
issue_command="GH_FORCE_TTY=$GH_COLUMNS gh issue list $issue_template -L $GH_FZF_DEFAULT_LIMIT"
issue_prompt="issue${*:+ $*}"

# FZF COMMAND {{{2
FZF_DEFAULT_COMMAND="GH_FORCE_TTY=$GH_COLUMNS gh issue list $issue_template -L $GH_FZF_DEFAULT_LIMIT $*" \
FZF_DEFAULT_COMMAND="$issue_command $*" \
fzf \
--preview='GH_FORCE_TTY=$((FZF_PREVIEW_COLUMNS-3)) gh issue view {1} --comments' \
--prompt="issue ❱ " \
--header="$issue_header" \
--bind="start:${GH_FZF_HIDE_HINTS:+"toggle-header"}" \
--bind="ctrl-o:execute-silent(gh issue view --web {1} &)+refresh-preview" \
--prompt="$issue_prompt ❱ " \
--border="bottom" \
--border-label="[mode: fzf] " \
--border-label-pos=-99999 \
--bind="start:unbind:change${GH_FZF_HIDE_HINTS:+"+toggle-header"}" \
--bind "change:reload-sync:sleep 0.5; $issue_command $* \${FZF_QUERY:+-S {q}} || true" \
--bind 'alt-/:transform:[[ ! $FZF_BORDER_LABEL =~ gh ]] &&
echo "rebind(change)+change-border-label([mode: gh] )+disable-search+transform-query(
echo \{q} > ${TMPDIR:-/tmp}/gh-fzf-issue-query-fzf;
cat ${TMPDIR:-/tmp}/gh-fzf-issue-query-gh
)+change-prompt('"$issue_prompt"' ❱ )+reload-sync($FZF_DEFAULT_COMMAND ${FZF_QUERY:+-S {q}} || true)" ||
echo "unbind(change)+change-border-label([mode: fzf] )+enable-search+transform-query(
echo \{q} > ${TMPDIR:-/tmp}/gh-fzf-issue-query-gh;
cat ${TMPDIR:-/tmp}/gh-fzf-issue-query-fzf
)"' \
--bind='ctrl-r:change-prompt('"$issue_prompt"' ❱ )+execute-silent(
rm -f ${TMPDIR:-/tmp}/gh-fzf-issue-query-*
)+clear-query+first+reload(eval "$FZF_DEFAULT_COMMAND")' \
--bind="ctrl-o:execute-silent(gh issue view --web {1}&)+refresh-preview" \
--bind="ctrl-y:execute-silent(gh fzf util copy-url issue {1})+refresh-preview" \
--bind="enter:execute(gh issue edit {1})+refresh-preview" \
--bind='alt-o:become(gh fzf util develop-issue {1})' \
Expand All @@ -259,15 +291,44 @@ $global_binds
--bind='alt-L:execute(gh fzf util select-labels remove issue {1})+refresh-preview' \
--bind="alt-O:execute(gh issue reopen {1})+refresh-preview" \
--bind="alt-X:execute(gh issue close {1})+refresh-preview" \
--bind='alt-M:execute(gh fzf milestone > /tmp/gh-fzf-milestone)+reload(
m="$(cat /tmp/gh-fzf-milestone)"
rm -f /tmp/gh-fzf-milestone;
eval "$FZF_DEFAULT_COMMAND${m:+ --milestone \"$m\"}"
)' \
--bind='alt-a:reload(eval "$FZF_DEFAULT_COMMAND --assignee @me")' \
--bind='alt-A:reload(eval "$FZF_DEFAULT_COMMAND --author @me")' \
--bind='alt-m:reload(eval "$FZF_DEFAULT_COMMAND --mention @me")' \
--bind='alt-s:reload(eval "$FZF_DEFAULT_COMMAND --state all")'
--bind='alt-M:execute(
rm -f "${TMPDIR:-/tmp}/gh-fzf-issue-milestone";
gh fzf milestone > "${TMPDIR:-/tmp}/gh-fzf-issue-milestone";
)+transform:
m="$(cat ${TMPDIR:-/tmp}/gh-fzf-issue-milestone)";
[[ ! $FZF_BORDER_LABEL =~ gh ]] &&
echo "reload(
eval \"\$FZF_DEFAULT_COMMAND --milestone '\''$m'\''\"
)+change-prompt:'"$issue_prompt"' --milestone \"$m\" ❱ " ||
[[ ! $FZF_QUERY =~ milestone: ]] && echo "put( milestone:\"$m\")"
' \
--bind 'alt-a:transform:[[ ! $FZF_BORDER_LABEL =~ gh ]] &&
echo "reload(
eval \"\$FZF_DEFAULT_COMMAND --assignee @me\"
)+change-prompt:'"$issue_prompt"' --assignee @me ❱ " ||
[[ ! $FZF_QUERY =~ assignee:@me ]] && echo "put( assignee:@me)"
' \
--bind 'alt-A:transform:[[ ! $FZF_BORDER_LABEL =~ gh ]] &&
echo "reload(
eval \"\$FZF_DEFAULT_COMMAND --author @me\"
)+change-prompt:'"$issue_prompt"' --author @me ❱ " ||
[[ ! $FZF_QUERY =~ author:@me ]] && echo "put( author:@me)"
' \
--bind 'alt-m:transform:[[ ! $FZF_BORDER_LABEL =~ gh ]] &&
echo "reload(
eval \"\$FZF_DEFAULT_COMMAND --mention @me\"
)+change-prompt:'"$issue_prompt"' --mention @me ❱ " ||
[[ ! $FZF_QUERY =~ mention:@me ]] && echo "put( mention:@me)"
' \
--bind 'alt-s:transform:if [[ ! $FZF_BORDER_LABEL =~ gh ]]; then
echo "reload(
eval \"\$FZF_DEFAULT_COMMAND --state all\"
)+change-prompt:'"$issue_prompt"' --state all ❱ "
else
[[ ! $FZF_QUERY =~ state:open ]] && act="put( state:open)"
[[ ! $FZF_QUERY =~ state:closed ]] && act="${act:+$act+}put( state:closed)"
echo "$act"
fi'

#2}}}
}
Expand All @@ -276,6 +337,8 @@ $global_binds
# COMMAND > PR {{{1

pr_cmd() {
# make sure state from the previous execution is destroyed
rm -f /tmp/gh-fzf-pr-*
# GO TEMPLATE {{{2
pr_template='\
--json "number,title,state,headRefName,milestone,updatedAt,labels,additions,deletions,changedFiles,isDraft" \
Expand Down Expand Up @@ -329,13 +392,38 @@ Filters > (alt-a: assignee) (alt-A: author) (alt-b: branch) (alt-s: state=all)
$global_binds

"
# INITIAL STATE {{{2
pr_command="GH_FORCE_TTY=$GH_COLUMNS gh pr list $pr_template -L $GH_FZF_DEFAULT_LIMIT"
pr_prompt="pr${*:+ $*}"

# FZF COMMAND {{{2
FZF_DEFAULT_COMMAND="GH_FORCE_TTY=$GH_COLUMNS gh pr list $pr_template -L $GH_FZF_DEFAULT_LIMIT $*" \
FZF_DEFAULT_COMMAND="$pr_command $*" \
fzf \
--preview='GH_FORCE_TTY=$((FZF_PREVIEW_COLUMNS-3)) gh pr view {1} --comments' \
--prompt="pr ❱ " \
--header="$pr_header" \
--bind="start:${GH_FZF_HIDE_HINTS:+"toggle-header"}" \
--prompt="$pr_prompt ❱ " \
--border="bottom" \
--border-label="[mode: fzf] " \
--border-label-pos=-99999 \
--bind="start:unbind:change${GH_FZF_HIDE_HINTS:+"+toggle-header"}" \
--bind "change:reload-sync:sleep 0.5; $pr_command $* \${FZF_QUERY:+-S {q}} || true" \
--bind 'alt-/:transform:
[[ ! $FZF_BORDER_LABEL =~ gh ]] &&
echo "rebind(change)+change-border-label([mode: gh] )+disable-search+transform-query(
echo \{q} > ${TMPDIR:-/tmp}/gh-fzf-pr-query-fzf;
cat ${TMPDIR:-/tmp}/gh-fzf-pr-query-gh
)+change-prompt('"$pr_prompt"' ❱ )+reload-sync(
$FZF_DEFAULT_COMMAND ${FZF_QUERY:+-S {q}} || true
)" ||
echo "unbind(change)+change-border-label([mode: fzf] )+enable-search+transform-query(
echo \{q} > ${TMPDIR:-/tmp}/gh-fzf-pr-query-gh;
cat ${TMPDIR:-/tmp}/gh-fzf-pr-query-fzf
)"
' \
--bind='ctrl-r:change-prompt('"$pr_prompt"' ❱ )+execute-silent(
rm -f ${TMPDIR:-/tmp}/gh-fzf-pr-query-*
)+clear-query+first+reload(eval "$FZF_DEFAULT_COMMAND")' \
--bind="ctrl-o:execute-silent(gh pr view --web {1} &)+refresh-preview" \
--bind="ctrl-y:execute-silent(gh fzf util copy-url pr {1})+refresh-preview" \
--bind="alt-y:execute-silent(
Expand All @@ -355,11 +443,35 @@ $global_binds
--bind="alt-M:execute(gh pr merge {1})+refresh-preview" \
--bind="alt-O:execute(gh pr reopen {1})+refresh-preview" \
--bind="alt-X:execute(gh pr close {1})+refresh-preview" \
--bind='alt-a:reload(eval "$FZF_DEFAULT_COMMAND --assignee @me")' \
--bind='alt-A:reload(eval "$FZF_DEFAULT_COMMAND --author @me")' \
--bind='alt-s:reload(eval "$FZF_DEFAULT_COMMAND --state all")' \
--bind='alt-b:reload(eval "$FZF_DEFAULT_COMMAND --head \
$(git symbolic-ref --short HEAD)")'
--bind 'alt-a:transform:[[ ! $FZF_BORDER_LABEL =~ gh ]] &&
echo "reload(
eval \"\$FZF_DEFAULT_COMMAND --assignee @me\"
)+change-prompt:'"$pr_prompt"' --assignee @me ❱ " ||
[[ ! $FZF_QUERY =~ assignee:@me ]] && echo "put( assignee:@me)"
' \
--bind 'alt-A:transform:[[ ! $FZF_BORDER_LABEL =~ gh ]] &&
echo "reload(
eval \"\$FZF_DEFAULT_COMMAND --author @me\"
)+change-prompt:'"$pr_prompt"' --author @me ❱ " ||
[[ ! $FZF_QUERY =~ author:@me ]] && echo "put( author:@me)"
' \
--bind 'alt-b:transform:
branch="$(git symbolic-ref --short HEAD)";
[[ ! $FZF_BORDER_LABEL =~ gh ]] &&
echo "reload(
eval \"\$FZF_DEFAULT_COMMAND --head $branch\"
)+change-prompt:'"$pr_prompt"' --head $branch ❱ " ||
[[ ! $FZF_QUERY =~ head:$branch ]] && echo "put( head:$branch)"
' \
--bind 'alt-s:transform:if [[ ! $FZF_BORDER_LABEL =~ gh ]]; then
echo "reload(
eval \"\$FZF_DEFAULT_COMMAND --state all\"
)+change-prompt:'"$pr_prompt"' --state all ❱ "
else
[[ ! $FZF_QUERY =~ state:open ]] && act="put( state:open)"
[[ ! $FZF_QUERY =~ state:closed ]] && act="${act:+$act+}put( state:closed)"
echo "$act"
fi'

#2}}}
}
Expand Down Expand Up @@ -901,7 +1013,7 @@ copy_url() {

case $1 in
issue | pr | run | release | repo)
gh $1 view --json 'url' -q '.url' $2 $REPO_FLAG | $GH_FZF_COPY_CMD
gh $1 view --json 'url' -q '.url' $2 | $GH_FZF_COPY_CMD
;;
*)
error "invalid command: \"$1\"" \
Expand Down Expand Up @@ -1047,25 +1159,55 @@ find_repo_flag() {

# ENTRY FUNCTION {{{2
main() {
requires_version "0.45.0"

command="$1"
[ -n "$command" ] && shift || default_cmd

find_repo_flag "$@"

case $command in
h | -h | help | --help) help_cmd "$@" ;;
i | -i | issue | issues | --issue | --issues) issue_cmd "$@" ;;
p | -p | pr | prs | --pr | --prs) pr_cmd "$@" ;;
r | -r | run | runs | --run | --runs) run_cmd "$@" ;;
repo | repos | --repo | --repos) repo_cmd "$@" ;;
release | releases | --release | --releases) release_cmd "$@" ;;
gist | gists | --gist | --gists) gist_cmd "$@" ;;
workflow | workflows | --workflow | --workflows) workflow_cmd "$@" ;;
label | labels | --label | --labels) label_cmd "$@" ;;
milestone | milestones | --milestone | --milestones) milestone_cmd "$@" ;;
util | utils | --util | --utils) util_cmd "$@" ;;
status) github_status ;;
changelog) gh fzf release --repo benelan/gh-fzf ;;
h | -h | help | --help)
help_cmd "$@"
;;
i | -i | issue | issues | --issue | --issues)
requires_version "0.49.0"
issue_cmd "$@"
;;
p | -p | pr | prs | --pr | --prs)
requires_version "0.49.0"
pr_cmd "$@"
;;
r | -r | run | runs | --run | --runs)
run_cmd "$@"
;;
repo | repos | --repo | --repos)
repo_cmd "$@"
;;
release | releases | --release | --releases)
release_cmd "$@"
;;
gist | gists | --gist | --gists)
gist_cmd "$@"
;;
workflow | workflows | --workflow | --workflows)
workflow_cmd "$@"
;;
label | labels | --label | --labels)
label_cmd "$@"
;;
milestone | milestones | --milestone | --milestones)
milestone_cmd "$@"
;;
util | utils | --util | --utils)
util_cmd "$@"
;;
changelog)
gh fzf release --repo benelan/gh-fzf
;;
status)
github_status
;;
upgrade)
latest_version=$(gh release view --json tagName --jq .tagName --repo benelan/gh-fzf)
if [ "$(version_number "$latest_version")" -gt "$(version_number "$GH_FZF_VERSION")" ]; then
Expand All @@ -1075,8 +1217,12 @@ main() {
echo "You are up to date!"
fi
;;
v | V | -v | -V | version | --version) printf "%s\n" "$GH_FZF_VERSION" ;;
*) error "invalid command: \"$command\"" ;;
v | V | -v | -V | version | --version)
printf "%s\n" "$GH_FZF_VERSION"
;;
*)
error "invalid command: \"$command\""
;;
esac
} #2}}}

Expand Down