Fix indentation in lists

* lisp/org-list.el (org-list-item-body-column): Take into
  consideration empty items and bullets followed by two spaces.

* lisp/org.el (org--get-expected-indentation): Fix return value for
  items in lists.
(org-indent-region): Fix infloop when indenting some types of plain
lists.  Also fix error when region starts with blank lines at the
beginning of the buffer.

* testing/lisp/test-org.el (test-org/indent-region): Add tests.
This commit is contained in:
Nicolas Goaziou 2014-10-13 19:03:14 +02:00
parent 352118bf7f
commit ce2090ccfd
3 changed files with 83 additions and 44 deletions

View File

@ -2051,16 +2051,19 @@ Possible values are: `folded', `children' or `subtree'. See
(defun org-list-item-body-column (item)
"Return column at which body of ITEM should start."
(let (bpos bcol tpos tcol)
(save-excursion
(goto-char item)
(looking-at "[ \t]*\\(\\S-+\\)\\(.*[ \t]+::\\)?\\([ \t]+\\|$\\)")
(setq bpos (match-beginning 1) tpos (match-end 0)
bcol (progn (goto-char bpos) (current-column))
tcol (progn (goto-char tpos) (current-column)))
(when (> tcol (+ bcol org-description-max-indent))
(setq tcol (+ bcol 5))))
tcol))
(save-excursion
(goto-char item)
(looking-at "[ \t]*\\(\\S-+\\)\\(.*[ \t]+::\\)?\\([ \t]+\\|$\\)")
(if (match-beginning 2)
(let ((start (1+ (match-end 2)))
(ind (org-get-indentation)))
(if (> start (+ ind org-description-max-indent)) (+ ind 5) start))
(+ (progn (goto-char (match-end 1)) (current-column))
(if (and org-list-two-spaces-after-bullet-regexp
(org-string-match-p org-list-two-spaces-after-bullet-regexp
(match-string 1)))
2
1)))))

View File

