Add interfacing.asciidoc describing how to interact with external programs
This commit is contained in:
parent
6cb8d69d29
commit
0be8566dd7
123
doc/interfacing.asciidoc
Normal file
123
doc/interfacing.asciidoc
Normal file
|
@ -0,0 +1,123 @@
|
|||
Interfacing Kakoune with external programs
|
||||
==========================================
|
||||
|
||||
In order to interact with the external world, Kakoune uses the shell, mainly
|
||||
through the +%sh{ ... }+ string type, and it's 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 status line using:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
:echo %sh{ date }
|
||||
----
|
||||
|
||||
For asynchrounous operations, the kakoune unix stream socket can be used. This
|
||||
is the same socket that kakoune clients connect to. It is available in the
|
||||
+kak_socket+ environment variable.
|
||||
|
||||
For example, we can echo a message in kakoune in 10 seconds with:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
:nop %sh{ (
|
||||
sleep 10
|
||||
echo "eval -client '$kak_client' 'echo sleep ended'" |
|
||||
socat stdin UNIX-CONNECT:${kak_socket}
|
||||
) >& /dev/null < /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
|
||||
it's +-client+ option to send commands to a specific client.
|
||||
* For the command to run asynchrounously, we wrap it in a subshell
|
||||
with parenthesis, redirect it's +std{in,err,out}+ to +/dev/null+, and
|
||||
run it in background with +&+. Using this pattern, the shell does
|
||||
not wait for this subshell to finish before quitting.
|
||||
|
||||
Interactive output
|
||||
------------------
|
||||
|
||||
It is a frequent interaction mode to run a program and display it's output
|
||||
in a kakoune buffer.
|
||||
|
||||
The common pattern to do that is to use a fifo buffer:
|
||||
|
||||
[source,bash]
|
||||
-----
|
||||
%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 < /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 exemple, most of the time, the echo command will as
|
||||
well contains
|
||||
|
||||
-----
|
||||
setb filetype <...>
|
||||
-----
|
||||
|
||||
and some hooks for this filetype will have been written
|
||||
|
||||
Completion candidates
|
||||
---------------------
|
||||
|
||||
Most of the time, filetype specific completion should be provided by
|
||||
external programs.
|
||||
|
||||
external completions are provided using the +completions+ option, which
|
||||
have the following format.
|
||||
|
||||
----
|
||||
line:column[+len]@timestamp;candidate1;candidate2;...
|
||||
----
|
||||
|
||||
the first element of this string list specify where and when this completions
|
||||
applies, the others are simply completion candidates.
|
||||
|
||||
As a completion program may take some time to compute the candidates, it should
|
||||
run asynchrounously. In order to do that, the following pattern may be used:
|
||||
|
||||
[source,bash]
|
||||
-----
|
||||
# Declare the option which will store the temporary filename
|
||||
decl str plugin_filename
|
||||
%sh{
|
||||
# ask kakoune to write current buffer to temporary file
|
||||
filename=$(mktemp -t kak-temp.XXXXXXXX)
|
||||
echo "setb plugin_filename '$filename'
|
||||
write '$filename'"
|
||||
}
|
||||
# End the %sh{} so that it's 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 an put output in semicolon separated format
|
||||
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 "setb -buffer '${kak_bufname}' completions '$completions'" |
|
||||
socat stdin UNIX-SOCKET:${kak_socket}
|
||||
) >& /dev/null < /dev/null & }
|
||||
-----
|
Loading…
Reference in New Issue
Block a user