From 37bf0576f2f2894c6e37239ee8db63a3ef21a840 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Sun, 31 Aug 2014 11:10:56 +0200 Subject: [PATCH 1/5] org-element: Make properties parsing more robust * lisp/org-element.el (org-element-property-drawer-parser, org-element-node-property-parser): Ignore lines that are not node properties. (org-element-node-property-interpreter): Allow nil properties. * lisp/org.el (org-re-property): Fix regexp to match properties with empty values. * testing/lisp/test-org-element.el (test-org-element/node-property): Add tests. Thanks to Eike for reporting it. http://permalink.gmane.org/gmane.emacs.orgmode/90293 --- lisp/org-element.el | 92 ++++++++++++++++---------------- lisp/org.el | 6 +-- testing/lisp/test-org-element.el | 34 ++++++++---- 3 files changed, 73 insertions(+), 59 deletions(-) diff --git a/lisp/org-element.el b/lisp/org-element.el index 76c93ceac..eb8ff4158 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -1312,36 +1312,36 @@ containing `:begin', `:end', `:hiddenp', `:contents-begin', `:contents-end', `:post-blank' and `:post-affiliated' keywords. Assume point is at the beginning of the property drawer." - (save-excursion - (let ((case-fold-search t)) - (if (not (save-excursion - (re-search-forward "^[ \t]*:END:[ \t]*$" limit t))) - ;; Incomplete drawer: parse it as a paragraph. - (org-element-paragraph-parser limit affiliated) - (save-excursion - (let* ((drawer-end-line (match-beginning 0)) - (begin (car affiliated)) - (post-affiliated (point)) - (contents-begin (progn (forward-line) - (and (< (point) drawer-end-line) - (point)))) - (contents-end (and contents-begin drawer-end-line)) - (hidden (org-invisible-p2)) - (pos-before-blank (progn (goto-char drawer-end-line) - (forward-line) - (point))) - (end (progn (skip-chars-forward " \r\t\n" limit) - (if (eobp) (point) (line-beginning-position))))) - (list 'property-drawer - (nconc - (list :begin begin - :end end - :hiddenp hidden - :contents-begin contents-begin - :contents-end contents-end - :post-blank (count-lines pos-before-blank end) - :post-affiliated post-affiliated) - (cdr affiliated))))))))) + (let ((case-fold-search t)) + (if (not (save-excursion (re-search-forward "^[ \t]*:END:[ \t]*$" limit t))) + ;; Incomplete drawer: parse it as a paragraph. + (org-element-paragraph-parser limit affiliated) + (save-excursion + (let* ((drawer-end-line (match-beginning 0)) + (begin (car affiliated)) + (post-affiliated (point)) + (contents-begin + (progn + (forward-line) + (and (re-search-forward org-property-re drawer-end-line t) + (line-beginning-position)))) + (contents-end (and contents-begin drawer-end-line)) + (hidden (org-invisible-p2)) + (pos-before-blank (progn (goto-char drawer-end-line) + (forward-line) + (point))) + (end (progn (skip-chars-forward " \r\t\n" limit) + (if (eobp) (point) (line-beginning-position))))) + (list 'property-drawer + (nconc + (list :begin begin + :end end + :hiddenp hidden + :contents-begin contents-begin + :contents-end contents-end + :post-blank (count-lines pos-before-blank end) + :post-affiliated post-affiliated) + (cdr affiliated)))))))) (defun org-element-property-drawer-interpreter (property-drawer contents) "Interpret PROPERTY-DRAWER element as Org syntax. @@ -2096,28 +2096,28 @@ LIMIT bounds the search. Return a list whose CAR is `node-property' and CDR is a plist containing `:key', `:value', `:begin', `:end' and `:post-blank' keywords." - (save-excursion - (looking-at org-property-re) - (let ((case-fold-search t) - (begin (point)) - (key (org-match-string-no-properties 2)) - (value (org-match-string-no-properties 3)) - (pos-before-blank (progn (forward-line) (point))) - (end (progn (skip-chars-forward " \r\t\n" limit) - (if (eobp) (point) (point-at-bol))))) - (list 'node-property - (list :key key - :value value - :begin begin - :end end - :post-blank (count-lines pos-before-blank end)))))) + (looking-at org-property-re) + (let ((begin (point)) + (key (org-match-string-no-properties 2)) + (value (org-match-string-no-properties 3)) + (end (save-excursion + (end-of-line) + (if (re-search-forward org-property-re limit t) + (line-beginning-position) + limit)))) + (list 'node-property + (list :key key + :value value + :begin begin + :end end + :post-blank 0)))) (defun org-element-node-property-interpreter (node-property contents) "Interpret NODE-PROPERTY element as Org syntax. CONTENTS is nil." (format org-property-format (format ":%s:" (org-element-property :key node-property)) - (org-element-property :value node-property))) + (or (org-element-property :value node-property) ""))) ;;;; Paragraph diff --git a/lisp/org.el b/lisp/org.el index 60658f439..af450cc64 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -6156,9 +6156,9 @@ Use `org-reduced-level' to remove the effect of `org-odd-levels'." Match group 3 will be set to the value if it exists." (concat "^\\(?4:[ \t]*\\)\\(?1::\\(?2:" (if literal property (regexp-quote property)) - "\\):\\)[ \t]+\\(?3:[^ \t\r\n]" - (if allow-null "*") - ".*?\\)\\(?5:[ \t]*\\)$")) + "\\):\\)\\(?:[ \t]+\\(?3:[^ \t\r\n].*?\\)\\)" + (and allow-null "?") + "\\(?5:[ \t]*\\)$")) (defconst org-property-re (org-re-property ".*?" 'literal t) diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el index 12cd2bd4e..fdd654f83 100644 --- a/testing/lisp/test-org-element.el +++ b/testing/lisp/test-org-element.el @@ -1479,23 +1479,37 @@ e^{i\\pi}+1=0 ;; Standard test. (should (equal '("abc" "value") - (org-test-with-temp-text ":PROPERTIES:\n:abc: value\n:END:" - (progn (forward-line) - (let ((element (org-element-at-point))) - (list (org-element-property :key element) - (org-element-property :value element))))))) + (org-test-with-temp-text ":PROPERTIES:\n:abc: value\n:END:" + (let ((element (org-element-at-point))) + (list (org-element-property :key element) + (org-element-property :value element)))))) ;; Value should be trimmed. (should (equal "value" - (org-test-with-temp-text ":PROPERTIES:\n:abc: value \n:END:" - (progn (forward-line) - (let ((element (org-element-at-point))) - (org-element-property :value element)))))) + (org-test-with-temp-text ":PROPERTIES:\n:abc: value \n:END:" + (org-element-property :value (org-element-at-point))))) ;; A node property requires to be wrapped within a property drawer. (should-not (eq 'node-property (org-test-with-temp-text ":abc: value" - (org-element-type (org-element-at-point)))))) + (org-element-type (org-element-at-point))))) + ;; Accept empty properties. + (should + (equal '(("foo" "value") ("bar" nil)) + (org-test-with-temp-text ":PROPERTIES:\n:foo: value\n:bar:\n:END:" + (org-element-map (org-element-parse-buffer) 'node-property + (lambda (p) + (list (org-element-property :key p) + (org-element-property :value p))))))) + ;; Ignore all non-property lines in property drawers. + (should + (equal + '(("foo" "value")) + (org-test-with-temp-text ":PROPERTIES:\nWrong1\n:foo: value\nWrong2\n:END:" + (org-element-map (org-element-parse-buffer) 'node-property + (lambda (p) + (list (org-element-property :key p) + (org-element-property :value p)))))))) ;;;; Paragraph From 288ffa15f55ccdeb7156ab5749034aad100a05fb Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Sun, 31 Aug 2014 11:43:38 +0200 Subject: [PATCH 2/5] Fix failing tests * lisp/org.el (org--align-node-property): Properly align properties with empty values. --- lisp/org.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/org.el b/lisp/org.el index 72a306bcb..bc8996889 100755 --- a/lisp/org.el +++ b/lisp/org.el @@ -22469,7 +22469,9 @@ Alignment is done according to `org-property-format', which see." (looking-at org-property-re)) (replace-match (concat (match-string 4) - (format org-property-format (match-string 1) (match-string 3))) + (if (match-string 3) + (format org-property-format (match-string 1) (match-string 3)) + (match-string 1))) t t))) (defun org-indent-line () From bbdca56e916f9f51f7b0bde169db8599669846d7 Mon Sep 17 00:00:00 2001 From: David Arroyo Menendez Date: Sun, 31 Aug 2014 13:19:30 +0200 Subject: [PATCH 3/5] org-license.el: Upgrade to Creative Commons 4.0 * contrib/lisp/org-license.el: Change url and text in international license. --- contrib/lisp/org-license.el | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/contrib/lisp/org-license.el b/contrib/lisp/org-license.el index 9b82d8e66..426b148fd 100644 --- a/contrib/lisp/org-license.el +++ b/contrib/lisp/org-license.el @@ -97,9 +97,9 @@ Dit werk is valt onder een [[" org-license-cc-url "][Creative Commons Naamsverme (insert (concat "* Licença Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição 3.0 Portugal]]\n"))) (t - (setq org-license-cc-url "http://creativecommons.org/licenses/by/3.0/en/deed.en") + (setq org-license-cc-url "http://creativecommons.org/licenses/by/4.0/deed") (concat (insert "* License -This document is under a [[" org-license-cc-url "][Creative Commons Attribution 3.0]]\n")))) +This document is under a [[" org-license-cc-url "][Creative Commons Attribution 4.0 International]]\n")))) (if (string= "" org-license-images-directory) (insert (concat "\n[[" org-license-cc-url "][file:http://i.creativecommons.org/l/by/3.0/80x15.png]]\n")) (insert (concat "\n[[" org-license-cc-url "][file:" org-license-images-directory "/by/3.0/80x15.png]]\n")))) @@ -155,9 +155,9 @@ Dit werk is valt onder een [[" org-license-cc-url "][Creative Commons Naamsverme (insert (concat "* Licença Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição-CompartilhaIgual 3.0 Portugal]]\n"))) (t - (setq org-license-cc-url "http://creativecommons.org/licenses/by-sa/3.0/deed") + (setq org-license-cc-url "http://creativecommons.org/licenses/by-sa/4.0/deed") (insert (concat "* License -This document is under a [[" org-license-cc-url "][Creative Commons Attribution-ShareAlike Unported 3.0]]\n")))) +This document is under a [[" org-license-cc-url "][Creative Commons Attribution-ShareAlike 4.0 International]]\n")))) (if (string= "" org-license-images-directory) (insert (concat "\n[[" org-license-cc-url "][file:http://i.creativecommons.org/l/by-sa/3.0/80x15.png]]\n")) (insert (concat "\n[[" org-license-cc-url "][file:" org-license-images-directory "/by-sa/3.0/80x15.png]]\n")))) @@ -213,9 +213,9 @@ Dit werk is valt onder een [[" org-license-cc-url "][Creative Commons Naamsverme (insert (concat "* Licença Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição Sem Derivados 3.0 Portugal]]\n"))) (t - (setq org-license-cc-url "http://creativecommons.org/licenses/by-nd/3.0/deed") + (setq org-license-cc-url "http://creativecommons.org/licenses/by-nd/4.0/deed") (insert (concat "* License -This document is under a [[" org-license-cc-url "][Creative Commons No Derivatives Unported 3.0]]\n")))) +This document is under a [[" org-license-cc-url "][Creative Commons No Derivatives 4.0 International]]\n")))) (if (string= "" org-license-images-directory) (insert (concat "\n[[" org-license-cc-url "][file:http://i.creativecommons.org/l/by-nd/3.0/80x15.png]]\n")) (insert (concat "\n[[" org-license-cc-url "][file:" org-license-images-directory "/by-nd/3.0/80x15.png]]\n")))) @@ -272,9 +272,9 @@ Dit werk is valt onder een [[" org-license-cc-url "][Creative Commons Naamsverme (insert (concat "* Licença Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição Não Comercial 3.0 Portugal]]\n"))) (t - (setq org-license-cc-url "http://creativecommons.org/licenses/by-nc/3.0/deed") + (setq org-license-cc-url "http://creativecommons.org/licenses/by-nc/4.0/deed") (insert (concat "* License -This document is under a [[" org-license-cc-url "][Creative Commons Attribution-NonCommercial 3.0 Unported]]\n")))) +This document is under a [[" org-license-cc-url "][Creative Commons Attribution-NonCommercial 4.0 International]]\n")))) (if (string= "" org-license-images-directory) (insert (concat "\n[[" org-license-cc-url "][file:http://i.creativecommons.org/l/by-nc/3.0/80x15.png]]\n")) (insert (concat "\n[[" org-license-cc-url "][file:" org-license-images-directory "/by-nc/3.0/80x15.png]]\n")))) @@ -330,9 +330,9 @@ Dit werk is valt onder een [[" org-license-cc-url "][Creative Commons Naamsverme (insert (concat "* Licença Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição NãoComercial Compartil ha Igual 3.0 Portugal]]\n"))) (t - (setq org-license-cc-url "http://creativecommons.org/licenses/by-nc-sa/3.0/deed") + (setq org-license-cc-url "http://creativecommons.org/licenses/by-nc-sa/4.0/deed") (insert (concat "* License -This document is under a [[" org-license-cc-url "][License Creative Commons Attribution Non Commercial Share Alike 3.0 Unported]]\n")))) +This document is under a [[" org-license-cc-url "][License Creative Commons Attribution Non Commercial Share Alike 4.0 International]]\n")))) (if (string= "" org-license-images-directory) (insert (concat "\n[[" org-license-cc-url "][file:http://i.creativecommons.org/l/by-nc-sa/3.0/80x15.png]]\n")) (insert (concat "\n[[" org-license-cc-url "][file:" org-license-images-directory "/by-nc-sa/3.0/80x15.png]]\n")))) @@ -388,10 +388,9 @@ Dit werk is valt onder een [[" org-license-cc-url "][Creative Commons Naamsverme (insert (concat "* Licença Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição Não Comercial Sem Derivados 3.0 Portugal]]\n"))) (t - (setq org-license-cc-url "http://creativecommons.org/licenses/by-nc-nd/3.0/deed") + (setq org-license-cc-url "http://creativecommons.org/licenses/by-nc-nd/4.0/deed") (insert (concat "* License -This document is under a [[" org-license-cc-url "][License Creative Commons -Reconocimiento-NoComercial-SinObraDerivada 3.0 Unported]]\n")))) +This document is under a [[" org-license-cc-url "][License Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International]]\n")))) (if (string= "" org-license-images-directory) (insert (concat "\n[[" org-license-cc-url "][file:http://i.creativecommons.org/l/by-nc-nd/3.0/80x15.png]]\n")) (insert (concat "\n[[" org-license-cc-url "][file:" org-license-images-directory "/by-nc-nd/3.0/80x15.png]]\n")))) From 539eac92111aa9f920fde3015dbd9598e20b3e5c Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Sun, 31 Aug 2014 15:39:35 +0200 Subject: [PATCH 4/5] org-element: Recognize planning info only right after a headline * lisp/org.el (org-planning-line-re): New variable. Renamed from `org-planning-or-clock-line-re'. * lisp/org-element.el (org-element-paragraph-separate, org-element-headline-parser, org-element-inlinetask-parser, , org-element--current-element): Use new variable. (org-element-planning-parser): Check previous line before parsing planning info. When right after a headline, fallback to paragraph parsing. * testing/lisp/test-org-element.el (test-org-element/planning-parser): Add a test. Update others. (test-org-element/timestamp): Remove a test. * testing/lisp/test-ox.el (test-org-export/handle-options): Update test. --- lisp/org-element.el | 75 +++++++++++++++----------------- lisp/org.el | 7 ++- testing/lisp/test-org-element.el | 45 ++++++++----------- testing/lisp/test-ox.el | 8 ++-- 4 files changed, 61 insertions(+), 74 deletions(-) diff --git a/lisp/org-element.el b/lisp/org-element.el index c1051f66e..a02b45340 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -153,12 +153,8 @@ "-\\{5,\\}[ \t]*$" "\\|" ;; LaTeX environments. "\\\\begin{\\([A-Za-z0-9]+\\*?\\)}" "\\|" - ;; Planning and Clock lines. - (regexp-opt (list org-scheduled-string - org-deadline-string - org-closed-string - org-clock-string)) - "\\|" + ;; Clock lines. + (regexp-quote org-clock-string) "\\|" ;; Lists. (let ((term (case org-plain-list-ordered-item-terminator (?\) ")") (?. "\\.") (otherwise "[.)]"))) @@ -847,7 +843,7 @@ Assume point is at beginning of the headline." ;; Read time properties on the line below the headline. (save-excursion (forward-line) - (when (looking-at org-planning-or-clock-line-re) + (when (looking-at org-planning-line-re) (let ((end (line-end-position)) plist) (while (re-search-forward org-keyword-time-not-clock-regexp end t) @@ -1006,8 +1002,7 @@ Assume point is at beginning of the inline task." ;; opening string. (when task-end (save-excursion - (when (progn (forward-line) - (looking-at org-planning-or-clock-line-re)) + (when (progn (forward-line) (looking-at org-planning-line-re)) (let ((end (line-end-position)) plist) (while (re-search-forward org-keyword-time-not-clock-regexp end t) @@ -2239,33 +2234,35 @@ LIMIT bounds the search. Return a list whose CAR is `planning' and CDR is a plist containing `:closed', `:deadline', `:scheduled', `:begin', `:end', `:post-blank' and `:post-affiliated' keywords." - (save-excursion - (let* ((case-fold-search nil) - (begin (point)) - (post-blank (let ((before-blank (progn (forward-line) (point)))) - (skip-chars-forward " \r\t\n" limit) - (skip-chars-backward " \t") - (unless (bolp) (end-of-line)) - (count-lines before-blank (point)))) - (end (point)) - closed deadline scheduled) - (goto-char begin) - (while (re-search-forward org-keyword-time-not-clock-regexp end t) - (goto-char (match-end 1)) - (skip-chars-forward " \t" end) - (let ((keyword (match-string 1)) - (time (org-element-timestamp-parser))) - (cond ((equal keyword org-closed-string) (setq closed time)) - ((equal keyword org-deadline-string) (setq deadline time)) - (t (setq scheduled time))))) - (list 'planning - (list :closed closed - :deadline deadline - :scheduled scheduled - :begin begin - :end end - :post-blank post-blank - :post-affiliated begin))))) + (if (not (save-excursion (forward-line -1) (org-at-heading-p))) + (org-element-paragraph-parser limit (list (point))) + (save-excursion + (let* ((case-fold-search nil) + (begin (point)) + (post-blank (let ((before-blank (progn (forward-line) (point)))) + (skip-chars-forward " \r\t\n" limit) + (skip-chars-backward " \t") + (unless (bolp) (end-of-line)) + (count-lines before-blank (point)))) + (end (point)) + closed deadline scheduled) + (goto-char begin) + (while (re-search-forward org-keyword-time-not-clock-regexp end t) + (goto-char (match-end 1)) + (skip-chars-forward " \t" end) + (let ((keyword (match-string 1)) + (time (org-element-timestamp-parser))) + (cond ((equal keyword org-closed-string) (setq closed time)) + ((equal keyword org-deadline-string) (setq deadline time)) + (t (setq scheduled time))))) + (list 'planning + (list :closed closed + :deadline deadline + :scheduled scheduled + :begin begin + :end end + :post-blank post-blank + :post-affiliated begin)))))) (defun org-element-planning-interpreter (planning contents) "Interpret PLANNING element as Org syntax. @@ -3667,10 +3664,8 @@ element it has to parse." ;; a footnote definition: next item is always a paragraph. ((not (bolp)) (org-element-paragraph-parser limit (list (point)))) ;; Planning and Clock. - ((looking-at org-planning-or-clock-line-re) - (if (equal (match-string 1) org-clock-string) - (org-element-clock-parser limit) - (org-element-planning-parser limit))) + ((looking-at org-planning-line-re) (org-element-planning-parser limit)) + ((looking-at org-clock-line-re) (org-element-clock-parser limit)) ;; Inlinetask. ((org-at-heading-p) (org-element-inlinetask-parser limit raw-secondary-p)) diff --git a/lisp/org.el b/lisp/org.el index bc8996889..2b3d00a7e 100755 --- a/lisp/org.el +++ b/lisp/org.el @@ -387,13 +387,12 @@ A schedule is this string, followed by a time stamp. Should be a word, terminated by a colon. You can insert a schedule keyword and a timestamp with \\[org-schedule].") -(defconst org-planning-or-clock-line-re +(defconst org-planning-line-re (concat "^[ \t]*" (regexp-opt - (list org-clock-string org-closed-string org-deadline-string - org-scheduled-string) + (list org-closed-string org-deadline-string org-scheduled-string) t)) - "Matches a line with planning or clock info. + "Matches a line with planning info. Matched keyword is in group 1.") (defconst org-clock-line-re diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el index ceff32993..6fb8db835 100644 --- a/testing/lisp/test-org-element.el +++ b/testing/lisp/test-org-element.el @@ -1693,30 +1693,27 @@ Outside list" (ert-deftest test-org-element/planning-parser () "Test `planning' parser." + ;; Test various keywords. (should - (equal "[2012-03-29 thu.]" - (org-element-property - :raw-value - (org-element-property - :closed - (org-test-with-temp-text "CLOSED: [2012-03-29 thu.]" - (org-element-at-point)))))) + (org-element-property + :closed + (org-test-with-temp-text "* H\nCLOSED: [2012-03-29 thu.]" + (org-element-at-point)))) (should - (equal "<2012-03-29 thu.>" - (org-element-property - :raw-value - (org-element-property - :deadline - (org-test-with-temp-text "DEADLINE: <2012-03-29 thu.>" - (org-element-at-point)))))) + (org-element-property + :deadline + (org-test-with-temp-text "* H\nDEADLINE: <2012-03-29 thu.>" + (org-element-at-point)))) (should - (equal "<2012-03-29 thu.>" - (org-element-property - :raw-value - (org-element-property - :scheduled - (org-test-with-temp-text "SCHEDULED: <2012-03-29 thu.>" - (org-element-at-point))))))) + (org-element-property + :scheduled + (org-test-with-temp-text "* H\nSCHEDULED: <2012-03-29 thu.>" + (org-element-at-point)))) + ;; Planning line only exists right after a headline. + (should-not + (eq 'planning + (org-test-with-temp-text "DEADLINE: <2012-03-29 thu.>" + (org-element-type (org-element-at-point)))))) ;;;; Property Drawer @@ -2089,11 +2086,7 @@ Outside list" (org-test-with-temp-text "<2012-03-29 Thu +1y -1y>" (let ((ts (org-element-context))) (list (org-element-property :repeater-type ts) - (org-element-property :warning-type ts)))))) - ;; Timestamps are not planning elements. - (should-not - (org-test-with-temp-text "SCHEDULED: <2012-03-29 Thu 16:40>" - (org-element-map (org-element-parse-buffer) 'timestamp 'identity)))) + (org-element-property :warning-type ts))))))) ;;;; Underline diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el index e67ee95ff..1e92afe5c 100644 --- a/testing/lisp/test-ox.el +++ b/testing/lisp/test-ox.el @@ -482,15 +482,15 @@ Paragraph" ;; Plannings. (should (string-match - "CLOSED: \\[2012-04-29 .* 10:45\\]" + "* H\nCLOSED: \\[2012-04-29 .* 10:45\\]" (let ((org-closed-string "CLOSED:")) - (org-test-with-temp-text "CLOSED: [2012-04-29 sun. 10:45]" + (org-test-with-temp-text "* H\nCLOSED: [2012-04-29 sun. 10:45]" (org-export-as (org-test-default-backend) nil nil nil '(:with-planning t)))))) (should - (equal "" + (equal "* H\n" (let ((org-closed-string "CLOSED:")) - (org-test-with-temp-text "CLOSED: [2012-04-29 sun. 10:45]" + (org-test-with-temp-text "* H\nCLOSED: [2012-04-29 sun. 10:45]" (org-export-as (org-test-default-backend) nil nil nil '(:with-planning nil)))))) ;; Property Drawers. From 21258060ad0f46be2d967fda6c6346a7f5723b8c Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Sun, 31 Aug 2014 16:31:59 +0200 Subject: [PATCH 5/5] org-element: Small optimization * lisp/org-element.el (org-element--current-element): Only look after planning lines right after parsing a section. (org-element--next-mode): New function. (org-element--parse-elements, org-element--parse-to): Use new function. --- lisp/org-element.el | 65 +++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/lisp/org-element.el b/lisp/org-element.el index a02b45340..d70cd995c 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -3610,8 +3610,7 @@ CONTENTS is nil." ;; `section'). Special modes are: `first-section', `item', ;; `node-property', `section' and `table-row'. -(defun org-element--current-element - (limit &optional granularity special structure) +(defun org-element--current-element (limit &optional granularity mode structure) "Parse the element starting at point. Return value is a list like (TYPE PROPS) where TYPE is the type @@ -3628,12 +3627,12 @@ recursion. Allowed values are `headline', `greater-element', nil), secondary values will not be parsed, since they only contain objects. -Optional argument SPECIAL, when non-nil, can be either -`first-section', `item', `node-property', `section', and -`table-row'. +Optional argument MODE, when non-nil, can be either +`first-section', `section', `planning', `item', `node-property' +and `table-row'. -If STRUCTURE isn't provided but SPECIAL is set to `item', it will -be computed. +If STRUCTURE isn't provided but MODE is set to `item', it will be +computed. This function assumes point is always at the beginning of the element it has to parse." @@ -3645,26 +3644,28 @@ element it has to parse." (raw-secondary-p (and granularity (not (eq granularity 'object))))) (cond ;; Item. - ((eq special 'item) + ((eq mode 'item) (org-element-item-parser limit structure raw-secondary-p)) ;; Table Row. - ((eq special 'table-row) (org-element-table-row-parser limit)) + ((eq mode 'table-row) (org-element-table-row-parser limit)) ;; Node Property. - ((eq special 'node-property) (org-element-node-property-parser limit)) + ((eq mode 'node-property) (org-element-node-property-parser limit)) ;; Headline. ((org-with-limited-levels (org-at-heading-p)) (org-element-headline-parser limit raw-secondary-p)) ;; Sections (must be checked after headline). - ((eq special 'section) (org-element-section-parser limit)) - ((eq special 'first-section) + ((eq mode 'section) (org-element-section-parser limit)) + ((eq mode 'first-section) (org-element-section-parser (or (save-excursion (org-with-limited-levels (outline-next-heading))) limit))) + ;; Planning. + ((and (eq mode 'planning) (looking-at org-planning-line-re)) + (org-element-planning-parser limit)) ;; When not at bol, point is at the beginning of an item or ;; a footnote definition: next item is always a paragraph. ((not (bolp)) (org-element-paragraph-parser limit (list (point)))) - ;; Planning and Clock. - ((looking-at org-planning-line-re) (org-element-planning-parser limit)) + ;; Clock. ((looking-at org-clock-line-re) (org-element-clock-parser limit)) ;; Inlinetask. ((org-at-heading-p) @@ -4078,6 +4079,18 @@ looking into captions: ;; object is searched only once at top level (but sometimes more for ;; nested types). +(defsubst org-element--next-mode (type) + "Return next special mode according to TYPE, or nil. +TYPE is a symbol representing the type of an element or object. +Modes can be either `first-section', `section', `planning', +`item', `node-property' and `table-row'." + (case type + (headline 'section) + (section 'planning) + (plain-list 'item) + (property-drawer 'node-property) + (table 'table-row))) + (defun org-element--parse-elements (beg end special structure granularity visible-only acc) "Parse elements between BEG and END positions. @@ -4132,11 +4145,7 @@ Elements are accumulated into ACC." (org-element--parse-elements cbeg (org-element-property :contents-end element) ;; Possibly switch to a special mode. - (case type - (headline 'section) - (plain-list 'item) - (property-drawer 'node-property) - (table 'table-row)) + (org-element--next-mode type) (and (memq type '(item plain-list)) (org-element-property :structure element)) granularity visible-only element)) @@ -5220,7 +5229,7 @@ the process stopped before finding the expected result." (let* ((cached (and (org-element--cache-active-p) (org-element--cache-find pos nil))) (begin (org-element-property :begin cached)) - element next) + element next mode) (cond ;; Nothing in cache before point: start parsing from first ;; element following headline above, or first element in @@ -5229,7 +5238,8 @@ the process stopped before finding the expected result." (when (org-with-limited-levels (outline-previous-heading)) (forward-line)) (skip-chars-forward " \r\t\n") - (beginning-of-line)) + (beginning-of-line) + (setq mode 'planning)) ;; Cache returned exact match: return it. ((= pos begin) (throw 'exit (if syncp (org-element-property :parent cached) cached))) @@ -5240,7 +5250,8 @@ the process stopped before finding the expected result." (org-with-limited-levels org-outline-regexp-bol) begin t) (forward-line) (skip-chars-forward " \r\t\n") - (beginning-of-line)) + (beginning-of-line) + (setq mode 'planning)) ;; Check if CACHED or any of its ancestors contain point. ;; ;; If there is such an element, we inspect it in order to know @@ -5274,8 +5285,7 @@ the process stopped before finding the expected result." (save-excursion (org-with-limited-levels (outline-next-heading)) (point)))) - (parent element) - special-flag) + (parent element)) (while t (when syncp (cond ((= (point) pos) (throw 'exit parent)) @@ -5283,7 +5293,7 @@ the process stopped before finding the expected result." (throw 'interrupt nil)))) (unless element (setq element (org-element--current-element - end 'element special-flag + end 'element mode (org-element-property :structure parent))) (org-element-put-property element :parent parent) (org-element--cache-put element)) @@ -5323,10 +5333,7 @@ the process stopped before finding the expected result." (and (= cend pos) (= (point-max) pos))))) (goto-char (or next cbeg)) (setq next nil - special-flag (case type - (plain-list 'item) - (property-drawer 'node-property) - (table 'table-row)) + mode (org-element--next-mode type) parent element end cend)))) ;; Otherwise, return ELEMENT as it is the smallest