我现在在尝试从evil切换到emacs键位,给evil里的功能一个一个找替代品。
一般需要替换重复字符的时候,我会用evil的cgn,emacs键位下用query-replace
代替。但是手动输入from-string
和to-string
有点麻烦,我就写了一个小包裹函数。使用方法:
(我绑定到C-x C-q)
- 选中要替换的地方
- C-x C-q
- 修改选区(选区会高亮)
- 完成后C-x C-q
- 进入query replace模式,
from-string
是原来的字符,to-string
是修改后的选区
一开始写的时候比较紧凑,后来不需要了,但是我也懒得改了,反正不复杂,可读性还可以
(defvar smart-query-edit-mode-overlay nil
"Overlay of region to be replaced.")
(define-minor-mode smart-query-edit-mode
"Edit region and query replace."
:lighter "QUERY"
(if smart-query-edit-mode
(if (not mark-active)
(setq smart-query-edit-mode nil)
(overlay-put
(setq smart-query-edit-mode-from-string
(buffer-substring
(region-beginning)
(region-end))
smart-query-edit-mode-overlay
(make-overlay (region-beginning)
(region-end)
nil
nil
t))
'face '(:inherit highlight)))
(overlay-put smart-query-edit-mode-overlay
'face '(:inherit default))
(goto-char (overlay-end
smart-query-edit-mode-overlay))
(query-replace smart-query-edit-mode-from-string
(buffer-substring-no-properties
(overlay-start
smart-query-edit-mode-overlay)
(overlay-end
smart-query-edit-mode-overlay)))
(delete-overlay
smart-query-edit-mode-overlay)))
2 个赞
解决了 from-string 输入的问题。
to-string 原本也是要输入的,如果输入内容简单,问题不大。如果输入内容复杂,我倾向开一个临时 buffer,优点是:
- 避免因误删导致 overlay 跟前后字符粘连
- 方便从别的缓冲区复制内容
如果改成临时 buffer 输入 to-string,那么 from-string 的方式也可以简化:
- 选中内容
-
C-x C-q
调用 query-replace+
并处于等待输入 to-string
,仍然保持原有的 query-replace
风格。此时根据 to-string
内容:
- 简单:直接输入,回车提交
- 复杂:按
C-c C-e
进入临时 buffer,输入完,按 C-c C-c
提交
抱歉忘了回了。我后来想了想,你说的其实只需要做一个自动前冲from-string的简单wrapper就好了。to-string的复杂编辑可以用minibuffer-edit搞定。(我记得有一个包是可以弹出一个temp buffer编辑minibuffer的内容)
(defvar query-replace-iedit-mode-overlay nil
"Overlay of region to be replaced.")
(defvar query-replace-iedit-mode-from-string nil)
(defvar query-replace-iedit-mode-delimited nil)
;;;###autoload
(define-minor-mode query-replace-iedit-mode
"Edit region and query replace."
:lighter "Q"
(if query-replace-iedit-mode
(let ((bounds (if (region-active-p) (cons (region-beginning) (region-end))
(bounds-of-thing-at-point 'symbol))))
(if (not bounds)
(setq query-replace-iedit-mode nil)
(overlay-put
(setq query-replace-iedit-mode-from-string
(buffer-substring
(car bounds)
(cdr bounds))
query-replace-iedit-mode-overlay
(make-overlay (car bounds)
(cdr bounds)
nil nil t))
'face '(:inherit highlight))
(setq query-replace-iedit-mode-delimited
(or (not (region-active-p))
(and current-prefix-arg
(not (eq current-prefix-arg '-)))))
(message "C-; replace, g:all, c:act e:edit replacement C-e:临时退出 C-cC-c:恢复")))
(let* ((start (overlay-start
query-replace-iedit-mode-overlay))
(end (overlay-end
query-replace-iedit-mode-overlay))
(to (buffer-substring-no-properties start end)))
(delete-overlay query-replace-iedit-mode-overlay)
(unless (string-equal query-replace-iedit-mode-from-string to)
(save-excursion
(delete-region start end)
(insert query-replace-iedit-mode-from-string)
(goto-char (point-min))
(query-replace query-replace-iedit-mode-from-string
to
query-replace-iedit-mode-delimited
(point)
(point-max)
nil (use-region-noncontiguous-p)))))))
略微改进了点,如果当前没有选中区域,则使用光标下的symbol 作为搜索内容
还有其他一些配置
;当敲 query-replace-map之外的按键不要退出query-replace
;; https://emacs.stackexchange.com/questions/80484/query-replace-ignore-events-not-binded-in-query-replace-map
(defvar vmacs-do-nothing-map
(let ((map (make-keymap)))
(set-char-table-range (nth 1 map) t 'ignore)
map))
(set-keymap-parent query-replace-map vmacs-do-nothing-map)
(define-key query-replace-map "g" 'automatic) ;old ! replace all automatic
(define-key query-replace-map "p" 'backup)
(define-key query-replace-map "c" 'act) ;old y
(define-key query-replace-map "\C-e" 'edit) ;临时退出 old C-r
(global-set-key (kbd "C-c C-c") #'exit-recursive-edit) ;query-replace C-r临时退出replace 后,可C-cC-c 继续replace
(setq query-replace-read-from-default #'vmacs-query-replace-read-from-default)
(defvar vmacs-query-replace-read-from-def nil)
(defun vmacs-query-replace-read-from-default()
(if (eq this-command 'vmacs-replace-all)
vmacs-query-replace-read-from-def
(if (use-region-p)
(buffer-substring-no-properties (region-beginning) (region-end))
(thing-at-point 'symbol))))
(defun vmacs-replace-all()
(interactive)
(save-excursion
(setq vmacs-query-replace-read-from-def
(if (use-region-p)
(buffer-substring-no-properties (region-beginning) (region-end))
(thing-at-point 'symbol)))
(goto-char (point-min))
(call-interactively #'query-replace)))
1 个赞