@ -22415,9 +22415,13 @@ ELEMENT."
(if (not org-adapt-indentation) 0
(let ((level (org-current-level)))
(if level (1+ level) 0))))
((item plain list)
(item
(org-list-item-body-column
(org-element-property :post-affiliated element)))
(plain-list
(save-excursion
(goto-char (org-element-property :post-affiliated element))
(org-get-indentation)))
(otherwise
(goto-char start)
(org-get-indentation))))
@ -22439,19 +22443,25 @@ ELEMENT."
(while t
(if (= (point-min) start) (throw 'exit 0)
(goto-char (1- start))
(let ((previous (org-element-at-point)))
(while (let ((parent (org-element-property :parent previous)))
(and parent
(setq previous parent)
(<= (org-element-property :end parent) start))))
(cond ((or (not previous)
(> (org-element-property :end previous) start))
(throw 'exit (org--get-expected-indentation previous t)))
((memq (org-element-type previous)
'(footnote-definition inlinetask))
(setq start (org-element-property :begin previous)))
(t (goto-char (org-element-property :begin previous))
(throw 'exit (org-get-indentation)))))))))
(let* ((previous (org-element-at-point))
(parent previous))
(while (and parent (<= (org-element-property :end parent) start))
(setq previous parent
parent (org-element-property :parent parent)))
(cond
((not previous) (throw 'exit 0))
((> (org-element-property :end previous) start)
(throw 'exit (org--get-expected-indentation previous t)))
((memq (org-element-type previous)
'(footnote-definition inlinetask))
(setq start (org-element-property :begin previous)))
(t (goto-char (org-element-property :begin previous))
(throw 'exit
(if (bolp) (org-get-indentation)
;; At first paragraph in an item or
;; a footnote definition.
(org--get-expected-indentation
(org-element-property :parent previous) t))))))))))
;; Otherwise, move to the first non-blank line above.
(t
(beginning-of-line)
@ -22584,13 +22594,14 @@ assumed to be significant there."
(interactive "r")
(save-excursion
(goto-char start)
(beginning-of-line)
(skip-chars-forward " \r\t\n")
(unless (eobp) (beginning-of-line))
(let ((indent-to
(lambda (ind pos)
;; Set IND as indentation for all lines between point and
;; POS or END, whichever comes first. Blank lines are
;; ignored. Leave point after POS once done.
(let ((limit (copy-marker (min end pos))))
(let ((limit (copy-marker (min end pos))))
(while (< (point) limit)
(unless (org-looking-at-p "[ \t]*$") (org-indent-line-to ind))
(forward-line))
@ -22602,17 +22613,18 @@ assumed to be significant there."
(type (org-element-type element))
(element-end (copy-marker (org-element-property :end element)))
(ind (org--get-expected-indentation element nil)))
(if (or (memq type '(paragraph table table-row))
(not (or (org-element-property :contents-begin element)
(memq type
'(example-block export-block src-block)))))
;; Elements here are indented as a single block. Also
;; align node properties.
(progn
(when (eq type 'node-property)
(org--align-node-property)
(beginning-of-line))
(funcall indent-to ind element-end))
(cond
((or (memq type '(paragraph table table-row))
(not (or (org-element-property :contents-begin element)
(memq type
'(example-block export-block src-block)))))
;; Elements here are indented as a single block. Also
;; align node properties.
(when (eq type 'node-property)
(org--align-node-property)
(beginning-of-line))
(funcall indent-to ind element-end))
(t
;; Elements in this category consist of three parts:
;; before the contents, the contents, and after the
;; contents. The contents are treated specially,
@ -22636,8 +22648,9 @@ assumed to be significant there."
;; from the second line.
(org-with-wide-buffer
(goto-char post)
(forward-line)
(point)))
(end-of-line)
(skip-chars-forward " \r\t\n")
(if (eobp) (point) (line-beginning-position))))
(t (org-element-property :contents-begin element)))))
(cend (copy-marker
(or (org-element-property :contents-end element)
@ -22646,13 +22659,24 @@ assumed to be significant there."
(goto-char element-end)
(skip-chars-backward " \r\t\n")
(line-beginning-position))))))
(funcall indent-to ind cbeg)
;; Do not change items indentation individually as it
;; might break the list as a whole. On the other
;; hand, when at a plain list, indent it as a whole.
(cond ((eq type 'plain-list)
(let ((offset (- ind (org-get-indentation))))
(unless (zerop offset)
(indent-rigidly (org-element-property :begin element)
(org-element-property :end element)
offset))
(goto-char cbeg)))
((eq type 'item) (goto-char cbeg))
(t (funcall indent-to ind cbeg)))
(when (< (point) end)
(case type
((example-block export-block verse-block))
(src-block
;; In a source block, indent source code according
;; to language major mode, but only if
;; In a source block, indent source code
;; according to language major mode, but only if
;; `org-src-tab-acts-natively' is non-nil.
(when (and (< (point) end) org-src-tab-acts-natively)
(ignore-errors
@ -22667,7 +22691,7 @@ assumed to be significant there."
(when (< (point) end) (funcall indent-to ind element-end)))
(set-marker post nil)
(set-marker cbeg nil)
(set-marker cend nil)))
(set-marker cend nil))))
(set-marker element-end nil))))
(set-marker end nil))))

View File

@ -655,15 +655,27 @@
(let ((org-property-format "%-10s %s"))
(org-indent-region (point-min) (point-max)))
(buffer-string))))
;; Special case: plain lists and footnote definitions.
;; Indent plain lists.
(should
(equal "- A\n B\n - C\n\n D"
(org-test-with-temp-text "- A\n B\n - C\n\n D"
(org-indent-region (point-min) (point-max))
(buffer-string))))
(should
(equal "- A\n\n- B"
(org-test-with-temp-text " - A\n\n - B"
(org-indent-region (point-min) (point-max))
(buffer-string))))
;; Indent footnote definitions.
(should
(equal "[fn:1] Definition\n\nDefinition"
(org-test-with-temp-text "[fn:1] Definition\n\n Definition"
(org-indent-region (point-min) (point-max))
(buffer-string))))
;; Special case: Start indenting on a blank line.
(should
(equal "\nParagraph"
(org-test-with-temp-text "\n Paragraph"
(org-indent-region (point-min) (point-max))
(buffer-string)))))