Wie werden die Start- und Endzeilen automatisch berechnet, wenn Quelldateien in den Organisationsmodus aufgenommen werden?

10

Ich habe Folgendes in meiner Dokumentation:

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

Hier habe ich Zeile 14 class basic extends ..und Zeile 116 habe ich endclass.

Gibt es eine Möglichkeit, die Nummern 14 und 117 (= 116 + 1) automatisch einzufügen, damit ich sie nicht jedes Mal manuell aktualisieren muss, wenn ich sie ändere code/basic.sv?

Kaushal Modi
quelle
Sie möchten also immer, dass es von der Klasse zur Endklasse geht?
Malabarba
1
Nein, das war ein Beispiel. Ich denke an eine Lösung, bei der ich Regex für Start- und Endzeilen bereitstellen kann. Etwas würde eine Funktion bewertenorg-include-src(FILE, LANGUAGE, REGEX_BEGIN, REGEX_END)
Kaushal Modi
Eine Möglichkeit besteht darin, eine Art eindeutiger Markierungen (Anfang bis Ende) in die enthaltene Datei einzufügen und diese mit einer Funktion zu finden, mit der org-export-before-processing-hookdie Zeilennummern vorverarbeitet werden können. Eine andere Möglichkeit besteht darin, eine Mail mit einer Funktionsanforderung an die Mailingliste der
Organisation zu

Antworten:

8

Hier ist eine weitere Option. In diesem Fall können Sie die regulären Ausdrücke pro Include anpassen. Es sollte besser zu einigen Workflows passen, da Sie nicht auf erweiterungsbasierte Definitionen beschränkt sind.

Benutzen

Gehen Sie in Ihrer Organisationsdatei wie folgt vor. (Das :linesSchlüsselwort ist optional)

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

Die Funktion besucht "my-class.sv" und sucht nach diesen beiden regulären Ausdrücken. Anschließend wird das :linesSchlüsselwort entsprechend dem Übereinstimmungsergebnis aktualisiert .

Wenn :range-beginfehlt, ist der Bereich "-80".
Wenn :range-endfehlt, ist der Bereich "14-".

Der Code

(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)))))
Malabarba
quelle
2
Das ist toll! Jetzt kann ich damit mehrere Snippets aus derselben Datei exportieren. Snippet 1 : #+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 1" :range-end "// End of Example 1". Snippet 2 : #+INCLUDE: "code/basic.sv" :src systemverilog :range-begin "// Example 2" :range-end "// End of Example 2". Die Ausführung ist einwandfrei! Vielen Dank, dass Sie dies so schnell umgesetzt haben!
Kaushal Modi
5

Der beste Weg, den ich mir vorstellen kann, besteht darin, diese Zahlen unmittelbar vor dem Export oder vor der Auswertung zu aktualisieren.

Der Updater

Dies ist die Funktion, die den Puffer durchläuft. Sie können es an einen Schlüssel binden oder einem Haken hinzufügen. Der folgende Code aktualisiert die Zeilen, wenn Sie die Datei speichern . Wenn Ihr Anwendungsfall jedoch anders ist, finden Sie einfach heraus, welchen Hook Sie benötigen! (org-mode ist voller Hooks)

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

Die Regexps

Hier definieren Sie die regulären Ausdrücke, die als erste und letzte Zeile verwendet werden sollen. Sie können für jede Dateierweiterung eine Liste mit regulären Ausdrücken angeben.

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

Der Hintergrundarbeiter

Dies ist der Typ, der den größten Teil der Arbeit erledigt.

(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))))))))
Malabarba
quelle
1
Wenn ich vorschlagen darf, edebug die beiden Funktionen und rufe dann die erste mit Mx auf. Das sollte sehr informativ sein. :-)
Malabarba
Die Funktion selbst läuft gut. Der Hook muss jedoch ein Argument an die aufgerufene Funktion übergeben. Aus den Dokumenten für org-export-before-processing-hook, Every function in this hook will be called with one argument: the back-end currently used, as a symbol. Da wir kein Argument übergeben, erhalten wir den Fehler run-hook-with-args: Wrong number of arguments. Jetzt bin ich mir nicht sicher, welches Argument ich hinzufügen soll endless/update-includes... (&optional dummy)?
Kaushal Modi
@kaushalmodi oops, mein schlechtes. Ich habe die Antwort aktualisiert. Sie können auch das verwenden, was Sie geschrieben haben.
Malabarba
OK .. Hinzufügen hat (&optional dummy)tatsächlich funktioniert! Aber ein interessanter Nebeneffekt beim Aufrufen der Funktion über Hook. Wenn ich die Funktion mit M-xaufrufe, ändert sie die .orgDatei mit den aktualisierten Zeilennummern. Wenn ich aber einfach nach HTML exportiere und dem Hook erlaube, die Funktion aufzurufen, werden die aktualisierten Zeilennummern nur in der exportierten Datei wiedergegeben, NICHT in der .orgDatei.
Kaushal Modi
@kaushalmodi Ja, so funktionieren Org Hooks. Sie können es stattdessen zu before-save-hook hinzufügen.
Malabarba