多个"交互式"选项

ele*_*kil 4 emacs elisp

我编写了一个小函数来使用逗号作为项目分隔符来反转标记区域中的项目.功能代码是:

(defun reverse-list (beg end)
  "Reverses a list in-place, where comma ',' is the list item separator."
  (interactive "r")
  (if (region-active-p)
    (let ((region-list (reverse (split-string (region-as-string) ","))))
      (kill-region beg end)
      (loop for s in region-list do (progn
                                      (insert (chomp s))
                                      (insert ", ")))
      (delete-char -2))
    (message "Error: No region selected!")))  
Run Code Online (Sandbox Code Playgroud)

其中chompstrip从字符串中前导/尾随空格并将region-as-string该区域作为字符串生成.

该功能非常有用,但是能够动态选择分隔符会很棒.我正在寻找的行为是:

  • 如果没有通用参数调用,则使用逗号作为项分隔符
  • 如果使用universal argument(C-u)调用,则要求用户输入一个(可能是多个char)分隔符字符串

我试图实现这一目标,但没有成功.如果你能提供帮助,那就太棒了!

提前谢谢,
elemakil

Gar*_*ees 7

您可以使用交互式代码 P来读取"原始"前缀参数.这是nil如果没有前缀参数,nil如果有前缀参数则为非,因此您可以测试它并决定是将设置分隔符","还是read-string用于提示用户输入它.

另外,我会对您的代码发表以下评论:

  1. 你的函数只有在被称为交互工作,以便begend真的开始和区域结束.如果以非交互方式调用,它们可能不匹配(或者甚至可能没有区域),在这种情况下,您的函数将出错(因为它删除了缓冲区之间的缓冲区beg,end但插入区域的反转).所以你需要打电话(buffer-substring beg end),而不是(region-as-string).

  2. [编辑,请参阅注释]在区域处于非活动状态的情况下引发错误并不是一个好主意.在Emacs中,即使该区域处于非活动状态(即不再突出显示),该区域仍然存在.或者用户可能已关闭,因此根本没有活动区域.在这两种情况下,用户可能仍希望运行您的命令.transient-mark-mode

    最多可以在区域处于活动状态时更改命令的行为(例如,参见参考资料comment-dwim).

  3. 您通过调用删除该区域kill-region,将删除的文本复制到kill-ring.这真的是你想要做的吗?它可能会让用户感到惊讶.delete-region除非您实际上是要保存已删除的文本,否则最好拨打电话.

  4. 在开始呼叫之前,您无法确保该点位于正确的位置insert.在交互式使用中,你可以使用它,但对于非交互式使用点可以在任何地方,所以你应该明确地移动它.save-excursion当然也可以使用.

  5. 插入一个额外的", ",然后必须删除它似乎非常不优雅.最好不要首先插入它.

这里有一些修改过的代码修复了以上所有内容:

(defun reverse-list (beg end read-separator)
  "Reverse the region in-place, treating it as a list of items
separated by commas. With a prefix argument, prompt for the
separator."
  (interactive "r\nP")
  (save-excursion
    (let* ((separator (if read-separator (read-string "Separator: ") ","))
           (region-list (nreverse (split-string (buffer-substring beg end) separator)))
           (separator (concat separator " ")))
      (goto-char beg)
      (delete-region beg end)
      (loop for s in region-list
            for sep = "" then separator
            do (insert sep) (insert (chomp s))))))
Run Code Online (Sandbox Code Playgroud)