*iroi*

mechairoi の Blog

Template-ToolkitのMACROとかBLOCKをctagsで

Exuberant ctagsで使えます.
~/.ctags にいい加減な正規表現を書く.

なんかmacだと動かない?
なんか他の環境では動かないらしい。
正規表現書き換えたら動いた。ctagsのバージョンとかは

$ ctags --version
Exuberant Ctags 5.8, Copyright (C) 1996-2009 Darren Hiebert
  Compiled: Jan 11 2011, 00:09:44
  Addresses: <@>, http://ctags.sourceforge.net
  Optional compiled features: +wildcards, +regex

perlのflymakeの設定

  • buffer localにしたかったのでPERL5LIBにsetenvせず起動オプションで -Mlib glob.
  • 常にgitを使うのでgitプロジェクトの一番上を起点にしている.
;; -- flymake
(add-to-list 'flymake-allowed-file-name-masks
             '("\\.t$" flymake-perl-init)) ; pm, pl は設定されてる.

(defconst my-flymake-perl-lib-suffix-list
  '("lib" "t/lib" "modules/*/lib" "modules/*/t/lib"))

(defun my-flymake-perl-options ()
  (when my-current-git-root
    (mapcar (lambda (suffix)
              (format "-Mlib glob qw(%s%s) " my-current-git-root suffix))
            my-flymake-perl-lib-suffix-list)))

;; override (flymake.el)
(defun flymake-perl-init ()
  (let* ((temp-file   (flymake-init-create-temp-buffer-copy
                       'flymake-create-temp-inplace))
         (local-file  (file-relative-name
                       temp-file
                       (file-name-directory buffer-file-name))))
    (list "perl" (append '("-wc ") (my-flymake-perl-options) (list local-file)))))

;; -- hook

(add-hook 'cperl-mode-hook 'my-cperl-mode-init)
(defun my-cperl-mode-init ()
  (let ((root (my-git-root)))
    (set (make-local-variable 'my-current-git-root) root)
    (when root (my-make-tags-if-need root t)))
  (flymake-mode t))

;; -- my-git

(defun my-git-root ()
  (flet ((iter (path)
               (let ((p (and path (vc-git-root path))))
                 (or (and p (iter (my-parent-directory p))) p))))
    (iter (if (buffer-file-name)
              (file-name-directory (buffer-file-name))
            default-directory))))

(defun my-parent-directory (path)
  (file-name-directory (directory-file-name (file-name-directory path))))

GTAGSのパスを指定したanything-gtagsのsourceを作る.

(バッファが属する)ProjectのTAGSと(global-modeに応じた)LibraryのTAGSとか同時に使いたいです.

anything-gtags.el でプロジェクトのGTAGSは既に使えるので, GTAGSファイルのパスを指定できるsourceを作って, 複数のsourceを扱うのはanythingにおまかせすることにしました. anything便利.

使い方はこんな感じ. ~/perl5に インストールしているperlのモジュールが入っていてGTAGSを作ってあります.

(defvar anything-c-source-gtags-select-with-home-perl-lib
  (anything-c-source-gtags-select-with-root "GTAGS ~/perl5" "~/perl5"))

(defun my-anything-gtags-select ()
  (interactive)
  (anything-other-buffer
     '(anything-c-source-gtags-select
       anything-c-source-gtags-select-with-home-perl-lib)
     "*anything gtags*"))

( perl用のGTAGSの作り方は gtags(GNU global)をperlとかで使う - *iroi* )

gtags.elやanything-gtags.el内部で使われているglobalコマンドは環境変数GTAGSROOTがあるとカレントディレクトリより優先してそっちを見るようなので、環境変数をdynamic-scope内でローカルに書き換えるマクロを作って囲んだだけです.

Test::Class でメソッドの単体テストを elisp でさくっと

Test::Class でメソッドの単体テストを vim script でさくっと - #生存戦略 、それは - subtechが便利過ぎる!!!のでemacsでもしたいです.

(defun run-perl-method-test ()
  (interactive)
  (let ((command compile-command))
    (save-excursion
      (when (or
             (re-search-backward "\\bsub\s+\\([_[:alpha:]]+\\)\s*:\s*Test" nil t)
             (re-search-forward "\\bsub\s+\\([_[:alpha:]]+\\)\s*:\s*Test" nil t))
        (setq command
              (format "TEST_METHOD=%s perl -w %s"
                      (match-string 1) (expand-file-name buffer-file-name)))))
    (when command (compile command))))

いつもテスト通らなくて本体を修正するので, 候補が無かったらグローバルに前回のを実行するようにした.

gtags(GNU global)をperlとかで使う

etagsは使いにくいしgtagsは対応ファイルフォーマットが少ないしと思って色々調べていたらExuberant ctagsを使ってGTAGSを作れるようなのでやってみた.ちゃんとした機能ではなくgtagsのプラギン例のようです. ctagsが元になってるので global -rはできないですが、global -cなどはperlで使えてます. 以下手順.

  • Exuberant ctagsをインストール
$ ctags --version
Exuberant Ctags 5.8, Copyright (C) 1996-2009 Darren Hiebert
  Compiled: Aug 17 2010, 17:33:33
  Addresses: <?@?>, http://ctags.sourceforge.net
  Optional compiled features: +wildcards, +regex

普通は入れてますね. emacs付属のとかだと駄目です.

plugin-example/READMEに書いてあるようにctagsのパスをつけて

./configure --with-exuberant-ctags=/usr/bin/ctags; make; sudo make install;
  • このままだとpackage名でjumpできず *.pm, *.tがperlのコードして扱われないので, 設定ファイルを修正してやります.
cp /usr/local/share/gtags/gtags.conf ~/.globalrc
--- /usr/local/share/gtags/gtags.conf	2010-11-28 15:25:21.167584987 +0900
+++ .globalrc	2010-11-28 17:20:45.211584987 +0900
@@ -34,18 +34,19 @@
 # See gtags(1).
 #---------------------------------------------------------------------
 common:\
-	:skip=GPATH,GTAGS,GRTAGS,GSYMS,HTML/,HTML.pub/,html/,tags,TAGS,ID,y.tab.c,y.tab.h,cscope.out,cscope.po.out,cscope.in.out,SCCS/,RCS/,CVS/,CVSROOT/,{arch}/,autom4te.cache/:
+	:skip=GPATH,GTAGS,GRTAGS,GSYMS,HTML/,HTML.pub/,html/,tags,TAGS,ID,y.tab.c,y.tab.h,cscope.out,cscope.po.out,cscope.in.out,SCCS/,RCS/,CVS/,CVSROOT/,{arch}/,autom4te.cache/,.git/:
 gtags:\
 	:tc=common:\
 	:langmap=c\:.c.h,yacc\:.y,asm\:.s.S,java\:.java,cpp\:.c++.cc.cpp.cxx.hxx.hpp.C.H,php\:.php.php3.phtml:
 #
 # plugin parser
 #
 plugin-example|Example of function layer plugin parser:\
-	:tc=common:extractmethod:\
+	:tc=common:\
 	:langmap=c\:.c.h,yacc\:.y,asm\:.s.S,java\:.java,cpp\:.c++.cc.cpp.cxx.hxx.hpp.C.H,php\:.php.php3.phtml:\
 	:langmap=fortran\:.f.for.f77.f90.f95,pascal\:.p.pas,c#\:.cs,lisp\:.l.el.lisp,scheme\:.scm:\
-	:langmap=awk\:.awk,ruby\:.rb,perl\:.pl,python\:.py,vim\:.vim,sh\:.sh:\
+	:langmap=awk\:.awk,ruby\:.rb,perl\:.pl.pm.t,python\:.py,sh\:.sh:\
 	:gtags_parser=c\:/usr/local/lib/gtags/exuberant-ctags.la:\
 	:gtags_parser=yacc\:/usr/local/lib/gtags/exuberant-ctags.la:\
 	:gtags_parser=asm\:/usr/local/lib/gtags/exuberant-ctags.la:\

(*.vimはSession.vimがあるとgtagsが死んでしまうので消した)

gtags --gtagslabel=plugin-example

でそれっぽいGTAGSとかのファイルが生成されて使えます.

globalの機能が全て使えるわけでは無いですが,
etagsのelispがなんとも近寄り難い感じだったので満足です.

使わないけどもhtagsでHTMLも生成出来た.

vimpulseとanythingを使う設定とか

vimpulseを使っているとanythingとかでminibufferに入ったときにinsert-stateになっててC-nとかC-zが使えなくて悲しいのでなんとかしてみた.

vimpulseはvimpulse-define-keyでmodeのkeybindを拡張できるようなのでまずminibufferにminor-modeをつける. よくわからないがこんな感じのをminibuffer-setup-hookに追加する.

;; ---- minibuffer with minor mode ----
(defvar my-minibuffer-minor-mode nil)
(defun my-minibuffer-minor-mode ()
  (when (fboundp my-minibuffer-minor-mode)
    (funcall (symbol-function my-minibuffer-minor-mode))))
(add-hook 'minibuffer-setup-hook 'my-minibuffer-minor-mode)
;;(add-hook 'minibuffer-exit-hook 'my-minibuffer-minor-mode)

これで minibuffer-minor-modeにminor-modeを入れとくとminibufferに入ったときにminor-modeがonになる.

(minor-modeがもともとonになってるとoffになってしまうがあまり気にならない? exit-hookでoffにした方がよいと思ったんですが無いほうが良さそうです.)

さらに専用のminor-modeを作って、anythingを呼ぶときにadviceでmy-mininbuffer-minor-modeをセットする.

;; --- anything minibuffer mode ---
(defadvice anything (around set-major-mode activate)
  (let ((my-minibuffer-minor-mode 'my-anything-minibuffer-mode))
    ad-do-it))
(easy-mmode-define-minor-mode
 my-anything-minibuffer-mode
 "Anything MiniBuffer Mode"
 nil
 " Anything MiniBuffer"
 '())

これでanythingからminibufferに入ったときにminor-modeがonになってるはず. あとはdefine-keyするだけで, vi-stateも使えてうはうはである.

(vimpulse-define-key 'my-anything-minibuffer-mode 'insert-state "\C-n" 'anything-next-line)
(vimpulse-define-key 'my-anything-minibuffer-mode 'insert-state "\C-p" 'anything-previous-line)
(vimpulse-define-key 'my-anything-minibuffer-mode 'insert-state "\C-f" 'anything-next-page)
(vimpulse-define-key 'my-anything-minibuffer-mode 'insert-state "\C-b" 'anything-previous-page)
(vimpulse-define-key 'my-anything-minibuffer-mode 'insert-state "\C-l" 'anything-force-update)
(vimpulse-define-key 'my-anything-minibuffer-mode 'vi-state "o" 'anything-follow-mode)
(vimpulse-define-key 'my-anything-minibuffer-mode 'vi-state "j" 'anything-next-line)
(vimpulse-define-key 'my-anything-minibuffer-mode 'vi-state "k" 'anything-previous-line)
(vimpulse-define-key 'my-anything-minibuffer-mode 'vi-state "\C-f" 'anything-next-page)
(vimpulse-define-key 'my-anything-minibuffer-mode 'vi-state "\C-b" 'anything-previous-page)
(vimpulse-define-key 'my-anything-minibuffer-mode 'vi-state "\C-l" 'anything-force-update)
(vimpulse-define-key 'my-anything-minibuffer-mode 'vi-state "}" 'anything-next-source)
(vimpulse-define-key 'my-anything-minibuffer-mode 'vi-state "{" 'anything-previous-source)
(vimpulse-define-key 'my-anything-minibuffer-mode 'vi-state "gg" 'anything-beginning-of-buffer)
(vimpulse-define-key 'my-anything-minibuffer-mode 'vi-state "G" 'anything-end-of-buffer)
(vimpulse-define-key 'my-anything-minibuffer-mode 'vi-state "/" 'anything-isearch)

minibufferに入ったらanything-follow-modeするとか,
anything-*-from-here的なのは即vi-stateにするとかもしている.

(defvar anything-follow-mode-flag nil)
(defvar anything-with-vi-state nil)
(add-hook 'minibuffer-setup-hook
          (lambda ()
            (when anything-follow-mode-flag (anything-follow-mode))
            (when anything-with-vi-state (viper-change-state-to-vi))) t)
(defadvice anything-for-lines-from-here (around anything-auto-follow-mode activate)
  (let ((anything-follow-mode-flag t)
        (anything-with-vi-state t))
    ad-do-it))

elispはどう書くのがいいのかよくわからないな..

anything.elでプロセスに対しても複数行のバグ

d:id:rubikitch:20101122:anythingで取り込んで頂いたパッチにprocessの出力が二回以上にわかれて来たときに二回目の挿入位置が前回の位置を覚えていないようで順番とか色々変になるバグを埋め込んでしまいました.
勘で修正してみましたがinsertとinsert-before-markersの違いがまだよくわかってない..

ついでに1個目のcandidateの手前のseparatorを消しました.

--- a/.emacs.d/auto-install/anything.el
+++ b/.emacs.d/auto-install/anything.el
@@ -2227,12 +2227,13 @@ the real value in a text property."
     (put-text-property start (point) 'face anything-header-face)))
 
 
-(defun anything-insert-candidate-separator ()
+(defun anything-insert-candidate-separator (&optional insert-function)
   "Insert separator of candidates into the anything buffer."
-  (insert anything-candidate-separator)
+  (unless insert-function (setq insert-function 'insert))
+  (funcall insert-function anything-candidate-separator)
   (put-text-property (point-at-bol)
                      (point-at-eol) 'anything-candidate-separator t)
-  (insert "\n"))
+  (funcall insert-function "\n"))
 
 
 
@@ -2267,7 +2268,8 @@ the real value in a text property."
     (if (not (assq 'multiline source))
         (anything-insert-match candidate 'insert-before-markers source)
       (let ((start (point)))
-        (anything-insert-candidate-separator)
+        (unless (= (cdr (assoc 'item-count source)) 0)
+          (anything-insert-candidate-separator 'insert-before-markers))
         (anything-insert-match candidate 'insert-before-markers source)
         (put-text-property start (point) 'anything-multiline t)))
     (incf (cdr (assoc 'item-count source)))