EMACS-DOCUMENT

=============>集思广益

对Emacs-modeline进行裁剪

为了美化mode-line,我做了很多实验.最开始的时候,我用过 smart-mode-line. 然后换成了 powerline. 但是觉得powerline太笨重了,因此换成了 spaceline. 最后我想:"为什么我不直接配置modeline呢,应该不会太难的!"

下面就是我配置的最终结果:

example.png

而最终的配置甚至比我的 powerline的配置 还要简洁明了的多.

Show line and column numbers in the mode-line

首先,我想要知道光标所在的列数,这一步很容易实现.

(column-number-mode 1)

Faces

我的“设计”的基色是蓝色:

  • buffer name,对我来说是最重要的内容,需要突出显示.
  • buffer所在的目录, 比buffer name的重要程度差点, 但是依然很重要,也需要突出显示,只不过不要像buffer name那么突出.
  • 使用box来突出显示光标指示的地方太难看了,我把它修改成用蓝色背景色来显示.
  • 最后,the inactive mode line 需要与背景融为一体.
(set-face-attribute 'mode-line           nil :background "light blue")
(set-face-attribute 'mode-line-buffer-id nil :background "blue" :foreground "white")
(defface mode-line-directory
  '((t :background "blue" :foreground "gray"))
  "Face used for buffer identification parts of the mode line."
  :group 'mode-line-faces
  :group 'basic-faces)
(set-face-attribute 'mode-line-highlight nil :box nil :background "deep sky blue")
(set-face-attribute 'mode-line-inactive  nil :inherit 'default)

Simplify the cursor position

我重新定义了一下 mode-line-position, 让它只显示光标所在的位置. 我根本不需要以百分比的方式来显示位置,也不需要显示像 “Bot”, “Top” , “All” 这样的文本. 当我还是Emacs新手的时候,这些东西时常把我搞迷糊了:-)

我这里保留了 mode-line-position 初始值中各元素的设置,如果需要的话可以取消对这些元素的注释即可. 而且我还为这些以 % 开头的转义字符做了说明.

(setq mode-line-position
      '(;; %p print percent of buffer above top of window, o Top, Bot or All
        ;; (-3 "%p")
        ;; %I print the size of the buffer, with kmG etc
        ;; (size-indication-mode ("/" (-4 "%I")))
        ;; " "
        ;; %l print the current line number
        ;; %c print the current column
        (line-number-mode ("%l" (column-number-mode ":%c")))))

Directory shortening

我希望能在buffer-id前面显示目录信息. 但我不希望显示完整的目录信息,因此需要进行一些精简(下面这个函数并不是我原创的,而是从网上找到的,不过我忘了具体在哪找到的了. 你可以试着在google上搜索一下 “defun shorten-directory”)

(defun shorten-directory (dir max-length)
  "Show up to `max-length' characters of a directory name `dir'."
  (let ((path (reverse (split-string (abbreviate-file-name dir) "/")))
        (output ""))
    (when (and path (equal "" (car path)))
      (setq path (cdr path)))
    (while (and path (< (length output) (- max-length 4)))
      (setq output (concat (car path) "/" output))
      (setq path (cdr path)))
    (when path
      (setq output (concat ".../" output)))
    output))

Directory name

这里存在的一个问题是,有些buffer,比如 *scratch* buffer,可能并没有相关联的文件(当然就更不可能有所属目录了), 这时 (buffer-file-name) 的返回值为 nil. 这种情况下,我就不能去尝试简化目录的显示.

不过不管是否显示目录,我们总是要在最开始的位置上显示一个空格用于将directory/buffer-id与其他的内容隔离开,这样显得好看点.

(defvar mode-line-directory
  '(:propertize
    (:eval (if (buffer-file-name) (concat " " (shorten-directory default-directory 20)) " "))
    face mode-line-directory)
  "Formats the current directory.")
(put 'mode-line-directory 'risky-local-variable t)

为了对称,我们在buffer-id后也加一个空格:

(setq-default mode-line-buffer-identification
              (propertized-buffer-identification "%b "))

Binding it together

最后组装出来的 mode-line-format 要比默认的设置更简单一些. 我将一些不需要的显示项都注释掉了.

(setq-default mode-line-format
              '("%e"
                mode-line-front-space
                ;; mode-line-mule-info -- I'm always on utf-8
                mode-line-client
                mode-line-modified
                ;; mode-line-remote -- no need to indicate this specially
                ;; mode-line-frame-identification -- this is for text-mode emacs only
                " "
                mode-line-directory
                mode-line-buffer-identification
                " "
                mode-line-position
                ;;(vc-mode vc-mode)  -- I use magit, not vc-mode
                (flycheck-mode flycheck-mode-line)
                " "
                mode-line-modes
                mode-line-misc-info
                mode-line-end-spaces))