Emacs定制:编译

本来自己的Emacs配置文件,是直接克隆的purcell的,然后又加入了一些自己的设定,结果导致现在的配置文件越来越臃肿,而且很多配置项发生了冲突,很多自己不需要的功能的配置,开始占用自己的精力。

所以,决定重新配置自己的Emacs。

从零开始,一项一项梳理,只保留自己需要的,自己用不到的一个也不加。

本文先整理出来编译代码相关的部分。大量来自purcell或者其它网友的配置,少量自己的定义。

编译之前

  • 自定义编译命令,把编译窗口减小一点。同时,编译完成还回到原来窗口。
lisp 复制代码
(defun my-compile ()
  "Run compile and resize the compile window."
  (interactive)
  (save-buffer)
  (call-interactively 'compile)
  (let* ((cur (selected-window))
         (win (get-buffer-window "*compilation*")))
    (select-window win)
    (shrink-window-horizontally 10)
    (select-window cur)))
  • 复用编译窗口
lisp 复制代码
;; 编译buffer变量
(defvar sanityinc/last-compilation-buffer nil
  "The last buffer in which compilation took place.")

;; 编译时自动保存编译buffer变量
(with-eval-after-load 'compile
  (defun sanityinc/save-compilation-buffer (&rest _)
    "Save the compilation buffer to find it later."
    (setq sanityinc/last-compilation-buffer next-error-last-buffer))
  (advice-add 'compilation-start :after 'sanityinc/save-compilation-buffer)

;; 编译前先查找是否编译buffer变量存在,而且可用
  (defun sanityinc/find-prev-compilation (orig &optional edit-command)
    "Find the previous compilation buffer, if present, and recompile there."
    (if (and (null edit-command)
             (not (derived-mode-p 'compilation-mode))
             sanityinc/last-compilation-buffer
             (buffer-live-p (get-buffer sanityinc/last-compilation-buffer)))
        (with-current-buffer sanityinc/last-compilation-buffer
          (funcall orig edit-command))
      (funcall orig edit-command)))

  ;; 添加编译前查找为recompile命令的advice
  (advice-add 'recompile :around 'sanityinc/find-prev-compilation))

编译中

  • 使用ansi-color显示编译过程中的颜色标识
lisp 复制代码
(with-eval-after-load 'compile
  (require 'ansi-color)
  ;; 动态颜色显示区域回调函数
  (defun sanityinc/colourise-compilation-buffer ()
    (when (eq major-mode 'compilation-mode)
      (ansi-color-apply-on-region compilation-filter-start (point-max))))
      
  ;; 添加为回调
  (add-hook 'compilation-filter-hook 'sanityinc/colourise-compilation-buffer))
  • 设定自动滚动编译输出
lisp 复制代码
(setq-default compilation-scroll-output t)

编译之后

  • 使用alert通知编译结果
lisp 复制代码
(require-package 'alert)

(defun sanityinc/alert-after-compilation-finish (buf result)
  "Use `alert' to report compilation RESULT if BUF is hidden."
  (when (buffer-live-p buf)
    (unless (catch 'is-visible
              (walk-windows (lambda (w)
                              (when (eq (window-buffer w) buf)
                                (throw 'is-visible t))))
              nil)
      (alert (concat "Compilation " result)
             :buffer buf
             :category 'compilation))))

(with-eval-after-load 'compile
  (add-hook 'compilation-finish-functions
            'sanityinc/alert-after-compilation-finish))
  • 如果编译的buffer没有位于多窗口中,切换到其它buffer;否则,关闭窗口。
lisp 复制代码
(defun my-compile-exit (&optional buffer)
  "Exit compile BUFFER."
  (interactive)
  (if (one-window-p t)
      (progn
        (projectile-project-buffers-other-buffer))
    (progn
      (delete-window (get-buffer-window buffer)))))
  • 跳转到第一个错误。如果没有错误,调用前面定义的退出buffer。
lisp 复制代码
(defun goto-first-error-or-exit (buffer string)
  "Call exit BUFFER when no errors."
  (interactive)
  (with-current-buffer buffer
    (goto-char (point-min))
    (condition-case err
	(compilation-next-error 1)
      (error
       (run-with-timer 1 nil
		       (lambda (buf)
			 (my-compile-exit buf))
		       buffer)))))
  • 编译完成自动执行前面定义的跳转或者关闭。
lisp 复制代码
(add-hook 'compilation-finish-functions 'goto-first-error-or-exit)

其中,关闭编译buffer之前等待1秒钟,方便简单留意一下编译信息。

  • 给编译窗口加几个快捷键
lisp 复制代码
(add-hook 'compilation-mode-hook
          (lambda ()
            (local-set-key (kbd "n") 'compilation-next-error)
            (local-set-key (kbd "p") 'compilation-previous-error)
            (local-set-key (kbd "q") (lambda ()
                                       (interactive)
                                       (my-compile-exit (current-buffer))))))

其中,p跳转到前面一个错误,n跳转到后面一个错误,q退出。

CMake相关

因为很多项目使用Cmake做的构建系统,所以CMake相关的配置,也一并整理到编译相关的配置里。

  • 关联CMake配置文件为cmake-mode
lisp 复制代码
(setq auto-mode-alist
      (append '(("CMakeLists\\.txt\\'" . cmake-mode)
		("\\.cmake\\'" . cmake-mode))
	      auto-mode-alist))
  • 添加cmake的自动补全
lisp 复制代码
(add-hook 'cmake-mode-hook
          (lambda()
            (add-to-list 'company-backends 'company-cmake)))

快捷键绑定

在cc-mode的模式下,使用Ctrl-x c编译;使用F7重编译。

lisp 复制代码
(with-eval-after-load 'cc-mode
  (define-key c-mode-base-map (kbd "C-x c") 'my-compile)
  (define-key c-mode-base-map (kbd "<F7>") 'recompile))