Файл Tangle Org, содержащий директивы # + INCLUDE и несколько целей tangle
Контекст
Я использую org-babel-tangleдля генерации своей конфигурации из файла организации config.org. Недавно я сделал небольшую уборку
- отправка
config.orgв несколько файлов Orgconfig/*.org; - замените содержимое
config.orgнесколькими#+INCLUDE: config/*.orgдирективами.
Для небольшой иллюстрации дерево каталогов выглядит следующим образом:
config/
|______ A.org
|______ B.org
|______ C.org
|
config.org
где
## config.org
#+INCLUDE: config/A.org
#+INCLUDE: config/B.org
#+INCLUDE: config/C.org
...
а также
## [ABC].org
#+BEGIN_SRC emacs-lisp :tangle target1.el
;; elisp code
#+END_SRC
#+BEGIN_SRC emacs-lisp :tangle target2.el
;; elisp code
#+END_SRC
...
Проблема и попытка
Однако я столкнулся с проблемой, org-babel-tangleкоторая не обрабатывает #+INCLUDEдирективы. Итак, я следую идее этого поста, который состоит из
- экспорт
config.orgв файл Orgconfig-export.orgс помощьюorg-export-to-file; org-babel-tangleэкспортированный файл Org,config-export.orgчтобы запутать цели.
Этот подход действительно заменяет несколько #+INCLUDEдиректив config.orgсодержимым config/*.org, но все параметры путаницы стираются . А именно, экспортированный config-export.orgфайл выглядит так (все целевые имена файлов emacs-lisp tangle теряются):
## config-export.org
#+BEGIN_SRC emacs-lisp
;; elisp code for target1.el
#+END_SRC
#+BEGIN_SRC emacs-lisp
;; elisp code for target2.el
#+END_SRC
...
Вопрос
Как org-babel-tangleполучить орг файл с #+INCLUDEдирективами по назначению?
( т.е. (1) включить все файлы Org (с сохранением :tangle target.el), затем (2) org-babel-tangleвесь файл Org.)
Связанный вопрос
Аналогичный вопрос был поднят в списке рассылки режима Org.
Ответы
Я не знаю, как это сделать, не меняя код (это могло быть возможно, org-babel-pre-tangle-hookно это не казалось совсем простым, поэтому я не пробовал). Но как только вы принимаете изменения кода, это уже не так уж плохо.
Самый простой способ, который я мог придумать, - это имитировать org-babel-tangleто, что org-export-asделают файлы, включенные в WRT. Простой тест (аналогичный тому, что вы описали выше) прошел легко (но см. Предостережения в конце), поэтому, если вы хотите попробовать воспроизвести изменение, я добавлю патч ниже.
Сам патч выглядел бы большим, но это только потому, что я беру весь код org-babel-tangleи заключаю его в другой слой, который меняет отступы, и это большая часть изменений. Игнорируя изменения пробелов, "реальное" изменение намного меньше: я получил патч ниже git diff -b, чтобы игнорировать пробелы. Затем вы можете видеть, что он очень маленький: мы просто заключаем почти все тело org-babel-tanglein (org-export-with-buffer-copy ...), чтобы мы могли выполнять преобразования текста во временном буфере и не нарушать оригинал, а затем добавляем еще одно преобразование для обработки #+INCLUDE:директив, прежде чем полученный буфер затем запутывается:
diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index b74b3fa0c..5e6eebf63 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -206,6 +206,9 @@ export file for all source blocks. Optional argument LANG-RE can
be used to limit the exported source code blocks by languages
matching a regular expression."
(interactive "P")
+ (org-export-with-buffer-copy
+ (org-export-expand-include-keyword)
+
(run-hooks 'org-babel-pre-tangle-hook)
;; Possibly Restrict the buffer to the current code block
(save-restriction
@@ -306,7 +309,7 @@ matching a regular expression."
(mapc (lambda (pair)
(when (cdr pair) (set-file-modes (car pair) (cdr pair))))
path-collector)
- (mapcar #'car path-collector)))))
+ (mapcar #'car path-collector))))))
(defun org-babel-tangle-clean ()
"Remove comments inserted by `org-babel-tangle'.
Это дает ожидаемые результаты. Я думаю, WRT запутанные файлы, но вы должны проверить, чтобы убедиться, что он работает правильно в вашем случае: мои тесты - это игрушечные тесты, поэтому они могут пропустить сложные ситуации, которые могут возникнуть в ваших тестах "реального мира" .
Есть одна проблема, которую я пока не понимаю: сам config.orgбуфер изменяется в моих тестах, несмотря на то org-export-with-copy-buffer, что в конце путаницы я должен отменить изменение C-x uи сохранить его. Вероятно, это потому, что я не понимаю, что org-export-with-copy-bufferна самом деле происходит, но я еще не проверял этот код.
OTOH, если это будет решено и все тесты пройдут успешно, мы можем предложить это как улучшение списка рассылки в режиме организации и решить эту проблему (с 2010 года!).
РЕДАКТИРОВАТЬ: Я не вижу никаких проблем с org-babel-tangle-file- он вызывает org-babel-tangleвнизу, поэтому теоретически он должен делать (почти) правильные вещи, и тестирование его на простом примере отлично подходит для меня. Может быть, вы можете опубликовать (небольшой) пример, который вызывает у вас проблемы, отредактировав свой вопрос?
Я также тестирую следующее обходное решение, чтобы обойти проблему с config.orgизменением:
#+begin_src emacs-lisp
(copy-file "./config.org.orig" "./config.org")
(org-babel-tangle-file "./config.org")
(delete-file "./config.org")
#+end_src
Уродливо, но вроде работает (за исключением того, что я должен ответить на вопрос «изменено на диске»).
Способ 1
Ручной метод с использованием привязок клавиш в организационном режиме по умолчанию
Настраивать
Добавьте
OrgвOrg Babel Load Languagesконфигурацию, а затем примените и сохраните новую конфигурацию.Добавьте
#+EXPORT_FILE_NAME:ключевое слово в верхней частиconfig.org.например
#+EXPORT_FILE_NAME: temp.orgДобавьте
#+PROPERTY: header-args:org :results drawer replaceключевое слово в верхней частиconfig.org.например
#+PROPERTY: header-args:org :results drawer replaceОбновите,
#+INCLUDE:чтобы включитьsrc orgсинтаксис.например
#+INCLUDE: config/A.org src org #+INCLUDE: config/B.org src org #+INCLUDE: config/C.org src orgДобавьте
:eval neverзаголовок к каждому изSRCблоков, которые будут запутываться внутри включенныхconfig/*.orgфайлов.например
#+BEGIN_SRC elisp :tangle tangle1.el :eval never ;; Code goes here #+END_SRC
Шаги ручного выполнения
Открыть
config.orgв emacs.config.orgФайл должен быть похож на пример ниже:#+EXPORT_FILE_NAME: temp.org #+PROPERTY: header-args:org :results drawer replace #+INCLUDE: config/A.org src org #+INCLUDE: config/B.org src org #+INCLUDE: config/C.org src orgЭкспорт
config.orgс использованиемC-cC-eOvключевого аккорда. Это создаст новыйtemp.orgфайл и откроется в emacs.temp.orgФайл должен быть похож на пример ниже:#+export_file_name: temp.org #+property: header-args:org :results drawer replace #+begin_src org ,#+BEGIN_SRC elisp :tangle tangle1.el :eval never ;; Code goes here ,#+END_SRC #+end_src #+begin_src org ,#+BEGIN_SRC elisp :tangle tangle2.el :eval never ;; Code goes here ,#+END_SRC #+end_src #+begin_src org ,#+BEGIN_SRC elisp :tangle tangle3.el :eval never ;; Code goes here ,#+END_SRC #+end_srcВыполнить все блоки в
temp.orgиспользованииC-cC-vC-bключевого аккорда.temp.orgФайл должен быть похож на пример ниже:#+export_file_name: temp.org #+property: header-args:org :results drawer replace #+begin_src org ,#+BEGIN_SRC elisp :tangle tangle1.el :eval never ;; Code goes here ,#+END_SRC #+end_src #+RESULTS: :results: #+BEGIN_SRC elisp :tangle tangle1.el :eval never ;; Code goes here #+END_SRC :end: #+begin_src org ,#+BEGIN_SRC elisp :tangle tangle2.el :eval never ;; Code goes here ,#+END_SRC #+end_src #+RESULTS: :results: #+BEGIN_SRC elisp :tangle tangle2.el :eval never ;; Code goes here #+END_SRC :end: #+begin_src org ,#+BEGIN_SRC elisp :tangle tangle3.el :eval never ;; Code goes here ,#+END_SRC #+end_src #+RESULTS: :results: #+BEGIN_SRC elisp :tangle tangle3.el :eval never ;; Code goes here #+END_SRC :end:Выполните путаницу с
temp.orgпомощьюC-cC-vC-tключевого аккорда. Это запутает импортированныеSRCблоки изconfig/*.orgфайлов.Это создаст запутанные файлы, подобные перечисленным ниже файлам:
config.org tangle1.el tangle2.el tangle3.el temp.org ./config: A.org B.org C.org
Этот ответ был протестирован с использованием:
версия emacs: GNU Emacs 27.1
версия орг-режима: 9.3.7