🐍

Vim9 script for Python Developers

2021/03/11に公開

Vim9 script for Python Developers

Vim9 scriptはVim scriptとの互換をなくし変数の型縛りを導入したり、コンパイルをすることなどにより、高速化を実現した新しい処理系です。

defコマンドで定義された関数内、またはVim script内でvim9scriptコマンドを使うことで利用できます(vim9scriptコマンドの後ではfunctionコマンドは利用できません)。

この記事は、 https://gist.github.com/yegappan/16d964a37ead0979b05e655aa036cad0 の内容を元にVim(v8.2.2576 で確認(できるだけHEAD))上のVim9 scriptで動作するように改変したものです。

Vim9 scriptで動作を確認できなかったもの、まだ実装されていなものはpassと表記し、省略しています。

この記事を書くにあたって、Vim-jpの方々に助けていただきました。ありがとうございます!。


Table of Contents


Literals

Type Python Vim script
decimal (integer) -1, 0, 5 -1, 0, 5
binary (integer) 0b1011 0b1011
octal (integer) 0o477 0o477
hexadecimal (integer) 0x1AE 0x1AE
float 3.14, -1.5e2 3.14, -1.5e2
string "hello", 'world' "hello", 'world'
boolean True, False true, false (v:true, v:false)
list [], [5, 9], ['a', 'b'] [], [5, 9], ['a', 'b']
dict {}, {'idx' : 2, 'name' : 'abc'} {}, {idx : 2, name : 'abc'}
special None v:none, null (v:null)

Vim9 script (Vim script)ではintegerにあたる型はnumberです。
また、Vim9 scriptではtrue/v:trueなど両方利用できますが、trueを使う方が新しいので、そちらを使うと良いでしょう。(かなり新しいVimでないと動かなくなりますが...)

Variables

Creating a Variable

Python:

i = 10
pi = 3.1415
str = "Hello"
a, b, s = 10, 20, "sky"

Vim script:

var i = 10
var pi = 3.1415
var str = "Hello"
var [a, b, s] = [10, 20, "sky"]

Deleting a Variable

Python:

del str

Vim script:

unlet str

Here Document

Assigning multi-line values to a variable.

Python:

import textwrap
i = textwrap.dedent("""
    one
    two three
      four
    five
""".lstrip('\n')).splitlines()
# i == ['one', 'two three', '  four', 'five']

Vim script:

# Not defined

Types

Type Python Vim script
Number num = 10 var num = 10
Float f = 3.4 var f = 3.4
Booelan done = True var done = v:true
String str = "green" var str = "green"
List l = [1, 2, 3] var l = [1, 2, 3]
Dictionary d = {'a' : 5, 'b' : 6} var d = {a: 5, b: 6}

Vim9 script Types

Type example
bool true, false
number 123, -123, 0
float 3.14, -1.5e2
string "Hello, World"
blob 0zFF00ED015DAF
list<{type}> [123, 234, 345]
dict<{type}> {key1: 123, key2: 2344}
void
any 123, "Test", [123, 234]

Vim9 scriptでは型ありの変数宣言が可能です。
宣言は以下の形で行います。

var foo1: number = 123
var foo2: list<string> = ["HUGE", "HUGO"]

any型にはどの型の値も入りますが、値はanyを持ちません。

Type Conversion

Conversion Python Vim script
Number to Float float(n) floor(n)
Float to Number int(f) float2nr(f)
Number to String str(n) string(n)
String to Number int(str) str2nr(str)
Float to String str(f) string(f)
String to Float float(str) str2float(str)
List to String str(l) string(l)
String to List eval(str) eval(str)
Dict to String str(d) string(d)
String to Dict eval(str) eval(str)

Type Check

Type Python Vim script
Number isintance(x, int) type(x) == v:t_number
String isinstance(x, str) type(x) == v:t_string
List isintance(x, list) type(x) == v:t_list
Dictionary isintance(x, dict) type(x) == v:t_dict
Float isintance(x, float) type(x) == v:t_float
Boolean isinstance(x, bool) type(x) == v:t_bool

Variable Namespaces

Vim scriptでは明示しないかぎりスコープはグローバルですが、Vim9 scriptではスクリプトローカルになります。

Scope Prefix Description
g: global
l: function-local
s: script-local
a: 廃止
v: internal
b: buffer local
w: window local
t: tab local

Operators

Arithmetic Operators

What Python Vim script
addition a = 10 + 20 a = 10 + 20
subtraction a = 30 - 10 a = 30 - 10
multiplication a = 3 * 5 a = 3 * 5
division a = 22 / 7 a = 22 / 7
modulus a = 10 % 3 a = 10 % 3
exponentiation a = 2 ** 3 a = float2nr(pow(2, 3))
floor division a = 10 // 3 a = floor(10 / 3.0)

Assignment Operators

What Python Vim script
addition a += 1 a += 1
subtraction a -= 2 a -= 2
multiplication a *= 4 a *= 4
division a /= 2 a /= 2
modulus a %= 2 a %= 2

Comparison Operators

What Python Vim script
equal to a == b a == b
not equal to a != b a != b
greater than a > b a > b
less than a < b a < b
greater than or equal to a >= b a >= b
less than or equal to a <= b a <= b

Logical Operators

What Python Vim script
logical and x and y x && y
logical or x or y x || y
logical not not x !x
!!を値の前に付けると、真偽値として扱うことができます。

Bitwise Operators

What Python Vim script
bitwise AND c = a & b c = and(a, b)
bitwise OR c = a | b c = or(a, b)
bitwise NOT c = ~a c = invert(a)
bitwise XOR c = a ^ b c = xor(a, b)
left shift c = a << b c = a * float2nr(pow(2, b))
right shift c = a >> b c = float2nr(floor(a / pow(2, b)))

Identity Operators

What Python Vim script
is x is y x is y
is not x is not y x is y

Vim9 scriptではisステートメントをlist,dict,blob,(string)で利用できます。
ただし、stringは参照先が等しいかではなく文字列同士が等しいかを比較するので注意してください。

String

Raw string

Python:

s1 = r"one\ntwo\n"
s2 = "one\ntwo\n"

Vim script:

var s1 = 'one\ntwo\n'
var s2 = "one\ntwo\n"

Finding string length

Python:

n = len("Hello World")

Vim script:

# count the number of bytes in a string
var n = len("Hello World")
# count the number of bytes in a string
var n = strlen("Hello World")
# count the number of characters in a string
var n = strwidth("Hello World")

String Concatenation

Python:

str1 = "blue"
str2 = "sky"
s = str1 + str2

Vim script:

var str1 = "blue"
var str2 = "sky"
var s = str1 .. str2

String Comparison

pass

Getting a substring

Python:

str = "HelloWorld"
sub = str[2:5]

Vim script:

var str = "HelloWorld"
# use character index and length
var sub = str[2 : 4]
var sub = str[-3]
var sub = str[2 : -3]
# use byte index and length
var sub = strpart(str, 2, 3)
# use character index and length
var sub = strcharpart(str, 2, 3)

Vim scriptではスライスを使った文字へのアクセスはbyte単位で行なわれますが、Vim9 scriptでは文字単位で行なわれます。

Counting the occurrences of a substring

Python:

str = "Hello World"
c = str.count("l")

Vim script:

var str = "Hello World"
var c = str->count("l")

Finding the position of a substring

Python:

str = "running"
idx = str.find("nn")    # leftmost
idx = str.rfind("ing")  # rightmost
# idx == -1 if the substring is not present

Vim script:

var str = "running"
var idx = str->stridx("nn")    # leftmost
idx = str->strridx("ing")  # rightmost
# idx == -1 if the substring is not present

Checking whether a string starts with or ends with a substring

Python:

str = "running"
if str.startswith("run"):
    print("starts with run")
if str.endswith("ing"):
    print("ends with ing")

Vim script:
pass

Joining strings in a List with a separator

Python:

s = ":".join(['ab', 'cd', 'ef'])

Vim script:

var s = ['ab', 'cd', 'ef']->join(':')

Changing the case of letters in a string

Python:

s = "Hello World"
l = s.lower()
l = s.upper()

Vim script:

var s = "Hello World"
var l = s->tolower()
l = s->toupper()

Replace a substring

Python:

s = "Hello World"
s2 = s.replace("Hello", "New")

Vim script:

var s = "Hello World"
var s2 = s->substitute("Hello", "New", 'g')

Split a string

Python:

s = "a:b:c"
s2 = s.split(":")

Vim script:

var s = "a:b:c"
var s2 = s->split(":")

文字単位の分割は"\zs"を使うことで可能です。

Stripping leading and trailing whitespace from a string

Python:

s = "  vim  "
s2 = s.strip()

Vim script:

var s = "  vim  "
# strip leading and trailing whitespace
var s2 = s->trim()
# strip leading space characters
s2 = s->trim(' ', 1)
# strip trailing space characters
s2 = s->trim(' ', 2)

Checking whether a string contains specific type of characters

pass

Data type conversion to string

Python:

s = str(268)
s = str(22.7)
s = str([1, 2, 3])
s = str({'a' : 1, 'b' : 2})

Vim script:

var s = string(268)
s = string(22.7)
s = string([1, 2, 3])
s = string({'a': 1, 'b': 2})

Evaluating a string

Python:

x = 10
y = eval("x * 2")
print(y)
n = eval("min([4, 3, 5])")

Vim script:

var x = 10
var y = eval("x * 2")
echo y
var n = eval("min([4, 3, 5])")
echo n

Executing commands in a string

Python:

exec("for i in range(5):\n    print(i)\n")

Vim script:

execute "for i in range(5)\necho i\nendfor"

Getting the Unicode value of a character and vice versa

Python:

print("Ordinal value of 'a' is " + str(ord("a")))
print("Character with value 65 is " + chr(65))

Vim script:

echo "Ordinal value of 'a' is " .. char2nr('a')
echo "Character with value 65 is " .. nr2char(65)

Getting the character values of a string

Python:

l = [ord(i) for i in 'Hello']
s = ''.join(chr(i) for i in l)
print(s)
print(l)

Vim script:

var l = str2list('Hello')
var s = list2str(l)
echo s
echo l

String Methods

Method Python Vim script
capitalize() 'one two'.capitalize() 'one two'->substitute('.', '\u&', '')
center() 'abc'.center(10) Not availalbe
count() "abbc".count('b') "abbc"->count('b')
decode() str.decode() Not availalbe
encode() str.encode() Not availalbe
endswith() 'running'.endswith('ing') 'running' =~# 'ing$'
expandtabs() "a\tb".expandtabs() "a\tb"->substitute("\t", repeat(' ', 8), 'g')
find() "running".find('nn') "running"->stridx('nn')
index() 'hello'.index('e') 'hello'->stridx('e')
isalnum() str.isalnum() str =~ '^[[:alnum:]]\+'
isalpha() str.isalpha() str =~ '^\a\+$'
isdigit() str.isdigit() str =~ '^\d\+$'
islower() str.islower() str =~ '^\l\+$'
isspace() str.isspace() str =~ '^\s\+$'
istitle() str.istitle() str =~ '\(\<\u\l\+\>\)\s\?'
isupper() str.isupper() str =~ '^\u\+$'
join() ':'.join(['a', 'b', 'c']) ['a', 'b', 'c']->join(':')
ljust() 'abc'.ljust(10) Not availalbe
lower() 'Hello'.lower() 'Hello'->tolower()
lstrip() ' vim '.lstrip() ' vim '->trim(' ', 1)
partition() 'ab-cd-ef'.partition('-') 'ab-cd-ef'->matchlist('\(.\{-}\)\(-\)\(.*\)')[1:3]
replace() 'abc'.replace('abc', 'xyz') 'abc'->substitute('abc', 'xyz', 'g')
rfind() 'running'.rfind('ing') 'running'->strridx('ing')
rindex() 'running'.rindex('ing') 'running'->strridx('ing')
rjust() 'abc'.rjust(10) Not availalbe
rpartition() 'ab-cd-ef'.rpartition('-') 'ab-cd-ef'->matchlist('\(.*\)\(-\)\(.*\)')[1:3]
rsplit() 'a-b-c-d'.rsplit('-', 2) Not availalbe
rstrip() ' vim '.rstrip() ' vim '->trim(' ', 2)
split() 'a-b-c'.split('-') 'a-b-c'->split('-')
splitlines() "one\ntwo".splitlines() "one\ntwo"->split("\n")
startswith() 'running'.startswith('run') 'running' =~# '^run'
strip() ' vim '.strip() ' vim '->trim()
swapcase() 'Abc'.swapcase() Not availalbe
title() 'onE twO'.title() 'onE twO'->substitute('\<\(.\)\(\S\+\)\>', '\u\1\L\2', 'g')
translate() 'abcd'.translate(string.maketrans('bd', '12')) 'abcd'->tr('bd', '12')
upper() 'Hello'.upper() 'Hello'->toupper()
zfill() str.zfill(10) Not availalbe

