将Emacs打造为C++ IDE 第二趴(译)

Table of Contents

  1. 将Emacs打造为C++ IDE 第二趴
    1. 更快的启动速度 - The Emacs Server and Client
    2. Ivy 和 Swiper
    3. 通过Tags在代码库中导航
    4. 使用ClangFromat优化代码格式
    5. C++ 11及以上 的语法高亮
    6. YouCompleteMe - 快速代码补全
    7. YouCompleteMe 提示
    8. Git 源代码管理
    9. 快速启动
    10. 我的配置文件/安装

翻译自https://nilsdeppe.com/posts/emacs-c++-ide2

将Emacs打造为C++ IDE 第二趴

2017-12-27 Nils

2018-02-10 更新

一年前,我写了一篇关于将Emacs作为C++ IDE的博客。过去一年中,许多小的改进使我得到一份完全不同的配置,一份更快,并且更加好用的配置。
在这篇博客中,我将会展示我正在使用的功能的截图,并在最后提供我的整个配置(init)文件。配置文件中含有详尽的注释来说明发生了什么。
如果仍有不明白的,留下你的评论,我将会尽力解释清楚。

变化预览:

首先我简要列出变化的大纲和原因:

  • 使用Emacs server-client: 打开emacsclient比打开Emacs更快
  • 更省电: RTags 相较于它提供的功能,它所使用的cpu过多
  • 更好的tags导航:再次,RTags使用了太多的cpu(在笔记本上真的很糟糕),而且对于拥有超过100,000行C++的大型项目也无法很好的扩展。
  • cmake-ide很笨拙: 就是这样。它需要为每一个大型项目进行大量的配置,并且过分依赖于RTags。
  • 自动补全使用company-mode和semantic,irony。此外rtags真的慢,特别是针对大型项目
  • Ivy 原来是一个更快,更轻量级的Helm替代品,可以很好的满足我的需求。

我继续研究替代配置的最大原因是RTag太过CPU密集了。如果我允许的话,它将耗尽8个超线程,并且每次我在低级头文件中更改某些内容时,
它将重新解析整个项目。 这种操作在笔记本电脑上代价太高昂了。 如果你有一个功能强大的桌面并且不关心电池续航时间可能没问题,但是当
你在旅途中时,这种配置就不太现实了。

更快的启动速度 - The Emacs Server and Client

随着Emacs配置复杂性增加,可能令人讨厌的一件事是启动时间增加。有几种方法可以解决这个问题。一个看起来很有希望但我还没有尝试的是[use-package] [se-package]。
基本的想法似乎是懒洋洋地加载软件包,以便分散加载时间而不是一次性加载。

我选择使用Emacs Server - Client方法。 这意味着我使用systemd在登录时启动Emacs一次,然后使用emacsclient连接到正在运行的会话。
我用来连接Emacs的别名是 alias ec=“emacsclient -c”
我的systemd文件位于 ~/.config/systemd/user/emacsd.service 中,内容如下:

[Unit]
Description=Emacs: the extensible, self-documenting text editor
Documentation=man:emacs(1) info:Emacs

