Skip to content

Integrating Other CLI apps

Girish Kumar edited this page Sep 12, 2020 · 3 revisions

Below a screen cast demonstrating a workflow all in one pane. This is an alternative to existing integrations shipped with kakoune (like ranger), that open tools is separate panes. This workflow translates very well to using multiple kakoune clients, as you're merely toggling the external tool in whichever client you have focused.

asciicast

Below is the generalized command suspend-and-resume that makes this possible. It backgrounds the currently focused kakoune client, launchs a cli process of your choosing, and has kakoune resume automatically on exit of said process (optionally doing any follow up work afterwards):

def suspend-and-resume \
    -params 1..2 \
    -docstring 'suspend-and-resume <cli command> [<kak command after resume>]: backgrounds current kakoune client and runs specified cli command.  Upon exit of command the optional kak command is executed.' \
    %{ evaluate-commands %sh{

    # Note we are adding '&& fg' which resumes the kakoune client process after the cli command exits
    cli_cmd="$1 && fg"
    post_resume_cmd="$2"

    # automation is different platform to platform
    platform=$(uname -s)
    case $platform in
        Darwin)
            automate_cmd="sleep 0.01; osascript -e 'tell application \"System Events\" to keystroke \"$cli_cmd\" & return '"
            kill_cmd="/bin/kill"
            break
            ;;
        Linux)
            automate_cmd="sleep 0.2; xdotool type '$cli_cmd'; xdotool key Return"
            kill_cmd="/usr/bin/kill"
            break
            ;;
    esac

    # Uses platforms automation to schedule the typing of our cli command
    nohup sh -c "$automate_cmd"  > /dev/null 2>&1 &
    # Send kakoune client to the background
    $kill_cmd -SIGTSTP $kak_client_pid

    # ...At this point the kakoune client is paused until the " && fg " gets run in the $automate_cmd

    # Upon resume, run the kak command is specified
    if [ ! -z "$post_resume_cmd" ]; then
        echo "$post_resume_cmd"
    fi
}}

One important caveat for this workflow is that your kakoune client needs to be running within an interactive shell process (otherwise backgrounding/foregrounding the kakoune process can't work). Kakoune's existing terminal integrations launch skip the interactive shell when making a new pane/window/tab, and therefore won't be compatible with this technique.

Example Integrations with suspend-and-resume

tig

This adds a user mode specific to tig, enabling quick access to blame, status, and main views (many more are possible).

def tig-blame -override -docstring 'Open blame in tig for current file and line' %{
    # Note here we aren't passing any command on resume of kakoune
    suspend-and-resume "tig blame +%val{cursor_line} %val{buffile}" 
}

declare-user-mode tig
map global tig b ': tig-blame<ret>' -docstring 'show blame (with tig)'
map global tig s ': suspend-and-resume "tig status"<ret>' -docstring 'show git status (with tig)'
map global tig m ': suspend-and-resume "tig"<ret>' -docstring 'show main view (with tig)'

map global user t ': enter-user-mode tig<ret>' -docstring 'tig commands'

ranger

def for-each-line \
    -docstring "for-each-line <command> <path to file>: run command with the value of each line in the file" \
    -params 2 \
    %{ evaluate-commands %sh{

    while read f; do
        printf "$1 $f\n"
    done < "$2"
}}

def toggle-ranger %{
    suspend-and-resume \
        "ranger --choosefiles=/tmp/ranger-files-%val{client_pid}" \
        "for-each-line edit /tmp/ranger-files-%val{client_pid}"
}

map global user r ': toggle-ranger<ret>' -docstring 'select files in ranger'
Clone this wiki locally