List

Creating a List

Python:

l = [1, 2, 3, 4]

Vim script:

var l = [1, 2, 3, 4]

listも型をつけて宣言することが可能です。
下記の例(mattnさんよりお借りしました)のようにlist<{type}>の形で宣言できます。
{type}で指定した型以外の値を代入するとエラーになりますが、{type}としてanyを指定すると、listの中に異なる型を代入できます。

var foo1: list<string> = ["foo", "bar"]
var foo2: list<number> = [1, 3, 3]
var foo3: list<bool>   = [true, false]
var foo4: list<any>    = ["foo", "bar", 3]
var foo5: list<string> = ["foo", "bar", 3]  # エラー

list内のアイテムに対してmap()を適用する際、元のlistの型と異なる型に置き換えるときはmapnew()を利用します。
mapnew()では引数に与えられたlistは更新されず新しいlistが返されますが、list内の要素は更新できるためそうしたくない場合deepcopy()を使用してください。

var foo = [123, 456, 789]

echo map(foo, (i, v) => string(v)) # エラー
echo mapnew(foo, (i, v) => string(v)) # -> ['123', '456', '789']

Accessing a List element

Python:

l = [1, 2, 3, 4]
v1 = l[2]
v2 = l[-2]

Vim script:

var l = [1, 2, 3, 4]
var v1 = l[2]
var v2 = l[-2]

Changing the value of a List element

Python:

l = [1, 2, 3, 4]
l[3] = 5

Vim script:

var l = [1, 2, 3, 4]
l[3] = 5

Adding an item to a List

Python:

l = []
l.append(5)
l += [6, 7]

Vim script:

var l = []
l->add(5)
l += [5, 6]

Inserting an item in a List

Python:

l = [1, 3]
l.insert(1, 2)

Vim script:

var l = [1, 3]
# insert before index 1
l->insert(2, 1)
# insert at the begining
l->insert(5)

Removing an item from a List

Python:

l = [4, 5, 6]
l.remove(5)
del l[0]

Vim script:

var l = [4, 5, 6]
var idx = index(l, 5)
if idx != -1
  remove(l, idx)
endif
unlet l[0]

Removing the last element from a List

Python:

l = [1, 2, 3]
v = l.pop()

Vim script:

var l = [1, 2, 3]
var v = l->remove(-1)

Find the index of an item in a List

Python:

l = [1, 2, 3]
x = l.index(2)

Vim script:

var l = [1, 2, 3]
var x = l->index(2)

List slices

Python:

l = [1, 2, 3, 4]
m = l[1:3]
m = l[2:]

Vim script:

var l = [1, 2, 3, 4]
var m = l[1 : 3]
m = l[2 :]
m = l[-2 :]

List Concatenation

Python:

l = [1, 2] + [3 ,4]

Vim script:

var l = [1, 2] + [3, 4]

Adding multiple items to a List using repetition

Python:

l = ['vim'] * 4

Vim script:

var l = ['vim']->repeat(4)

Count the number of occurrences of an item in a List

Python:

l = [2, 4, 4, 5]
x = l.count(4)

Vim script:

var l = [2, 4, 4, 5]
var x = l->count(2)

Finding the List length

Python:

l = ['a', 'b', 'c']
n = len(l)

Vim script:

var l = ['a', 'b', 'c']
var n = l->len()

Sort a List

Python:

l = [3, 2, 1]
l.sort()
print(l)

Vim script:

var l = [3, 2, 1]
echo l->sort()

Getting unique elements in a List

Python:

l = ['a', 'b', 'b', 'c', 'c', 'd']
# order of the elements is not retained
tset = set(l)
print(list(tset))

Vim script:

# needs a sorted list
var l = ['a', 'b', 'b', 'c', 'c', 'd']
echo copy(l)->uniq()

Reverse a List

Python:

l = [1, 2, 3]
l.reverse()
print(l)

Vim script:

var l = [1, 2, 3]
echo l->reverse()

Copying a List

Python:

l = [3, 2, 1]
l2 = l.copy()

Vim script:

var l = [3, 2, 1]
var l2 = l->copy()

Deep Copying a List

Python:

import copy
a = [[1, 2], [3, 4]]
b = copy.deepcopy(a)

Vim script:

var a = [[1, 2], [3, 4]]
var b = a->deepcopy()

Empty a List

Python:

l = [3, 2, 1]
l.clear()

Vim script:

var l = [3, 2, 1]
unlet l[:]

Comparing two Lists

Python:

l1 = [1, 2]
l2 = l1
l3 = [1, 2]
if l1 is l2:
  print("Lists l1 and l2 refer to the same list")
if l1 is not l3:
  print("Lists l1 and l3 do not refer to the same list")
if l1 == l3:
  print("Lists l1 and l3 contain the same elements")
if l1 != l3:
  print("Lists l1 and l3 are different")

Vim script:

var l1 = [1, 2]
var l2 = l1
var l3 = [1, 2]
if l1 is l2
  echo "Lists l1 and l2 refer to the same list"
endif
if l1 isnot l3
  echo "Lists l1 and l2 do not refer to the same list"
endif
if l1 == l3
  echo "Lists l1 and l3 contain the same elements"
endif
if l1 != l3
  echo "Lists l1 and l3 are different"
endif

Filter selected elements from a List

Note that Vim does not support List comprehension.

Python:

odd = list(filter(lambda x: x % 2, range(10)))
odd = [x for x in range(10) if x % 2]

Vim script:

var odd = filter(range(10), (idx, v) => (v % 2))

Map List elements

Note that Vim does not support List comprehension.

Python:

num_str = list(map(lambda x: str(x), range(10)))
num_str = [str(x) for x in range(10)]

