24 Feb 2023I needed to define a custom completion function to suggest files when typing vfa <TAB>
. vfa
is my alias around git-file-add
. I needed it to suggest modified/added files.
Telling zsh about the completion function
I started by telling zsh which completion method to call when completion git-file-add
with this code:
compdef _git-files-dirty git-file-add
The convention in zsh is that completion methods should start with _
, hence the _git-files-dirty
. I didn't name if _git-file-add
, because I wanted the name to reflect what it displayed, not the method it was completing
Weaving it together
I created a _.git-files-dirty
in my custom zsh config ./config/zsh/completion/compdef
directory.
I also need to tell zsh about this path, by adding it to its fpath
.
Note that the order here is important:
- Add the folder to
fpath
- Run
compinit
- Call
compdef
Writing the completion function
The _git-files-dirty
file must follow a strict convention for zsh to pick it up.
- It must start with
#compdef
on its first line - It must contain a function named
_git-files-dirty
The core of the function itself is free form, the important thing it need to do is build an array of the suggestions and store it in a variable
Once the array if built, it must call _describe -V "Header name" {variableName}
.
Note that it should not pass the variable directly (using $
), but actually passing the name of the variable.
The -V
forces the suggestions to be displayed in the exact order they are saved in the array (otherwise they are alphabetically sorted).
07 Feb 2023Some of my vimscripts need to call external commands, through the shell CLI. I learned some quirks the hard way, and documenting them here
The basics
Calling an external command is done through system('external-command')
. If you need to pass arguments you must wrap them in shellescape(myArgument)
or it will mess up spaces and quotes.
The quirks
If you echom
the result and see it through :messages
, you might see some ^@
weird characters. Those are how vim displays new lines, but not how they are encoded in the result.
To split the result on new lines, you should run split(myResult, "\n")
and not split(myResult, '^@')
.
07 Feb 2023Vimscript Array
s are called List
s. They have a set of rules and functions that I'll document here for my own reference:
Basics
- They are defined with
let myArray=['one', 'two', 'three']
- They are zero-indexed:
echo myArray[0]
is one
- They can be accessed from the end
echo myArray[-1]
is three
Functions
add(myArray, 'four')
adds a new elements. myArray+=['four']
also worksget(myArray, 0, 'default value')
reads a value, with a fallbacklen(myArray)
returns 3
index(myArray, 'three')
returns 2
(or -1
if not found)join(myArray, '/')
returns one/two/three
split('one/two/three', '/')
creates ['one', 'two', 'three']
Source
06 Feb 2023I had a commandOptions
string variable that I wanted to use as arguments to fzf
. But commandOptions
had all kind of spaces and quoted strings in it and I had a hard time passing it as a set of distinct arguments and not one long string argument.
The best solution I found was to actually display this commandOptions
in a multiline format, where each line was an option. Then, using the ${(f)commandOptions}
modifier to read it.
get_options
#!/usr/bin/env zsh
local commandOptions=()
commandOptions+="--disabled"
commandOptions+="--delimiter= "
commandOptions+="--with-nth=3"
commandOptions+="--bind=change:reload:sleep 0.1;${sourceBinary} {q} || true"
for line in $commandOptions; do
echo $line
done
use_options
#!/usr/bin/env zsh
local myOptions="$(get_options)"
local selection="$(fzf ${(f)myOptions})"
03 Feb 2023Given an array with a lot of values, I want to keep only one occurence of each value. I want to make those values unique.
The (u)
modifier
local myArray=(a b c d a b b)
echo ${(u)myArray} # a b c d
Applied on an array, the (u)
(for u
nique) deduplicates the array.
The typeset -aU
definition
Somehow, I didn't work in my case and I'm still unsure why, so I found another way.
By defining my variable as an array with unique values from the get go, I don't need to deduplicate it manually, it will automatically refuse duplicate values.
typeset -aU myArray
local myArray=(a b c d a b b)
echo ${(u)myArray} # a b c d