4

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

(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!")))  

其中chomp从字符串中去除前导/尾随空格region-as-string并将区域生成为字符串。

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

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

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

提前致谢,
elemakil

4

2 回答 2

7

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

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

  1. 您的函数仅在交互调用时才有效,因此beg并且end实际上是该区域的开始和结束。如果以非交互方式调用,这些可能不匹配(或者甚至可能没有区域),在这种情况下,您的函数将出错(因为它删除了之间的缓冲区begend但插入了区域的反转)。所以你需要打电话(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))))))
于 2012-12-03T13:54:47.610 回答
-1
r -- Region: point and mark as 2 numeric args, smallest first.  Does no I/O.

因为r总是前两个参数。如果你C-u用来传递参数。然后您可能需要将参数作为分隔符传递给第三个参数。但是如果没有第一个和第二个参数,你就不能传递第三个参数。(我不确定。我也是初学者)

我的目的是让您使用 ar和 as选项来实现它。尽管您总是需要提供分隔符参数。

例子:

(defun reverse-list (beg end &optional sepeartor )
  (interactive "r
ssepeartor:")
  (princ beg)
  (princ "*")
  (princ end)
  (princ sepeartor))
于 2012-12-03T13:47:11.107 回答