攒了一个移动/交换光标/选区内容(regions/sexps/lines/words)的扩展


#1

开始也只是想实现一个交换选区的功能,但是希望在操作上更“无感”一些,把它附着在 yank 上,少占用快捷键,减轻记忆负担。然后我看 @xuchunyang 已经写了一个 swap-regions.el,就压着没放出来。

后来把其他操作也慢慢纳进来,不再适合叫 swap 了,就一直在琢磨起个什么名字,拖了很久。直到最近才决心整理一下。由于是不同时期的代码,也没有整体的规划,难免有些乱(包括命名和代码组织)。不过好在我写了不少测试,保证这些功能都符合我的预期,将来重构如果改偏了也能很快发现。

以下是效果展示(我用到了 hydra 和 evil):

交换选区(支持跨 buffer)

output

交换光标左右的内容

output

交换选区左右的内容

output

移动 sexp (也可以是 word 和 line)

output

以 sexp(也可以是 word 和 line)作为步长移动选区内容

output

在临时 buffer 中重新排列当前列表中的 sexp

output

欢迎建议,pr 或者修改英语语法错误😅


#2

看着很酷, 好奇什么场景会用到这种功能?


#3

我自己经常用到

  • 交换选区

    虽然是多年 Emacs 用户,对 Kill ring 还是有点不太顺手,所以就有了这个想法。

  • 交换光标上下/左右内容

    一直以来写 elisp 都比较喜欢这样排版:

    (if cond1
        (if cond2
            (progn
            (foo)
            (bar)
            (qux "quux"))
        ))
    

    为的的就是方便剪切/调整 progn 中的语句,降低编辑出错概率。有这种就纠结的不止我一个:

    但有时候一个孤零零的 ) 单独一行不太好看,比如 (let ((...))) 末尾的括号。所以就想要一个可以原地直接交换的操作,不仅以光标为中心,还可以以选区为中心交换距离比较远的内容。

    在非 lisp 语言中也能用,比如调换数组/参数的顺序,而不必担心中间的逗号。

    最后一个,对于复杂的跨多行的列表,直接进入临时 buffer,把列表中的元素简化成行来重新排序。

  • 移动光标/选区内容

    是交换操作的另一种形式,更直观一些。

    如果选中 () 前后移动,还可以实现类似 smartparens/paredit 中的 slurp/barf 效果:

    (foo (qux ["quux")] bar) -> (foo (qux bar "quux")) ;; forward
    (foo (qux "quux") [bar)] -> (foo bar) (qux "quux") ;; backward
    

    paredit-forward-slurp


#4

我一般都是快速调到要移动的地方, 用我写的 thing-edit.el 快速剪切 (不需要选中), 然后再跳到需要交换的地方, 直接 yank

个人不太喜欢需要选中的东西, 选中太麻烦.


#5
  1. 习惯问题

    我对编辑器的部分行为还是不太放心,使用 vim 的时候也一样。特别是有时候的编辑操作,并不是以语法单元为基础,更要选中,才直到边界在哪里。

    如果不选中,如何同时移动 2 个以上的 sexp?

    选择虽然麻烦一步,但是结合 hydra 就很省事了。只要第一步组合键,后边连续操作都是单键。相比起 C-u 3 move-something-forward 这样需要精确计算、费脑费眼(还有可能看错)的一步到位的神操作,我更喜欢 M-x move-something-forward f f 这样渐进式、每一步进展都可观察的笨操作

  2. 上边演示的并不是都必须要选区,而是基本每个操作都支持选区作为可选参数,除了交换 region 这个操作必须要选区。


#6

最后这个gif,脑机接口连入matrix意念操作语法树的感觉……