]> code.delx.au - gnu-emacs/blob - lisp/textmodes/org.el
(flyspell-auto-correct-binding, flyspell-incorrect-face)
[gnu-emacs] / lisp / textmodes / org.el
1 ;; org.el --- Outline-based notes management and organizer
2 ;; Carstens outline-mode for keeping track of everything.
3 ;; Copyright (c) 2004, 2005 Free Software Foundation
4 ;;
5 ;; Author: Carsten Dominik <dominik at science dot uva dot nl>
6 ;; Keywords: outlines, hypermedia, calendar
7 ;; Homepage: http://www.astro.uva.nl/~dominik/Tools/org/
8 ;; Version: 3.10
9 ;;
10 ;; This file is part of GNU Emacs.
11 ;;
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
26 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
27 ;;
28 ;;; Commentary:
29 ;;
30 ;; Org-mode is a mode for keeping notes, maintaining ToDo lists, and doing
31 ;; project planning with a fast and effective plain-text system.
32 ;;
33 ;; Org-mode develops organizational tasks around a NOTES file that contains
34 ;; information about projects as plain text. Org-mode is implemented on top
35 ;; of outline-mode - ideal to keep the content of large files well structured.
36 ;; It supports ToDo items, deadlines and time stamps, which can be extracted
37 ;; to create a daily/weekly agenda that also integrates the diary of the Emacs
38 ;; calendar. Tables are easily created with a built-in table editor. Plain
39 ;; text URL-like links connect to websites, emails (VM, RMAIL, WANDERLUST),
40 ;; Usenet messages (Gnus), BBDB entries, and any files related to the
41 ;; projects. For printing and sharing of notes, an Org-mode file (or a part
42 ;; of it) can be exported as a structured ASCII file, or as HTML.
43 ;;
44 ;; Installation
45 ;; ------------
46 ;; If Org-mode is part of the Emacs distribution or an XEmacs package, you
47 ;; only need to copy the following lines to your .emacs file. The last two
48 ;; lines define *global* keys for the commands `org-store-link' and
49 ;; `org-agenda' - please choose suitable keys yourself.
50 ;;
51 ;; (add-to-list 'auto-mode-alist '("\\.org$" . org-mode))
52 ;; (define-key global-map "\C-cl" 'org-store-link)
53 ;; (define-key global-map "\C-ca" 'org-agenda)
54 ;;
55 ;; If you have downloaded Org-mode from the Web, you must byte-compile
56 ;; org.el and put it on your load path. In addition to the Emacs Lisp
57 ;; lines above, you also need to add the following lines to .emacs:
58 ;;
59 ;; (autoload 'org-mode "org" "Org mode" t)
60 ;; (autoload 'org-diary "org" "Diary entries from Org mode")
61 ;; (autoload 'org-agenda "org" "Multi-file agenda from Org mode" t)
62 ;; (autoload 'org-store-link "org" "Store a link to the current location" t)
63 ;; (autoload 'orgtbl-mode "org" "Org tables as a minor mode" t)
64 ;; (autoload 'turn-on-orgtbl "org" "Org tables as a minor mode")
65 ;;
66 ;; This setup will put all files with extension ".org" into Org-mode. As
67 ;; an alternative, make the first line of a file look like this:
68 ;;
69 ;; MY PROJECTS -*- mode: org; -*-
70 ;;
71 ;; which will select Org-mode for this buffer no matter what the file's
72 ;; name is.
73 ;;
74 ;; Documentation
75 ;; -------------
76 ;; The documentation of Org-mode can be found in the TeXInfo file. The
77 ;; distribution also contains a PDF version of it. At the homepage of
78 ;; Org-mode, you can read the same text online as HTML. There is also an
79 ;; excellent reference card made by Philip Rooke.
80 ;;
81 ;; Changes:
82 ;; -------
83 ;; Version 3.10
84 ;; - Using `define-derived-mode' to derive `org-mode' from `outline-mode'.
85 ;;
86 ;; Version 3.09
87 ;; - Time-of-day specifications in agenda are extracted and placed
88 ;; into the prefix. Timed entries can be placed into a time grid for
89 ;; day.
90 ;;
91 ;; Version 3.08
92 ;; - "|" no longer allowed as part of a link, to allow links in tables.
93 ;; - The prefix of items in the agenda buffer can be configured.
94 ;; - Cleanup.
95 ;;
96 ;; Version 3.07
97 ;; - Some folding incinsistencies removed.
98 ;; - BBDB links to company-only entries.
99 ;; - Bug fixes and global cleanup.
100 ;;
101 ;; Version 3.06
102 ;; - M-S-RET inserts a new TODO heading.
103 ;; - New startup option `content'.
104 ;; - Better visual response when TODO items in agenda change status.
105 ;; - Window positioning after visibility state changes optimized and made
106 ;; configurable. See `org-cycle-hook' and `org-occur-hook'.
107 ;;
108 ;; Version 3.05
109 ;; - Agenda entries from the diary are linked to the diary file, so
110 ;; adding and editing diary entries can be done directly from the agenda.
111 ;; - Many calendar/diary commands available directly from agenda.
112 ;; - Field copying in tables with S-RET does increment.
113 ;; - C-c C-x C-v extracts the visible part of the buffer for printing.
114 ;; - Moving subtrees up and down preserves the whitespace at the tree end.
115 ;;
116 ;; Version 3.04
117 ;; - Table editor optimized to need fewer realignments, and to keep
118 ;; table shape when typing in fields.
119 ;; - A new minor mode, orgtbl-mode, introduces the Org-mode table editor
120 ;; into arbitrary major modes.
121 ;; - Fixed bug with realignment in XEmacs.
122 ;; - Startup options can be set with special #+STARTUP line.
123 ;; - Heading following a match in org-occur can be suppressed.
124 ;;
125 ;; Version 3.03
126 ;; - Copyright transfer to the FSF.
127 ;; - Effect of C-u and C-u C-u in org-timeline swapped.
128 ;; - Timeline now always contains today, and `.' jumps to it.
129 ;; - Table editor:
130 ;; - cut and paste of rectangular regions in tables
131 ;; - command to convert org-mode table to table.el table and back
132 ;; - command to treat several cells like a paragraph and fill it
133 ;; - command to convert a buffer region to a table
134 ;; - import/export tables as tab-separated files (exchange with Excel)
135 ;; - Agenda:
136 ;; - Sorting mechanism for agenda items rewritten from scratch.
137 ;; - Sorting fully configurable.
138 ;; - Entries specifying a time are sorted together.
139 ;; - Completion also covers option keywords after `#-'.
140 ;; - Bug fixes.
141 ;;
142 ;; Version 3.01
143 ;; - New reference card, thanks to Philip Rooke for creating it.
144 ;; - Single file agenda renamed to "Timeline". It no longer shows
145 ;; warnings about upcoming deadlines/overdue scheduled items.
146 ;; That functionality is now limited to the (multifile) agenda.
147 ;; - When reading a date, the calendar can be manipulated with keys.
148 ;; - Link support for RMAIL and Wanderlust (from planner.el, untested).
149 ;; - Minor bug fixes and documentation improvements.
150
151 ;;; Code:
152
153 (eval-when-compile (require 'cl) (require 'calendar))
154 (require 'outline)
155 (require 'time-date)
156 (require 'easymenu)
157 (or (fboundp 'run-mode-hooks)
158 (defalias 'run-mode-hooks 'run-hooks))
159
160 ;;; Customization variables
161
162 (defvar org-version "3.10"
163 "The version number of the file org.el.")
164 (defun org-version ()
165 (interactive)
166 (message "Org-mode version %s" org-version))
167
168 ;; The following two constants are for compatibility with different Emacs
169 ;; versions (Emacs versus XEmacs) and with different versions of outline.el.
170 ;; The compatibility code in org.el is based on these two constants.
171 (defconst org-xemacs-p (featurep 'xemacs)
172 "Are we running xemacs?")
173 (defconst org-noutline-p (featurep 'noutline)
174 "Are we using the new outline mode?")
175
176 (defgroup org nil
177 "Outline-based notes management and organizer "
178 :tag "Org"
179 :group 'outlines
180 :group 'hypermedia
181 :group 'calendar)
182
183 (defgroup org-startup nil
184 "Options concerning startup of Org-mode."
185 :tag "Org Startup"
186 :group 'org)
187
188 (defcustom org-startup-folded t
189 "Non-nil means, entering Org-mode will switch to OVERVIEW.
190 This can also be configured on a per-file basis by adding one of
191 the following lines anywhere in the buffer:
192
193 #+STARTUP: fold
194 #+STARTUP: nofold
195 #+STARTUP: content"
196 :group 'org-startup
197 :type '(choice
198 (const :tag "nofold: show all" nil)
199 (const :tag "fold: overview" t)
200 (const :tag "content: all headlines" content)))
201
202 (defcustom org-startup-truncated t
203 "Non-nil means, entering Org-mode will set `truncate-lines'.
204 This is useful since some lines containing links can be very long and
205 uninteresting. Also tables look terrible when wrapped."
206 :group 'org-startup
207 :type 'boolean)
208
209 (defcustom org-startup-with-deadline-check nil
210 "Non-nil means, entering Org-mode will run the deadline check.
211 This means, if you start editing an org file, you will get an
212 immediate reminder of any due deadlines.
213 This can also be configured on a per-file basis by adding one of
214 the following lines anywhere in the buffer:
215
216 #+STARTUP: dlcheck
217 #+STARTUP: nodlcheck"
218 :group 'org-startup
219 :type 'boolean)
220
221 (defcustom org-insert-mode-line-in-empty-file nil
222 "Non-nil means insert the first line setting Org-mode in empty files.
223 When the function `org-mode' is called interactively in an empty file, this
224 normally means that the file name does not automatically trigger Org-mode.
225 To ensure that the file will always be in Org-mode in the future, a
226 line enforcing Org-mode will be inserted into the buffer, if this option
227 has been set."
228 :group 'org-startup
229 :type 'boolean)
230
231 (defgroup org-keywords nil
232 "Options concerning TODO items in Org-mode."
233 :tag "Org Keywords"
234 :group 'org)
235
236 (defcustom org-todo-keywords '("TODO" "DONE")
237 "List of TODO entry keywords.
238 \\<org-mode-map>By default, this is '(\"TODO\" \"DONE\"). The last entry in the list is
239 considered to mean that the entry is \"done\". All the other mean that
240 action is required, and will make the entry show up in todo lists, diaries
241 etc.
242 The command \\[org-todo] cycles an entry through these states, and an
243 additional state where no keyword is present. For details about this
244 cycling, see also the variable `org-todo-interpretation'
245 Changes become only effective after restarting Emacs."
246 :group 'org-keywords
247 :type '(repeat (string :tag "Keyword")))
248
249 (defcustom org-todo-interpretation 'sequence
250 "Controls how TODO keywords are interpreted.
251 \\<org-mode-map>Possible values are `sequence' and `type'.
252 This variable is only relevant if `org-todo-keywords' contains more than two
253 states. There are two ways how these keywords can be used:
254
255 - As a sequence in the process of working on a TODO item, for example
256 (setq org-todo-keywords '(\"TODO\" \"STARTED\" \"VERIFY\" \"DONE\")
257 org-todo-interpretation 'sequence)
258
259 - As different types of TODO items, for example
260 (setq org-todo-keywords '(\"URGENT\" \"RELAXED\" \"REMIND\" \"FOR_TOM\" \"DONE\")
261 org-todo-interpretation 'type)
262
263 When the states are interpreted as a sequence, \\[org-todo] always cycles
264 to the next state, in order to walk through all different states. So with
265 \\[org-todo], you turn an empty entry into the state TODO. When you started
266 working on the item, you use \\[org-todo] again to switch it to \"STARTED\",
267 later to VERIFY and finally to DONE.
268
269 When the states are interpreted as types, \\[org-todo] still cycles through
270 when it is called several times in direct succession, in order to initially
271 select the type. However, if not called immediately after a previous
272 \\[org-todo], it switches from each type directly to DONE. So with the
273 above example, you could use `\\[org-todo] \\[org-todo]' to label an entry
274 RELAXED. If you later return to this entry and press \\[org-todo] again,
275 RELAXED will not be changed REMIND, but directly to DONE.
276
277 You can create a large number of types. To initially select a
278 type, it is then best to use \\[universal-argument] \\[org-todo] in order to specify the
279 type with completion. Of course, you can also type the keyword
280 directly into the buffer. M-TAB completes TODO keywords at the
281 beginning of a headline."
282 :group 'org-keywords
283 :type '(choice (const sequence)
284 (const type)))
285
286 (defcustom org-default-priority ?B
287 "The default priority of TODO items.
288 This is the priority an item get if no explicit priority is given."
289 :group 'org-keywords
290 :type 'character)
291
292 (defcustom org-lowest-priority ?C
293 "The lowest priority of TODO items. A character like ?A, ?B etc."
294 :group 'org-keywords
295 :type 'character)
296
297 (defcustom org-deadline-string "DEADLINE:"
298 "String to mark deadline entries.
299 A deadline is this string, followed by a time stamp. Should be a word,
300 terminated by a colon. You can insert a schedule keyword and
301 a timestamp with \\[org-deadline].
302 Changes become only effective after restarting Emacs."
303 :group 'org-keywords
304 :type 'string)
305
306 (defcustom org-scheduled-string "SCHEDULED:"
307 "String to mark scheduled TODO entries.
308 A schedule is this string, followed by a time stamp. Should be a word,
309 terminated by a colon. You can insert a schedule keyword and
310 a timestamp with \\[org-schedule].
311 Changes become only effective after restarting Emacs."
312 :group 'org-keywords
313 :type 'string)
314
315 (defcustom org-comment-string "COMMENT"
316 "Entries starting with this keyword will never be exported.
317 An entry can be toggled between COMMENT and normal with
318 \\[org-toggle-comment].
319 Changes become only effective after restarting Emacs."
320 :group 'org-keywords
321 :type 'string)
322
323 (defcustom org-after-todo-state-change-hook nil
324 "Hook which is run after the state of a TODO item was changed.
325 The new state (a string with a todo keyword, or nil) is available in the
326 Lisp variable `state'."
327 :group 'org-keywords
328 :type 'hook)
329
330 ;; Variables for pre-computed regular expressions, all buffer local
331 (defvar org-todo-kwd-priority-p nil
332 "Do TODO items have priorities?")
333 (make-variable-buffer-local 'org-todo-kwd-priority-p)
334 (defvar org-todo-kwd-max-priority nil
335 "Maximum priority of TODO items.")
336 (make-variable-buffer-local 'org-todo-kwd-max-priority)
337 (defvar org-ds-keyword-length 12
338 "Maximum length of the Deadline and SCHEDULED keywords.")
339 (make-variable-buffer-local 'org-ds-keyword-length)
340 (defvar org-done-string nil
341 "The last string in `org-todo-keywords', indicating an item is DONE.")
342 (make-variable-buffer-local 'org-done-string)
343 (defvar org-todo-regexp nil
344 "Matches any of the TODO state keywords.")
345 (make-variable-buffer-local 'org-todo-regexp)
346 (defvar org-not-done-regexp nil
347 "Matches any of the TODO state keywords except the last one.")
348 (make-variable-buffer-local 'org-not-done-regexp)
349 (defvar org-todo-line-regexp nil
350 "Matches a headline and puts TODO state into group 2 if present.")
351 (make-variable-buffer-local 'org-todo-line-regexp)
352 (defvar org-nl-done-regexp nil
353 "Matches newline followed by a headline with the DONE keyword.")
354 (make-variable-buffer-local 'org-nl-done-regexp)
355 (defvar org-looking-at-done-regexp nil
356 "Matches the DONE keyword a point.")
357 (make-variable-buffer-local 'org-looking-at-done-regexp)
358 (defvar org-deadline-regexp nil
359 "Matches the DEADLINE keyword.")
360 (make-variable-buffer-local 'org-deadline-regexp)
361 (defvar org-deadline-time-regexp nil
362 "Matches the DEADLINE keyword together with a time stamp.")
363 (make-variable-buffer-local 'org-deadline-time-regexp)
364 (defvar org-deadline-line-regexp nil
365 "Matches the DEADLINE keyword and the rest of the line.")
366 (make-variable-buffer-local 'org-deadline-line-regexp)
367 (defvar org-scheduled-regexp nil
368 "Matches the SCHEDULED keyword.")
369 (make-variable-buffer-local 'org-scheduled-regexp)
370 (defvar org-scheduled-time-regexp nil
371 "Matches the SCHEDULED keyword together with a time stamp.")
372 (make-variable-buffer-local 'org-scheduled-time-regexp)
373
374 (defvar org-category nil
375 "Variable used by org files to set a category for agenda display.
376 Such files should use a file variable to set it, for example
377
378 -*- mode: org; org-category: \"ELisp\"
379
380 or contain a special line
381
382 #+CATEGORY: ELisp
383
384 If the file does not specify a category, then file's base name
385 is used instead.")
386
387 (defun org-set-regexps-and-options ()
388 "Precompute regular expressions for current buffer."
389 (when (eq major-mode 'org-mode)
390 (let ((re (org-make-options-regexp
391 '("CATEGORY" "SEQ_TODO" "PRI_TODO" "TYP_TODO" "STARTUP")))
392 (splitre "[ \t]+")
393 kwds int key value cat)
394 (save-excursion
395 (save-restriction
396 (widen)
397 (goto-char (point-min))
398 (while (re-search-forward re nil t)
399 (setq key (match-string 1) value (match-string 2))
400 (cond
401 ((equal key "CATEGORY")
402 (if (string-match "[ \t]+$" value)
403 (setq value (replace-match "" t t value)))
404 (setq cat (intern value)))
405 ((equal key "SEQ_TODO")
406 (setq int 'sequence
407 kwds (append kwds (org-split-string value splitre))))
408 ((equal key "PRI_TODO")
409 (setq int 'priority
410 kwds (append kwds (org-split-string value splitre))))
411 ((equal key "TYP_TODO")
412 (setq int 'type
413 kwds (append kwds (org-split-string value splitre))))
414 ((equal key "STARTUP")
415 (let ((opts (org-split-string value splitre))
416 (set '(("fold" org-startup-folded t)
417 ("nofold" org-startup-folded nil)
418 ("content" org-startup-folded content)
419 ("dlcheck" org-startup-with-deadline-check t)
420 ("nodlcheck" org-startup-with-deadline-check nil)))
421 l var val)
422 (while (setq l (assoc (pop opts) set))
423 (setq var (nth 1 l) val (nth 2 l))
424 (set (make-local-variable var) val)))))
425 )))
426 (and cat (set (make-local-variable 'org-category) cat))
427 (and kwds (set (make-local-variable 'org-todo-keywords) kwds))
428 (and int (set (make-local-variable 'org-todo-interpretation) int)))
429 ;; Compute the regular expressions and other local variables
430 (setq org-todo-kwd-priority-p (equal org-todo-interpretation 'priority)
431 org-todo-kwd-max-priority (1- (length org-todo-keywords))
432 org-ds-keyword-length (+ 2 (max (length org-deadline-string)
433 (length org-scheduled-string)))
434 org-done-string
435 (nth (1- (length org-todo-keywords)) org-todo-keywords)
436 org-todo-regexp
437 (concat "\\<\\(" (mapconcat 'regexp-quote org-todo-keywords
438 "\\|") "\\)\\>")
439 org-not-done-regexp
440 (concat "\\<\\("
441 (mapconcat 'regexp-quote
442 (nreverse (cdr (reverse org-todo-keywords)))
443 "\\|")
444 "\\)\\>")
445 org-todo-line-regexp
446 (concat "^\\(\\*+\\)[ \t]*\\("
447 (mapconcat 'regexp-quote org-todo-keywords "\\|")
448 "\\)? *\\(.*\\)")
449 org-nl-done-regexp
450 (concat "[\r\n]\\*+[ \t]+" org-done-string "\\>")
451 org-looking-at-done-regexp (concat "^" org-done-string "\\>")
452 org-deadline-regexp (concat "\\<" org-deadline-string)
453 org-deadline-time-regexp
454 (concat "\\<" org-deadline-string " *<\\([^>]+\\)>")
455 org-deadline-line-regexp
456 (concat "\\<\\(" org-deadline-string "\\).*")
457 org-scheduled-regexp
458 (concat "\\<" org-scheduled-string)
459 org-scheduled-time-regexp
460 (concat "\\<" org-scheduled-string " *<\\([^>]+\\)>"))
461 (org-set-font-lock-defaults)))
462
463 (defgroup org-time nil
464 "Options concerning time stamps and deadlines in Org-mode."
465 :tag "Org Time"
466 :group 'org)
467
468 (defcustom org-deadline-warning-days 30
469 "No. of days before expiration during which a deadline becomes active.
470 This variable governs the display in the org file."
471 :group 'org-time
472 :type 'number)
473
474 (defcustom org-popup-calendar-for-date-prompt t
475 "Non-nil means, pop up a calendar when prompting for a date.
476 In the calendar, the date can be selected with mouse-1. However, the
477 minibuffer will also be active, and you can simply enter the date as well.
478 When nil, only the minibuffer will be available."
479 :group 'org-time
480 :type 'number)
481
482 (defcustom org-calendar-follow-timestamp-change t
483 "Non-nil means, make the calendar window follow timestamp changes.
484 When a timestamp is modified and the calendar window is visible, it will be
485 moved to the new date."
486 :group 'org-time
487 :type 'boolean)
488
489 (defgroup org-agenda nil
490 "Options concerning agenda display Org-mode."
491 :tag "Org Agenda"
492 :group 'org)
493
494 (defcustom org-agenda-files nil
495 "A list of org files for agenda/diary display.
496 Entries are added to this list with \\[org-add-file] and removed with
497 \\[org-remove-file]. You can also use customize to edit the list."
498 :group 'org-agenda
499 :type '(repeat file))
500
501 (defcustom org-select-timeline-window t
502 "Non-nil means, after creating a timeline, move cursor into Timeline window.
503 When nil, cursor will remain in the current window."
504 :group 'org-agenda
505 :type 'boolean)
506
507 (defcustom org-select-agenda-window t
508 "Non-nil means, after creating an agenda, move cursor into Agenda window.
509 When nil, cursor will remain in the current window."
510 :group 'org-agenda
511 :type 'boolean)
512
513 (defcustom org-fit-agenda-window t
514 "Non-nil means, change window size of agenda to fit content."
515 :group 'org-agenda
516 :type 'boolean)
517
518 (defcustom org-agenda-show-all-dates t
519 "Non-nil means, `org-agenda' shows every day in the selected range.
520 When nil, only the days which actually have entries are shown."
521 :group 'org-agenda
522 :type 'boolean)
523
524 ;; FIXME: First day of month works only for current month because it would
525 ;; require a variable ndays treatment.
526 (defcustom org-agenda-start-on-weekday 1
527 "Non-nil means, start the overview always on the specified weekday.
528 0 Denotes Sunday, 1 denotes Monday etc.
529 When nil, always start on the current day."
530 :group 'org-agenda
531 :type '(choice (const :tag "Today" nil)
532 (const :tag "First day of month" t)
533 (number :tag "Weekday No.")))
534
535 (defcustom org-agenda-ndays 7
536 "Number of days to include in overview display."
537 :group 'org-agenda
538 :type 'number)
539
540 (defcustom org-agenda-include-all-todo t
541 "Non-nil means, the agenda will always contain all TODO entries.
542 When nil, date-less entries will only be shown if `org-agenda' is called
543 with a prefix argument.
544 When non-nil, the TODO entries will be listed at the top of the agenda, before
545 the entries for specific days."
546 :group 'org-agenda
547 :type 'boolean)
548
549 (defcustom org-agenda-include-diary nil
550 "If non-nil, include in the agenda entries from the Emacs Calendar's diary."
551 :group 'org-agenda
552 :type 'boolean)
553
554 (defcustom org-calendar-to-agenda-key [?c]
555 "The key to be installed in `calendar-mode-map' for switching to the agenda.
556 The command `org-calendar-goto-agenda' will be bound to this key. The
557 default is the character `c' because then`c' can be used to switch back and
558 force between agenda and calendar."
559 :group 'org-agenda
560 :type 'sexp)
561
562 (defcustom org-agenda-sorting-strategy '(time-up category-keep priority-down)
563 "Sorting structure for the agenda items of a single day.
564 This is a list of symbols which will be used in sequence to determine
565 if an entry should be listed before another entry. The following
566 symbols are recognized.
567
568 time-up Put entries with time-of-day indications first, early first
569 time-down Put entries with time-of-day indications first, late first
570 category-keep Keep the default order of categories, corresponding to the
571 sequence in `org-agenda-files'.
572 category-up Sort alphabetically by category, A-Z.
573 category-down Sort alphabetically by category, Z-A.
574 priority-up Sort numerically by priority, high priority last.
575 priority-down Sort numerically by priority, high priority first.
576
577 The different possibilities will be tried in sequence, and testing stops
578 if one comparison returns a \"not-equal\". For example, the default
579 '(time-up category-keep priority-down)
580 means: Pull out all entries having a specified time of day and sort them,
581 in order to make a time schedule for the current day the first thing in the
582 agenda listing for the day. Of the entries without a time indication, keep
583 the grouped in categories, don't sort the categories, but keep them in
584 the sequence given in `org-agenda-files'. Within each category sort by
585 priority.
586
587 Leaving out `category-keep' would mean that items will be sorted across
588 categories by priority."
589 :group 'org-agenda
590 :type '(repeat
591 (choice
592 (const time-up)
593 (const time-down)
594 (const category-keep)
595 (const category-up)
596 (const category-down)
597 (const priority-up)
598 (const priority-down))))
599
600 (defcustom org-agenda-prefix-format " %-12:c%?-12t% s"
601 "Format specification for the prefix of items in the agenda buffer.
602 This format works similar to a printf format, with the following meaning:
603
604 %c the category of the item, \"Diary\" for entries from the diary, or
605 as given by the CATEGORY keyword or derived from the file name.
606 %t the time-of-day specification if one applies to the entry, in the
607 format HH:MM
608 %s Scheduling/Deadline information, a short string
609
610 All specifiers work basically like the standard `%s' of printf, but may
611 contain two additional characters: A question mark just after the `%' and
612 a whitespace/punctuation character just before the final letter.
613
614 If the first character after `%' is a question mark, the entire field
615 will only be included if the corresponding value applies to the
616 current entry. This is useful for fields which should have fixed
617 width when present, but zero width when absent. For example,
618 \"%?-12t\" will result in a 12 character time field if a time of the
619 day is specified, but will completely disappear in entries which do
620 not contain a time.
621
622 If there is punctuation or whitespace character just before the final
623 format letter, this character will be appended to the field value if
624 the value is not empty. For example, the format \"%-12:c\" leads to
625 \"Diary: \" if the category is \"Diary\". If the category were be
626 empty, no additional colon would be interted.
627
628 The default value of this option is \" %-12:c%?-12t% s\", meaning:
629 - Indent the line with two space characters
630 - Give the category in a 12 chars wide field, padded with whitespace on
631 the right (because of `-'). Append a colon if there is a category
632 (because of `:').
633 - If there is a time-of-day, put it into a 12 chars wide field. If no
634 time, don't put in an empty field, just skip it (because of '?').
635 - Finally, put the scheduling information and append a whitespace.
636
637 As another example, if you don't want the time-of-day of entries in
638 the prefix, you could use:
639
640 (setq org-agenda-prefix-format \" %-11:c% s\")
641
642 See also the variable `org-agenda-remove-times-when-in-prefix'."
643 :type 'string
644 :group 'org-agenda)
645
646 (defcustom org-timeline-prefix-format " % s"
647 "Like `org-agenda-prefix-format', but for the timeline of a single file."
648 :type 'string
649 :group 'org-agenda)
650
651 (defvar org-prefix-format-compiled nil
652 "The compiled version of the most recently used prefix format.
653 Depending on which command was used last, this may be the compiled version
654 of `org-agenda-prefix-format' or `org-timeline-prefix-format'.")
655
656 (defcustom org-agenda-use-time-grid t
657 "Non-nil means, show a time grid in the agenda schedule.
658 A time grid is a set of lines for specific times (like every two hours between
659 8:00 and 20:00. The items scheduled for a day at specific times are
660 sorted in between these lines.
661 For deails about when the grid will be shown, and what it will look like, see
662 the variable `org-agenda-time-grid'."
663 :group 'org-agenda
664 :type 'boolean)
665
666 (defcustom org-agenda-time-grid
667 '((daily today require-timed)
668 "----------------"
669 (800 1000 1200 1400 1600 1800 2000))
670
671 "FIXME: document"
672 :group 'org-agenda
673 :type
674 '(list
675 (set :greedy t :tag "Grid Display Options"
676 (const :tag "Show grid in single day agenda display" daily)
677 (const :tag "Show grid in weekly agenda display" weekly)
678 (const :tag "Always show grid for today" today)
679 (const :tag "Show grid only if any timed entries are present"
680 require-timed)
681 (const :tag "Skip grid times already present in an entry"
682 remove-match))
683 (string :tag "Grid String")
684 (repeat :tag "Grid Times" (integer :tag "Time"))))
685
686 (defcustom org-agenda-remove-times-when-in-prefix t
687 "Non-nil means, remove duplicate time specifications in agenda items.
688 When the format `org-agenda-prefix-format' contains a `%t' specifier, a
689 time-of-day specification in a headline or diary entry is extracted and
690 placed into the prefix. If this option is non-nil, the original specification
691 \(a timestamp or -range, or just a plain time(range) specification like
692 11:30-4pm) will be removed for agenda display. This makes the agenda less
693 cluttered.
694 The option can be t or nil. It may also be the symbol `beg', indicating
695 that the time should only be removed what it is located at the beginning of
696 the headline/diary entry."
697 :group 'org-agenda
698 :type '(choice
699 (const :tag "Always" t)
700 (const :tag "Never" nil)
701 (const :tag "When at beginning of entry" beg)))
702
703 (defcustom org-sort-agenda-notime-is-late t
704 "Non-nil means, items without time are considered late.
705 This is only relevant for sorting. When t, items which have no explicit
706 time like 15:30 will be considered as 24:01, i.e. later than any items which
707 do have a time. When nil, the default time is before 0:00. You can use this
708 option to decide if the schedule for today should come before or after timeless
709 agenda entries."
710 :group 'org-agenda
711 :type 'boolean)
712
713 (defgroup org-structure nil
714 "Options concerning structure editing in Org-mode."
715 :tag "Org Structure"
716 :group 'org)
717
718 (defcustom org-cycle-hook '(org-optimize-window-after-visibility-change)
719 "Hook that is run after `org-cycle' has changed the buffer visibility.
720 The function(s) in this hook must accept a single argument which indicates
721 the new state that was set by the most recent `org-cycle' command. The
722 argument is a symbol. After a global state change, it can have the values
723 `overview', `content', or `all'. After a local state change, it can have
724 the values `folded', `children', or `subtree'."
725 :group 'org-structure
726 :type 'hook)
727
728 (defcustom org-occur-hook '(org-first-headline-recenter)
729 "Hook that is run after `org-occur' has constructed a sparse tree.
730 This can be used to recenter the window to show as much of the structure
731 as possible."
732 :group 'org-structure
733 :type 'hook)
734
735 (defcustom org-adapt-indentation t
736 "Non-nil means, adapt indentation when promoting and demoting.
737 When this is set and the *entire* text in an entry is indented, the
738 indentation is increased by one space in a demotion command, and
739 decreased by one in a promotion command. If any line in the entry
740 body starts at column 0, indentation is not changed at all."
741 :group 'org-structure
742 :type 'boolean)
743
744 (defcustom org-cycle-emulate-tab t
745 "Where should `org-cycle' emulate TAB.
746 nil Never
747 white Only in completely white lines
748 t Everywhere except in headlines"
749 :group 'org-structure
750 :type '(choice (const :tag "Never" nil)
751 (const :tag "Only in completely white lines" white)
752 (const :tag "Everywhere except in headlines" t)
753 ))
754
755 (defconst org-time-stamp-formats '("<%Y-%m-%d %a>" . "<%Y-%m-%d %a %H:%M>")
756 "Formats for `format-time-string' which are used for time stamps.
757 It is not recommended to change this constant.")
758
759 (defcustom org-show-following-heading t
760 "Non-nil means, show heading following match in `org-occur'.
761 When doing an `org-occur' it is useful to show the headline which
762 follows the match, even if they do not match the regexp. This makes it
763 easier to edit directly inside the sparse tree. However, if you use
764 org-occur mainly as an overview, the following headlines are
765 unnecessary clutter."
766 :group 'org-structure
767 :type 'boolean)
768
769
770 (defgroup org-link nil
771 "Options concerning links in Org-mode."
772 :tag "Org Link"
773 :group 'org)
774
775 (defcustom org-allow-space-in-links t
776 "Non-nil means, file names in links may contain space characters.
777 When nil, it becomes possible to put several links into a line.
778 Note that in tables, a link never extends accross fields, so in a table
779 it is always possible to put several links into a line.
780 Changing this varable requires a re-launch of Emacs of become effective."
781 :group 'org-link
782 :type 'boolean)
783
784 (defcustom org-line-numbers-in-file-links t
785 "Non-nil means, file links from `org-store-link' contain line numbers.
786 The line number will be added to the file name with :NNN and interpreted
787 by the command `org-open-at-point'.
788 Using a prefix arg to the command \\[org-store-link] (`org-store-link')
789 negates this setting for the duration of the command."
790 :group 'org-link
791 :type 'boolean)
792
793 (defcustom org-keep-stored-link-after-insertion nil
794 "Non-nil means, keep link in list for entire session.
795
796 The command `org-store-link' adds a link pointing to the current
797 location to an internal list. These links accumulate during a session.
798 The command `org-insert-link' can be used to insert links into any
799 Org-mode file (offering completion for all stored links). When this
800 option is nil, every link which has been inserted once using \\[org-insert-link]
801 will be removed from the list, to make completing the unused links
802 more efficient."
803 :group 'org-link
804 :type 'boolean)
805
806 (defcustom org-link-frame-setup
807 '((vm . vm-visit-folder-other-frame)
808 (gnus . gnus-other-frame)
809 (file . find-file-other-window))
810 "Setup the frame configuration for following links.
811 When following a link with Emacs, it may often be useful to display
812 this link in another window or frame. This variable can be used to
813 set this up for the different types of links.
814 For VM, use any of
815 `vm-visit-folder'
816 `vm-visit-folder-other-frame'
817 For Gnus, use any of
818 `gnus'
819 `gnus-other-frame'
820 For FILE, use any of
821 `find-file'
822 `find-file-other-window'
823 `find-file-other-frame'
824 For the calendar, use the variable `calendar-setup'.
825 For BBDB, it is currently only possible to display the matches in
826 another window."
827 :group 'org-link
828 :type '(list
829 (cons (const vm)
830 (choice
831 (const vm-visit-folder)
832 (const vm-visit-folder-other-window)
833 (const vm-visit-folder-other-frame)))
834 (cons (const gnus)
835 (choice
836 (const gnus)
837 (const gnus-other-frame)))
838 (cons (const file)
839 (choice
840 (const find-file)
841 (const find-file-other-window)
842 (const find-file-other-frame)))))
843
844 (defcustom org-usenet-links-prefer-google nil
845 "Non-nil means, `org-store-link' will create web links to google groups.
846 When nil, Gnus will be used for such links.
847 Using a prefix arg to the command \\[org-store-link] (`org-store-link')
848 negates this setting for the duration of the command."
849 :group 'org-link
850 :type 'boolean)
851
852 (defcustom org-open-non-existing-files nil
853 "Non-nil means, `org-open-file' will open non-existing file.
854 When nil, an error will be generated."
855 :group 'org-link
856 :type 'boolean)
857
858 (defcustom org-confirm-shell-links t
859 "Non-nil means, ask for confirmation before executing shell links.
860 The default is true, to keep new users from shooting into their own foot."
861 :group 'org-link
862 :type 'boolean)
863
864 (defconst org-file-apps-defaults-linux
865 '((t . emacs)
866 ("jpg" . "xv %s")
867 ("gif" . "xv %s")
868 ("ppm" . "xv %s")
869 ("pgm" . "xv %s")
870 ("pbm" . "xv %s")
871 ("tif" . "xv %s")
872 ("png" . "xv %s")
873 ("ps" . "gv %s")
874 ("ps.gz" . "gv %s")
875 ("eps" . "gv %s")
876 ("eps.gz" . "gv %s")
877 ("dvi" . "xdvi %s")
878 ("mpeg" . "plaympeg %s")
879 ("mp3" . "plaympeg %s")
880 ("fig" . "xfig %s")
881 ("pdf" . "acroread %s")
882 ("doc" . "soffice %s")
883 ("ppt" . "soffice %s")
884 ("pps" . "soffice %s")
885 ("html" . "netscape -remote openURL(%s,new-window)")
886 ("htm" . "netscape -remote openURL(%s,new-window)")
887 ("xs" . "soffice %s"))
888 "Default file applications on a UNIX/LINUX system.
889 See `org-file-apps'.")
890
891 (defconst org-file-apps-defaults-macosx
892 '((t . "open %s")
893 ("ps" . "gv %s")
894 ("ps.gz" . "gv %s")
895 ("eps" . "gv %s")
896 ("eps.gz" . "gv %s")
897 ("dvi" . "xdvi %s")
898 ("fig" . "xfig %s"))
899 "Default file applications on a MacOS X system.
900 The system \"open\" is known as a default, but we use X11 applications
901 for some files for which the OS does not have a good default.
902 See `org-file-apps'.")
903
904 (defconst org-file-apps-defaults-windowsnt
905 '((t . (w32-shell-execute "open" file)))
906 "Default file applications on a Windows NT system.
907 The system \"open\" is used for most files.
908 See `org-file-apps'.")
909
910 (defcustom org-file-apps
911 '(
912 ("txt" . emacs)
913 ("tex" . emacs)
914 ("ltx" . emacs)
915 ("org" . emacs)
916 ("el" . emacs)
917 )
918 "External applications for opening `file:path' items in a document.
919 Org-mode uses system defaults for different file types, but
920 you can use this variable to set the application for a given file
921 extension. The entries in this list are cons cells with a file extension
922 and the corresponding command. Possible values for the command are:
923 `emacs' The file will be visited by the current Emacs process.
924 `default' Use the default application for this file type.
925 string A command to be executed by a shell; %s will be replaced
926 by the path to the file.
927 sexp A Lisp form which will be evaluated. The file path will
928 be available in the Lisp variable `file'.
929 For more examples, see the system specific constants
930 `org-file-apps-defaults-macosx'
931 `org-file-apps-defaults-windowsnt'
932 `org-file-apps-defaults-linux'."
933 :group 'org-link
934 :type '(repeat
935 (cons (string :tag "Extension")
936 (choice :value ""
937 (const :tag "Visit with Emacs" 'emacs)
938 (const :tag "Use system default" 'default)
939 (string :tag "Command")
940 (sexp :tag "Lisp form")))))
941
942
943 (defgroup org-remember nil
944 "Options concerning interaction with remember.el."
945 :tag "Org Remember"
946 :group 'org)
947
948 (defcustom org-directory "~/org"
949 "Directory with org files.
950 This directory will be used as default to prompt for org files.
951 Used by the hooks for remember.el."
952 :group 'org-remember
953 :type 'directory)
954
955 (defcustom org-default-notes-file "~/.notes"
956 "Default target for storing notes.
957 Used by the hooks for remember.el. This can be a string, or nil to mean
958 the value of `remember-data-file'."
959 :group 'org-remember
960 :type '(choice
961 (const :tag "Default from remember-data-file" nil)
962 file))
963
964 (defcustom org-reverse-note-order nil
965 "Non-nil means, store new notes at the beginning of a file or entry.
966 When nil, new notes will be filed to the end of a file or entry."
967 :group 'org-remember
968 :type '(choice
969 (const :tag "Reverse always" t)
970 (const :tag "Reverse never" nil)
971 (repeat :tag "By file name regexp"
972 (cons regexp boolean))))
973
974 (defgroup org-table nil
975 "Options concerning tables in Org-mode."
976 :tag "Org Table"
977 :group 'org)
978
979 (defcustom org-enable-table-editor 'optimized
980 "Non-nil means, lines starting with \"|\" are handled by the table editor.
981 When nil, such lines will be treated like ordinary lines.
982
983 When equal to the symbol `optimized', the table editor will be optimized to
984 do the following
985 - Use automatic overwrite mode in front of whitespace in table fields.
986 This make the structure of the table stay in tact as long as the edited
987 field does not exceed the column width.
988 - Minimize the number of realigns. Normally, the table is aligned each time
989 TAB or RET are pressed to move to another field. With optimization this
990 happens only if changes to a field might have changed the column width.
991 Optimization requires replacing the functions `self-insert-command',
992 `delete-char', and `backward-delete-char' in Org-mode buffers, with a
993 slight (in fact: unnoticeable) speed impact for normal typing. Org-mode is
994 very good at guessing when a re-align will be necessary, but you can always
995 force one with `C-c C-c'.
996
997 If you would like to use the optimized version in Org-mode, but the
998 un-optimized version in OrgTbl-mode, see the variable `orgtbl-optimized'.
999
1000 This variable can be used to turn on and off the table editor during a session,
1001 but in order to toggle optimization, a restart is required."
1002 :group 'org-table
1003 :type '(choice
1004 (const :tag "off" nil)
1005 (const :tag "on" t)
1006 (const :tag "on, optimized" optimized)))
1007
1008 (defcustom org-table-default-size "5x2"
1009 "The default size for newly created tables, Columns x Rows."
1010 :group 'org-table
1011 :type 'string)
1012
1013 (defcustom org-table-automatic-realign t
1014 "Non-nil means, automatically re-align table when pressing TAB or RETURN.
1015 When nil, aligning is only done with \\[org-table-align], or after column
1016 removal/insertion."
1017 :group 'org-table
1018 :type 'boolean)
1019
1020 (defcustom org-table-spaces-around-separators '(1 . 1)
1021 "The number of spaces to be placed before and after separators."
1022 :group 'org-table
1023 :type '(cons (number :tag "Before \"|\"") (number :tag " After \"|\"")))
1024
1025 (defcustom org-table-spaces-around-invisible-separators '(1 . 2)
1026 "The number of spaces to be placed before and after separators.
1027 This option applies when the column separators have been made invisible."
1028 :group 'org-table
1029 :type '(cons (number :tag "Before \"|\"") (number :tag " After \"|\"")))
1030
1031 (defcustom org-table-number-regexp "^[<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%]*$"
1032 "Regular expression for recognizing numbers in table columns.
1033 If a table column contains mostly numbers, it will be aligned to the
1034 right. If not, it will be aligned to the left.
1035
1036 The default value of this option is a regular expression which allows
1037 anything which looks remotely like a number as used in scientific
1038 context. For example, all of the following will be considered a
1039 number:
1040 12 12.2 2.4e-08 2x10^12 4.034+-0.02 2.7(10) >3.5
1041
1042 Other options offered by the customize interface are more restrictive."
1043 :group 'org-table
1044 :type '(choice
1045 (const :tag "Positive Integers"
1046 "^[0-9]+$")
1047 (const :tag "Integers"
1048 "^[-+]?[0-9]+$")
1049 (const :tag "Floating Point Numbers"
1050 "^[-+]?\\([0-9]*\\.[0-9]+\\|[0-9]+\\.[0-9]*\\)$")
1051 (const :tag "Floating Point Number or Integer"
1052 "^[-+]?\\([0-9]*\\.[0-9]+\\|[0-9]+\\.?[0-9]*\\)$")
1053 (const :tag "Exponential, Floating point, Integer"
1054 "^[-+]?[0-9.]+\\([eEdD][-+0-9]+\\)?$")
1055 (const :tag "Very General Number-Like"
1056 "^[<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%]*$")
1057 (string :tag "Regexp:")))
1058
1059 (defcustom org-table-number-fraction 0.5
1060 "Fraction of numbers in a column required to make the column align right.
1061 In a column all non-white fields are considered. If at least this
1062 fraction of fields is matched by `org-table-number-fraction',
1063 alignment to the right border applies."
1064 :group 'org-table
1065 :type 'number)
1066
1067 (defcustom org-export-highlight-first-table-line t
1068 "Non-nil means, highlight the first table line.
1069 In HTML export, this means use <th> instead of <td>.
1070 In tables created with table.el, this applies to the first table line.
1071 In Org-mode tables, all lines before the first horizontal separator
1072 line will be formatted with <th> tags."
1073 :group 'org-table
1074 :type 'boolean)
1075
1076 (defcustom org-table-copy-increment t
1077 "Non-nil means, increment when copying current field with \\[org-table-copy-down]."
1078 :group 'org-table
1079 :type 'boolean)
1080
1081 (defcustom org-table-tab-recognizes-table.el t
1082 "Non-nil means, TAB will automatically notice a table.el table.
1083 When it sees such a table, it moves point into it and - if necessary -
1084 calls `table-recognize-table'."
1085 :group 'org-table
1086 :type 'boolean)
1087
1088 (defcustom org-export-prefer-native-exporter-for-tables nil
1089 "Non-nil means, always export tables created with table.el natively.
1090 Natively means, use the HTML code generator in table.el.
1091 When nil, Org-mode's own HTML generator is used when possible (i.e. if
1092 the table does not use row- or column-spanning). This has the
1093 advantage, that the automatic HTML conversions for math symbols and
1094 sub/superscripts can be applied. Org-mode's HTML generator is also
1095 much faster."
1096 :group 'org-table
1097 :type 'boolean)
1098
1099 (defcustom org-enable-fixed-width-editor t
1100 "Non-nil means, lines starting with \":\" are treated as fixed-width.
1101 This currently only means, they are never auto-wrapped.
1102 When nil, such lines will be treated like ordinary lines."
1103 :group 'org-table
1104 :type 'boolean)
1105
1106 (defgroup org-export nil
1107 "Options for exporting org-listings."
1108 :tag "Org Export"
1109 :group 'org)
1110
1111 (defcustom org-export-language-setup
1112 '(("en" "Author" "Date" "Table of Contents")
1113 ("da" "Ophavsmand" "Dato" "Indhold")
1114 ("de" "Autor" "Datum" "Inhaltsverzeichnis")
1115 ("es" "Autor" "Fecha" "\xccndice")
1116 ("fr" "Auteur" "Date" "Table des Mati\xe8res")
1117 ("it" "Autore" "Data" "Indice")
1118 ("nl" "Auteur" "Datum" "Inhoudsopgave")
1119 ("nn" "Forfattar" "Dato" "Innhold") ;; nn = Norsk (nynorsk)
1120 ("sv" "F\xf6rfattarens" "Datum" "Inneh\xe5ll"))
1121 "Terms used in export text, translated to different languages.
1122 Use the variable `org-export-default-language' to set the language,
1123 or use the +OPTION lines for a per-file setting."
1124 :group 'org-export
1125 :type '(repeat
1126 (list
1127 (string :tag "HTML language tag")
1128 (string :tag "Author")
1129 (string :tag "Date")
1130 (string :tag "Table of Contents"))))
1131
1132 (defcustom org-export-default-language "en"
1133 "The default language of HTML export, as a string.
1134 This should have an association in `org-export-language-setup'"
1135 :group 'org-export
1136 :type 'string)
1137
1138 (defcustom org-export-headline-levels 3
1139 "The last level which is still exported as a headline.
1140 Inferior levels will produce itemize lists when exported.
1141 Note that a numeric prefix argument to an exporter function overrides
1142 this setting.
1143
1144 This option can also be set with the +OPTIONS line, e.g. \"H:2\"."
1145 :group 'org-export
1146 :type 'number)
1147
1148 (defcustom org-export-with-section-numbers t
1149 "Non-nil means, add section numbers to headlines when exporting.
1150
1151 This option can also be set with the +OPTIONS line, e.g. \"num:t\"."
1152 :group 'org-export
1153 :type 'boolean)
1154
1155 (defcustom org-export-with-toc t
1156 "Non-nil means, create a table of contents in exported files.
1157 The TOC contains headlines with levels up to`org-export-headline-levels'.
1158
1159 Headlines which contain any TODO items will be marked with \"(*)\" in
1160 ASCII export, and with red color in HTML output.
1161
1162 In HTML output, the TOC will be clickable.
1163
1164 This option can also be set with the +OPTIONS line, e.g. \"toc:nil\"."
1165 :group 'org-export
1166 :type 'boolean)
1167
1168 (defcustom org-export-preserve-breaks nil
1169 "Non-nil means, preserve all line breaks when exporting.
1170 Normally, in HTML output paragraphs will be reformatted. In ASCII
1171 export, line breaks will always be preserved, regardless of this variable.
1172
1173 This option can also be set with the +OPTIONS line, e.g. \"\\n:t\"."
1174 :group 'org-export
1175 :type 'boolean)
1176
1177 (defcustom org-export-html-inline-images t
1178 "Non-nil means, inline images into exported HTML pages.
1179 The link will still be to the original location of the image file.
1180 So if you are moving the page, lets say to your public HTML site,
1181 you will have to move the image and maybe change the link."
1182 :group 'org-export
1183 :type 'boolean)
1184
1185 (defcustom org-export-html-expand t
1186 "Non-nil means, for HTML export, treat @<...> as HTML tag.
1187 When nil, these tags will be exported as plain text and therefore
1188 not be interpreted by a browser.
1189
1190 This option can also be set with the +OPTIONS line, e.g. \"@:nil\"."
1191 :group 'org-export
1192 :type 'boolean)
1193
1194 (defcustom org-export-with-fixed-width t
1195 "Non-nil means, lines starting with \":\" will be in fixed width font.
1196 This can be used to have pre-formatted text, fragments of code etc. For
1197 example
1198 : ;; Some Lisp examples
1199 : (while (defc cnt)
1200 : (ding))
1201 will be looking just like this in also HTML. In ASCII export, this option
1202 has no effect.
1203
1204 This option can also be set with the +OPTIONS line, e.g. \"::nil\"."
1205 :group 'org-export
1206 :type 'boolean)
1207
1208 (defcustom org-export-with-tables t
1209 "If non-nil, lines starting with \"|\" define a table.
1210 For example:
1211
1212 | Name | Address | Birthday |
1213 |-------------+----------+-----------|
1214 | Arthur Dent | England | 29.2.2100 |
1215
1216 In ASCII export, this option has no effect.
1217
1218 This option can also be set with the +OPTIONS line, e.g. \"|:nil\"."
1219 :group 'org-export
1220 :type 'boolean)
1221
1222 (defcustom org-export-html-table-tag
1223 "<table border=1 cellspacing=0 cellpadding=6>"
1224 "The HTML tag used to start a table.
1225 This must be a <table> tag, but you may change the options like
1226 borders and spacing."
1227 :group 'org-export
1228 :type 'string)
1229
1230 (defcustom org-export-with-emphasize t
1231 "Non-nil means, interpret *word*, /word/, and _word_ as emphasized text.
1232 If the export target supports emphasizing text, the word will be
1233 typeset in bold, italic, or underlined, respectively. Works only for
1234 single words, but you can say: I *really* *mean* *this*.
1235 In ASCII export, this option has no effect.
1236
1237 This option can also be set with the +OPTIONS line, e.g. \"*:nil\"."
1238 :group 'org-export
1239 :type 'boolean)
1240
1241 (defcustom org-match-sexp-depth 3
1242 "Number of stacked braces for sub/superscript matching.
1243 This has to be set before loading org.el to be effective."
1244 :group 'org-export
1245 :type 'integer)
1246
1247 ;; FIXME: Should () parens be removed as well in sub/superscripts?
1248 (defcustom org-export-with-sub-superscripts t
1249 "Non-nil means, interpret \"_\" and \"^\" for export.
1250 When this option is turned on, you can use TeX-like syntax for sub- and
1251 superscripts. Several characters after \"_\" or \"^\" will be
1252 considered as a single item - so grouping with {} is normally not
1253 needed. For example, the following things will be parsed as single
1254 sub- or superscripts.
1255
1256 10^24 or 10^tau several digits will be considered 1 item
1257 10^-12 or 10^-tau a leading sign with digits or a word
1258 x^2-y^3 will be read as x^2 - y^3, because items are
1259 terminated by almost any nonword/nondigit char.
1260 x_{i^2} or x^(2-i) braces or parenthesis do grouping.
1261
1262 Still, ambiguity is possible - so when in doubt use {} to enclose the
1263 sub/superscript.
1264 In ASCII export, this option has no effect.
1265
1266 This option can also be set with the +OPTIONS line, e.g. \"^:nil\"."
1267 :group 'org-export
1268 :type 'boolean)
1269
1270 (defcustom org-export-with-TeX-macros t
1271 "Non-nil means, interpret simple TeX-like macros when exporting.
1272 For example, HTML export converts \\alpha to &alpha; and \\AA to &Aring;.
1273 No only real TeX macros will work here, but the standard HTML entities
1274 for math can be used as macro names as well. For a list of supported
1275 names in HTML export, see the constant `org-html-entities'.
1276 In ASCII export, this option has no effect.
1277
1278 This option can also be set with the +OPTIONS line, e.g. \"TeX:nil\"."
1279 :group 'org-export
1280 :type 'boolean)
1281
1282 (defcustom org-export-html-with-timestamp nil
1283 "If non-nil, write `org-export-html-html-helper-timestamp'
1284 into the exported html text. Otherwise, the buffer will just be saved
1285 to a file."
1286 :group 'org-export
1287 :type 'boolean)
1288
1289 (defcustom org-export-html-html-helper-timestamp
1290 "<br><br><hr><p><!-- hhmts start --> <!-- hhmts end -->\n"
1291 "The HTML tag used as timestamp delimiter for HTML-helper-mode."
1292 :group 'org-export
1293 :type 'string)
1294
1295 (defcustom org-export-ascii-show-new-buffer t
1296 "Non-nil means, popup buffer containing the exported ASCII text.
1297 Otherwise the buffer will just be saved to a file and stay hidden."
1298 :group 'org-export
1299 :type 'boolean)
1300
1301 (defcustom org-export-html-show-new-buffer nil
1302 "Non-nil means, popup buffer containing the exported html text.
1303 Otherwise, the buffer will just be saved to a file and stay hidden."
1304 :group 'org-export
1305 :type 'boolean)
1306
1307
1308 (defgroup org-faces nil
1309 "Faces for highlighting in Org-mode."
1310 :tag "Org Faces"
1311 :group 'org)
1312
1313 (defface org-level-1-face ;; font-lock-function-name-face
1314 '((((type tty) (class color)) (:foreground "blue" :weight bold))
1315 (((class color) (background light)) (:foreground "Blue"))
1316 (((class color) (background dark)) (:foreground "LightSkyBlue"))
1317 (t (:inverse-video t :bold t)))
1318 "Face used for level 1 headlines."
1319 :group 'org-faces)
1320
1321 (defface org-level-2-face ;; font-lock-variable-name-face
1322 '((((type tty) (class color)) (:foreground "yellow" :weight light))
1323 (((class color) (background light)) (:foreground "DarkGoldenrod"))
1324 (((class color) (background dark)) (:foreground "LightGoldenrod"))
1325 (t (:bold t :italic t)))
1326 "Face used for level 2 headlines."
1327 :group 'org-faces)
1328
1329 (defface org-level-3-face ;; font-lock-keyword-face
1330 '((((type tty) (class color)) (:foreground "cyan" :weight bold))
1331 (((class color) (background light)) (:foreground "Purple"))
1332 (((class color) (background dark)) (:foreground "Cyan"))
1333 (t (:bold t)))
1334 "Face used for level 3 headlines."
1335 :group 'org-faces)
1336
1337 (defface org-level-4-face ;; font-lock-comment-face
1338 '((((type tty pc) (class color) (background light)) (:foreground "red"))
1339 (((type tty pc) (class color) (background dark)) (:foreground "red1"))
1340 (((class color) (background light)) (:foreground "Firebrick"))
1341 (((class color) (background dark)) (:foreground "chocolate1"))
1342 (t (:bold t :italic t)))
1343 "Face used for level 4 headlines."
1344 :group 'org-faces)
1345
1346 (defface org-level-5-face ;; font-lock-type-face
1347 '((((type tty) (class color)) (:foreground "green"))
1348 (((class color) (background light)) (:foreground "ForestGreen"))
1349 (((class color) (background dark)) (:foreground "PaleGreen"))
1350 (t (:bold t :underline t)))
1351 "Face used for level 5 headlines."
1352 :group 'org-faces)
1353
1354 (defface org-level-6-face ;; font-lock-constant-face
1355 '((((type tty) (class color)) (:foreground "magenta"))
1356 (((class color) (background light)) (:foreground "CadetBlue"))
1357 (((class color) (background dark)) (:foreground "Aquamarine"))
1358 (t (:bold t :underline t)))
1359 "Face used for level 6 headlines."
1360 :group 'org-faces)
1361
1362 (defface org-level-7-face ;; font-lock-builtin-face
1363 '((((type tty) (class color)) (:foreground "blue" :weight light))
1364 (((class color) (background light)) (:foreground "Orchid"))
1365 (((class color) (background dark)) (:foreground "LightSteelBlue"))
1366 (t (:bold t)))
1367 "Face used for level 7 headlines."
1368 :group 'org-faces)
1369
1370 (defface org-level-8-face ;; font-lock-string-face
1371 '((((type tty) (class color)) (:foreground "green"))
1372 (((class color) (background light)) (:foreground "RosyBrown"))
1373 (((class color) (background dark)) (:foreground "LightSalmon"))
1374 (t (:italic t)))
1375 "Face used for level 8 headlines."
1376 :group 'org-faces)
1377
1378 (defface org-warning-face ;; font-lock-warning-face
1379 '((((type tty) (class color)) (:foreground "red"))
1380 (((class color) (background light)) (:foreground "Red" :bold t))
1381 (((class color) (background dark)) (:foreground "Red1" :bold t))
1382 ; (((class color) (background dark)) (:foreground "Pink" :bold t))
1383 (t (:inverse-video t :bold t)))
1384 "Face for deadlines and TODO keywords."
1385 :group 'org-faces)
1386
1387 (defcustom org-fontify-done-headline nil
1388 "Non-nil means, change the face of a headline if it is marked DONE.
1389 Normally, only the TODO/DONE keyword indicates the state of a headline.
1390 When this is non-nil, the headline after the keyword is set to the
1391 `org-headline-done-face' as an additional indication."
1392 :group 'org-faces
1393 :type 'boolean)
1394
1395 (defface org-headline-done-face ;; font-lock-string-face
1396 '((((type tty) (class color)) (:foreground "green"))
1397 (((class color) (background light)) (:foreground "RosyBrown"))
1398 (((class color) (background dark)) (:foreground "LightSalmon"))
1399 (t (:italic t)))
1400 "Face used to indicate that a headline is DONE. See also the variable
1401 `org-fontify-done-headline'."
1402 :group 'org-faces)
1403
1404 ;; Inheritance does not yet work for xemacs. So we just copy...
1405
1406 (defface org-deadline-announce-face
1407 '((((type tty) (class color)) (:foreground "blue" :weight bold))
1408 (((class color) (background light)) (:foreground "Blue"))
1409 (((class color) (background dark)) (:foreground "LightSkyBlue"))
1410 (t (:inverse-video t :bold t)))
1411 "Face for upcoming deadlines."
1412 :group 'org-faces)
1413
1414 (defface org-scheduled-today-face
1415 '((((type tty) (class color)) (:foreground "green"))
1416 (((class color) (background light)) (:foreground "DarkGreen"))
1417 (((class color) (background dark)) (:foreground "PaleGreen"))
1418 (t (:bold t :underline t)))
1419 "Face for items scheduled for a certain day."
1420 :group 'org-faces)
1421
1422 (defface org-scheduled-previously-face
1423 '((((type tty pc) (class color) (background light)) (:foreground "red"))
1424 (((type tty pc) (class color) (background dark)) (:foreground "red1"))
1425 (((class color) (background light)) (:foreground "Firebrick"))
1426 (((class color) (background dark)) (:foreground "chocolate1"))
1427 (t (:bold t :italic t)))
1428 "Face for items scheduled previously, and not yet done."
1429 :group 'org-faces)
1430
1431 (defface org-link-face
1432 '((((type tty) (class color)) (:foreground "cyan" :weight bold))
1433 (((class color) (background light)) (:foreground "Purple"))
1434 (((class color) (background dark)) (:foreground "Cyan"))
1435 (t (:bold t)))
1436 "Face for links."
1437 :group 'org-faces)
1438
1439 (defface org-done-face ;; font-lock-type-face
1440 '((((type tty) (class color)) (:foreground "green"))
1441 (((class color) (background light)) (:foreground "ForestGreen" :bold t))
1442 (((class color) (background dark)) (:foreground "PaleGreen" :bold t))
1443 (t (:bold t :underline t)))
1444 "Face used for DONE."
1445 :group 'org-faces)
1446
1447 (defface org-table-face ;; font-lock-function-name-face
1448 '((((type tty) (class color)) (:foreground "blue" :weight bold))
1449 (((class color) (background light)) (:foreground "Blue"))
1450 (((class color) (background dark)) (:foreground "LightSkyBlue"))
1451 (t (:inverse-video t :bold t)))
1452 "Face used for tables."
1453 :group 'org-faces)
1454
1455 (defface org-time-grid-face ;; font-lock-variable-name-face
1456 '((((type tty) (class color)) (:foreground "yellow" :weight light))
1457 (((class color) (background light)) (:foreground "DarkGoldenrod"))
1458 (((class color) (background dark)) (:foreground "LightGoldenrod"))
1459 (t (:bold t :italic t)))
1460 "Face used for level 2 headlines."
1461 :group 'org-faces)
1462
1463 (defvar org-level-faces
1464 '(
1465 org-level-1-face
1466 org-level-2-face
1467 org-level-3-face
1468 org-level-4-face
1469 org-level-5-face
1470 org-level-6-face
1471 org-level-7-face
1472 org-level-8-face
1473 ))
1474 (defvar org-n-levels (length org-level-faces))
1475
1476 ;; Tell the compiler about dynamically scoped variables,
1477 ;; and variables from other packages
1478 (eval-when-compile
1479 (defvar zmacs-regions)
1480 (defvar original-date)
1481 (defvar org-transient-mark-mode)
1482 (defvar org-old-auto-fill-inhibit-regexp)
1483 (defvar orgtbl-mode-menu)
1484 (defvar org-html-entities)
1485 (defvar org-goto-start-pos)
1486 (defvar org-cursor-color)
1487 (defvar org-time-was-given)
1488 (defvar org-ts-what)
1489 (defvar mark-active)
1490 (defvar timecnt)
1491 (defvar levels-open)
1492 (defvar title)
1493 (defvar author)
1494 (defvar email)
1495 (defvar text)
1496 (defvar entry)
1497 (defvar date)
1498 (defvar language)
1499 (defvar options)
1500 (defvar ans1)
1501 (defvar ans2)
1502 (defvar starting-day)
1503 (defvar include-all-loc)
1504 (defvar vm-message-pointer)
1505 (defvar vm-folder-directory)
1506 (defvar wl-summary-buffer-elmo-folder)
1507 (defvar wl-summary-buffer-folder-name)
1508 (defvar gnus-group-name)
1509 (defvar gnus-article-current)
1510 (defvar w3m-current-url)
1511 (defvar org-selected-point)
1512 (defvar calendar-mode-map)
1513 (defvar remember-save-after-remembering)
1514 (defvar remember-data-file))
1515
1516
1517 ;;; Define the mode
1518
1519 (defvar org-mode-map (copy-keymap outline-mode-map)
1520 "Keymap for Org-mode.")
1521
1522 (defvar org-struct-menu)
1523 (defvar org-org-menu)
1524
1525 ;; We use a before-change function to check if a table might need
1526 ;; an update.
1527 (defvar org-table-may-need-update t
1528 "Indicates of a table might need an update.
1529 This variable is set by `org-before-change-function'. `org-table-align'
1530 sets it back to nil.")
1531
1532 (defvar org-mode-hook nil)
1533 (defvar org-inhibit-startup nil) ; Dynamically-scoped param.
1534
1535
1536 ;;;###autoload
1537 (define-derived-mode org-mode outline-mode "Org"
1538 "Outline-based notes management and organizer, alias
1539 \"Carstens outline-mode for keeping track of everything.\"
1540
1541 Org-mode develops organizational tasks around a NOTES file which
1542 contains information about projects as plain text. Org-mode is
1543 implemented on top of outline-mode, which is ideal to keep the content
1544 of large files well structured. It supports ToDo items, deadlines and
1545 time stamps, which magically appear in the diary listing of the Emacs
1546 calendar. Tables are easily created with a built-in table editor.
1547 Plain text URL-like links connect to websites, emails (VM), Usenet
1548 messages (Gnus), BBDB entries, and any files related to the project.
1549 For printing and sharing of notes, an Org-mode file (or a part of it)
1550 can be exported as a structured ASCII or HTML file.
1551
1552 The following commands are available:
1553
1554 \\{org-mode-map}"
1555 (easy-menu-add org-org-menu)
1556 (org-install-agenda-files-menu)
1557 (setq outline-regexp "\\*+")
1558 (if org-startup-truncated (setq truncate-lines t))
1559 (org-set-regexps-and-options)
1560 (set (make-local-variable 'font-lock-unfontify-region-function)
1561 'org-unfontify-region)
1562 ;; Activate before-change-function
1563 (set (make-local-variable 'org-table-may-need-update) t)
1564 (make-local-hook 'before-change-functions) ;; needed for XEmacs
1565 (add-hook 'before-change-functions 'org-before-change-function nil
1566 'local)
1567 ;; Inhibit auto-fill for headers, tables and fixed-width lines.
1568 (set (make-local-variable 'auto-fill-inhibit-regexp)
1569 (concat "\\*"
1570 (if (or org-enable-table-editor org-enable-fixed-width-editor)
1571 (concat
1572 "\\|[ \t]*["
1573 (if org-enable-table-editor "|" "")
1574 (if org-enable-fixed-width-editor ":" "")
1575 "]"))))
1576 (if (and org-insert-mode-line-in-empty-file
1577 (interactive-p)
1578 (= (point-min) (point-max)))
1579 (insert " -*- mode: org -*-\n\n"))
1580 (unless org-inhibit-startup
1581 (if org-startup-with-deadline-check
1582 (call-interactively 'org-check-deadlines)
1583 (cond
1584 ((eq org-startup-folded t)
1585 (org-cycle '(4)))
1586 ((eq org-startup-folded 'content)
1587 (let ((this-command 'org-cycle) (last-command 'org-cycle))
1588 (org-cycle '(4)) (org-cycle '(4))))))))
1589
1590 ;;; Font-Lock stuff
1591
1592 (defvar org-mouse-map (make-sparse-keymap))
1593 (define-key org-mouse-map
1594 (if org-xemacs-p [button2] [mouse-2]) 'org-open-at-mouse)
1595 (define-key org-mouse-map
1596 (if org-xemacs-p [button3] [mouse-3]) 'org-find-file-at-mouse)
1597
1598 (require 'font-lock)
1599
1600 (defconst org-non-link-chars "\t\n\r|")
1601 (defconst org-link-regexp
1602 (if org-allow-space-in-links
1603 (concat
1604 "\\(https?\\|ftp\\|mailto|\\|file\\|news\\|bbdb\\|vm\\|wl\\|rmail\\|gnus\\|shell\\):\\([^" org-non-link-chars "]+[^ " org-non-link-chars "]\\)")
1605 (concat
1606 "\\(https?\\|ftp\\|mailto\\|file\\|news\\|bbdb\\|vm\\|wl\\|rmail\\|gnus\\|shell\\):\\([^ " org-non-link-chars "]+\\)")
1607 )
1608 "Regular expression for matching links.")
1609 (defconst org-ts-lengths
1610 (cons (length (format-time-string (car org-time-stamp-formats)))
1611 (length (format-time-string (cdr org-time-stamp-formats))))
1612 "This holds the lengths of the two different time formats.")
1613 (defconst org-ts-regexp "<\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}[^\r\n>]*\\)>"
1614 "Regular expression for fast time stamp matching.")
1615 (defconst org-ts-regexp1 "\\(\\([0-9]\\{4\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\)\\([^0-9>\r\n]*\\)\\(\\([0-9]\\{2\\}\\):\\([0-9]\\{2\\}\\)\\)?\\)"
1616 "Regular expression matching time strings for analysis.")
1617 (defconst org-ts-regexp2 (concat "<" org-ts-regexp1 ">")
1618 "Regular expression matching time stamps, with groups.")
1619 (defconst org-tr-regexp (concat org-ts-regexp "--?-?" org-ts-regexp)
1620 "Regular expression matching a time stamp range.")
1621 (defconst org-tsr-regexp (concat org-ts-regexp "\\(--?-?"
1622 org-ts-regexp "\\)?")
1623 "Regular expression matching a time stamp or time stamp range.")
1624
1625 (defun org-activate-links (limit)
1626 "Run through the buffer and add overlays to links."
1627 (if (re-search-forward org-link-regexp limit t)
1628 (progn
1629 (add-text-properties (match-beginning 0) (match-end 0)
1630 (list 'mouse-face 'highlight
1631 'keymap org-mouse-map))
1632 t)))
1633
1634 (defun org-activate-dates (limit)
1635 "Run through the buffer and add overlays to dates."
1636 (if (re-search-forward org-tsr-regexp limit t)
1637 (progn
1638 (add-text-properties (match-beginning 0) (match-end 0)
1639 (list 'mouse-face 'highlight
1640 'keymap org-mouse-map))
1641 t)))
1642
1643 (defun org-font-lock-level ()
1644 (save-excursion
1645 (org-back-to-heading t)
1646 (- (match-end 0) (match-beginning 0))))
1647
1648 (defvar org-font-lock-keywords nil)
1649
1650 (defun org-set-font-lock-defaults ()
1651 (let ((org-font-lock-extra-keywords
1652 (list
1653 '(org-activate-links (0 'org-link-face))
1654 '(org-activate-dates (0 'org-link-face))
1655 (list (concat "^\\*+[ \t]*" org-not-done-regexp)
1656 '(1 'org-warning-face t))
1657 (list (concat "\\[#[A-Z]\\]") '(0 'org-warning-face t))
1658 (list (concat "\\<" org-deadline-string) '(0 'org-warning-face t))
1659 (list (concat "\\<" org-scheduled-string) '(0 'org-warning-face t))
1660 ;; '("\\(\\s-\\|^\\)\\(\\*\\([a-zA-Z]+\\)\\*\\)\\([^a-zA-Z*]\\|$\\)"
1661 ;; (3 'bold))
1662 ;; '("\\(\\s-\\|^\\)\\(/\\([a-zA-Z]+\\)/\\)\\([^a-zA-Z*]\\|$\\)"
1663 ;; (3 'italic))
1664 ;; '("\\(\\s-\\|^\\)\\(_\\([a-zA-Z]+\\)_\\)\\([^a-zA-Z*]\\|$\\)"
1665 ;; (3 'underline))
1666 '("\\<FIXME\\>" (0 'org-warning-face t))
1667 (list (concat "^\\*+[ \t]*\\<\\(" org-comment-string "\\)\\>")
1668 '(1 'org-warning-face t))
1669 '("^#.*" (0 'font-lock-comment-face t))
1670 (if org-fontify-done-headline
1671 (list (concat "^[*]+ +\\<\\(" org-done-string "\\)\\(.*\\)\\>")
1672 '(1 'org-done-face t) '(2 'org-headline-done-face t))
1673 (list (concat "^[*]+ +\\<\\(" org-done-string "\\)\\>")
1674 '(1 'org-done-face t)))
1675 '("^[ \t]*\\(\\(|\\|\\+-[-+]\\).*\\S-\\)"
1676 (1 'org-table-face t))
1677 '("^[ \t]*\\(:.*\\)" (1 'org-table-face t)))))
1678 (set (make-local-variable 'org-font-lock-keywords)
1679 (append
1680 (if org-noutline-p ; FIXME: I am not sure if eval will work
1681 ; on XEmacs if noutline is ever ported
1682 '((eval . (list "^\\(\\*+\\).*"
1683 0 '(nth
1684 (% (- (match-end 1) (match-beginning 1) 1)
1685 org-n-levels)
1686 org-level-faces)
1687 nil t)))
1688 '(("^\\(\\(\\*+\\)[^\r\n]*\\)[\n\r]"
1689 (1 (nth (% (- (match-end 2) (match-beginning 2) 1)
1690 org-n-levels)
1691 org-level-faces)
1692 nil t))))
1693 org-font-lock-extra-keywords))
1694 (set (make-local-variable 'font-lock-defaults)
1695 '(org-font-lock-keywords t nil nil backward-paragraph))
1696 (kill-local-variable 'font-lock-keywords) nil))
1697
1698 (defun org-unfontify-region (beg end &optional maybe_loudly)
1699 "Remove fontification and activation overlays from links."
1700 (font-lock-default-unfontify-region beg end)
1701 (let* ((buffer-undo-list t)
1702 (inhibit-read-only t) (inhibit-point-motion-hooks t)
1703 (inhibit-modification-hooks t)
1704 deactivate-mark buffer-file-name buffer-file-truename)
1705 (remove-text-properties beg end '(mouse-face nil keymap nil))))
1706
1707 ;;; Visibility cycling
1708
1709 (defvar org-cycle-global-status nil)
1710 (defvar org-cycle-subtree-status nil)
1711 (defun org-cycle (&optional arg)
1712 "Visibility cycling for Org-mode.
1713
1714 - When this function is called with a prefix argument, rotate the entire
1715 buffer through 3 states (global cycling)
1716 1. OVERVIEW: Show only top-level headlines.
1717 2. CONTENTS: Show all headlines of all levels, but no body text.
1718 3. SHOW ALL: Show everything.
1719
1720 - When point is at the beginning of a headline, rotate the subtree started
1721 by this line through 3 different states (local cycling)
1722 1. FOLDED: Only the main headline is shown.
1723 2. CHILDREN: The main headline and the direct children are shown. From
1724 this state, you can move to one of the children and
1725 zoom in further.
1726 3. SUBTREE: Show the entire subtree, including body text.
1727
1728 - When there is a numeric prefix, go ARG levels up and do a `show-subtree',
1729 keeping cursor position.
1730
1731 - When point is not at the beginning of a headline, execute
1732 `indent-relative', like TAB normally does. See the option
1733 `org-cycle-emulate-tab' for details.
1734
1735 - Special case: if point is the the beginning of the buffer and there is
1736 no headline in line 1, this function will act as if called with prefix arg."
1737 (interactive "P")
1738
1739 (if (or (and (bobp) (not (looking-at outline-regexp)))
1740 (equal arg '(4)))
1741 ;; special case: use global cycling
1742 (setq arg t))
1743
1744 (cond
1745
1746 ((org-at-table-p 'any)
1747 ;; Enter the table or move to the next field in the table
1748 (or (org-table-recognize-table.el)
1749 (progn
1750 (org-table-justify-field-maybe)
1751 (org-table-next-field))))
1752
1753 ((eq arg t) ;; Global cycling
1754
1755 (cond
1756 ((and (eq last-command this-command)
1757 (eq org-cycle-global-status 'overview))
1758 ;; We just created the overview - now do table of contents
1759 ;; This can be slow in very large buffers, so indicate action
1760 (message "CONTENTS...")
1761 (save-excursion
1762 ;; Visit all headings and show their offspring
1763 (goto-char (point-max))
1764 (catch 'exit
1765 (while (and (progn (condition-case nil
1766 (outline-previous-visible-heading 1)
1767 (error (goto-char (point-min))))
1768 t)
1769 (looking-at outline-regexp))
1770 (show-branches)
1771 (if (bobp) (throw 'exit nil))))
1772 (message "CONTENTS...done"))
1773 (setq org-cycle-global-status 'contents)
1774 (run-hook-with-args 'org-cycle-hook 'contents))
1775
1776 ((and (eq last-command this-command)
1777 (eq org-cycle-global-status 'contents))
1778 ;; We just showed the table of contents - now show everything
1779 (show-all)
1780 (message "SHOW ALL")
1781 (setq org-cycle-global-status 'all)
1782 (run-hook-with-args 'org-cycle-hook 'all))
1783
1784 (t
1785 ;; Default action: go to overview
1786 (hide-sublevels 1)
1787 (message "OVERVIEW")
1788 (setq org-cycle-global-status 'overview)
1789 (run-hook-with-args 'org-cycle-hook 'overview))))
1790
1791 ((integerp arg)
1792 ;; Show-subtree, ARG levels up from here.
1793 (save-excursion
1794 (org-back-to-heading)
1795 (outline-up-heading arg)
1796 (org-show-subtree)))
1797
1798 ((save-excursion (beginning-of-line 1) (looking-at outline-regexp))
1799 ;; At a heading: rotate between three different views
1800 (org-back-to-heading)
1801 (let ((goal-column 0) eoh eol eos)
1802 ;; First, some boundaries
1803 (save-excursion
1804 (org-back-to-heading)
1805 (save-excursion
1806 (beginning-of-line 2)
1807 (while (and (not (eobp)) ;; this is like `next-line'
1808 (get-char-property (1- (point)) 'invisible))
1809 (beginning-of-line 2)) (setq eol (point)))
1810 (outline-end-of-heading) (setq eoh (point))
1811 (outline-end-of-subtree) (setq eos (point))
1812 (outline-next-heading))
1813 ;; Find out what to do next and set `this-command'
1814 (cond
1815 ((= eos eoh)
1816 ;; Nothing is hidden behind this heading
1817 (message "EMPTY ENTRY")
1818 (setq org-cycle-subtree-status nil))
1819 ((>= eol eos)
1820 ;; Entire subtree is hidden in one line: open it
1821 (org-show-entry)
1822 (show-children)
1823 (message "CHILDREN")
1824 (setq org-cycle-subtree-status 'children)
1825 (run-hook-with-args 'org-cycle-hook 'children))
1826 ((and (eq last-command this-command)
1827 (eq org-cycle-subtree-status 'children))
1828 ;; We just showed the children, now show everything.
1829 (org-show-subtree)
1830 (message "SUBTREE")
1831 (setq org-cycle-subtree-status 'subtree)
1832 (run-hook-with-args 'org-cycle-hook 'subtree))
1833 (t
1834 ;; Default action: hide the subtree.
1835 (hide-subtree)
1836 (message "FOLDED")
1837 (setq org-cycle-subtree-status 'folded)
1838 (run-hook-with-args 'org-cycle-hook 'folded)))))
1839
1840 ;; TAB emulation
1841 (buffer-read-only (org-back-to-heading))
1842 ((if (and (eq org-cycle-emulate-tab 'white)
1843 (save-excursion (beginning-of-line 1) (looking-at "[ \t]+$")))
1844 t
1845 (eq org-cycle-emulate-tab t))
1846 (if (and (looking-at "[ \n\r\t]")
1847 (string-match "^[ \t]*$" (buffer-substring
1848 (point-at-bol) (point))))
1849 (progn
1850 (beginning-of-line 1)
1851 (and (looking-at "[ \t]+") (replace-match ""))))
1852 (indent-relative))
1853
1854 (t (save-excursion
1855 (org-back-to-heading)
1856 (org-cycle)))))
1857
1858 (defun org-optimize-window-after-visibility-change (state)
1859 "Adjust the window after a change in outline visibility.
1860 This function is the default value of the hook `org-cycle-hook'."
1861 (cond
1862 ((eq state 'overview) (org-first-headline-recenter 1))
1863 ((eq state 'content) nil)
1864 ((eq state 'all) nil)
1865 ((eq state 'folded) nil)
1866 ((eq state 'children) (or (org-subtree-end-visible-p) (recenter 1)))
1867 ((eq state 'subtree) (or (org-subtree-end-visible-p) (recenter 1)))))
1868
1869 (defun org-subtree-end-visible-p ()
1870 "Is the end of the current subtree visible?"
1871 (pos-visible-in-window-p
1872 (save-excursion (outline-end-of-subtree) (point))))
1873
1874 (defun org-first-headline-recenter (&optional N)
1875 "Move cursor to the first headline and recenter the headline.
1876 Optional argument N means, put the headline into the Nth line of the window."
1877 (goto-char (point-min))
1878 (when (re-search-forward (concat "^" outline-regexp) nil t)
1879 (beginning-of-line)
1880 (recenter (prefix-numeric-value N))))
1881
1882 (defvar org-goto-window-configuration nil)
1883 (defvar org-goto-marker nil)
1884 (defvar org-goto-map (make-sparse-keymap))
1885 (let ((cmds '(isearch-forward isearch-backward)) cmd)
1886 (while (setq cmd (pop cmds))
1887 (substitute-key-definition cmd cmd org-goto-map global-map)))
1888 (define-key org-goto-map [(return)] 'org-goto-ret)
1889 (define-key org-goto-map [(left)] 'org-goto-left)
1890 (define-key org-goto-map [(right)] 'org-goto-right)
1891 (define-key org-goto-map [(?q)] 'org-goto-quit)
1892 (define-key org-goto-map [(control ?g)] 'org-goto-quit)
1893 (define-key org-goto-map [(tab)] 'org-cycle)
1894 (define-key org-goto-map [(down)] 'outline-next-visible-heading)
1895 (define-key org-goto-map [(up)] 'outline-previous-visible-heading)
1896 (define-key org-goto-map "n" 'outline-next-visible-heading)
1897 (define-key org-goto-map "p" 'outline-previous-visible-heading)
1898 (define-key org-goto-map "f" 'outline-forward-same-level)
1899 (define-key org-goto-map "b" 'outline-backward-same-level)
1900 (define-key org-goto-map "u" 'outline-up-heading)
1901 (define-key org-goto-map "\C-c\C-n" 'outline-next-visible-heading)
1902 (define-key org-goto-map "\C-c\C-p" 'outline-previous-visible-heading)
1903 (define-key org-goto-map "\C-c\C-f" 'outline-forward-same-level)
1904 (define-key org-goto-map "\C-c\C-b" 'outline-backward-same-level)
1905 (define-key org-goto-map "\C-c\C-u" 'outline-up-heading)
1906 (let ((l '(1 2 3 4 5 6 7 8 9 0)))
1907 (while l (define-key org-goto-map (int-to-string (pop l)) 'digit-argument)))
1908
1909 (defconst org-goto-help
1910 "Select a location to jump to, press RET
1911 \[Up]/[Down]=next/prev headline TAB=cycle visibility RET=select [Q]uit")
1912
1913 (defun org-goto ()
1914 "Go to a different location of the document, keeping current visibility.
1915
1916 When you want to go to a different location in a document, the fastest way
1917 is often to fold the entire buffer and then dive into the tree. This
1918 method has the disadvantage, that the previous location will be folded,
1919 which may not be what you want.
1920
1921 This command works around this by showing a copy of the current buffer in
1922 overview mode. You can dive into the tree in that copy, to find the
1923 location you want to reach. When pressing RET, the command returns to the
1924 original buffer in which the visibility is still unchanged. It then jumps
1925 to the new location, making it and the headline hierarchy above it visible."
1926 (interactive)
1927 (let* ((org-goto-start-pos (point))
1928 (selected-point
1929 (org-get-location (current-buffer) org-goto-help)))
1930 (if selected-point
1931 (progn
1932 (goto-char selected-point)
1933 (if (org-invisible-p) (org-show-hierarchy-above)))
1934 (error "Quit"))))
1935
1936 (defun org-get-location (buf help)
1937 "Let the user select a location in the Org-mode buffer BUF.
1938 This function uses a recursive edit. It returns the selected position
1939 or nil."
1940 (let (org-selected-point)
1941 (save-excursion
1942 (save-window-excursion
1943 (delete-other-windows)
1944 (switch-to-buffer (get-buffer-create "*org-goto*"))
1945 (with-output-to-temp-buffer "*Help*"
1946 (princ help))
1947 (shrink-window-if-larger-than-buffer (get-buffer-window "*Help*"))
1948 (setq buffer-read-only nil)
1949 (erase-buffer)
1950 (insert-buffer buf)
1951 (let ((org-startup-truncated t)
1952 (org-startup-folded t)
1953 (org-startup-with-deadline-check nil))
1954 (org-mode))
1955 (setq buffer-read-only t)
1956 (if (boundp 'org-goto-start-pos)
1957 (goto-char org-goto-start-pos)
1958 (goto-char (point-min)))
1959 (org-beginning-of-line)
1960 (message "Select location and press RET")
1961 ;; now we make sure that during selection, ony very few keys work
1962 ;; and that it is impossible to switch to another window.
1963 (let ((gm (current-global-map))
1964 (overriding-local-map org-goto-map))
1965 (unwind-protect
1966 (progn
1967 (use-global-map org-goto-map)
1968 (recursive-edit))
1969 (use-global-map gm)))))
1970 (kill-buffer "*org-goto*")
1971 org-selected-point))
1972
1973 ;; FIXME: It may not be a good idea to temper with the prefix argument...
1974 (defun org-goto-ret (&optional arg)
1975 "Finish org-goto by going to the new location."
1976 (interactive "P")
1977 (setq org-selected-point (point)
1978 current-prefix-arg arg)
1979 (throw 'exit nil))
1980
1981 (defun org-goto-left ()
1982 "Finish org-goto by going to the new location."
1983 (interactive)
1984 (if (org-on-heading-p)
1985 (progn
1986 (beginning-of-line 1)
1987 (setq org-selected-point (point)
1988 current-prefix-arg (- (match-end 0) (match-beginning 0)))
1989 (throw 'exit nil))
1990 (error "Not on a heading")))
1991
1992 (defun org-goto-right ()
1993 "Finish org-goto by going to the new location."
1994 (interactive)
1995 (if (org-on-heading-p)
1996 (progn
1997 (outline-end-of-subtree)
1998 (or (eobp) (forward-char 1))
1999 (setq org-selected-point (point)
2000 current-prefix-arg (- (match-end 0) (match-beginning 0)))
2001 (throw 'exit nil))
2002 (error "Not on a heading")))
2003
2004 (defun org-goto-quit ()
2005 "Finish org-goto without cursor motion."
2006 (interactive)
2007 (setq org-selected-point nil)
2008 (throw 'exit nil))
2009
2010 ;;; Promotion, Demotion, Inserting new headlines
2011
2012 (defvar org-ignore-region nil
2013 "To temporarily disable the active region.")
2014
2015 (defun org-insert-heading ()
2016 "Insert a new heading with same depth at point."
2017 (interactive)
2018 (let* ((head (save-excursion
2019 (condition-case nil
2020 (org-back-to-heading)
2021 (error (outline-next-heading)))
2022 (prog1 (match-string 0)
2023 (funcall outline-level)))))
2024 (unless (bolp) (newline))
2025 (insert head)
2026 (unless (eolp)
2027 (save-excursion (newline-and-indent)))
2028 (unless (equal (char-before) ?\ )
2029 (insert " "))
2030 (run-hooks 'org-insert-heading-hook)))
2031
2032 (defun org-insert-todo-heading (arg)
2033 "Insert a new heading with the same level and TODO state as current heading.
2034 If the heading has no TODO state, or if the state is DONE, use the first
2035 state (TODO by default). Also with prefix arg, force first state."
2036 (interactive "P")
2037 (org-insert-heading)
2038 (save-excursion
2039 (org-back-to-heading)
2040 (outline-previous-heading)
2041 (looking-at org-todo-line-regexp))
2042 (if (or arg
2043 (not (match-beginning 2))
2044 (equal (match-string 2) org-done-string))
2045 (insert (car org-todo-keywords) " ")
2046 (insert (match-string 2) " ")))
2047
2048 (defun org-promote-subtree ()
2049 "Promote the entire subtree.
2050 See also `org-promote'."
2051 (interactive)
2052 (save-excursion
2053 (org-map-tree 'org-promote)))
2054
2055 (defun org-demote-subtree ()
2056 "Demote the entire subtree. See `org-demote'.
2057 See also `org-promote'."
2058 (interactive)
2059 (save-excursion
2060 (org-map-tree 'org-demote)))
2061
2062 (defun org-do-promote ()
2063 "Promote the current heading higher up the tree.
2064 If the region is active in `transient-mark-mode', promote all headings
2065 in the region."
2066 (interactive)
2067 (save-excursion
2068 (if (org-region-active-p)
2069 (org-map-region 'org-promote (region-beginning) (region-end))
2070 (org-promote)))
2071 (org-fix-position-after-promote))
2072
2073 (defun org-do-demote ()
2074 "Demote the current heading lower down the tree.
2075 If the region is active in `transient-mark-mode', demote all headings
2076 in the region."
2077 (interactive)
2078 (save-excursion
2079 (if (org-region-active-p)
2080 (org-map-region 'org-demote (region-beginning) (region-end))
2081 (org-demote)))
2082 (org-fix-position-after-promote))
2083
2084 (defun org-fix-position-after-promote ()
2085 "Make sure that after pro/demotion cursor position is right."
2086 (and (equal (char-after) ?\ )
2087 (equal (char-before) ?*)
2088 (forward-char 1)))
2089
2090 (defun org-promote ()
2091 "Promote the current heading higher up the tree.
2092 If the region is active in `transient-mark-mode', promote all headings
2093 in the region."
2094 (org-back-to-heading t)
2095 (let* ((level (save-match-data (funcall outline-level)))
2096 (up-head (make-string (1- level) ?*)))
2097 (if (= level 1) (error "Cannot promote to level 0. UNDO to recover."))
2098 (replace-match up-head nil t)
2099 (if org-adapt-indentation
2100 (org-fixup-indentation "^ " "" "^ ?\\S-"))))
2101
2102 (defun org-demote ()
2103 "Demote the current heading lower down the tree.
2104 If the region is active in `transient-mark-mode', demote all headings
2105 in the region."
2106 (org-back-to-heading t)
2107 (let* ((level (save-match-data (funcall outline-level)))
2108 (down-head (make-string (1+ level) ?*)))
2109 (replace-match down-head nil t)
2110 (if org-adapt-indentation
2111 (org-fixup-indentation "^ " " " "^\\S-"))))
2112
2113 (defun org-map-tree (fun)
2114 "Call FUN for every heading underneath the current one."
2115 (org-back-to-heading)
2116 (let ((level (outline-level)))
2117 (save-excursion
2118 (funcall fun)
2119 (while (and (progn
2120 (outline-next-heading)
2121 (> (funcall outline-level) level))
2122 (not (eobp)))
2123 (funcall fun)))))
2124
2125 (defun org-map-region (fun beg end)
2126 "Call FUN for every heading between BEG and END."
2127 (let ((org-ignore-region t))
2128 (save-excursion
2129 (setq end (copy-marker end))
2130 (goto-char beg)
2131 ;; (if (fboundp 'deactivate-mark) (deactivate-mark))
2132 ;; (if (fboundp 'zmacs-deactivate-region) (zmacs-deactivate-region))
2133 (if (and (re-search-forward (concat "^" outline-regexp) nil t)
2134 (< (point) end))
2135 (funcall fun))
2136 (while (and (progn
2137 (outline-next-heading)
2138 (< (point) end))
2139 (not (eobp)))
2140 (funcall fun)))))
2141
2142 (defun org-fixup-indentation (from to prohibit)
2143 "Change the indentation in the current entry by re-replacing FROM with TO.
2144 However, if the regexp PROHIBIT matches at all, don't do anything.
2145 This is being used to change indentation along with the length of the
2146 heading marker. But if there are any lines which are not indented, nothing
2147 is changed at all."
2148 (save-excursion
2149 (let ((end (save-excursion (outline-next-heading)
2150 (point-marker))))
2151 (unless (save-excursion (re-search-forward prohibit end t))
2152 (while (re-search-forward from end t)
2153 (replace-match to)
2154 (beginning-of-line 2)))
2155 (move-marker end nil))))
2156
2157 ;;; Vertical tree motion, cutting and pasting of subtrees
2158
2159 (defun org-move-subtree-up (&optional arg)
2160 "Move the current subtree up past ARG headlines of the same level."
2161 (interactive "p")
2162 (org-move-subtree-down (- (prefix-numeric-value arg))))
2163
2164 (defun org-move-subtree-down (&optional arg)
2165 "Move the current subtree down past ARG headlines of the same level."
2166 (interactive "p")
2167 (setq arg (prefix-numeric-value arg))
2168 (let ((movfunc (if (> arg 0) 'outline-get-next-sibling
2169 'outline-get-last-sibling))
2170 (ins-point (make-marker))
2171 (cnt (abs arg))
2172 beg end txt folded)
2173 ;; Select the tree
2174 (org-back-to-heading)
2175 (setq beg (point))
2176 (save-match-data
2177 (save-excursion (outline-end-of-heading)
2178 (setq folded (org-invisible-p)))
2179 (outline-end-of-subtree))
2180 (outline-next-heading)
2181 (setq end (point))
2182 ;; Find insertion point, with error handling
2183 (goto-char beg)
2184 (while (> cnt 0)
2185 (or (and (funcall movfunc) (looking-at outline-regexp))
2186 (progn (goto-char beg)
2187 (error "Cannot move past superior level or buffer limit")))
2188 (setq cnt (1- cnt)))
2189 (if (> arg 0)
2190 ;; Moving forward - still need to move over subtree
2191 (progn (outline-end-of-subtree)
2192 (outline-next-heading)
2193 (if (not (or (looking-at (concat "^" outline-regexp))
2194 (bolp)))
2195 (newline))))
2196 (move-marker ins-point (point))
2197 (setq txt (buffer-substring beg end))
2198 (delete-region beg end)
2199 (insert txt)
2200 (goto-char ins-point)
2201 (if folded (hide-subtree))
2202 (move-marker ins-point nil)))
2203
2204 (defvar org-subtree-clip ""
2205 "Clipboard for cut and paste of subtrees.
2206 This is actually only a copy of the kill, because we use the normal kill
2207 ring. We need it to check if the kill was created by `org-copy-subtree'.")
2208
2209 (defvar org-subtree-clip-folded nil
2210 "Was the last copied subtree folded?
2211 This is used to fold the tree back after pasting.")
2212
2213 (defun org-cut-subtree ()
2214 "Cut the current subtree into the clipboard.
2215 This is a short-hand for marking the subtree and then cutting it."
2216 (interactive)
2217 (org-copy-subtree 'cut))
2218
2219 (defun org-copy-subtree (&optional cut)
2220 "Cut the current subtree into the clipboard.
2221 This is a short-hand for marking the subtree and then copying it.
2222 If CUT is non nil, actually cut the subtree."
2223 (interactive)
2224 (let (beg end folded)
2225 (org-back-to-heading)
2226 (setq beg (point))
2227 (save-match-data
2228 (save-excursion (outline-end-of-heading)
2229 (setq folded (org-invisible-p)))
2230 (outline-end-of-subtree))
2231 (if (equal (char-after) ?\n) (forward-char 1))
2232 (setq end (point))
2233 (goto-char beg)
2234 (when (> end beg)
2235 (setq org-subtree-clip-folded folded)
2236 (if cut (kill-region beg end) (copy-region-as-kill beg end))
2237 (setq org-subtree-clip (current-kill 0))
2238 (message "%s: Subtree with %d characters"
2239 (if cut "Cut" "Copied")
2240 (length org-subtree-clip)))))
2241
2242 (defun org-paste-subtree (&optional level tree)
2243 "Paste the clipboard as a subtree, with modification of headline level.
2244 The entire subtree is promoted or demoted in order to match a new headline
2245 level. By default, the new level is derived from the visible headings
2246 before and after the insertion point, and taken to be the inferior headline
2247 level of the two. So if the previous visible heading is level 3 and the
2248 next is level 4 (or vice versa), level 4 will be used for insertion.
2249 This makes sure that the subtree remains an independent subtree and does
2250 not swallow low level entries.
2251
2252 You can also force a different level, either by using a numeric prefix
2253 argument, or by inserting the heading marker by hand. For example, if the
2254 cursor is after \"*****\", then the tree will be shifted to level 5.
2255
2256 If you want to insert the tree as is, just use \\[yank].
2257
2258 If optional TREE is given, use this text instead of the kill ring."
2259 (interactive "P")
2260 (unless (org-kill-is-subtree-p tree)
2261 (error
2262 (substitute-command-keys
2263 "The kill is not a (set of) tree(s) - please use \\[yank] to yank anyway")))
2264 (let* ((txt (or tree (current-kill 0)))
2265 (^re (concat "^\\(" outline-regexp "\\)"))
2266 (re (concat "\\(" outline-regexp "\\)"))
2267 (^re_ (concat "\\(" outline-regexp "\\)[ \t]*"))
2268
2269 (old-level (if (string-match ^re txt)
2270 (- (match-end 0) (match-beginning 0))
2271 -1))
2272 (force-level (cond (level (prefix-numeric-value level))
2273 ((string-match
2274 ^re_ (buffer-substring (point-at-bol) (point)))
2275 (- (match-end 0) (match-beginning 0)))
2276 (t nil)))
2277 (previous-level (save-excursion
2278 (outline-previous-visible-heading 1)
2279 (if (looking-at re)
2280 (- (match-end 0) (match-beginning 0))
2281 1)))
2282 (next-level (save-excursion
2283 (outline-next-visible-heading 1)
2284 (if (looking-at re)
2285 (- (match-end 0) (match-beginning 0))
2286 1)))
2287 (new-level (or force-level (max previous-level next-level)))
2288 (shift (if (or (= old-level -1)
2289 (= new-level -1)
2290 (= old-level new-level))
2291 0
2292 (- new-level old-level)))
2293 (shift1 shift)
2294 (delta (if (> shift 0) -1 1))
2295 (func (if (> shift 0) 'org-demote 'org-promote))
2296 beg end)
2297 ;; Remove the forces level indicator
2298 (if force-level
2299 (delete-region (point-at-bol) (point)))
2300 ;; Make sure we start at the beginning of an empty line
2301 (if (not (bolp)) (insert "\n"))
2302 (if (not (looking-at "[ \t]*$"))
2303 (progn (insert "\n") (backward-char 1)))
2304 ;; Paste
2305 (setq beg (point))
2306 (insert txt)
2307 (setq end (point))
2308 (goto-char beg)
2309 ;; Shift if necessary
2310 (if (= shift 0)
2311 (message "Pasted at level %d, without shift" new-level)
2312 (save-restriction
2313 (narrow-to-region beg end)
2314 (while (not (= shift 0))
2315 (org-map-region func (point-min) (point-max))
2316 (setq shift (+ delta shift)))
2317 (goto-char (point-min))
2318 (message "Pasted at level %d, with shift by %d levels"
2319 new-level shift1)))
2320 (if (and (eq org-subtree-clip (current-kill 0))
2321 org-subtree-clip-folded)
2322 ;; The tree was folded before it was killed/copied
2323 (hide-subtree))))
2324
2325 (defun org-kill-is-subtree-p (&optional txt)
2326 "Check if the current kill is an outline subtree, or a set of trees.
2327 Returns nil if kill does not start with a headline, or if the first
2328 headline level is not the largest headline level in the tree.
2329 So this will actually accept several entries of equal levels as well,
2330 which is OK for `org-paste-subtree'.
2331 If optional TXT is given, check this string instead of the current kill."
2332 (let* ((kill (or txt (current-kill 0) ""))
2333 (start-level (and (string-match (concat "\\`" outline-regexp) kill)
2334 (- (match-end 0) (match-beginning 0))))
2335 (re (concat "^" outline-regexp))
2336 (start 1))
2337 (if (not start-level)
2338 nil ;; does not even start with a heading
2339 (catch 'exit
2340 (while (setq start (string-match re kill (1+ start)))
2341 (if (< (- (match-end 0) (match-beginning 0)) start-level)
2342 (throw 'exit nil)))
2343 t))))
2344
2345 ;;; Completion
2346
2347 (defun org-complete (&optional arg)
2348 "Perform completion on word at point.
2349 At the beginning of a headline, this completes TODO keywords as given in
2350 `org-todo-keywords'.
2351 If the current word is preceded by a backslash, completes the TeX symbols
2352 that are supported for HTML support.
2353 If the current word is preceded by \"#+\", completes special words for
2354 setting file options.
2355 At all other locations, this simply calls `ispell-complete-word'."
2356 (interactive "P")
2357 (catch 'exit
2358 (let* ((end (point))
2359 (beg (save-excursion
2360 (if (equal (char-before (point)) ?\ ) (backward-char 1))
2361 (skip-chars-backward "a-zA-Z0-9_:")
2362 (point)))
2363 (texp (equal (char-before beg) ?\\))
2364 (opt (equal (buffer-substring (max (point-at-bol) (- beg 2))
2365 beg)
2366 "#+"))
2367 (pattern (buffer-substring-no-properties beg end))
2368 (completion-ignore-case opt)
2369 (type nil)
2370 (table (cond
2371 (opt
2372 (setq type :opt)
2373 (mapcar (lambda (x)
2374 (string-match "^#\\+\\(\\([A-Z_]+:?\\).*\\)" x)
2375 (cons (match-string 2 x) (match-string 1 x)))
2376 (org-split-string (org-get-current-options) "\n")))
2377 (texp
2378 (setq type :tex)
2379 org-html-entities)
2380 ((string-match "\\`\\*+[ \t]*\\'"
2381 (buffer-substring (point-at-bol) beg))
2382 (setq type :todo)
2383 (mapcar 'list org-todo-keywords))
2384 (t (progn (ispell-complete-word arg) (throw 'exit nil)))))
2385 (completion (try-completion pattern table)))
2386 (cond ((eq completion t)
2387 (if (equal type :opt)
2388 (insert (substring (cdr (assoc (upcase pattern) table))
2389 (length pattern)))))
2390 ((null completion)
2391 (message "Can't find completion for \"%s\"" pattern)
2392 (ding))
2393 ((not (string= pattern completion))
2394 (delete-region beg end)
2395 (if (string-match " +$" completion)
2396 (setq completion (replace-match "" t t completion)))
2397 (insert completion)
2398 (if (get-buffer-window "*Completions*")
2399 (delete-window (get-buffer-window "*Completions*")))
2400 (if (and (eq type :todo)
2401 (assoc completion table))
2402 (insert " "))
2403 (if (and (equal type :opt) (assoc completion table))
2404 (message (substitute-command-keys
2405 "Press \\[org-complete] again to insert example settings"))))
2406 (t
2407 (message "Making completion list...")
2408 (let ((list (sort (all-completions pattern table) 'string<)))
2409 (with-output-to-temp-buffer "*Completions*"
2410 (display-completion-list list)))
2411 (message "Making completion list...%s" "done"))))))
2412
2413 ;;; Comments, TODO and DEADLINE
2414
2415 (defun org-toggle-comment ()
2416 "Change the COMMENT state of an entry."
2417 (interactive)
2418 (save-excursion
2419 (org-back-to-heading)
2420 (if (looking-at (concat outline-regexp
2421 "\\( +\\<" org-comment-string "\\>\\)"))
2422 (replace-match "" t t nil 1)
2423 (if (looking-at outline-regexp)
2424 (progn
2425 (goto-char (match-end 0))
2426 (insert " " org-comment-string))))))
2427
2428 (defvar org-last-todo-state-is-todo nil
2429 "This is non-nil when the last TODO state change led to a TODO state.
2430 If the last change removed the TODO tag or switched to DONE, then
2431 this is nil.")
2432
2433 (defun org-todo (&optional arg)
2434 "Change the TODO state of an item.
2435 The state of an item is given by a keyword at the start of the heading,
2436 like
2437 *** TODO Write paper
2438 *** DONE Call mom
2439
2440 The different keywords are specified in the variable `org-todo-keywords'. By
2441 default the available states are \"TODO\" and \"DONE\".
2442 So for this example: when the item starts with TODO, it is changed to DONE.
2443 When it starts with DONE, the DONE is removed. And when neither TODO nor
2444 DONE are present, add TODO at the beginning of the heading.
2445
2446 With prefix arg, use completion to determined the new state. With numeric
2447 prefix arg, switch to that state."
2448 (interactive "P")
2449 (save-excursion
2450 (org-back-to-heading)
2451 (if (looking-at outline-regexp) (goto-char (match-end 0)))
2452 (or (looking-at (concat " +" org-todo-regexp " *"))
2453 (looking-at " *"))
2454 (let* ((this (match-string 1))
2455 (completion-ignore-case t)
2456 (member (member this org-todo-keywords))
2457 (tail (cdr member))
2458 (state (cond
2459 ((equal arg '(4))
2460 ;; Read a state with completion
2461 (completing-read "State: " (mapcar (lambda(x) (list x))
2462 org-todo-keywords)
2463 nil t))
2464 (arg
2465 ;; user requests a specific state
2466 (nth (1- (prefix-numeric-value arg))
2467 org-todo-keywords))
2468 ((null member) (car org-todo-keywords))
2469 ((null tail) nil) ;; -> first entry
2470 ((eq org-todo-interpretation 'sequence)
2471 (car tail))
2472 ((memq org-todo-interpretation '(type priority))
2473 (if (eq this-command last-command)
2474 (car tail)
2475 (if (> (length tail) 0) org-done-string nil)))
2476 (t nil)))
2477 (next (if state (concat " " state " ") " ")))
2478 (replace-match next t t)
2479 (setq org-last-todo-state-is-todo
2480 (not (equal state org-done-string)))
2481 (run-hooks 'org-after-todo-state-change-hook)))
2482 ;; Fixup cursor location if close to the keyword
2483 (if (and (outline-on-heading-p)
2484 (not (bolp))
2485 (save-excursion (beginning-of-line 1)
2486 (looking-at org-todo-line-regexp))
2487 (< (point) (+ 2 (or (match-end 2) (match-end 1)))))
2488 (progn
2489 (goto-char (or (match-end 2) (match-end 1)))
2490 (just-one-space))))
2491
2492 (defun org-show-todo-tree (arg)
2493 "Make a compact tree which shows all headlines marked with TODO.
2494 The tree will show the lines where the regexp matches, and all higher
2495 headlines above the match."
2496 (interactive "P")
2497 (let ((case-fold-search nil)
2498 (kwd-re (if arg org-todo-regexp org-not-done-regexp)))
2499 (message "%d TODO entries found"
2500 (org-occur (concat "^" outline-regexp " +" kwd-re )))))
2501
2502 (defun org-deadline ()
2503 "Insert the DEADLINE: string to make a deadline.
2504 A timestamp is also inserted - use \\[org-timestamp-up] and \\[org-timestamp-down]
2505 to modify it to the correct date."
2506 (interactive)
2507 (insert
2508 org-deadline-string " "
2509 (format-time-string (car org-time-stamp-formats)
2510 (org-read-date nil 'to-time)))
2511 (message (substitute-command-keys
2512 "Use \\[org-timestamp-up-day] and \\[org-timestamp-down-day] to change the date.")))
2513
2514 (defun org-schedule ()
2515 "Insert the SCHEDULED: string to schedule a TODO item.
2516 A timestamp is also inserted - use \\[org-timestamp-up] and \\[org-timestamp-down]
2517 to modify it to the correct date."
2518 (interactive)
2519 (insert
2520 org-scheduled-string " "
2521 (format-time-string (car org-time-stamp-formats)
2522 (org-read-date nil 'to-time)))
2523 (message (substitute-command-keys
2524 "Use \\[org-timestamp-up-day] and \\[org-timestamp-down-day] to change the date.")))
2525
2526
2527 (defun org-occur (regexp &optional callback)
2528 "Make a compact tree which shows all matches of REGEXP.
2529 The tree will show the lines where the regexp matches, and all higher
2530 headlines above the match. It will also show the heading after the match,
2531 to make sure editing the matching entry is easy.
2532 if CALLBACK is non-nil, it is a function which is called to confirm
2533 that the match should indeed be shown."
2534 (interactive "sRegexp: ")
2535 (setq regexp (org-check-occur-regexp regexp))
2536 (let ((cnt 0))
2537 (save-excursion
2538 (goto-char (point-min))
2539 (hide-sublevels 1)
2540 (while (re-search-forward regexp nil t)
2541 (when (or (not callback)
2542 (funcall callback))
2543 (setq cnt (1+ cnt))
2544 (org-show-hierarchy-above))))
2545 (run-hooks 'org-occur-hook)
2546 (if (interactive-p)
2547 (message "%d match(es) for regexp %s" cnt regexp))
2548 cnt))
2549
2550 (defun org-show-hierarchy-above ()
2551 "Make sure point and the headings hierarchy above is visible."
2552 (if (org-on-heading-p t)
2553 (org-flag-heading nil) ; only show the heading
2554 (org-show-hidden-entry)) ; show entire entry
2555 (save-excursion
2556 (and org-show-following-heading
2557 (outline-next-heading)
2558 (org-flag-heading nil))) ; show the next heading
2559 (save-excursion ; show all higher headings
2560 (while (condition-case nil
2561 (progn (org-up-heading-all 1) t)
2562 (error nil))
2563 (org-flag-heading nil))))
2564
2565 ;;; Priorities
2566
2567 (defvar org-priority-regexp ".*?\\(\\[#\\([A-Z]\\)\\] ?\\)"
2568 "Regular expression matching the priority indicator.")
2569
2570 (defvar org-remove-priority-next-time nil)
2571
2572 (defun org-priority-up ()
2573 "Increase the priority of the current item."
2574 (interactive)
2575 (org-priority 'up))
2576
2577 (defun org-priority-down ()
2578 "Decrease the priority of the current item."
2579 (interactive)
2580 (org-priority 'down))
2581
2582 (defun org-priority (&optional action)
2583 "Change the priority of an item by ARG.
2584 ACTION can be set, up, or down."
2585 (interactive)
2586 (setq action (or action 'set))
2587 (let (current new news have remove)
2588 (save-excursion
2589 (org-back-to-heading)
2590 (if (looking-at org-priority-regexp)
2591 (setq current (string-to-char (match-string 2))
2592 have t)
2593 (setq current org-default-priority))
2594 (cond
2595 ((eq action 'set)
2596 (message (format "Priority A-%c, SPC to remove: " org-lowest-priority))
2597 (setq new (read-char-exclusive))
2598 (cond ((equal new ?\ ) (setq remove t))
2599 ((or (< (upcase new) ?A) (> (upcase new) org-lowest-priority))
2600 (error "Priority must be between `%c' and `%c'"
2601 ?A org-lowest-priority))))
2602 ((eq action 'up)
2603 (setq new (1- current)))
2604 ((eq action 'down)
2605 (setq new (1+ current)))
2606 (t (error "Invalid action")))
2607 (setq new (min (max ?A (upcase new)) org-lowest-priority))
2608 (setq news (format "%c" new))
2609 (if have
2610 (if remove
2611 (replace-match "" t t nil 1)
2612 (replace-match news t t nil 2))
2613 (if remove
2614 (error "No priority cookie found in line")
2615 (looking-at org-todo-line-regexp)
2616 (if (match-end 2)
2617 (progn
2618 (goto-char (match-end 2))
2619 (insert " [#" news "]"))
2620 (goto-char (match-beginning 3))
2621 (insert "[#" news "] ")))))
2622 (if remove
2623 (message "Priority removed")
2624 (message "Priority of current item set to %s" news))))
2625
2626
2627 (defun org-get-priority (s)
2628 "Find priority cookie and return priority."
2629 (save-match-data
2630 (if (not (string-match org-priority-regexp s))
2631 (* 1000 (- org-lowest-priority org-default-priority))
2632 (* 1000 (- org-lowest-priority
2633 (string-to-char (match-string 2 s)))))))
2634
2635 ;;; Timestamps
2636
2637 (defvar org-last-changed-timestamp nil)
2638
2639 (defun org-time-stamp (arg)
2640 "Prompt for a date/time and insert a time stamp.
2641 If the user specifies a time like HH:MM, or if this command is called
2642 with a prefix argument, the time stamp will contain date and time.
2643 Otherwise, only the date will be included. All parts of a date not
2644 specified by the user will be filled in from the current date/time.
2645 So if you press just return without typing anything, the time stamp
2646 will represent the current date/time. If there is already a timestamp
2647 at the cursor, it will be modified."
2648 (interactive "P")
2649 (let ((fmt (if arg (cdr org-time-stamp-formats)
2650 (car org-time-stamp-formats)))
2651 (org-time-was-given nil)
2652 time)
2653 (cond
2654 ((and (org-at-timestamp-p)
2655 (eq last-command 'org-time-stamp)
2656 (eq this-command 'org-time-stamp))
2657 (insert "--")
2658 (setq time (let ((this-command this-command))
2659 (org-read-date arg 'totime)))
2660 (if org-time-was-given (setq fmt (cdr org-time-stamp-formats)))
2661 (insert (format-time-string fmt time)))
2662 ((org-at-timestamp-p)
2663 (setq time (let ((this-command this-command))
2664 (org-read-date arg 'totime)))
2665 (and (org-at-timestamp-p) (replace-match
2666 (setq org-last-changed-timestamp
2667 (format-time-string fmt time))
2668 t t))
2669 (message "Timestamp updated"))
2670 (t
2671 (setq time (let ((this-command this-command))
2672 (org-read-date arg 'totime)))
2673 (if org-time-was-given (setq fmt (cdr org-time-stamp-formats)))
2674 (insert (format-time-string fmt time))))))
2675
2676 ;;; FIXME: Make the function take "Fri" as "next friday"
2677 (defun org-read-date (&optional with-time to-time)
2678 "Read a date and make things smooth for the user.
2679 The prompt will suggest to enter an ISO date, but you can also enter anything
2680 which will at least partially be understood by `parse-time-string'.
2681 Unrecognized parts of the date will default to the current day, month ,year,
2682 hour and minute. For example,
2683 3-2-5 --> 2003-02-05
2684 feb 15 --> currentyear-02-15
2685 sep 12 9 --> 2009-09-12
2686 12:45 --> today 12:45
2687 22 sept 0:34 --> currentyear-09-22 0:34
2688 12 --> currentyear-currentmonth-12
2689 etc.
2690 The function understands only English month and weekday abbreviations,
2691 but this can be configured with the variables `parse-time-months' and
2692 `parse-time-weekdays'.
2693
2694 While prompting, a calendar is popped up - you can also select the
2695 date with the mouse (button 1). The calendar shows a period of three
2696 month. To scroll it to other months, use the keys `>' and `<'.
2697 If you don't like the calendar, turn it off with
2698 \(setq org-popup-calendar-for-date-prompt nil).
2699
2700 With optional argument TO-TIME, the date will immediately be converted
2701 to an internal time.
2702 With an optional argument WITH-TIME, the prompt will suggest to also
2703 insert a time. Note that when WITH-TIME is not set, you can still
2704 enter a time, and this function will inform the calling routine about
2705 this change. The calling routine may then choose to change the format
2706 used to insert the time stamp into the buffer to include the time."
2707 (let* ((default-time
2708 ;; Default time is either today, or, when entering a range,
2709 ;; the range start.
2710 (if (save-excursion
2711 (re-search-backward
2712 (concat org-ts-regexp "--\\=")
2713 (- (point) 20) t))
2714 (apply
2715 'encode-time
2716 (mapcar (lambda(x) (or x 0)) ;; FIXME: Problem with timezone?
2717 (parse-time-string (match-string 1))))
2718 (current-time)))
2719 (timestr (format-time-string
2720 (if with-time "%Y-%m-%d %H:%M" "%Y-%m-%d") default-time))
2721 (prompt (format "YYYY-MM-DD [%s]: " timestr))
2722 ans ans1 ans2
2723 second minute hour day month year tl)
2724
2725 (if org-popup-calendar-for-date-prompt
2726 ;; Also show a calendar for date selection
2727 ;; Copied (with modifications) from planner.el by John Wiegley
2728 (save-excursion
2729 (save-window-excursion
2730 (calendar)
2731 (calendar-forward-day (- (time-to-days default-time)
2732 (calendar-absolute-from-gregorian
2733 (calendar-current-date))))
2734 (let* ((old-map (current-local-map))
2735 (map (copy-keymap calendar-mode-map))
2736 (minibuffer-local-map (copy-keymap minibuffer-local-map)))
2737 (define-key map (kbd "RET") 'org-calendar-select)
2738 (define-key map (if org-xemacs-p [button1] [mouse-1])
2739 'org-calendar-select)
2740 (define-key minibuffer-local-map [(meta shift left)]
2741 (lambda () (interactive)
2742 (org-eval-in-calendar '(calendar-backward-month 1))))
2743 (define-key minibuffer-local-map [(meta shift right)]
2744 (lambda () (interactive)
2745 (org-eval-in-calendar '(calendar-forward-month 1))))
2746 (define-key minibuffer-local-map [(shift up)]
2747 (lambda () (interactive)
2748 (org-eval-in-calendar '(calendar-backward-week 1))))
2749 (define-key minibuffer-local-map [(shift down)]
2750 (lambda () (interactive)
2751 (org-eval-in-calendar '(calendar-forward-week 1))))
2752 (define-key minibuffer-local-map [(shift left)]
2753 (lambda () (interactive)
2754 (org-eval-in-calendar '(calendar-backward-day 1))))
2755 (define-key minibuffer-local-map [(shift right)]
2756 (lambda () (interactive)
2757 (org-eval-in-calendar '(calendar-forward-day 1))))
2758 (define-key minibuffer-local-map ">"
2759 (lambda () (interactive)
2760 (org-eval-in-calendar '(scroll-calendar-left 1))))
2761 (define-key minibuffer-local-map "<"
2762 (lambda () (interactive)
2763 (org-eval-in-calendar '(scroll-calendar-right 1))))
2764 (unwind-protect
2765 (progn
2766 (use-local-map map)
2767 (setq ans (read-string prompt "" nil nil))
2768 (setq ans (or ans1 ans2 ans)))
2769 (use-local-map old-map)))))
2770 ;; Naked prompt only
2771 (setq ans (read-string prompt "" nil timestr)))
2772
2773 (if (string-match
2774 "^ *\\(\\([0-9]+\\)-\\)?\\([0-1]?[0-9]\\)-\\([0-3]?[0-9]\\)\\([^-0-9]\\|$\\)" ans)
2775 (progn
2776 (setq year (if (match-end 2)
2777 (string-to-number (match-string 2 ans))
2778 (string-to-number (format-time-string "%Y")))
2779 month (string-to-number (match-string 3 ans))
2780 day (string-to-number (match-string 4 ans)))
2781 (if (< year 100) (setq year (+ 2000 year)))
2782 (setq ans (replace-match (format "%04d-%02d-%02d" year month day)
2783 t t ans))))
2784 (setq tl (parse-time-string ans)
2785 year (or (nth 5 tl) (string-to-number (format-time-string "%Y")))
2786 month (or (nth 4 tl) (string-to-number (format-time-string "%m")))
2787 day (or (nth 3 tl) (string-to-number (format-time-string "%d")))
2788 hour (or (nth 2 tl) (string-to-number (format-time-string "%H")))
2789 minute (or (nth 1 tl) (string-to-number (format-time-string "%M")))
2790 second (or (nth 0 tl) 0))
2791 (if (and (boundp 'org-time-was-given)
2792 (nth 2 tl))
2793 (setq org-time-was-given t))
2794 (if (< year 100) (setq year (+ 2000 year)))
2795 (if to-time
2796 (encode-time second minute hour day month year)
2797 (if (or (nth 1 tl) (nth 2 tl))
2798 (format "%04d-%02d-%02d %02d:%02d" year month day hour minute)
2799 (format "%04d-%02d-%02d" year month day)))))
2800
2801 (defun org-eval-in-calendar (form)
2802 "Eval FORM in the calendar window and return to current window.
2803 Also, store the cursor date in variable ans2."
2804 (let ((sw (selected-window)))
2805 (select-window (get-buffer-window "*Calendar*"))
2806 (eval form)
2807 (when (calendar-cursor-to-date)
2808 (let* ((date (calendar-cursor-to-date))
2809 (time (encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date))))
2810 (setq ans2 (format-time-string "%Y-%m-%d" time))))
2811 (select-window sw)))
2812
2813 (defun org-calendar-select ()
2814 "Return to `org-read-date' with the date currently selected.
2815 This is used by `org-read-date' in a temporary keymap for the calendar buffer."
2816 (interactive)
2817 (when (calendar-cursor-to-date)
2818 (let* ((date (calendar-cursor-to-date))
2819 (time (encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date))))
2820 (setq ans1 (format-time-string "%Y-%m-%d" time)))
2821 (if (active-minibuffer-window) (exit-minibuffer))))
2822
2823 (defun org-check-deadlines (ndays)
2824 "Check if there are any deadlines due or past due.
2825 A deadline is considered due if it happens within `org-deadline-warning-days'
2826 days from today's date. If the deadline appears in an entry marked DONE,
2827 it is not shown. The prefix arg NDAYS can be used to test that many
2828 days. If the prefix is a raw \\[universal-argument] prefix, all deadlines are shown."
2829 (interactive "P")
2830 (let* ((org-warn-days
2831 (cond
2832 ((equal ndays '(4)) 100000)
2833 (ndays (prefix-numeric-value ndays))
2834 (t org-deadline-warning-days)))
2835 (case-fold-search nil)
2836 (regexp (concat "\\<" org-deadline-string " *<\\([^>]+\\)>"))
2837 (callback
2838 (lambda ()
2839 (and (let ((d1 (time-to-days (current-time)))
2840 (d2 (time-to-days
2841 (org-time-string-to-time (match-string 1)))))
2842 (< (- d2 d1) org-warn-days))
2843 (not (org-entry-is-done-p))))))
2844 (message "%d deadlines past-due or due within %d days"
2845 (org-occur regexp callback)
2846 org-warn-days)))
2847
2848 (defun org-evaluate-time-range (&optional to-buffer)
2849 "Evaluate a time range by computing the difference between start and end.
2850 Normally the result is just printed in the echo area, but with prefix arg
2851 TO-BUFFER, the result is inserted just after the date stamp into the buffer.
2852 If the time range is actually in a table, the result is inserted into the
2853 next column.
2854 For time difference computation, a year is assumed to be exactly 365
2855 days in order to avoid rounding problems."
2856 (interactive "P")
2857 (save-excursion
2858 (unless (org-at-date-range-p)
2859 (goto-char (point-at-bol))
2860 (re-search-forward org-tr-regexp (point-at-eol) t))
2861 (if (not (org-at-date-range-p))
2862 (error "Not at a time-stamp range, and none found in current line.")))
2863 (let* ((ts1 (match-string 1))
2864 (ts2 (match-string 2))
2865 (havetime (or (> (length ts1) 15) (> (length ts2) 15)))
2866 (match-end (match-end 0))
2867 (time1 (org-time-string-to-time ts1))
2868 (time2 (org-time-string-to-time ts2))
2869 (t1 (time-to-seconds time1))
2870 (t2 (time-to-seconds time2))
2871 (diff (abs (- t2 t1)))
2872 (negative (< (- t2 t1) 0))
2873 ;; (ys (floor (* 365 24 60 60)))
2874 (ds (* 24 60 60))
2875 (hs (* 60 60))
2876 (fy "%dy %dd %02d:%02d")
2877 (fy1 "%dy %dd")
2878 (fd "%dd %02d:%02d")
2879 (fd1 "%dd")
2880 (fh "%02d:%02d")
2881 y d h m align)
2882 ;; FIXME: Should I re-introduce years, make year refer to same date?
2883 ;; This would be the only useful way to have years, actually.
2884 (if havetime
2885 (setq ; y (floor (/ diff ys)) diff (mod diff ys)
2886 y 0
2887 d (floor (/ diff ds)) diff (mod diff ds)
2888 h (floor (/ diff hs)) diff (mod diff hs)
2889 m (floor (/ diff 60)))
2890 (setq ; y (floor (/ diff ys)) diff (mod diff ys)
2891 y 0
2892 d (floor (+ (/ diff ds) 0.5))
2893 h 0 m 0))
2894 (if (not to-buffer)
2895 (message (org-make-tdiff-string y d h m))
2896 (when (org-at-table-p)
2897 (goto-char match-end)
2898 (setq align t)
2899 (and (looking-at " *|") (goto-char (match-end 0))))
2900 (if (looking-at
2901 "\\( *-? *[0-9]+y\\)?\\( *[0-9]+d\\)? *[0-9][0-9]:[0-9][0-9]")
2902 (replace-match ""))
2903 (if negative (insert " -"))
2904 (if (> y 0) (insert " " (format (if havetime fy fy1) y d h m))
2905 (if (> d 0) (insert " " (format (if havetime fd fd1) d h m))
2906 (insert " " (format fh h m))))
2907 (if align (org-table-align))
2908 (message "Time difference inserted"))))
2909
2910 (defun org-make-tdiff-string (y d h m)
2911 (let ((fmt "")
2912 (l nil))
2913 (if (> y 0) (setq fmt (concat fmt "%d year" (if (> y 1) "s" "") " ")
2914 l (push y l)))
2915 (if (> d 0) (setq fmt (concat fmt "%d day" (if (> d 1) "s" "") " ")
2916 l (push d l)))
2917 (if (> h 0) (setq fmt (concat fmt "%d hour" (if (> h 1) "s" "") " ")
2918 l (push h l)))
2919 (if (> m 0) (setq fmt (concat fmt "%d minute" (if (> m 1) "s" "") " ")
2920 l (push m l)))
2921 (apply 'format fmt (nreverse l))))
2922
2923 (defun org-time-string-to-time (s)
2924 (apply 'encode-time (org-parse-time-string s)))
2925
2926 (defun org-parse-time-string (s &optional nodefault)
2927 "Parse the standard Org-mode time string.
2928 This should be a lot faster than the normal `parse-time-string'.
2929 If time is not given, defaults to 0:00. However, with optional NODEFAULT,
2930 hour and minute fields will be nil if not given."
2931 (if (string-match org-ts-regexp1 s)
2932 (list 0
2933 (if (or (match-beginning 8) (not nodefault))
2934 (string-to-number (or (match-string 8 s) "0")))
2935 (if (or (match-beginning 7) (not nodefault))
2936 (string-to-number (or (match-string 7 s) "0")))
2937 (string-to-number (match-string 4 s))
2938 (string-to-number (match-string 3 s))
2939 (string-to-number (match-string 2 s))
2940 nil nil nil)
2941 (make-list 9 0)))
2942
2943 (defun org-timestamp-up (&optional arg)
2944 "Increase the date item at the cursor by one.
2945 If the cursor is on the year, change the year. If it is on the month or
2946 the day, change that.
2947 With prefix ARG, change by that many units."
2948 (interactive "p")
2949 (org-timestamp-change (prefix-numeric-value arg)))
2950
2951 (defun org-timestamp-down (&optional arg)
2952 "Decrease the date item at the cursor by one.
2953 If the cursor is on the year, change the year. If it is on the month or
2954 the day, change that.
2955 With prefix ARG, change by that many units."
2956 (interactive "p")
2957 (org-timestamp-change (- (prefix-numeric-value arg))))
2958
2959 (defun org-timestamp-up-day (&optional arg)
2960 "Increase the date in the time stamp by one day.
2961 With prefix ARG, change that many days."
2962 (interactive "p")
2963 (org-timestamp-change (prefix-numeric-value arg) 'day))
2964
2965 (defun org-timestamp-down-day (&optional arg)
2966 "Decrease the date in the time stamp by one day.
2967 With prefix ARG, change that many days."
2968 (interactive "p")
2969 (org-timestamp-change (- (prefix-numeric-value arg)) 'day))
2970
2971 (defsubst org-pos-in-match-range (pos n)
2972 (and (match-beginning n)
2973 (<= (match-beginning n) pos)
2974 (>= (match-end n) pos)))
2975
2976 (defun org-at-timestamp-p ()
2977 "Determine if the cursor is or at a timestamp."
2978 (interactive)
2979 (let* ((tsr org-ts-regexp2)
2980 (pos (point))
2981 (ans (or (looking-at tsr)
2982 (save-excursion
2983 (skip-chars-backward "^<\n\r\t")
2984 (if (> (point) 1) (backward-char 1))
2985 (and (looking-at tsr)
2986 (> (- (match-end 0) pos) -1))))))
2987 (and (boundp 'org-ts-what)
2988 (setq org-ts-what
2989 (cond
2990 ((org-pos-in-match-range pos 2) 'year)
2991 ((org-pos-in-match-range pos 3) 'month)
2992 ((org-pos-in-match-range pos 7) 'hour)
2993 ((org-pos-in-match-range pos 8) 'minute)
2994 ((or (org-pos-in-match-range pos 4)
2995 (org-pos-in-match-range pos 5)) 'day)
2996 (t 'day))))
2997 ans))
2998
2999 (defun org-timestamp-change (n &optional what)
3000 "Change the date in the time stamp at point.
3001 The date will be changed by N times WHAT. WHAT can be `day', `month',
3002 `year', `minute', `second'. If WHAT is not given, the cursor position
3003 in the timestamp determines what will be changed."
3004 (let ((fmt (car org-time-stamp-formats))
3005 org-ts-what
3006 (pos (point))
3007 ts time time0)
3008 (if (not (org-at-timestamp-p))
3009 (error "Not at a timestamp"))
3010 (setq org-ts-what (or what org-ts-what))
3011 (setq fmt (if (<= (abs (- (cdr org-ts-lengths)
3012 (- (match-end 0) (match-beginning 0))))
3013 1)
3014 (cdr org-time-stamp-formats)
3015 (car org-time-stamp-formats)))
3016 (setq ts (match-string 0))
3017 (replace-match "")
3018 (setq time0 (org-parse-time-string ts))
3019 (setq time
3020 (apply 'encode-time
3021 (append
3022 (list (or (car time0) 0))
3023 (list (+ (if (eq org-ts-what 'minute) n 0) (nth 1 time0)))
3024 (list (+ (if (eq org-ts-what 'hour) n 0) (nth 2 time0)))
3025 (list (+ (if (eq org-ts-what 'day) n 0) (nth 3 time0)))
3026 (list (+ (if (eq org-ts-what 'month) n 0) (nth 4 time0)))
3027 (list (+ (if (eq org-ts-what 'year) n 0) (nth 5 time0)))
3028 (nthcdr 6 time0))))
3029 (if (eq what 'calendar)
3030 (let ((cal-date
3031 (save-excursion
3032 (save-match-data
3033 (set-buffer "*Calendar*")
3034 (calendar-cursor-to-date)))))
3035 (setcar (nthcdr 4 time0) (nth 0 cal-date)) ; month
3036 (setcar (nthcdr 3 time0) (nth 1 cal-date)) ; day
3037 (setcar (nthcdr 5 time0) (nth 2 cal-date)) ; year
3038 (setcar time0 (or (car time0) 0))
3039 (setcar (nthcdr 1 time0) (or (nth 1 time0) 0))
3040 (setcar (nthcdr 2 time0) (or (nth 1 time0) 0))
3041 (setq time (apply 'encode-time time0))))
3042 (insert (setq org-last-changed-timestamp (format-time-string fmt time)))
3043 (goto-char pos)
3044 ;; Try to recenter the calendar window, if any
3045 (if (and org-calendar-follow-timestamp-change
3046 (get-buffer-window "*Calendar*" t)
3047 (memq org-ts-what '(day month year)))
3048 (org-recenter-calendar (time-to-days time)))))
3049
3050 (defun org-recenter-calendar (date)
3051 "If the calendar is visible, recenter it to DATE."
3052 (let* ((win (selected-window))
3053 (cwin (get-buffer-window "*Calendar*" t)))
3054 (when cwin
3055 (select-window cwin)
3056 (calendar-goto-date (if (listp date) date
3057 (calendar-gregorian-from-absolute date)))
3058 (select-window win))))
3059
3060 (defun org-goto-calendar (&optional arg)
3061 "Go to the Emacs calendar at the current date.
3062 If there is a time stamp in the current line, go to that date.
3063 A prefix ARG can be used force the current date."
3064 (interactive "P")
3065 (let ((tsr org-ts-regexp) diff)
3066 (if (or (org-at-timestamp-p)
3067 (save-excursion
3068 (beginning-of-line 1)
3069 (looking-at (concat ".*" tsr))))
3070 (let ((d1 (time-to-days (current-time)))
3071 (d2 (time-to-days
3072 (org-time-string-to-time (match-string 1)))))
3073 (setq diff (- d2 d1))))
3074 (calendar)
3075 (calendar-goto-today)
3076 (if (and diff (not arg)) (calendar-forward-day diff))))
3077
3078 (defun org-date-from-calendar ()
3079 "Insert time stamp corresponding to cursor date in *Calendar* buffer.
3080 If there is already a time stamp at the cursor position, update it."
3081 (interactive)
3082 (org-timestamp-change 0 'calendar))
3083
3084 ;;; Agenda, and Diary Integration
3085
3086 ;;; Define the mode
3087
3088 (defvar org-agenda-mode-map (make-sparse-keymap)
3089 "Keymap for `org-agenda-mode'.")
3090
3091 (defvar org-agenda-menu)
3092 (defvar org-agenda-follow-mode nil)
3093 (defvar org-agenda-buffer-name "*Org Agenda*")
3094 (defvar org-agenda-redo-command nil)
3095
3096 ;;;###autoload
3097 (defun org-agenda-mode ()
3098 "Mode for time-sorted view on action items in Org-mode files.
3099
3100 The following commands are available:
3101
3102 \\{org-agenda-mode-map}"
3103 (interactive)
3104 (kill-all-local-variables)
3105 (setq major-mode 'org-agenda-mode)
3106 (setq mode-name "Org-Agenda")
3107 (use-local-map org-agenda-mode-map)
3108 (easy-menu-add org-agenda-menu)
3109 (if org-startup-truncated (setq truncate-lines t))
3110 (add-hook 'post-command-hook 'org-agenda-post-command-hook nil 'local)
3111 (add-hook 'pre-command-hook 'org-unhighlight nil 'local)
3112 (setq org-agenda-follow-mode nil)
3113 (easy-menu-change
3114 '("Agenda") "Agenda Files"
3115 (append
3116 (list
3117 ["Edit File List" (customize-variable 'org-agenda-files) t]
3118 "--")
3119 (mapcar 'org-file-menu-entry org-agenda-files)))
3120 (org-agenda-set-mode-name)
3121 (run-mode-hooks 'org-agenda-mode-hook))
3122
3123 (define-key org-agenda-mode-map [(tab)] 'org-agenda-goto)
3124 (define-key org-agenda-mode-map [(return)] 'org-agenda-switch-to)
3125 (define-key org-agenda-mode-map " " 'org-agenda-show)
3126 (define-key org-agenda-mode-map "\C-c\C-t" 'org-agenda-todo)
3127 (define-key org-agenda-mode-map "o" 'delete-other-windows)
3128 (define-key org-agenda-mode-map "l" 'org-agenda-recenter)
3129 (define-key org-agenda-mode-map "t" 'org-agenda-todo)
3130 (define-key org-agenda-mode-map "." 'org-agenda-goto-today)
3131 (define-key org-agenda-mode-map "w" 'org-agenda-toggle-week-view)
3132 (define-key org-agenda-mode-map [(shift right)] 'org-agenda-date-later)
3133 (define-key org-agenda-mode-map [(shift left)] 'org-agenda-date-earlier)
3134
3135 (define-key org-agenda-mode-map ">" 'org-agenda-date-prompt)
3136 (let ((l '(1 2 3 4 5 6 7 8 9 0)))
3137 (while l (define-key org-agenda-mode-map
3138 (int-to-string (pop l)) 'digit-argument)))
3139
3140 (define-key org-agenda-mode-map "f" 'org-agenda-follow-mode)
3141 (define-key org-agenda-mode-map "d" 'org-agenda-toggle-diary)
3142 (define-key org-agenda-mode-map "g" 'org-agenda-toggle-time-grid)
3143 (define-key org-agenda-mode-map "r" 'org-agenda-redo)
3144 (define-key org-agenda-mode-map "q" 'org-agenda-quit)
3145 (define-key org-agenda-mode-map "x" 'org-agenda-exit)
3146 (define-key org-agenda-mode-map "P" 'org-agenda-show-priority)
3147 (define-key org-agenda-mode-map "n" 'next-line)
3148 (define-key org-agenda-mode-map "p" 'previous-line)
3149 (define-key org-agenda-mode-map "\C-n" 'org-agenda-next-date-line)
3150 (define-key org-agenda-mode-map "\C-p" 'org-agenda-previous-date-line)
3151 (define-key org-agenda-mode-map "," 'org-agenda-priority)
3152 (define-key org-agenda-mode-map "\C-c," 'org-agenda-priority)
3153 (define-key org-agenda-mode-map "i" 'org-agenda-diary-entry)
3154 (define-key org-agenda-mode-map "c" 'org-agenda-goto-calendar)
3155 (eval-after-load "calendar"
3156 '(define-key calendar-mode-map org-calendar-to-agenda-key
3157 'org-calendar-goto-agenda))
3158 (define-key org-agenda-mode-map "C" 'org-agenda-convert-date)
3159 (define-key org-agenda-mode-map "m" 'org-agenda-phases-of-moon)
3160 (define-key org-agenda-mode-map "M" 'org-agenda-phases-of-moon)
3161 (define-key org-agenda-mode-map "s" 'org-agenda-sunrise-sunset)
3162 (define-key org-agenda-mode-map "S" 'org-agenda-sunrise-sunset)
3163 (define-key org-agenda-mode-map "h" 'org-agenda-holidays)
3164 (define-key org-agenda-mode-map "H" 'org-agenda-holidays)
3165 (define-key org-agenda-mode-map "+" 'org-agenda-priority-up)
3166 (define-key org-agenda-mode-map "-" 'org-agenda-priority-down)
3167 (define-key org-agenda-mode-map [(shift up)] 'org-agenda-priority-up)
3168 (define-key org-agenda-mode-map [(shift down)] 'org-agenda-priority-down)
3169 (define-key org-agenda-mode-map [(right)] 'org-agenda-later)
3170 (define-key org-agenda-mode-map [(left)] 'org-agenda-earlier)
3171
3172 (defvar org-agenda-keymap (copy-keymap org-agenda-mode-map)
3173 "Local keymap for agenda entries from Org-mode.")
3174
3175 (define-key org-agenda-keymap
3176 (if org-xemacs-p [(button2)] [(mouse-2)]) 'org-agenda-goto-mouse)
3177 (define-key org-agenda-keymap
3178 (if org-xemacs-p [(button3)] [(mouse-3)]) 'org-agenda-show-mouse)
3179
3180 (easy-menu-define org-agenda-menu org-agenda-mode-map "Agenda menu"
3181 '("Agenda"
3182 ("Agenda Files")
3183 "--"
3184 ["Show" org-agenda-show t]
3185 ["Go To (other window)" org-agenda-goto t]
3186 ["Go To (one window)" org-agenda-switch-to t]
3187 ["Follow Mode" org-agenda-follow-mode
3188 :style toggle :selected org-agenda-follow-mode :active t]
3189 "--"
3190 ["Cycle TODO" org-agenda-todo t]
3191 ("Reschedule"
3192 ["Reschedule +1 day" org-agenda-date-later t]
3193 ["Reschedule -1 day" org-agenda-date-earlier t]
3194 "--"
3195 ["Reschedule to ..." org-agenda-date-prompt t])
3196 ("Priority"
3197 ["Set Priority" org-agenda-priority t]
3198 ["Increase Priority" org-agenda-priority-up t]
3199 ["Decrease Priority" org-agenda-priority-down t]
3200 ["Show Priority" org-agenda-show-priority t])
3201 "--"
3202 ["Rebuild buffer" org-agenda-redo t]
3203 ["Goto Today" org-agenda-goto-today t]
3204 ["Next Dates" org-agenda-later (local-variable-p 'starting-day)]
3205 ["Previous Dates" org-agenda-earlier (local-variable-p 'starting-day)]
3206 "--"
3207 ["Week/Day View" org-agenda-toggle-week-view
3208 (local-variable-p 'starting-day)]
3209 ["Include Diary" org-agenda-toggle-diary
3210 :style toggle :selected org-agenda-include-diary :active t]
3211 ["Use Time Grid" org-agenda-toggle-time-grid
3212 :style toggle :selected org-agenda-use-time-grid :active t]
3213 "--"
3214 ["New Diary Entry" org-agenda-diary-entry t]
3215 ("Calendar Commands"
3216 ["Goto Calendar" org-agenda-goto-calendar t]
3217 ["Phases of the Moon" org-agenda-phases-of-moon t]
3218 ["Sunrise/Sunset" org-agenda-sunrise-sunset t]
3219 ["Holidays" org-agenda-holidays t]
3220 ["Convert" org-agenda-convert-date t])
3221 "--"
3222 ["Quit" org-agenda-quit t]
3223 ["Exit and Release Buffers" org-agenda-exit t]
3224 ))
3225
3226 (defvar org-agenda-markers nil
3227 "List of all currently active markers created by `org-agenda'.")
3228 (defvar org-agenda-last-marker-time (time-to-seconds (current-time))
3229 "Creation time of the last agenda marker.")
3230
3231 (defun org-agenda-new-marker (&optional pos)
3232 "Return a new agenda marker.
3233 Org-mode keeps a list of these markers and resets them when they are
3234 no longer in use."
3235 (let ((m (copy-marker (or pos (point)))))
3236 (setq org-agenda-last-marker-time (time-to-seconds (current-time)))
3237 (push m org-agenda-markers)
3238 m))
3239
3240 (defun org-agenda-maybe-reset-markers (&optional force)
3241 "Reset markers created by `org-agenda'. But only if they are old enough."
3242 (if (or force
3243 (> (- (time-to-seconds (current-time))
3244 org-agenda-last-marker-time)
3245 5))
3246 (while org-agenda-markers
3247 (move-marker (pop org-agenda-markers) nil))))
3248
3249 (defvar org-agenda-new-buffers nil
3250 "Buffers created to visit agenda files.")
3251
3252 (defun org-get-agenda-file-buffer (file)
3253 "Get a buffer visiting FILE. If the buffer needs to be created, add
3254 it to the list of buffers which might be released later."
3255 (let ((buf (find-buffer-visiting file)))
3256 (if buf
3257 buf ; just return it
3258 ;; Make a new buffer and remember it
3259 (setq buf (find-file-noselect file))
3260 (if buf (push buf org-agenda-new-buffers))
3261 buf)))
3262
3263 (defun org-release-buffers (blist)
3264 "Release all buffers in list, asking the user for confirmation when needed.
3265 When a buffer is unmodified, it is just killed. When modified, it is saved
3266 \(if the user agrees) and then killed."
3267 (let (buf file)
3268 (while (setq buf (pop blist))
3269 (setq file (buffer-file-name buf))
3270 (when (and (buffer-modified-p buf)
3271 file
3272 (y-or-n-p (format "Save file %s? " file)))
3273 (with-current-buffer buf (save-buffer)))
3274 (kill-buffer buf))))
3275
3276 (defvar org-respect-restriction nil) ; Dynamically-scoped param.
3277
3278 (defun org-timeline (&optional include-all)
3279 "Show a time-sorted view of the entries in the current org file.
3280 Only entries with a time stamp of today or later will be listed. With
3281 one \\[universal-argument] prefix argument, past entries will also be listed.
3282 With two \\[universal-argument] prefixes, all unfinished TODO items will also be shown,
3283 under the current date.
3284 If the buffer contains an active region, only check the region for
3285 dates."
3286 (interactive "P")
3287 (require 'calendar)
3288 (org-agenda-maybe-reset-markers 'force)
3289 (org-compile-prefix-format org-timeline-prefix-format)
3290 (let* ((dopast include-all)
3291 (dotodo (equal include-all '(16)))
3292 (entry (buffer-file-name))
3293 (org-agenda-files (list (buffer-file-name)))
3294 (date (calendar-current-date))
3295 (win (selected-window))
3296 (pos1 (point))
3297 (beg (if (org-region-active-p) (region-beginning) (point-min)))
3298 (end (if (org-region-active-p) (region-end) (point-max)))
3299 (day-numbers (org-get-all-dates beg end 'no-ranges
3300 t)) ; always include today
3301 (today (time-to-days (current-time)))
3302 (org-respect-restriction t)
3303 (past t)
3304 s e rtn d)
3305 (setq org-agenda-redo-command
3306 (list 'progn
3307 (list 'switch-to-buffer-other-window (current-buffer))
3308 (list 'org-timeline include-all)))
3309 (if (not dopast)
3310 ;; Remove past dates from the list of dates.
3311 (setq day-numbers (delq nil (mapcar (lambda(x)
3312 (if (>= x today) x nil))
3313 day-numbers))))
3314 (switch-to-buffer-other-window
3315 (get-buffer-create org-agenda-buffer-name))
3316 (setq buffer-read-only nil)
3317 (erase-buffer)
3318 (org-agenda-mode) (setq buffer-read-only nil)
3319 (while (setq d (pop day-numbers))
3320 (if (and (>= d today)
3321 dopast
3322 past)
3323 (progn
3324 (setq past nil)
3325 (insert (make-string 79 ?-) "\n")))
3326 (setq date (calendar-gregorian-from-absolute d))
3327 (setq s (point))
3328 (if dotodo
3329 (setq rtn (org-agenda-get-day-entries
3330 entry date :todo :timestamp))
3331 (setq rtn (org-agenda-get-day-entries entry date :timestamp)))
3332 (if (or rtn (equal d today))
3333 (progn
3334 (insert (calendar-day-name date) " "
3335 (number-to-string (extract-calendar-day date)) " "
3336 (calendar-month-name (extract-calendar-month date)) " "
3337 (number-to-string (extract-calendar-year date)) "\n")
3338 (put-text-property s (1- (point)) 'face
3339 'org-link-face)
3340 (if (equal d today)
3341 (put-text-property s (1- (point)) 'org-today t))
3342 (insert (org-finalize-agenda-entries rtn) "\n")
3343 (put-text-property s (1- (point)) 'day d))))
3344 (goto-char (point-min))
3345 (setq buffer-read-only t)
3346 (goto-char (or (text-property-any (point-min) (point-max) 'org-today t)
3347 (point-min)))
3348 (when (not org-select-timeline-window)
3349 (select-window win)
3350 (goto-char pos1))))
3351
3352 ;;;###autoload
3353 (defun org-agenda (&optional include-all start-day ndays)
3354 "Produce a weekly view from all files in variable `org-agenda-files'.
3355 The view will be for the current week, but from the overview buffer you
3356 will be able to go to other weeks.
3357 With one \\[universal-argument] prefix argument INCLUDE-ALL, all unfinished TODO items will
3358 also be shown, under the current date.
3359 START-DAY defaults to TODAY, or to the most recent match for the weekday
3360 given in `org-agenda-start-on-weekday'.
3361 NDAYS defaults to `org-agenda-ndays'."
3362 (interactive "P")
3363 (org-agenda-maybe-reset-markers 'force)
3364 (org-compile-prefix-format org-agenda-prefix-format)
3365 (require 'calendar)
3366 (let* ((org-agenda-start-on-weekday
3367 (if (or (equal ndays 1)
3368 (and (null ndays) (equal 1 org-agenda-ndays)))
3369 nil org-agenda-start-on-weekday))
3370 (files (copy-sequence org-agenda-files))
3371 (win (selected-window))
3372 (today (time-to-days (current-time)))
3373 (sd (or start-day today))
3374 (start (if (or (null org-agenda-start-on-weekday)
3375 (< org-agenda-ndays 7))
3376 sd
3377 (let* ((nt (calendar-day-of-week
3378 (calendar-gregorian-from-absolute sd)))
3379 (n1 org-agenda-start-on-weekday)
3380 (d (- nt n1)))
3381 (- sd (+ (if (< d 0) 7 0) d)))))
3382 (day-numbers (list start))
3383 (inhibit-redisplay t)
3384 s e rtn rtnall file date d start-pos end-pos todayp nd)
3385 (setq org-agenda-redo-command
3386 (list 'org-agenda include-all start-day ndays))
3387 ;; Make the list of days
3388 (setq ndays (or ndays org-agenda-ndays)
3389 nd ndays)
3390 (while (> ndays 1)
3391 (push (1+ (car day-numbers)) day-numbers)
3392 (setq ndays (1- ndays)))
3393 (setq day-numbers (nreverse day-numbers))
3394 (if (not (equal (current-buffer) (get-buffer org-agenda-buffer-name)))
3395 (progn
3396 (delete-other-windows)
3397 (switch-to-buffer-other-window
3398 (get-buffer-create org-agenda-buffer-name))))
3399 (setq buffer-read-only nil)
3400 (erase-buffer)
3401 (org-agenda-mode) (setq buffer-read-only nil)
3402 (set (make-local-variable 'starting-day) (car day-numbers))
3403 (set (make-local-variable 'include-all-loc) include-all)
3404 (when (and (or include-all org-agenda-include-all-todo)
3405 (member today day-numbers))
3406 (setq files org-agenda-files
3407 rtnall nil)
3408 (while (setq file (pop files))
3409 (catch 'nextfile
3410 (org-check-agenda-file file)
3411 (setq date (calendar-gregorian-from-absolute today)
3412 rtn (org-agenda-get-day-entries
3413 file date :todo))
3414 (setq rtnall (append rtnall rtn))))
3415 (when rtnall
3416 (insert "ALL CURRENTLY OPEN TODO ITEMS:\n")
3417 (add-text-properties (point-min) (1- (point))
3418 (list 'face 'org-link-face))
3419 (insert (org-finalize-agenda-entries rtnall) "\n")))
3420 (while (setq d (pop day-numbers))
3421 (setq date (calendar-gregorian-from-absolute d)
3422 s (point))
3423 (if (or (setq todayp (= d today))
3424 (and (not start-pos) (= d sd)))
3425 (setq start-pos (point))
3426 (if (and start-pos (not end-pos))
3427 (setq end-pos (point))))
3428 (setq files org-agenda-files
3429 rtnall nil)
3430 (while (setq file (pop files))
3431 (catch 'nextfile
3432 (org-check-agenda-file file)
3433 (setq rtn (org-agenda-get-day-entries file date))
3434 (setq rtnall (append rtnall rtn))))
3435 (if org-agenda-include-diary
3436 (progn
3437 (require 'diary-lib)
3438 (setq rtn (org-get-entries-from-diary date))
3439 (setq rtnall (append rtnall rtn))))
3440 (if (or rtnall org-agenda-show-all-dates)
3441 (progn
3442 (insert (format "%-9s %2d %s %4d\n"
3443 (calendar-day-name date)
3444 (extract-calendar-day date)
3445 (calendar-month-name (extract-calendar-month date))
3446 (extract-calendar-year date)))
3447 (put-text-property s (1- (point)) 'face
3448 'org-link-face)
3449 (if rtnall (insert
3450 (org-finalize-agenda-entries ;; FIXME: condition needed
3451 (org-agenda-add-time-grid-maybe
3452 rtnall nd todayp))
3453 "\n"))
3454 (put-text-property s (1- (point)) 'day d))))
3455 (goto-char (point-min))
3456 (setq buffer-read-only t)
3457 (if org-fit-agenda-window
3458 (fit-window-to-buffer nil (/ (* (frame-height) 3) 4)
3459 (/ (frame-height) 2)))
3460 (unless (and (pos-visible-in-window-p (point-min))
3461 (pos-visible-in-window-p (point-max)))
3462 (goto-char (1- (point-max)))
3463 (recenter -1)
3464 (if (not (pos-visible-in-window-p (or start-pos 1)))
3465 (progn
3466 (goto-char (or start-pos 1))
3467 (recenter 1))))
3468 (goto-char (or start-pos 1))
3469 (if (not org-select-agenda-window) (select-window win))
3470 (message "")))
3471
3472 (defun org-check-agenda-file (file)
3473 "Make sure FILE exists. If not, ask user what to do."
3474 ;; FIXME: this does not correctly change the menus
3475 ;; Could probably be fixed by explicitly going to the buffer.
3476 (when (not (file-exists-p file))
3477 (message "non-existent file %s. [R]emove from agenda-files or [A]bort?"
3478 file)
3479 (let ((r (downcase (read-char-exclusive))))
3480 (cond
3481 ((equal r ?r)
3482 (org-remove-file file)
3483 (throw 'nextfile t))
3484 (t (error "Abort"))))))
3485
3486 (defun org-agenda-quit ()
3487 "Exit agenda by removing the window or the buffer."
3488 (interactive)
3489 (let ((buf (current-buffer)))
3490 (if (not (one-window-p)) (delete-window))
3491 (kill-buffer buf)
3492 (org-agenda-maybe-reset-markers 'force)))
3493
3494 (defun org-agenda-exit ()
3495 "Exit agenda by removing the window or the buffer.
3496 Also kill all Org-mode buffers which have been loaded by `org-agenda'.
3497 Org-mode buffers visited directly by the user will not be touched."
3498 (interactive)
3499 (org-release-buffers org-agenda-new-buffers)
3500 (setq org-agenda-new-buffers nil)
3501 (org-agenda-quit))
3502
3503 (defun org-agenda-redo ()
3504 "Rebuild Agenda."
3505 (interactive)
3506 (eval org-agenda-redo-command))
3507
3508 (defun org-agenda-goto-today ()
3509 "Go to today."
3510 (interactive)
3511 (if (boundp 'starting-day)
3512 (let ((cmd (car org-agenda-redo-command))
3513 (iall (nth 1 org-agenda-redo-command))
3514 (nday (nth 3 org-agenda-redo-command)))
3515 (eval (list cmd iall nil nday)))
3516 (goto-char (or (text-property-any (point-min) (point-max) 'org-today t)
3517 (point-min)))))
3518
3519 (defun org-agenda-later (arg)
3520 "Go forward in time by `org-agenda-ndays' days.
3521 With prefix ARG, go forward that many times `org-agenda-ndays'."
3522 (interactive "p")
3523 (unless (boundp 'starting-day)
3524 (error "Not allowed"))
3525 (org-agenda (if (boundp 'include-all-loc) include-all-loc nil)
3526 (+ starting-day (* arg org-agenda-ndays))))
3527
3528 (defun org-agenda-earlier (arg)
3529 "Go back in time by `org-agenda-ndays' days.
3530 With prefix ARG, go back that many times `org-agenda-ndays'."
3531 (interactive "p")
3532 (unless (boundp 'starting-day)
3533 (error "Not allowed"))
3534 (org-agenda (if (boundp 'include-all-loc) include-all-loc nil)
3535 (- starting-day (* arg org-agenda-ndays))))
3536
3537 (defun org-agenda-toggle-week-view ()
3538 "Toggle weekly/daily view for aagenda."
3539 (interactive)
3540 (unless (boundp 'starting-day)
3541 (error "Not allowed"))
3542 (setq org-agenda-ndays
3543 (if (equal org-agenda-ndays 1) 7 1))
3544 (org-agenda include-all-loc
3545 (or (get-text-property (point) 'day)
3546 starting-day))
3547 (org-agenda-set-mode-name)
3548 (message "Switched to %s view"
3549 (if (equal org-agenda-ndays 1) "day" "week")))
3550
3551 (defun org-agenda-next-date-line (&optional arg)
3552 "Jump to the next line indicating a date in agenda buffer."
3553 (interactive "p")
3554 (beginning-of-line 1)
3555 (if (looking-at "^\\S-") (forward-char 1))
3556 (if (not (re-search-forward "^\\S-" nil t arg))
3557 (progn
3558 (backward-char 1)
3559 (error "No next date after this line in this buffer.")))
3560 (goto-char (match-beginning 0)))
3561
3562 (defun org-agenda-previous-date-line (&optional arg)
3563 "Jump to the next line indicating a date in agenda buffer."
3564 (interactive "p")
3565 (beginning-of-line 1)
3566 (if (not (re-search-backward "^\\S-" nil t arg))
3567 (error "No previous date before this line in this buffer.")))
3568
3569 ;; Initialize the highlight
3570 (defvar org-hl (funcall (if org-xemacs-p 'make-extent 'make-overlay) 1 1))
3571 (funcall (if org-xemacs-p 'set-extent-property 'overlay-put) org-hl
3572 'face 'highlight)
3573
3574 (defun org-highlight (begin end &optional buffer)
3575 "Highlight a region with overlay."
3576 (funcall (if org-xemacs-p 'set-extent-endpoints 'move-overlay)
3577 org-hl begin end (or buffer (current-buffer))))
3578
3579 (defun org-unhighlight ()
3580 "Detach overlay INDEX."
3581 (funcall (if org-xemacs-p 'detach-extent 'delete-overlay) org-hl))
3582
3583
3584 (defun org-agenda-follow-mode ()
3585 "Toggle follow mode in an agenda buffer."
3586 (interactive)
3587 (setq org-agenda-follow-mode (not org-agenda-follow-mode))
3588 (org-agenda-set-mode-name)
3589 (message "Follow mode is %s"
3590 (if org-agenda-follow-mode "on" "off")))
3591
3592 (defun org-agenda-toggle-diary ()
3593 "Toggle follow mode in an agenda buffer."
3594 (interactive)
3595 (setq org-agenda-include-diary (not org-agenda-include-diary))
3596 (org-agenda-redo)
3597 (org-agenda-set-mode-name)
3598 (message "Diary inclusion turned %s"
3599 (if org-agenda-include-diary "on" "off")))
3600
3601 (defun org-agenda-toggle-time-grid ()
3602 "Toggle follow mode in an agenda buffer."
3603 (interactive)
3604 (setq org-agenda-use-time-grid (not org-agenda-use-time-grid))
3605 (org-agenda-redo)
3606 (org-agenda-set-mode-name)
3607 (message "Time-grid turned %s"
3608 (if org-agenda-use-time-grid "on" "off")))
3609
3610 (defun org-agenda-set-mode-name ()
3611 "Set the mode name to indicate all the small mode settings."
3612 (setq mode-name
3613 (concat "Org-Agenda"
3614 (if (equal org-agenda-ndays 1) " Day" "")
3615 (if (equal org-agenda-ndays 7) " Week" "")
3616 (if org-agenda-follow-mode " Follow" "")
3617 (if org-agenda-include-diary " Diary" "")
3618 (if org-agenda-use-time-grid " Grid" "")))
3619 (force-mode-line-update))
3620
3621 (defun org-agenda-post-command-hook ()
3622 (and (eolp) (not (bolp)) (backward-char 1))
3623 (if (and org-agenda-follow-mode
3624 (get-text-property (point) 'org-marker))
3625 (org-agenda-show)))
3626
3627 (defvar org-disable-diary nil) ;Dynamically-scoped param.
3628
3629 (defun org-get-entries-from-diary (date)
3630 "Get the (Emacs Calendar) diary entries for DATE."
3631 (let* ((fancy-diary-buffer "*temporary-fancy-diary-buffer*")
3632 (diary-display-hook '(fancy-diary-display))
3633 (list-diary-entries-hook
3634 (cons 'org-diary-default-entry list-diary-entries-hook))
3635 entries
3636 (org-disable-diary t))
3637 (save-excursion
3638 (save-window-excursion
3639 (list-diary-entries date 1)))
3640 (if (not (get-buffer fancy-diary-buffer))
3641 (setq entries nil)
3642 (with-current-buffer fancy-diary-buffer
3643 (setq buffer-read-only nil)
3644 (if (= (point-max) 1)
3645 ;; No entries
3646 (setq entries nil)
3647 ;; Omit the date and other unnecessary stuff
3648 (org-agenda-cleanup-fancy-diary)
3649 ;; Add prefix to each line and extend the text properties
3650 (if (= (point-max) 1)
3651 (setq entries nil)
3652 (setq entries (buffer-substring (point-min) (- (point-max) 1)))))
3653 (set-buffer-modified-p nil)
3654 (kill-buffer fancy-diary-buffer)))
3655 (when entries
3656 (setq entries (org-split-string entries "\n"))
3657 (setq entries
3658 (mapcar
3659 (lambda (x)
3660 (setq x (org-format-agenda-item "" x "Diary" 'time))
3661 ;; Extend the text properties to the beginning of the line
3662 (add-text-properties
3663 0 (length x)
3664 (text-properties-at (1- (length x)) x)
3665 x)
3666 x)
3667 entries)))))
3668
3669 (defun org-agenda-cleanup-fancy-diary ()
3670 "Remove unwanted stuff in buffer created by fancy-diary-display.
3671 This gets rid of the date, the underline under the date, and
3672 the dummy entry installed by `org-mode' to ensure non-empty diary for each
3673 date. Itt also removes lines that contain only whitespace."
3674 (goto-char (point-min))
3675 (if (looking-at ".*?:[ \t]*")
3676 (progn
3677 (replace-match "")
3678 (re-search-forward "\n=+$" nil t)
3679 (replace-match "")
3680 (while (re-search-backward "^ +\n?" nil t) (replace-match "")))
3681 (re-search-forward "\n=+$" nil t)
3682 (delete-region (point-min) (min (point-max) (1+ (match-end 0)))))
3683 (goto-char (point-min))
3684 (while (re-search-forward "^ +\n" nil t)
3685 (replace-match ""))
3686 (goto-char (point-min))
3687 (if (re-search-forward "^Org-mode dummy\n?" nil t)
3688 (replace-match "")))
3689
3690 ;; Advise the add-to-diary-list function to allow org to jump to
3691 ;; diary entries. Wrapped into eval-after-load to avoid loading
3692 ;; advice unnecessarily
3693 (eval-after-load "diary-lib"
3694 '(defadvice add-to-diary-list (before org-mark-diary-entry activate)
3695 "Make the position visible."
3696 (if (and org-disable-diary ;; called from org-agenda
3697 (stringp string)
3698 (buffer-file-name))
3699 (add-text-properties
3700 0 (length string)
3701 (list 'mouse-face 'highlight
3702 'keymap org-agenda-keymap
3703 'help-echo
3704 (format
3705 "mouse-2 or RET jump to diary file %s"
3706 (abbreviate-file-name (buffer-file-name)))
3707 'org-agenda-diary-link t
3708 'org-marker (org-agenda-new-marker (point-at-bol)))
3709 string))))
3710
3711 (defun org-diary-default-entry ()
3712 "Add a dummy entry to the diary.
3713 Needed to avoid empty dates which mess up holiday display."
3714 ;; Catch the error if dealing with the new add-to-diary-alist
3715 (condition-case nil
3716 (add-to-diary-list original-date "Org-mode dummy" "")
3717 (error
3718 (add-to-diary-list original-date "Org-mode dummy" "" nil))))
3719
3720 (defun org-add-file (&optional file)
3721 "Add current file to the list of files in variable `org-agenda-files'.
3722 These are the files which are being checked for agenda entries.
3723 Optional argument FILE means, use this file instead of the current.
3724 It is possible (but not recommended) to add this function to the
3725 `org-mode-hook'."
3726 (interactive)
3727 (catch 'exit
3728 (let* ((file (or file (buffer-file-name)
3729 (if (interactive-p)
3730 (error "Buffer is not visiting a file")
3731 (throw 'exit nil))))
3732 (true-file (file-truename file))
3733 (afile (abbreviate-file-name file))
3734 (present (delq nil (mapcar
3735 (lambda (x)
3736 (equal true-file (file-truename x)))
3737 org-agenda-files))))
3738 (if (not present)
3739 (progn
3740 (setq org-agenda-files
3741 (cons afile org-agenda-files))
3742 ;; Make sure custom.el does not end up with Org-mode
3743 (let ((org-mode-hook nil) (default-major-mode 'fundamental-mode))
3744 (customize-save-variable 'org-agenda-files org-agenda-files))
3745 (org-install-agenda-files-menu)
3746 (message "Added file: %s" afile))
3747 (message "File was already in list: %s" afile)))))
3748
3749 (defun org-remove-file (&optional file)
3750 "Remove current file from the list of files in variable `org-agenda-files'.
3751 These are the files which are being checked for agenda entries.
3752 Optional argument FILE means, use this file instead of the current."
3753 (interactive)
3754 (let* ((file (or file (buffer-file-name)))
3755 (true-file (file-truename file))
3756 (afile (abbreviate-file-name file))
3757 (files (delq nil (mapcar
3758 (lambda (x)
3759 (if (equal true-file
3760 (file-truename x))
3761 nil x))
3762 org-agenda-files))))
3763 (if (not (= (length files) (length org-agenda-files)))
3764 (progn
3765 (setq org-agenda-files files)
3766 (customize-save-variable 'org-agenda-files org-agenda-files)
3767 (org-install-agenda-files-menu)
3768 (message "Removed file: %s" afile))
3769 (message "File was not in list: %s" afile))))
3770
3771 (defun org-file-menu-entry (file)
3772 (vector file (list 'find-file file) t))
3773
3774 (defun org-get-all-dates (beg end &optional no-ranges force-today)
3775 "Return a list of all relevant day numbers from BEG to END buffer positions.
3776 If NO-RANGES is non-nil, include only the start and end dates of a range,
3777 not every single day in the range. If FORCE-TODAY is non-nil, make
3778 sure that TODAY is included in the list."
3779 (let (dates date day day1 day2 ts1 ts2)
3780 (if force-today
3781 (setq dates (list (time-to-days (current-time)))))
3782 (save-excursion
3783 (goto-char beg)
3784 (while (re-search-forward org-ts-regexp end t)
3785 (setq day (time-to-days (org-time-string-to-time
3786 (substring (match-string 1) 0 10))))
3787 (or (memq day dates) (push day dates)))
3788 (unless no-ranges
3789 (goto-char beg)
3790 (while (re-search-forward org-tr-regexp end t)
3791 (setq ts1 (substring (match-string 1) 0 10)
3792 ts2 (substring (match-string 2) 0 10)
3793 day1 (time-to-days (org-time-string-to-time ts1))
3794 day2 (time-to-days (org-time-string-to-time ts2)))
3795 (while (< (setq day1 (1+ day1)) day2)
3796 (or (memq day1 dates) (push day1 dates)))))
3797 (sort dates '<))))
3798
3799 ;;;###autoload
3800 (defun org-diary (&rest args)
3801 "Return diary information from org-files.
3802 This function can be used in a \"sexp\" diary entry in the Emacs calendar.
3803 It accesses org files and extracts information from those files to be
3804 listed in the diary. The function accepts arguments specifying what
3805 items should be listed. The following arguments are allowed:
3806
3807 :timestamp List the headlines of items containing a date stamp or
3808 date range matching the selected date. Deadlines will
3809 also be listed, on the expiration day.
3810
3811 :deadline List any deadlines past due, or due within
3812 `org-deadline-warning-days'. The listing occurs only
3813 in the diary for *today*, not at any other date. If
3814 an entry is marked DONE, it is no longer listed.
3815
3816 :scheduled List all items which are scheduled for the given date.
3817 The diary for *today* also contains items which were
3818 scheduled earlier and are not yet marked DONE.
3819
3820 :todo List all TODO items from the org-file. This may be a
3821 long list - so this is not turned on by default.
3822 Like deadlines, these entries only show up in the
3823 diary for *today*, not at any other date.
3824
3825 The call in the diary file should look like this:
3826
3827 &%%(org-diary) ~/path/to/some/orgfile.org
3828
3829 Use a separate line for each org file to check. Or, if you omit the file name,
3830 all files listed in `org-agenda-files' will be checked automatically:
3831
3832 &%%(org-diary)
3833
3834 If you don't give any arguments (as in the example above), the default
3835 arguments (:deadline :scheduled :timestamp) are used. So the example above may
3836 also be written as
3837
3838 &%%(org-diary :deadline :timestamp :scheduled)
3839
3840 The function expects the lisp variables `entry' and `date' to be provided
3841 by the caller, because this is how the calendar works. Don't use this
3842 function from a program - use `org-agenda-get-day-entries' instead."
3843 (org-agenda-maybe-reset-markers)
3844 (org-compile-agenda-prefix-format org-agenda-prefix-format)
3845 (setq args (or args '(:deadline :scheduled :timestamp)))
3846 (let* ((files (if (and entry (stringp entry) (string-match "\\S-" entry))
3847 (list entry)
3848 org-agenda-files))
3849 file rtn results)
3850 ;; If this is called during org-agenda, don't return any entries to
3851 ;; the calendar. Org Agenda will list these entries itself.
3852 (if org-disable-diary (setq files nil))
3853 (while (setq file (pop files))
3854 (setq rtn (apply 'org-agenda-get-day-entries file date args))
3855 (setq results (append results rtn)))
3856 (concat (org-finalize-agenda-entries results) "\n")))
3857
3858 (defun org-agenda-get-day-entries (file date &rest args)
3859 "Does the work for `org-diary' and `org-agenda'.
3860 FILE is the path to a file to be checked for entries. DATE is date like
3861 the one returned by `calendar-current-date'. ARGS are symbols indicating
3862 which kind of entries should be extracted. For details about these, see
3863 the documentation of `org-diary'."
3864 (setq args (or args '(:deadline :scheduled :timestamp)))
3865 (let* ((org-startup-with-deadline-check nil)
3866 (org-startup-folded nil)
3867 (buffer (if (file-exists-p file)
3868 (org-get-agenda-file-buffer file)
3869 (error "No such file %s" file)))
3870 arg results rtn)
3871 (if (not buffer)
3872 ;; If file does not exist, make sure an error message ends up in diary
3873 (list (format "ORG-AGENDA-ERROR: No such org-file %s" file))
3874 (with-current-buffer buffer
3875 (unless (eq major-mode 'org-mode)
3876 (error "Agenda file %s is not in `org-mode'" file))
3877 (let ((case-fold-search nil))
3878 (save-excursion
3879 (save-restriction
3880 (if org-respect-restriction
3881 (if (org-region-active-p)
3882 ;; Respect a region to restrict search
3883 (narrow-to-region (region-beginning) (region-end)))
3884 ;; If we work for the calendar or many files,
3885 ;; get rid of any restriction
3886 (widen))
3887 ;; The way we repeatedly append to `results' makes it O(n^2) :-(
3888 (while (setq arg (pop args))
3889 (cond
3890 ((and (eq arg :todo)
3891 (equal date (calendar-current-date)))
3892 (setq rtn (org-agenda-get-todos))
3893 (setq results (append results rtn)))
3894 ((eq arg :timestamp)
3895 (setq rtn (org-agenda-get-blocks))
3896 (setq results (append results rtn))
3897 (setq rtn (org-agenda-get-timestamps))
3898 (setq results (append results rtn)))
3899 ((eq arg :scheduled)
3900 (setq rtn (org-agenda-get-scheduled))
3901 (setq results (append results rtn)))
3902 ((and (eq arg :deadline)
3903 (equal date (calendar-current-date)))
3904 (setq rtn (org-agenda-get-deadlines))
3905 (setq results (append results rtn))))))))
3906 results))))
3907
3908 (defun org-entry-is-done-p ()
3909 "Is the current entry marked DONE?"
3910 (save-excursion
3911 (and (re-search-backward "[\r\n]\\*" nil t)
3912 (looking-at org-nl-done-regexp))))
3913
3914 (defun org-at-date-range-p ()
3915 "Is the cursor inside a date range?"
3916 (interactive)
3917 (save-excursion
3918 (catch 'exit
3919 (let ((pos (point)))
3920 (skip-chars-backward "^<\r\n")
3921 (skip-chars-backward "<")
3922 (and (looking-at org-tr-regexp)
3923 (>= (match-end 0) pos)
3924 (throw 'exit t))
3925 (skip-chars-backward "^<\r\n")
3926 (skip-chars-backward "<")
3927 (and (looking-at org-tr-regexp)
3928 (>= (match-end 0) pos)
3929 (throw 'exit t)))
3930 nil)))
3931
3932 (defun org-agenda-get-todos ()
3933 "Return the TODO information for agenda display."
3934 (let* ((props (list 'face nil
3935 'done-face 'org-done-face
3936 'mouse-face 'highlight
3937 'keymap org-agenda-keymap
3938 'help-echo
3939 (format "mouse-2 or RET jump to org file %s"
3940 (abbreviate-file-name (buffer-file-name)))))
3941 (regexp (concat "[\n\r]\\*+ *\\(" org-not-done-regexp
3942 "[^\n\r]*\\)"))
3943 marker priority
3944 ee txt)
3945 (goto-char (point-min))
3946 (while (re-search-forward regexp nil t)
3947 (goto-char (match-beginning 1))
3948 (setq marker (org-agenda-new-marker (point-at-bol))
3949 txt (org-format-agenda-item "" (match-string 1))
3950 priority
3951 (+ (org-get-priority txt)
3952 (if org-todo-kwd-priority-p
3953 (- org-todo-kwd-max-priority -2
3954 (length
3955 (member (match-string 2) org-todo-keywords)))
3956 1)))
3957 (add-text-properties
3958 0 (length txt) (append (list 'org-marker marker 'org-hd-marker marker
3959 'priority priority)
3960 props)
3961 txt)
3962 (push txt ee)
3963 (goto-char (match-end 1)))
3964 (nreverse ee)))
3965
3966 (defconst org-agenda-no-heading-message
3967 "No heading for this item in buffer or region")
3968
3969 (defun org-agenda-get-timestamps ()
3970 "Return the date stamp information for agenda display."
3971 (let* ((props (list 'face nil
3972 'mouse-face 'highlight
3973 'keymap org-agenda-keymap
3974 'help-echo
3975 (format "mouse-2 or RET jump to org file %s"
3976 (abbreviate-file-name (buffer-file-name)))))
3977 (regexp (regexp-quote
3978 (substring
3979 (format-time-string
3980 (car org-time-stamp-formats)
3981 (apply 'encode-time ; DATE bound by calendar
3982 (list 0 0 0 (nth 1 date) (car date) (nth 2 date))))
3983 0 11)))
3984 marker hdmarker deadlinep scheduledp donep tmp priority
3985 ee txt timestr)
3986 (goto-char (point-min))
3987 (while (re-search-forward regexp nil t)
3988 (if (not (save-match-data (org-at-date-range-p)))
3989 (progn
3990 (setq marker (org-agenda-new-marker (match-beginning 0))
3991 tmp (buffer-substring (max (point-min)
3992 (- (match-beginning 0)
3993 org-ds-keyword-length))
3994 (match-beginning 0))
3995 timestr (buffer-substring (match-beginning 0) (point-at-eol))
3996 deadlinep (string-match org-deadline-regexp tmp)
3997 scheduledp (string-match org-scheduled-regexp tmp)
3998 donep (org-entry-is-done-p))
3999 (if (string-match ">" timestr)
4000 ;; substring should only run to end of time stamp
4001 (setq timestr (substring timestr 0 (match-end 0))))
4002 (save-excursion
4003 (if (re-search-backward "\\(^\\|\r\\)\\*+" nil t)
4004 (progn
4005 (goto-char (match-end 1))
4006 (setq hdmarker (org-agenda-new-marker))
4007 (looking-at "\\*+[ \t]*\\([^\r\n]+\\)")
4008 (setq txt (org-format-agenda-item
4009 (format "%s%s"
4010 (if deadlinep "Deadline: " "")
4011 (if scheduledp "Scheduled: " ""))
4012 (match-string 1) nil timestr)))
4013 (setq txt org-agenda-no-heading-message))
4014 (setq priority (org-get-priority txt))
4015 (add-text-properties
4016 0 (length txt) (append (list 'org-marker marker
4017 'org-hd-marker hdmarker) props)
4018 txt)
4019 (if deadlinep
4020 (add-text-properties
4021 0 (length txt)
4022 (list 'face
4023 (if donep 'org-done-face 'org-warning-face)
4024 'undone-face 'org-warning-face
4025 'done-face 'org-done-face
4026 'priority (+ 100 priority))
4027 txt)
4028 (if scheduledp
4029 (add-text-properties
4030 0 (length txt)
4031 (list 'face 'org-scheduled-today-face
4032 'undone-face 'org-scheduled-today-face
4033 'done-face 'org-done-face
4034 priority (+ 99 priority))
4035 txt)
4036 (add-text-properties
4037 0 (length txt)
4038 (list 'priority priority) txt)))
4039 (push txt ee))
4040 (outline-next-heading))))
4041 (nreverse ee)))
4042
4043 (defun org-agenda-get-deadlines ()
4044 "Return the deadline information for agenda display."
4045 (let* ((wdays org-deadline-warning-days)
4046 (props (list 'mouse-face 'highlight
4047 'keymap org-agenda-keymap
4048 'help-echo
4049 (format "mouse-2 or RET jump to org file %s"
4050 (abbreviate-file-name (buffer-file-name)))))
4051 (regexp org-deadline-time-regexp)
4052 (todayp (equal date (calendar-current-date))) ; DATE bound by calendar
4053 (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar
4054 d2 diff pos pos1
4055 ee txt head)
4056 (goto-char (point-min))
4057 (while (re-search-forward regexp nil t)
4058 (setq pos (1- (match-beginning 1))
4059 d2 (time-to-days
4060 (org-time-string-to-time (match-string 1)))
4061 diff (- d2 d1))
4062 ;; When to show a deadline in the calendar:
4063 ;; If the expiration is within wdays warning time.
4064 ;; Past-due deadlines are only shown on the current date
4065 (if (and (< diff wdays) todayp (not (= diff 0)))
4066 (save-excursion
4067 (if (re-search-backward "\\(^\\|\r\\)\\*+[ \t]*" nil t)
4068 (progn
4069 (goto-char (match-end 0))
4070 (setq pos1 (match-end 1))
4071 (setq head (buffer-substring-no-properties
4072 (point)
4073 (progn (skip-chars-forward "^\r\n")
4074 (point))))
4075 (if (string-match org-looking-at-done-regexp head)
4076 (setq txt nil)
4077 (setq txt (org-format-agenda-item
4078 (format "In %3d d.: " diff) head))))
4079 (setq txt org-agenda-no-heading-message))
4080 (when txt
4081 (add-text-properties
4082 0 (length txt)
4083 (append
4084 (list 'org-marker (org-agenda-new-marker pos)
4085 'org-hd-marker (org-agenda-new-marker pos1)
4086 'priority (+ (- 10 diff) (org-get-priority txt))
4087 'face (cond ((<= diff 0) 'org-warning-face)
4088 ((<= diff 5) 'org-scheduled-previously-face)
4089 (t nil))
4090 'undone-face (cond
4091 ((<= diff 0) 'org-warning-face)
4092 ((<= diff 5) 'org-scheduled-previously-face)
4093 (t nil))
4094 'done-face 'org-done-face)
4095 props)
4096 txt)
4097 (push txt ee)))))
4098 ee))
4099
4100 (defun org-agenda-get-scheduled ()
4101 "Return the scheduled information for agenda display."
4102 (let* ((props (list 'face 'org-scheduled-previously-face
4103 'undone-face 'org-scheduled-previously-face
4104 'done-face 'org-done-face
4105 'mouse-face 'highlight
4106 'keymap org-agenda-keymap
4107 'help-echo
4108 (format "mouse-2 or RET jump to org file %s"
4109 (abbreviate-file-name (buffer-file-name)))))
4110 (regexp org-scheduled-time-regexp)
4111 (todayp (equal date (calendar-current-date))) ; DATE bound by calendar
4112 (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar
4113 d2 diff pos pos1
4114 ee txt head)
4115 (goto-char (point-min))
4116 (while (re-search-forward regexp nil t)
4117 (setq pos (1- (match-beginning 1))
4118 d2 (time-to-days
4119 (org-time-string-to-time (match-string 1)))
4120 diff (- d2 d1))
4121 ;; When to show a scheduled item in the calendar:
4122 ;; If it is on or past the date.
4123 (if (and (< diff 0) todayp)
4124 (save-excursion
4125 (if (re-search-backward "\\(^\\|\r\\)\\*+[ \t]*" nil t)
4126 (progn
4127 (goto-char (match-end 0))
4128 (setq pos1 (match-end 1))
4129 (setq head (buffer-substring-no-properties
4130 (point)
4131 (progn (skip-chars-forward "^\r\n") (point))))
4132 (if (string-match org-looking-at-done-regexp head)
4133 (setq txt nil)
4134 (setq txt (org-format-agenda-item
4135 (format "Sched.%2dx: " (- 1 diff)) head))))
4136 (setq txt org-agenda-no-heading-message))
4137 (when txt
4138 (add-text-properties
4139 0 (length txt)
4140 (append (list 'org-marker (org-agenda-new-marker pos)
4141 'org-hd-marker (org-agenda-new-marker pos1)
4142 'priority (+ (- 5 diff) (org-get-priority txt)))
4143 props) txt)
4144 (push txt ee)))))
4145 ee))
4146
4147 (defun org-agenda-get-blocks ()
4148 "Return the date-range information for agenda display."
4149 (let* ((props (list 'face nil
4150 'mouse-face 'highlight
4151 'keymap org-agenda-keymap
4152 'help-echo
4153 (format "mouse-2 or RET jump to org file %s"
4154 (abbreviate-file-name (buffer-file-name)))))
4155 (regexp org-tr-regexp)
4156 (d0 (calendar-absolute-from-gregorian date))
4157 marker hdmarker ee txt d1 d2 s1 s2 timestr)
4158 (goto-char (point-min))
4159 (while (re-search-forward regexp nil t)
4160 (setq timestr (match-string 0)
4161 s1 (match-string 1)
4162 s2 (match-string 2)
4163 d1 (time-to-days (org-time-string-to-time s1))
4164 d2 (time-to-days (org-time-string-to-time s2)))
4165 (if (and (> (- d0 d1) -1) (> (- d2 d0) -1))
4166 ;; Only allow days between the limits, because the normal
4167 ;; date stamps will catch the limits.
4168 (save-excursion
4169 (setq marker (org-agenda-new-marker (point)))
4170 (if (re-search-backward "\\(^\\|\r\\)\\*+" nil t)
4171 (progn
4172 (setq hdmarker (org-agenda-new-marker (match-end 1)))
4173 (goto-char (match-end 1))
4174 (looking-at "\\*+[ \t]*\\([^\r\n]+\\)")
4175 (setq txt (org-format-agenda-item
4176 (format (if (= d1 d2) "" "(%d/%d): ")
4177 (1+ (- d0 d1)) (1+ (- d2 d1)))
4178 (match-string 1) nil (if (= d0 d1) timestr))))
4179 (setq txt org-agenda-no-heading-message))
4180 (add-text-properties
4181 0 (length txt) (append (list 'org-marker marker
4182 'org-hd-marker hdmarker
4183 'priority (org-get-priority txt))
4184 props)
4185 txt)
4186 (push txt ee)))
4187 (outline-next-heading))
4188 ;; Sort the entries by expiration date.
4189 (nreverse ee)))
4190
4191
4192
4193 (defconst org-plain-time-of-day-regexp
4194 (concat
4195 "\\(\\<[012]?[0-9]"
4196 "\\(\\(:\\([0-5][0-9]\\([AaPp][Mm]\\)?\\)\\)\\|\\([AaPp][Mm]\\)\\)\\>\\)"
4197 "\\(--?"
4198 "\\(\\<[012]?[0-9]"
4199 "\\(\\(:\\([0-5][0-9]\\([AaPp][Mm]\\)?\\)\\)\\|\\([AaPp][Mm]\\)\\)\\>\\)"
4200 "\\)?")
4201 "Regular expression to match a plain time or time range.
4202 Examples: 11:45 or 8am-13:15 or 2:45-2:45pm. After a match, the following
4203 groups carry important information:
4204 0 the full match
4205 1 the first time, range or not
4206 8 the second time, if it is a range.")
4207
4208 (defconst org-stamp-time-of-day-regexp
4209 (concat
4210 "<\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} +[a-zA-Z]+ +\\)"
4211 "\\([012][0-9]:[0-5][0-9]\\)>"
4212 "\\(--?"
4213 "<\\1\\([012][0-9]:[0-5][0-9]\\)>\\)?")
4214 "Regular expression to match a timestamp time or time range.
4215 After a match, the following groups carry important information:
4216 0 the full match
4217 1 date plus weekday, for backreferencing to make sure both times on same day
4218 2 the first time, range or not
4219 4 the second time, if it is a range.")
4220
4221 (defvar org-prefix-has-time nil
4222 "A flag, set by `org-compile-prefix-format'.
4223 The flag is set if the currently compiled format contains a `%t'.")
4224
4225 (defun org-format-agenda-item (extra txt &optional category dotime noprefix)
4226 "Format TXT to be inserted into the agenda buffer.
4227 In particular, it adds the prefix and corresponding text properties. EXTRA
4228 must be a string and replaces the `%s' specifier in the prefix format.
4229 CATEGORY (string, symbol or nil) may be used to overule the default
4230 category taken from local variable or file name. It will replace the `%c'
4231 specifier in the format. DOTIME, when non-nil, indicates that a
4232 time-of-day should be extracted from TXT for sorting of this entry, and for
4233 the `%t' specifier in the format. When DOTIME is a string, this string is
4234 searched for a time before TXT is. NOPREFIX is a flag and indicates that
4235 only the correctly processes TXT should be returned - this is used by
4236 `org-agenda-change-all-lines'."
4237 (save-match-data
4238 ;; Diary entries sometimes have extra whitespace at the beginning
4239 (if (string-match "^ +" txt) (setq txt (replace-match "" nil nil txt)))
4240 (let* ((category (or category
4241 org-category
4242 (if (buffer-file-name)
4243 (file-name-sans-extension
4244 (file-name-nondirectory (buffer-file-name)))
4245 "")))
4246 time ;; needed for the eval of the prefix format
4247 (ts (if dotime (concat (if (stringp dotime) dotime "") txt)))
4248 (time-of-day (and dotime (org-get-time-of-day ts)))
4249 stamp plain s0 s1 s2 rtn)
4250 (when (and dotime time-of-day org-prefix-has-time)
4251 ;; Extract starting and ending time and move them to prefix
4252 (when (or (setq stamp (string-match org-stamp-time-of-day-regexp ts))
4253 (setq plain (string-match org-plain-time-of-day-regexp ts)))
4254 (setq s0 (match-string 0 ts)
4255 s1 (match-string (if plain 1 2) ts)
4256 s2 (match-string (if plain 8 4) ts))
4257
4258 ;; If the times are in TXT (not in DOTIMES), and the prefix will list
4259 ;; them, we might want to remove them there to avoid duplication.
4260 ;; The user can turn this off with a variable.
4261 (if (and org-agenda-remove-times-when-in-prefix (or stamp plain)
4262 (string-match (concat (regexp-quote s0) " *") txt)
4263 (if (eq org-agenda-remove-times-when-in-prefix 'beg)
4264 (= (match-beginning 0) 0)
4265 t))
4266 (setq txt (replace-match "" nil nil txt))))
4267 ;; Normalize the time(s) to 24 hour
4268 (if s1 (setq s1 (org-get-time-of-day s1 'string)))
4269 (if s2 (setq s2 (org-get-time-of-day s2 'string))))
4270
4271 ;; Create the final string
4272 (if noprefix
4273 (setq rtn txt)
4274 ;; Prepare the variables needed in the eval of the compiled format
4275 (setq time (cond (s2 (concat s1 "-" s2))
4276 (s1 (concat s1 "......"))
4277 (t ""))
4278 extra (or extra "")
4279 category (if (symbolp category) (symbol-name category) category))
4280 ;; Evaluate the compiled format
4281 (setq rtn (concat (eval org-prefix-format-compiled) txt)))
4282
4283 ;; And finally add the text properties
4284 (add-text-properties
4285 0 (length rtn) (list 'category (downcase category)
4286 'prefix-length (- (length rtn) (length txt))
4287 'time-of-day time-of-day
4288 'dotime dotime)
4289 rtn)
4290 rtn)))
4291
4292 (defun org-agenda-add-time-grid-maybe (list ndays todayp)
4293 (catch 'exit
4294 (cond ((not org-agenda-use-time-grid) (throw 'exit list))
4295 ((and todayp (member 'today (car org-agenda-time-grid))))
4296 ((and (= ndays 1) (member 'daily (car org-agenda-time-grid))))
4297 ((member 'weekly (car org-agenda-time-grid)))
4298 (t (throw 'exit list)))
4299 (let* ((have (delq nil (mapcar
4300 (lambda (x) (get-text-property 1 'time-of-day x))
4301 list)))
4302 (string (nth 1 org-agenda-time-grid))
4303 (gridtimes (nth 2 org-agenda-time-grid))
4304 (req (car org-agenda-time-grid))
4305 (remove (member 'remove-match req))
4306 new time)
4307 (if (and (member 'require-timed req) (not have))
4308 ;; don't show empty grid
4309 (throw 'exit list))
4310 (while (setq time (pop gridtimes))
4311 (unless (and remove (member time have))
4312 (setq time (int-to-string time))
4313 (push (org-format-agenda-item
4314 nil string "" ;; FIXME: put a category?
4315 (concat (substring time 0 -2) ":" (substring time -2)))
4316 new)
4317 (put-text-property
4318 1 (length (car new)) 'face 'org-time-grid-face (car new))))
4319 (if (member 'time-up org-agenda-sorting-strategy)
4320 (append new list)
4321 (append list new)))))
4322
4323 (defun org-compile-prefix-format (format)
4324 "Compile the prefix format into a Lisp form that can be evaluated.
4325 The resulting form is returned and stored in the variable
4326 `org-prefix-format-compiled'."
4327 (setq org-prefix-has-time nil)
4328 (let ((start 0) varform vars var (s format) c f opt)
4329 (while (string-match "%\\(\\?\\)?\\([-+]?[0-9.]*\\)\\([ .;,:!?=|/<>]?\\)\\([cts]\\)"
4330 s start)
4331 (setq var (cdr (assoc (match-string 4 s)
4332 '(("c" . category) ("t" . time) ("s" . extra))))
4333 c (or (match-string 3 s) "")
4334 opt (match-beginning 1)
4335 start (1+ (match-beginning 0)))
4336 (if (equal var 'time) (setq org-prefix-has-time t))
4337 (setq f (concat "%" (match-string 2 s) "s"))
4338 (if opt
4339 (setq varform
4340 `(if (equal "" ,var)
4341 ""
4342 (format ,f (if (equal "" ,var) "" (concat ,var ,c)))))
4343 (setq varform `(format ,f (if (equal ,var "") "" (concat ,var ,c)))))
4344 (setq s (replace-match "%s" t nil s))
4345 (push varform vars))
4346 (setq vars (nreverse vars))
4347 (setq org-prefix-format-compiled `(format ,s ,@vars))))
4348
4349 (defun org-get-time-of-day (s &optional string)
4350 "Check string S for a time of day.
4351 If found, return it as a military time number between 0 and 2400.
4352 If not found, return nil.
4353 The optional STRING argument forces conversion into a 5 character wide string
4354 HH:MM."
4355 (save-match-data
4356 (when
4357 (or
4358 (string-match
4359 "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)\\([AaPp][Mm]\\)?\\> *" s)
4360 (string-match
4361 "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?\\([AaPp][Mm]\\)\\> *" s))
4362 (let* ((t0 (+ (* 100
4363 (+ (string-to-number (match-string 1 s))
4364 (if (and (match-beginning 4)
4365 (equal (downcase (match-string 4 s)) "pm"))
4366 12 0)))
4367 (if (match-beginning 3)
4368 (string-to-number (match-string 3 s))
4369 0)))
4370 (t1 (concat " " (int-to-string t0))))
4371 (if string (concat (substring t1 -4 -2) ":" (substring t1 -2)) t0)))))
4372
4373 (defun org-finalize-agenda-entries (list)
4374 "Sort and concatenate the agenda items."
4375 (mapconcat 'identity (sort list 'org-entries-lessp) "\n"))
4376
4377 (defsubst org-cmp-priority (a b)
4378 "Compare the priorities of string a and b."
4379 (let ((pa (or (get-text-property 1 'priority a) 0))
4380 (pb (or (get-text-property 1 'priority b) 0)))
4381 (cond ((> pa pb) +1)
4382 ((< pa pb) -1)
4383 (t nil))))
4384
4385 (defsubst org-cmp-category (a b)
4386 "Compare the string values of categories of strings a and b."
4387 (let ((ca (or (get-text-property 1 'category a) ""))
4388 (cb (or (get-text-property 1 'category b) "")))
4389 (cond ((string-lessp ca cb) -1)
4390 ((string-lessp cb ca) +1)
4391 (t nil))))
4392
4393 (defsubst org-cmp-time (a b)
4394 "Compare the time-of-day values of strings a and b."
4395 (let* ((def (if org-sort-agenda-notime-is-late 2401 -1))
4396 (ta (or (get-text-property 1 'time-of-day a) def))
4397 (tb (or (get-text-property 1 'time-of-day b) def)))
4398 (cond ((< ta tb) -1)
4399 ((< tb ta) +1)
4400 (t nil))))
4401
4402 (defun org-entries-lessp (a b)
4403 "Predicate for sorting agenda entries."
4404 (let* ((time-up (org-cmp-time a b))
4405 (time-down (if time-up (- time-up) nil))
4406 (priority-up (org-cmp-priority a b))
4407 (priority-down (if priority-up (- priority-up) nil))
4408 (category-up (org-cmp-category a b))
4409 (category-down (if category-up (- category-up) nil))
4410 (category-keep (if category-up +1 nil))) ; FIXME +1 or -1?
4411 (cdr (assoc
4412 (eval (cons 'or org-agenda-sorting-strategy))
4413 '((-1 . t) (1 . nil) (nil . nil))))))
4414
4415 (defun org-agenda-show-priority ()
4416 "Show the priority of the current item.
4417 This priority is composed of the main priority given with the [#A] cookies,
4418 and by additional input from the age of a schedules or deadline entry."
4419 (interactive)
4420 (let* ((pri (get-text-property (point-at-bol) 'priority)))
4421 (message "Priority is %d" (if pri pri -1000))))
4422
4423 (defun org-agenda-goto (&optional highlight)
4424 "Go to the Org-mode file which contains the item at point."
4425 (interactive)
4426 (let* ((marker (or (get-text-property (point) 'org-marker)
4427 (org-agenda-error)))
4428 (buffer (marker-buffer marker))
4429 (pos (marker-position marker)))
4430 (switch-to-buffer-other-window buffer)
4431 (widen)
4432 (goto-char pos)
4433 (when (eq major-mode 'org-mode)
4434 (org-show-hidden-entry)
4435 (save-excursion
4436 (and (outline-next-heading)
4437 (org-flag-heading nil)))) ; show the next heading
4438 (and highlight (org-highlight (point-at-bol) (point-at-eol)))))
4439
4440 (defun org-agenda-switch-to ()
4441 "Go to the Org-mode file which contains the item at point."
4442 (interactive)
4443 (let* ((marker (or (get-text-property (point) 'org-marker)
4444 (org-agenda-error)))
4445 (buffer (marker-buffer marker))
4446 (pos (marker-position marker)))
4447 (switch-to-buffer buffer)
4448 (delete-other-windows)
4449 (widen)
4450 (goto-char pos)
4451 (when (eq major-mode 'org-mode)
4452 (org-show-hidden-entry)
4453 (save-excursion
4454 (and (outline-next-heading)
4455 (org-flag-heading nil)))))) ; show the next heading
4456
4457 (defun org-agenda-goto-mouse (ev)
4458 "Go to the Org-mode file which contains the item at the mouse click."
4459 (interactive "e")
4460 (mouse-set-point ev)
4461 (org-agenda-goto))
4462
4463 (defun org-agenda-show ()
4464 "Display the Org-mode file which contains the item at point."
4465 (interactive)
4466 (let ((win (selected-window)))
4467 (org-agenda-goto t)
4468 (select-window win)))
4469
4470 (defun org-agenda-recenter (arg)
4471 "Display the Org-mode file which contains the item at point and recenter."
4472 (interactive "P")
4473 (let ((win (selected-window)))
4474 (org-agenda-goto t)
4475 (recenter arg)
4476 (select-window win)))
4477
4478 (defun org-agenda-show-mouse (ev)
4479 "Display the Org-mode file which contains the item at the mouse click."
4480 (interactive "e")
4481 (mouse-set-point ev)
4482 (org-agenda-show))
4483
4484 (defun org-agenda-check-no-diary ()
4485 "Check if the entry is a diary link and abort if yes."
4486 (if (get-text-property (point) 'org-agenda-diary-link)
4487 (org-agenda-error)))
4488
4489 (defun org-agenda-error ()
4490 (error "Command not allowed in this line."))
4491
4492 (defvar org-last-heading-marker (make-marker)
4493 "Marker pointing to the headline that last changed its TODO state
4494 by a remote command from the agenda.")
4495
4496 (defun org-agenda-todo ()
4497 "Cycle TODO state of line at point, also in Org-mode file.
4498 This changes the line at point, all other lines in the agenda referring to
4499 the same tree node, and the headline of the tree node in the Org-mode file."
4500 (interactive)
4501 (org-agenda-check-no-diary)
4502 (let* ((col (current-column))
4503 (marker (or (get-text-property (point) 'org-marker)
4504 (org-agenda-error)))
4505 (buffer (marker-buffer marker))
4506 (pos (marker-position marker))
4507 (hdmarker (get-text-property (point) 'org-hd-marker))
4508 (buffer-read-only nil)
4509 newhead)
4510 (with-current-buffer buffer
4511 (widen)
4512 (goto-char pos)
4513 (org-show-hidden-entry)
4514 (save-excursion
4515 (and (outline-next-heading)
4516 (org-flag-heading nil))) ; show the next heading
4517 (org-todo)
4518 (forward-char 1)
4519 (setq newhead (org-get-heading))
4520 (save-excursion
4521 (org-back-to-heading)
4522 (move-marker org-last-heading-marker (point))))
4523 (beginning-of-line 1)
4524 (save-excursion
4525 (org-agenda-change-all-lines newhead hdmarker 'fixface))
4526 (move-to-column col)))
4527
4528 (defun org-agenda-change-all-lines (newhead hdmarker &optional fixface)
4529 "Change all lines in the agenda buffer which match hdmarker.
4530 The new content of the line will be NEWHEAD (as modified by
4531 `org-format-agenda-item'). HDMARKER is checked with
4532 `equal' against all `org-hd-marker' text properties in the file.
4533 If FIXFACE is non-nil, the face of each item is modified acording to
4534 the new TODO state."
4535 (let* (props m pl undone-face done-face finish new dotime)
4536 ; (setq newhead (org-format-agenda-item "x" newhead "x" nil 'noprefix))
4537 (save-excursion
4538 (goto-char (point-max))
4539 (beginning-of-line 1)
4540 (while (not finish)
4541 (setq finish (bobp))
4542 (when (and (setq m (get-text-property (point) 'org-hd-marker))
4543 (equal m hdmarker))
4544 (setq props (text-properties-at (point))
4545 dotime (get-text-property (point) 'dotime)
4546 new (org-format-agenda-item "x" newhead "x" dotime 'noprefix)
4547 pl (get-text-property (point) 'prefix-length)
4548 undone-face (get-text-property (point) 'undone-face)
4549 done-face (get-text-property (point) 'done-face))
4550 (move-to-column pl)
4551 (if (looking-at ".*")
4552 (progn
4553 (replace-match new t t)
4554 (beginning-of-line 1)
4555 (add-text-properties (point-at-bol) (point-at-eol) props)
4556 (if fixface
4557 (add-text-properties
4558 (point-at-bol) (point-at-eol)
4559 (list 'face
4560 (if org-last-todo-state-is-todo
4561 undone-face done-face))))
4562 (beginning-of-line 1))
4563 (error "Line update did not work")))
4564 (beginning-of-line 0)))))
4565
4566 (defun org-agenda-priority-up ()
4567 "Increase the priority of line at point, also in Org-mode file."
4568 (interactive)
4569 (org-agenda-priority 'up))
4570
4571 (defun org-agenda-priority-down ()
4572 "Decrease the priority of line at point, also in Org-mode file."
4573 (interactive)
4574 (org-agenda-priority 'down))
4575
4576 (defun org-agenda-priority (&optional force-direction)
4577 "Set the priority of line at point, also in Org-mode file.
4578 This changes the line at point, all other lines in the agenda referring to
4579 the same tree node, and the headline of the tree node in the Org-mode file."
4580 (interactive)
4581 (org-agenda-check-no-diary)
4582 (let* ((marker (or (get-text-property (point) 'org-marker)
4583 (org-agenda-error)))
4584 (buffer (marker-buffer marker))
4585 (pos (marker-position marker))
4586 (hdmarker (get-text-property (point) 'org-hd-marker))
4587 (buffer-read-only nil)
4588 newhead)
4589 (with-current-buffer buffer
4590 (widen)
4591 (goto-char pos)
4592 (org-show-hidden-entry)
4593 (save-excursion
4594 (and (outline-next-heading)
4595 (org-flag-heading nil))) ; show the next heading
4596 (funcall 'org-priority force-direction)
4597 (end-of-line 1)
4598 (setq newhead (org-get-heading)))
4599 (org-agenda-change-all-lines newhead hdmarker)
4600 (beginning-of-line 1)))
4601
4602 (defun org-agenda-date-later (arg &optional what)
4603 "Change the date of this item to one day later."
4604 (interactive "p")
4605 (org-agenda-check-no-diary)
4606 (let* ((marker (or (get-text-property (point) 'org-marker)
4607 (org-agenda-error)))
4608 (buffer (marker-buffer marker))
4609 (pos (marker-position marker)))
4610 (with-current-buffer buffer
4611 (widen)
4612 (goto-char pos)
4613 (if (not (org-at-timestamp-p))
4614 (error "Cannot find time stamp"))
4615 (org-timestamp-change arg (or what 'day))
4616 (message "Time stamp changed to %s" org-last-changed-timestamp))))
4617
4618 (defun org-agenda-date-earlier (arg &optional what)
4619 "Change the date of this item to one day earlier."
4620 (interactive "p")
4621 (org-agenda-date-later (- arg) what))
4622
4623 (defun org-agenda-date-prompt (arg)
4624 "Change the date of this item. Date is prompted for, with default today.
4625 The prefix ARG is passed to the `org-time-stamp' command and can therefore
4626 be used to request time specification in the time stamp."
4627 (interactive "P")
4628 (org-agenda-check-no-diary)
4629 (let* ((marker (or (get-text-property (point) 'org-marker)
4630 (org-agenda-error)))
4631 (buffer (marker-buffer marker))
4632 (pos (marker-position marker)))
4633 (with-current-buffer buffer
4634 (widen)
4635 (goto-char pos)
4636 (if (not (org-at-timestamp-p))
4637 (error "Cannot find time stamp"))
4638 (org-time-stamp arg)
4639 (message "Time stamp changed to %s" org-last-changed-timestamp))))
4640
4641 (defun org-get-heading ()
4642 "Return the heading of the current entry, without the stars."
4643 (save-excursion
4644 (if (and (re-search-backward "[\r\n]\\*" nil t)
4645 (looking-at "[\r\n]\\*+[ \t]+\\(.*\\)"))
4646 (match-string 1)
4647 "")))
4648
4649 (defun org-agenda-diary-entry ()
4650 "Make a diary entry, like the `i' command from the calendar.
4651 All the standard commands work: block, weekly etc"
4652 (interactive)
4653 (require 'diary-lib)
4654 (let* ((char (progn
4655 (message "Diary entry: [d]ay [w]eekly [m]onthly [y]early [a]nniversary [b]lock [c]yclic")
4656 (read-char-exclusive)))
4657 (cmd (cdr (assoc char
4658 '((?d . insert-diary-entry)
4659 (?w . insert-weekly-diary-entry)
4660 (?m . insert-monthly-diary-entry)
4661 (?y . insert-yearly-diary-entry)
4662 (?a . insert-anniversary-diary-entry)
4663 (?b . insert-block-diary-entry)
4664 (?c . insert-cyclic-diary-entry)))))
4665 (oldf (symbol-function 'calendar-cursor-to-date))
4666 (point (point))
4667 (mark (or (mark t) (point))))
4668 (unless cmd
4669 (error "No command associated with <%c>" char))
4670 (unless (and (get-text-property point 'day)
4671 (or (not (equal ?b char))
4672 (get-text-property mark 'day)))
4673 (error "Don't know which date to use for diary entry"))
4674 ;; We implement this by hacking the `calendar-cursor-to-date' function
4675 ;; and the `calendar-mark-ring' variable. Saves a lot of code.
4676 (let ((calendar-mark-ring
4677 (list (calendar-gregorian-from-absolute
4678 (or (get-text-property mark 'day)
4679 (get-text-property point 'day))))))
4680 (unwind-protect
4681 (progn
4682 (fset 'calendar-cursor-to-date
4683 (lambda (&optional error)
4684 (calendar-gregorian-from-absolute
4685 (get-text-property point 'day))))
4686 (call-interactively cmd))
4687 (fset 'calendar-cursor-to-date oldf)))))
4688
4689
4690 (defun org-agenda-execute-calendar-command (cmd)
4691 "Execute a calendar command from the agenda, with the date associated to
4692 the cursor position."
4693 (require 'diary-lib)
4694 (unless (get-text-property (point) 'day)
4695 (error "Don't know which date to use for calendar command"))
4696 (let* ((oldf (symbol-function 'calendar-cursor-to-date))
4697 (point (point))
4698 (date (calendar-gregorian-from-absolute
4699 (get-text-property point 'day)))
4700 (displayed-day (extract-calendar-day date))
4701 (displayed-month (extract-calendar-month date))
4702 (displayed-year (extract-calendar-year date)))
4703 (unwind-protect
4704 (progn
4705 (fset 'calendar-cursor-to-date
4706 (lambda (&optional error)
4707 (calendar-gregorian-from-absolute
4708 (get-text-property point 'day))))
4709 (call-interactively cmd))
4710 (fset 'calendar-cursor-to-date oldf))))
4711
4712 (defun org-agenda-phases-of-moon ()
4713 "Display the phases of the moon for the 3 months around the cursor date."
4714 (interactive)
4715 (org-agenda-execute-calendar-command 'calendar-phases-of-moon))
4716
4717 (defun org-agenda-holidays ()
4718 "Display the holidays for the 3 months around the cursor date."
4719 (interactive)
4720 (org-agenda-execute-calendar-command 'list-calendar-holidays))
4721
4722 (defun org-agenda-sunrise-sunset (arg)
4723 "Display sunrise and sunset for the cursor date.
4724 Latitude and longitude can be specified with the variables
4725 `calendar-latitude' and `calendar-longitude'. When called with prefix
4726 argument, latitude and longitude will be prompted for."
4727 (interactive "P")
4728 (let ((calendar-longitude (if arg nil calendar-longitude))
4729 (calendar-latitude (if arg nil calendar-latitude))
4730 (calendar-location-name
4731 (if arg "the given coordinates" calendar-location-name)))
4732 (org-agenda-execute-calendar-command 'calendar-sunrise-sunset)))
4733
4734 (defun org-agenda-goto-calendar ()
4735 "Open the Emacs calendar with the date at the cursor."
4736 (interactive)
4737 (let* ((day (or (get-text-property (point) 'day)
4738 (error "Don't know which date to open in calendar")))
4739 (date (calendar-gregorian-from-absolute day)))
4740 (calendar)
4741 (calendar-goto-date date)))
4742
4743 (defun org-calendar-goto-agenda ()
4744 "Compute the Org-mode agenda for the calendar date displayed at the cursor.
4745 This is a command that has to be installed in `calendar-mode-map'."
4746 (interactive)
4747 (org-agenda nil (calendar-absolute-from-gregorian
4748 (calendar-cursor-to-date))))
4749
4750 (defun org-agenda-convert-date ()
4751 (interactive)
4752 (let ((day (get-text-property (point) 'day))
4753 date s)
4754 (unless day
4755 (error "Don't know which date to convert"))
4756 (setq date (calendar-gregorian-from-absolute day))
4757 (setq s (concat
4758 "Gregorian: " (calendar-date-string date) "\n"
4759 "ISO: " (calendar-iso-date-string date) "\n"
4760 "Day of Yr: " (calendar-day-of-year-string date) "\n"
4761 "Julian: " (calendar-julian-date-string date) "\n"
4762 "Astron. JD: " (calendar-astro-date-string date)
4763 " (Julian date number at noon UTC)\n"
4764 "Hebrew: " (calendar-hebrew-date-string date) " (until sunset)\n"
4765 "Islamic: " (calendar-islamic-date-string date) " (until sunset)\n"
4766 "French: " (calendar-french-date-string date) "\n"
4767 "Mayan: " (calendar-mayan-date-string date) "\n"
4768 "Coptic: " (calendar-coptic-date-string date) "\n"
4769 "Ethiopic: " (calendar-ethiopic-date-string date) "\n"
4770 "Persian: " (calendar-persian-date-string date) "\n"
4771 "Chinese: " (calendar-chinese-date-string date) "\n"))
4772 (with-output-to-temp-buffer "*Dates*"
4773 (princ s))
4774 (fit-window-to-buffer (get-buffer-window "*Dates*"))))
4775
4776 ;;; Link Stuff
4777
4778 (defun org-find-file-at-mouse (ev)
4779 "Open file link or URL at mouse."
4780 (interactive "e")
4781 (mouse-set-point ev)
4782 (org-open-at-point 'in-emacs))
4783
4784 (defun org-open-at-mouse (ev)
4785 "Open file link or URL at mouse."
4786 (interactive "e")
4787 (mouse-set-point ev)
4788 (org-open-at-point))
4789
4790 (defun org-open-at-point (&optional in-emacs)
4791 "Open link at or after point.
4792 If there is no link at point, this function will search forward up to
4793 the end of the current subtree.
4794 Normally, files will be opened by an appropriate application. If the
4795 optional argument IN-EMACS is non-nil, Emacs will visit the file."
4796 (interactive "P")
4797 (if (org-at-timestamp-p)
4798 (org-agenda nil (time-to-days (org-time-string-to-time
4799 (substring (match-string 1) 0 10)))
4800 1)
4801 (let (type path line (pos (point)))
4802 (save-excursion
4803 (skip-chars-backward
4804 (if org-allow-space-in-links "^\t\n\r" "^ \t\n\r"))
4805 (if (re-search-forward
4806 org-link-regexp
4807 (save-excursion
4808 (condition-case nil
4809 (progn (outline-end-of-subtree) (max pos (point)))
4810 (error (end-of-line 1) (point))))
4811 t)
4812 (setq type (match-string 1)
4813 path (match-string 2)))
4814 (unless path
4815 (error "No link found."))
4816 ;; Remove any trailing spaces in path
4817 (if (string-match " +\\'" path)
4818 (setq path (replace-match "" t t path)))
4819
4820 (cond
4821
4822 ((string= type "file")
4823 (if (string-match ":\\([0-9]+\\)\\'" path)
4824 (setq line (string-to-number (match-string 1 path))
4825 path (substring path 0 (match-beginning 0))))
4826 (org-open-file path in-emacs line))
4827
4828 ((string= type "news")
4829 (org-follow-gnus-link path))
4830
4831 ((string= type "bbdb")
4832 (org-follow-bbdb-link path))
4833
4834 ((string= type "gnus")
4835 (let (group article)
4836 (if (not (string-match "\\`\\([^#]+\\)\\(#\\(.*\\)\\)?" path))
4837 (error "Error in Gnus link"))
4838 (setq group (match-string 1 path)
4839 article (match-string 3 path))
4840 (org-follow-gnus-link group article)))
4841
4842 ((string= type "vm")
4843 (let (folder article)
4844 (if (not (string-match "\\`\\([^#]+\\)\\(#\\(.*\\)\\)?" path))
4845 (error "Error in VM link"))
4846 (setq folder (match-string 1 path)
4847 article (match-string 3 path))
4848 ;; in-emacs is the prefix arg, will be interpreted as read-only
4849 (org-follow-vm-link folder article in-emacs)))
4850
4851 ((string= type "wl")
4852 (let (folder article)
4853 (if (not (string-match "\\`\\([^#]+\\)\\(#\\(.*\\)\\)?" path))
4854 (error "Error in Wanderlust link"))
4855 (setq folder (match-string 1 path)
4856 article (match-string 3 path))
4857 (org-follow-wl-link folder article)))
4858
4859 ((string= type "rmail")
4860 (let (folder article)
4861 (if (not (string-match "\\`\\([^#]+\\)\\(#\\(.*\\)\\)?" path))
4862 (error "Error in RMAIL link"))
4863 (setq folder (match-string 1 path)
4864 article (match-string 3 path))
4865 (org-follow-rmail-link folder article)))
4866
4867 ((string= type "shell")
4868 (let ((cmd path))
4869 (if (or (not org-confirm-shell-links)
4870 (yes-or-no-p (format "Execute \"%s\" in the shell? " cmd)))
4871 (shell-command cmd)
4872 (error "Abort"))))
4873
4874 (t
4875 (browse-url-at-point)))))))
4876
4877 (defun org-follow-bbdb-link (name)
4878 "Follow a BBDB link to NAME."
4879 (require 'bbdb)
4880 (let ((inhibit-redisplay t))
4881 (catch 'exit
4882 ;; Exact match on name
4883 (bbdb-name (concat "\\`" name "\\'") nil)
4884 (if (< 0 (buffer-size (get-buffer "*BBDB*"))) (throw 'exit nil))
4885 ;; Exact match on name
4886 (bbdb-company (concat "\\`" name "\\'") nil)
4887 (if (< 0 (buffer-size (get-buffer "*BBDB*"))) (throw 'exit nil))
4888 ;; Partial match on name
4889 (bbdb-name name nil)
4890 (if (< 0 (buffer-size (get-buffer "*BBDB*"))) (throw 'exit nil))
4891 ;; Partial match on company
4892 (bbdb-company name nil)
4893 (if (< 0 (buffer-size (get-buffer "*BBDB*"))) (throw 'exit nil))
4894 ;; General match including network address and notes
4895 (bbdb name nil)
4896 (when (= 0 (buffer-size (get-buffer "*BBDB*")))
4897 (delete-window (get-buffer-window "*BBDB*"))
4898 (error "No matching BBDB record")))))
4899
4900 (defun org-follow-gnus-link (&optional group article)
4901 "Follow a Gnus link to GROUP and ARTICLE."
4902 (require 'gnus)
4903 (funcall (cdr (assq 'gnus org-link-frame-setup)))
4904 (if group (gnus-fetch-group group))
4905 (if article
4906 (or (gnus-summary-goto-article article nil 'force)
4907 (if (fboundp 'gnus-summary-insert-cached-articles)
4908 (progn
4909 (gnus-summary-insert-cached-articles)
4910 (gnus-summary-goto-article article nil 'force))
4911 (message "Message could not be found.")))))
4912
4913 (defun org-follow-vm-link (&optional folder article readonly)
4914 "Follow a VM link to FOLDER and ARTICLE."
4915 (require 'vm)
4916 (if (string-match "^//\\([a-zA-Z]+@\\)?\\([^:]+\\):\\(.*\\)" folder)
4917 ;; ange-ftp or efs or tramp access
4918 (let ((user (or (match-string 1 folder) (user-login-name)))
4919 (host (match-string 2 folder))
4920 (file (match-string 3 folder)))
4921 (cond
4922 ((featurep 'tramp)
4923 ;; use tramp to access the file
4924 (if org-xemacs-p
4925 (setq folder (format "[%s@%s]%s" user host file))
4926 (setq folder (format "/%s@%s:%s" user host file))))
4927 (t
4928 ;; use ange-ftp or efs
4929 (require (if org-xemacs-p 'efs 'ange-ftp))
4930 (setq folder (format "/%s@%s:%s" user host file))))))
4931 (when folder
4932 (funcall (cdr (assq 'vm org-link-frame-setup)) folder readonly)
4933 (sit-for 0.1)
4934 (when article
4935 (vm-select-folder-buffer)
4936 (widen)
4937 (let ((case-fold-search t))
4938 (goto-char (point-min))
4939 (if (not (re-search-forward
4940 (concat "^" "message-id: *" (regexp-quote article))))
4941 (error "Could not find the specified message in this folder"))
4942 (vm-isearch-update)
4943 (vm-isearch-narrow)
4944 (vm-beginning-of-message)
4945 (vm-summarize)))))
4946
4947 (defun org-follow-wl-link (folder article)
4948 "Follow a Wanderlust link to FOLDER and ARTICLE."
4949 (wl-summary-goto-folder-subr folder 'no-sync t nil t)
4950 (if article (wl-summary-jump-to-msg-by-message-id article))
4951 (wl-summary-redisplay))
4952
4953 (defun org-follow-rmail-link (folder article)
4954 "Follow an RMAIL link to FOLDER and ARTICLE."
4955 (let (message-number)
4956 (save-excursion
4957 (save-window-excursion
4958 (rmail (if (string= folder "RMAIL") rmail-file-name folder))
4959 (setq message-number
4960 (save-restriction
4961 (widen)
4962 (goto-char (point-max))
4963 (if (re-search-backward
4964 (concat "^Message-ID:\\s-+" (regexp-quote
4965 (or article "")))
4966 nil t)
4967 (rmail-what-message))))))
4968 (if message-number
4969 (progn
4970 (rmail (if (string= folder "RMAIL") rmail-file-name folder))
4971 (rmail-show-message message-number)
4972 message-number)
4973 (error "Message not found"))))
4974
4975 (defun org-open-file (path &optional in-emacs line)
4976 "Open the file at PATH.
4977 First, this expands any special file name abbreviations. Then the
4978 configuration variable `org-file-apps' is checked if it contains an
4979 entry for this file type, and if yes, the corresponding command is launched.
4980 If no application is found, Emacs simply visits the file.
4981 With optional argument IN-EMACS, Emacs will visit the file.
4982 If the file does not exist, an error is thrown."
4983 (let* ((file (convert-standard-filename (org-expand-file-name path)))
4984 (dfile (downcase file))
4985 ext cmd apps)
4986 (if (and (not (file-exists-p file))
4987 (not org-open-non-existing-files))
4988 (error "No such file: %s" file))
4989 (if (string-match "^.*\\.\\([a-zA-Z0-9]+\\.gz\\)$" dfile)
4990 (setq ext (match-string 1 dfile))
4991 (if (string-match "^.*\\.\\([a-zA-Z0-9]+\\)$" dfile)
4992 (setq ext (match-string 1 dfile))))
4993 (setq apps (append org-file-apps (org-default-apps)))
4994 (if in-emacs
4995 (setq cmd 'emacs)
4996 (setq cmd (or (cdr (assoc ext apps))
4997 (cdr (assoc t apps)))))
4998 (cond
4999 ((and (stringp cmd) (not (string-match "^\\s-*$" cmd)))
5000 (setq cmd (format cmd file))
5001 (save-window-excursion
5002 (shell-command (concat cmd " & &"))))
5003 ((or (stringp cmd)
5004 (eq cmd 'emacs))
5005 (funcall (cdr (assq 'file org-link-frame-setup)) file)
5006 (if line (goto-line line)))
5007 ((consp cmd)
5008 (eval cmd))
5009 (t (funcall (cdr (assq 'file org-link-frame-setup)) file)))))
5010
5011 (defun org-default-apps ()
5012 "Return the default applications for this operating system."
5013 (cond
5014 ((eq system-type 'darwin)
5015 org-file-apps-defaults-macosx)
5016 ((eq system-type 'windows-nt)
5017 org-file-apps-defaults-windowsnt)
5018 ((eq system-type 'linux)
5019 org-file-apps-defaults-linux)
5020 (t org-file-apps-defaults-linux)))
5021
5022 (defun org-expand-file-name (path)
5023 "Replace special path abbreviations and expand the file name."
5024 (expand-file-name path))
5025
5026
5027 (defvar org-insert-link-history nil
5028 "Minibuffer history for links inserted with `org-insert-link'.")
5029
5030 (defvar org-stored-links nil
5031 "Contains the links stored with `org-store-link'.")
5032
5033 ;;;###autoload
5034 (defun org-store-link (arg)
5035 "\\<org-mode-map>Store an org-link to the current location.
5036 This link can later be inserted into an org-buffer with
5037 \\[org-insert-link].
5038 For some link types, a prefix arg is interpreted:
5039 For links to usenet articles, arg negates `org-usenet-links-prefer-google'.
5040 For file links, arg negates `org-line-numbers-in-file-links'."
5041 (interactive "P")
5042 (let (link cpltxt)
5043 (cond
5044
5045 ((eq major-mode 'bbdb-mode)
5046 (setq link (concat "bbdb:"
5047 (or (bbdb-record-name (bbdb-current-record))
5048 (bbdb-record-company (bbdb-current-record))))))
5049
5050 ((eq major-mode 'calendar-mode)
5051 (let ((cd (calendar-cursor-to-date)))
5052 (setq link
5053 (format-time-string
5054 (car org-time-stamp-formats)
5055 (apply 'encode-time
5056 (list 0 0 0 (nth 1 cd) (nth 0 cd) (nth 2 cd)
5057 nil nil nil))))))
5058
5059 ((or (eq major-mode 'vm-summary-mode)
5060 (eq major-mode 'vm-presentation-mode))
5061 (and (eq major-mode 'vm-presentation-mode) (vm-summarize))
5062 (vm-follow-summary-cursor)
5063 (save-excursion
5064 (vm-select-folder-buffer)
5065 (let* ((message (car vm-message-pointer))
5066 (folder (buffer-file-name))
5067 (subject (vm-su-subject message))
5068 (author (vm-su-full-name message))
5069 (message-id (vm-su-message-id message)))
5070 (setq folder (abbreviate-file-name folder))
5071 (if (string-match (concat "^" (regexp-quote vm-folder-directory))
5072 folder)
5073 (setq folder (replace-match "" t t folder)))
5074 (setq cpltxt (concat author " on: " subject))
5075 (setq link (concat cpltxt "\n " "vm:" folder
5076 "#" message-id)))))
5077
5078 ((eq major-mode 'wl-summary-mode)
5079 (let* ((msgnum (wl-summary-message-number))
5080 (message-id (elmo-message-field wl-summary-buffer-elmo-folder
5081 msgnum 'message-id))
5082 (wl-message-entity (elmo-msgdb-overview-get-entity
5083 msgnum (wl-summary-buffer-msgdb)))
5084 (author (wl-summary-line-from)) ; FIXME: how to get author name?
5085 (subject "???")) ; FIXME: How to get subject of email?
5086 (setq cpltxt (concat author " on: " subject))
5087 (setq link (concat cpltxt "\n " "wl:" wl-summary-buffer-folder-name
5088 "#" message-id))))
5089
5090 ((eq major-mode 'rmail-mode)
5091 (save-excursion
5092 (save-restriction
5093 (rmail-narrow-to-non-pruned-header)
5094 (let ((folder (buffer-file-name))
5095 (message-id (mail-fetch-field "message-id"))
5096 (author (mail-fetch-field "from"))
5097 (subject (mail-fetch-field "subject")))
5098 (setq cpltxt (concat author " on: " subject))
5099 (setq link (concat cpltxt "\n " "rmail:" folder
5100 "#" message-id))))))
5101
5102 ((eq major-mode 'gnus-group-mode)
5103 (let ((group (cond ((fboundp 'gnus-group-group-name) ; depending on Gnus
5104 (gnus-group-group-name)) ; version
5105 ((fboundp 'gnus-group-name)
5106 (gnus-group-name))
5107 (t "???"))))
5108 (setq link (concat
5109 (if (org-xor arg org-usenet-links-prefer-google)
5110 "http://groups.google.com/groups?group="
5111 "gnus:")
5112 group))))
5113
5114 ((memq major-mode '(gnus-summary-mode gnus-article-mode))
5115 (and (eq major-mode 'gnus-article-mode) (gnus-article-show-summary))
5116 (gnus-summary-beginning-of-article)
5117 (let* ((group (car gnus-article-current))
5118 (article (cdr gnus-article-current))
5119 (header (gnus-summary-article-header article))
5120 (author (mail-header-from header))
5121 (message-id (mail-header-id header))
5122 (date (mail-header-date header))
5123 (subject (gnus-summary-subject-string)))
5124 (setq cpltxt (concat author " on: " subject))
5125 (if (org-xor arg org-usenet-links-prefer-google)
5126 (setq link
5127 (concat
5128 cpltxt "\n "
5129 (format "http://groups.google.com/groups?as_umsgid=%s"
5130 (org-fixup-message-id-for-http message-id))))
5131 (setq link (concat cpltxt "\n" "gnus:" group
5132 "#" (number-to-string article))))))
5133
5134 ((eq major-mode 'w3-mode)
5135 (setq link (url-view-url t)))
5136 ((eq major-mode 'w3m-mode)
5137 (setq link w3m-current-url))
5138
5139 ((buffer-file-name)
5140 ;; Just link to this file here.
5141 (setq link (concat "file:"
5142 (abbreviate-file-name (buffer-file-name))))
5143 ;; Add the line number?
5144 (if (org-xor org-line-numbers-in-file-links arg)
5145 (setq link
5146 (concat link
5147 ":" (int-to-string
5148 (+ (if (bolp) 1 0) (count-lines
5149 (point-min) (point))))))))
5150 ((interactive-p)
5151 (error "Cannot link to a buffer which is not visiting a file"))
5152 (t (setq link nil)))
5153
5154 (if (and (interactive-p) link)
5155 (progn
5156 (setq org-stored-links
5157 (cons (cons (or cpltxt link) link) org-stored-links))
5158 (message "Stored: %s" (or cpltxt link)))
5159 link)))
5160
5161 (defun org-xor (a b)
5162 "Exclusive or."
5163 (if a (not b) b))
5164
5165 (defun org-get-header (header)
5166 "Find a header field in the current buffer."
5167 (save-excursion
5168 (goto-char (point-min))
5169 (let ((case-fold-search t) s)
5170 (cond
5171 ((eq header 'from)
5172 (if (re-search-forward "^From:\\s-+\\(.*\\)" nil t)
5173 (setq s (match-string 1)))
5174 (while (string-match "\"" s)
5175 (setq s (replace-match "" t t s)))
5176 (if (string-match "[<(].*" s)
5177 (setq s (replace-match "" t t s))))
5178 ((eq header 'message-id)
5179 (if (re-search-forward "^message-id:\\s-+\\(.*\\)" nil t)
5180 (setq s (match-string 1))))
5181 ((eq header 'subject)
5182 (if (re-search-forward "^subject:\\s-+\\(.*\\)" nil t)
5183 (setq s (match-string 1)))))
5184 (if (string-match "\\`[ \t\]+" s) (setq s (replace-match "" t t s)))
5185 (if (string-match "[ \t\]+\\'" s) (setq s (replace-match "" t t s)))
5186 s)))
5187
5188
5189 (defun org-fixup-message-id-for-http (s)
5190 "Replace special characters in a message id, so it can be used in an http query."
5191 (while (string-match "<" s)
5192 (setq s (replace-match "%3C" t t s)))
5193 (while (string-match ">" s)
5194 (setq s (replace-match "%3E" t t s)))
5195 (while (string-match "@" s)
5196 (setq s (replace-match "%40" t t s)))
5197 s)
5198
5199 (defun org-insert-link (&optional complete-file)
5200 "Insert a link. At the prompt, enter the link.
5201
5202 Completion can be used to select a link previously stored with
5203 `org-store-link'. When the empty string is entered (i.e. if you just
5204 press RET at the prompt), the link defaults to the most recently
5205 stored link.
5206
5207 With a \\[universal-argument] prefix, prompts for a file to link to. The file name can be
5208 selected using completion. The path to the file will be relative to
5209 the current directory if the file is in the current directory or a
5210 subdirectory. Otherwise, the link will be the absolute path as
5211 completed in the minibuffer (i.e. normally ~/path/to/file).
5212
5213 With two \\[universal-argument] prefixes, enforce an absolute path even if the file
5214 is in the current directory or below."
5215 (interactive "P")
5216 (let ((link (if complete-file
5217 (read-file-name "File: ")
5218 (completing-read
5219 "Link: " org-stored-links nil nil nil
5220 org-insert-link-history
5221 (or (car (car org-stored-links))))))
5222 linktxt matched)
5223 (if (or (not link) (equal link ""))
5224 (error "No links available"))
5225 (if complete-file
5226 (let ((pwd (file-name-as-directory (expand-file-name "."))))
5227 (cond
5228 ((equal complete-file '(16))
5229 (insert "file:" (abbreviate-file-name (expand-file-name link))))
5230 ((string-match (concat "^" (regexp-quote pwd) "\\(.+\\)")
5231 (expand-file-name link))
5232 (insert "file:" (match-string 1 (expand-file-name link))))
5233 (t (insert "file:" link))))
5234 (setq linktxt (cdr (assoc link org-stored-links)))
5235 (if (not org-keep-stored-link-after-insertion)
5236 (setq org-stored-links (delq (assoc link org-stored-links)
5237 org-stored-links)))
5238 (let ((lines (org-split-string (or linktxt link) "\n")))
5239 (insert (car lines))
5240 (setq matched (string-match org-link-regexp (car lines)))
5241 (setq lines (cdr lines))
5242 (while lines
5243 (insert "\n")
5244 (if (save-excursion
5245 (beginning-of-line 0)
5246 (looking-at "[ \t]+\\S-"))
5247 (indent-relative))
5248 (setq matched (or matched
5249 (string-match org-link-regexp (car lines))))
5250 (insert (car lines))
5251 (setq lines (cdr lines))))
5252 (unless matched
5253 (error "Add link type: http(s),ftp,mailto,file,news,bbdb,vm,wl,rmail,gnus, or shell")))))
5254
5255 ;;; Hooks for remember.el
5256 ;;;###autoload
5257 (defun org-remember-annotation ()
5258 "Return a link to the current location as an annotation for remember.el.
5259 If you are using Org-mode files as target for data storage with
5260 remember.el, then the annotations should include a link compatible with the
5261 conventions in Org-mode. This function returns such a link."
5262 (org-store-link nil))
5263
5264 (defconst org-remember-help
5265 "Select a destination location for the note.
5266 UP/DOWN=headline TAB=cycle visibility [Q]uit RET/<left>/<right>=Store
5267 RET at beg-of-buf -> Append to file as level 2 headline
5268 RET on headline -> Store as sublevel entry to current headline
5269 <left>/<right> -> before/after current headline, same headings level")
5270
5271 ;;;###autoload
5272 (defun org-remember-handler ()
5273 "Store stuff from remember.el into an org file.
5274 First prompts for an org file. If the user just presses return, the value
5275 of `org-default-notes-file' is used.
5276 Then the command offers the headings tree of the selected file in order to
5277 file the text at a specific location.
5278 You can either immediately press RET to get the note appended to the
5279 file. Or you can use vertical cursor motion and visibility cycling (TAB) to
5280 find a better place. Then press RET or <left> or <right> in insert the note.
5281
5282 Key Cursor position Note gets inserted
5283 -----------------------------------------------------------------------------
5284 RET buffer-start as level 2 heading at end of file
5285 RET on headline as sublevel of the heading at cursor
5286 RET no heading at cursor position, level taken from context.
5287 Or use prefix arg to specify level manually.
5288 <left> on headline as same level, before current heading
5289 <right> on headline as same level, after current heading
5290
5291 So the fastest way to store the note is to press RET RET to append it to
5292 the default file. This way your current train of thought is not
5293 interrupted, in accordance with the principles of remember.el. But with
5294 little extra effort, you can push it directly to the correct location.
5295
5296 Before being stored away, the function ensures that the text has a
5297 headline, i.e. a first line that starts with a \"*\". If not, a headline
5298 is constructed from the current date and some additional data.
5299
5300 If the variable `org-adapt-indentation' is non-nil, the entire text is
5301 also indented so that it starts in the same column as the headline
5302 \(i.e. after the stars).
5303
5304 See also the variable `org-reverse-note-order'."
5305 (catch 'quit
5306 (let* ((txt (buffer-substring (point-min) (point-max)))
5307 (fastp current-prefix-arg)
5308 (file (if fastp org-default-notes-file (org-get-org-file)))
5309 (visiting (find-buffer-visiting file))
5310 (org-startup-with-deadline-check nil)
5311 (org-startup-folded nil)
5312 spos level indent reversed)
5313 ;; Modify text so that it becomes a nice subtree which can be inserted
5314 ;; into an org tree.
5315 (let* ((lines (split-string txt "\n"))
5316 (first (car lines))
5317 (lines (cdr lines)))
5318 (if (string-match "^\\*+" first)
5319 ;; Is already a headline
5320 (setq indent (make-string (- (match-end 0) (match-beginning 0)
5321 -1) ?\ ))
5322 ;; We need to add a headline: Use time and first buffer line
5323 (setq lines (cons first lines)
5324 first (concat "* " (current-time-string)
5325 " (" (remember-buffer-desc) ")")
5326 indent " "))
5327 (if org-adapt-indentation
5328 (setq lines (mapcar (lambda (x) (concat indent x)) lines)))
5329 (setq txt (concat first "\n"
5330 (mapconcat 'identity lines "\n"))))
5331 ;; Find the file
5332 (if (not visiting)
5333 (find-file-noselect file))
5334 (with-current-buffer (get-file-buffer file)
5335 (setq reversed (org-notes-order-reversed-p))
5336 (save-excursion
5337 (save-restriction
5338 (widen)
5339 ;; Ask the User for a location
5340 (setq spos (if fastp 1 (org-get-location
5341 (current-buffer)
5342 org-remember-help)))
5343 (if (not spos) (throw 'quit nil)) ; return nil to show we did
5344 ; not handle this note
5345 (goto-char spos)
5346 (cond ((bobp)
5347 ;; Put it at the start or end, as level 2
5348 (save-restriction
5349 (widen)
5350 (goto-char (if reversed (point-min) (point-max)))
5351 (if (not (bolp)) (newline))
5352 (org-paste-subtree (or current-prefix-arg 2) txt)))
5353 ((and (org-on-heading-p nil) (not current-prefix-arg))
5354 ;; Put it below this entry, at the beg/end of the subtree
5355 (org-back-to-heading)
5356 (setq level (outline-level))
5357 (if reversed
5358 (outline-end-of-heading)
5359 (outline-end-of-subtree))
5360 (if (not (bolp)) (newline))
5361 (beginning-of-line 1)
5362 (org-paste-subtree (1+ level) txt))
5363 (t
5364 ;; Put it right there, with automatic level determined by
5365 ;; org-paste-subtree or from prefix arg
5366 (org-paste-subtree current-prefix-arg txt)))
5367 (when remember-save-after-remembering
5368 (save-buffer)
5369 (if (not visiting) (kill-buffer (current-buffer)))))))))
5370 t) ;; return t to indicate that we took care of this note.
5371
5372 (defun org-get-org-file ()
5373 "Read a filename, with default directory `org-directory'."
5374 (let ((default (or org-default-notes-file remember-data-file)))
5375 (read-file-name (format "File name [%s]: " default)
5376 (file-name-as-directory org-directory)
5377 default)))
5378
5379 (defun org-notes-order-reversed-p ()
5380 "Check if the current file should receive notes in reversed order."
5381 (cond
5382 ((not org-reverse-note-order) nil)
5383 ((eq t org-reverse-note-order) t)
5384 ((not (listp org-reverse-note-order)) nil)
5385 (t (catch 'exit
5386 (let ((all org-reverse-note-order)
5387 entry)
5388 (while (setq entry (pop all))
5389 (if (string-match (car entry) (buffer-file-name))
5390 (throw 'exit (cdr entry))))
5391 nil)))))
5392
5393 ;;; Tables
5394
5395 ;; Watch out: Here we are talking about two different kind of tables.
5396 ;; Most of the code is for the tables created with the Org-mode table editor.
5397 ;; Sometimes, we talk about tables created and edited with the table.el
5398 ;; Emacs package. We call the former org-type tables, and the latter
5399 ;; table.el-type tables.
5400
5401
5402 (defun org-before-change-function (beg end)
5403 "Every change indicates that a table might need an update."
5404 (setq org-table-may-need-update t))
5405
5406 (defconst org-table-line-regexp "^[ \t]*|"
5407 "Detects an org-type table line.")
5408 (defconst org-table-dataline-regexp "^[ \t]*|[^-]"
5409 "Detects an org-type table line.")
5410 (defconst org-table-hline-regexp "^[ \t]*|-"
5411 "Detects an org-type table hline.")
5412 (defconst org-table1-hline-regexp "^[ \t]*\\+-[-+]"
5413 "Detects a table-type table hline.")
5414 (defconst org-table-any-line-regexp "^[ \t]*\\(|\\|\\+-[-+]\\)"
5415 "Detects an org-type or table-type table.")
5416 (defconst org-table-border-regexp "^[ \t]*[^| \t]"
5417 "Searching from within a table (any type) this finds the first line
5418 outside the table.")
5419 (defconst org-table-any-border-regexp "^[ \t]*[^|+ \t]"
5420 "Searching from within a table (any type) this finds the first line
5421 outside the table.")
5422
5423 (defun org-table-create-with-table.el ()
5424 "Use the table.el package to insert a new table.
5425 If there is already a table at point, convert between Org-mode tables
5426 and table.el tables."
5427 (interactive)
5428 (require 'table)
5429 (cond
5430 ((org-at-table.el-p)
5431 (if (y-or-n-p "Convert table to Org-mode table? ")
5432 (org-table-convert)))
5433 ((org-at-table-p)
5434 (if (y-or-n-p "Convert table to table.el table? ")
5435 (org-table-convert)))
5436 (t (call-interactively 'table-insert))))
5437
5438 (defun org-table-create (&optional size)
5439 "Query for a size and insert a table skeleton.
5440 SIZE is a string Columns x Rows like for example \"3x2\"."
5441 (interactive "P")
5442 (unless size
5443 (setq size (read-string
5444 (concat "Table size Columns x Rows [e.g. "
5445 org-table-default-size "]: ")
5446 "" nil org-table-default-size)))
5447
5448 (let* ((pos (point))
5449 (indent (make-string (current-column) ?\ ))
5450 (split (org-split-string size " *x *"))
5451 (rows (string-to-number (nth 1 split)))
5452 (columns (string-to-number (car split)))
5453 (line (concat (apply 'concat indent "|" (make-list columns " |"))
5454 "\n")))
5455 (if (string-match "^[ \t]*$" (buffer-substring-no-properties
5456 (point-at-bol) (point)))
5457 (beginning-of-line 1)
5458 (newline))
5459 ;; (mapcar (lambda (x) (insert line)) (make-list rows t))
5460 (dotimes (i rows) (insert line))
5461 (goto-char pos)
5462 (if (> rows 1)
5463 ;; Insert a hline after the first row.
5464 (progn
5465 (end-of-line 1)
5466 (insert "\n|-")
5467 (goto-char pos)))
5468 (org-table-align)))
5469
5470 (defun org-table-convert-region (beg0 end0 nspace)
5471 "Convert region to a table.
5472 The region goes from BEG0 to END0, but these borders will be moved
5473 slightly, to make sure a beginning of line in the first line is included.
5474 When NSPACE is non-nil, it indicates the minimum number of spaces that
5475 separate columns (default: just one space)"
5476 (let* ((beg (min beg0 end0))
5477 (end (max beg0 end0))
5478 (tabsep t)
5479 re)
5480 (goto-char beg)
5481 (beginning-of-line 1)
5482 (setq beg (move-marker (make-marker) (point)))
5483 (goto-char end)
5484 (if (bolp) (backward-char 1) (end-of-line 1))
5485 (setq end (move-marker (make-marker) (point)))
5486 ;; Lets see if this is tab-separated material. If every nonempty line
5487 ;; contains a tab, we will assume that it is tab-separated material
5488 (if nspace
5489 (setq tabsep nil)
5490 (goto-char beg)
5491 (and (re-search-forward "^[^\n\t]+$" end t) (setq tabsep nil)))
5492 (if nspace (setq tabsep nil))
5493 (if tabsep
5494 (setq re "^\\|\t")
5495 (setq re (format "^ *\\| *\t *\\| \\{%d,\\}"
5496 (max 1 (prefix-numeric-value nspace)))))
5497 (goto-char beg)
5498 (while (re-search-forward re end t)
5499 (replace-match "|" t t))
5500 (goto-char beg)
5501 (insert " ")
5502 (org-table-align)))
5503
5504 (defun org-table-import (file arg)
5505 "Import FILE as a table.
5506 The file is assumed to be tab-separated. Such files can be produced by most
5507 spreadsheet and database applications. If no tabs (at least one per line)
5508 are found, lines will be split on whitespace into fields."
5509 (interactive "f\nP")
5510 (or (bolp) (newline))
5511 (let ((beg (point))
5512 (pm (point-max)))
5513 (insert-file-contents file)
5514 (org-table-convert-region beg (+ (point) (- (point-max) pm)) arg)))
5515
5516 (defun org-table-export ()
5517 "Export table as a tab-separated file.
5518 Such a file can be imported into a spreadsheet program like Excel."
5519 (interactive)
5520 (let* ((beg (org-table-begin))
5521 (end (org-table-end))
5522 (table (buffer-substring beg end))
5523 (file (read-file-name "Export table to: "))
5524 buf)
5525 (unless (or (not (file-exists-p file))
5526 (y-or-n-p (format "Overwrite file %s? " file)))
5527 (error "Abort"))
5528 (with-current-buffer (find-file-noselect file)
5529 (setq buf (current-buffer))
5530 (erase-buffer)
5531 (fundamental-mode)
5532 (insert table)
5533 (goto-char (point-min))
5534 (while (re-search-forward "^[ \t]*|[ \t]*" nil t)
5535 (replace-match "" t t)
5536 (end-of-line 1))
5537 (goto-char (point-min))
5538 (while (re-search-forward "[ \t]*|[ \t]*$" nil t)
5539 (replace-match "" t t)
5540 (goto-char (min (1+ (point)) (point-max))))
5541 (goto-char (point-min))
5542 (while (re-search-forward "^-[-+]*$" nil t)
5543 (replace-match "")
5544 (if (looking-at "\n")
5545 (delete-char 1)))
5546 (goto-char (point-min))
5547 (while (re-search-forward "[ \t]*|[ \t]*" nil t)
5548 (replace-match "\t" t t))
5549 (save-buffer))
5550 (kill-buffer buf)))
5551
5552 (defvar org-table-aligned-begin-marker (make-marker)
5553 "Marker at the beginning of the table last aligned.
5554 Used to check if cursor still is in that table, to minimize realignment.")
5555 (defvar org-table-aligned-end-marker (make-marker)
5556 "Marker at the end of the table last aligned.
5557 Used to check if cursor still is in that table, to minimize realignment.")
5558 (defvar org-table-last-alignment nil
5559 "List of flags for flushright alignment, from the last re-alignment.
5560 This is being used to correctly align a single field after TAB or RET.")
5561 ;; FIXME: The following is currently not used.
5562 (defvar org-table-last-column-widths nil
5563 "List of max width of fields in each column.
5564 This is being used to correctly align a single field after TAB or RET.")
5565
5566
5567 (defun org-table-align ()
5568 "Align the table at point by aligning all vertical bars."
5569 (interactive)
5570 (let* (
5571 ;; Limits of table
5572 (beg (org-table-begin))
5573 (end (org-table-end))
5574 ;; Current cursor position
5575 (linepos (+ (if (bolp) 1 0) (count-lines (point-min) (point))))
5576 (colpos (org-table-current-column))
5577 (winstart (window-start))
5578 text lines (new "") lengths l typenums ty fields maxfields i
5579 column
5580 (indent "") cnt frac
5581 rfmt hfmt
5582 (spaces (if (org-in-invisibility-spec-p '(org-table))
5583 org-table-spaces-around-invisible-separators
5584 org-table-spaces-around-separators))
5585 (sp1 (car spaces))
5586 (sp2 (cdr spaces))
5587 (rfmt1 (concat
5588 (make-string sp2 ?\ ) "%%%s%ds" (make-string sp1 ?\ ) "|"))
5589 (hfmt1 (concat
5590 (make-string sp2 ?-) "%s" (make-string sp1 ?-) "+"))
5591 emptystrings)
5592 (untabify beg end)
5593 ;; (message "Aligning table...")
5594 ;; Get the rows
5595 (setq lines (org-split-string
5596 (buffer-substring-no-properties beg end) "\n"))
5597 ;; Store the indentation of the first line
5598 (if (string-match "^ *" (car lines))
5599 (setq indent (make-string (- (match-end 0) (match-beginning 0)) ?\ )))
5600 ;; Mark the hlines
5601 (setq lines (mapcar (lambda (l) (if (string-match "^ *|-" l) nil l))
5602 lines))
5603 ;; Get the data fields
5604 (setq fields (mapcar
5605 (lambda (l)
5606 (org-split-string l " *| *"))
5607 (delq nil (copy-sequence lines))))
5608 ;; How many fields in the longest line?
5609 (condition-case nil
5610 (setq maxfields (apply 'max (mapcar 'length fields)))
5611 (error
5612 (kill-region beg end)
5613 (org-table-create org-table-default-size)
5614 (error "Empty table - created default table")))
5615 ;; A list of empty string to fill any short rows on output
5616 (setq emptystrings (make-list maxfields ""))
5617 ;; Get the maximum length of a field and the most common datatype
5618 ;; for each column
5619 (setq i -1)
5620 (while (< (setq i (1+ i)) maxfields) ;; Loop over all columns
5621 (setq column (mapcar (lambda (x) (or (nth i x) "")) fields))
5622 ;; maximum length
5623 (push (apply 'max 1 (mapcar 'length column)) lengths)
5624 ;; compute the fraction stepwise, ignoring empty fields
5625 (setq cnt 0 frac 0.0)
5626 (mapcar
5627 (lambda (x)
5628 (if (equal x "")
5629 nil
5630 (setq frac ( / (+ (* frac cnt)
5631 (if (string-match org-table-number-regexp x) 1 0))
5632 (setq cnt (1+ cnt))))))
5633 column)
5634 (push (>= frac org-table-number-fraction) typenums))
5635 (setq lengths (nreverse lengths)
5636 typenums (nreverse typenums))
5637 (setq org-table-last-alignment typenums
5638 org-table-last-column-widths lengths)
5639 ;; Compute the formats needed for output of the table
5640 (setq rfmt (concat indent "|") hfmt (concat indent "|"))
5641 (while (setq l (pop lengths))
5642 (setq ty (if (pop typenums) "" "-")) ; number types flushright
5643 (setq rfmt (concat rfmt (format rfmt1 ty l))
5644 hfmt (concat hfmt (format hfmt1 (make-string l ?-)))))
5645 (setq rfmt (concat rfmt "\n")
5646 hfmt (concat (substring hfmt 0 -1) "|\n"))
5647 ;; Produce the new table
5648 ;;(while lines
5649 ;; (setq l (pop lines))
5650 ;; (if l
5651 ;; (setq new (concat new (apply 'format rfmt
5652 ;; (append (pop fields) emptystrings))))
5653 ;; (setq new (concat new hfmt))))
5654 (setq new (mapconcat
5655 (lambda (l)
5656 (if l (apply 'format rfmt
5657 (append (pop fields) emptystrings))
5658 hfmt))
5659 lines ""))
5660 ;; Replace the old one
5661 (delete-region beg end)
5662 (move-marker end nil)
5663 (move-marker org-table-aligned-begin-marker (point))
5664 (insert new)
5665 (move-marker org-table-aligned-end-marker (point))
5666 ;; Try to move to the old location (approximately)
5667 (goto-line linepos)
5668 (set-window-start (selected-window) winstart 'noforce)
5669 (org-table-goto-column colpos)
5670 (setq org-table-may-need-update nil)
5671 (if (org-in-invisibility-spec-p '(org-table))
5672 (org-table-add-invisible-to-vertical-lines))
5673 ))
5674
5675 (defun org-table-begin (&optional table-type)
5676 "Find the beginning of the table and return its position.
5677 With argument TABLE-TYPE, go to the beginning of a table.el-type table."
5678 (save-excursion
5679 (if (not (re-search-backward
5680 (if table-type org-table-any-border-regexp
5681 org-table-border-regexp)
5682 nil t))
5683 (error "Can't find beginning of table")
5684 (goto-char (match-beginning 0))
5685 (beginning-of-line 2)
5686 (point))))
5687
5688 (defun org-table-end (&optional table-type)
5689 "Find the end of the table and return its position.
5690 With argument TABLE-TYPE, go to the end of a table.el-type table."
5691 (save-excursion
5692 (if (not (re-search-forward
5693 (if table-type org-table-any-border-regexp
5694 org-table-border-regexp)
5695 nil t))
5696 (goto-char (point-max))
5697 (goto-char (match-beginning 0)))
5698 (point-marker)))
5699
5700 (defun org-table-justify-field-maybe ()
5701 "Justify the current field, text to left, number to right."
5702 (cond
5703 (org-table-may-need-update) ; Realignment will happen anyway, don't bother
5704 ((org-at-table-hline-p)
5705 ;; This is pretty stupid, but I don't know how to deal with hlines
5706 (setq org-table-may-need-update t))
5707 ((or (not (equal (marker-buffer org-table-aligned-begin-marker)
5708 (current-buffer)))
5709 (< (point) org-table-aligned-begin-marker)
5710 (>= (point) org-table-aligned-end-marker))
5711 ;; This is not the same table, force a full re-align
5712 (setq org-table-may-need-update t))
5713 (t ;; realign the current field, based on previous full realign
5714 (let* ((pos (point)) s org-table-may-need-update
5715 (col (org-table-current-column))
5716 (num (nth (1- col) org-table-last-alignment))
5717 l f)
5718 (when (> col 0)
5719 (skip-chars-backward "^|\n")
5720 (if (looking-at " *\\([^|\n]*?\\) *|")
5721 (progn
5722 (setq s (match-string 1)
5723 l (max 1 (- (match-end 0) (match-beginning 0) 3)))
5724 (setq f (format (if num " %%%ds |" " %%-%ds |") l))
5725 (replace-match (format f s t t)))
5726 (setq org-table-may-need-update t))
5727 (goto-char pos))))))
5728
5729 (defun org-table-next-field ()
5730 "Go to the next field in the current table.
5731 Before doing so, re-align the table if necessary."
5732 (interactive)
5733 (if (and org-table-automatic-realign
5734 org-table-may-need-update)
5735 (org-table-align))
5736 (if (org-at-table-hline-p)
5737 (end-of-line 1))
5738 (condition-case nil
5739 (progn
5740 (re-search-forward "|" (org-table-end))
5741 (if (looking-at "[ \t]*$")
5742 (re-search-forward "|" (org-table-end)))
5743 (if (looking-at "-")
5744 (progn
5745 (beginning-of-line 0)
5746 (org-table-insert-row 'below))
5747 (if (looking-at " ") (forward-char 1))))
5748 (error
5749 (org-table-insert-row 'below))))
5750
5751 (defun org-table-previous-field ()
5752 "Go to the previous field in the table.
5753 Before doing so, re-align the table if necessary."
5754 (interactive)
5755 (if (and org-table-automatic-realign
5756 org-table-may-need-update)
5757 (org-table-align))
5758 (if (org-at-table-hline-p)
5759 (end-of-line 1))
5760 (re-search-backward "|" (org-table-begin))
5761 (re-search-backward "|" (org-table-begin))
5762 (while (looking-at "|\\(-\\|[ \t]*$\\)")
5763 (re-search-backward "|" (org-table-begin)))
5764 (if (looking-at "| ?")
5765 (goto-char (match-end 0))))
5766
5767 (defun org-table-next-row ()
5768 "Go to the next row (same column) in the current table.
5769 Before doing so, re-align the table if necessary."
5770 (interactive)
5771 (if (or (looking-at "[ \t]*$")
5772 (save-excursion (skip-chars-backward " \t") (bolp)))
5773 (newline)
5774 (if (and org-table-automatic-realign
5775 org-table-may-need-update)
5776 (org-table-align))
5777 (let ((col (org-table-current-column)))
5778 (beginning-of-line 2)
5779 (if (or (not (org-at-table-p))
5780 (org-at-table-hline-p))
5781 (progn
5782 (beginning-of-line 0)
5783 (org-table-insert-row 'below)))
5784 (org-table-goto-column col)
5785 (skip-chars-backward "^|\n\r")
5786 (if (looking-at " ") (forward-char 1)))))
5787
5788 (defun org-table-copy-down (n)
5789 "Copy a field down in the current column.
5790 If the field at the cursor is empty, copy into it the content of the nearest
5791 non-empty field above. With argument N, use the Nth non-empty field.
5792 If the current field is not empty, it is copied down to the next row, and
5793 the cursor is moved with it. Therefore, repeating this command causes the
5794 column to be filled row-by-row.
5795 If the variable `org-table-copy-increment' is non-nil and the field is an
5796 integer, it will be incremented while copying."
5797 (interactive "p")
5798 (let* ((colpos (org-table-current-column))
5799 (field (org-table-get-field))
5800 (non-empty (string-match "[^ \t]" field))
5801 (beg (org-table-begin))
5802 txt)
5803 (org-table-check-inside-data-field)
5804 (if non-empty (progn (org-table-next-row) (org-table-blank-field)))
5805 (if (save-excursion
5806 (setq txt
5807 (catch 'exit
5808 (while (progn (beginning-of-line 1)
5809 (re-search-backward org-table-dataline-regexp
5810 beg t))
5811 (org-table-goto-column colpos t)
5812 (if (and (looking-at
5813 "|[ \t]*\\([^| \t][^|]*?\\)[ \t]*|")
5814 (= (setq n (1- n)) 0))
5815 (throw 'exit (match-string 1)))))))
5816 (progn
5817 (if (and org-table-copy-increment
5818 (string-match "^[0-9]+$" txt))
5819 (setq txt (format "%d" (+ (string-to-int txt) 1))))
5820 (insert txt)
5821 (org-table-align))
5822 (error "No non-empty field found"))))
5823
5824 (defun org-table-check-inside-data-field ()
5825 "Is point inside a table data field?
5826 I.e. not on a hline or before the first or after the last column?"
5827 (if (or (not (org-at-table-p))
5828 (= (org-table-current-column) 0)
5829 (org-at-table-hline-p)
5830 (looking-at "[ \t]*$"))
5831 (error "Not in table data field")))
5832
5833 (defvar org-table-clip nil
5834 "Clipboard for table regions.")
5835
5836 (defun org-table-blank-field ()
5837 "Blank the current table field or active region."
5838 (interactive)
5839 (org-table-check-inside-data-field)
5840 (if (and (interactive-p) (org-region-active-p))
5841 (let (org-table-clip)
5842 (org-table-cut-region))
5843 (skip-chars-backward "^|")
5844 (backward-char 1)
5845 (if (looking-at "|[^|]+")
5846 (let* ((pos (match-beginning 0))
5847 (match (match-string 0))
5848 (len (length match)))
5849 (replace-match (concat "|" (make-string (1- len) ?\ )))
5850 (goto-char (+ 2 pos))
5851 (substring match 1)))))
5852
5853 (defun org-table-get-field (&optional n replace)
5854 "Return the value of the field in column N of current row.
5855 N defaults to current field.
5856 If REPLACE is a string, replace field with this value. The return value
5857 is always the old value."
5858 (and n (org-table-goto-column n))
5859 (skip-chars-backward "^|")
5860 (backward-char 1)
5861 (if (looking-at "|[^|\r\n]*")
5862 (let* ((pos (match-beginning 0))
5863 (val (buffer-substring (1+ pos) (match-end 0))))
5864 (if replace
5865 (replace-match (concat "|" replace)))
5866 (goto-char (+ 2 pos))
5867 val)))
5868
5869 (defun org-table-current-column ()
5870 "Find out which column we are in.
5871 When called interactively, column is also displayed in echo area."
5872 (interactive)
5873 (if (interactive-p) (org-table-check-inside-data-field))
5874 (save-excursion
5875 (let ((cnt 0) (pos (point)))
5876 (beginning-of-line 1)
5877 (while (search-forward "|" pos t)
5878 (setq cnt (1+ cnt)))
5879 (if (interactive-p) (message "This is table column %d" cnt))
5880 cnt)))
5881
5882 (defun org-table-goto-column (n &optional on-delim force)
5883 "Move the cursor to the Nth column in the current table line.
5884 With optional argument ON-DELIM, stop with point before the left delimiter
5885 of the field.
5886 If there are less than N fields, just go to after the last delimiter.
5887 However, when FORCE is non-nil, create new columns if necessary."
5888 (let ((pos (point-at-eol)))
5889 (beginning-of-line 1)
5890 (when (> n 0)
5891 (while (and (> (setq n (1- n)) -1)
5892 (or (search-forward "|" pos t)
5893 (and force
5894 (progn (end-of-line 1)
5895 (skip-chars-backward "^|")
5896 (insert " |")
5897 (backward-char 2) t)))))
5898 (when (and force (not (looking-at ".*|")))
5899 (save-excursion (end-of-line 1) (insert "|")))
5900 (if on-delim
5901 (backward-char 1)
5902 (if (looking-at " ") (forward-char 1))))))
5903
5904 (defun org-at-table-p (&optional table-type)
5905 "Return t if the cursor is inside an org-type table."
5906 (if org-enable-table-editor
5907 (save-excursion
5908 (beginning-of-line 1)
5909 (looking-at (if table-type org-table-any-line-regexp
5910 org-table-line-regexp)))
5911 nil))
5912
5913 (defun org-table-recognize-table.el ()
5914 "If there is a table.el table nearby, recognize it and move into it."
5915 (if org-table-tab-recognizes-table.el
5916 (if (org-at-table.el-p)
5917 (progn
5918 (beginning-of-line 1)
5919 (if (looking-at org-table-dataline-regexp)
5920 nil
5921 (if (looking-at org-table1-hline-regexp)
5922 (progn
5923 (beginning-of-line 2)
5924 (if (looking-at org-table-any-border-regexp)
5925 (beginning-of-line -1)))))
5926 (if (re-search-forward "|" (org-table-end t) t)
5927 (progn
5928 (require 'table)
5929 (if (table--at-cell-p (point))
5930 t
5931 (message "recognizing table.el table...")
5932 (table-recognize-table)
5933 (message "recognizing table.el table...done")))
5934 (error "This should not happen..."))
5935 t)
5936 nil)
5937 nil))
5938
5939 (defun org-at-table.el-p ()
5940 "Return t if the cursor is inside a table.el-type table."
5941 (save-excursion
5942 (if (org-at-table-p 'any)
5943 (progn
5944 (goto-char (org-table-begin 'any))
5945 (looking-at org-table1-hline-regexp))
5946 nil)))
5947
5948 (defun org-at-table-hline-p ()
5949 "Return t if the cursor is inside a hline in a table."
5950 (if org-enable-table-editor
5951 (save-excursion
5952 (beginning-of-line 1)
5953 (looking-at org-table-hline-regexp))
5954 nil))
5955
5956 (defun org-table-insert-column ()
5957 "Insert a new column into the table."
5958 (interactive)
5959 (if (not (org-at-table-p))
5960 (error "Not at a table"))
5961 (org-table-find-dataline)
5962 (let* ((col (max 1 (org-table-current-column)))
5963 (beg (org-table-begin))
5964 (end (org-table-end))
5965 ;; Current cursor position
5966 (linepos (+ (if (bolp) 1 0) (count-lines (point-min) (point))))
5967 (colpos col))
5968 (goto-char beg)
5969 (while (< (point) end)
5970 (if (org-at-table-hline-p)
5971 nil
5972 (org-table-goto-column col t)
5973 (insert "| "))
5974 (beginning-of-line 2))
5975 (move-marker end nil)
5976 (goto-line linepos)
5977 (org-table-goto-column colpos))
5978 (org-table-align))
5979
5980 (defun org-table-find-dataline ()
5981 "Find a dataline in the current table, which is needed for column commands."
5982 (if (and (org-at-table-p)
5983 (not (org-at-table-hline-p)))
5984 t
5985 (let ((col (current-column))
5986 (end (org-table-end)))
5987 (move-to-column col)
5988 (while (and (< (point) end)
5989 (or (not (= (current-column) col))
5990 (org-at-table-hline-p)))
5991 (beginning-of-line 2)
5992 (move-to-column col))
5993 (if (and (org-at-table-p)
5994 (not (org-at-table-hline-p)))
5995 t
5996 (error
5997 "Please position cursor in a data line for column operations")))))
5998
5999 (defun org-table-delete-column ()
6000 "Delete a column into the table."
6001 (interactive)
6002 (if (not (org-at-table-p))
6003 (error "Not at a table"))
6004 (org-table-find-dataline)
6005 (org-table-check-inside-data-field)
6006 (let* ((col (org-table-current-column))
6007 (beg (org-table-begin))
6008 (end (org-table-end))
6009 ;; Current cursor position
6010 (linepos (+ (if (bolp) 1 0) (count-lines (point-min) (point))))
6011 (colpos col))
6012 (goto-char beg)
6013 (while (< (point) end)
6014 (if (org-at-table-hline-p)
6015 nil
6016 (org-table-goto-column col t)
6017 (and (looking-at "|[^|\n]+|")
6018 (replace-match "|")))
6019 (beginning-of-line 2))
6020 (move-marker end nil)
6021 (goto-line linepos)
6022 (org-table-goto-column colpos))
6023 (org-table-align))
6024
6025 (defun org-table-move-column-right ()
6026 "Move column to the right."
6027 (interactive)
6028 (org-table-move-column nil))
6029 (defun org-table-move-column-left ()
6030 "Move column to the left."
6031 (interactive)
6032 (org-table-move-column 'left))
6033
6034 (defun org-table-move-column (&optional left)
6035 "Move the current column to the right. With arg LEFT, move to the left."
6036 (interactive "P")
6037 (if (not (org-at-table-p))
6038 (error "Not at a table"))
6039 (org-table-find-dataline)
6040 (org-table-check-inside-data-field)
6041 (let* ((col (org-table-current-column))
6042 (col1 (if left (1- col) col))
6043 (beg (org-table-begin))
6044 (end (org-table-end))
6045 ;; Current cursor position
6046 (linepos (+ (if (bolp) 1 0) (count-lines (point-min) (point))))
6047 (colpos (if left (1- col) (1+ col))))
6048 (if (and left (= col 1))
6049 (error "Cannot move column further left"))
6050 (if (and (not left) (looking-at "[^|\n]*|[^|\n]*$"))
6051 (error "Cannot move column further right"))
6052 (goto-char beg)
6053 (while (< (point) end)
6054 (if (org-at-table-hline-p)
6055 nil
6056 (org-table-goto-column col1 t)
6057 (and (looking-at "|\\([^|\n]+\\)|\\([^|\n]+\\)|")
6058 (replace-match "|\\2|\\1|")))
6059 (beginning-of-line 2))
6060 (move-marker end nil)
6061 (goto-line linepos)
6062 (org-table-goto-column colpos))
6063 (org-table-align))
6064
6065 (defun org-table-move-row-down ()
6066 "Move table row down."
6067 (interactive)
6068 (org-table-move-row nil))
6069 (defun org-table-move-row-up ()
6070 "Move table row up."
6071 (interactive)
6072 (org-table-move-row 'up))
6073
6074 (defun org-table-move-row (&optional up)
6075 "Move the current table line down. With arg UP, move it up."
6076 (interactive "P")
6077 (let ((col (current-column))
6078 (pos (point))
6079 (tonew (if up 0 2))
6080 txt)
6081 (beginning-of-line tonew)
6082 (if (not (org-at-table-p))
6083 (progn
6084 (goto-char pos)
6085 (error "Cannot move row further.")))
6086 (goto-char pos)
6087 (beginning-of-line 1)
6088 (setq pos (point))
6089 (setq txt (buffer-substring (point) (1+ (point-at-eol))))
6090 (delete-region (point) (1+ (point-at-eol)))
6091 (beginning-of-line tonew)
6092 (insert txt)
6093 (beginning-of-line 0)
6094 (move-to-column col)))
6095
6096 (defun org-table-insert-row (&optional arg)
6097 "Insert a new row above the current line into the table.
6098 With prefix ARG, insert below the current line."
6099 (interactive "P")
6100 (if (not (org-at-table-p))
6101 (error "Not at a table"))
6102 (let ((line (buffer-substring-no-properties (point-at-bol) (point-at-eol))))
6103 (if (string-match "^[ \t]*|-" line)
6104 (setq line (mapcar (lambda (x) (if (member x '(?| ?+)) ?| ?\ )) line))
6105 (setq line (mapcar (lambda (x) (if (equal x ?|) ?| ?\ )) line)))
6106 (beginning-of-line (if arg 2 1))
6107 (let (org-table-may-need-update)
6108 (apply 'insert-before-markers line)
6109 (insert-before-markers "\n"))
6110 (beginning-of-line 0)
6111 (re-search-forward "| ?" (point-at-eol) t)
6112 (and org-table-may-need-update (org-table-align))))
6113
6114 (defun org-table-insert-hline (&optional arg)
6115 "Insert a horizontal-line below the current line into the table.
6116 With prefix ARG, insert above the current line."
6117 (interactive "P")
6118 (if (not (org-at-table-p))
6119 (error "Not at a table"))
6120 (let ((line (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
6121 (col (current-column))
6122 start)
6123 (if (string-match "^[ \t]*|-" line)
6124 (setq line
6125 (mapcar (lambda (x) (if (member x '(?| ?+))
6126 (prog1 (if start ?+ ?|) (setq start t))
6127 (if start ?- ?\ )))
6128 line))
6129 (setq line
6130 (mapcar (lambda (x) (if (equal x ?|)
6131 (prog1 (if start ?+ ?|) (setq start t))
6132 (if start ?- ?\ )))
6133 line)))
6134 (beginning-of-line (if arg 1 2))
6135 (apply 'insert line)
6136 (if (equal (char-before (point)) ?+)
6137 (progn (backward-delete-char 1) (insert "|")))
6138 (insert "\n")
6139 (beginning-of-line 0)
6140 (move-to-column col)))
6141
6142 (defun org-table-kill-row ()
6143 "Delete the current row or horizontal line from the table."
6144 (interactive)
6145 (if (not (org-at-table-p))
6146 (error "Not at a table"))
6147 (let ((col (current-column)))
6148 (kill-region (point-at-bol) (min (1+ (point-at-eol)) (point-max)))
6149 (if (not (org-at-table-p)) (beginning-of-line 0))
6150 (move-to-column col)))
6151
6152
6153 (defun org-table-cut-region ()
6154 "Copy region in table to the clipboard and blank all relevant fields."
6155 (interactive)
6156 (org-table-copy-region 'cut))
6157
6158 (defun org-table-copy-region (&optional cut)
6159 "Copy rectangular region in table to clipboard.
6160 A special clipboard is used which can only be accessed
6161 with `org-table-paste-rectangle'"
6162 (interactive "P")
6163 (unless (org-region-active-p) (error "No active region"))
6164 (let* ((beg (region-beginning))
6165 (end (region-end))
6166 l01 c01 l02 c02 l1 c1 l2 c2 ic1 ic2
6167 region cols
6168 (rpl (if cut " " nil)))
6169 (goto-char beg)
6170 (org-table-check-inside-data-field)
6171 (setq l01 (count-lines (point-min) (point))
6172 c01 (org-table-current-column))
6173 (goto-char end)
6174 (org-table-check-inside-data-field)
6175 (setq l02 (count-lines (point-min) (point))
6176 c02 (org-table-current-column))
6177 (setq l1 (min l01 l02) l2 (max l01 l02)
6178 c1 (min c01 c02) c2 (max c01 c02))
6179 (catch 'exit
6180 (while t
6181 (catch 'nextline
6182 (if (> l1 l2) (throw 'exit t))
6183 (goto-line l1)
6184 (if (org-at-table-hline-p) (throw 'nextline (setq l1 (1+ l1))))
6185 (setq cols nil ic1 c1 ic2 c2)
6186 (while (< ic1 (1+ ic2))
6187 (push (org-table-get-field ic1 rpl) cols)
6188 (setq ic1 (1+ ic1)))
6189 (push (nreverse cols) region)
6190 (setq l1 (1+ l1)))))
6191 (setq org-table-clip (nreverse region))
6192 (if cut (org-table-align))))
6193
6194 (defun org-table-paste-rectangle ()
6195 "Paste a rectangular region into a table.
6196 The upper right corner ends up in the current field. All involved fields
6197 will be overwritten. If the rectangle does not fit into the present table,
6198 the table is enlarged as needed. The process ignores horizontal separator
6199 lines."
6200 (interactive)
6201 (unless (and org-table-clip (listp org-table-clip))
6202 (error "First cut/copy a region to paste!"))
6203 (org-table-check-inside-data-field)
6204 (let* ((clip org-table-clip)
6205 (line (count-lines (point-min) (point)))
6206 (col (org-table-current-column))
6207 (org-enable-table-editor t)
6208 (org-table-automatic-realign nil)
6209 c cols field)
6210 (while (setq cols (pop clip))
6211 (while (org-at-table-hline-p) (beginning-of-line 2))
6212 (if (not (org-at-table-p))
6213 (progn (end-of-line 0) (org-table-next-field)))
6214 (setq c col)
6215 (while (setq field (pop cols))
6216 (org-table-goto-column c nil 'force)
6217 (org-table-get-field nil field)
6218 (setq c (1+ c)))
6219 (beginning-of-line 2))
6220 (goto-line line)
6221 (org-table-goto-column col)
6222 (org-table-align)))
6223
6224 (defun org-table-convert ()
6225 "Convert from `org-mode' table to table.el and back.
6226 Obviously, this only works within limits. When an Org-mode table is
6227 converted to table.el, all horizontal separator lines get lost, because
6228 table.el uses these as cell boundaries and has no notion of horizontal lines.
6229 A table.el table can be converted to an Org-mode table only if it does not
6230 do row or column spanning. Multiline cells will become multiple cells.
6231 Beware, Org-mode does not test if the table can be successfully converted - it
6232 blindly applies a recipe that works for simple tables."
6233 (interactive)
6234 (require 'table)
6235 (if (org-at-table.el-p)
6236 ;; convert to Org-mode table
6237 (let ((beg (move-marker (make-marker) (org-table-begin t)))
6238 (end (move-marker (make-marker) (org-table-end t))))
6239 (table-unrecognize-region beg end)
6240 (goto-char beg)
6241 (while (re-search-forward "^\\([ \t]*\\)\\+-.*\n" end t)
6242 (replace-match ""))
6243 (goto-char beg))
6244 (if (org-at-table-p)
6245 ;; convert to table.el table
6246 (let ((beg (move-marker (make-marker) (org-table-begin)))
6247 (end (move-marker (make-marker) (org-table-end))))
6248 ;; first, get rid of all horizontal lines
6249 (goto-char beg)
6250 (while (re-search-forward "^\\([ \t]*\\)|-.*\n" end t)
6251 (replace-match ""))
6252 ;; insert a hline before first
6253 (goto-char beg)
6254 (org-table-insert-hline 'above)
6255 ;; insert a hline after each line
6256 (while (progn (beginning-of-line 2) (< (point) end))
6257 (org-table-insert-hline))
6258 (goto-char beg)
6259 (setq end (move-marker end (org-table-end)))
6260 ;; replace "+" at beginning and ending of hlines
6261 (while (re-search-forward "^\\([ \t]*\\)|-" end t)
6262 (replace-match "\\1+-"))
6263 (goto-char beg)
6264 (while (re-search-forward "-|[ \t]*$" end t)
6265 (replace-match "-+"))
6266 (goto-char beg)))))
6267
6268 (defun org-table-wrap-region (arg)
6269 "Wrap several fields in a column like a paragraph.
6270 This is useful if you'd like to spread the contents of a field over several
6271 lines, in order to keep the table compact.
6272
6273 If there is an active region, and both point and mark are in the same column,
6274 the text in the column is wrapped to minimum width for the given number of
6275 lines. Generally, this makes the table more compact. A prefix ARG may be
6276 used to change the number of desired lines. For example, `C-2 \\[org-table-wrap]'
6277 formats the selected text to two lines. If the region was longer than 2
6278 lines, the remaining lines remain empty. A negative prefix argument reduces
6279 the current number of lines by that amount. The wrapped text is pasted back
6280 into the table. If you formatted it to more lines than it was before, fields
6281 further down in the table get overwritten - so you might need to make space in
6282 the table first.
6283
6284 If there is no region, the current field is split at the cursor position and
6285 the text fragment to the right of the cursor is prepended to the field one
6286 line down.
6287
6288 If there is no region, but you specify a prefix ARG, the current field gets
6289 blank, and the content is appended to the field above."
6290 (interactive "P")
6291 (org-table-check-inside-data-field)
6292 (if (org-region-active-p)
6293 ;; There is a region: fill as a paragraph
6294 (let ((beg (region-beginning))
6295 nlines)
6296 (org-table-cut-region)
6297 (if (> (length (car org-table-clip)) 1)
6298 (error "Region must be limited to single column"))
6299 (setq nlines (if arg
6300 (if (< arg 1)
6301 (+ (length org-table-clip) arg)
6302 arg)
6303 (length org-table-clip)))
6304 (setq org-table-clip
6305 (mapcar 'list (org-wrap (mapconcat 'car org-table-clip " ")
6306 nil nlines)))
6307 (goto-char beg)
6308 (org-table-paste-rectangle))
6309 ;; No region, split the current field at point
6310 (if arg
6311 ;; combine with field above
6312 (let ((s (org-table-blank-field))
6313 (col (org-table-current-column)))
6314 (beginning-of-line 0)
6315 (while (org-at-table-hline-p) (beginning-of-line 0))
6316 (org-table-goto-column col)
6317 (skip-chars-forward "^|")
6318 (skip-chars-backward " ")
6319 (insert " " (org-trim s))
6320 (org-table-align))
6321 ;; split field
6322 (when (looking-at "\\([^|]+\\)+|")
6323 (let ((s (match-string 1)))
6324 (replace-match " |")
6325 (goto-char (match-beginning 0))
6326 (org-table-next-row)
6327 (insert (org-trim s) " ")
6328 (org-table-align))))))
6329
6330 (defun org-trim (s)
6331 "Remove whitespace at beginning and end of string."
6332 (if (string-match "^[ \t]+" s) (setq s (replace-match "" t t s)))
6333 (if (string-match "[ \t]+$" s) (setq s (replace-match "" t t s))))
6334
6335 (defun org-wrap (string &optional width lines)
6336 "Wrap string to either a number of lines, or a width in characters.
6337 If WIDTH is non-nil, the string is wrapped to that width, however many lines
6338 that costs. If there is a word longer than WIDTH, the text is actually
6339 wrapped to the length of that word.
6340 IF WIDTH is nil and LINES is non-nil, the string is forced into at most that
6341 many lines, whatever width that takes.
6342 The return value is a list of lines, without newlines at the end."
6343 (let* ((words (org-split-string string "[ \t\n]+"))
6344 (maxword (apply 'max (mapcar 'length words)))
6345 w ll)
6346 (cond (width
6347 (org-do-wrap words (max maxword width)))
6348 (lines
6349 (setq w maxword)
6350 (setq ll (org-do-wrap words maxword))
6351 (if (<= (length ll) lines)
6352 ll
6353 (setq ll words)
6354 (while (> (length ll) lines)
6355 (setq w (1+ w))
6356 (setq ll (org-do-wrap words w)))
6357 ll))
6358 (t (error "Cannot wrap this")))))
6359
6360
6361 (defun org-do-wrap (words width)
6362 "Create lines of maximum width WIDTH (in characters) from word list WORDS."
6363 (let (lines line)
6364 (while words
6365 (setq line (pop words))
6366 (while (and words (< (+ (length line) (length (car words))) width))
6367 (setq line (concat line " " (pop words))))
6368 (setq lines (push line lines)))
6369 (nreverse lines)))
6370
6371 ;; FIXME: I think I can make this more efficient
6372 (defun org-split-string (string &optional separators)
6373 "Splits STRING into substrings at SEPARATORS.
6374 No empty strings are returned if there are matches at the beginning
6375 and end of string."
6376 (let ((rexp (or separators "[ \f\t\n\r\v]+"))
6377 (start 0)
6378 notfirst
6379 (list nil))
6380 (while (and (string-match rexp string
6381 (if (and notfirst
6382 (= start (match-beginning 0))
6383 (< start (length string)))
6384 (1+ start) start))
6385 (< (match-beginning 0) (length string)))
6386 (setq notfirst t)
6387 (or (eq (match-beginning 0) 0)
6388 (and (eq (match-beginning 0) (match-end 0))
6389 (eq (match-beginning 0) start))
6390 (setq list
6391 (cons (substring string start (match-beginning 0))
6392 list)))
6393 (setq start (match-end 0)))
6394 (or (eq start (length string))
6395 (setq list
6396 (cons (substring string start)
6397 list)))
6398 (nreverse list)))
6399
6400 (defun org-table-add-invisible-to-vertical-lines ()
6401 "Add an `invisible' property to vertical lines of current table."
6402 (interactive)
6403 (let* ((beg (org-table-begin))
6404 (end (org-table-end))
6405 (end1))
6406 (save-excursion
6407 (goto-char beg)
6408 (while (< (point) end)
6409 (setq end1 (point-at-eol))
6410 (if (looking-at org-table-dataline-regexp)
6411 (while (re-search-forward "|" end1 t)
6412 (add-text-properties (1- (point)) (point)
6413 '(invisible org-table)))
6414 (while (re-search-forward "[+|]" end1 t)
6415 (add-text-properties (1- (point)) (point)
6416 '(invisible org-table))))
6417 (beginning-of-line 2)))))
6418
6419 (defun org-table-toggle-vline-visibility (&optional arg)
6420 "Toggle the visibility of table vertical lines.
6421 The effect is immediate and on all tables in the file.
6422 With prefix ARG, make lines invisible when ARG is positive, make lines
6423 visible when ARG is not positive"
6424 (interactive "P")
6425 (let ((action (cond
6426 ((and arg (> (prefix-numeric-value arg) 0)) 'on)
6427 ((and arg (< (prefix-numeric-value arg) 1)) 'off)
6428 (t (if (org-in-invisibility-spec-p '(org-table))
6429 'off
6430 'on)))))
6431 (if (eq action 'off)
6432 (progn
6433 (org-remove-from-invisibility-spec '(org-table))
6434 (org-table-map-tables 'org-table-align)
6435 (message "Vertical table lines visible")
6436 (if (org-at-table-p)
6437 (org-table-align)))
6438 (org-add-to-invisibility-spec '(org-table))
6439 (org-table-map-tables 'org-table-align)
6440 (message "Vertical table lines invisible"))
6441 (redraw-frame (selected-frame))))
6442
6443 (defun org-table-map-tables (function)
6444 "Apply FUNCTION to the start of all tables in the buffer."
6445 (save-excursion
6446 (save-restriction
6447 (widen)
6448 (goto-char (point-min))
6449 (while (re-search-forward org-table-any-line-regexp nil t)
6450 (message "Mapping tables: %d%%" (/ (* 100.0 (point)) (buffer-size)))
6451 (beginning-of-line 1)
6452 (if (looking-at org-table-line-regexp)
6453 (save-excursion (funcall function)))
6454 (re-search-forward org-table-any-border-regexp nil 1)))))
6455
6456 (defun org-table-sum ()
6457 "Sum numbers in region of current table column.
6458 The result will be displayed in the echo area, and will be available
6459 as kill to be inserted with \\[yank].
6460
6461 If there is an active region, it is interpreted as a rectangle and all
6462 numbers in that rectangle will be summed. If there is no active
6463 region and point is located in a table column, sum all numbers in that
6464 column.
6465
6466 If at least one number looks like a time HH:MM or HH:MM:SS, all other
6467 numbers are assumed to be times as well (in decimal hours) and the
6468 numbers are added as such."
6469 (interactive)
6470 (save-excursion
6471 (let (beg end col (timecnt 0) diff h m s)
6472 (if (org-region-active-p)
6473 (setq beg (region-beginning) end (region-end))
6474 (setq col (org-table-current-column))
6475 (goto-char (org-table-begin))
6476 (unless (re-search-forward "^[ \t]*|[^-]" nil t)
6477 (error "No table data"))
6478 (org-table-goto-column col)
6479 (skip-chars-backward "^|")
6480 (setq beg (point))
6481 (goto-char (org-table-end))
6482 (unless (re-search-backward "^[ \t]*|[^-]" nil t)
6483 (error "No table data"))
6484 (org-table-goto-column col)
6485 (skip-chars-forward "^|")
6486 (setq end (point)))
6487 (let* ((l1 (progn (goto-char beg)
6488 (+ (if (bolp) 1 0) (count-lines (point-min) (point)))))
6489 (l2 (progn (goto-char end)
6490 (+ (if (bolp) 1 0) (count-lines (point-min) (point)))))
6491 (items (if (= l1 l2)
6492 (split-string (buffer-substring beg end))
6493 (split-string
6494 (mapconcat 'identity (extract-rectangle beg end) " "))))
6495 (numbers (delq nil (mapcar 'org-table-get-number-for-summing
6496 items)))
6497 (res (apply '+ numbers))
6498 (sres (if (= timecnt 0)
6499 (format "%g" res)
6500 (setq diff (* 3600 res)
6501 h (floor (/ diff 3600)) diff (mod diff 3600)
6502 m (floor (/ diff 60)) diff (mod diff 60)
6503 s diff)
6504 (format "%d:%02d:%02d" h m s))))
6505 (kill-new sres)
6506 (message (substitute-command-keys
6507 (format "Sum of %d items: %-20s (\\[yank] will insert result into buffer)"
6508 (length numbers) sres)))))))
6509
6510 (defun org-table-get-number-for-summing (s)
6511 (let (n)
6512 (if (string-match "^ *|? *" s)
6513 (setq s (replace-match "" nil nil s)))
6514 (if (string-match " *|? *$" s)
6515 (setq s (replace-match "" nil nil s)))
6516 (setq n (string-to-number s))
6517 (cond
6518 ((and (string-match "0" s)
6519 (string-match "\\`[-+ \t0.edED]+\\'" s)) 0)
6520 ((string-match "\\`[ \t]+\\'" s) nil)
6521 ((string-match "\\`\\([0-9]+\\):\\([0-9]+\\)\\(:\\([0-9]+\\)\\)?\\'" s)
6522 (let ((h (string-to-number (or (match-string 1 s) "0")))
6523 (m (string-to-number (or (match-string 2 s) "0")))
6524 (s (string-to-number (or (match-string 4 s) "0"))))
6525 (if (boundp 'timecnt) (setq timecnt (1+ timecnt)))
6526 (* 1.0 (+ h (/ m 60.0) (/ s 3600.0)))))
6527 ((equal n 0) nil)
6528 (t n))))
6529
6530 (defvar org-table-current-formula nil)
6531 (defvar org-table-formula-history nil)
6532 (defun org-table-get-formula (current)
6533 (if (and current (not (equal "" org-table-current-formula)))
6534 org-table-current-formula
6535 (setq org-table-current-formula
6536 (read-string
6537 "Formula [last]: " "" 'org-table-formula-history
6538 org-table-current-formula))))
6539
6540 (defun org-this-word ()
6541 ;; Get the current word
6542 (save-excursion
6543 (let ((beg (progn (skip-chars-backward "^ \t\n") (point)))
6544 (end (progn (skip-chars-forward "^ \t\n") (point))))
6545 (buffer-substring-no-properties beg end))))
6546
6547 (defun org-table-eval-formula (&optional ndown)
6548 "Replace the table field value at the cursor by the result of a calculation.
6549
6550 This function makes use of Dave Gillespie's calc package, arguably the most
6551 exciting program ever written for GNU Emacs. So you need to have calc
6552 installed in order to use this function.
6553
6554 In a table, this command replaces the value in the current field with the
6555 result of a formula. While nowhere near the computation options of a
6556 spreadsheet program, this is still very useful. Note that there is no
6557 automatic updating of a calculated field, nor will the field remember the
6558 formula. The command needs to be applied again after changing input
6559 fields.
6560
6561 When called, the command first prompts for a formula, which is read in the
6562 minibuffer. Previously entered formulae are available through the history
6563 list, and the last used formula is the default, reachable by simply
6564 pressing RET.
6565
6566 The formula can be any algebraic expression understood by the calc package.
6567 Before evaluation, variable substitution takes place: \"$\" is replaced by
6568 the field the cursor is currently in, and $1..$n reference the fields in
6569 the current row. Values from a *different* row can *not* be referenced
6570 here, so the command supports only horizontal computing. The formula can
6571 contain an optional printf format specifier after a semicolon, to reformat
6572 the result.
6573
6574 A few examples for formulae:
6575 $1+$2 Sum of first and second field
6576 $1+$2;%.2f Same, and format result to two digits after dec.point
6577 exp($2)+exp($1) Math functions can be used
6578 $;%.1f Reformat current cell to 1 digit after dec.point
6579 ($3-32)*5/9 degrees F -> C conversion
6580
6581 When called with a raw \\[universal-argument] prefix, the formula is applied to the current
6582 field, and to the same same column in all following rows, until reaching a
6583 horizontal line or the end of the table. When the command is called with a
6584 numeric prefix argument (like M-3 or C-7 or \\[universal-argument] 24), the formula is applied
6585 to the current row, and to the following n-1 rows (but not beyond a
6586 separator line)."
6587 (interactive "P")
6588 (setq ndown (if (equal ndown '(4)) 10000 (prefix-numeric-value ndown)))
6589 (require 'calc)
6590 (org-table-check-inside-data-field)
6591 (let* (fields
6592 (org-table-automatic-realign nil)
6593 (down (> ndown 1))
6594 (formula (org-table-get-formula nil))
6595 (n0 (org-table-current-column))
6596 n form fmt x ev)
6597 (if (string-match ";" formula)
6598 (let ((tmp (org-split-string formula ";")))
6599 (setq formula (car tmp) fmt (nth 1 tmp))))
6600 (while (> ndown 0)
6601 (setq fields (org-split-string
6602 (concat " " (buffer-substring
6603 (point-at-bol) (point-at-eol))) "|"))
6604 (setq ndown (1- ndown))
6605 (setq form (copy-sequence formula))
6606 (while (string-match "\\$\\([0-9]+\\)?" form)
6607 (setq n (if (match-beginning 1)
6608 (string-to-int (match-string 1 form))
6609 n0)
6610 x (nth n fields))
6611 (unless x (error "Invalid field specifier \"%s\""
6612 (match-string 0 form)))
6613 (if (equal (string-to-number x) 0) (setq x "0"))
6614 (setq form (replace-match x t t form)))
6615 (setq ev (calc-eval (list form) 'num))
6616 (if (listp ev)
6617 (error "Invalid expression: %s (%s at %d)" form (nth 1 ev) (car ev)))
6618 (org-table-blank-field)
6619 (if fmt
6620 (insert (format fmt (string-to-number ev)))
6621 (insert ev))
6622 (if (and down (> ndown 0) (looking-at ".*\n[ \t]*|[^-]"))
6623 (call-interactively 'org-return)
6624 (setq ndown 0)))
6625 (org-table-align)))
6626
6627 ;;; The orgtbl minor mode
6628
6629 ;; Define a minor mode which can be used in other modes in order to
6630 ;; integrate the org-mode table editor.
6631
6632 ;; This is really a hack, because the org-mode table editor uses several
6633 ;; keys which normally belong to the major mode, for example the TAB and
6634 ;; RET keys. Here is how it works: The minor mode defines all the keys
6635 ;; necessary to operate the table editor, but wraps the commands into a
6636 ;; function which tests if the cursor is currently inside a table. If that
6637 ;; is the case, the table editor command is executed. However, when any of
6638 ;; those keys is used outside a table, the function uses `key-binding' to
6639 ;; look up if the key has an associated command in another currently active
6640 ;; keymap (minor modes, major mode, global), and executes that command.
6641 ;; There might be problems if any of the keys used by the table editor is
6642 ;; otherwise used as a prefix key.
6643
6644 ;; Another challenge is that the key binding for TAB can be tab or \C-i,
6645 ;; likewise the binding for RET can be return or \C-m. Orgtbl-mode
6646 ;; addresses this by checking explicitly for both bindings.
6647
6648 ;; The optimized version (see variable `orgtbl-optimized') takes over
6649 ;; all keys which are bound to `self-insert-command' in the *global map*.
6650 ;; Some modes bind other commands to simple characters, for example
6651 ;; AUCTeX binds the double quote to `Tex-insert-quote'. With orgtbl-mode
6652 ;; active, this binding is ignored inside tables and replaced with a
6653 ;; modified self-insert.
6654
6655 (defcustom orgtbl-optimized (eq org-enable-table-editor 'optimized)
6656 "Non-nil means, use the optimized table editor version for `orgtbl-mode'.
6657 In the optimized version, the table editor takes over all simple keys that
6658 normally just insert a character. In tables, the characters are inserted
6659 in a way to minimize disturbing the table structure (i.e. in overwrite mode
6660 for empty fields). Outside tables, the correct binding of the keys is
6661 restored.
6662
6663 The default for this option is t if the optimized version is also used in
6664 Org-mode. See the variable `org-enable-table-editor' for details. Changing
6665 this variable requires a restart of Emacs to become effective."
6666 :group 'org-table
6667 :type 'boolean)
6668
6669 (defvar orgtbl-mode nil
6670 "Variable controlling `orgtbl-mode', a minor mode enabling the `org-mode'
6671 table editor in arbitrary modes.")
6672 (make-variable-buffer-local 'orgtbl-mode)
6673
6674 (defvar orgtbl-mode-map (make-sparse-keymap)
6675 "Keymap for `orgtbl-mode'.")
6676
6677 ;;;###autoload
6678 (defun turn-on-orgtbl ()
6679 "Unconditionally turn on `orgtbl-mode'."
6680 (orgtbl-mode 1))
6681
6682 ;;;###autoload
6683 (defun orgtbl-mode (&optional arg)
6684 "The `org-mode' table editor as a minor mode for use in other modes."
6685 (interactive)
6686 (setq orgtbl-mode
6687 (if arg (> (prefix-numeric-value arg) 0) (not orgtbl-mode)))
6688 (if orgtbl-mode
6689 (progn
6690 (set (make-local-variable (quote org-table-may-need-update)) t)
6691 (make-local-hook (quote before-change-functions))
6692 (add-hook 'before-change-functions 'org-before-change-function
6693 nil 'local)
6694 (set (make-local-variable 'org-old-auto-fill-inhibit-regexp)
6695 auto-fill-inhibit-regexp)
6696 (set (make-local-variable 'auto-fill-inhibit-regexp)
6697 (if auto-fill-inhibit-regexp
6698 (concat "\\([ \t]*|\\|" auto-fill-inhibit-regexp)
6699 "[ \t]*|"))
6700 (easy-menu-add orgtbl-mode-menu)
6701 (run-hooks 'orgtbl-mode-hook))
6702 (setq auto-fill-inhibit-regexp org-old-auto-fill-inhibit-regexp)
6703 (remove-hook 'before-change-functions 'org-before-change-function t)
6704 (easy-menu-remove orgtbl-mode-menu)
6705 (force-mode-line-update 'all)))
6706
6707 ;; Install it as a minor mode.
6708 (put 'orgtbl-mode :included t)
6709 (put 'orgtbl-mode :menu-tag "Org Table Mode")
6710 (add-minor-mode 'orgtbl-mode " OrgTbl" orgtbl-mode-map)
6711
6712 (defun orgtbl-make-binding (fun &rest keys)
6713 "Create a function for binding in the table minor mode."
6714 (list 'lambda '(arg) '(interactive "p")
6715 (list 'if
6716 '(org-at-table-p)
6717 (list 'call-interactively (list 'quote fun))
6718 (list 'let '(orgtbl-mode)
6719 (list 'call-interactively
6720 (append '(or)
6721 (mapcar (lambda (k)
6722 (list 'key-binding k))
6723 keys)
6724 '('orgtbl-error)))))))
6725
6726 (defun orgtbl-error ()
6727 "Error when there is no default binding for a table key."
6728 (interactive)
6729 (error "This key is has no function outside tables"))
6730
6731 ;; Keybindings for the minor mode
6732 (let ((bindings
6733 '(([(meta shift left)] org-table-delete-column)
6734 ([(meta left)] org-table-move-column-left)
6735 ([(meta right)] org-table-move-column-right)
6736 ([(meta shift right)] org-table-insert-column)
6737 ([(meta shift up)] org-table-kill-row)
6738 ([(meta shift down)] org-table-insert-row)
6739 ([(meta up)] org-table-move-row-up)
6740 ([(meta down)] org-table-move-row-down)
6741 ("\C-c\C-w" org-table-cut-region)
6742 ("\C-c\M-w" org-table-copy-region)
6743 ("\C-c\C-y" org-table-paste-rectangle)
6744 ("\C-c-" org-table-insert-hline)
6745 ([(shift tab)] org-table-previous-field)
6746 ("\C-c\C-c" org-table-align)
6747 ([(return)] org-table-next-row)
6748 ([(shift return)] org-table-copy-down)
6749 ([(meta return)] org-table-wrap-region)
6750 ("\C-c\C-q" org-table-wrap-region)
6751 ("\C-c?" org-table-current-column)
6752 ("\C-c " org-table-blank-field)
6753 ("\C-c+" org-table-sum)
6754 ("\C-c|" org-table-toggle-vline-visibility)
6755 ("\C-c=" org-table-eval-formula)))
6756 elt key fun cmd)
6757 (while (setq elt (pop bindings))
6758 (setq key (car elt)
6759 fun (nth 1 elt)
6760 cmd (orgtbl-make-binding fun key))
6761 (define-key orgtbl-mode-map key cmd)))
6762
6763 ;; Special treatment needed for TAB and RET
6764 ;(define-key orgtbl-mode-map [(return)]
6765 ; (orgtbl-make-binding 'org-table-next-row [(return)] "\C-m"))
6766 ;(define-key orgtbl-mode-map "\C-m"
6767 ; (orgtbl-make-binding 'org-table-next-row "\C-m" [(return)]))
6768 ;(define-key orgtbl-mode-map [(tab)]
6769 ; (orgtbl-make-binding 'org-table-next-field [(tab)] "\C-i"))
6770 ;(define-key orgtbl-mode-map "\C-i"
6771 ; (orgtbl-make-binding 'org-table-next-field "\C-i" [(tab)]))
6772
6773 (define-key orgtbl-mode-map [(return)]
6774 (orgtbl-make-binding 'orgtbl-ret [(return)] "\C-m"))
6775 (define-key orgtbl-mode-map "\C-m"
6776 (orgtbl-make-binding 'orgtbl-ret "\C-m" [(return)]))
6777 (define-key orgtbl-mode-map [(tab)]
6778 (orgtbl-make-binding 'orgtbl-tab [(tab)] "\C-i"))
6779 (define-key orgtbl-mode-map "\C-i"
6780 (orgtbl-make-binding 'orgtbl-tab "\C-i" [(tab)]))
6781
6782 (when orgtbl-optimized
6783 ;; If the user wants maximum table support, we need to hijack
6784 ;; some standard editing functions
6785 (substitute-key-definition 'self-insert-command 'orgtbl-self-insert-command
6786 orgtbl-mode-map global-map)
6787 (substitute-key-definition 'delete-char 'orgtbl-delete-char
6788 orgtbl-mode-map global-map)
6789 (substitute-key-definition 'delete-backward-char 'orgtbl-delete-backward-char
6790 orgtbl-mode-map global-map)
6791 (define-key org-mode-map "|" 'self-insert-command))
6792
6793 (defun orgtbl-tab ()
6794 "Justification and field motion for `orgtbl-mode'."
6795 (interactive)
6796 (org-table-justify-field-maybe)
6797 (org-table-next-field))
6798
6799 (defun orgtbl-ret ()
6800 "Justification and field motion for `orgtbl-mode'."
6801 (interactive)
6802 (org-table-justify-field-maybe)
6803 (org-table-next-row))
6804
6805 (defun orgtbl-self-insert-command (N)
6806 "Like `self-insert-command', use overwrite-mode for whitespace in tables.
6807 If the cursor is in a table looking at whitespace, the whitespace is
6808 overwritten, and the table is not marked as requiring realignment."
6809 (interactive "p")
6810 (if (and (org-at-table-p)
6811 (eq N 1)
6812 (looking-at "[^|\n]* +|"))
6813 (let (org-table-may-need-update)
6814 (goto-char (1- (match-end 0)))
6815 (delete-backward-char 1)
6816 (goto-char (match-beginning 0))
6817 (self-insert-command N))
6818 (setq org-table-may-need-update t)
6819 (let (orgtbl-mode)
6820 (call-interactively (key-binding (vector last-input-event))))))
6821
6822 (defun orgtbl-delete-backward-char (N)
6823 "Like `delete-backward-char', insert whitespace at field end in tables.
6824 When deleting backwards, in tables this function will insert whitespace in
6825 front of the next \"|\" separator, to keep the table aligned. The table will
6826 still be marked for re-alignment, because a narrow field may lead to a
6827 reduced column width."
6828 (interactive "p")
6829 (if (and (org-at-table-p)
6830 (eq N 1)
6831 (looking-at ".*?|"))
6832 (let ((pos (point)))
6833 (backward-delete-char N)
6834 (skip-chars-forward "^|")
6835 (insert " ")
6836 (goto-char (1- pos)))
6837 (message "%s" last-input-event) (sit-for 1)
6838 (delete-backward-char N)))
6839
6840 (defun orgtbl-delete-char (N)
6841 "Like `delete-char', but insert whitespace at field end in tables.
6842 When deleting characters, in tables this function will insert whitespace in
6843 front of the next \"|\" separator, to keep the table aligned. The table
6844 will still be marked for re-alignment, because a narrow field may lead to
6845 a reduced column width."
6846 (interactive "p")
6847 (if (and (org-at-table-p)
6848 (eq N 1))
6849 (if (looking-at ".*?|")
6850 (let ((pos (point)))
6851 (replace-match (concat
6852 (substring (match-string 0) 1 -1)
6853 " |"))
6854 (goto-char pos)))
6855 (delete-char N)))
6856
6857 (easy-menu-define orgtbl-mode-menu orgtbl-mode-map "OrgTbl menu"
6858 '("Tbl"
6859 ["Align" org-ctrl-c-ctrl-c :active (org-at-table-p) :keys "C-c C-c"]
6860 ["Next Field" org-cycle :active (org-at-table-p) :keys "TAB"]
6861 ["Previous Field" org-shifttab :active (org-at-table-p) :keys "S-TAB"]
6862 ["Next Row" org-return :active (org-at-table-p) :keys "RET"]
6863 "--"
6864 ["Blank Field" org-table-blank-field :active (org-at-table-p) :keys "C-c SPC"]
6865 ["Copy Field from Above"
6866 org-table-copy-down :active (org-at-table-p) :keys "S-RET"]
6867 "--"
6868 ("Column"
6869 ["Move Column Left" org-metaleft :active (org-at-table-p) :keys "M-<left>"]
6870 ["Move Column Right" org-metaright :active (org-at-table-p) :keys "M-<right>"]
6871 ["Delete Column" org-shiftmetaleft :active (org-at-table-p) :keys "M-S-<left>"]
6872 ["Insert Column" org-shiftmetaright :active (org-at-table-p) :keys "M-S-<right>"])
6873 ("Row"
6874 ["Move Row Up" org-metaup :active (org-at-table-p) :keys "M-<up>"]
6875 ["Move Row Down" org-metadown :active (org-at-table-p) :keys "M-<down>"]
6876 ["Delete Row" org-shiftmetaup :active (org-at-table-p) :keys "M-S-<up>"]
6877 ["Insert Row" org-shiftmetadown :active (org-at-table-p) :keys "M-S-<down>"]
6878 "--"
6879 ["Insert Hline" org-table-insert-hline :active (org-at-table-p) :keys "C-c -"])
6880 ("Rectangle"
6881 ["Copy Rectangle" org-copy-special :active (org-at-table-p) :keys "C-c M-w"]
6882 ["Cut Rectangle" org-cut-special :active (org-at-table-p) :keys "C-c C-w"]
6883 ["Paste Rectangle" org-paste-special :active (org-at-table-p) :keys "C-c C-y"]
6884 ["Fill Rectangle" org-table-wrap-region :active (org-at-table-p) :keys "C-c C-q"])
6885 "--"
6886 ["Which Column?" org-table-current-column :active (org-at-table-p) :keys "C-c ?"]
6887 ["Sum Column/Rectangle" org-table-sum
6888 :active (or (org-at-table-p) (org-region-active-p)) :keys "C-c +"]
6889 ["Eval Formula" org-table-eval-formula :active (org-at-table-p) :keys "C-c ="]
6890 ))
6891
6892 ;;; Exporting
6893
6894 (defconst org-level-max 20)
6895
6896 (defun org-export-find-first-heading-line (list)
6897 "Remove all lines from LIST which are before the first headline."
6898 (let ((orig-list list)
6899 (re (concat "^" outline-regexp)))
6900 (while (and list
6901 (not (string-match re (car list))))
6902 (pop list))
6903 (or list orig-list)))
6904
6905 (defun org-skip-comments (lines)
6906 "Skip lines starting with \"#\" and subtrees starting with COMMENT."
6907 (let ((re1 (concat "^\\(\\*+\\)[ \t]+" org-comment-string))
6908 (re2 "^\\(\\*+\\)[ \t\n\r]")
6909 rtn line level)
6910 (while (setq line (pop lines))
6911 (cond
6912 ((and (string-match re1 line)
6913 (setq level (- (match-end 1) (match-beginning 1))))
6914 ;; Beginning of a COMMENT subtree. Skip it.
6915 (while (and (setq line (pop lines))
6916 (or (not (string-match re2 line))
6917 (> (- (match-end 1) (match-beginning 1)) level))))
6918 (setq lines (cons line lines)))
6919 ((string-match "^#" line)
6920 ;; an ordinary comment line
6921 )
6922 (t (setq rtn (cons line rtn)))))
6923 (nreverse rtn)))
6924
6925 ;; ASCII
6926
6927 (defconst org-ascii-underline '(?\$ ?\# ?^ ?\~ ?\= ?\-)
6928 "Characters for underlining headings in ASCII export.")
6929
6930 (defconst org-html-entities
6931 '(("nbsp")
6932 ("iexcl")
6933 ("cent")
6934 ("pound")
6935 ("curren")
6936 ("yen")
6937 ("brvbar")
6938 ("sect")
6939 ("uml")
6940 ("copy")
6941 ("ordf")
6942 ("laquo")
6943 ("not")
6944 ("shy")
6945 ("reg")
6946 ("macr")
6947 ("deg")
6948 ("plusmn")
6949 ("sup2")
6950 ("sup3")
6951 ("acute")
6952 ("micro")
6953 ("para")
6954 ("middot")
6955 ("odot"."o")
6956 ("star"."*")
6957 ("cedil")
6958 ("sup1")
6959 ("ordm")
6960 ("raquo")
6961 ("frac14")
6962 ("frac12")
6963 ("frac34")
6964 ("iquest")
6965 ("Agrave")
6966 ("Aacute")
6967 ("Acirc")
6968 ("Atilde")
6969 ("Auml")
6970 ("Aring") ("AA"."&Aring;")
6971 ("AElig")
6972 ("Ccedil")
6973 ("Egrave")
6974 ("Eacute")
6975 ("Ecirc")
6976 ("Euml")
6977 ("Igrave")
6978 ("Iacute")
6979 ("Icirc")
6980 ("Iuml")
6981 ("ETH")
6982 ("Ntilde")
6983 ("Ograve")
6984 ("Oacute")
6985 ("Ocirc")
6986 ("Otilde")
6987 ("Ouml")
6988 ("times")
6989 ("Oslash")
6990 ("Ugrave")
6991 ("Uacute")
6992 ("Ucirc")
6993 ("Uuml")
6994 ("Yacute")
6995 ("THORN")
6996 ("szlig")
6997 ("agrave")
6998 ("aacute")
6999 ("acirc")
7000 ("atilde")
7001 ("auml")
7002 ("aring")
7003 ("aelig")
7004 ("ccedil")
7005 ("egrave")
7006 ("eacute")
7007 ("ecirc")
7008 ("euml")
7009 ("igrave")
7010 ("iacute")
7011 ("icirc")
7012 ("iuml")
7013 ("eth")
7014 ("ntilde")
7015 ("ograve")
7016 ("oacute")
7017 ("ocirc")
7018 ("otilde")
7019 ("ouml")
7020 ("divide")
7021 ("oslash")
7022 ("ugrave")
7023 ("uacute")
7024 ("ucirc")
7025 ("uuml")
7026 ("yacute")
7027 ("thorn")
7028 ("yuml")
7029 ("fnof")
7030 ("Alpha")
7031 ("Beta")
7032 ("Gamma")
7033 ("Delta")
7034 ("Epsilon")
7035 ("Zeta")
7036 ("Eta")
7037 ("Theta")
7038 ("Iota")
7039 ("Kappa")
7040 ("Lambda")
7041 ("Mu")
7042 ("Nu")
7043 ("Xi")
7044 ("Omicron")
7045 ("Pi")
7046 ("Rho")
7047 ("Sigma")
7048 ("Tau")
7049 ("Upsilon")
7050 ("Phi")
7051 ("Chi")
7052 ("Psi")
7053 ("Omega")
7054 ("alpha")
7055 ("beta")
7056 ("gamma")
7057 ("delta")
7058 ("epsilon")
7059 ("varepsilon"."&epsilon;")
7060 ("zeta")
7061 ("eta")
7062 ("theta")
7063 ("iota")
7064 ("kappa")
7065 ("lambda")
7066 ("mu")
7067 ("nu")
7068 ("xi")
7069 ("omicron")
7070 ("pi")
7071 ("rho")
7072 ("sigmaf") ("varsigma"."&sigmaf;")
7073 ("sigma")
7074 ("tau")
7075 ("upsilon")
7076 ("phi")
7077 ("chi")
7078 ("psi")
7079 ("omega")
7080 ("thetasym") ("vartheta"."&thetasym;")
7081 ("upsih")
7082 ("piv")
7083 ("bull") ("bullet"."&bull;")
7084 ("hellip") ("dots"."&hellip;")
7085 ("prime")
7086 ("Prime")
7087 ("oline")
7088 ("frasl")
7089 ("weierp")
7090 ("image")
7091 ("real")
7092 ("trade")
7093 ("alefsym")
7094 ("larr") ("leftarrow"."&larr;") ("gets"."&larr;")
7095 ("uarr") ("uparrow"."&uarr;")
7096 ("rarr") ("to"."&rarr;") ("rightarrow"."&rarr;")
7097 ("darr")("downarrow"."&darr;")
7098 ("harr") ("leftrightarrow"."&harr;")
7099 ("crarr") ("hookleftarrow"."&crarr;") ; has round hook, not quite CR
7100 ("lArr") ("Leftarrow"."&lArr;")
7101 ("uArr") ("Uparrow"."&uArr;")
7102 ("rArr") ("Rightarrow"."&rArr;")
7103 ("dArr") ("Downarrow"."&dArr;")
7104 ("hArr") ("Leftrightarrow"."&hArr;")
7105 ("forall")
7106 ("part") ("partial"."&part;")
7107 ("exist") ("exists"."&exist;")
7108 ("empty") ("emptyset"."&empty;")
7109 ("nabla")
7110 ("isin") ("in"."&isin;")
7111 ("notin")
7112 ("ni")
7113 ("prod")
7114 ("sum")
7115 ("minus")
7116 ("lowast") ("ast"."&lowast;")
7117 ("radic")
7118 ("prop") ("proptp"."&prop;")
7119 ("infin") ("infty"."&infin;")
7120 ("ang") ("angle"."&ang;")
7121 ("and") ("vee"."&and;")
7122 ("or") ("wedge"."&or;")
7123 ("cap")
7124 ("cup")
7125 ("int")
7126 ("there4")
7127 ("sim")
7128 ("cong") ("simeq"."&cong;")
7129 ("asymp")("approx"."&asymp;")
7130 ("ne") ("neq"."&ne;")
7131 ("equiv")
7132 ("le")
7133 ("ge")
7134 ("sub") ("subset"."&sub;")
7135 ("sup") ("supset"."&sup;")
7136 ("nsub")
7137 ("sube")
7138 ("supe")
7139 ("oplus")
7140 ("otimes")
7141 ("perp")
7142 ("sdot") ("cdot"."&sdot;")
7143 ("lceil")
7144 ("rceil")
7145 ("lfloor")
7146 ("rfloor")
7147 ("lang")
7148 ("rang")
7149 ("loz") ("Diamond"."&loz;")
7150 ("spades") ("spadesuit"."&spades;")
7151 ("clubs") ("clubsuit"."&clubs;")
7152 ("hearts") ("diamondsuit"."&hearts;")
7153 ("diams") ("diamondsuit"."&diams;")
7154 ("quot")
7155 ("amp")
7156 ("lt")
7157 ("gt")
7158 ("OElig")
7159 ("oelig")
7160 ("Scaron")
7161 ("scaron")
7162 ("Yuml")
7163 ("circ")
7164 ("tilde")
7165 ("ensp")
7166 ("emsp")
7167 ("thinsp")
7168 ("zwnj")
7169 ("zwj")
7170 ("lrm")
7171 ("rlm")
7172 ("ndash")
7173 ("mdash")
7174 ("lsquo")
7175 ("rsquo")
7176 ("sbquo")
7177 ("ldquo")
7178 ("rdquo")
7179 ("bdquo")
7180 ("dagger")
7181 ("Dagger")
7182 ("permil")
7183 ("lsaquo")
7184 ("rsaquo")
7185 ("euro")
7186
7187 ("arccos"."arccos")
7188 ("arcsin"."arcsin")
7189 ("arctan"."arctan")
7190 ("arg"."arg")
7191 ("cos"."cos")
7192 ("cosh"."cosh")
7193 ("cot"."cot")
7194 ("coth"."coth")
7195 ("csc"."csc")
7196 ("deg"."deg")
7197 ("det"."det")
7198 ("dim"."dim")
7199 ("exp"."exp")
7200 ("gcd"."gcd")
7201 ("hom"."hom")
7202 ("inf"."inf")
7203 ("ker"."ker")
7204 ("lg"."lg")
7205 ("lim"."lim")
7206 ("liminf"."liminf")
7207 ("limsup"."limsup")
7208 ("ln"."ln")
7209 ("log"."log")
7210 ("max"."max")
7211 ("min"."min")
7212 ("Pr"."Pr")
7213 ("sec"."sec")
7214 ("sin"."sin")
7215 ("sinh"."sinh")
7216 ("sup"."sup")
7217 ("tan"."tan")
7218 ("tanh"."tanh")
7219 )
7220 "Entities for TeX->HTML translation.
7221 Entries can be like (\"ent\"), in which case \"\\ent\" will be translated to
7222 \"&ent;\". An entry can also be a dotted pair like (\"ent\".\"&other;\").
7223 In that case, \"\\ent\" will be translated to \"&other;\".
7224 The list contains HTML entities for Latin-1, Greek and other symbols.
7225 It is supplemented by a number of commonly used TeX macros with appropriate
7226 translations.")
7227
7228 (defvar org-last-level nil) ; dynamically scoped variable
7229
7230 (defun org-export-as-ascii (arg)
7231 "Export the outline as a pretty ASCII file.
7232 If there is an active region, export only the region.
7233 The prefix ARG specifies how many levels of the outline should become
7234 underlined headlines. The default is 3."
7235 (interactive "P")
7236 (setq-default org-todo-line-regexp org-todo-line-regexp)
7237 (let* ((region
7238 (buffer-substring
7239 (if (org-region-active-p) (region-beginning) (point-min))
7240 (if (org-region-active-p) (region-end) (point-max))))
7241 (lines (org-export-find-first-heading-line
7242 (org-skip-comments (org-split-string region "[\r\n]"))))
7243 (org-startup-with-deadline-check nil)
7244 (level 0) line txt
7245 (umax nil)
7246 (case-fold-search nil)
7247 (filename (concat (file-name-sans-extension (buffer-file-name))
7248 ".txt"))
7249 (buffer (find-file-noselect filename))
7250 (levels-open (make-vector org-level-max nil))
7251 (date (format-time-string "%Y/%m/%d" (current-time)))
7252 (time (format-time-string "%X" (current-time)))
7253 (author user-full-name)
7254 (title (buffer-name))
7255 (options nil)
7256 (email user-mail-address)
7257 (language org-export-default-language)
7258 (text nil)
7259 (todo nil)
7260 (lang-words nil))
7261
7262 (setq org-last-level 1)
7263 (org-init-section-numbers)
7264
7265 (find-file-noselect filename)
7266
7267 ;; Search for the export key lines
7268 (org-parse-key-lines)
7269
7270 (setq lang-words (or (assoc language org-export-language-setup)
7271 (assoc "en" org-export-language-setup)))
7272 (if org-export-ascii-show-new-buffer
7273 (switch-to-buffer-other-window buffer)
7274 (set-buffer buffer))
7275 (erase-buffer)
7276 (fundamental-mode)
7277 (if options (org-parse-export-options options))
7278 (setq umax (if arg (prefix-numeric-value arg)
7279 org-export-headline-levels))
7280
7281 ;; File header
7282 (if title (org-insert-centered title ?=))
7283 (insert "\n")
7284 (if (or author email)
7285 (insert (concat (nth 1 lang-words) ": " (or author "")
7286 (if email (concat " <" email ">") "")
7287 "\n")))
7288 (if (and date time)
7289 (insert (concat (nth 2 lang-words) ": " date " " time "\n")))
7290 (if text (insert (concat (org-html-expand-for-ascii text) "\n\n")))
7291
7292 (insert "\n\n")
7293
7294 (if org-export-with-toc
7295 (progn
7296 (insert (nth 3 lang-words) "\n"
7297 (make-string (length (nth 3 lang-words)) ?=) "\n")
7298 (mapcar '(lambda (line)
7299 (if (string-match org-todo-line-regexp
7300 line)
7301 ;; This is a headline
7302 (progn
7303 (setq level (- (match-end 1) (match-beginning 1))
7304 txt (match-string 3 line)
7305 todo
7306 (or (and (match-beginning 2)
7307 (not (equal (match-string 2 line)
7308 org-done-string)))
7309 ; TODO, not DONE
7310 (and (= level umax)
7311 (org-search-todo-below
7312 line lines level))))
7313 (setq txt (org-html-expand-for-ascii txt))
7314
7315 (if org-export-with-section-numbers
7316 (setq txt (concat (org-section-number level)
7317 " " txt)))
7318 (if (<= level umax)
7319 (progn
7320 (insert
7321 (make-string (* (1- level) 4) ?\ )
7322 (format (if todo "%s (*)\n" "%s\n") txt))
7323 (setq org-last-level level))
7324 ))))
7325 lines)))
7326
7327 (org-init-section-numbers)
7328 (while (setq line (pop lines))
7329 ;; Remove the quoted HTML tags.
7330 (setq line (org-html-expand-for-ascii line))
7331 (cond
7332 ((string-match "^\\(\\*+\\)[ \t]*\\(.*\\)" line)
7333 ;; a Headline
7334 (setq level (- (match-end 1) (match-beginning 1))
7335 txt (match-string 2 line))
7336 (org-ascii-level-start level txt umax))
7337 (t (insert line "\n"))))
7338 (normal-mode)
7339 (save-buffer)
7340 (goto-char (point-min))))
7341
7342 (defun org-search-todo-below (line lines level)
7343 "Search the subtree below LINE for any TODO entries."
7344 (let ((rest (cdr (memq line lines)))
7345 (re org-todo-line-regexp)
7346 line lv todo)
7347 (catch 'exit
7348 (while (setq line (pop rest))
7349 (if (string-match re line)
7350 (progn
7351 (setq lv (- (match-end 1) (match-beginning 1))
7352 todo (and (match-beginning 2)
7353 (not (equal (match-string 2 line)
7354 org-done-string))))
7355 ; TODO, not DONE
7356 (if (<= lv level) (throw 'exit nil))
7357 (if todo (throw 'exit t))))))))
7358
7359 ;; FIXME: Try to handle <b> and <i> as faces via text properties.
7360 ;; FIXME: Can I implement *bold*,/italic/ and _underline_ for ASCII export?
7361 (defun org-html-expand-for-ascii (line)
7362 "Handle quoted HTML for ASCII export."
7363 (if org-export-html-expand
7364 (while (string-match "@<[^<>\n]*>" line)
7365 ;; We just remove the tags for now.
7366 (setq line (replace-match "" nil nil line))))
7367 line)
7368
7369 (defun org-insert-centered (s &optional underline)
7370 "Insert the string S centered and underline it with character UNDERLINE."
7371 (let ((ind (max (/ (- 80 (length s)) 2) 0)))
7372 (insert (make-string ind ?\ ) s "\n")
7373 (if underline
7374 (insert (make-string ind ?\ )
7375 (make-string (length s) underline)
7376 "\n"))))
7377
7378 (defun org-ascii-level-start (level title umax)
7379 "Insert a new level in ASCII export."
7380 (let (char)
7381 (if (> level umax)
7382 (insert (make-string (* 2 (- level umax 1)) ?\ ) "* " title "\n")
7383 (if (or (not (equal (char-before) ?\n))
7384 (not (equal (char-before (1- (point))) ?\n)))
7385 (insert "\n"))
7386 (setq char (nth (- umax level) (reverse org-ascii-underline)))
7387 (if org-export-with-section-numbers
7388 (setq title (concat (org-section-number level) " " title)))
7389 (insert title "\n" (make-string (string-width title) char) "\n"))))
7390
7391 (defun org-export-copy-visible ()
7392 "Copy the visible part of the buffer to another buffer, for printing.
7393 Also removes the first line of the buffer if it specifies a mode,
7394 and all options lines."
7395 (interactive)
7396 (let* ((filename (concat (file-name-sans-extension (buffer-file-name))
7397 ".txt"))
7398 (buffer (find-file-noselect filename))
7399 (ore (concat
7400 (org-make-options-regexp
7401 '("CATEGORY" "SEQ_TODO" "PRI_TODO" "TYP_TODO" "STARTUP"
7402 "TITLE" "AUTHOR" "EMAIL" "TEXT" "OPTIONS" "LANGUAGE"))
7403 (if org-noutline-p "\\(\n\\|$\\)" "")))
7404 s e)
7405 (with-current-buffer buffer
7406 (erase-buffer)
7407 (text-mode))
7408 (save-excursion
7409 (setq s (goto-char (point-min)))
7410 (while (not (= (point) (point-max)))
7411 (goto-char (org-find-invisible))
7412 (append-to-buffer buffer s (point))
7413 (setq s (goto-char (org-find-visible)))))
7414 (switch-to-buffer-other-window buffer)
7415 (newline)
7416 (goto-char (point-min))
7417 (if (looking-at ".*-\\*- mode:.*\n")
7418 (replace-match ""))
7419 (while (re-search-forward ore nil t)
7420 (replace-match ""))
7421 (goto-char (point-min))))
7422
7423 (defun org-find-visible ()
7424 (if (featurep 'noutline)
7425 (let ((s (point)))
7426 (while (and (not (= (point-max) (setq s (next-overlay-change s))))
7427 (get-char-property s 'invisible)))
7428 s)
7429 (skip-chars-forward "^\n")
7430 (point)))
7431 (defun org-find-invisible ()
7432 (if (featurep 'noutline)
7433 (let ((s (point)))
7434 (while (and (not (= (point-max) (setq s (next-overlay-change s))))
7435 (not (get-char-property s 'invisible))))
7436 s)
7437 (skip-chars-forward "^\r")
7438 (point)))
7439
7440 ;; HTML
7441
7442 (defun org-get-current-options ()
7443 "Return a string with current options as keyword options.
7444 Does include HTML export options as well as TODO and CATEGORY stuff."
7445 (format
7446 "#+TITLE: %s
7447 #+AUTHOR: %s
7448 #+EMAIL: %s
7449 #+LANGUAGE: %s
7450 #+TEXT: Some descriptive text to be emitted. Several lines OK.
7451 #+OPTIONS: H:%d num:%s toc:%s \\n:%s @:%s ::%s |:%s ^:%s *:%s TeX:%s
7452 #+CATEGORY: %s
7453 #+SEQ_TODO: %s
7454 #+TYP_TODO: %s
7455 #+STARTUP: %s %s
7456 "
7457 (buffer-name) (user-full-name) user-mail-address org-export-default-language
7458 org-export-headline-levels
7459 org-export-with-section-numbers
7460 org-export-with-toc
7461 org-export-preserve-breaks
7462 org-export-html-expand
7463 org-export-with-fixed-width
7464 org-export-with-tables
7465 org-export-with-sub-superscripts
7466 org-export-with-emphasize
7467 org-export-with-TeX-macros
7468 (file-name-nondirectory (buffer-file-name))
7469 (if (equal org-todo-interpretation 'sequence)
7470 (mapconcat 'identity org-todo-keywords " ")
7471 "TODO FEEDBACK VERIFY DONE")
7472 (if (equal org-todo-interpretation 'type)
7473 (mapconcat 'identity org-todo-keywords " ")
7474 "Me Jason Marie DONE")
7475 (cdr (assoc org-startup-folded
7476 '((nil . "nofold")(t . "fold")(content . "content"))))
7477 (if org-startup-with-deadline-check "dlcheck" "nodlcheck")
7478 ))
7479
7480 (defun org-insert-export-options-template ()
7481 "Insert into the buffer a template with information for exporting."
7482 (interactive)
7483 (if (not (bolp)) (newline))
7484 (let ((s (org-get-current-options)))
7485 (and (string-match "#\\+CATEGORY" s)
7486 (setq s (substring s 0 (match-beginning 0))))
7487 (insert s)))
7488
7489 (defun org-toggle-fixed-width-section (arg)
7490 "Toggle the fixed-width indicator at the beginning of lines in the region.
7491 If there is no active region, only acts on the current line.
7492 If the first non-white character in the first line of the region is a
7493 vertical bar \"|\", then the command removes the bar from all lines in
7494 the region. If the first character is not a bar, the command adds a
7495 bar to all lines, in the column given by the beginning of the region.
7496
7497 If there is a numerical prefix ARG, create ARG new lines starting with \"|\"."
7498 (interactive "P")
7499 (let* ((cc 0)
7500 (regionp (org-region-active-p))
7501 (beg (if regionp (region-beginning) (point)))
7502 (end (if regionp (region-end)))
7503 (nlines (or arg (if (and beg end) (count-lines beg end) 1)))
7504 (re "[ \t]*\\(:\\)")
7505 off)
7506 (save-excursion
7507 (goto-char beg)
7508 (setq cc (current-column))
7509 (beginning-of-line 1)
7510 (setq off (looking-at re))
7511 (while (> nlines 0)
7512 (setq nlines (1- nlines))
7513 (beginning-of-line 1)
7514 (cond
7515 (arg
7516 (move-to-column cc t)
7517 (insert ":\n")
7518 (forward-line -1))
7519 ((and off (looking-at re))
7520 (replace-match "" t t nil 1))
7521 ((not off) (move-to-column cc t) (insert ":")))
7522 (forward-line 1)))))
7523
7524 (defun org-export-as-html-and-open (arg)
7525 "Export the outline as HTML and immediately open it with a browser.
7526 If there is an active region, export only the region.
7527 The prefix ARG specifies how many levels of the outline should become
7528 headlines. The default is 3. Lower levels will become bulleted lists."
7529 (interactive "P")
7530 (org-export-as-html arg 'hidden)
7531 (org-open-file (buffer-file-name)))
7532
7533 (defun org-export-as-html-batch ()
7534 "Call `org-export-as-html', may be used in batch processing as
7535 emacs --batch
7536 --load=$HOME/lib/emacs/org.el
7537 --eval \"(setq org-export-headline-levels 2)\"
7538 --visit=MyFile --funcall org-export-as-html-batch"
7539 (org-export-as-html org-export-headline-levels 'hidden))
7540
7541 (defun org-export-as-html (arg &optional hidden)
7542 "Export the outline as a pretty HTML file.
7543 If there is an active region, export only the region.
7544 The prefix ARG specifies how many levels of the outline should become
7545 headlines. The default is 3. Lower levels will become bulleted lists."
7546 (interactive "P")
7547 (setq-default org-todo-line-regexp org-todo-line-regexp)
7548 (setq-default org-deadline-line-regexp org-deadline-line-regexp)
7549 (setq-default org-done-string org-done-string)
7550 (let* ((region-p (org-region-active-p))
7551 (region
7552 (buffer-substring
7553 (if region-p (region-beginning) (point-min))
7554 (if region-p (region-end) (point-max))))
7555 (all_lines
7556 (org-skip-comments (org-split-string region "[\r\n]")))
7557 (lines (org-export-find-first-heading-line all_lines))
7558 (level 0) (line "") (origline "") txt todo
7559 (umax nil)
7560 (filename (concat (file-name-sans-extension (buffer-file-name))
7561 ".html"))
7562 (buffer (find-file-noselect filename))
7563 (levels-open (make-vector org-level-max nil))
7564 (date (format-time-string "%Y/%m/%d" (current-time)))
7565 (time (format-time-string "%X" (current-time)))
7566 (author user-full-name)
7567 (title (buffer-name))
7568 (options nil)
7569 (email user-mail-address)
7570 (language org-export-default-language)
7571 (text nil)
7572 (lang-words nil)
7573 (head-count 0) cnt
7574 table-open type
7575 table-buffer table-orig-buffer
7576 )
7577 (message "Exporting...")
7578
7579 (setq org-last-level 1)
7580 (org-init-section-numbers)
7581
7582 ;; Search for the export key lines
7583 (org-parse-key-lines)
7584 (setq lang-words (or (assoc language org-export-language-setup)
7585 (assoc "en" org-export-language-setup)))
7586
7587 ;; Switch to the output buffer
7588 (if (or hidden (not org-export-html-show-new-buffer))
7589 (set-buffer buffer)
7590 (switch-to-buffer-other-window buffer))
7591 (erase-buffer)
7592 (fundamental-mode)
7593 (let ((case-fold-search nil))
7594 (if options (org-parse-export-options options))
7595 (setq umax (if arg (prefix-numeric-value arg)
7596 org-export-headline-levels))
7597
7598 ;; File header
7599 (insert (format
7600 "<html lang=\"%s\"><head>
7601 <title>%s</title>
7602 <meta http-equiv=\"Content-Type\" content=\"text/html\">
7603 <meta name=generator content=\"Org-mode\">
7604 <meta name=generated content=\"%s %s\">
7605 <meta name=author content=\"%s\">
7606 </head><body>
7607 "
7608 language (org-html-expand title) date time author))
7609 (if title (insert (concat "<H1 align=\"center\">"
7610 (org-html-expand title) "</H1>\n")))
7611 (if author (insert (concat (nth 1 lang-words) ": " author "\n")))
7612 (if email (insert (concat "<a href=\"mailto:" email "\">&lt;"
7613 email "&gt;</a>\n")))
7614 (if (or author email) (insert "<br>\n"))
7615 (if (and date time) (insert (concat (nth 2 lang-words) ": "
7616 date " " time "<br>\n")))
7617 (if text (insert (concat "<p>\n" (org-html-expand text))))
7618 (if org-export-with-toc
7619 (progn
7620 (insert (format "<H2>%s</H2>\n" (nth 3 lang-words)))
7621 (insert "<ul>\n")
7622 (mapcar '(lambda (line)
7623 (if (string-match org-todo-line-regexp line)
7624 ;; This is a headline
7625 (progn
7626 (setq level (- (match-end 1) (match-beginning 1))
7627 txt (save-match-data
7628 (org-html-expand
7629 (match-string 3 line)))
7630 todo
7631 (or (and (match-beginning 2)
7632 (not (equal (match-string 2 line)
7633 org-done-string)))
7634 ; TODO, not DONE
7635 (and (= level umax)
7636 (org-search-todo-below
7637 line lines level))))
7638 (if org-export-with-section-numbers
7639 (setq txt (concat (org-section-number level)
7640 " " txt)))
7641 (if (<= level umax)
7642 (progn
7643 (setq head-count (+ head-count 1))
7644 (if (> level org-last-level)
7645 (progn
7646 (setq cnt (- level org-last-level))
7647 (while (>= (setq cnt (1- cnt)) 0)
7648 (insert "<ul>"))
7649 (insert "\n")))
7650 (if (< level org-last-level)
7651 (progn
7652 (setq cnt (- org-last-level level))
7653 (while (>= (setq cnt (1- cnt)) 0)
7654 (insert "</ul>"))
7655 (insert "\n")))
7656 (insert
7657 (format
7658 (if todo
7659 "<li><a href=\"#sec-%d\"><span style='color:red'>%s</span></a></li>\n"
7660 "<li><a href=\"#sec-%d\">%s</a></li>\n")
7661 head-count txt))
7662 (setq org-last-level level))
7663 ))))
7664 lines)
7665 (while (> org-last-level 0)
7666 (setq org-last-level (1- org-last-level))
7667 (insert "</ul>\n"))
7668 ))
7669 (setq head-count 0)
7670 (org-init-section-numbers)
7671
7672 (while (setq line (pop lines) origline line)
7673 ;; replace "<" and ">" by "&lt;" and "&gt;"
7674 ;; handle @<..> HTML tags (replace "@&gt;..&lt;" by "<..>")
7675 (setq line (org-html-expand line))
7676
7677 ;; Verbatim lines
7678 (if (and org-export-with-fixed-width
7679 (string-match "^[ \t]*:\\(.*\\)" line))
7680 (progn
7681 (let ((l (match-string 1 line)))
7682 (while (string-match " " l)
7683 (setq l (replace-match "&nbsp;" t t l)))
7684 (insert "\n<span style='font-family:Courier'>"
7685 l "</span>"
7686 (if (and lines
7687 (not (string-match "^[ \t]+\\(:.*\\)"
7688 (car lines))))
7689 "<br>\n" "\n"))))
7690
7691 (when (string-match org-link-regexp line)
7692 (setq type (match-string 1 line))
7693 (cond
7694 ((member type '("http" "https" "ftp" "mailto" "news"))
7695 ;; standard URL
7696 (setq line (replace-match
7697 "<a href=\"\\1:\\2\">&lt;\\1:\\2&gt;</a>"
7698 nil nil line)))
7699 ((string= type "file")
7700 ;; FILE link
7701
7702 (let* ((filename (match-string 2 line))
7703 (file-is-image-p
7704 (save-match-data
7705 (string-match (org-image-file-name-regexp) filename))))
7706 (setq line (replace-match
7707 (if (and org-export-html-inline-images
7708 file-is-image-p)
7709 "<img src=\"\\2\"/>"
7710 "<a href=\"\\2\">\\1:\\2</a>")
7711 nil nil line))))
7712
7713 ((member type '("bbdb" "vm" "wl" "rmail" "gnus" "shell"))
7714 (setq line (replace-match
7715 "<i>&lt;\\1:\\2&gt;</i>" nil nil line)))))
7716
7717 ;; TODO items
7718 (if (and (string-match org-todo-line-regexp line)
7719 (match-beginning 2))
7720 (if (equal (match-string 2 line) org-done-string)
7721 (setq line (replace-match
7722 "<span style='color:green'>\\2</span>"
7723 nil nil line 2))
7724 (setq line (replace-match "<span style='color:red'>\\2</span>"
7725 nil nil line 2))))
7726
7727 ;; DEADLINES
7728 (if (string-match org-deadline-line-regexp line)
7729 (progn
7730 (if (save-match-data
7731 (string-match "<a href"
7732 (substring line 0 (match-beginning 0))))
7733 nil ; Don't do the replacement - it is inside a link
7734 (setq line (replace-match "<span style='color:red'>\\&</span>"
7735 nil nil line 1)))))
7736
7737 (cond
7738 ((string-match "^\\(\\*+\\)[ \t]*\\(.*\\)" line)
7739 ;; This is a headline
7740 (setq level (- (match-end 1) (match-beginning 1))
7741 txt (match-string 2 line))
7742 (if (<= level umax) (setq head-count (+ head-count 1)))
7743 (org-html-level-start level txt umax
7744 (and org-export-with-toc (<= level umax))
7745 head-count))
7746
7747 ((and org-export-with-tables
7748 (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)" line))
7749 (if (not table-open)
7750 ;; New table starts
7751 (setq table-open t table-buffer nil table-orig-buffer nil))
7752 ;; Accumulate lines
7753 (setq table-buffer (cons line table-buffer)
7754 table-orig-buffer (cons origline table-orig-buffer))
7755 (when (or (not lines)
7756 (not (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)"
7757 (car lines))))
7758 (setq table-open nil
7759 table-buffer (nreverse table-buffer)
7760 table-orig-buffer (nreverse table-orig-buffer))
7761 (insert (org-format-table-html table-buffer table-orig-buffer))))
7762 (t
7763 ;; Normal lines
7764 ;; Lines starting with "-", and empty lines make new paragraph.
7765 (if (string-match "^ *-\\|^[ \t]*$" line) (insert "<p>"))
7766 (insert line (if org-export-preserve-breaks "<br>\n" "\n"))))
7767 ))
7768 (if org-export-html-with-timestamp
7769 (insert org-export-html-html-helper-timestamp))
7770 (insert "</body>\n</html>\n")
7771 (normal-mode)
7772 (save-buffer)
7773 (goto-char (point-min)))))
7774
7775 (defun org-format-table-html (lines olines)
7776 "Find out which HTML converter to use and return the HTML code."
7777 (if (string-match "^[ \t]*|" (car lines))
7778 ;; A normal org table
7779 (org-format-org-table-html lines)
7780 ;; Table made by table.el - test for spanning
7781 (let* ((hlines (delq nil (mapcar
7782 (lambda (x)
7783 (if (string-match "^[ \t]*\\+-" x) x
7784 nil))
7785 lines)))
7786 (first (car hlines))
7787 (ll (and (string-match "\\S-+" first)
7788 (match-string 0 first)))
7789 (re (concat "^[ \t]*" (regexp-quote ll)))
7790 (spanning (delq nil (mapcar (lambda (x) (not (string-match re x)))
7791 hlines))))
7792 (if (and (not spanning)
7793 (not org-export-prefer-native-exporter-for-tables))
7794 ;; We can use my own converter with HTML conversions
7795 (org-format-table-table-html lines)
7796 ;; Need to use the code generator in table.el, with the original text.
7797 (org-format-table-table-html-using-table-generate-source olines)))))
7798
7799 (defun org-format-org-table-html (lines)
7800 "Format a table into html."
7801 (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines)))
7802 (setq lines (nreverse lines))
7803 (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines)))
7804 (setq lines (nreverse lines))
7805 (let ((head (and org-export-highlight-first-table-line
7806 (delq nil (mapcar
7807 (lambda (x) (string-match "^[ \t]*|-" x))
7808 lines))))
7809 lastline line fields html empty)
7810 (setq html (concat org-export-html-table-tag "\n"))
7811 (while (setq lastline line
7812 line (pop lines))
7813 (setq empty "&nbsp")
7814 (catch 'next-line
7815 (if (string-match "^[ \t]*|-" line)
7816 (if lastline
7817 ;; A hline: simulate an empty table row instead.
7818 (setq line (org-fake-empty-table-line lastline)
7819 head nil
7820 empty "")
7821 ;; Ignore this line
7822 (throw 'next-line t)))
7823 ;; Break the line into fields
7824 (setq fields (org-split-string line "[ \t]*|[ \t]*"))
7825 (setq html (concat
7826 html
7827 "<tr>"
7828 (mapconcat (lambda (x)
7829 (if (equal x "") (setq x empty))
7830 (if head
7831 (concat "<th>" x "</th>")
7832 (concat "<td valign=\"top\">" x "</td>")))
7833 fields "")
7834 "</tr>\n"))))
7835 (setq html (concat html "</table>\n"))
7836 html))
7837
7838 (defun org-fake-empty-table-line (line)
7839 "Replace everything except \"|\" with spaces."
7840 (let ((i (length line))
7841 (newstr (copy-sequence line)))
7842 (while (> i 0)
7843 (setq i (1- i))
7844 (if (not (eq (aref newstr i) ?|))
7845 (aset newstr i ?\ )))
7846 newstr))
7847
7848 (defun org-format-table-table-html (lines)
7849 "Format a table generated by table.el into html.
7850 This conversion does *not* use `table-generate-source' from table.el.
7851 This has the advantage that Org-mode's HTML conversions can be used.
7852 But it has the disadvantage, that no cell- or row-spanning is allowed."
7853 (let (line field-buffer
7854 (head org-export-highlight-first-table-line)
7855 fields html empty)
7856 (setq html (concat org-export-html-table-tag "\n"))
7857 (while (setq line (pop lines))
7858 (setq empty "&nbsp")
7859 (catch 'next-line
7860 (if (string-match "^[ \t]*\\+-" line)
7861 (progn
7862 (if field-buffer
7863 (progn
7864 (setq html (concat
7865 html
7866 "<tr>"
7867 (mapconcat
7868 (lambda (x)
7869 (if (equal x "") (setq x empty))
7870 (if head
7871 (concat "<th valign=\"top\">" x
7872 "</th>\n")
7873 (concat "<td valign=\"top\">" x
7874 "</td>\n")))
7875 field-buffer "\n")
7876 "</tr>\n"))
7877 (setq head nil)
7878 (setq field-buffer nil)))
7879 ;; Ignore this line
7880 (throw 'next-line t)))
7881 ;; Break the line into fields and store the fields
7882 (setq fields (org-split-string line "[ \t]*|[ \t]*"))
7883 (if field-buffer
7884 (setq field-buffer (mapcar
7885 (lambda (x)
7886 (concat x "<br>" (pop fields)))
7887 field-buffer))
7888 (setq field-buffer fields))))
7889 (setq html (concat html "</table>\n"))
7890 html))
7891
7892 (defun org-format-table-table-html-using-table-generate-source (lines)
7893 "Format a table into html, using `table-generate-source' from table.el.
7894 This has the advantage that cell- or row-spanning is allowed.
7895 But it has the disadvantage, that Org-mode's HTML conversions cannot be used."
7896 (require 'table)
7897 (with-current-buffer (get-buffer-create " org-tmp1 ")
7898 (erase-buffer)
7899 (insert (mapconcat 'identity lines "\n"))
7900 (goto-char (point-min))
7901 (if (not (re-search-forward "|[^+]" nil t))
7902 (error "Error processing table."))
7903 (table-recognize-table)
7904 (with-current-buffer (get-buffer-create " org-tmp2 ") (erase-buffer))
7905 (table-generate-source 'html " org-tmp2 ")
7906 (set-buffer " org-tmp2 ")
7907 (buffer-substring (point-min) (point-max))))
7908
7909 (defun org-html-expand (string)
7910 "Prepare STRING for HTML export. Applies all active conversions."
7911 ;; First check if there is a link in the line - if yes, apply conversions
7912 ;; only before the start of the link.
7913 (let* ((m (string-match org-link-regexp string))
7914 (s (if m (substring string 0 m) string))
7915 (r (if m (substring string m) "")))
7916 ;; convert < to &lt; and > to &gt;
7917 (while (string-match "<" s)
7918 (setq s (replace-match "&lt;" nil nil s)))
7919 (while (string-match ">" s)
7920 (setq s (replace-match "&gt;" nil nil s)))
7921 (if org-export-html-expand
7922 (while (string-match "@&lt;\\([^&]*\\)&gt;" s)
7923 (setq s (replace-match "<\\1>" nil nil s))))
7924 (if org-export-with-emphasize
7925 (setq s (org-export-html-convert-emphasize s)))
7926 (if org-export-with-sub-superscripts
7927 (setq s (org-export-html-convert-sub-super s)))
7928 (if org-export-with-TeX-macros
7929 (let ((start 0) wd ass)
7930 (while (setq start (string-match "\\\\\\([a-zA-Z]+\\)" s start))
7931 (setq wd (match-string 1 s))
7932 (if (setq ass (assoc wd org-html-entities))
7933 (setq s (replace-match (or (cdr ass)
7934 (concat "&" (car ass) ";"))
7935 t t s))
7936 (setq start (+ start (length wd)))))))
7937 (concat s r)))
7938
7939 (defun org-create-multibrace-regexp (left right n)
7940 "Create a regular expression which will match a balanced sexp.
7941 Opening delimiter is LEFT, and closing delimiter is RIGHT, both given
7942 as single character strings.
7943 The regexp returned will match the entire expression including the
7944 delimiters. It will also define a single group which contains the
7945 match except for the outermost delimiters. The maximum depth of
7946 stacked delimiters is N. Escaping delimiters is not possible."
7947 (let* ((nothing (concat "[^" "\\" left "\\" right "]*?"))
7948 (or "\\|")
7949 (re nothing)
7950 (next (concat "\\(?:" nothing left nothing right "\\)+" nothing)))
7951 (while (> n 1)
7952 (setq n (1- n)
7953 re (concat re or next)
7954 next (concat "\\(?:" nothing left next right "\\)+" nothing)))
7955 (concat left "\\(" re "\\)" right)))
7956
7957 (defvar org-match-substring-regexp
7958 (concat
7959 "\\([^\\]\\)\\([_^]\\)\\("
7960 "\\(" (org-create-multibrace-regexp "{" "}" org-match-sexp-depth) "\\)"
7961 "\\|"
7962 "\\(" (org-create-multibrace-regexp "(" ")" org-match-sexp-depth) "\\)"
7963 "\\|"
7964 "\\(\\(?:\\*\\|[-+]?[^-+*!@#$%^_ \t\r\n,:\"?<>~;./{}=()]+\\)\\)\\)")
7965 "The regular expression matching a sub- or superscript.")
7966
7967 (defun org-export-html-convert-sub-super (string)
7968 "Convert sub- and superscripts in STRING to HTML."
7969 (let (key c)
7970 (while (string-match org-match-substring-regexp string)
7971 (setq key (if (string= (match-string 2 string) "_") "sub" "sup"))
7972 (setq c (or (match-string 8 string)
7973 (match-string 6 string)
7974 (match-string 5 string)))
7975 (setq string (replace-match
7976 (concat (match-string 1 string)
7977 "<" key ">" c "</" key ">")
7978 t t string)))
7979 (while (string-match "\\\\\\([_^]\\)" string)
7980 (setq string (replace-match (match-string 1 string) t t string))))
7981 string)
7982
7983 (defun org-export-html-convert-emphasize (string)
7984 (while (string-match
7985 "\\(\\s-\\|^\\)\\(\\*\\([a-zA-Z]+\\)\\*\\)\\([^a-zA-Z*]\\|$\\)"
7986 string)
7987 (setq string (replace-match
7988 (concat "<b>" (match-string 3 string) "</b>")
7989 t t string 2)))
7990 (while (string-match
7991 "\\(\\s-\\|^\\)\\(/\\([a-zA-Z]+\\)/\\)\\([^a-zA-Z*]\\|$\\)"
7992 string)
7993 (setq string (replace-match
7994 (concat "<i>" (match-string 3 string) "</i>")
7995 t t string 2)))
7996 (while (string-match
7997 "\\(\\s-\\|^\\)\\(_\\([a-zA-Z]+\\)_\\)\\([^a-zA-Z*]\\|$\\)"
7998 string)
7999 (setq string (replace-match
8000 (concat "<u>" (match-string 3 string) "</u>")
8001 t t string 2)))
8002 string)
8003
8004 (defun org-parse-key-lines ()
8005 "Find the special key lines with the information for exporters."
8006 (save-excursion
8007 (goto-char 0)
8008 (let ((re (org-make-options-regexp
8009 '("TITLE" "AUTHOR" "EMAIL" "TEXT" "OPTIONS" "LANGUAGE")))
8010 key)
8011 (while (re-search-forward re nil t)
8012 (setq key (match-string 1))
8013 (cond ((string-equal key "TITLE")
8014 (setq title (match-string 2)))
8015 ((string-equal key "AUTHOR")
8016 (setq author (match-string 2)))
8017 ((string-equal key "EMAIL")
8018 (setq email (match-string 2)))
8019 ((string-equal key "LANGUAGE")
8020 (setq language (match-string 2)))
8021 ((string-equal key "TEXT")
8022 (setq text (concat text "\n" (match-string 2))))
8023 ((string-equal key "OPTIONS")
8024 (setq options (match-string 2))))))))
8025
8026 (defun org-parse-export-options (s)
8027 "Parse the export options line."
8028 (let ((op '(("H" . org-export-headline-levels)
8029 ("num" . org-export-with-section-numbers)
8030 ("toc" . org-export-with-toc)
8031 ("\\n" . org-export-preserve-breaks)
8032 ("@" . org-export-html-expand)
8033 (":" . org-export-with-fixed-width)
8034 ("|" . org-export-with-tables)
8035 ("^" . org-export-with-sub-superscripts)
8036 ("*" . org-export-with-emphasize)
8037 ("TeX" . org-export-with-TeX-macros)))
8038 o)
8039 (while (setq o (pop op))
8040 (if (string-match (concat (regexp-quote (car o)) ":\\([^ \t\n\r;,.]*\\)")
8041 s)
8042 (set (make-local-variable (cdr o))
8043 (car (read-from-string (match-string 1 s))))))))
8044
8045 (defun org-html-level-start (level title umax with-toc head-count)
8046 "Insert a new level in HTML export."
8047 (let ((l (1+ (max level umax))))
8048 (while (<= l org-level-max)
8049 (if (aref levels-open (1- l))
8050 (progn
8051 (org-html-level-close l)
8052 (aset levels-open (1- l) nil)))
8053 (setq l (1+ l)))
8054 (if (> level umax)
8055 (progn
8056 (if (aref levels-open (1- level))
8057 (insert "<li>" title "<p>\n")
8058 (aset levels-open (1- level) t)
8059 (insert "<ul><li>" title "<p>\n")))
8060 (if org-export-with-section-numbers
8061 (setq title (concat (org-section-number level) " " title)))
8062 (setq level (+ level 1))
8063 (if with-toc
8064 (insert (format "\n<H%d><a name=\"sec-%d\">%s</a></H%d>\n"
8065 level head-count title level))
8066 (insert (format "\n<H%d>%s</H%d>\n" level title level))))))
8067
8068 (defun org-html-level-close (&rest args)
8069 "Terminate one level in HTML export."
8070 (insert "</ul>"))
8071
8072
8073 ;; Variable holding the vector with section numbers
8074 (defvar org-section-numbers (make-vector org-level-max 0))
8075
8076 (defun org-init-section-numbers ()
8077 "Initialize the vector for the section numbers."
8078 (let* ((level -1)
8079 (numbers (nreverse (org-split-string "" "\\.")))
8080 (depth (1- (length org-section-numbers)))
8081 (i depth) number-string)
8082 (while (>= i 0)
8083 (if (> i level)
8084 (aset org-section-numbers i 0)
8085 (setq number-string (or (car numbers) "0"))
8086 (if (string-match "\\`[A-Z]\\'" number-string)
8087 (aset org-section-numbers i
8088 (- (string-to-char number-string) ?A -1))
8089 (aset org-section-numbers i (string-to-int number-string)))
8090 (pop numbers))
8091 (setq i (1- i)))))
8092
8093 (defun org-section-number (&optional level)
8094 "Return a string with the current section number.
8095 When LEVEL is non-nil, increase section numbers on that level."
8096 (let* ((depth (1- (length org-section-numbers))) idx n (string ""))
8097 (when level
8098 (when (> level -1)
8099 (aset org-section-numbers
8100 level (1+ (aref org-section-numbers level))))
8101 (setq idx (1+ level))
8102 (while (<= idx depth)
8103 (if (not (= idx 1))
8104 (aset org-section-numbers idx 0))
8105 (setq idx (1+ idx))))
8106 (setq idx 0)
8107 (while (<= idx depth)
8108 (setq n (aref org-section-numbers idx))
8109 (setq string (concat string (if (not (string= string "")) "." "")
8110 (int-to-string n)))
8111 (setq idx (1+ idx)))
8112 (save-match-data
8113 (if (string-match "\\`\\([@0]\\.\\)+" string)
8114 (setq string (replace-match "" nil nil string)))
8115 (if (string-match "\\(\\.0\\)+\\'" string)
8116 (setq string (replace-match "" nil nil string))))
8117 string))
8118
8119
8120 ;;; Key bindings
8121
8122 ;; - Bindings in Org-mode map are currently
8123 ;; 0123456789abcdefghijklmnopqrstuvwxyz!?@#$%^&-+*/=()_{}[]:;"|,.<>~`'\t the alphabet
8124 ;; abcd fgh j lmnopqrstuvwxyz ? # -+ /= [] ; |,.<> \t necessary bindings
8125 ;; e (?) useful from outline-mode
8126 ;; i k @ expendable from outline-mode
8127 ;; 0123456789 ! $%^& * ()_{} " ~`' free
8128
8129 (define-key org-mode-map [(tab)] 'org-cycle)
8130 (define-key org-mode-map "\C-i" 'org-cycle)
8131 (define-key org-mode-map [(meta tab)] 'org-complete)
8132 (define-key org-mode-map "\M-\C-i" 'org-complete)
8133 (define-key org-mode-map [(meta shift left)] 'org-shiftmetaleft)
8134 (define-key org-mode-map [(meta left)] 'org-metaleft)
8135 (define-key org-mode-map [(meta shift right)] 'org-shiftmetaright)
8136 (define-key org-mode-map [(meta shift up)] 'org-shiftmetaup)
8137 (define-key org-mode-map [(meta shift down)] 'org-shiftmetadown)
8138 (define-key org-mode-map [(meta right)] 'org-metaright)
8139 (define-key org-mode-map [(meta up)] 'org-metaup)
8140 (define-key org-mode-map [(meta down)] 'org-metadown)
8141 ;(define-key org-mode-map "\C-c\C-h\C-w" 'org-cut-subtree)
8142 ;(define-key org-mode-map "\C-c\C-h\M-w" 'org-copy-subtree)
8143 ;(define-key org-mode-map "\C-c\C-h\C-y" 'org-paste-subtree)
8144 (define-key org-mode-map "\C-c\C-h\C-w" 'org-cut-special)
8145 (define-key org-mode-map "\C-c\C-h\M-w" 'org-copy-special)
8146 (define-key org-mode-map "\C-c\C-h\C-y" 'org-paste-special)
8147 (define-key org-mode-map "\C-c\C-j" 'org-goto)
8148 (define-key org-mode-map "\C-c\C-t" 'org-todo)
8149 (define-key org-mode-map "\C-c\C-s" 'org-schedule)
8150 (define-key org-mode-map "\C-c\C-d" 'org-deadline)
8151 (define-key org-mode-map "\C-c;" 'org-toggle-comment)
8152 (define-key org-mode-map "\C-c\C-v" 'org-show-todo-tree)
8153 (define-key org-mode-map "\C-c\C-w" 'org-check-deadlines)
8154 (define-key org-mode-map "\C-c/" 'org-occur) ; Minor-mode reserved
8155 (define-key org-mode-map "\C-c\C-m" 'org-insert-heading)
8156 (define-key org-mode-map "\M-\C-m" 'org-insert-heading)
8157 (define-key org-mode-map [(meta shift return)] 'org-insert-todo-heading)
8158 (define-key org-mode-map "\C-c\C-l" 'org-insert-link)
8159 (define-key org-mode-map "\C-c\C-o" 'org-open-at-point)
8160 (define-key org-mode-map "\C-c\C-z" 'org-time-stamp) ; Alternative binding
8161 (define-key org-mode-map "\C-c." 'org-time-stamp) ; Minor-mode reserved
8162 (define-key org-mode-map "\C-c," 'org-priority) ; Minor-mode reserved
8163 (define-key org-mode-map "\C-c\C-y" 'org-evaluate-time-range)
8164 (define-key org-mode-map "\C-c>" 'org-goto-calendar)
8165 (define-key org-mode-map "\C-c<" 'org-date-from-calendar)
8166 (define-key org-mode-map "\C-c[" 'org-add-file)
8167 (define-key org-mode-map "\C-c]" 'org-remove-file)
8168 (define-key org-mode-map "\C-c\C-r" 'org-timeline)
8169 (define-key org-mode-map [(shift up)] 'org-shiftup)
8170 (define-key org-mode-map [(shift down)] 'org-shiftdown)
8171 (define-key org-mode-map [(shift left)] 'org-timestamp-down-day)
8172 (define-key org-mode-map [(shift right)] 'org-timestamp-up-day)
8173 (define-key org-mode-map "\C-c-" 'org-table-insert-hline)
8174 ;; The following line is e.g. necessary for German keyboards under Suse Linux
8175 (unless org-xemacs-p
8176 (define-key org-mode-map [S-iso-lefttab] 'org-shifttab))
8177 (define-key org-mode-map [(shift tab)] 'org-shifttab)
8178 (define-key org-mode-map "\C-c\C-c" 'org-ctrl-c-ctrl-c)
8179 (define-key org-mode-map [(return)] 'org-return)
8180 (define-key org-mode-map [(shift return)] 'org-table-copy-down)
8181 (define-key org-mode-map [(meta return)] 'org-meta-return)
8182 (define-key org-mode-map [(control up)] 'org-move-line-up)
8183 (define-key org-mode-map [(control down)] 'org-move-line-down)
8184 (define-key org-mode-map "\C-c?" 'org-table-current-column)
8185 (define-key org-mode-map "\C-c " 'org-table-blank-field)
8186 (define-key org-mode-map "\C-c+" 'org-table-sum)
8187 (define-key org-mode-map "\C-c|" 'org-table-toggle-vline-visibility)
8188 (define-key org-mode-map "\C-c=" 'org-table-eval-formula)
8189 (define-key org-mode-map "\C-c#" 'org-table-create-with-table.el)
8190 (define-key org-mode-map "\C-c\C-q" 'org-table-wrap-region)
8191 (define-key org-mode-map "\C-c\C-xa" 'org-export-as-ascii)
8192 (define-key org-mode-map "\C-c\C-x\C-a" 'org-export-as-ascii)
8193 (define-key org-mode-map "\C-c\C-xv" 'org-export-copy-visible)
8194 (define-key org-mode-map "\C-c\C-x\C-v" 'org-export-copy-visible)
8195 ;(define-key org-mode-map "\C-c\C-xo" 'org-export-as-opml)
8196 ;(define-key org-mode-map "\C-c\C-x\C-o" 'org-export-as-opml)
8197 (define-key org-mode-map "\C-c\C-xt" 'org-insert-export-options-template)
8198 (define-key org-mode-map "\C-c:" 'org-toggle-fixed-width-section)
8199 (define-key org-mode-map "\C-c\C-xh" 'org-export-as-html)
8200 (define-key org-mode-map "\C-c\C-x\C-h" 'org-export-as-html-and-open)
8201
8202
8203 ;; FIXME: Do we really need to save match data in these commands?
8204 ;; I would like to remove it in order to minimize impact.
8205 ;; Self-insert already does not preserve it. How much resources used by this???
8206
8207 (defsubst org-table-p ()
8208 (if (and (eq major-mode 'org-mode) font-lock-mode)
8209 (eq (get-text-property (point) 'face) 'org-table-face)
8210 (save-match-data (org-at-table-p))))
8211
8212 (defun org-self-insert-command (N)
8213 "Like `self-insert-command', use overwrite-mode for whitespace in tables.
8214 If the cursor is in a table looking at whitespace, the whitespace is
8215 overwritten, and the table is not marked as requiring realignment."
8216 (interactive "p")
8217 (if (and (org-table-p)
8218 (eq N 1)
8219 (looking-at "[^|\n]* +|"))
8220 (let (org-table-may-need-update)
8221 (goto-char (1- (match-end 0)))
8222 (delete-backward-char 1)
8223 (goto-char (match-beginning 0))
8224 (self-insert-command N))
8225 (setq org-table-may-need-update t)
8226 (self-insert-command N)))
8227
8228 ;; FIXME:
8229 ;; The following two functions might still be optimized to trigger
8230 ;; re-alignment less frequently.
8231
8232 (defun org-delete-backward-char (N)
8233 "Like `delete-backward-char', insert whitespace at field end in tables.
8234 When deleting backwards, in tables this function will insert whitespace in
8235 front of the next \"|\" separator, to keep the table aligned. The table will
8236 still be marked for re-alignment, because a narrow field may lead to a
8237 reduced column width."
8238 (interactive "p")
8239 (if (and (org-table-p)
8240 (eq N 1)
8241 (looking-at ".*?|"))
8242 (let ((pos (point)))
8243 (backward-delete-char N)
8244 (skip-chars-forward "^|")
8245 (insert " ")
8246 (goto-char (1- pos)))
8247 (backward-delete-char N)))
8248
8249 (defun org-delete-char (N)
8250 "Like `delete-char', but insert whitespace at field end in tables.
8251 When deleting characters, in tables this function will insert whitespace in
8252 front of the next \"|\" separator, to keep the table aligned. The table
8253 will still be marked for re-alignment, because a narrow field may lead to
8254 a reduced column width."
8255 (interactive "p")
8256 (if (and (org-table-p)
8257 (eq N 1))
8258 (if (looking-at ".*?|")
8259 (let ((pos (point)))
8260 (replace-match (concat
8261 (substring (match-string 0) 1 -1)
8262 " |"))
8263 (goto-char pos)))
8264 (delete-char N)))
8265
8266 ;; How to do this: Measure non-white length of current string
8267 ;; If equal to column width, we should realign.
8268
8269 (when (eq org-enable-table-editor 'optimized)
8270 ;; If the user wants maximum table support, we need to hijack
8271 ;; some standard editing functions
8272 (substitute-key-definition 'self-insert-command 'org-self-insert-command
8273 org-mode-map global-map)
8274 (substitute-key-definition 'delete-char 'org-delete-char
8275 org-mode-map global-map)
8276 (substitute-key-definition 'delete-backward-char 'org-delete-backward-char
8277 org-mode-map global-map)
8278 (define-key org-mode-map "|" 'self-insert-command))
8279
8280 (defun org-shiftcursor-error ()
8281 "Throw an error because Shift-Cursor command was applied in wrong context."
8282 (error "This command is only active in tables and on headlines."))
8283
8284 (defun org-shifttab ()
8285 "Call `(org-cycle t)' or `org-table-previous-field'."
8286 (interactive)
8287 (cond
8288 ((org-at-table-p) (org-table-previous-field))
8289 (t (org-cycle '(4)))))
8290
8291 (defun org-shiftmetaleft ()
8292 "Call `org-promote-subtree' or `org-table-delete-column'."
8293 (interactive)
8294 (cond
8295 ((org-at-table-p) (org-table-delete-column))
8296 ((org-on-heading-p) (org-promote-subtree))
8297 (t (org-shiftcursor-error))))
8298
8299 (defun org-shiftmetaright ()
8300 "Call `org-demote-subtree' or `org-table-insert-column'."
8301 (interactive)
8302 (cond
8303 ((org-at-table-p) (org-table-insert-column))
8304 ((org-on-heading-p) (org-demote-subtree))
8305 (t (org-shiftcursor-error))))
8306
8307 (defun org-shiftmetaup (&optional arg)
8308 "Call `org-move-subtree-up' or `org-table-kill-row'."
8309 (interactive "P")
8310 (cond
8311 ((org-at-table-p) (org-table-kill-row))
8312 ((org-on-heading-p) (org-move-subtree-up arg))
8313 (t (org-shiftcursor-error))))
8314 (defun org-shiftmetadown (&optional arg)
8315 "Call `org-move-subtree-down' or `org-table-insert-row'."
8316 (interactive "P")
8317 (cond
8318 ((org-at-table-p) (org-table-insert-row arg))
8319 ((org-on-heading-p) (org-move-subtree-down arg))
8320 (t (org-shiftcursor-error))))
8321
8322 (defun org-metaleft (&optional arg)
8323 "Call `org-do-promote' or `org-table-move-column' to left."
8324 (interactive "P")
8325 (cond
8326 ((org-at-table-p) (org-table-move-column 'left))
8327 ((or (org-on-heading-p) (org-region-active-p)) (org-do-promote))
8328 (t (backward-word (prefix-numeric-value arg)))))
8329
8330 (defun org-metaright (&optional arg)
8331 "Call `org-do-demote' or `org-table-move-column' to right."
8332 (interactive "P")
8333 (cond
8334 ((org-at-table-p) (org-table-move-column nil))
8335 ((or (org-on-heading-p) (org-region-active-p)) (org-do-demote))
8336 (t (forward-word (prefix-numeric-value arg)))))
8337
8338 (defun org-metaup (&optional arg)
8339 "Call `org-move-subtree-up' or `org-table-move-row' up."
8340 (interactive "P")
8341 (cond
8342 ((org-at-table-p) (org-table-move-row 'up))
8343 ((org-on-heading-p) (org-move-subtree-up arg))
8344 (t (org-shiftcursor-error))))
8345
8346 (defun org-metadown (&optional arg)
8347 "Call `org-move-subtree-down' or `org-table-move-row' down."
8348 (interactive "P")
8349 (cond
8350 ((org-at-table-p) (org-table-move-row nil))
8351 ((org-on-heading-p) (org-move-subtree-down arg))
8352 (t (org-shiftcursor-error))))
8353
8354 (defun org-shiftup (&optional arg)
8355 "Call `org-timestamp-up' or `org-priority-up'."
8356 (interactive "P")
8357 (cond
8358 ((org-at-timestamp-p) (org-timestamp-up arg))
8359 (t (org-priority-up))))
8360
8361 (defun org-shiftdown (&optional arg)
8362 "Call `org-timestamp-down' or `org-priority-down'."
8363 (interactive "P")
8364 (cond
8365 ((org-at-timestamp-p) (org-timestamp-down arg))
8366 (t (org-priority-down))))
8367
8368 (defun org-copy-special ()
8369 "Call either `org-table-copy' or `org-copy-subtree'."
8370 (interactive)
8371 (if (org-at-table-p)
8372 (org-table-copy-region)
8373 (org-copy-subtree)))
8374
8375 (defun org-cut-special ()
8376 "Call either `org-table-copy' or `org-cut-subtree'."
8377 (interactive)
8378 (if (org-at-table-p)
8379 (org-table-cut-region)
8380 (org-cut-subtree)))
8381
8382 (defun org-paste-special (arg)
8383 "Call either `org-table-paste-rectangle' or `org-paste-subtree'."
8384 (interactive "P")
8385 (if (org-at-table-p)
8386 (org-table-paste-rectangle)
8387 (org-paste-subtree arg)))
8388
8389 (defun org-ctrl-c-ctrl-c (&optional arg)
8390 "Call realign table, or recognize a table.el table.
8391 When the cursor is inside a table created by the table.el package,
8392 activate that table. Otherwise, if the cursor is at a normal table
8393 created with org.el, re-align that table. This command works even if
8394 the automatic table editor has been turned off."
8395 (interactive "P")
8396 (let ((org-enable-table-editor t))
8397 (cond
8398 ((org-at-table.el-p)
8399 (require 'table)
8400 (beginning-of-line 1)
8401 (re-search-forward "|" (save-excursion (end-of-line 2) (point))) ;FIXME: line-end-position?
8402 (table-recognize-table))
8403 ((org-at-table-p)
8404 (org-table-align))
8405 ((save-excursion (beginning-of-line 1) (looking-at "#\\+[A-Z]+"))
8406 (let ((org-inhibit-startup t)) (org-mode)))
8407 ((org-region-active-p)
8408 (org-table-convert-region (region-beginning) (region-end) arg))
8409 ((and (region-beginning) (region-end))
8410 (if (y-or-n-p "Convert inactive region to table? ")
8411 (org-table-convert-region (region-beginning) (region-end) arg)
8412 (error "Abort")))
8413 (t (error "No table at point, and no region to make one.")))))
8414
8415 (defun org-return ()
8416 "Call `org-table-next-row' or `newline'."
8417 (interactive)
8418 (cond
8419 ((org-at-table-p)
8420 (org-table-justify-field-maybe)
8421 (org-table-next-row))
8422 (t (newline))))
8423
8424 (defun org-meta-return (&optional arg)
8425 "Call `org-insert-heading' or `org-table-wrap-region'."
8426 (interactive "P")
8427 (cond
8428 ((org-at-table-p)
8429 (org-table-wrap-region arg))
8430 (t (org-insert-heading))))
8431
8432 ;;; Menu entries
8433
8434 ;; First, remove the outline menus. Org-mode does not neede these commands.
8435 (if org-xemacs-p
8436 (add-hook 'org-mode-hook
8437 (lambda ()
8438 (delete-menu-item '("Headings"))
8439 (delete-menu-item '("Show"))
8440 (delete-menu-item '("Hide"))
8441 (set-menubar-dirty-flag)))
8442 (setq org-mode-map (delq (assoc 'menu-bar (cdr org-mode-map))
8443 org-mode-map)))
8444
8445 ;; Define the Org-mode menus
8446 (easy-menu-define org-org-menu org-mode-map "Org menu"
8447 '("Org"
8448 ["Cycle Visibility" org-cycle (or (bobp) (outline-on-heading-p))]
8449 ["Sparse Tree" org-occur t]
8450 ["Show All" show-all t]
8451 "--"
8452 ["New Heading" org-insert-heading t]
8453 ("Navigate Headings"
8454 ["Up" outline-up-heading t]
8455 ["Next" outline-next-visible-heading t]
8456 ["Previous" outline-previous-visible-heading t]
8457 ["Next Same Level" outline-forward-same-level t]
8458 ["Previous Same Level" outline-backward-same-level t]
8459 "--"
8460 ["Jump" org-goto t])
8461 ("Edit Structure"
8462 ["Move Subtree Up" org-shiftmetaup (not (org-at-table-p))]
8463 ["Move Subtree Down" org-shiftmetadown (not (org-at-table-p))]
8464 "--"
8465 ["Copy Subtree" org-copy-special (not (org-at-table-p))]
8466 ["Cut Subtree" org-cut-special (not (org-at-table-p))]
8467 ["Paste Subtree" org-paste-special (not (org-at-table-p))]
8468 "--"
8469 ["Promote Heading" org-metaleft (not (org-at-table-p))]
8470 ["Promote Subtree" org-shiftmetaleft (not (org-at-table-p))]
8471 ["Demote Heading" org-metaright (not (org-at-table-p))]
8472 ["Demote Subtree" org-shiftmetaright (not (org-at-table-p))])
8473 "--"
8474 ("TODO Lists"
8475 ["TODO/DONE/-" org-todo t]
8476 ["Show TODO Tree" org-show-todo-tree t]
8477 "--"
8478 ["Set Priority" org-priority t]
8479 ["Priority Up" org-shiftup t]
8480 ["Priority Down" org-shiftdown t])
8481 ("Dates and Scheduling"
8482 ["Timestamp" org-time-stamp t]
8483 ("Change Date"
8484 ["1 Day Later" org-timestamp-up-day t]
8485 ["1 Day Earlier" org-timestamp-down-day t]
8486 ["1 ... Later" org-shiftup t]
8487 ["1 ... Earlier" org-shiftdown t])
8488 ["Compute Time Range" org-evaluate-time-range t]
8489 ["Schedule Item" org-schedule t]
8490 ["Deadline" org-deadline t]
8491 "--"
8492 ["Goto Calendar" org-goto-calendar t]
8493 ["Date from Calendar" org-date-from-calendar t])
8494 "--"
8495 ("Timeline/Agenda"
8496 ["Show TODO Tree this File" org-show-todo-tree t]
8497 ["Check Deadlines this File" org-check-deadlines t]
8498 ["Timeline Current File" org-timeline t]
8499 "--"
8500 ["Agenda" org-agenda t])
8501 ("File List for Agenda")
8502 "--"
8503 ("Hyperlinks"
8504 ["Store Link (Global)" org-store-link t]
8505 ["Insert Link" org-insert-link t]
8506 ["Follow Link" org-open-at-point t])
8507 "--"
8508 ("Table"
8509 ["Align" org-ctrl-c-ctrl-c (org-at-table-p)]
8510 ["Next Field" org-cycle (org-at-table-p)]
8511 ["Previous Field" org-shifttab (org-at-table-p)]
8512 ["Next Row" org-return (org-at-table-p)]
8513 "--"
8514 ["Blank Field" org-table-blank-field (org-at-table-p)]
8515 ["Copy Field from Above" org-table-copy-down (org-at-table-p)]
8516 "--"
8517 ("Column"
8518 ["Move Column Left" org-metaleft (org-at-table-p)]
8519 ["Move Column Right" org-metaright (org-at-table-p)]
8520 ["Delete Column" org-shiftmetaleft (org-at-table-p)]
8521 ["Insert Column" org-shiftmetaright (org-at-table-p)])
8522 ("Row"
8523 ["Move Row Up" org-metaup (org-at-table-p)]
8524 ["Move Row Down" org-metadown (org-at-table-p)]
8525 ["Delete Row" org-shiftmetaup (org-at-table-p)]
8526 ["Insert Row" org-shiftmetadown (org-at-table-p)]
8527 "--"
8528 ["Insert Hline" org-table-insert-hline (org-at-table-p)])
8529 ("Rectangle"
8530 ["Copy Rectangle" org-copy-special (org-at-table-p)]
8531 ["Cut Rectangle" org-cut-special (org-at-table-p)]
8532 ["Paste Rectangle" org-paste-special (org-at-table-p)]
8533 ["Fill Rectangle" org-table-wrap-region (org-at-table-p)])
8534 "--"
8535 ["Which Column?" org-table-current-column (org-at-table-p)]
8536 ["Sum Column/Rectangle" org-table-sum
8537 (or (org-at-table-p) (org-region-active-p))]
8538 ["Eval Formula" org-table-eval-formula (org-at-table-p)]
8539 "--"
8540 ["Invisible Vlines" org-table-toggle-vline-visibility
8541 :style toggle :selected (org-in-invisibility-spec-p '(org-table))]
8542 "--"
8543 ["Create" org-table-create (and (not (org-at-table-p))
8544 org-enable-table-editor)]
8545 ["Convert Region" org-ctrl-c-ctrl-c (not (org-at-table-p 'any))]
8546 ["Import from File" org-table-import (not (org-at-table-p))]
8547 ["Export to File" org-table-export (org-at-table-p)]
8548 "--"
8549 ["Create/Convert from/to table.el" org-table-create-with-table.el t])
8550 "--"
8551 ("Export"
8552 ["ASCII" org-export-as-ascii t]
8553 ["Extract Visible Text" org-export-copy-visible t]
8554 ["HTML" org-export-as-html t]
8555 ["HTML and Open" org-export-as-html-and-open t]
8556 ; ["OPML" org-export-as-opml nil]
8557 "--"
8558 ["Option Template" org-insert-export-options-template t]
8559 ["Toggle Fixed Width" org-toggle-fixed-width-section t])
8560 "--"
8561 ("Documentation"
8562 ["Show Version" org-version t]
8563 ["Info Documentation" org-info t])
8564 ("Customize"
8565 ["Browse Org Group" org-customize t]
8566 "--"
8567 ["Build Full Customize Menu" org-create-customize-menu
8568 (fboundp 'customize-menu-create)])
8569 ))
8570
8571 (defun org-info (&optional node)
8572 "Read documentation for Org-mode in the info system.
8573 With optional NODE, go directly to that node."
8574 (interactive)
8575 (require 'info)
8576 (Info-goto-node (format "(org)%s" (or node ""))))
8577
8578 (defun org-install-agenda-files-menu ()
8579 (easy-menu-change
8580 '("Org") "File List for Agenda"
8581 (append
8582 (list
8583 ["Edit File List" (customize-variable 'org-agenda-files) t]
8584 ["Add Current File to List" org-add-file t]
8585 ["Remove Current File from List" org-remove-file t]
8586 "--")
8587 (mapcar 'org-file-menu-entry org-agenda-files))))
8588
8589 ;;; Documentation
8590
8591 (defun org-customize ()
8592 "Call the customize function with org as argument."
8593 (interactive)
8594 (customize-browse 'org))
8595
8596 (defun org-create-customize-menu ()
8597 "Create a full customization menu for Org-mode, insert it into the menu."
8598 (interactive)
8599 (if (fboundp 'customize-menu-create)
8600 (progn
8601 (easy-menu-change
8602 '("Org") "Customize"
8603 `(["Browse Org group" org-customize t]
8604 "--"
8605 ,(customize-menu-create 'org)
8606 ["Set" Custom-set t]
8607 ["Save" Custom-save t]
8608 ["Reset to Current" Custom-reset-current t]
8609 ["Reset to Saved" Custom-reset-saved t]
8610 ["Reset to Standard Settings" Custom-reset-standard t]))
8611 (message "\"Org\"-menu now contains full customization menu"))
8612 (error "Cannot expand menu (outdated version of cus-edit.el)")))
8613
8614 ;;; Miscellaneous stuff
8615
8616 (defun org-move-line-down (arg)
8617 "Move the current line down. With prefix argument, move it past ARG lines."
8618 (interactive "p")
8619 (let ((col (current-column))
8620 beg end pos)
8621 (beginning-of-line 1) (setq beg (point))
8622 (beginning-of-line 2) (setq end (point))
8623 (beginning-of-line (+ 1 arg))
8624 (setq pos (move-marker (make-marker) (point)))
8625 (insert (delete-and-extract-region beg end))
8626 (goto-char pos)
8627 (move-to-column col)))
8628
8629 (defun org-move-line-up (arg)
8630 "Move the current line up. With prefix argument, move it past ARG lines."
8631 (interactive "p")
8632 (let ((col (current-column))
8633 beg end pos)
8634 (beginning-of-line 1) (setq beg (point))
8635 (beginning-of-line 2) (setq end (point))
8636 (beginning-of-line (- arg))
8637 (setq pos (move-marker (make-marker) (point)))
8638 (insert (delete-and-extract-region beg end))
8639 (goto-char pos)
8640 (move-to-column col)))
8641
8642 ;; Functions needed for Emacs/XEmacs region compatibility
8643
8644 (defun org-region-active-p ()
8645 "Is `transient-mark-mode' on and the region active?
8646 Works on both Emacs and XEmacs."
8647 (if org-ignore-region
8648 nil
8649 (if org-xemacs-p
8650 (and zmacs-regions (region-active-p))
8651 (and transient-mark-mode mark-active))))
8652
8653 (defun org-add-to-invisibility-spec (arg)
8654 "Add elements to `buffer-invisibility-spec'.
8655 See documentation for `buffer-invisibility-spec' for the kind of elements
8656 that can be added."
8657 (cond
8658 ((fboundp 'add-to-invisibility-spec)
8659 (add-to-invisibility-spec arg))
8660 ((or (null buffer-invisibility-spec) (eq buffer-invisibility-spec t))
8661 (setq buffer-invisibility-spec (list arg)))
8662 (t
8663 (setq buffer-invisibility-spec
8664 (cons arg buffer-invisibility-spec)))))
8665
8666 (defun org-remove-from-invisibility-spec (arg)
8667 "Remove elements from `buffer-invisibility-spec'."
8668 (if (fboundp 'remove-from-invisibility-spec)
8669 (remove-from-invisibility-spec arg)
8670 (if (consp buffer-invisibility-spec)
8671 (setq buffer-invisibility-spec
8672 (delete arg buffer-invisibility-spec)))))
8673
8674 (defun org-in-invisibility-spec-p (arg)
8675 "Is ARG a member of `buffer-invisibility-spec'?."
8676 (if (consp buffer-invisibility-spec)
8677 (member arg buffer-invisibility-spec)
8678 nil))
8679
8680 (defun org-image-file-name-regexp ()
8681 "Return regexp matching the file names of images."
8682 (if (fboundp 'image-file-name-regexp)
8683 (image-file-name-regexp)
8684 (let ((image-file-name-extensions
8685 '("png" "jpeg" "jpg" "gif" "tiff" "tif"
8686 "xbm" "xpm" "pbm" "pgm" "ppm")))
8687 (concat "\\."
8688 (regexp-opt (nconc (mapcar 'upcase
8689 image-file-name-extensions)
8690 image-file-name-extensions)
8691 t)
8692 "\\'"))))
8693
8694 ;; Functions needed for compatibility with old outline.el
8695
8696 ;; The following functions capture almost the entire compatibility code
8697 ;; between the different versions of outline-mode. The only other place
8698 ;; where this is important are the font-lock-keywords. Search for
8699 ;; `org-noutline-p' to find it.
8700
8701 ;; C-a should go to the beginning of a *visible* line, also in the
8702 ;; new outline.el. I guess this should be patched into Emacs?
8703 (defun org-beginning-of-line ()
8704 "Go to the beginning of the current line. If that is invisible, continue
8705 to a visible line beginning. This makes the function of C-a more intuitive."
8706 (interactive)
8707 (beginning-of-line 1)
8708 (if (bobp)
8709 nil
8710 (backward-char 1)
8711 (if (org-invisible-p)
8712 (while (and (not (bobp)) (org-invisible-p))
8713 (backward-char 1)
8714 (beginning-of-line 1))
8715 (forward-char 1))))
8716 (when org-noutline-p
8717 (define-key org-mode-map "\C-a" 'org-beginning-of-line))
8718
8719 (defun org-invisible-p ()
8720 "Check if point is at a character currently not visible."
8721 (if org-noutline-p
8722 ;; Early versions of noutline don't have `outline-invisible-p'.
8723 (if (fboundp 'outline-invisible-p)
8724 (outline-invisible-p)
8725 (get-char-property (point) 'invisible))
8726 (save-excursion
8727 (skip-chars-backward "^\r\n")
8728 (equal (char-before) ?\r))))
8729
8730 (defun org-back-to-heading (&optional invisible-ok)
8731 "Move to previous heading line, or beg of this line if it's a heading.
8732 Only visible heading lines are considered, unless INVISIBLE-OK is non-nil."
8733 (if org-noutline-p
8734 (outline-back-to-heading invisible-ok)
8735 (if (looking-at outline-regexp)
8736 t
8737 (if (re-search-backward (concat (if invisible-ok "[\r\n]" "^")
8738 outline-regexp)
8739 nil t)
8740 (if invisible-ok
8741 (progn (forward-char 1)
8742 (looking-at outline-regexp)))
8743 (error "Before first heading")))))
8744
8745 (defun org-on-heading-p (&optional invisible-ok)
8746 "Return t if point is on a (visible) heading line.
8747 If INVISIBLE-OK is non-nil, an invisible heading line is ok too."
8748 (if org-noutline-p
8749 (outline-on-heading-p 'invisible-ok)
8750 (save-excursion
8751 (skip-chars-backward "^\n\r")
8752 (and (looking-at outline-regexp)
8753 (or invisible-ok
8754 (bobp)
8755 (equal (char-before) ?\n))))))
8756
8757 (defun org-up-heading-all (arg)
8758 "Move to the heading line of which the present line is a subheading.
8759 This function considers both visible and invisible heading lines.
8760 With argument, move up ARG levels."
8761 (if org-noutline-p
8762 (if (fboundp 'outline-up-heading-all)
8763 (outline-up-heading-all arg) ; emacs 21 version of outline.el
8764 (outline-up-heading arg t)) ; emacs 22 version of outline.el
8765 (org-back-to-heading t)
8766 (looking-at outline-regexp)
8767 (if (<= (- (match-end 0) (match-beginning 0)) arg)
8768 (error "Cannot move up %d levels" arg)
8769 (re-search-backward
8770 (concat "[\n\r]" (regexp-quote
8771 (make-string (- (match-end 0) (match-beginning 0) arg)
8772 ?*))
8773 "[^*]"))
8774 (forward-char 1))))
8775
8776 (defun org-show-hidden-entry ()
8777 "Show an entry where even the heading is hidden."
8778 (save-excursion
8779 (if (not org-noutline-p)
8780 (progn
8781 (org-back-to-heading t)
8782 (org-flag-heading nil)))
8783 (org-show-entry)))
8784
8785 (defun org-check-occur-regexp (regexp)
8786 "If REGEXP starts with \"^\", modify it to check for \\r as well.
8787 Of course, only for the old outline mode."
8788 (if org-noutline-p
8789 regexp
8790 (if (string-match "^\\^" regexp)
8791 (concat "[\n\r]" (substring regexp 1))
8792 regexp)))
8793
8794 (defun org-flag-heading (flag &optional entry)
8795 "Flag the current heading. FLAG non-nil means make invisible.
8796 When ENTRY is non-nil, show the entire entry."
8797 (save-excursion
8798 (org-back-to-heading t)
8799 (if (not org-noutline-p)
8800 ;; Make the current headline visible
8801 (outline-flag-region (max 1 (1- (point))) (point) (if flag ?\r ?\n)))
8802 ;; Check if we should show the entire entry
8803 (if entry
8804 (progn
8805 (org-show-entry)
8806 (save-excursion ;; FIXME: Is this the fix for points in the -|
8807 ;; middle of text? |
8808 (and (outline-next-heading) ;; |
8809 (org-flag-heading nil)))) ; show the next heading _|
8810 (outline-flag-region (max 1 (1- (point)))
8811 (save-excursion (outline-end-of-heading) (point))
8812 (if org-noutline-p
8813 flag
8814 (if flag ?\r ?\n))))))
8815
8816 (defun org-show-subtree ()
8817 "Show everything after this heading at deeper levels."
8818 (outline-flag-region
8819 (point)
8820 (save-excursion
8821 (outline-end-of-subtree) (outline-next-heading) (point))
8822 (if org-noutline-p nil ?\n)))
8823
8824 (defun org-show-entry ()
8825 "Show the body directly following this heading.
8826 Show the heading too, if it is currently invisible."
8827 (interactive)
8828 (save-excursion
8829 (org-back-to-heading t)
8830 (outline-flag-region
8831 (1- (point))
8832 (save-excursion
8833 (re-search-forward (concat "[\r\n]\\(" outline-regexp "\\)") nil 'move)
8834 (or (match-beginning 1) (point-max)))
8835 (if org-noutline-p nil ?\n))))
8836
8837
8838 (defun org-make-options-regexp (kwds)
8839 "Make a regular expression for keyword lines."
8840 (concat
8841 (if org-noutline-p "^" "[\n\r]")
8842 "#?[ \t]*\\+\\("
8843 (mapconcat 'regexp-quote kwds "\\|")
8844 "\\):[ \t]*"
8845 (if org-noutline-p "\\(.+\\)" "\\([^\n\r]+\\)")))
8846
8847 ;; Advise the bookmark-jump function to make jump position visible
8848 ;; Wrapped into eval-after-load to avoid loading advice unnecessarily
8849 (eval-after-load "bookmark"
8850 '(defadvice bookmark-jump (after org-make-visible activate)
8851 "Make the position visible."
8852 (and (eq major-mode 'org-mode)
8853 (org-invisible-p)
8854 (org-show-hierarchy-above))))
8855
8856 ;;; Finish up
8857
8858 (provide 'org)
8859
8860 (run-hooks 'org-load-hook)
8861
8862 ;; arch-tag: e77da1a7-acc7-4336-b19e-efa25af3f9fd
8863
8864 ;;; org.el ends here
8865