複数のキーでほぼ同一のコマンド


7

Visual Studioには、何かにポイントを置いて押すことができるこの優れた機能があり、ポイントのC-f3下にあるものの次のインスタンスを見つけて、それを記憶します。次に、を押しf3て次のインスタンスを見つけ、S-f3同じものを逆方向に検索します。

私が書いたelispを使用して、Emacsで同じことを行うことができます。(かさばるし、確かに悪いので省略します)。

私は何をしたいのは、のために同様の機能を有効にすると言う、することでf2f3f4、とf5。したがって、押すと、C-f2そのものを変数/関連付け配列/シンボルにどこかに保存することでそのポイントの下にあるものを検索C-f3し、別のものを押すと、emacsはその2番目のものを別個の変数に保存するため、検索できます一つf2f3は未来を押すことで、二つ目は未来を押すことで検索できます。

Control-X用に1つ、プレーンX用に1つ、Shift-X用に3つ目の関数を作成したいのですが、これにどのように取り組むかわかりません。

関数に現在のキー押下を要求させる必要があるのですか(la this-single-command-keys)、または(関数を既に押しているので、ユーザーにプロンプ​​トを表示せずに)からインタラクティブ関数にパラメーターを渡す方法を見つける方が良いですか?

インタラクティブ機能に追加情報を渡すにはどうすればよいですか?


質問はあまり明確ではありません、IMO。どの情報をどのように渡したいですか?プレフィックス引数を使用して、インタラクティブに情報を渡すことができます。コマンドは情報を要求することができます(あなたはそれを望まない、とあなたは言った)。関数は、グローバル変数から、またはファイルから情報を取得できます。...何をいつ、どのように渡したいですか?コードがある場合は、それを表示することもできます。これは、(これまでのところ)質問IMOよりも明確である可能性があります。
ドリュー

4
@Drew誤解を招くような一般的なタイトルを超えると、特定の設計上の問題があると思います。呼び出しごとに異なる変数を使用して状態を保存することを除いて、まったく同じことを行う複数のコマンドがあります。
Gilles「SO-邪悪なことをやめ

@ギレス:それが私がそれを不明確であるとして閉じるために投票しなかった理由です。まだはっきりしているかもしれません。たとえば、変数がそのように使用される場合、実際には何が問題になりますか?
ドリュー

Q:「インタラクティブ機能に追加情報を渡すにはどうすればよいですか?A:これは通常、次のようなコマンド接頭辞で行われC-uます。または、ミニバッファーからの選択を入力するようにユーザーに要求するか、特定のキーを選択するようユーザーに要求します。たとえば、fooの場合は1を押し、小節の場合は2を押し、bazの場合は3を押します。[質問全体の約90%は興味深いものですが、最後の質問/回答(私の意見では)には関係ありません。最後から2番目の質問は意見を求めます。]
法律家

回答:


4

1つのコマンドを複数のキーシーケンスにバインドし、を使用してコマンド内の呼び出しキーシーケンスにアクセスできますthis-command-keys。次のコードでそれを示します。同じコマンドがありmy-command、間接的にキーの配列にバインドされているF9C-c aC-c b。これにより、「間接的」とは薄いラッパーが存在することを意味しますmy-command-wrapper。このラッパーはインタラクティブコマンドとして使用され、非常にシンプルに保たれています。デバッグセッションでののedebug-defun戻り値はthis-command-keys意味をなさないため、これを装備するべきではありません。

サンプルコードは、個別の呼び出しキーシーケンスに対して個別の履歴を保持する方法を示しています。

キーシーケンスを初めて呼び出す場合、プレフィックス引数を使用する場合、またはシフト修飾子を使用する場合は、引数値を変更できます。my-commandそれ以外の場合は、履歴の最後の引数値が使用されます。

(defvar my-command-history-alist nil
  "Association of key sequence")
(defvar my-command--history nil)

