站内链接:

Lint

Introduction

lint and linter:

"linter"--A machine for removing short-staple cotton-fibre from cotton-seed after ginning;
the fibre thus obtained, used in making mattresses, etc.
In our more modern context, "lint" isn't just the unwanted fluffy stuff out of the dryer,
it's also bad or unnecessary stuff in programs.
Lint doesn't usually cause show-stopping bugs,
but cleaning it out can often prevent small or annoying misbehaviours in programs.

翻译:

linter最古老的含义是一种将棉籽处理, 去除短纤棉纤维的机器, 从而获取符合要求的纤维, 用于制作床垫等其他工业品.
在现代的编程环境中, lint不仅仅代表着棉籽中不需要的冗余物体, 更代表着程序中不好的/不必要的冗余代码.
程序中的lint通常不会产生程序运行停止的BUG, 但是清楚这些冗余的lint, 可以防止一些小巧并让人困惑的错误.

例如在 python 编程环境, 使用 linter–pylinter, 对一些冗余的错误, 例如unused-argument冗余的 lint, 此时就需要pylinter进行linting操作,

Classify

代码检查工具有两种类型: 动态测试, 静态检查.

  • 动态测试: 运行被测试程序, 检查运行结果和预期结果的差异, 分析运行效率, 正确性, 健壮性, 须构造测试用例, 执行程序, 分析程序. 例如: 调试器
  • 静态检查: 利用 linter 在代码编写时或者运行前进行代码检查.

通过 ALEInfo 进行查看当前 markdown 中生效的 linter: linter

代码检查

Ale

Asynchronous Lint Engine–异步代码检查工具引擎, 类似同步代码检查工具-synstatic, 通过配置各个语言的 linter, 基于 ALE
进行静态代码检查.

关于 ale 的配置, 见官网: ALE

Ale 实现的功能:

  • 通过 linter 进行语法检查
  • 进行代码调整(定义, 引用), 代码检查/代码补全都具备该功能, 算是一种标配吧
  • 代码补全, 不建议开启

对于 Ale 的错误检查步骤:

  • 查看相应语言的 linter, 使用命令: ALEInfo
  • 根据错误的信息定位相应的 linter
  • 检查 linter 的配置
  • 根据相应的 linter 配置进行精确打击处理

利用 git 来进行 ale 安装: vim 安装具体的配置可以见官网说明.

本人目前的 ale 配置, 主要是 python 开发环境:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
" 控制错误输出格式, 通过这个 linter找到确切的忽略错误的方式
let g:airline#extensions#ale#enabled = 1
let g:ale_echo_msg_error_str = 'E'
let g:ale_echo_msg_warning_str = 'W'
let g:ale_echo_msg_format = '%...code...%: [%linter%] %%s [%severity%]'
" use quickfix list instead of the loclist
let g:ale_set_loclist = 0
let g:ale_set_quickfix = 1
let g:ale_open_list = 1
let g:ale_keep_list_window_open = 0

let g:ale_python_pylint_options = '--rcfile ~/.vim/.pylintrc'
let g:ale_python_pylint_use_global = 0
let g:ale_html_tidy_options = '-q -e -language en -config ~/.vim/.tidy.conf'

" 错误移动
noremap <leader>ef :ALEFirst<CR>
noremap <leader>en :ALENext<CR>
noremap <leader>el :ALELast<CR>
noremap <leader>ep :ALEPrevious<CR>
" 关闭自动打开错误quickfix
" noremap <leader>ec :call BambooDisableAleQuickfix() <CR>
" function BambooDisableAleQuickfix()
" let g:ale_set_quickfix = 0
" let g:ale_open_list = 0
" endfunc

错误的 pylinter 示例: pylinter-error

Synstatic

vim 环境下的同步语法检查工具, 目前本人不在使用(代码检查时, 会有卡顿延时), 具体可以查看官网: synstatic.

代码补全与跳转

代码补全

代码补全主要有两大类: 基于文本自动补全, 基于语义补全, 前者需要生成额外的标签文件, 后者则使用 CS 模式进行代码补全

