* net/tramp-compat.el (top): Autoload used functions from
[bpt/emacs.git] / lisp / org / org-list.el
CommitLineData
47ffc456
CD
1;;; org-list.el --- Plain lists for Org-mode
2;;
1e4f816a
CD
3;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
4;; Free Software Foundation, Inc.
47ffc456
CD
5;;
6;; Author: Carsten Dominik <carsten at orgmode dot org>
33306645 7;; Bastien Guerry <bzg AT altern DOT org>
47ffc456
CD
8;; Keywords: outlines, hypermedia, calendar, wp
9;; Homepage: http://orgmode.org
c8d0cf5c 10;; Version: 6.29c
47ffc456
CD
11;;
12;; This file is part of GNU Emacs.
13;;
14;; GNU Emacs is free software: you can redistribute it and/or modify
15;; it under the terms of the GNU General Public License as published by
16;; the Free Software Foundation, either version 3 of the License, or
17;; (at your option) any later version.
18
19;; GNU Emacs is distributed in the hope that it will be useful,
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
33306645 21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47ffc456
CD
22;; GNU General Public License for more details.
23
24;; You should have received a copy of the GNU General Public License
25;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
27;;
28;;; Commentary:
29
30;; This file contains the code dealing with plain lists in Org-mode.
31
32;;; Code:
33
34(require 'org-macs)
35(require 'org-compat)
36
37(defvar org-blank-before-new-entry)
38(defvar org-M-RET-may-split-line)
c8d0cf5c
CD
39(defvar org-complex-heading-regexp)
40(defvar org-odd-levels-only)
47ffc456
CD
41
42(declare-function org-invisible-p "org" ())
43(declare-function org-on-heading-p "org" (&optional invisible-ok))
9fc10007
GM
44(declare-function outline-next-heading "outline" ())
45(declare-function outline-back-to-heading "outline" (&optional invisible-ok))
47ffc456
CD
46(declare-function org-back-to-heading "org" (&optional invisible-ok))
47(declare-function org-back-over-empty-lines "org" ())
48(declare-function org-skip-whitespace "org" ())
49(declare-function org-trim "org" (s))
50(declare-function org-get-indentation "org" (&optional line))
ff4be292 51(declare-function org-timer-item "org-timer" (&optional arg))
0bd48b37 52(declare-function org-combine-plists "org" (&rest plists))
c8d0cf5c
CD
53(declare-function org-entry-get "org" (pom property &optional inherit))
54(declare-function org-narrow-to-subtree "org" ())
55(declare-function org-show-subtree "org" ())
47ffc456
CD
56
57(defgroup org-plain-lists nil
58 "Options concerning plain lists in Org-mode."
59 :tag "Org Plain lists"
60 :group 'org-structure)
61
c8d0cf5c
CD
62(defcustom org-cycle-include-plain-lists t
63 "When t, make TAB cycle visibility on plain list items.
64
65Cycling plain lists works only when the cursor is on a plain list
66item. When the cursor is on an outline heading, plain lists are
67treated as text. This is the most stable way of handling this,
68which is why it is the default.
69
70When this is the symbol `integrate', then during cycling, plain
71list items will *temporarily* be interpreted as outline headlines
72with a level given by 1000+i where i is the indentation of the
73bullet. This setting can lead to strange effects when switching
74visibility to `children', because the first \"child\" in a
75subtree decides what children should be listed. If that first
76\"child\" is a plain list item with an implied large level
77number, all true children and grand children of the outline
78heading will be exposed in a children' view."
47ffc456 79 :group 'org-plain-lists
c8d0cf5c
CD
80 :type '(choice
81 (const :tag "Never" nil)
82 (const :tag "With cursor in plain list (recommended)" t)
83 (const :tag "As children of outline headings" integrate)))
84
85(defcustom org-list-demote-modify-bullet nil
86 "Default bullet type installed when demoting an item.
87This is an association list, for each bullet type, this alist will point
88to the bulled that should be used when this item is demoted."
89 :group 'org-plain-lists
90 :type '(repeat
91 (cons
92 (choice :tag "If the current bullet is "
93 (const "-")
94 (const "+")
95 (const "*")
96 (const "1.")
97 (const "1)"))
98 (choice :tag "demotion will change it to"
99 (const "-")
100 (const "+")
101 (const "*")
102 (const "1.")
103 (const "1)")))))
47ffc456
CD
104
105(defcustom org-plain-list-ordered-item-terminator t
106 "The character that makes a line with leading number an ordered list item.
107Valid values are ?. and ?\). To get both terminators, use t. While
108?. may look nicer, it creates the danger that a line with leading
109number may be incorrectly interpreted as an item. ?\) therefore is
110the safe choice."
111 :group 'org-plain-lists
112 :type '(choice (const :tag "dot like in \"2.\"" ?.)
113 (const :tag "paren like in \"2)\"" ?\))
114 (const :tab "both" t)))
115
ce4fdcb9
CD
116(defcustom org-list-two-spaces-after-bullet-regexp nil
117 "A regular expression matching bullets that should have 2 spaces after them.
118When nil, no bullet will have two spaces after them.
33306645 119When a string, it will be used as a regular expression. When the bullet
ce4fdcb9 120type of a list is changed, the new bullet type will be matched against this
33306645 121regexp. If it matches, there will be two spaces instead of one after
ce4fdcb9
CD
122the bullet in each item of he list."
123 :group 'org-plain-list
124 :type '(choice
125 (const :tag "never" nil)
126 (regexp)))
127
47ffc456
CD
128(defcustom org-empty-line-terminates-plain-lists nil
129 "Non-nil means, an empty line ends all plain list levels.
805b5d9c 130When nil, empty lines are part of the preceding item."
47ffc456
CD
131 :group 'org-plain-lists
132 :type 'boolean)
133
134(defcustom org-auto-renumber-ordered-lists t
135 "Non-nil means, automatically renumber ordered plain lists.
136Renumbering happens when the sequence have been changed with
137\\[org-shiftmetaup] or \\[org-shiftmetadown]. After other editing commands,
138use \\[org-ctrl-c-ctrl-c] to trigger renumbering."
139 :group 'org-plain-lists
140 :type 'boolean)
141
142(defcustom org-provide-checkbox-statistics t
143 "Non-nil means, update checkbox statistics after insert and toggle.
c8d0cf5c
CD
144When this is set, checkbox statistics is updated each time you
145either insert a new checkbox with \\[org-insert-todo-heading] or
146toggle a checkbox with \\[org-ctrl-c-ctrl-c]."
147 :group 'org-plain-lists
148 :type 'boolean)
149
150(defcustom org-hierarchical-checkbox-statistics t
151 "Non-nil means, checkbox statistics counts only the state of direct children.
152When nil, all boxes below the cookie are counted."
47ffc456
CD
153 :group 'org-plain-lists
154 :type 'boolean)
155
156(defcustom org-description-max-indent 20
157 "Maximum indentation for the second line of a description list.
158When the indentation would be larger than this, it will become
1595 characters instead."
160 :group 'org-plain-lists
161 :type 'integer)
162
163(defvar org-list-beginning-re
c8d0cf5c 164 "^\\([ \t]*\\)\\([-+]\\|[0-9]+[.)]\\) +\\(.*\\)$")
47ffc456
CD
165
166(defcustom org-list-radio-list-templates
167 '((latex-mode "% BEGIN RECEIVE ORGLST %n
168% END RECEIVE ORGLST %n
169\\begin{comment}
170#+ORGLST: SEND %n org-list-to-latex
171| | |
172\\end{comment}\n")
173 (texinfo-mode "@c BEGIN RECEIVE ORGLST %n
174@c END RECEIVE ORGLST %n
175@ignore
176#+ORGLST: SEND %n org-list-to-texinfo
177| | |
178@end ignore\n")
179 (html-mode "<!-- BEGIN RECEIVE ORGLST %n -->
180<!-- END RECEIVE ORGLST %n -->
181<!--
182#+ORGLST: SEND %n org-list-to-html
183| | |
184-->\n"))
185 "Templates for radio lists in different major modes.
186All occurrences of %n in a template will be replaced with the name of the
187list, obtained by prompting the user."
188 :group 'org-plain-lists
189 :type '(repeat
190 (list (symbol :tag "Major mode")
191 (string :tag "Format"))))
192
193;;;; Plain list items, including checkboxes
194
195;;; Plain list items
196
197(defun org-at-item-p ()
198 "Is point in a line starting a hand-formatted item?"
199 (let ((llt org-plain-list-ordered-item-terminator))
200 (save-excursion
201 (goto-char (point-at-bol))
202 (looking-at
203 (cond
204 ((eq llt t) "\\([ \t]*\\([-+]\\|\\([0-9]+[.)]\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
205 ((= llt ?.) "\\([ \t]*\\([-+]\\|\\([0-9]+\\.\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
c8d0cf5c 206 ((= llt ?\)) "\\([ \t]*\\([-+]\\|\\([0-9]+)\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)")
47ffc456
CD
207 (t (error "Invalid value of `org-plain-list-ordered-item-terminator'")))))))
208
65c439fd
CD
209(defun org-at-item-bullet-p ()
210 "Is point at the bullet of a plain list item?"
211 (and (org-at-item-p)
212 (not (member (char-after) '(?\ ?\t)))
213 (< (point) (match-end 0))))
214
47ffc456
CD
215(defun org-in-item-p ()
216 "It the cursor inside a plain list item.
217Does not have to be the first line."
218 (save-excursion
219 (condition-case nil
220 (progn
221 (org-beginning-of-item)
222 (org-at-item-p)
223 t)
224 (error nil))))
225
226(defun org-insert-item (&optional checkbox)
227 "Insert a new item at the current level.
228Return t when things worked, nil when we are not in an item."
229 (when (save-excursion
230 (condition-case nil
231 (progn
232 (org-beginning-of-item)
233 (org-at-item-p)
234 (if (org-invisible-p) (error "Invisible item"))
235 t)
236 (error nil)))
237 (let* ((bul (match-string 0))
238 (descp (save-excursion (goto-char (match-beginning 0))
239 (beginning-of-line 1)
240 (save-match-data
ff4be292
CD
241 (and (looking-at "[ \t]*\\(.*?\\) ::")
242 (match-string 1)))))
0bd48b37
CD
243 (empty-line-p (save-excursion
244 (goto-char (match-beginning 0))
245 (and (not (bobp))
246 (or (beginning-of-line 0) t)
247 (save-match-data
248 (looking-at "[ \t]*$")))))
ff4be292
CD
249 (timerp (and descp
250 (save-match-data
251 (string-match "^[-+*][ \t]+[0-9]+:[0-9]+:[0-9]+$"
252 descp))))
47ffc456
CD
253 (eow (save-excursion (beginning-of-line 1) (looking-at "[ \t]*")
254 (match-end 0)))
c8d0cf5c
CD
255 (blank-a (if org-empty-line-terminates-plain-lists
256 nil
257 (cdr (assq 'plain-list-item org-blank-before-new-entry))))
0bd48b37 258 (blank (if (eq blank-a 'auto) empty-line-p blank-a))
47ffc456
CD
259 pos)
260 (if descp (setq checkbox nil))
ff4be292
CD
261 (if timerp
262 (progn (org-timer-item) t)
263 (cond
264 ((and (org-at-item-p) (<= (point) eow))
265 ;; before the bullet
266 (beginning-of-line 1)
267 (open-line (if blank 2 1)))
268 ((<= (point) eow)
269 (beginning-of-line 1))
270 (t
271 (unless (org-get-alist-option org-M-RET-may-split-line 'item)
272 (end-of-line 1)
273 (delete-horizontal-space))
274 (newline (if blank 2 1))))
275 (insert bul
276 (if checkbox "[ ]" "")
277 (if descp (concat (if checkbox " " "")
278 (read-string "Term: ") " :: ") ""))
279 (just-one-space)
280 (setq pos (point))
281 (end-of-line 1)
282 (unless (= (point) pos) (just-one-space) (backward-delete-char 1)))
283 (org-maybe-renumber-ordered-list)
284 (and checkbox (org-update-checkbox-count-maybe))
285 t)))
47ffc456
CD
286
287;;; Checkboxes
288
289(defun org-at-item-checkbox-p ()
290 "Is point at a line starting a plain-list item with a checklet?"
291 (and (org-at-item-p)
292 (save-excursion
293 (goto-char (match-end 0))
294 (skip-chars-forward " \t")
295 (looking-at "\\[[- X]\\]"))))
296
d6685abc
CD
297(defun org-toggle-checkbox (&optional toggle-presence)
298 "Toggle the checkbox in the current line.
299With prefix arg TOGGLE-PRESENCE, add or remove checkboxes.
c8d0cf5c 300With double prefix, set checkbox to [-].
d6685abc
CD
301When there is an active region, toggle status or presence of the checkbox
302in the first line, and make every item in the region have the same
805b5d9c 303status or presence, respectively.
a2a2e7fb
CD
304If the cursor is in a headline, apply this to all checkbox items in the
305text below the heading."
47ffc456
CD
306 (interactive "P")
307 (catch 'exit
c8d0cf5c 308 (let (beg end status first-present first-status blocked)
47ffc456
CD
309 (cond
310 ((org-region-active-p)
311 (setq beg (region-beginning) end (region-end)))
312 ((org-on-heading-p)
313 (setq beg (point) end (save-excursion (outline-next-heading) (point))))
314 ((org-at-item-checkbox-p)
c8d0cf5c
CD
315 (save-excursion
316 (if (equal toggle-presence '(4))
d6685abc
CD
317 (progn
318 (replace-match "")
319 (goto-char (match-beginning 0))
320 (just-one-space))
c8d0cf5c
CD
321 (when (setq blocked (org-checkbox-blocked-p))
322 (error "Checkbox blocked because of unchecked box in line %d"
323 blocked))
d6685abc 324 (replace-match
c8d0cf5c
CD
325 (cond ((equal toggle-presence '(16)) "[-]")
326 ((member (match-string 0) '("[ ]" "[-]")) "[X]")
d6685abc 327 (t "[ ]"))
c8d0cf5c 328 t t)))
47ffc456 329 (throw 'exit t))
d6685abc
CD
330 ((org-at-item-p)
331 ;; add a checkbox
332 (save-excursion
333 (goto-char (match-end 0))
334 (insert "[ ] "))
335 (throw 'exit t))
47ffc456 336 (t (error "Not at a checkbox or heading, and no active region")))
d6685abc 337 (setq end (move-marker (make-marker) end))
47ffc456
CD
338 (save-excursion
339 (goto-char beg)
d6685abc 340 (setq first-present (org-at-item-checkbox-p)
a2a2e7fb
CD
341 first-status
342 (save-excursion
343 (and (re-search-forward "[ \t]\\(\\[[ X]\\]\\)" end t)
344 (equal (match-string 1) "[X]"))))
47ffc456 345 (while (< (point) end)
d6685abc
CD
346 (if toggle-presence
347 (cond
348 ((and first-present (org-at-item-checkbox-p))
349 (save-excursion
350 (replace-match "")
351 (goto-char (match-beginning 0))
352 (just-one-space)))
353 ((and (not first-present) (not (org-at-item-checkbox-p))
354 (org-at-item-p))
355 (save-excursion
356 (goto-char (match-end 0))
357 (insert "[ ] "))))
358 (when (org-at-item-checkbox-p)
359 (setq status (equal (match-string 0) "[X]"))
360 (replace-match
361 (if first-status "[ ]" "[X]") t t)))
47ffc456
CD
362 (beginning-of-line 2)))))
363 (org-update-checkbox-count-maybe))
364
c8d0cf5c
CD
365(defun org-reset-checkbox-state-subtree ()
366 "Reset all checkboxes in an entry subtree."
367 (interactive "*")
368 (save-restriction
369 (save-excursion
370 (org-narrow-to-subtree)
371 (org-show-subtree)
372 (goto-char (point-min))
373 (let ((end (point-max)))
374 (while (< (point) end)
375 (when (org-at-item-checkbox-p)
376 (replace-match "[ ]" t t))
377 (beginning-of-line 2))))
378 (org-update-checkbox-count-maybe)))
379
380(defun org-checkbox-blocked-p ()
381 "Is the current checkbox blocked from for being checked now?
382A checkbox is blocked if all of the following conditions are fulfilled:
383
3841. The checkbox is not checked already.
3852. The current entry has the ORDERED property set.
3863. There is an unchecked checkbox in this entry before the current line."
387 (catch 'exit
388 (save-match-data
389 (save-excursion
390 (unless (org-at-item-checkbox-p) (throw 'exit nil))
391 (when (equal (match-string 0) "[X]")
392 ;; the box is already checked!
393 (throw 'exit nil))
394 (let ((end (point-at-bol)))
395 (condition-case nil (org-back-to-heading t)
396 (error (throw 'exit nil)))
397 (unless (org-entry-get nil "ORDERED") (throw 'exit nil))
398 (if (re-search-forward "^[ \t]*[-+*0-9.)] \\[[- ]\\]" end t)
399 (org-current-line)
400 nil))))))
401
402(defvar org-checkbox-statistics-hook nil
403 "Hook that is run whenever Org thinks checkbox statistics should be updated.
404This hook runs even if `org-provide-checkbox-statistics' is nil, to it can
405be used to implement alternative ways of collecting statistics information.")
406
47ffc456
CD
407(defun org-update-checkbox-count-maybe ()
408 "Update checkbox statistics unless turned off by user."
409 (when org-provide-checkbox-statistics
c8d0cf5c
CD
410 (org-update-checkbox-count))
411 (run-hooks 'org-checkbox-statistics-hook))
47ffc456
CD
412
413(defun org-update-checkbox-count (&optional all)
414 "Update the checkbox statistics in the current section.
415This will find all statistic cookies like [57%] and [6/12] and update them
416with the current numbers. With optional prefix argument ALL, do this for
417the whole buffer."
418 (interactive "P")
419 (save-excursion
420 (let* ((buffer-invisibility-spec (org-inhibit-invisibility)) ; Emacs 21
421 (beg (condition-case nil
ce4fdcb9 422 (progn (org-back-to-heading) (point))
47ffc456
CD
423 (error (point-min))))
424 (end (move-marker (make-marker)
425 (progn (outline-next-heading) (point))))
426 (re "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)")
427 (re-box "^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +\\(\\[[- X]\\]\\)")
428 (re-find (concat re "\\|" re-box))
429 beg-cookie end-cookie is-percent c-on c-off lim
33306645 430 eline curr-ind next-ind continue-from startsearch
c8d0cf5c
CD
431 (recursive
432 (or (not org-hierarchical-checkbox-statistics)
433 (string-match "\\<recursive\\>"
434 (or (org-entry-get nil "COOKIE_DATA") ""))))
33306645
CD
435 (cstat 0)
436 )
47ffc456
CD
437 (when all
438 (goto-char (point-min))
439 (outline-next-heading)
440 (setq beg (point) end (point-max)))
441 (goto-char end)
c8d0cf5c
CD
442 ;; find each statistics cookie
443 (while (and (re-search-backward re-find beg t)
444 (not (save-match-data
445 (and (org-on-heading-p)
446 (string-match "\\<todo\\>"
447 (downcase
448 (or (org-entry-get
449 nil "COOKIE_DATA")
450 "")))))))
47ffc456 451 (setq beg-cookie (match-beginning 1)
33306645 452 end-cookie (match-end 1)
47ffc456
CD
453 cstat (+ cstat (if end-cookie 1 0))
454 startsearch (point-at-eol)
a2a2e7fb 455 continue-from (match-beginning 0)
33306645 456 is-percent (match-beginning 2)
47ffc456
CD
457 lim (cond
458 ((org-on-heading-p) (outline-next-heading) (point))
459 ((org-at-item-p) (org-end-of-item) (point))
460 (t nil))
33306645
CD
461 c-on 0
462 c-off 0)
47ffc456 463 (when lim
33306645
CD
464 ;; find first checkbox for this cookie and gather
465 ;; statistics from all that are at this indentation level
466 (goto-char startsearch)
467 (if (re-search-forward re-box lim t)
468 (progn
469 (org-beginning-of-item)
470 (setq curr-ind (org-get-indentation))
471 (setq next-ind curr-ind)
c8d0cf5c
CD
472 (while (and (bolp) (org-at-item-p)
473 (if recursive
474 (<= curr-ind next-ind)
475 (= curr-ind next-ind)))
33306645
CD
476 (save-excursion (end-of-line) (setq eline (point)))
477 (if (re-search-forward re-box eline t)
47ffc456
CD
478 (if (member (match-string 2) '("[ ]" "[-]"))
479 (setq c-off (1+ c-off))
c8d0cf5c
CD
480 (setq c-on (1+ c-on))))
481 (if (not recursive)
482 (org-end-of-item)
483 (end-of-line)
484 (when (re-search-forward org-list-beginning-re lim t)
485 (beginning-of-line)))
486 (setq next-ind (org-get-indentation)))))
47ffc456 487 (goto-char continue-from)
33306645 488 ;; update cookie
47ffc456
CD
489 (when end-cookie
490 (delete-region beg-cookie end-cookie)
491 (goto-char beg-cookie)
492 (insert
493 (if is-percent
494 (format "[%d%%]" (/ (* 100 c-on) (max 1 (+ c-on c-off))))
495 (format "[%d/%d]" c-on (+ c-on c-off)))))
33306645
CD
496 ;; update items checkbox if it has one
497 (when (org-at-item-p)
498 (org-beginning-of-item)
499 (when (and (> (+ c-on c-off) 0)
47ffc456 500 (re-search-forward re-box (point-at-eol) t))
33306645
CD
501 (setq beg-cookie (match-beginning 2)
502 end-cookie (match-end 2))
503 (delete-region beg-cookie end-cookie)
504 (goto-char beg-cookie)
505 (cond ((= c-off 0) (insert "[X]"))
506 ((= c-on 0) (insert "[ ]"))
507 (t (insert "[-]")))
508 )))
47ffc456
CD
509 (goto-char continue-from))
510 (when (interactive-p)
33306645 511 (message "Checkbox statistics updated %s (%d places)"
47ffc456
CD
512 (if all "in entire file" "in current outline entry") cstat)))))
513
514(defun org-get-checkbox-statistics-face ()
515 "Select the face for checkbox statistics.
516The face will be `org-done' when all relevant boxes are checked. Otherwise
517it will be `org-todo'."
518 (if (match-end 1)
c8d0cf5c
CD
519 (if (equal (match-string 1) "100%")
520 'org-checkbox-statistics-done
521 'org-checkbox-statistics-todo)
47ffc456
CD
522 (if (and (> (match-end 2) (match-beginning 2))
523 (equal (match-string 2) (match-string 3)))
c8d0cf5c
CD
524 'org-checkbox-statistics-done
525 'org-checkbox-statistics-todo)))
47ffc456
CD
526
527(defun org-beginning-of-item ()
528 "Go to the beginning of the current hand-formatted item.
529If the cursor is not in an item, throw an error."
530 (interactive)
531 (let ((pos (point))
532 (limit (save-excursion
533 (condition-case nil
534 (progn
535 (org-back-to-heading)
536 (beginning-of-line 2) (point))
537 (error (point-min)))))
538 (ind-empty (if org-empty-line-terminates-plain-lists 0 10000))
539 ind ind1)
540 (if (org-at-item-p)
541 (beginning-of-line 1)
542 (beginning-of-line 1)
543 (skip-chars-forward " \t")
544 (setq ind (current-column))
545 (if (catch 'exit
546 (while t
547 (beginning-of-line 0)
548 (if (or (bobp) (< (point) limit)) (throw 'exit nil))
549
550 (if (looking-at "[ \t]*$")
551 (setq ind1 ind-empty)
552 (skip-chars-forward " \t")
553 (setq ind1 (current-column)))
554 (if (< ind1 ind)
555 (progn (beginning-of-line 1) (throw 'exit (org-at-item-p))))))
556 nil
557 (goto-char pos)
558 (error "Not in an item")))))
559
560(defun org-end-of-item ()
561 "Go to the end of the current hand-formatted item.
562If the cursor is not in an item, throw an error."
563 (interactive)
564 (let* ((pos (point))
565 ind1
566 (ind-empty (if org-empty-line-terminates-plain-lists 0 10000))
567 (limit (save-excursion (outline-next-heading) (point)))
568 (ind (save-excursion
569 (org-beginning-of-item)
570 (skip-chars-forward " \t")
571 (current-column)))
572 (end (catch 'exit
573 (while t
574 (beginning-of-line 2)
575 (if (eobp) (throw 'exit (point)))
576 (if (>= (point) limit) (throw 'exit (point-at-bol)))
577 (if (looking-at "[ \t]*$")
578 (setq ind1 ind-empty)
579 (skip-chars-forward " \t")
580 (setq ind1 (current-column)))
581 (if (<= ind1 ind)
582 (throw 'exit (point-at-bol)))))))
583 (if end
584 (goto-char end)
585 (goto-char pos)
586 (error "Not in an item"))))
587
588(defun org-next-item ()
589 "Move to the beginning of the next item in the current plain list.
590Error if not at a plain list, or if this is the last item in the list."
591 (interactive)
592 (let (ind ind1 (pos (point)))
593 (org-beginning-of-item)
594 (setq ind (org-get-indentation))
595 (org-end-of-item)
596 (setq ind1 (org-get-indentation))
597 (unless (and (org-at-item-p) (= ind ind1))
598 (goto-char pos)
599 (error "On last item"))))
600
601(defun org-previous-item ()
602 "Move to the beginning of the previous item in the current plain list.
603Error if not at a plain list, or if this is the first item in the list."
604 (interactive)
605 (let (beg ind ind1 (pos (point)))
606 (org-beginning-of-item)
607 (setq beg (point))
608 (setq ind (org-get-indentation))
609 (goto-char beg)
610 (catch 'exit
611 (while t
612 (beginning-of-line 0)
613 (if (looking-at "[ \t]*$")
614 nil
615 (if (<= (setq ind1 (org-get-indentation)) ind)
616 (throw 'exit t)))))
617 (condition-case nil
618 (if (or (not (org-at-item-p))
619 (< ind1 (1- ind)))
620 (error "")
621 (org-beginning-of-item))
622 (error (goto-char pos)
623 (error "On first item")))))
624
625(defun org-first-list-item-p ()
c8d0cf5c 626 "Is this heading the first item in a plain list?"
47ffc456
CD
627 (unless (org-at-item-p)
628 (error "Not at a plain list item"))
c8d0cf5c
CD
629 (save-excursion
630 (org-beginning-of-item)
631 (= (point) (save-excursion (org-beginning-of-item-list)))))
47ffc456
CD
632
633(defun org-move-item-down ()
634 "Move the plain list item at point down, i.e. swap with following item.
635Subitems (items with larger indentation) are considered part of the item,
636so this really moves item trees."
637 (interactive)
638 (let ((col (current-column))
639 (pos (point))
640 beg beg0 end end0 ind ind1 txt ne-end ne-beg)
641 (org-beginning-of-item)
642 (setq beg0 (point))
643 (save-excursion
644 (setq ne-beg (org-back-over-empty-lines))
645 (setq beg (point)))
646 (goto-char beg0)
647 (setq ind (org-get-indentation))
648 (org-end-of-item)
649 (setq end0 (point))
650 (setq ind1 (org-get-indentation))
651 (setq ne-end (org-back-over-empty-lines))
652 (setq end (point))
653 (goto-char beg0)
654 (when (and (org-first-list-item-p) (< ne-end ne-beg))
655 ;; include less whitespace
656 (save-excursion
657 (goto-char beg)
658 (forward-line (- ne-beg ne-end))
659 (setq beg (point))))
660 (goto-char end0)
661 (if (and (org-at-item-p) (= ind ind1))
662 (progn
663 (org-end-of-item)
664 (org-back-over-empty-lines)
665 (setq txt (buffer-substring beg end))
666 (save-excursion
667 (delete-region beg end))
668 (setq pos (point))
669 (insert txt)
670 (goto-char pos) (org-skip-whitespace)
671 (org-maybe-renumber-ordered-list)
672 (move-to-column col))
673 (goto-char pos)
674 (move-to-column col)
675 (error "Cannot move this item further down"))))
676
677(defun org-move-item-up (arg)
678 "Move the plain list item at point up, i.e. swap with previous item.
679Subitems (items with larger indentation) are considered part of the item,
680so this really moves item trees."
681 (interactive "p")
682 (let ((col (current-column)) (pos (point))
683 beg beg0 end ind ind1 txt
684 ne-beg ne-ins ins-end)
685 (org-beginning-of-item)
686 (setq beg0 (point))
687 (setq ind (org-get-indentation))
688 (save-excursion
689 (setq ne-beg (org-back-over-empty-lines))
690 (setq beg (point)))
691 (goto-char beg0)
692 (org-end-of-item)
693 (org-back-over-empty-lines)
694 (setq end (point))
695 (goto-char beg0)
696 (catch 'exit
697 (while t
698 (beginning-of-line 0)
699 (if (looking-at "[ \t]*$")
700 (if org-empty-line-terminates-plain-lists
701 (progn
702 (goto-char pos)
703 (error "Cannot move this item further up"))
704 nil)
705 (if (<= (setq ind1 (org-get-indentation)) ind)
706 (throw 'exit t)))))
707 (condition-case nil
708 (org-beginning-of-item)
709 (error (goto-char beg0)
710 (move-to-column col)
711 (error "Cannot move this item further up")))
712 (setq ind1 (org-get-indentation))
713 (if (and (org-at-item-p) (= ind ind1))
714 (progn
715 (setq ne-ins (org-back-over-empty-lines))
716 (setq txt (buffer-substring beg end))
717 (save-excursion
718 (delete-region beg end))
719 (setq pos (point))
720 (insert txt)
721 (setq ins-end (point))
722 (goto-char pos) (org-skip-whitespace)
723
724 (when (and (org-first-list-item-p) (> ne-ins ne-beg))
725 ;; Move whitespace back to beginning
726 (save-excursion
727 (goto-char ins-end)
728 (let ((kill-whole-line t))
729 (kill-line (- ne-ins ne-beg)) (point)))
730 (insert (make-string (- ne-ins ne-beg) ?\n)))
731
732 (org-maybe-renumber-ordered-list)
733 (move-to-column col))
734 (goto-char pos)
735 (move-to-column col)
736 (error "Cannot move this item further up"))))
737
738(defun org-maybe-renumber-ordered-list ()
739 "Renumber the ordered list at point if setup allows it.
740This tests the user option `org-auto-renumber-ordered-lists' before
741doing the renumbering."
742 (interactive)
743 (when (and org-auto-renumber-ordered-lists
744 (org-at-item-p))
745 (if (match-beginning 3)
746 (org-renumber-ordered-list 1)
747 (org-fix-bullet-type))))
748
749(defun org-maybe-renumber-ordered-list-safe ()
750 (condition-case nil
751 (save-excursion
752 (org-maybe-renumber-ordered-list))
753 (error nil)))
754
755(defun org-cycle-list-bullet (&optional which)
756 "Cycle through the different itemize/enumerate bullets.
757This cycle the entire list level through the sequence:
758
33306645 759 `-' -> `+' -> `*' -> `1.' -> `1)'
47ffc456
CD
760
761If WHICH is a string, use that as the new bullet. If WHICH is an integer,
33306645 7620 means `-', 1 means `+' etc."
47ffc456
CD
763 (interactive "P")
764 (org-preserve-lc
765 (org-beginning-of-item-list)
766 (org-at-item-p)
767 (beginning-of-line 1)
768 (let ((current (match-string 0))
769 (prevp (eq which 'previous))
ce4fdcb9 770 new old)
47ffc456
CD
771 (setq new (cond
772 ((and (numberp which)
773 (nth (1- which) '("-" "+" "*" "1." "1)"))))
774 ((string-match "-" current) (if prevp "1)" "+"))
775 ((string-match "\\+" current)
776 (if prevp "-" (if (looking-at "\\S-") "1." "*")))
777 ((string-match "\\*" current) (if prevp "+" "1."))
ce4fdcb9
CD
778 ((string-match "\\." current)
779 (if prevp (if (looking-at "\\S-") "+" "*") "1)"))
47ffc456
CD
780 ((string-match ")" current) (if prevp "1." "-"))
781 (t (error "This should not happen"))))
ce4fdcb9
CD
782 (and (looking-at "\\([ \t]*\\)\\(\\S-+\\)")
783 (setq old (match-string 2))
784 (replace-match (concat "\\1" new)))
785 (org-shift-item-indentation (- (length new) (length old)))
47ffc456
CD
786 (org-fix-bullet-type)
787 (org-maybe-renumber-ordered-list))))
788
789(defun org-get-string-indentation (s)
790 "What indentation has S due to SPACE and TAB at the beginning of the string?"
791 (let ((n -1) (i 0) (w tab-width) c)
792 (catch 'exit
793 (while (< (setq n (1+ n)) (length s))
794 (setq c (aref s n))
795 (cond ((= c ?\ ) (setq i (1+ i)))
796 ((= c ?\t) (setq i (* (/ (+ w i) w) w)))
797 (t (throw 'exit t)))))
798 i))
799
800(defun org-renumber-ordered-list (arg)
801 "Renumber an ordered plain list.
802Cursor needs to be in the first line of an item, the line that starts
803with something like \"1.\" or \"2)\"."
804 (interactive "p")
805 (unless (and (org-at-item-p)
806 (match-beginning 3))
807 (error "This is not an ordered list"))
808 (let ((line (org-current-line))
809 (col (current-column))
810 (ind (org-get-string-indentation
811 (buffer-substring (point-at-bol) (match-beginning 3))))
812 ;; (term (substring (match-string 3) -1))
813 ind1 (n (1- arg))
ce4fdcb9 814 fmt bobp old new)
47ffc456
CD
815 ;; find where this list begins
816 (org-beginning-of-item-list)
817 (setq bobp (bobp))
818 (looking-at "[ \t]*[0-9]+\\([.)]\\)")
c8d0cf5c 819 (setq fmt (concat "%d" (or (match-string 1) ".")))
47ffc456
CD
820 (beginning-of-line 0)
821 ;; walk forward and replace these numbers
822 (catch 'exit
823 (while t
824 (catch 'next
825 (if bobp (setq bobp nil) (beginning-of-line 2))
826 (if (eobp) (throw 'exit nil))
827 (if (looking-at "[ \t]*$") (throw 'next nil))
828 (skip-chars-forward " \t") (setq ind1 (current-column))
829 (if (> ind1 ind) (throw 'next t))
830 (if (< ind1 ind) (throw 'exit t))
831 (if (not (org-at-item-p)) (throw 'exit nil))
ce4fdcb9 832 (setq old (match-string 2))
47ffc456
CD
833 (delete-region (match-beginning 2) (match-end 2))
834 (goto-char (match-beginning 2))
ce4fdcb9
CD
835 (insert (setq new (format fmt (setq n (1+ n)))))
836 (org-shift-item-indentation (- (length new) (length old))))))
47ffc456
CD
837 (goto-line line)
838 (org-move-to-column col)))
839
c8d0cf5c 840(defun org-fix-bullet-type (&optional force-bullet)
ce4fdcb9
CD
841 "Make sure all items in this list have the same bullet as the first item.
842Also, fix the indentation."
47ffc456
CD
843 (interactive)
844 (unless (org-at-item-p) (error "This is not a list"))
845 (let ((line (org-current-line))
846 (col (current-column))
847 (ind (current-indentation))
ce4fdcb9 848 ind1 bullet oldbullet)
47ffc456
CD
849 ;; find where this list begins
850 (org-beginning-of-item-list)
851 (beginning-of-line 1)
852 ;; find out what the bullet type is
853 (looking-at "[ \t]*\\(\\S-+\\)")
c8d0cf5c 854 (setq bullet (concat (or force-bullet (match-string 1)) " "))
ce4fdcb9
CD
855 (if (and org-list-two-spaces-after-bullet-regexp
856 (string-match org-list-two-spaces-after-bullet-regexp bullet))
857 (setq bullet (concat bullet " ")))
47ffc456
CD
858 ;; walk forward and replace these numbers
859 (beginning-of-line 0)
860 (catch 'exit
861 (while t
862 (catch 'next
863 (beginning-of-line 2)
864 (if (eobp) (throw 'exit nil))
865 (if (looking-at "[ \t]*$") (throw 'next nil))
866 (skip-chars-forward " \t") (setq ind1 (current-column))
867 (if (> ind1 ind) (throw 'next t))
868 (if (< ind1 ind) (throw 'exit t))
869 (if (not (org-at-item-p)) (throw 'exit nil))
870 (skip-chars-forward " \t")
ce4fdcb9
CD
871 (looking-at "\\S-+ *")
872 (setq oldbullet (match-string 0))
c8d0cf5c 873 (unless (equal bullet oldbullet) (replace-match bullet))
ce4fdcb9 874 (org-shift-item-indentation (- (length bullet) (length oldbullet))))))
47ffc456
CD
875 (goto-line line)
876 (org-move-to-column col)
877 (if (string-match "[0-9]" bullet)
878 (org-renumber-ordered-list 1))))
879
ce4fdcb9
CD
880(defun org-shift-item-indentation (delta)
881 "Shift the indentation in current item by DELTA."
882 (save-excursion
883 (let ((beg (point-at-bol))
884 (end (progn (org-end-of-item) (point)))
885 i)
886 (goto-char end)
887 (beginning-of-line 0)
888 (while (> (point) beg)
889 (when (looking-at "[ \t]*\\S-")
890 ;; this is not an empty line
891 (setq i (org-get-indentation))
892 (if (and (> i 0) (> (setq i (+ i delta)) 0))
893 (indent-line-to i)))
894 (beginning-of-line 0)))))
895
47ffc456
CD
896(defun org-beginning-of-item-list ()
897 "Go to the beginning of the current item list.
898I.e. to the first item in this list."
899 (interactive)
900 (org-beginning-of-item)
901 (let ((pos (point-at-bol))
33306645 902 (ind (org-get-indentation))
47ffc456
CD
903 ind1)
904 ;; find where this list begins
905 (catch 'exit
906 (while t
907 (catch 'next
908 (beginning-of-line 0)
909 (if (looking-at "[ \t]*$")
910 (throw (if (bobp) 'exit 'next) t))
911 (skip-chars-forward " \t") (setq ind1 (current-column))
912 (if (or (< ind1 ind)
913 (and (= ind1 ind)
914 (not (org-at-item-p)))
915 (and (= (point-at-bol) (point-min))
916 (setq pos (point-min))))
917 (throw 'exit t)
918 (when (org-at-item-p) (setq pos (point-at-bol)))))))
919 (goto-char pos)))
920
47ffc456
CD
921(defun org-end-of-item-list ()
922 "Go to the end of the current item list.
923I.e. to the text after the last item."
924 (interactive)
925 (org-beginning-of-item)
926 (let ((pos (point-at-bol))
33306645 927 (ind (org-get-indentation))
47ffc456
CD
928 ind1)
929 ;; find where this list begins
930 (catch 'exit
931 (while t
932 (catch 'next
933 (beginning-of-line 2)
934 (if (looking-at "[ \t]*$")
c8d0cf5c
CD
935 (if (eobp)
936 (progn (setq pos (point)) (throw 'exit t))
937 (throw 'next t)))
47ffc456
CD
938 (skip-chars-forward " \t") (setq ind1 (current-column))
939 (if (or (< ind1 ind)
940 (and (= ind1 ind)
941 (not (org-at-item-p)))
942 (eobp))
943 (progn
944 (setq pos (point-at-bol))
945 (throw 'exit t))))))
946 (goto-char pos)))
947
948
949(defvar org-last-indent-begin-marker (make-marker))
950(defvar org-last-indent-end-marker (make-marker))
951
952(defun org-outdent-item (arg)
953 "Outdent a local list item."
954 (interactive "p")
955 (org-indent-item (- arg)))
956
957(defun org-indent-item (arg)
958 "Indent a local list item."
959 (interactive "p")
c8d0cf5c 960 (and (org-region-active-p) (org-cursor-to-region-beginning))
47ffc456
CD
961 (unless (org-at-item-p)
962 (error "Not on an item"))
c8d0cf5c
CD
963 (let (beg end ind ind1 ind-bul delta ind-down ind-up firstp)
964 (setq firstp (org-first-list-item-p))
965 (save-excursion
966 (setq end (and (org-region-active-p) (region-end)))
47ffc456
CD
967 (if (memq last-command '(org-shiftmetaright org-shiftmetaleft))
968 (setq beg org-last-indent-begin-marker
969 end org-last-indent-end-marker)
970 (org-beginning-of-item)
971 (setq beg (move-marker org-last-indent-begin-marker (point)))
972 (org-end-of-item)
c8d0cf5c 973 (setq end (move-marker org-last-indent-end-marker (or end (point)))))
47ffc456 974 (goto-char beg)
c8d0cf5c
CD
975 (setq ind-bul (org-item-indent-positions)
976 ind (caar ind-bul)
977 ind-down (car (nth 2 ind-bul))
978 ind-up (car (nth 1 ind-bul))
47ffc456
CD
979 delta (if (> arg 0)
980 (if ind-down (- ind-down ind) 2)
981 (if ind-up (- ind-up ind) -2)))
982 (if (< (+ delta ind) 0) (error "Cannot outdent beyond margin"))
983 (while (< (point) end)
984 (beginning-of-line 1)
985 (skip-chars-forward " \t") (setq ind1 (current-column))
986 (delete-region (point-at-bol) (point))
987 (or (eolp) (org-indent-to-column (+ ind1 delta)))
c8d0cf5c
CD
988 (beginning-of-line 2)))
989 (org-fix-bullet-type
990 (and (> arg 0)
991 (not firstp)
992 (cdr (assoc (cdr (nth 0 ind-bul)) org-list-demote-modify-bullet))))
993 (org-maybe-renumber-ordered-list-safe)
994 (save-excursion
995 (beginning-of-line 0)
996 (condition-case nil (org-beginning-of-item) (error nil))
997 (org-maybe-renumber-ordered-list-safe))))
47ffc456
CD
998
999(defun org-item-indent-positions ()
1000 "Return indentation for plain list items.
33306645
CD
1001This returns a list with three values: The current indentation, the
1002parent indentation and the indentation a child should have.
47ffc456
CD
1003Assumes cursor in item line."
1004 (let* ((bolpos (point-at-bol))
1005 (ind (org-get-indentation))
c8d0cf5c
CD
1006 (bullet (org-get-bullet))
1007 ind-down ind-up bullet-up bullet-down pos)
47ffc456
CD
1008 (save-excursion
1009 (org-beginning-of-item-list)
1010 (skip-chars-backward "\n\r \t")
1011 (when (org-in-item-p)
1012 (org-beginning-of-item)
c8d0cf5c
CD
1013 (setq ind-up (org-get-indentation))
1014 (setq bullet-up (org-get-bullet))))
47ffc456
CD
1015 (setq pos (point))
1016 (save-excursion
1017 (cond
1018 ((and (condition-case nil (progn (org-previous-item) t)
1019 (error nil))
1020 (or (forward-char 1) t)
1021 (re-search-forward "^\\([ \t]*\\([-+]\\|\\([0-9]+[.)]\\)\\)\\|[ \t]+\\*\\)\\( \\|$\\)" bolpos t))
c8d0cf5c
CD
1022 (setq ind-down (org-get-indentation)
1023 bullet-down (org-get-bullet)))
47ffc456
CD
1024 ((and (goto-char pos)
1025 (org-at-item-p))
1026 (goto-char (match-end 0))
1027 (skip-chars-forward " \t")
c8d0cf5c
CD
1028 (setq ind-down (current-column)
1029 bullet-down (org-get-bullet)))))
1030 (if (and bullet-down (string-match "\\`[0-9]+\\(\\.\\|)\\)\\'" bullet-down))
1031 (setq bullet-down (concat "1" (match-string 1 bullet-down))))
1032 (if (and bullet-up (string-match "\\`[0-9]+\\(\\.\\|)\\)\\'" bullet-up))
1033 (setq bullet-up (concat "1" (match-string 1 bullet-up))))
1034 (if (and bullet (string-match "\\`[0-9]+\\(\\.\\|)\\)\\'" bullet))
1035 (setq bullet (concat "1" (match-string 1 bullet))))
1036 (list (cons ind bullet)
1037 (cons ind-up bullet-up)
1038 (cons ind-down bullet-down))))
1039
1040(defun org-get-bullet ()
1041 (save-excursion
1042 (goto-char (point-at-bol))
1043 (and (looking-at
1044 "^\\([ \t]*\\([-+]\\|\\([0-9]+[.)]\\)\\)\\|[ \t]+\\(\\*\\)\\)\\( \\|$\\)")
1045 (or (match-string 2) (match-string 4)))))
47ffc456
CD
1046
1047;;; Send and receive lists
1048
1049(defun org-list-parse-list (&optional delete)
1050 "Parse the list at point and maybe DELETE it.
1051Return a list containing first level items as strings and
1052sublevels as a list of strings."
1053 (let* ((item-beginning (org-list-item-beginning))
33306645
CD
1054 (start (car item-beginning))
1055 (end (org-list-end (cdr item-beginning)))
1056 output itemsep ltype)
47ffc456
CD
1057 (while (re-search-forward org-list-beginning-re end t)
1058 (goto-char (match-beginning 3))
1059 (save-match-data
33306645
CD
1060 (cond ((string-match "[0-9]" (match-string 2))
1061 (setq itemsep "[0-9]+\\(?:\\.\\|)\\)"
1062 ltype 'ordered))
1063 ((string-match "^.*::" (match-string 0))
1064 (setq itemsep "[-+]" ltype 'descriptive))
1065 (t (setq itemsep "[-+]" ltype 'unordered))))
47ffc456
CD
1066 (let* ((indent1 (match-string 1))
1067 (nextitem (save-excursion
1068 (save-match-data
1069 (or (and (re-search-forward
1070 (concat "^" indent1 itemsep " *?") end t)
1071 (match-beginning 0)) end))))
1072 (item (buffer-substring
1073 (point)
1074 (or (and (re-search-forward
1075 org-list-beginning-re end t)
1076 (goto-char (match-beginning 0)))
1077 (goto-char end))))
1078 (nextindent (match-string 1))
1079 (item (org-trim item))
0bd48b37
CD
1080 (item (if (string-match "^\\[\\([xX ]\\)\\]" item)
1081 (replace-match (if (equal (match-string 1 item) " ")
1082 "[CBOFF]"
1083 "[CBON]")
1084 t nil item)
1085 item)))
47ffc456
CD
1086 (push item output)
1087 (when (> (length nextindent)
1088 (length indent1))
1089 (narrow-to-region (point) nextitem)
1090 (push (org-list-parse-list) output)
1091 (widen))))
1092 (when delete (delete-region start end))
1093 (setq output (nreverse output))
1094 (push ltype output)))
1095
1096(defun org-list-item-beginning ()
1097 "Find the beginning of the list item.
1098Return a cons which car is the beginning position of the item and
1099cdr is the indentation string."
1100 (save-excursion
1101 (if (not (or (looking-at org-list-beginning-re)
1102 (re-search-backward
1103 org-list-beginning-re nil t)))
1104 (progn (goto-char (point-min)) (point))
1105 (cons (match-beginning 0) (match-string 1)))))
1106
c8d0cf5c
CD
1107(defun org-list-goto-true-beginning ()
1108 "Go to the beginning of the list at point."
1109 (beginning-of-line 1)
1110 (while (looking-at org-list-beginning-re)
1111 (beginning-of-line 0))
1112 (progn
1113 (re-search-forward org-list-beginning-re nil t)
1114 (goto-char (match-beginning 0))))
1115
1116(defun org-list-make-subtree ()
1117 "Convert the plain list at point into a subtree."
1118 (interactive)
1119 (org-list-goto-true-beginning)
1120 (let ((list (org-list-parse-list t)) nstars)
1121 (save-excursion
1122 (if (condition-case nil
1123 (org-back-to-heading)
1124 (error nil))
1125 (progn (re-search-forward org-complex-heading-regexp nil t)
1126 (setq nstars (length (match-string 1))))
1127 (setq nstars 0)))
1128 (org-list-make-subtrees list (1+ nstars))))
1129
1130(defun org-list-make-subtrees (list level)
1131 "Convert LIST into subtrees starting at LEVEL."
1132 (if (symbolp (car list))
1133 (org-list-make-subtrees (cdr list) level)
1134 (mapcar (lambda (item)
1135 (if (stringp item)
1136 (insert (make-string
1137 (if org-odd-levels-only
1138 (1- (* 2 level)) level) ?*) " " item "\n")
1139 (org-list-make-subtrees item (1+ level))))
1140 list)))
1141
47ffc456
CD
1142(defun org-list-end (indent)
1143 "Return the position of the end of the list.
c8d0cf5c 1144INDENT is the indentation of the list, as a string."
47ffc456
CD
1145 (save-excursion
1146 (catch 'exit
1147 (while (or (looking-at org-list-beginning-re)
c8d0cf5c
CD
1148 (looking-at (concat "^" indent "[ \t]+\\|^$"))
1149 (> (or (get-text-property (point) 'original-indentation) -1)
1150 (length indent)))
47ffc456
CD
1151 (if (eq (point) (point-max))
1152 (throw 'exit (point-max)))
c8d0cf5c
CD
1153 (forward-line 1)))
1154 (point)))
47ffc456
CD
1155
1156(defun org-list-insert-radio-list ()
1157 "Insert a radio list template appropriate for this major mode."
1158 (interactive)
1159 (let* ((e (assq major-mode org-list-radio-list-templates))
1160 (txt (nth 1 e))
1161 name pos)
1162 (unless e (error "No radio list setup defined for %s" major-mode))
1163 (setq name (read-string "List name: "))
1164 (while (string-match "%n" txt)
1165 (setq txt (replace-match name t t txt)))
1166 (or (bolp) (insert "\n"))
1167 (setq pos (point))
1168 (insert txt)
1169 (goto-char pos)))
1170
1171(defun org-list-send-list (&optional maybe)
1172 "Send a tranformed version of this list to the receiver position.
1173With argument MAYBE, fail quietly if no transformation is defined for
1174this list."
1175 (interactive)
1176 (catch 'exit
1177 (unless (org-at-item-p) (error "Not at a list"))
1178 (save-excursion
c8d0cf5c 1179 (org-list-goto-true-beginning)
47ffc456
CD
1180 (beginning-of-line 0)
1181 (unless (looking-at "#\\+ORGLST: *SEND +\\([a-zA-Z0-9_]+\\) +\\([^ \t\r\n]+\\)\\( +.*\\)?")
1182 (if maybe
1183 (throw 'exit nil)
1184 (error "Don't know how to transform this list"))))
1185 (let* ((name (match-string 1))
33306645 1186 (item-beginning (org-list-item-beginning))
47ffc456
CD
1187 (transform (intern (match-string 2)))
1188 (txt (buffer-substring-no-properties
33306645 1189 (car item-beginning)
47ffc456
CD
1190 (org-list-end (cdr item-beginning))))
1191 (list (org-list-parse-list))
33306645 1192 beg)
47ffc456
CD
1193 (unless (fboundp transform)
1194 (error "No such transformation function %s" transform))
1195 (setq txt (funcall transform list))
1196 ;; Find the insertion place
1197 (save-excursion
1198 (goto-char (point-min))
1199 (unless (re-search-forward
1200 (concat "BEGIN RECEIVE ORGLST +" name "\\([ \t]\\|$\\)") nil t)
1201 (error "Don't know where to insert translated list"))
1202 (goto-char (match-beginning 0))
1203 (beginning-of-line 2)
1204 (setq beg (point))
1205 (unless (re-search-forward (concat "END RECEIVE ORGLST +" name) nil t)
1206 (error "Cannot find end of insertion region"))
1207 (beginning-of-line 1)
1208 (delete-region beg (point))
1209 (goto-char beg)
1210 (insert txt "\n"))
1211 (message "List converted and installed at receiver location"))))
1212
1213(defun org-list-to-generic (list params)
1214 "Convert a LIST parsed through `org-list-parse-list' to other formats.
1215
1216Valid parameters PARAMS are
1217
33306645
CD
1218:ustart String to start an unordered list
1219:uend String to end an unordered list
47ffc456 1220
33306645
CD
1221:ostart String to start an ordered list
1222:oend String to end an ordered list
47ffc456 1223
33306645
CD
1224:dstart String to start a descriptive list
1225:dend String to end a descriptive list
47ffc456 1226:dtstart String to start a descriptive term
33306645 1227:dtend String to end a descriptive term
47ffc456 1228:ddstart String to start a description
33306645 1229:ddend String to end a description
47ffc456 1230
33306645
CD
1231:splice When set to t, return only list body lines, don't wrap
1232 them into :[u/o]start and :[u/o]end. Default is nil.
47ffc456 1233
33306645
CD
1234:istart String to start a list item
1235:iend String to end a list item
1236:isep String to separate items
0bd48b37
CD
1237:lsep String to separate sublists
1238
1239:cboff String to insert for an unchecked checkbox
1240:cbon String to insert for a checked checkbox"
47ffc456
CD
1241 (interactive)
1242 (let* ((p params) sublist
1243 (splicep (plist-get p :splice))
1244 (ostart (plist-get p :ostart))
33306645 1245 (oend (plist-get p :oend))
47ffc456 1246 (ustart (plist-get p :ustart))
33306645 1247 (uend (plist-get p :uend))
47ffc456 1248 (dstart (plist-get p :dstart))
33306645 1249 (dend (plist-get p :dend))
47ffc456 1250 (dtstart (plist-get p :dtstart))
33306645 1251 (dtend (plist-get p :dtend))
47ffc456 1252 (ddstart (plist-get p :ddstart))
33306645 1253 (ddend (plist-get p :ddend))
47ffc456 1254 (istart (plist-get p :istart))
33306645
CD
1255 (iend (plist-get p :iend))
1256 (isep (plist-get p :isep))
0bd48b37
CD
1257 (lsep (plist-get p :lsep))
1258 (cbon (plist-get p :cbon))
1259 (cboff (plist-get p :cboff)))
47ffc456
CD
1260 (let ((wrapper
1261 (cond ((eq (car list) 'ordered)
1262 (concat ostart "\n%s" oend "\n"))
1263 ((eq (car list) 'unordered)
1264 (concat ustart "\n%s" uend "\n"))
1265 ((eq (car list) 'descriptive)
1266 (concat dstart "\n%s" dend "\n"))))
1267 rtn term defstart defend)
1268 (while (setq sublist (pop list))
1269 (cond ((symbolp sublist) nil)
1270 ((stringp sublist)
33306645
CD
1271 (when (string-match "^\\(.*\\) ::" sublist)
1272 (setq term (org-trim (format (concat dtstart "%s" dtend)
1273 (match-string 1 sublist))))
1274 (setq sublist (substring sublist (1+ (length term)))))
0bd48b37
CD
1275 (if (string-match "\\[CBON\\]" sublist)
1276 (setq sublist (replace-match cbon t t sublist)))
1277 (if (string-match "\\[CBOFF\\]" sublist)
1278 (setq sublist (replace-match cboff t t sublist)))
33306645
CD
1279 (setq rtn (concat rtn istart term ddstart
1280 sublist ddend iend isep)))
1281 (t (setq rtn (concat rtn ;; previous list
1282 lsep ;; list separator
1283 (org-list-to-generic sublist p)
1284 lsep ;; list separator
1285 )))))
47ffc456
CD
1286 (format wrapper rtn))))
1287
0bd48b37
CD
1288(defun org-list-to-latex (list &optional params)
1289 "Convert LIST into a LaTeX list.
1290LIST is as returnd by `org-list-parse-list'. PARAMS is a property list
1291with overruling parameters for `org-list-to-generic'."
47ffc456 1292 (org-list-to-generic
0bd48b37
CD
1293 list
1294 (org-combine-plists
1295 '(:splicep nil :ostart "\\begin{enumerate}" :oend "\\end{enumerate}"
1296 :ustart "\\begin{itemize}" :uend "\\end{itemize}"
1297 :dstart "\\begin{description}" :dend "\\end{description}"
1298 :dtstart "[" :dtend "]"
1299 :ddstart "" :ddend ""
1300 :istart "\\item " :iend ""
1301 :isep "\n" :lsep "\n"
1302 :cbon "\\texttt{[X]}" :cboff "\\texttt{[ ]}")
1303 params)))
1304
1305(defun org-list-to-html (list &optional params)
1306 "Convert LIST into a HTML list.
1307LIST is as returnd by `org-list-parse-list'. PARAMS is a property list
1308with overruling parameters for `org-list-to-generic'."
47ffc456 1309 (org-list-to-generic
0bd48b37
CD
1310 list
1311 (org-combine-plists
1312 '(:splicep nil :ostart "<ol>" :oend "</ol>"
1313 :ustart "<ul>" :uend "</ul>"
1314 :dstart "<dl>" :dend "</dl>"
1315 :dtstart "<dt>" :dtend "</dt>"
1316 :ddstart "<dd>" :ddend "</dd>"
1317 :istart "<li>" :iend "</li>"
1318 :isep "\n" :lsep "\n"
1319 :cbon "<code>[X]</code>" :cboff "<code>[ ]</code>")
1320 params)))
1321
1322(defun org-list-to-texinfo (list &optional params)
1323 "Convert LIST into a Texinfo list.
1324LIST is as returnd by `org-list-parse-list'. PARAMS is a property list
1325with overruling parameters for `org-list-to-generic'."
47ffc456 1326 (org-list-to-generic
c8d0cf5c 1327 list
0bd48b37
CD
1328 (org-combine-plists
1329 '(:splicep nil :ostart "@itemize @minus" :oend "@end itemize"
1330 :ustart "@enumerate" :uend "@end enumerate"
1331 :dstart "@table" :dend "@end table"
1332 :dtstart "@item " :dtend "\n"
1333 :ddstart "" :ddend ""
1334 :istart "@item\n" :iend ""
1335 :isep "\n" :lsep "\n"
1336 :cbon "@code{[X]}" :cboff "@code{[ ]}")
1337 params)))
47ffc456
CD
1338
1339(provide 'org-list)
1340
3048977d 1341;; arch-tag: 73cf50c1-200f-4d1d-8a53-4e842a5b11c8
47ffc456 1342;;; org-list.el ends here