日記はScrapboxに移動しました。

  • Emacs interface to Ditz issue tracking system

    ,

    Ditz はとても素晴らしいと思います! – ¬¬日常日記で知った、コンソールベースのBTSであるところのDitzがいい感じだなーと思った。しかしやっぱり、せっかくだからEmacsから使いたいと思ったので、それっぽいのを書いてみた。

    まあ色々と微妙なところもあるけど、使っていくうちに改善していければいいな。まだあんまり使ってないのでアレだけど、プロジェクトのソースツリーの中に使い勝手のいいTODOリストをつっこんでおくというのは、普通なようでいて、けっこういいかもしれんね。なにやるんだっけー、って時に、単なるTODOリストや作業ログファイルじゃなくて、コマンド一発でリストされたり、編集できたりするのはいい感じ。あと、ditz htmlコマンドを使えば、ditz Issue Trackerこんな感じでHTMLファイルも書き出せたりするので、これを見えるとこに置いておけばよい。

    Ditz自体の使い方については上記の紹介エントリや、DitzのREADMEを見ていただくとして、以下にditz.elのREADMEをコピペしておきます。コンソールから使うのと、そんなに変わらないのけど、せっかくEmacsから使うようにしたので、ちょっと楽になるかも。

    基本的には、ditz-todoを使いまくる。ditz-add/ditz-add-releaseでタスクを追加し、作業の進捗につれて、ditz-todoでリストアップしたissueやreleaseを、s(show), c(close), r(release)して消していく感じ。

    ともあれ、GitHubで公開しているので、フィードバックいただけるとありがたいです(リポジトリのフォーク→pull requestとか、コミッタに登録しろ!とか)。

    README for emacs-ditz
    =====================
    * Description
    emacs-ditz provides ditz.el, Emacs interface to Ditz issue tracking
    system. You can get Ditz from http://ditz.rubyforge.org/.
    * Usage
    (1) Checkout from repository.
    $ git clone git://github.com/kentaro/emacs-ditz.git
    (2) Add the checkout directory into your load-path.
    (add-to-list 'load-path "/path/to/emacs-ditz")
    (3) Load dzit.el.
    (require 'ditz)
    (4) Set some variables as you like.
    ;; Path to the ditz command (default: "ditz")
    (setq ditz-program "/path/to/ditz")
    ;; If you don't want to always set issue dir when you run commands,
    ;; ditz.el provides automatic finding functionality. Add the
    ;; settings below:
    ;; Issue directory name (default: "bugs")
    (setq ditz-issue-directory "issues")
    ;; Enable automatic finding functionality.
    (setq ditz-find-issue-directory-automatically-flag t))
    (5) Run M-x ditz-init to initialize your ditz issues.
    (6) Run M-x ditz-add-release to add a new release.
    (7) Run M-x ditz-add to add a new issue
    (8) M-x ditz-status, ditz-todo, ditz-log are useful for
    browsing your issues.
    (9) To change issues/releases' status:
    [1] Run M-x ditz-todo to list issues up.
    [2] Enter the keys below on underlined strings:
    - "s": ditz-show         (Show issue's detail)
    - "e": ditz-edit         (Edit issue's detail)
    - "a": ditz-assign       (Assign/reassign issue to a release)
    - "c": ditz-close        (Close issue)
    - "r": ditz-release      (Mark release as done)
    - "g": ditz-reload       (Reload status/todo/log buffer)
    - "q": ditz-close-buffer (Close ditz-mode buffer)
    (10) M-x ditz-html generates HTML files including all statuses.
    (11) For the usage of Ditz itself, see the document below:
    http://ditz.rubyforge.org/README.txt
    * AUTHOR
    Kentaro Kuribayashi
    http://kentarok.org/
  • yasnippet関連の設定

    ,

    ここ数日、yasnippetに限らず.emacsいじりやelisp書きに没頭し過ぎて、公私各方面での活動に支障をきたしているので、ここらでとりあえずyasnippet関連の設定でも晒して、Emacsいじりを切り上げることにしたい。昨日、ver 0.4.0が出て、さらにいろいろ便利になった。しかし、まだいろいろと流動的かつ人柱的なので、根気がないと大変かも。

    以下、注釈(コメントでも書いてるけど)。

    ;; yasnippet
    ;; http://code.google.com/p/yasnippet/
    (require 'yasnippet)
    ;; メニューは使わない
    (setq yas/use-menu nil)
    ;; トリガはSPC, 次の候補への移動はTAB
    (setq yas/trigger-key (kbd "SPC"))
    (setq yas/next-field-key (kbd "TAB"))
    ;;; [2008-03-20]
    ;;; ポップアップをdropdown-listにする
    ;; ver 0.4.0からyasnippel.el内にdropdown-list.elが含まれるようになった
    ;; が、いまのところ、それだとリストの選択肢でC-mしてもinsertされない。
    ;; 理由はわからないが、とりあえず自前で用意したものをrequireするとうま
    ;; く行く。
    (require 'dropdown-list)
    (setq yas/text-popup-function
    #'yas/dropdown-list-popup-for-template)
    ;;; [2008-03-20]
    ;;; コメントやリテラルではスニペットを展開しない
    ;; ver 0.4.0からそれを利用して、コメント・リテラルの中では、スニペット
    ;; で特に指定されない限り、展開を行わない。
    (setq yas/buffer-local-condition
    '(or (not (or (string= "font-lock-comment-face"
    (get-char-property (point) 'face))
    (string= "font-lock-string-face"
    (get-char-property (point) 'face))))
    '(require-snippet-condition . force-in-comment)))
    ;;; [2008-03-15]
    ;;; 複数のディレクトリからスニペットを読み込む。
    ;; yasnippetのsnippetを置いてあるディレクトリ
    (setq yas/root-directory (expand-file-name "~/dev/yasnippet/snippets"))
    ;; 自分用スニペットディレクトリ(リストで複数指定可)
    (defvar my-snippet-directories
    (list (expand-file-name "~/dev/yasnippet-snippets/common")  ; CodeRepos
    (expand-file-name "~/dev/yasnippet-snippets/kentaro") ; CodeRepos
    (expand-file-name "~/.emacs.d/snippets")))            ; Private
    ;; yasnippet公式提供のものと、自分用カスタマイズスニペットをロード同名
    ;; のスニペットが複数ある場合、あとから読みこんだ自分用のものが優先され
    ;; る。また、スニペットを変更、追加した場合、このコマンドを実行すること
    ;; で、変更・追加が反映される。
    (defun yas/load-all-directories ()
    (interactive)
    (yas/reload-all)
    (mapc 'yas/load-directory-1 my-snippet-directories))
    ;;; [2008-03-17]
    ;;; yasnippet展開中はflymakeを無効にする
    (defvar flymake-is-active-flag nil)
    (defadvice yas/expand-snippet
    (before inhibit-flymake-syntax-checking-while-expanding-snippet activate)
    (setq flymake-is-active-flag
    (or flymake-is-active-flag
    (assoc-default 'flymake-mode (buffer-local-variables))))
    (when flymake-is-active-flag
    (flymake-mode-off)))
    (add-hook 'yas/after-exit-snippet-hook
    '(lambda ()
    (when flymake-is-active-flag
    (flymake-mode-on)
    (setq flymake-is-active-flag nil))))
    ;;; [2008-03-19]
    ;;; yasnippetを使って、ttのディレクティヴを補完
    ;; スニペットに`(tt-directives)`と書いて置くと補完読み込みする。
    ;; http://clouder.jp/yoshiki/mt/archives/000377.html から。
    ;; TODO: minor-modeでフェイスを定義して、色をつけたい。
    (defvar tt-directives
    '(
    ("IF")
    ("UNLESS")
    ("ELSIF")
    ("ELSE")
    ("FOREACH")
    ("WHILE")
    ("FILTER")
    ("GET")
    ("CALL")
    ("MACRO")
    ("SET")
    ("DEFAULT")
    ("INSERT")
    ("INCLUDE")
    ("BLOCK")
    ("END")
    ("PROCESS")
    ("WRAPPER")
    ("SWITCH")
    ("CASE")
    ("USE")
    ("PERL")
    ("RAWPERL")
    ("TRY")
    ("THROW")
    ("FINAL")
    ("CATCH")
    ("NEXT")
    ("LAST")
    ("RETURN")
    ("STOP")
    ("CLEAR")
    ("META")
    ("TAGS")
    ))
    (defun tt-insert-directive ()
    (let ((directive (completing-read "Directive Name: " tt-directives nil t)))
    (when (and directive
    (not (string= directive "")))
    (concat "[%- " directive " %]"))))
    ;; yasnippet初期化
    (yas/initialize)
    (yas/load-all-directories)
    
  • yasnippetのスニペット展開中にflymakeするのを防ぐ

    ,

    2008-03-19追記: 不具合があったので、少し修正しました。

    yasnippet超便利なのですが、flymakeしてると、yasnippetのフェイスがflymakeのフェイスで上書きされちゃうことがよくある。そこでこんな設定を追加してみた。つーか、yas/expandにもフック欲しいな。要望しておこう。

    flymakeが有効か否かを調べる方法は、id:elimんに教えてもらったお!id:elim++

    ;; yasnippet展開中はflymakeを無効にする
    (defvar flymake-is-active-flag nil)
    (defadvice yas/expand-snippet
    (before inhibit-flymake-syntax-checking-while-expanding-snippet activate)
    (setq flymake-is-active-flag
    (or flymake-is-active-flag
    (assoc-default 'flymake-mode (buffer-local-variables))))
    (when flymake-is-active-flag
    (flymake-mode-off)))
    (add-hook 'yas/after-exit-snippet-hook
    '(lambda ()
    (when flymake-is-active-flag
    (flymake-mode-on)
    (setq flymake-is-active-flag nil))))
    
  • yasnippetのトリガをスペースキーにする

    ,


    とか書いてたら、ver 3.0に上がって、この方法はそっこーでobsoleteになった。まぁそういアツさが、できたばかりのものを触る醍醐味でもあるかと。

    yasnippetのトリガはデフォルトではTABキーなのですが、これは変更することが可能です。僕はいまんとこabbrevを使っていないので、abbrevと同じ感じで使えるよう、スペースキーにしてみました。こんな感じで、スニペットがなかった場合に実行されるyas/default-trigger-fallbackを定義してやる必要があります。

    しかしこれって、スニペット補完を意図していない場所でスペース押すたびにも実行されるんだろうからかなlり富豪的過ぎる感じがするけど、まあいいじゃないか!!!しばらくこんなんで様子見。

    (setq yas/trigger-key " ")
    ;; 対応するsnippetがない場合はSPCを挿入する
    (fset 'yas/default-trigger-fallback
    (lambda ()
    (interactive)
    (insert yas/trigger-key)))
    
  • yasnippetのスニペットをCodeReposで共有しよう!

    ,

    yasnippetがすごい!!!!1112345!」で話題にしたyasnippetは、スニペットをあれこれ登録しまくってこそ、真にその力を発揮するわけですが、こういうのはやっぱりみんなで作ってこそだよねーというわけで、CodeReposで共有しましょう!!!とりあえず、まずはPerl用に、Test::Moreのスニペットを作って、CodeReposに上げておきました。

    /config/yasnippet – CodeRepos::Share – Trac

    スニペットの作り方に関しては、HowtoDefineSnippet – yasnippet – Google Codeを見れば、だいたいわかります。というか、配布物の中に例がたくさんあるので、ディレクトリ配置や、テンプレートを適当に真似て書けばオケです。

    公式の配布物と合わせて、CodeRepos等での共有スニペットや、あるいは自分で書いたスニペットを利用する場合には、ちょっと設定を書く必要があります。yasnippetのサイトに書いてある通りの設定をすると、スニペットを置くディレクトリをひとつしか指定できないのでこんな感じで。

    (require 'yasnippet)
    ;; yasnippetのsnippetを置いてあるディレクトリ
    (setq yas/root-directory (expand-file-name "~/dev/yasnippet/snippets"))
    ;; 自分用スニペットディレクトリ(リストで複数指定可)
    (defvar my-snippet-directories (list (expand-file-name "~/dev/yasnippet-snippets")))
    ;; yasnippet公式提供のものと、自分用カスタマイズスニペットをロード
    ;; 同名のスニペットが複数ある場合、あとから読みこんだ自分用のものが優先
    ;; される。また、スニペットを変更、追加した場合、このコマンドを実行する
    ;; ことで、変更・追加が反映される。
    (defun yas/load-all-directories ()
    (interactive)
    (yas/reload-all)
    (mapc 'yas/load-directory-1 my-snippet-directories))
    ;; yasnippet初期化
    (yas/initialize)
    (yas/load-all-directories)
    
  • yasnippetがすごい!!!!1112345!

    Yet Another Snippet Package | M-x all-things-emacs“で知った、yasnippetがすご過ぎる!!!!1112345!これは、同じ作者が以前に作っていたsmart-snippet.elのリライト版?みたいなものらしいのだが、ともあれGoogle Codeにてプロジェクトが開始されたのが3/7というから、アツい。

    まぁ、とりあえずこれを見てくださいよ(YouTubeの画質だとアレだという場合は、上記プロジェクトページからaviの動画が落とせるので、そちらを見るのが良いです)。

    最初のあたりは、まぁ、emacs-railsでも使われているsnippet.elとかでも十分可能なことなのだけど、複数のテンプレート候補が選択リスト表示されたり、メニューバーからテンプレートを挿入できたりするのがいい感じだし、後半、どんどんヤバくなってくる。一箇所に入力していくだけで、複数箇所が同時に変更されていくあたりとか、なんだこれは!!!11123!つって、まじビビる。

    また、動画だとわかりにくいんだけど、テンプレートにelispを埋め込んで、実行時にevalすることで高い表現力を実現している。elispの評価、結果挿入自体は、(使ったことないからよくわからないが)skelton-modeでも可能ではある。しかしながらyasnippetsは、たとえば`(current-time-string)’といった埋め込みelispを評価するだけでなく、`(capitalize text)’という感じで、入力文字列をtextという引数に取って評価、結果を挿入することが可能であるため、さらにヤバい。

    よいところをまとめると、こんな感じ。

    • 設定が超簡単。
    • テンプレートの記法が簡単明瞭。
    • テンプレートをファイル内にテキストで書くので見通しがよく、いじりやすい(S式内のリテラルでも書けるけど、見づらい)。
    • テンプレートの配置が簡単明瞭。
      • ディレクトリがテンプレートを適用するメジャーモードを、ファイル名によりテンプレートを実行するトリガとなるキーを表す。
    • Synchronization!
    • Sexp evaluation!
    • Transformation!

    ……つってもわかりにく過ぎるので、HowtoDefineSnippet – yasnippetをざっとご覧になると良いと思う。

    ただし、まだ開発が始まったばかりということもあって、問題もある。いま僕はemacs -nwで主にEmacsを使っているのだが、それだとあの動画のように複数候補の選択リストが出てこないというのはまぁ当然としても、そもそも複数候補があるテンプレート自体が正しく扱えずエラーとなる状態。 ver-0.2.3で修正された(http://code.google.com/p/yasnippet/issues/detail?id=7)

    また、先にも書いた通り、テンプレートの定義は`(yas/define-snippets … )’という感じで書くか、あるいは、テンプレートファイルに書いていく感じなのだけど、abbrevに比べると定義の自由度が高いのと引き換えに、新規テンプレートの追加がめんどくさい。そのあたりはまぁ、今後解決されていくのではないかと思われるので期待。

    つーか、abbrevにしてもsnippetにしても、略語自体を記憶するのが困難であるという、そもそも的な問題がある。そこで、「略語の候補リスト表示、絞り込みをanything.elにより行うことができたら、これはもうヤバ過ぎ果てまくることになるのではないか lang:ja」という感じなのだが、ちょっと見てみたところでは、僕には簡単にはできそうになかった。是非とも、誰か!!!!1112345!

  • シンプルEmacs

    極小ネタ。

    Emacsに慣れきってしまって、ちょっとしたものを書くのですらVimとかまったく使えない体に成り果ててしまったので、なんでもEmacsでやりたい!!!とか思ったりする。しかし、Emacsをもう一個立ち上げるのも重いし、とりあえず設定ファイルをちょっと修正するぐらいなら、素のEmacsでもなんとかなりそうなので、jedを入れたりするのはおおげさだ。んじゃ、emacs -Q的な感じで起動すればよいじゃないかということになった。

    しかし、一個だけ問題があって、デフォルトではC-hでバックスペースにならず、それだけはかなり耐えがたい感じなので、そこんとこだけちょっとどうにかしたものを、id:elimさんと相談の上、というかid:elimさんに教えてもらって、semacsとかいう名前でaliasした。

    alias -g semacs="emacs -Q --eval '(keyboard-translate ?\C-h ?\C-?))'"

    追記:

    僕は普段、multi-ttyが有効なEmacsを使っていて、かつ、EDITOR=emacsclientしてるので、自分のユーザ権限で編集できるものについてはemacsclientで不便がなかったりするのだけど、上記のようなことをしたいと思ったのは、emacsclientじゃsudoできないと思っていたからなのだった。んで、「emacsclient / gnuclientを使えばシェルから既存のEmacsを呼べる – ’(rubikitch wanna be (a . lisper))」を読んだ後に、気になってぐぐってみたら、あー!!!sudoeditあるいはsudo -eでいいのかー。じゃぁ、上記のsemacsとかいらないじゃんw

    man sudoeditより引用。

    The -e (edit) option indicates that, instead of running a command, the user wishes to edit one or more files. In lieu of a command, the string “sudoedit” is used when consulting the sudoers file. If the user is authorized by sudoers the following steps are taken:

    1. Temporary copies are made of the files to be edited with the owner set to the invoking user.

    2. The editor specified by the VISUAL or EDITOR environment variables is run to edit the temporary files. If neither VISUAL nor EDITOR are set, the program listed in the editor sudoers variable is used.

    3. If they have been modified, the temporary files are copied back to their original location and the temporary versions are removed.

    If the specified file does not exist, it will be created. Note that unlike most commands run by sudo, the editor is run with the invoking user’s environment unmodified. If, for some reason, sudo is unable to update a file with its edited version, the user will receive a warning and the edited copy will remain in a temporary file.

    常識ですか><

  • My .emacs files on 2008/03/13

    ,

    現在、僕の中で第3期にあたる空前のEmacsブームが訪れており、.emacsを整理したり、新しいelispをあれこれ試したり、自分でelispを書いたりしている。

    ちょっと前の話になるけど、「Software Design 2008年2月号」のEmacs特集が素晴しくて、また、その特集でもid:rubikitchさんが取り上げているanything.elがすげー!すげー!というわけで、超盛り上がる。というかその特集、その他も素晴しい記事だらけ過ぎて永久保存版まくり。僕もそのうち、EmacsWikiにあれこれ書いたりできるようになりたい!!!

    んでもって以前、CodeReposEmacsの設定を晒したりしたのだったが、参考にしていただいていたりするので、設定部分に関して整理したものを、改めて更新してみたり。

    /dotfiles/emacs/kentaro – CodeRepos::Share – Trac

    これぐらいでも、設定だけで合計にして約1,900行ぐらいになるのだけど、しかしすごいひとはまったくレベルの違うすごさなので僕ごときじゃアレなのだが、しかしまぁ、あんまりにもすご過ぎるとなにがなんだかわからないので、むしろこのぐらいでもなんかの役に立ったりもするのかもしれないとも思ったりもする。

    それにしてもEmacsつーのはアレですな。まったくもって初心者を脱け出せる気がしない奥の深さ。しかしそろそろ、なんかやるたびにEmacsの設定を見直して先に進まないのをどうにかしたいものです……。

  • Emacsからackの検索結果を使う

    ,

    よくわかんないけど、こんなんでいんじゃねもうもう。quickfixって何。vimとかわかりません><

    (defun ack ()
    (interactive)
    (let ((grep-find-command "ack --nocolor --nogroup "))
    (call-interactively 'grep-find)))
    

    ちなみにackは、CPANのApp::Ackから入れるとackなのだけど、debianのパッケージだとack-grepなので注意を要する。あと、最近anything.el(素敵!!!)を使いはじめたので、そこに出すようにしてみようかと思ったりもしたけど、それはそれで微妙な気もした。どうだろ。

  • EmacsでPerlのモジュール名を動的に補完する

    ,

    追記: id:rubikitchさんに、auto-revert-modeってのを教えていただきました!素晴しい!!!1

    /path/to/pmlistをauto-revert-modeした状態にしておけばcronの更新が反映されるはず。

    そこで(global-)?auto-revert-modeですよ – (rubikitch loves (Emacs Ruby CUI Books))

    というわけで、そっちを使うように書き直した。

    EmacsでPerlのモジュール名を補完する – subpop – subtech」で書いたネタだったりするのだけど、ともあれ、Perlモジュール名を補完(dabbrev)したいよー的な要求について。上記リンク先で書いたのは、cperl-mode初回起動時にコマンドを流していて、すごく重くていらいらしてたので、あらかじめモジュールの一覧だけのファイルを作るようにした。依然として、アホっぽいけど。

    下記のようなてけとースクリプトを用意し、cronで定期的に回す。

    # make_pmlist.sh
    # 0 * * * * /path/to/make_pmlist.sh /path/to/pmlist
    find `perl -e 'print join(q{ }, grep {-e $_} @INC);'` -name '*.pm' -type f |
    xargs egrep -h -o 'package [a-zA-Z0-9:]+;' |
    perl -nle 's/package\s+(.+);/$1/; print' |
    sort |
    uniq > $1
    

    んでもって、Emacsの設定ファイルにこんな感じで追記。

    (defvar perl-pmlist-file-name "/path/to/pmlist")
    (defvar perl-pmlist-buffer-name "*PerlModules*")
    (defvar perl-pmlist-make-command (concat "/path/to/make_pmlist.sh"
    " "
    perl-pmlist-file-name))
    (defun perl-make-pmlist-buffer ()
    (interactive)
    (save-excursion
    (when (interactive-p)
    (shell-command perl-pmlist-make-command))
    (unless (get-buffer perl-pmlist-buffer-name)
    (find-file perl-pmlist-file-name)
    (rename-buffer perl-pmlist-buffer-name)
    (auto-revert-mode t))))
    (add-hook 'cperl-mode-hook 'perl-make-pmlist-buffer)
    

    これで、cperl-mode初回起動時に、あらかじめ作っておいたPerlモジュール一覧を読み込んだバッファを作成しておくので、dabbrevの候補に上がってくる感じ。んでもって、一覧がcronで更新されたら、auto-revert-modeによりEmacsのバッファ上も自動的に反映される。モジュールの新規インストール後に、cronによる更新をを待たずに手動で反映させるには、M-x perl-make-pmlist-bufferを実行すればよい(これはちょっと時間がかかる)。

    一覧をあらかじめ作っておくってのがすごくアレな感じだが、まぁないよりはマシかなぁとは思われる。もっとかっけー方法があったら教えてください><