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

写代码时, 一般我们有两种多标签使用场景:

  1. 快速重命名: 一般都是重命名光标下的 相同符号 , 这方面 symbol-overlay 做的最简单易用
  2. 数据清洗: 快速把不同名字的符号进行格式化清洗, 从一种格式转换成另外一种格式, 这方面 Meow 的键盘宏做的最好用

但是我平常写代码的时间远远多于看代码的时间, 非常不习惯任何模式转换插件, 所以我下午研究了一下 Meow 的键盘宏原理, 重写了一个新的插件 markmacro

markmacro 的原理和 Meow 键盘宏的理念一样:

  1. 用overlay快速标记一系列对象, 并自动启动键盘宏记录
  2. 对最后一个对象进行任意操作
  3. 最后操作一下, 把一个对象上的所有键盘宏扩展到所有标记的对象

通过上面三个步骤, 我们灵活结合Emacs其他插件的能力, 快速清洗数据成我们期望的格式, 提升我们日常的编程效率。

为了直观的让大家理解这个插件的作用, 我编写了一些测试用例:

Case 1

case1

fruit = apple watermelon peaches

=>

fruit = ["apple", "watermelon", "peaches"]
  • select last three words
  • markmacro-mark-words mark words in region and start kmacro record automatically
  • Type " character, forward-word, type " character and , character
  • markmacro-apply-all apply kmacro to all mark words

Case 2

case2

it-is-ver-long-variable

=>

it_is_ver_long_variable
  • markmacro-mark-words mark words in symbol and start kmacro record automatically
  • delete - and type ‘_’ character
  • markmacro-apply-all-except-first apply kmacro to all mark words except first word

Case 3

case3

flex-auto
flex-col

flex-col-reverse
flex-grow
flex-initial

flex-no-wrap
flex-none
flex-nowrap
flex-row

=>

prefix-flex-auto.txtt
prefix-flex-col.txtt

prefix-flex-col-reverse.txtt
prefix-flex-grow.txtt
prefix-flex-initial.txtt

prefix-flex-no-wrap.txtt
prefix-flex-none.txtt
prefix-flex-nowrap.txtt
prefix-flex-row.txt
  • Select buffer
  • markmacro-mark-lines mark lines in buffer and start kmacro record automatically
  • Move to end of line, type .txt and move to beginning of line type prefix-
  • markmacro-apply-all apply kmacro to all mark lines

Case 4

case4

("s-/" . markmacro-mark-WORDS)
("s-?" . markmacro-mark-LINES)
("s-<" . markmacro-apply-ALL)
("s->" . markmacro-apply-FIRST)

=>

("s-/" . markmacro-words)
("s-?" . markmacro-lines)
("s-<" . markmacro-all)
("s->" . markmacro-first)
  • markmacro-rect-set record point at first line of rectangle, then move cursor to last line
  • markmacro-rect-mark-symbols mark all symbols in rectangle area
  • Move to end of line call downcase-word, and delete left word
  • markmacro-apply-all apply kmacro to all mark symbols

Case 5

case5

("s-/" . markmacro-mark-words)
("s-?" . markmacro-mark-lines)
("s-<" . markmacro-apply-all)
("s->" . markmacro-apply-all-except-first)
("s-M" . markmacro-rect-set)
("s-D" . markmacro-rect-delete)
("s-F" . markmacro-rect-replace)
("s-I" . markmacro-rect-insert)
("s-C" . markmacro-rect-mark-columns)
("s-S" . markmacro-rect-mark-symbols)

=>

