想和大牛们聊一聊关于C代码编辑器的问题

首先先请教几个问题:

个人的日常工作主要以写c代码为主(90%以上时间),目前使用的是spacemacs,但是感觉对emacs功能的利用率可能不到10%,甚至不到1%,请问在spacemacs或emacs中:

  1. c模式是否可以做到修改.c文件中的函数定义时,.h文件对应的声明也跟着变化?
  2. c模式是否可以做到当调用了某一个函数时,可以自动或通过快捷键的方式包含对应的头文件?(能支持工程中的头文件最好,否则只支持标准库的也可以)。
  3. c模式是否可以像eclipse那样选择一个变量将其提取成局部变量,或将一段代码提取成一个函数?

题外话:目前编辑C代码的话,都有哪些公认的强大工具或功能插件?希望大家能够帮我推荐一下。

PS:个人是键盘党,目前我只知道emacs和vim(没用过 :sweat_smile:)可以在不碰鼠标且双手不离开打字区的情况下完成工作。

1 个赞

本站搜索cquery看看

这个是一个类似ycmd的东西吗?

好像是,我不用,等用过的人来回答。

关于第三点,我试了下 GitHub - tuhdo/semantic-refactor: Semantic Refactor is a refactoring tool based on Semantic parser framework 感觉应该能满足你的功能。

特性: 局部变量重命名 将region提取成函数 生成函数指纹信息 … 常用的refactor都有提供,还有专门针对c,c++的生成header到header文件

emacs

我的配置,我平时也用写一点 c,规模不大. init-c-c++.el: rtags 代替 ctag gtag 实现 reference, definition 等的跳转,irony-mode 改善 c/c++的编码体验,cmake-ide,cmake-mode集成rtags 以及cmake 实现IDE 的build 和index.

;;; package --- Summary:
;;; Commentary:
;;; Code:

