Як автоматично обчислити початковий і кінцевий рядки, включаючи вихідні файли в org-режимі?


10

У своїй документації я маю наступне:

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

Тут рядок 14 є там, де я маю, class basic extends ..а рядок 116 - там, де я маю endclass.

Чи є спосіб автоматичного вставлення чисел 14 і 117 (= 116 + 1), щоб мені не потрібно було вручну оновлювати їх щоразу, коли я змінював code/basic.sv?


Тож ти завжди хочеш, щоб він перейшов від класу до закінчення класу?
Малабарба

1
Ні. Це був приклад. Я думаю про рішення, де можу надати регулярний вираз для початкових та кінцевих рядків. Щось оцінить функціюorg-include-src(FILE, LANGUAGE, REGEX_BEGIN, REGEX_END)
Каушал Моді

Один із способів - розміщення у включеному файлі якихось унікальних маркерів (початковий кінець) і знаходження їх з функцією, яку слід підключити org-export-before-processing-hookдо попередньої обробки номерів рядків. Ще один спосіб - просто надіслати запит на функцію електронною поштою до списку розсилки org :)
kindahero

Відповіді:


8

Ось ще один варіант. Це дозволить вам налаштувати регулярні вирази на основі включення. Він повинен краще відповідати деяким робочим процесам, оскільки ви не обмежуєтесь визначеннями на основі розширень.

Використовувати

Зробіть щось подібне у своєму org-файлі. ( :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". Виконання бездоганне! Дякую за реалізацію цього це Швидко!
Каушал Моді

5

Найкращий спосіб, який я можу придумати, - це оновлення цих номерів безпосередньо перед експортом або перед оцінкою.

Оновлення

Це функція, яка проходить через буфер. Ви можете прив'язати його до ключа або додати до гачка. Наступний код оновлює рядки щоразу, коли ви зберігаєте файл , але якщо ваш випадок використання інший, просто з’ясуйте, який гак вам потрібен! (org-режим повний гачків)

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

Regexps

Тут ви визначаєте регулярні вирази, які будуть використовуватися як перший і останній рядки, які будуть включені. Ви можете дати список регулярних виразів для кожного розширення файлу.

(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. Це має бути дуже інформативним. :-)
Малабарба

Сама функція працює нормально. Але гачок повинен передати аргумент функції, яку він викликає. З документів для org-export-before-processing-hook, Every 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)?
Каушал Моді

@kaushalmodi На жаль, мені погано. Я оновив відповідь. Ви можете також використовувати те, що ви написали.
Малабарба,

Добре .. додавання (&optional dummy)насправді працювало! Але цікавий побічний ефект виклику функції через гачок. Якщо я називаю функцію за допомогою M-x, вона змінює .orgфайл із оновленими номерами рядків. Але якщо я просто експортую в html і дозволяю гачку викликати функцію, оновлені номери рядків відображаються лише у експортованому файлі, а не у .orgфайлі.
Каушал Моді

@kaushalmodi Так, так працюють гачки орга. Ви можете замість цього додати його до попереднього збереження.
Малабарба
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.