Vim script:

var num_str = mapnew(range(10), (idx, v) => (string(v)))

Reducing List elements

Python:

# using a lambda function
from functools import reduce
sum = reduce((lambda x, y: x + y), [1, 2, 3, 4])

# using a function
def SumNum(a, b):
    return a + b
sum = reduce(SumNum, [1, 2, 3, 4])

Vim script:

# using a lambda function
var sum = reduce([1, 2, 3, 4], (x, y) => (x + y))

# using a function
def SumNum(x: number, y: number): number
  return x + y
enddef
sum = reduce([1, 2, 3, 4], function('SumNum'))
echo sum

Finding the mix/max value in a List

Python:

l = [3, 10, 8]
v1 = min(l)
v2 = max(l)
print(v1, v2)

Vim script:

var l = [3, 10, 8]
var v1 = l->min()
var v2 = l->max()
echo v1 v2

Converting a List to a string

Python:

s = str([3, 5, 7])

Vim script:

var s = string([3, 5, 7])

List Methods

Method Python Vim script
append() m.append(6) m->add(6)
clear() m.clear() unlet m[:]
copy() m.copy() m->copy()
count() m.count(6) m->count(6)
extend() m.extend([5, 6]) m->extend([5, 6])
index() m.index(6) m->index(6)
insert() m.insert(2, 9) m->insert(9, 2)
pop() m.pop() m->remove(-1)
remove() m.remove(6) m->remove(m->index(6))
reverse() m.reverse() m->reverse()
sort() m.sort() m->sort()

Dictionary

Creating a Dict

Python:

d = {'red' : 10, 'blue' : 20}
x = {}

Vim script:

var d = {red: 10, blue: 20}
var x = {}

dictlistと同様に型をつけて宣言することができます。

dict内のアイテムに対してmap()を適用する際、元のdictの型と異なる型に置き換えるときはmapnew()を利用します。
mapnew()では引数に与えられたdictは更新されず新しいdictが返されますが、dict内の要素は更新できるためそうしたくない場合deepcopy()を使用してください。

var foo = {key1: 123, key2: 234}

echo map(foo, (k, v) => string(v)) # エラー
echo mapnew(foo, (k, v) => string(v)) # -> {'key1': '123', 'key2': '234'}

Retrieving the value of a Dict item

Python:

d = {'red' : 10, 'blue' : 20}
x = d['red']

Vim script:

var d = {red: 10, blue: 20}
var x = d['red']
x = d.red

Changing the value of a Dict item

Python:

d = {'red' : 10, 'blue' : 20}
d['red'] = 15

Vim script:

var d = {red: 10, blue: 20}
d.red = 15
d['red'] = 15

Accessing a Dict item

Python:

d = {'red' : 10, 'blue' : 20}
v = d.get('red')

Vim script:

var d = {red: 10, blue: 20}
var v = d->get('red')

Adding a new Dict item

Python:

d = {'red' : 10, 'blue' : 20}
d['green'] = 30

Vim script:

var d = {red: 10, blue: 20}
d.green = 30
d['green'] = 30

Extending a Dict using another Dict

Python:

d = {}
d.update({'color' : 'grey'})

Vim script:

var d = {}
eval d->extend({color: 'grey'})

Removing an item from a Dict

Python:

d = {'red' : 10, 'blue' : 20}
d.pop('red')

Vim script:

var d = {red: 10, blue: 20}
d->remove('red')

Clearing all the items from a Dict

Python:

d = {'red' : 10, 'blue' : 20}
d.clear()

Vim script:

var d = {red: 10, blue: 20}
d->filter("0")

Getting the size of a Dict

Python:

d = {'red' : 10, 'blue' : 20}
n = len(d)

Vim script:

var d = {red: 10, blue: 20}
var n = d->len()

Count the number of occurrences of a value in a Dict

Python:

d = {'red' : 10, 'blue' : 10}
x = sum(n == 10 for n in d.values())
print(x)

Vim script:

var d = {red: 10, blue: 10}
var x = d->count(10)
echo x

Checking Dict membership

Python:

d = {'red' : 10, 'blue' : 20}
if 'red' in d:
    print("found red key")

Vim script:

var d = {red: 10, blue: 20}
if d->has_key('red')
  echo "found red key"
endif

Iterating through all the keys in a Dict

Python:

d = {'red' : 10, 'blue' : 20}
for k in d:
    print(k)
for k in d:
    print(d[k])

Vim script:

var d = {red: 10, blue: 20}
for k in keys(d)
  echo k
endfor
for k in d->keys()
  echo d[k]
endfor

Iterating through all the values in a Dict

Python:

d = {'red' : 10, 'blue' : 20}
for v in d.values():
    print(v)

Vim script:

var d = {red: 10, blue: 20}
for v in d->values()
  echo v
endfor

Iterating through all the key, value pairs in a Dict

Python:

d = {'red' : 10, 'blue' : 20}
for k, v in d.items():
    print(k, v)

Vim script:

var d = {red: 10, blue: 20}
for [k, v] in d->items()
  echo k v
endfor

Copying a Dict

Python:

d = {'red' : 10, 'blue' : 20}
new_d = d.copy()

Vim script:

var d = {red: 10, blue: 20}
var new_d = d->copy()

Deep Copying a Dict

Python:

import copy
a = {'x' : [1, 2], 'y' : [3, 4]}
b = copy.deepcopy(a)

Vim script:

var a = {x: [1, 2], y: [3, 4]}
var b = a->deepcopy()

Comparing two Dicts

Python:

d1 = {'a' : 10, 'b' : 20}
d2 = {'a' : 10, 'b' : 20}
if d1 == d2:
    print("Dicts d1 and d2 have the same content")
d3 = d1
if d1 is d3:
  print("Dicts d1 and d3 refer to the same dict")
if d2 is not d3:
  print("Dicts d2 and d3 do not refer to the same dict")

Vim script:

var d1 = {a: 10, b: 20}
var d2 = {a: 10, b: 20}
if d1 == d2
  echo "Dicts d1 and d2 have the same content"
endif
var d3 = d1
if d1 is d3
  echo "Dicts d1 and d3 refer to the same dict"
endif
if d2 isnot d3
  echo "Dicts d2 and d3 do not refer to the same dict"
