Các lệnh gần giống nhau trên nhiều khóa


7

Visual Studio có tính năng tuyệt vời này, nơi bạn có thể đặt điểm vào một cái gì đó, nhấn C-f3và cả hai sẽ tìm thấy phiên bản tiếp theo của điều đó và nó sẽ ghi nhớ nó. Sau đó, bạn có thể nhấn f3để tìm phiên bản tiếp theo và S-f3để tìm kiếm điều tương tự, nhưng ngược lại.

Tôi có thể làm điều tương tự trong Emacs bằng cách sử dụng một số elisp mà tôi đã viết. (Nó cồng kềnh, và tôi chắc chắn là xấu, vì vậy tôi sẽ bỏ qua nó).

Những gì tôi muốn làm là để kích hoạt chức năng tương tự cho, nói, f2, f3, f4, và f5. Do đó, nhấn C-f2tìm kiếm thứ dưới điểm bằng cách lưu thứ đó vào một mảng / biểu tượng / liên kết ở đâu đó, nhấn C-f3vào một thứ khác khiến emacs lưu thứ thứ hai đó vào một biến khác biệt và vì vậy tôi có thể tìm kiếm cho điều đầu tiên bằng cách nhấn f2trong tương lai, và tôi có thể tìm kiếm điều thứ hai bằng cách nhấn f3trong tương lai.

Tôi muốn tạo một chức năng duy nhất cho Control-X, một chức năng khác cho X đơn giản và thứ ba cho Shift-X, nhưng tôi không chắc cách tiếp cận này.

Có tốt hơn không khi có chức năng yêu cầu bấm phím hiện tại (a la this-single-command-keys) hoặc tìm cách chuyển tham số từ chức năng tương tác ( mà không nhắc người dùng, vì họ đã nhấn phím)?

Làm thế nào để một người truyền thông tin bổ sung vào một chức năng tương tác?


Câu hỏi không rõ ràng lắm, IMO. Thông tin gì và làm thế nào để bạn muốn vượt qua nó? Bạn có thể sử dụng một đối số tiền tố để truyền thông tin tương tác. Một lệnh có thể nhắc thông tin (bạn không muốn điều đó, bạn nói). Một hàm có thể lấy thông tin từ các biến toàn cục hoặc từ một tệp hoặc ... Bạn muốn vượt qua cái gì, khi nào và như thế nào? Nếu bạn có một số mã, có thể hiển thị nó - điều đó có thể rõ ràng hơn câu hỏi của bạn (cho đến nay), IMO.
Drew

4
@Drew Tôi nghĩ rằng một khi bạn vượt qua tiêu đề chung dễ gây hiểu lầm, có một vấn đề thiết kế cụ thể ở đó: nhiều lệnh thực hiện chính xác cùng một điều, ngoại trừ việc chúng sử dụng một biến khác nhau để lưu trữ trạng thái từ lần gọi này sang lần gọi tiếp theo.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles: Đó là lý do tại sao tôi không bỏ phiếu để đóng nó là không rõ ràng. Nó vẫn có thể rõ ràng hơn. Ví dụ, nếu các biến được sử dụng theo cách đó, thì câu hỏi thực sự là gì?
Drew

Hỏi : " Làm thế nào để truyền thông tin bổ sung vào chức năng tương tác? " A : Điều này thường được thực hiện với tiền tố lệnh như C-u; hoặc, bằng cách nhắc người dùng nhập một lựa chọn từ xe buýt nhỏ hoặc yêu cầu người dùng chọn một khóa cụ thể; ví dụ: nhấn 1 cho foo, nhấn 2 cho thanh, nhấn 3 cho baz. [Khoảng 90% toàn bộ câu hỏi là thú vị , nhưng không liên quan đến câu hỏi / câu trả lời cuối cùng (theo ý kiến ​​của tôi). Câu hỏi thứ hai cho câu hỏi cuối cùng tìm kiếm một ý kiến .]
luật

Câu trả lời:


4

