summaryrefslogtreecommitdiff
path: root/lisp/org/org-list.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/org/org-list.el')
-rw-r--r--lisp/org/org-list.el313
1 files changed, 102 insertions, 211 deletions
diff --git a/lisp/org/org-list.el b/lisp/org/org-list.el
index 22692d224a8..c4aef32fc08 100644
--- a/lisp/org/org-list.el
+++ b/lisp/org/org-list.el
@@ -91,6 +91,7 @@
(defvar org-drawer-regexp)
(defvar org-element-all-objects)
(defvar org-inhibit-startup)
+(defvar org-loop-over-headlines-in-active-region)
(defvar org-odd-levels-only)
(defvar org-outline-regexp-bol)
(defvar org-scheduled-string)
@@ -101,43 +102,31 @@
(declare-function org-at-heading-p "org" (&optional invisible-ok))
(declare-function org-back-to-heading "org" (&optional invisible-ok))
(declare-function org-before-first-heading-p "org" ())
-(declare-function org-combine-plists "org" (&rest plists))
(declare-function org-current-level "org" ())
(declare-function org-element-at-point "org-element" ())
(declare-function org-element-context "org-element" (&optional element))
(declare-function org-element-interpret-data "org-element" (data))
-(declare-function
- org-element-lineage "org-element" (blob &optional types with-self))
+(declare-function org-element-lineage "org-element" (blob &optional types with-self))
(declare-function org-element-macro-interpreter "org-element" (macro ##))
-(declare-function
- org-element-map "org-element"
- (data types fun &optional info first-match no-recursion with-affiliated))
+(declare-function org-element-map "org-element" (data types fun &optional info first-match no-recursion with-affiliated))
(declare-function org-element-normalize-string "org-element" (s))
-(declare-function org-element-parse-buffer "org-element"
- (&optional granularity visible-only))
+(declare-function org-element-parse-buffer "org-element" (&optional granularity visible-only))
(declare-function org-element-property "org-element" (property element))
-(declare-function org-element-put-property "org-element"
- (element property value))
+(declare-function org-element-put-property "org-element" (element property value))
(declare-function org-element-set-element "org-element" (old new))
(declare-function org-element-type "org-element" (element))
(declare-function org-element-update-syntax "org-element" ())
(declare-function org-end-of-meta-data "org" (&optional full))
-(declare-function org-entry-get "org"
- (pom property &optional inherit literal-nil))
+(declare-function org-entry-get "org" (pom property &optional inherit literal-nil))
(declare-function org-export-create-backend "ox" (&rest rest) t)
(declare-function org-export-data-with-backend "ox" (data backend info))
(declare-function org-export-get-backend "ox" (name))
-(declare-function org-export-get-environment "ox"
- (&optional backend subtreep ext-plist))
-(declare-function org-export-get-next-element "ox"
- (blob info &optional n))
-(declare-function org-export-with-backend "ox"
- (backend data &optional contents info))
+(declare-function org-export-get-environment "ox" (&optional backend subtreep ext-plist))
+(declare-function org-export-get-next-element "ox" (blob info &optional n))
+(declare-function org-export-with-backend "ox" (backend data &optional contents info))
(declare-function org-fix-tags-on-the-fly "org" ())
-(declare-function org-get-indentation "org" (&optional line))
(declare-function org-get-todo-state "org" ())
(declare-function org-in-block-p "org" (names))
-(declare-function org-in-regexp "org" (re &optional nlines visually))
(declare-function org-inlinetask-goto-beginning "org-inlinetask" ())
(declare-function org-inlinetask-goto-end "org-inlinetask" ())
(declare-function org-inlinetask-in-task-p "org-inlinetask" ())
@@ -147,16 +136,12 @@
(declare-function org-outline-level "org" ())
(declare-function org-previous-line-empty-p "org" ())
(declare-function org-reduced-level "org" (L))
-(declare-function org-remove-indentation "org" (code &optional n))
+(declare-function org-set-tags "org" (tags))
(declare-function org-show-subtree "org" ())
(declare-function org-sort-remove-invisible "org" (S))
(declare-function org-time-string-to-seconds "org" (s))
(declare-function org-timer-hms-to-secs "org-timer" (hms))
(declare-function org-timer-item "org-timer" (&optional arg))
-(declare-function org-trim "org" (s &optional keep-lead))
-(declare-function org-uniquify "org" (list))
-(declare-function org-invisible-p "org" (&optional pos))
-(declare-function outline-flag-region "outline" (from to flag))
(declare-function outline-next-heading "outline" ())
(declare-function outline-previous-heading "outline" ())
@@ -343,13 +328,6 @@ with the word \"recursive\" in the value."
:group 'org-plain-lists
:type 'boolean)
-(defcustom org-list-description-max-indent 20
- "Maximum indentation for the second line of a description list.
-When the indentation would be larger than this, it will become
-5 characters instead."
- :group 'org-plain-lists
- :type 'integer)
-
(defcustom org-list-indent-offset 0
"Additional indentation for sub-items in a list.
By setting this to a small number, usually 1 or 2, one can more
@@ -358,45 +336,10 @@ clearly distinguish sub-items in a list."
:version "24.1"
:type 'integer)
-(defcustom org-list-radio-list-templates
- '((latex-mode "% BEGIN RECEIVE ORGLST %n
-% END RECEIVE ORGLST %n
-\\begin{comment}
-#+ORGLST: SEND %n org-list-to-latex
--
-\\end{comment}\n")
- (texinfo-mode "@c BEGIN RECEIVE ORGLST %n
-@c END RECEIVE ORGLST %n
-@ignore
-#+ORGLST: SEND %n org-list-to-texinfo
--
-@end ignore\n")
- (html-mode "<!-- BEGIN RECEIVE ORGLST %n -->
-<!-- END RECEIVE ORGLST %n -->
-<!--
-#+ORGLST: SEND %n org-list-to-html
--
--->\n"))
- "Templates for radio lists in different major modes.
-All occurrences of %n in a template will be replaced with the name of the
-list, obtained by prompting the user."
- :group 'org-plain-lists
- :type '(repeat
- (list (symbol :tag "Major mode")
- (string :tag "Format"))))
-
(defvar org-list-forbidden-blocks '("example" "verse" "src" "export")
"Names of blocks where lists are not allowed.
Names must be in lower case.")
-(defvar org-list-export-context '(block inlinetask)
- "Context types where lists will be interpreted during export.
-
-Valid types are `drawer', `inlinetask' and `block'. More
-specifically, type `block' is determined by the variable
-`org-list-forbidden-blocks'.")
-
-
;;; Predicates and regexps
@@ -462,7 +405,7 @@ group 4: description tag")
(ind-ref (if (or (looking-at "^[ \t]*$")
(and inlinetask-re (looking-at inlinetask-re)))
10000
- (org-get-indentation))))
+ (current-indentation))))
(cond
((eq (nth 2 context) 'invalid) nil)
((looking-at item-re) (point))
@@ -484,7 +427,7 @@ group 4: description tag")
;; Look for an item, less indented that reference line.
(catch 'exit
(while t
- (let ((ind (org-get-indentation)))
+ (let ((ind (current-indentation)))
(cond
;; This is exactly what we want.
((and (looking-at item-re) (< ind ind-ref))
@@ -654,7 +597,7 @@ Assume point is at an item."
(item-re (org-item-re))
(inlinetask-re (and (featurep 'org-inlinetask)
(org-inlinetask-outline-regexp)))
- (beg-cell (cons (point) (org-get-indentation)))
+ (beg-cell (cons (point) (current-indentation)))
itm-lst itm-lst-2 end-lst end-lst-2 struct
(assoc-at-point
(function
@@ -682,7 +625,7 @@ Assume point is at an item."
(save-excursion
(catch 'exit
(while t
- (let ((ind (org-get-indentation)))
+ (let ((ind (current-indentation)))
(cond
((<= (point) lim-up)
;; At upward limit: if we ended at an item, store it,
@@ -742,7 +685,7 @@ Assume point is at an item."
;; position of items in END-LST-2.
(catch 'exit
(while t
- (let ((ind (org-get-indentation)))
+ (let ((ind (current-indentation)))
(cond
((>= (point) lim-down)
;; At downward limit: this is de facto the end of the
@@ -861,6 +804,17 @@ This function modifies STRUCT."
(t (cons pos (cdar ind-to-ori))))))
(cdr struct)))))
+(defun org-list--delete-metadata ()
+ "Delete metadata from the heading at point.
+Metadata are tags, planning information and properties drawers."
+ (save-match-data
+ (org-with-wide-buffer
+ (org-set-tags nil)
+ (delete-region (line-beginning-position 2)
+ (save-excursion
+ (org-end-of-meta-data)
+ (org-skip-whitespace)
+ (if (eobp) (point) (line-beginning-position)))))))
;;; Accessors
@@ -1281,10 +1235,18 @@ function ends.
This function modifies STRUCT."
(let ((case-fold-search t))
- ;; 1. Get information about list: position of point with regards
- ;; to item start (BEFOREP), blank lines number separating items
- ;; (BLANK-NB), if we're allowed to (SPLIT-LINE-P).
- (let* ((item (progn (goto-char pos) (goto-char (org-list-get-item-begin))))
+ ;; 1. Get information about list: ITEM containing POS, position of
+ ;; point with regards to item start (BEFOREP), blank lines
+ ;; number separating items (BLANK-NB), if we're allowed to
+ ;; (SPLIT-LINE-P).
+ (let* ((item (goto-char (catch :exit
+ (let ((inner-item 0))
+ (pcase-dolist (`(,i . ,_) struct)
+ (cond
+ ((= i pos) (throw :exit i))
+ ((< i pos) (setq inner-item i))
+ (t (throw :exit inner-item))))
+ inner-item))))
(item-end (org-list-get-item-end item struct))
(item-end-no-blank (org-list-get-item-end-before-blank item struct))
(beforep
@@ -1497,8 +1459,8 @@ This function returns, destructively, the new list structure."
(org-M-RET-may-split-line nil)
;; Store inner overlays (to preserve visibility).
(overlays (cl-remove-if (lambda (o) (or (< (overlay-start o) item)
- (> (overlay-end o) item)))
- (overlays-in item item-end))))
+ (> (overlay-end o) item)))
+ (overlays-in item item-end))))
(cond
((eq dest 'delete) (org-list-delete-item item struct))
((eq dest 'kill)
@@ -1590,23 +1552,6 @@ STRUCT may be modified if `org-list-demote-modify-bullet' matches
bullets between START and END."
(let* (acc
(set-assoc (lambda (cell) (push cell acc) cell))
- (change-bullet-maybe
- (function
- (lambda (item)
- (let ((new-bul-p
- (cdr (assoc
- ;; Normalize ordered bullets.
- (let ((bul (org-trim
- (org-list-get-bullet item struct))))
- (cond ((string-match "[A-Z]\\." bul) "A.")
- ((string-match "[A-Z])" bul) "A)")
- ((string-match "[a-z]\\." bul) "a.")
- ((string-match "[a-z])" bul) "a)")
- ((string-match "[0-9]\\." bul) "1.")
- ((string-match "[0-9])" bul) "1)")
- (t bul)))
- org-list-demote-modify-bullet))))
- (when new-bul-p (org-list-set-bullet item struct new-bul-p))))))
(ind
(lambda (cell)
(let* ((item (car cell))
@@ -1622,11 +1567,24 @@ bullets between START and END."
;; Item is in zone...
(let ((prev (org-list-get-prev-item item struct prevs)))
;; Check if bullet needs to be changed.
- (funcall change-bullet-maybe item)
+ (pcase (assoc (let ((b (org-list-get-bullet item struct))
+ (case-fold-search nil))
+ (cond ((string-match "[A-Z]\\." b) "A.")
+ ((string-match "[A-Z])" b) "A)")
+ ((string-match "[a-z]\\." b) "a.")
+ ((string-match "[a-z])" b) "a)")
+ ((string-match "[0-9]\\." b) "1.")
+ ((string-match "[0-9])" b) "1)")
+ (t (org-trim b))))
+ org-list-demote-modify-bullet)
+ (`(,_ . ,bullet)
+ (org-list-set-bullet
+ item struct (org-list-bullet-string bullet)))
+ (_ nil))
(cond
;; First item indented but not parent: error
- ((and (not prev) (< parent start))
- (error "Cannot indent the first item of a list"))
+ ((and (not prev) (or (not parent) (< parent start)))
+ (user-error "Cannot indent the first item of a list"))
;; First item and parent indented: keep same
;; parent.
((not prev) (funcall set-assoc cell))
@@ -1899,7 +1857,7 @@ Initial position of cursor is restored after the changes."
(org-inlinetask-goto-beginning))
;; Shift only non-empty lines.
((looking-at-p "^[ \t]*\\S-")
- (indent-line-to (+ (org-get-indentation) delta))))
+ (indent-line-to (+ (current-indentation) delta))))
(forward-line -1)))))
(modify-item
(function
@@ -1908,7 +1866,7 @@ Initial position of cursor is restored after the changes."
(lambda (item)
(goto-char item)
(let* ((new-ind (org-list-get-ind item struct))
- (old-ind (org-get-indentation))
+ (old-ind (current-indentation))
(new-bul (org-list-bullet-string
(org-list-get-bullet item struct)))
(old-bul (org-list-get-bullet item old-struct))
@@ -1983,7 +1941,7 @@ Initial position of cursor is restored after the changes."
;; Ignore empty lines. Also ignore blocks and
;; drawers contents.
(unless (looking-at-p "[ \t]*$")
- (setq min-ind (min (org-get-indentation) min-ind))
+ (setq min-ind (min (current-indentation) min-ind))
(cond
((and (looking-at "#\\+BEGIN\\(:\\|_\\S-+\\)")
(re-search-forward
@@ -2037,7 +1995,9 @@ doesn't correspond anymore to the real list in buffer."
;; 5. Eventually fix checkboxes.
(org-list-struct-fix-box struct parents prevs))
;; 6. Apply structure modifications to buffer.
- (org-list-struct-apply-struct struct old-struct)))
+ (org-list-struct-apply-struct struct old-struct))
+ ;; 7. Return the updated structure
+ struct)
@@ -2078,8 +2038,8 @@ Possible values are: `folded', `children' or `subtree'. See
((eq view 'folded)
(let ((item-end (org-list-get-item-end-before-blank item struct)))
;; Hide from eol
- (outline-flag-region (save-excursion (goto-char item) (point-at-eol))
- item-end t)))
+ (org-flag-region (save-excursion (goto-char item) (line-end-position))
+ item-end t 'outline)))
((eq view 'children)
;; First show everything.
(org-list-set-item-visibility item struct 'subtree)
@@ -2092,31 +2052,19 @@ Possible values are: `folded', `children' or `subtree'. See
((eq view 'subtree)
;; Show everything
(let ((item-end (org-list-get-item-end item struct)))
- (outline-flag-region item item-end nil)))))
+ (org-flag-region item item-end nil 'outline)))))
(defun org-list-item-body-column (item)
"Return column at which body of ITEM should start."
(save-excursion
(goto-char item)
- (if (save-excursion
- (end-of-line)
- (re-search-backward
- "[ \t]::\\([ \t]\\|$\\)" (line-beginning-position) t))
- ;; Descriptive list item. Body starts after item's tag, if
- ;; possible.
- (let ((start (1+ (- (match-beginning 1) (line-beginning-position))))
- (ind (org-get-indentation)))
- (if (> start (+ ind org-list-description-max-indent))
- (+ ind 5)
- start))
- ;; Regular item. Body starts after bullet.
- (looking-at "[ \t]*\\(\\S-+\\)")
- (+ (progn (goto-char (match-end 1)) (current-column))
- (if (and org-list-two-spaces-after-bullet-regexp
- (string-match-p org-list-two-spaces-after-bullet-regexp
- (match-string 1)))
- 2
- 1)))))
+ (looking-at "[ \t]*\\(\\S-+\\)")
+ (+ (progn (goto-char (match-end 1)) (current-column))
+ (if (and org-list-two-spaces-after-bullet-regexp
+ (string-match-p org-list-two-spaces-after-bullet-regexp
+ (match-string 1)))
+ 2
+ 1))))
@@ -2280,7 +2228,7 @@ item is invisible."
(string-match "[.)]" (match-string 1))))
(match-beginning 4)
(match-end 0)))
- (if desc (backward-char 1))
+ (when desc (backward-char 1))
t)))))
(defun org-list-repair ()
@@ -2707,11 +2655,12 @@ Return t if successful."
(error "Cannot outdent an item without its children"))
;; Normal shifting
(t
- (let* ((new-parents
+ (let* ((old-struct (copy-tree struct))
+ (new-parents
(if (< arg 0)
(org-list-struct-outdent beg end struct parents)
(org-list-struct-indent beg end struct parents prevs))))
- (org-list-write-struct struct new-parents))
+ (org-list-write-struct struct new-parents old-struct))
(org-update-checkbox-count-maybe))))))
t)
@@ -2840,7 +2789,8 @@ Sorting can be alphabetically, numerically, by date/time as given
by a time stamp, by a property or by priority.
Comparing entries ignores case by default. However, with an
-optional argument WITH-CASE, the sorting considers case as well.
+optional argument WITH-CASE, the sorting considers case as well,
+if the current locale allows for it.
The command prompts for the sorting type unless it has been given
to the function through the SORTING-TYPE argument, which needs to
@@ -2886,7 +2836,7 @@ function is being called interactively."
(error "Missing key extractor"))))
(sort-func
(cond
- ((= dcst ?a) #'string<)
+ ((= dcst ?a) #'org-string-collate-lessp)
((= dcst ?f)
(or compare-func
(and interactive?
@@ -2977,7 +2927,7 @@ With a prefix argument ARG, change the region in a single item."
(save-excursion
(catch 'exit
(while (< (point) end)
- (let ((i (org-get-indentation)))
+ (let ((i (current-indentation)))
(cond
;; Skip blank lines and inline tasks.
((looking-at "^[ \t]*$"))
@@ -2993,7 +2943,7 @@ With a prefix argument ARG, change the region in a single item."
(while (< (point) end)
(unless (or (looking-at "^[ \t]*$")
(looking-at org-outline-regexp-bol))
- (indent-line-to (+ (org-get-indentation) delta)))
+ (indent-line-to (+ (current-indentation) delta)))
(forward-line))))))
(skip-blanks
(lambda (pos)
@@ -3027,6 +2977,9 @@ With a prefix argument ARG, change the region in a single item."
(forward-line)))
;; Case 2. Start at an heading: convert to items.
((org-at-heading-p)
+ ;; Remove metadata
+ (let (org-loop-over-headlines-in-active-region)
+ (org-list--delete-metadata))
(let* ((bul (org-list-bullet-string "-"))
(bul-len (length bul))
;; Indentation of the first heading. It should be
@@ -3047,6 +3000,9 @@ With a prefix argument ARG, change the region in a single item."
;; one, set it as reference, in order to preserve
;; subtrees.
(when (< level ref-level) (setq ref-level level))
+ ;; Remove metadata
+ (let (org-loop-over-headlines-in-active-region)
+ (org-list--delete-metadata))
;; Remove stars and TODO keyword.
(let ((case-fold-search nil)) (looking-at org-todo-line-regexp))
(delete-region (point) (or (match-beginning 3)
@@ -3079,7 +3035,7 @@ With a prefix argument ARG, change the region in a single item."
;; set them as item's body.
(arg (let* ((bul (org-list-bullet-string "-"))
(bul-len (length bul))
- (ref-ind (org-get-indentation)))
+ (ref-ind (current-indentation)))
(skip-chars-forward " \t")
(insert bul)
(forward-line)
@@ -3195,80 +3151,14 @@ Point is left at list's end."
(defun org-list-make-subtree ()
"Convert the plain list at point into a subtree."
(interactive)
- (if (not (ignore-errors (goto-char (org-in-item-p))))
- (error "Not in a list")
- (let ((list (save-excursion (org-list-to-lisp t))))
- (insert (org-list-to-subtree list)))))
-
-(defun org-list-insert-radio-list ()
- "Insert a radio list template appropriate for this major mode."
- (interactive)
- (let* ((e (cl-assoc-if #'derived-mode-p org-list-radio-list-templates))
- (txt (nth 1 e))
- name pos)
- (unless e (error "No radio list setup defined for %s" major-mode))
- (setq name (read-string "List name: "))
- (while (string-match "%n" txt)
- (setq txt (replace-match name t t txt)))
- (or (bolp) (insert "\n"))
- (setq pos (point))
- (insert txt)
- (goto-char pos)))
-
-(defun org-list-send-list (&optional maybe)
- "Send a transformed version of this list to the receiver position.
-With argument MAYBE, fail quietly if no transformation is defined
-for this list."
- (interactive)
- (catch 'exit
- (unless (org-at-item-p) (error "Not at a list item"))
- (save-excursion
- (let ((case-fold-search t))
- (re-search-backward "^[ \t]*#\\+ORGLST:" nil t)
- (unless (looking-at
- "[ \t]*#\\+ORGLST:[ \t]+SEND[ \t]+\\(\\S-+\\)[ \t]+\\([^ \t\n]+\\)")
- (if maybe (throw 'exit nil)
- (error "Don't know how to transform this list")))))
- (let* ((name (regexp-quote (match-string 1)))
- (transform (intern (match-string 2)))
- (bottom-point
- (save-excursion
- (re-search-forward
- "\\(\\\\end{comment}\\|@end ignore\\|-->\\)" nil t)
- (match-beginning 0)))
- (top-point
- (progn
- (re-search-backward "#\\+ORGLST" nil t)
- (re-search-forward (org-item-beginning-re) bottom-point t)
- (match-beginning 0)))
- (plain-list (save-excursion
- (goto-char top-point)
- (org-list-to-lisp))))
- (unless (fboundp transform)
- (error "No such transformation function %s" transform))
- (let ((txt (funcall transform plain-list)))
- ;; Find the insertion(s) place(s).
- (save-excursion
- (goto-char (point-min))
- (let ((receiver-count 0)
- (begin-re (format "BEGIN +RECEIVE +ORGLST +%s\\([ \t]\\|$\\)"
- name))
- (end-re (format "END +RECEIVE +ORGLST +%s\\([ \t]\\|$\\)"
- name)))
- (while (re-search-forward begin-re nil t)
- (cl-incf receiver-count)
- (let ((beg (line-beginning-position 2)))
- (unless (re-search-forward end-re nil t)
- (user-error "Cannot find end of receiver location at %d" beg))
- (beginning-of-line)
- (delete-region beg (point))
- (insert txt "\n")))
- (cond
- ((> receiver-count 1)
- (message "List converted and installed at receiver locations"))
- ((= receiver-count 1)
- (message "List converted and installed at receiver location"))
- (t (user-error "No valid receiver location found")))))))))
+ (let ((item (org-in-item-p)))
+ (unless item (error "Not in a list"))
+ (goto-char item)
+ (let ((level (pcase (org-current-level)
+ (`nil 1)
+ (l (1+ (org-reduced-level l)))))
+ (list (save-excursion (org-list-to-lisp t))))
+ (insert (org-list-to-subtree list level) "\n"))))
(defun org-list-to-generic (list params)
"Convert a LIST parsed through `org-list-to-lisp' to a custom format.
@@ -3577,21 +3467,22 @@ with overruling parameters for `org-list-to-generic'."
:cbtrans "[-] ")))
(org-list-to-generic list (org-combine-plists defaults params))))
-(defun org-list-to-subtree (list &optional params)
+(defun org-list-to-subtree (list &optional start-level params)
"Convert LIST into an Org subtree.
-LIST is as returned by `org-list-to-lisp'. PARAMS is a property
-list with overruling parameters for `org-list-to-generic'."
+LIST is as returned by `org-list-to-lisp'. Subtree starts at
+START-LEVEL or level 1 if nil. PARAMS is a property list with
+overruling parameters for `org-list-to-generic'."
(let* ((blank (pcase (cdr (assq 'heading org-blank-before-new-entry))
(`t t)
(`auto (save-excursion
(org-with-limited-levels (outline-previous-heading))
(org-previous-line-empty-p)))))
- (level (org-reduced-level (or (org-current-level) 0)))
+ (level (or start-level 1))
(make-stars
(lambda (_type depth &optional _count)
;; Return the string for the heading, depending on DEPTH
;; of current sub-list.
- (let ((oddeven-level (+ level depth)))
+ (let ((oddeven-level (+ level (1- depth))))
(concat (make-string (if org-odd-levels-only
(1- (* 2 oddeven-level))
oddeven-level)