<< 前のページ | 次のページ >>

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Elisp メモ: メジャーモードを切り替えるタイミングで処理を実行させる

注)以下の方法がベストか?という点についてはよく分かりません。 添削歓迎です。


M-x apropos RET hook RET して "major-mode" で検索すると after-change-major-mode-hook と change-major-mode-hook という項目が出てくるので調べてみた。

大ざっぱに言えばモード移行時に「現在のモードの最後」に実行するか 「次のモードの最初」に実行するかの違いらしく、 次のように my-mode を作り my-mode から別のモードへ切り替えると どのモードの時に呼ばれているか確認できる。


(defun my-mode ()
  (interactive)
  (setq major-mode 'my-mode)
  (setq mode-name "MY mode")

  (add-hook 'change-major-mode-hook
            (lambda ()
              (message (format "change-major-mode-hook: %s" major-mode))
              (sit-for 2)))

  (add-hook 'after-change-major-mode-hook
            (lambda ()
              (message (format "after-change-major-mode-hook: %s" major-mode))
              (sit-for 2))))

ただし、これだけだと大域的なフック変数に登録されてしまうらしく、 すべてのモード切り替え時に実行されてしまって都合が悪い。 M-x でミニバッファを開くだけでも change-major-mode-hook に登録した関数が実行されてしまう。

そうではなく、「my-mode から」別のモードへ切り替える時「だけ」実行させたい。 調べてみると、フック変数をバッファローカルにすると良いらしい。

GNU Emacs Lispリファレンスマニュアル: Creating Buffer-Local の change-major-mode-hook の説明から引用:

この変数をバッファローカルにしておくとその役目を終えると変数は消えてしまい、 それ以降のメジャーモードに干渉しない。

フック変数をローカルにするためには make-local-hook を使う……のかと思ったが、 それではダメで、 add-hook の第4引数を nil 以外にすると期待通りに動いた。


my-mode の時だけあるアドバイスが有効になる (my-mode に切り替えたときにアドバイスが有効になり、 他のモードに切り替えたときに無効になる) ようにするサンプル:


(defun my-mode ()
  (interactive)
  (setq major-mode 'my-mode)
  (setq mode-name "MY mode")
  
  (defadvice next-line
    (after advc-foo activate)
    (message (format "%c" (char-after))))
  (ad-activate 'next-line) ;; my-mode 実行時にアドバイスを有効に
  
  ;;(make-local-hook 'change-major-mode-hook)
  (add-hook 'change-major-mode-hook
            (lambda ()
                ;; my-mode から別のモードへの切り替え時にアドバイスを無効に
                (ad-deactivate 'next-line))
            nil
            t))

環境

GNU Emacs 23.0.91.1

Emacs Lisp メモ / アドバイス: C-x 2 した後で開いたウィンドウに自動的に移動する

「開いたウィンドウに移動する」は other-window(C-x o)。 これを、C-x 2(split-window-vertically)を呼んだ後で自動的に実行するようにしたい。

とりあえずフックが使えるかどうか調べてみようと split-window-vertically のヘルプを 見てみたが、できるかどうかちょっと分からなかった。

そこで、フックに似た仕組みである「アドバイス」という機能を使う方向で調べてみたところ、 次のようになった。
「split-window-vertically の『後に』other-window を実行する」 の「後に」の部分は「after」で指定する。


(defadvice split-window-vertically
  (after other-window-after-split-window-vertically activate)
  (other-window 1))
(ad-activate 'split-window-vertically)

同じ要領で「C-x 3(split-window-horizontally)の後で other-window」もできる。

Emacs Lisp メモ: Enumerable的な何かのようなもの

まあなんというか練習も兼ねた書き散らかしです。ものすごく適当です。 Emacs Lisp 詳しくないのでダメコードだと思います。 気が向いたら追加・修正するかも。


(defun each (f list)
      (let ((temp list))
        (while (not (eq (car temp) nil))
          (funcall f (car temp))
          (setq temp (cdr temp)))))
;;=> dolist
;; list.each{|x| print x }
;; ↓
;; (dolist (x list)
;;   (print x))


(defun all? (f list)
  (let ((temp list)
        (flag t))
    (while (not (eq nil (car temp)))
      (if (eq nil (funcall f (car temp)))
          (setq flag nil))
      (setq temp (cdr temp)))
    flag))


;; map, collect
(mapcar
 '(lambda (x) (+ x 1))
 '(1 2))

(defun detect (f list) ; or find
  (let ((temp list)
        (result nil))
    (while (and (eq result nil)
                (> (length temp) 0))
      (if (funcall f (car temp))
          (setq result (car temp)))
      (setq temp (cdr temp)))
    result))


(defun find-all (f list) ; or select
  (let ((temp list)
        (result '()))
    (while (< 0 (length temp))
      (if (funcall f (car temp))
          (setq result (append result (list (car temp)))))
      (setq temp (cdr temp)))
    result))
;; => remove-if, remove-if-not


(defun include? (f list) ; or member?
  (let ((temp list)
        (result nil))
    (while (and (eq nil result)
                (< 0 (length temp)))
      (if (funcall f (car temp))
          (setq result t))
      (setq temp (cdr temp)))
    result))
;;=> memq(eq で比較), member(equal で比較)


;; The MIT License

;; Copyright (c) 2009 sonota (yosiot8753@gmail.com)

;; Permission is hereby granted, free of charge, to any person obtaining a copy
;; of this software and associated documentation files (the "Software"), to deal
;; in the Software without restriction, including without limitation the rights
;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
;; copies of the Software, and to permit persons to whom the Software is
;; furnished to do so, subject to the following conditions:

;; The above copyright notice and this permission notice shall be included in
;; all copies or substantial portions of the Software.

;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;; THE SOFTWARE.
include?, member?
→ memq(eq), memql(eql), member(equal)

Emacs: shell-mode で日本語が文字化けする場合の対処法

自分の場合、Windows + NTEmacs では:
M-x set-buffer-process-coding-system RET sjis RET sjis RET
または
C-x RET p sjis RET sjis RET

.emacs に書く場合


(add-hook
 'shell-mode-hook
 '(lambda ()
    (set-buffer-process-coding-system 'sjis 'sjis)))

関連

指定できる coding-system の一覧を表示:
M-x list-coding-systems

Lisp/Scheme のコメント・文字列・括弧に色を付ける簡易ツール(Javascirpt)

  • ブログなどに貼った Lisp/Scheme 系のソースコードを google-code-prettify のように強調表示(ハイライト)するツールを探してみたのですが、ちょうどいいのが見つけられず……というわけで簡単なのを作ってみました*1 *2
  • キーワードや関数名、シンボルなどには色は付きません。 Lisp/Scheme っぽいものにそのまま使いまわせるようにしたかったのと、 なるべく処理が重くならないようにしたかったので、あまり複雑にならないようにしました。
  • Common Lisp とかはよく知らないのでとりあえず Emacs Lisp を想定してます……
20100417 追記
*1: これを書いたときは見つけられなかったのですが、その後 highlight.js というのを見つけました。こっち(highlight.js)の方がおすすめです。
20120513 追記
*2: これまた見つけられていなかったのですが、google-code-prettify も Lisp に対応しているようです。 README に「LISPy languages are supported via an extension: lang-lisp.js.」とあり、Change Log によれば 2008年に加わったようです。

ダウンロード

gist: 228735 - GitHub からどうぞ。

サンプル

こんな感じで色が付きます。

(defun factorial (x)
  "Calculate factorial." ; 関数の説明
  (if (= x 1)
      1
    (* x (factorial (- x 1))))) ; 再帰呼び出し

動作チェック

;; ダブルクォート文字列
aa "bb" cc
aa "b\"b" cc ; バックスラッシュでエスケープ
aa "b\\b" cc
aa "b;b" cc  ; セミコロン
aa "b(b" cc  ; 括弧
aa "b)b" cc

;; 一行コメント
aa ; bb
; aa"bb ; ダブルクォート
; aa\bb ; バックスラッシュ
; aa)bb ; 括弧
; aa(bb

;; 括弧
aa(bb)cc

;; 記号
(1 . 2)
'()

;; HTMLの文字参照
a < b
a > b
a & b

;; 最後のダブルクォートが不整合
"aa

参考(外部リンク)



** ホームに戻る

<< 前のページ | 次のページ >>
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。