You are on page 1of 3

用linum+智能显示行号 | Emacs中文网 http://emacser.com/linum-plus.

htm

稍微现代点的编辑器都有行号显示功能,行号显示是在buffer的左侧一栏显示当前buffer每行的行
号,比较直观,但其实在以鼠标为中心的编辑器、IDE中,其实这个行号显示功能不大,但是在以
纯键盘为中心的编辑器,如vi, Emacs中这个行号显示功能就非常方便了,它可以帮助你迅速定位
到某行,知道了行号,直接通过M-x goto-line到达某行,非常方便。

但是Emacs比较“土”,Emacs23之前一直没有内置的行号显示功能,但是“土”归“土”,但是它
很听话,你要怎样控制它就怎样控制它,所以诞生了一堆外置的行号显示插件,比如wb-line-
number, setnu, setnu-plus, display-line-number, 虽然很多,但是都有一些小bug,不是很方
便。Emacs23出来后,我欣喜的看到,它已经内置了行号显示功能,用的是linum-mode,既然是内
置的,当然性能比较好,bug也比较少。它每次只显示当前buffer可视区域内的行号,而且用了一
个小缓存的技巧,保证了性能,即使打开大文件也没问题。它的行号显示格式是通过linum-format
来控制的,该值为’dynamic的话,就会动态控制行号的宽度,比如当前buffer最大行是3位数,那
么行号的宽度就是3,这个format还可以设为固定的宽度,比如设置成”%4d”,那么始终显示成4
个字符宽度。一般的编辑器用的都是那个’dynamic, 动态控制行号显示的宽度。

但是这个动态显示宽度还不够智能,比如当前buffer最大行的行号是3位数,我显示前面几行行号
的时候,比如从1到50,没必要也用3个字符宽度来显示,只需要用2位就可以了,所以我写了一个
linum+,来弥补linum这个缺点,linum+主要是重新定义了下linum里面更新行号的函数linum-
update-window,代码如下:
?
View Code LISP

1 ;;;###autoload
2 (defun linum+-generate-linum-format (format-type limit)
3 "Generate line number format by FORMAT-TYPE, LIMIT is `window-end' of win."
4 (cond ((stringp format-type) format-type)
5 ((or (listp format-type) (vectorp format-type)
6 (eq format-type 'dynamic) (eq format-type 'smart))
7 (let* ((dynamic-width (or (vectorp format-type) (eq format-type 'smart)))
8 (old-format
9 (if (eq format-type 'dynamic)
10 linum+-dynamic-format
11 (if (eq format-type 'smart)
12 linum+-smart-format
13 format-type)))
14 (w (length
15 (number-to-string
16 (line-number-at-pos (if dynamic-width limit (point-max))))))
17 (new-format
18 (if (listp old-format)
19 (car old-format)
20 (if (vectorp old-format)
21 (aref old-format 0)
22 old-format))))
23 (format new-format w)))))
24
25 ;;;###autoload
26 (defun linum-update-window (win)
27 "Update line numbers for the portion visible in window WIN."
28 (goto-char (window-start win))
29 (let* ((line (line-number-at-pos))
30 (limit (window-end win t))
31 (fmt (linum+-generate-linum-format linum-format limit))
32 (width 0))
33 (run-hooks 'linum-before-numbering-hook)
34 ;; Create an overlay (or reuse an existing one) for each

1 of 3 2010/6/8 16:55
用linum+智能显示行号 | Emacs中文网 http://emacser.com/linum-plus.htm

35 ;; line visible in this window, if necessary.


36 (while (and (not (eobp)) (<= (point) limit))
37 (let* ((str (if fmt
38 (propertize (format fmt line) 'face 'linum)
39 (funcall linum-format line)))
40 (visited (catch 'visited
41 (dolist (o (overlays-in (point) (point)))
42 (when (equal-including-properties
43 (overlay-get o 'linum-str) str)
44 (unless (memq o linum-overlays)
45 (push o linum-overlays))
46 (setq linum-available (delq o linum-available))
47 (throw 'visited t))))))
48 (setq width (max width (length str)))
49 (unless visited
50 (let ((ov (if (null linum-available)
51 (make-overlay (point) (point))
52 (move-overlay (pop linum-available) (point) (point)))))
53 (push ov linum-overlays)
54 (overlay-put ov 'before-string
55 (propertize " " 'display `((margin left-margin) ,str)))
56 (overlay-put ov 'linum-str str))))
57 (forward-line)
58 (setq line (1+ line)))
59 (set-window-margins win width)))

其实这个linum-update-window改的很简单,主要是根据当前最大行号来制定一个宽度。
linum+.el全文件在这里下载。
因为只有行号从n位数过度到n+1位数的时候,行号宽度才会发生改变,这种机会并不多,所以我这
个linum+性能基本上和linum一样。

linum中, linum-format有可以有三种形式, string, ‘dynamic, 或者函数, 你使用了linum+以


后,增加了三种形式, 分别是’smart, 含有一个字符串的list, 和含有一个字符串的vector,
string和函数还和linum中的作用一样, ‘dynamic还是根据当前buffer最大行来控制最大的行号宽
度, ’smart则是智能根据当前可使范围内最大行号来控制行号显示宽度的, 如果是list的话, 则
是根据list中的字符串来和当前最大行号的宽度一起作为format函数的参数来生成当前行号的格
式,然后再用这个格式来显示行号,比如当前buffer显示的行数是从1到50,那么最大的行号是
50,其宽度是2,list的值为’(“%%%dd|”), 那么当前buffer每行行号的显示格式就是:
?
View Code LISP

1 (format "%%%dd|" 2)
2 =>"%2d|"

得到”%2d|”,然后当前buffer每行的行号显示格式就是”%2d|”了。
当linum-format为vector的时候, 处理过程基本和list的一样, 唯一的差别就是行号的格式的时
候, “%d”是用当前buffer最大行号的宽度去替换的, 比如当前最大行号是125, 其宽度是3, 那么
当前buffer每行行号的显示格式就是:
?
View Code LISP

1 (format "%%%dd|" 3)
2 =>"%2d|"

2 of 3 2010/6/8 16:55
用linum+智能显示行号 | Emacs中文网 http://emacser.com/linum-plus.htm

得到”%3d|”,然后当前buffer每行的行号显示格式就是”%2d|”了。
其实, linum+内部实现时, ‘dynamic和’(“%%%dd|”)作用一样, ’smart和["%%%dd|"]作用一
样. 你不喜欢’smart后面的”|”的话, 把linum-format设置为["%%%dd"]就可以了.
如果你喜欢linum中的’dynamic, 根据buffer最大的行号生成固定的宽度, 而不喜欢linum+
中’smart那样动态变化的宽度, 你仍然可以把linum-format配置成’dynamic, 或者配置成list,
比如’(“%%%dd”), 这样既可以享受固定的宽度, 又可以享受可配置的格式(linum中linum-
format为’dynamic, 行号的格式你是控制不了的)

下面是linum+的截图:

用linum+智能显示行号 用linum+智能显示行号

GD Star Rating
loading...

标签:autoload, Emacs, face, IDE, linum+, linum-plus, org, screenshot, 截图, 插件, 行
号, 鼠标

相关日志

3 of 3 2010/6/8 16:55

You might also like