From 7f287d1b6277b5588fb7aa375411e46dac52885c Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Fri, 7 Feb 2014 20:00:45 +0100 Subject: [PATCH] org-element: Fix indentation normalization * lisp/org-element.el (org-element-normalize-contents): Do not ignore empty lines when an object follows. * testing/lisp/test-org-element.el (test-org-element/normalize-contents): Add test. --- lisp/org-element.el | 98 +++++++++++++++----------------- testing/lisp/test-org-element.el | 20 ++++--- 2 files changed, 58 insertions(+), 60 deletions(-) diff --git a/lisp/org-element.el b/lisp/org-element.el index f3e5a2e4f..dcc8f8a79 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -4609,71 +4609,65 @@ indentation to compute maximal common indentation. Return the normalized element that is element with global indentation removed from its contents. The function assumes that indentation is not done with TAB characters." - (let* (ind-list ; for byte-compiler - collect-inds ; for byte-compiler - (collect-inds + (let* ((min-ind most-positive-fixnum) + find-min-ind ; For byte-compiler. + (find-min-ind (function - ;; Return list of indentations within BLOB. This is done by - ;; walking recursively BLOB and updating IND-LIST along the - ;; way. FIRST-FLAG is non-nil when the first string hasn't - ;; been seen yet. It is required as this string is the only - ;; one whose indentation doesn't happen after a newline - ;; character. + ;; Return minimal common indentation within BLOB. This is + ;; done by walking recursively BLOB and updating MIN-IND + ;; along the way. FIRST-FLAG is non-nil when the first + ;; string hasn't been seen yet. It is required as this + ;; string is the only one whose indentation doesn't happen + ;; after a newline character. (lambda (blob first-flag) - (mapc - (lambda (object) - (when (and first-flag (stringp object)) - (setq first-flag nil) - (string-match "\\`\\( *\\)" object) - (let ((len (length (match-string 1 object)))) - ;; An indentation of zero means no string will be - ;; modified. Quit the process. - (if (zerop len) (throw 'zero (setq ind-list nil)) - (push len ind-list)))) - (cond - ((stringp object) - (let ((start 0)) - ;; Avoid matching blank or empty lines. - (while (and (string-match "\n\\( *\\)\\(.\\)" object start) - (not (equal (match-string 2 object) " "))) - (setq start (match-end 0)) - (push (length (match-string 1 object)) ind-list)))) - ((memq (org-element-type object) org-element-recursive-objects) - (funcall collect-inds object first-flag)))) - (org-element-contents blob)))))) - ;; Collect indentation list in ELEMENT. Possibly remove first - ;; value if IGNORE-FIRST is non-nil. - (catch 'zero (funcall collect-inds element (not ignore-first))) - (if (not ind-list) element + (dolist (object (org-element-contents blob)) + (when (and first-flag (stringp object)) + (setq first-flag nil) + (string-match "\\`\\( *\\)" object) + (let ((len (length (match-string 1 object)))) + ;; An indentation of zero means no string will be + ;; modified. Quit the process. + (if (zerop len) (throw 'zero (setq min-ind 0)) + (setq min-ind (min len min-ind))))) + (cond + ((stringp object) + (dolist (line (delq "" (cdr (org-split-string object " *\n")))) + (setq min-ind (min (org-get-indentation line) min-ind)))) + ((memq (org-element-type object) org-element-recursive-objects) + (funcall find-min-ind object first-flag)))))))) + ;; Find minimal indentation in ELEMENT. + (catch 'zero (funcall find-min-ind element (not ignore-first))) + (if (or (zerop min-ind) (= min-ind most-positive-fixnum)) element ;; Build ELEMENT back, replacing each string with the same ;; string minus common indentation. (let* (build ; For byte compiler. (build (function - (lambda (blob mci first-flag) + (lambda (blob first-flag) ;; Return BLOB with all its strings indentation - ;; shortened from MCI white spaces. FIRST-FLAG is - ;; non-nil when the first string hasn't been seen + ;; shortened from MIN-IND white spaces. FIRST-FLAG + ;; is non-nil when the first string hasn't been seen ;; yet. (setcdr (cdr blob) (mapcar - (lambda (object) - (when (and first-flag (stringp object)) - (setq first-flag nil) - (setq object - (replace-regexp-in-string - (format "\\` \\{%d\\}" mci) "" object))) - (cond - ((stringp object) - (replace-regexp-in-string - (format "\n \\{%d\\}" mci) "\n" object)) - ((memq (org-element-type object) - org-element-recursive-objects) - (funcall build object mci first-flag)) - (t object))) + #'(lambda (object) + (when (and first-flag (stringp object)) + (setq first-flag nil) + (setq object + (replace-regexp-in-string + (format "\\` \\{%d\\}" min-ind) + "" object))) + (cond + ((stringp object) + (replace-regexp-in-string + (format "\n \\{%d\\}" min-ind) "\n" object)) + ((memq (org-element-type object) + org-element-recursive-objects) + (funcall build object first-flag)) + (t object))) (org-element-contents blob))) blob)))) - (funcall build element (apply 'min ind-list) (not ignore-first)))))) + (funcall build element (not ignore-first)))))) diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el index c51f2bd24..71c29ef0f 100644 --- a/testing/lisp/test-org-element.el +++ b/testing/lisp/test-org-element.el @@ -2869,34 +2869,38 @@ Paragraph \\alpha." (ert-deftest test-org-element/normalize-contents () "Test `org-element-normalize-contents' specifications." - ;; 1. Remove maximum common indentation from element's contents. + ;; Remove maximum common indentation from element's contents. (should (equal (org-element-normalize-contents '(paragraph nil " Two spaces\n Three spaces")) '(paragraph nil "Two spaces\n Three spaces"))) - ;; 2. Ignore objects within contents when computing maximum common - ;; indentation. + ;; Ignore objects within contents when computing maximum common + ;; indentation. (should (equal (org-element-normalize-contents '(paragraph nil " One " (emphasis nil "space") "\n Two spaces")) '(paragraph nil "One " (emphasis nil "space") "\n Two spaces"))) - ;; 3. Ignore blank lines. + ;; Ignore blank lines. (should (equal (org-element-normalize-contents '(paragraph nil " Two spaces\n\n \n Two spaces")) '(paragraph nil "Two spaces\n\n \nTwo spaces"))) - ;; 4. Recursively enter objects in order to compute common - ;; indentation. + (should + (equal + '(paragraph nil " Two spaces\n" (verbatim nil "V") "\n Two spaces") + (org-element-normalize-contents + '(paragraph nil " Two spaces\n " (verbatim nil "V") "\n Two spaces")))) + ;; Recursively enter objects in order to compute common indentation. (should (equal (org-element-normalize-contents '(paragraph nil " Two spaces " (bold nil " and\n One space"))) '(paragraph nil " Two spaces " (bold nil " and\nOne space")))) - ;; 5. When optional argument is provided, ignore first line - ;; indentation. + ;; When optional argument is provided, ignore first line + ;; indentation. (should (equal (org-element-normalize-contents