From 236396ebf8a4ed8d8021b0064c6b0981ec6cdb16 Mon Sep 17 00:00:00 2001 From: Carsten Dominik Date: Wed, 28 May 2008 16:59:17 +0200 Subject: [PATCH] Split the export pre-processor into a zillion small functions. --- lisp/ChangeLog | 20 +++ lisp/org-exp.el | 328 +++++++++++++++++++++++++++--------------------- lisp/org.el | 6 +- 3 files changed, 211 insertions(+), 143 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 2fe377235..68819ed97 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,5 +1,25 @@ 2008-05-28 Carsten Dominik + * org-exp.el (org-export-ascii-preprocess): Renamed from + `org-export-ascii-clean-string'. + (org-export-kill-licensed-text) + (org-export-define-heading-targets) + (org-export-handle-invisible-targets) + (org-export-target-internal-links) + (org-export-remove-or-extract-drawers) + (org-export-remove-archived-trees) + (org-export-protect-quoted-subtrees) + (org-export-protect-verbatim, org-export-protect-examples) + (org-export-select-backend-specific-text) + (org-export-mark-blockquote-and-verse) + (org-export-remove-comment-blocks-and-subtrees) + (org-export-handle-comments, org-export-mark-radio-links) + (org-export-remove-special-table-lines) + (org-export-normalize-links) + (org-export-concatenate-multiline-links) + (org-export-concatenate-multiline-emphasis): New functions, + obtained from spliiting the export preprocessor. + * org-table.el (org-table-recalculate): Improve error message if the row number is invalid. diff --git a/lisp/org-exp.el b/lisp/org-exp.el index a9a8325f1..47602f3ad 100644 --- a/lisp/org-exp.el +++ b/lisp/org-exp.el @@ -1239,18 +1239,14 @@ to export. It then creates a temporary buffer where it does its job. The result is then again returned as a string, and the exporter works on this string to produce the exported version." (interactive) - (let* ((re-radio (and org-target-link-regexp - (concat "\\([^<]\\)\\(" org-target-link-regexp "\\)"))) - (htmlp (plist-get parameters :for-html)) + (let* ((htmlp (plist-get parameters :for-html)) (asciip (plist-get parameters :for-ascii)) (latexp (plist-get parameters :for-LaTeX)) - (commentsp (plist-get parameters :comments)) (archived-trees (plist-get parameters :archived-trees)) (inhibit-read-only t) (drawers org-drawers) (outline-regexp "\\*+ ") - target-alist tmp target level - a b rtn p) + target-alist rtn) (with-current-buffer (get-buffer-create " org-mode-tmp") (erase-buffer) @@ -1263,21 +1259,21 @@ on this string to produce the exported version." ;; The caller markes some stuff fo killing, stuff that has been ;; used to create the page title, for example. (org-export-kill-licensed-text) - + (let ((org-inhibit-startup t)) (org-mode)) (setq case-fold-search t) (untabify (point-min) (point-max)) - + ;; Handle incude files (org-export-handle-include-files) - + ;; Handle source code snippets (org-export-replace-src-segments) - + ;; Get rid of drawers (org-export-remove-or-extract-drawers drawers (plist-get parameters :drawers)) - + ;; Get the correct stuff before the first headline (when (plist-get parameters :skip-before-1st-heading) (goto-char (point-min)) @@ -1288,77 +1284,23 @@ on this string to produce the exported version." (when (plist-get parameters :add-text) (goto-char (point-min)) (insert (plist-get parameters :add-text) "\n")) - + ;; Get rid of archived trees (org-export-remove-archived-trees archived-trees) - + ;; Find all headings and compute the targets for them - (goto-char (point-min)) - (org-init-section-numbers) - (let ((re (concat "^" org-outline-regexp))) - (while (re-search-forward re nil t) - (setq level (org-reduced-level - (save-excursion (goto-char (point-at-bol)) - (org-outline-level)))) - (setq target (org-solidify-link-text - (format "sec-%s" (org-section-number level)))) - (push (cons target target) target-alist) - (add-text-properties - (point-at-bol) (point-at-eol) - (list 'target target)))) + (setq target-alist (org-export-define-heading-targets target-alist)) ;; Find targets in comments and move them out of comments, ;; but mark them as targets that should be invisible - (goto-char (point-min)) - (while (re-search-forward "^#.*?\\(<<\r\n]+\\)>>>?\\).*" nil t) - ;; Check if the line before or after is a headline with a target - (if (setq target (or (get-text-property (point-at-bol 0) 'target) - (get-text-property (point-at-bol 2) 'target))) - (progn - ;; use the existing target in a neighboring line - (setq tmp (match-string 2)) - (replace-match "") - (and (looking-at "\n") (delete-char 1)) - (push (cons (org-solidify-link-text tmp) target) - target-alist)) - ;; Make an invisible target - (replace-match "\\1(INVISIBLE)"))) + (setq target-alist (org-export-handle-invisible-targets target-alist)) + + ;; Protect examples + (org-export-protect-examples) ;; Protect backend specific stuff, throw away the others. - (let ((formatters - `((,htmlp "HTML" "BEGIN_HTML" "END_HTML") - (,asciip "ASCII" "BEGIN_ASCII" "END_ASCII") - (,latexp "LaTeX" "BEGIN_LaTeX" "END_LaTeX"))) - fmt) - (goto-char (point-min)) - (while (re-search-forward "^#\\+BEGIN_EXAMPLE[ \t]*\n" nil t) - (goto-char (match-end 0)) - (while (not (looking-at "#\\+END_EXAMPLE")) - (insert ": ") - (beginning-of-line 2))) - (goto-char (point-min)) - (while (re-search-forward "^[ \t]*:.*\\(\n[ \t]*:.*\\)*" nil t) - (add-text-properties (match-beginning 0) (match-end 0) - '(org-protected t))) - (while formatters - (setq fmt (pop formatters)) - (when (car fmt) - (goto-char (point-min)) - (while (re-search-forward (concat "^#\\+" (cadr fmt) - ":[ \t]*\\(.*\\)") nil t) - (replace-match "\\1" t) - (add-text-properties - (point-at-bol) (min (1+ (point-at-eol)) (point-max)) - '(org-protected t)))) - (goto-char (point-min)) - (while (re-search-forward - (concat "^#\\+" - (caddr fmt) "\\>.*\\(\\(\n.*\\)*?\n\\)#\\+" - (cadddr fmt) "\\>.*\n?") nil t) - (if (car fmt) - (add-text-properties (match-beginning 1) (1+ (match-end 1)) - '(org-protected t)) - (delete-region (match-beginning 0) (match-end 0)))))) + (org-export-select-backend-specific-text + (cond (htmlp 'html) (latexp 'latex) (asciip 'ascii))) ;; Protect quoted subtrees (org-export-protect-quoted-subtrees) @@ -1381,40 +1323,19 @@ on this string to produce the exported version." (require 'org-export-latex nil) (org-export-latex-preprocess)) + ;; Specific ASCII stuff (when asciip - (org-export-ascii-clean-string)) + (org-export-ascii-preprocess)) ;; Specific HTML stuff (when htmlp - ;; Convert LaTeX fragments to images - (when (plist-get parameters :LaTeX-fragments) - (org-format-latex - (concat "ltxpng/" (file-name-sans-extension - (file-name-nondirectory - org-current-export-file))) - org-current-export-dir nil "Creating LaTeX image %s")) - (message "Exporting...")) + (org-export-html-preprocess parameters)) ;; Remove or replace comments - (goto-char (point-min)) - (while (re-search-forward "^#\\(.*\n?\\)" nil t) - (setq pos (match-beginning 0)) - (if commentsp - (progn (add-text-properties - (match-beginning 0) (match-end 0) '(org-protected t)) - (replace-match (format commentsp (match-string 1)) t t)) - (goto-char (1+ pos)) - (org-if-unprotected - (replace-match "") - (goto-char (max (point-min) (1- pos)))) - (end-of-line 1))) + (org-export-handle-comments (plist-get parameters :comments)) ;; Find matches for radio targets and turn them into internal links - (goto-char (point-min)) - (when re-radio - (while (re-search-forward re-radio nil t) - (org-if-unprotected - (replace-match "\\1[[\\2]]")))) + (org-export-mark-radio-links) ;; Find all links that contain a newline and put them into a single line (org-export-concatenate-multiline-links) @@ -1422,42 +1343,10 @@ on this string to produce the exported version." ;; Find all internal links. If they have a fuzzy match (i.e. not ;; a *dedicated* target match, let the link point to the ;; corresponding section. - - (goto-char (point-min)) - (while (re-search-forward org-bracket-link-regexp nil t) - (org-if-unprotected - (let* ((md (match-data)) - (desc (match-end 2)) - (link (org-link-unescape (match-string 1))) - (slink (org-solidify-link-text link)) - found props pos - (target - (or (cdr (assoc slink target-alist)) - (save-excursion - (unless (string-match org-link-types-re link) - (setq found (condition-case nil (org-link-search link) - (error nil))) - (when (and found - (or (org-on-heading-p) - (not (eq found 'dedicated)))) - (or (get-text-property (point) 'target) - (get-text-property - (max (point-min) - (1- (previous-single-property-change - (point) 'target))) - 'target)))))))) - (when target - (set-match-data md) - (goto-char (match-beginning 1)) - (setq props (text-properties-at (point))) - (delete-region (match-beginning 1) (match-end 1)) - (setq pos (point)) - (insert target) - (unless desc (insert "][" link)) - (add-text-properties pos (point) props))))) + (org-export-target-internal-links target-alist) ;; Normalize links: Convert angle and plain links into bracket links - ;; Expand link abbreviations + ;; and expand link abbreviations (org-export-normalize-links) ;; Find multiline emphasis and put them into single line @@ -1470,9 +1359,86 @@ on this string to produce the exported version." (defun org-export-kill-licensed-text () "Remove all text that is marked with a :org-license-to-kill property." - (while (setq p (text-property-any (point-min) (point-max) - :org-license-to-kill t)) - (delete-region p (next-single-property-change p :org-license-to-kill)))) + (let (p) + (while (setq p (text-property-any (point-min) (point-max) + :org-license-to-kill t)) + (delete-region p (next-single-property-change p :org-license-to-kill))))) + +(defun org-export-define-heading-targets (target-alist) + "Find all headings and define the targets for them. +The new targets are added to TARGET-ALIST, which is also returned." + (goto-char (point-min)) + (org-init-section-numbers) + (let ((re (concat "^" org-outline-regexp)) + level target) + (while (re-search-forward re nil t) + (setq level (org-reduced-level + (save-excursion (goto-char (point-at-bol)) + (org-outline-level)))) + (setq target (org-solidify-link-text + (format "sec-%s" (org-section-number level)))) + (push (cons target target) target-alist) + (add-text-properties + (point-at-bol) (point-at-eol) + (list 'target target)))) + target-alist) + +(defun org-export-handle-invisible-targets (target-alist) + "Find targets in comments and move them out of comments. +Mark them as invisible targets." + (let (target tmp) + (goto-char (point-min)) + (while (re-search-forward "^#.*?\\(<<\r\n]+\\)>>>?\\).*" nil t) + ;; Check if the line before or after is a headline with a target + (if (setq target (or (get-text-property (point-at-bol 0) 'target) + (get-text-property (point-at-bol 2) 'target))) + (progn + ;; use the existing target in a neighboring line + (setq tmp (match-string 2)) + (replace-match "") + (and (looking-at "\n") (delete-char 1)) + (push (cons (org-solidify-link-text tmp) target) + target-alist)) + ;; Make an invisible target + (replace-match "\\1(INVISIBLE)")))) + target-alist) + +(defun org-export-target-internal-links (target-alist) + "Find all internal links and assign target to them. +If a link has a fuzzy match (i.e. not a *dedicated* target match), +let the link point to the corresponding section." + (goto-char (point-min)) + (while (re-search-forward org-bracket-link-regexp nil t) + (org-if-unprotected + (let* ((md (match-data)) + (desc (match-end 2)) + (link (org-link-unescape (match-string 1))) + (slink (org-solidify-link-text link)) + found props pos + (target + (or (cdr (assoc slink target-alist)) + (save-excursion + (unless (string-match org-link-types-re link) + (setq found (condition-case nil (org-link-search link) + (error nil))) + (when (and found + (or (org-on-heading-p) + (not (eq found 'dedicated)))) + (or (get-text-property (point) 'target) + (get-text-property + (max (point-min) + (1- (previous-single-property-change + (point) 'target))) + 'target)))))))) + (when target + (set-match-data md) + (goto-char (match-beginning 1)) + (setq props (text-properties-at (point))) + (delete-region (match-beginning 1) (match-end 1)) + (setq pos (point)) + (insert target) + (unless desc (insert "][" link)) + (add-text-properties pos (point) props)))))) (defun org-export-remove-or-extract-drawers (all-drawers exp-drawers) "Remove drawers, or extract the content. @@ -1499,13 +1465,13 @@ When it is nil the entire tree including the headline will be removed from the buffer." (let ((re-archive (concat ":" org-archive-tag ":")) a b) - (when (not (eq archived-trees t)) + (when (not (eq export-archived-trees t)) (goto-char (point-min)) (while (re-search-forward re-archive nil t) (if (not (org-on-heading-p t)) (org-end-of-subtree t) (beginning-of-line 1) - (setq a (if archived-trees + (setq a (if export-archived-trees (1+ (point-at-eol)) (point)) b (org-end-of-subtree t)) (if (> b a) (delete-region a b))))))) @@ -1528,6 +1494,49 @@ from the buffer." '(org-protected t)) (goto-char (1+ (match-end 4))))) +(defun org-export-protect-examples () + "Protect code that should be exported as monospaced examples." + (goto-char (point-min)) + (while (re-search-forward "^#\\+BEGIN_EXAMPLE[ \t]*\n" nil t) + (goto-char (match-end 0)) + (while (not (looking-at "#\\+END_EXAMPLE")) + (insert ": ") + (beginning-of-line 2))) + (goto-char (point-min)) + (while (re-search-forward "^[ \t]*:.*\\(\n[ \t]*:.*\\)*" nil t) + (add-text-properties (match-beginning 0) (match-end 0) + '(org-protected t)))) + +(defun org-export-select-backend-specific-text (backend) + (let ((formatters + '((html "HTML" "BEGIN_HTML" "END_HTML") + (ascii "ASCII" "BEGIN_ASCII" "END_ASCII") + (latex "LaTeX" "BEGIN_LaTeX" "END_LaTeX"))) + fmt) + + (while formatters + (setq fmt (pop formatters)) + (when (eq (car fmt) backend) + ;; This is selected code, put it into the file for real + (goto-char (point-min)) + (while (re-search-forward (concat "^#\\+" (cadr fmt) + ":[ \t]*\\(.*\\)") nil t) + (replace-match "\\1" t) + (add-text-properties + (point-at-bol) (min (1+ (point-at-eol)) (point-max)) + '(org-protected t)))) + (goto-char (point-min)) + (while (re-search-forward + (concat "^#\\+" + (caddr fmt) "\\>.*\\(\\(\n.*\\)*?\n\\)#\\+" + (cadddr fmt) "\\>.*\n?") nil t) + (if (eq (car fmt) backend) + ;; yes, keep this + (add-text-properties (match-beginning 1) (1+ (match-end 1)) + '(org-protected t)) + ;; No, this is for a different backend, kill it + (delete-region (match-beginning 0) (match-end 0))))))) + (defun org-export-mark-blockquote-and-verse () "Mark block quote and verse environments with special cookies. These special cookies will later be interpreted by the backend." @@ -1559,6 +1568,34 @@ These special cookies will later be interpreted by the backend." (goto-char (match-beginning 0)) (delete-region (point) (org-end-of-subtree t))))) +(defun org-export-handle-comments (commentsp) + "Remove comments, or convert to backend-specific format. +COMMENTSP can be a format string for publishing comments. +When it is nit, all comments will be removed." + (let (pos) + (goto-char (point-min)) + (while (re-search-forward "^#\\(.*\n?\\)" nil t) + (setq pos (match-beginning 0)) + (if commentsp + (progn (add-text-properties + (match-beginning 0) (match-end 0) '(org-protected t)) + (replace-match (format commentsp (match-string 1)) t t)) + (goto-char (1+ pos)) + (org-if-unprotected + (replace-match "") + (goto-char (max (point-min) (1- pos)))) + (end-of-line 1))))) + +(defun org-export-mark-radio-links () + "Find all matches for radio targets and turn them into internal links." + (let ((re-radio (and org-target-link-regexp + (concat "\\([^<]\\)\\(" org-target-link-regexp "\\)")))) + (goto-char (point-min)) + (when re-radio + (while (re-search-forward re-radio nil t) + (org-if-unprotected + (replace-match "\\1[[\\2]]")))))) + (defun org-export-remove-special-table-lines () "Remove tables lines that are used for internal purposes." (goto-char (point-min)) @@ -1616,7 +1653,6 @@ can work correctly." (replace-match "\\1 \\3") (goto-char (match-beginning 0))))) - (defun org-export-concatenate-multiline-emphasis () "Find multi-line emphasis and put it all into a single line. This is to make sure that the line-processing export backends @@ -2097,7 +2133,7 @@ underlined headlines. The default is 3." (goto-char beg))) (goto-char (point-min)))) -(defun org-export-ascii-clean-string () +(defun org-export-ascii-preprocess () "Do extra work for ASCII export" (goto-char (point-min)) (while (re-search-forward org-verbatim-re nil t) @@ -2320,6 +2356,16 @@ Does include HTML export options as well as TODO and CATEGORY stuff." "org file:~/org/%s.org" )) +(defun org-export-html-preprocess (parameters) + ;; Convert LaTeX fragments to images + (when (plist-get parameters :LaTeX-fragments) + (org-format-latex + (concat "ltxpng/" (file-name-sans-extension + (file-name-nondirectory + org-current-export-file))) + org-current-export-dir nil "Creating LaTeX image %s")) + (message "Exporting...")) + ;;;###autoload (defun org-insert-export-options-template () "Insert into the buffer a template with information for exporting." diff --git a/lisp/org.el b/lisp/org.el index 2d813add9..3de880aa3 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -5335,6 +5335,8 @@ If WITH-CASE is non-nil, the sorting will be case-sensitive." (defvar org-exit-edit-mode-map (make-sparse-keymap)) (define-key org-exit-edit-mode-map "\C-c'" 'org-edit-src-exit) +(defvar org-edit-src-force-single-line nil) +(defvar org-edit-src-from-org-mode nil) (define-minor-mode org-exit-edit-mode "Minor mode installing a single key binding, \"C-c '\" to exit special edit.") @@ -5351,7 +5353,7 @@ exit by killing the buffer with \\[org-edit-src-exit]." "Edit, then exit with C-c ' (C-c and single quote)")) (info (org-edit-src-find-region-and-lang)) (org-mode-p (eq major-mode 'org-mode)) - beg end lang single) + beg end lang lang-f single) (if (not info) nil (setq beg (nth 0 info) @@ -5406,7 +5408,7 @@ the language, a switch telling of the content should be in a single line." ("^#\\+ascii:" "\n" "ascii" single-line) )) (pos (point)) - re beg end lang) + re re1 re2 single beg end lang) (catch 'exit (while (setq entry (pop re-list)) (setq re1 (car entry) re2 (nth 1 entry) lang (nth 2 entry)