youcomplete的vimrc配置文件demo

离开youcompleteme, vim的使用体验差很多。
下面是vimrc文件中ycm相关配置demo。对于C/C++语言的语法补齐需要安装clangd,python常用的有Jedi

set nu
set expandtab
set tabstop=4
set shiftwidth=4
set mouse=a
set shell=bash
set hls
set encoding=utf-8

"YoucomPleteMe:语句补全插件", ref to https://blog.csdn.net/OIDCAT/article/details/106816941
set runtimepath+=~/.vim/bundle/YouCompleteMe
set shellcmdflag=-ic

autocmd InsertLeave * if pumvisible() == 0|pclose|endif     " 离开插入模式后自动关闭预览窗口"
let g:ycm_clangd_uses_ycmd_caching = 0
let g:ycm_collect_identifiers_from_tags_files = 1           " 开启YCM基于标签引擎
let g:ycm_collect_identifiers_from_comments_and_strings = 1 " 注释与字符串中的内容也用于补全
let g:syntastic_ignore_files=[".*\.py$"]
let g:ycm_seed_identifiers_with_syntax = 1                  " 语法关键字补全
let g:ycm_complete_in_strings = 1
let g:ycm_confirm_extra_conf = 0                            " 关闭加载.ycm_extra_conf.py提示
let g:ycm_key_list_select_completion = ['<c-n>', '<Down>']  " 映射按键,没有这个会拦截掉tab, 导致其他插件的tab不能用.
let g:ycm_key_list_previous_completion = ['<c-p>', '<Up>']
let g:ycm_key_invoke_completion = '<C-a>'
let g:ycm_complete_in_comments = 1                          " 在注释输入中也能补全
let g:ycm_complete_in_strings = 1                           " 在字符串输入中也能补全
let g:ycm_collect_identifiers_from_comments_and_strings = 1 " 注释和字符串中的文字也会被收入补全
let g:ycm_global_ycm_extra_conf='~/.vim/bundle/YouCompleteMe/third_party/ycmd/.ycm_extra_conf.py'
"let g:ycm_global_ycm_extra_conf='~/.vim/.ycm_extra_conf.py' "加载文件路径
let g:ycm_clangd_binary_path = "~/software/llvm-13.0.0.obj/bin/clangd"
"let g:clang_library_path='/home/zwl/software/llvm-13.0.0.obj/lib/libclang.so' "libclang路径
let g:ycm_show_diagnostics_ui = 0                           " 禁用语法检查

inoremap <expr> <CR> pumvisible() ? "<Down>\<CR>" : "\<CR>"
inoremap <a-cr> <CR>
nnoremap <c-j> :YcmCompleter GoToDefinitionElseDeclaration<CR>
let g:ycm_min_num_of_chars_for_completion = 2                 " 从第2个键入字符就开始罗列匹配项
let g:ycm_max_num_candidates = 15                                                         " 候选数量设置
let g:ycm_auto_trigger = 1                                                                        " 签名帮助

当你想使用全局头文件中符号自动进行补齐,如算子api头文件,可以在.ycm_extra_conf.py中设置flag, -include /home/zwl/Ascend/ascend-toolkit/latest/tools/tikicpulib/lib/include/stub_fun.h.

ycm程序架构探索

ycm根据editor的不同语言发送消息给不同的lsp server, 如c/c++的clangd, python的Jedi.

youcompleteme插件执行过程是:vim主进程执行youcompleteme的vim源码脚本-》脚本中启动python执行ycmd。ycmd作为服务接收editor种种请求,ycmd接收代码补齐、跳转到定义等language server protocal(lsp)请求后,根据不同语言进行处理,其中C/C++吊起clangd+特定任务的参数,获取lsp的response。

下面是c/c++和python lsp启动示例

"/usr/bin/python3", "/home/zwl/.vim/bundle/YouCompleteMe/python/ycm/../../third_party/ycmd/ycmd", "--port=42047", "--options_file=/tmp/tmpn1p1ne_x", "--log=info", "--idle_suicide_seconds=1800", "--stdout=/tmp/ycmd_42047_stdout_wbj8o3qd.log", "--stderr=/tmp/ycmd_42047_stderr_9by64a7b.log"
"/home/zwl/software/llvm-project16/build_fun/bin/clangd", "--version"
"/home/zwl/software/llvm-project16/build_fun/bin/clangd", "-header-insertion-decorators=0"

