Learn Vim
Ch24. Vimscript Basic Data Types
In the next few chapters, you will learn about Vimscript, Vim's built-in programming language.
When learning a new language, there are three basic elements to look for:
- Primitives
- Means of Combination
- Means of Abstraction
In this chapter, you will learn Vim's primitive data types.
Data Types
Vim has 10 different data types:
- Number
- Float
- String
- List
- Dictionary
- Special
- Funcref
- Job
- Channel
- Blob
I will cover the first six data types here. In Ch. 27, you will learn about Funcref. For more about Vim data types, check out :h variables
.
Following Along With Ex Mode
Vim technically does not have a built-in REPL, but it has a mode, Ex mode, that can be used like one. You can go to the Ex mode with Q
or gQ
. The Ex mode is like an extended command-line mode (it's like typing command-line mode commands non-stop). To quit the Ex mode, type :visual
.
You can use either :echo
or :echom
on this chapter and the subsequent Vimscript chapters to code along. They are like console.log
in JS or print
in Python. The :echo
command prints the evaluated expression you give. The :echom
command does the same, but in addition, it stores the result in the message history.
:echom "hello echo message"
You can view the message history with:
:messages
To clear your message history, run:
:messages clear
Number
Vim has 4 different number types: decimal, hexadecimal, binary, and octal. By the way, when I say number data type, often this means an integer data type. In this guide, I will use the terms number and integer interchangeably.
Decimal
You should be familiar with the decimal system. Vim accepts positive and negative decimals. 1, -1, 10, etc. In Vimscript programming, you will probably be using the decimal type most of the time.
Hexadecimal
Hexadecimals start with 0x
or 0X
. Mnemonic: Hexadecimal.
Binary
Binaries start with 0b
or 0B
. Mnemonic: Binary.
Octal
Octals start with 0
, 0o
, and 0O
. Mnemonic: Octal.
Printing Numbers
If you echo
either a hexadecimal, a binary, or an octal number, Vim automatically converts them to decimals.
:echo 42" returns 42
:echo 052" returns 42
:echo 0b101010" returns 42
:echo 0x2A" returns 42
Truthy and Falsy
In Vim, a 0 value is falsy and all non-0 values are truthy.
The following will not echo anything.
:if 0: echo "Nope":endif
However, this will:
:if 1: echo "Yes":endif
Any values other than 0 is truthy, including negative numbers. 100 is truthy. -1 is truthy.
Number Arithmetic
Numbers can be used to run arithmetic expressions:
:echo 3 + 1" returns 4
: echo 5 - 3" returns 2
:echo 2 * 2" returns 4
:echo 4 / 2" returns 2
When dividing a number with a remainder, Vim drops the remainder.
:echo 5 / 2" returns 2 instead of 2.5
To get a more accurate result, you need to use a float number.
Float
Floats are numbers with trailing decimals. There are two ways to represent floating numbers: dot point notation (like 31.4) and exponent (3.14e01). Similar to numbers, you can use positive and negative signs:
:echo +123.4" returns 123.4
:echo -1.234e2" returns -123.4
:echo 0.25" returns 0.25
:echo 2.5e-1" returns 0.25
You need to give a float a dot and trailing digits. 25e-2
(no dot) and 1234.
(has a dot, but no trailing digits) are both invalid float numbers.
Float Arithmetic
When doing an arithmetic expression between a number and a float, Vim coerces the result to a float.
:echo 5 / 2.0" returns 2.5
Float and float arithmetic gives you another float.
:echo 1.0 + 1.0" returns 2.0
String
Strings are characters surrounded by either double-quotes (""
) or single-quotes (''
). "Hello", "123", and '123.4' are examples of strings.
String Concatenation
To concatenate a string in Vim, use the .
operator.
:echo "Hello" . " world"" returns "Hello world"
String Arithmetic
When you run arithmetic operators (+ - * /
) with a number and a string, Vim coerces the string into a number.
:echo "12 donuts" + 3" returns 15
When Vim sees "12 donuts", it extracts the 12 from the string and converts it into the number 12. Then it performs addition, returning 15. For this string-to-number coercion to work, the number character needs to be the first character in the string.
The following won't work because 12 is not the first character in the string:
:echo "donuts 12" + 3" returns 3
This also won't work because an empty space is the first character of the string:
:echo " 12 donuts" + 3" returns 3
This coercion works even with two strings:
:echo "12 donuts" + "6 pastries"" returns 18
This works with any arithmetic operator, not only +
:
:echo "12 donuts" * "5 boxes"" returns 60
:echo "12 donuts" - 5" returns 7
:echo "12 donuts" / "3 people"" returns 4
A neat trick to force a string-to-number conversion is to just add 0 or multiply by 1:
:echo "12" + 0" returns 12
:echo "12" * 1" returns 12
When arithmetic is done against a float in a string, Vim treats it like an integer, not a float:
:echo "12.0 donuts" + 12" returns 24, not 24.0
Number and String Concatenation
You can coerce a number into a string with a dot operator (.
):
:echo 12 . "donuts"" returns "12donuts"
The coercion only works with number data type, not float. This won't work:
:echo 12.0 . "donuts"" does not return "12.0donuts" but throws an error
String Conditionals
Recall that 0 is falsy and all non-0 numbers are truthy. This is also true when using string as conditionals.
In the following if statement, Vim coerces "12donuts" into 12, which is truthy:
:if "12donuts": echo "Yum":endif" returns "Yum"
On the other hand, this is falsy:
:if "donuts12": echo "Nope":endif" rerturns nothing
Vim coerces "donuts12" into 0, because the first character is not a number.
Double vs Single quotes
Double quotes behave differently than single quotes. Single quotes display characters literally while double quotes accept special characters.
What are special characters? Check out the newline and double-quotes display:
:echo "hello\nworld"" returns" hello" world
:echo "hello \"world\""" returns "hello "world""
Compare that with single-quotes:
:echo 'hello\nworld'" returns 'hello\nworld'
:echo 'hello \"world\"'" returns 'hello \"world\"'
Special characters are special string characters that when escaped, behave differently. \n
acts like a newline. \"
behaves like a literal "
. For a list of other special characters, check out :h expr-quote
.
String Procedures
Let's look at some built-in string procedures.
You can get the length of a string with strlen()
.
:echo strlen("choco")" returns 5
You can convert string to a number with str2nr()
:
:echo str2nr("12donuts")" returns 12
:echo str2nr("donuts12")" returns 0
Similar to the string-to-number coercion earlier, if the number is not the first character, Vim won't catch it.
The good news is that Vim has a method that transforms a string to a float, str2float()
:
:echo str2float("12.5donuts")" returns 12.5
You can substitute a pattern in a string with the substitute()
method:
:echo substitute("sweet", "e", "o", "g")" returns "swoot"
The last parameter, "g", is the global flag. With it, Vim will substitute all matching occurrences. Without it, Vim will only substitute the first match.
:echo substitute("sweet", "e", "o", "")" returns "swoet"
The substitute command can be combined with getline()
. Recall that the function getline()
gets the text on the given line number. Suppose you have the text "chocolate donut" on line 5. You can use the procedure:
:echo substitute(getline(5), "chocolate", "glazed", "g")" returns glazed donut
There are many other string procedures. Check out :h string-functions
.
List
A Vimscript list is like an Array in Javascript or List in Python. It is an ordered sequence of items. You can mix-and-match the content with different data types:
[1,2,3]['a', 'b', 'c'][1,'a', 3.14][1,2,[3,4]]
Sublists
Vim list is zero-indexed. You can access a particular item in a list with [n]
, where n is the index.
:echo ["a", "sweet", "dessert"][0]" returns "a"
:echo ["a", "sweet", "dessert"][2]" returns "dessert"
If you go over the maximum index number, Vim will throw an error saying that the index is out of range:
:echo ["a", "sweet", "dessert"][999]" returns an error
When you go below zero, Vim will start the index from the last element. Going past the minimum index number will also throw you an error:
:echo ["a", "sweet", "dessert"][-1]" returns "dessert"
:echo ["a", "sweet", "dessert"][-3]" returns "a"
:echo ["a", "sweet", "dessert"][-999]" returns an error
You can "slice" several elements from a list with [n:m]
, where n
is the starting index and m
is the ending index.
:echo ["chocolate", "glazed", "plain", "strawberry", "lemon", "sugar", "cream"][2:4]" returns ["plain", "strawberry", "lemon"]
If you don't pass m
([n:]
), Vim will return the rest of the elements starting from the nth element. If you don't pass n
([:m]
), Vim will return the first element up to the mth element.
:echo ["chocolate", "glazed", "plain", "strawberry", "lemon", "sugar", "cream"][2:]" returns ['plain', 'strawberry', 'lemon', 'sugar', 'cream']
:echo ["chocolate", "glazed", "plain", "strawberry", "lemon", "sugar", "cream"][:4]" returns ['chocolate', 'glazed', 'plain', 'strawberry', 'lemon']
You can pass an index that exceeds the maximum items when slicing an array.
:echo ["chocolate", "glazed", "plain", "strawberry", "lemon", "sugar", "cream"][2:999]" returns ['plain', 'strawberry', 'lemon', 'sugar', 'cream']
Slicing String
You can slice and target strings just like lists:
:echo "choco"[0]" returns "c"
:echo "choco"[1:3]" returns "hoc"
:echo "choco"[:3]" returns choc
:echo "choco"[1:]" returns hoco
List Arithmetic
You can use +
to concatenate and mutate a list:
:let sweetList = ["chocolate", "strawberry"]:let sweetList += ["sugar"]:echo sweetList" returns ["chocolate", "strawberry", "sugar"]
List Functions
Let's explore Vim's built-in list functions.
To get the length of a list, use len()
:
:echo len(["chocolate", "strawberry"])" returns 2
To prepend an element to a list, you can use insert()
:
:let sweetList = ["chocolate", "strawberry"]:call insert(sweetList, "glazed")
:echo sweetList" returns ["glazed", "chocolate", "strawberry"]
You can also pass insert()
the index where you want to prepend the element to. If you want to prepend an item before the second element (index 1):
:let sweeterList = ["glazed", "chocolate", "strawberry"]:call insert(sweeterList, "cream", 1)
:echo sweeterList" returns ['glazed', 'cream', 'chocolate', 'strawberry']
To remove a list item, use remove()
. It accepts a list and the element index you want to remove.
:let sweeterList = ["glazed", "chocolate", "strawberry"]:call remove(sweeterList, 1)
:echo sweeterList" returns ['glazed', 'strawberry']
You can use map()
and filter()
on a list. To filter out element containing the phrase "choco":
:let sweeterList = ["glazed", "chocolate", "strawberry"]:call filter(sweeterList, 'v:val !~ "choco"'):echo sweeterList" returns ["glazed", "strawberry"]
:let sweetestList = ["chocolate", "glazed", "sugar"]:call map(sweetestList, 'v:val . " donut"'):echo sweetestList" returns ['chocolate donut', 'glazed donut', 'sugar donut']
The v:val
variable is a Vim special variable. It is available when iterating a list or a dictionary using map()
or filter()
. It represents each iterated item.
For more, check out :h list-functions
.
List Unpacking
You can unpack a list and assign variables to the list items:
:let favoriteFlavor = ["chocolate", "glazed", "plain"]:let [flavor1, flavor2, flavor3] = favoriteFlavor
:echo flavor1" returns "chocolate"
:echo flavor2" returns "glazed"
To assign the rest of list items, you can use ;
followed with a variable name:
:let favoriteFruits = ["apple", "banana", "lemon", "blueberry", "raspberry"]:let [fruit1, fruit2; restFruits] = favoriteFruits
:echo fruit1" returns "apple"
:echo restFruits" returns ['lemon', 'blueberry', 'raspberry']
Modifying List
You can modify a list item directly:
:let favoriteFlavor = ["chocolate", "glazed", "plain"]:let favoriteFlavor[0] = "sugar":echo favoriteFlavor" returns ['sugar', 'glazed', 'plain']
You can mutate multiple list items directly:
:let favoriteFlavor = ["chocolate", "glazed", "plain"]:let favoriteFlavor[2:] = ["strawberry", "chocolate"]:echo favoriteFlavor" returns ['chocolate', 'glazed', 'strawberry', 'chocolate']
Dictionary
A Vimscript dictionary is an associative, unordered list. A non-empty dictionary consists of at least a key-value pair.
{"breakfast": "waffles", "lunch": "pancakes"}{"meal": ["breakfast", "second breakfast", "third breakfast"]}{"dinner": 1, "dessert": 2}
A Vim dictionary data object uses string for key. If you try to use a number, Vim will coerce it into a string.
:let breakfastNo = {1: "7am", 2: "9am", "11ses": "11am"}
:echo breakfastNo" returns {'1': '7am', '2': '9am', '11ses': '11am'}
If you are too lazy to put quotes around each key, you can use the #{}
notation:
:let mealPlans = #{breakfast: "waffles", lunch: "pancakes", dinner: "donuts"}
:echo mealPlans" returns {'lunch': 'pancakes', 'breakfast': 'waffles', 'dinner': 'donuts'}
The only requirement for using the #{}
syntax is that each key must be either:
- ASCII character.
- Digit.
- An underscore (
_
). - A hyphen (
-
).
Just like list, you can use any data type as values.
:let mealPlan = {"breakfast": ["pancake", "waffle", "hash brown"], "lunch": WhatsForLunch(), "dinner": {"appetizer": "gruel", "entree": "more gruel"}}
Accessing Dictionary
To access a value from a dictionary, you can call the key with either the square brackets (['key']
) or the dot notation (.key
).
:let meal = {"breakfast": "gruel omelettes", "lunch": "gruel sandwiches", "dinner": "more gruel"}
:let breakfast = meal['breakfast']:let lunch = meal.lunch
:echo breakfast" returns "gruel omelettes"
:echo lunch" returns "gruel sandwiches"
Modifying Dictionary
You can modify or even add a dictionary content:
:let meal = {"breakfast": "gruel omelettes", "lunch": "gruel sandwiches"}
:let meal.breakfast = "breakfast tacos":let meal["lunch"] = "tacos al pastor":let meal["dinner"] = "quesadillas"
:echo meal" returns {'lunch': 'tacos al pastor', 'breakfast': 'breakfast tacos', 'dinner': 'quesadillas'}
Dictionary Functions
Let's explore some of Vim's built-in functions to handle dictionaries.
To check the length of a dictionary, use len()
.
:let mealPlans = #{breakfast: "waffles", lunch: "pancakes", dinner: "donuts"}
:echo len(meaPlans)" returns 3
To see if a dictionary contains a specific key, use has_key()
.
:let mealPlans = #{breakfast: "waffles", lunch: "pancakes", dinner: "donuts"}
:echo has_key(mealPlans, "breakfast")" returns 1
:echo has_key(mealPlans, "dessert")" returns 0
To see if a dictionary has any item, use empty()
. The empty()
procedure works with all data types: list, dictionary, string, number, float, etc.
:let mealPlans = #{breakfast: "waffles", lunch: "pancakes", dinner: "donuts"}:let noMealPlan = {}
:echo empty(noMealPlan)" returns 1
:echo empty(mealPlans)" returns 0
To remove an entry from a dictionary, use remove()
.
:let mealPlans = #{breakfast: "waffles", lunch: "pancakes", dinner: "donuts"}
:echo "removing breakfast: " . remove(mealPlans, "breakfast")" returns "removing breakfast: 'waffles'""
:echo mealPlans" returns {'lunch': 'pancakes', 'dinner': 'donuts'}
To convert a dictionary into a list of lists, use items()
:
:let mealPlans = #{breakfast: "waffles", lunch: "pancakes", dinner: "donuts"}
:echo items(mealPlans)" returns [['lunch', 'pancakes'], ['breakfast', 'waffles'], ['dinner', 'donuts']]
filter()
and map()
are also available.
:let breakfastNo = {1: "7am", 2: "9am", "11ses": "11am"}:call filter(breakfastNo, 'v:key > 1')
:echo breakfastNo" returns {'2': '9am', '11ses': '11am'}
Since a dictionary contains key-value pairs, Vim provides v:key
special variable that works similar to v:val
. When iterating through a dictionary, v:key
will hold the value of the current iterated key.
If you have a mealPlans
dictionary, you can map it using v:key
.
:let mealPlans = #{breakfast: "waffles", lunch: "pancakes", dinner: "donuts"}:call map(mealPlans, 'v:key . " and milk"')
:echo mealPlans" returns {'lunch': 'lunch and milk', 'breakfast': 'breakfast and milk', 'dinner': 'dinner and milk'}
Similarly, you can map it using v:val
:
:let mealPlans = #{breakfast: "waffles", lunch: "pancakes", dinner: "donuts"}:call map(mealPlans, 'v:val . " and milk"')
:echo mealPlans" returns {'lunch': 'pancakes and milk', 'breakfast': 'waffles and milk', 'dinner': 'donuts and milk'}
To see more dictionary functions, check out :h dict-functions
.
Special Primitives
Vim has special primitives:
v:false
v:true
v:none
v:null
By the way, v:
is Vim's built-in variable. They will be covered more in a later chapter.
In my experience, you won't use these special primitives often. If you need a truthy / falsy value, you can just use 0 (falsy) and non-0 (truthy). If you need an empty string, just use ""
. But it is still good to know, so let's quickly go over them.
True
This is equivalent to true
. It is equivalent to a number with value of non-0 . When decoding json with json_encode()
, it is interpreted as "true".
:echo json_encode({"test": v:true})" returns {"test": true}
False
This is equivalent to false
. It is equivalent to a number with value of 0. When decoding json with json_encode()
, it is interpreted as "false".
:echo json_encode({"test": v:false})" returns {"test": false}
None
It is equivalent to an empty string. When decoding json with json_encode()
, it is interpreted as an empty item (null
).
:echo json_encode({"test": v:none})" returns {"test": null}
Null
Similar to v:none
.
:echo json_encode({"test": v:null})" returns {"test": null}
Learn Data Types The Smart Way
In this chapter, you learned about Vimscript's basic data types: number, float, string, list, dictionary, and special. Learning these is the first step to start Vimscript programming.
In the next chapter, you will learn how to combine them for writing expressions like equalities, conditionals, and loops.
Edit this page on GitHub