[Service]
Type=forking
ExecStart=/usr/bin/emacs --daemon
ExecStop=/usr/bin/emacsclient --eval "(progn (setq kill-emacs-hook nil) (kill-emacs))"
Restart=on-failure
Environment=DISPLAY=:%i
# Provide access to SSH
Environment=SSH_AUTH_SOCK=/run/user/1000/keyring/ssh
# Setup modules
Environment=PATH="/home/nils/Research/mosh/install/bin/:/home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.1.1/catch-1.9.4-qgdxfjhwk4mqhelhn2ggxmvyxvx6xm3k/bin:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/gsl-2.3-hsntrnj45jqjdmb6fq74tnxkmqxekts6/bin:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/openblas-0.2.19-if6giqoypphsmgle4anxox5kmb23g3vj/bin:/home/nils/Research/install/bin:/home/nils/.gem/ruby/2.4.0/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/home/nils/Research/spack/bin:/opt/intel/bin:/opt/intel/vtune_amplifier_xe_2017.2.0.499904/bin64:/home/nils/Research/llvm/build/bin:/home/nils/Research/templight-tools/build/bin:/home/nils/Research/standardese/build/tool:$PATH"
Environment=CPATH="/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/brigand-master-pcaoburzhlfibhh4mvmcia2e6dkbry5x/include:/home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.2.0/kvasir-mpl-develop-hr2lgqezjkiif3vbjsoxccorj2f5wppm/include:/home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.1.1/catch-1.9.4-qgdxfjhwk4mqhelhn2ggxmvyxvx6xm3k/include:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/yaml-cpp-master-gmc3k4n2vsvmqwjcyqrxwaz2h5fukxc2/include:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/gsl-2.3-hsntrnj45jqjdmb6fq74tnxkmqxekts6/include:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/openblas-0.2.19-if6giqoypphsmgle4anxox5kmb23g3vj/include:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/libxsmm-1.8.1-mevsuzxzo47g33rihi4t7fdohp3ga7gk/include:/home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.2.0/blaze-3.2-mnkglifq5s6ib5ltbvil4xt66fekqq2l/include:/home/nils/Research/install/include::/opt/petsc/linux-c-opt/include:$CPATH"
Environment=LD_LIBRARY_PATH="/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/yaml-cpp-master-gmc3k4n2vsvmqwjcyqrxwaz2h5fukxc2/lib:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/gsl-2.3-hsntrnj45jqjdmb6fq74tnxkmqxekts6/lib:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/openblas-0.2.19-if6giqoypphsmgle4anxox5kmb23g3vj/lib:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/libxsmm-1.8.1-mevsuzxzo47g33rihi4t7fdohp3ga7gk/lib:/home/nils/Research/install/lib:::/opt/petsc/linux-c-opt/lib:$LD_LIBRARY_PATH"
Environment=LIBRARY_PATH="/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/yaml-cpp-master-gmc3k4n2vsvmqwjcyqrxwaz2h5fukxc2/lib:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/gsl-2.3-hsntrnj45jqjdmb6fq74tnxkmqxekts6/lib:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/openblas-0.2.19-if6giqoypphsmgle4anxox5kmb23g3vj/lib:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/libxsmm-1.8.1-mevsuzxzo47g33rihi4t7fdohp3ga7gk/lib:/opt/petsc/linux-c-opt/lib:$LIBRARY_PATH"
Environment=CMAKE_PREFIX_PATH="/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/brigand-master-pcaoburzhlfibhh4mvmcia2e6dkbry5x:/home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.2.0/kvasir-mpl-develop-hr2lgqezjkiif3vbjsoxccorj2f5wppm:/home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.1.1/catch-1.9.4-qgdxfjhwk4mqhelhn2ggxmvyxvx6xm3k:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/yaml-cpp-master-gmc3k4n2vsvmqwjcyqrxwaz2h5fukxc2:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/gsl-2.3-hsntrnj45jqjdmb6fq74tnxkmqxekts6:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/openblas-0.2.19-if6giqoypphsmgle4anxox5kmb23g3vj:/home/nils/Research/spack/opt/spack/linux-antergos17-x86_64/gcc-6.3.1/libxsmm-1.8.1-mevsuzxzo47g33rihi4t7fdohp3ga7gk:/home/nils/Research/spack/opt/spack/linux-antergosrolling-x86_64/gcc-7.2.0/blaze-3.2-mnkglifq5s6ib5ltbvil4xt66fekqq2l"
TimeoutStartSec=0

[Install]
WantedBy=default.target

最重要的部分是 Environment=SSH_AUTH_SOCK 这行。 这确保你可以从Emacs会话中访问你的SSH代理。 如果没有此行,你每次使用时都需要重新输入SSH密钥的密码。
第14-18行是我工作中所需要使用的各种环境变量。
你可以创建文件执行 systemctl --user enable emacsd.service && systemctl --user start emacsd.service 来启动后台运行的Emacs进程,并将其设置为在登录时启动。
可以使用 systemctl --user restart emacsd.service 重新启动Emacs守护程序。

Ivy 和 Swiper

我已经转而使用Ivy进行模糊匹配而不是Helm。Ivy比Helm小很多,因为它只是其他软件包的底层补全引擎。 需要注意的重要一点是,
我还使用ripgrep进行更快速的搜索。 如果你没有或无法安装ripgrep,那么只需从我的init文件中删除任何引用ripgrep或rg的行。
在下面的截屏视频中,我展示了在打开文件时以及使用project-find-file时使用Ivy的模糊匹配。
为了易于使用,我已将 C-x M-f 映射到project-find-file。因此我没有必要使用projectile。

另一个基于Ivy构建的有用插件是swiper,它取代了Emacs中的标准搜索。swiper不是必须手动在文件中跳转,而是在扩展的minibuffer(迷你缓冲区)中显示所有匹配项。
这意味着正向和反向搜索实际上是相同的,并且两者都可以重新映射到swiper。

通过Tags在代码库中导航

和RTags类似的有CTags和]GTags。它们允许你在代码库中快速的跳转到类或者函数的定义。例如,假设我想查看我正在查看的代码中使用的函数的定义,我可以按 M-. 跳转到定义。
一旦我从函数定义中得到了我需要的信息,我可以按 M-, 跳转回之前的位置。类似的 M-t 显示Tags数据库中所有的光标所在位置的单词(the word-at-point).希望以上的用例
讲清楚了如何使用tags。我想要的是一个解析快速,准确的tags实现。在尝试了五个不同的方案后,我最终确定了Universal-CTags作为标签数据库的生成器。第一步是在你的系统中
安装Universal-CTags.你应该通过运行 ctags --version 来验证是否安装了Universal-CTag而不是其他实现。

在Emacs中的Tags导航,我使用的是counsel-etags.尽管它还很年轻,但效果非常好。我的配置会在每次保存文件时或距离上次构建Tags数据库已经3分钟了就会触发Tags数据库的重建,
这可以确保可以导航到新的类或函数上。请注意,在撰写本文时,我使用能够在文件名和目录名中使用通配符的函数覆盖了默认提供的自动更新函数。默认情况下,只有文件名支持通配符。
下面是源代码导航的演示。

使用ClangFromat优化代码格式

如果你不使用ClangFormat,你应该认真考虑它。 这是我简单的Emacs配置:

