# Interfacing

**URL:** <https://discuss.kakoune.com/t/interfacing/533>\
**Category:** Manual++\
**Created:** [May 8, 2019, 2:10am UTC](https://discuss.kakoune.com/t/interfacing/533 "2019-05-08T02:10:40Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![robertmeta](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/robertmeta/32/833_2.png) [@robertmeta](https://discuss.kakoune.com/u/robertmeta)\
**Post date:** [May 8, 2019, 2:10am UTC](https://discuss.kakoune.com/t/interfacing/533/1 "2019-05-08T02:10:40Z")

</div>

In order to interact with the external world, Kakoune uses the shell,  
mainly through the `%sh{ … }` string type, and its control socket.

# Basic interaction

For synchronous operations, `%sh{ … }` blocks are easy to use, they  
behave similarly to `$( … )` shell construct.

For example, one can echo the current time in Kakoune’s status line  
using:

```
:echo %sh{ date }

```

For asynchronous operations, the Kakoune Unix stream socket can be used.  
This is the same socket that Kakoune clients connect to. It is available  
through the `kak_session` environment variable: the socket is

For example, we can echo a message in Kakoune in 10 seconds with:

```
:nop %sh{ {
    sleep 10
    echo "eval -client '$kak_client' 'echo sleep ended'" |
        kak -p ${kak_session}
} > /dev/null 2>&1 < /dev/null & }

```

- The `nop` command is used so that any eventual output from the  
`%sh{ … }` is not interpreted by Kakoune

- When writing to the socket, Kakoune has no way to guess in which  
client’s context the command should be evaluated. A temporary  
context is used, which does not have any user interface, so if we  
want to interact with the user, we need to use the `eval` command,  
with its `-client` option to send commands to a specific client.

- For the command to run asynchronously, we wrap it in a sub shell  
with braces, redirect its `std{in,err,out}` to `/dev/null`, and run  
it in background with `&`. Using this pattern, the shell does not  
wait for this sub shell to finish before quitting.

# Interactive output

It is a frequent interaction mode to run a program and display its  
output in a Kakoune buffer.

The common pattern to do that is to use a fifo buffer:

```
evaluate-commands %sh{
     # Create a temporary fifo for communication
     output=$(mktemp -d -t kak-temp-XXXXXXXX)/fifo
     mkfifo ${output}
     # run command detached from the shell
     { run command here > ${output} } > /dev/null 2>&1 < /dev/null &
     # Open the file in Kakoune and add a hook to remove the fifo
     echo "edit! -fifo ${output} *buffer-name*
           hook buffer BufClose .* %{ nop %sh{ rm -r $(dirname ${output})} }"
}

```

This is a very simple example, most of the time, the echo command will  
as well contain

```
set buffer filetype <...>

```

and some hooks for this filetype will have been written

# Completion candidates

Filetype specific completion should be provided by external programs.

External completions are provided using an option to store completion,  
which have the following format.

```
line.column[+len]@timestamp candidate1|select1|menu1 candidate2|select2|menu2 ...

```

the first element of this string list specify where and when this  
completion applies, the others are a triplet  
`<completion text>|<select cmd>|<menu text>`

The select command is executed whenever this menu item gets selected,  
and is usually used to display an item specific documentation with  
`info -placement menu '<menu item description>'`

The menu text is a markup string (see [`:doc faces markup-strings`](https://discuss.kakoune.com/t/faces/541#markup-strings)), so it can contain `{face}`  
directives.

To effectively use that completion option, it should get added to the  
completers option.

— set -add buffer completers option=my\_option\_name —

As a completion program may take some time to compute the candidates, it  
should run asynchronously. In order to do that, the following pattern  
may be used:

```
# Declare the option which will store the temporary filename
decl str plugin_filename
# Declare the completion option
decl completions plugin_completions
# Add plugin_completions to completers for files of good filetype
hook global BufSetOption filetype=my_filetype %{
    set -add buffer completers option=plugin_completions
}
evaluate-commands %sh{
    # ask Kakoune to write current buffer to temporary file
    filename=$(mktemp -t kak-temp.XXXXXXXX)
    echo "set buffer plugin_filename '$filename'
          write '$filename'"
}
# End the %sh{} so that its output gets executed by Kakoune.
# Use a nop so that any eventual output of this %sh does not get interpreted.
nop %sh{ { # launch a detached shell
    buffer="${kak_opt_plugin_filename}"
    line="${kak_cursor_line}"
    column="${kak_cursor_column}"
    # run completer program and format the output in a list of completions
    candidates=$(completer $buffer $line $column | completer_filter)
    # remove temporary file
    rm $buffer
    # generate completion option value
    completions="$line.$column@$kak_timestamp $candidates"
    # write to Kakoune socket for the buffer that triggered the completion
    echo "set buffer=${kak_bufname} plugin_completions $completions" |
        kak -p ${kak_session}
} > /dev/null 2>&1 < /dev/null & }
```

---

<div class="post-metadata">

**Author:** ![schickm](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/schickm/32/79_2.png) [@schickm](https://discuss.kakoune.com/u/schickm)\
**Post date:** [March 18, 2021, 5:08pm UTC](https://discuss.kakoune.com/t/interfacing/533/2 "2021-03-18T17:08:14Z")

</div>

> [@robertmeta](#):
>
> ```auto
> # run command detached from the shell
> { run command here > ${output} } > /dev/null 2>&1 < /dev/null &
> 
> ```

I was getting a shell error until I changed the “run command” part quoted above to be wrapped with parenthesis rather then curly braces:

```auto
# run command detached from the shell
     ( run command here > ${output} ) > /dev/null 2>&1 < /dev/null &

```

Not sure why…but just wanted to note that here for others. Thanks for the great walkthrough @robertmeta - that was so helpful for a first timer trying to integrate some long running processes into my workflows in kakoune!

---

<div class="post-metadata">

**Author:** ![alexherbo2](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/alexherbo2/32/1140_2.png) [@alexherbo2](https://discuss.kakoune.com/u/alexherbo2)\
**Post date:** [March 19, 2021, 1:21am UTC](https://discuss.kakoune.com/t/interfacing/533/3 "2021-03-19T01:21:13Z")

</div>

With curly braces, the command needs to end with a semicolon if on a single line.

Curly braces cause the commands to be grouped and parentheses to run in a subshell.

---

<div class="post-metadata">

**Author:** ![schickm](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/schickm/32/79_2.png) [@schickm](https://discuss.kakoune.com/u/schickm)\
**Post date:** [March 19, 2021, 3:46am UTC](https://discuss.kakoune.com/t/interfacing/533/4 "2021-03-19T03:46:48Z")

</div>

Thank you!

@robertmeta you probably want to update your example above so shell-newbs like myself don’t get sidetracked by that.

---

<div class="post-metadata">

**Author:** ![duncan](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/duncan/32/95_2.png) [@duncan](https://discuss.kakoune.com/u/duncan)\
**Post date:** [September 15, 2021, 4:41pm UTC](https://discuss.kakoune.com/t/interfacing/533/5 "2021-09-15T16:41:40Z")

</div>

More refactoring @robertmeta and took into account the comments left by @schickm and @alexherbo2 (bullet point three). Cool guys, as always let me know of any improvements that can be made.

* * *

# Interfacing with external programs

Kakoune interfaces mainly through `%sh{ ... }` blocks using string types, and  
its control socket by invoking the [shell](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html).

## Basic interaction

Synchronous operations: `%sh{ ... }` blocks are easy to use, they behave  
similarly to `$( ... )` shell construct.

For example, one can `echo` the current time on Kakoune’s status line using:

```bash
:echo %sh{ date }

```

Asynchronous operations: using Kakoune Unix stream socket, clients connect to  
this socket via the environment variable `kak_session`. The socket location is  
`/tmp/kakoune/${username}/${kak_session}`

To illustrate, we can `echo` a message to Kakoune in 10 seconds with:

```bash
:nop %sh{ {
    sleep 10
    echo "eval -client '$kak_client' 'echo sleep ended'" |
        kak -p ${kak_session}
} > /dev/null 2>&1 < /dev/null & }

```

- Use the `nop` command so any output from the `%sh{ ... }` isn’t interpreted by Kakoune.
- When writing to the socket, Kakoune uses a temporary context which doesn’t  
have a user interface. So, user interaction is via the `eval` command, with its  
`-client` option to send commands to a specific client.
- First, the command runs asynchronously in a sub shell when wrapping the  
command in parentheses for a single line or braces in a multiline scenario.  
Second, it inherits a file descriptor via redirection through `std {in,err,out}`  
to `/dev/null`. Lastly, conclude with the `&` to run the command as a background  
process. Using this pattern allows for shell termination before sub-shell  
completion.

## Interactive output

Kakoune provides buffers for frequent user interaction to display a program’s  
output. The `fifo` buffer is a common pattern to use:

```bash
evaluate-commands %sh{
     # Create a temporary fifo for communication
     output=$(mktemp -d -t kak-temp-XXXXXXXX)/fifo
     mkfifo ${output}
     # run command detached from the shell
     ( run command here > ${output} ) > /dev/null 2>&1 < /dev/null &
     # Open the file in Kakoune and add a hook to remove the fifo
     echo "edit! -fifo ${output} *buffer-name*
           hook buffer BufClose .* %{ nop %sh{ rm -r $(dirname ${output})} }"
}

```

This is a very simple example, frequently the `echo` command will contain:

```bash
set buffer filetype <...>

```

with `hook`’s written for filetypes:

```bash
hook global BufSetOption filetype=(asciidoc|latex|markdown) %{
    set-option buffer formatcmd "par 102f"
    alias buffer fs format-selections
}

```

## Completion candidates

Kakoune will interface with external programs to provide filetype completion.  
The option to store completion candidates has the following format:

```auto
line.column[+len]@timestamp candidate1|select1|menu1 candidate2|select2|menu2 ...

```

The first element of this string list specifies where and when this completion  
applies, the others are `<completion text>|<select cmd>|<menu item>`.

Selection of the menu item executes the select command and can display item  
documentation with `info -placement menu '<menu item description>'`. The menu  
items text markup string (see `:doc faces markup-strings`)  
can contain `{face}` directives.

Add completion candidates to the completers option for effective use.

```bash
set -add buffer completers option=my_option_name

```

A completion program may take some time to compute the candidates, it should run  
asynchronously. To do that, use the following pattern:

```bash
# Declare the option which will store the temporary filename
decl str plugin_filename
# Declare the completion option
decl completions plugin_completions
# Add plugin_completions to completers for files
hook global BufSetOption filetype=my_filetype %{
    set -add buffer completers option=plugin_completions
}
evaluate-commands %sh{
    # ask Kakoune to write current buffer to temporary file
    filename=$(mktemp -t kak-temp.XXXXXXXX)
    echo "set buffer plugin_filename '$filename'
          write '$filename'"
}
# End the %sh{} so that its output gets executed by Kakoune.
# Use a nop so that any eventual output of this %sh does not get interpreted.
nop %sh{ { # launch a detached shell
    buffer="${kak_opt_plugin_filename}"
    line="${kak_cursor_line}"
    column="${kak_cursor_column}"
    # run completer program and format the output in a list of completions
    candidates=$(completer $buffer $line $column | completer_filter)
    # remove temporary file
    rm $buffer
    # generate completion option value
    completions="$line.$column@$kak_timestamp $candidates"
    # write to Kakoune socket for the buffer that triggered the completion
    echo "set buffer=${kak_bufname} plugin_completions $completions" |
        kak -p ${kak_session}
} > /dev/null 2>&1 < /dev/null & }

```
