# Writing Scripts

**URL:** <https://discuss.kakoune.com/t/writing-scripts/535>\
**Category:** Manual++\
**Created:** [May 8, 2019, 2:11am UTC](https://discuss.kakoune.com/t/writing-scripts/535 "2019-05-08T02:11:42Z")\
**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:11am UTC](https://discuss.kakoune.com/t/writing-scripts/535/1 "2019-05-08T02:11:42Z")

</div>

Interaction with external tools from a Kakoune session is supported  
through the use of scripts. Once loaded by the editor (either  
automatically or manually), they allow extending the functionalities  
provided by default through commands and hooks.

Their implementation should be kept as simple as possible, as they are  
not meant to be generic tools themselves but a mere API to actual  
software.

```
                                               +------+
                                          +--> | tmux |
                                          | +------+
                                          |
        +---------+ | +------+
        | Kakoune | <-------> scripts +-+--> | X11 |
        +---------+ | +------+
                                          |
                                          | +------+
                                          +--> | ... |
                                               +------+

```

# Dependencies

The amount of dependencies of a given script should be kept to a minimum  
for practicality reasons, and have to be reasonable and expected  
considering the purpose of the script itself.

Examples:

- the `clang.kak` script provides with code completion using the  
`clang` compiler

- the `tmux.kak` script provides with terminal splitting using the  
`tmux` multiplexer

- the `ctags.kak` script provides with symbol lookups using the  
`readtags` utility provided by some `ctags` implementations

# Naming convention

All options and commands declared in a Kakoune script have to be  
prefixed with the name of the script, or a one word description of the  
purpose of the script.

Examples:

- in `tmux.kak`: command `tmux-new-window`

- in `comment.kak`: option `comment_line`

The following conventions apply as well:

- **options** : if a separator is needed to separate a multiple word  
option name, an underscore should be used to allow shell scopes to  
use them

- **commands** : if a separator is needed, a hyphen is usually used to  
differentiate a command name from an option’s

# Documentation

Non-hidden commands and options should always be declared with a  
documentation string, so that their purpose is clearly described  
whenever completed upon interactively from the prompt.

# POSIX shell

Shell expansions are a useful tool to interact with an external utility,  
and the shell code that they contain should be as portable as possible.  
As such, scripts that rely on those expansions have to be implemented  
with POSIX in mind, most shells follow this standard nowadays which  
somewhat guarantees that the script will be portable across the most  
common systems.

# Common shell patterns

## Printing variables

In order to print a string that contains a variable expansion, prefer  
`printf` to `echo`, as the latter is implementation defined and may  
interpret some characters differently depending on the shell (e.g.  
flags, backslashes).

```
        printf %s\\n "${var}"
        printf "value: %s\\n" "${var}"

```

The following won’t cause any issues, as the string to print doesn’t  
contain ambiguous characters:

```
        echo "set global scrolloff 999,0"

```

## Variable base name

Replace `$(basename "${var}")` with `"${var##*/}"`.

## Testing

The `[[` keyword is provided by `bash`, and should be replaced with `[`.

## Standard error redirection

Redirecting both standard and error streams is simplified in the `bash`  
shell with the `&>` operator, however this syntax is not portable and  
has to be replaced with the following: `>/dev/null 2>&1`.

## Regular expression

The `bash` shell provides with a `[[` keyword that supports the `=~`  
operator to match a regular expression against a variable. This  
functionality can be implemented with the `expr` utility:

- `expr "${var}" : '[a-z]*' >/dev/null` returns successfully when the  
variable is empty or only contains lowercase characters, otherwise a  
non-zero exit code is returned

- `expr "${var}" : '\([a-z]*\)'` prints the variable when empty or  
only contains lowercase characters

Note that the regular expression matches the whole string, using the `^`  
and `$` anchors is an undefined behavior.

## Running a process in the background

In order to get a process running in the background without having it  
quit when the shell scope that spawns it terminates, use the following  
syntax:

```
        {
            command
        } </dev/null >/dev/null 2>&1 &
```

---

<div class="post-metadata">

**Author:** ![scr](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/scr/32/486_2.png) [@scr](https://discuss.kakoune.com/u/scr)\
**Post date:** [October 4, 2020, 10:33am UTC](https://discuss.kakoune.com/t/writing-scripts/535/2 "2020-10-04T10:33:44Z")

</div>

I don’t know if this belong here but could you give an example on how to use `kak -p` ?  
I tried  
`kak -s myses`  
and in another terminal  
`echo 'ihello' | kak -p myses`  
and also  
`echo "execute-keys 'ihello' " | kak -p myses`  
Expecting to write “hello” in my buffer but nothing happend.  
Am I using it right ?

---

<div class="post-metadata">

**Author:** ![scr](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/scr/32/486_2.png) [@scr](https://discuss.kakoune.com/u/scr)\
**Post date:** [October 4, 2020, 11:04am UTC](https://discuss.kakoune.com/t/writing-scripts/535/3 "2020-10-04T11:04:46Z")

</div>

Ok I got it.  
You need to use the `-client` option like so:

`echo "execute-keys -client $client_id 'ihello' " | kak -p myses`

---

<div class="post-metadata">

**Author:** ![Screwtapello](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/screwtapello/32/12_2.png) [@Screwtapello](https://discuss.kakoune.com/u/Screwtapello)\
**Post date:** [October 4, 2020, 11:12am UTC](https://discuss.kakoune.com/t/writing-scripts/535/4 "2020-10-04T11:12:35Z")

</div>

If you just want to modify the buffer and don’t want to mess with the client’s state (like whether it’s in insert mode, etc.) you could also do something like:

```
echo "execute-keys -buffer /path/to/file 'ihello'" | kak -p myses

```

The documentation describes `-buffer` as “run in a disposable context for each given buffer”, where “context” includes things like “are we in insert mode” and “where is the cursor”.

---

<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 17, 2021, 12:29pm UTC](https://discuss.kakoune.com/t/writing-scripts/535/5 "2021-09-17T12:29:01Z")

</div>

Theme song it:

Punk D 2005, Technologic, Human After All, Spotify, Youtube, viewed 17 September,

- [https://open.spotify.com/track/1iNeZGJsoC0D7ZyJTdIbDS?si=173b163b3b514ef5](https://open.spotify.com/track/1iNeZGJsoC0D7ZyJTdIbDS?si=173b163b3b514ef5)
- [https://youtu.be/D8K90hX4PrE](https://youtu.be/D8K90hX4PrE)

* * *

# Writing kak scripts

A Kakoune session supports interaction with external tools through the use of  
scripts. As they’re a mere API to software, keep their implementation as simple  
as possible. Once loaded either automatically or manually by the editor, they  
allow extending software functionalities through commands and hooks.

```plaintext
	                                       +------+
	                                  +--> | tmux |
	                                  | +------+
	                                  |
	+---------+ | +------+
	| Kakoune | <-------> scripts +-+--> | X11 |
	+---------+ | +------+
	                                  |
	                                  | +------+
	                                  +--> | ... |
	                                       +------+

```

## Dependencies

Minimise third party dependencies within kak scripts for practical reasons and  
ensure correlation to the script itself.

Examples:

- the `clang.kak` script provides with code completion using the `clang`  
compiler

- the `tmux.kak` script provides with terminal splitting using the  
`tmux` multiplexer

- the `ctags.kak` script provides with symbol lookups using the  
`readtags` utility provided by some `ctags` implementations

## Naming conventions

Declare options and commands in kakoune script with a prefix of the script name  
or a one word purpose description of the script.

Examples:

- in `tmux.kak`: command `tmux-new-window`

- in `comment.kak`: option `comment_line`

Apply the following conventions:

- _options_: use underscores to separate multiple word option names, this  
allows shell scopes to use them.

- _commands_: use hyphens to differentiate a command name from an option’s.

## Documentation

Declare non-hidden commands and options with a documentation string, to  
describe clearly their purpose upon interactive completion from the prompt.

```bash
declare-option -docstring "run shell command to look for a given pattern" str ag_menu_cmd "ag --all-text --vimgrep"

define-command -params 1.. -file-completion \
    -docstring %{ag-menu <pattern> [targets]: search one or more targets for a given pattern} \
    ag-menu %{ evaluate-commands %sh{
        readonly PATTERN="$1"
        shift
        eval "${kak_opt_ag_menu_cmd}" "${PATTERN}" -- "$@" | awk "
            /^[^:]*:[0-9]*:[0-9]*:/ {
                # escape all simple quotes
                gsub(/'/, \"''\")
                # gather filename and coordinates into an array
                split(\$0, s, \":\")
                # remove the coordinates information from the matched line
                sub(\"^[^:]*:[0-9]*:[0-9]*:\", \"\")
                # strip the matched line
                sub(\"^[\t]*|[\t]*\$\", \"\")

                candidates = candidates \" \" \"'\" s[1] \":\" s[2] \":\" s[3] \" \" \$0 \"' ' edit! %{\" s[1] \"} \" s[2] \" \" s[3] \"'\"
            }

            END {
                if (length(candidates))
                    print \"menu\" candidates
            }
        "
} }

map -docstring "ag-menu | pattern match on word(s) in target directory" global user g ': ag-menu '
# source edited: grepmenu.kak by lenormf

```

## POSIX shell

Shell expansions benefit interactions with external utilities. For portability  
most scripts on common systems need to implement with POSIX in mind, with most  
shells conforming to this standard, a script that relies on those expansions  
need be mindful of inconsistencies.

## Common shell patterns

#### Printing variables

To print strings which contain a variable expansion, prefer `printf` to `echo`,  
as the latter is implementation defined and may interpret some characters  
differently depending on the shell (e.g. flags, backslashes).

```bash
	printf %s\\n "${var}"
	printf "value: %s\\n" "${var}"

```

The following snippet prints the string as there are no ambiguous characters:

```bash
	echo "set global scrolloff 999,0"

```

For more information about portability issues with `echo`, refer to [Rich’s sh tricks](https://www.etalabs.net/sh_tricks.html).

#### Variable base name

Replace `$(basename "${var}")+ with +"${var##*/}"`.

#### Testing

The `[[` keyword is provided by `bash`, replace with `[` for the shell.

#### Standard error redirection

Redirecting both standard and error streams is simplified in the `bash` shell  
with the `&>` operator. This syntax isn’t portable and has to be replaced with  
the following: `>/dev/null 2>&1`. See the [Illustrated Redirection Tutorial](https://wiki.bash-hackers.org/howto/redirection_tutorial)  
for more information.

#### Regular expression

The +bash+ shell provides a `[[` keyword that supports the `=~`  
operator to match a regular expression against a variable. This  
functionality can be implemented with the `expr` utility:

- `expr "${var}" : '[a-z]*' >/dev/null` returns successfully when the  
variable is empty or only contains lower case characters, otherwise a  
non-zero exit code is returned

- `expr "${var}" : '\([a-z]*\)'` prints the variable when empty or  
only contains lower case characters

Note that the regular expression matches the whole string, using the `^`  
and `$` anchors is an undefined behaviour.

#### Running a process in the background

To get a process running in the background without having it quit when the  
shell scope that spawns it terminates, use the following syntax with braces for  
a mulitline commands:

```bash
{
    command
    command
} </dev/null >/dev/null 2>&1 &

```

With commands on a single-line use parentheses:

```bash
( command ) </dev/null >/dev/null 2>&1 &

```
