-
-
Save noahmayr/ed545a6bcd7c27d19dab1b629af0d144 to your computer and use it in GitHub Desktop.
| #!/bin/sh | |
| ### CONFIG ### | |
| changeIdColumn="2" | |
| commitIdColumn="3" | |
| nodeTypes="@○◆•" | |
| delimiterPattern='((?:^[^ ] +)|[^[:alnum:]:.])+' | |
| defaultLogArgs="" | |
| copyStdinToClipboard="pbcopy" | |
| ### END CONFIG ### | |
| # need to export this so all subshells created by fzf are also going to use sh and the correct PATH env var | |
| export SHELL=/bin/sh | |
| export PATH="$PATH" | |
| command="jj --color=always" | |
| ignoreWcCommand="$command --ignore-working-copy" | |
| baseLogCommand="$ignoreWcCommand log" | |
| reload="toggle-preview+reload($baseLogCommand)+toggle-preview" | |
| loadObsLog="reload($ignoreWcCommand obslog -r {$changeIdColumn})" | |
| previewCommand="$ignoreWcCommand show --color-words {$commitIdColumn}" | |
| selectedOrFocusedRevset="echo {+$commitIdColumn} | tr '[:blank:]' '|'" | |
| pipeToPager="2>&1 | less -KR > /dev/tty" | |
| logCommand="if [ -z \"\$FZF_BORDER_LABEL\" ]; then $baseLogCommand $defaultLogArgs; else $baseLogCommand -r \"\$FZF_BORDER_LABEL\"; fi" | |
| reloadLog="reload($logCommand)+first" | |
| rebaseCommand="$selectedOrFocusedRevset | xargs -I% $command rebase" | |
| help=$'### NORMAL MODE ### | |
| [q] Quit | |
| [i] Enter revset query mode | |
| [o] Enter obslog mode for focused revision | |
| [esc] Reload | |
| [enter] Print selected change ids to stdout | |
| [u] Undo | |
| [s] Status | |
| [e] Edit focused | |
| [n] New with selected parents | |
| [d] Describe focused | |
| [a] Abandon selected | |
| [U] Rebase selected on trunk | |
| [f] Fetch | |
| [S] Sync | |
| [r] Set selected as parents of @ | |
| [p] Add selected as parents of @ | |
| [P] Remove selected as parents of @ | |
| [c] Copy change id | |
| [C] Copy commit id | |
| [space] Show change in detail | |
| (i) "selected" falls back to whichever revision is focused if there is no selection | |
| ### REVSET QUERY MODE ### | |
| [esc] Go back to normal mode | |
| [enter] search for revset, invalid queries will result in empty log (pressing enter with empty query will restore default query) | |
| ### OBSLOG MODE ### | |
| [esc] Go back to normal mode | |
| [space] Show commit in detail | |
| [c] Copy change id | |
| [C] Copy commit id | |
| [enter] Print selected commit ids to stdout | |
| ' | |
| normal_header='Press ? for help, q to quit' | |
| revset_header='Press ? for help, ctrl+c to quit' | |
| obslog_header='Press ? for help, q to quit' | |
| $baseLogCommand | | |
| fzf --ansi --exact --reverse --no-sort --tiebreak=index --border --no-info --multi --phony --no-mouse --prompt "normal" \ | |
| --delimiter "$delimiterPattern" \ | |
| --header 'Press ? for help, ctrl+q to quit' \ | |
| --preview "$previewCommand" \ | |
| --height 100% --preview-window right \ | |
| --bind "esc:change-prompt(normal)+rebind(u,S,e,n,d,a,U,f,s,r,p,p,i,o,space,y,Y,q,?)+$reloadLog" \ | |
| --bind "change:transform:[[ \$FZF_PROMPT ~= 'revset: ' ]] && echo 'clear-query'" \ | |
| --bind "?:execute(echo '$help' $pipeToPager)" \ | |
| --bind "u:execute($command undo $pipeToPager)+$reloadLog" \ | |
| --bind "s:execute($command status $pipeToPager)+$reloadLog" \ | |
| --bind "e:execute($command edit {$commitIdColumn} $pipeToPager)+$reloadLog" \ | |
| --bind "n:execute($command new {+$commitIdColumn} $pipeToPager)+$reloadLog" \ | |
| --bind "d:execute($command describe {$commitIdColumn} > /dev/tty)+$reloadLog" \ | |
| --bind "a:execute($command abandon {$commitIdColumn} $pipeToPager)+$reloadLog" \ | |
| --bind "U:execute($rebaseCommand -b 'all:%' -d 'trunk()' $pipeToPager)+$reloadLog" \ | |
| --bind "f:execute($command git fetch $pipeToPager)+$reloadLog" \ | |
| --bind "S:execute($command git push $pipeToPager)+$reloadLog" \ | |
| --bind "r:execute($rebaseCommand -r @ -d 'all:%' $pipeToPager)+$reloadLog" \ | |
| --bind "p:execute($rebaseCommand -r @ -d 'all:@- | %' $pipeToPager)+$reloadLog" \ | |
| --bind "P:execute($rebaseCommand -r @ -d 'all:@- & ~%' $pipeToPager)+$reloadLog" \ | |
| --bind "y:execute-silent(echo {$changeIdColumn} | $copyStdinToClipboard)" \ | |
| --bind "Y:execute-silent(echo {$commitIdColumn} | $copyStdinToClipboard)" \ | |
| --bind "q:abort" \ | |
| --bind "space:execute($command show --ignore-working-copy {$commitIdColumn} $pipeToPager)" \ | |
| --bind "o:change-prompt(obslog)+unbind(u,S,e,n,d,a,U,f,s,r,p,p,i,o)+rebind(?,space,y,Y,q)+$loadObsLog+first" \ | |
| --bind "i:change-prompt(revset: )+unbind(u,S,e,n,d,a,U,f,s,r,p,p,i,o,space,y,Y,q)+rebind(?)+$reloadLog" \ | |
| --bind "enter:transform:if [ \"\$FZF_PROMPT\" = 'revset: ' ]; then echo 'transform-border-label(echo \"\$FZF_QUERY\")+clear-query+$reloadLog'; elif [ \$FZF_PROMPT = 'normal' ]; then echo 'become(echo {+$changeIdColumn})'; else echo 'become(echo {+$commitIdColumn})'; fi" \ | |
| --bind "focus:transform:echo {} | grep -q '[$nodeTypes]' && exit || test {fzf:action} = up && echo up || echo down" |
The base of primitives here is excellent. Thanks so much!
I took most of the primitives here, kept my original idea of eval()-ing the query, and made the bindings more vimmish (i learned you could do this using change:clear-query + binding to single keys). The result is a huge QoL improvement for me, because I get to keep all of the Emacs-style keybindings to edit the query + I like single key bindings anyway.
#... config and variables
becomeNormal="change-prompt(NORMAL MODE: )+rebind(change,i,j,k,n,E,A,d,U,O,y,Y,space)+unbind(enter)"
becomeInsert="change-prompt(INSERT MODE: )+unbind(change,i,j,k,n,E,A,d,U,O,y,Y,space)+rebind(enter)"
eval $baseLogCommand |
fzf --ansi --exact --reverse --no-sort --no-info --phony --prompt "NORMAL MODE: " \
--delimiter "$delimiterPattern" \
--header 'Press ? for help, ctrl+q to quit' \
--preview "$command --ignore-working-copy show --color-words {$commitIdColumn}" \
--height 100% --preview-window right \
--bind "change:clear-query" \
--bind "j:down" \
--bind "k:up" \
--bind "n:execute-silent($command new {+$commitIdColumn})+$reloadLog" \
--bind "E:execute-silent($command edit {+$commitIdColumn})+$reloadLog" \
--bind "A:execute-silent($command abandon {+$commitIdColumn})+$reloadLog" \
--bind "d:execute-silent($command describe {+$commitIdColumn})+$reloadLog" \
--bind "U:execute-silent($command undo)+$reloadLog" \
--bind "space:execute($command show --ignore-working-copy {$commitIdColumn} | $pipeToPager)" \
--bind "O:change-prompt(OBSLOG MODE)+$loadObsLog+first" \
--bind "y:execute-silent(echo -n {$changeIdColumn} | $copyStdinToClipboard)" \
--bind "Y:execute-silent(echo -n {$commitIdColumn} | $copyStdinToClipboard)" \
--bind "enter:execute(eval {q})+$becomeNormal+$reload" \
--bind "esc:$becomeNormal+$reload" \
--bind "i:$becomeInsert" \
--bind "start:$becomeNormal"
I'll probably post something somewhere sometime.
Updated this one to be more vimlike as well, you can enter revset mode by pressing i, entering a revset and submitting it with enter, the revset is then persisted in the FZF_BORDER_LABEL and can be cleared again by pressing enter with an empty query in revset mode.
obslog is also a separate mode with only a subset of keybinds supported.
I'm thinking about also adding a command mode for your eval needs
notes:
alt-c/alt-pwhich is alsoç/πon my keyboard)builtin_change_id_with_hidden_and_divergent_infoto achieve this. Play around with the columns in the config until the correct one is extracted:transformto all of them to prevent them from working in that mode