first commit
This commit is contained in:
commit
7733126206
76
README.org
Normal file
76
README.org
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#+title: org-auto-tangle
|
||||||
|
#+author: Yilkal Argaw
|
||||||
|
|
||||||
|
|
||||||
|
This package (i.e org-auto-tangle) is a very simple emacs package that
|
||||||
|
allows you to automatically tangle org files on save. This is done by
|
||||||
|
adding the option ~#+auto_tangle: t~ in your org file.
|
||||||
|
|
||||||
|
The tangling process happens asynchronously so it will not block your
|
||||||
|
emacs session.
|
||||||
|
|
||||||
|
* USAGE
|
||||||
|
|
||||||
|
Simply require the package in you emacs init and hook it into org-mode.
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
|
||||||
|
(require 'org-auto-tangle)
|
||||||
|
|
||||||
|
(add-hook 'org-src-mode-hook 'org-auto-tangle-mode)
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
or you can use use-package
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package org-auto-tangle
|
||||||
|
:load-path "site-lisp/org-auto-tangle/" ;; this line is necessary only if you cloned the repo in your site-lisp directory
|
||||||
|
:defer t
|
||||||
|
:hook (org-src-mode . org-auto-tangle-mode))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
If the minor mode is on, it will try to automatically tangle
|
||||||
|
your org files if they contain a non nil value for the
|
||||||
|
~#+auto_tangle:~ option.
|
||||||
|
|
||||||
|
You can configure auto-tangle as the default behavior for all org buffers by
|
||||||
|
setting the ~org-auto-tangle-default~ variable to ~t~. In this case, you can disable
|
||||||
|
it for some buffers by setting the ~#+auto_tangle:~ option to ~nil~.
|
||||||
|
|
||||||
|
The ~#+auto_tangle:~ option may also be used to specify variables that should be
|
||||||
|
preserved in the asynchronous tangling process. For example, if you have
|
||||||
|
installed a newer version of ~org-mode~ or additional Babel processors, using
|
||||||
|
|
||||||
|
#+begin_src org
|
||||||
|
#+auto_tangle: vars:load-path
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
will be sure that they are available during tangling. The ~vars~ option takes a
|
||||||
|
colon-separated list so multiple variables may be specified
|
||||||
|
|
||||||
|
#+begin_src org
|
||||||
|
#+auto_tangle: vars:calendar-longitude:calendar-latitude:calendar-location-name
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
It is also possible to disable auto-tangling by adding the ~nil~ option to the
|
||||||
|
line without removing any ~vars~ list.
|
||||||
|
|
||||||
|
#+begin_src org
|
||||||
|
#+auto_tangle: vars:load-path nil
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Babel Auto Tangle Safelist
|
||||||
|
Add a list of files to the safelist to autotangle with noweb evaluation
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(setq org-auto-tangle-babel-safelist '(
|
||||||
|
"~/system.org"
|
||||||
|
"~/test.org"
|
||||||
|
))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
* License
|
||||||
|
|
||||||
|
This package (i.e. ~org-auto-tangle~) is licensed under the the 2-Clause BSD License.
|
||||||
|
|
||||||
179
iadrian-org-tangle.el
Normal file
179
iadrian-org-tangle.el
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
;;; iadrian-iadrian-org-auto-tangle.el --- Automatically and Asynchronously tangles org files on save -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Original Author: Yilkal Argaw <yilkalargawworkneh@gmail.com>
|
||||||
|
;; Original License: https://github.com/yilkalargaw/org-auto-tangle/blob/master/License.org
|
||||||
|
;; Maintainer: Ionut Adrian Ciolan <iadrian.ciolan@gmail.com>
|
||||||
|
;; Version: 0.6.1
|
||||||
|
;; Keywords: outlines
|
||||||
|
;; Package-Requires: ((emacs "24.1") (async "1.9.3"))
|
||||||
|
|
||||||
|
;; This file is not part of GNU Emacs
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; It is common to want to tangle org files everytime you save your changes,
|
||||||
|
;; especially for tangled init files. So this program allows you to
|
||||||
|
;; do so using #+auto_tangle option in an org file. It also accomplishes
|
||||||
|
;; this feat asynchronously so it does not let you Emacs session hang.
|
||||||
|
|
||||||
|
;;; Usage:
|
||||||
|
|
||||||
|
;; - Add #+auto_tangle: t to your tangled org file
|
||||||
|
;; - Make changes to the emacs file and save your changes
|
||||||
|
|
||||||
|
(require 'async)
|
||||||
|
(require 'cl-lib)
|
||||||
|
(require 'org)
|
||||||
|
(require 'ox) ; org-export--parse-option-keyword
|
||||||
|
|
||||||
|
(defcustom iadrian-org-auto-tangle-default nil
|
||||||
|
"Default behavior of iadrian-org-auto-tangle.
|
||||||
|
|
||||||
|
If nil (default), auto-tangle will only happen on buffers with
|
||||||
|
the `#+auto_tangle: t' keyword. If t, auto-tangle will happen on
|
||||||
|
all Org buffers unless `#+auto_tangle: nil' is set."
|
||||||
|
:group 'iadrian-org-auto-tangle
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
|
(defcustom iadrian-org-auto-tangle-babel-safelist '()
|
||||||
|
"List of full path of files for which code blocks need to be evaluated.
|
||||||
|
|
||||||
|
By default, code blocks are not evaluated during the auto-tangle to avoid
|
||||||
|
possible code execution from unstrusted source. To enable code blocks evaluation
|
||||||
|
for a specific file, add its full path to this list."
|
||||||
|
:group 'iadrian-org-auto-tangle
|
||||||
|
:type '(repeat (file :tag "Full file path")))
|
||||||
|
|
||||||
|
(defun iadrian-org-auto-tangle-find-value (buffer)
|
||||||
|
"Return the value of the `auto_tangle' keyword in BUFFER."
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(cdr (assoc "AUTO_TANGLE" (org-collect-keywords '("AUTO_TANGLE"))))))
|
||||||
|
|
||||||
|
;; This is modeled after `org-export-filters-alist', since it is
|
||||||
|
;; passed to `org-export--parse-option-keyword'.
|
||||||
|
(defconst iadrian-org-auto-tangle-options-alist
|
||||||
|
'((:with-vars nil "vars" iadrian-org-auto-tangle-with-vars))
|
||||||
|
"Alist between auto-tangle properties and ways to set them.
|
||||||
|
|
||||||
|
The key of the alist is the property name, and the value is a list
|
||||||
|
like (KEYWORD OPTION DEFAULT BEHAVIOR) where:
|
||||||
|
|
||||||
|
KEYWORD is a string representing a buffer keyword, or nil. Each
|
||||||
|
property defined this way can also be set, during subtree
|
||||||
|
export, through a headline property named after the keyword
|
||||||
|
with the \"EXPORT_\" prefix (i.e. DATE keyword and EXPORT_DATE
|
||||||
|
property).
|
||||||
|
OPTION is a string that could be found in an #+OPTIONS: line.
|
||||||
|
DEFAULT is the default value for the property.
|
||||||
|
BEHAVIOR determines how Org should handle multiple keywords for
|
||||||
|
the same property. It is a symbol among:
|
||||||
|
nil Keep old value and discard the new one.
|
||||||
|
t Replace old value with the new one.
|
||||||
|
`space' Concatenate the values, separating them with a space.
|
||||||
|
`newline' Concatenate the values, separating them with
|
||||||
|
a newline.
|
||||||
|
`split' Split values at white spaces, and cons them to the
|
||||||
|
previous list.
|
||||||
|
`parse' Parse value as a list of strings and Org objects,
|
||||||
|
which can then be transcoded with, e.g.,
|
||||||
|
`org-export-data'. It implies `space' behavior.
|
||||||
|
|
||||||
|
Values set through KEYWORD and OPTION have precedence over
|
||||||
|
DEFAULT.")
|
||||||
|
|
||||||
|
(defgroup iadrian-org-auto-tangle nil
|
||||||
|
"Automatic tangling of `org-mode' documents."
|
||||||
|
:tag "Org Auto Tangle"
|
||||||
|
:group 'org-babel)
|
||||||
|
|
||||||
|
(defcustom iadrian-org-auto-tangle-with-vars nil
|
||||||
|
"Non-nil means pass VARS variables to the async tangling process.
|
||||||
|
|
||||||
|
This option can also be set with the AUTO_TANGLE keyword,
|
||||||
|
e.g. \"vars:calendar-latitude\".
|
||||||
|
|
||||||
|
The `org-src-preserve-indentation', `org-babel-pre-tangle-hook',
|
||||||
|
and `org-babel-post-tangle-hook' variables are automatically
|
||||||
|
preserved and do not need to be listed here."
|
||||||
|
:group 'iadrian-org-auto-tangle
|
||||||
|
:type '(repeat (symbol :tag "Variable name")))
|
||||||
|
|
||||||
|
(defun iadrian-org-auto-tangle--get-inbuffer-options ()
|
||||||
|
"Return current buffer auto-tangle options, as a plist.
|
||||||
|
|
||||||
|
Assume buffer is in Org mode. Narrowing, if any, is ignored."
|
||||||
|
(let (plist)
|
||||||
|
;; Read options in the current buffer and return value.
|
||||||
|
(dolist (entry (org-collect-keywords '("AUTO_TANGLE")) plist)
|
||||||
|
(pcase entry
|
||||||
|
(`("AUTO_TANGLE" . ,values)
|
||||||
|
(setq plist
|
||||||
|
(apply #'org-combine-plists
|
||||||
|
plist
|
||||||
|
(mapcar (lambda (v)
|
||||||
|
(let ((org-export-options-alist)))
|
||||||
|
(iadrian-org-auto-tangle--parse-auto-tangle-keyword v))
|
||||||
|
values))))))))
|
||||||
|
|
||||||
|
(defun iadrian-org-auto-tangle--parse-auto-tangle-keyword (auto-tangle)
|
||||||
|
"Parse an AUTO-TANGLE line and return values as a plist."
|
||||||
|
(let ((org-export-options-alist iadrian-org-auto-tangle-options-alist))
|
||||||
|
(org-export--parse-option-keyword auto-tangle)))
|
||||||
|
|
||||||
|
(defun iadrian-org-auto-tangle-async (file)
|
||||||
|
"Invoke `org-babel-tangle-file' asynchronously on FILE."
|
||||||
|
(message "Tangling %s..." (buffer-file-name))
|
||||||
|
(async-start
|
||||||
|
(let* ((buf-vars (plist-get (iadrian-org-auto-tangle--get-inbuffer-options)
|
||||||
|
:with-vars))
|
||||||
|
(with-vars (if buf-vars
|
||||||
|
(mapcar #'intern
|
||||||
|
(org-uniquify (org-split-string
|
||||||
|
(symbol-name buf-vars) ":")))
|
||||||
|
iadrian-org-auto-tangle-with-vars))
|
||||||
|
(preserved (mapcar (lambda (v)
|
||||||
|
(cons v (symbol-value v)))
|
||||||
|
(append '(org-src-preserve-indentation
|
||||||
|
org-babel-pre-tangle-hook
|
||||||
|
org-babel-post-tangle-hook)
|
||||||
|
with-vars)))
|
||||||
|
(evaluate (not (member file iadrian-org-auto-tangle-babel-safelist))))
|
||||||
|
(lambda ()
|
||||||
|
(require 'org)
|
||||||
|
(let ((start-time (current-time))
|
||||||
|
(non-essential t)
|
||||||
|
(org-confirm-babel-evaluate evaluate))
|
||||||
|
(cl-progv (mapcar #'car preserved) (mapcar #'cdr preserved)
|
||||||
|
(org-babel-tangle-file file))
|
||||||
|
(format "%.2f" (float-time (time-since start-time))))))
|
||||||
|
(let ((message-string (format "Tangling %S completed after" file)))
|
||||||
|
(lambda (tangle-time)
|
||||||
|
(message "%s %s seconds" message-string tangle-time)))))
|
||||||
|
|
||||||
|
(defun iadrian-org-auto-tangle-tangle-if-needed ()
|
||||||
|
"Call iadrian-org-auto-tangle-async if needed.
|
||||||
|
|
||||||
|
Tangle will happen depending on the value of
|
||||||
|
`iadrian-org-auto-tangle-default' and on the presence and value of the
|
||||||
|
`#+auto_tangle' keyword in the current buffer. If present,
|
||||||
|
`#+auto_tangle' always overrides `iadrian-org-auto-tangle-default'."
|
||||||
|
(let ((auto-tangle-kw (iadrian-org-auto-tangle-find-value (current-buffer))))
|
||||||
|
(when (and (derived-mode-p 'org-mode)
|
||||||
|
(if auto-tangle-kw
|
||||||
|
(not (member "nil" auto-tangle-kw))
|
||||||
|
iadrian-org-auto-tangle-default))
|
||||||
|
(iadrian-org-auto-tangle-async (buffer-file-name)))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(define-minor-mode iadrian-org-auto-tangle-mode
|
||||||
|
"Automatically tangle org-mode files with the option #+auto_tangle: t."
|
||||||
|
:lighter " org-a-t"
|
||||||
|
|
||||||
|
(if iadrian-org-auto-tangle-mode
|
||||||
|
(add-hook 'after-save-hook #'iadrian-org-auto-tangle-tangle-if-needed
|
||||||
|
nil 'local)
|
||||||
|
(remove-hook 'after-save-hook #'iadrian-org-auto-tangle-tangle-if-needed 'local)))
|
||||||
|
|
||||||
|
(provide 'iadrian-org-auto-tangle)
|
||||||
|
|
||||||
|
;;; iadrian-org-auto-tangle.el ends here
|
||||||
Loading…
Reference in New Issue
user.block.title