参考 Youtube
1 Hello World
输出函数:
echo
echon
echomsg
echohl
注意 echon
, 其将输出合并到前一个输出中.
echomsg
有 message history.
可用 :message
查看, 也可以用 :message clear
清除.
输出颜色用 echohl
, 如:
1 2 3 4 5 6 7 8
| echohl PmenuSel echomsg "Hello"
echohl None echon " "
echohl IncSearch echon "World"
|
用 :highlight
来查看.
2 定义自己的 highlight group
如:
1 2 3 4 5 6 7 8 9 10 11
| highlight hello guifg=red gui=bold, italic highlight world guifg=lightblue gui=bold,italic
echohl hello echomsg "Hello"
echohl None echon " "
echohl world echon "World"
|
属性可以查看 :h attr-list
3 变量
任何时候改变变量的值, 都需要 let
.
可以用 exists()
函数来检查一个变量是否被声明.
设置一个 option 有两种写法, 如:
1 2
| let &textwidth = 50 set textwidth = 50
|
4 if/elseif/else 语句
如:
1 2 3 4 5 6 7 8 9 10 11 12
| let number = 1 let string = ""
if number > 0 let string = "positive value" elseif number == 0 let string = "the value is 0" else let string = "negative value" endif
echo string
|
5 真值和假值
1 2 3 4
| let number = -1 let is_positive = number > 0
echo is_positive
|
除 0 以外的数都是 true.
空字符串 是 false
6 数和浮点数
vimscript 中没有幂运算的 **
符号, 其他的运算都有:
1 2 3 4 5
| let plus = 10 + 3 let minus = 10 - 3 let multiply = 10 * 3 let divide = 10 / 3 let modulo = 10 % 3
|
二元运算的一侧出现浮点数, 其值就会变为浮点数.
如:
将 float 强制转换为 integer 可以用:
7 数学运算
vimscript 没有自增和自减符号.
但有:
1 2
| let number = 1 let number += 1
|
这类符号.
vimscript 有三元运算符 condition ? expression1 : expression2
如:
1 2
| let number = 1 echo if number > 0 ? "positive" : "negative"
|
8 字符串
注意双引号和单引号的区别, 单引号中只有 '
为特殊字符. (和其他语言有点不同)
如:
1 2 3 4 5
| highlight blue guifg=LightBlue gui=bold,italic echohl blue
let double = "I asked \"why?\"" let single = 'I''m fine'
|
在单引号中输出单引号用 ''
9 字符串连接
用 .
和 ..
都可以.
1 2 3
| let string = "hello" let string .= " world" echo string
|
也可以用 join
函数:
1
| let string = join([string, "world"], "\n")
|
第二个参数为连接符号.
10 去除字符串中的空白字符
使用 trim
函数, 有两种形式.
使用一个参数:
1 2
| let string = " trim " echo trim(string)
|
三个参数:
1 2 3
| echo trim(" trim ", " ", 0) echo trim(" trim ", " ", 1) echo trim(" trim ", " ", 2)
|
第二个参数为要去除的字符 (不只是空白字符), 第三个参数决定去除的 side, 0
表示两边, 1
表示 beginning, 2
表示 ending.
第二个参数并不支持正则表达式.
11 提取子字符串
1 2
| let string = "hello world" echo string[0:4]
|
也就是切片. 可以为负数.
超出 index 则会返回空字符串.
也可以用 strcharpart
函数:
1 2 3 4 5
| let string = "hello world" echo string[0:4]
let result = strcharpart(string, 6, 2) echo result
|
第二个参数是开始位置的 index, 第三个参数是要提取的长度.
12 list 的创建和获取
1 2 3 4
| let list = [1, 2, 3, 4, 5] echo list echo list[-1] let list[0] = 3
|
可以使用 get
函数来获取 list 的内容:
13 list 的比较
数值数组用 ==
1 2 3 4
| let list1 = [1, 2, 3] let list2 = [1, 2, 3]
echo list1 == list2
|
字符串数组:
1 2 3 4 5
| let simple = ['hello', 'salam'] let simple = ['Hello', 'Salam']
set ignorecase echo simple == capital
|
14 提取子 list
1 2
| let list = [0, 1, 2, 3, 4, 5] let sublist = list[0:4]
|
可以用变量标识范围:
1 2 3 4
| let start = 2 let end = 4 let sublist = list[start:end] echo sublist
|
15 unpacking 一个 list
1 2
| let list = [1, 2, 3, 4] let [first, second, third, fourth] = list
|
16 探查 list
1 2 3 4 5 6 7 8 9 10 11
| let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
echo len(numbers)
echo max(numbers)
echo min(numbers)
echo count(numbers, 0)
echo index(numbers, 9)
|
17 将一个 element appending to 一个 list
1 2 3
| let first = [0, 1, 2] call add(first, 3) echo first
|
合并两个 list:
1 2 3 4
| let second = [3, 4, 5] let first = first + second
call extend(first, second)
|
18 将一个 element prepending to 一个 list
1 2 3
| let numbers = [7, 8, 9]
call insert(numbers, 6)
|
19 连接两个 lists
用 +
或 extend
:
1 2 3 4 5 6
| let first = [1, 2, 3] let second = [4, 5, 6]
let plug = first + second
call extend(first, second)
|
20 根据 index 删除一个 list 中的元素
用 remove
:
1 2 3 4
| let numbers = ['zero', 'one', 'two']
call remove(numbers, 1, 2) echo numbers
|
第二个参数为起始 index, 第三个为结束 index.
或者用 unlet
:
1 2 3 4
| let numbers = ['zero', 'one', 'two']
unlet numbers[1] echo numbers
|
21 利用循环遍历 list
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| let list = [1, 2, 3, 4, 5]
let index = 0 while index < len(list) let number = list[index] echo number
let index += 1 endwhile
for number in list echo number endfor
|
unpack 的例子:
1 2 3 4 5 6 7 8
| let address = [ \['Ichinomiya', 'Aichi', 'Japan'], \['Gombak', 'KL', 'Malaysia'] ]
for [city, state, country] in address echo city state country endfor
|
22 获取一个范围
1 2 3
| echo range(10) echo range(1,10) echo range(1,10,2)
|
23 复制一个 list
使用 copy
1 2 3 4 5 6
| let original = ['outer1', ['inner1', 'inner2']]
let copy = copy(original)
echo original echo copy
|
修改 copy 会影响原列表.
使用 deepcopy
则不会影响.
24 将 list 转换为 string
1 2 3
| let list = [1, 2, 3, 4, 5]
let string = join(list, "\n")
|
25 过滤一个 list
使用 filter
. 其会修改 list.
第二个参数是一个 string (包含筛选方式).
1 2 3 4 5
| let list = range(-10,10) echo list
call filter(list, 'v:var > 0') echo list
|
第二个参数为 funcref:
1 2 3 4 5 6
| function! Negative(key, value) abort return a:value < 0 endfunc
call filter(list, function('Negative')) echo list
|
26 排序一个 list
使用 sort
.
1 2 3 4
| let string = ['apple', 'orange', 'durian', 'mango', 'Banana', 'jackfruit'] let numbers = [5, 2, 1, 6, 3, 4]
echo sort(numbers)
|
可以查看第二个参数.
27 用自建函数来 sort list
同样需要传递 function reference.
1 2 3 4 5 6 7 8 9 10
| let string = ['apple', 'orange', 'durian', 'mango', 'Banana', 'jackfruit'] let numbers = [5, 2, 1, 6, 3, 4]
function! Reverse(a, b) abort return a:a - a:b endfunc
let FuncR = function('Reverse')
echo sort(numbers, FuncR)
|
28 reverse 一个 list
使用 reverse
.
1 2 3 4
| let string = ['apple', 'orange', 'durian', 'mango', 'Banana', 'jackfruit'] let numbers = [5, 2, 1, 6, 3, 4]
call reverse(numbers)
|
29 移除 list 中重复的元素
使用 uniq
:
1 2 3 4 5 6 7 8
| let numbers = [1, 2, 3, 4, 4, 4, 5, 7, 8, 9] let strings = ['orange', 'apple', 'mango', 'banana', 'orange']
call sort(numbers) call uniq(numbers)
call sort(strings) call uniq(strings)
|
需要先 sort
.
30 创建字典
1 2
| let uthman = { 'name': 'uthman', 'age': 30, } echo uthman
|
值可以是变量.
在 hash 之前加上 #
则不需要添加引号:
1
| let uthman = #{ name: name, age: age }
|
字典可以嵌套.
31 访问和修改字典
两种写法来访问:
1 2 3
| let uthman = #{ name: name, age: age } echo uthman['name'] echo uthman.name
|
添加或修改:
32 删除一对键值对
使用 remove
和 unlet
:
1 2 3
| let uthman = #{ name: name, age: age } call remove(uthman, 'name') call unlet uthman.age
|
33 合并两个字典
使用 extend
:
1 2 3 4
| let dict1 = #{ 1: '1 from dict1', 2: '2 from dict1', } let dict2 = #{ 3: '3 from dict2', 4: '4 from dict1', }
call extend(dict1, dict2)
|
注意相同的 key 所在的键值对会被重写. (可以改变 extend
的第三个参数改变行为)
34 用循环遍历字典
keys
可以获取全部键名.
values
可以获取全部值.
items
获取全部 pairs.
35 过滤字典
使用 filter
1 2 3 4
| let days = #{ 1: 'Sunday', 2: 'Monday', 3: 'Tuesday', 4: 'Wednesday', 5: 'Thursday', 6: 'Friday', 7: 'Saturday' }
call filter(days, 'v:key < 4') call filter(days, 'v:value =~ "t"')
|
同样可以传递 function reference.
36 将字典视为对象
1 2 3 4 5 6 7 8 9 10 11
| let person = #{ \name: 'uthman', \age: 30, \introduce: function('Introduce') \}
function Introduce() abort echo "My name is" self.name endfunc
call person.introduce()
|
也可以写为:
1 2 3 4 5 6 7 8 9 10
| let person = #{ \name: 'uthman', \age: 30, \} function person.introduce() abort echo "My name is" self.name "from person.introduce()" endfunc
call person.introduce()
|
37 使用 map() 处理 list 和 dict
同样可以传入 function reference 或 使用 lambda 函数:
1 2 3
| let numbers = range(1,100)
call map(numbers, { index, value -> value * value })
|
function reference 会自动被传入参数, 如果是 list 就是 index 和 value, dict 就是 key 和 value:
1 2 3 4 5
| function! WithIndex(key, value) abort return a:key . ' = ' . a:value endfunc
call map(list, function('WithIndex'))
|
38 定义和调用函数
函数名首字母需大写.
定义和调用如:
1 2 3 4 5
| function Greet() echo "Hello" endfunc
call Greet()
|
override 之前的函数可以加上 !
:
1 2 3 4 5
| function! Greet() echo "Hello" endfunc
call Greet()
|
查看一个函数在哪里定义的可以用 :verbose
, 如 :verbose function Greet
.
传递和使用参数 (注意 a:
):
1 2 3 4 5
| function! Greet(name) echo "Hello" a:name endfunc
call Greet('Jie')
|
可以设置默认参数值:
1 2 3 4 5
| function! Greet(name = 'bro') echo "Hello" a:name endfunc
call Greet()
|
39 函数有不定数量的参数
用 ...
, 访问时用 a:000
:
1 2 3 4 5 6
| function Basket(...) echo a:000 echo a:000[0] endfunc
call Basket('apple', 'banana', 'orange')
|
可以写为:
1 2 3 4 5 6
| function Basket(...) let args = a:000 echo args endfunc
call Basket('apple', 'banana', 'orange')
|
同时 a:1
也表示第一个参数.
40 函数引用
函数引用的变量也需要首字母大写.
使用 function
来获取引用:
1 2 3 4 5 6 7 8
| function Basket(...) let args = a:000 echo args endfunc
let FuncR = function('Basket')
call FuncR
|
41 lambda 表达式
本质上和 function reference 类似.
格式:
1 2
| let Add = { num1, num2 -> num1 + num2 } echo Add(5, 5)
|
前面的 num1, num2
表示有两个参数, num1 + num2
表示函数体.
注意, lambda 表达式中只能包含表达式, 不能包含命令.
42 local 作用域
添加 s:
(script):
1 2 3 4 5
| function! s:hello() abort echo "Hello" endfunc
call s:hello()
|
43 在 normal 中查看 function
输入 :function <TAB>
或者 :function! <TAB>
或者 :verbose function! <TAB>
<SID>
和 :scriptnames
的输出相关.
44 Buffer, 获取行号
使用 line
函数.
显示当前行的行号:
显示当前文件最后一行的行号:
显示当前 window 的第一行
显示当前 window 的最后一行
显示某一个 mark 的行号:
45 提取当前 Buffer 的行
使用 getline
, 其参数和 line
的使用一样.
1 2 3 4 5 6
| let line = getline('.') echo line
if line == '' echo 'empty string' endif
|
两个参数的形式, 获取一个范围的行:
1 2 3 4 5
| let lines = getline(1, 3)
for i in lines echo i endfor
|
46 替换当前 Buffer 里的行
使用 setline
1
| call setline(1, " haha")
|
替换一个范围的行, 传递一个 list:
1
| call setline(1, ['line 1', 'line 2', 'line 3'])
|
47 向当前 Buffer 添加行
使用 append
:
1
| call append('.', ' append line')
|
同样可以添加几行:
1
| call append($, ['line 1', 'line 2', 'line 3'])
|
48 在不打开一个 Buffer 的情况下创建和删除 Buffer
创建一个新的 buffer, 用 :badd name
(buffer add),
加载一个 buffer, 用 bufload
用 bufloaded
来判断一个 buffer 是否被 loaded.
setbufline 以及 appendbufline.
如:
1 2 3
| let lines = [ '# title: new file', '', 'the content here!', '', '# end of file' ] call setbufline('new', 1, lines) call appendbufline('new', 4, [ 'some more content', '' ])
|
读取 buffer 内容:
1
| echo getbufline('new', 3, '$')
|
删除 buffer 中的内容:
1
| call deletebufline('new', 2, 4)
|
49 创建 prompt buffer
1 2 3 4 5 6 7 8 9 10
| function! TextEntered(text) abort echo "You entered: " a:text endfunc
new set buftype=prompt let buf = bufnr() call prompt_setcallback(buf, function("TextEntered"))
nnoremap <buffer> <silent> <Escape> :bw!<CR>
|
关于 prompt buffer
在 Vim 编辑器中,set buftype=prompt
命令将当前缓冲区的类型设置为 prompt
。这将告诉 Vim 编辑器将当前缓冲区视为命令行提示符,而不是普通的文本文件或其他类型的缓冲区。
具体而言,set buftype=prompt
命令的作用包括:
将当前缓冲区标记为命令行提示符缓冲区,这意味着 Vim 将使用特定的方式处理此缓冲区。例如,不会保存文件,不会使用自动缩进等功能,不会进行撤销操作等。
允许 Vim 将当前缓冲区作为交互式 shell 的输入和输出,这可以让你在 Vim 中直接运行命令并查看命令输出,就像在命令行界面中一样。
允许 Vim 将当前缓冲区作为外部程序的输入和输出。这对于与其他程序的集成非常有用,例如使用 Vim 作为 Git 编辑器时,Git 可以将 Git 命令的输出发送到 Vim 的命令行提示符缓冲区,并在其中接收用户输入。
总的来说,使用 set buftype=prompt 命令将缓冲区类型设置为命令行提示符可以让 Vim 在某些情况下更加灵活和强大。
50 append text 到 prompt buffer
1 2 3 4 5 6 7 8 9 10 11 12
| function! TextEntered(text) abort
call append(line('$') - 1, "You entered: " . a:text)
endfunc
new set buftype=prompt let buf = bufnr() call prompt_setcallback(buf, function("TextEntered"))
nnoremap <buffer> <silent> <Escape> :bw!<CR>
|
51 制作终端模拟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function! s:on_stdout(id, data, event) dict let str = join(a:data, "\n") echo str
call append(line('$') - 1, a:data) endfunc
let opts = #{ on_stdout: function('s:on_stdout') }
let g:job_id = jobstart(['/bin/sh'], opts)
function! s:callback(input) abort call chansend(g:job_id, [a:input, '']) endfunc
new set buftype=prompt call prompt_setcallback(bufnr(), function('s:callback')) nnoremap <buffer> <silent> <Escape> :bw!<CR> startinsert
|
52 面向对象编程
构造器:
1 2 3 4 5 6 7 8
| let person = {}
function! person.init(name, age) abort let object = { name: a:name, age: a:age } return object endfunc
let uthman = person.init('uthman', 30)
|
53 方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| let person = {}
function! person.init(name, age) abort let object = { name: a:name, age: a:age } function! object.introduce() abort echo "My name is" self.name echo "I am" self.age "years old" echo "Nice to meet you" endfunc return object endfunc
let uthman = person.init('uthman', 30)
|
54 修改对象属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| let person = {}
function! person.init(name, age) abort let object = { name: a:name, age: a:age } function! object.introduce() abort echo "My name is" self.name echo "I am" self.age "years old" echo "Nice to meet you" endfunc
function! object.aged(years = 1) abort let self.age += a:years endfunc
return object endfunc
let uthman = person.init('uthman', 30)
|