浏览代码

Fix cba2f0a

* lisp/org.el (org-adapt-indentation): Update docstring.
(org-fixup-indentation): Ignore contents of source blocks and example
blocks when indentation should be preserved.

* testing/lisp/test-org.el (test-org/demote, test-org/promote): Add
  tests.
Nicolas Goaziou 10 年之前
父节点
当前提交
83d8a2b16d
共有 2 个文件被更改,包括 162 次插入52 次删除
  1. 78 47
      lisp/org.el
  2. 84 5
      testing/lisp/test-org.el

+ 78 - 47
lisp/org.el

@@ -1461,23 +1461,25 @@ lines to the buffer:
   "Non-nil means adapt indentation to outline node level.
   "Non-nil means adapt indentation to outline node level.
 
 
 When this variable is set, Org assumes that you write outlines by
 When this variable is set, Org assumes that you write outlines by
-indenting text in each node to align with the headline (after the stars).
-The following issues are influenced by this variable:
+indenting text in each node to align with the headline (after the
+stars).  The following issues are influenced by this variable:
 
 
-- When this is set and the *entire* text in an entry is indented, the
-  indentation is increased by one space in a demotion command, and
-  decreased by one in a promotion command.  If any line in the entry
-  body starts with text at column 0, indentation is not changed at all.
+- The indentation is increased by one space in a demotion
+  command, and decreased by one in a promotion command.  However,
+  in the latter case, if shifting some line in the entry body
+  would alter document structure (e.g., insert a new headline),
+  indentation is not changed at all.
 
 
-- Property drawers and planning information is inserted indented when
-  this variable is set.  When nil, they will not be indented.
+- Property drawers and planning information is inserted indented
+  when this variable is set.  When nil, they will not be indented.
 
 
-- TAB indents a line relative to context.  The lines below a headline
-  will be indented when this variable is set.
+- TAB indents a line relative to current level.  The lines below
+  a headline will be indented when this variable is set.
 
 
-Note that this is all about true indentation, by adding and removing
-space characters.  See also `org-indent.el' which does level-dependent
-indentation in a virtual way, i.e. at display time in Emacs."
+Note that this is all about true indentation, by adding and
+removing space characters.  See also `org-indent.el' which does
+level-dependent indentation in a virtual way, i.e. at display
+time in Emacs."
   :group 'org-edit-structure
   :group 'org-edit-structure
   :type 'boolean)
   :type 'boolean)
 
 
