1. Overview

One of the reasons most power users prefer Vim is its extensibility through Vim Script, a scripting language specifically designed for customizing and enhancing Vim’s functionality. With the release of Vim 9, a major upgrade to the editor, there are significant changes to the Vim Script language.

In this tutorial, we’ll explore how to upgrade our old Vim Script code to the newer Vim 9 Script. We’ll discuss the major constructs that we usually use in our Vim configuration, such as comments, variables, dictionaries, and functions.

2. What Is Vim Script?

Vim Script is a powerful scripting language designed explicitly for the Vim text editor. It allows users to automate tasks, customize the editor’s behavior, and extend its functionality. Vim Script makes it possible to create macros, define custom commands, and configure various aspects of Vim’s behavior.

Vim Script has evolved over time through continuous community contributions. It has grown in functionality and flexibility, accommodating user needs and incorporating new features.

3. Vim 9 Script

In this section, we’ll go over the new features and key changes available in Vim 9 Script that we can utilize in the .vimrc file.

3.1. Comments

In Vim 9 Script, we can comment out the lines using Bash-like comments that are prefixed with the # character. Prior to that, we’d use a double quote to comment out a line:

" A comment before Vim 9 Script

Here’s the new syntax in Vim 9 Script:

# A comment in Vim 9 Script

3.2. Variables

In Vim 9 Script, variables are declared using the var keyword instead of the let:g and let:b prefixes for global and buffer-local variables, respectively.

Prior to Vim 9 Script, variable declarations look like:

let g:nerdtree_open=false
let b:words_count=0
let words_count+=1

We notice that there are no spaces to the left and right of the assignment operator. Apart from that, we rewrote the let keyword again for incrementing the words_count variable.

However, this is not the case in Vim 9 Script. We can upgrade the above code to the new Vim 9 Script like so:

g:nerdtree_open = false
var words_count = 0
a += 1

Here, we see that for the global variable, we omit the let keyword entirely. In contrast, we initialized the non-global variable words_count to 0. In the final statement, we don’t need the var or let keyword, so we omitted that.

One more thing to notice is that the spaces around the = operator are now required in Vim 9 Script.

3.3. Dictionaries

Dictionaries in Vim 9 Script have a simplified syntax and no longer require the line continuation character \ for multiline dictionaries. So, if we have an older .vimrc file, a dictionary inside it will look like this:

g:golang_opts = {
  \'format_buffer': false,
  \'remove_unused_imports': true,
  \}

In Vim 9, we can write the same dictionary in a neat way:

g:golang_opts = {
  'format_buffer': false,
  'remove_unused_imports': true,
}

3.4. Functions

Functions in Vim 9 Script have undergone significant changes. Instead of using the function keyword, we can now define functions using the def keyword. Additionally, Vim 9 Script also introduced return and argument types for functions.

Prior to Vim 9 Script, a function would look like this:

function! AutoSave(message)
  if &modified
    silent! write
    echo a:message
  endif
endfunction

augroup AutoSaveGroup
  autocmd!
  autocmd CursorHold * call AutoSave("File saved.")
augroup END

The function saves a file and writes the message passed to it as an argument. In Vim 9, we replace the function! and endfunction keywords with def and enddef:

def AutoSave(message: string)
  if &modified
    silent! write
    echo message
  endif
enddef

augroup AutoSaveGroup
  autocmd!
  autocmd CursorHold * AutoSave("File saved.")
augroup END

In addition, we also omit the a: prefix from the variable, and we can call the function without the call keyword.

Notably, the use of the function and func keyword is still allowed if preferred. However, it might deprecate in the future, so it’s best to avoid it altogether.

3.5. Lambdas

Vim 9 introduces lambdas, which allow us to define anonymous functions. Lambdas are useful for one-time or ad hoc operations that don’t require a separate named function.

Here is an example of a lambda function in Vim 9 Script:

let nums = [1, 2, 3, 4, 5]
let nums_squared = map(nums, {n -> n * n})

Let’s break it down:

  • we declared nums that contain integer values.
  • we created a new array nums_squared where each number is squared
  • the map() function is used to iterate over each element of the nums array that is passed as an argument
  • the second argument to map() specifies a lambda that accepts n  as the input parameter
  • the lambda returns the value of n * n

As we can see, it makes the code much more concise and readable.

3.6. Variable-Length Arguments

In Vim 9 Script, we can define functions that accept a variable number of arguments using the “…” syntax. This can come in handy when we need to handle functions with a flexible number of parameters.

As an example, we’ll write a function that reverses words passed to it:

def ReverseWords(...) abort
  let reversed_words = []
  for word in a:000
    let reversed_word = strrev(word)
    add(reversed_words, reversed_word)
  endfor
  return reversed_words
enddef

In this function, the accepted input parameter is ““, which signifies that it accepts variable-length arguments. Then, we created a new empty array that will hold the reversed words.

In the for loop, we iterate through items of the a:000. a:000 is a special variable that represents the variable list of arguments passed to a function. We grab each word from a:000, reverse it and append it to reversed_words.

4. Conclusion

In this article, we learned how to upgrade an older Vim Script code to the newer Vim 9 Script. We saw how Vim 9 Script format could bring the benefits of improved features and enhancements to our existing Vim Script code.

By following the guidelines in the article as a reference, we can smoothly transition our existing Vim configuration files to a newer version.