Làm thế nào tôi có thể tìm ra trong đó keymap mà một khóa bị ràng buộc?


63

Tôi đã bật lại phím 'd' gnus-article-mode, nhưng hành vi cũ của nó vẫn hoạt động khi điểm nằm trên tệp đính kèm. Tôi có thể thấy rằng việc đóng lại không có hiệu lực ở đó bằng cách thực hiện C-h k d, nhưng nó không cho tôi biết sơ đồ phím nào có hiệu lực vào thời điểm đó, để tôi có thể buộc lại nó.

Có cách nào để tìm ra nó?

Đây là một ví dụ chính xác: Tôi đang sử dụng cái ác và tôi muốn các bài viết ở chế độ chuyển động. Đối với bố trí bàn phím của tôi, tôi đã cấu hình 'phím' làm phím.

(evil-mode 1)
(add-to-list 'evil-motion-state-modes 'gnus-article-mode)
(setq evil-emacs-state-modes (remove 'gnus-article-mode evil-emacs-state-modes))
(define-key evil-motion-state-map "d" 'evil-previous-line)

Để đảm bảo các khóa ác được tính đến, tôi bỏ đặt khóa gnus trong bản đồ địa phương:

(defun as/alter-article-evil-map ()
  (local-unset-key "d"))
(add-hook 'gnus-article-mode-hook 'as/alter-article-evil-map)

Thật không may, khi điểm nằm trên tệp đính kèm, phím 'd' không còn tăng nữa nhưng nó cho phép tôi xóa tệp đính kèm. Tôi đoán một ràng buộc khác đang hoạt động tại thời điểm đó, do đó câu hỏi.

Giải pháp tôi đã sử dụng keymaps-at-pointdưới đây để tìm sơ đồ bàn phím được sử dụng là từ một thuộc tính văn bản. Sau đó tôi nhìn vào mã của hàm bị ràng buộc để tìm tên của sơ đồ bàn phím gnus-mime-button-map. Các mã sau đây làm những gì tôi muốn:

(defun as/alter-article-evil-map ()
  (define-key gnus-mime-button-map "d" nil))
(add-hook 'gnus-article-mode-hook 'as/alter-article-evil-map)

3
Sử dụng Lisp mã giả này và mô tả làm hướng dẫn cấp cao của bạn về cách Emacs tìm kiếm một khóa : Hướng dẫn sử dụng, nútSearching Keymaps . Xem thêm các nút Functions for Key LookupActive Keymaps.
vẽ

Có một lỗi khá lớn với câu trả lời ban đầu của tôi trong hàm thứ hai. Tôi vừa mới sửa nó, vì vậy nó sẽ có thể xác định vị trí bàn phím của bạn. Bạn có thể thử lại không?
Malabarba

Câu trả lời:


61

Emacs 25

Như @YoungFrog đã đề cập trong các bình luận, bắt đầu với Emacs 25.1 , C-h kphương pháp mô tả các liên kết khóa cũ cũng sẽ cho bạn biết sơ đồ phím nào được tìm thấy.

Trước Emacs 25

Có một số mã ở đây về điều này, nhưng nó không đầy đủ vì nó không bao gồm mọi thứ. Dưới đây là một phiên bản cải tiến của nó.

Khóa có thể được ràng buộc theo 9 cách (!). Cảm ơn @Drew cho liên kết này (cũng được bổ sung bởi điều này ) với danh sách đầy đủ. Theo thứ tự ưu tiên, chúng là:

  1. Một bộ khóa dành riêng cho thiết bị đầu cuối , overriding-terminal-local-map. Điều này được xác định bởi set-transient-mapchức năng.
  2. Một bản đồ ghi đè bộ đệm cục bộ , overriding-local-map. Nếu cái này được đặt, các mục 3 Ném8 sẽ bị bỏ qua (có thể là lý do tại sao bạn không thấy nhiều thứ này).
  3. Tại điểm thông qua keymapvăn bản-propety (có thể đi trên văn bản thực tế hoặc trên lớp phủ).
  4. Một biến về cơ bản mô phỏng các bộ chế độ nhỏ được kích hoạt khác nhau có thể , emulation-mode-map-alists.
  5. Một biến trong đó các chế độ chính có thể ghi đè các tổ hợp phím của chế độ phụ , minor-mode-overriding-map-alist.
  6. Các chế độ nhỏ thực tế , có bàn phím được lưu trữ trong minor-mode-map-alist.
  7. Tại điểm (một lần nữa), thông qua các thuộc tính local-mapvăn bản. Nếu điều này tồn tại, mục 8 được bỏ qua.
  8. Sơ đồ bàn phím đệm cục bộ tiêu chuẩn (trong đó các phím bàn phím chế độ chính hoặc đệm cục bộ đi), được trả về bởi hàm current-local-map.
  9. Các sơ đồ toàn cầu , được trả lại bởi current-global-map.

Ngoài ra còn có một mục bán 10. Bất kỳ lệnh nào được tìm thấy thông qua quy trình trên cũng có thể đã được khắc phục.

Hàm sau truy vấn một số khả năng này (khả năng cao nhất) và trả về hoặc in kết quả.

(defun locate-key-binding (key)
  "Determine in which keymap KEY is defined."
  (interactive "kPress key: ")
  (let ((ret
         (list
          (key-binding-at-point key)
          (minor-mode-key-binding key)
          (local-key-binding key)
          (global-key-binding key))))
    (when (called-interactively-p 'any)
      (message "At Point: %s\nMinor-mode: %s\nLocal: %s\nGlobal: %s"
               (or (nth 0 ret) "") 
               (or (mapconcat (lambda (x) (format "%s: %s" (car x) (cdr x)))
                              (nth 1 ret) "\n             ")
                   "")
               (or (nth 2 ret) "")
               (or (nth 3 ret) "")))
    ret))

Có các hàm dựng sẵn cho mỗi hàm này ngoại trừ hàm đầu tiên, vì vậy chúng ta phải tạo một hàm (cũng là phiên bản cải tiến của mã được liên kết ở trên).

(defun key-binding-at-point (key)
  (mapcar (lambda (keymap) (when (keymapp keymap)
                             (lookup-key keymap key)))
          (list
           ;; More likely
           (get-text-property (point) 'keymap)
           (mapcar (lambda (overlay)
                     (overlay-get overlay 'keymap))
                   (overlays-at (point)))
           ;; Less likely
           (get-text-property (point) 'local-map)
           (mapcar (lambda (overlay)
                     (overlay-get overlay 'local-map))
                   (overlays-at (point))))))

Vì bạn đang nói rằng hành vi được kích hoạt khi điểm nằm trên tệp đính kèm, rất có thể khóa phím này diễn ra trên lớp phủ hoặc thuộc tính văn bản.

Nếu điều đó không làm việc , hãy thử lệnh sau đây. Chỉ cần đặt con trỏ trên tệp đính kèm và làm M-x keymaps-at-point.

(defun keymaps-at-point ()
  "List entire keymaps present at point."
  (interactive)
  (let ((map-list
         (list
          (mapcar (lambda (overlay)
                    (overlay-get overlay 'keymap))
                  (overlays-at (point)))
          (mapcar (lambda (overlay)
                    (overlay-get overlay 'local-map))
                  (overlays-at (point)))
          (get-text-property (point) 'keymap)
          (get-text-property (point) 'local-map))))
    (apply #'message
           (concat 
            "Overlay keymap: %s\n"
            "Overlay local-map: %s\n"
            "Text-property keymap: %s\n"
            "Text-property local-map: %s")
           map-list)))

Điều này sẽ cho tôi biết liệu khóa có ràng buộc cục bộ hay không và nó được ràng buộc với lệnh nào, nhưng nó vẫn không cho tôi biết tên của sơ đồ khóa mà nó xuất phát.
nispio

@nispio nếu nó có một ràng buộc cục bộ, nó phải từ sơ đồ phím của chế độ chính hoặc từ một cuộc gọi đến khóa cục bộ. Thật không may, không có cách nào dễ dàng để phân biệt hai trường hợp.
Malabarba

1
@Malabarba Ý bạn là "Thật không may, không có cách nào dễ dàng để phân biệt hai trường hợp?" Chắc chắn các thông tin là tất cả hiện tại. Ngoài ra, có phải mọi chế độ chính đều có chính xác một bản đồ chế độ không? Nếu không, có cách nào để biết bản đồ chế độ chính nào đang hoạt động không?
nispio

1
Bắt đầu từ khi chưa được phát hành vào ngày 25, "Ch k" sẽ, trong một số trường hợp (tốt, "trong hầu hết các trường hợp" hy vọng) cho bạn biết trong sơ đồ bàn phím nào (chính xác hơn: một biểu tượng giữ sơ đồ đó làm giá trị của nó) xác định. đầu ra ví dụ:k runs the command gnus-summary-kill-same-subject-and-select (found in gnus-summary-mode-map), which is (...)
YoungFrog

2
Đối với bất kỳ ai quan tâm, đây là cam kết có liên quan hiển thị sơ đồ phím của ràng buộc chính trong emacs 25+.
Kaushal Modi

2

Đó là về:

(defun my-lookup-key (key)
  "Search for KEY in all known keymaps."
  (mapatoms (lambda (ob) (when (and (boundp ob) (keymapp (symbol-value ob)))
                      (when (functionp (lookup-key (symbol-value ob) key))
                        (message "%S" ob))))
            obarray))

Ví dụ cho (my-lookup-key (kbd "C-c v v"))tôi nhận danh sách trong *Message*bộ đệm:

global-map
term-pager-break-map
widget-global-map

Cách tiếp cận này hữu ích cho việc tìm kiếm sơ đồ bàn phím phụ được đưa vào sơ đồ khóa cấp cao hơn, ví dụ đầu ra từ:

(my-lookup-key (kbd "d"))

được vc-prefix-mapbao gồm trong global-map:

(eq (lookup-key global-map (kbd "C-x v")) 'vc-prefix-map)

Nếu bạn sửa đổi điều kiện lọc để bao gồm keymapp- bạn sẽ có thể tìm kiếm các tiền tố:

(defun my-lookup-key-prefix (key)
  "Search for KEY as prefix in all known keymaps."
  (mapatoms (lambda (ob) (when (and (boundp ob) (keymapp (symbol-value ob)))
                      (when (let ((m (lookup-key (symbol-value ob) key)))
                              (and m (or (symbolp m) (keymapp m))))
                        (message "%S" ob))))
            obarray))

Vì vậy, rst-mode-mapsẽ được tìm thấy trên cả hai:

(my-lookup-key-prefix (kbd "C-c C-t"))
(my-lookup-key-prefix (kbd "C-c C-t C-t"))

1

Tôi biết rằng những điều sau đây không trả lời cho câu hỏi Làm thế nào tôi có thể tìm ra sơ đồ phím nào , tuy nhiên nó giải quyết vấn đề cơ bản trong trường hợp này để đảm bảo rằng dkhóa hoạt động theo những gì người dùng muốn. Nếu được ưu tiên, tôi có thể xóa câu trả lời này và chuyển thành câu hỏi khác + câu trả lời liên quan đến vấn đề đó.

Là một phương pháp để ghi đè lên text-property/overlaybản đồ, bạn sẽ có thể sử dụng:

(let ((map (make-sparse-keymap)))
  (define-key map "d" 'evil-previous-line)
  (setq overriding-local-map map))

Theo Kiểm soát Bản đồ hoạt động , overriding-local-mapđược ưu tiên hơn mọi bản đồ hoạt động khác ngoài overriding-terminal-local-map.


Điều này phá vỡ mọi thứ: Tôi không còn có thể mở một tin nhắn trong chế độ tóm tắt, và cái ác và cột băng ngừng hoạt động.
brab

Điều này phá vỡ mọi thứ: Tôi không còn có thể mở một tin nhắn trong chế độ tóm tắt, và cái ác và cột băng ngừng hoạt động.
Emily Hoover

0

các nút emacs cung cấp buttons-display, với đối số tiền tố hiển thị trực quan đệ quy của tất cả các ràng buộc hiện tại.

(Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả của gói)

https://github.com/erjoalgo/emacs-buttons/blob/master/doc/img/sample-visualization.png

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.