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
02 Feb 2023Another one of those things I need to often do in zsh and never remember the syntax.
I had a multiline string (as returned by fzf
) and wanted to convert it into a single line, with spaces instead of spaces.
This was the right formula: selection=("${(f)selection}")
02 Feb 2023I had a large chunk of text (output from another command), and needed to perform a search and replace on it. I usually do that either with zsh builting ${var:gs/x/y/}
syntax or sed
, but this time my pattern was spread on several lines.
Multi-line with --null-data
The trick here is to use sed ---null-data
to make it operate on the full text instead of on invidual lines. Technically, it now considers a "line" to end with a NUL
character, and not a \n
anymore.
Improve readability with --regexp-extended
To improve readability of my regexps, I also used --regexp-extended
which allows me to write capturing groups without having to escape them ((.*)
instead of \(.*\)
).
Non-greedy
sed
does not have a non-greedy mode, which means it will always capture the largest group it can.
The way to work around that involves writing a slightly more complex regexp by specifically defining the one character we don't want to capture.
For example with the string foo_bar_baz
, I might want to find the part before the first _
by doing ^(.*)_
. This will actually return foo_bar
because it's greedy.
The way to work around that is to use ^([^_]*)_
instead. This can be read as: capture everything that is not a _
from the start until you met a _
.