Emacs选中文本高亮

所谓选中高亮, 就是任何时候选中一段文本, 在当前可见区域内高亮该文本, 对于一个编辑器来讲这是一个相当重要的功能, 而且实际中非常有用. 例如函数的参数和局部变量, 我们有时候会希望一眼辨别出他们出现在了哪些地方.

现在主要用Emacs, 所以希望Emacs也能支持这样的功能. 第一件事情是找有没有现成的方案, 没有找到完全符合要求的, 但是找到一个类似的:msearch.el.

这个插件可以实现鼠标选择文本, 然后高亮所有这个文本出现的地方. 现在只需要将其改为同时支持键盘选择文本并高亮即可. 看了一下代码之后找到两个有用的函数

 
msearch-set-word
msearch-cleanup
 

分别的作用是高亮某段文本所有的出现和清除高亮. 稍微修改一下就可以做到我们要的效果

 
    (if (use-region-p)
      (progn
        (msearch-cleanup)
        (msearch-set-word (buffer-substring-no-properties (region-beginning)  (region-end)))
      )
      (msearch-cleanup)
    )
 

如果buffer中有选中的文本, 首先清除高亮, 然后对选中的文本进行高亮显示, 如果没有选中的文本则执行清除高亮.

剩下的问题是这段代码要挂在什么地方才能起作用. 首先想起来的是handle-shift-selection, 每次shift选则的时候都会调用这个函数. 之前修改键绑定的时候也对这个函数有所了解. 实验一番之后发现一个问题, handle-shift-selection函数中接受到的关于region的信息总是是当前的region的状态延迟一个单位. 即在这个函数中看到的region信息总是上一次操作的状态. 例如选中的文本是"abc", 实际高亮的是"ab", 原因可能是Emacs先调用这个函数, 然后才更新region的信息.

最后找到了想要的hook: post-command-hook, 这个hook是针对任何编辑命令的, 而且是命令完成之后执行, 那么region信息会是正确的. 下面的代码可以达到想要的效果:

 
(add-hook 'post-command-hook
  (lambda ()    
    (if (use-region-p)
      (progn
        (msearch-cleanup)
        (msearch-set-word (buffer-substring-no-properties (region-beginning)  (region-end)))
      )
      (msearch-cleanup)
    )
  )
)
 

效果图

emacs 高亮, 选择文本