关键词: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
的末尾写下如下的代码:
这就相当于把init-emacs.el
文件以init-emacs
的名字暴露在init.el
前面,而在init.el
中,只需要:
1 2 (add-to-list 'load-path "~/.emacs.d/lisp" ) (require 'init-emacs)
就可以将init-emacs.el
引入主配置文件了。
2. 包的安装 可以手动安装,输入如下命令:
然后安装想要的包就可以了。
但这显然不方便,可以采用use-package
包管理器统一管理包的安装,在相应的设置文件中设置:
1 2 3 4 5 6 7 8 9 (unless (package-installed-p 'use-package) (package-refresh-contents ) (package-install 'use-package)) (require 'use-package) (setq use-package-always-ensure t )
之后你就可以应用它了。格式大概如下:
1 2 3 (use-package rainbow-delimiters :ensure t :hook (prog-mode . rainbow-delimiters-mode))
3. 主题设置 您可以根据自己所需,进行配置。
1. 基本的UI设置 令工具栏、滚动栏等不显示,并显示行号。在右下角显示时间。
1 2 3 4 5 6 7 8 9 (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
,在右下角显示一个彩虹猫,权当装饰,配置如下:
1 2 3 4 5 6 7 8 (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论坛上找到一个中英文都能妥善设置的方案:
1 2 3 4 5 6 7 8 9 10 11 (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
。
1 2 3 4 5 6 7 8 (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
。毕竟,看见乱码再修改编码方式实在令人恼火。
1 2 3 4 5 6 7 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的配置以及相应语言服务器的下载。
我的配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 (use-package lsp-mode :init (setq lsp-keymap-prefix "C-c l" ) :hook ( (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) (setq lsp-latex-java-executable "usr/bin/java" ) (setq lsp-latex-texlab-jar-file 'search-from-exec-path) (use-package lsp-julia :config (setq lsp-julia-default-environment "~/.julia/environments/v1.7" )) (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) (add-hook 'haskell-mode-hook #'lsp) (add-hook 'haskell-literate-mode-hook #'lsp) (use-package lsp-ui :commands lsp-ui-mode) (use-package helm-lsp :commands helm-lsp-workspace-symbol) (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
。
1 2 (helm-mode 1 ) (smex-initialize )
4. 文本补全 我使用company
。它会自动根据你在当前文件中输入过的单词进行补全。
1 2 3 4 5 (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
。
1 2 3 (use-package rainbow-delimiters :ensure t :hook (prog-mode . rainbow-delimiters-mode))
6. 撤销操作树 通过使用undo-tree
包,可以通过C-u
快捷键方便地回滚到过去的状态。我的第二行配置是为了将undo-tree
文件,也就是记录撤销操作树的文件都存到统一的文件夹中,相信我,这很有必要。
1 2 (add-hook 'after-init-hook 'global-undo-tree-mode) (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo" )))
7. 语法检查 我使用flycheck
,感觉比自带的flymake
好用一些。
1 (global-flycheck-mode t )
8. Vim键位 Vim键位实在是太香了。我使用evil
包,将Vim的键位和Emacs的键位结合在一起,非常好用。
9. 搜索强化 您可以试一试iedit
和avy
。
10. 杂项 我还使用用于项目管理的projectile
和版本管理的magit
。
5. 自编写过程 我自己写了几个自动编译运行的过程,有挺多bug的。
但是我懒得改了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 (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. 键位绑定 您可以使用如下的键位绑定过程:
1 2 3 4 5 (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的配置也会随着需求逐渐变化迭代,有现成的包就用,没有符合自己需求的包,便自己写一个。