基于标记对象的键盘宏展开插件

@VagrantJoker

markmaro 主要有这几种玩法:

  1. 直接 mark word、 mark line、 mark imenu 后, 执行键盘宏, 调用 markmacro-apply-*
  2. markmacro-rect-set 设置矩形操作后, 执行 delete、 insert 和 replace 操作
  3. markmacro-rect-set 设置矩形操作后, 调用 markmacro-rect-mark-* 命令直接转换标记, 执行键盘宏, 调用 markmacro-apply-*
  4. markmacro-secondary-region-set 设置二次选中区域, 调用 markmacro-secondary-region-mark-cursors , 执行键盘宏, 调用 markmacro-apply-*

这四种玩法分别对应的场景是:

  1. 标记同范围的字符串(注意不是同名)进行键盘宏
  2. Emacs内置的矩形操作
  3. 矩形列对应的范围或者symbols进行键盘宏操作
  4. 选中区域同名字符串的键盘宏操作

所以, 我认为 markmacro-mark-lines 不应该和 secondary-region 以及 rect 相关, 它们是不同场景下的不同命令, 混在一起就搞复杂了。

1 个赞

如果你要限定选择区域的非空行, 直接选择以后 markmacro-mark-lines 就好了呀, secondary-region 增加了一步操作, secondary-region 存在的意义是你又要限定范围, 又要选择限定范围的某个同名单词, 这种附加操作才需要 secondary-region 呀。

不用道歉, 只是要理清楚逻辑, 我觉得现在的补丁有点乱。

那就回退吧,正好这个补丁有个 bug ,确实是我对矩形操作的理解不够深入。

case8

增加了 markmacro-mark-chars 命令, 特别适合快速重构字符串内的这种 ; 场景。

