有没有像Vim里:s
那种快速替换当前行的函数?
我知道可以自己写,不过写之前我想问问有没有现成的,或者更好的操作。
更新:我写了一个
有没有像Vim里:s
那种快速替换当前行的函数?
我知道可以自己写,不过写之前我想问问有没有现成的,或者更好的操作。
更新:我写了一个
C-a C-SPACE C-n M-Shift-5
不了解 Vim,Emacs 自带的替换命令像 M-%
(query-replace
) 之类的支持 Region。
自己写吧, 写的比发帖快
写了一个一键替换。这回不用动脑子操作了。
(defvar inline-replace-last-input "")
(defvar inline-replace-history nil)
(defvar inline-replace-count 1)
(defvar inline-replace-original-buffer nil)
(defvar inline-replace-overlay nil)
(defvar inline-replace-beg nil)
(defvar inline-replace-minibuffer-map (let ((map minibuffer-local-map))
(define-key map (kbd "C-p") #'inline-replace-previous)
(define-key map (kbd "C-n") #'inline-replace-next)
map))
(defun inline-replace-previous ()
"Previous match."
(interactive)
(when (> inline-replace-count 1)
(decf inline-replace-count)))
(defun inline-replace-next ()
"Next match."
(interactive)
(incf inline-replace-count))
(defun inline-replace ()
"Search for the matching REGEXP COUNT times before END.
You can use \\&, \\N to refer matched text."
(interactive)
(condition-case nil
(save-excursion
(setq inline-replace-beg (progn (beginning-of-line) (point-marker)))
(setq inline-replace-original-buffer (current-buffer))
(add-hook 'post-command-hook #'inline-replace-highlight)
(let* ((minibuffer-local-map inline-replace-minibuffer-map)
(input (read-string "regexp/replacement: " nil 'inline-replace-history))
(replace (or (nth 1 (split-string input "/")) "")))
(goto-char inline-replace-beg)
(re-search-forward (car (split-string input "/")) (line-end-position) t inline-replace-count)
(unless (equal input inline-replace-last-input)
(push input inline-replace-history)
(setq inline-replace-last-input input))
(remove-hook 'post-command-hook #'inline-replace-highlight)
(delete-overlay inline-replace-overlay)
(replace-match replace)
(setq inline-replace-count 1)))
((quit error)
(delete-overlay inline-replace-overlay)
(remove-hook 'post-command-hook #'inline-replace-highlight)
(setq inline-replace-count 1))))
(defun inline-replace-highlight ()
"Highlight matched text and replacement."
(when inline-replace-overlay
(delete-overlay inline-replace-overlay))
(when (>= (point-max) (length "regexp/replacement: "))
(let* ((input (buffer-substring-no-properties (1+ (length "regexp/replacement: ")) (point-max)))
(replace (or (nth 1 (split-string input "/")) "")))
(with-current-buffer inline-replace-original-buffer
(goto-char inline-replace-beg)
;; if no match and count is greater than 1, try to decrease count
;; this way if there are only 2 match, you can't increase count to anything greater than 2
(while (and (not (re-search-forward (car (split-string input "/")) (line-end-position) t inline-replace-count))
(> inline-replace-count 1))
(decf inline-replace-count))
(setq inline-replace-overlay (make-overlay (match-beginning 0) (match-end 0)))
(overlay-put inline-replace-overlay 'face '(:strike-through t :background "#75000F"))
(overlay-put inline-replace-overlay 'after-string (propertize replace 'face '(:background "#078A00")))))))
UPDATE:我把prompt里的Replace/replacement
改成regexp/replacement
了。
UPDATE:C-n/p
替换下一个/上一个符合regexp的字符
UPDATE: 然后发现了轮子……
UPDATE:修复了一个很傻的错误:inline-replace-count
应该恢复为1
,我写成了0
(这,修改帖子也会被推送到顶端吗……)