在以组织方式包含源文件时,如何自动计算开始和结束行?


10

我的文档中包含以下内容:

#+INCLUDE: "code/basic.sv" :src systemverilog :lines "14-117"

在这里,第14行是我拥有的位置,class basic extends ..而在116行是我拥有的位置endclass

有没有一种方法可以自动插入数字14和117(= 116 + 1),这样我每次修改时都不必手动更新它们code/basic.sv


因此,您始终希望它从一堂课到另一堂课?
马拉巴巴2014年

1
不,那是一个例子。我正在考虑一个解决方案,其中可以为起点和org-include-src(FILE, LANGUAGE, REGEX_BEGIN, REGEX_END)
终点线

一种方法是,在包含的文件中放置某种独特的标记(从头开始),然后使用函数将其找到,以将其挂钩以org-export-before-processing-hook对行号进行预处理。另一种方法是将功能请求邮件发送到组织邮件列表:)
kindahero 2014年

Answers:


8

这是另一种选择。这是让您基于每个包含自定义正则表达式的方法。它应该更好地适合某些工作流程,因为您不仅限于基于扩展的定义。

使用

在组织文件中执行以下操作。(:lines关键字是可选的)

#+INCLUDE: "code/my-class.sv" :src systemverilog :range-begin "^class" :range-end "^endclass" :lines "14-80"

该函数将访问“ my-class.sv”并搜索这两个正则表达式,然后它将:lines根据匹配结果更新关键字。

如果:range-begin丢失,范围将为“ -80”。
如果:range-end丢失,范围将为“ 14-”。

编码

(add-hook 'before-save-hook #'endless/update-includes)

(defun endless/update-includes (&rest ignore)
  "Update the line numbers of #+INCLUDE:s in current buffer.
Only looks at INCLUDEs that have either :range-begin or :range-end.
This function does nothing if not in org-mode, so you can safely
add it to `before-save-hook'."
  (interactive)
  (when (derived-mode-p 'org-mode)
    (save-excursion
      (goto-char (point-min))
      (while (search-forward-regexp
              "^\\s-*#\\+INCLUDE: *\"\\([^\"]+\\)\".*:range-\\(begin\\|end\\)"
              nil 'noerror)
        (let* ((file (expand-file-name (match-string-no-properties 1)))
               lines begin end)
          (forward-line 0)
          (when (looking-at "^.*:range-begin *\"\\([^\"]+\\)\"")
            (setq begin (match-string-no-properties 1)))
          (when (looking-at "^.*:range-end *\"\\([^\"]+\\)\"")
            (setq end (match-string-no-properties 1)))
          (setq lines (endless/decide-line-range file begin end))
          (when lines
            (if (looking-at ".*:lines *\"\\([-0-9]+\\)\"")
                (replace-match lines :fixedcase :literal nil 1)
              (goto-char (line-end-position))
              (insert " :lines \"" lines "\""))))))))

(defun endless/decide-line-range (file begin end)
  "Visit FILE and decide which lines to include.
BEGIN and END are regexps which define the line range to use."
  (let (l r)
    (save-match-data
      (with-temp-buffer
        (insert-file file)
        (goto-char (point-min))
        (if (null begin)
            (setq l "")
          (search-forward-regexp begin)
          (setq l (line-number-at-pos (match-beginning 0))))
        (if (null end)
            (setq r "")
          (search-forward-regexp end)
          (setq r (1+ (line-number-at-pos (match-end 0)))))
        (format "%s-%s" l r)))))

2
这很棒!现在,我可以使用它从同一文件中导出多个片段。片段1 :#+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 1" :range-end "// End of Example 1"。片段2 :#+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 2" :range-end "// End of Example 2"。执行是完美的!感谢您实现这个这个快!
考沙尔·莫迪2014年

5

我能想到的最好方法是在导出或评估之前立即更新这些数字。

更新器

这是通过缓冲区的功能。您可以将其绑定到键,也可以将其添加到钩子。以下代码在每次保存文件时都会更新这些行 ,但是如果您的用例不同,则只需找出所需的钩子即可!(org-mode 充满了钩子)

(add-hook 'before-save-hook #'endless/update-includes)

(defun endless/update-includes (&rest ignore)
  "Update the line numbers of all #+INCLUDE:s in current buffer.
Only looks at INCLUDEs that already have a line number listed!
This function does nothing if not in org-mode, so you can safely
add it to `before-save-hook'."
  (interactive)
  (when (derived-mode-p 'org-mode)
    (save-excursion
      (goto-char (point-min))
      (while (search-forward-regexp
              "^\\s-*#\\+INCLUDE: *\"\\([^\"]+\\)\".*:lines *\"\\([-0-9]+\\)\""
              nil 'noerror)
        (let* ((file (expand-file-name (match-string-no-properties 1)))
               (lines (endless/decide-line-range file)))
          (when lines
            (replace-match lines :fixedcase :literal nil 2)))))))

正则表达式

在这里定义正则表达式,将其用作要包括的第一行和最后一行。您可以提供每个文件扩展名的正则表达式列表。

(defcustom endless/extension-regexp-map 
  '(("sv" ("^class\\b" . "^endclass\\b") ("^enum\\b" . "^endenum\\b")))
  "Alist of regexps to use for each file extension.
Each item should be
    (EXTENSION (REGEXP-BEGIN . REGEXP-END) (REGEXP-BEGIN . REGEXP-END))
See `endless/decide-line-range' for more information."
  :type '(repeat (cons string (repeat (cons regexp regexp)))))

后台工作者

这是负责大部分工作的人。

(defun endless/decide-line-range (file)
  "Visit FILE and decide which lines to include.
The FILE's extension is used to get a list of cons cells from
`endless/extension-regexp-map'. Each cons cell is a pair of
regexps, which determine the beginning and end of region to be
included. The first one which matches is used."
  (let ((regexps (cdr-safe (assoc (file-name-extension file)
                                  endless/extension-regexp-map)))
        it l r)
    (when regexps
      (save-match-data
        (with-temp-buffer
          (insert-file file)
          (while regexps
            (goto-char (point-min))
            (setq it (pop regexps))
            (when (search-forward-regexp (car it) nil 'noerror)
              (setq l (line-number-at-pos (match-beginning 0)))
              (when (search-forward-regexp (cdr it) nil 'noerror)
                (setq regexps nil
                      r (line-number-at-pos (match-end 0))))))
          (when r (format "%s-%s" l (+ r 1))))))))

1
如果我建议的话,请对两个函数进行调试,然后使用Mx调用第一个函数。那应该非常有用。:-)
马拉巴巴2014年

该功能本身运行良好。但是钩子需要将参数传递给它正在调用的函数。从的文档中org-export-before-processing-hookEvery function in this hook will be called with one argument: the back-end currently used, as a symbol。因为我们没有传递任何参数,所以我们得到了error run-hook-with-args: Wrong number of arguments。现在我不确定要添加什么参数endless/update-includes... (&optional dummy)
Kaushal Modi 2014年

@kaushalmodi糟糕,我不好。我已经更新了答案。您也可以使用自己写的东西。
马拉巴巴2014年

确定..添加(&optional dummy)实际有效!但是通过钩子调用该函数有一个有趣的副作用。如果使用调用函数M-x,它将使用.org更新的行号修改文件。但是,如果我只是导出为html并允许钩子调用该函数,则更新的行号仅反映在导出的文件中,而不反映在.org文件中。
Kaushal Modi 2014年

@kaushalmodi是的,这就是组织挂钩的工作方式。您可以将其添加到保存前挂机。
马拉巴巴2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.