QA@IT

define-key に動的?な引数付き関数をセットしたい場合のなんか良い感じの手法はありますか

2409 PV

やりたいこと

イメージとしては以下のような感じ(エラー出ます)。

(defun add-click-property (str msg)
  (let ((map (make-sparse-keymap))
        (func (lambda () (interactive) (message msg))))
        ;; (func (lambda () (interactive) (message "hoge")))) ;; これなら問題無し
    (define-key map [return] func)
    (define-key map [mouse-1] func)
    (define-key map [down-mouse-1] 'mouse-set-point)
    (add-text-properties 0 (- (length str) 1)
                         (list 'keymap map)
                         str)
    (insert str)))

(add-click-property "click!!" "Hello, World!")
  • こいつを評価して挿入された click!! って文字上で Enter or クリックしたら Hello, World! ってメッセージが表示されて欲しい。
  • 表示されるメッセージは呼出側で決めたい(not固定)
    • 固定であれば上記コードのコメント部分のようにやればうまくいく

現状

このままだと Symbol's value as variable is void: msg だからできない。

解決策として思いつくもの

  • msg をグローバル変数に代入するなどして、そいつを呼び出す関数を define-key に渡せばいける
    • あまりグローバル変数を増やしたくない気分
  • その他ローカルなスコープで完結できる方法があるのかどうか

回答

clを使えるのだったら

(require 'cl)

(defun add-click-property (str msg)
  (lexical-let ((msg msg))
    (let ((map (make-sparse-keymap))
          (func (lambda () (interactive) (message msg))))
      (define-key map [return] func)
      (define-key map [mouse-1] func)
      (define-key map [down-mouse-1] 'mouse-set-point)
      (add-text-properties 0 (- (length str) 1)
                           (list 'keymap map)
                           str)
      (insert str))
    ))

(add-click-property "click!!" "Hello, World!")

ではどうでしょう?

編集 履歴 (2)
  • 期待通りの動き確認できました!ありがとうございます。

    lexical-let、こういう動きができるのですね。まだまだ理解不足でした。
    -
  • twitterで見かけて、つい反応してしまいました:)
    お役に立てたらうれしいです。
    -

いまさらですが、バッククォート記法を使って msg を変数展開してしまうのも手ではないでしょうか。

(defun add-click-property (str msg)
  (let ((map (make-sparse-keymap))
        (func `(lambda () (interactive) (message ,msg))))
    (define-key map [return] func)
    (define-key map [mouse-1] func)
    (define-key map [down-mouse-1] 'mouse-set-point)
    (add-text-properties 0 (- (length str) 1)
                         (list 'keymap map)
                         str)
    (insert str)))

(add-click-property "click!!" "Hello, World!")
編集 履歴 (0)
  • なるほど。そういう手もあるですね。ありがとうございます! -
ウォッチ

この質問への回答やコメントをメールでお知らせします。