论坛首页 综合技术论坛

Programming in Emacs Lisp笔记(十六).emacs文件

浏览 8267 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-07-20  

.emacs文件

Emacs的缺省配置

Emacs缺省配置的优点。Emacs在你编辑C文件时将启动C mod,编写Fortan源文件时启动Fortran mode,编写未知文件时使用Fundamental mod。这些都是自动检测的,不需要干预。

可以通过~/.emacs对Emacs进行定制。这是你个人的初始化文件;它的内容是Emacs Lisp代码。

全局初始化文件

除了个人初始化文件外,Emacs将自动加载全局初始化文件,这与.emacs文件一样,但它将被所有的用户加载。

有两个全局初始化文件site-load.el和site-init.el,在被加载到Emacs后被'dumped'(如果Emacs 'dumped'版本被创建,Dumped的Emacs复制版本加载更快)。但是,一旦文件被加载并被dumped,对文件的修改将不会影响Emacs除 非你re-dump Emacs(详情,请查找INSTALL文件)。

有3个全局文件在每次启动Emacs时被执行(如果他们存在)。site-start.el在.emacs文件执行前执行,default.el和终端类型文件,这两上在.emacs加载后执行。

.emacs中的设置将覆盖site-start.el中的设置。default.el或终端类型文件将覆盖.emacs文件。(可以通过设置term-file-prefix为nil来防止与终端类型文件冲突)

发行版本中的INSTALL文件描述了site-init.el和site-load.el文件。

loadup.el,startup.el,loaddefs.el文件控制加载的过程。这些文件在Emacs发行版本的lisp目录中,值得精读。

loaddefs.el包含了大量设置.emacs文件或全局初始化文件的建议。

使用defcustom设置变量

可以使用defcustom以使用使用Emacs的customize功能设置变量的值。(不可以将customize用于函数定义;但可以在.emacs中使用defuns)实际上,可以在.emacs中写任何的Lisp语句。

customize功能取决于defcustom。忙乎你可以使用defvar或setq来设置变量,但defcustom是被设计为做此项工作的。

你可以将defvar的知识运用到defcustom的3个参数中。第一个参数是变量名称。第二个参数如果存在则表示变量实始值,并且这个值只会在变量未设置值时设置。第三个参数是文档字符串。

第四个和后面的参数是为defcustom设置类型和选项的;这些是defvar所没有的功能。(这些参数是可选的)

这些参数的每个值由键值对组成。每个键以一个字母开头:

举例来说,用户自定义变量text-mode-hook如下:

(defcustom text-mode-hook nil
"Normal hook run when entering Text mode and many related modes."
:type 'hook
:options '(turn-on-auto-fill flyspell-mode)
:group 'data)
变量text-mode-hook;没有缺省值;并且它的文档字符串告诉你它起什么作用。

:type关键字告诉Emacs应该给text-mode-hook设置什么样的数据,在一个自定义缓冲区中如何显示它的值。

:options关键词,指定了一个备选值的列表。可以用于这个hook的:options。列表中的仅是建议值,并不是唯一备选值;人们可以设置为其它的任意值;:options关键字给用户提出了最合适的建议。

最后是:group关键字,它告诉Emacs的自定义命令将这个变量分到哪个组,以便于查找这个变量。

以text-mode-hook为例。

有两种方式来定制这个变量。你可以使用自定义变量的命令或者编写适当的语句。

使用自定义变量命令,可以输入:

M-x customize
找到对就的分组'data'。进入这个分组。TextMode Hook是第一个成员。你可以点击它的选项来设置它的值。最后点击下面的按钮
Save for Future Sessions
Emacs将会向.emacs文件中写入下面的语句:
(custom-set-variables
;; custom-set-variables was added by Custom --
;; don't edit or cut/paste it!
;; Your init file should contain only one such instance.
'(text-mode-hook (quote (turn-on-auto-fill text-mode-hook-identify))))
(text-mode-hook-identify函数告诉toggle-text-mode-auto-fill哪个缓冲区处于Text mode。)

你可以不用管警告信息来修改这些语句。警告的目的是为了恐吓那些不明白自己在做什么的人。

custom-set-variables的工作与setq不同。我从不去了解这些不同,我不手工修改.emacs中的custom-set-variables语句。

另一个custom-set-...函数是custom-set-faces。这个函数设置字体外观。

第二种定制text-mode-hook的方法是在.emacs中编写代码,与custom-set-...函数无关。

开始编写一个.emacs文件

启动Emacs时,将加载你的.emacs文件,除非你在命令行使用了-q命令(emacs -q)。

.emacs文件包含了Lisp语句。通常是设值语句,有时有函数定义。

这章将以作者的.emacs文件为例。

文件的第一个部分是注释:

;;;; Bob's .emacs file
;; Robert J. Chassell
;; 26 September 1985
看看时间,在很久以前加的。
;; Each section in this file is introduced by a
;; line beginning with four semicolons; and each
;; entry is introduced by a line beginning with
;; three semicolons.
这段描述是Emacs Lisp的习惯性注释方式。分号后面是注释。两个、三个或四个分号用于区分章节。
;;;; The Help Key
;; Control-h is the help key;
;; after typing control-h, type a letter to
;; indicate the subject about which you want help.
;; For an explanation of the help facility,
;; type control-h two times in a row.
记住:输入C-h两次显示帮助。
;; To find out about any mode, type control-h m
;; while in that mode. For example, to find out
;; about mail mode, enter mail mode and then type
;; control-h m.
'Mode help'非常有用,它告诉你所有你需要知道的。

当然你不需要在你的.emacs文件包含这些。我添加这些只是为了记住Model help或者注释约定。

Text 和 Auto Fill Mode

接下来到'tuns on' Text mode和Auto Fill mode。

;;; Text mode and Auto Fill mode
;; The next three lines put Emacs into Text mode
;; and Auto Fill mode, and are for writers who
;; want to start writing prose rather than code.

(setq default-major-mode 'text-mode)
(add-hook 'text-mode-hook 'text-mode-hook-identify)
(add-hook 'text-mode-hook 'turn-on-auto-fill)

前面两行告诉Emacs在打开文件时,如果找不到对应的mode就打开Text mode。

当Emacs读取一个文件时,它查找文件的扩展名,如果有,如果以.c或.h结尾,Emacs开启C mode。Emacs也会检查文件的第一个非空白行;如果行上有-*- C -*-,Emacs也会开启C mode。Emacs处理了一个扩展名列表。In addition, Emacs looks near the last page for a per-buffer, "local variables list",if any.

现在,回到.emacs文件。

又出现了这行;它是如何工作的?

(setq default-major-mode 'text-mode)
这行是一个完整的Emacs Lisp语句。

它使用了我们早已经熟悉的setq。它设置变量default-major-mode为text-mode。单引号告诉Emacs把text-mode直接作为变量。

接下来的两行是:

(add-hook 'text-mode-hook 'text-mode-hook-identify)
(add-hook 'text-mode-hook 'turn-on-auto-fill)
这两行中,add-hook首先添加了text-mode-hook-identify到变量text-mode-hook中,然后添加了turn-on-auto-fill到这个变量中。

turn-on-auto-fill是程序名称,它开启Auto Fill mode。text-mode-hook-identify是一个函数,它告诉toggle-text-mode-auto-fill哪个缓冲区处于Text mode。

每次Emacs进入Text mode,Emacs将会执行'hooked'命令。因此,每次Emacs开启Text mode时,Emacs也将开启Auto Fill mode。

简单来说,第一行让Emacs在编辑文件时自动进入Text mode,除非文件扩展名或第一个非空行或局部变量能告诉Emacs该进入哪种mode。

Text mode中有其它动作,设置语法表以便于编写。在Text mode中,Emacs像处理信件一样把省略号当作单词的一部分;但Emacs不会把逗号或空白当作单词的一部分。因此M-f将移过it's。另一方面, 在C mode中,M-f将在it's中t的后面停止。

第二和第三行将使Emacs在进入Text mode时开启Auto Fill mode。在Auto Fill mode中,Emacs自动换行,并将过长的部分移到下一行。Emacs会在单词之间换行,而不会把单词截断。

当Auto Fill mode关闭时,文件中的行将与输入时保持一致。取决于trucate-lines变量的值,你输入的单词有可能消失在屏幕的右边,也有可以显示以非常乱的方式显示,也有可能显示为一个非常长的行。

另外,在我的.emacs文件的这一部分,我告诉Emacs在分号后添加两个空格:

(setq colon-double-space t)

邮件别名

这里使用setq开启邮件别名,也有一些用于提醒的注释。

;;; Mail mode
;; To enter mail mode, type `C-x m'
;; To enter RMAIL (for reading mail),
;; type `M-x rmail'

(setq mail-aliases t)
setq命令设置变量mail-aliases为t。因为t表示true,这行就是在说"Yes,use mail aliases."

邮件别名是一种email地址的缩写。别名保存在~/.mailrc中。你可以这样书写:

alias geo george@foobar.wiz.edu
当你给George发邮件时,地址可以输入geo;邮件发送者将自动将geo展开为完整的邮箱地址。

Indent Tabs Mode

缺省情况下,Emacs在格式化一个区域时会在需要空白的位置插入tab。(比如在需要缩进时)。Tab在使用终端或普通打印机时看起来很正常,但如果是在TeX或Texinfo中就会不正常。因为TeX将忽略tab。

下面的代码关闭Tabs mode:

;;; Prevent Extraneous Tabs
(setq-default indent-tabs-mode nil)
注意,这里使用了setq-default而不是使用setq。setq-default命令只会在局部变量没有值时设置这个变量的值。

一些按键绑定

下面是一些个性化的按键绑定:

;;; Compare windows
(global-set-key "\C-cw" 'compare-windows)
compare-window将比较当前窗口中的文本和下一个窗口中的文本。

这里也显示了如何设置一个全局按键绑定,它在任何mode下都有效。

命令global-set-key后面跟按键绑定。在.emacs文件中,按键绑定被书写为:\C-c表示'control-c',表示'按住control键的同时按c键'。w表示'按w键'。按键设置用双引号包含。在编写文档的时候,你可以写成C-c w。(如果绑定的键是键,比如M-c则书写为\M-c

这个按键组成将调用compare-windows命令。注意,compare-windows前面有一个单引号;如果不加Emacs将对它求值。

三件事:双引号,C前面的反余线和单引号。

这里还有另一个按键绑定:

;;; Keybinding for `occur'
;; I use occur a lot, so let's bind it to a key:
(global-set-key "\C-co" 'occur)
occur命令显示当前缓冲区中匹配某个正则表达式的所有行。匹配的行被显示在*Occur*缓冲区中。

下面演示了如何取消一个按键绑定:

;;; Unbind `C-x f'
(global-unset-key "\C-xf")
取消这个绑定的原因是:我经常在需要输入C-x C-f时输入了C-x f。

下面的语句重新设置了一个已经存在的绑定:

;;; Rebind `C-x C-b' for `buffer-menu'
(global-set-key "\C-x\C-b" 'buffer-menu)
缺省情况下C-x C-b执行list-buffer命令。这个命令在另一个window中列出缓冲区。因为我几乎一直都需要在那个窗口中做一些操作,我比较喜欢buffer-menu命令,它不只是列出缓冲区,也会将point移到那个窗口中。

Keymaps

Emacs使用keymaps记录按键与命令的对应关系。当使用global-set-key设置按键绑定时,就是在current-global-map中指定了一个按键绑定。

特殊的模式下,比如C mode或Text mode,有他们自己的按键绑定;它将覆盖全局keymap。

global-set-key函数用于绑定或重新绑定全局keymap。比如,下面的代码将C-x C-b绑定到buffer-menu函数:

(global-set-key "\C-x\C-b" 'buffer-menu)

特殊模式下的keymap用defin-key设置,它接收一个指定的keymap作为参数,还有按键组合和命令。比如,我的.emacs文件包含下面的语句绑定textinfo-insert-@group命令到C-c C-c g:

(define-key texinfo-mode-map "\C-c\C-cg" 'texinfo-insert-@group)
text-info-insert-@group函数是一个Texinfo mode下的扩展,它用于在Texinfo文件中插入@group标记。我可以用三次按键C-c C-c g来输入,而不需要按六个键@ g r o u p。(@group与@end匹配,group命令用于保持它所包含的文本被放在同一页上)

下面是texinfo-insert-@group函数的定义:

(defun texinfo-insert-@group ()
"Insert the string @group in a Texinfo buffer."
(interactive)
(beginning-of-line)
(insert "@group\n"))
(当然,我也可以用Abbrev来完成类似工作,而不需要编写一个函数来插入单词;但是我更喜欢与Texinfo mode的其它按键保持一致。)

在loaddefs.el中你可以在各种mode中看到无数多的define-key语句,比如cc-mode.el和lisp-mode.el中。

加载文件

很多GNU Emacs社区的人们都自己编写Emacs的扩展。随着时间的推移,这些扩展通常都会出现新的版本。比如,Calendar和Diary包现在已经变成了GNU Emacs标准发行包中的一部分了。

可以使用load命令来执行整个文件,而将文件中的函数和变量设置安装到Emacs中。比如:

(load "~/emacs/slowsplit")

它个语句执行,或者说加载了slowsplit.el这个文件(如果文件存在),或者加载编译过的slowsplit.elc文件。这个文件包含了split-window-quietly函数,它是John Robinson于1989年编写的。

split-window-quietly函数在分隔窗口时,只使用了少量的重绘。我在1989年安装了它因为它与当时我使用的慢速的1200 baud终端工作得很好。现在很少遇到这种慢速连接了,但我仍然使用这个函数,因为我喜欢这种方式:缓冲区的下半部分在下面的新窗口中,而缓冲区的上半部 分在上面的窗口中。

为了替换split-window-vertically的缺省按键绑定,你需要先取消split-window-quietly的按键绑定,如下:

(global-unset-key "\C-x2")
(global-set-key "\C-x2" 'split-window-quietly)

如果要加载很多扩展,你需要指定扩展文件所在的位置,需要将扩展所在目录添加到Emacs的load-path中。在Emacs加载文件时,它将搜索这个目录列表中的目录。(缺省的列表在Emacs构建时在paths.h中指定。)

下面的命令将你的~/emacs目录添加到load-path中:

;;; Emacs Load Path
(setq load-path (cons "~/emacs" load-path))

load-library是一个交互式的load函数。完整的函数如下:

(defun load-library (library)
"Load the library named LIBRARY.
This is an interface to the function `
load'."
(interactive "sLoad library: ")
(load library))
load-library函数的名称来自于将'file'称为'library'。load-library命令在files.el中。

另一个交互式命令load-file完成的工作有些许不同。

自动加载

与通过加载文件的方式或者执行函数定义等方式加载函数不同,可以使用函数在被调用时自动加载。这被称作自动加载(autoloading)。

当执行自动加载函数时,Emacs自动执行文件中包含定义然后调用这个函数。

使用自动加载可以使Emacs启动得更快一些,因为库没有被立即加载;但是在第一次执行函数时,在加载对应的文件时需要稍等一下。

那些使用得较少的函数通常使用自动加载。loaddefs.el库包含了数百个自动加载函数,从bookmark-set到wordstar-mode。当然,如果有可能经常需要使用一些'罕见'的函数,可以在.emacs文件中使用load语句加载它。

autoload是一个内置函数可以传递5个参数,最后三个是可选的。第一个参数是需要自动加载的函数名称;第二个参数是要加载的文件名。第三个参 数是函数的文档,第四个用于说明这个函数是否可以以交互的方式运行。第五个参数说明对象的类型——autoload可以处理按键或者宏或者函数(缺省是函 数)。

下面是一个典型的例子:

(autoload 'html-helper-mode
"html-helper-mode" "Edit HTML documents" t)
(html-helper-mode是html-mode的另一选择,它是标准发行版的一部分)

自动加载html-helper-mode函数。它将从html-helper-mode.el(或从编译过的html-helper- mode.elc)加载。这个文件必须位于load-path指定的目录列表中。文档字符串说明这个mode是用于编辑html文件的。你可以以交互的方 式输入M-x html-helper-mode来执行。(你需要在这里提供文档字符串,虽然函数定义中有,但在这里函数还没有加载,它的文档字符串还不可用)

一个简单的扩展:line-to-top-of-window

这里是一个简单的Emacs扩展它将point移到窗口的顶部。

你可以将下面的代码放到独立的文件中,然后在.emacs文件中加载,或者你可以在.emacs文件中直接包含这些代码。

定义如下:

;;; Line to top of window;
;;; replace three keystroke sequence C-u 0 C-l
(defun line-to-top-of-window ()
"Move the line point is on to top of window."
(interactive)
(recenter 0))

现在设置按键绑定。

现在,功能键和鼠标按键事件和非ASCII字符写在方括号中,不需要使用引号。(在Emacs 18或以前的版本中,你需要为不同的终端编写不同的功能键绑定)

我们将line-to-top-of-window绑定到<f6>功能键上。</f6>

(global-set-key [f6] 'line-to-top-of-window)

如果你运行有两个版本的GNU Emacs,比如20和21,并使用同一个.emacs文件,你可以使用下面的方法选择执行不同的代码:

(cond
((string-equal (number-to-string 20) (substring (emacs-version) 10 12))
;; evaluate version 20 code
( ... ))
((string-equal (number-to-string 21) (substring (emacs-version) 10 12))
;; evaluate version 21 code
( ... )))
比如,在21版中光标缺省是闪烁的。我不喜欢这种效果。
(if (string-equal "21" (substring (emacs-version) 10 12))
(progn
(blink-cursor-mode 0)
;; Insert newline when you press `C-n' (next-line)
;; at the end of the buffer
(setq next-line-add-newlines t)
;; Turn on image viewing
(auto-image-file-mode t)
;; Turn on menu bar (this bar has text)
;; (Use numeric argument to turn on)
(menu-bar-mode 1)
;; Turn off tool bar (this bar has icons)
;; (Use numeric argument to turn on)
(tool-bar-mode nil)
;; Turn off tooltip mode for tool bar
;; (This mode causes icon explanations to pop up)
;; (Use numeric argument to turn on)
(tooltip-mode nil)
;; If tooltips turned on, make tips appear promptly
(setq tooltip-delay 0.1) ; default is one second
))
(注意这里没有使用(number-to-string 21),没有使用函数将整数转化为字符串。短的表达式比长的更好,但(number-to-string 21)更通用。然而如果你不知道前面返回值的类型时,就需要使用number-to-string函数了。)

X11颜色

在MIT X Windowing系统上使用Emacs时可以指定颜色。

我不喜欢缺省的颜色而指定了自己的颜色。

.emacs中的这些语句指定了这些值:

;; Set cursor color
(set-cursor-color "white")

;; Set mouse color
(set-mouse-color "white")

;; Set foreground and background
(set-foreground-color "white")
(set-background-color "darkblue")

;;; Set highlighting colors for isearch and drag
(set-face-foreground 'highlight "white")
(set-face-background 'highlight "blue")

(set-face-foreground 'region "cyan")
(set-face-background 'region "blue")

(set-face-foreground 'secondary-selection "skyblue")
(set-face-background 'secondary-selection "darkblue")

;; Set calendar highlighting colors
(setq calendar-load-hook
'(lambda ()
(set-face-foreground 'diary-face "skyblue")
(set-face-background 'holiday-face "slate blue")
(set-face-foreground 'holiday-face "white")))

不同色调的蓝色防止人感觉屏幕的闪烁。

另一种选择是在X初始化文件中指定彩色。比如,可以在~/.Xresources文件中设置前景色、背景色、光标和指针颜色等:

Emacs*foreground:   white
Emacs*background: darkblue
Emacs*cursorColor: white
Emacs*pointerColor: white

这并不是Emacs的一部分,还可以在~/.xinitrc文件中指定X window根窗口的颜色:

# I use TWM for window manager.
xsetroot -solid Navy -fg white &

.emacs中的杂项设置

一些杂项设置:

  • 设置鼠标光标的颜色和外观:
;; Cursor shapes are defined in
;; `/usr/include/X11/cursorfont.h';
;; for example, the `target' cursor is number 128;
;; the `top_left_arrow' cursor is number 132.

(let ((mpointer (x-get-resource "*mpointer"
"*emacs*mpointer")))
;; If you have not set your mouse pointer
;; then set it, otherwise leave as is:
(if (eq mpointer nil)
(setq mpointer "132")) ; top_left_arrow
(setq x-pointer-shape (string-to-int mpointer))
(set-mouse-color "white"))

状态栏(Modified Mode Line)

当我在网络中工作时,会忘记使用的是哪台机器。也有可能忘记point位于什么位置。

因此我重置了mode line:

-:-- foo.texi   rattlesnake:/home/bob/  Line 1  (Texinfo Fill) Top
表示访问的文件名为foo.texi,在rattlesnake这台机器的/home/bob缓冲区中。位于第一行,处于Texinfo mode,位于缓冲区的顶部。

.emacs文件中有如下的部分:

;; Set a Mode Line that tells me which machine, which directory,
;; and which line I am on, plus the other customary information.
(setq default-mode-line-format
(quote
(#("-" 0 1
(help-echo
"mouse-1: select window, mouse-2: delete others ..."))
mode-line-mule-info
mode-line-modified
mode-line-frame-identification
" "
mode-line-buffer-identification
" "
(:eval (substring
(system-name) 0 (string-match "\\..+" (system-name))))
":"
default-directory
#(" " 0 1
(help-echo
"mouse-1: select window, mouse-2: delete others ..."))
(line-number-mode " Line %l ")
global-mode-string
#(" %[(" 0 6
(help-echo
"mouse-1: select window, mouse-2: delete others ..."))
(:eval (mode-line-mode-name))
mode-line-process
minor-mode-alist
#("%n" 0 2 (help-echo "mouse-2: widen" local-map (keymap ...)))
")%] "
(-3 . "%P")
;; "-%-"
)))

这里重定义了缺省的mode line。多数设置来自于原始值;但作了一些修改。设置了default mode line format以便支持多种mode,比如Info。

列表中的很多元素是自描述的:mode-line-modified是一个变量,它说明了缓冲区是否被修改了,mode-name说明mode的名称,等等。format看起来复杂一些,因为它使用了两个我们没有讨论过的功能。

mode line字符串的第一行是一个短线-。在原来,它只能是一个简单的"-"。但现在,Emacs允许给字符串添加属性,比如高亮,或者像这里一样,是一个帮 助功能。如果你将鼠标光标放在短线上,一些帮助信息将会显示出来。(缺省情况下,你需要等1秒。你也可以通过修改tooltip-delay变量来修改这 个时间。)

新的字符串有一个特定的格式:

#("-" 0 1 (help-echo "mouse-1: select window, ..."))
#(开头的list。第一个元素是字符串本身,只有一个"-"。第二个和第三个元素指定第四个元素的应用范围。范围从一个字符 后面开始,0表示从第一个字符之前开始;1表示范围在第一个字符后面结束。第三个元素是范围的属性。它包含了一个属性列表,属性名help-echo,后 面跟了一个属性值,是一个字符串。第二、三和四个元素可以重复出现。

mode-line-buffer-identification显示当前缓冲区名称。它是以(#("%12b" 0 4 .... 开头的list。

"%12b"显示缓冲区的名称,使用buffer-name函数;'12'设置了最大显示的字符数量。当名称的长度小于这个长度时会将空白添加到字符串中。(缓冲区名称通常大于12个字符,这个长度在典型的80列的窗口中工作得很好)

:eval是GNU Emacs 21中的新功能。它执行后面的语句交把结果作为字符串显示。在这里,这个语句显示完整的系统名称的第一个部分。第一个部分的结束位置是一个'.',因此使 用了string-match函数计算第一个部分的长度。substring取从0到那个位置的字符串。

语句如下:

(:eval (substring
(system-name) 0 (string-match "\\..+" (system-name))))

%[和%]这对括号显示每个递归编辑的层次。%n表示'Narrow'(在narrowed时)。%P表示窗口底部上缓冲区的百分比,或者'Top'或'Bottom'或'All'。(小写的p表示离窗口顶部上的百分比。)%-插入用于填充的连字符。

如果想要在启动时不加载~/.emacs,可以使用:

emacs -q
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics