4

emacs 24 ではset-temporary-overlay-map、ユーザーがそのキーマップで定義されていないキーを押すとすぐに非アクティブになるキーマップをアクティブにします。

オーバーレイ キーマップを手動で無効にする必要がありますが、これを行うための機能は特に提供されていません。ソースコードをのぞきました:

(defun set-temporary-overlay-map (map &optional keep-pred)
  "Set MAP as a temporary keymap taking precedence over most other keymaps.
Note that this does NOT take precedence over the \"overriding\" maps
`overriding-terminal-local-map' and `overriding-local-map' (or the
`keymap' text property).  Unlike those maps, if no match for a key is
found in MAP, the normal key lookup sequence then continues.

Normally, MAP is used only once.  If the optional argument
KEEP-PRED is t, MAP stays active if a key from MAP is used.
KEEP-PRED can also be a function of no arguments: if it returns
non-nil then MAP stays active."
  (let* ((clearfunsym (make-symbol "clear-temporary-overlay-map"))
         (overlaysym (make-symbol "t"))
         (alist (list (cons overlaysym map)))
         (clearfun
          ;; FIXME: Use lexical-binding.
          `(lambda ()
             (unless ,(cond ((null keep-pred) nil)
                            ((eq t keep-pred)
                             `(eq this-command
                                  (lookup-key ',map
                                              (this-command-keys-vector))))
                            (t `(funcall ',keep-pred)))
               (set ',overlaysym nil)   ;Just in case.
               (remove-hook 'pre-command-hook ',clearfunsym)
               (setq emulation-mode-map-alists
                     (delq ',alist emulation-mode-map-alists))))))
    (set overlaysym overlaysym)
    (fset clearfunsym clearfun)
    (add-hook 'pre-command-hook clearfunsym)
    ;; FIXME: That's the keymaps with highest precedence, except for
    ;; the `keymap' text-property ;-(
    (push alist emulation-mode-map-alists)))

現在のオーバーレイ キーマップを非アクティブ化するメカニズムは次のようになっていると思います。

  1. 関数clearfunは、すべてのコマンドの前に実行されるように定義され、呼び出された前のコマンドがマップにあったかどうかをチェックします。
  2. マップにない場合は、次のコードが実行されます。

(なぜこの形式は正しくないのですか?わかりました、今はそうです)

(set ',overlaysym nil)   ;Just in case.
               (remove-hook 'pre-command-hook ',clearfunsym)
               (setq emulation-mode-map-alists
                     (delq ',alist emulation-mode-map-alists))

したがって、私が本当に望んでいるのは、適切な変数を使用して上記のコードを実行することです。しかし、このコードはクロージャーの一部であり、クロージャー内overlaysymclearfunsym,などの値を決定するのに問題がありますalist。-ingで探してみましclearfunsymたが、不思議なことに何もありません (別の関係のないフックを除いて)。evalpre-command-hook

(add-hook 'pre-command-hook clearfunsym)関数定義の再評価とデバッグを試みたところ、が , のpre-command-hookままであることに気付き、nil困惑しました。私はソース コードをさらに深く掘り下げていきます。この関数の独自のバージョンを書き直して、force-clear後で呼び出すことができる関数を追加で作成するかもしれませんが、誰かがよりクリーンなソリューションを見つけることができるかもしれません。

4

3 に答える 3

2

あなたが書いた: 「overlaysym のような値を決定するのに問題があります」 しかし、overlaysym は評価されます。値は (make-symbol "t") です。t という名前のシンボルです。これにより、アクセスが困難になりますが、不可能ではありません。次の行を評価すると、コメントアウトされた結果が得られます。

(setq mysym (make-symbol "t"))
;; t
(set mysym 'test)
;; test
(symbol-value mysym)
;; test

同じことが、clear-temporary-overlay-map に評価される clearfusym にも当てはまります。

もう 1 つコメント: set-temporary-overlay-map をデバッグするとき、キーを押しています。これらのキーストロークが clear-temporary-overlay-map と clear pre-command-hook を呼び出しているのではないでしょうか?

それを試してください:

(defadvice set-temporary-overlay-map (after test activate)
  (setq test-pre-command-hook pre-command-hook))

次に text-scale-mode (C-+) に入り、test-pre-command-hook を調べます。私のコンピューターで評価test-pre-command-hookしているインスタンスの場合、次のリストが表示されました。

( clear-temporary-overlay-map tooltip-hide)。

で同じことをしましょうemulation-mode-map-alists。次に、次のようになります。

(((t keymap (67108912 . #[0 "\301\302\300!!\207" [1 text-scale-adjust abs] 3 "
...

(fn)" nil]) (45 . #[0 "\301\302\300!!\207" [1 text-scale-adjust abs] 3 "
(fn)" nil]))))

特に、t冒頭に注意してください。つまりt、先頭に記号があるリストを検索することで、オーバーレイ マップを見つけることができます。

オーバーレイ マップを削除するには、次のコード フラグメントのようなもので十分です。

(when (assoc-string "t" (car emulation-mode-map-alists))
  (setq emulation-mode-map-alists (cdr emulation-mode-map-alists)))

when単なる保護です。(おそらく、以前に別の何かがマップを殺してしまったのでしょうか?) 一時的なマップは常に前面にある必要があります ( pushinのためset-temporary-overlay-map)。その前に別のキーマップを配置する機会はありますか? たぶん、時間制御された何か?emulation-mode-map-alists次に、キーマップで連想リストを検索する必要があります(make-symbol "t")

于 2013-10-11T17:32:08.263 に答える
0

オリジナルset-temporary-overlay-mapは非常に紛らわしく、読みにくく、多くの不必要な汚いハックやトリックに依存しています。レキシカル バインディングを使用して、より明確でモジュール化された方法で関数を書き直しました。

  1. 改訂された関数は、lexical-binding を使用して、eager-lazy 評価ハックを置き換えます (この場合、それらは完全に不要です)。
  2. 元の関数は、関数ごとに 2 つのシンボルを不必要に作成します (clearfunsymclear-funは基本的に同じもので、後者は前者の関数セルとしてのみ使用されます)。
  3. 改訂された関数は、条件が満たされた場合 (つまり、最後のキーがオーバーレイ マップになかった場合) に pre-command-hookforce-overlay-clearによって呼び出される を提供します。clear-temporary-overlay-mapこのマップを手動でクリアしたい場合は、ユーザーが呼び出すこともできます。この関数は 自身の関数セルを無効force-overlay-clearにするため、2 回呼び出すとエラーになります。
  4. クリアが適用可能かどうかをテストするコードを簡素化しました。

他のコードがこのシンボル(overlaysym (make-symbol "t"))に依存するのではないかと恐れて、非常に奇妙な を取り除くことができませんでした。tしたがって、改訂版はほぼ確実にオリジナル版と同等です。私はこれをテストしましたが、うまく機能します。

(defun set-temporary-overlay-map (map &optional keep-pred)
  (lexical-let* (
   (map map)
   (keep-pred keep-pred)
   (clear-temporary-overlay-map  nil)
   (force-overlay-clear nil)
   (overlaysym (make-symbol "t"))
   (alist (list (cons overlaysym map))))

    (fset 'force-overlay-clear (lambda ()
          (message "clearing overlay")              
          ;this is a copy of the original code to clear
          (set overlaysym nil)   ;Just in case.
          (remove-hook 'pre-command-hook 'clear-temporary-overlay-map)
          (setq emulation-mode-map-alists
          (delq alist emulation-mode-map-alists))
          ;void the function cell of 'force-overlay-clear', an attempt to clear overlay twice will err
          (fset 'force-overlay-clear nil)
    ))
   (fset 'clear-temporary-overlay-map (lambda ()
          (unless (cond
         ((null keep-pred) nil)
         (keep-pred
          (lookup-key map (this-command-keys-vector)))
         (t (funcall keep-pred)))
      (force-overlay-clear)
      )))

    (set overlaysym overlaysym)
    (add-hook 'pre-command-hook 'clear-temporary-overlay-map)
    ;; FIXME: That's the keymaps with highest precedence, except for
    ;; the `keymap' text-property ;-
    (push alist emulation-mode-map-alists))
  )
于 2013-10-13T15:00:10.987 に答える