【问题标题】:How do I navigate efficiently through emacs buffer modifying lines如何通过 emacs 缓冲区修改行有效导航
【发布时间】:2016-03-20 15:10:53
【问题描述】:

我是 elisp(但不是编程)初学者,对实现某个功能的最佳实践有一些疑问。我写了一个 elisp 函数,它根据某些规则重新格式化汇编源代码;此功能目前适用于单行。它基本上使用行内导航、查看子表达式和替换匹配调用来实现目标。

现在我想将其应用于标记区域,逐行处理该区域。该行为将类似于 indent-region 函数。

推荐(且有效)的方法是什么?我考虑使用(line-number-at-pos ...) 应用于(region-beginning)(region-end) 来计算行号,然后从上到下移动,逐行处理缓冲区,修改这些。

另外,我需要通过此操作保留什么?我虽然关于 (save-match-data ...) 并且不确定如何处理标记和点。我猜它们将无用,因为文本范围发生了变化。

【问题讨论】:

标签: emacs elisp


【解决方案1】:

使用save-excursion保存和恢复点和标记,save-restriction缩小到区域。

模板应该是这样的:

(defun my-process-region (beg end)
  "Apply `my-process-line` to every line in region."
  (interactive "r")
  (save-restriction
    (widen)
    (save-excursion
      (narrow-to-region beg end)
      (goto-char (point-min))
      (while (not (eobp))
        (my-process-line)))))

【讨论】:

  • 谢谢,但我的理解是save-excursion 也会恢复缓冲区的修改,这不是我想要的(代码重新格式化了行)。关于上面的代码:如果处理改变了行的长度,结束将不再指向正确的地方,不是吗?
  • 帮助说:“保存点和当前缓冲区;执行BODY;恢复那些东西。像`progn'一样执行BODY。点和当前缓冲区的值即使在异常的情况下也会恢复退出(抛出或错误)。”
  • 好的,我明白了,current-buffer 不是指内容而是指缓冲区。不过,如果我修改缓冲区,则结束“移动”,因此“while”部分不适用于建议的测试。
  • while 循环中应该有一个next-line 吗?
  • 我假设你的行处理代码前进到下一行,否则你需要forward-line
【解决方案2】:

我接受 sds 的回答。最后,我使用了下面的代码。原因是我希望整行都可用于重新格式化,而不仅仅是标记的区域。因此,仅(narrow-to-region) 就无法完成这项工作。 我很高兴了解更多信息,并感谢 cmets 的优点/缺点或遗漏的东西:

(defun x-mode-reformat-region (beg end)
  "..."
  (interactive "r")
  (save-excursion
    (let ((nlines (+ 1 (apply '- (mapcar 'line-number-at-pos `(,end ,beg)))))
          bol
          ...)
      (goto-char beg)
      (dotimes (i nlines)
        (setq bol (line-beginning-position))
        (goto-char bol)
        ;; do reformatting for this line -- uses bol for calculations
        (forward-line)))))

下一次尝试——根据评论修改。我没有找到一种更简单的方法来扩展选择以包括整行...任何想法是否可以进一步简化 setq / narrow-to-region 组合(除了直接使用 (progn ...) 作为参数?

(defun x-mode-reformat-region (beg end)
  "..."
  (interactive "r")
  (save-restriction
    (widen)
    (save-excursion
      (setq beg (progn (goto-char beg) (line-beginning-position))
            end (progn (goto-char end) (line-end-position)))
      (narrow-to-region beg end)
      (goto-char (point-min))
      (while (not (eobp))
        (insert "*") ;; placeholder for fancy reformatting
        (forward-line)))))

【讨论】:

  • 计算nlines 的方式非常丑陋。你不需要bol,只需要(goto-char (line-beginning-position))。如果您担心您的标记和点不在行首,您应该将您传递的数字调整为narrow-to-region。简而言之,您应该与 Emacs 习惯用法保持一致,就像我的回答一样。
  • 好的,尝试修改代码,参见上面的编辑版本。我明白这些成语的意义,但问题是要了解这些是什么......
  • 任何时候你可以想到一个现有的函数正在做类似于你想做的事情,你可以看看它的源代码,看看它是如何工作的。当然,这可能是一个比您实际想要的复杂得多的示例,具体取决于您正在查看的事物处理了多少复杂性,但您通常能够掌握常见 elisp 的明智方法以这种方式完成任务。 M-x find-function 是你的朋友。我发现C-h C-f 是一个方便的绑定。
猜你喜欢
  • 2010-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-22
  • 1970-01-01
  • 2012-08-05
相关资源
最近更新 更多