emacs 第一部分:熟悉emacs
经验从来都是一张网,知识都是相互关联引用的。
而我们希望学习过程是一条线,先有基础,逐步递进,每个概念在遇到的时候都有前序概念的支撑。这个过程需要非常精细的组织和编排。
这种方式我们称之为上课,参照材料我们称其为课本。除了课本,我们还有老师、辅导书和周而复始的考试。十几年下来我们一定程度上适应了这种‘学习方式’。
人是要长大的,不总会在课堂里,而且真知不会来自于循序渐进的灌输。
自发的学习过程,从实践,从blog,甚至看书,总会有从消防栓喝水感觉。太多的概念,太多的未知铺面而来的感觉并不享受,很容易受挫,难以坚持。
多做准备,从教和学两个方面都是: 从教来说:尽量循序渐进,都是从三岁数过手指头过来的,回到初学者的心态。写作是一种很好的梳理方法,写作中思考的跳跃性会受约束,迫使自己的思路和传达更加逻辑。 从学来说:多做准备,子曰:“不愤不启,不悱不发”。有积累才有顿悟。开放心态,不要抱有成见,不为已知所累。
作为emacs系列的第一篇文章,我希望能够说清楚:
- 什么是emacs:emacs本身极大有别于我们传统认知中的编辑器。
- 开始使用emacs,了解基buffer、mode等基础概念
- 了解emacs的配置,从purcell的配置开始,了解配置文件的组织
- 熟悉emacs的包管理,自动/手动升级卸载扩展。
为什么emacs不仅仅是个编辑器
从emacs中,我找了效率和乐趣。
Emacs与其说是个编辑器,更是一个elisp(emacs lisp 语言)运行环境,极端一点,可以说它是个操作系统。
“I’m using Linux. A library that emacs uses to communicate with Intel hardware.” – Erwin, #emacs, Freenode.
几乎不会关闭emacs,很多任务都放到上面执行
- 组织笔记:
org-mode - 写markdown:
markdown-mode - 各个工程的git客户端:
magit - 文档/公式编辑:
org-mode + latex - clojure/clojurescript 开发环境:
cider - ...
通过M-x uptimes命令我可以看到最长42天都没有关闭过,比起操作系统。。。很多时候我更依赖emacs。
Last 200 uptimes
Boot Endtime Uptime This emacs
=================== =================== ============ ==========
2019-09-29 13:37:08 2019-10-01 20:00:37 2.06:23:28 <--
2019-09-23 20:46:39 2019-09-29 11:34:39 5.14:47:59
2019-08-12 08:31:38 2019-09-23 19:38:59 42.11:07:21
2019-08-07 16:27:23 2019-08-11 21:48:30 4.05:21:07
2019-08-04 23:44:06 2019-08-07 16:12:26 2.16:28:19
2019-08-04 11:22:58 2019-08-04 21:29:52 0.10:06:54
emacs 安装
虽然在各个系统有差异,我们推荐使用purcell配置,clojure开发依赖的clojure-mode, cider, paredit都含在其中了。是一个很赞的start kit。
osx
推荐使用brew,brew cask安装带UI的应用程序,比如emacs、mpv、wireshark。
#安装emacs26.3 带GUI
brew cask install emacs
#使用purcell start kit
git clone https://github.com/purcell/emacs.d.git ~/.emacs.d
Windows
#安装emacs26.3 带GUI
#安装步骤待补充
#使用purcell start kit
git clone https://github.com/purcell/emacs.d.git ~/.emacs.d
Linux
#安装emacs26.3 带GUI
#安装步骤待补充
#使用purcell start kit
git clone https://github.com/purcell/emacs.d.git ~/.emacs.d
emacs的UI

buffer
Emacs的界面元素中,主界面被称为frame,每一个可见的区域称为一个window,这个很反直觉(现在普遍的认知是windw最大,其他窗体元素比如frame都是window的子元素)。
Emacs有40余年的历史,它诞生大大早于现代GUI之前,那个时候frame,window和现代通常的GUI元素的涵义不同。
个人建议Window和Frame放到一边,着眼于buffer。
emacs支持同时打开多个buffer,buffer不一定对应文件。
比如emacs打开时候的默认的*scratch*buffer
有特殊用途的一般都是*开始*结束,基本不对应具体文件。
buffer首先是个数据结构,星号buffer很多使用用来做I/O,比如:
*scratch*:emacs的草稿buffer*Message*:emacs的用户交互历史信息*Help*:emacs的帮助buffer*eshell*:eshell模型开始后的交互buffer
emacs可以非常灵活的组织buffer,在一个大屏幕上(哪个程序员没有大屏幕),这种方式尤其方便。
modeline
emacs通过modeline来和用户沟通当前buffer的状态,一个典型的modeline类似下面:
U:--- buffer-name (major-mode minor-mode1 minor-mode2 ...)
第一个U代表编码:当前的bufferUnicode
U:后面的代表当前buffer的文件状态:
**– 有未保存的修改--– 所有修改已经保存%*– 只读,但是有修改%%– 只读,没有修改
接下来是buffer的名字,对应文件的buffer名就是文件名。
再往后就是各种mode,每个buffer都只有一个major-mode(主模式)和至少一个minor-mode(辅模式)。
major-mode根据文件的后缀和文件属性自动判定,minor-mode挂在major-mode上。也可以手动开启和关闭。
emacs是高度可定制的,并不是一个编辑器,或者换个说法,编辑器的功能也是抽象为多个模式,比如行号这种基础的功能,对于emacs来说都是一个辅模式。
如果我们希望素有的clojure代码打开的时候都显示行号,我们可以在elisp中添加:
(add-hook 'clojure-mode-hook (lambda () (linmu-mode 1)))
主模式和辅模式的对应关系在配置文件中维护, 参见官方文档:
现在正在编辑的.md文件的major-mode是Markdown,自动启动的minor-mode有FlyC projectile Undo-Tree ElDoc。
如果我需要编辑其中嵌入的clojure代码,我会通过(M-x clojure-mode RET)切换为clojure-mode, 代码编辑完成后,再切换为markdown-mode。
mini buffer
emacs的minibuffer是用户输入命令,emacs也会通过这个区域做用户提醒(学名echo area), 每次M-x以后输入的命令(以后你会知道命令都是elisp的函数名)都是在此区域。
生活自理必须掌握的快捷键
emacs中常用的几个组合按键中:
C: Control键M: Meta键,可以映射为option或者commandS: ShiftC-x: Control和x一起按下C-x C-f: Control和x按下,再Control和f一起按下,打开一个文件,如果这个文件不存在,就创建一个新的。C-c p f: Control和c按下,按p,按f,查找当前project的某个文件。
窗体操作
C-x o不同窗体之间切换C-x 1干掉其他所有窗体,注意窗体和buffer是两个概念,不影响任何buffer和文件。C-x 2打开第二个窗体,上下排列C-x 3打开第二个窗体,左右排列C-x 0关闭当前窗体
操作buffer和文件
- 切换buffer,
C-x b输入buffer 名称 - 创建新buffer,
C-x b输入buffer名称,是的切换和创建是同一个命令 - 打开某个文件,
C-x C-f打开某个文件,如果文件不存在,就创建个新的 - 保存buffer到文件
C-x C-s
移动光标(point)
一闪一闪的称为point。
C-a移动到行首M-m移动到行第一个非空白字符C-e移动到行尾C-f前移一个字符C-b后移一个字符M-f前移一个词M-b后移一个词C-s正则查找匹配,继续按查找下一个处匹配C-r返乡正则查找M-<跳到buffer头M->跳到buffer尾M-g g跳转到某行
emacs中选择区域(region)
mark是一个标记,c-@打一个标记,然后移动point。x
光标(point)和标记(mark)之间的区域称为一个region。
在创建一个region之后, 可以在这个region中,进行复制、剪切。
粘贴复制
C-w剪切M-w拷贝C-y粘贴
clojure-mode和cider
在一个clojure工程中,需要启动cider来启动REPL。
M-x cider-jack-in-clj: 启动一个clj的replM-x cider-jack-in-cljs: 启动一个cljs的repl