endif

Filter selected elements from a Dict

Note that Vim does not support Dict comprehension.

Python:

d1 = {'red' : 10, 'green' : 20, 'blue' : 10}
# filter dict items with value 10
d2 = dict(filter(lambda e : e[1] == 10, d1.items()))
print(d1, d2)
# use dict comprehension
d3 = {k: v for [k, v] in d1.items() if v == 10}
print(d1, d3)

Vim script:

var d1 = {red: 10, green: 20, blue: 10}
# filter dict items with value 10
var d2 = copy(d1)->filter((k, v) => (v == 10))
echo d1 d2

Map Dict elements

Note that Vim does not support Dict comprehension.

Python:

d1 = {'red' : 10, 'green' : 20, 'blue' : 30}
# increment the values by 5
d2 = dict(map(lambda e : (e[0], e[1] + 5), d1.items()))
print(d1, d2)
# use dict comprehension
d3 = {k: v + 5 for k, v in d1.items()}
print(d1, d3)

Vim script:

var d1 = {red: 10, green: 20, blue: 30}
# increment the values by 5
var d2 = copy(d1)->map((k, v) => (v + 5))
echo d1 d2

Finding the min/max value in a Dict

Python:

d = {'red' : 10, 'green' : 20}
v1 = min(d.values())
v2 = max(d.values())
print(v1, v2)

Vim script:

var d = {red: 10, green: 20}
var v1 = d->min()
var v2 = d->max()
echo v1 v2

Converting a Dict to a string

Python:

d = str({'a' : 1, 'b' : 2})

Vim script:

var d = string({a: 1, b: 2})

Dictionary Methods

