From 1a21aa6e77e6d20c0666a3adb08f1302dba25405 Mon Sep 17 00:00:00 2001 From: Damien Dart Date: Thu, 2 May 2024 23:44:21 +0100 Subject: [PATCH] Replace "fuzzy-snippets.vim". - Replace the Vimscript implementation of the "fuzzy-snippets" shell script with a small wrapper over the aforementioned script. - Update the "fuzzy-snippets" shell script so that it can adjust its functionality for better Vim integration. - Update the help text for "fuzzy-snippets". --- .vim/plugin/fuzzy-finders.vim | 91 ++++++++++++++++++++++++++++++++++ .vim/plugin/fuzzy-snippets.vim | 83 ------------------------------- bin/fuzzy-snippets | 80 ++++++++++++++++++++++-------- 3 files changed, 149 insertions(+), 105 deletions(-) create mode 100644 .vim/plugin/fuzzy-finders.vim delete mode 100644 .vim/plugin/fuzzy-snippets.vim diff --git a/.vim/plugin/fuzzy-finders.vim b/.vim/plugin/fuzzy-finders.vim new file mode 100644 index 0000000..9667e27 --- /dev/null +++ b/.vim/plugin/fuzzy-finders.vim @@ -0,0 +1,91 @@ +" This file was written by Damien Dart, . This is +" free and unencumbered software released into the public domain. For +" more information, please refer to the accompanying "UNLICENCE" file. + +function! s:Fuzzy(command, select_cb) abort + let l:callback = { + \ 'select_cb': a:select_cb, + \ 'filename': tempname(), + \ 'window_id': win_getid(), + \ 'winrestcmd': winrestcmd(), + \ } + + function l:callback.exit_cb(...) abort + call win_gotoid(l:self.window_id) + execute l:self.winrestcmd + + if filereadable(l:self.filename) + try + call l:self.select_cb(readfile(l:self.filename)) + catch /^Vim:Interrupt$/ + catch /E684/ + catch /E11/ + echohl ErrorMsg + echom join(split(v:exception, ':')[1:2], ':') + echohl None + return + finally + call delete(l:self.filename) + endtry + endif + + redraw! + endfunction + + execute 'botright' 20 'new' + + call term_start( + \ [ + \ &shell, + \ &shellcmdflag, + \ "TERM=xterm-color256 " . a:command . '>' . l:callback.filename + \ ], + \ { + \ 'curwin': 1, + \ 'cwd': getcwd(), + \ 'exit_cb': l:callback.exit_cb, + \ 'term_kill': 'term', + \ } + \ ) + + setlocal nospell bufhidden=wipe nobuflisted nonumber + setfiletype fuzzyfinder + startinsert +endfunction + +function! s:FuzzySnippets() abort + function! Handler(input) closure + if a:input[0] ==? 'ctrl-h' + execute "h :FS" + + return + endif + + let l:output = join(a:input[1:], "\n") + + if a:input[0] ==? 'ctrl-y' + call setreg('"', l:output) + + return + endif + + try + let l:paste = &paste + + set paste + execute "normal! a" . l:output . "\" + finally + let &paste = l:paste + endtry + endfunction + + call s:Fuzzy("fuzzy-snippets --vim", funcref("Handler")) +endfunction + +autocmd FileType fuzzyfinder let b:laststatus = &laststatus + \| set laststatus=0 noshowmode noruler + \| autocmd BufLeave set showmode ruler + \| let &laststatus = b:laststatus + \| autocmd WinLeave close! + +command! FS call s:FuzzySnippets() diff --git a/.vim/plugin/fuzzy-snippets.vim b/.vim/plugin/fuzzy-snippets.vim deleted file mode 100644 index b9b504f..0000000 --- a/.vim/plugin/fuzzy-snippets.vim +++ /dev/null @@ -1,83 +0,0 @@ -" A Vim-orientated version of "$TOOLBOX_ROOT/bin/fuzzy-snippets". -" -" For more information, see "$TOOLBOX_ROOT/.vim/doc/toolbox.txt" (or -" search for "toolbox-fuzzy" using Vim's help functionality if the help -" tags file for "toolbox.txt" has been generated). -" -" This file was written by Damien Dart, . This is -" free and unencumbered software released into the public domain. For -" more information, please refer to the accompanying "UNLICENCE" file. - -if exists('g:loaded_fuzzy_snippets') - finish -endif - -let g:fuzzy_snippets_source_command = 'fuzzy-snippets --list' -let g:loaded_fuzzy_snippets = 1 - -function! s:FuzzySnippets() abort - if !executable('fuzzy-snippets') || !executable('snippet-placeholder') || !exists('g:loaded_fzf') - throw 'FuzzySnippets requires fzf, fzf.vim, fuzzy-snippets, and snippet-placeholder' - elseif !exists('$SNIPPET_PATH') - throw 'SNIPPET_PATH environment variable not set' - endif - - let l:spec = copy(g:fzf_base_spec) - - call extend( - \ l:spec, - \ { - \ 'options': [ - \ '--border-label', 'CTRL+H: help ╱ CTRL+Y: yank ╱ ENTER: append', - \ '--border-label-pos', '-3:bottom', - \ '--delimiter', '/', - \ '--expect', 'ctrl-h,ctrl-y', - \ '--info=inline-right', - \ '--preview', g:fzf_preview_command, - \ '--prompt', '--8<-- ', - \ '--scheme', 'path', - \ '--with-nth', '-1', - \ ], - \ 'sink*': function('s:FuzzySnippetsHandler'), - \ 'source': g:fuzzy_snippets_source_command, - \ } - \ ) - - try - call fzf#run(l:spec) - " Improve the appearance of some commonly-encountered errors. - catch /E11/ - echohl ErrorMsg - echom join(split(v:exception, ':')[1:2], ':') - echohl None - return - endtry -endfunction - -function! s:FuzzySnippetsHandler(lines) abort - if a:lines[0] ==? 'ctrl-h' - execute "h :FS" - return - endif - - let l:output = system( - \ 'snippet-placeholder', - \ join(readfile(a:lines[1]), "\n") - \) - - if v:shell_error - echoerr l:output - - return - endif - - if a:lines[0] ==? 'ctrl-y' - call setreg('"', l:output) - - return - endif - - execute "normal! a" . l:output . "\" -endfunction - -command! FS call s:FuzzySnippets() diff --git a/bin/fuzzy-snippets b/bin/fuzzy-snippets index 9183298..578cea7 100755 --- a/bin/fuzzy-snippets +++ b/bin/fuzzy-snippets @@ -1,8 +1,6 @@ #!/bin/sh # -# A simple fzf-powered snippet browser and selector script. -# -# See also "$HOME/.vim/plugin/fuzzy-snippets.vim". +# A snippet browser and selector. # # This file was written by Damien Dart, . This is # free and unencumbered software released into the public domain. For @@ -12,42 +10,53 @@ set -e help() { cat << HELP -Usage: $(basename "$0") [FLAGS] [INITIAL-QUERY] +A snippet browser and selector. -Opens up a fzf-powered snippet browser. +Usage: $(basename "$0") [FLAGS] [INITIAL-QUERY] Requires fzf, ripgrep, snippet-placeholder, and xsel, and that the SNIPPET_PATH environment variable is set to a colon-seperated list of -directories containing files to use as snippets. If the GNU version of -getopt is available it will be used to parse command-line arguments, -adding support for grouped short options and other niceties. +directories containing files to use as snippets. + +Placeholder content in snippets are expanded using snippet-placeholder. +For more information, see . + +If the GNU version of getopt is available it will be used to preprocess +command-line arguments, enabling support for grouped short options and +other niceties. FLAGS: -h, --help - Displays this help text and exits. + Display this help text and exits. -l, --list - Prints out a list of available snippet files and exits. + Print out a list of available snippet files and exits. -FZF COMMANDS: + --vim + Adjust the application's functionality for better Vim integration. + For more information, search for ":FS" in Vim's help. + +ACTIONS: ENTER - Pass the selected snippet through snippet-placeholder and copy the - output to the clipboard. + Copy the selected snippet to the clipboard. + + CTRL-H + Display this help text and exits. CTRL-P - Pass the selected snippet through snippet-placeholder and print the - output to standard input. + Print the selected snippet to standard output. HELP } LIST_FILES=0 +VIM_MODE=0 # Using the GNU version of getopt to parse command-line arguments adds # support for grouped short options and other niceties. if test "$(getopt --test >/dev/null 2>&1 && echo "$?" || echo "$?")" -eq 4; then - if ! ARGS=$(getopt -l help,list -n "$(basename "$0")" -o hl -- "$@"); then + if ! ARGS=$(getopt -l help,list,vim -n "$(basename "$0")" -o hl -- "$@"); then printf 'See "%s --help" for available options\n' "$(basename "$0")" >&2 exit 2 fi @@ -57,9 +66,10 @@ fi if ! type 'fzf' 1>/dev/null 2>&1 || \ ! type 'rg' 1>/dev/null 2>&1 || \ + ! type 'snippet-placeholder' 1>/dev/null 2>&1 || \ ! type 'xsel' 1>/dev/null 2>&1; then - printf 'ERROR: "%s" requires fzf, ripgrep, and xsel\n' "$(basename "$0")" >&2 + printf 'ERROR: "%s" requires fzf, ripgrep, snippet-placeholder, and xsel\n' "$(basename "$0")" >&2 exit 2 fi @@ -82,6 +92,10 @@ while :; do shift break ;; + --vim) + VIM_MODE=1 + shift + ;; --) shift break @@ -118,30 +132,52 @@ if [ "$LIST_FILES" = 1 ]; then exit fi +FZF_EXPECT='ctrl-h,ctrl-p' +FZF_LABEL='CTRL+H: Help ╱ CTRL+P: Print snippet ╱ ENTER: Copy snippet' + +if [ "$VIM_MODE" = 1 ]; then + FZF_EXPECT='ctrl-h,ctrl-y' + FZF_LABEL='CTRL+H: help ╱ CTRL+Y: yank ╱ ENTER: insert' +fi + # CTRL+Z process suspension is suppressed as it doesn't work properly # (see ). FZF_OUTPUT=$(\ echo "$SNIPPET_FILES" | sort | fzf \ --bind='ctrl-z:ignore' \ + --border-label="$FZF_LABEL" \ + --border-label-pos='-3:bottom' \ --delimiter='/' \ - --expect='ctrl-p' \ - --header='CTRL+P: Print snippet ╱ ENTER: Copy snippet' \ - --with-nth='-1' \ + --expect="$FZF_EXPECT" \ + --info='inline-right' \ --preview='cat {} 2>/dev/null' \ --prompt='--%<-- ' \ --query="$1" \ --scheme='path' \ + --with-nth='-1' \ ) SELECTED_ACTION=$(echo "$FZF_OUTPUT" | head -1) SELECTED_FILE=$(echo "$FZF_OUTPUT" | tail -1) case $SELECTED_ACTION in + ctrl-h) + if [ "$VIM_MODE" = 1 ]; then + echo "$SELECTED_ACTION" + else + help + fi + ;; ctrl-p) snippet-placeholder "$SELECTED_FILE" ;; *) SNIPPET="$(snippet-placeholder "$SELECTED_FILE")" - printf "%s" "$SNIPPET" | xsel -i --clipboard - echo "[✔] Copied snippet \"$SELECTED_FILE\" to the clipboard!" + + if [ "$VIM_MODE" = 1 ]; then + printf "%s\n%s" "$SELECTED_ACTION" "$SNIPPET" + else + printf "%s" "$SNIPPET" | xsel -i --clipboard + echo "[✔] Copied snippet \"$SELECTED_FILE\" to the clipboard!" + fi ;; esac