Emacs Lisp搜索后退

3

前言

在使用C++编程时,经常需要使用VTK库进行编写,这时我会写下如下的代码:

vtkInteractorStyleRubberBandZoom *isrbz = vtkInteractorStyleRubberBandZoom::New();

此外,每当我需要在程序中使用一个新的VTK类时,我都必须去源文件的某个位置添加 #include "vtkInteractorStyleRubberBandZoom.h"。
如何自动化这一过程,以便我只需输入每个极长的类名一次而不是三次?
我尝试编写了一个Emacs小模式。可能已经存在现成的解决方案(如YaSnippet?),但我认为自己编写它也是一个很好的练习。 代码
;vtk-mode.el
;add to .emacs:
;(load  "vtk-mode")
;(global-set-key [(control =)] 'expand-vtk)

(defun expand-vtk ()
  (interactive)
  (setq now (point))
  (setq vtkstart (search-backward "vtk"))
  (setq vtkend (- (search-forward " ") 1))
  (setq vtkname (buffer-substring vtkstart vtkend))

  ;check for #include "vtkBlah.h"
  (setq includename (format "#include \"%s.h\"\n" vtkname))
  (search-backward includename nil (append-include-vtk includename))
  (goto-char (+ now (length includename)))

  (insert (format "= %s::New();" vtkname)))

(defun append-include-vtk (incname)
  (goto-char 0)
  (insert incname))

问题

基本上,它可以工作,但搜索包含名称始终失败,例如:

vtkSomething *smth /*press C-= here, it looks backward for 
#include "vtkSomething.h", can't find it and 
calls append-include-vtk, adding it to the beginning 
of the file, then comes back here and expands this line into: */

vtkSomething *smth = vtkSomething::New();

//and let's add another instance of vtkSomething...
vtkSomething *smth2 /*press C-= again, it looks backward for 
#include "vtkSomething", and fails, despite the fact 
that it was added by the previous command. So it adds it again."*/

我在使用search-backward时做错了什么?

(代码中可能还有其他至少一个bug,如果search-backward成功了,我不应该添加(length includename),但现在我更关心的是如何使其首先成功)

2个回答

2

好的,我明白了。不知怎么地,我误以为search-backward的第三个参数(noerror)是一个回调函数,但实际上它并不是。因此它会每次都被评估,而不仅仅是在搜索失败时。应该改成这样:

(defun expand-vtk ()
  (interactive)
  (setq now (point))
  (setq vtkstart (search-backward "vtk"))
  (setq vtkend (- (search-forward " ") 1))
  (setq vtkname (buffer-substring vtkstart vtkend))

  ;check for #include "vtkBlah.h"
  (setq includename (format "#include \"%s.h\"\n" vtkname))
  (if (search-backward includename nil t) 
      (goto-char now) 
      (progn (append-include-vtk includename) 
             (goto-char (+ now (length includename)))))  

  (insert (format "= %s::New();" vtkname)))

(defun append-include-vtk (incname)
  (goto-char 0)
  (insert incname))

1
一个内置于Emacs中的命令,可以帮助你避免输入极长的类名,它就是dabbrev-expand(绑定到M-/):
(dabbrev-expand ARG)

Expand previous word "dynamically".

Expands to the most recent, preceding word for which this is a prefix.
If no suitable preceding word is found, words following point are
considered.  If still no suitable word is found, then look in the
buffers accepted by the function pointed out by variable
`dabbrev-friend-buffer-function'.

在编程中,当你第一次输入 vtkInteractorStyleRubberBandZoom 时,下一次你只需要输入 vtkI M-/ 就可以了。


谢谢。我知道这个并且尽可能使用它。然而,在这种特殊情况下,它并不总是有用的,因为该库有许多长类名共享许多长公共前缀。例如,有大约12个以“vtkInteractorStyle…”开头的类,如果我需要在同一源上使用多个,则仍然需要键入“vtkInteractorStyleX…”和“vtkInteractorStyleY…”。 - Headcrab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接