EMACS-DOCUMENT

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

momentary-string-display

前段时间 我写过一篇文章,是关于如何在不修改buffer的情况让Emacs显示出新内容的方法. 当时我是通过text properties来做到这一点的,然后我还提到了,其实借助于overlays,我们也能实现这一功能.

结果我发现,Emacs针对这种情况已经内置了一个函数:momentary-string-display(而且它的内部就是使用overlay来实现的). 该函数接受一个字符串以及要在buffer中显示的位置,它就会在指定位置显示出这个字符串了,直到你按一下键盘或点一下鼠标. 不过 momentary-string-display 有一点让我不爽的就是,你必须选择一个 退出字符,(通常是空格或者回车), 按下这个字符也会让临时显示的字符串消失,但是该字符本身不会被插入(相对的按下其他字符则会插入). 我试过将该参数设置为 nil ,然而并没有什么卵用,这种情况下, momentary-string-display 默认实用空格作为 退出字符. 怎么说呢,毕竟人生总是不完满的.

不过也说不定. 下面是 momentary-string-display 的源代码.

(defun momentary-string-display (string pos &optional exit-char message)
  "Momentarily display STRING in the buffer at POS.
Display remains until next event is input.
If POS is a marker, only its position is used; its buffer is ignored.
Optional third arg EXIT-CHAR can be a character, event or event
description list.  EXIT-CHAR defaults to SPC.  If the input is
EXIT-CHAR it is swallowed; otherwise it is then available as
input (as a command if nothing else).
Display MESSAGE (optional fourth arg) in the echo area.
If MESSAGE is nil, instructions to type EXIT-CHAR are displayed there."
  (or exit-char (setq exit-char ?\s))
  (let ((ol (make-overlay pos pos))
    (str (copy-sequence string)))
  (unwind-protect
    (progn
      (save-excursion
      (overlay-put ol 'after-string str)
      (goto-char pos)
      ;; To avoid trouble with out-of-bounds position
      (setq pos (point))
      ;; If the string end is off screen, recenter now.
      (if (<= (window-end nil t) pos)
        (recenter (/ (window-height) 2))))
      (message (or message "Type %s to continue editing.")
           (single-key-description exit-char))
    (let ((event (read-key)))
    ;; `exit-char' can be an event, or an event description list.
    (or (eq event exit-char)
    (eq event (event-convert-list exit-char))
    (setq unread-command-events
            (append (this-single-command-raw-keys)
                unread-command-events)))))
    (delete-overlay ol))))

只需要经过少许修改就能让所有字符都能够在取消临时字符的同时插入自身:

(defun momentary-string-display-no-key (string pos &optional message)
  "Momentarily display STRING in the buffer at POS.
Display remains until next event is input.  If POS is a marker,
only its position is used; its buffer is ignored.  Display
MESSAGE (optional third arg) in the echo area."
  (let ((ol (make-overlay pos pos))
        (str (copy-sequence string)))
    (unwind-protect
        (progn
          (save-excursion
            (overlay-put ol 'after-string str)
            (goto-char pos)
            ;; To avoid trouble with out-of-bounds position
            (setq pos (point))
            ;; If the string end is off screen, recenter now.
            (if (<= (window-end nil t) pos)
                (recenter (/ (window-height) 2))))
          (message "%s" (or message "Press any key to continue editing."))
          (let ((event (read-key)))
            (setq unread-command-events
                  (append (this-single-command-raw-keys)
                          unread-command-events))))
      (delete-overlay ol))))

你会发现,这并不复杂. 可能也就是 read-keythis-single-command-raw-keys 的使用难以理解一点. 我必须承认,我并没有很仔细地检查这段代码,不过似乎 read-key 会通过某种方式修改全局状态 – i.e., 它会将输入事件保存到某个地方 – 而 this-single-command-raw-keys 能够取出这些输入事件. 这可能不是实现该功能的最清晰的方法,不过它确实证实了Emacs真算得上是一个文本编辑器工具箱. 不管怎样,我又学到了新东西.