diff options
author | Nicolas Goaziou <mail@nicolasgoaziou.fr> | 2014-08-31 11:10:56 +0200 |
---|---|---|
committer | Nicolas Goaziou <mail@nicolasgoaziou.fr> | 2014-08-31 11:10:56 +0200 |
commit | 37bf0576f2f2894c6e37239ee8db63a3ef21a840 (patch) | |
tree | 35bc65aa97768cf1281f19de85d38275191f1c9f | |
parent | 2e5b3dede103bba0071144ec7b7fc250471c1463 (diff) | |
download | org-mode-37bf0576f2f2894c6e37239ee8db63a3ef21a840.tar.gz |
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
-rw-r--r-- | lisp/org-element.el | 92 | ||||
-rw-r--r-- | lisp/org.el | 6 | ||||
-rw-r--r-- | 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 76c93ce..eb8ff41 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 60658f4..af450cc 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 12cd2bd..fdd654f 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<point>: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<point>: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 |