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