diff --git a/vim9script.md b/vim9script.md new file mode 100644 index 00000000..183e43a7 --- /dev/null +++ b/vim9script.md @@ -0,0 +1,443 @@ +--- +name: Vim9script +filename: learn9vimscript.vim +contributors: + - ["HiPhish", "http://hiphish.github.io/"] +--- + +```vim +# ############## +# Introduction +# ############## + +# Vim9 script is a modernized version of Vim's scripting language, offering features like variables, functions, and loops. +# Accoding to `:help vim9-differences`, the principal differences from legacy Vim script are as follows: +# +# - Comments start with #, not ": > +# echo "hello" # comment +# - Using a backslash for line continuation is hardly ever needed: > +# echo "hello " +# .. yourName +# .. ", how are you?" +# - White space is required in many places to improve readability. +# - Assign values without `:let` *E1126* , declare variables with `:var`: > +# var count = 0 +# count += 3 +# - Constants can be declared with `:final` and `:const`: > +# final matches = [] # add to the list later +# const names = ['Betty', 'Peter'] # cannot be changed +# - `:final` cannot be used as an abbreviation of `:finally`. +# - Variables and functions are script-local by default. +# - Functions are declared with argument types and return type: > +# def CallMe(count: number, message: string): bool +# - Call functions without `:call`: > +# writefile(['done'], 'file.txt') +# - You cannot use old Ex commands: +# `:Print` +# `:append` +# `:change` +# `:d` directly followed by 'd' or 'p'. +# `:insert` +# `:k` +# `:mode` +# `:open` +# `:s` with only flags +# `:t` +# `:xit` +# - Some commands, especially those used for flow control, cannot be shortened. +# E.g., `:throw` cannot be written as `:th`. *vim9-no-shorten* +# - You cannot use curly-braces names. +# - A range before a command must be prefixed with a colon: > +# :%s/this/that +# - Executing a register with "@r" does not work, you can prepend a colon or use +# `:exe`: > +# :exe @a +# - Unless mentioned specifically, the highest |scriptversion| is used. +# - When defining an expression mapping, the expression will be evaluated in the +# context of the script where it was defined. +# - When indexing a string the index is counted in characters, not bytes: +# |vim9-string-index| +# - Some possibly unexpected differences: |vim9-gotchas|. +# +# You can run Vim9 script commands in command-line mode or write them to a file and source it in Vim. +# This guide assumes familiarity with ex-commands and focuses on scripting. + +# Comments start with # +# The vertical line '|' separates commands +echo 'Hello' | echo 'world!' + +# Putting a comment after a command usually works +pwd # Displays the current working directory + +# Line continuation is rarely needed +echo "Hello " + .. "world" + +echo [1, 2] + +echo { + 'a': 1, + 'b': 2 +} + +# ####### +# Types +# ####### + +# Numbers +echo 123 # Decimal +echo 0b1111011 # Binary +echo 0173 # Octal +echo 0x7B # Hexadecimal +echo 123.0 # Floating-point +echo 1.23e2 # Floating-point (scientific notation) + +# Booleans +echo true # Evaluates to true +echo false # Evaluates to false + +# Boolean values from comparison +echo x == y # Equality by value +echo x != y # Inequality +echo x > y # Greater than +echo x >= y # Greater than or equal +echo x < y # Smaller than +echo x <= y # Smaller than or equal +echo x is y # Instance identity +echo x isnot y # Instance non-identity + +# Strings +echo 'a' < 'B' # True or false depending on 'ignorecase' +echo 'a' x * x} # Anonymous function + +# Regular expression +substitute/hello/Hello/ + +# ########################### +# Implicit type conversions +# ########################### + +echo "1" + 1 # Number +echo "1" .. 1 # String +echo "0xA" + 1 # Number + +# ########### +# Variables +# ########### + +var b:my_var = 1 # Local to current buffer +var w:my_var = 1 # Local to current window +var t:my_var = 1 # Local to current tab page +var g:my_var = 1 # Global variable + +# Access special Vim memory like variables +var @a = 'Hello' # Register +var $PATH='' # Environment variable +var &textwidth = 79 # Option +var &l:textwidth = 79 # Local option +var &g:textwidth = 79 # Global option + +# Access scopes as dictionaries +echo b: # All buffer variables +echo w: # All window variables +echo t: # All tab page variables +echo g: # All global variables +echo v: # All Vim variables + +# Constant variables +const x = 10 # Constant + +# Function reference variables +var IsString = {x -> type(x) == type('')} # Global +var isNumber = {x -> type(x) == type(0)} # Local + +# Multiple value binding +var [x, y] = [1, 2] + +# Assign the remainder to a rest variable +var [mother, father; children] = ['Alice', 'Bob', 'Carol', 'Dennis', 'Emily'] + +# ############## +# Flow control +# ############## + +# Conditional +var condition = true + +if condition + echo 'First condition' +elseif another_condition + echo 'Second condition' +else + echo 'Fail' +endif + +# Loops + +# For-loop +for person in ['Alice', 'Bob', 'Carol', 'Dennis', 'Emily'] + echo 'Hello ' .. person +endfor + +# Iterate over a nested list +for [x, y] in [[1, 0], [0, 1], [-1, 0], [0, -1]] + echo 'Position: x =' .. x .. ', y = ' .. y +endfor + +# Iterate over a range of numbers +for i in range(10, 0, -1) + echo 'T minus' .. i +endfor + +# Iterate over the keys of a dictionary +for symbol in keys({'π': 3.14, 'e': 2.71}) + echo 'The constant ' .. symbol .. ' is a transcendent number' +endfor + +# Iterate over the values of a dictionary +for value in values({'π': 3.14, 'e': 2.71}) + echo 'The value ' .. value .. ' approximates a transcendent number' +endfor + +# Iterate over the keys and values of a dictionary +for [symbol, value] in items({'π': 3.14, 'e': 2.71}) + echo 'The number ' .. symbol .. ' is approximately ' .. value +endfor + +# While-loops +var there_yet = true +while !there_yet + echo 'Are we there yet?' +endwhile + +# Exception handling +try + source path/to/file +catch /Cannot open/ + echo 'Looks like that file does not exist' +catch /.*/ + echo 'Something went wrong, but I do not know what' +finally + echo 'I am done trying' +endtry + +# ########## +# Functions +# ########## + +# Defining functions +def AddNumbersLoudly(x: number, y: number): number + echo 'Adding' .. x .. 'and' .. y + return x + y +enddef + +def s:addNumbersLoudly(x: number, y: number): number + echo 'Adding' .. x .. 'and' .. y + return x + y +enddef + +# Range functions +def FirstAndLastLine() range + echo [a:firstline, a:lastline] +enddef + +# Aborting functions +def SourceMyFile() abort + source my-file.vim + echo 'This will never be printed' +enddef + +# Closures +def MakeAdder(x: number) + def Adder(n: number) closure + return n + x + enddef + return funcref('Adder') +enddef +var AddFive = MakeAdder(5) +echo AddFive(3) # Prints 8 + +# Dictionary functions +def Mylen() dict + return len(self.data) +enddef +var mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")} +echo mydict.len() + +# Alternatively, more concise +var mydict = {'data': [0, 1, 2, 3]} +def mydict.len() + return len(self.data) +enddef + +# Calling functions +var animals = keys({'cow': 'moo', 'dog': 'woof', 'cat': 'meow'}) + +# Call a function for its side effects only +call sign_undefine() + +# The call() function +echo call(function('get'), [{'a': 1, 'b': 2}, 'c', 3]) # Prints 3 + +# Function namespaces +def foo#bar#log(value: string) + echomsg value +enddef + +call foo#bar#log('Hello') + +# ############################# +# Frequently used ex-commands +# ############################# + +# Sourcing runtime files +runtime plugin/my-plugin.vim + +# Defining new ex-commands +command! SwapAdjacentLines normal! ddp + +command! -nargs=1 Error echoerr + +# Defining auto-commands +autocmd BufWritePost $MYVIMRC source $MYVIMRC + +# Auto groups +augroup auto-source + autocmd! + autocmd BufWritePost $MYVIMRC source $MYVIMRC +augroup END + +# Executing +var line = 3 +execute line .. 'delete' + +# Executing normal-mode commands +normal! ggddGp + +# Window commands +wincmd L + +# ########################### +# Frequently used functions +# ########################### + +# Feature check +echo has('nvim') +echo has('python3') +echo has('unix') +echo has('win32') + +# Test if something exists +echo exists('&mouse') +echo exists('+mouse') +echo exists('$HOSTNAME') +echo exists('*strftime') +echo exists('**s:MyFunc') +echo exists('bufcount') +echo exists('my_dict["foo"]') +echo exists(':Make') +echo exists("#CursorHold") +echo exists("#BufReadPre#*.gz") +echo exists("#filetypeindent") +echo exists("##ColorScheme") + +# Various dynamic values +echo expand('%') +echo expand('') +echo expand('%:p') + +# Type tests +echo type(my_var) == v:t_number +echo type(my_var) == v:t_string +echo type(my_var) == v:t_func +echo type(my_var) == v:t_list +echo type(my_var) == v:t_dict +echo type(my_var) == v:t_float +echo type(my_var) == v:t_bool +echo my_var is v:null + +# Format strings +echo printf('%d in hexadecimal is %X', 123, 123) + +# ##################### +# Tricks of the trade +# ##################### + +# Source guard +if exists('g:loaded_my_plugin') + finish +endif +var g_loaded_my_plugin = true + +# Default values +var greeting = get(g:, 'my_plugin_greeting', 'Hello') +```