;; clang-format can be triggered using C-c C-f
;; Create clang-format file using google style
;; clang-format -style=google -dump-config > .clang-format
(require 'clang-format)
(global-set-key (kbd "C-c C-f") 'clang-format-region)

C++ 11及以上 的语法高亮

内置的语法高亮显示在现代C++方面做得不是很好。
幸运的是有一个补救措施:modern-cpp-font-lock。 配置使用:

(require 'modern-cpp-font-lock)
(modern-c++-font-lock-global-mode t)

YouCompleteMe - 快速代码补全

代码补全最重要的两个部分是速度和准确性。如果其中任何一个不达标,则代码补全对经验丰富的开发人员来说没有用。对我来说重要的第三个标准是代码补全引擎使用的CPU资源少于
编译代码所需的CPU资源,否则我可能只使用编译器给我的建议。我还希望能够在旅行时使用代码补全,CPU使用率低意味着更长的电池续航时间。我找到的最佳解决方案是
带有emacs-ycmd的YouCompleteMeDaemon。ycmd使用libclang来查找和补全,因此即使对于大型项目也是如此准确和快速。此外,它只解析你当前打开的文件,这与一些重新
解析整个项目的完成框架不同。

首先你必须安装ycmd 服务,这里有相关的说明。接下来在Emacs中安装emacs-ycmd软件包,该软件包hook到company和flycheck,以提供补全和动态语法检查。在下面的截屏视频中,
我展示了使用代码补全和语法检查功能将容器的大小输出到标准输出。minibuffer末尾出现的错误消息告诉我们标头未包含在内。

在我的init文件中,我将ycmd,company和flycheck的设置分为三个不同的部分,以便将来更容易维护。 有了ycmd,company和flycheck,我的CPU在大多数时间都处于空闲状态,
因此我可以获得非常快速且非常准确的补全,因此我也获得了很长的电池寿命。 最后,任务完成了!

YouCompleteMe 提示

在一个相当复杂的C ++ 14项目中我使用YCMD,它使用了许多新的语言特性,并且有很多类和函数模板。为了获得非常好的代码补全,我为YCMD开发了一个python脚本,
它非常积极地找到头文件的编译标志。 这样的脚本是必要的原因是因为compilecommands.json文件不包含头文件的任何编译标志,因为它们没有被编译。
我在这里分享了脚本作为一个要点。 该脚本必须放在~/ .ycmextraconf.py中,以便Emacs配置查找并使用它。 如果你不想使用该脚本,请在配置中删除这行

另一件需要注意的事情是,让YCMD,或者更具体地说是libclang,与预编译头文件很好地协同工作需要一些工作。 有关详细信息,请参阅YCMD GitHub上的此问题。
简短的说法是,如果使用预编译的头文件,则可能需要使用系统libclang构建YCMD,方法是将–system-libclang传递给构建脚本。

Git 源代码管理

我还使用magit在Emacs中执行我的所有git操作,并使用git-gutter向我显示我在当前文件中更改了哪些行。 Magit功能非常丰富,我强烈建议你阅读冗长的文档。
通过不再输入长git命令,你将很快节省你的投资时间。 magit网站上还有截屏视频,所以我不会在这里显示任何内容。

快速启动

注意:此部分是在2018年2月10日添加的。配置的功能不会更改,但加载速度更快。

我没有做太多的python开发,我特别试图避免使用笔记本,但有时我别无选择。我发现Web浏览器是一个糟糕的开发环境,所以我开始使用EIN来编辑Jupyter笔记本。
这使得该过程更加可以容忍。 不幸的是,启动Emacs时启动Jupyter服务器需要大约2.5秒,这很长一段时间。 我在我的开发机器上使用Emacs服务器,但是当我在
超级计算机上工作时,我通常不会,或者在我登录时仍然必须加载它。我决定做一些研究并使用use-package来加速加载时间。
结果是我的Emacs启动时间从~4.7s下降到约0.6s而不会丢失功能。 虽然我喜欢它是0.1秒,0.6秒使启动时间非常容易。
除了我在Gist中分享了我最近版本的~/ .emacs.el文件之外,我不会再说这些了。

我的配置文件/安装

我在这里将我的init文件在Gist上共享。 要完全替换当前配置,你需要做的就是安装ycmd并更改安装ycmd的路径(在.emacs.el文件中搜索/ home / nils / Research / ycmd)。
要确保Emacs加载新的init文件,请确保没有/.emacs或/.emacs.d/init.el文件。 启动Emacs时确保你有Internet连接,因为它会自动为你下载并安装任何丢失或过时的软件包。
如果一切正确,你不应在* Messages warnings ycmd-server * buffer中收到任何错误或警告。

我现在将指导一步一步来安装我的配置。

前期准备条件:

Emacs 24.5或更新的版本
YCMD及其要求(例如glibc 2.14或更新版本)
ripgrep(可选,如果没有,请从init中删除与ripgrep有关的行)
安装:

复制~/.emacs~/.emacs.el,以及~/.emacs.d
删除~/.emacs~/.emacs.el~/.emacs.d/init.el,无论你使用哪个
将Gist复制到~/.emacs.el
启动Emacs。如果Emacs没有立即开始安装软件包,请按M-x并运行list-packages,然后关闭并再次启动Emacs。
如果任何软件包无法自动安装,请按M-x并运行list-packages手动安装它们,但大多数软件包将自动安装。
编辑~/.emacs.el将/home/nils/Research/ycmd/ycmd替换为你选择安装ycmd并重新启动Emacs的路径。
将ycmd Gist复制到~/.ycmextraconf.py
注意:在我安装此配置的一台机器上,我必须注释掉(require 'yasnippet)部分,启动Emacs并让所有内容安装,然后取消注释该部分并重新启动Emacs。

摘要
在这篇文章中,我简要概述了我对Emacs配置所做的主要更改。我已经花了相当多的精力来清理和组织我的Emacs init文件,所以希望在这里分享它足以让你入门。
如果没有,请对你想要我解释的内容发表评论,我将更新此帖子并提供更多信息。

你可能感兴趣的:(将Emacs打造为C++ IDE 第二趴(译))