diff options
author | Nicolas Goaziou <mail@nicolasgoaziou.fr> | 2020-01-12 11:38:04 +0100 |
---|---|---|
committer | Nicolas Goaziou <mail@nicolasgoaziou.fr> | 2020-01-12 11:38:04 +0100 |
commit | c1aed9f809ea89ee2df79f966327aab558c0ad69 (patch) | |
tree | 1171743c816fe043c0f9093bc12f723f71549c88 | |
parent | 3999320aa4c4c86d5b04d7a98dbb78798de7a6d8 (diff) | |
download | org-mode-c1aed9f809ea89ee2df79f966327aab558c0ad69.tar.gz |
ob-core: Refactor `org-babel-expand-noweb-references'
* lisp/ob-core.el (org-babel-expand-noweb-references): Refactor code.
Improve cache handling.
-rw-r--r-- | lisp/ob-core.el | 137 |
1 files changed, 61 insertions, 76 deletions
diff --git a/lisp/ob-core.el b/lisp/ob-core.el index 3fedf2e..1a01221 100644 --- a/lisp/ob-core.el +++ b/lisp/ob-core.el @@ -2708,20 +2708,17 @@ would set the value of argument \"a\" equal to \"9\". Note that these arguments are not evaluated in the current source-code block but are passed literally to the \"example-block\"." (let* ((parent-buffer (or parent-buffer (current-buffer))) - (info (or info (org-babel-get-src-block-info 'light))) + (info (or info (org-babel-get-src-block-info 'light))) (lang (nth 0 info)) (body (nth 1 info)) - (ob-nww-start org-babel-noweb-wrap-start) - (ob-nww-end org-babel-noweb-wrap-end) - (new-body "") - (nb-add (lambda (text) (setq new-body (concat new-body text)))) (comment (string= "noweb" (cdr (assq :comments (nth 2 info))))) - (noweb-re (org-babel-noweb-wrap)) - (references nil) - (index 1) + (noweb-re (format "^\\(.*?\\)\\(%s\\)" + (with-current-buffer parent-buffer + (org-babel-noweb-wrap)))) + (cache nil) (c-wrap (lambda (s) - ;; Comment, according to LANG mode, string S. Return new + ;; Comment string S, according to LANG mode. Return new ;; string. (with-temp-buffer (funcall (org-src-get-lang-mode lang)) @@ -2730,8 +2727,7 @@ block but are passed literally to the \"example-block\"." (org-trim (buffer-string))))) (expand-body (lambda (i) - ;; Expand body of code blocked represented by block info - ;; I. + ;; Expand body of code represented by block info I. (let ((b (if (org-babel-noweb-p (nth 2 i) :eval) (org-babel-expand-noweb-references i) (nth 1 i)))) @@ -2761,71 +2757,60 @@ block but are passed literally to the \"example-block\"." (error "Cannot resolve %s (see `org-babel-noweb-error-langs')" (org-babel-noweb-wrap ref))) (_ ""))))) - (with-temp-buffer - (setq-local org-babel-noweb-wrap-start ob-nww-start) - (setq-local org-babel-noweb-wrap-end ob-nww-end) - (insert body) - (goto-char (point-min)) - (while (re-search-forward noweb-re nil t) - (let* ((source-name (match-string 1)) - (evaluate (save-match-data (string-match "(.*)" source-name))) - (prefix (buffer-substring (match-beginning 0) - (line-beginning-position)))) - ;; Add interval to NEW-BODY (removing Noweb reference). - (goto-char (match-beginning 0)) - (funcall nb-add (buffer-substring index (point))) - (goto-char (match-end 0)) - (setq index (point)) - (funcall - nb-add - (with-current-buffer parent-buffer - (org-with-wide-buffer - ;; Interpose PREFIX between every line. - (mapconcat - #'identity - (split-string - (cond - (evaluate - (let ((raw (org-babel-ref-resolve source-name))) - (if (stringp raw) raw (format "%S" raw)))) - ;; Retrieve from the Library of Babel. - ((nth 2 (assoc-string source-name org-babel-library-of-babel))) - ;; Return the contents of headlines literally. - ((save-excursion (org-babel-ref-goto-headline-id source-name)) - (org-babel-ref-headline-body)) - ;; Look for a source block named SOURCE-NAME. If - ;; found, assume it is unique; do not look after - ;; `:noweb-ref' header argument. - ((save-excursion - (goto-char (point-min)) - (and - (re-search-forward - (org-babel-named-src-block-regexp-for-name source-name) - nil t) - (not (org-in-commented-heading-p)) - (funcall expand-body (org-babel-get-src-block-info t))))) - ;; All Noweb references were cached in a previous - ;; run. Extract the information from the cache. - ((hash-table-p references) - (funcall expand-references source-name references)) - ;; Though luck. We go into the long process of - ;; checking each source block and expand those with - ;; a matching Noweb reference. Since we're going to - ;; visit all source blocks in the document, cache - ;; information about them as well. - (t - (setq references (make-hash-table :test #'equal)) - (org-babel-map-src-blocks nil - (if (org-in-commented-heading-p) - (org-forward-heading-same-level nil t) - (let* ((info (org-babel-get-src-block-info t)) - (ref (cdr (assq :noweb-ref (nth 2 info))))) - (push info (gethash ref references))))) - (funcall expand-references source-name references))) - "[\n\r]") - (concat "\n" prefix))))))) - (funcall nb-add (buffer-substring index (point-max)))) - new-body)) + (replace-regexp-in-string + noweb-re + (lambda (m) + (with-current-buffer parent-buffer + (save-match-data + (let* ((prefix (match-string 1 m)) + (id (match-string 3 m)) + (evaluate (string-match-p "(.*)" id)) + (expansion + (cond + (evaluate + ;; Evaluation can potentially modify the buffer + ;; and invalidate the cache: reset it. + (setq cache nil) + (let ((raw (org-babel-ref-resolve id))) + (if (stringp raw) raw (format "%S" raw)))) + ;; Retrieve from the Library of Babel. + ((nth 2 (assoc-string id org-babel-library-of-babel))) + ;; Return the contents of headlines literally. + ((org-babel-ref-goto-headline-id id) + (org-babel-ref-headline-body)) + ;; Look for a source block named SOURCE-NAME. If + ;; found, assume it is unique; do not look after + ;; `:noweb-ref' header argument. + ((org-with-point-at 1 + (let ((r (org-babel-named-src-block-regexp-for-name id))) + (and (re-search-forward r nil t) + (not (org-in-commented-heading-p)) + (funcall expand-body + (org-babel-get-src-block-info t)))))) + ;; All Noweb references were cached in a previous + ;; run. Extract the information from the cache. + ((hash-table-p cache) + (funcall expand-references id cache)) + ;; Though luck. We go into the long process of + ;; checking each source block and expand those + ;; with a matching Noweb reference. Since we're + ;; going to visit all source blocks in the + ;; document, cache information about them as well. + (t + (setq cache (make-hash-table :test #'equal)) + (org-with-wide-buffer + (org-babel-map-src-blocks nil + (if (org-in-commented-heading-p) + (org-forward-heading-same-level nil t) + (let* ((info (org-babel-get-src-block-info t)) + (ref (cdr (assq :noweb-ref (nth 2 info))))) + (push info (gethash ref cache)))))) + (funcall expand-references id cache))))) + ;; Interpose PREFIX between every line. + (mapconcat #'identity + (split-string expansion "[\n\r]") + (concat "\n" prefix)))))) + body nil t 2))) (defun org-babel--script-escape-inner (str) (let (in-single in-double backslash out) |