编辑python文件时jedi的执行命令,
/usr/bin/python3
/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/jedi_deps/jedi/jedi/inference/compiled/subprocess/__main__.py
/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/jedi_deps/parso
3.10.12

这里的python执行给定的是一个目录。这种方式运行的是目录下的__main__.py文件,若import执行的是目录下的__init__.py文件。

ycmd调起jedi进程,jedi进程会驻守在内存中。可以看到ycmd和jedi进程输入输出关系。ycmd准备一个socket port接收vim发送的lsp请求,并作为ycmd标准输入0,ycmd的标准输出应该是pipe到vim中FIFO, pipe直接出口经过vim渲染到光标点的地方。jedi的标准输入则来自ycmd中建的管道,输出至ycmd中另外一个管道,通过两个管道,ycmd可以做到这jedi的数据传输。

同样可以看到ycmd和clangd的交互是通过pipe完成的

可以通过strace查看jedi进程read(0,)操作中收到的信息。注意,若是在docker中使用strace -p来attach到一个进程,需要root权限,且docker run时给定参数--cap-add=SYS_PTRACE。当然也可以去梳理jedi处理程序,将中间过程打印到log文件。

ycm和jedi都是python程序,他们之间通信用的是python object的序列化和反序列化工具pickle,更友好和高效。而ycm和clangd之间lsp通信用的则是标准的lsp协议中字符串的格式,如下是通过strace -p clangd_pid -s1024 | grep 'read\|write'看到的clangd读写交互的信息。clangd写回ycmd的操作应该是在clangd起来的子进程中完成,已经看不到了。

ycmd和clangd交互的信息

read(0, "Content-Length: 308\r\n\r\n{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"contentChanges\":[{\"text\":\"int a[10] = {1,2,3};\\n#include <stdio.h>\\n\\nint main() {\\n  int b = 0;\\n  for(int i=0; i<10;
i++) {\\n     printf(\\\"%d\\\\n\\\", a[i]);\\n  }\\n  printf(\\\"%d\\\", a[\\n}\\n\"}],\"textDocument\":{\"uri\":\"file:///tmp/a.c\",\"version\":49}}}", 4096) = 331

ycmd和jedi的交互信息


2024-06-16 18:16:56,503 received: (139690319253216, <function get_module_info at 0x7f3a07f4c3a0>, (), {'string': 'sys', 'full_name': 'sys', 'sys_path': ['/tmp', '/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd', '/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/bottle', '/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/regex-build', '/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/frozendict', '/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/jedi_deps/jedi', '/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/jedi_deps/parso', '/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/watchdog_deps/watchdog/build/lib3', '/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/watchdog_deps/pathtools', '/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/waitress', '/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '/home/zwl/.local/lib/python3.10/site-packages', '/usr/local/lib/python3.10/dist-packages', '/usr/lib/python3/dist-packages', '/home/zwl/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/jedi_deps/numpydoc'], 'is_global_search': True})

2024-06-16 18:16:56,503 response: (None, False)

2024-06-16 18:16:56,503 received: (139690319253216, <function load_module at 0x7f3a07f4c1f0>, (), {'dotted_name': 'sys', 'sys_path': ['/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '/home/zwl/.local/lib/python3.10/site-packages', '/usr/local/lib/python3.10/dist-packages', '/usr/lib/python3/dist-packages']})

2024-06-16 18:16:56,503 response: <jedi.inference.compiled.access.AccessPath object at 0x7f3a07c3cd90>

2024-06-16 18:16:56,504 received: (139690319253216, <function get_compiled_method_return at 0x7f3a07f4c280>, (139887231738768, 'py__file__'), {})

2024-06-16 18:16:56,504 response: None

这里的python执行给定的是一个目录。这种方式运行的是目录下的__main__.py文件,若import执行的是目录下的__init__.py文件。

posted @ 2024-06-14 22:14  zwlwf  阅读(3)  评论(0编辑  收藏  举报