Browse Source

ox: Do not trim leading and trailing blank lines from code

* lisp/ox.el (org-export-get-loc):
(org-export-unravel-code):
(org-export-format-code):
(org-export-format-code-default): Do not trim leading and trailing
blank lines from code during export.

* testing/lisp/test-ox.el (test-org-export/unravel-code): Update tests.
(test-org-export/format-code-default): Add tests.

Reported-by: Li DebugFan <debugfanli@gmail.com>
<http://permalink.gmane.org/gmane.emacs.orgmode/113205>
Nicolas Goaziou 7 years ago
parent
commit
1332bbd616
2 changed files with 55 additions and 36 deletions
  1. 25 26
      lisp/ox.el
  2. 30 10
      testing/lisp/test-ox.el

+ 25 - 26
lisp/ox.el

@@ -4503,7 +4503,7 @@ ELEMENT doesn't allow line numbering."
 	     (let ((linum (org-element-property :number-lines el)))
 	       (when linum
 		 (let ((lines (org-count-lines
-			       (org-trim (org-element-property :value el)))))
+			       (org-element-property :value el))))
 		   ;; Accumulate locs or reset them.
 		   (pcase linum
 		     (`(new . ,n) (setq loc (+ n lines)))
@@ -4522,30 +4522,28 @@ an alist between relative line number (integer) and name of code
 reference on that line (string)."
   (let* ((line 0) refs
 	 (value (org-element-property :value element))
-	 ;; Get code and clean it.  Remove blank lines at its
-	 ;; beginning and end.
+	 ;; Remove global indentation from code, if necessary.  Also
+	 ;; remove final newline character, since it doesn't belongs
+	 ;; to the code proper.
 	 (code (replace-regexp-in-string
-		"\\`\\([ \t]*\n\\)+" ""
-		(replace-regexp-in-string
-		 "\\([ \t]*\n\\)*[ \t]*\\'" "\n"
-		 (if (or org-src-preserve-indentation
-			 (org-element-property :preserve-indent element))
-		     value
-		   (org-remove-indentation value)))))
+		"\n\\'" ""
+		(if (or org-src-preserve-indentation
+			(org-element-property :preserve-indent element))
+		    value
+		  (org-remove-indentation value))))
 	 ;; Build a regexp matching a loc with a reference.
 	 (ref-re (org-src-coderef-regexp (org-src-coderef-format element))))
     ;; Return value.
     (cons
      ;; Code with references removed.
-     (org-element-normalize-string
-      (mapconcat
-       (lambda (loc)
-	 (cl-incf line)
-	 (if (not (string-match ref-re loc)) loc
-	   ;; Ref line: remove ref, and signal its position in REFS.
-	   (push (cons line (match-string 3 loc)) refs)
-	   (replace-match "" nil nil loc 1)))
-       (org-split-string code "\n") "\n"))
+     (mapconcat
+      (lambda (loc)
+	(cl-incf line)
+	(if (not (string-match ref-re loc)) loc
+	  ;; Ref line: remove ref, and add its position in REFS.
+	  (push (cons line (match-string 3 loc)) refs)
+	  (replace-match "" nil nil loc 1)))
+      (split-string code "\n") "\n")
      ;; Reference alist.
      refs)))
 