Bạn có thể liên kết một lệnh với một vài chuỗi khóa và truy cập chuỗi khóa gọi trong lệnh với this-command-keys. Điều đó được thể hiện với mã sau đây. Có lệnh cùng my-commandlà gián tiếp liên kết với các chuỗi chìa khóa F9, C-c aC-c b. Do đó "gián tiếp" có nghĩa là có một lớp bọc mỏng my-command-wrapper. Đó là trình bao bọc được sử dụng như lệnh tương tác và được giữ rất đơn giản. Không nên sử dụng công cụ này edebug-defunvì giá trị trả về của this-command-keysphiên gỡ lỗi không có ý nghĩa.

Mã ví dụ minh họa cách bạn có thể giữ các lịch sử riêng biệt cho các chuỗi khóa gọi riêng biệt.

Nếu bạn gọi các chuỗi khóa lần đầu tiên hoặc với tiền tố arg hoặc với công cụ sửa đổi shift, thì bạn có thể thay đổi giá trị đối số cho my-commandgiá trị đối số cuối cùng từ lịch sử được sử dụng.

(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

Hãy xem xét điều này một cách logic: bạn muốn có các lệnh gần giống nhau bị ràng buộc C-f2C-f3. Sự khác biệt duy nhất giữa các lệnh này là liệu chúng lưu trữ vật dưới điểm trong f2bộ nhớ hay trong f3bộ nhớ. Sau đó, bạn cần phải xây dựng các lệnh khác nhau hoặc bạn cần phải có một lệnh duy nhất có hành vi phụ thuộc vào khóa nào được ràng buộc.

Bạn có thể liên kết một khóa với một lệnh được xây dựng tại thời điểm bạn tạo liên kết. Đối số lệnh define-keyvà bạn bè không phải là tên lệnh dưới dạng ký hiệu, nó có thể là biểu thức lambda.

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

Điều này hoạt động, nhưng nó không phải là rất tốt đẹp. Ví dụ: các lệnh trợ giúp và lịch sử lệnh sẽ không hiển thị cho bạn một tên lệnh.

Bạn có thể đặt phần lớn mã trong một hàm và xác định các hàm bao bọc nhỏ. Để tránh lặp lại nhiều mã, có một hàm hoặc macro tạo các hàm bao bọc.

(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)

Ngoài ra, bạn có thể xác định một lệnh duy nhất cho từng chức năng (tìm kiếm đầu tiên, lặp lại tiến, lặp lại lùi). Điều này hơi kém linh hoạt (ví dụ: bạn không thể rebind `search-thing-at-point-f2 thành H-snếu nó ưa thích của bạn) nhưng ít dài dòng hơn.

Một lệnh có thể tìm thấy khóa nào được gọi nó. Cách dễ nhất cho bạn là sử dụng biến 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)

Tôi không nghĩ giao diện được đề xuất của bạn là một bổ sung đặc biệt hữu ích cho Emacs. Tìm kiếm tích hợp cơ bản của Emacs có những cách dễ dàng để tìm kiếm điểm đó và lặp lại các tìm kiếm trong quá khứ.


2

Giải quyết trường hợp sử dụng ban đầu của bạn thay vì câu hỏi lập trình Elisp, gói highlight-symbollàm những gì bạn muốn. Tôi đã là một người dùng hạnh phúc trong nhiều năm.

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

Từ mô tả gói:

;; 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.

Đẹp! Tôi thấy rằng có một số tùy chọn cho loại điều này và thực sự đã sử dụng HiLock để làm nổi bật (chủ yếu là vì nó đã được tích hợp vào Emacs (tôi quên phiên bản nào).
MikeTheTall

Ngoài ra - Tôi yêu những gì bạn đã có, nhưng câu hỏi được hỏi cụ thể là 'lưu' thứ mà tôi đang tìm kiếm vào nhiều khóa. Vì vậy, tôi cần điều này để làm việc cho F3, và cũng có thể tìm kiếm riêng một thứ khác tại F4, và sau đó tìm kiếm thứ ba tại F5, v.v.
MikeTheTall
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.