Method Python Vim script
clear() d.clear() call filter(d, '0')
copy() newDict = d.copy() var newDict = d->copy()
fromkeys() d = dict.fromkeys(x) Not availalbe
get() v = d.get('red') var v = d->get('red')
in or has_key() 'red' in d d->has_key('red')
items() d.items() d->items()
keys() d.keys() d->keys()
pop() d.pop('red') d->remove('red')
popitem() d.popitem() Not availalbe
setdefault() d.setdefault('red', 10) Not availalbe
update() d.update({'a' : 10, 'b' : 20} d->extend({a: 10, b: 20})
values() d.values() d->values()

If statement

Basic If statement

Python:

if a > b:
    print("a is greater than b")

Vim script:

if a > b
  echo "a is greater than b"
endif

If-else statement

Python:

if a > b:
    print("a is greater than b")
else:
    print("a is less than or equal to b")

Vim script:

if a > b
  echo "a is greater than b"
else
  echo "a is less than or equal to b"
endif

If-elseif statement

Python:

if a > b:
    print("a is greater than b")
elif a < b:
    print("a is less than b")
else:
    print("a is equal to b")

Vim script:

if a > b
  echo "a is greater than b"
elseif a < b
  echo "a is less than b"
else
  echo "a is equal to b"
endif

Checking multiple conditions

Python:

if a > b and (a > c or a > d):
    print "a is greater than b and greater than c or d"

Vim script:

if a > b && (a > c || a > d)
  echo "a is greater than b and greater than c or d"
endif

Nested If statements

Python:

if status == True:
    if a >= 1:
	print("Nested if")

Vim script:

if status == true
  if a >= 1
    echo "Nested if"
  endif
endif

For Loop

Python:

for i in range(5) :
    print(i)

Vim script:

for i in range(5)
  echo i
endfor

Breaking out of a For loop

Python:

for i in ['a', 'b', 'c']:
    if i == 'b':
        break
    print(i)

Vim script:

for i in ['a', 'b', 'c']
  if i == 'b'
    break
  endif
  echo i
endfor

Continuing a For loop

Python:

for i in ['a', 'b', 'c']:
    if i == 'b':
        continue
    print(i)

Vim script:

for i in ['a', 'b', 'c']
  if i == 'b'
    continue
  endif
  echo i
endfor

Nested For Loops

Python:

for i in range(10):
    for j in range(10):
	print(str(i) + 'x' + str(j) + '=' + str(i * j))

Vim script:

for i in range(4)
  for j in range(4)
    echo i .. 'x' .. j .. '=' .. i * j
  endfor
endfor

While Loop

Python:

i = 1
while i <= 5 :
   print(i)
   i += 1

Vim script:

var i = 1
while i <= 5
  echo i
  i += 1
endwhile

Comment

Python:

# This is a python comment
i = 0    # First iteration

Vim script:

# This is a Vim script comment
var i = 0 # First iteration

Vim9 scriptの関数は大文字で初める必要があります。また、デフォルトのスコープはスクリプトローカルなためグローバル関数を定義するにはg:を先頭につけます。
また、エラーが発生するとその時点で実行は止まるため、abortは必要ありません。また、定義済みの関数を上書きするにはdef!を使います。
引数の型、返り値の型を指定する必要があります。

Defining a Function

Python:

def Min(x, y):
    return x if < y else y

print(Min(6, 3)

Vim script:

def! Min(x: number, y: number): number
  return x < y ? x : y
enddef

echo Min(6, 3)

Calling a Function

Python:

def EchoValue(v):
    print(v)

EchoValue(100)

Vim script:

def EchoValue(v: number)
  echo v
enddef

EchoValue(100)

Function return value

Python:

def Sum(a, b):
    return a + b

s = Sum(10, 20)

Vim script:

def Sum(a: number, b: number): number
  return a + b
enddef

var s = Sum(10, 20)

Pass by reference

Python:

def AddValues(l):
    l.extend([1, 2, 3, 4])

Vim script:

def AddValues(l: list<number>)
  extend(l, [1, 2, 3, 4])
enddef

Variable number of arguments

Python:

def Sum(v1, *args):
    sum = v1
    for i in *args:
	sum += i
    return sum

Vim script:

def Sum(...args: list<number>): number
  var sum = 0
  for i in args
    sum += i
  endfor
  return sum
enddef

var s1 = Sum(10, 20, 30, 40)
s1 = Sum(10)

Default value for arguments

Python:

def Powerof(base, exp = 2):
    return base ** exp

Vim script:

def PowerOf(base: number, exp: number = 2): number
  return float2nr(pow(base, exp))
enddef

var val = PowerOf(4)
val = PowerOf(4, 3)

Accessing global variables

Python:

counter = 1
def Incr():
    global counter
    counter += 1

Vim script:
pass

Function reference

Python:

def Foo():
    print("Foo")
Bar = Foo
Bar()

Vim script:

def! Foo()
  echo "Foo"
enddef
var Bar = function("Foo")
Bar()

Lambda Function

Python:

F = lambda x , y: x - y
print(F(5,2))

Vim script:

var F = (x, y) => (x - y)
echo F(5, 2)

Partial Function

Python:

import functools
def Mylog(subsys, msg):
    print("%s: %s" % (subsys, msg))

ErrLog = functools.partial(Mylog, 'ERR')
ErrLog("Failed to open file")

Vim script:

def Mylog(subsys: string, msg: string)
  echo printf("%s: %s", subsys, msg)
enddef

var ErrLog = function('Mylog', ['ERR'])
ErrLog("Failed to open file")

Closure

Closure with a lambda function

Python:

def foo(arg):
  i = 3
  return lambda x: x + i - arg

bar = foo(4)
print(bar(6))

Vim script:
pass

Closure with a function reference

Python:

def Foo(base):
    def Bar(val):
	return base + val
    return Bar

F = Foo(10)
print(F(2))
F = Foo(20)
print(F(2))

Vim script:
pass


Class

Defining a class

Python:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def getX(self):
        return self.x

    def getY(self):
        return self.y

    def setX(self, x):
        self.x = x

    def setY(self, y):
        self.y = y

    def Print(self):
        print("Pt = (" + str(self.x) + ", " + str(self.y) + ")")

pt = Point(10, 20)
pt.setX(40)
pt.setY(50)
pt.Print()

Vim script:
not implemented yet


Exception Handling

Basic exception handling

Python:

try:
    f = open('buf.java', 'r')
    lines = f.readlines()
    f.close()
except IOError:
    print("Failed to open file")

Vim script:

try
  var l = readfile('buf.java')
catch /E484:/
  echo "Failed to read file"
endtry

Catching all exceptions

Python:

try:
    f = open('buf.java', 'r')
    lines = f.readlines()
    f.close()
except Exception as e:
    print("Caught " + str(e))

Vim script:

try
  var l = readfile('buf.java')
catch
  echo "Caught " .. v:exception
endtry

Executing code after a try block (finally)

Python:

try:
    f = open('buf.java', 'r')
    lines = f.readlines()
    f.close()
finally:
    print("executing code in finally block")

Vim script:
pass

Raising a custom exception

Python:

try:
    raise Exception('MyException')
except Exception as e:
    if str(e) == 'MyException':
	print("Caught MyException")
finally:
    print("Finally block")

Vim script:

try
  throw 'MyException'
catch /MyException/
  echo "Caught MyException"
endtry

Line Continuation

Python:

a = 1 + 2 + 3 + \
      4 + 5 + 6

Vim script:

# 演算子
var a = 1 + 2 + 3 +
        4 + 5 + 6
# 関数呼び出し
var result = Func(
        arg1,
        arg2
        )
# コマンド
autocmd BufNewFile *.match if condition
    |   echo 'match'
    | endif

File Operations

Reading all the lines from a file

Python:

with open('myfile.txt', 'r') as f:
    lines = f.readlines()
# lines == ['line1\n', 'line2\n']

Vim script:

var lines = readfile("myfile.txt")
# lines == ['line1', 'line2']

Writing lines to a file

Python:

lines = ['line1\n', 'line2\n']
with open('myfile.txt', 'w') as fh:
    fh.writelines(lines)

lines = ['line1', 'line2']
with open('myfile.txt', 'w') as fh:
    print(*lines, sep='\n', file=fh)

Vim script:

writefile(['line1', 'line2'], 'myfile.txt')

Appending lines to a file

Python:

lines = ["line3\n", "line4\n"]
with open('myfile.txt', 'a') as fh:
    fh.writelines(lines)

Vim script:

writefile(['line3', 'line4'], 'myfile.txt', 'a')

Checking whether a file exists

Python:

import os.path
if os.path.isfile('myfile.txt'):
    print("File exists")

Vim script:

if filereadable('myfile.txt')
  echo "File is readable"
endif

Deleting a file

Python:

import os
os.remove('myfile.txt')

Vim script:

delete('myfile.txt')

Renaming a file

Python:

import os
os.rename('myfile.txt', 'somefile.txt)

Vim script:

rename('myfile.txt', 'somefile.txt')

Getting the size of a file

Python:

import os
sz = os.path.getsize('move.py')

Vim script:

var sz = getfsize('move.py')

Directory Operations

Creating a directory

Python:

os.mkdir('somedir')

Vim script:

mkdir('somedir')

Changing to a directory

Python:

os.chdir('someotherdir')

Vim script:

chdir('someotherdir')

Getting the current directory

Python:

dir = os.getcwd()

Vim script:

var dir = getcwd()

Deleting a directory

Python:

os.rmdir('somedir')

Vim script:

delete('somedir', 'd')

Random numbers

Generating a random number

Python:

import random
r = random.randint(0, 2147483647)

Vim script:

var r = rand()

Generating a random number from a seed

Python:

import random
random.seed()
r = random.randint(0, 2147483647)
print(r)

Vim script:

var seed = srand()
var r = rand(seed)

Mathematical Functions

いくつかの関数はVimが+floatでコンパイルされている必要があります。

Function Python Vim script
abs f = math.fabs(-10) var f = abs(-10)
acos f = math.acos(0.8) var f = acos(0.8)
asin f = math.asin(0.8) var f = asin(0.8)
atan f = math.atan(0.8) var f = atan(0.8)
atan2 f = math.atan2(0.4, 0.8) var f = atan2(0.4, 0.8)
ceil f = math.ceil(1.2) var f = ceil(1.2)
cos f = math.cos(4) var f = cos(4)
cosh f = math.cosh(4) var f = cosh(4)
exp f = math.exp(2) var f = exp(2)
floor f = math.floor(1.4) var f = floor(1.4)
log f = math.log(12) var f = log(12)
log10 f = math.log10(100) var f = log10(100)
mod f = math.fmod(4, 3) var f = fmod(4, 3)
pow f = math.pow(2, 3) var f = pow(2, 3)
sin f = math.sin(4) var f = sin(4)
sinh f = math.sinh(4) var f = sinh(4)
sqrt f = math.sqrt(9) var f = sqrt(9)
tan f = math.tan(4) var f = tan(4)
tanh f = math.tanh(4) var f = tanh(4)
trunc f = math.trunc(1.3) var f = trunc(1.3)

Date/Time functions

Get current date and time

Python:

from datetime import datetime
d = datetime.now()
print(d.strftime("%c"))

Vim script:

echo strftime("%c")

Parse a date/time string

Python:

from datetime import datetime
print(datetime.strptime("1997 Apr 27 11:49:23", "%Y %b %d %X"))

Vim script:

echo strptime("%Y %b %d %X", "1997 Apr 27 11:49:23")

Getting the time in seconds since epoch

Python:

import time
print int(time.time())

Vim script:

echo localtime()

Measuring elapsed time

Python:

import time
start_time = time.perf_counter()
sum = 1
for i in range(1000):
    sum += i
end_time = time.perf_counter()
print("Elapsed time " + str(end_time - start_time))

Vim script:

var start = reltime()
var sum = 0
for i in range(1000)
  sum += i
endfor
var elapsed_time = reltime(start)
echo "Elasped time" reltimefloat(elapsed_time)

External commands

Getting the output of an external command as a string

Python:

import subprocess
procObj = subprocess.Popen('grep class *.java',
			stdout=subprocess.PIPE,
			shell=True)
lines, err = procObj.communicate()
print(lines)
print("Error = " + str(procObj.returncode))

Vim script:

var lines = system('grep class *.java')
echo lines
echo "Error = " .. v:shell_error

Splitting the output of an external command into lines

Python:

import subprocess
procObj = subprocess.Popen('grep class *.java',
			stdout=subprocess.PIPE,
			shell=True)
lines, err = procObj.communicate()
print("Number of matches = " + str(len(lines.splitlines())))

Vim script:

var lines = systemlist('grep class *.java')
echo "Number of matches = " .. len(lines)

Sending input to an external command and getting the output

Python:

import subprocess
procObj = subprocess.Popen('wc',
			stdout=subprocess.PIPE,
			stdin=subprocess.PIPE,
			shell=True)
lines, err = procObj.communicate("one\ntwo\n")
print(lines)
print("Error = " + str(procObj.returncode))

Vim script:

var lines = system('wc', "one\ntwo\n")
echo lines
echo "Error = " .. v:shell_error

User Input/Output

Getting input from the user

Python:

choice = input("coffee or tea? ")
print("You selected " + choice)

Vim script:

var ans = input("coffee or tea? ", "tea")
echo "You selected " .. ans

Getting password from the user

Python:

import getpass
passwd = getpass.getpass("Password: ")
print("You entered " + passwd)

Vim script:

var passwd = inputsecret("Password: ")
echo "You entered " .. passwd

Python:

print("Hello World\n")
s = "vim"
print("Editor = %s" % (s))

Vim script:

echo "Hello World"
var s = "vim"
echo "Editor = " .. s

Formatted Output

Python:

name = "John"
id = 1001
print(f"Name: {name}, ID: {id}")
print("Name: {}, ID: {}".format(name, id))
print("Name: %s, ID: %d" % (name, id))

Vim script:

var name = "John"
var id = 1001
echo printf("Name: %s, ID: %d", name, id)

Environment Variables

Getting the value of an environment variable

Python:

import os
h = os.environ.get('HOME', '')
if h == '':
    print("HOME is not set")
else:
    print("HOME = " + h)

Vim script:

if !exists('$HOME')
  echo 'HOME is not set'
else
  echo 'HOME = ' .. $HOME
endif

Setting an environment variable

Python:

import os
os.environ['FOO'] = "BAR"

Vim script:

setenv('FOO', 'BAR')

var $FOOなどで変数にsetできますが、既に定義されている場合エラーになるのでsetenv()を利用すとよいでしょう。

Removing an environment variable

Python:

import os
del os.environ['FOO']

Vim script:

setenv('FOO', v:null)

Getting all the environment variables

Python:

import os
print(os.environ)

Vim script:

echo environ()

Command-line Arguments

Displaying the command-line arguments

Python:

import sys
print("Number of arguments = " + str(len(sys.argv)))
print("Arguments = " + str(sys.argv))
for arg in sys.argv:
    print(arg)

Vim script:

echo "Number of arguments = " .. len(v:argv)
echo "Arguments = " .. string(v:argv)
for arg in v:argv
  echo arg
endfor

Regular Expressions

Finding whether a pattern matches a string

Python:

import re
s = 'Test failed with error E123:'
if re.search(r'E\d+:', s):
    print('Error code found')

s = 'Test successful'
if re.search(r'E\d+:', s) is None:
    print("Test passed")

Vim script:

var s = 'Test failed with error E123:'
if s =~# 'E\d\+:'
  echo "Error code found"
endif

s = 'Test successful'
if s !~# 'E\d\+:'
  echo "Test passed"
endif

Finding the beginning or ending index of a pattern in a string

Python:

import re
m = re.search(r'\d+', "Abc 123 Def")
if m is not None:
    idx = m.start()
    end_idx = m.end()

Vim script:

var idx = match("Abc 123 Def", '\d\+')
var end_idx = matchend("Abc 123 Def", '\d\+')

var l = matchstrpos("Abc 123 Def", '\d\+')
echo "start:" l[1] "end:" l[2]

Getting matching substring using a pattern

Python:

import re
m = re.search(r'\d+', "Abc 123 Def")
if m is not None:
    s = m.group(0)
    print s

Vim script:

var s = matchstr("Abc 123 Def", '\d\+')

Getting multiple matches using a pattern

Python:

import re
m = re.match(r'(\w+) (\w+) (\w+)', "foo bar baz")
if m is not None:
    print("Full match: " + m.group(0))
    print("1: " + m.group(1) + " 2: " + m.group(2) + " 3: " + m.group(3))

Vim script:

var list = matchlist("foo bar baz", '\(\w\+\) \(\w\+\) \(\w\+\)')
echo "Full match:" list[0]
echo "1:" list[1] "2:" list[2] "3:" list[3]

Substituting text using a pattern

Python:

import re
s = re.sub(r'bar', r'baz', "foo bar")
print(s)

Vim script:

var s = substitute("foo bar", 'bar', 'baz', '')
echo s

Using a function to get the replacement string

Python:

import re
def Dashrepl(m):
  if m.group(0) == '-':
    return ' '
  else:
    return '-'
s = re.sub('-{1,2}', Dashrepl, 'pro----gram-files')
print(s)

Vim script:

def Dashrepl(m: list<string>): string
  if m[0] == '-'
    return ' '
  else
    return '-'
  endif
enddef
var s = substitute("pro----gram-files", '-\{1,2}', function('Dashrepl'), 'g')
echo s

Regular expression comparison

Note that the below table contains only the regular expressions that are present in both Python and Vim.

What Python Vim
single character . .
start of string ^ ^
end of string $ $
0 or more matches * *
1 or more matches + \+
0 or 1 match ? \?
non-greedy match *? \{-}
fixed matches {n} \{n}
m to n matches {m,n} \{m,n}
m to n non-greedy matches {m,n}? \{-m,n}
character class [...] [...]
negated character class [^...] [^...]
range [a-z] [a-z]
either-or branch | \|
capturing group (...) \(...\)
non-capturing match (?:...) \%(...\)
positive look-ahead (?=...) \(...\)\@=
negative look-ahead (?!...) \(...\)\@!
positive look-behind (?<=...) \(...\)\@<=
negative look-behind (?<!...) \(...\)\@<!
start of word \b \<
end of word \b \>
digit \d \d
non-digit \D \D
whitespace \s \s
non-whitespace \S \S
word character \w \w
non-word character \W \W
ignore case (?i) \c

Binary Data

Storing binary data in a variable

Python:

data = bytearray(b'\x12\xF6\xAB\xFF\x49\xC0\x88\x3A\xE2\xC1\x42\xAA')
print(data)
print(data[0:4])

Vim script:

var data = 0z12F6ABFF.49C0883A.E2C142AA
echo data
echo data[0 : 3]

Manipulating binary data stored in a variable

Python:

data = bytearray(b'')
data.append(0xC2)
data += b'\xB3\xF7\xA5'
del data[2]
print(data)

Vim script:

var data = 0z
data[0] = 0xC2
data += 0zB3F7A5
remove(data, 2)
echo data

Reading and writing binary data from a file

Python:

with open("datafile.bin", "rb") as bin_fh:
    data = bytearray(bin_fh.read())

with open("data2.bin", "wb") as bin_fh:
    bin_fh.write(data)

Vim script:

var data = readfile('datafile.bin', 'B')
writefile(data, 'data2.bin')

Timers

One-shot Timer

Python:

import threading
def TimerCallback(ctx):
    print("Timer callback, context = " + ctx)

timer = threading.Timer(5, TimerCallback, args=["green"])
timer.start()

Vim script:

def TimerCallback(ctx: string, timer_id: number)
  echo "Timer callback, context = " .. ctx .. ", id = " .. timer_id
enddef

# Run a function after 5 seconds
var timer_id = timer_start(5 * 1000, function('TimerCallback', ["green"]))

Periodic Timer

Python:

import threading
def TimerCallback():
    print("Timer callback")
    threading.Timer(5, TimerCallback).start()

# run a function every 5 seconds (approximately)
timer = threading.Timer(5, TimerCallback)
timer.start()

Vim script:

def TimerCallback(timer_id: number)
  echo "Timer callback"
enddef

# run a function every 5 seconds periodically
var timer_id = timer_start(5 * 1000, function('TimerCallback'), {'repeat': -1})

Stopping a timer

Python:

import threading
def TimerCallback():
    print("Timer callback")

timer = threading.Timer(1, TimerCallback)
timer.start()
timer.cancel()

Vim script:

def TimerCallback(timer_id: number)
  echo "Timer callback"
enddef

# start a timer and then stop it
var timer_id = timer_start(1000, 'TimerCallback')
timer_stop(timer_id)

# to stop all the timers
timer_stopall()

Sleeping for a specified number of seconds

Python:

import time
time.sleep(5)
time.sleep(0.2)

Vim script:

# sleep for 5 seconds
sleep 5
# sleep for 200 milliseconds
sleep 200m

JSON encoder and decoder

Python:

import json
v = ['foo', {'a' : 3}, True]
# encode data to JSON
str = json.dumps(v)
# decode data from JSON
x = json.loads(str)

Vim script:

var v = ['foo', {'a': 3}, v:true]
# encode data to JSON
var str = v->json_encode()
echo str
# decode data from JSON
var x = str->json_decode()
echo x

Network Sockets

Python:

import requests
# Get a web page from http://httpbin.org
def Display_Page():
  r = requests.get('http://httpbin.org/')
  if r.status_code == requests.codes.ok:
    # display the received header and contents
    print(r.headers)
    print(r.text)
  else:
    print("Error: Failed to open URL")
Display_Page()

Vim script:
pass


Background Processes

Starting a background process and communicating with it

Python:

import subprocess
procObj = subprocess.Popen('bc',
			stdin=subprocess.PIPE,
			stdout=subprocess.PIPE,
			shell=True)
lines, err = procObj.communicate("12 * 6\n")
print("Result = " + lines)
print("Exitcode = " + str(procObj.returncode))

Vim script:

var job = job_start('bc')
if job_status(job) != "run"
  echo "Failed to start bc"
else
  var output = ch_evalraw(job, "6 * 12\n")
  echo "Result =" output
  call job_stop(job, "kill")
  var info = job_info(job)
  echo "Exitcode = " info.exitval
endif

Unit Tests

Python:

import unittest

class TestDemoMethods(unittest.TestCase):
    def test_abc(self):
        self.assertEqual('FOO'.lower(), 'foo')
        self.assertNotEqual(1, 2)
        self.assertTrue('foo' == 'foo')
        self.assertFalse('FOO' == 'foo')
        self.assertIsNot('foo', 1)
        self.assertRegex('ab123xy', '\d+')
        self.assertNotRegex('abcd', '\d+')
        with self.assertRaises(TypeError):
            'a:b'.split(2)

unittest.main()

Vim script:
通常のVim scriptで行うことをお勧めします。

Discussion