基于文本的补全: 例如 acp, omnicppcomplete, 基于 ctags 生成的标签文件进行代码补全操作

基于语义的补全: 例如 clang/llvm, YouCompleteMe, 其中 YCM 使用插件UltiSnips进行补全操作(completion interpreter), 相关原理见下文

基于语义补全的代码层面原理

  • 后端调用 libclang 获取 AST 或者其他语义分析库
  • 前段使用 C++开发, 提高补全效率
  • 最外层使用 python 包装, 提高一键化部署的能力

基于语义补全的运行原理:

  • C 端: 默认 YCM 会启动一个 C 端, 利用 http + json 和 S 端进行交互
  • S 端: 在启动 vim 的时候会默认启动 YCM 的服务

当然, 类似代码检查工具, YCM 也是一个代码补全的平台, 需要根据相应配置各种语言的 interpreter 来进行真正的语法补全操作,
例如 python 环境中的jedi

Ctags

ctags 中文手册

功能:根据已经生成的标签文件,从而在 vim 中查看函数调用关系、类、结构、宏等各种定义,跳转于各个标签中

生成 tags: 见本人的 vim 配置, unlessbamboo

关于 tags 文件的格式, 主要有 head/body 两部分组成, 其中 head:

  • !_TAGXXXX_: 用于加入额外的信息
  • !_TAG_FILE_SORTED<Tab>1<Tab>{anything}: 表示 tag 文件是经过排序的, 0-未经过排序, 1-区分大小写, 2-不区分

body 的文件格式: {tagname} {TAB} {tagfile} {TAB} {tagaddress} {term} {field} .., 其中各个字段含义

  • field: 可选字段, 用于表示 tagname 的类型信息
  • term: 设置为;, 兼容 vi
  • tagaddress: 定位 tagname 光标位置的 Ex 命令, 一般为行号或者搜索命令, 非常重要
  • tagfile: 包含 tagname 的文件
  • tagname: 标识符名字, 例如 function, classname, construct name

具体见实例截图:

tags-format

关于 tags 文件的建议: 考虑到开发过程中可能有多个项目(python, C, C++等), 所以建议在每一个项目根目录下面放置 XX.vim 配置进行个性化的导入.

cscope

cscope 和 ctags 组合, 往往用于基于文本的代码跳转和查找, 补全操作

tags 的加强版, 和 ctags 合作, 在首次使用时需要先生成数据库文件, 根据源文件中的各类标签生成符号数据库, 之后根据这些数据库文件进行
特定标识符的查找. 关于 cscope 的生成见 ctags 章节的链接.

缺点: ctags/cscope 有一个通用的缺点, 也是基于文本补全的缺点, 即: 每一次更改源文件之后, 需要重新构建数据库, 否则可能匹配或者调整失败

关于 ctags 和 cscope 生成的文件, 见下图实例, 其中包含 ctags, cscope 库文件:

cscope文件

YCM

关于 YCM, 可以参考官网YouCompleteMe, 其中对于c#, go, typescript, javascript, rust, java,
在安装编译的时候需要额外的指定参数, 建议根据自身的语言进行相应的编译操作, 特别是没进行翻墙的同学, 因为编译过程需要下载很多的
第三方库或者插件, 所以需要一定的时间.

本人目前的 YCM 配置如下, 对于 C/C++, 需要在相应的项目目录下生成独有的.ycm_extra_conf.py 文件, 当然我已经不写 C/C++ 2 年了, 所以这里仅仅
给出 python 的配置

1
2
3
4
5
6
7
8
" 设置python或者python3
let g:ycm_python_binary_path="python"
let g:ycm_complete_in_strings = 2
let g:ycm_collect_identifiers_from_tags_files = 1
let g:ycm_add_preview_to_completeopt = 1
let g:ycm_global_ycm_extra_conf = "~/.vim/bundle/YouCompleteMe/cpp/ycm/.ycm_extra_conf.py"
let g:ycm_key_invoke_completion = ''
nnoremap <leader>jd :YcmCompleter GoTo<cr>

