[分享] separedit.el (原 comment-edit.el): 在单独的缓冲区编辑注释、docstring 或其中的代码块

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

我只是想要在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:

这个问题应该在我昨天晚上这个 https://github.com/twlz0ne/comment-edit.el/commit/f7c6366d89bc651e1e9f77d968fe9f658c6bc0b7 提交修复了。

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

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

尴尬了,发现一个同名的扩展 https://www.emacswiki.org/emacs/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

https://github.com/cireu/emacsql-sqlite3/blob/master/emacsql-sqlite3.el#L28

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

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

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

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

1赞

感觉这翻译一般。可惜我不是学中文的,想不出来更好的翻译。escape-edit可能更准确,但难理解其功能;comment-edit能一眼看出来能做什么,不失为一个好名字。

昨天思路不太对,反而把事情搞复杂了。现在给 comment-edit 加了一个参数,直接输入编辑区域(甚至可以考虑手动选择), 这样就可以应对 Commentary 以及类似场景了:

(defun comment-edit-el-commentary ()
  "Edit elisp Commentary section."
  (interactive)
  (let* ((comment-edit-default-mode 'markdown-mode)
         (comment-edit-leave-blank-line-in-comment t)
         (beg (save-excursion
                (goto-char (point-min))
                (re-search-forward "^;;; Commentary:\n+" nil t)))
         (end (save-excursion
                (goto-char beg)
                (re-search-forward "\n;;; .*$" nil t)
                (goto-char (match-beginning 0)))))
    (comment-edit (list :beginning beg :end end))))

EDIT: 1.调整匹配规则,忽略头部空行,2.无需将光标移动到 Commentary 区域内。

1赞

回去更新一下试试

现在全面支持递归(之前只实现了字符串的递归 unscape)进入了:

+--------+   C-c '   +--------+   C-c '   +--------+   C-c '
| source | --------> | edit   | --------> | edit   | --------> ...
| buffer | <-------- | buffer | <-------- | buffer | <-------- ...
+--------+  C-c C-c  +--------+  C-c C-c  +--------+  C-c C-c

不过嵌套多了会晕,两次应该是日常比较用的到的:

source buffer -> edit buffer (markdown/orgmode) -> code block

1赞

乞丐版 el2readme:

(defun el-commentary-to-readme-md ()
  "Write elisp Commentary section to README.md."
  (interactive)
  (let* ((beg (save-excursion
                (goto-char (point-min))
                (re-search-forward "^;;; Commentary:\n+" nil t)))
         (end (save-excursion
                (goto-char beg)
                (re-search-forward "\n;;; .*$" nil t)
                (goto-char (match-beginning 0))))
         (str (buffer-substring-no-properties beg end)))
    (with-temp-buffer
      (insert str)
      (comment-edit--remove-comment-delimiter
       (comment-edit--comment-delimiter-regexp 'emacs-lisp-mode))
      (write-file (expand-file-name "README.md")))))