(global-set-key (kbd "s-/") 'markmacro-mark-words)
(global-set-key (kbd "s-?") 'markmacro-mark-lines)
(global-set-key (kbd "s-<") 'markmacro-apply-all)
(global-set-key (kbd "s->") 'markmacro-apply-all-except-first)
(global-set-key (kbd "s-M") 'markmacro-rect-set)
(global-set-key (kbd "s-D") 'markmacro-rect-delete)
(global-set-key (kbd "s-F") 'markmacro-rect-replace)
(global-set-key (kbd "s-I") 'markmacro-rect-insert)
(global-set-key (kbd "s-C") 'markmacro-rect-mark-columns)
(global-set-key (kbd "s-S") 'markmacro-rect-mark-symbols)
  • markmacro-rect-set record point at first line of rectangle, then move cursor to last line
  • markmacro-rect-insert insert (global-set-key
  • markmacro-rect-set record point at first line of rectangle, then move cursor to last line, forward-char
  • markmacro-rect-replace replace ( with (kbd
  • markmacro-rect-set record point at first line of rectangle, then move cursor to last line
  • markmacro-rect-insert insert )
  • markmacro-rect-set record point at first line of rectangle, then move cursor to last line
  • markmacro-rect-delete delete .
  • markmacro-rect-set record point at first line of rectangle, then move cursor to last line
  • markmacro-rect-mark-columns mark all columns in rectangle area
  • Delete right character and type '
13 个赞

我们平常编程的时候, 会遇到非常多的数据清理场景, 比如快速把空格分割的单词加上双引号和逗号、 转换变量的链接符为下划线、 复杂的矩形操作等。 一般的办法是编写很多特殊场景的函数来自动化进行数据清理, 但是这样做会遇到两个问题, 一是函数太多了又不经常用, 时间长了快捷键都记不住; 二是特殊函数的使用非常不灵活, 数据稍微发生变化就无法适应了。 所以, 我仿照 Meow 的键盘宏理念写了 markmacro

markmacro 的原理:

  1. 用 overlay 快速标记一系列对象, 并自动启动键盘宏记录
  2. 对最后一个对象进行任意操作
  3. 最后操作一下, 把一个对象上的所有键盘宏扩展到所有标记的对象

通过上面三个步骤, 灵活结合 Emacs 其他插件的编辑能力, 我们可以快速清洗数据成期望的格式, 提升我们日常的编程效率。 同时, 这个插件是基于键盘宏来实现的, 整个数据清洗的过程不管数据格式发生了怎样的变化, 都是用几个基础的函数来组合实现, 大大降低了心智负担。

1 个赞

我感觉懒猫大佬应该搞个个人置顶资源合集,或者是已有但是被淹没在帖子里了?最近你的帖子感觉都非常受用。

:slightly_smiling_face:

今晚我在各种proxy下尝试用大佬的全部emacs配置,好庞大的插件库,Orz

2 个赞

合集可以看博客 ManateeLazyCat

不过博客少了一些讨论交流的内容。

看起来很不错的,支持一下。很多用 meow 的人上来就去研究按键绑定,HJKL,leader key 了,到是知道这个功能的人不多。

5 个赞

感谢狗哥的文档,让我这种不用模式转换插件的人可以学习下。

尝试了一下,发现了几个 bug:

  1. 在第一个例子中,如果 (= (point) (point-max)), (forward-word) 不会移动光标,导致 markmacro-mark-words 陷入死循环
  2. 下面的 dolist 可能需要改成 cl-dolist ? 不然会报 progn: No catch for tag: --cl-block-nil--,
(defun markmacro-kmacro-start ()
  (setq-local markmacro-start-overlay
              (dolist (overlay markmacro-overlays)
                (when (and (>= (point) (overlay-start overlay))
                           (< (point) (overlay-end overlay)))
                  (cl-return overlay))))
  (kmacro-start-macro 0))
  1. 在 emacs -Q 下试的时候,发现需要 (require 'cl-macs)

麻烦猫大确认下,需要提个 PR 吗?

大佬提交PR吧, 昨天才写的项目, 还有诸多不完善的地方。

已经合并, 感谢大佬提交修复补丁!

在使用 markmacro-mark-markmacro-rect- 相关命令的时候,如果中途按 C-g 退出,命令是停止了,但是 overlays 不会删除,是不是删除一下比较好?

对,ctrl+g还没有处理,大佬可以给个补丁不?

已提 PR,麻烦看一下是否合适。

补丁挺好的, 感谢大佬, 已经合并。

现在用着就比较舒服了,就差把函数的 docstring 给补充完整。

哈哈哈, 狗哥 @DogLooksGood 这个基于选中对象的键盘宏理念确实很先进, 基础很简单, 但是组合各种插件命令, 往往有极高的生产力, 也不需要记忆啥东西, 边想边干就好了。

我比较懒, 欢迎大佬发PR. :wink:

meow用户用这个已经爽了很久了 :rofl: 局部的简单重构比用各种语法工具都顺手。

对, 标记对象 + 键盘宏的方法, 标记对象越多, 效率提升越快。

大佬可以分享一下 Meow 的更多用法, 让我把功能移植到 markmacro 里, 我主要不喜欢模式切换, 但是又眼馋 Meow 的这个功能。

我回去录两个曾经我用到的场景。是批量修改函数名和添加公共的参数之类的操作。

能和 tree sitter 协作的话会更强大,可惜狗哥之前说不打算在 meow 中引入 tree sitter 。

不喜欢模式编辑又眼馋 Meow +1,其实我一直想把 beacon 抄出来,奈何行动力不足。

Meow EXPLANATION 里面 grab 相关操作和 kmacro 结合的挺不错的,可以抄一下。

Emacs Tree Sitter 其实不咋地, 我写 grammatical-edit 发现, 不加也罢, 加入了反而很多bug.