您的位置:首页 > 其它

emacs入门技巧:常用定制函数

2007-03-04 16:52 387 查看
用Emacs的乐趣之一就是亲眼看到自己的编辑效率随使用时间的累积而增长。而且有了elisp的帮助,可以将其它编辑器的优秀功能”拷贝”过来,大有海纳百川的壮阔感觉。Babar K. Zafar的网页上有篇汇集Emacs技巧的文章。非常有用。我尤其喜欢里面实现常用VI功能的函数:这样我就不用丢掉以前用惯的编辑功能了。什么时候Elicpse也支持自己的脚本语言就好了。让我们轻易地读取和操纵Eclipse Runtime以及Java AST,不用为了在console里加上文件链接都要创建N个类。Wiki的创造人Ward Cunningham正在做这项工作。但愿他快点搞定。

下面解释一下自己常用的几则技巧。原文还有更多技巧,强烈推荐。

先说说怎么试用这些技巧。Emacs根本就是elisp的解释环境,碰巧实现了编辑器而已。所以和elisp的函数勾兑再容易不过。假设我们打开一个Emacs的缓冲:




现在c-x 2, 增加新的缓冲




接着c-x o, 把光标切换到新增的缓冲里:




再切换到*scratch*缓冲就行了。Emacs提供的*scratch*缓冲的缺省模式是elisp-mode,正适合我们做elisp的编辑和试验。输入命令c-x b, 再敲入scratch, 回车,就成了:




在*scratch*缓冲里输入代码后,m-x eval-buffer, 输入的代码就被装载运行。

下面是Babar提供的技巧:

加强搜索
Emacs下c-s对应渐进搜索。不过我们更多的时候需要搜索某种模式,所以用得最多的还是渐进式的正则表达式搜索。正则表达式搜索有个烦人的问题:搜索结束时光标不一定停留在匹配字串的开端。幸好这个问题容易解决:
(local-set-key [(control s)] 'isearch-forward-regexp)
(local-set-key [(control r)] 'isearch-backward-regexp)

;; Always end searches at the beginning of the matching expression.
(add-hook 'isearch-mode-end-hook 'custom-goto-match-beginning)
(defun custom-goto-match-beginning ()
"Use with isearch hook to end search at first char of match."
(when isearch-forward (goto-char isearch-other-end)))

头两行重新绑定标准搜索键c-s和c-r,把isearch换成regex-isearch。后面三行加入定制函数。关键的语句是(goto-char isearch-other-end),保证光标停留在匹配字串的开头,而不是缺省的末尾。

自动完成
Emacs的hippie-expansion非常强大,可以帮我们自动完成很多重复输入。我用惯了Eclipse和Vim,所以把自动完成CTRL-Space绑定到自动完成,而把CTRL-ENTER绑定到CTRL-space缺省对应的set-mark了:
(global-set-key [(control space)] 'hippie-expand)
(global-set-key [(control return)] 'set-mark-command)

(require 'hippie-exp)
(setq hippie-expand-try-functions-list
         '(try-expand-dabbrev
               try-expand-dabbrev-all-buffers
               try-expand-dabbrev-from-kill
               try-complete-file-name-partially
               try-complete-file-name
               try-complete-lisp-symbol-partially
               try-complete-lisp-symbol
               try-expand-whole-kill))


括号自动完成
用Emacs的大部分时间都在编程。编程是少有遇到不配对的括号。既然如此,干嘛不让Emacs帮我们配对呢?下面的语句自动完成(, [, {, 和<。
(setq skeleton-pair t)
(local-set-key (kbd "[") 'skeleton-pair-insert-maybe)
(local-set-key (kbd "(") 'skeleton-pair-insert-maybe)
(local-set-key (kbd "{") 'skeleton-pair-insert-maybe)
(local-set-key (kbd "<") 'skeleton-pair-insert-maybe)


移动整行
这个功能是从苹果机里非常流行的编辑器TextMate学来的。在TextMate里,ALT-up会把光标所在的整行文字上移一行,而ALT-down会把光标所在的整行文字下移一行。这在调整语句顺序时非常有用。有了这个功能,我们可以和烦琐的“选中全行―》剪切 -》移动鼠标-》换行-》粘贴”告别了。
(local-set-key [(meta up)] 'move-line-up)
(local-set-key [(meta down)] 'move-line-down)
(defun move-line (&optional n)
 "Move current line N (1) lines up/down leaving point in place."
 (interactive "p")
 (when (null n)
    (setq n 1))
 (let ((col (current-column)))
    (beginning-of-line)
    (next-line 1)
    (transpose-lines n)
    (previous-line 1)
    (forward-char col)))
(defun move-line-up (n)
 "Moves current line N (1) lines up leaving point in place."
 (interactive "p")
 (move-line (if (null n) -1 (- n))))

(defun move-line-down (n)
 "Moves current line N (1) lines down leaving point in place."
 (interactive "p")
 (move-line (if (null n) 1 n)))


换行对齐
这个看似简单功能太有用了!!!不知道省了多少无谓的光标移动。很多时候,我们修改了一行语句后,想立刻跳到下一行,并且光标自动移到正确缩进的位置。在普通的编辑器里,换行前光标得移动到行尾,然后我们再敲下ENTER。Vi里CTRL-o解决了这个问题,让我们在一行的任何地方换到下一行,自动缩进,而不用担心把上一行分成两半。而Emacs有了下面的配置,也就支持CTRL-o了。够强大吧?

(local-set-key [(control o)] 'vi-open-next-line)

(defun vi-open-next-line (arg)
 "Move to the next line (like vi) and then opens a line."
 (interactive "p")
 (end-of-line)
 (open-line arg)
 (next-line 1)
 (indent-according-to-mode))

括号匹配
也是从Vi来的酷功能。当光标在括号上是,输入%光标自动跳到匹配的另一个括号上。
(local-set-key "%" 'match-paren)
(defun match-paren (arg)
 "Go to the matching parenthesis if on parenthesis otherwise insert %."
 (interactive "p")
 (cond ((looking-at "//s/(") (forward-list 1) (backward-char 1))
        ((looking-at "//s/)") (forward-char 1) (backward-list 1))
        (t (self-insert-command (or arg 1)))))

拷贝当前行
很多时候我们想把光标所在的整行语句放到kill-ring(Windows下的剪贴板)里。但选取整行,CTRL-W还是太烦琐。SlickEdit里,如果没有任何区域被选中,COPY命令会自动拷贝光标所在的整行,CUT则剪取光标所在地整行。Emacs下可以这么做:
(defadvice kill-ring-save (before slickcopy activate compile)
"When called interactively with no active region, copy a single line instead."
(interactive
(if mark-active (list (region-beginning) (region-end))
(list (line-beginning-position)
(line-beginning-position 2)))))

(defadvice kill-region (before slickcut activate compile)
"When called interactively with no active region, kill a single line instead."
(interactive
(if mark-active (list (region-beginning) (region-end))
(list (line-beginning-position)
(line-beginning-position 2)))))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: