8000 GitHub - lhwgwg/Spacemacs-rocks: Happy Hacking Emacs & Spacemacs (Simplified Chinese)
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

lhwgwg/Spacemacs-rocks

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Master Emacs in 21 Days

https://travis-ci.org/emacs-china/Spacemacs-rocks.svg?branch=master

Spacemacs Rocks 第二季

./Artwork.png

GitHub Spacemacs Rocks 作者 zilongshanren 编者 li-xinyang, lsytj0413

在这一季中我们计划用 21 天学习 Emacs ä»¥åŠ Spacemacs 的使用。从基础安装开始到å¯ä»¥ è¿ç”¨åˆ°å·¥ä½œç”Ÿäº§çŽ¯èŠ‚ä¸­ã€‚ä¸ºäº†ç¡®ä¿å­¦ä¹ è´¨é‡ï¼Œè¯·åŠ¡å¿…å®Œæˆå’Œç†è§£è®¡åˆ’中的æ¯ä¸€é¡¹å­¦ä¹ ä»»åŠ¡ã€‚

第一天:准备开始

视频地å€å¦‚下

说在最å‰é¢

如果你第一次å¬è¯´ Emacs ä½ å¯ä»¥åœ¨æ€§æ„Ÿçš„ Emacs(Emacs is Sexyï¼‰ä¸€æ–‡ä¸­æ‰¾åˆ°ä½¿ç”¨å®ƒçš„ç† ç”±ï¼æˆ‘相信你一定会被它的强大所å¸å¼•。

如果你还没有安装 Emacs å¯ä»¥åœ¨ Mac OS X å®‰è£…é“¾æŽ¥ä»¥åŠ Window 安装链接找到它。本文 我们使用的为 Emacs 25.0.x Pretest 版本,一些é…置在 Emacs 24 中å¯èƒ½å¹¶ä¸é€‚用。

在开始本教程之å‰è¯·åŠ¡å¿…å…ˆå®Œæˆ Emacs æä¾›çš„å®˜æ–¹æ•™ç¨‹ï¼ˆå®Œæˆæ—¶é—´å¤§çº¦ 30 åˆ†é’Ÿï¼‰ï¼Œå®ƒå¯ ä»¥é€šè¿‡ä½¿ç”¨ C-h t ï¼ˆåŒæ—¶æŒ‰ä½ Ctrl 与 h é”®ï¼ŒæŽ¥ç€æŒ‰ t é”® t 在这里代表 tutorial) 在 Emacs 中直接将其打开。

Emacs Lisp 是 Emacs 所用的编程语言,你å¯ä»¥åœ¨é˜…读这篇教程(Learn X in Y Minutes) åŽå¾ˆå¿«åœ°äº†è§£å®ƒçš„基础用法。

基础æ“作

因为 Control 键在 Emacs 中æžä¸ºå¸¸ç”¨ï¼Œæ‰€ä»¥ä¸ºäº†æ›´æ–¹ä¾¿åœ°ä½¿ç”¨ Emacs 的键ä½ä¿®æ”¹ï¼Œéœ€è¦ 对其åšå‡ºä¿®æ”¹ã€‚建议将大写é”定键(Caps Lock)替æ¢ä¸º Control 键。这里是一个å¯ä»¥å‚考 的把大写é”定键替æ¢ä¸º Control 键的教程:移动 Control é”® (Moving The Ctrl Key)。如 果这个的教程ä¸é€‚用于你的æ“作系统,请自行æœç´¢å…¶å®ƒçš„修改方å¼ã€‚

常è§ç¬¦å·æ‰€ä»£è¡¨çš„æ„ä¹‰å¦‚ä¸‹

  • M(eta),在 Mac 下为 Option é”®
  • s(uper),在 Mac 环境下为左 Command é”®
  • S(Shift)
  • C(trl)

光标的移动是编辑器中最常用的æ“作所以必须熟知。

  • C-f 为å‰ç§»ä¸€ä¸ªå­—符, f 代表 forward。
  • C-b 为åŽç§»ä¸€ä¸ªå­—符, b 代表 backward。
  • C-p 为上移至å‰ä¸€è¡Œï¼Œ p 代表 previous。
  • C-n 为上移至下一行, n 代表 next。
  • C-a 为移至行首, a 代表 ahead。
  • C-e 为移至行尾, e 代表 end。

常用的文件æ“作快æ·é”®ç»„åˆä¹Ÿå¿…须熟记。

  • C-x C-f 为打开目标文件, f 代表 find/file
  • C-x C-s 为ä¿å­˜å½“å‰ç¼“冲区(Buffer), s 代表 save

C-x 是 Emacs 的快æ·é”®ä¸­å¸¸ç”¨çš„å‰ç¼€å‘½ä»¤ã€‚这些å‰ç¼€å‘½ä»¤å¸¸å¸¸ä»£è¡¨äº†ä¸€ç³»åˆ—有关è”的指 令,å分é‡è¦ï¼Œè¯·ç‰¹åˆ«ç‰¢è®°ã€‚其它常è§çš„还有 C-c, C-h 。打断组åˆé”®ä¸º C-g ,它 ç”¨äºŽç»ˆç«¯å–æ¶ˆä¹‹å‰çš„æŒ‡ä»¤ã€‚å¿«æ·é”®å°±æ˜¯ç”¨é¢„先绑定好的方å¼å‘Šè¯‰ Emacs 去执行指定的命令。 (之åŽä¼šä»‹ç»åˆ°æ›´å¤šæœ‰å…³ç»‘定的内容)

内置功能

Emacs 功能强大,但是部分功能默认情况下并未开å¯ã€‚下é¢å°±æœ‰å‡ ä¸ªä¾‹å­ï¼Œ

编辑器内显示行å·å¯ä½¿ç”¨ M-x linum-mode æ¥å¼€å¯ã€‚

获å–帮助

Emacs 是一个富文档编辑器(Self document, extensible editor)而下é¢çš„ä¸‰ç§æ–¹æ³•在学 ä¹  Emacs 的过程中也éžå¸¸é‡è¦ã€‚他们分别是,

  • C-h k 寻找快æ·é”®çš„帮助信æ¯
  • C-h v 寻找å˜é‡çš„帮助信æ¯
  • C-h f 寻找函数的帮助信æ¯

学习基础 Elisp

请务必完æˆè¿™ç¯‡æ•™ç¨‹ï¼ˆLearn X in Y Minutes)æ¥äº†è§£ Elisp 的使用(阅读时间大约 15 分钟),你也å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°å®ƒçš„中文版。Emacs Lisp 为一个函数å¼çš„语言,所以它全部 功能都是由函数æ¥å®žçŽ°çš„ã€‚

下é¢ä¸ºä¸€äº›ç®€å•的例å­

;; 2 + 2
(+ 2 2)

;; 2 + 3 * 4
(+ 2 (* 3 4))

;; 定义å˜é‡
(setq name "username")
(message name) ; -> "username"

;; 定义函数
(defun func ()
  (message "Hello, %s" name))

;; 执行函数
(func) ; -> Hello, username

