読者です 読者をやめる 読者になる 読者になる

*iroi*

mechairoi の Blog

perlのflymakeの設定

emacs
  • 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を作る.

emacs

(バッファが属する)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 でさくっと

emacs perl

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とかで使う

emacs

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を使う設定とか

emacs 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でプロセスに対しても複数行のバグ

emacs

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)))

File ... is checked in. Check it out?

emacs vimpulse
File ~/config/.emacs.d/elisp/init.el is checked in. Check it out?

とか聞いてくる鬱陶しいのはemacsさんだと思っていたら, viperさんだった. emacsさん疑ってごめんなさい.
http://www.emacswiki.org/emacs/ViperMode#toc10
に解決方法が載ってた.