org-modeにソースファイルを含めるときに、開始行と終了行を自動計算する方法は?


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)
Kaushal Modi

1つの方法は、インクルードファイルにある種の一意のマーカー(先頭と末尾)を配置org-export-before-processing-hookし、行番号を前処理するためにフックされる関数でそれらを見つけることです。もう1つの方法は、機能要求メールを組織のメーリングリストに送信することです:)
kindahero

回答:


8

これは別のオプションです。これは、正規表現をインクルードごとにカスタマイズできるようにするためのものです。拡張機能ベースの定義に限定されないため、一部のワークフローに適しています。

使用する

org-fileで次のようなことを行います。(:linesキーワードはオプションです)

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

この関数は「my-class.sv」にアクセスしてこれら2つの正規表現を検索: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"。処刑は完璧です!これをすばやく実装していただきありがとうございます。
Kaushal Modi 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
私が提案するかもしれない場合は、2つの関数をedebugしてから、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。引数を渡していないため、エラーが発生しますrun-hook-with-args: Wrong number of arguments。今、どの引数を追加するのかわかりませんendless/update-includes... (&optional dummy)
Kaushal Modi 2014

@kaushalmodiおっと、私の悪い。答えを更新しました。書いたものも使えます。
Malabarba 2014

OK ..追加は(&optional dummy)実際に機能しました!しかし、フック経由で関数を呼び出すことの興味深い副作用。を使用して関数を呼び出すと、更新された行番号でファイルがM-x変更.orgされます。しかし、単純にhtmlにエクスポートしてフックが関数を呼び出せるようにすると、更新された行番号はファイルではなく、エクスポートされたファイルにのみ反映され.orgます。
Kaushal Modi 2014

@kaushalmodiはい、それがorgフックの仕組みです。代わりにbefore-save-hookに追加できます。
Malabarba 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.