2017-07-13-emacs配置ycmd补全

Table of Contents

1 ycmd介绍

它本来是vim上的插件 YouCompleteMe 。现在整成了一个通用的。

可以补全很多语言: C,C++,C#,python,js,go 等。看看下面就知道它支持 多少语言了。

    C-family, C#, Go, JavaScript, Python, Rust, and TypeScript languages
    are supported natively by YouCompleteMe using the Clang, OmniSharp,
    Gocode/Godef, Tern, Jedi, racer, and TSServer engines, respectively.
language backend
C-family Clang
C# OmniSharp
Go Gocode/Godef
JavaScript Tern
Python Jedi
Rust racer
TypeScript TSServer

它可以是基于语义的和不基于语言的。根据不同的语言,把两种的结果都汇 总后一起返回。

ycmdclient-server 架构的。我们使用的编辑器 vim, emacs 等等 都是client。真正的server是在它们需要补全的时候启动。server的工作是解 析源码文件,给client返回需要补全的内容。

server端能补全这么多类型的代码,光使用ycmd是搞不定的。 比如对于 C-family 的语言,ycmd补全功能需要 libclang ,它是编译器clang的 libary,一般也叫llvm。ycmd会用它来分析源文件。

ycmd使用不同的编译参数才能支持不同的语言, ./build.py --all 是支持 ycmd可以全部补全的语言。不过不推荐使用它。依赖太多啦。编译方面具体可 以参考 编译ycmd

2 编译ycmd

2.1 基本步骤

Dependencies

  1. 编译需要使用 python3 环境。建议使用virtualenv来新建一个 python3 的环境。可以参考 python使用virtualenv
  2. 支持 c-family 语言需要使用 libclang 。编译时会自动下载,如果 自动下载很慢,可以参考 编译时下载libclang很慢

从源码编译ycmd需要下面几步:

  1. clone源码:

            git clone https://github.com/Valloric/ycmd.git 
    
  2. 更新子库

            git submodule update --init --recursive
    
  3. 根据官网上说的直接调用下面这句编译可能会因为依赖太多,不一定编译 得过:

            ./build.py --all
    

使用 ./build.py --help 查看一下:

     (python3)  ~/github/ycmd/ [master] ./build.py --help
     usage: build.py [-h] [--clang-completer] [--system-libclang]
                     [--omnisharp-completer] [--gocode-completer]
                     [--racer-completer] [--system-boost] [--msvc {12,14,15}]
                     [--tern-completer] [--all] [--enable-coverage]
                     [--enable-debug] [--build-dir BUILD_DIR]

     optional arguments:
       -h, --help            show this help message and exit
       --clang-completer     Build C-family semantic completion engine.
       --system-libclang     Use system libclang instead of downloading one from
                             llvm.org. NOT RECOMMENDED OR SUPPORTED!
       --omnisharp-completer
                             Build C# semantic completion engine.
       --gocode-completer    Build Go semantic completion engine.
       --racer-completer     Build rust semantic completion engine.
       --system-boost        Use the system boost instead of bundled one. NOT
                             RECOMMENDED OR SUPPORTED!
       --msvc {12,14,15}     Choose the Microsoft Visual Studio version (default:
                             15).
       --tern-completer      Enable tern javascript completer
       --all                 Enable all supported completers
       --enable-coverage     For developers: Enable gcov coverage for the c++
                             module
       --enable-debug        For developers: build ycm_core library with debug
                             symbols
       --build-dir BUILD_DIR
                             For developers: perform the build in the specified
                             directory, and do not delete the build output. This is
                             useful for incremental builds, and required for
                             coverage data
  • --clang-completer 可以编译 c-family 语言的补全。它会下载它需 要的libclang到 clang_archives 目录。如果你觉得下载速度太慢,也 可自己下载放进去
  • --omnisharp-completerC#
  • --gocode-completergo
  • --tern-completerjs

这样看来,如果需要对 c-family 系语言进行补全,直接使用 ./build.py --clang-completer 就可以了。

注意 :我当前在 ebf04bafde342f2be5fd5717f368ebbe8bf6643c 这个 commit-id上编译的,此时需要使用 4.0.1 的libclang版本。我发现编译 ycmd的时候,需要使用 python3 才行。使用 python2 可能编译能成功, 但是编出来不有正常使用。

编译完成后,最好是测试下能不能使用,可以参考 测试ycmd是否能正常工作

2.2 编译时下载libclang很慢

下载clang编译器真的时太慢啦。可以到其它网络好的机器上先下载下来。我 是去云主机上使用wget下载的。当然,需要找到当前下载的clang的版本。这 个在 ./build.py --clang-completer 执行时会有输出。

     wget http://releases.llvm.org/4.0.1/clang+llvm-4.0.1-x86_64-apple-darwin.tar.xz

下载好后,直接放到ycmd的 clang_archives 目录下。然后直接 ./build.py --clang-completer 就可以编出来对 c-family 语言的补全。

2.3 编译ycmd时可能出错

如果第二次编译,可能失败,出现错误:

     Error: could not load cache

这种情况下,需要把 cpp 目录中的 CMakeCache.txt 文件删掉。这时再 重试就可以了。

3 测试ycmd是否能正常工作

从ycmd目录进入 examples 目录可以直接运行测试。

    cd examples/
    pip install -r requirements.txt
    ./example_client.py

测试脚本一定要运行在 python3 。所以改一下:

    mkdir -p /tmp/python3/
    virtualenv -p /usr/local/bin/python3 /tmp/python3/
    cd examples/
    pip install -r requirements.txt
    ./example_client.py

这个测试是对全部ycmd支持的语言。所以如果没有编译对js的支持,它会报错 的。不用care,只要你需要的补全是ok的就好。

4 emacs-ycmd

在emacs中使用,可以直接使用 emacs-ycmd 这个插件。

    (require 'ycmd)
    ;;; 这个设置编译出来的ycmd目录。注意这里的ycmd不是一个可执行文件,而是
    ;;; 一个目录,注意需要使用python3
    (set-variable 'ycmd-server-command '("/usr/local/bin/python3" "/Users/pengpengxp/github/ycmd/ycmd"))
    (set-variable 'ycmd-global-config "/Users/pengpengxp/src/asp/nginx/.ycm_extra_conf.py")


    ;;; 设置等待server的时间,默认是3s
    (setq ycmd-startup-timeout 5)

    ;;; 当ycmd-mode开启后,把ycmd加入到默认emacs的补全中,这样可以使用 C-M-i 来补全
    (defun ycmd-setup-completion-at-point-function ()
      "Setup `completion-at-point-functions' for `ycmd-mode'."
      (add-hook 'completion-at-point-functions
                #'ycmd-complete-at-point nil :local))

    (add-hook 'ycmd-mode #'ycmd-setup-completion-at-point-function)

    ;;; show debug info to *Messages* buffer
    (setq url-show-status t)

    ;;; tab setup
    (setq tab-always-indent 'complete)

    (defun peng-setup-ycmd ()
      " setup ycmd, add `ycmd-complete-at-point' to
      `completion-at-point-functions' so that `C-M-i' can toggle the
      complete.
    "
      (interactive)
      (ycmd-mode 1)
      (add-hook 'completion-at-point-functions
                #'ycmd-complete-at-point nil :local))

    (provide 'init-ycmd)

这样配置好后,使用 C-M-i 就可以调出补全内容啦。

5 C-family language

使用libclang的时候,它需要知道编译时提供的编译参数。这样libclang才能 分析代码,ycmd才能提供 c-family 基于语言的补全。有两种方式可以得到 编译选项。

5.1 emacs配置

把下面的函数和 emacs-ycmd 中的 peng-setup-ycmd 函数加入到 cc-mode 的hook中就可以了。

     (defun peng-setup-cc-mode-for-complete ()
       "use tab to indent and complete.
     tab on left will act as indent while on the right of character as
     `completion-at-point'
     "
       (interactive)
       (setq c-tab-always-indent 'nil)
       (setq c-insert-tab-function #'completion-at-point)
       )

有时候找不到对应的补全时,可以使用 ycmd-toggle-force-semantic-completion 把基于语言的补全强制打开。这 样它会去分析文件啦。

5.2 手动提供编译选项

对于编译选项,可以使用 .ycm_extra_conf.py 文件机制来靠诉ycmd我的 编译选项。比如我写测试readline的函数。当前目录结构是这样的:

     /tmp/readline/
     ├── hello.c
     ├── main.c
     ├── makefile
     └── test.cpp

     0 directories, 4 files

要对这个preject进行补全,新建一个 .ycm_extra_conf.py 文件,它就包 括一个函数就可以啦:

     def FlagsForFile( filename, **kwargs ):
       return {
         'flags': [ '-x', 'c', '-Wall', '-Wextra', '-Werror', '-lreadline' ],
       }

需要关注的只是 flags 这一行。把所有需要的flag就这样一个一个写进去 就可以啦。前面的两个选项 -xc 是选择C语言,cpp就把 c 换成 cpp 就可以啦。

对于一些大型的项目,手动编写 .ycm_extra_conf.py 太麻烦,可以考虑 下使用 ycm-generator 。它的基本用法:

       ./config_gen.py -x c++ ~/src/ASP-Engine/core/src

6 python

使用 jedi 来补全python。应该是需要在电脑上下载jedi:

    pip install jedi

然后默认就是支持python补全的。

Author: Peng Xie

Created: 2018-10-01 Mon 21:36