separedit.el: 在单独的缓冲区编辑注释、docstring 或其中的代码块

这个扩展其实在几个月前讨论《 如何善用注释/文档中的代码? - #9,来自 twlz0ne 》的时候就差不多了(当时没实现的功能现在也没😅)

一直捂着,不如放出来,集思广益,慢慢改进。

现在整理了一下,并把包名由 commentdown 改为 separedit,一是因为并没有以 markdown-mode 作为编辑主模式,二是保留将来支持 orgmode 的可能(不被名称限定)

关于注释块/行概念的厘清

不以注释符号来区别「块」和「行」,因为 /* */ 也可以是行注释。而是以是否连续作为判断依据。

在讨论「连续性」之前,先给 /* */// 两种注释赋予新的解释:

  • /* */ 封闭型注释。自带边界,隔绝外部。
  • // 开放型注释。以空行和左侧代码为界,两两相邻集结成块。

所以,是否连续就要看上下两行首尾之间有无被代码/空行所阻断,例如:

/*
 * 这是
 * 注释块
 */
 
//
// 这也是
// 注释块
//

//
// 这另一个
// 注释块
//

code 1 // 这些都是行注释
code 2 // 这些都是行注释
code 3 /* 这些都是行注释 */
code 4 /* 这些都是行注释 */

有时候需要忽略空行,把多个注释块(例如 Elisp 文件的 Commentary)作为整体来编辑?参见:#22 楼

功能&特性

  • 编辑注释、字符串和 docstring,或直接编辑其中的代码块,separedit 会去掉包裹在编辑内容之外的字符,例如:

     在注释或 docstring 中              在编辑模式中
    
     // ```
     // this is a                       this is a
     // code block                      code block
     // ```
    
     // ,---
     // | this is a                     this is a
     // | code block                    code block
     // `---
    

    编辑完,返回,恢复包裹字符。

    • 可以使用 markdown / orgmode 或任何你喜欢的 mode 作为编辑主模式。
    • 编辑代码块时自动判定所需的 mode,如果判断不出则沿用当前的 major-mode,还可以手动选择。
    • 如果编辑的块(无论是注释块还是代码块)中有嵌套,可以再次开启新的 edit buffer 进行编辑(理论上不限制嵌套层数,但层数多了容易头晕)。
  • 消除引号转义。例如:

                       C-c '
      "(foo \"bar\")"   -->   (foo "bar")
    

    同样也支持嵌套的转义字符编辑:

                                   C-c '                       C-c '
      "(foo \"bar\\\"quux\\\"\")"   -->   (foo "bar\"quux\"")   -->   bar"quux"
    
  • 编辑 minibuffer。广阔空间大有可为,不必困在方寸之间数括号。

  • 编辑 help-mode / helpul-mode 中的表达式。再也不担心 hook 中的 lambda 有问题了,现在可以就地编辑。


ChangeLog:

  • 支持单双引号嵌套转义 #11
  • 支持直接传递 block 给编辑函数,以实现编辑类似 elisp commentary section 的区块 #22
  • 全面支持递归 #24
  • 支持Local Variables: 块的编辑 #30
  • 支持 fill-column 接力 #35
  • 支持手动选择编辑模式 #36
  • 更名为 separedit.el
  • melpa 审核通过,增加 -preserve-string-indentation 选项 #56
  • 增加对help-mode helpful-mode 支持,修复了进入编辑/提交返回之后光标位置不固定、以及部分情况下空格丢失的问题 #68
  • 支持 minibuffer 编辑 #71
  • 支持 doxygen 风格的 c/c++ 注释 #72
  • 发布版本 v0.3.0
  • 支持无窗口模式 #91
  • 支持 swagger-jsdoc #88 #89
  • 支持用 heredoc 标记指定编辑模式 #91
14 个赞

老铁真是高产啊

都是些无关紧要的 idea

以前看tumashu推荐过lentic,和本贴所要达到的目标类似,不过太高端了,至今我不会用。。

2 个赞

有装类似的 string-edit,一直想不起来用。

这个厉害了,只是我感觉平时都不这么用呢

我只是想要在Commentary里用org-mode写个README而已 :joy: 因为Melpa的default recipe居然只能抓取Texinfo格式的文档

tumashu还写了专门提取Commentary的插件

这个很强大。不知道它在进入编辑状态( org-mode ) 之后,能否再次进入 code block 的编辑?

没看到有 docstring 的例子?

例子太少了,所以根本不知道怎么用

@tumashu 能不能指教一下?

另外有点讨厌的是他不能直接复用Elisp文件原有的outline而是要自己再弄一层outline

总觉得把简单的事给复杂化了,可能是不会用吧 :joy::joy::joy:

刚刚试了一下 string-edit,发现它对 js 字符串单/双引号嵌套使用和 python docstring 支持不好。

我参考 string-edit 修复了 comment-edit--string-region 函数结果不准确的问题,并把上述需求也一并解决了。

1 个赞

多层嵌套的转义符号竟然是指数增长(原以为是x2):

(cl-labels ((escape
             (sl)
             (cond ((not sl) "")
                   ((stringp sl) (format "%S" sl))
                   (t (format "%S" (concat (car sl) (escape (cadr sl))))))))
  (insert
   (escape '("a" ("b" ("c" ("d" ("e" ("f" ("g" ("h" "i")))))))))))

;; => "a\"b\\\"c\\\\\\\"d\\\\\\\\\\\\\\\"e\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"f\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"g\\\\\\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"h\\\\\\\\\\\\\\\\\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\"i\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;;    \\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\
;;    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\
;;    \\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\"\\\"\""

试了一下 4 层转义(再多层就晕了),层层进入编辑(代码还没提交到 github)时的缓冲区内容是这样的:

| n | *edit buffer*                                                       |
|---|---------------------------------------------------------------------|
| 0 | "a\"b\\\"c\\\\\\\"d\\\\\\\\\\\\\\\"e\\\\\\\\\\\\\\\"\\\\\\\"\\\"\"" |
| 1 | "b\"c\\\"d\\\\\\\"e\\\\\\\"\\\"\""                                  |
| 2 | "c\"d\\\"e\\\"\""                                                   |
| 3 | "d\"e\""                                                            |
| 4 | "e"                                                                 |

编辑完了再一层一层提交回去。

1 个赞

用到了edit-indirect,最好在readme里说一下。


编辑C 的 block comment 的话,星号后面不会自动加入空格:

之前:

/*
 *
 */

编辑buffer:

Test

之后:

/*
 *Test
 */

不过如果本来就有文字的话就没问题: 之前:

/*
 * Test
 */

之后

/*
 * Test
 * Add
 */

我是想着以后要上 melpa 就没写。或许也可以加一个首次运行提示并自动安装的函数,就像 markdown-mode:

这个问题应该在我昨天晚上这个 Fix comment end determination · twlz0ne/separedit.el@f7c6366 · GitHub 提交修复了。

总是有一些边角/边界的问题不好处理。

这两天都在思考怎么解决,期间还写了一版用 syntax-ppss 来定位边界的代码,后来发现很不靠谱,很多 mode 下表现不一致 :sweat:

尴尬了,发现一个同名的扩展 EmacsWiki: comment-edit.el

支持这种方框包围的注释:

;; Style n. 3: "narrow-box"
;; 
;;     ##################
;;     # comment line 1 #
;;     # comment line 2 #
;;     # comment line 3 #
;;     ##################
;; 
;; Style n. 4: "wide-box"
;; 
;;     ########################################################################
;;     # comment line 1                                                       #
;;     # comment line 2                                                       #
;;     # comment line 3                                                       #
;;     ########################################################################

不过它仅限于 shell-like 类的注释,不支持 /* */ 以及其它形式的注释,也不支持 docstring 和注释里的 code block,我释然了。

2 个赞

还有 poporg, org-commentary outorg 等等的,只不过是用Org Mode编辑模式。我 自己就经常用 poporg. 还是很好用的,尤其是对于我这样的Org Mode重度使用者。

1 个赞

Commentary 里写 README 是个好注意。

Commentary 里边的空行是否必须留白?如果不是必须,现在就可以用 comment-edit 来编辑,只需把 comment-edit-default-mode 设为 org-mode

(defun comment-edit-el-commentary ()
  (interactive)
  (let ((comment-edit-default-mode 'org-mode))
    (comment-edit)))

如果希望保持空行留白,目前有两个问题需要解决:

  1. comment-edit 以连续的 ;; 作为编辑块,遇到空行则认为块结束。

    解决方案:设置一个 greedy 开关,为 t 时可以跨过空行搜索。

  2. 编辑完了之后,提交的时候会在每一行(包括空行)前面添加注释符 ;;

    解决方案:允许提交函数忽略空行。

待我明天来看看怎么实现。

如果用el2org生成README,是不需要对空白行额外加;;

pyim的源文件是一个例子,不过他那个太复杂了,类似文学编程。我用的是简化后的框架,只用来写README

我比较倾向于写完readme自动插入到el文件commentary里。不过comment-edit一包多用也不错

忽然想到,这个包应该改名为 escape-edit。港台把 escape 翻译作「跳脱」,我认为更准确。

字符串引号加斜杠叫跳脱,那么加注释符和 code block 包裹符可视为另一种层次的跳脱。

干着 escape 字符串的活,名称却叫 comment-edit,有一种词不达意、强行凑功能的感觉。

1 个赞