(defun my-command-wrapper (&rest args)
  "Thin wrapper for `my-command'.
Adds stringified `this-command-keys' as the first argument to ARGS.
Don't instrument this function with `edebug-defun' otherwise
`this-command-keys' gives the wrong answer!"
  (interactive)
  (apply #'my-command (format "%s" (this-command-keys))
     args))

(defun my-command (keys &optional what)
  "Depending on the call sequence KEYS and PREFIX for this command do something with argument WHAT."
  (unless what
   (let* ((key-history (assoc-string keys my-command-history-alist))
      (my-command--history (cdr key-history)))
     (if (or (null my-command--history)
         current-prefix-arg
         this-command-keys-shift-translated)
     (progn
       (setq what (read-string (format "Input string for key sequence \"%s\":" keys) (car my-command--history) 'my-command--history))
       (if key-history
           (setcdr key-history my-command--history)
         (push (cons keys my-command--history) my-command-history-alist)))
       (setq what (car my-command--history)))))
  (message "Doing something with \"%s\"" what))

(global-set-key (kbd "<f9>") #'my-command-wrapper)
(global-set-key (kbd "C-c a") #'my-command-wrapper)
(global-set-key (kbd "C-c b") #'my-command-wrapper)

4

これを論理的に見てみましょう。ほぼ同じコマンドをC-f2andにバインドしたいとしC-f3ます。これらのコマンドの唯一の違いは、ポイント内の物をf2メモリに保存するか、メモリに保存するかf3です。次に、さまざまなコマンドを作成するか、バインドされているキーに応じて動作が異なる単一のコマンドを用意する必要があります。

バインディングの作成時に作成されたコマンドにキーをバインドできます。define-keyand friends へのコマンド引数は、シンボルの形式のコマンド名である必要はありません。ラムダ式にすることができます。

(global-set-key [C-f3] (lambda ()
                         (interactive)
                         …))

これは機能しますが、あまり良くありません。たとえば、ヘルプコマンドとコマンド履歴では、コマンド名は表示されません。

コードの大部分を関数に入れ、小さなラッパー関数を定義できます。大量のコードを繰り返さないようにするには、関数またはマクロでラッパー関数を生成します。

(defun repeat-search-thing-at-point-forward (memory)
  (search-forward (symbol-value memory)))
(defun repeat-search-thing-at-point-backward (memory)
  (search-backward (symbol-value memory)))
(defun search-thing-at-point (memory)
  "Search the thing at point.
Store the thing in MEMORY for a future search with
`repeat-search-thing-at-point-forward' and
`repeat-search-thing-at-point-backward'."
  (set memory (thing-at-point 'word))
  (repeat-search-thing-at-point-forward memory))
(defun define-search-thing-at-point (map key)
  "Define commands to search a thing at point "
  (let* ((memory-variable (intern (format "search-memory-%s" key)))
         (set-function (intern (format "search-thing-at-point-%s" key)))
         (forward-function (intern (format "repeat-search-thing-at-point-forward-%s" key)))
         (backward-function (intern (format "repeat-search-thing-at-point-backward-%s" key)))
         (forward-key (vector key))
         (backward-key (vector (list 'shift key)))
         (set-key (vector (list 'control key))))
    (eval `(progn
             (defvar ,memory-variable nil
               ,(format "The last thing searched with \\[%s]." set-function))
             (defun ,set-function ()
               ,(format "Search the thing at point.
Use \\[%s] and \\[%s] to repeat the search forward and backward
respectively." forward-function backward-function)
               (interactive "@")
               (search-thing-at-point ',memory-variable))
             (defun ,forward-function ()
               ,(format "Search forward for the last thing searched with \\[%s]." set-function)
               (interactive "@")
               (repeat-search-thing-at-point-forward ',memory-variable))
             (defun ,backward-function ()
               ,(format "Search backward for the last thing searched with \\[%s]." set-function)
               (interactive "@")
               (repeat-search-thing-at-point-backward ',memory-variable))
             (define-key map ',set-key #',set-function)
             (define-key map ',forward-key #',forward-function)
             (define-key map ',backward-key #',backward-function)
             t))))

(define-search-thing-at-point global-map 'f2)
(define-search-thing-at-point global-map 'f3)
(define-search-thing-at-point global-map 'f4)

または、機能ごとに1つのコマンドを定義することもできます(最初の検索、前方への繰り返し、後方への繰り返し)。これはやや柔軟性が低くなりますが(たとえば、 `search-thing-at-point-f2 'をH-s空想が必要な場合に再バインドすることはできません)、冗長性ははるかに低くなります。

コマンドは、それを呼び出したキーを見つけることができます。変数を使用するのが最も簡単な方法ですlast-command-event

(defvar search-thing-memory nil
  "History of things searched with `search-thing-at-point'.")
(defun search-thing-at-point (key)
  "Search the thing at point.
Store the thing in MEMORY for a future search with
`repeat-search-thing-at-point-forward' and
`repeat-search-thing-at-point-backward'."
  (interactive (list (event-basic-type last-command-event)))
  (let ((thing (thing-at-point 'word))
    (memory (assq key search-thing-memory)))
    (if memory
    (setcdr memory thing)
      (setq search-thing-memory (cons (cons key thing)
                      search-thing-memory)))
    (search-forward thing)))
(defun repeat-search-thing-at-point-forward (key)
  "Repeat the last thing searched with `search-thing-at-point'
with a matching key binding."
  (interactive (list (event-basic-type last-command-event)))
  (search-forward (cdr (assq key search-thing-memory))))
(defun repeat-search-thing-at-point-backward (key)
  "Repeat the last thing searched with `search-thing-at-point'
with a matching key binding."
  (interactive (list (event-basic-type last-command-event)))
  (search-backward (cdr (assq key search-thing-memory))))

(global-set-key [C-f2] 'search-thing-at-point)
(global-set-key [C-f3] 'search-thing-at-point)
(global-set-key [C-f4] 'search-thing-at-point)
(global-set-key [f2] 'repeat-search-thing-at-point-forward)
(global-set-key [f3] 'repeat-search-thing-at-point-forward)
(global-set-key [f4] 'repeat-search-thing-at-point-forward)
(global-set-key [S-f2] 'repeat-search-thing-at-point-backward)
(global-set-key [S-f3] 'repeat-search-thing-at-point-backward)
(global-set-key [S-f4] 'repeat-search-thing-at-point-backward)

私はあなたの提案されたインターフェースがEmacsへの特に有用な追加だとは思いません。Emacsの基本的な組み込み検索には、事物をその時点で検索し、過去の検索を繰り返す簡単な方法があります。


2

Elispプログラミングの質問ではなく、元のユースケースに対処することで、パッケージhighlight-symbolは目的どおりに機能します。私は長年幸せなユーザーでした。

http://nschum.de/src/emacs/highlight-symbol/

パッケージの説明から:

;; Add the following to your .emacs file:
;; (require 'highlight-symbol)
;; (global-set-key [(control f3)] 'highlight-symbol)
;; (global-set-key [f3] 'highlight-symbol-next)
;; (global-set-key [(shift f3)] 'highlight-symbol-prev)
;; (global-set-key [(meta f3)] 'highlight-symbol-query-replace)
;;
;; Use `highlight-symbol' to toggle highlighting of the symbol at
;; point throughout the current buffer.  Use `highlight-symbol-mode' to keep the
;; symbol at point highlighted.
;;
;; The functions `highlight-symbol-next', `highlight-symbol-prev',
;; `highlight-symbol-next-in-defun' and `highlight-symbol-prev-in-defun' allow
;; for cycling through the locations of any symbol at point.  Use
;; `highlight-symbol-nav-mode' to enable key bindings (M-p and M-p) for
;; navigation. When `highlight-symbol-on-navigation-p' is set, highlighting is
;; triggered regardless of `highlight-symbol-idle-delay'.
;;
;; `highlight-symbol-query-replace' can be used to replace the symbol.

いいね!この種のものにはいくつかのオプションがあり、実際にはHiLockを使用して強調表示を行っていました(主にEmacsに既に組み込まれているためです(どのバージョンを忘れたか)
MikeTheTall

また、私はあなたが持っているものを愛していますが、質問は特に私が探しているものを複数のキーに「保存」することを求めました。私はF3のための仕事にこれを必要があると思いますので、また別途F4で何か他のものを検索することができるようにし、その後などF5、で3つ目の検索
MikeTheTall
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.