@@ -4568,15 +4566,16 @@ number (i.e. ignoring NUM-LINES) and the name of the code
 reference on it.  If it is nil, FUN's third argument will always
 be nil.  It can be obtained through the use of
 `org-export-unravel-code' function."
-  (let ((--locs (org-split-string code "\n"))
+  (let ((--locs (split-string code "\n"))
 	(--line 0))
-    (org-element-normalize-string
+    (concat
      (mapconcat
       (lambda (--loc)
 	(cl-incf --line)
 	(let ((--ref (cdr (assq --line ref-alist))))
 	  (funcall fun --loc (and num-lines (+ num-lines --line)) --ref)))
-      --locs "\n"))))
+      --locs "\n")
+     "\n")))
 
 (defun org-export-format-code-default (element info)
   "Return source code from ELEMENT, formatted in a standard way.
@@ -4593,7 +4592,7 @@ code."
   ;; Extract code and references.
   (let* ((code-info (org-export-unravel-code element))
          (code (car code-info))
-	 (code-lines (org-split-string code "\n")))
+	 (code-lines (split-string code "\n")))
     (if (null code-lines) ""
       (let* ((refs (and (org-element-property :retain-labels element)
 			(cdr code-info)))
@@ -4618,9 +4617,9 @@ code."
 	      number-str
 	      loc
 	      (and ref
-		   (concat (make-string
-			    (- (+ 6 max-width)
-			       (+ (length loc) (length number-str))) ? )
+		   (concat (make-string (- (+ 6 max-width)
+					   (+ (length loc) (length number-str)))
+					?\s)
 			   (format "(%s)" ref))))))
 	 num-start refs)))))
 

+ 30 - 10
testing/lisp/test-ox.el

@@ -3363,12 +3363,12 @@ Another text. (ref:text)
   "Test `org-export-unravel-code' function."
   ;; Code without reference.
   (should
-   (equal '("(+ 1 1)\n")
+   (equal '("(+ 1 1)")
 	  (org-test-with-temp-text "#+BEGIN_EXAMPLE\n(+ 1 1)\n#+END_EXAMPLE"
 	    (org-export-unravel-code (org-element-at-point)))))
   ;; Code with reference.
   (should
-   (equal '("(+ 1 1)\n" (1 . "test"))
+   (equal '("(+ 1 1)" (1 . "test"))
 	  (org-test-with-temp-text
 	      "#+BEGIN_EXAMPLE\n(+ 1 1) (ref:test)\n#+END_EXAMPLE"
 	    (let  ((org-coderef-label-format "(ref:%s)"))
@@ -3376,14 +3376,14 @@ Another text. (ref:text)
   ;; Code with user-defined reference.
   (should
    (equal
-    '("(+ 1 1)\n" (1 . "test"))
+    '("(+ 1 1)" (1 . "test"))
     (org-test-with-temp-text
 	"#+BEGIN_EXAMPLE -l \"[ref:%s]\"\n(+ 1 1) [ref:test]\n#+END_EXAMPLE"
       (let ((org-coderef-label-format "(ref:%s)"))
 	(org-export-unravel-code (org-element-at-point))))))
   ;; Code references keys are relative to the current block.
   (should
-   (equal '("(+ 2 2)\n(+ 3 3)\n" (2 . "one"))
+   (equal '("(+ 2 2)\n(+ 3 3)" (2 . "one"))
 	  (org-test-with-temp-text "
 #+BEGIN_EXAMPLE -n
 \(+ 1 1)
@@ -3394,23 +3394,43 @@ Another text. (ref:text)
 #+END_EXAMPLE"
 	    (goto-line 5)
 	    (let ((org-coderef-label-format "(ref:%s)"))
-	      (org-export-unravel-code (org-element-at-point)))))))
+	      (org-export-unravel-code (org-element-at-point)))))))
 
 (ert-deftest test-org-export/format-code-default ()
   "Test `org-export-format-code-default' specifications."
-  ;; Return the empty string when code is empty.
+  ;; Preserve blank lines, even when code is empty.
   (should
-   (equal ""
+   (equal "\n\n"
 	  (org-test-with-parsed-data "#+BEGIN_SRC emacs-lisp\n\n\n#+END_SRC"
 	    (org-export-format-code-default
-	     (org-element-map tree 'src-block 'identity info t) info))))
+	     (org-element-map tree 'src-block #'identity info t) info))))
+  ;; Likewise, preserve leading and trailing blank lines in the code.
+  (should
+   (equal "\n(+ 1 1)\n"
+	  (org-test-with-parsed-data
+	      "#+BEGIN_SRC emacs-lisp\n\n(+ 1 1)\n#+END_SRC"
+	    (org-export-format-code-default
+	     (org-element-map tree 'src-block #'identity info t) info))))
+  (should
+   (equal "(+ 1 1)\n\n"
+	  (org-test-with-parsed-data
+	      "#+BEGIN_SRC emacs-lisp\n(+ 1 1)\n\n#+END_SRC"
+	    (org-export-format-code-default
+	     (org-element-map tree 'src-block #'identity info t) info))))
   ;; Number lines, two whitespace characters before the actual loc.
   (should
    (equal "1  a\n2  b\n"
 	  (org-test-with-parsed-data
 	      "#+BEGIN_SRC emacs-lisp +n\na\nb\n#+END_SRC"
 	    (org-export-format-code-default
-	     (org-element-map tree 'src-block 'identity info t) info))))
+	     (org-element-map tree 'src-block #'identity info t) info))))
+  ;; Numbering includes blank lines.
+  (should
+   (equal "1  \n2  a\n3  \n4  b\n5  \n"
+	  (org-test-with-parsed-data
+	      "#+BEGIN_SRC emacs-lisp +n\n\na\n\nb\n\n#+END_SRC"
+	    (org-export-format-code-default
+	     (org-element-map tree 'src-block #'identity info t) info))))
   ;; Put references 6 whitespace characters after the widest line,
   ;; wrapped within parenthesis.
   (should
@@ -3419,7 +3439,7 @@ Another text. (ref:text)
 	    (org-test-with-parsed-data
 		"#+BEGIN_SRC emacs-lisp\n123 (ref:a)\n1 (ref:b)\n#+END_SRC"
 	      (org-export-format-code-default
-	       (org-element-map tree 'src-block 'identity info t) info))))))
+	       (org-element-map tree 'src-block #'identity info t) info))))))