你好,我是孔令飞,字节跳动云原生资深研发、前腾讯云原生技术专家。《企业级 Go 项目开发实战》、《从零开发企业级 Go 应用》作者,欢迎加入 孔令飞的云原生实战营,助你进阶 Go + 云原生高级开发工程师。
作为一名 Golang 开发,你需要一个编辑器来完成你日常的代码编写。在编写代码过程中,会有一些高频、重要的代码开发操作需要去执行,例如:查看函数的定义、快速的跳转到上一次打开的文件、代码补全等。这些操作如果能用工具来自动完成,或者提供一种高效的方式协助我们去完成,那么我们的开发效率会大大提高。
当这些功能聚集在一个编辑器中,我们就可以称这个编辑器为IDE(集成开发环境,Integrated Development Environment)了。
所以,为了提高代码开发效率,我们需要的是一个包含了基本代码编辑功能的 IDE。当前有很多优秀的 IDE 可供我们去开发 Go 代码:
- Visual Studio Code: Visual Studio Code是一个轻量级的、跨平台的代码编辑器,它支持Golang的开发。它具有丰富的插件生态系统,可以通过安装Go相关的插件来提供代码编辑、调试、自动完成等功能;
- GoLand: GoLand是由JetBrains开发的专为Golang开发而设计的IDE。它提供了一套完整的工具和功能,包括代码编辑、调试、自动完成、代码导航等。GoLand还具有强大的代码分析和重构功能,可以帮助开发人员提高代码质量和效率;
- LiteIDE: LiteIDE是一个专门为Golang开发者打造的轻量级IDE。它提供了简洁的界面和直观的操作,支持代码编辑、调试、自动完成等功能。LiteIDE还具有代码导航、项目管理和快速构建等实用工具;
- Sublime Text: Sublime Text是一个流行的跨平台代码编辑器,也可以用于Golang开发。它具有简洁的界面和丰富的插件生态系统,可以通过安装相关插件来提供Golang的代码编辑和调试功能;
- Atom: Atom是由GitHub开发的免费、开源的代码编辑器,也可以用于Golang开发。它具有可定制的界面和丰富的插件生态系统,可以通过安装相关插件来提供Golang的代码编辑、调试和自动完成功能;
- Vim: Vim是一个高度可定制的文本编辑器,广泛用于代码编辑和开发。它具有强大的编辑功能和快捷键,可以通过安装插件和配置文件来提供代码高亮、自动完成、代码导航等功能。Vim还支持Golang的开发,可以通过安装相关插件来提供Golang的代码编辑和调试功能;
- Emacs: Emacs是一个可扩展的文本编辑器,也用于代码开发。它具有强大的编辑功能和内置的Lisp编程环境,可以通过安装插件和配置文件来提供代码高亮、自动完成、代码导航等功能。Emacs也支持Golang的开发,可以通过安装相关插件来提供Golang的代码编辑和调试功能。
这些IDE都具有不同的特点和功能,你可以根据自己的需求和偏好选择适合自己的IDE。无论选择哪个IDE,掌握其功能和工具,熟练使用它们,都能提高Golang代码开发的效率和质量。
可以看到 IDE 有很多,当前最受环境的 IDE 是 GoLand,也是我很喜欢的 IDE。但日常开发中,我使用的是 Vim IDE。
为什么选择 VIM?
提示:萝卜白菜各有所爱,你觉得用着舒服的 IDE 就是最好的 IDE。这里,不是辩论哪个 IDE 更好,而是来分享下,我在选择 IDE 的一些思考过程。
这里,先来解释下,我为什么会选择 Vim IDE。先来看下我的开发环境,如下图所示:
首先,公司为了网络安全,会至少隔离出以下 3 种网络:
- 开发网(Development Network):开发网是专门用于软件开发和测试的网络环境。在开发网中,开发人员可以进行软件开发、调试和测试,并与其他开发人员共享代码和资源。开发网通常与外部网络隔离,以保护敏感的开发和测试环境,同时提供更高的安全性和灵活性;
- 办公网(Office Network):办公网是企业或组织内部员工进行日常办公和业务活动的网络环境。在办公网中,员工可以访问共享文件、电子邮件、内部网站和其他办公应用程序。办公网通常连接到互联网,以便员工可以与外部网络进行通信和访问;
- 生产网(Production Network):生产网是用于生产环境和业务运行的网络环境。在生产网中,企业或组织的主要业务应用程序和服务运行,并提供对外服务。生产网的稳定性和安全性非常重要,因为它直接影响到业务的正常运行和数据的安全性。
通常一个开发中的服务/组件,需要访问公司内的其他服务,这些服务可能是公共服务,也可能是其他非公共服务。这些测试服务都是部署在开发网中的。所以,如果你的服务,想要具有一个完整的测试环境,就一定需要部署到开发网中。
如果你的办公机和开发机不是同一台机器,势必会需要同步办公机中的代码到开发机或者办公机中的构建产物到开发机,那么这就会遇到以下 2 个问题:
- 违背了不重复造轮子的哲学:作为一名开发者,不重复造轮子应该是我们一直需要去遵守的哲学,不冲突造轮子,会使事情变得更易维护、效率更高;
- 代码不一致:因为需要双向同步,可能就会因为网络抖动,开发 IDE 异常、人为操作等原因,造成远端和本地的代码不一致,从而带来一些其他问题,降低开发效率。
上面的 2 个原因,造成我想直接基于开发网的的开发机去开发代码,但这还不足以说服自己。这里,再来从另一个方面解释下,我为什么要直接在开发机开发代码。
开发代码通常包含很多工作,例如:代码编写、代码编译、代码部署等。我们需要尽可能提高每个流程的开发效率,只有这样整个开发效率才会很高。本地开发机,可能会提供很多效率工具来提高我们的开发效率,但是最能提高开发效率的可能是 Linux 操作系统自带或者可以安装的各类工具,例如:Bash、AWK、Sed、Makefile、Find 等工具。Linux 操作系统中非常丰富的工具、便捷高效的命令行操作方式、以及可编程、灵活的运维脚本语言 Shell 等,都可以极大提高我们的开发效率。
基于以上原因,我比较倾向于选择 Vim。但是 Vim 相比于其他 IDE 的上手难度、功能缺失、操作复杂度,又让我觉得 Vim 不够完美。
我试图寻找更完美的解决方案,例如:使用 Goland 的 SSH 远程开发模式,在本地开发代码,实时同步到开发机中的源码目录。Goland的远程开发模式,通过部署在开发机上的 agent,跟本地 Goland 客户端进行通信,代码用的都是同一份,虽然解决重复造轮子的问题,但是在使用过程中,也发现了其他一些问题:
- 受限于网络连接的稳定性,在启动Goland SSH 项目的时候,经常会卡死;
- Goland 中的搜索和操作只能局限在项目内,如果你想跳转到项目外进行一些操作和搜索,就实现不了;
- 总是会遇到一些未知问题,导致代码跳转失效。
所以,基于以上原因,我觉得用 Goland 不是一个好的方法,又将目光转回 Vim 中。这时候,我在想,如果能将 Vim 配置成跟Goland 一样好用,就完美了。我思考了一下我开发过程中常用的操作,发现这些操作,都可以通过 Vim 的各类插件来完成,并且从功能、易用性上能够跟 Goland 相媲美。
所以,基于我的开发环境、需求等,我最终选择了使用 Vim IDE。那么接下来我就来介绍下,如何安装,并配置 Vim 为一个顺手的 Go 代码开发 IDE。
安装 Vim 9
如果你当前的 Linux 发行版,已经安装了 Vim 9,可跳过 Vim 9 的安装。如果没有安装 Vim 或者版本不是 9,建议升级到 Vim 9。安装命令如下:
$ git clone https://github.com/vim/vim /tmp/vim
$ cd /tmp/vim
$ sudo apt install -y libncurses5-dev
$ CFLAGS="-I/usr/local/include -fPIC" ./configure --prefix=/usr/local --with-features=huge --enable-cscope --enable-multibyte --enable-rubyinterp --enable-perlinterp --enable-python3interp --enable-luainterp --with-tlib=ncurses --without-local-dir
$ make
$ sudo make install
$ echo "alias vi=/usr/local/bin/vim" >> ~/.bash_aliases # 设置 vi 为最新的 vim 版本
$ bash
Vim IDE 安装和配置
上面,我们安装好了 Vim 编辑器。接下来,就可以安装 Vim IDE,具体安装命令如下:
$ rm -rf $HOME/.vim; mkdir -p ~/.vim/pack/plugins/start/
$ git clone https://github.com/colin404/vim-go ~/.vim/pack/plugins/start/vim-go
$ git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim
$ git clone --depth=1 https://github.com/colin404/vimrc.git ~/.vim_runtime
$ sh ~/.vim_runtime/install_awesome_vimrc.sh
$ git clone https://github.com/superproj/vimrc /tmp/vimrc # 安装自定义 Vim 配置
$ cp /tmp/vimrc/vimrc $HOME/.vim_runtime/my_configs.vim
在之前使用 Vim 的过程中,发现依赖的仓库,例如:fatih/vim-go
、amix/vimrc
最新版本会有一些 Bug 或环境不适配,导致 Vim IDE 配置失败。为了提高你的配置成功率,我 Fork 了一份稳定版本。上面安装配置,是从我 Fork 出来的(colin404/vim-go
、colin404/vimrc
)、经过验证(Debian 12)的代码仓库来安装的。当然,我会定期跟上游进行代码同步,确保 Fork 出来的代码仓库,功能上能跟最新的上游对齐。
提示:https://github.com/superproj/vimrc 是我的 vimrc 配置。
Vim 基础语法介绍
后面,我会介绍如何配置 Vim 使其成为一个顺手的 IDE,这就需要我们了解如何配置 Vim。Vim 使用 vimrc 文件来配置。
.vimrc
文件是 Vim 的配置文件,用于个性化和定制 Vim 编辑器的行为。它是一个文本文件,位于用户的主目录下(在 Linux 和 macOS 系统中是 $HOME/.vimrc
,在 Windows 系统中是 $HOME/_vimrc
或 $HOME/vimfiles/vimrc
)。
.vimrc
文件中包含了一系列的 Vim 命令,用于设置编辑器的各种选项和功能。以下是一些常见的 .vimrc
配置语法:
- 设置选项:使用
set
命令来设置 Vim 的选项。
例如,要设置缩进为 4 个空格:
set tabstop=4
set shiftwidth=4
set expandtab
- 映射按键:使用
map
、nnoremap
、inoremap
指令将一个按键绑定到某一个操作上。
在 .vimrc
配置文件中,有三个常用的按键映射指令:map
、nnoremap
和 inoremap
,它们分别用于创建递归映射、非递归映射和插入模式下的映射。
map
指令
map
指令用于创建递归映射,它将按键映射到一个命令,并且可以被其他映射所影响。它的语法如下:
map {lhs} {rhs}
其中,{lhs}
是按键的左手边(left-hand side),{rhs}
是按键的右手边(right-hand side),表示按下左手边的按键时执行右手边的命令。例如,下面的命令将 <F2>
键映射到保存文件的命令:
map <F2> :w<CR>
当按下 <F2>
键时,将会执行 :w<CR>
命令来保存文件。
请注意,map
指令创建的按键映射是递归的,这意味着它可以被其他映射所影响。这可能会导致按键映射冲突和意外行为。
nnoremap
指令
nnoremap
指令用于创建非递归映射。语法和map
指令一致。请注意,nnoremap
指令创建的按键映射是非递归的,这意味着它不会被其他映射所影响。这在避免按键映射冲突和意外行为方面非常有用。inoremap
指令
inoremap
指令用于创建插入模式下的映射,它将按键映射到一个文本字符串,并且只在插入模式下生效。语法和map
指令一致。请注意,inoremap
指令创建的按键映射只在插入模式下生效,这意味着它不会影响普通模式下的按键映射。
在使用这些指令时,请注意避免按键映射冲突和意外行为。
另外,可以使用 unmap
指令来取消一个按键映射,例如:
unmap <F10>
- 定义函数:使用
function
命令来定义函数。例如,定义一个函数来删除当前行并保存文件:
function! DeleteAndSave()
execute "normal! dd"
write
endfunction
- 自动命令:使用
autocmd
命令来定义自动命令。例如,定义一个自动命令,在保存文件时自动运行 Go 代码格式化工具:
autocmd BufWritePre *.go :silent! GoFmt
- 条件语句:使用
if
语句来根据条件执行不同的命令。例如,如果文件类型是 Markdown,则设置文本宽度为 80 个字符:
if &filetype == 'markdown'
set textwidth=80
endif
- 注释:使用
"
符号来添加注释。例如:
" 这是一个注释
这只是 Vim 脚本语言的一小部分。您可以在 Vim 的帮助文档中找到更多关于配置语法和命令的详细信息。要使新的 .vimrc
配置生效,可以重新启动 Vim,或者在 Vim 中输入以下命令重新加载配置:
:source ~/.vimrc
Vim IDE 插件配置
提示:我根据自己的操作习惯,自定义了一些个人喜欢的按键操作,你可以根据按键设置方法,设置为自己喜欢的按键。
这里,先来看下,在进行 Go 代码开发的过程中,通常需要进行哪些类别的操作:
- 代码编辑:基本的代码编辑操作;
- 代码跳转:跳转到函数定义、类型定义等处;
- 文件查看:查看文件列表,例如:最近访问的文件列表、项目根目录下的所有文件列表等;
- 缓冲区操作:在编辑代码的过程中,会打开多个文件,这些文件内容都放在 Vim 缓冲区中,需要经常切换缓冲区,查看已打开的文件;
- 字符串查询:在当前目录下查询指定的字符串并跳转到指定位置。
- 窗口操作:关闭、移动光标到新窗口等操作。
接下来,我们来看下,这些功能如何在 Vim 中较好的实现。
代码编辑
Vim 编辑器本身 提供了基本的、高效说的代码编辑功能。
代码跳转
可以使用 vim-go
的代码跳转功能来完成 Go 代码跳转等功能。
vim-go 是一个专门为 Go 语言开发者设计的 Vim 插件,它提供了一系列的功能和工具,以提高 Go 语言开发的效率和舒适度。以下是 vim-go 插件的一些主要功能:
- 代码自动补全:vim-go 插件集成了 gocode,可以实现 Go 代码的自动补全功能。它可以根据当前上下文提供变量、函数、结构体等的补全建议。
- 代码导航:vim-go 插件支持快速跳转到函数定义、变量声明和类型定义等。通过使用gd命令可以跳转到光标下的标识符的定义,使用gD命令可以跳转到标识符的声明。
- 文档查看:vim-go 插件可以方便地查看 Go 代码的文档。通过使用K命令可以在 Vim 中查看当前光标下标识符的文档。
- 代码重构:vim-go 插件提供了一些代码重构的功能,如重命名变量、提取函数、提取接口等。这些功能可以帮助开发者快速进行代码重构操作。
- 单元测试:vim-go 插件支持运行和调试 Go 代码的单元测试。通过使用:GoTest命令可以运行当前文件的单元测试,使用:GoTestFunc命令可以运行当前光标下的测试函数。
- 代码格式化:vim-go 插件可以根据 Go 语言的官方代码格式规范自动格式化代码。通过使用:GoFmt命令可以格式化整个文件,使用:GoImport命令可以自动导入缺失的包。
- 构建和运行:vim-go 插件提供了一些命令来构建和运行 Go 代码。通过使用:GoBuild命令可以构建当前文件,使用:GoRun命令可以运行当前文件。
- 代码分析:vim-go 插件集成了 golint、govet、gotype 等工具,可以对 Go 代码进行静态分析,提供代码质量和错误检查。
查看安装方式如下:
Plugin 'fatih/vim-go', { 'do': ':GoUpdateBinaries' }
vim-go
提供了很多函数用来完成代码跳转,你可以将这些函数绑定到快捷键,使用快捷键进行快速跳转。
文件查看
可以使用 Vim fzf 插件来完成文件查看等功能。
fzf(Fuzzy Finder)是一个强大的命令行模糊查找工具,可以快速在大量数据中进行模糊搜索。fzf 插件是将 fzf
集成到 Vim 中的插件,可以使 Vim 的文件、缓冲区、标签等搜索更加高效和便捷。
插件安装方式如下:
Plugin 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
Plugin 'junegunn/fzf.vim'
fzf
插件提供很多功能,比较重要的功能列表如下:
fzf
插件默认只在当前目录中进行查询,但日常开发中,我们进行查询时,可能经常期望在整个项目进行查询,所以这里,我们可以通过使用 vim-rooter
插件,来自动根据当前打开的文件,确定项目的根目录,并将 Vim 的当前工作目录设置为项目根目录。
可以通过以下方式安装 vim-rooter
插件:
Plugin 'airblade/vim-rooter'
为了便于使用这些按钮,我们配置成快捷键:
nnoremap <leader>f :RG<cr>
nnoremap <leader>r :History<cr>
nnoremap <leader>j :Buffers<cr>
nnoremap <leader>k :Files<cr>
nnoremap <leader>l :cd %:p:h<cr>:Files<cr>
nnoremap <leader>t :Tags<cr>
" 使用 <leader> 键不便于单手操作,为了提高操作效率,我又进行了以下按键映射:
nnoremap <C-Q> :RG<cr>
nnoremap <C-R> :History<cr>
nnoremap <C-E> :Buffers<cr>
nnoremap <C-K> :Files<cr>
注意,这里的 <leader>
键,我们配置的是空格键:
nnoremap <SPACE> <Nop>
map <Space> <Leader>
此外,为了更方便的使用 fzf
,还需要进行一些配置:
let g:fzf_preview_window = ['right:hidden', 'ctrl-/']
let g:fzf_layout = {'up':'~90%', 'window': { 'width': 0.8, 'height': 0.8,'yoffset':0.5,'xoffset': 0.5, 'highlight': 'Todo', 'border': 'rounded' } }
" [Buffers] Jump to the existing window if possible
let g:fzf_buffers_jump = 1
"let g:fzf_action = { 'ctrl-c': ['abort', 'cancel'] }
" [[B]Commits] Customize the options used by 'git log':
let g:fzf_commits_log_options = '--graph --color=always --format="%C(auto)%h%d %s %C(black)%C(bold)%cr"'
" [Tags] Command to generate tags file
let g:fzf_tags_command = 'ctags -R'
之后,我们就可以在 Vim 中键入 <leader> + r
来查看最近打开的文件和缓冲区:
可通过键入 <leader> + k
来在当前项目中查找文件:
缓冲区操作
我们可以使用 fzf 提供的 :Buffers
指令,来查看当前打开的缓冲区。例如,键入 <leader> + j
来查看当前打开的缓冲区:
另外,还可以使用以下快捷键,来执行各类缓冲区出操作:
快捷键 | 功能 |
---|---|
Ctrl + w, c | 关闭当前缓冲区 |
字符串查询
我们可以使用 fzf
提供的 :RG
指令,来在当前项目目录中指定字符串查询。例如,键入 <leader> + f
来查查询指定的字符串:
窗口操作
可以执行以下快捷键来执行各类窗口操作
快捷键映射
上面,我们配置了 Vim IDE,也映射了一些按键,为了方便你统一查找、记忆,这里将这些按键映射整理成列表供你查看。根据快捷键类型分为以下 2 类快捷键类型,供你区别查找:
- 基础快捷键:Vim 编辑器自带的非常基础的快捷键;
- 非基础快捷键:配置的、插件自带的、其它常用的快捷键。
基础快捷键
提示:
<leader>
: 空格键。
非基础类快捷键
提示:
<leader>
:空格键。
参考
一些值得参考学习的文章:
- Using Vim for Go Development
- 一个很受欢迎的 vimrc 配置
欢迎关注我的公众号【令飞编程】,会不定期分享 Go、云原生、AI 相关的技术栈。