有大佬适配一下 evil的选区么,用evil选中区域,然后调用 markmacro 会报下面的错

Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p nil)
  goto-char(nil)
  (save-excursion (goto-char mark-bound-start) (while (and (<= (point) mark-bound-end) (> (point) last-point)) (setq current-bound (bounds-of-thing-at-point 'word)) (if current-bound (progn (if (member current-bound mark-bounds) mark-bounds (setq mark-bounds (append mark-bounds (list current-bound)))))) (setq last-point (point)) (forward-word)) mark-bounds)
  (let ((mark-bound-start (car bound)) (mark-bound-end (cdr bound)) (last-point 0) (mark-bounds 'nil) current-bound) (save-excursion (goto-char mark-bound-start) (while (and (<= (point) mark-bound-end) (> (point) last-point)) (setq current-bound (bounds-of-thing-at-point 'word)) (if current-bound (progn (if (member current-bound mark-bounds) mark-bounds (setq mark-bounds (append mark-bounds ...))))) (setq last-point (point)) (forward-word)) mark-bounds))
  (let ((bound (if (region-active-p) (cons (region-beginning) (region-end)) (bounds-of-thing-at-point 'symbol)))) (let ((mark-bound-start (car bound)) (mark-bound-end (cdr bound)) (last-point 0) (mark-bounds 'nil) current-bound) (save-excursion (goto-char mark-bound-start) (while (and (<= (point) mark-bound-end) (> (point) last-point)) (setq current-bound (bounds-of-thing-at-point 'word)) (if current-bound (progn (if (member current-bound mark-bounds) mark-bounds (setq mark-bounds ...)))) (setq last-point (point)) (forward-word)) mark-bounds)))
  (let ((tail (let ((bound (if (region-active-p) (cons ... ...) (bounds-of-thing-at-point ...)))) (let ((mark-bound-start (car bound)) (mark-bound-end (cdr bound)) (last-point 0) (mark-bounds 'nil) current-bound) (save-excursion (goto-char mark-bound-start) (while (and ... ...) (setq current-bound ...) (if current-bound ...) (setq last-point ...) (forward-word)) mark-bounds))))) (while tail (let ((bound (car tail))) (let* ((overlay (make-overlay (car bound) (cdr bound)))) (overlay-put overlay 'face 'markmacro-mark-face) (add-to-list 'markmacro-overlays overlay t)) (setq tail (cdr tail)))))
  (progn (if (region-active-p) (progn (deactivate-mark))) (let ((tail (let ((bound (if ... ... ...))) (let ((mark-bound-start ...) (mark-bound-end ...) (last-point 0) (mark-bounds ...) current-bound) (save-excursion (goto-char mark-bound-start) (while ... ... ... ... ...) mark-bounds))))) (while tail (let ((bound (car tail))) (let* ((overlay (make-overlay ... ...))) (overlay-put overlay 'face 'markmacro-mark-face) (add-to-list 'markmacro-overlays overlay t)) (setq tail (cdr tail))))) (markmacro-select-last-overlay))
  (if (if (region-active-p) (cons (region-beginning) (region-end)) (bounds-of-thing-at-point 'symbol)) (progn (if (region-active-p) (progn (deactivate-mark))) (let ((tail (let ((bound ...)) (let (... ... ... ... current-bound) (save-excursion ... ... mark-bounds))))) (while tail (let ((bound (car tail))) (let* ((overlay ...)) (overlay-put overlay 'face 'markmacro-mark-face) (add-to-list 'markmacro-overlays overlay t)) (setq tail (cdr tail))))) (markmacro-select-last-overlay)))
  markmacro-mark-words()
  funcall-interactively(markmacro-mark-words)
  command-execute(markmacro-mark-words record)
  counsel-M-x-action("markmacro-mark-words")
  ivy-call()
  ivy-read("M-x " ("toggle-debug-on-error" "markmacro-mark-chars" "markmacro-apply-all" "markmacro-secondary-region-mark-cursors" "markmacro-secondary-region-set" "markmacro-mark-imenus" "mc/mark-all-in-region" "lsp-bridge-mode" "mc/mark-next-like-this" "mc/edit-lines" "try" "mc/mark-all-words-like-this-in-defun" "mc--mark-symbol-at-point" "magit-find-file" "color-rg-search-input" "color-rg-search-input-in-project" "org-roam-tag-add" "popweb-dict-youglish-input" "popweb-url-preview-pointer" "popweb-org-roam-link-show" "popweb-dict-bing-pointer" "package-delete" "vundo" "markmacro-mark-lines" "tree-sitter-query-builder" "blink-search" "python-black-region" "lsp-bridge-toggle-sdcv-helper" "helpful-symbol" "spacemacs/symbol-overlay-transient-state/spacemacs..." "lsp-bridge-workspace-list-symbols" "insert-translated-name-insert" "package-refresh-contents" "profiler-start" "ediff-buffers" "company-mode" "lsp-bridge-diagnostic-jump-next" "topsy-mode" "ediff-files" "fancy-widen" "dumb-jump-go" "my/open-in-vscode" "lsp-ivy-workspace-symbol" "lsp-bridge-popup-complete-menu" "lsp-doctor" "global-hl-line-mode" "ediff-regions-wordwise" "lsp-bridge-diagnostic-list" "liuyan/native-compile-async" "lsp-bridge-diagnostic-jump-prev" ...) :predicate counsel--M-x-externs-predicate :require-match t :history counsel-M-x-history :action counsel-M-x-action :keymap (keymap (67108908 . counsel--info-lookup-symbol) (67108910 . counsel-find-symbol)) :initial-input nil :caller counsel-M-x)
  counsel-M-x()
  funcall-interactively(counsel-M-x)
  command-execute(counsel-M-x)

我不用evil,欢迎发补丁吧。

如果你用 evil 这种按键模式转换, 为啥不直接切换到 Meow ?

Meow 应该有 evil 的所有功能, 同时也有 markmacro 的功能。

确实可以考虑meow,我之前一直想试试

对, 我是因为完全不用模式编辑(我写代码的时候比看代码多很多), 所以才用的 markmacro.

我相信 Meow 对应的功能应该比 markmacro 还要强(毕竟 markmacro 的理念本质是从 Meow 那里学习的)

1 个赞

推送了新的补丁:

实现的效果: case9

操作步骤:

  • 移动光标到第二个 .git, 然后从第二个 .git 选择到最后
  • 执行 markmacro-secondary-region-set 命令, 转换成次要选择区域
  • 再在次要选择区域中, 选中 .git 字符串
  • 执行 markmacro-secondary-region-mark-cursors 命令, 标记次要区域所有 .git 字符串
  • 按回车, 执行 markmacro-apply-all 命令, 让所有 .git 字符串都执行回车键盘宏

通过上面的操作就可以对某一个区域内的选中字符串统一的执行键盘宏操作, 成10倍的提升重复操作效率。

这里的操作都可以用 multiple-cursors 来做,我平时也都是这么用的。这个的优势是可以批量标记吗?multiple-cursors 需要加 prefix 或者手动标记多处

makmacro 相对于 multip-cursors 的优势是根据选区的对象自动搜索标记, 特别是二次选中区域, 不需要手动一个一个的标记。

同时它是基于键盘宏的, 比 multip-cursors 操作更灵活。

好的,谢谢,multiple-cursors 标记大批量时确实不太方便,性能上其实也有点问题,回头试试看这个

今天写了一个补丁 Add new command markmacro-mark-function-parameters · manateelazycat/markmacro@88ff6f1 · GitHub

结合 treesit 自动标记函数的参数, 并批量操作。

case10

欢迎大家编写更多的 treesit 函数, treesit 在匹配模式类似但字符串没有任何关联的场景(函数、变量、参数等)非常方便。

1 个赞

这种直接标记 import 代码的场景也很爽, 不用光标一个一个的标记了。

最新版光标只要在列表里面, 都可以自动标记列表中所有对象, markmacro-mark-parameters 特别适合各种列表数据合并或者分开的操作。