关键词:Emacs、Emacs Lisp
引子
Emacs是什么?让我们来看看Emacs吧的标语:“不能煮咖啡的编辑器不是一个好操作系统”。
首先,Emacs是个编辑器,由Richard M Stallman等人最开始编写而成,后来有很多的衍生,现在常常使用的是1984年由Stallman发起维护的GNU Emacs,如果您对这段历史感兴趣,强烈推荐您读一读Steven Levy的《黑客》这本书。这本书对黑客道德、开源文化的历史等等有着非常详细的介绍。。
与此同时,Emacs又不只是一个编辑器。经过合理配置之后,Emacs可以变成不同语言的编程环境,可以编写Markdown、LaTeX文件,可以浏览PDF、网页,可以播放音乐、视频,也可以接发邮件,进行IRC聊天等等。至于“煮咖啡”“操作系统”一类的说法,仅仅是为了体现其功能强大而已。
本文只作为自己的Emacs学习记录而已,若可以给您一些启发,再好不过。用多了Emacs,真觉得把手从键盘挪到鼠标上太费劲了。
我的配置已经上传到github上:coder109/.emacs.d。Emacs的配置主要用到Emacs Lisp语言。
为什么要用Emacs?
- 快捷键多。熟练之后,写代码双手几乎不需要离开键盘。
- 自由度、模块化程度高。有需要的配置可以找现成的模块,或者用强大的Emacs Lisp写个新的。如果自己配置,可以完全贴近自己的需求,避免功能冗余。
- 兼容性高。Window、Linux、MacOS都可以用Emacs。
- 配置后功能强大。需要其它软件的频率会降低。
- 资源比较丰富。自带文档、Emacs China论坛里都有很多资料可供参考。
- …
1. 配置文件的结构
通常来说,一般采用如下的方法:
~/.emacs.d/init.el作为主配置文件,通过设置,Emacs可以从这个文件中调取配置。~/.emacs.d/lisp/作为其它配置文件的文件夹,init.el可以从这个文件夹里读取其它的配置文件。你可以使用provide、require这两个过程进行配置文件的读取,比如,在~/.emacs.d/lisp/init-emacs.el的末尾写下如下的代码:(provide 'init-emacs)这就相当于把
init-emacs.el文件以init-emacs的名字暴露在init.el前面,而在init.el中,只需要:(add-to-list 'load-path "~/.emacs.d/lisp") (require 'init-emacs)就可以将
init-emacs.el引入主配置文件了。
2. 包的安装
可以手动安装,输入如下命令:
M-x package-install然后安装想要的包就可以了。
但这显然不方便,可以采用use-package包管理器统一管理包的安装,在相应的设置文件中设置:
;; 如果没安装use-package,就安装它。
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(require 'use-package)
;; 自动安装所有需要的软件包
(setq use-package-always-ensure t)之后你就可以应用它了。格式大概如下:
(use-package rainbow-delimiters
:ensure t
:hook (prog-mode . rainbow-delimiters-mode))3. 主题设置
您可以根据自己所需,进行配置。
1. 基本的UI设置
令工具栏、滚动栏等不显示,并显示行号。在右下角显示时间。
(tool-bar-mode -1)
(scroll-bar-mode -1)
(menu-bar-mode -1)
(global-display-line-numbers-mode t)
(column-number-mode t)
(display-time-mode t)
(setq display-time-24hr-format t)
(setq display-time-day-and-date t)2. 主题和modeline设置
您可以去github上搜索主题。笔者采用moe-theme+powerline的方案,顺便使用nyan-mode,在右下角显示一个彩虹猫,权当装饰,配置如下:
(add-hook 'after-init-hook 'nyan-mode)
(use-package moe-theme)
(show-paren-mode t)
(setq moe-theme-mode-line-color 'blue)
(setq show-paren-style 'expression)
(moe-dark)
(powerline-default-theme)3. 字体
笔者曾经在Emacs China论坛上找到一个中英文都能妥善设置的方案:
(setq fonts '("Source Code Pro Medium" "Microsoft YaHei"))
(set-fontset-font t 'unicode "Segoe UI Emoji" nil 'prepend)
(set-face-attribute 'default nil
:font (format "%s:pixelsize=%d" (car fonts) 20))
(setq default-frame-alist '((font . "Source Code Pro-16")))
(if (display-graphic-p)
(dolist (charset '(kana han symbol cjk-misc bopomofo))
(set-fontset-font (frame-parameter nil 'font) charset
(font-spec :family (car (cdr fonts))))))4. 欢迎界面
使用dashboard。
(use-package dashboard
:ensure t
:config (dashboard-setup-startup-hook))
(setq dashboard-banner-logo-title "Let's all love Lain...")
(setq dashboard-startup-banner "/home/bruce/Lain_avatar.png")
(setq dashboard-image-banner-max-height 300) ;; 设置图片高度
(setq dashboard-image-banner-max-width 300) ;; 设置图片宽度
(setq dashboard-center-content t)4. 编程相关设置
1. 编码设置
笔者将编码设置为UTF-8。毕竟,看见乱码再修改编码方式实在令人恼火。
(set-keyboard-coding-system 'utf-8)
(set-clipboard-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-buffer-file-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(modify-coding-system-alist 'process "*" 'utf-8)
(setq default-process-coding-system '(utf-8 . utf-8))
(setq-default pathname-coding-system 'utf-8)2. LSP与DAP的设置
LSP,全称叫做Language Server Protocol,大概的作用就是能提供语法高亮、语法提示功能的工具。
DAP,全称叫做Debug Adapter Protocol,和调试有关的工具。
建议参考github进行lsp的配置以及相应语言服务器的下载。
我的配置如下:
(use-package lsp-mode
:init
;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")
(setq lsp-keymap-prefix "C-c l")
:hook (;; replace XXX-mode with concrete major-mode(e. g. python-mode)
(c-mode . lsp)
(julia-mode . lsp)
(lua-mode . lsp)
(ocaml-mode . lsp)
(perl-mode . lsp)
(dart-mode . lsp)
(haskell-mode . lsp)
(go-mode . lsp)
(php-mode . lsp)
(racket-mode . lsp)
(ruby-mode . lsp)
(rust-mode . lsp)
(erlang-mode . lsp)
(elixir-mode . lsp)
(clojure-mode . lsp)
(verilog-mode . lsp)
)
:commands lsp
:init
(setq lsp-auto-configure t
lsp-auto-guess-root t
lsp-idle-delay 0.500
lsp-session-file "~/.emacs/.cache.lsp-sessions"))
(require 'lsp-python-ms)
(setq lsp-python-ms-auto-install-server t)
(add-hook 'python-mode-hook 'lsp)
(add-hook 'c++-mode-hook 'lsp)
;; LSP-latex
(setq lsp-latex-java-executable "usr/bin/java")
(setq lsp-latex-texlab-jar-file 'search-from-exec-path)
;; LSP-juliaLang
(use-package lsp-julia
:config
(setq lsp-julia-default-environment "~/.julia/environments/v1.7"))
;; Set up before-save hooks to format buffer and add/delete imports.
;; Make sure you don't have other gofmt/goimports hooks enabled.
(defun lsp-go-install-save-hooks ()
(add-hook 'before-save-hook #'lsp-format-buffer t t)
(add-hook 'before-save-hook #'lsp-organize-imports t t))
(add-hook 'go-mode-hook #'lsp-go-install-save-hooks)
;; LSP-Haskell
(add-hook 'haskell-mode-hook #'lsp)
(add-hook 'haskell-literate-mode-hook #'lsp)
;; optional
(use-package lsp-ui :commands lsp-ui-mode)
;; if you are helm user
(use-package helm-lsp :commands helm-lsp-workspace-symbol)
;; if you are ivy user
;;(use-package lsp-ivy :commands lsp-ivy-workspace-symbol)
;;(use-package lsp-treemacs :commands lsp-treemacs-errors-list)
;; Debugger
(use-package dap-mode
:ensure t
:commands dap-debug
:custom
(dap-auto-configure-mode t)
:config
(dap-ui-mode 1)
)
(require 'dap-python)3. Emacs命令补全与加强
我使用Helm+smex。
(helm-mode 1)
(smex-initialize)4. 文本补全
我使用company。它会自动根据你在当前文件中输入过的单词进行补全。
(global-company-mode t)
(setq company-minimum-prefix-length 2)
(setq company-idle-delay 0)
(setq company-selection-wrap-around t)
(company-quickhelp-mode)5. 括号的分级显示
Lisp语言的一大特点就是:括号太tm多了。
有必要对不同等级的括号,用不同的颜色显示出来,我选用rainbow-delimiters。
(use-package rainbow-delimiters
:ensure t
:hook (prog-mode . rainbow-delimiters-mode))6. 撤销操作树
通过使用undo-tree包,可以通过C-u快捷键方便地回滚到过去的状态。我的第二行配置是为了将undo-tree文件,也就是记录撤销操作树的文件都存到统一的文件夹中,相信我,这很有必要。
(add-hook 'after-init-hook 'global-undo-tree-mode)
(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo")))7. 语法检查
我使用flycheck,感觉比自带的flymake好用一些。
(global-flycheck-mode t)8. Vim键位
Vim键位实在是太香了。我使用evil包,将Vim的键位和Emacs的键位结合在一起,非常好用。
(evil-mode 1)9. 搜索强化
您可以试一试iedit和avy。
10. 杂项
我还使用用于项目管理的projectile和版本管理的magit。
5. 自编写过程
我自己写了几个自动编译运行的过程,有挺多bug的。
但是我懒得改了。
(defun c-quick-compile ()
(interactive)
(compile (format "gcc %s && ./a.out" (buffer-name) ) t)
)
(defun c-compile-no-run ()
(interactive)
(compile (format "gcc %s" (buffer-name)))
)
(defun compile-no-run ()
(interactive)
(if (eq major-mode 'java-mode)
(java-compile-no-run))
(if (eq major-mode 'c-mode)
(c-compile-no-run))
)6. 键位绑定
您可以使用如下的键位绑定过程:
(global-set-key (kbd "C-c a l") 'avy-goto-line)
(global-set-key (kbd "C-c a a") 'avy-copy-line)
(global-set-key (kbd "C-c a b") 'avy-copy-region)
(global-set-key (kbd "C-c a m") 'avy-move-line)
(global-set-key (kbd "C-c a n") 'avy-move-region)后记
参考了Emacs China、Reddit(r/emacs)、知乎、CSDN等平台的配置。有一些小package没有列出。本文会持续更新。私以为Emacs的配置也是如此,从编程菜鸟到编程老鸟的过程中,Emacs的配置也会随着需求逐渐变化迭代,有现成的包就用,没有符合自己需求的包,便自己写一个。