@@ -8262,41 +8264,70 @@ Assume point is at a heading or an inlinetask beginning."
      ;; If DIFF is negative, first check if a shift is possible at all
      ;; If DIFF is negative, first check if a shift is possible at all
      ;; (e.g., it doesn't break structure).  This can only happen if
      ;; (e.g., it doesn't break structure).  This can only happen if
      ;; some contents are not properly indented.
      ;; some contents are not properly indented.
-     (when (< diff 0)
-       (let ((diff (- diff))
-	     (forbidden-re (concat org-outline-regexp
-				   "\\|"
-				   (substring org-footnote-definition-re 1))))
-	 (save-excursion
-	   (while (not (eobp))
-	     (cond
-	      ((org-looking-at-p "[ \t]*$") (forward-line))
-	      ((and (org-looking-at-p org-footnote-definition-re)
+     (let ((case-fold-search t))
+       (when (< diff 0)
+	 (let ((diff (- diff))
+	       (forbidden-re (concat org-outline-regexp
+				     "\\|"
+				     (substring org-footnote-definition-re 1))))
+	   (save-excursion
+	     (while (not (eobp))
+	       (cond
+		((org-looking-at-p "[ \t]*$") (forward-line))
+		((and (org-looking-at-p org-footnote-definition-re)
+		      (let ((e (org-element-at-point)))
+			(and (eq (org-element-type e) 'footnote-definition)
+			     (goto-char (org-element-property :end e))))))
+		((org-looking-at-p org-outline-regexp) (forward-line))
+		;; Give up if shifting would move before column 0 or
+		;; if it would introduce a headline or a footnote
+		;; definition.
+		(t
+		 (skip-chars-forward " \t")
+		 (let ((ind (current-column)))
+		   (when (or (< ind diff)
+			     (and (= ind diff) (org-looking-at-p forbidden-re)))
+		     (throw 'no-shift nil)))
+		 ;; Ignore contents of example blocks and source
+		 ;; blocks if their indentation is meant to be
+		 ;; preserved.  Jump to block's closing line.
+		 (beginning-of-line)
+		 (or (and (org-looking-at-p "[ \t]*#\\+BEGIN_\\(EXAMPLE\\|SRC\\)")
+			  (let ((e (org-element-at-point)))
+			    (and (memq (org-element-type e)
+				       '(example-block src-block))
+				 (or org-src-preserve-indentation
+				     (org-element-property :preserve-indent e))
+				 (goto-char (org-element-property :end e))
+				 (progn (skip-chars-backward " \r\t\n")
+					(beginning-of-line)
+					t))))
+		     (forward-line))))))))
+       ;; Shift lines but footnote definitions, inlinetasks boundaries
+       ;; by DIFF.  Also skip contents of source or example blocks
+       ;; when indentation is meant to be preserved.
+       (while (not (eobp))
+	 (cond
+	  ((and (org-looking-at-p org-footnote-definition-re)
+		(let ((e (org-element-at-point)))
+		  (and (eq (org-element-type e) 'footnote-definition)
+		       (goto-char (org-element-property :end e))))))
+	  ((org-looking-at-p org-outline-regexp) (forward-line))
+	  ((org-looking-at-p "[ \t]*$") (forward-line))
+	  (t
+	   (org-indent-line-to (+ (org-get-indentation) diff))
+	   (beginning-of-line)
+	   (or (and (org-looking-at-p "[ \t]*#\\+BEGIN_\\(EXAMPLE\\|SRC\\)")
 		    (let ((e (org-element-at-point)))
 		    (let ((e (org-element-at-point)))
-		      (and (eq (org-element-type e) 'footnote-definition)
-			   (goto-char (org-element-property :end e))))))
-	      ((org-looking-at-p org-outline-regexp) (forward-line))
-	      ;; Give up if shifting would move before column 0 or if
-	      ;; it would introduce a headline or a footnote
-	      ;; definition.
-	      (t
-	       (skip-chars-forward " \t")
-	       (let ((ind (current-column)))
-		 (when (or (< ind diff)
-			   (and (= ind diff) (org-looking-at-p forbidden-re)))
-		   (throw 'no-shift nil)))
-	       (forward-line)))))))
-     ;; Shift lines but footnote definitions and inlinetasks by DIFF.
-     (while (not (eobp))
-       (cond
-	((and (org-looking-at-p org-footnote-definition-re)
-	      (let ((e (org-element-at-point)))
-		(and (eq (org-element-type e) 'footnote-definition)
-		     (goto-char (org-element-property :end e))))))
-	((org-looking-at-p org-outline-regexp) (forward-line))
-	((org-looking-at-p "[ \t]*$") (forward-line))
-	(t (org-indent-line-to (+ (org-get-indentation) diff))
-	   (forward-line)))))))
+		      (and (memq (org-element-type e)
+				 '(example-block src-block))
+			   (or org-src-preserve-indentation
+			       (org-element-property :preserve-indent e))
+			   (goto-char (org-element-property :end e))
+			   (progn (skip-chars-backward " \r\t\n")
+				  (beginning-of-line)
+				  t))))
+	       (forward-line)))))))))
 
 
 (defun org-convert-to-odd-levels ()
 (defun org-convert-to-odd-levels ()
   "Convert an org-mode file with all levels allowed to one with odd levels.
   "Convert an org-mode file with all levels allowed to one with odd levels.

+ 84 - 5
testing/lisp/test-org.el

@@ -2037,11 +2037,11 @@ Text.
 	(org-get-indentation))))
 	(org-get-indentation))))
   (should
   (should
    (zerop
    (zerop
-    (org-test-with-temp-text "* H\n[fn:1] Definition."
+    (org-test-with-temp-text "* H\n[fn:1] def line 1\ndef line 2"
       (let ((org-odd-levels-only nil)
       (let ((org-odd-levels-only nil)
 	    (org-adapt-indentation t))
 	    (org-adapt-indentation t))
 	(org-demote))
 	(org-demote))
-      (forward-line)
+      (goto-char (point-max))
       (org-get-indentation))))
       (org-get-indentation))))
   (should
   (should
    (= 3
    (= 3
@@ -2068,7 +2068,43 @@ Text.
 	  (org-test-with-temp-text "* H\n***** I\n  Contents\n***** END"
 	  (org-test-with-temp-text "* H\n***** I\n  Contents\n***** END"
 	    (org-demote)
 	    (org-demote)
 	    (forward-line 2)
 	    (forward-line 2)
-	    (org-get-indentation)))))))
+	    (org-get-indentation))))))
+  ;; Ignore contents of source blocks or example blocks when
+  ;; indentation should be preserved (through
+  ;; `org-src-preserve-indentation' or "-i" flag).
+  (should-not
+   (zerop
+    (org-test-with-temp-text "* H\n#+BEGIN_SRC emacs-lisp\n(+ 1 1)\n#+END_SRC"
+      (let ((org-adapt-indentation t)
+	    (org-src-preserve-indentation nil))
+	(org-demote))
+      (forward-line 2)
+      (org-get-indentation))))
+  (should
+   (zerop
+    (org-test-with-temp-text "* H\n#+BEGIN_EXAMPLE\n(+ 1 1)\n#+END_EXAMPLE"
+      (let ((org-adapt-indentation t)
+	    (org-src-preserve-indentation t))
+	(org-demote))
+      (forward-line 2)
+      (org-get-indentation))))
+  (should
+   (zerop
+    (org-test-with-temp-text "* H\n#+BEGIN_SRC emacs-lisp\n(+ 1 1)\n#+END_SRC"
+      (let ((org-adapt-indentation t)
+	    (org-src-preserve-indentation t))
+	(org-demote))
+      (forward-line 2)
+      (org-get-indentation))))
+  (should
+   (zerop
+    (org-test-with-temp-text
+	"* H\n#+BEGIN_SRC emacs-lisp -i\n(+ 1 1)\n#+END_SRC"
+      (let ((org-adapt-indentation t)
+	    (org-src-preserve-indentation nil))
+	(org-demote))
+      (forward-line 2)
+      (org-get-indentation)))))
 
 
 (ert-deftest test-org/promote ()
 (ert-deftest test-org/promote ()
   "Test `org-promote' specifications."
   "Test `org-promote' specifications."
@@ -2159,7 +2195,7 @@ Text.
 	(org-get-indentation))))
 	(org-get-indentation))))
   (should
   (should
    (= 2
    (= 2
-      (org-test-with-temp-text "** H\n   Paragraph\n[fn:1] Definition."
+      (org-test-with-temp-text "** H\n   Paragraph\n[fn:1] line1\nline2"
 	(let ((org-odd-levels-only nil)
 	(let ((org-odd-levels-only nil)
 	      (org-adapt-indentation t))
 	      (org-adapt-indentation t))
 	  (org-promote))
 	  (org-promote))
@@ -2200,7 +2236,50 @@ Text.
 	      (org-adapt-indentation t))
 	      (org-adapt-indentation t))
 	  (org-promote))
 	  (org-promote))
 	(forward-line)
 	(forward-line)
-	(org-get-indentation)))))
+	(org-get-indentation))))
+  ;; Ignore contents of source blocks or example blocks when
+  ;; indentation should be preserved (through
+  ;; `org-src-preserve-indentation' or "-i" flag).
+  (should-not
+   (zerop
+    (org-test-with-temp-text
+	"** H\n #+BEGIN_SRC emacs-lisp\n(+ 1 1)\n #+END_SRC"
+      (let ((org-adapt-indentation t)
+	    (org-src-preserve-indentation nil)
+	    (org-odd-levels-only nil))
+	(org-promote))
+      (forward-line)
+      (org-get-indentation))))
+  (should
+   (zerop
+    (org-test-with-temp-text
+	"** H\n #+BEGIN_EXAMPLE\nContents\n #+END_EXAMPLE"
+      (let ((org-adapt-indentation t)
+	    (org-src-preserve-indentation t)
+	    (org-odd-levels-only nil))
+	(org-promote))
+      (forward-line)
+      (org-get-indentation))))
+  (should
+   (zerop
+    (org-test-with-temp-text
+	"** H\n #+BEGIN_SRC emacs-lisp\n(+ 1 1)\n #+END_SRC"
+      (let ((org-adapt-indentation t)
+	    (org-src-preserve-indentation t)
+	    (org-odd-levels-only nil))
+	(org-promote))
+      (forward-line)
+      (org-get-indentation))))
+  (should
+   (zerop
+    (org-test-with-temp-text
+	"** H\n #+BEGIN_SRC emacs-lisp -i\n(+ 1 1)\n #+END_SRC"
+      (let ((org-adapt-indentation t)
+	    (org-src-preserve-indentation nil)
+	    (org-odd-levels-only nil))
+	(org-promote))
+      (forward-line)
+      (org-get-indentation)))))
 
 
 
 
 ;;; Planning
 ;;; Planning