(use-package irony
  :ensure t
  :init (progn
	  (defun samray/irony-mode-hook ()
	    (define-key irony-mode-map [remap completion-at-point] 'counsel-irony)
	    (define-key irony-mode-map [remap complete-symbol] 'counsel-irony))
	  (add-hook 'c++-mode-hook 'irony-mode)
	  (add-hook 'c-mode-hook 'irony-mode)
	  (add-hook 'irony-mode-hook 'samray/irony-mode-hook)
	  (add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options))
  )
(use-package clang-format
  :ensure t
  :commands (clang-format-region clang-format-buffer)
  )
(use-package cmake-ide
  :ensure t
  :init (progn
	  (add-hook 'c++-mode-hook (lambda () (cmake-ide-setup)))
	  (add-hook 'c-mode-hook (lambda () (cmake-ide-setup)))
	  )
  )
(use-package cmake-mode
  :ensure t
  :mode (
	   ("CMakeLists\\.txt\\'" . cmake-mode)
	   ("\\.cmake\\'" . cmake-mode)
	  ))
(use-package rtags
  :ensure t
  :init (progn
	  (setq rtags-completions-enabled t)
	  (eval-after-load 'company
	    '(add-to-list
	      'company-backends 'company-rtags))
	  ;; (setq rtags-autostart-diagnostics t)
	  (rtags-enable-standard-keybindings)
	  )
  )
;;; Tell emacs to open .h file in C++ mode
(add-to-list 'auto-mode-alist '("\\.h\\'" . c++-mode))
(provide 'init-c-c++)

;;; init-c-c++.el ends here

使用flycheckflycheck-irony 做syntax check init-syntax-check.el

;;; package --- Summary:
;;; Commentary:
;;; Code:

(use-package flycheck
  :ensure t
  :demand t
  :config(progn
	   (setq flycheck-mode-line-prefix "FC")
	   (global-flycheck-mode t)))
(use-package flycheck-irony
  :ensure t
  :defer t
  :init (progn
	  (add-hook 'flycheck-mode-hook #'flycheck-irony-setup)
	  ))
(add-hook 'c++-mode-hook (lambda ()
			   (setq flycheck-clang-language-standard "c++11")
			   (setq irony-additional-clang-options '("-std=c++11"))
			   ))
(provide 'init-syntax-checking)
;;; init-syntax-checking.el ends here

代码补全部分:company 驱动,其他的注释也挺清楚了

;;; C/C++ headers completion
(use-package company-c-headers
  :ensure t
  :defer t
  :init (progn (add-hook 'c-mode-hook
			 (lambda () (add-to-list 'company-backends 'company-c-headers))
			 )
	       (add-hook 'c++-mode-hook
			 (lambda () (add-to-list 'company-backends 'company-c-headers)))
	       )
  )
;;; backends for irony
(use-package company-irony
  :ensure t
  :defer t
  :init (progn (add-hook 'c-mode-hook
			 (lambda () (add-to-list 'company-backends 'company-irony)))
	       (add-hook 'c++-mode-hook
			 (lambda () (add-to-list 'company-backends 'company-irony)))
	       ))

;;; backends for irony-c-header
(use-package company-irony-c-headers
  :ensure t
  :defer t
  :init (progn (add-hook 'c-mode-hook
			 (lambda () (add-to-list 'company-backends 'company-irony-c-headers)))
	       (add-hook 'c++-mode-hook
			 (lambda () (add-to-list 'company-backends 'company-irony-c-headers)))
	       ))

我的 全部Emacs 配置

一位大佬的教程: https://tuhdo.github.io/c-ide.html

Thanks all.

我先各种测试一下 :smile:

好的,看了一些,配置都是依赖clang,但有些时候真不想用clang,因为很多服务器各种原因限制上安装特别麻烦,还有种思路是基于tags,感觉基于buffer的很不灵活,很多根本就没有补全啊

什么叫基于 buffer 的补全很不灵活? 不太理解你的意思,不基于 clang的补全也有,那是基于 tags的补全,我见得比较多的就是像我上面提到的那位大佬那样,使用 ggtags 生成源文件和头文件的 symbol,进行补全和跳转的。而上面提到的 rtags 是根据编译器生成的 compile_command.json 来进行补全的(这个表述可能不准确,我没有详细了解过,大意是这样),不过对于大项目来说,有同学提到 rtags 性能会出现问题

对的,company补全看后端:

1,现在最好用的是clang,最智能,能识别变量,函数以及之间的关系;

2,比较死板的的就是基于tag,像ctags,gtags等都是基于分析代码,根据符号生成tag文件,但我觉得这个有个问题,一是他会查找tag中所有的符号,有时候我不需要那么多,另一个是tag文件是手动生成的,我定义一个新变量,后面马上用就没法补全了;

3,基于buffer就是分析当前buffer中的符号,相关信息应该是保存在内存中,提供补全机制。我了解的是company-dabbrev实现了这个功能。但是我在写c++代码时,写一个之前有过的变量时,完全没有补全提示,自己试了试,有些情况可以,有些不可以,所以我觉得比较难用。我用vscode和vim就没有这种问题。

  1. ctags blog.binchen.org 有隔段时间自动更新tags的代码,gtags我用spacemacs会自动生成tags,具体怎么做的没研究。
  2. dabbrev应该还是比较可靠的,不会动不动不行,看看company-backends是不是出了问题?

最近不大想用tags了,因为更好的lsp已经在敲门了。而且我现在不写服务端了,用不到XD

好的,多谢,我在研究研究。 lsp看起来很吊,但我觉得真正用起来也有挑战,C++补全本身就比较蛋疼,使用lsp我觉得还是要用clang来支持,但服务器和别人一起用,真的不想装软件或者更新,太麻烦了。

lsp很不错, 不过需要装cquery. 你可以搜索一下大牛MaskRay的贴子.

如果你服务器和别人一起用,我觉得你可以试试Emacs 的tramp,你在本地安装clang 等依赖,然后用本地的编辑器编辑服务器上的源码,我有时候就是这么做的。只不过我编辑的不是服务器的代码,是docker 里面的代码,因为docker 的镜像一般只有一个vi 编辑器

LLVM Download Page 下載預編譯 clang+llvm

spacemacs 默認 spacemacs-jump-handlers-c+±mode 的 dumb-mode 以前總是搗蛋,大項目很容易卡死

dumb-jump 是工作原理就是使用 rg/ag 进行搜索,然后匹配,没有半点语法或者语意上的分析,感觉性能还不如 ctags/ggtags, 但是优点是简单易用,没有那么多的配置要求,不想 tags 系统那么折腾.

dumb-jump-go 是默認 jump handlers 裏的,其他選項 如果不移動point (比如 find-references 列出選項後你取消了) 那麼 dumb-jump 就會生效

我的基於 lsp-ui、cquery 的配置

https://github.com/MaskRay/Config/blob/master/home/.emacs.d/layers/%2Bmy/my-cquery/packages.el https://github.com/MaskRay/Config/blob/master/home/.emacs.d/layers/%2Bmy/my-code/packages.el

有點亂。不知道爲什麼放在 ~/.emacs.d/private 下沒反應

我想看下你cquery的配置,上面的链接失效了,新链接可以给下么

然而,1、2 cquery和ccls都做不到。