首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
138 阅读
2
nvim番外之将配置的插件管理器更新为lazy
98 阅读
3
2018总结与2019规划
69 阅读
4
从零开始配置 vim(15)——状态栏配置
58 阅读
5
PDF标准详解(五)——图形状态
46 阅读
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
linux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
Thinking
FIRE
菜谱
登录
Search
标签搜索
c++
c
学习笔记
windows
文本操作术
编辑器
NeoVim
Vim
win32
VimScript
emacs
linux
elisp
文本编辑器
Java
读书笔记
反汇编
OLEDB
数据库编程
数据结构
Masimaro
累计撰写
331
篇文章
累计收到
31
条评论
首页
栏目
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
linux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
Thinking
FIRE
菜谱
页面
归档
友情链接
关于
搜索到
104
篇与
的结果
2022-08-08
从零开始配置 vim(9)——初始配置
虽然本系列文章叫做从0开始配置vim,似乎我们从一开始就要写vimrc配置文件,但是我们并没有这么做。我们先经过几篇文章了解了下面的几个内容如何设置vim属性,从而改变vim的特征配置快捷键,以提高我们的使用效率使用自动命令,以便使用vim来自动化我们的相关操作这些既有vimscript的东西,也有vim自身一些特性的描述。拥有这些基础知识之后,在阅读其他人写的配置或者自己配置将会变得更加容易。当然关于vim我们还有很多内容没有讲,例如该如何自定义命令,如何弹出一个窗口,以及到最后如何编写自己的插件。如果后续在配置过程中涉及到新的内容,我将会给大家进行讲解,尽量让大家明白我们配置的每行代码都有哪些作用,让大家不仅仅是照着抄一遍,而是能举一反三,根据自己的习惯打造完全属于自己的 vim。话不多说,下面就让我们从0开始来一步一步的将原始落后的vim打造成现代化的好用的编辑器。相应的准备工作开始配置前,让我们进行一些准备工作。我们采用 neovim 进行配置,也打算使用 纯 lua 进行配置。如果你用的是 vim,请安装下载最新的 neovim。我本地的环境采用的是 neovim0.7.2 版本,你可以使用稍微低一点的版本,但至少保证版本在 0.6 及以上版本。(不要怪我一直变换版本,因为7以上的版本添加了自动命令的 lua 接口。)我随教程创建了一个 github仓库用于保存记录每次的配置,各位小伙伴可以克隆下来,也可以自己按照上面的目录结构和文章所描述的自己一步步手动组织。仓库地址: nvimrc-tutorial 。我们先使用 git clone https://github.com/aMonst/nvimrc-tutorial.git ~/.config/nvim 将仓库克隆到本地,然后在里面创建一个 init.lua 文件作为配置文件的入口基础配置我们在 init.lua 中写入如下内容作为基础配置-- 设置文件编码格式为 utf-8 vim.g.encoding = "utf-8" -- 设置终端编码格式为 utf-8 vim.o.termencoding = "utf-8" -- 开启语法高亮 vim.o.syntax = "enable" -- 显示相对行号 vim.o.relativenumber = true -- 显示行号 vim.o.number = true -- 高亮所在行 vim.o.cursorline = true -- 自动换行 vim.o.wrap = true -- 显示光标位置 vim.o.ruler = true -- 边输入边搜索 vim.o.incsearch = true -- 开启搜索匹配高亮 vim.o.hlsearch = true -- 搜索时自行判断是否需要忽略大小写 vim.o.smartcase = true -- tab键转换为 4 个空格 vim.o.tabstop = 4 vim.o.softtabstop = 4 vim.o.shiftwidth = 4 -- 新行对齐当前行,tab转换为空格 vim.o.expandtab = true vim.bo.expandtab = true vim.o.autoindent = true vim.bo.autoindent = true vim.o.smartindent = true -- << >> 缩进时移动的长度 vim.o.shiftwidth = 4 vim.bo.shiftwidth = 4 -- 使用jk移动光标时,上下方保留8行 vim.o.scrolloff = 8 vim.o.sidescrolloff = 8 -- 设置自动折叠 vim.o.smartindent = true -- 历史命令最多保存1000条 vim.o.history = 1000 -- 显示空白字符 vim.o.list = true -- 样式 vim.o.background = "dark" vim.o.termguicolors = true vim.opt.termguicolors = true完成之后,再次打开vim发现它已经变成了这样本篇就到这里了,下一篇我们将对默认的快捷键进行配置
2022年08月08日
11 阅读
0 评论
1 点赞
2022-08-05
从零开始配置 vim(8)——文件类型检测
在上一章介绍自动命令的时候,我们提到可以使用 FileType来根据文件类型来触发事件,但是关于文件类型并没有深入的介绍,本篇我们来补充关于文件类型相关的内容,让大家更好的理解,看不懂也没关系,你只需要知道vim能识别各种编程语言的文件并启用事先定义好的配置即可。事先做几点声明:跳过这篇文章对后面介绍的内容的理解不会有任何障碍,如果你不想看,直接拉到最后看结论即可1. 跳过这篇文章对后面介绍的内容的理解不会有任何障碍,如果你不想看,直接拉到最后看结论即可1. 跳过这篇文章对后面介绍的内容的理解不会有任何障碍,如果你不想看,直接拉到最后看结论即可1. 跳过这篇文章对后面介绍的内容的理解不会有任何障碍,如果你不想看,直接拉到最后看结论即可本篇文章会针对 neovim 的部分代码进行简单的剖析以便深入讲解文件类型。涉及到的 neovim 版本为 0.7.2,如果你使用的是更早版本,代码可能会不太一样,但是重点代码应该是一样的2. 本篇文章会针对 neovim 的部分代码进行简单的剖析以便深入讲解文件类型。涉及到的 neovim 版本为 0.7.2,如果你使用的是更早版本,代码可能会不太一样,但是重点代码应该是一样的2. 本篇文章会针对 neovim 的部分代码进行简单的剖析以便深入讲解文件类型。涉及到的 neovim 版本为 0.7.2,如果你使用的是更早版本,代码可能会不太一样,但是重点代码应该是一样的2. 本篇文章会针对 neovim 的部分代码进行简单的剖析以便深入讲解文件类型。涉及到的 neovim 版本为 0.7.2,如果你使用的是更早版本,代码可能会不太一样,但是重点代码应该是一样的里面的代码可能有些小伙伴并不能理解,但是我们只是通过代码来描述它的一些流程,不理解代码能理解这个流程也是OK的,再退一步即使不理解流程,也没关系,毕竟我们只需要知道它有这个功能,不需要知道它的细节,不理解细节完全不会阻碍我们使用并对它进行配置3. 里面的代码可能有些小伙伴并不能理解,但是我们只是通过代码来描述它的一些流程,不理解代码能理解这个流程也是OK的,再退一步即使不理解流程,也没关系,毕竟我们只需要知道它有这个功能,不需要知道它的细节,不理解细节完全不会阻碍我们使用并对它进行配置3. 里面的代码可能有些小伙伴并不能理解,但是我们只是通过代码来描述它的一些流程,不理解代码能理解这个流程也是OK的,再退一步即使不理解流程,也没关系,毕竟我们只需要知道它有这个功能,不需要知道它的细节,不理解细节完全不会阻碍我们使用并对它进行配置3. 里面的代码可能有些小伙伴并不能理解,但是我们只是通过代码来描述它的一些流程,不理解代码能理解这个流程也是OK的,再退一步即使不理解流程,也没关系,毕竟我们只需要知道它有这个功能,不需要知道它的细节,不理解细节完全不会阻碍我们使用并对它进行配置让我们进入相应的主题吧文件类型简介在 vim 中可以使用 filetype plugin indent on 来打开文件类型检测,而在 neovim 中已经默认打开了这些属性,因此我们可以不设置这些。我们可以使用 :filetype 来查看打开的状态。它会返回如下的内容 filetype detection:ON plugin:ON indent:ON 我们发现它包含了三个部分。上述的设置语句我们可以将它拆分成3个部分:filetype on filetype plugin on filetype indent on它打开了三个东西,文件类型检测,针对文件类型相关的插件,针对文件类型相关的缩进和隐藏代码块的格式。下面我们依次来介绍这些东西文件类型检测filetype on 将打开文件类型检测。如果该项被打开,vim 在初始化的时候会读取脚本 $VIMRUNTIME/filetype.vim 和 $VIMRUNTIME/filetype.lua 的内容。这两个脚本用来识别文件类型。$VIMRUNTIME 是 vim 里面的环境变量与 $MYVIMRC 类似,我们可以通过使用 :echo $VIMRUNTIME 来查看具体的路径,也可以直接在命令模式中将它当做一个路径来使用我们先来阅读以下 filetype.vim 的内容,在这段脚本中,我们可以发现大量这样的语句au BufNewFile,BufRead *.cxx,*.c++,*.hh,*.hxx,*.hpp,*.ipp,*.moc,*.tcc,*.inl setf cpp au BufNewFile,BufRead $VIMRUNTIME/doc/*.txt setf help au BufNewFile,BufRead .htaccess,*/etc/httpd/*.conf setf apache au BufNewFile,BufRead */etc/apache2/sites-*/*.com setf apache结合我们之前学习的自动命令相关的内容可以知道,这些代码会根据文件路径和后缀来自动设置文件类型。从这写代码中可以看到,vim 也是靠命令来设置文件类型的。使用 :setf 或者 使用 :set filetype=c 或者使用它的简写形式 set ft=c来设置文件类型除了根据文件后缀,vim 也可以根据文件内容来判别文件类型。我们进入到 filetype.lua 中可以看到,真正根据文件内容来决定类型是通过文件 script.vim 。该文件中主要使用正则表达式来匹配对应的特征值从而确定该文件类型,例如脚本中有这么一些代码elseif s:line1 =~# '<?\s*xml.*?>' set ft=xml " XHTML (e.g.: PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN") elseif s:line1 =~# '\<DTD\s\+XHTML\s' set ft=xhtml " HTML (e.g.: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN") " Avoid "doctype html", used by slim. elseif s:line1 =~? '<!DOCTYPE\s\+html\>' set ft=html elseif s:line1 =~? '-\*-.*C++.*-\*-' set ft=cpp如果我们的文件无法满足 vim 识别文件类型的要求,也可以在文件中添加注释来帮助 vim 进行识别例如使用如下注释来使vim 确定它是一个 c 的代码/* vim: ft=c */可以在注释中使用 vim: ft= 来设置文件类型。除了设置文件类型,这类注释还是设置像文件是否显示行号、列宽等等信息。更多信息可以查看 :help modeline 。文件类型插件在得到文件类型之后,vim 会根据文件类型加载不同的文件插件。它也是一个脚本,该脚本为 $VIMRUMTIME/ftplugin.vim 。打开这个文件,我们需要重点关注这么几句代码for name in split(s, '\.') exe 'runtime! ftplugin/' . name . '.vim ftplugin/' . name . '_*.vim ftplugin/' . name . '/*.vim' " Load lua ftplugins exe printf('runtime! ftplugin/%s.lua ftplugin/%s_*.lua ftplugin/%s/*.lua', name, name, name) endfor其中 s 是一个字符串,它是一个包含了扩展名的文件名,在这里以 . 作为分割,读取它以.分割的所有内容。例如 aaa.bbb 会被分割为 aaa 和 bbb。然后根据 aaa 和 bbb 来分别执行下面的循环exe 是用来执行对应文件内代码的语句。后面是一个字符串的拼接,假设当前打开的是一个.py 结尾的文件,对应的这句话就可以拼接为 exe 'runtim! ftplugin/py.vim ftplugin/py__*.vim' ftplugin/py/*.vim 。后面两句拼接的内容相似,只是一个是给vim 脚本用的,一个是给 lua 脚本用的。这里我们以 lua脚本为例。runtime! 你可以理解成 python 的 import 或者 c/c++ 中的 #include,加载文件的路径一个是 $VIMRUNTIME 所在路径,我们可以在 $VIMRUNTIME/ftplugin 目录中找到很多语言预定义的设置,还有一个是配置文件所在的根目录。对于 neovim 来说,这个路径就是 ~/.config/nvim 。这样我们就明白了,我们可以将对应文件类型的个性化配置放到 ~/.config/nvim/ftplugin 目录中。以 python 为例来说的话。它会加载 ftplugin/py.lua ,ftplugin/py_*.lua (以py 开头,以 .lua 结尾的文件), ftplugin/py/*.lua(py 目录下所有的lua文件)。这样以后针对不同语言的设置完全可以在 ftplugin 中以对应名字命名。从而更好的组织我们的目录结构。文件类型缩进文件类型缩进运行我们为不同类型的文件设置不同格式的缩进,例如有的习惯使用4空格缩进,有的习惯使用 2空格或者8空格缩进。定义缩进格式的脚本是 $VIMRUNTIME/indent.vim 。在这个文件中我们又见到了类似的写法for name in split(s, '\.') exe 'runtime! indent/' . name . '.vim' exe 'runtime! indent/' . name . '.lua' endfor有了上面讲解的基础,理解这段代码就容易多了,它这里加载的主要是 indent 目录中以后缀命名的缩进文件。但是它默认加载的文件比较少。从代码上看.py 文件如果使用 python.vim 应该是不会被加载的,但是它默认的目录中针对 python 的缩进仍然是以 python.vim 命名,就证明它是可以被加载的。这里我还不理解为什么会被加载。有知道的小伙伴可以在评论区留言,大家一起交流学习。 好了,本章内容就到这里了。前面分析了那么多内容,总结起来就很简单的几点# 最后的结论vim 可以根据文件后缀和文件内容来决定文件类型。如果无法决定也可以使用 set ft 来设置,或者在文件头部添加注释 vim: ft= 来知名类型我们可以针对不同文件类型进行个性化配置,包括插件和缩进,插件的用户配置文件的路径在 ~/.config/nvim/ftplugin 中,以类型名命名。缩进的配置在 ~/.config/nvim/indent 目录中,以类型名命名。
2022年08月05日
12 阅读
0 评论
0 点赞
2022-08-04
从零开始配置 vim(7)——自动命令
这篇我们来谈论vim一个相当重要的东西——自动命令。从编程的角度来看,自动命令有点类似于事件响应,或者回调函数之类。当外部发生某些事件的时候,自动执行事先定义好的一组命令。定义一个自动命令的格式如下autocmd type pattern cmdautocmd: 自动命令以 autocmd 关键字开始,它的作用类似与 js 中定义函数时使用的 function 关键字type: 触发该命令的事件类型pattern: 事件的过滤,根据不同的事件类型有不同的含义cmd : 将要执行的命令说了这么多,我们以一个例子来说明:当我们使用 vim 打开一个不存在的文件,如果直接退出,我们会发现它并没有被保存。因为打开一个不存在的文件时 vim 并没有真的在磁盘中创建这么一个文件,它仅仅新开了一个缓冲区,当执行写命令的时候才真正会创建文件。我们使用 q! 退出的话,它是不会往文件中写的我们来试试修改这一行为,打开新文件的时候就创建,也就是打开一个新文件的时候就执行写操作。打开新文件的事件使用 BufNewFile 来表示。这里我们不限定文件格式,因此 pattern 这块就使用 * 来表示,执行的命令是 :w 来写入。:autocmd BufNewFile * w自动命令的事件类型自动命令可以监听的事件类型主要有以下几种开始编辑一个当前并不存在的文件,也就是我们上面介绍的一种情况。这种情况使用 BufNewFile 来表示开始编辑一个已存在的文件。这种情况使用 BufReadPre 或者 BufReadPost 来表示。他们分别表示文件内容被加载前和被加载后改变一个缓冲区的 filetype 选项的时候,它与 vim 的文件类型配合使用。这种情况使用 FileType 来表示文件被写回磁盘。这种情况用 BufWritePre 和 BufWritePost。他们的含义与上面 BufReadPre 和 BufReadPost 类似。进入和退出插入模式,进入插入模式时使用 InsertEnter,退出插入模式时使用 InsertLevel。Vim 完成启动所有初始化操作之后可以使用 VimEnter 来表示输入可以使 vim 退出的命令,可以使用 ExitPre 来表示。如果输入 :quit ,在决定是否退出之前,可以使用 QuitPre。这些只是 vim 庞大事件中的一小部分,想要了解其他的事件,可以使用 :help autocmd-events同时绑定多个事件我们可以同时绑定多个事件,事件之间使用逗号作为分割即可,例如我们想要在写入或者加载HTML文件之前对其进行自动排版,那么就可以使用如下代码:autocmd BufReadPost,BufWritePre *.html normal gg=G自动命令它是在事件触发时,执行命令。相当于我们在命令模式下手动输入命令。在之前介绍命令模式的时候说到过,要在命令模式下使用普通模式的操作可以使用 normal。gg表示将光标移动到第一行,=G表示从当前光标到最后一行执行自动排版的操作。我们在 html 文件中输入<html> <body> <div> <div> <p>hello!</p> </div> </div> </body> </html>执行 :w之后我们发现它自动排版了。或者我们也可以使用 :edit打开一个排版混乱的HTML文件,会发现vim自动为它排版了。或者我们再举一个例子,我们在之前设置了自动换行功能,因为在一般的编程语言中,一行代码写太长确实不是一个好习惯。但是像 markdown 或者 html 这种用来写文档的标记语言,难免会出现很长的文本,这个时候再设置自动换行就有点不合适了,我们可以使用下面的语句来针对这两种文档来消除:autocmd BufNewFile, BufReadPost *.html setlocal nowrap这里我们使用 BufNewFile和 BufReadPost,因为我们需要对新创建的和已存在的 html文件都启用该设置。FileType 事件这种类型的事件可以说是我们最常用的,通过这个事件配合 setlocal 可以很方便的针对不同的编程语言做不同的设置例如我们将上述取消 HTML 自动换行的代码做一个改写,改写成使用 FileType:autocmd FileType html setlocal nowrap又或者我们可以根据不同的语言,定义一个快捷键快速添加注释:autocmd FileType python nnoremap <buffer> <localleader>c I#<esc> :autocmd FileType javascript nnoremap <buffer> <localleader>c I//<esc>在输入完命令之后,我们新打开一个 js或者 python文件,就可以直接测试我们也可以结合之前介绍过的本地缩写的定义,针对不同的文件类型定义不同的缩写,例如:autocmd FileType c iabbrev <buffer> main int main(int argc, char* argv[]) :autocmd FileType python iabbrev <buffer> main if __name__ == "__main__":针对不同语言快速填充main函数。我们结合FileType 事件和缩写似乎可以针对不同语言定义出对应的代码片段,这个也就是有的编辑器提供的 code snippet 的功能,结合插件我们可以使用 vim 定义出更加强大的代码片段自动命令组已经讨论了自动命令的这么多东西了,各位小伙伴可能已经掌握了甚至已经开始迫不及待想往配置文件里面添加内容了。但是在 lua中该怎么使用自动命令呢?先别着急,自动命令相关内容还没讨论完,先容我卖个关子,我们在后面来讨论如何在 lua中添加自动命令吧。我们暂时不讲如何在 lua 中添加自动命令,这里我们先尝试启用 init.vim 文件。我们在里面加入一行autocmd BufWrite * sleep 200m然后我们保存并使用 :source $MYVIMRC启用好像也没什么变化是不是。别着急,我们多次执行 :source $MYVIMRC。然后再执行保存操作。是不是发现vim越来越慢了。这是怎么回事呢?我们每次执行 :source $MYVIMRC 的时候,vim 不会丢弃原有的设置,只会重头再来读取并加载新的设置,有点像文件的追加。在多次加载配置文件的时候,vim 已经创建了多个自动命令了。随着加载次数的增多,vim 中保存了多个休眠的自动命令了。所以 vim 会变得越来越卡。你可能会说,谁没事闲着一直加载配置文件玩啊,而且也没有人会写延时吧。但是想想这个场景是不是像我们在反复修改并测试配置的时候会做的操作。虽然我们不会做延时,但是加载配置或者加载插件也是要时间的,插件有的也会执行自动命令,如果数量大起来了,自然会影响vim的启动速度。我们该如何处理这个问题呢?vim中给出的解决办法是将自动命令放到一个用户命名的组中,组成一个自动命令组。使用关键字 augroup 来创建一个自动命令组。例如我们可以创建下面的自动命令组:augroup testgrp : autocmd BufWrite * echom "hello1" : autocmd BufWrite * echom "hello2" :augroup END直接在命令行输入这么些东西太麻烦了,我们还是在 init.vim 中输入。启用之后我们再来执行保存操作接着,执行 :message 命令来查看日志,发现有两条打印我们再来修改一下配置文件或者在命令行输入添加下面一句:augroup testgrp : autocmd BufWrite * echom "hello3" :augroup END我们先退出vim,再打开,然后执行保存操作,再看看日志里面有几条输出呢?答案可能会另各位百思不得其解,它会打印三条。并不是各位想象的那样,同名的组发生覆盖。这里它也会发生追加现象,将同一组的多个命令组合在一起。既然用不用组都会追加,那么我要它有何用,我还多写了这么多代码。别着急,我们慢慢往下看。分组一个是为了划分模块,第二个原因就是我们可以使用 autocmd! 来清除同一组之前的命令。例如我们将上述命令修改为:augroup testgrp : autocmd! : autocmd BufWrite * echom "hello3" :augroup END这个时候再次测试,我们发现它只会打印一条语句了。但是这里如果我们将它放在不同组的时候,情况就又发生变化了:augroup testgrp : autocmd BufWrite * echom "hello1" : autocmd BufWrite * echom "hello2" :augroup END :augroup testgrp1 : autocmd! : autocmd BufWrite * echom "hello3" :augroup END我们发现在保存之后,它还是会打印3条语句autocmd! 只会清除同一组之前的所有命令,而不同组的命令它不会生效。这就给我们按模块划分命名提供了便利。改进自动加载配置文件的操作之前我们通过绑定快捷键 <leader>ss来自动重新加载配置,学习了自动命令之后我们可以进一步的偷懒了,利用自动命令,我们可以做到只要配置文件被保存了,就自动加载。:augroup NVIMRC : autocmd! : autocmd BufWritePost init.vim source % :augroup END这里我们先使用 autocmd!清除之前的加载操作。后面的自动命令中,我们使用 BufWritePost在配置文件保存到磁盘之后再来执行加载操作,保证从磁盘中加载到的配置文件与我们修改过后的保持一致。自动命名在我们实现 vim 自动化编程的一个重要工具。甚至 vim 自身也有很多功能依靠它来实现,比如文件类型检测。文件类型检测我们将在下一章进行讨论。
2022年08月04日
7 阅读
0 评论
1 点赞
2022-08-03
从零开始配置 vim(6)——缩写
关于vim能快速编辑文本的能力,我们见识到了 operator + motion ,见识到了. 范式和宏。甚至可以使用命令来加快文本编辑。在后面我们又介绍了快捷键绑定来快速执行我们想要的操作。今天我们再来介绍一个新的能加快我们编辑文本速度的东西——Abbreviations缩写简介Abbreviations 翻译成中文的意思大概是缩写。但是仅仅以缩写来描述这个特性,似乎是不够的,但是也找不到准确的中文来描述,暂时就采用这个名称吧。它的这个特性允许我们将输入的一段内容自动更新为新的内容我们先来体验一下它的基本用法。在命令中输入 :iabbrev mian main我们输入 mian( 后它会自动将内容替换为 main(。这样即使我们手误将 main 写成了 mian ,vim能自动帮我们更新。再也不用怕编辑器报找不到 main 函数了我们发现了它的第一个用途——纠正笔误。但是基于这一特性,我们还可以使用几个简单的字符来快速展开成常用的长文本。例如:iabbrev pcr Copyright 2022 Masimaro, all rights reserved 通过输入 pcr(program copy right) 来快速产生一条程序的版权信息。又或者在 python 使用 nmain 展开成 if name== "__main__":。快速写下测试语句。我们发现 iabbrev 是 i+ abbrev 合成的一条命令。看到这相信各位小伙伴应该明白了。这个命令是作用于插入模式下。该特性还可以作用于 命令模式和替换模式。但是这里就不对它做深入的介绍了。有兴趣的小伙伴可以查看vim手册来了解。对比键盘映射我们可以使用快捷键映射来达到同样的效果,例如我们可以定义 :inoremap mian <esc>viwdimain 同样可以达到更正 mian 为 main 的效果但是我们发现这有几个弊端,第一因为我们定义了一个 mian 的关键字,这就需要手速要够快了,在短时间内输入完成 mian 。第二我们针对只输入mian 确实能达到更正的效果,但是如果我连着其他的语句一起输入就不一定有这个效果了,例如我们想输入 miantest 但是它会给我们替换成 maintest 这就有点得不偿失了。在这种情况下,abbreviations 可以正常工作。而且我们发现相比于使用映射,abbreviations 显得更为简洁,也更加符合逻辑。keywords characters我们发现在使用 abbreviations 这一特性的时候,只有在输入空格或者回车的时候它才会启用自动更新,但是输入字母的时候却不会。如何定义输入何种字符的时候它才会启用自动更新呢?abbreviations 这一特性是在我们输入 non-keyword character 的时候会检查上一个 non-keyword character 到这个之间的单词是否符合之前定义的替换规则,如果符合将会发生替换行为,否则不会发生。只要定义了 non-keyword character 就可以定义它发生更新的时机。那么我们该如何定义 non-keyword character 字符呢?只要不在 iskeyword 中的字符都算是 non-keyword character。我们执行 set iskeyword? 可以看到 iskeyword 的定义如下:@,48-57,_,192-255看起来很复杂是不是?首先 @ 代表字母字符,48-57是字符0到字符9的ascii 编码,_ 单纯的代表下划线,192-255代表ascii码中一些特殊字符。你只需要记住它包含一切字母,数字,_ 以及一些特殊字符。或者更简单地说,格式控制字符(像空格、制表符、回车)都会触发这一行为。如果你想修改 keyword 。可以在vim手册中详细阅读关于 iskeyword 部分的说明。这里就不再过多介绍,我认为当前定义更符合编码时的直觉。本地缓冲缩写结合上一章学习的本地设置,我们也可以设置本地缓冲的缩写,例如:iabbre <buffer> mian main我们发现它只在当前缓冲区中启用了。到现在我们似乎可以结合缩写的这个特性完成代码片段的功能呢。但是别着急,要得到这个功能,还得接着往下学习。如何形成记忆跟快捷键类似,我们一时兴起,根据自己的习惯定义了一堆缩写,例如 定义 fnc 为 function,定义 ret 为 return 结果自己之前养成了把这些关键字都输全的习惯。后面怎么也改不过来,这些都白定义了,该如何解决这个问题呢?与我们当初禁用快捷键类似,我们也可以禁用某些内容,只是iabbrev 并没有提供类似 <nop> 的指令已达到禁用的目的,但是我们我们可以将对应的字符串映射成为某些无效的字符。例如我们使用如下两个命令:iabbrev return <space> :iabbrev ret return为了养成习惯我们将 return 映射为空格,一旦我们习惯输入 return 就会意识到我们已经用简写 ret 代替了。当我们养成肌肉记忆之后这条映射的作用也就显得可有可无了。
2022年08月03日
5 阅读
0 评论
1 点赞
2022-08-02
从零开始配置 vim(5)——本地设置与全局设置
在前面的一系列文章中,我们介绍了使用 :noremap 进行键盘映射,使用 set 来设置选项和 vim 的变量。并且已经在配置文件中对他们进行了相关配置。在介绍设置那一篇文章中我们提到了,lua 提供的函数有全局设置、窗口设置和缓冲区设置。当初有小伙伴在评论区问到相关问题,现在我们就来详细的解释这些之前被搁置的内容。本地缓冲区设置与本地窗口设置我们先以一个例子来说明我们先注释掉配置文件中显示行号的设置,然后随机打开一个文件例如我打开 nvim-config/init.lua 。在这个缓冲区中,我们使用 :set number来显示行号。这个时候不管如何打开新的文件,我们发现新打开的文件都会显示行号,这没什么新鲜的。接下来我们来点不一样的。如果我不希望新打开的文件显示行号,但是又希望原来的文件能够显示行号该怎么办呢?要实现这个功能,我们可以使用本地缓冲区设置。使用 set 来设置全局选项,但是使用 setlocal 可以设置当前被打开缓冲区的选项。例如这里要实现这个功能,我们只需要在老文件中使用 setlocal number。再打开新文件就会发现它只在原来的缓冲区中显示了行号。我们可以在配置文件中使用 setlocal 来针对不同缓冲区进行不同的设置。我们之前介绍缓冲区的时候说过,缓冲区是被随机进行编号的。每次打开或者关闭不同的文件会导致缓冲区变化发生变化,这就导致了我们没办法通过编号精准的为每个缓冲区设置我们想要的效果(不过这个需求也基本很少遇到就是了,后续将会学习新的技术来实现这一需求)在 vimscript 中,统一使用 setlocal 来设置本地选项。但是在 lua 中,对窗口值和缓冲区值进行了区分。并且定义了 vim.api.nvim_buf_set_option 来设置缓冲区值,定义 vim.api.nvim_win_set_option 来设置窗口值。例如我们上面演示了 number 就是一个窗口值,我们在配置文件中加上一句 vim.api.nvim_win_set_option(0, 'number', true) ,将0号窗口设置为显示行号本地leader 键既然选项分本地和全局两类,那么其他设置也基本遵守本地和全局设置。本地 leader 可以使用 localleader 来设置本地快捷键,例如 :let maplocalleader = " "。在 neovim中使用 vim.g.maplocalleader 来设置本地 leader 键作为普通用户来说,我仅仅是进行配置,让 vim 更好用,我更喜欢所有的 leader 都一样。因此我平时很少使用,但是不能排除有的插件使用 localleader 作为快捷键,这个时候我推荐将 leader 和 localleader 设置成同一个键。本地快捷键与全局快捷键我们同样可以定义本地缓冲的快捷键,使用 :nnoremap <buffer> <leader>x dd 来定义只在当前缓冲区中将 <leader>x 定义为删除一行这个有前面的基础应该很好理解,在结束本节之前,我们来看点不一样的我们打开一个文件在命令行中输入:nnoremap <buffer> Q x :nnoremap Q dd然后再执行 Q 发现它只删除了一个字符,没有执行 dd命令。这是因为定义的本地行为把全局行为给覆盖掉了。我们可以理解为局部变量会覆盖全局变量。但是我们切换到新的文件发现它执行的是 dd操作,以编程语言作为类比的话,此时已经跳出了局部设置的生命周期了。这里我们看到设置本地选项似乎作用不大,与其分开设置到不如用全局设置一次性设置好的了。看起来本地设置似乎是vim提供的一个比较鸡肋的功能。别着急,本地设置将在后面介绍的内容中大放异彩。
2022年08月02日
6 阅读
0 评论
1 点赞
2022-07-15
从零开始配置 vim(4)——键盘映射的一些技巧
通过前面的学习,我们已经知道了如何进行键盘映射,并且也知道了在任何场合应该使用非递归版本的映射。这篇再介绍一些使用关于快捷键映射的内容作为收尾快速编辑 vimrc 文件通过前面掌握的知识,相信各位小伙伴已经在配置文件中加入了不少配置了。不知道小伙伴们加配置是怎么加的呢?是不是先进入配置文件,编辑完了之后退出,再重新进入看看配置是否生效呢了?又或者在使用vim编程的过程中觉得需要加入某个属性或者特性。这个时候是不是要先退出当前编辑的文件,或者聪明一点的小伙伴知道使用 :vs 命令新建一个窗口打开配置文件。但是在编辑完了配置文件,想让它生效还是得先退出vim,然后再进入。如果配置出错,就得不断的退出进入。这个过程是很耽误编程的。有没有想过怎么改进呢?我们学了快捷键的映射,完全可以定义两个快捷键用于快速打开和应用配置文件。在完成这个事情的过程中需要了解绍一个变量和一个命令。要介绍的变量是 $MYVIMRC 它代表当前vim使用的配置文件的路径,针对neovim来说,如果你使用init.vim作为配置文件,那么它的值就是 ~/.config/nvim/init.vim。如果你用 init.lua 作为配置文件,那么它的值就是 ~/.config/nvim/init.lua 。只要你的配置写的位置是正确的,使用它总能对应上要介绍的命令就是 :source 命令。熟悉 shell 的应该对这个命令不陌生,shell 中,使用 source 来使对应的配置文件生效。vim中它也是使vim的配置文件生效。两个命令的用法也一样,都是跟对应配置文件的路径。使用它配合 $MYVIMRC 能做到在不退出vim的过程中重新加载配置有了这两个东东,我们就可以定义出快捷键了vim.api.nvim_set_keymap("n", "<leader>ee", ":vs $MYVIMRC<CR>", {silent = true, noremap = true}) vim.api.nvim_set_keymap("n", "<leader>ss", ":source $MYVIMRC<CR>:q<CR>", {silent = true, noremap = true})它的效果如下这里我使用 ee 来打开主要考虑到 e 代表的是 edit ,s 代表 s 或者 source 比较好记,各位小伙伴可以先使用其他方便记忆的按键。如果在写完配置之后,不想按 :w 来保存,完全可以将 <leader>ss 映射为 :wq<CR>:source $MYVIMRC<CR>。将保存和启用一并使用。我自己是属于那种稍微改一点就要按 :w 来保存的人。我这里就只需要启用就行。在保存并启用之后,我这里又用了 :q 来关闭之前打开的新窗口。现在你就又可以专注于当前的编程任务了。学会使用新映射的快捷键从插入模式回到普通模式有这么几种方式 <esc>、<Ctrl+[>和 <Ctrl +c>。但是不管哪种方式都存在比较难按的情况,手指需要移开较大距离我们可以使用快捷键映射的方式,将 jk 映射为退出键(这里就可以使用上面定义的快捷键快速的打开配置文件了)vim.api.nvim_set_keymap("i", "jk", "<esc>", {silent = true, noremap = true})这个时候我们似乎用 <esc>习惯了,已经形成肌肉记忆了,只要一想到退回到普通模式,就下意识的使用 <esc>,我们辛辛苦苦分析建立的更高效的快捷键完全没有用处。又或者有 vim 高手指出,要学会更快速的移动光标应该摒弃 j、k、l、h 这些按键,但是明明知道用w或者 f 能更快速的移动光标,但是有时候就是控制不住手,手不自觉的就按到这些键上面去了,就像我在使用 notepad 时总是无意识的输入 <esc>:wq 来保存退出一样。该如何处理这种情况呢?一种有效的办法是将它们都设置为无效键,当你下意识的使用到这些被无效的键时发现它没任何作用,此时你会意识到自己将它们定义为了无效键,同时你也会想起来该使用之前定义的那些更高效的替代品。虽然开始你可能不太习惯,但是一旦形成记忆,你会跟以前一样得心应手。我们可以使用 <nop> 来定义一个键失效, 例如我可以使用 :inoremap <esc> <nop>。定义之后在插入模式下就无法使用 <esc> 来退回到普通模式了。在 lua 中就可以使用如下语句来取消 escvim.api.nvim_set_keymap("i", "<esc>", "<nop>", {silent = true, noremap = true})我们可以看到,在写下那段配置之后,<esc> 已经无法从插入模式退回到普通模式了,只有使用 jk 才能退回。
2022年07月15日
8 阅读
0 评论
1 点赞
2022-07-13
从零开始配置 vim(3)—— 键盘映射进阶
严格意义上来说,快捷键的绑定应该是键盘映射,将某些键映射为另一些键。在上篇我们介绍了基本的键盘映射操作,知道了如何 :map、:imap、:vmap、:nmap这些命令来映射键盘快捷键。它们很方便,也很简单,但是有一个致命的缺点。他们是递归的,我们先来讨论什么是递归映射的递归问题让我们先来执行下面的命令:nmap jj J :nmap J j这里我们原本是想 jj来实现 J的功能,更加快速的实现合并行的功能,但是我们按下之后发现,它只是将光标移动到下一行了。这并不是我们想要的。到底发生什么了呢?因为这些命令是递归的。如何理解递归呢?我们以函数的思想来考虑,每定义一个快捷键,就相当于定义了一个函数。并且在新定义的函数中调用老函数。依照这个思路我们来分析一下上述两个命令产生的结果:首先定义了一个名为 jj的函数,它的函数代码为 J()然后我们定义了一个名为 J的函数,它的代码定义为 j()我们执行 jj函数的时候,它在函数内部调用 J(),J函数内部调用 j()。因此它表现出来的最终效果就是 jj等效与 j。这些映射产生的伪代码如下:void J() { j(); } void jj() { J(); }我们在调用 jj 这个函数的时候就相当于在调用 j有点绕是不是呢。为了讲述这个问题,我们再来看这么一个例子:nmap dd o<esc>kddj我们来分析一下它的本意:首先使用 o在光标所在行之下插入一行退回到普通模式,并且让光标向上移动一行删除光标所在行移动到下一行,也就是刚刚的插入行看起来这个命令的作用是清除本行,但是vim并没有这么做,只有按下 <C-c>才能停下来,而且vim中多出了许多空白行。依照上述分析思路,我们可以对这个命令的执行结果写出如下的伪代码void dd() { o(); esc(); k(); dd(); j(); }从上述的代码看出这个映射会陷入无限循环,或者叫死递归。我们只能使用 来终止。在正式进入下一步之前让我们先删除这个映射。我们可以使用 :nunmpa 来删除一条快捷键映射,输入 :nunmap dd 来终止上述出错的映射。之前介绍的那些映射命令都有 un 系列的命令,例如 map 对应 unmap,imap 对应 iunmap 。我们从上面的几个例子应该看出来了, 之前介绍的函数好用是好用,但是会形成递归。在上述代码中还算是比较好找,如果我们配置文件大了,不同插件有自己的映射,而我们也会定义一堆自己的映射,这个时候出问题就难查了。为了解决这个问题,vim提供了一系列的 nore 开头的函数。它相比于之前介绍的函数来说,是非递归的。之前每个命令对应的非递归版本如下:nmap 对应 nnoremapimap 对应 inorempapvmap 对应 vnoremapcmap 对应 cnoremap相信各位应该看出来了,我们在原来命令的基础之上添加了 nore 作为非递归版本。我们来做一个试验:nmap x dd :nnoremap \ x我们输入 \ 发现它只删除了一个单词,即使用 :nnoremap 只保留了 \ 作为 x 操作符的作用,而斩断了之前 x 被映射为 dd 的操作。那么我们何时该使用递归版本,何时使用非递归版本呢?答案是在任何时候,永远使用非递归版本,现在就请各位小伙伴忘掉非递归版本把。现在多敲几个单词将来会省去大量排错时间。lua 配置到此位置我们学会了怎么使用 :map 系列的命令定义快捷键,同时也知道什么是快捷键之间的递归和非递归。可以说掌握了关于 vimscript 定义快捷键的基本方法。那么如何跟 lua 对应呢?neovim 定义了一系列的函数帮助我们定义、获取和删除快捷键vim.api.nvim_set_keymap: 设置快捷键vim.api.nvim_get_keymap: 获取快捷键vim.api.nvim_del_keymap: 删除快捷键我们可以通过帮助文档查到 vim.api.nvim_set_keymap 的定义如下:nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts})mode 是一个字符串,对应着一个模式,即我们之前说的可视模式、插入模式或者普通模式,下面是各个模式对应的字符串名称 。字符串模式对应的vim 命令""所有模式:map"n"普通模式:nmap"v"可视模式:vmap"i"插入模式:imap"s"选择模式:smap"c"命令模式:cmaplhs 对应着一个键位,即我们想映射的键位,如果传入空字符串,相当于通过 :map传入 <NOP>。表示将要禁用这个键rhs 对应着将要执行的命令,是 :map 的第二个参数opts 代表映射的其他属性,主要是一个表,你可以暂时理解为一个字典。比如可以使用 noremap 表示禁止递归,使用 silent 表示执行命令时不回显内容例如我们在配置文件中定义vim.api.nvim_set_keymap("n", "<space>", "/nvim<CR>", {noremap = true, silent = false})通过这段代码,我们将 空格键映射为在文件中查找 nvim 字符。因为 silent 设置的是 false 因此我们在按下空格键之后在vim 的左下角会看到 /nvim 的字样我们可以通过设置 silent = true来取消这个回显。vim.api.nvim_set_keymap("n", "<space>", "/nvim<CR>", {norema=true, silent = true});映射leader 键常见的映射主要出现在普通模式下,普通模式下的很多按键都有其特殊用途,而且还大多挺常用的,想来想去不怎么使用,而且位置好按的也就 <space>、H、L、D 这些了,将他们进行映射,映射到常用功能,减轻我们的按键负担是再好不过了。但是我们常用功能又那么多,特别是装了插件之后的。这些键完全不够使用的。这个时候我们要延续 emacs 或者其他软件的思路了,一个键不够就两个键,比如使用下面的映射:noremap -d dd :noremap -c ddO这意味着我们可以使用一个键作为前缀,后面接其他字符,将他们作为一个整体来映射一个功能。多按一个键而已,比你输入整个命令要轻松多了。这就引入一个新的思路了,我们可以统一定义一个键作为前缀键,后面添加一些字符来整体进行映射。当然我们可以手工这么做,每次需要多个按键的时候的就手动写上 - 或者其他的。但是后期我发现 - 并不容易按到,我觉得 <space> 或者 ,更容易按到,要进行修改,那么修改的量就太大了。vim 中有一个被称之为 leader 键的东西来解决这个问题,我们可以提前定义一个 leader ,在映射的时候使用 <leader> 来代表对应的前缀键。例如,先设置 leader 为 <space> 后面再定义 <leader>d 作为 dd,后面可以很方便的修改 <space>d 这个映射为 ,d,只需要修改 leader 键的定义。可以使用 :let mapleader = <space> 来定义 leader 键为空格。这里你可以定义成你喜欢的键,我平时喜欢用空格,因为它比较大,平时也在大拇指的位置,方便按。然后我们可以使用 :noremap <leader>d dd 来定义映射如何在 lua 中定义 leader 键呢?从上面的 vimscript 代码中可以看到 mapleader 是用 let 关键字来设置的,一般 let 是用来设置变量的。lua 中自定义变量可以直接定义,但是 mapleader 明显是vim 自带的变量。跟设置选项类似,neovim 提供了两种访问 vim 内部变量的方式,一种是使用函数,一种是使用 元访问器。跟变量有关的函数主要有:vim.api.nvim_set_var():设置全局变量的值vim.api.nvim_get_var():获取全局变量vim.api.nvim_del_var():删除全局变量当然使用元访问器会更加简便,对应的元访问器为 vim.g。所以这里我们可以使用 vim.g.mapleader = " " 来设置到此我们已经学会了关于映射的所有初级的内容,现在已经可以完成大部分的配置工作了。至于在定义快捷键的时候是使用 leader键还是使用多个普通键,看具体场景和各位小伙伴的使用习惯了。这里我就不给建议了,一切以方便好按为主。
2022年07月13日
12 阅读
3 评论
1 点赞
2022-07-11
从零开始匹配vim(2)——快捷键绑定
如果说 vim有什么最吸引人,我想vim允许你自由的定义各种快捷键算是一个原因吧。你可以通过绑定各种快捷键来使经常使用的功能更加便利。通俗的讲,快捷键映射就是我按下某个键,我想让vim将它当成另一个键,例如我按下 k,我想让vim把它当做 c 来使用(当然这么映射会把人逼疯)快捷键映射我们使用 :map 命令来进行快捷键的映射,例如我们输入如下内容:map - dd通过这个命令,我们将 - 映射为 dd ,也就是说现在我们按下 - 就可以删除光标所在行了。针对功能键,例如 Ctrl 、空格、Tab键 等,在 vim 中使用 <keyname> 的形式,其中 keyname 是按键名称,下面列举出一些常用的控制键的表示方式:Ctrl 键对应 <c>空格 键对应 <space>alt 键对应 <a> esc 键对应 <esc>退格键对应 <bs>回车键对应 <cr>shift 键对应 <shift>f1 到 f12 对应 <f1> 到 <f12>这些功能键与普通字母做配合时,将字母键放入到 <> 中,并以 - 和 功能键做分割,比如 :map <c-d> dd 来将 <Ctrl +d> 映射为 dd当然有时候为了可读性,我们可以将这些功能键以大写字母来表示,例如 <C-d> 就表示 <Ctrl +d>快捷键映射就是这么简单,接下来要做的就是思考如何进行映射能提升我们的效率,即提取常用的操作将他们映射为快捷键。我们来通过几个小例子来给小伙伴们提供一些思路。定义 -为将当前行往下移动移动我们知道,在普通模式下要将当前行往下移动,可以首先执行 dd 删除一行,然后执行 p 来拷贝到下一行,因此我们可以这样定义快捷键:map - ddp定义 _ 为将当前行往上移动移动在这个例子中,第一步仍然是执行删除,但是与上一个例子不同的是,我们要将删除部分往上一行粘贴。如果往上一行粘贴呢,在之前介绍的时候我们并没有提到如何执行这么一个操作。如果你的第一反应是要去翻用户手册或者去查其他的资料,那么我建议你仔细去阅读一下我之前写的内容。体会一下vim的一些思想和技巧。仔细回想一下 o(小写)和 O (大写) 的区别,而且我们曾经提到过,普通模式下,大写字母和小写字母功能类似。说到这我想你应该知道答案了。我们使用 P来粘贴到上一行。因此这里的映射可以写成:map _ ddP如果你觉得这两个映射对你有用,你可以将它放入你的 vimrc 中,或者先记下来,等我们介绍完使用 lua 配置之后,再写到 init.lua 中。其他模式下的映射map 可以定义映射,但是各位小伙伴可以做一下试验,map 命令定义的快捷键在 visual 模式下仍然有效。这样就会带来一个问题,如果我想在多个模式下都对 - 这个键进行了定义,而且定义成了不同的快捷键,这该怎么处理呢?其实 vim 针对不同的模式有不同的快捷键定义命令,例如 :nmap 负责在普通模式下定义快捷键, :vmap 负责在 visual 模式下定义快捷键。这个时候你肯定已经猜到了,:imap 可以在插入模式下定义快捷键,或者使用 :cmap 定义命令行模式下的快捷键。这些命令的格式与 :map 一样。下面还是以例子为主吧例1: 重新在普通模式下定义 -例如我们使用 :nmap 重新定义 - 为 ddp ,这个时候我们发现它只在普通模式下有用,而在选择模式下无效。例2: 定义 为复制粘贴不知道有没有小伙伴在初学vim的时候希望也能像在Windows中那样,使用 <Ctrl+c> 和 <Ctrl+v> 来进行复制粘贴。学到现在我们终于有能力自己动手实现这个需求了。虽然不推荐这么干,但是还是满足各位折腾的欲望吧。仔细回想一下,<Ctrl+c> 实际上是拷贝选中的文本,而<Ctrl+v> 是在输入的时候直接粘贴的。因此我们知道映射 <Ctrl+c> 应该是在 可视模式下。而<Ctrl+v> 应该是在插入模式下。另外在插入模式下是不支持使用 p 来进行粘贴的。还记得我们在插入模式下介绍的那些技巧吗?其中有一个快速从寄存器中粘贴的技巧。正好可以在这里用到。而复制操作会将复制的文本拷贝到寄存器中(也就是 0寄存器)。结合这两个知识点,我们可以很方便的映射出这两个快捷键:vmap <C-c> y :imap <C-v> <C-r>0虽然它仍有一些不完美,但是已经够用了。最后还是不推荐这么干,毕竟使用 y 等操作就能搞定的事情没必要弄的这么麻烦。而且在linux平台,特别是在终端上,这些键都另有用途。例如 <C-c> 在vim中可以退回到普通模式。例3: 定义 <c-d> 为在插入模式下删除一行我们再举一个例子,我想在插入模式下使用 <C-d> 来删除光标所在行。vim 在插入模式下并没有提供快捷键来删除一行,需要使用退格键一个个的删除,想要快速删除可以回到普通模式使用dd。那么我们可以使用 :imap <c-d> <esc>dd 。我们会发现按下 <c-d> 之后它成功删除了一行,但是它自己退回到普通模式去了,我们想要的是它能在删除一行后仍然处于插入模式,这样我们就可以直接输入了,因此我们可以在后面新加一个再次进入插入模式的步骤,即 :imap <c-d> <esc>ddi 。再次尝试,我们发现它已经满足我们的需求了。例4: 在插入模式下定义快捷键快速转换单词为全大写我们定义一个在插入模式下能快速将光标所在单词改为全大写字母。例如 C/C++ 语言的编程规范中都会讲到宏或者常量最好以大写字母命名。例如 #define MAX_CONNECTIONS_QUEUE 100 这样长的宏定义,我们在输入的时候要一直按着 shift 键是很痛苦的事情。我们需要有这么一个快捷键我们可以先输入小写字母然后使用快捷键将它改为全大写。首先我们思考一下,不使用快捷键该是如何操作呢?首先我们将光标移动到单词所在位置并退回到普通模式,接着使用 viw选中,然后使用 U来改为大写。根据这一串操作命令,我们可以就知道了该如何定义快捷键了,:imap <c-u> <esc>viwU 。根据上面的一个例子我们知道,这样它最终会停留在普通模式下面,我们还是希望能够回到插入模式,考虑到我的使用场景是,我在写完整个单词之后会立马将它转化为大写,然后再编辑后面的其他部分,因此我将光标移动到被大写的单词的尾部,并且进入插入模式。现在命令就变成了 :imap <c-u> <esc>viwUwa。这里你可以根据需要灵活的进行调整,例如可以改为 :imap <c-u> <esc>viwUA,在行尾进入插入模式。最后做一个总结。本篇提到的比较重要的定义快捷键的命令有:map: 定义所有模式下的通用快捷键imap: 定义插入模式下的快捷键 (insert)nmpa: 定义普通模式下的快捷键 (normal)vmap: 定义选择模式下的快捷键 (visual)
2022年07月11日
10 阅读
0 评论
1 点赞
2022-07-11
从零开始匹配vim(1)——选项设置
前面我们算是对 vimscript 做了一个入门,并且实现了一个 输出 hello world 的语句。现在我们继续进行 vimscript 的学习。set语句之前在介绍 vim 基础的时候,我们说要开启或者关闭某个属性,并且给出了相关的配置代码。那个时候已经接触了 set 语句了。例如我们使用 set number 来显示行号。这里我们可以知道 set的第一个用法:set attribute其中这个 attribute 是一个属性名称,用于开启/关闭属性。设置布尔值一般在程序设计中将开启或者关闭某个特性的变量设置为 bool 值。在 vim 中也是如此,但是它的特殊性在于它并不是将这个变量设置为 true 或者 false 而是设置为 name 或者 noname 的样子。举个例子,设置显示行号使用 set number 设置不显示行号使用 set nonumber 。另外对于 bool 类型的属性值还可以使用 ! 来对现有值进行取反,使用 ? 来查看当前使用的值。例如,如果当前不显示行号 set number! 会显示行号,再次执行则 :set number! 则不会执行。我们可以使用 set number? 来查看当前是否显示行号下面我们来执行这么一个例子set number set number? set number! set number?第一个 set number? 应该会返回 number 而第二个应该会返回 nonumber设置键值对有些值是属于 bool 类型,我们只需要 set 某一选项即可。但是有些属性并不适合设计成 bool 类型,例如窗口宽度、高度等等。他们更适合做成一个键值对的形式。针对这种形式的属性,我们直接使用 set key=value 的形式。例如 set columns=80 。对于这种类型的属性仍然可以使用 ? 来显示当前的值。例如 set columns? 来显示当前每行的最大字符长度。当然,与其他编程语言类似,我们也可以使用 set 语句,一次性给多个属性进行赋值,例如set number columns=80只是一般编程语言多个变量的赋值使用 , 作为分割,但是 vimscript 中使用 空格。使用 lua 设置vim属性作为一门更加规范的编程语言,lua 提供了多种方式来对这些变量进行赋值。目前有如下办法能对这些属性进行赋值。使用neovim提供的全局函数进行设置neovim 中提供了一组函数来设置这些属性。常见的分为三类:设置全局属性 a. vim.api.nvim_set_option() :设置值 b. vim.api.nvim_get_option() : 获取值设置窗口相关属性 a. vim.api.nvim_win_set_option() : 设置值 b. vim.api.nvim_win_get_option(): 获取值设置缓冲区相关属性 a. vim.api.nvim_buf_set_option() :设置值 b. vim.api.nvim_buf_set_option() : 获取值例如我们可以使用 vim.api.nvim_set_option('number', true) 来设置 显示行号。使用这些函数时需要严格区分对应属性是 bool、数字或者字符串类型。在 vimscript 中则没有这么严格的区分。使用元访问器进行设置neovim 的接口针对上述这些函数进行了一定的封装,提供了一组元访问器,以便我们能够像使用普通变量一样使用这些属性值。至于什么是元访问器暂时不用关心,只需要知道我们可以像使用变量一样来设置和获得这些属性,但是本质上还是在调用上述那些函数。针对上述函数,我们可以使用如下几种访问对象:vim.o: 全局属性,我们可以利用 options来记忆vim.bo: 缓冲区属性,我们可以利用 buffer-option来记忆vim.wo: 窗口属性, 我们可以利用 window-option来记忆例如我们可以使用 vim.o.number = true 或者 vim.o.columns = 80 来设置对应选项。等效于 vim.api.nvim_set_option("number", true) 和 vim.api.nvim_set_option("columns", 80)总结通过这篇文章,我们讨论了使用 set 来设置一些选项,并且给出了对应的使用 lua 来设置的方法。下面小伙伴们要做的就是读一下 vim 的用户手册,根据自己的喜好尝试着设置一些其他选项。例如我喜欢的基本配置如下:vim.o.syntax = "enable" vim.o.relativenumber = true vim.o.number = true vim.o.wrap = true vim.o.ruler = true vim.o.incsearch = true vim.o.softtabstop = 4 vim.o.shiftwidth = 4 vim.o.expandtab = true如果是vim可能需要的配置更多,但是 neovim 没有历史包袱,默认的已经很好用了最后,目前教程采取这种 vimscript 穿插着 lua 的方式进行讲解,后续配置虽然主要以 lua 为主,但是有时候又离不开 vimscript,neovim并没有完全开放 vim 的内置功能,有些功能只能使用 vimscript 来实现。目前我不太确定是继续采用这种 vimscript 穿插着 lua 进行讲解还是采用将 vimscript 和 lua 分开进行讲述。各位小伙伴觉得哪种方式更能接受呢?
2022年07月11日
9 阅读
0 评论
1 点赞
2022-07-06
从零开始匹配vim(0)——vimscript 简介
通过之前一系列的文章,相信各位小伙伴应该已经对vim产生了浓厚的兴趣,可能不少小伙伴通过慢慢的使用变的跟我一样,离开vim就不会写代码了。如果你希望继续长时间使用vim,甚至将vim作为主要的代码编辑器,那么花一定的时间来学习vim的配置是很有用的。如果你只是因为 linux 平台默认安装了 vi/vim ,平时又主要用它改改配置文件,临时用用,那么还是赶紧退出这个文章,免得耽误时间吧。标题上说从零基础打造vim多少有点标题党,要理解后面一系列文章的内容至少要了解vim里面的一些基本概念,我认为在阅读本系列专栏之前,你应该了解以下内容知道vim,并且知道 vim 的基本操作,例如进入插入模式、移动光标,并且知道如何保存退出知道vim的相关术语,缓冲区列表、缓冲区、窗口、命令模式、插入模式等等知道 vim的配置文件在哪3. 知道 vim的配置文件在哪如果你还不知道,请移步我的专栏,跟着专栏中的内容做做实验。理解一下里面提到的这些概念。关于配置部分,我准备介绍以下几个方面的内容:vimscript 的基础内容,并补充一些之前没介绍过的vim的特性neovim lua对应的接口推荐一些插件和相关配置,做到抛砖引玉可能有小伙伴要问了,vimscript 不管写还是读都比较晦涩,而且 neovim 已经采用更容易理解也更加现代化的 lua了,有必要学习 vim script吗?我觉得是有必要的,首先 neovim 是 vim 的另一个实现版本,要想学好 neovim 自然绕不开 vim,而学好 vim 自然也绕不开 vimscript 。其次,lua 脚本中的接口继承自 vimscript 。想要使用 lua 配置的前提是知道使用 vimscript 配置。它们就好像学习 MFC 绕不开 Win32 API 一样。所以我觉得想要学习 neovim 的配置自然绕不开 vimscript 。而且 neovim 完全兼容 vim 基本不用担心 vimscript 在 neovim 中执行不了的问题。 倒是 neovim 并没有实现 vimscript 百分之百的功能,有些时候还是得靠 vimscript 来实现。演示环境之前一系列的文章本来打算在 mac 上做演示的,但是我发现 mac上录屏比较麻烦,而且 mac上的 neovim 我已经配置好了,行为上可能跟裸 vim 有些差距(虽然可以不加载配置文件启动),所以我采用 WSL2 Ubuntu上的 neovim做演示。刚好这个演示环境没有对vim进行过配置。也方便演示从0开始配置。本教程的环境是 linux中 neovim 的 0.6.1 版本,虽然官方已经放出来 0.8 版本,但是Ubuntu官方源中好像还是 0.6。这里就继续用它演示吧第一个 vimscript 脚本我学习的任何一门语言好像都是从打印 hello world 开始的,我也不能免俗。我们这个教程也从打印 hello world 开始吧vimscript 中可以使用 echo 和 echom 来打印语句,例如我们可以在命令模式中输入 echo "hello world"。我们发现在屏幕的下方出现了 hello world 字样。接着我们再使用 echom "hello world" 发现,它仍然在下方打印了 hello world 字样。这两者有什么区别呢?要理解它们的区别我们需要介绍一个新的命令 :message 。这条命令可以查看 message-history 中的内容,我们可以简单的将这条命令理解为查看 vim 的运行日志(虽然并不是在查看日志)。执行这条命令我们发现,message-history 中只有一条 hello world。这个时候他们的区别就出来了,一个在打印的同时会将打印信息写入 message-history,另一个就仅仅只是打印而已。各位小伙伴只需要简单打印不同的语句就能知道 echom 会将内容写入到日志中,而 echo 不会。这里留个各位自己去实验吧,我就不做演示了。我们现在来完成一个小练习,使用vim脚本来写一段欢迎信息例如 hello, jack, 我们让用户每次打开都能看到这个欢迎信息 。这里的用户我们暂时让它固定,后续我们可以做到动态的修改 欢迎的用户。我们知道每次打开vim,它都会去加载配置文件,我们只要将要执行的命令写到配置文件中就好了。还记得配置文件在哪吗?针对 neovim 来说它支持 vimscript 和 lua 配置(当然它也支持其他语言)。我们将目录切换到 ~/.config/nvim 。如果各位小伙伴之前有过配置,那么请先将配置做一个备份。同时确保 init.lua (lua配置)和 init.vim (vimscript 配置) 只能有一个我们先尝试着用 vimscript 的方式来完成这个功能。我们建立一个新文件 ~/.config/nvim/init.vim。然后在里面写上一句 echo 'hello, jack',然后退出。我们发现每次进入 neovim 之后,总会在下方显示这么一句话了。我们再来看看如何使用 lua 来打印这么一句话呢?lua 中对应的函数是 print 。我们可以直接在 之前备份的 init.lua 中写上 print("hello, jack") 来完成这一个工作(记得现将之前的 init.vim 备份)。需要注意的是 lua 中的 print 写将信息一并写入到 message 中,也就是说它与 echom 效果相同。如果想执行 echo 操作可以使用 api.vim.nvim_echo() 。它的用法比较复杂,这就就不介绍它了,有兴趣的小伙伴可以去官网查一下,试试用它来实现这个打印欢迎信息的例子。这篇文章的内容到此就结束了,最后给大家做一个总结:neovim如果想要加载 vimscript配置,可以将配置文件放到 ~/.config/nvim/init.vim 中,如果想要加载 lua 配置,可以将文件放到 ~/.config/nvim/init.lua 中。echo、echom 都会打印字符串,不同的是 echom 将打印的内容往一个叫做 message-history 的地方写。lua 中的 print 具备 echom的功能可以使用 message 命令查看 message-history 的内容从 vimscript 的使用上看,它里面写的是vim的一些命令,我们将命令写在文件中让vim去执行。vim命令与 vimscript 的关系有点像 shell 命令和 shell 脚本的关系
2022年07月06日
8 阅读
0 评论
1 点赞
1
...
6
7
8
...
11