源码浏览

taglist

后期使用 tarbar 替代

将标签(宏, 全局变量, 函数)等显示在 Symbol 窗口, 并根据这些 tag 进行跳转(windows 操作开发)

  • plugin/taglist.vim taglist 插件
  • doc/taglist.txt 帮助文件,记得使用 helptags 进行帮助信息的加载

Condition:

  • 开启 vim 的文件类型自动检测: filetype plugin indent on
  • 安装了 Exuberant ctags 工具, 并且可以找到该工具的路径
  • vim 需要支持 system()调用

相应配置:

1
2
3
4
5
6
7
8
9
10
11
12
" 在剩余多少窗口时退出缓存
let Tlist_Exit_OnlyWindow=1
" 单一窗口显示的文件数
let Tlist_Show_One_File=1
" 窗口显示在右边或者左边,1为右边
let Tlist_Use_Right_Window=0
" 非当前文件,函数列表折叠隐藏,1为隐藏
let Tlist_File_Fold_Auto_Close=0
" 打开/关闭taglist窗口,不过被winmanager替代,见文件缓冲区插件2说明
" map <silent> <F6> :TlistToggle<cr>
" 自动加载
autocmd BufWritePost *.* :TlistUpdate

nerdtree

文件目录树

显示当前目录的树结构, 实现类似 IDE 中的代码文件树结构, 便于浏览文件以及快速的打开, 配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
" 是否在vim启动的时候默认开启NERDTree
" autocmd VimEnter * NERDTree
" 窗口显示的位置,默认为左边
" let NERDTreeWinPos='right'
" 是否自动显示BookMarks
let NERDTreeShowBookmarks=1
" nerdtree 子窗口中不显示冗余帮助信息
let NERDTreeMinimalUI=1
" 删除文件时自动删除文件对应 buffer
let NERDTreeAutoDeleteBuffer=1
" exclude some files
let NERDTreeIgnore = ['\.pyc$', 'migrations', 'log?', 'cscope.*', 'tags',
\ 'media', 'doc']
" 启动或者隐藏NERDTree
nmap <silent> <F2> :NERDTreeToggle<cr>

winmanager

winmanager
文件缓冲区, 使用BufExplorer, FileExplorerlorer, Taglist来查看代码中的 function, class 等, 相应配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
let g:winManagerWindowLayout = "BufExplorer,FileExplorer|TagList"
let g:defaultExplorer = 0
" 自动打开winmanager
let g:AutoOpenWinManager=0
" 设置宽度
let g:winMaagerWidth=30
" goto first explorer window
map <silent> <leader>ff :FirstExplorerWindow<cr>
" goto bottom explorer window
map <silent> <leader>bb :BottomExplorerWindow<cr>
" reload
nmap <silent> <F6> :WMToggle<cr>

上述三者组成源码浏览的基本结构, 作为 IDE 的主体, 辅助开发者进行文件的快速定位, 但是主要目的是进行快速的浏览.

版本控制

  • vim-gigutter: 用于 git 版本控制
  • singnify: 用于 vim, svn 等版本控制

shell

bashsupport

Write and run BASH-scripts using menus and hotkeys.
Bash IDE, 在打开 shell 文件时自动填充的值以及对函数的注释等等.

shellcheck

A static analysis tool for shell scripts. 配合 ALE/Syntastic 语法检查工具.

shell

markdown

首先安装 instant-markdown-d:

1
2
# 如果node没有安装,见插件管理-3中关于node的安装
npm -g install instant-markdown-d

配置 vim

1
2
3
4
5
6
7
"zshrc的配置
set shell=bash\ -i
" 映射快捷键
let g:instant_markdown_autostart=0
" 关闭自动开启浏览器的配置,使用命令:InstantMarkdownPreview
let g:instant_markdown_slow=1
map <silent> <leader>imp :InstantMarkdownPreview<cr>

后记, 关于各个语言的最终 IDE 效果, 见后期的文章, 对于每一种语言, 会给出响应的 gif 演示