;; 设置快æ·é”®
(global-set-key (kbd "<f1>") 'func)

;; 使函数å¯ç›´æŽ¥è¢«è°ƒç”¨å¯æ·»åŠ  (interactive)
(defun func ()
  (interactive)
  (message "Hello, %s" name))

开始 Hackingï¼

Emacs çš„é…置文件默认ä¿å­˜åœ¨ ~/.emacs.d/init.el 文件中。(如果其ä¸å­˜åœ¨å¯è‡ªè¡Œåˆ›å»ºï¼Œ é…置文件也å¯ä¿å­˜åœ¨ ~/.emacs 文件中,他们之间的区别我们会在åŽé¢åšè®¨è®ºï¼‰

**注æ„:** 如果希望把é…置放在 ~/.emacs.d/init.el æ–‡ä»¶ä¸­ï¼Œé‚£ä¹ˆéœ€è¦æ‰‹å·¥åˆ é™¤ ~/.emacs 文件。

在开始é…置之å‰è®©æˆ‘们先æ¥åŒºåˆ« Emacs 中 Major Mode 与 Minor Mode 的区别。Major Mode é€šå¸¸æ˜¯å®šä¹‰å¯¹äºŽä¸€ç§æ–‡ä»¶ç±»åž‹ç¼–辑的核心规则,例如语法高亮ã€ç¼©è¿›ã€å¿«æ·é”®ç»‘定等。 而 Minor Mode 是除去 Major Mode 所æä¾›çš„æ ¸å¿ƒåŠŸèƒ½ä»¥å¤–çš„é¢å¤–编辑功能(辅助功能)。 例如在下é¢çš„é…置文件中 tool-bar-mode 与 linum-mode ç­‰å‡ä¸º Minor Mode*。

ç®€å•æ¥è¯´å°±æ˜¯ï¼Œä¸€ç§æ–‡ä»¶ç±»åž‹åŒæ—¶åªèƒ½å­˜åœ¨ä¸€ç§ Major Mode 但是它å¯ä»¥åŒæ—¶æ¿€æ´»ä¸€ç§æˆ–多 ç§ Minor Mode。如果你希望知é“当å‰çš„æ¨¡å¼ä¿¡æ¯ï¼Œå¯ä»¥ä½¿ç”¨ C-h m æ¥æ˜¾ç¤ºå½“剿‰€æœ‰å¼€å¯ 的全部 Minor Mode 的信æ¯ã€‚

简å•的编辑器自定义

䏋颿˜¯ä¸€äº›ç®€å•的编辑器é…置信æ¯ï¼Œä½ éœ€è¦åšçš„就是将其写入你的é…置文件中 ( ~/.emacs.d/init.el )å³å¯ã€‚

;; 关闭工具æ ï¼Œtool-bar-mode å³ä¸ºä¸€ä¸ª Minor Mode
(tool-bar-mode -1)

;; 关闭文件滑动控件
(scroll-bar-mode -1)

;; 显示行å·
(global-linum-mode 1)

;; 更改光标的样å¼ï¼ˆä¸èƒ½ç”Ÿæ•ˆï¼Œè§£å†³æ–¹æ¡ˆè§ç¬¬äºŒé›†ï¼‰
(setq cursor-type 'bar)

;; 关闭å¯åŠ¨å¸®åŠ©ç”»é¢
(setq inhibit-splash-screen 1)

;; 关闭缩进 (第二天中被去除)
;; (electric-indent-mode -1)

;; æ›´æ”¹æ˜¾ç¤ºå­—ä½“å¤§å° 16pt
;; http://stackoverflow.com/questions/294664/how-to-set-the-font-size-in-emacs
(set-face-attribute 'default nil :height 160)

;; 快速打开é…置文件
(defun open-init-file()
  (interactive)
  (find-file "~/.emacs.d/init.el"))

;; 这一行代ç ï¼Œå°†å‡½æ•° open-init-file 绑定到 <f2> 键上
(global-set-key (kbd "<f2>") 'open-init-file)

åœ¨æ¯æ¬¡ç¼–辑é…置文件åŽï¼Œåˆšåˆšåšçš„修改并ä¸ä¼šç«‹åˆ»ç”Ÿæ•ˆã€‚这时你需è¦é‡å¯ç¼–è¾‘å™¨æˆ–è€…é‡æ–°åŠ  è½½é…ç½®æ–‡ä»¶ã€‚é‡æ–°åŠ è½½é…置文件你需è¦åœ¨å½“å‰é…置文件中使用 M-x load-file åŒå‡»ä¸¤æ¬¡ 回车确认默认文件å,或者使用 M-x eval-buffer 去执行当å‰ç¼“冲区的所有 Lisp 命令。 你也å¯ä»¥ä½¿ç”¨ C-x C-e æ¥æ‰§è¡ŒæŸä¸€è¡Œçš„ Lisp 代ç ã€‚这些å¯ä½¿åˆšåˆšä¿®æ”¹çš„é…置文件生效。 当然你也å¯ä»¥å°†è¿™äº›å‡½æ•°ç»‘定为快æ·é”®ã€‚

æ’件管ç†

使用默认的æ’件管ç†ç³»ç»Ÿï¼ˆå¯åœ¨èœå•æ  Options > Manage Emacs Packages 中找到)安 装 Company æ’件,他是一个用于代ç è¡¥å…¨çš„æ’ä»¶ã€‚å®ƒçš„åå­—ä»£è¡¨è¡¥å…¨ä¸€åˆ‡çš„æ„æ€ï¼ˆ Comp lete Any thing)。因为默认的æ’件管ç†ç³»ç»Ÿæä¾›çš„æ’ä»¶å分有é™ï¼Œæ‰€ä»¥æˆ‘们会在之åŽçš„ 几天中继续将其强化。

使用的下é¢çš„é…置将 Company-mode 在全局模å¼ä¸‹æ¿€æ´»

; å¼€å¯å…¨å±€ Company 补全
(global-company-mode 1)

Org-mode

简å•çš„ Org-mode 使用,它å¯ä»¥åˆ—出æçº²ï¼Œå¹¶æ–¹ä¾¿åœ°ä½¿ç”¨ tab é”®æ¥å¯¹å…¶è¿›è¡Œå±•开与关闭。 C-c C-t å¯ä»¥å°†ä¸€ä¸ªæ¡ç›®è½¬æ¢æˆä¸€æ¡å¾…办事件。

* 为一级标题
** 为二级标题
*** 为三级标题并以此类推

第二天:高级自定义

视频地å€å¦‚下

说在最å‰é¢

如果你想深入学习 Emacs Lisp å¯ä»¥é˜…读 GNU æä¾›çš„ An Introduction to Programming in Emacs Lisp 。(也å¯ä»¥ M-x info ç„¶åŽé€‰æ‹© Emacs Lisp Intro)

我们先解决å‰ä¸€å¤©ä¸­é‡åˆ°çš„一些问题。首先是在对象是一个缓冲区局部å˜é‡ï¼ˆBuffer-local variable)的时候,比如这里的 cursor-type ,我们需è¦åŒºåˆ† setq 与 setq-default : setq 设置当å‰ç¼“冲区(Buffer)中的å˜é‡å€¼ï¼Œ setq-default 设 置的为全局的å˜é‡çš„值(具体内容å¯ä»¥åœ¨ StackOverflow æ‰¾åˆ°ï¼‰ã€‚ä¸‹é¢æ˜¯ä¸€ä¸ªä¾‹å­ï¼Œç”¨äºŽ 设置光标样å¼çš„æ–¹æ³•。

(setq-default cursor-type 'bar)

今天我们需è¦å°†ç¬¬ä¸€å¤©å…³é—­çš„自动缩进 (electric-indent-mode) 从é…置文件中去除,它 是 Emacs 24.4 中加入的新特性,你å¯ä»¥åœ¨è¿™ç¯‡æ–‡ç« ä¸­æ‰¾åˆ°æ›´å¤šå…³äºŽå®ƒçš„内容。我们之å‰å…³ 闭它是因为,它存在ä¸ç†æƒ³çš„缩进效果(在 Emacs Lisp 中用分å·åšæ³¨é‡Šæ—¶ fancy-comment 会造æˆå¾ˆè¿œçš„缩进,其实解决方法是使用 Emacs Lisp 推è的两个分å·è€Œ 䏿˜¯ä¸€ä¸ª ;; ,这样就å¯ä»¥é¿å…这个问题。于是我们也就将其从é…置文件中删除)

因为通常我们的é…置文件以åŠé¡¹ç›®æ–‡ä»¶å‡ä½¿ç”¨ç‰ˆæœ¬æŽ§åˆ¶ç³»ç»Ÿï¼Œæ‰€ä»¥è‡ªåŠ¨ç”Ÿæˆçš„备份文件就显 得有些多余。我们还å¯ä»¥ç¦æ­¢ Emacs 自动生æˆå¤‡ä»½æ–‡ä»¶ï¼Œä¾‹å¦‚ init.el~ 。( ~ ä¸ºåŽ ç¼€çš„æ–‡ä»¶ä¸ºè‡ªåŠ¨ç”Ÿæˆçš„备份文件)我们å¯ä»¥ä½¿ç”¨ä¸‹é¢çš„æ–¹æ³•将其关闭。

(setq make-backup-files nil)

关于分å±çš„使用,如果你已ç»è¯»è¿‡ Emacs è‡ªå¸¦çš„æ•™ç¨‹ï¼ŒçŽ°åœ¨ä½ åº”è¯¥å·²ç»æŽŒæ¡äº†åŸºæœ¬çš„åˆ†å± æ“作方法了。关于分å±çš„æ›´å¤šå†…容你å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ã€‚

  • C-x 1 ä»…ä¿ç•™å½“å‰çª—å£
  • C-x 2 将当å‰çª—å£åˆ†åˆ°ä¸Šè¾¹
  • C-x 3 将当å‰çª—å£åˆ†åˆ°å³è¾¹

使用下é¢çš„é…ç½®æ¥åŠ å…¥æœ€è¿‘æ‰“å¼€è¿‡æ–‡ä»¶çš„é€‰é¡¹è®©æˆ‘ä»¬æ›´å¿«æ·çš„在图形界é¢çš„èœå•中打开最近 编辑过的文件。

(require 'recentf)
(recentf-mode 1)
(setq recentf-max-menu-item 10)

;; 这个快æ·é”®ç»‘定å¯ä»¥ç”¨ä¹‹åŽçš„æ’ä»¶ counsel 代替
;; (global-set-key (kbd "C-x C-r") 'recentf-open-files)

require çš„æ„æ€ä¸ºä»Žæ–‡ä»¶ä¸­åŠ è½½ç‰¹æ€§ï¼Œä½ å¯ä»¥åœ¨æ€å“¥çš„网站读到关于 Emacs Lisp 库系统 的更多内容,文章在这里。

使用下é¢çš„é…置文件将删除功能é…ç½®æˆä¸Žå…¶ä»–图形界é¢çš„编辑器相åŒï¼Œå³å½“你选中一段文字 之åŽè¾“å…¥ä¸€ä¸ªå­—ç¬¦ä¼šæ›¿æ¢æŽ‰ä½ é€‰ä¸­éƒ¨åˆ†çš„æ–‡å­—ã€‚

(delete-selection-mode 1)

下é¢çš„这些函数å¯ä»¥è®©ä½ æ‰¾åˆ°ä¸åŒå‡½æ•°ï¼Œå˜é‡ä»¥åŠå¿«æ·é”®æ‰€å®šä¹‰çš„æ–‡ä»¶ä½ç½®ã€‚因为éžå¸¸å¸¸ç”¨ 所以我们建议将其设置为与查找文档类似的快æ·é”®ï¼ˆå¦‚下所示),

  • find-function ( C-h C-f )
  • find-variable ( C-h C-v )
  • find-function-on-key ( C-h C-k )

在我们进入下一个部分之间让我们æ¥çœ‹çœ‹ä½¿ç”¨ ~/.emacs.d/init.el 与 ~/.emacs 的区 别(更多关于他们区别的讨论å¯åœ¨è¿™é‡Œæ‰¾åˆ°ï¼‰ã€‚ç®€å•æ¥è¯´è¯·ä½¿ç”¨å‰è€…,因为它有下é¢çš„两个 优点,

  • 它å¯ä»¥æ›´å¥½å°†æ‰€æœ‰ Emacs 相关的文件整åˆåœ¨ä¸€ä¸ªç›®å½•内(干净的 HOME ,网盘备份等优点)
  • 更好的版本控制

Emacs 也很美

é…ç½®æ’ä»¶æº

åœ¨è¿›è¡Œç¾ŽåŒ–ä¹‹å‰æˆ‘们需è¦é…ç½®æ’ä»¶çš„æºï¼ˆé»˜è®¤çš„æºéžå¸¸æœ‰é™ï¼‰ï¼Œæœ€å¸¸ä½¿ç”¨çš„æ˜¯ MELPA (Milkypostman’s Emacs Lisp Package Archive)。它有éžå¸¸å¤šçš„æ’ä»¶ï¼ˆ3000 多个æ’件)。 一个æ’件下载的次数多并ä¸èƒ½è¯´æ˜Žå®ƒéžå¸¸æœ‰ç”¨ï¼Œä¹Ÿè®¸è¿™ä¸ªæ’件是其他的æ’ä»¶çš„ä¾èµ–。在这里 ä½ å¯ä»¥æ‰¾åˆ°å…¶å®‰è£…使用方法。添加æºåŽï¼Œæˆ‘们就å¯ä»¥ä½¿ç”¨ M-x package-list-packages æ¥æŸ¥çœ‹æ‰€æœ‰ MELPA 上的æ’件了。在表å•中å¯ä»¥ä½¿ç”¨ I æ¥æ ‡è®°å®‰è£… D æ¥æ ‡è®°åˆ é™¤ï¼Œ U æ¥æ›´æ–°ï¼Œå¹¶ç”¨ X æ¥ç¡®è®¤ã€‚

ä½ å¯ä»¥ç›´æŽ¥å°†ä¸‹é¢çš„代ç å¤åˆ¶åˆ°ä½ çš„é…置文件顶端,从而直接使用 Melpa 作为æ’ä»¶çš„æºã€‚ ä½ å¯ä»¥å°†ä½ éœ€è¦çš„æ’ä»¶å字写在 my/packages 中,Emacs 在å¯åŠ¨æ—¶ä¼šè‡ªåŠ¨ä¸‹è½½æœªè¢«å®‰è£… çš„æ’件。

 (when (>= emacs-major-version 24)
     (require 'package)
     (package-initialize)
     (setq package-archives '(("gnu"   . "http://elpa.emacs-china.org/gnu/")
                      ("melpa" . "http://elpa.emacs-china.org/melpa/"))))

;; æ³¨æ„ elpa.emacs-china.org 是 Emacs China 中文社区在国内æ­å»ºçš„一个 ELPA 镜åƒ

 ;; cl - Common Lisp Extension
 (require 'cl)

 ;; Add Packages
 (defvar my/packages '(
                ;; --- Auto-completion ---
                company
                ;; --- Better Editor ---
                hungry-delete
                swiper
                counsel
                smartparens
                ;; --- Major Mode ---
                js2-mode
                ;; --- Minor Mode ---
                nodejs-repl
                exec-path-from-shell
                ;; --- Themes ---
                monokai-theme
                ;; solarized-theme
                ) "Default packages")

 (setq package-selected-packages my/packages)

 (defun my/packages-installed-p ()
     (loop for pkg in my/packages
           when (not (package-installed-p pkg)) do (return nil)
           finally (return t)))

 (unless (my/packages-installed-p)
     (message "%s" "Refreshing package database...")
     (package-refresh-contents)
     (dolist (pkg my/packages)
       (when (not (package-installed-p pkg))
         (package-install pkg))))

 ;; Find Executable Path on OS X
 (when (memq window-system '(mac ns))
   (exec-path-from-shell-initialize))

关于上é¢è¿™æ®µé…ç½®ä»£ç æœ‰å‡ ä¸ªçŸ¥è¯†ç‚¹ï¼Œé¦–先就是这段é…置文件中用到了 loop for ... in ,它æ¥è‡ª cl å³ Common Lisp 扩展。 for , in, collect å‡ä¸º cl-loop 中的 ä¿ç•™å…³é”®å­—ã€‚ä¸‹é¢æ˜¯ä¸€äº›ç®€å•çš„ cl-loop 的使用示例:

;; é历æ¯ä¸€ä¸ªç¼“冲区(Buffer)
(cl-loop for buf in (buffer-list)
         collect (buffer-file-name buf))

;; 寻找 729 的平方根(设置最大为 100 为了防止无é™å¾ªçŽ¯ï¼‰
(cl-loop for x from 1 to 100
         for y = (* x x)
         until (>= y 729)
         finally return (list x (= y 729)))

ä½ å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°æ›´å¤šå…³äºŽå¾ªçŽ¯çš„ä½¿ç”¨è¯´æ˜Žã€‚

其次就是它使用到了 quote, 它其实就是我们之å‰å¸¸å¸¸è§åˆ°çš„ ' (å•引å·ï¼‰çš„完全体。 因为它在 Lisp 中å分常用,所以就æä¾›äº†ç®€å†™çš„æ–¹æ³•。

;; 下é¢ä¸¤è¡Œçš„æ•ˆæžœå®Œå…¨ç›¸åŒçš„
(quote foo)
'foo

quote çš„æ„æ€æ˜¯ä¸è¦æ‰§è¡ŒåŽé¢çš„内容,返回它原本的内容(具体请å‚考下é¢çš„例å­ï¼‰

(print '(+ 1 1)) ;; -> (+ 1 1)
(print (+ 1 1))  ;; -> 2

更多关于 quote 的内容å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ï¼Œæˆ–者在这里找到 StackOverflow 上对于它的讨论。

这样我们就å¯ä»¥åŒºåˆ†ä¸‹é¢ä¸‰è¡Œä»£ç çš„区别,

;; 第一ç§
(setq package-selected-packages my/packages)
;; 第二ç§
(setq package-selected-packages 'my/packages)
;; 第三ç§
(setq package-selected-packages (quote my/packages))

第一ç§è®¾ç½®æ˜¯åœ¨ç¼“冲区中设置一个å为 package-selected-packages çš„å˜é‡ï¼Œå°†å…¶çš„值 设定为 my/packages å˜é‡çš„值。第二ç§å’Œç¬¬ä¸‰ç§å…¶å®žæ˜¯å®Œå…¨ç›¸åŒçš„,将一个å为 package-selected-packages çš„å˜é‡è®¾ç½®ä¸º my/packages 。

我们å¯ä»¥ç”¨ä¸‹é¢ä»£ç å°† Emacs 设置为开å¯é»˜è®¤å…¨å±ï¼Œ

(setq initial-frame-alist (quote ((fullscreen . maximized))))

我们也å¯ä»¥å¯ç”¨è‡ªåŠ¨æ‹¬å·åŒ¹é…(Highlight Matching Parenthesis),éšåŽä¼šä»‹ç»æ’ä»¶æ¥å¢ž 强这个匹é…的功能。你å¯ä»¥å F438 œ¨è¿™é‡Œè¯»åˆ°å…³äºŽé’©å­çš„æ›´å¤šä¿¡æ¯ã€‚

(add-hook 'emacs-lisp-mode-hook 'show-paren-mode)

高亮当å‰è¡Œï¼Œå½“文本内容很多时å¯ä»¥å¾ˆå®¹æ˜“找到光标的ä½ç½®ã€‚

(global-hl-line-mode 1)

安装主题

(add-to-list 'my/packages 'monokai-theme)

ç„¶åŽä½¿ç”¨ä¸‹é¢çš„é…ç½®ä½¿å…¶æ¯æ¬¡æ‰“开编辑器时加载主题,

(load-theme 'monokai 1)

æŽ¨èæ’ä»¶

使用 M-x customize-group åŽé€‰æ‹©å¯¹åº”çš„æ’ä»¶å称,å¯ä»¥è¿›å…¥å¯è§†åŒ–é€‰é¡¹åŒºå¯¹æŒ‡å®šçš„æ’ ä»¶åšè‡ªå®šä¹‰è®¾ç½®ã€‚当选择 Save for future session åŽï¼Œåˆšåˆšåšçš„设计就会被ä¿å­˜åœ¨ä½ çš„ é…置文件( init.el )中。关于å„个æ’件的安装与使用方法通常都å¯ä»¥åœ¨å…¶å®˜æ–¹é¡µé¢æ‰¾ 到(GitHub Pages 或者是项目仓库中的 README æ–‡ä»¶ï¼‰ã€‚æˆ‘ä»¬å¼ºçƒˆå»ºè®®å¤§å®¶åœ¨å®‰è£…è¿™äº›æ’ ä»¶åŽé˜…è¯»ä½¿ç”¨æ–¹æ³•æ¥æ›´å¥½çš„将它们使用到你的日常工作当中使效率最大化。

JavaScript IDE

Emacs æä¾›çš„默认 JavaScript Major Mode 并䏿˜¯éžå¸¸å¥½ç”¨ã€‚所以我们å¯ä»¥å°†é»˜è®¤çš„æ¨¡å¼ æ›¿æ¢æˆ js2-mode 一个比默认模å¼å¥½ç”¨çš„ Major Mode。我们å¯ä»¥é€šè¿‡ MELPA æ¥ä¸‹è½½å®ƒï¼Œç„¶ åŽç”¨ä¸‹é¢çš„代ç å°†å…¶å¯ç”¨ã€‚

(setq auto-mode-alist
      (append
       '(("\\.js\\'" . js2-mode))
       auto-mode-alist))

ä½ å¯ä»¥åœ¨è¿™é‡Œï¼ˆHow Emacs Chooses a Major Mode)找到 Emacs 是如何选择何时该选用何 ç§ Major Mode 的方法。

在这里我们需è¦çŸ¥é“ auto-mode-alist 的作用,这个å˜é‡æ˜¯ä¸€ä¸ª AssociationList,它 使用正则表达å¼ï¼ˆREGEXP)的规则æ¥åŒ¹é…ä¸åŒç±»åž‹æ–‡ä»¶åº”使用的 Major Mode。 䏋颿˜¯å‡ ä¸ª 正则表达å¼åŒ¹é…的例å­ï¼Œ

(("\\`/tmp/fol/" . text-mode)
 ("\\.texinfo\\'" . texinfo-mode)
 ("\\.texi\\'" . texinfo-mode)
 ("\\.el\\'" . emacs-lisp-mode)
 ("\\.c\\'" . c-mode)
 ("\\.h\\'" . c-mode)
 …)

䏋颿˜¯å¦‚何添加新的模å¼ä¸Žå¯¹åº”文件类型的例å­ï¼ˆä¸Žæˆ‘们é…ç½® js2-mode 时相似的例å­ï¼‰ï¼Œ

(setq auto-mode-alist
  (append
   ;; File name (within directory) starts with a dot.
   '(("/\\.[^/]*\\'" . fundamental-mode)
     ;; File name has no dot.
     ("/[^\\./]*\\'" . fundamental-mode)
     ;; File name ends in ‘.C’.
     ("\\.C\\'" . c++-mode))
   auto-mode-alist))

在 js2-mode 模å¼ä¸­ä¼šæä¾›

  • 语法高亮
  • 语法检查器(Linter)

执行缓冲区的代ç å¯ä»¥ä½¿ç”¨ nodejs-repl æ’件,它需è¦ä½ çš„æœºå™¨ä¸Šå·²ç»å®‰è£…了 NodeJS。 然而在 Mac OS X 上å¯èƒ½ä¼šå‡ºçŽ°æ‰¾ä¸åˆ° NodeJS 坿‰§è¡Œæ–‡ä»¶çš„问题,è¦è§£å†³è¿™ä¸ªé—®é¢˜ä½ éœ€è¦ 安装å¦å¤–一个 exec-path-from-shell çš„æ’件并将其å¯ç”¨ã€‚

(when (memq window-system '(mac ns))
  (exec-path-from-shell-initialize))

有了 nodejs-repl 我们就å¯ä»¥æ–¹ä¾¿çš„æµ‹è¯•å’Œå¼€å‘æˆ‘们的 JavaScript 代ç äº†ï¼ˆä½ å¯ä»¥åœ¨ 这里找到更多关于它的使用方法)。

Org-mode 进阶

在 Org-mode 中你å¯ä»¥ç›´æŽ¥å¼€å¯æ–°çš„缓冲区(Buffer)直接用相应的 Major Mode æ¥ç¼–辑代 ç å—内的内容。在代ç å—中使用 C-c ' 会直接打开对应模å¼çš„缓冲区(ä¸ä»…é™äºŽ Lisp)。 这样就使在 Org-mode 中编辑代ç å˜çš„å分方便快æ·ã€‚

使用 <s ç„¶åŽ Tab å¯ä»¥ç›´æŽ¥æ’入代ç å—的代ç ç‰‡æ®µï¼ˆSnippet),更多类似的代ç ç‰‡æ®µ (Org-mode Easy Templates)å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ã€‚

#+BEGIN_SRC emacs-lisp
  ;; Your code goes here
  ;; 你的代ç å†™åœ¨è¿™é‡Œ
#+END_SRC

添加 Org-mode 文本内语法高亮

(require 'org)
(setq org-src-fontify-natively t)

在 Org-mode 中é‡ç½®æœ‰åºåˆ—表åºå·å¯ä»¥ç›´æŽ¥ä½¿ç”¨ M-<RET> 。

Agenda 的使用

;; 设置默认 Org Agenda 文件目录
(setq org-agenda-files '("~/org"))

;; 设置 org-agenda 打开快æ·é”®
(global-set-key (kbd "C-c a") 'org-agenda)

ä½ åªéœ€å°†ä½ çš„ *.org æ–‡ä»¶æ”¾å…¥ä¸Šé¢æ‰€æŒ‡å®šçš„æ–‡ä»¶å¤¹ä¸­å°±å¯ä»¥å¼€å§‹ä½¿ç”¨ Agenda 模å¼äº†ã€‚

  • C-c C-s 选择想è¦å¼€å§‹çš„æ—¶é—´
  • C-c C-d 选择想è¦ç»“æŸçš„æ—¶é—´
  • C-c a å¯ä»¥æ‰“å¼€ Agenda 模å¼èœå•并选择ä¸åŒçš„å¯è§†æ–¹å¼ï¼ˆ r )

第三天:é…置文件模å—化(上)

视频地å€å¦‚下

多文件存储é…置文件(上)

å°†ä¸åŒçš„é…ç½®ä»£ç æ”¾ç½®åˆ°ä¸åŒçš„æ–‡ä»¶ä¸­ï¼Œä½¿å…¶æ¨¡å—化,这让我们的åŽç»­ç»´æŠ¤å˜å¾—更加简å•。 䏋颿˜¯æˆ‘们现在的 ~/.emacs.d/ 目录中的样å­ï¼Œ

├── auto-save-list # 自动生æˆçš„ä¿å­˜æ•°æ®
├── elpa           # 下载的æ’件目录
├── init.el        # 我们的é…置文件
└── recentf        # 最近访问的文件列表

通常我们åªä¿å­˜é…置文件和对其进行版本控制,其他的æ’ä»¶å‡ä¸ºåœ¨ç¬¬ä¸€æ¬¡ä½¿ç”¨ç¼–辑器时å†é€š è¿‡ç½‘ç»œé‡æ–°ä¸‹è½½ï¼Œå½“然你也å¯ä»¥é€‰æ‹©å°†å…¨éƒ¨é…置文件进行版本控制æ¥ä¿è¯è‡ªå·±æ—¶åˆ»æ‹¥æœ‰æœ€ç¨³ 定的生产环境。

Elisp 中并没有命å空间(Namespace),æ¢å¥è¯è¯´å°±æ˜¯æ‰€æœ‰çš„å˜é‡å‡ä¸ºå…¨å±€å˜é‡ï¼Œæ‰€ä»¥å…¶ 命忖¹æ³•å°±å˜çš„éžå¸¸é‡è¦ã€‚䏋颿˜¯ä¸€ä¸ªç®€å•的命å规则,

#自定义å˜é‡å¯ä»¥ä½¿ç”¨è‡ªå·±çš„åå­—ä½œä¸ºå‘½åæ–¹å¼ï¼ˆå¯ä»¥æ˜¯å˜é‡å或者函数å)
my/XXXX

#模å¼å‘½å规则
ModeName-mode

#模å¼å†…çš„å˜é‡åˆ™å¯ä»¥ä½¿ç”¨
ModeName-VariableName

éµå®ˆä¸Šé¢çš„命å规则å¯ä»¥æœ€å¤§ç¨‹åº¦çš„å‡å°‘命å冲çªå‘生的å¯èƒ½æ€§ã€‚

现在我们想将原本混åˆåœ¨ä¸€èµ·çš„é…置文件分为下é¢çš„几个模å—(æ¯ä¸€ä¸ªæ¨¡å—ä¸ºä¸€ä¸ªç‹¬ç«‹çš„é… ç½®æ–‡ä»¶å¹¶å°†å…¶ä¿å­˜åœ¨æŒ‡å®šçš„å­ç›®å½•中),它们分别是

init-packages.el        # æ’件管ç†
init-ui.el              # 视觉层é…ç½®
init-better-defaults.el # 增强内置功能
init-keybindings.el     # å¿«æ·é”®ç»‘定
init-org.el             # Org 模å¼ç›¸å…³çš„全部设定
custome.el              # 存放使用编辑器接å£äº§ç”Ÿçš„é…置信æ¯

下é¢ä¸ºå°†é…置文件进行模å—化åŽçš„目录结构,

├── init.el
└── lisp
    ├── custom.el
    ├── init-better-defaults.el
    ├── init-helper.el
    ├── init-keybindings.el
    ├── init-packages.el
    ├── init-ui.el
    └── init-org.el

使用模å—化é…置就å¯ä»¥è®©æˆ‘们在之åŽçš„é…置中迅速的定ä½ä¸Žæ›´æ”¹é…置内容,让整个过程å˜å¾— 更有æ¡ç†ä¹Ÿæ›´åŠ é«˜æ•ˆã€‚

和之å‰ä¸€æ · init.el 是é…置文件的入å£ï¼ŒçŽ°åœ¨å®ƒä¾¿æˆä¸ºäº†æ‰€æœ‰æ¨¡å—é…置文件的入å£ï¼Œæ‰€ 以è¦ä½¿ç”¨è¿™äº›æ¨¡å—时,我们需è¦åœ¨å…¶ä¸­å¼•用需è¦åŠ è½½çš„æ¨¡å—。下é¢ä»¥ init-packages.el (此é…置为添加æ’件的模å—) 为例,详细说明如何模å—化以åŠåº”用的方法。

䏋颿˜¯åœ¨æ¨¡å—化é…置之å‰ï¼Œæˆ‘们所使用的é…置文件 ~/.emacs.d/init.el 的样å­ï¼Œæˆ‘们将 所有的é…置代ç éƒ½æ”¾ç½®åœ¨äº†åŒä¸€ä¸ªæ–‡ä»¶ä¸­ï¼ˆå¦‚下所示)

下é¢ä¸º ~/.emacs.d/init.el 文件的内容

;;  __        __             __   ___
;; |__)  /\  /  ` |__/  /\  / _` |__
;; |    /~~\ \__, |  \ /~~\ \__> |___
;;                      __   ___        ___      ___
;; |\/|  /\  |\ |  /\  / _` |__   |\/| |__  |\ |  |
;; |  | /~~\ | \| /~~\ \__> |___  |  | |___ | \|  |
(when (>= emacs-major-version 24)
    (require 'package)
    (package-initialize)
    (setq package-archives '(("gnu"   . "http://elpa.emacs-china.org/gnu/")
                         ("melpa" . "http://elpa.emacs-china.org/melpa/"))))

;; cl - Common Lisp Extension
(require 'cl)

;; Add Packages
(defvar my/packages '(
			   ;; --- Auto-completion ---
			   company
			   ;; --- Better Editor ---
			   smooth-scrolling
			   hungry-delete
			   swiper
			   counsel
			   smartparens
			   ;; --- Major Mode ---
			   js2-mode
			   markdown-mode
			   ;; --- Minor Mode ---
			   ;; Quick Note Taking
			   deft
			   ;; JavaScript REPL
			   nodejs-repl
			   ;; Find OS X Executable Helper Package
;; ...

之å‰ä¸ºäº†æ›´å¥½çš„区分ä¸åŒçš„区域我使用的方法是使用 ASCII Art ç„¶åŽå†ä»¥å…³é”®å­—æ¥åšæœç´¢ 跳转,但是这样å†ç¼–è¾‘å·¥ç¨‹ä¸­ä¾æ—§å分缓慢和麻烦。于是我们现在è¦å°†é…置文件全部模å—化, 把ä¸åŒéƒ¨åˆ†çš„é…ç½®ä»£ç æ”¾ç½®åœ¨ä¸åŒçš„é…ç½®æ–‡ä»¶ä¸­ï¼Œå¹¶åœ¨å…¥å£æ–‡ä»¶ï¼ˆ ~/.emacs.d/init.el ï¼‰ä¸­ä¾æ¬¡å¼•用ä¸ç”¨çš„æ¨¡å—。

下é¢ä¸º ~/.emacs.d/lisp/init-packages.el 模å—中的代ç 

;;  __        __             __   ___
;; |__)  /\  /  ` |__/  /\  / _` |__
;; |    /~~\ \__, |  \ /~~\ \__> |___
;;                      __   ___        ___      ___
;; |\/|  /\  |\ |  /\  / _` |__   |\/| |__  |\ |  |
;; |  | /~~\ | \| /~~\ \__> |___  |  | |___ | \|  |
(when (>= emacs-major-version 24)
    (require 'package)
    (package-initialize)
    (setq package-archives '(("gnu"   . "http://elpa.emacs-china.org/gnu/")
                         ("melpa" . "http://elpa.emacs-china.org/melpa/"))))

;; cl - Common Lisp Extension
(require 'cl)

;; Add Packages
(defvar my/packages '(
			   ;; --- Auto-completion ---
			   company
			   ;; --- Better Editor ---
			   smooth-scrolling
			   hungry-delete
			   swiper
			   counsel
			   smartparens
			   popwin
			   ;; --- Major Mode ---
			   js2-mode
			   markdown-mode

;; ...

;; 文件末尾
(provide 'init-packages)

下é¢ä¸º ~/.emacs.d/init.el 入壿–‡ä»¶ä¸­çš„代ç 

(package-initialize)

(add-to-list 'load-path "~/.emacs.d/lisp/")

;; Package Management
;; -----------------------------------------------------------------
(require 'init-packages)

模å—化è¦åšçš„其实éžå¸¸ç®€å•,我们è¦åšçš„其实就是把æŸä¸€ä¸ªæ›´æ”¹ç¼–辑器æŸå®šéƒ¨åˆ†ï¼ˆä¾‹å¦‚ï¼Œæ’ ä»¶ç®¡ç†ï¼Œæ˜¾ç¤ºå±‚,快æ·é”®ç»‘定等)的é…置代ç å†™å…¥ä¸€ä¸ªç‹¬ç«‹çš„æ–‡ä»¶ä¸­å¹¶åœ¨æœ«å°¾ä¸ºå…¶æ·»åŠ  (provide 'modul-name) (这里我们的模å—å为 init-packages )使其å¯ä»¥åœ¨å…¥å£æ–‡ä»¶ 中被调用,然åŽå†åœ¨å…¥å£æ–‡ä»¶ä¸­å°†å…¶å¼•用既å¯ã€‚

è¿™é‡Œéœ€è¦æ³¨æ„的是,我们需è¦åœ¨å…¥å£æ–‡ä»¶ä¸­æ·»åŠ  (add-to-list 'load-path "~/.emacs.d/lisp/") è¿™å¯ä»¥è®© Emacs 找到需è¦åŠ è½½çš„æ¨¡å—æ‰€å¤„çš„ä½ç½®ã€‚

更多模å—化的é…置文件å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ã€‚

Major 与 Minor Mode 详解

åœ¨è¿™ä¸€èŠ‚æˆ‘ä»¬å°†è¯¦ç»†ä»‹ç» Major Mode 与 Minor Mode 去区别。æ¯ä¸€ä¸ªæ–‡ä»¶ç±»åž‹éƒ½å¯¹åº”一个 Major Mode,它æä¾›è¯­æ³•高亮以åŠç¼©è¿›ç­‰åŸºæœ¬çš„编辑支æŒåŠŸèƒ½ï¼Œç„¶åŽè€Œ Minor Mode 则æä¾› 其余的增强性的功能(例如 linum-mode )。

在 Emacs 中,Major Mode åˆåˆ†ä¸ºä¸‰ç§ï¼Œ

  • text-mode ,用于编辑文本文件
  • special-mode ,特殊模å¼ï¼ˆå¾ˆå°‘è§ï¼‰
  • prog-mode ,所有的编程语言的父模å¼

在æ¯ä¸€ä¸ªæ¨¡å¼ï¼ˆmode)中它的å称与å„个å˜é‡è¿˜æœ‰å‡½æ•°éƒ½æ˜¯æœ‰ç‰¹å®šçš„命å规则,比如所有的 模å¼éƒ½è¢«å‘½å为 ModeName-mode ï¼Œé‡Œé¢æ‰€è®¾ç½®çš„å¿«æ·é”®åˆ™ä¸º ModeName-mode-key-map ,而所有的钩å­åˆ™ä¼šè¢«å‘½å为 ModeName-mode-hook 。

æ³¨æ˜Žï¼šä¸ºäº†ä¿æŒé˜…读的完整性,部分第三天的关于默认编辑器优化的内容被移至第四天。

第四天:é…置文件模å—化(下)以åŠä½¿ç”¨ä¼˜åŒ–

视频地å€å¦‚下

é…置文件模å—化(下)

在这一部分我们首先需è¦çŸ¥é“的是什么是 features 。在 Emacs 中æ¯ä¸€ä¸ª feature 都 是一个 Elisp 符å·ï¼Œç”¨äºŽä»£è¡¨ä¸€ä¸ª Lisp æ’件(Package)。

当一个æ’件调用 (provide 'symbol_name) 函数时,Emacs 就会将这个符å·åŠ å…¥åˆ° features 的列表中去。你å¯ä»¥åœ¨è¿™é‡Œè¯»åˆ°æ›´å¤šå…³äºŽ feature 的内容。

æŽ¥ç€æˆ‘们需è¦å¼„明白的是 load-file , load , require , autoload 之间的区别。 (他们之间区别的链接已ç»å†å‰é¢è´´è¿‡äº†ï¼Œä½ ä¹Ÿå¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ä¹‹å‰åŒæ ·çš„链接)

ç®€å•æ¥è¯´ï¼Œ load-file 用于打开æŸä¸€ä¸ªæŒ‡å®šçš„æ–‡ä»¶ï¼Œç”¨äºŽå½“你䏿ƒ³è®© Emacs æ¥åŽ»å†³å®šåŠ  è½½æŸä¸ªé…置文件时( .el 或者 .elc 文件)。

load æœç´¢ load-path ä¸­çš„è·¯å¾„å¹¶æ‰“å¼€ç¬¬ä¸€ä¸ªæ‰€æ‰¾åˆ°çš„åŒ¹é…æ–‡ä»¶å的文件。此方法用于 你预先ä¸çŸ¥é“文件路径的时候。

require 加载还未被加载的æ’件。首先它会查看å˜é‡ features 中是å¦å­˜åœ¨æ‰€è¦åŠ è½½çš„ 符å·å¦‚æžœä¸å­˜åœ¨åˆ™ä½¿ç”¨ä¸Šé¢æåˆ°çš„ load 将其载入。(有点类似于其他编程语言中的 import )

autoload 用于仅在函数调用时加载文件,使用此方法å¯ä»¥å¤§å¤§èŠ‚çœç¼–辑器的å¯åŠ¨æ—¶é—´ã€‚

更好的默认设置

在这一节我们会é…ç½®æˆ‘ä»¬çš„ç¼–è¾‘å™¨ä½¿å…¶æœ‰æ›´å¥½çš„ä½¿ç”¨ä½“éªŒã€‚æ•´ä¸ªè¿‡ç¨‹å°±å¦‚åŒæ­ç§¯æœ¨ä¸€èˆ¬ï¼Œå°† 更好的体验建立在已有的功能基础之上。这样的优化使整个过程å˜å¾—更高效,也更有趣。

下é¢çš„代ç å¯ä»¥æ˜¯ Emacs 自动加载外部修改过的文件。

(global-auto-revert-mode 1)

使用下é¢çš„代ç å¯ä»¥å…³é—­è‡ªå·±ç”Ÿäº§çš„ä¿å­˜æ–‡ä»¶ï¼ˆä¹‹å‰æˆ‘们已ç»å…³é—­è¿‡äº† Emacs 自动生产的 备份文件了,现在是关闭自动ä¿å­˜æ–‡ä»¶ï¼‰ã€‚

(setq auto-save-default nil)

如果你å‘现你在使用中å‘现了那些编辑行为与你预期的ä¸ç›¸ç¬¦æ—¶ï¼Œä½ å¯ä»¥é€šè¿‡æœç´¢å¼•擎去寻 找解决方案然åŽå°†å…¶åŠ å…¥ä½ çš„é…置中并打造一个真正属于你的神器ï¼

popwin æ’ä»¶å¯ä»¥è‡ªåŠ¨å°†å…‰æ ‡ç§»åŠ¨åˆ°ï¼Œæ–°åˆ›å»ºçš„çª—å£ä¸­ã€‚使用下é¢çš„代ç å°†å…¶å¯ç”¨ï¼Œ

(require 'popwin)
(popwin-mode 1)

也许你并ä¸å–œæ¬¢å¬åˆ°é”™è¯¯æ—¶çš„“哔哔â€çš„警告æç¤ºéŸ³ï¼Œä½¿ç”¨ä¸‹é¢çš„代ç ä½ å¯ä»¥å…³é—­ Emacs 中的警告音,

(setq ring-bell-function 'ignore)

æ¯ä¸€æ¬¡å½“ Emacs 需è¦ä¸Žä½ ç¡®è®¤æŸä¸ªå‘½ä»¤æ—¶éœ€è¦è¾“å…¥ (yes or no) æ¯”è¾ƒéº»çƒ¦ï¼Œæ‰€æœ‰æˆ‘ä»¬å¯ ä»¥ä½¿ç”¨ä¸‹é¢çš„代ç ï¼Œè®¾ç½®ä¸€ä¸ªåˆ«å将其简化为åªè¾“å…¥ (y or n) 。

(fset 'yes-or-no-p 'y-or-n-p)

代ç ç¼©è¿›

indent-region å¯ä»¥å¸®æˆ‘们釿–°ç¼©è¿›æ‰€é€‰åŒºåŸŸçš„代ç ï¼Œä½†æ˜¯æ¯ä¸€æ¬¡éƒ½é€‰ä¸­å分麻烦。使用 下é¢çš„代ç å¯ä»¥ä¸€æ¬¡é‡æ–°ç¼©è¿›å…¨éƒ¨ç¼“冲区的代ç ã€‚(之åŽä¹Ÿä¼šä»‹ç»æ›´å¥½ç”¨çš„ï¼Œä»£ç æ ¼å¼ç¾ŽåŒ– çš„æ’件)

(defun indent-buffer()
  (interactive)
  (indent-region (point-min) (point-max)))

(defun indent-region-or-buffer()
  (interactive)
  (save-excursion
    (if (region-active-p)
        (progn
          (indent-region (region-beginning) (region-end))
          (message "Indent selected region."))
      (progn
        (indent-buffer)
        (message "Indent buffer.")))))

ç„¶åŽå†å°†å…¶ç”¨ä¸‹é¢çš„代ç å°†å…¶ç»‘定为快æ·é”®ï¼Œç¬¬ä¸€ä¸ª \ 用于将紧跟的 \ 进行逃脱(escape)。

(global-set-key (kbd "C-M-\\") 'indent-region-or-buffer)

缩写补全

使用下é¢çš„ä»£ç æˆ‘们å¯ä»¥å¼€å¯ abbrev 模å¼å¹¶å®šä¹‰ä¸€ä¸ªç¼©å†™è¡¨ï¼Œæ¯å½“我们输入下é¢çš„缩写 å¹¶ä»¥ç©ºæ ¼ç»“æŸæ—¶ï¼ŒEmacs 就会将其自动展开æˆä¸ºæˆ‘们所需è¦çš„字符串。

(setq-default abbrev-mode t)
(define-abbrev-table 'global-abbrev-table '(
                                            ;; Shifu
                                            ("8zl" "zilongshanren")
                                            ;; Tudi
                                            ("8lxy" "lixinyang")
                                           ))

上é¢çš„缩写å‰ä½¿ç”¨çš„ 8 也类似于命å空间的作用,使其ä¸ä¼šä¸Žæˆ‘们所常用的字符串冲çªã€‚

Hippie 补全

Company æœ‰æ—¶å€™è¡¥å…¨åŠŸèƒ½å¹¶ä¸æ˜¯éžå¸¸ç†æƒ³ï¼Œè¿™æ—¶å°±å¯ä»¥ä½¿ç”¨ Hippie Expand æ¥å®Œæˆè¡¥å…¨ã€‚ Company Mode 补全效果ä¸ç†æƒ³çš„原因是在ä¸åŒçš„区域中会使用ä¸åŒçš„åŽç«¯å‡½æ•°æ¥å®Œæˆè¡¥å…¨ï¼Œ 但是当åŽç«¯è¡¥å…¨å‡½æ•°ä¸èƒ½è¢«æ¿€æ´»æ—¶ï¼Œåˆ™è¡¥å…¨å°±ä¸ä¼šè¢«æ¿€æ´»ã€‚

我们å¯ä»¥å°†ä¸‹é¢çš„代ç åŠ å…¥åˆ°æˆ‘ä»¬çš„é…置文件中,æ¥å¢žå¼º Hippie Expand 的功能,

(setq hippie-expand-try-function-list '(try-expand-debbrev
                                        try-expand-debbrev-all-buffers
                                        try-expand-debbrev-from-kill
                                        try-complete-file-name-partially
                                        try-complete-file-name
                                        try-expand-all-abbrevs
                                        try-expand-list
                                        try-expand-line
                                        try-complete-lisp-symbol-partially
                                        try-complete-lisp-symbol))

ç„¶åŽå°†å…¶ç»‘定为快æ·é”®ï¼Œä½¿æˆ‘们å¯ä»¥æ›´æ–¹ä¾¿çš„使用它。

(global-set-key (kbd "s-/") 'hippie-expand)

Dired Mode

Dired Mode 是一个强大的模å¼å®ƒèƒ½è®©æˆ‘们完æˆå’Œæ–‡ä»¶ç®¡ç†ç›¸å…³çš„æ‰€æœ‰æ“作。

使用 C-x d å°±å¯ä»¥è¿›å…¥ Dired Mode,这个模å¼ç±»ä¼¼äºŽå›¾å½¢ç•Œé¢ç³»ç»Ÿä¸­çš„资æºç®¡ç†å™¨ã€‚ä½  å¯ä»¥åœ¨å…¶ä¸­æŸ¥çœ‹æ–‡ä»¶å’Œç›®å½•的详细信æ¯ï¼Œå¯¹ä»–们进行å„ç§æ“作,甚至å¤åˆ¶ç²˜è´´ç¼“冲区中的内 å®¹ã€‚ä¸‹é¢æ˜¯ä¸€äº›å¸¸ç”¨çš„æ“ä½œï¼ˆä¸‹é¢çš„æ‰€æœ‰é”®å‡éœ€åœ¨ Dired Mode 下使用),

  • + 创建目录
  • g 刷新目录
  • C æ‹·è´
  • D 删除
  • R é‡å‘½å
  • d 标记删除
  • u å–æ¶ˆæ ‡è®°
  • x 执行所有的标记

这里有几点å¯ä»¥ä¼˜åŒ–的地方。第一是删除目录的时候 Emacs 会询问是å¦é€’归删除或拷è´ï¼Œ 这也有些麻烦我们å¯ä»¥ç”¨ä¸‹é¢çš„é…置将其设定为默认递归删除目录(出于安全原因的考虑, 也许你需è¦ä¿æŒæ­¤è¡Œä¸ºã€‚所有文中的é…置请务必按需é…置)。

(setq dired-recursive-deletes 'always)
(setq dired-recursive-copies 'always)

第二是,æ¯ä¸€æ¬¡ä½ è¿›å…¥ä¸€ä¸ªå›žè½¦è¿›å…¥ä¸€ä¸ªæ–°çš„目录中是,一个新的缓冲区就会被建立。这使 å¾—æˆ‘ä»¬çš„ç¼“å†²åŒºåˆ—è¡¨ä¸­å……æ»¡äº†å¤§é‡æ²¡æœ‰å®žé™…æ„义的记录。我们å¯ä»¥ä½¿ç”¨ä¸‹é¢çš„代ç ï¼Œè®© Emacs é‡ç”¨å”¯ä¸€çš„一个缓冲区作为 Dired Mode 显示专用缓冲区。

(put 'dired-find-alternate-file 'disabled nil)

;; 主动加载 Dired Mode
;; (require 'dired)
;; (defined-key dired-mode-map (kbd "RET") 'dired-find-alternate-file)

;; 延迟加载
(with-eval-after-load 'dired
    (define-key dired-mode-map (kbd "RET") 'dired-find-alternate-file))

使用延迟加载å¯ä»¥ä½¿ç¼–辑器加载速度有所æå‡ã€‚

å¯ç”¨ dired-x å¯ä»¥è®©æ¯ä¸€æ¬¡è¿›å…¥ Dired æ¨¡å¼æ—¶ï¼Œä½¿ç”¨æ–°çš„å¿«æ·é”® C-x C-j å°±å¯ä»¥è¿› 入当剿–‡ä»¶å¤¹çš„æ‰€åœ¨çš„路径。

(require 'dired-x)

使用 (setq dired-dwin-target 1) 则å¯ä»¥ä½¿å½“一个窗å£ï¼ˆframeï¼‰ä¸­å­˜åœ¨ä¸¤ä¸ªåˆ†å± ï¼ˆwindow)时,将å¦ä¸€ä¸ªåˆ†å±è‡ªåŠ¨è®¾ç½®æˆæ‹·è´åœ°å€çš„目标。

最åŽå¦‚果你是 Mac OS X 的用户,å¯ä»¥å®‰è£… reveal-in-osx-finder 这个æ’件(你å¯ä»¥åœ¨ 这里找到它),它å¯ä»¥å°†ä»»æ„文件直接在 Finder 中打开。你想安装这个æ’件,将其添加至 第二天的æ’件列表中å³å¯ï¼Œä¸‹æ¬¡å¯åЍ Emacs 时,它就会自动帮你完æˆä¸‹è½½ã€‚

Org-mode ç®¡ç† Emacs é…ç½®

Org-mode 下的文学编程将颠覆你对于 Emacs 的看法。因为我们也å¯ä»¥ä½¿ç”¨ Org æ¥ç®¡ç† Emacs çš„é…置文件(笔者和他的师傅其实更倾å‘于模å—管ç†é…置文件)。

你需è¦å°†ä¸‹é¢çš„ä»£ç æ”¾å…¥é…ç½®å…¥å£æ–‡ä»¶ï¼ˆ init.el )中,

(package-initialize)

(require 'org-install)
(require 'ob-tangle)
(org-babel-load-file (expand-file-name "org-file-name.org" user-emacs-directory))

ä¹‹åŽæˆ‘们需è¦åšçš„ä»…ä»…åªæ˜¯å°†æ‰€æœ‰çš„é…置文件放入 Org 模å¼ä¸­çš„代ç å—å³å¯ï¼Œå¹¶ä½¿ç”¨ç›®å½• 结构æ¥è¡¨è¿°ä½ çš„é…ç½®æ–‡ä»¶å†æŠŠå®ƒä¿å­˜åœ¨ä¸Žå…¥å£æ–‡ä»¶ç›¸åŒçš„目录中å³å¯ï¼ˆæ–‡ä»¶å为 org-file-name.org )。Emacs 会æå–其中的é…置并使其生效。这样åšçš„好处是å¯ä»¥ä½¿è‡ª 己和他人更直观的,ç†è§£ä½ çš„é…置文件或者代ç ã€‚

第五天:打造å‰ç«¯å¼€å‘神器

视频地å€å¦‚下

照例我们先修å¤ä¸€äº›çŽ°åœ¨å­˜åœ¨çš„å°é—®é¢˜ã€‚首先是自动é…对的å°é—®é¢˜ï¼Œåœ¨ Emacs Lisp 中我们 有时候åªéœ€è¦ä¸€ä¸ª ' 但是 Emacs 很好心的帮我们åšäº†è¡¥å…¨ï¼Œä½†è¿™å¹¶ä¸æ˜¯æˆ‘们需è¦çš„。我 们å¯ä»¥é€šè¿‡ä¸‹é¢çš„ä»£ç æ¥è®©ä½¿ Emacs Lisp 在 Emacs 中的编辑å˜å¾—更方便(å¯ä»¥å°†å…¶æ·»åŠ  至 init-default.el é…置文件中)。

(sp-local-pair 'emacs-lisp-mode "'" nil :actions nil)
(sp-local-pair 'lisp-interaction-mode "'" nil :actions nil)

;; 也å¯ä»¥æŠŠä¸Šé¢ä¸¤å¥åˆèµ·æ¥
(sp-local-pair '(emacs-lisp-mode lisp-interaction-mode) "'" nil :actions nil)

在添加é…置代ç åŽé‡å¯ Emacs 使其生效。当然这个方法你也å¯ä»¥è¿ç”¨åœ¨å…¶ä»–çš„å„个 Major Mode ä¸­ï¼Œå¦‚æžœä½ ä¸æƒ³ Emacs 对æŸäº›ç¬¦å·è¿›è¡Œç±»ä¼¼çš„自动匹é…补全。

show-paren-mode å¯ä»¥ä½¿é¼ æ ‡åœ¨æ‹¬å·ä¸Šæ˜¯é«˜äº®å…¶æ‰€åŒ¹é…çš„å¦ä¸€åŠæ‹¬å·ï¼Œç„¶è€Œæˆ‘们想è¦å…‰æ ‡ 在括å·å†…时就高亮包å«å†…容的两个括å·ï¼Œä½¿ç”¨ä¸‹é¢çš„代ç å°±å¯ä»¥åšåˆ°è¿™ä¸€ç‚¹ã€‚

(define-advice show-paren-function (:around (fn) fix-show-paren-function)
  "Highlight enclosing parens."
  (cond ((looking-at-p "\\s(") (funcall fn))
        (t (save-excursion
             (ignore-errors (backward-up-list))
             (funcall fn)))))

Lisp çš„å®ï¼ˆMacro)类似于 C++ 中的模æ¿ï¼Œå¹¶å¯ä»¥ç”Ÿäº§æ–°çš„代ç ï¼ˆä½ å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°æ›´å¤š 关于å®çš„讨论)。使用它,我们å¯ä»¥å¢žå¼ºæŸä¸ªå‡½æ•°çš„功能而ä¸åŽ»æ›´æ”¹è¿™ä¸ªå‡½æ•°çš„ä»£ç ã€‚

还有一个å°é—®é¢˜å°±æ˜¯è§£å†³åœ¨ä¸åŒç³»ç»Ÿä¸­çš„æ¢è¡Œç¬¦ï¼Œä¾‹å¦‚åœ¨ DOS 系统下的 \r(^M) æ¢è¡Œç¬¦ï¼Œ 这让我们有时候在 Unix 系统中很是头疼,因为它的存在会使版本控制误以为整行的代ç éƒ½ 被修改过而造æˆä¸å¿…è¦çš„麻烦。(你å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°æ›´å¤šå…³äºŽ \r(^M) 的信æ¯ï¼‰

æˆ‘ä»¬ç”¨ä¸¤ç§æ–¹å¼æ¥å¤„ç†è¿™ä¸ªé—®é¢˜ï¼Œéšè—这个æ¢è¡Œç¬¦æˆ–è€…å°†å…¶åˆ é™¤ã€‚é¦–å…ˆä¸‹é¢æ˜¯éšè—的方法,

(defun hidden-dos-eol ()
  "Do not show ^M in files containing mixed UNIX and DOS line endings."
  (interactive)
  (unless buffer-display-table
    (setq buffer-display-table (make-display-table)))
  (aset buffer-display-table ?\^M []))

使用下é¢çš„代ç åˆ™å¯ä»¥å®šä¹‰å‡½æ•°å°†æ­¤æ¢è¡Œç¬¦åˆ é™¤ï¼Œ

(defun remove-dos-eol ()
  "Replace DOS eolns CR LF with Unix eolns CR"
  (interactive)
  (goto-char (point-min))
  (while (search-forward "\r" nil t) (replace-match "")))

web-mode

Emacs 自带的 HTML Mode 使用起æ¥å¹¶ä¸æ˜¯é‚£ä¹ˆçš„æ–¹ä¾¿ï¼Œè€Œ web-mode 则是一个éžå¸¸å¸¸ç”¨ä¹Ÿ 很强大的用于编辑å‰ç«¯ä»£ç çš„ Major Mode(你å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°æ›´å¤šå…³äºŽå®ƒçš„ä¿¡æ¯ï¼‰ã€‚

首先我们需è¦å®‰è£…它,照例我们需è¦å°†å…¶æ·»åŠ è‡³æˆ‘ä»¬çš„æ’件列表中去。

(defvar xinyang/packages '(
                           ;; ä½ å…¶ä»–çš„æ’件在这里
                           web-mode
                           ) "Default packages")

在安装完æˆåŽæˆ‘们就å¯ä»¥å¼€å§‹é…置它了,首先我们需è¦åšçš„æ˜¯å°†æ‰€æœ‰çš„ *.html 文件都使 用 web-mode æ¥æ‰“开。

(setq auto-mode-alist
      (append
       '(("\\.js\\'" . js2-mode))
       '(("\\.html\\'" . web-mode))
       auto-mode-alist))

这样所有的 HTML 代ç åœ¨ Emacs 中就会之间å¯ç”¨ web-mode 而éžé»˜è®¤çš„ HTML Mode 了。你 å¯ä»¥é˜…读它的文档æ¥å­¦ä¹ æ›´å¤š web-mode 详细的使用方法。

例如使用 M-; å°±å¯ä»¥æ³¨é‡Šå½“å‰è¡Œä»£ç æˆ–选中行的代ç ã€‚

æŽ¥ä¸‹æ¥æˆ‘们æ¥åšæ›´å¤šç»†èŠ‚çš„é…置,首先是缩å‡çš„大å°çš„设置。因为 web-mode 支æŒåœ¨ HTML 文件中存在多语言,所以我们å¯ä»¥å¯¹ä¸åŒçš„语言的缩å‡åšå‡ºè®¾ç½®ã€‚下é¢çš„代ç ç”¨äºŽè®¾ç½®åˆå§‹ 的代ç ç¼©è¿›ï¼Œ

(defun my-web-mode-indent-setup ()
  (setq web-mode-markup-indent-offset 2) ; web-mode, html tag in html file
  (setq web-mode-css-indent-offset 2)    ; web-mode, css in html file
  (setq web-mode-code-indent-offset 2)   ; web-mode, js code in html file
  )
(add-hook 'web-mode-hook 'my-web-mode-indent-setup)

下é¢çš„函数å¯ä»¥ç”¨äºŽåœ¨ä¸¤ä¸ªç©ºæ ¼å’Œå››ä¸ªç©ºæ ¼ä¹‹é—´è¿›è¡Œåˆ‡æ¢ï¼Œ

(defun my-toggle-web-indent ()
  (interactive)
  ;; web development
  (if (or (eq major-mode 'js-mode) (eq major-mode 'js2-mode))
      (progn
        (setq js-indent-level (if (= js-indent-level 2) 4 2))
        (setq js2-basic-offset (if (= js2-basic-offset 2) 4 2))))

  (if (eq major-mode 'web-mode)
      (progn (setq web-mode-markup-indent-offset (if (= web-mode-markup-indent-offset 2) 4 2))
             (setq web-mode-css-indent-offset (if (= web-mode-css-indent-offset 2) 4 2))
             (setq web-mode-code-indent-offset (if (= web-mode-code-indent-offset 2) 4 2))))
  (if (eq major-mode 'css-mode)
      (setq css-indent-offset (if (= css-indent-offset 2) 4 2)))

  (setq indent-tabs-mode nil))

(global-set-key (kbd "C-c t i") 'my-toggle-web-indent)

js2-refactor

js2-refactor æ˜¯ä¸€ä¸ªç”¨äºŽé‡æž„ JavaScript çš„æ’件,它是一个 Minor Mode,你å¯ä»¥åœ¨ GitHub 找到更多关于这个æ’件的信æ¯ã€‚

我们使用刚刚所æåˆ°çš„æ–¹æ³•æ¥å®‰è£… js2-refactor æ’件。

在安装完æˆåŽï¼Œæ·»åŠ ä¸€ä¸ªé’©å­ï¼ˆHook):

(add-hook 'js2-mode-hook #'js2-refactor-mode)
(js2r-add-keybindings-with-prefix "C-c C-m")

我们å¯ä»¥ä½¿ç”¨ C-c C-m ç„¶åŽè¾“入功能å‰ç¼€ï¼Œä¾‹å¦‚ em 是 extract-method çš„å‰ç¼€ã€‚æ›´ 多的功能和使用方法也å¯ä»¥åœ¨ä¸Šé¢ç»™å‡ºçš„链接中找到,所有的å‰ç¼€ä¹Ÿå¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ã€‚

优化 occur 与 imenu

下é¢çš„代ç ç”¨äºŽé…ç½® Occur Mode 使其默认æœç´¢å½“å‰è¢«é€‰ä¸­çš„æˆ–者在光标下的字符串:

(defun occur-dwim ()
  "Call `occur' with a sane default."
  (interactive)
  (push (if (region-active-p)
            (buffer-substring-no-properties
             (region-beginning)
             (region-end))
          (let ((sym (thing-at-point 'symbol)))
            (when (stringp sym)
              (regexp-quote sym))))
        regexp-history)
  (call-interactively 'occur))
(global-set-key (kbd "M-s o") 'occur-dwim)

dwim 是按我说的åšçš„缩写(Do what I mean)。

Occur å¯ä»¥ç”¨äºŽæ˜¾ç¤ºå˜é‡æˆ–函数的定义,我们å¯ä»¥é€šè¿‡ popwin çš„ customize-group 将定 义显示设置为å³è¾¹è€Œä¸æ˜¯é»˜è®¤çš„底部( customize-group > popwin > Popup Window Position 设置为 right),也å¯ä»¥åœ¨è¿™é‡Œå¯¹å…¶å®½åº¦è¿›è¡Œè°ƒèŠ‚ã€‚

Occur 与普通的æœç´¢æ¨¡å¼ä¸åŒçš„æ˜¯ï¼Œå®ƒå¯ä»¥ä½¿ç”¨ Occur-Edit Mode (在弹出的窗å£ä¸­æŒ‰ e 进入编辑模å¼) 对æœç´¢åˆ°çš„结果进行之间的编辑。

imenu å¯ä»¥æ˜¾ç¤ºå½“剿‰€æœ‰ç¼“冲区的列表,下é¢çš„é…ç½®å¯ä»¥è®©å…¶æ‹¥æœ‰æ›´ç²¾ç¡®çš„跳转,

(defun js2-imenu-make-index ()
      (interactive)
      (save-excursion
        ;; (setq imenu-generic-expression '((nil "describe\\(\"\\(.+\\)\"" 1)))
        (imenu--generic-function '(("describe" "\\s-*describe\\s-*(\\s-*[\"']\\(.+\\)[\"']\\s-*,.*" 1)
                                   ("it" "\\s-*it\\s-*(\\s-*[\"']\\(.+\\)[\"']\\s-*,.*" 1)
                                   ("test" "\\s-*test\\s-*(\\s-*[\"']\\(.+\\)[\"']\\s-*,.*" 1)
                                   ("before" "\\s-*before\\s-*(\\s-*[\"']\\(.+\\)[\"']\\s-*,.*" 1)
                                   ("after" "\\s-*after\\s-*(\\s-*[\"']\\(.+\\)[\"']\\s-*,.*" 1)
                                   ("Function" "function[ \t]+\\([a-zA-Z0-9_$.]+\\)[ \t]*(" 1)
                                   ("Function" "^[ \t]*\\([a-zA-Z0-9_$.]+\\)[ \t]*=[ \t]*function[ \t]*(" 1)
                                   ("Function" "^var[ \t]*\\([a-zA-Z0-9_$.]+\\)[ \t]*=[ \t]*function[ \t]*(" 1)
                                   ("Function" "^[ \t]*\\([a-zA-Z0-9_$.]+\\)[ \t]*()[ \t]*{" 1)
                                   ("Function" "^[ \t]*\\([a-zA-Z0-9_$.]+\\)[ \t]*:[ \t]*function[ \t]*(" 1)
                                   ("Task" "[. \t]task([ \t]*['\"]\\([^'\"]+\\)" 1)))))
(add-hook 'js2-mode-hook
              (lambda ()
                (setq imenu-create-index-function 'js2-imenu-make-index)))

(global-set-key (kbd "M-s i") 'counsel-imenu)

expand-region

ä½¿ç”¨åŒæ ·çš„æ–¹æ³•å°† expand-region 添加至我们的æ’件列表中,é‡å¯ Emacs 安装æ’件。

å†ä¸ºå…¶ç»‘定一个快æ·é”®ï¼Œ

(global-set-key (kbd "C-=") 'er/expand-region)

使用这个æ’ä»¶å¯ä»¥ä½¿æˆ‘们更方便的选中一个区域。(更多使用方法和文档å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ï¼‰

iedit

iedit 是一个å¯ä»¥åŒæ—¶ç¼–辑多个区域的æ’件,它类似 Sublime Text 中的多光标编辑。它的 GitHub 仓库在这里。

我们将其绑定快æ·é”®ä»¥ä¾¿æ›´å¿«æ·çš„使用这个模å¼ï¼ˆ C-; 为默认快æ·é”®ï¼‰ï¼Œ

(global-set-key (kbd "M-s e") 'iedit-mode)

我们å¯ä»¥ä½¿ç”¨ Customized-group æ¥æ›´æ”¹å…¶é«˜äº®çš„背景色,将 highlight 改为 region 。

Org 导出

使用 C-c C-e å¯ä»¥å°† Org-mode 文档导出为你需è¦çš„æ ¼å¼ï¼Œä¾‹å¦‚ HTML 或者 PDF 文件。 你现在看到的这本教程就是由 Org-mode 所导出生æˆçš„。

第六天:代ç ç‰‡æ®µä¸Žè¯­æ³•检查器

视频地å€å¦‚下

åœ¨å¼€å§‹å‰æˆ‘ä»¬éœ€è¦æ³¨æ„çš„æ˜¯ä¹‹å‰æ¨¡å—化的é…置文件 init-keybindings.el 应该放在所有 调用模å—的最åŽé¢ï¼Œå› ä¸ºä¹Ÿè®¸åœ¨è®¾ç½®å¿«æ·é”®æ—¶æŸäº›å‡½æ•°è¿˜æœªè¢«åŠ è½½ã€‚

我们å¯ä»¥ä½¿ç”¨ä¸‹é¢çš„é…ç½®æ¥åœ¨ Company-mode 中使用 C-n 与 C-p æ¥é€‰æ‹©è¡¥å…¨é¡¹ï¼Œ

(with-eval-after-load 'company
  (define-key company-active-map (kbd "M-n") nil)
  (define-key company-active-map (kbd "M-p") nil)
  (define-key company-active-map (kbd "C-n") #'company-select-next)
  (define-key company-active-map (kbd "C-p") #'company-select-previous))

Org-mode 进阶使用

在学习代ç ç‰‡æ®µå’Œè¯­æ³•检查器(Linter)之å‰ï¼Œæˆ‘们先æ¥å­¦ä¹ ä¸€ä¸‹å¦‚何使用 Org-mode æ¥åš 学习笔记和安排工作时间。我们用下é¢çš„é…ç½®ä»£ç æ¥è®¾ç½®ä¸€ä¸ªæ¨¡æ¿ï¼ˆå…¶ä¸­è®¾ç½®äº†å¾…办事项的 优先级还有触å‘键),

(setq org-capture-templates
      '(("t" "Todo" entry (file+headline "~/.emacs.d/gtd.org" "工作安排")
         "* TODO [#B] %?\n  %i\n"
         :empty-lines 1)))

我们也å¯ä»¥ä¸ºå…¶ç»‘定一个快æ·é”®ï¼Œ

(global-set-key (kbd "C-c r") 'org-capture)

这个功能除了å¯ä»¥è®°å½•待办事项还有其他许许多多的功能例如获å–将当剿µè§ˆå™¨ä¸­çš„ URL(下é¢çš„例å­åªåœ¨ Mac OS X 平尿œ‰æ•ˆï¼‰ã€‚

(defun YOUR_NAME/retrieve-chrome-current-tab-url()
  "Get the URL of the active tab of the first window"
  (interactive)
      (let ((result (do-applescript
                     (concat
                      "set frontmostApplication to path to frontmost application\n"
                      "tell application \"Google Chrome\"\n"
                      " set theUrl to get URL of active tab of first window\n"
                      " set theResult to (get theUrl) \n"
                      "end tell\n"
                      "activate application (frontmostApplication as text)\n"
                      "set links to {}\n"
                      "copy theResult to the end of links\n"
                      "return links as string\n"))))
        (format "%s" (s-chop-suffix "\"" (s-chop-prefix "\"" result)))))

更多有关 Org-capture 的内容å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ã€‚

Org-pomodoro 是一个番茄时间工作法的æ’件(更多关于这个工作法的信æ¯å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ï¼‰ã€‚ 它的 GitHub 地å€åœ¨è¿™é‡Œã€‚在 (require 'org-pomodoro) åŽå¯ä»¥é€šè¿‡ Customize-group æ¥å¯¹å…¶è¿›è¡Œè®¾ç½®ï¼ŒåŒ…括ä¸åŒä¼‘æ¯ç§ç±»çš„æ—¶é•¿ã€‚

å› ä¸ºæ¯æ¬¡ä¿å­˜ä¸­æ–‡çš„æ—¶å€™éƒ½éœ€è¦é€‰æ‹©è§£ç ï¼Œæˆ‘们å¯ä»¥ä½¿ç”¨ä¸‹é¢çš„é…置将文本解ç è®¾ç½®é»˜è®¤ä¸º UTF-8,

(set-language-environment "UTF-8")

当 org-mode ä¸èƒ½ç”Ÿæ•ˆæ—¶ï¼Œæˆ‘们需è¦å°†ä¸Ž Org 相关的é…置放置于 with-eval-after-load 中,

(with-eval-after-load 'org
  ;; Org 模å¼ç›¸å…³è®¾å®š
  )

批é‡ä¿®æ”¹æ–‡ä»¶å

C-x C-q å°±å¯ä»¥ç›´æŽ¥åœ¨ Dired Mode 中进行编辑,使用之å‰å­¦çš„ iedit-mode 和区域选择 å°±å¯ä»¥ç›´æŽ¥å¯¹å¤šä¸ªæ–‡ä»¶è¿›è¡Œé‡å‘½å编辑了。

æœç´¢ä¸Žæ›¿æ¢

全局æœç´¢åœ¨æˆ‘们的编辑工作中是ä¸å¯ç¼ºå°‘的,今天我们介ç»çš„æ˜¯ ag。它是éžå¸¸å¿«é€Ÿçš„命令 行æœç´¢å·¥å…·ï¼Œå®ƒæ˜¯ Linux 的所有æœç´¢å·¥å…·ä¸­æœ€å¿«çš„。

ag > pt > ack > grep

在使用 ag 剿ˆ‘们需è¦è¿›è¡Œå®‰è£…ï¼Œä¸‹é¢æ˜¯ Mac OS X 与 Ubuntu 下的安装方法,

# Mac OS X 通过 Homebrew 安装
brew install the_silver_searcher

# Ubuntu 下安装
apt-get install silversearcher-ag

# Windows 下通过 msys2 安装(确ä¿åœ¨ path 中)
pacman -S mingw-w64-i686-ag # 32 ä½ç”µè„‘
pacman -S mingw-w64-x86_64-ag # 64 ä½ç”µè„‘

安装好 ag åŽæˆ‘们就å¯ä»¥å®‰è£… helm-ag æ’件了。(它的 GitHub 仓库地å€åœ¨è¿™é‡Œï¼‰åœ¨å®‰è£… 完æˆåŽå¯ä»¥ä¸ºå…¶è®¾ç½®å¿«æ·é”®ï¼Œ

(global-set-key (kbd "C-c p s") 'helm-do-ag-project-root)

使用这个æ’ä»¶æˆ‘ä»¬åŒæ ·å¯ä»¥åœ¨ç¼“冲区对æœç´¢åˆ°çš„结果进行直接的修改,这样就å¯ä»¥åšåˆ°å¿«é€Ÿ çš„æœç´¢ä¸Žæ›¿æ¢ã€‚

语法检查器(Linter)

语法检查器å¯ä»¥åœ¨å¼€å‘动æ€è¯­è¨€ï¼ˆInterpreted/Dynamic Programming Language)时æžå¤§çš„ æé«˜ä½ çš„å¼€å‘æ•ˆçŽ‡ï¼Œå®ƒä¼šå®žæ—¶çš„æ£€æŸ¥ä½ çš„ä»£ç å¹¶å°†å¥æ³•错误(Syntax Errorï¼‰ä¸Žé™æ€è¯­ä¹‰ (Static Semantic Error)错误进行高亮与æç¤ºã€‚

æˆ‘ä»¬åœ¨è¿™é‡Œä½¿ç”¨çš„ä¾‹å­æ˜¯ JavaScript 的语法检查器 eslint 它的安装方法å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ã€‚

在安装好语法检查器åŽå°±å¯ä»¥å®‰è£… flycheck çš„æ’件了,它的 GitHub 的地å€åœ¨è¿™é‡Œã€‚

使用下é¢çš„代ç å¯ä»¥å°† flycheck-mode 在特定模å¼ä¸‹æ¿€æ´»ï¼ˆä¸‹é¢çš„例å­å°±æ˜¯åªæœ‰åœ¨æ‰“å¼€ JavaScript æ—¶æ‰ä¼šæ¿€æ´»è¯­æ³•检查器),

(add-hook 'js2-mode-hook 'flycheck-mode)

使用 flycheck-verify-setup å¯ä»¥è¿›è¡Œè¯­æ³•检查器的选择。

eslint 检查器的é…置也å¯ä»¥ä½¿ç”¨é¡¹ç›®ç›®å½•下的 .eslintrc æ¥è¿›è¡Œé…置,更多é…ç½®æ–¹æ³•å¯ ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ã€‚

代ç å—

yasnippet 是一个代ç å—补全的æ’件(GitHub 地å€ï¼‰ã€‚使用下é¢çš„é…置文件将其在所有 的编程语言的模å¼ä¸­æ¿€æ´»ã€‚

(yas-reload-all)
(add-hook 'prog-mode-hook #'yas-minor-mode)

自定义代ç å—的方法å¯ä»¥åœ¨ä¸Šé¢æä¾›çš„链接中找到。

auto-yasnippet

auto-yasnippet 也是一个éžå¸¸å¥½ç”¨ä»£ç å—补全æ’件。安装并未其设置快æ·é”®ï¼Œ

(global-set-key (kbd "H-w") #'aya-create)
(global-set-key (kbd "H-y") #'aya-expand)

简å•的使用方法就是使用 ~ æ¥å®šä¹‰æ¨¡æ¿ï¼Œç„¶åŽè°ƒç”¨ aya-create å†ä½¿ç”¨ aya-expand æ¥ä½¿ç”¨æ¨¡æ¿ã€‚

第七天:Evil 模å¼

视频地å€å¦‚下,

开始之剿ˆ‘们先将 C-w æ¥ä½¿å…¶å¯ä»¥å‘åŽåˆ é™¤ä¸€ä¸ªå•è¯ï¼Œè¿™æ ·å°±å¯ä»¥ä¸Ž Shell 中的快æ·é”®æ“ä½œåŒæ­¥ã€‚

(global-set-key (kbd "C-w") 'backward-kill-word)

å¦‚æžœä½ ä¸æ˜¯ Vim 的用户,你å¯ä»¥é€‰æ‹©è·³è¿‡è¿™ä¸€å¤©çš„内容。但是我们强烈建议你花一些时间 æ¥å­¦ä¹ åŸºæœ¬çš„ Vim æ“作,å³ä½¿ Emacs 是你的最爱 Vim 的快æ·é”®ä¹Ÿåœ¨ä¸€å®šç¨‹åº¦ä¼šå¢žåŠ ä½ çš„ 编辑效率。基础的 Vim æ“作å¯ä»¥åœ¨è¿™é‡Œå­¦ä¼šã€‚

Evil 模å¼ä¸­çš„ State 就相当与 Vim 中的模å¼ï¼Œå¸¸ç”¨çš„æ¨¡å¼æœ‰ä¸‹é¢å‡ ç§ï¼ˆåŽé¢å¯¹äºŽäº†ç›¸åº” çš„ Emacs 中的 State),

  • Normal Mode -> Normal State
  • Insert Mode -> Insert State
  • Visual Mode -> Visual State
  • Motion Mode -> Motion State

还有一个 Emacs ä¸­çš„ç‰¹æ®ŠçŠ¶æ€æ˜¯ Emacs State。

Evil 的安装

照例我们需è¦å°† Evil æ’件添加至我们的æ’件列表中æ¥å®Œæˆå®‰è£…。在é‡å¯ Emacs 完æˆå®‰è£… åŽå¯ä»¥æ·»åР䏋é¢çš„代ç å°†å…¶æ¿€æ´»ã€‚

(evil-mode 1)

在激活 Evil 模å¼åŽå°±å¯ä»¥ï¼Œåœ¨ Emacs 中使用 Vim 的快æ·é”®äº†ã€‚æœ‰ä¸€ç‚¹éœ€è¦æ³¨æ„ C-u 在 Emacs 中有特殊的功所(Universal args)以能我们å¯ä»¥é€šè¿‡ä½¿ç”¨ customize-group æ¥å¯¹ Evil 模å¼è¿›è¡Œä¿®æ”¹ï¼Œå°† Evil Want C U Scroll 设置为开å¯ã€‚

下é¢çš„代ç å¯ä»¥å°† insert state map 中的快æ·é”®æ¸…空,使其å¯ä»¥å›žé€€ï¼ˆFallback)到 Emacs State 中,这样我们之å‰çš„ Emacs State 里é¢å®šä¹‰çš„ C-w 等快æ·é”®å°±ä¸ä¼šè¢« evil insert minor mode state 所覆盖,

(setcdr evil-insert-state-map nil)
(define-key evil-insert-state-map [escape] 'evil-normal-state)

这样你就å¯ä»¥ä½¿ç”¨ Evil æ¥åœ¨ Emacs 中完æˆç™¾åˆ†ä¹‹å…«å作用的快æ·é”®æ“作了。

完整的 Evil Mode çš„ PDF 版本的æ“作指å—å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ï¼Œå»ºè®®ä»Ž Vim 转 Emacs 的用户 多次阅读æ¥å®Œæ•´çš„æŽŒæ¡è¿™ä¸ªæ¨¡å¼çš„使用方法。

Evil æ¨¡å¼æ’ä»¶

Leader Key

在 Emacs 中使用 Leader Key å¯ä»¥é€šè¿‡ evil-leader æ¥å®žçŽ°ã€‚ä½ éœ€è¦åšçš„就是在安装åŽå°†å…¶æ¿€æ´»å³å¯ã€‚

æç¤º: æ ¹æ®cofi/evil-leader 的说明,你应该在激活 evil-mode 之å‰å°±æ¿€æ´» global-evil-leader-mode,å¦åˆ™ evil-leader 在几个åˆå§‹ç¼“冲区(scratch, Message,…)上将ä¸ç”Ÿæ•ˆã€‚

(global-evil-leader-mode)

Leader Key å¯ä»¥é€šè¿‡ customize-group æ¥è¿›è¡Œè®¾ç½®ï¼ˆEvil Leader/Leaderï¼‰ã€‚å› ä¸ºä¹‹åŽæˆ‘ 们会转移至 Spacemacs 所以我们å¯ä»¥å°†å…¶è®¾ç½®ä¸ºç©ºæ ¼é”® SPC 。

在通过下é¢çš„é…ç½®æ¥è®¾ç½®ç®€å•çš„ç»“åˆ Leader Key å¿«æ·é”®ç»„åˆï¼ˆæˆ‘们使用ä¸åŒçš„键讲ä¸åŒçš„ 功能分组,例如我们使用 f é”®æ¥åšå…³äºŽæ–‡ä»¶çš„æ“ä½œï¼Œä½¿ç”¨ b é”®æ¥åšå…³äºŽç¼“冲区 (Buffer)的æ“作),

(evil-leader/set-key
  "ff" 'find-file
  "bb" 'switch-to-buffer
  "0"  'select-window-0
  "1"  'select-window-1
  "2"  'select-window-2
  "3"  'select-window-3
  "w/" 'split-window-right
  "w-" 'split-window-below
  ":"  'counsel-M-x
  "wM" 'delete-other-windows
  )

注æ„上é¢çª—å£è·³è½¬ç›¸å…³çš„è®¾ç½®éœ€è¦ window-numbering å®‰è£…åŽæ–¹å¯ç”Ÿæ•ˆã€‚

Window-numbering

这个æ’ä»¶å¯ä»¥è®©æˆ‘们快速的使用 Leader Key ä¸Žæ•°å­—é”®çš„ç»„åˆæ¥åœ¨å¤šä¸ªçª—å£ä¹‹é—´è¿›è¡Œè·³è½¬ã€‚ 它的 GitHub 地å€å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ã€‚

下载安装åŽé€šè¿‡ä¸‹é¢çš„代ç å¯ä»¥å°†å…¶æ¿€æ´»ï¼Œ

(window-numbering-mode 1)

Evil-Surround

Evil-surround 是一个 Vim 上éžå¸¸å¸¸ç”¨çš„æ’ä»¶æ”¹å†™çš„ï¼Œä½¿ç”¨å®ƒå¯ä»¥å¿«é€Ÿçš„将选中区域进行 匹é…çš„æ“ä½œï¼Œä¾‹å¦‚é€‰ä¸­åŒºåŸŸä¸¤è¾¹åŒæ—¶è¿›è¡Œæ·»åŠ æˆ–ä¿®æ”¹æ‹¬å·ï¼Œå¼•å·ç­‰æ“作。

下载安装åŽä½¿ç”¨ä¸‹é¢çš„代ç å°†å…¶æ¿€æ´»ï¼Œ

(require 'evil-surround)
(global-evil-surround-mode)

简å•的使用方法就是在选中所选区域åŽï¼Œä½¿ç”¨ S( æ¥å°†é€‰ä¸­åŒºåŸŸåŒ…括在括å·ä¹‹ä¸­ã€‚如果想 å°†æ‹¬å·æ”¹å˜æˆ " å¯ä»¥åœ¨é€‰ä¸­åŽä½¿ç”¨ cs("

Evil-nerd-commenter

è¿™æ˜¯ä¸€ä¸ªå¿«é€Ÿæ·»åŠ ä¸Žå–æ¶ˆæ³¨é‡Šçš„æ’ä»¶ï¼Œå®ƒçš„ GitHub 地å€åœ¨è¿™é‡Œã€‚

使用下é¢ä»£ç å¯ä»¥å°†å…¶æ¿€æ´»ï¼Œ

(evilnc-default-hotkeys)

使用下é¢çš„代ç å°†å…¶ä¸Ž Evil 模å¼è¿›è¡Œç»‘定,这里我们选择使用 ,/ 作为快æ·é”®ã€‚

(define-key evil-normal-state-map (kbd ",/") 'evilnc-comment-or-uncomment-lines)
(define-key evil-visual-state-map (kbd ",/") 'evilnc-comment-or-uncomment-lines)

Which-key

which-key å¯ä»¥æ˜¾ç¤ºå½“å‰ç»„åˆé”®ä¸‹æ‰€æœ‰å¯ä»¥ä½¿ç”¨çš„全部组åˆé”®çš„选项。使用这个æ’ä»¶å¯ä»¥å¾ˆ 好的解决快æ·é”®å¤ªå¤šçš„问题,我们无需在记忆任何快æ·é”®ï¼Œè€Œæ˜¯æ ¹æ®è‡ªå·±çš„需求使用ä¸åŒåˆ† 组的快æ·é”®åŽå†åœ¨å…¶ä¸­åŽ»éœ€æ‰¾è‡ªå·±éœ€è¦çš„功能。

在下载åŽå¯ä»¥ä½¿ç”¨ä¸‹é¢çš„代ç è¿›è¡Œæ¿€æ´»ï¼Œ

(which-key-mode 1)

Org Mode 中的æœç´¢

C-c a 中å¯ä»¥æ ¹æ®æç¤ºä½¿ç”¨ s æ¥è¿›è¡Œå…³é”®å­—所æœã€‚使用 t 则å¯ä»¥è¿›è¡Œä»£åŠžäº‹é¡¹çš„æœç´¢ã€‚

第八天:Cask 介ç»ä¸Žå®žè·µ

视频地å€å¦‚下:

什么是 Cask:

Cask 是一个 Emacs Lisp 的项目管ç†å·¥å…·.

Cask 的安装

Cask 的地å€: Cask

å¯ä»¥ä½¿ç”¨å¦‚下命令安装 Cask:

curl -fsSL https://raw.githubusercontent.com/cask/cask/master/go | python

安装过程中 Cask 将会进行 Bootstrap, 安装一些包到~/.emacs.d 目录中.

安装完æˆä¹‹åŽéœ€è¦å°† Cask çš„å¯æ‰§è¡Œæ–‡ä»¶ç›®å½•加入到 PATH 中.

å¯ä»¥çœ‹åˆ°, Cask 的安装过程在 ~/.emacs.d 中新建了一个 .Cask 目录.

安装 Pallet: Pallet 是一个基于 Cask 的包管ç†å·¥å…·, å¯ä»¥ä½¿ç”¨ Emacs 的包安装方å¼å®‰è£….

ç„¶åŽä½¿ç”¨ä»¥ä¸‹ä»£ç å¯ç”¨ Pallet:

(pallet-mode)  
(pallet-init)    ; 在.emacs.d 中生æˆä¸€ä¸ª Cask 文件, 写入æºä¸ŽçŽ°æœ‰åŒ…
(pallet-install) ; å°† elpa 中的 package æ‹·è´åˆ°.Cask/<you version>/elpa 目录中

ç„¶åŽåœ¨é…置文件中加入以下代ç (在其他包加载之å‰) :

(require 'cask "<path-to-cask>/cask.el")
(cask-initialize)    ; 类似于 package-initialize
(require 'pallet)
(pallet-mode t)      ; 激活 pallet, 在安装包时将 Cask 文件写入相应信æ¯

具体使用方å¼è§æ–‡æ¡£: Pallet

为何使用 Cask

  • 使用 Cask 文件ä¿å­˜åŒ…的信æ¯, å¯ä»¥é€šè¿‡ Cask install 自动安装
  • 当有多个版本的 Emacs æ—¶, å°†å„版本的包å•独存放

故障排除

Emacs24.5 æ—¶ä¸èƒ½å®‰è£… let-alist

解决方案: å°† Gnu çš„æºåŠ å…¥æºåˆ—表中, 示例代ç å¦‚下(加入 Cask 文件)

(source "gnu" "http://elpa.zilongshanren.com/gnu/")

在 Emacs24.5 中没有定义 define-advice

define-advice 是一个 Emacs25 中加入的å®, 在 Emacs24 中ä¸èƒ½ä½¿ç”¨, å¯ä»¥ä½¿ç”¨ defadvice 代替:

(defadvice show-paren-function (around fix-show-paren-function activate)
  (cond ((looking-at-p "\\s(") ad-do-it)
	(t (save-excursion
	     (ignore-errors (backward-up-list))
	     ad-do-it)))
  )

而且使用 defadvice 相比 define-advice 还有一个优点:

使用 define-advice 定义的代ç , 当在 Normal æ¨¡å¼æ—¶å…‰æ ‡ä¸¤è¾¹çš„æ‹¬å·ä¸ä¼šé«˜äº®, 而使用 defadvice å¯ä»¥.

第ä¹å¤©ï¼šMacro 与 Use-package

视频地å€å¦‚下:

这次主è¦ä»‹ç» Emacs Lisp 中的å®(Macro)ä»¥åŠ Use-package æ’ä»¶.

Macro

什么是 Macro

宿˜¯ä¸€ç§å¯ä»¥ç”Ÿæˆä»£ç çš„代ç . 类比与 C 语言中的å®ä»¥åŠ C++中的模æ¿. 先看一个简å•的例å­:

(defmacro inc (var)
  (list 'setq var (list '1+ var)))

(setq my-var 1)
(setq my-var (+ 1 my-var))

(macroexpand '(inc my-var))

以上这个å®çš„作用是将å˜é‡çš„值+1. 执行以上代ç ä¹‹åŽ, my-var 的结果为 2.

å¯ä»¥ä½¿ç”¨ macroexpand 获得å®å±•开的结果, 如以上代ç ç»“果为:

(setq my-var (1+ my-var))

我们也å¯ä»¥ä½¿ç”¨å‡½æ•°æ¥å®žçŽ°ç›¸åŒçš„功能, 但 Macro 与函数有以下两个区别:

  1. å®çš„傿•°å¹¶ä¸ä¼šè¢«é©¬ä¸Šæ±‚值, 解释器会先展开å®, å®å±•开之åŽè§£é‡Šå™¨æ‰ä¼šæ‰§è¡Œå®å±•开的 结果; è€Œå‡½æ•°çš„å‚æ•°ä¼šé©¬ä¸Šæ±‚值
  2. å®çš„æ‰§è¡Œç»“果是一个表达å¼, 该表达å¼ä¼šç«‹å³è¢«è§£é‡Šå™¨æ‰§è¡Œ; 而函数的结果是一个值

backquote

backquote 是指å引å·(`), å³é”®ç›˜ä¸Šæ•°å­— 1 左边的键.

当在 Emacs 输入 backquote 时会æ’入两个å引å·, å¯ä»¥ä½¿ç”¨ä»¥ä¸‹ä»£ç å…³é—­è¿™ä¸ªåŠŸèƒ½:

(sp-local-pair 'emacs-lisp-mode "`" nil :actions nil)

å…ˆçœ‹ä»¥ä¸‹ä¾‹å­æ¥ä½“会 backquote 的作用:

(defun my-print (number)
  (message "This is a number: %d" number))

(my-print 2)               ; 1. output= This is a number: 2
(my-print (+ 2 3))         ; 2. output= This is a number: 5

(quote (+ 1 1))
;; return a list= (+ 1 1)

(defmacro my-print-2 (number)
  `(message "This is a number: %d" ,number))

(my-print-2 2)             ; 3. output= This is a number: 2
(my-print-2 (+ 2 3))       ; 4. output= This is a number: 5

(setq my-var 2)
(inc my-var)

(defmacro inc2 (var1 var2)
  (list 'progn (list 'inc var1) (list 'inc var2)))

(macroexpand '(inc2 my-var my-var))
(macroexpand-all '(inc2 my-var my-var))

quote 的作用是返回åŽé¢çš„表达å¼, ä¸å¯¹è¡¨è¾¾å¼è¿›è¡Œæ±‚值. 所以以下代ç :

(quote (+ 1 1))
;; return a list= (+ 1 1)

å¹¶æ²¡æœ‰å¯¹è¡¨è¾¾å¼ (+ 1 1) 进行求值返回 2, 而是返回一个 list.

backquote 的作用与 quote 相似, åŒæ ·ä¸å¯¹åŽé¢çš„è¡¨è¾¾å¼æ±‚值, 但是当 backquote 在å®ä¸­ 与逗å·(,)一起使用时, 用逗å·ä¿®é¥°çš„å˜é‡å°†è¿›è¡Œæ±‚值.

例如以下代ç :

(defmacro my-print-2 (number)
  `(message "This is a number: %d" ,number))

(pp (macroexpand '(my-print-2 (+ 2 3))))
(my-print-2 (+ 2 3))

当输出 message 且 number ä¸å¸¦é€—å·æ—¶, my-print-2 的执行将æç¤ºé”™è¯¯. 因为å®ä¸å¯¹å‚ 数进行求值, 所以以上å®å±•开相当于:

(message "This is a number:" number)

因为我们没有定义 number å˜é‡, 所以执行出错.

而如果加入逗å·, 则在å®å±•开时会对å˜é‡ number 进行求值, 展开结果为:

(message "This is a number: %d" (+ 2 3))

在调试å®çš„过程中, å¯ä»¥ä½¿ç”¨ macroexpand å’Œ macroexpand-all 获å–å®å±•开的结果.

关于 backquote 的更多讨论, å¯ä»¥è§ä»¥ä¸‹åœ°å€: lisp 中的`与,是怎么用的?

为什么使用å®

使用å®å¯ä»¥å‡å°‘é‡å¤çš„代ç , ä»¥ä¸‹æ˜¯ä¸€ä¸ªä½¿ç”¨å®æ¥å®šä¹‰å‡½æ•°çš„例å­:

(defun prelude-search (query-url prompt)
  "Open the search url constructed with the QUERY-URL.
PROMPT sets the `read-string prompt."
  (browse-url
   (concat query-url
           (url-hexify-string
            (if mark-active
                (buffer-substring (region-beginning) (region-end))
              (read-string prompt))))))

(defmacro prelude-install-search-engine (search-engine-name search-engine-url search-engine-prompt)                   ; #1
  "Given some information regarding a search engine, install the interactive command to search through them"    
  `(defun ,(intern (format "prelude-%s" search-engine-name)) ()                                                       ; #2
       ,(format "Search %s with a query or region if any." search-engine-name)                                        ; #3
       (interactive)
       (prelude-search ,search-engine-url ,search-engine-prompt)))                                                    ; #4

(prelude-install-search-engine "google"     "http://www.google.com/search?q="              "Google: ")                ; #5
(prelude-install-search-engine "youtube"    "http://www.youtube.com/results?search_query=" "Search YouTube: ")
(prelude-install-search-engine "github"     "https://github.com/search?q="                 "Search GitHub: ")
(prelude-install-search-engine "duckduckgo" "https://duckduckgo.com/?t=lm&q="              "Search DuckDuckGo: ")

下é¢å¯¹ä»¥ä¸Šä»£ç è¿›è¡Œè®²è§£:

第#1 行, 通过 prelude-install-search-engine å®šä¹‰äº†ä¸€ä¸ªéœ€è¦ 3 ä¸ªå‚æ•°çš„å®, 这个 å®çš„作用是生æˆä¸€ä¸ªå‡½æ•°.

第#2 行, 通过 intern 生æˆä¸€ä¸ªç¬¦å·ä½œä¸ºå‡½æ•°å, å称为 *prelude-xxx* , 其中 xxx ä¸ºç¬¬ä¸€ä¸ªå‚æ•°çš„值.

第#3 行, 生æˆäº†è¿™ä¸ªå‡½æ•°çš„æè¿°.

第#4 行, 调用 prelude-search 函数进行æœç´¢å¤„ç†.

第#5 行, 调用这个å®å®šä¹‰äº†ä¸€ä¸ªå为 *prelude-google* 的函数.

从以上代ç å¯ä»¥çŸ¥é“, 我们利用å®ç”Ÿæˆäº†ï¼”个åç§°ä¸åŒçš„函数, é¿å…了手动编写函数的问题 (因为这4个函数的代ç éžå¸¸ç›¸ä¼¼, æ ¹æ® DRY 原则应该尽é‡é¿å…åšè¿™ç§é‡å¤å·¥ä½œ).

关于å®çš„æ›´å¤šå†…容, å¯ä»¥é˜…读 Paul Graham 的著作 《On Lisp》

Use-package

简介

Use-package 是一个å®, 它能让你将一个包的 require 和它的相关的åˆå§‹åŒ–ç­‰é…置组织 在一起, é¿å…对åŒä¸€ä¸ªåŒ…çš„é…ç½®ä»£ç æ•£è½åœ¨ä¸åŒçš„æ–‡ä»¶ä¸­.

Use-package 的更多信æ¯å‚è§ä»¥ä¸‹åœ°å€: Use-package

一些简å•的用法

更安全的 require

在 Emacs 中, 当我们è¦å¼•入一个包时, 通常会使用以下代ç :

(require 'package-name)

但是当 package-name ä¸åœ¨ load-path 中时, 以上代ç ä¼šæŠ›å‡ºé”™è¯¯. 使用 Use-package å¯ä»¥é¿å…:

(use-package package-name)

以上代ç å±•开的结果如下:

(if
    (not
     (require 'package-name nil 't))
    (ignore
     (message
      (format "Cannot load %s" 'package-name))))

å¯ä»¥çœ‹åˆ°, Use-package 使用 ignore æ¥é¿å…抛出错误, 这样当æŸä¸ªåŒ…ä¸å­˜åœ¨æ—¶, eamcs 也能够正常å¯åЍ.

å°†é…置集中

当我们引入æŸä¸ªåŒ…æ—¶, 有å¯èƒ½éœ€è¦å®šä¹‰ä¸€äº›ä¸Žè¿™ä¸ªåŒ…相关的å˜é‡, 使用 Use-package 实 现这个需求如下:

(use-package package-name
  :init
  (setq my-var1 "xxx")
  :config
  (progn
    (setq my-var2 "xxx")
    (setq my-var3 "xxx")
    )
  )

在上例中, init åŽçš„代ç åœ¨åŒ…çš„ require 之剿‰§è¡Œ, 如果这段代ç å‡ºé”™åˆ™è·³è¿‡åŒ…çš„ require.

config åŽçš„代ç åœ¨åŒ…çš„ require ä¹‹åŽæ‰§è¡Œ.

init 与 config 之åŽåªèƒ½æŽ¥å•个表达å¼è¯­å¥, å¦‚æžœéœ€è¦æ‰§è¡Œå¤šä¸ªè¯­å¥, å¯ä»¥ç”¨ progn .

autoload

使用 require 时会引入这个包, 但是当你的包很多时会影å“å¯åŠ¨é€Ÿåº¦. 而使用 autoload 则å¯ä»¥åœ¨çœŸæ­£éœ€è¦è¿™ä¸ªåŒ…æ—¶å† require, æé«˜å¯åŠ¨é€Ÿåº¦, é¿å…æ— è°“çš„ require.

使用 Use-package å¯ä»¥è½»æ¾çš„实现这个功能:

(use-package package-name
  :commands
  (global-company-mode)
  :defer t
  )

使用 commands å¯ä»¥è®© package 延迟加载, 如以上代ç ä¼šé¦–先判断 package çš„ç¬¦å·æ˜¯å¦ 存在, 如果存在则在 package-name 的路径下加载. defer 也å¯ä»¥è®© package-name 进行延迟加载.

键绑定

在之å‰çš„代ç ä¸­, 如果我们需è¦ç»‘定一个键, 需è¦ä½¿ç”¨ global-key-bind 或 define-key 实现, 而使用*Use-package* 实现更简å•:

(use-package color-moccur
  :commands (isearch-moccur isearch-all)
  :bind (("M-s O" . moccur)
         :map isearch-mode-map
         ("M-o" . isearch-moccur)
         ("M-O" . isearch-moccur-all))
  :init
  (setq isearch-lazy-highlight t)
  :config
  (use-package moccur-edit))

为什么使用 Use-package

  1. Use-package 能让相关的é…置更为集中, é¿å…é…置分散带æ¥çš„维护困难
  2. Use-package 有完善的错误处ç†, 使é…ç½®ä»£ç æ›´ä¸ºå¥å£®
  3. Spacemacs 也大é‡ä½¿ç”¨äº† Use-package

第å天: Company-mode 与 auto-completion

视频地å€å¦‚下:

内容概è¦:

  1. 给出 Cask å’Œ Use-package 的简å•示例
  2. è¯¦ç»†ä»‹ç» Company-mode 的工作原ç†, å„ç§ backend åŠå…¶ç”¨æ³•

扩展阅读:

  1. 编写一个简å•çš„ comopany backend
  2. Company Mode Emacs wiki

å‡çº§ Package ä¹‹åŽæœ‰ BUG 怎么办

有些时候我们将一个 Package å‡çº§åˆ°æœ€æ–°çš„版本(例如 github 上最新的 commit), 而该版本å¯èƒ½ä¼šå­˜åœ¨ä¸€äº› BUG, 这就会导致我们的é…ç½®ä¸èƒ½ä½¿ç”¨.

如果我们使用 stable 版本的 Package(例如使用 github 上最新的 release), å°±å¯ä»¥å°½é‡åœ°å‡å°‘因为å‡çº§åŒ…之åŽçš„ BUG 导致é…ç½®ä¸å¯ç”¨çš„æƒ…况.

å¦ä¸€ç§è§£å†³æ–¹å¼æ˜¯ä½¿ç”¨ Cask 进行包管ç†, 举例如下:

首先我们添加一个包, 例如我们编辑 Cask 文件, 添加 monokai-theme :

(depends-on "monokai-theme"
            :git "https://github.com/oneKelvinSmith/monokai-emacs/releases"
            :ref "02c5f5d")

ç„¶åŽå¯åЍ emacs, 但是出现了 BUG. 这时我们å¯ä»¥ç›´æŽ¥å°† ref 的值修改为最新的 commit, Cask å³ä¼šæ›´æ–°è¿™ä¸ªåŒ…, 而ä¸ç”¨ç­‰å¾… melpa 对包进行更新.

Use-package 的更多用法

如果我们å¯ç”¨ exec-path-from-shell , 在 emacs å¯åŠ¨æ—¶å¯èƒ½ä¼šæç¤º PATH å˜é‡é‡å¤å®šä¹‰, 解决方案如下:

(use-package exec-path-from-shell
  :ensure t
  :if (and (eq system-type 'darwin) (display-graphic-p))
  :config
  (progn
    (when (string-match-p "/zsh$" (getenv "SHELL"))
      ;; Use a non-interactive login shell.  A login shell, because my
      ;; environment variables are mostly set in `.zprofile'.
      (setq exec-path-from-shell-arguments '("-l")))

    (exec-path-from-shell-initialize)
    )
  )

;; (use-package monokai-theme
;; :ensure t)

其中 if å­å¥å¯ä»¥ç¡®å®šå¯ç”¨ Package çš„æ¡ä»¶, 在 config å­å¥ä¸­å‘ exec-path-from-shell-arguments å³å¯æ¶ˆé™¤è¿™ä¸ªè­¦å‘Š.

ensure å­å¥æ¥ç¡®ä¿ Package 被安装. 如果è¦ä½¿ç”¨ stable 版, 则添加以下å­å¥:

:pin melpa-stable

Company-mode 的工作原ç†

Company-mode 需è¦é…åˆåŽç«¯ä½¿ç”¨, 所有的 backend 都ä¿å­˜åœ¨ company-backends 这个å˜é‡ä¸­, 例如在我的环境中该å˜é‡å€¼å¦‚下:

(company-capf
 (company-dabbrev-code company-gtags company-etags company-keywords)
 company-files
 company-dabbrev
 )

*company-backends*å˜é‡çš„值是一个列表, 其中的æ¯ä¸€é¡¹éƒ½æ˜¯ä¸€ä¸ªåŽç«¯æˆ– Group Backend.

Company-mode ä¼šä¾æ¬¡è°ƒç”¨è¯¥å˜é‡ä¸­çš„ backend, 并判断该 backend 是å¦åˆé€‚å½“å‰ Buffer, 直到找到一个åˆé€‚的补全åŽç«¯.

在进行补全项选择的时候, 我们也å¯ä»¥åœ¨ mode-line 中看到是使用的哪一个åŽç«¯.

  1. company-dabbrev: 将当剿‰“开的所有 buffer 中的关键字作为补全显示(默认ä¸ä½¿ç”¨ scratch buffer).
  2. company-files: 补全路径.

å¦‚æžœåœ¨è¡¥å…¨è¿‡ç¨‹ä¸­å–æ¶ˆäº†è¡¥å…¨, 也å¯ä»¥ä½¿ç”¨å‘½ä»¤å†æ¬¡å¼€å¯è¡¥å…¨. 例如 company-files 补全方å¼å°±å¯ä»¥ä½¿ç”¨ company-files 函数开å¯.

在输入英文时å¯ä»¥ä½¿ç”¨ company-ispell 进行输入æç¤º.

为什么有时 Python 的补全 ä¸å·¥ä½œ

有时在编写 Python 代ç çš„æ—¶å€™è¡¥å…¨ä¸èƒ½å·¥ä½œ, 这时我们å¯ä»¥å…ˆæŸ¥çœ‹ company-backends 的值, 查看是å¦éœ€è¦å®‰è£… company-anaconda 用于补全.

在 Mac 系统中, 如果 anaconda-mode 的安装过程出现错误, å¯ä»¥å‚照以下解决方案: Mac 上é¢ç¼–辑 python 的时候安装 anaconda-mode 出错

ç„¶åŽç¡®ä¿åœ¨ company-backends 中有 company-anaconda 这个åŽç«¯å³å¯. å¯ä»¥ä½¿ç”¨å¦‚下代ç :

(add-hook 'python-mode-hook
          (lambda ()
            (set (make-local-variable 'company-backends) '(company-anaconda))))

以上代ç åœ¨ python-mode 被激活时设置 company-backends çš„å˜é‡å€¼ä¸º (company-anaconda), 则在编辑 python ä»£ç æ—¶å°±å¯ä»¥ä½¿ç”¨ anaconda-mode 进行补全.

在 emacs 中有两ç§è¡¥å…¨æ–¹å¼:

  1. 如 company-files ç­‰, æ ¹æ®å…³é”®å­—等进行补全, åªéœ€è¦ emacs 自己进行一些处ç†å³å¯å¾—到补全数æ®;
  2. 如 company-anaconda ç­‰, 需è¦ä½¿ç”¨å®¢æˆ·ç«¯-æœåŠ¡ç«¯æ¨¡å¼, 补全åŽç«¯éœ€è¦æœåŠ¡ç«¯çš„é…åˆæ‰èƒ½å¾—到补全数æ®.

在进行编程时, 一般使用第二ç§è¡¥å…¨åŽç«¯, 例如 编写 python 代ç ä½¿ç”¨ company-anaconda, 编写 C/C++代ç ä½¿ç”¨ company-ycmd, 编写 javascript 代ç ä½¿ç”¨ company-tern.

上述示例代ç å¼€å¯ company-anaconda 时有一个缺点, 比如当我们在 python 的注释时没法使用补全, 因为补全åŽç«¯åªæœ‰ company-anaconda, 在注释时ä¸å·¥ä½œ. 我们å¯ä»¥å°† dabbrev 加入åŽç«¯åˆ—表:

(add-hook 'python-mode-hook
          (lambda ()
            (set (make-local-variable 'company-backends) '(company-anaconda company-dabbrev))))

当 company-anaconda ä¸åˆé€‚时使用 company-dabbrev 进行补全, å³å¯æ»¡è¶³ä¸Šè¿°éœ€æ±‚.

Group Backend

company-dabbrev-code: 类似于 company-dabbrev, 但是 dabbrev 对代ç å’Œæ³¨é‡Šéƒ½è¿›è¡Œè¡¥å…¨, dabbrev-code åªè¡¥å…¨ä»£ç .

å‡è®¾æˆ‘们的é…置代ç å¦‚下:

(add-hook 'python-mode-hook
          (lambda ()
            (set (make-local-variable 'company-backends) '((company-anaconda company-dabbrev-code)
                                                           company-dabbrev)))
          )

如果我们在注释中出现了 xxx 这个字符串, 在编写 python ä»£ç æ—¶ xxx ä¸ä¼šå‡ºçŽ°åœ¨è¡¥å…¨é€‰é¡¹ä¸­. 因为在此时会先匹é…到 company-anaconda, å¹¶ä¸ä¼šè¿›å…¥ company-dabbrev. 而因为 company-anaconda 是一个 Group Backend, 所以 company-dabbrev-code 的补全数æ®ä¼šå‡ºçŽ°åœ¨è¡¥å…¨åˆ—è¡¨ä¸­.

怎样写一个简å•的补全åŽç«¯

因为视频时间关系, 大家å¯ä»¥åŽ»é˜…è¯»ä»¥ä¸‹æ–‡ç« :

Writing the Simplest Emacs company-mode Backend

实现方å¼ç®€å•介ç»å¦‚下:

  1. 定义一个补全数æ®åˆ—表
  2. 定义一个补全函数, 返回对应输入的补全数æ®

更多的内容å¯ä»¥æŸ¥çœ‹è¯¥æ–‡æ¡£, åŒæ—¶åœ¨ç½‘页å³ä¾§çš„链接中有更多的详细内容.

第å一天: Spacemacs 简介åŠå®‰è£…

视频地å€å¦‚下:

ä»Žä»Šå¤©çš„å†…å®¹å¼€å§‹ä»‹ç» Spacemacs. 地å€: Spacemacs

今天的内容包括:

  1. 如何安装 Spacemacs
  2. 一些简å•çš„é…ç½®, ä»¥åŠ package 管ç†
  3. 管ç†è‡ªå·±çš„é…ç½®

安装 Spacemacs

安装 Spacemacs éžå¸¸ç®€å•, åªéœ€è¦å°† github 上的仓库克隆å³å¯, 峿‰§è¡Œä»¥ä¸‹å‘½ä»¤(如有必è¦å¯ä»¥å…ˆå¤‡ä»½ä»¥å‰çš„é…ç½®):

cd ~
mv .emacs.d .emacs.d.bak
mv .emacs .emacs.bak
git clone https://github.com/syl20bnr/spacemacs ~/.emacs.d

在克隆完æˆåŽç›´æŽ¥è¿è¡Œ Emacs. 在第一次使用 Spacemacs 时需è¦ä¸‹è½½ä¸€äº› Package, ç„¶åŽåœ¨ Bootstrap 完æˆä¹‹åŽä½ éœ€è¦è¿›è¡Œå¦‚下一些é…ç½®:

  1. 使用哪ç§ç¼–辑方å¼, 包括 vim æ–¹å¼(默认) ä»¥åŠ emacs æ–¹å¼.
  2. ä½¿ç”¨å“ªç§ Spacemacs distribution. 包括标准版(默认)以åŠåŸºç¡€ç‰ˆ. 区别在于标准版包å«éžå¸¸å¤šçš„功能, 而基础版åªåŒ…嫿 ¸å¿ƒåŠŸèƒ½.

在完æˆä»¥ä¸Šä¸¤ä¸ªé…置之åŽ, 就会在 HOME 目录生æˆä¸€ä¸ª ~/.spacemacs é…置文件. ç„¶åŽ Spacemacs 会进行进一步的åˆå§‹åŒ–, 下载更多的需è¦çš„ Package. 如果你需è¦ä½¿ç”¨ emacs-china çš„é…ç½®æº, 此时å¯ä»¥ç»ˆæ­¢ emacs, ç„¶åŽåœ¨~/.spacemacs 中的 dotspacemacs/user-init 函数中加入以下代ç :

(setq configuration-layer--elpa-archives
      '(("melpa-cn" . "http://elpa.zilongshanren.com/melpa/")
        ("org-cn"   . "http://elpa.zilongshanren.com/org/")
        ("gnu-cn"   . "http://elpa.zilongshanren.com/gnu/")))

釿–°å¯åЍ emacs, 等待 Spacemacs 完æˆå®‰è£…å³å¯.

å¦‚æžœä½ éœ€è¦æ›´æ–¹ä¾¿çš„管ç†ä½ è‡ªå·±çš„é…ç½®, å¯ä»¥åˆ›å»º ~/.spacemacs.d 目录, ç„¶åŽå°† ~/.spacemacs 文件移动到该目录中并é‡å‘½å为 init.el.

在 Spacemacs 中的æ“作方å¼å¦‚下:

  1. 按下 SPC f j 打开 dired 目录
  2. 按下按键 + , 创建 ~/.spacemacs.d 目录
  3. 将光标移动到 .spacemacs 文件上, 按下 R, 将该文件移动到 .spacemacs.d 目录中
  4. 进入 .spacemacs.d 目录, 将光标移动到 .spacemacs 文件上, 按下 R, 将该文件é‡å‘½å为 init.el
  5. 按下 qq 退出 dired

ç„¶åŽå¯åЍ emacs å³å¯.

ä½¿ç”¨è¿™ç§æ–¹å¼ç®¡ç†é…ç½®, ä½ å¯ä»¥å°†è‡ªå·±çš„é…置集中到 ~/.spacemacs.d 目录中, 更容易进行统一管ç†. 你也å¯ä»¥å°†è‡ªå·±çš„é…ç½® push 到 github 上.

添加内置的 layer

åœ¨å®‰è£…å®Œæˆ Spacemacs 之åŽ, 按下 SPC f e d 打开 ~/.spacemacs 文件, 修改 dotspacemacs-configuration-layers å˜é‡çš„值, å°† auto-completion, better-defaults, emacs-lisp, git, markdown, org, spell-checking, syntax-checking ç­‰ layer 加入列表.

ç„¶åŽé€€å‡º emacs å†é‡å¯, 或者按下 SPC f e R 安装需è¦çš„ package.

一些简å•çš„é…ç½®

å¯åŠ¨æ—¶å…¨å±æ˜¾ç¤º

在 dotspacemacs/init 函数中, å°† dotspacemacs-fullscreen-at-startup å˜é‡è®¾ç½®ä¸º t å³å¯. 代ç å¦‚下:

;; If non nil the frame is maximized when Emacs starts up.
;; Takes effect only if `dotspacemacs-fullscreen-at-startup' is nil.
;; (default nil) (Emacs 24.4+ only)
dotspacemacs-maximized-at-startup t

ivy layer

å°† ivy 加入 dotspacemacs-configuration-layers 列表中. 按下 CTRL s 使用 swiper å¯ä»¥è¿›è¡Œæœç´¢.

查看 layer 下的 文档信æ¯

按下 SPC h SPC å³ä¼šå¼¹å‡ºä¸€ä¸ªä¿¡æ¯çª—å£, å¯ä»¥ä»Žçª—å£ä¸­é€‰æ‹©å…·ä½“çš„ layer 或者其他信æ¯è¿›è¡ŒæŸ¥çœ‹.

删除安装的 package

åªéœ€è¦å°†éœ€è¦åˆ é™¤çš„ package å称加入到 dotspacemacs-excluded-packages å˜é‡ä¸­, 在下一次å¯åЍ emacs æ—¶å³ä¼šåˆ é™¤è¯¥ package. 示例代ç å¦‚下:

;; A list of packages and/or extensions that will not be install and loaded.
dotspacemacs-excluded-packages '(vi-tilde-fringe)

安装 package

在 Spacemacs 中安装 package 时最好ä¸è¦ä½¿ç”¨ package-install, 因为这样安装的 package 会在下一次å¯åŠ¨æ—¶è¢«åˆ é™¤.

Spacemacs æä¾›äº†ä¸€ä¸ªæ–¹å¼, ä½ åªéœ€å°†éœ€è¦å®‰è£…çš„ package 加入到 dotspacemacs-additional-package å˜é‡ä¸­å³å¯, 示例代ç å¦‚下:

;; List of additional packages that will be installed without being
;; wrapped in a layer. If you need some configuration for these
;; packages, then consider creating a layer. You can also put the
;; configuration in `dotspacemacs/user-config'.
dotspacemacs-additional-packages '(youdao-dictionary)

é…ç½® customize-group

如果使用 customize-group 对é…置进行了修改, ä½ å¯ä»¥ä»¥ä¸‹ä»£ç å°†ç”Ÿæˆçš„ custom.el é…置文件纳入 ~/.spacemacs.d 目录中进行统一管ç†:

(setq custom-file (expand-file-name "custom.el" dotspacemacs-directory))
(load custom-file 'no-error 'no-message)

修改主题

åªéœ€ä¿®æ”¹ dotspacemacs-themes å˜é‡çš„值, 将主题加入列表å³å¯. 在列表中é å‰çš„主题会优先使用. 示例代ç å¦‚下:

;; List of themes, the first of the list is loaded when spacemacs starts.
;; Press <SPC> T n to cycle to the next theme in the list (works great
;; with 2 themes variants, one dark and one light)
dotspacemacs-themes '(
                      monokai
                      ;; spacemacs-dark
                      ;; spacemacs-light
                      ;; solarized-light
                      solarized-dark
                      ;; leuven
                      ;; monokai
                      ;; zenburn
                      )

第å二天: 创建你的第一个 Spacemacs Layer

视频地å€å¦‚下:

主è¦å†…容:

  1. 如何更新 Spacemacs, åŒæ­¥å®˜æ–¹ develop åˆ†æ”¯åŠæ³¨æ„事项
  2. Layer çš„ variables å˜é‡åŠä½¿ç”¨æ–¹æ³•
  3. 如何创建自己的 Layer
  4. 如何定制 modeline
  5. evlified state

如何更新 Spacemacs

å¯ä»¥é€šè¿‡ git çš„æ–¹å¼æ¥æ›´æ–°ä»£ç , å‡è®¾æˆ‘们使用的是 develop 分支:

git checkout develop
git fetch upstream
git merge upstream/develop

一般æ¥è¯´, 如果你ä¸ç†Ÿæ‚‰ emacs 并且你的 Spacemacs é…置能够正常工作, 则ä¸éœ€è¦é¢‘ç¹çš„æ›´æ–°ä»£ç , 以é¿å…更新之åŽé…ç½®ä¸èƒ½ä½¿ç”¨.

variables å˜é‡

æ¯ä¸€ä¸ª layer 都å¯ä»¥é…置一些å˜é‡, å¯ä»¥é€šè¿‡ SPC h SPC ç„¶åŽè¾“å…¥ layer åç§°, 点击对应的选项å³å¯æ‰“开该 layer çš„ README.org 文件. ç„¶åŽæŒ‰ä¸‹ SPC f j 进入 dired 模å¼, 选择 config.el 文件打开, 该文件中å³å®šä¹‰äº†è¯¥ layer çš„å˜é‡.

例如 better-default layer çš„å˜é‡å¦‚下:

(defvar better-defaults-move-to-beginning-of-code-first t
  "when t, first stroke of C-a will move the cursor to the beginning of code.
When nil, first stroke will go to the beginning of line.
Subsequent strokes will toggle between beginning of line and beginning of code.")

(defvar better-defaults-move-to-end-of-code-first nil
  "when t, first stroke of C-e will move the cursor to the end of code (before comments).
When nil, first stroke will go to the end of line (after comments).
Subsequent strokes will toggle between end of line and end of code.")

è¦é…置使用这些å˜é‡, å¯ä»¥åœ¨å¯ç”¨ layer 时使用如下的代ç :

(better-defaults :variables
                 better-defaults-move-to-end-of-code-first t)

定制 modeline

在 emacs25.1 中, 该版本的 modeline 和以å‰ç‰ˆæœ¬ä¸åŒ, å¯ä»¥é€šè¿‡å¦‚下方å¼å°† modeline 修改为以å‰çš„æ˜¾ç¤ºå½¢çж:

在 dotspacemacs/user-config 中加入如下代ç :

(setq ns-use-srgb-colorspace nil)

创建自己的 layer

å‡è®¾æˆ‘们需è¦åˆ›å»ºä¸€ä¸ª layer, åå« zilongshanren, 并且在 layer 下包å«ä¸€ä¸ªåå« youdao-dictionary çš„ package.

首先利用 spacemacs æä¾›çš„函数创建 layer. 按下 M-x 并且输入 configuration-layer/create-layer, ç„¶åŽé€‰æ‹©è·¯å¾„ ~/.spacemacs.d, 确定创建 README, ç„¶åŽæˆ‘们就å¯ä»¥çœ‹åˆ° layer 创建æˆåŠŸ.

æ¯ä¸€ä¸ª layer 的结构如下:

[layer_name]
  |__ [local]
  | |__ [package 1]
  | |     ...
  | |__ [package n]
  |-- layers.el
  |__ packages.el
  |__ funcs.el
  |__ config.el
  |__ keybindings.el

[] = directory

峿¯ä¸€ä¸ª layer 目录下都å¯ä»¥åŒ…å« layers.el, packages.el 等文件, 以åŠä¸€ä¸ªåå« local 的目录.

æ¯ä¸€ä¸ªæ–‡ä»¶çš„内容æè¿°å¦‚下:

文件å用处
layers.el申明一些é¢å¤–çš„ layer ä¾èµ–
packages.el一些 layer 使用到的 package 以åŠç›¸å…³é…置函数
funcs.el定义一些 layer 层次的函数, å³å…¨å±€å‡½æ•°
config.ellayer çš„é…ç½®, 此处定义的é…ç½®å¯ä»¥åœ¨ .spacemacs 中申明 layer 时进行é…ç½®, 也å¯ä»¥å®šä¹‰ emacs 的默认é…ç½®
keybindings.elå¿«æ·é”®é…ç½®

现在我们å¯ä»¥æŠŠ youdao-dictionary 加入到 layer 中, 编辑 packages.el:

;; 添加 package
(defconst zilongshanren-packages
  '(youdao-dictionary)
  )

;; åˆå§‹åŒ– package
;; å¯ä»¥ä½¿ç”¨ , d m å¿«æ·é”®, ç„¶åŽæŒ‰ä¸‹ e 展开å®
(defun zilongshanren/init-youdao-dictionary ()
  (use-package youdao-dictionary
    :defer t
    :init
    (spacemacs/set-leader-keys "oy" 'youdao-dictionary-search-at-point+)
    )
  )

编辑 config.el 文件:

;; å¼€å¯è¡Œå·æ˜¾ç¤º
(global-linum-mode t)

;; 定义快æ·é”®
(global-set-key (kbd "M-s o") 'occur-dwim)

;; å°† occur çš„ buffer 中的光标移动方å¼ä¿®æ”¹ä¸º HJKL
(evilified-state-evilify-map occur-mode-map
  :mode occur-mode)

编辑 keybindings.el 文件:

;; dwin = do what i mean.
(defun occur-dwim ()
  "Call `occur' with a sane default."
  (interactive)
  (push (if (region-active-p)
            (buffer-substring-no-properties
             (region-beginning)
             (region-end))
          (let ((sym (thing-at-point 'symbol)))
            (when (stringp sym)
              (regexp-quote sym))))
        regexp-history)
  (call-interactively 'occur))

ç„¶åŽå°† zilongshanren 加到 dotspacemacs-configuration-layers å˜é‡ä¸­, å³å¯è®© layer é…置生效.

文档

spacemacs 的文档ä¿å­˜åœ¨ doc 目录下, åŒ…å«æœ‰ CONVENTIONS.org, DOCUMENTATION.org 等文档文件, 建议大家多多阅读.

第å三天: 定制你的 Layer

视频地å€å¦‚下:

主è¦å†…容:

  1. ä¿®å¤ä¸Šä¸€æœŸè§†é¢‘中 occur-mode å¯åŠ¨çš„é—®é¢˜
  2. ä¿®å¤ ivy0.8 导致的问题, åŒæ—¶ç®€å•探讨了一下今åŽå¦‚何é¿å…和处ç†ç±»ä¼¼çš„问题
  3. ä»‹ç» post-init å’Œ pre-init 的用法, 介ç»äº†å¦‚何定制 spacemacs çš„ company-mode
  4. ä»‹ç» layers.el 文件, 演示该文件的作用
  5. ä»‹ç» layer çš„ package çš„ location å˜é‡, 演示了如何从 github 获å–并安装 package 的方法

ä¿®å¤ä¸Šä¸€æœŸè§†é¢‘中的é…置问题

在之å‰çš„é…置代ç ä¸­, 如果我们å¯åЍ emacs 会出现以下错误:

Symbol's function definition is void: evilified-state-evilify-map

这是因为这个符å·åœ¨ config.el 中使用的时候还是空的, 我们å¯ä»¥é€šè¿‡ä»¥ä¸‹æ–¹å¼ä¿®å¤, 编辑 config.el 文件, 将以下代ç ç§»åŠ¨åˆ° dotspacemacs/user-config 函数中:

(evilified-state-evilify-map occur-mode-map
  :mode occur-mode)

ä¿®å¤ ivy0.8 的问题

在 ivy å‡çº§åˆ°0.8版本时, 对其中一个API的返回值进行了修改:

(let (res)
  (ivy-with
   '(ivy-read "test: "
              '(("one" . 1) ("three" . 3))
              :action (lambda (x) (setq res x)))
   "t C-m")
  res)
;; =>
;; ("three" . 3)

在之å‰çš„版本中, 这个函数的返回值是 3, 在0.8版本中被修改为了一个列表. 如果è¦ä¿®å¤è¿™ä¸ªé—®é¢˜, 我们需è¦åœ¨ä½¿ç”¨è¿”回值的时候加上 cdr, 具体的修改å¯ä»¥æŸ¥çœ‹fix break API changes for ivy 0.8.

post-init 和 pre-init

有一些 mode å·²ç»å®‰è£…, 例如 company-mode å·²ç»è¢« auto-completion layer 安装, 如果这时我们还想对该 mode 进行一些定制, 那么我们å¯ä»¥è¿™æ ·å¤„ç†:

  1. 在我们的 layer 中添加这个包
;; 添加 package
(defconst zilongshanren-packages
  '(youdao-dictionary
    company  ; 添加 company package
    )
  )
  1. ç„¶åŽå®šä¹‰ä¸€ä¸ª post-init 函数
;; 定制 company-mode
(defun zilongshanren/post-init-company ()
  (setq company-minimum-prefix-length 1)
  )

ç„¶åŽé‡å¯ emacs å³å¯ä»¥çœ‹åˆ°å®šåˆ¶çš„æ•ˆæžœ.

对于 package 的三个函数: pre-init, init, post-init, spacemacsæ˜¯æŒ‰ç…§è¿™ä¸ªé¡ºåºæ¥ä¾æ¬¡è°ƒç”¨çš„.

location

在安装 package æ—¶, 我们如果åªè¾“å…¥ package çš„åå­—, 那么默认是从 melpa 下载安装的. 如果我们想自定义 package 的安装地å€, 那么我们就å¯ä»¥ä½¿ç”¨ location å˜é‡.

自带 package

例如我们使用一个自带的 occur package:

;; 自定义 package 安装地å€
(defconst zilongshanren-packages
  '(youdao-dictionary
    (occur-mode :location built-in)
    )
  )

;; åˆå§‹åŒ– occur mode
(defun zilongshanren/init-occur-mode ()
  (evilified-state-evilify-map occur-mode-map
    :mode occur-mmode)
  )

从 github 安装

例如我们从 github 安装 gulpjs package:

;; 自定义 package 安装地å€
(defconst zilongshanren-packages
  '(youdao-dictionary
    (occur-mode :location built-in)
    (gulpjs :location (recipe :fetcher github :repo "zilongshanren/emacs-gulpjs"))
    )
  )

(defun zilongshanren/init-gulpjs ()
  (use-package gulpjs
    :init)
  )

在 emacs å¯åŠ¨æ—¶å°±ä¼šä»Ž github 上下载 guiljs package 并安装到本地.

layers.el

如果我们需è¦å¯¹æŸäº› layer 中的 package é…置进行大é‡çš„é‡å†™, 那么我们å¯ä»¥ç§»é™¤è¿™ä¸ª layer çš„æŸä¸ª package. 我们å¯ä»¥é€šè¿‡ layers.el æ¥å®žçŽ°è¿™ä¸€ç‚¹, 例如移除 chinese layer çš„ youdao-dictionary package:

(configuration-layer/remove-layer 'youdao-dictionary)

ç„¶åŽæˆ‘们å¯ä»¥åœ¨è‡ªå·±çš„ layer 中添加这个 package, ç„¶åŽå¯¹å®ƒè¿›è¡Œå®šåˆ¶. åœ¨è¿™ç§æƒ…况下, spacemacs ä¸ä¼šåœ¨ chinese layer 中加载 youdao-dictionary 这个 package, 而是在我们的 layer 中加载这个 package, 以实现对 spacemacs 内置的package 的定制.

第å四天: 文件和 Buffer æ“作

视频地å€å¦‚下:

主è¦å†…容:

  1. 我的é…置和 spacemacsé…置的一些ä¸åŒç‚¹
  2. 文件相关æ“作
  3. Buffer 相关æ“作
  4. Dired

ä¸åŒç‚¹

从今天的视频开始, 将使用 å­é¾™å±±äººçš„é…ç½® æ¥è®²è§£è§†é¢‘. 这份é…置对 spacemacs 的定制有两个ä¸åŒç‚¹:

  • 没有使用官方的 modeline, 而是采用自己定制的
  • 排除掉了大é‡çš„作者认为对他没有作用的 package, 因为这些 package 确实ä¸ç»å¸¸ä½¿ç”¨, å而å¯èƒ½å¯¼è‡´ä¸€äº› BUG 或者导致 spacemacs å¯åŠ¨æˆ–ä½¿ç”¨è¿‡ç¨‹ä¸­å˜æ…¢

文件相关æ“作

  1. SPC p f

    在当å‰çš„项目中查找文件, 类似于 vim 中的 Ctrl-p. 在作者的é…置中, 该快æ·é”®è¢«ç»‘定到了以下函数:

    (defun zilongshanren/open-file-with-projectile-or-counsel-git ()
      (interactive)
      (if (zilongshanren/vcs-project-root)
          (counsel-git)
        (if (projectile-project-p)
            (projectile-find-file)
          (ido-find-file))))
        

    该函数会针对ä¸åŒçš„项目类型使用ä¸åŒçš„æŸ¥æ‰¾æ–¹å¼:

    • 如果是 git 项目, 那么使用 counsel-git æ¥æŸ¥æ‰¾æ–‡ä»¶, ä¸ä½¿ç”¨ projectile 的原因是 counsel-git æ›´å¿«
    • 如果是 projectile 项目, å³åœ¨é¡¹ç›®çš„æ ¹ç›®å½•中存在 .projectile 文件, 那么使用 projectile-find-file æ¥æŸ¥æ‰¾æ–‡ä»¶
    • å¦åˆ™ä½¿ç”¨ ido-fine-file æ¥æŸ¥æ‰¾æ–‡ä»¶
  2. SPC f f

    从当å‰ç›®å½•开始查找文件. 在作者的é…ç½®ä¸­åŒæ—¶å¯ç”¨äº† ivy-layer å’Œ helm-layer, 默认使用的是 helm æ¥æŸ¥æ‰¾æ–‡ä»¶.

  3. SPC f L

    使用 helm-locate æ¥åœ¨å½“å‰ç³»ç»Ÿä¸­æŸ¥æ‰¾æ–‡ä»¶.

  4. SPC f l

    查找文件并使用 literal çš„æ–¹å¼æ¥æ‰“开文件, 使用 literal æ–¹å¼æ‰“开的文件ä¸ä¼šé™„加编ç ä¿¡æ¯, 例如 utf-8 ç¼–ç ä¸­å¯èƒ½å­˜åœ¨çš„ BOM 头信æ¯, 使用 literal 模å¼å³å¯ä»¥çœ‹åˆ° BOM头.

  5. SPC f h

    æŸ¥æ‰¾æ–‡ä»¶å¹¶ä½¿ç”¨äºŒè¿›åˆ¶çš„æ–¹å¼æ¥æ‰“开文件, å¯ä»¥ä½¿ç”¨ C-c C-c 回到之å‰çš„æ¨¡å¼.

  6. SPC f o

    ä½¿ç”¨å¤–éƒ¨ç¨‹åºæ‰“开文件.

  7. SPC f E

    使用 sudo æ¥ç¼–辑文件, 当æŸäº›æ–‡ä»¶æ˜¯åªè¯»çš„æ—¶å€™å¯ä»¥é‡‡ç”¨è¿™ç§æ–¹å¼æ¥ç¼–辑文件.

  8. SPC f D

    删除当å‰çš„æ–‡ä»¶å’Œ buffer.

  9. SPC f j

    以当剿–‡ä»¶çš„目录打开 dired buffer.

  10. SPC f r

    使用 ivy 打开最近文件列表.

  11. SPC f R

    é‡å‘½å当剿–‡ä»¶.

  12. SPC f v

    添加 local variables, å¯ä»¥é€šè¿‡è¿™ä¸ªåŠŸèƒ½ç»™é¡¹ç›®åšä¸€äº›ç‰¹æ®Šçš„设置. 例如按下 SPC f v, ç„¶åŽé€‰æ‹© add-dir-local-variable, 选择 org-mode, å†é€‰æ‹©org-highlight-links å˜é‡, 此时 emacs ä¼šåœ¨å½“å‰æ–‡ä»¶çš„目录下生æˆä¸€ä¸ª .dir-locals.el 文件, 内容如下:

    ;;; Directory Local Variables
    ;;; For more information see (info "(emacs) Directory Variables")
    
    ((org-mode
      (org-highlight-links)))
        

    这个文件中的代ç ä¼šåœ¨å½“å‰ç›®å½•下的所有文件 buffer 中生效.

  13. SPC f y

    æ‹·è´å½“剿–‡ä»¶çš„全路径.

  14. SPC f a d

    列出最近访问的目录, 使用命令行工具 fasd 实现.

  15. SPC f C d/u

    将当剿–‡ä»¶çš„ç¼–ç è½¬æ¢ä¸º DOS/UNIX ç¼–ç .

  16. SPC f e d

    打开 .spacemacs 或 .spacemacs.d/init.el 文件.

  17. SPC f e i

    打开 .emacs 或 .emacs.d/init.el 文件.

  18. SPC f e l

    打开系统中已ç»å®‰è£…çš„ el 文件.

  19. SPC f c

    å¤åˆ¶æ–‡ä»¶.

  20. SPC f b

    打开标签.

  21. SPC f s/S

    ä¿å­˜å½“å‰ buffer 或 所有 buffer.

buffer 相关æ“作

  1. SPC b .

    打开 Buffer Selection Transient State, 在该模å¼ä¸‹å¯ä»¥è¿›è¡Œæ›´å¤šçš„æ“ä½œ, ç”± hydra æä¾›.

  2. SPC b b

    切æ¢åˆ°å·²ç»æ‰“开的 buffer.

  3. SPC b d

    关闭一个 buffer.

  4. SPC b f

    在 finder ä¸­æ‰“å¼€å½“å‰æ–‡ä»¶, åªåœ¨ Mac系统下生效.

  5. SPC b B/i

    以类似 Dired Mode çš„å½¢å¼æ‰“å¼€ buffer 列表, 在这个列表中å¯ä»¥æ‰§è¡Œå’Œ Dired Mode 类似的æ“作.

  6. SPC b h

    进入 \*spacemacs\* buffer.

  7. SPC b k

    ä½¿ç”¨æ­£åˆ™è¡¨è¾¾å¼æ¥åˆ é™¤ buffer.

  8. SPC b N

    新建一个 buffer.

  9. SPC b m

    åˆ é™¤é™¤å½“å‰ buffer 外的所有 buffer.

  10. SPC b R

    使用 emacs 自动备份的文件æ¢å¤æ–‡ä»¶.

  11. SPC b s

    跳转到 scratch buffer.

  12. SPC b w

    关闭/打开 buffer 的 read-only.

  13. SPC b Y

    å¤åˆ¶æ•´ä¸ª buffer 的内容.

  14. SPC b P

    将剪切æ¿çš„内容粘贴到整个 buffer.

  15. SPC <tab>

    åœ¨å½“å‰ buffer 和上一个打开的 buffer 中进行切æ¢.

Dired

在第四天的内容中已ç»è®²è§£è¿‡ Dired Mode çš„æ“作, 具体å¯ä»¥æŸ¥çœ‹ Dired Mode.

第å五天: layout, windows å’Œ project 相关

视频地å€å¦‚下:

主è¦å†…容:

  1. Layout 相关æ“作
  2. Window 相关æ“作
  3. project 相关æ“作

Layout 相关æ“作

  1. SPC l L

    加载 layout 文件

  2. SPC l l

    在 layout 之间切æ¢

  3. SPC l s

    å°† layout ä¿å­˜åˆ°æ–‡ä»¶

  4. SPC l <tab>

    åœ¨å½“å‰ layout 和上一个 layout 之间切æ¢

  5. SPC l o

    é…ç½® layout

  6. SPC l R

    é‡å‘½å layout

  7. SPC l ?

    显示更多的与 layout 相关的命令

Window 相关æ“作

  1. SPC w -

    上下拆分窗å£

  2. SPC w /

    左峿‹†åˆ†çª—å£

  3. SPC w .

    显示更多的与 window micro state 的相关的命令

  4. SPC w 2/3

    左峿˜¾ç¤º 2/3 个窗å£

  5. SPC w =

    将窗å£å‡ç­‰åˆ†

  6. SPC w b

    切æ¢åˆ° minibuffer

  7. SPC w d

    删除当å‰çª—å£

  8. SPC w h/j/k/l

    å‘ å·¦/下/上/å³ ç§»åŠ¨çª—å£

  9. SPC w m

    最大化显示当å‰çª—å£

  10. SPC W H/J/K/L

    将当å‰çª—å£å‘ å·¦/下/上/å³ ç§»åŠ¨

  11. SPC w u/U

    å–æ¶ˆ/é‡ç½®ä¸Šæ¬¡æ“作

  12. SPC w o

    切æ¢åˆ°å…¶ä»– frame

  13. SPC w F

    创建一个新的 frame

  14. SPC w 1/2/3/4

    切æ¢åˆ°å¯¹åº”的编å·çš„窗å£

  15. SPC w w

    便¬¡åˆ‡æ¢åˆ°å…¶ä»–窗å£

  16. SPC w W

    ä½¿ç”¨å­—æ¯æ ‡è¯†éœ€è¦è·³è½¬çš„窗å£, 并按下字æ¯è¿›è¡Œè·³è½¬

  17. SPC t g

    将当剿˜¾ç¤ºçš„窗å£ä¸Žå…¶ä»–窗å£è¿›è¡Œé»„金分割显示

  18. SPC t -

    å¼€å¯/关闭 将光标始终显示在中心行

project 相关æ“作

  1. SPC p f

    åœ¨å½“å‰ project 中查找并打开文件

  2. SPC p b

    åœ¨å½“å‰ project 中查找打开的 buffer

  3. SPC p p

    切æ¢åˆ°å…¶ä»–çš„ project

  4. SPC p l

    切æ¢åˆ°å…¶ä»–çš„ project 并创建一个新的 layout

  5. find-file-in-project

    这是一个æ’ä»¶, 支æŒå…¨å¹³å°. ç›®å‰ç»‘定在 SUPER f å¿«æ·é”®ä¸Š.

更多内容

对 Spacemacs 中的快æ·é”®æ“作就介ç»åˆ°è¿™é‡Œ, 更多的快æ·é”®ä»‹ç»å¯ä»¥åˆ° Spacemacs ABC 去查看.

第å六天: 使用 ctags å’Œ company-etags

视频地å€å¦‚下:

主è¦å†…容:

这期视频主è¦ä»‹ç» ctags å’Œ company-mode 的使用.

为什么使用 ctags

ctags 是一个开æºçš„, å¯ä»¥æ–¹ä¾¿çš„对大型代ç åº“进行索引的软件, 在使用 ctags ç”Ÿæˆ tag 之åŽå°±å¯ä»¥éžå¸¸æ–¹ä¾¿çš„在这些 tag 中进行跳转. 因为有些编程语言, 例如 javascript 或者 lua, 它们ä¸èƒ½è¿›è¡Œç²¾ç¡®çš„语义补全, 在有 ctags 进行索引补全的情况下也å¯ä»¥æ–¹ä¾¿ç¼–写代ç .

在之å‰ä¹Ÿä»‹ç»è¿‡ term-mode, 也å¯ä»¥åšåˆ°ä¸€äº›è¯­ä¹‰è¡¥å…¨. 但是它也有一些缺点:

  1. é…置方å¼å¤æ‚, 对于比较大的项目的é…置比较有难度
  2. 有些时候ä¸èƒ½å¾—到想è¦çš„补全结果

之å‰ä½œè€…使用 YCMD æ¥å¯¹ C/C++ 代ç è¿›è¡Œè¡¥å…¨, 但是它ä¸å¤ªç¨³å®š, 现在已ç»åˆ‡æ¢ä¸º ctags æ¥è¿›è¡Œè¡¥å…¨, 对于调试和 profile 会使用 IDE 进行æ“作.

如何é…ç½® ctags

首先新建一个 testJs-ctags 目录, ç„¶åŽåœ¨è¯¥ç›®å½•下新建 a.js ä»¥åŠ b.js 两个文件:

mkdir testJs-ctags
cd testJs-ctags
touch a.js
touch b.js

ç„¶åŽç¼–辑 a.js 的内容如下:

var func1 = function () {
    console.log("func1");
};

var func2 = function () {
};

ç„¶åŽåœ¨ b.js 中的补全中å¯ä»¥æ˜¾ç¤ºå¤„ func1 å’Œ func2 的补全æç¤ºçš„. 为了更方便的讲解之åŽçš„内容, 我们å¯ä»¥æŸ¥çœ‹ä½¿ç”¨çš„补全的åŽç«¯: 输入 M-x, diminish-undo, 选择 company-mode, 这样在 modeline å°±å¯ä»¥çœ‹åˆ° company-mode 的具体信æ¯.

冿¬¡è¾“å…¥ fun 等待弹出补全æç¤º, 在补全选项中上下移动, å¯ä»¥çœ‹åˆ°ä½¿ç”¨çš„补全åŽç«¯åŒ…括 dabbrev-code å’Œ etags ç­‰, 如果我们关闭 a.js çš„ buffer, å°±ä¸ä¼šå‡ºçް func1 å’Œ func2 的补全选项.

在之å‰çš„æ“ä½œä¸­, æˆ‘ä»¬å¹¶æ²¡æœ‰ç”Ÿæˆ ctags, 为什么也能使用 ctags 补全呢? 我们å¯ä»¥ä½¿ç”¨ SPC h d v, ç„¶åŽè¾“出 tags-table-list æ¥æŸ¥çœ‹è¯¥å˜é‡çš„值, 当å‰çš„值是指å‘作者 cocos目录下的 TAGS 文件. ä½¿ç”¨ä»¥ä¸‹ä»£ç æ¸…空该值:

(setq-default tags-table-list nil)

ç„¶åŽå†æ¬¡å°è¯•补全, 这时就ä¸ä¼šä½¿ç”¨ ctags 补全了.

é‚£ä¹ˆå¦‚ä½•ç”Ÿæˆ ctags 补全的文件呢? 使用以下命令å³å¯:

cd testJs-ctags
ctags -e a.js
# 针对目录
# ctags -eR foldername

company-etags 在进行补全的时候, 会从å˜é‡ tags-table-list 值的文件列表中去查找 tags, 而且 tags 是ä¸åŒºåˆ†è¯­è¨€çš„.

å¦‚æžœéœ€è¦æ‰‹åŠ¨åŠ è½½ TAGS 文件, 那么å¯ä»¥è°ƒç”¨ visit-tags-table 命令. 而在打开一个文件时, ctags 会从文件所在的目录进行查找, 一直到根目录, 加载所找到的 TAGS 文件.

如何高效的使用 ctags

è‡ªåŠ¨é‡æ–°ç”Ÿæˆ TAGS 文件

在使用 ctags 的过程中, 如果文件的内容被改å˜, 那么需è¦é‡æ–°ç”Ÿæˆ TAGS 文件, 以便 ctags 的补全结果更精确. 作者实现了一个函数æ¥è‡ªåŠ¨åŠ è½½å¿…é¡»çš„ TAGS 文件:

(defun my-setup-develop-environment ()
  (interactive)
  (when (my-project-name-contains-substring "guanghui")
    (cond
     ((my-project-name-contains-substring "cocos2d-x")
      ;; C++ project don't need html tags
      (setq tags-table-list (list (my-create-tags-if-needed "~/cocos2d-x/cocos"))))
     ((my-project-name-contains-substring "Github/fireball")
      (message "load tags for fireball engine repo...")
      ;; html project donot need C++ tags
      (setq tags-table-list (list (my-create-tags-if-needed "~/Github/fireball/engine/cocos2d")))))))

有å¦å¤–一个工具函数, 当ä¿å­˜æ–‡ä»¶æ—¶ä¼šè‡ªåŠ¨çš„é‡æ–°ç”Ÿæˆ TAGS:

(defun my-auto-update-tags-when-save (prefix)
  (interactive "P")
  (cond
   ((not my-tags-updated-time)
    (setq my-tags-updated-time (current-time)))

   ((and (not prefix)
         (< (- (float-time (current-time)) (float-time my-tags-updated-time)) 300))
    ;; < 300 seconds
    (message "no need to update the tags")
    )
   (t
    (setq my-tags-updated-time (current-time))
    (my-update-tags)
    (message "updated tags after %d seconds." (- (float-time (current-time)) (float-time my-tags-updated-time))))))

å¯ä»¥å°† my-auto-udpate-tags-when-save 函数加入 after-save-hook 中, 或者绑定到快æ·é”®ä¸Š.

é…置规则æ¥ç”Ÿæˆæ›´å¤šçš„ TAGS

ctags 自身也有一个é…置文件, å¯ä»¥åœ¨è¯¥æ–‡ä»¶ä¸­å®šä¹‰è§„åˆ™æ¥æ›´å¥½çš„ç”Ÿæˆ TAGS, 一个é…置文件的示例如下:

--exclude=*.svn*
--exclude=*.git*
--exclude=*tmp*
--exclude=.#*
--tag-relative=yes
--recurse=yes

--langdef=js

--regex-js=/[ \t.]([A-Z][A-Z0-9._$]+)[ \t]*[=:][ \t]*([0-9"'\[\{]|null)/\1/n,constant/

--langdef=css
--langmap=css:.css
--regex-css=/^[ \t]*\.([A-Za-z0-9_-]+)/.\1/c,class,classes/

在é…置文件中å¯ä»¥ä½¿ç”¨ –exclude æ¥å¿½ç•¥æ–‡ä»¶æˆ–路径, 使用 –langdef æ¥å®šä¹‰å“ªäº›æ–‡ä»¶å±žäºŽ js 文件, 使用 –regex-js æ¥å®šä¹‰ TAGS ç”Ÿæˆæ—¶çš„匹é…规则. 这些匹é…规则中å¯ä»¥ä½¿ç”¨æ­£åˆ™è¡¨è¾¾å¼æ¥æå–å†…å®¹ç”Ÿæˆ TAGS.

使用 etags-select æ¥æµè§ˆé¡¹ç›®

在有 TAGS 之åŽ, å¯ä»¥ä½¿ç”¨ ctags æ¥æ–¹ä¾¿çš„æµè§ˆæ–‡ä»¶å†…å®¹. 例如在æŸä¸ªå‡½æ•°å上点击 [, g], ç„¶åŽé€‰æ‹© etags-select-find-tag-at-point, 这时会把所有相关的内容列出到 buffer 中, ç„¶åŽå¯ä»¥é€‰æ‹©æƒ³è¦è·³è½¬çš„ä½ç½®è·³è½¬è¿‡åŽ».

最åŽçš„æ€è€ƒ

company-etags ä¸èƒ½å¯¹æ‰€æœ‰çš„ mode 进行补全, 例如在 org-mode 中默认是ä¸ä½¿ç”¨ company-etags çš„. 因为在 company-etags.el 文件中有如下的代ç :

(defvar company-etags-modes '(prog-mode c-mode objc-mode c++-mode java-mode
                                        jde-mode pascal-mode perl-mode python-mode))

在该å˜é‡ä¸­å®šä¹‰äº†å¯ä»¥ä½¿ç”¨ company-etags çš„ mode, å°† org-mode 加入该å˜é‡çš„值中å³å¯åœ¨ org-mode 使用 company-etags 进行补全.

ctags 支æŒä¸Šç™¾ç§è¯­è¨€, 学会使用 ctags 能够æäº¤æ•ˆçއ.

About

Happy Hacking Emacs & Spacemacs (Simplified Chinese)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • CSS 75.9%
  • Emacs Lisp 12.5%
  • JavaScript 8.7%
  • Shell 1.2%
  • C++ 1.2%
  • CMake 0.5%
0