Browse Source

Merge branch 'master' of orgmode.org:org-mode

Bastien Guerry 11 years ago
parent
commit
255f060ad0
5 changed files with 184 additions and 174 deletions
  1. 12 13
      contrib/lisp/org-license.el
  2. 116 113
      lisp/org-element.el
  3. 9 8
      lisp/org.el
  4. 43 36
      testing/lisp/test-org-element.el
  5. 4 4
      testing/lisp/test-ox.el

+ 12 - 13
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
 	  (insert (concat "* Licença
 Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição 3.0 Portugal]]\n")))
 Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição 3.0 Portugal]]\n")))
 	 (t
 	 (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
 	  (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)
   (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: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"))))
     (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
 	 (insert (concat "* Licença
 Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição-CompartilhaIgual 3.0 Portugal]]\n")))
 Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição-CompartilhaIgual 3.0 Portugal]]\n")))
 	(t
 	(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
 	 (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)
   (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: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"))))
     (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
 	 (insert (concat "* Licença
 Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição Sem Derivados 3.0 Portugal]]\n")))
 Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição Sem Derivados 3.0 Portugal]]\n")))
 	(t
 	(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
 	 (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)
   (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: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"))))
     (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
 	 (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")))
 Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição Não Comercial 3.0 Portugal]]\n")))
 	(t 
 	(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 
 	 (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)
   (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: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"))))
     (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
 	 (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")))
 Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição NãoComercial Compartil ha Igual 3.0 Portugal]]\n")))
 	(t 
 	(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
 	 (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)
   (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: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"))))
     (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
 	 (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")))
 Este texto é disponibilizado nos termos da licença [[" org-license-cc-url "][Atribuição Não Comercial Sem Derivados 3.0 Portugal]]\n")))
 	(t 
 	(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
 	 (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)
   (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: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"))))
     (insert (concat "\n[[" org-license-cc-url "][file:" org-license-images-directory "/by-nc-nd/3.0/80x15.png]]\n"))))

+ 116 - 113
lisp/org-element.el

@@ -153,12 +153,8 @@
           "-\\{5,\\}[ \t]*$" "\\|"
           "-\\{5,\\}[ \t]*$" "\\|"
           ;; LaTeX environments.
           ;; LaTeX environments.
           "\\\\begin{\\([A-Za-z0-9]+\\*?\\)}" "\\|"
           "\\\\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.
           ;; Lists.
           (let ((term (case org-plain-list-ordered-item-terminator
           (let ((term (case org-plain-list-ordered-item-terminator
                         (?\) ")") (?. "\\.") (otherwise "[.)]")))
                         (?\) ")") (?. "\\.") (otherwise "[.)]")))
@@ -847,7 +843,7 @@ Assume point is at beginning of the headline."
 	    ;; Read time properties on the line below the headline.
 	    ;; Read time properties on the line below the headline.
 	    (save-excursion
 	    (save-excursion
 	      (forward-line)
 	      (forward-line)
-	      (when (looking-at org-planning-or-clock-line-re)
+	      (when (looking-at org-planning-line-re)
 		(let ((end (line-end-position)) plist)
 		(let ((end (line-end-position)) plist)
 		  (while (re-search-forward
 		  (while (re-search-forward
 			  org-keyword-time-not-clock-regexp end t)
 			  org-keyword-time-not-clock-regexp end t)
@@ -1006,8 +1002,7 @@ Assume point is at beginning of the inline task."
 	    ;; opening string.
 	    ;; opening string.
 	    (when task-end
 	    (when task-end
 	      (save-excursion
 	      (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)
 		  (let ((end (line-end-position)) plist)
 		    (while (re-search-forward
 		    (while (re-search-forward
 			    org-keyword-time-not-clock-regexp end t)
 			    org-keyword-time-not-clock-regexp end t)
@@ -1396,34 +1391,34 @@ containing `:begin', `:end', `:contents-begin', `:contents-end',
 `:post-blank' and `:post-affiliated' keywords.
 `:post-blank' and `:post-affiliated' keywords.
 
 
 Assume point is at the beginning of the property drawer."
 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))
-		 (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
-			 :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))
+	       (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
+		       :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)
 (defun org-element-property-drawer-interpreter (property-drawer contents)
   "Interpret PROPERTY-DRAWER element as Org syntax.
   "Interpret PROPERTY-DRAWER element as Org syntax.
@@ -2105,29 +2100,30 @@ LIMIT bounds the search.
 Return a list whose CAR is `node-property' and CDR is a plist
 Return a list whose CAR is `node-property' and CDR is a plist
 containing `:key', `:value', `:begin', `:end', `:post-blank' and
 containing `:key', `:value', `:begin', `:end', `:post-blank' and
 `:post-affiliated' keywords."
 `:post-affiliated' 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)
-		  :post-affiliated begin)))))
+  (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))
+	(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
+		:post-affiliated begin))))
 
 
 (defun org-element-node-property-interpreter (node-property contents)
 (defun org-element-node-property-interpreter (node-property contents)
   "Interpret NODE-PROPERTY element as Org syntax.
   "Interpret NODE-PROPERTY element as Org syntax.
 CONTENTS is nil."
 CONTENTS is nil."
   (format org-property-format
   (format org-property-format
 	  (format ":%s:" (org-element-property :key node-property))
 	  (format ":%s:" (org-element-property :key node-property))
-	  (org-element-property :value node-property)))
+	  (or (org-element-property :value node-property) "")))
 
 
 
 
 ;;;; Paragraph
 ;;;; Paragraph
@@ -2238,33 +2234,35 @@ LIMIT bounds the search.
 Return a list whose CAR is `planning' and CDR is a plist
 Return a list whose CAR is `planning' and CDR is a plist
 containing `:closed', `:deadline', `:scheduled', `:begin',
 containing `:closed', `:deadline', `:scheduled', `:begin',
 `:end', `:post-blank' and `:post-affiliated' keywords."
 `: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)
 (defun org-element-planning-interpreter (planning contents)
   "Interpret PLANNING element as Org syntax.
   "Interpret PLANNING element as Org syntax.
@@ -3612,8 +3610,7 @@ CONTENTS is nil."
 ;; `section').  Special modes are: `first-section', `item',
 ;; `section').  Special modes are: `first-section', `item',
 ;; `node-property', `section' and `table-row'.
 ;; `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.
   "Parse the element starting at point.
 
 
 Return value is a list like (TYPE PROPS) where TYPE is the type
 Return value is a list like (TYPE PROPS) where TYPE is the type
@@ -3630,12 +3627,12 @@ recursion.  Allowed values are `headline', `greater-element',
 nil), secondary values will not be parsed, since they only
 nil), secondary values will not be parsed, since they only
 contain objects.
 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
 This function assumes point is always at the beginning of the
 element it has to parse."
 element it has to parse."
@@ -3647,29 +3644,29 @@ element it has to parse."
 	  (raw-secondary-p (and granularity (not (eq granularity 'object)))))
 	  (raw-secondary-p (and granularity (not (eq granularity 'object)))))
       (cond
       (cond
        ;; Item.
        ;; Item.
-       ((eq special 'item)
+       ((eq mode 'item)
 	(org-element-item-parser limit structure raw-secondary-p))
 	(org-element-item-parser limit structure raw-secondary-p))
        ;; Table Row.
        ;; Table Row.
-       ((eq special 'table-row) (org-element-table-row-parser limit))
+       ((eq mode 'table-row) (org-element-table-row-parser limit))
        ;; Node Property.
        ;; Node Property.
-       ((eq special 'node-property) (org-element-node-property-parser limit))
+       ((eq mode 'node-property) (org-element-node-property-parser limit))
        ;; Headline.
        ;; Headline.
        ((org-with-limited-levels (org-at-heading-p))
        ((org-with-limited-levels (org-at-heading-p))
         (org-element-headline-parser limit raw-secondary-p))
         (org-element-headline-parser limit raw-secondary-p))
        ;; Sections (must be checked after headline).
        ;; 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
 	(org-element-section-parser
 	 (or (save-excursion (org-with-limited-levels (outline-next-heading)))
 	 (or (save-excursion (org-with-limited-levels (outline-next-heading)))
 	     limit)))
 	     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
        ;; When not at bol, point is at the beginning of an item or
        ;; a footnote definition: next item is always a paragraph.
        ;; a footnote definition: next item is always a paragraph.
        ((not (bolp)) (org-element-paragraph-parser limit (list (point))))
        ((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)))
+       ;; Clock.
+       ((looking-at org-clock-line-re) (org-element-clock-parser limit))
        ;; Inlinetask.
        ;; Inlinetask.
        ((org-at-heading-p)
        ((org-at-heading-p)
 	(org-element-inlinetask-parser limit raw-secondary-p))
 	(org-element-inlinetask-parser limit raw-secondary-p))
@@ -4082,6 +4079,18 @@ looking into captions:
 ;; object is searched only once at top level (but sometimes more for
 ;; object is searched only once at top level (but sometimes more for
 ;; nested types).
 ;; 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
 (defun org-element--parse-elements
   (beg end special structure granularity visible-only acc)
   (beg end special structure granularity visible-only acc)
   "Parse elements between BEG and END positions.
   "Parse elements between BEG and END positions.
@@ -4136,11 +4145,7 @@ Elements are accumulated into ACC."
 	  (org-element--parse-elements
 	  (org-element--parse-elements
 	   cbeg (org-element-property :contents-end element)
 	   cbeg (org-element-property :contents-end element)
 	   ;; Possibly switch to a special mode.
 	   ;; 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))
 	   (and (memq type '(item plain-list))
 		(org-element-property :structure element))
 		(org-element-property :structure element))
 	   granularity visible-only element))
 	   granularity visible-only element))
@@ -5224,7 +5229,7 @@ the process stopped before finding the expected result."
      (let* ((cached (and (org-element--cache-active-p)
      (let* ((cached (and (org-element--cache-active-p)
 			 (org-element--cache-find pos nil)))
 			 (org-element--cache-find pos nil)))
             (begin (org-element-property :begin cached))
             (begin (org-element-property :begin cached))
-            element next)
+            element next mode)
        (cond
        (cond
         ;; Nothing in cache before point: start parsing from first
         ;; Nothing in cache before point: start parsing from first
         ;; element following headline above, or first element in
         ;; element following headline above, or first element in
@@ -5233,7 +5238,8 @@ the process stopped before finding the expected result."
          (when (org-with-limited-levels (outline-previous-heading))
          (when (org-with-limited-levels (outline-previous-heading))
            (forward-line))
            (forward-line))
          (skip-chars-forward " \r\t\n")
          (skip-chars-forward " \r\t\n")
-         (beginning-of-line))
+         (beginning-of-line)
+	 (setq mode 'planning))
         ;; Cache returned exact match: return it.
         ;; Cache returned exact match: return it.
         ((= pos begin)
         ((= pos begin)
 	 (throw 'exit (if syncp (org-element-property :parent cached) cached)))
 	 (throw 'exit (if syncp (org-element-property :parent cached) cached)))
@@ -5244,7 +5250,8 @@ the process stopped before finding the expected result."
           (org-with-limited-levels org-outline-regexp-bol) begin t)
           (org-with-limited-levels org-outline-regexp-bol) begin t)
          (forward-line)
          (forward-line)
          (skip-chars-forward " \r\t\n")
          (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.
         ;; Check if CACHED or any of its ancestors contain point.
         ;;
         ;;
         ;; If there is such an element, we inspect it in order to know
         ;; If there is such an element, we inspect it in order to know
@@ -5278,8 +5285,7 @@ the process stopped before finding the expected result."
 		      (save-excursion
 		      (save-excursion
 			(org-with-limited-levels (outline-next-heading))
 			(org-with-limited-levels (outline-next-heading))
 			(point))))
 			(point))))
-	     (parent element)
-	     special-flag)
+	     (parent element))
 	 (while t
 	 (while t
 	   (when syncp
 	   (when syncp
 	     (cond ((= (point) pos) (throw 'exit parent))
 	     (cond ((= (point) pos) (throw 'exit parent))
@@ -5287,7 +5293,7 @@ the process stopped before finding the expected result."
 		    (throw 'interrupt nil))))
 		    (throw 'interrupt nil))))
 	   (unless element
 	   (unless element
 	     (setq element (org-element--current-element
 	     (setq element (org-element--current-element
-			    end 'element special-flag
+			    end 'element mode
 			    (org-element-property :structure parent)))
 			    (org-element-property :structure parent)))
 	     (org-element-put-property element :parent parent)
 	     (org-element-put-property element :parent parent)
 	     (org-element--cache-put element))
 	     (org-element--cache-put element))
@@ -5327,10 +5333,7 @@ the process stopped before finding the expected result."
 				    (and (= cend pos) (= (point-max) pos)))))
 				    (and (= cend pos) (= (point-max) pos)))))
 		   (goto-char (or next cbeg))
 		   (goto-char (or next cbeg))
 		   (setq next nil
 		   (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
 			 parent element
 			 end cend))))
 			 end cend))))
 	      ;; Otherwise, return ELEMENT as it is the smallest
 	      ;; Otherwise, return ELEMENT as it is the smallest

+ 9 - 8
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
 terminated by a colon.  You can insert a schedule keyword and
 a timestamp with \\[org-schedule].")
 a timestamp with \\[org-schedule].")
 
 
-(defconst org-planning-or-clock-line-re
+(defconst org-planning-line-re
   (concat "^[ \t]*"
   (concat "^[ \t]*"
 	  (regexp-opt
 	  (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))
 	   t))
-  "Matches a line with planning or clock info.
+  "Matches a line with planning info.
 Matched keyword is in group 1.")
 Matched keyword is in group 1.")
 
 
 (defconst org-clock-line-re
 (defconst org-clock-line-re
@@ -6261,9 +6260,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."
  Match group 3 will be set to the value if it exists."
   (concat "^\\(?4:[ \t]*\\)\\(?1::\\(?2:"
   (concat "^\\(?4:[ \t]*\\)\\(?1::\\(?2:"
  	  (if literal property (regexp-quote property))
  	  (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
 (defconst org-property-re
   (org-re-property ".*?" 'literal t)
   (org-re-property ".*?" 'literal t)
@@ -22469,7 +22468,9 @@ Alignment is done according to `org-property-format', which see."
 	  (looking-at org-property-re))
 	  (looking-at org-property-re))
     (replace-match
     (replace-match
      (concat (match-string 4)
      (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)))
      t t)))
 
 
 (defun org-indent-line ()
 (defun org-indent-line ()

+ 43 - 36
testing/lisp/test-org-element.el

@@ -1571,23 +1571,37 @@ e^{i\\pi}+1=0
   ;; Standard test.
   ;; Standard test.
   (should
   (should
    (equal '("abc" "value")
    (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.
   ;; Value should be trimmed.
   (should
   (should
    (equal "value"
    (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.
   ;; A node property requires to be wrapped within a property drawer.
   (should-not
   (should-not
    (eq 'node-property
    (eq 'node-property
        (org-test-with-temp-text ":abc: value"
        (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
 ;;;; Paragraph
@@ -1679,30 +1693,27 @@ Outside list"
 
 
 (ert-deftest test-org-element/planning-parser ()
 (ert-deftest test-org-element/planning-parser ()
   "Test `planning' parser."
   "Test `planning' parser."
+  ;; Test various keywords.
   (should
   (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\n<point>CLOSED: [2012-03-29 thu.]"
+      (org-element-at-point))))
   (should
   (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\n<point>DEADLINE: <2012-03-29 thu.>"
+      (org-element-at-point))))
   (should
   (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\n<point>SCHEDULED: <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
 ;;;; Property Drawer
@@ -2075,11 +2086,7 @@ Outside list"
 	  (org-test-with-temp-text "<2012-03-29 Thu +1y -1y>"
 	  (org-test-with-temp-text "<2012-03-29 Thu +1y -1y>"
 	    (let ((ts (org-element-context)))
 	    (let ((ts (org-element-context)))
 	      (list (org-element-property :repeater-type ts)
 	      (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
 ;;;; Underline

+ 4 - 4
testing/lisp/test-ox.el

@@ -482,15 +482,15 @@ Paragraph"
   ;; Plannings.
   ;; Plannings.
   (should
   (should
    (string-match
    (string-match
-    "CLOSED: \\[2012-04-29 .* 10:45\\]"
+    "* H\nCLOSED: \\[2012-04-29 .* 10:45\\]"
     (let ((org-closed-string "CLOSED:"))
     (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)
 	(org-export-as (org-test-default-backend)
 		       nil nil nil '(:with-planning t))))))
 		       nil nil nil '(:with-planning t))))))
   (should
   (should
-   (equal ""
+   (equal "* H\n"
 	  (let ((org-closed-string "CLOSED:"))
 	  (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)
 	      (org-export-as (org-test-default-backend)
 			     nil nil nil '(:with-planning nil))))))
 			     nil nil nil '(:with-planning nil))))))
   ;; Property Drawers.
   ;; Property Drawers.