Search code examples
shellzshprompt

Send zsh prompt to program and replace content with result


I would like to send my prompt contents to my snippets application and replace the line with the result:

Example initial prompt:

$ while foo bar

Example replaced prompt:

$ while foo ; do bar ; done

Having the first prompt I would run a shortcut and replace the line with the value returned by the program.

I imagine the solution would be something like this:

bindkey "^y" evaluateSnippets
evaluateSnippets() {
    return mySnippetsTool <<< "$promptLine"
}

How can I accomplish that in zsh?

A further correlated question is if it is possible to replace just the selected part of the prompt in another shortcut.


Solution

  • evaluate-snippets () {
        BUFFER=$(mySnippetsTool <<< $BUFFER)
    }
    zle -N evaluate-snippets
    bindkey '^Y' evaluate-snippets
    

    Within widgets (aka the functions behind the key bindings) the content of the edit buffer is contained in the parameter BUFFER. The edit buffer can also be modified by writing to BUFFER. So saving the output of mySnippetsTool in BUFFER should be enough. The command zle -N foo creates a widget named foo, which runs the function fo the same name when called.

    As you can manipulate the contents of BUFFER in any way you want, it is also possible to modify only parts of it. The main caveat here is that the selection has to be done from withing the shell - e.g. visual-mode (v) with the vicmd keybindings or set-mark-command (Control+@) with the emacs keybindings - and (probably) cannot be done with the mouse. For example:

    evaluate-snippets-selection () {
        if [[ $CURSOR -gt $MARK ]]; then
            start=$MARK
            end=$(( CURSOR + 1 ))
        else
            start=$(( CURSOR + 1 ))
            end=$MARK
        fi
        BUFFER="$BUFFER[0,start]$(mySnippetsTool <<< $BUFFER[start+1,end])$BUFFER[end+1,-1]"
    }
    zle -N evaluate-snippets-selection
    bindkey '^Z' evaluate-snippets-selection
    

    (Note: some fine-tuning for the indices and ranges might be necessary in order to match the expectation of what is currently selected. For example whether the current cursor position is part of the selection or not.)

    You might not even need separate commands. As long as you did not set a mark and the cursor is at the very end of the line, both commands should deliver the same results.