1
0
mirror of https://git.savannah.gnu.org/git/emacs/org-mode.git synced 2025-01-19 19:07:43 +00:00

Preserve hierarchy when converting items to headlines and the other way

* lisp/org.el (org-toggle-item, org-toggle-heading): make sure every
  sub-item in a list is changed into a sub-heading and sub-headings
  are translated into sub-items. Also ignore inline tasks in the
  process.

org-toggle-item on headlines preserves hierarchy
This commit is contained in:
Nicolas Goaziou 2011-02-12 16:42:42 +01:00
parent de3d3652bb
commit 713262edc1

View File

@ -17571,80 +17571,93 @@ Calls `org-table-insert-hline', `org-toggle-item', or
"Convert headings or normal lines to items, items to normal lines.
If there is no active region, only the current line is considered.
If the first line in the region is a headline, convert all
headlines to items.
If the first non blank line in the region is an headline, convert
all headlines to items.
If the first line in the region is an item, convert all items to
normal lines.
If it is an item, convert all items to normal lines.
If the first line is normal text, change region into an
item. With a prefix argument ARG, change each line in region into
an item."
If it is normal text, change region into an item. With a prefix
argument ARG, change each line in region into an item."
(interactive "P")
(let (l2 l beg end)
(if (org-region-active-p)
(setq beg (region-beginning) end (region-end))
(setq beg (point-at-bol)
end (min (1+ (point-at-eol)) (point-max))))
(save-excursion
(goto-char end)
(setq l2 (org-current-line))
(goto-char beg)
(beginning-of-line 1)
;; Ignore blank lines at beginning of region
(skip-chars-forward " \t\r\n")
(beginning-of-line 1)
(setq l (1- (org-current-line)))
(if (org-at-item-p)
;; We already have items, de-itemize
(while (< (setq l (1+ l)) l2)
(when (org-at-item-p)
(skip-chars-forward " \t")
(delete-region (point) (match-end 0)))
(beginning-of-line 2))
(if (org-on-heading-p)
;; Headings, convert to items
(while (< (setq l (1+ l)) l2)
(if (looking-at org-outline-regexp)
(replace-match (org-list-bullet-string "-") t t))
(beginning-of-line 2))
;; normal lines, with ARG, turn all of them into items
;; unless they are already one.
(if arg
(while (< (setq l (1+ l)) l2)
(unless (org-at-item-p)
(if (looking-at "\\([ \t]*\\)\\(\\S-\\)")
(replace-match
(concat "\\1" (org-list-bullet-string "-") "\\2"))))
(beginning-of-line 2))
;; Without ARG, make the first line of region an item, and
;; shift indentation of others lines to set them as item's
;; body.
(let* ((bul (org-list-bullet-string "-"))
(bul-len (length bul))
(ref-ind (org-get-indentation)))
(skip-chars-forward " \t")
(insert bul)
(beginning-of-line 2)
(while (and (< (setq l (1+ l)) l2) (< (point) end))
;; Ensure that lines less indented than first one
;; still get included in item body.
(org-indent-line-to (+ (max ref-ind (org-get-indentation))
bul-len))
(beginning-of-line 2)))))))))
(org-with-limited-levels
(save-excursion
(goto-char end)
(setq l2 (org-current-line))
(goto-char beg)
(beginning-of-line 1)
;; Ignore blank lines at beginning of region
(skip-chars-forward " \t\r\n")
(beginning-of-line 1)
(setq l (1- (org-current-line)))
(cond
;; Case 1. Start at an item: de-itemize.
((org-at-item-p)
(while (< (setq l (1+ l)) l2)
(when (org-at-item-p)
(skip-chars-forward " \t")
(delete-region (point) (match-end 0)))
(beginning-of-line 2)))
;; Case 2. Start an an heading: convert to items.
((org-on-heading-p)
(let* ((bul (org-list-bullet-string "-"))
(len (length bul))
(ind 0) (level 0))
(while (< (setq l (1+ l)) l2)
(cond
((looking-at outline-regexp)
(let* ((lvl (org-reduced-level
(- (length (match-string 0)) 2)))
(s (concat (make-string (* len lvl) ? ) bul)))
(replace-match s t t)
(setq ind (length s) level lvl)))
;; Ignore blank lines and inline tasks.
((looking-at "^[ \t]*$"))
((looking-at "^\\*+ "))
;; Ensure normal text belongs to the new item.
(t (org-indent-line-to (+ (max (- (org-get-indentation) level 2) 0)
ind))))
(beginning-of-line 2))))
;; Case 3. Normal line with ARG: turn each of them into items
;; unless they are already one.
(arg
(while (< (setq l (1+ l)) l2)
(unless (or (org-on-heading-p) (org-at-item-p))
(if (looking-at "\\([ \t]*\\)\\(\\S-\\)")
(replace-match
(concat "\\1" (org-list-bullet-string "-") "\\2"))))
(beginning-of-line 2)))
;; Case 4. Normal line without ARG: make the first line of
;; region an item, and shift indentation of others
;; lines to set them as item's body.
(t (let* ((bul (org-list-bullet-string "-"))
(bul-len (length bul))
(ref-ind (org-get-indentation)))
(skip-chars-forward " \t")
(insert bul)
(beginning-of-line 2)
(while (and (< (setq l (1+ l)) l2) (< (point) end))
;; Ensure that lines less indented than first one
;; still get included in item body.
(org-indent-line-to (+ (max ref-ind (org-get-indentation))
bul-len))
(beginning-of-line 2)))))))))
(defun org-toggle-heading (&optional nstars)
"Convert headings to normal text, or items or text to headings.
If there is no active region, only the current line is considered.
If the first line is a heading, remove the stars from all headlines
in the region.
If the first non blank line is an headline, remove the stars from
all headlines in the region.
If the first line is a plain list item, turn all plain list items
into headings.
If it is a plain list item, turn all plain list items into headings.
If the first line is a normal line, turn each and every line in the
region into a heading.
If it is a normal line, turn each and every normal line (i.e. not
an heading or an item) in the region into a heading.
When converting a line into a heading, the number of stars is chosen
such that the lines become children of the current entry. However,
@ -17653,41 +17666,65 @@ stars to add."
(interactive "P")
(let (l2 l itemp beg end)
(if (org-region-active-p)
(setq beg (region-beginning) end (region-end))
(setq beg (region-beginning) end (copy-marker (region-end)))
(setq beg (point-at-bol)
end (min (1+ (point-at-eol)) (point-max))))
(save-excursion
(goto-char end)
(setq l2 (org-current-line))
(goto-char beg)
(beginning-of-line 1)
(setq l (1- (org-current-line)))
(if (org-on-heading-p)
;; We already have headlines, de-star them
(while (< (setq l (1+ l)) l2)
(when (org-on-heading-p t)
(and (looking-at outline-regexp) (replace-match "")))
(beginning-of-line 2))
(setq itemp (org-at-item-p))
(let* ((stars
(if nstars
(make-string (prefix-numeric-value current-prefix-arg)
?*)
(save-excursion
(if (re-search-backward org-complex-heading-regexp nil t)
(match-string 1) ""))))
(add-stars (cond (nstars "")
((equal stars "") "*")
(org-odd-levels-only "**")
(t "*")))
(rpl (concat stars add-stars " ")))
(while (< (setq l (1+ l)) l2)
(if itemp
(and (org-at-item-p) (replace-match rpl t t))
(unless (org-on-heading-p)
(if (looking-at "\\([ \t]*\\)\\(\\S-\\)")
(replace-match (concat rpl (match-string 2))))))
(beginning-of-line 2)))))))
;; Ensure inline tasks don't count as headings.
(org-with-limited-levels
(save-excursion
(goto-char end)
(setq l2 (org-current-line))
(goto-char beg)
(beginning-of-line 1)
;; Ignore blank lines at beginning of region
(skip-chars-forward " \t\r\n")
(beginning-of-line 1)
(setq l (1- (org-current-line)))
(cond
;; Case 1. Started at an heading: de-star headings.
((org-on-heading-p)
(while (< (setq l (1+ l)) l2)
(when (org-on-heading-p t)
(looking-at outline-regexp) (replace-match ""))
(beginning-of-line 2)))
;; Case 2. Started at an item: change items into headlines.
((org-at-item-p)
(let ((stars (make-string
(if nstars
(prefix-numeric-value current-prefix-arg)
(or (org-current-level) 0))
?*)))
(while (< (point) end)
(when (org-at-item-p)
;; Pay attention to cases when region ends before list.
(let* ((struct (org-list-struct))
(list-end (min (org-list-get-bottom-point struct) end)))
(save-restriction
(narrow-to-region (point) list-end)
(insert
(org-list-to-subtree
(org-list-parse-list t)
'(:istart (concat stars (funcall get-stars depth))
:icount (concat stars
(funcall get-stars depth))))))))
(beginning-of-line 2))))
;; Case 3. Started at normal text: make every line an heading,
;; skipping headlines and items.
(t (let* ((stars (make-string
(if nstars
(prefix-numeric-value current-prefix-arg)
(or (org-current-level) 0))
?*))
(add-stars (cond (nstars "")
((equal stars "") "*")
(org-odd-levels-only "**")
(t "*")))
(rpl (concat stars add-stars " ")))
(while (< (setq l (1+ l)) l2)
(unless (or (org-on-heading-p) (org-at-item-p))
(when (looking-at "\\([ \t]*\\)\\(\\S-\\)")
(replace-match (concat rpl (match-string 2)))))
(beginning-of-line 2)))))))))
(defun org-meta-return (&optional arg)
"Insert a new heading or wrap a region in a table.