* progmodes/cc-cmds.el (c-forward-into-nomenclature)
[bpt/emacs.git] / lisp / org / org-agenda.el
CommitLineData
b349f79f 1;;; org-agenda.el --- Dynamic task and appointment lists for Org
20908596 2
ae940284 3;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
ca8ef0dc 4;; Free Software Foundation, Inc.
20908596
CD
5
6;; Author: Carsten Dominik <carsten at orgmode dot org>
7;; Keywords: outlines, hypermedia, calendar, wp
8;; Homepage: http://orgmode.org
1bcdebed 9;; Version: 6.33c
20908596
CD
10;;
11;; This file is part of GNU Emacs.
12;;
b1fc2b50 13;; GNU Emacs is free software: you can redistribute it and/or modify
20908596 14;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
20908596
CD
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
b1fc2b50 24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
20908596
CD
25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
26;;
27;;; Commentary:
28
29;; This file contains the code for creating and using the Agenda for Org-mode.
30
31;;; Code:
32
33(require 'org)
34(eval-when-compile
71d35b24 35 (require 'cl)
20908596
CD
36 (require 'calendar))
37
b349f79f 38(declare-function diary-add-to-list "diary-lib"
20908596
CD
39 (date string specifier &optional marker globcolor literal))
40(declare-function calendar-absolute-from-iso "cal-iso" (date))
41(declare-function calendar-astro-date-string "cal-julian" (&optional date))
42(declare-function calendar-bahai-date-string "cal-bahai" (&optional date))
20908596
CD
43(declare-function calendar-chinese-date-string "cal-china" (&optional date))
44(declare-function calendar-coptic-date-string "cal-coptic" (&optional date))
45(declare-function calendar-ethiopic-date-string "cal-coptic" (&optional date))
46(declare-function calendar-french-date-string "cal-french" (&optional date))
47(declare-function calendar-goto-date "cal-move" (date))
48(declare-function calendar-hebrew-date-string "cal-hebrew" (&optional date))
49(declare-function calendar-islamic-date-string "cal-islam" (&optional date))
50(declare-function calendar-iso-date-string "cal-iso" (&optional date))
f6aafbed 51(declare-function calendar-iso-from-absolute "cal-iso" (date))
20908596
CD
52(declare-function calendar-julian-date-string "cal-julian" (&optional date))
53(declare-function calendar-mayan-date-string "cal-mayan" (&optional date))
54(declare-function calendar-persian-date-string "cal-persia" (&optional date))
68a1b090
GM
55(declare-function org-datetree-find-date-create "org-datetree"
56 (date &optional keep-restriction))
20908596 57(declare-function org-columns-quit "org-colview" ())
8bfe682a
CD
58(declare-function diary-date-display-form "diary-lib" (&optional type))
59(declare-function org-mobile-write-agenda-for-mobile "org-mobile" (file))
60(declare-function org-habit-insert-consistency-graphs
61 "org-habit" (&optional line))
62(declare-function org-is-habit-p "org-habit" (&optional pom))
63(declare-function org-habit-parse-todo "org-habit" (&optional pom))
68a1b090 64(declare-function org-habit-get-priority "org-habit" (habit &optional moment))
20908596 65(defvar calendar-mode-map)
8d642074 66(defvar org-mobile-force-id-on-agenda-items) ; defined in org-mobile.el
8bfe682a
CD
67(defvar org-habit-show-habits)
68(defvar org-habit-show-habits-only-for-today)
20908596
CD
69
70;; Defined somewhere in this file, but used before definition.
71(defvar org-agenda-buffer-name)
72(defvar org-agenda-overriding-header)
8d642074 73(defvar org-agenda-title-append nil)
20908596
CD
74(defvar entry)
75(defvar date)
76(defvar org-agenda-undo-list)
77(defvar org-agenda-pending-undo-list)
78(defvar original-date) ; dynamically scoped, calendar.el does scope this
79
80(defcustom org-agenda-confirm-kill 1
81 "When set, remote killing from the agenda buffer needs confirmation.
82When t, a confirmation is always needed. When a number N, confirmation is
83only needed when the text to be killed contains more than N non-white lines."
84 :group 'org-agenda
85 :type '(choice
86 (const :tag "Never" nil)
87 (const :tag "Always" t)
c8d0cf5c 88 (integer :tag "When more than N lines")))
20908596
CD
89
90(defcustom org-agenda-compact-blocks nil
91 "Non-nil means, make the block agenda more compact.
92This is done by leaving out unnecessary lines."
93 :group 'org-agenda
94 :type 'boolean)
95
0bd48b37
CD
96(defcustom org-agenda-block-separator ?=
97 "The separator between blocks in the agenda.
98If this is a string, it will be used as the separator, with a newline added.
99If it is a character, it will be repeated to fill the window width."
100 :group 'org-agenda
101 :type '(choice
102 (character)
103 (string)))
104
20908596
CD
105(defgroup org-agenda-export nil
106 "Options concerning exporting agenda views in Org-mode."
107 :tag "Org Agenda Export"
108 :group 'org-agenda)
109
110(defcustom org-agenda-with-colors t
111 "Non-nil means, use colors in agenda views."
112 :group 'org-agenda-export
113 :type 'boolean)
114
115(defcustom org-agenda-exporter-settings nil
116 "Alist of variable/value pairs that should be active during agenda export.
c8d0cf5c
CD
117This is a good place to set options for ps-print and for htmlize.
118Note that the way this is implemented, the values will be evaluated
119before assigned to the variables. So make sure to quote values you do
120*not* want evaluated, for example
121
122 (setq org-agenda-exporter-settings
123 '((ps-print-color-p 'black-white)))"
20908596
CD
124 :group 'org-agenda-export
125 :type '(repeat
126 (list
127 (variable)
128 (sexp :tag "Value"))))
129
c8d0cf5c
CD
130(defcustom org-agenda-before-write-hook '(org-agenda-add-entry-text)
131 "Hook run in temporary buffer before writing it to an export file.
132A useful function is `org-agenda-add-entry-text'."
133 :group 'org-agenda-export
134 :type 'hook
135 :options '(org-agenda-add-entry-text))
136
137(defcustom org-agenda-add-entry-text-maxlines 0
138 "Maximum number of entry text lines to be added to agenda.
139This is only relevant when `org-agenda-add-entry-text' is part of
140`org-agenda-before-write-hook', which it is by default.
141When this is 0, nothing will happen. When it is greater than 0, it
142specifies the maximum number of lines that will be added for each entry
54a0dee5
CD
143that is listed in the agenda view.
144
145Note that this variable is not used during display, only when exporting
146the agenda. For agenda display, see org-agenda-entry-text-mode and the
147variable `org-agenda-entry-text-maxlines'."
c8d0cf5c
CD
148 :group 'org-agenda
149 :type 'integer)
150
151(defcustom org-agenda-add-entry-text-descriptive-links t
152 "Non-nil means, export org-links as descriptive links in agenda added text.
153This variable applies to the text added to the agenda when
154`org-agenda-add-entry-text-maxlines' is larger than 0.
155When this variable nil, the URL will (also) be shown."
156 :group 'org-agenda
157 :type 'boolean)
158
20908596
CD
159(defcustom org-agenda-export-html-style ""
160 "The style specification for exported HTML Agenda files.
161If this variable contains a string, it will replace the default <style>
162section as produced by `htmlize'.
163Since there are different ways of setting style information, this variable
164needs to contain the full HTML structure to provide a style, including the
165surrounding HTML tags. The style specifications should include definitions
166the fonts used by the agenda, here is an example:
167
168 <style type=\"text/css\">
169 p { font-weight: normal; color: gray; }
170 .org-agenda-structure {
171 font-size: 110%;
172 color: #003399;
173 font-weight: 600;
174 }
175 .org-todo {
176 color: #cc6666;
177 font-weight: bold;
178 }
c8d0cf5c
CD
179 .org-agenda-done {
180 color: #339933;
181 }
20908596
CD
182 .org-done {
183 color: #339933;
184 }
185 .title { text-align: center; }
186 .todo, .deadline { color: red; }
187 .done { color: green; }
188 </style>
189
190or, if you want to keep the style in a file,
191
192 <link rel=\"stylesheet\" type=\"text/css\" href=\"mystyles.css\">
193
194As the value of this option simply gets inserted into the HTML <head> header,
195you can \"misuse\" it to also add other text to the header. However,
196<style>...</style> is required, if not present the variable will be ignored."
197 :group 'org-agenda-export
198 :group 'org-export-html
199 :type 'string)
200
201(defgroup org-agenda-custom-commands nil
202 "Options concerning agenda views in Org-mode."
203 :tag "Org Agenda Custom Commands"
204 :group 'org-agenda)
205
206(defconst org-sorting-choice
207 '(choice
208 (const time-up) (const time-down)
209 (const category-keep) (const category-up) (const category-down)
210 (const tag-down) (const tag-up)
211 (const priority-up) (const priority-down)
621f83e4 212 (const todo-state-up) (const todo-state-down)
c8d0cf5c 213 (const effort-up) (const effort-down)
8bfe682a 214 (const habit-up) (const habit-down)
c8d0cf5c 215 (const user-defined-up) (const user-defined-down))
20908596
CD
216 "Sorting choices.")
217
218(defconst org-agenda-custom-commands-local-options
219 `(repeat :tag "Local settings for this command. Remember to quote values"
220 (choice :tag "Setting"
c8d0cf5c
CD
221 (list :tag "Heading for this block"
222 (const org-agenda-overriding-header)
223 (string :tag "Headline"))
20908596
CD
224 (list :tag "Files to be searched"
225 (const org-agenda-files)
226 (list
227 (const :format "" quote)
c8d0cf5c 228 (repeat (file))))
20908596
CD
229 (list :tag "Sorting strategy"
230 (const org-agenda-sorting-strategy)
231 (list
232 (const :format "" quote)
233 (repeat
234 ,org-sorting-choice)))
235 (list :tag "Prefix format"
236 (const org-agenda-prefix-format :value " %-12:c%?-12t% s")
237 (string))
238 (list :tag "Number of days in agenda"
239 (const org-agenda-ndays)
240 (integer :value 1))
241 (list :tag "Fixed starting date"
242 (const org-agenda-start-day)
243 (string :value "2007-11-01"))
244 (list :tag "Start on day of week"
245 (const org-agenda-start-on-weekday)
246 (choice :value 1
247 (const :tag "Today" nil)
c8d0cf5c 248 (integer :tag "Weekday No.")))
20908596
CD
249 (list :tag "Include data from diary"
250 (const org-agenda-include-diary)
251 (boolean))
252 (list :tag "Deadline Warning days"
253 (const org-deadline-warning-days)
254 (integer :value 1))
c8d0cf5c
CD
255 (list :tag "Tags filter preset"
256 (const org-agenda-filter-preset)
257 (list
258 (const :format "" quote)
259 (repeat
260 (string :tag "+tag or -tag"))))
20908596
CD
261 (list :tag "Standard skipping condition"
262 :value (org-agenda-skip-function '(org-agenda-skip-entry-if))
263 (const org-agenda-skip-function)
264 (list
265 (const :format "" quote)
266 (list
267 (choice
33306645 268 :tag "Skipping range"
20908596
CD
269 (const :tag "Skip entry" org-agenda-skip-entry-if)
270 (const :tag "Skip subtree" org-agenda-skip-subtree-if))
271 (repeat :inline t :tag "Conditions for skipping"
272 (choice
273 :tag "Condition type"
274 (list :tag "Regexp matches" :inline t (const :format "" 'regexp) (regexp))
275 (list :tag "Regexp does not match" :inline t (const :format "" 'notregexp) (regexp))
276 (const :tag "scheduled" 'scheduled)
277 (const :tag "not scheduled" 'notscheduled)
278 (const :tag "deadline" 'deadline)
c8d0cf5c
CD
279 (const :tag "no deadline" 'notdeadline)
280 (const :tag "timestamp" 'timestamp)
281 (const :tag "no timestamp" 'nottimestamp))))))
20908596
CD
282 (list :tag "Non-standard skipping condition"
283 :value (org-agenda-skip-function)
2c3ad40d 284 (const org-agenda-skip-function)
c8d0cf5c
CD
285 (sexp :tag "Function or form (quoted!)"))
286 (list :tag "Any variable"
287 (variable :tag "Variable")
288 (sexp :tag "Value (sexp)"))))
20908596
CD
289 "Selection of examples for agenda command settings.
290This will be spliced into the custom type of
291`org-agenda-custom-commands'.")
292
293
294(defcustom org-agenda-custom-commands nil
295 "Custom commands for the agenda.
296These commands will be offered on the splash screen displayed by the
297agenda dispatcher \\[org-agenda]. Each entry is a list like this:
298
299 (key desc type match settings files)
300
301key The key (one or more characters as a string) to be associated
302 with the command.
303desc A description of the command, when omitted or nil, a default
304 description is built using MATCH.
305type The command type, any of the following symbols:
306 agenda The daily/weekly agenda.
307 todo Entries with a specific TODO keyword, in all agenda files.
308 search Entries containing search words entry or headline.
309 tags Tags/Property/TODO match in all agenda files.
310 tags-todo Tags/P/T match in all agenda files, TODO entries only.
311 todo-tree Sparse tree of specific TODO keyword in *current* file.
312 tags-tree Sparse tree with all tags matches in *current* file.
313 occur-tree Occur sparse tree for *current* file.
314 ... A user-defined function.
315match What to search for:
316 - a single keyword for TODO keyword searches
317 - a tags match expression for tags searches
318 - a word search expression for text searches.
319 - a regular expression for occur searches
320 For all other commands, this should be the empty string.
321settings A list of option settings, similar to that in a let form, so like
322 this: ((opt1 val1) (opt2 val2) ...). The values will be
323 evaluated at the moment of execution, so quote them when needed.
324files A list of files file to write the produced agenda buffer to
325 with the command `org-store-agenda-views'.
326 If a file name ends in \".html\", an HTML version of the buffer
327 is written out. If it ends in \".ps\", a postscript version is
33306645 328 produced. Otherwise, only the plain text is written to the file.
20908596
CD
329
330You can also define a set of commands, to create a composite agenda buffer.
331In this case, an entry looks like this:
332
333 (key desc (cmd1 cmd2 ...) general-settings-for-whole-set files)
334
335where
336
337desc A description string to be displayed in the dispatcher menu.
338cmd An agenda command, similar to the above. However, tree commands
339 are no allowed, but instead you can get agenda and global todo list.
340 So valid commands for a set are:
341 (agenda \"\" settings)
342 (alltodo \"\" settings)
343 (stuck \"\" settings)
344 (todo \"match\" settings files)
345 (search \"match\" settings files)
346 (tags \"match\" settings files)
347 (tags-todo \"match\" settings files)
348
349Each command can carry a list of options, and another set of options can be
350given for the whole set of commands. Individual command options take
351precedence over the general options.
352
353When using several characters as key to a command, the first characters
354are prefix commands. For the dispatcher to display useful information, you
355should provide a description for the prefix, like
356
357 (setq org-agenda-custom-commands
358 '((\"h\" . \"HOME + Name tag searches\") ; describe prefix \"h\"
359 (\"hl\" tags \"+HOME+Lisa\")
360 (\"hp\" tags \"+HOME+Peter\")
361 (\"hk\" tags \"+HOME+Kim\")))"
362 :group 'org-agenda-custom-commands
363 :type `(repeat
364 (choice :value ("x" "Describe command here" tags "" nil)
365 (list :tag "Single command"
366 (string :tag "Access Key(s) ")
367 (option (string :tag "Description"))
368 (choice
369 (const :tag "Agenda" agenda)
370 (const :tag "TODO list" alltodo)
371 (const :tag "Search words" search)
372 (const :tag "Stuck projects" stuck)
c8d0cf5c
CD
373 (const :tag "Tags/Property match (all agenda files)" tags)
374 (const :tag "Tags/Property match of TODO entries (all agenda files)" tags-todo)
20908596
CD
375 (const :tag "TODO keyword search (all agenda files)" todo)
376 (const :tag "Tags sparse tree (current buffer)" tags-tree)
377 (const :tag "TODO keyword tree (current buffer)" todo-tree)
378 (const :tag "Occur tree (current buffer)" occur-tree)
379 (sexp :tag "Other, user-defined function"))
380 (string :tag "Match (only for some commands)")
381 ,org-agenda-custom-commands-local-options
382 (option (repeat :tag "Export" (file :tag "Export to"))))
383 (list :tag "Command series, all agenda files"
384 (string :tag "Access Key(s)")
385 (string :tag "Description ")
386 (repeat :tag "Component"
387 (choice
388 (list :tag "Agenda"
389 (const :format "" agenda)
390 (const :tag "" :format "" "")
391 ,org-agenda-custom-commands-local-options)
392 (list :tag "TODO list (all keywords)"
393 (const :format "" alltodo)
394 (const :tag "" :format "" "")
395 ,org-agenda-custom-commands-local-options)
396 (list :tag "Search words"
397 (const :format "" search)
398 (string :tag "Match")
399 ,org-agenda-custom-commands-local-options)
400 (list :tag "Stuck projects"
401 (const :format "" stuck)
402 (const :tag "" :format "" "")
403 ,org-agenda-custom-commands-local-options)
404 (list :tag "Tags search"
405 (const :format "" tags)
406 (string :tag "Match")
407 ,org-agenda-custom-commands-local-options)
408 (list :tag "Tags search, TODO entries only"
409 (const :format "" tags-todo)
410 (string :tag "Match")
411 ,org-agenda-custom-commands-local-options)
412 (list :tag "TODO keyword search"
413 (const :format "" todo)
414 (string :tag "Match")
415 ,org-agenda-custom-commands-local-options)
416 (list :tag "Other, user-defined function"
417 (symbol :tag "function")
418 (string :tag "Match")
419 ,org-agenda-custom-commands-local-options)))
420
421 (repeat :tag "Settings for entire command set"
422 (list (variable :tag "Any variable")
423 (sexp :tag "Value")))
424 (option (repeat :tag "Export" (file :tag "Export to"))))
425 (cons :tag "Prefix key documentation"
426 (string :tag "Access Key(s)")
427 (string :tag "Description ")))))
428
429(defcustom org-agenda-query-register ?o
430 "The register holding the current query string.
33306645 431The purpose of this is that if you construct a query string interactively,
20908596
CD
432you can then use it to define a custom command."
433 :group 'org-agenda-custom-commands
434 :type 'character)
435
436(defcustom org-stuck-projects
437 '("+LEVEL=2/-DONE" ("TODO" "NEXT" "NEXTACTION") nil "")
438 "How to identify stuck projects.
439This is a list of four items:
c8d0cf5c
CD
4401. A tags/todo/property matcher string that is used to identify a project.
441 See the manual for a description of tag and property searches.
20908596
CD
442 The entire tree below a headline matched by this is considered one project.
4432. A list of TODO keywords identifying non-stuck projects.
444 If the project subtree contains any headline with one of these todo
445 keywords, the project is considered to be not stuck. If you specify
446 \"*\" as a keyword, any TODO keyword will mark the project unstuck.
4473. A list of tags identifying non-stuck projects.
448 If the project subtree contains any headline with one of these tags,
449 the project is considered to be not stuck. If you specify \"*\" as
c8d0cf5c
CD
450 a tag, any tag will mark the project unstuck. Note that this is about
451 the explicit presence of a tag somewhere in the subtree, inherited
452 tags to not count here. If inherited tags make a project not stuck,
453 use \"-TAG\" in the tags part of the matcher under (1.) above.
20908596
CD
4544. An arbitrary regular expression matching non-stuck projects.
455
c8d0cf5c
CD
456If the project turns out to be not stuck, search continues also in the
457subtree to see if any of the subtasks have project status.
458
459See also the variable `org-tags-match-list-sublevels' which applies
460to projects matched by this search as well.
461
20908596
CD
462After defining this variable, you may use \\[org-agenda-list-stuck-projects]
463or `C-c a #' to produce the list."
464 :group 'org-agenda-custom-commands
465 :type '(list
466 (string :tag "Tags/TODO match to identify a project")
467 (repeat :tag "Projects are *not* stuck if they have an entry with TODO keyword any of" (string))
468 (repeat :tag "Projects are *not* stuck if they have an entry with TAG being any of" (string))
c8d0cf5c 469 (regexp :tag "Projects are *not* stuck if this regexp matches inside the subtree")))
20908596 470
71d35b24
CD
471(defcustom org-agenda-filter-effort-default-operator "<"
472 "The default operator for effort estimate filtering.
93b62de8 473If you select an effort estimate limit without first pressing an operator,
71d35b24
CD
474this one will be used."
475 :group 'org-agenda-custom-commands
476 :type '(choice (const :tag "less or equal" "<")
477 (const :tag "greater or equal"">")
478 (const :tag "equal" "=")))
20908596
CD
479
480(defgroup org-agenda-skip nil
481 "Options concerning skipping parts of agenda files."
482 :tag "Org Agenda Skip"
483 :group 'org-agenda)
0bd48b37
CD
484(defgroup org-agenda-daily/weekly nil
485 "Options concerning the daily/weekly agenda."
486 :tag "Org Agenda Daily/Weekly"
487 :group 'org-agenda)
488(defgroup org-agenda-todo-list nil
489 "Options concerning the global todo list agenda view."
490 :tag "Org Agenda Todo List"
491 :group 'org-agenda)
492(defgroup org-agenda-match-view nil
493 "Options concerning the general tags/property/todo match agenda view."
494 :tag "Org Agenda Match View"
495 :group 'org-agenda)
8bfe682a
CD
496(defgroup org-agenda-search-view nil
497 "Options concerning the general tags/property/todo match agenda view."
498 :tag "Org Agenda Match View"
499 :group 'org-agenda)
20908596 500
2c3ad40d
CD
501(defvar org-agenda-archives-mode nil
502 "Non-nil means, the agenda will include archived items.
503If this is the symbol `trees', trees in the selected agenda scope
504that are marked with the ARCHIVE tag will be included anyway. When this is
505t, also all archive files associated with the current selection of agenda
506files will be included.")
507
b349f79f 508(defcustom org-agenda-skip-comment-trees t
93b62de8 509 "Non-nil means, skip trees that start with the COMMENT keyword.
33306645 510When nil, these trees are also scanned by agenda commands."
b349f79f
CD
511 :group 'org-agenda-skip
512 :type 'boolean)
513
20908596
CD
514(defcustom org-agenda-todo-list-sublevels t
515 "Non-nil means, check also the sublevels of a TODO entry for TODO entries.
516When nil, the sublevels of a TODO entry are not checked, resulting in
517potentially much shorter TODO lists."
518 :group 'org-agenda-skip
0bd48b37 519 :group 'org-agenda-todo-list
20908596
CD
520 :type 'boolean)
521
522(defcustom org-agenda-todo-ignore-with-date nil
523 "Non-nil means, don't show entries with a date in the global todo list.
524You can use this if you prefer to mark mere appointments with a TODO keyword,
525but don't want them to show up in the TODO list.
526When this is set, it also covers deadlines and scheduled items, the settings
527of `org-agenda-todo-ignore-scheduled' and `org-agenda-todo-ignore-deadlines'
c8d0cf5c
CD
528will be ignored.
529See also the variable `org-agenda-tags-todo-honor-ignore-options'."
20908596 530 :group 'org-agenda-skip
0bd48b37 531 :group 'org-agenda-todo-list
20908596
CD
532 :type 'boolean)
533
534(defcustom org-agenda-todo-ignore-scheduled nil
535 "Non-nil means, don't show scheduled entries in the global todo list.
536The idea behind this is that by scheduling it, you have already taken care
537of this item.
c8d0cf5c
CD
538See also `org-agenda-todo-ignore-with-date'.
539See also the variable `org-agenda-tags-todo-honor-ignore-options'."
20908596 540 :group 'org-agenda-skip
0bd48b37 541 :group 'org-agenda-todo-list
20908596
CD
542 :type 'boolean)
543
544(defcustom org-agenda-todo-ignore-deadlines nil
545 "Non-nil means, don't show near deadline entries in the global todo list.
546Near means closer than `org-deadline-warning-days' days.
547The idea behind this is that such items will appear in the agenda anyway.
c8d0cf5c
CD
548See also `org-agenda-todo-ignore-with-date'.
549See also the variable `org-agenda-tags-todo-honor-ignore-options'."
20908596 550 :group 'org-agenda-skip
0bd48b37
CD
551 :group 'org-agenda-todo-list
552 :type 'boolean)
553
554(defcustom org-agenda-tags-todo-honor-ignore-options nil
555 "Non-nil means, honor todo-list ...ignore options also in tags-todo search.
556The variables
557 `org-agenda-todo-ignore-with-date',
c8d0cf5c 558 `org-agenda-todo-ignore-scheduled'
0bd48b37
CD
559 `org-agenda-todo-ignore-deadlines'
560make the global TODO list skip entries that have time stamps of certain
561kinds. If this option is set, the same options will also apply for the
562tags-todo search, which is the general tags/property matcher
563restricted to unfinished TODO entries only."
564 :group 'org-agenda-skip
565 :group 'org-agenda-todo-list
566 :group 'org-agenda-match-view
20908596
CD
567 :type 'boolean)
568
569(defcustom org-agenda-skip-scheduled-if-done nil
570 "Non-nil means don't show scheduled items in agenda when they are done.
571This is relevant for the daily/weekly agenda, not for the TODO list. And
572it applies only to the actual date of the scheduling. Warnings about
573an item with a past scheduling dates are always turned off when the item
574is DONE."
575 :group 'org-agenda-skip
0bd48b37 576 :group 'org-agenda-daily/weekly
20908596
CD
577 :type 'boolean)
578
54a0dee5
CD
579(defcustom org-agenda-skip-scheduled-if-deadline-is-shown nil
580 "Non-nil means skip scheduling line if same entry shows because of deadline.
581In the agenda of today, an entry can show up multiple times because
582it is both scheduled and has a nearby deadline, and maybe a plain time
583stamp as well.
584When this variable is t, then only the deadline is shown and the fact that
585the entry is scheduled today or was scheduled previously is not shown.
586When this variable is nil, the entry will be shown several times. When
587the variable is the symbol `not-today', then skip scheduled previously,
588but not scheduled today."
589 :group 'org-agenda-skip
590 :group 'org-agenda-daily/weekly
591 :type '(choice
592 (const :tag "Never" nil)
593 (const :tag "Always" t)
594 (const :tag "Not when scheduled today" not-today)))
595
20908596 596(defcustom org-agenda-skip-deadline-if-done nil
33306645 597 "Non-nil means don't show deadlines when the corresponding item is done.
20908596
CD
598When nil, the deadline is still shown and should give you a happy feeling.
599This is relevant for the daily/weekly agenda. And it applied only to the
33306645 600actually date of the deadline. Warnings about approaching and past-due
20908596
CD
601deadlines are always turned off when the item is DONE."
602 :group 'org-agenda-skip
0bd48b37 603 :group 'org-agenda-daily/weekly
20908596
CD
604 :type 'boolean)
605
c8d0cf5c
CD
606(defcustom org-agenda-skip-additional-timestamps-same-entry t
607 "When nil, multiple same-day timestamps in entry make multiple agenda lines.
608When non-nil, after the search for timestamps has matched once in an
609entry, the rest of the entry will not be searched."
610 :group 'org-agenda-skip
611 :type 'boolean)
612
20908596
CD
613(defcustom org-agenda-skip-timestamp-if-done nil
614 "Non-nil means don't select item by timestamp or -range if it is DONE."
615 :group 'org-agenda-skip
0bd48b37 616 :group 'org-agenda-daily/weekly
20908596
CD
617 :type 'boolean)
618
d6685abc
CD
619(defcustom org-agenda-dim-blocked-tasks t
620 "Non-nil means, dim blocked tasks in the agenda display.
c8d0cf5c
CD
621This causes some overhead during agenda construction, but if you
622have turned on `org-enforce-todo-dependencies',
623`org-enforce-todo-checkbox-dependencies', or any other blocking
624mechanism, this will create useful feedback in the agenda.
625
8bfe682a 626Instead of t, this variable can also have the value `invisible'.
c8d0cf5c
CD
627Then blocked tasks will be invisible and only become visible when
628they become unblocked. An exemption to this behavior is when a task is
629blocked because of unchecked checkboxes below it. Since checkboxes do
630not show up in the agenda views, making this task invisible you remove any
631trace from agenda views that there is something to do. Therefore, a task
632that is blocked because of checkboxes will never be made invisible, it
633will only be dimmed."
d6685abc
CD
634 :group 'org-agenda-daily/weekly
635 :group 'org-agenda-todo-list
636 :type '(choice
637 (const :tag "Do not dim" nil)
638 (const :tag "Dim to a grey face" t)
8bfe682a 639 (const :tag "Make invisible" invisible)))
d6685abc 640
20908596
CD
641(defcustom org-timeline-show-empty-dates 3
642 "Non-nil means, `org-timeline' also shows dates without an entry.
643When nil, only the days which actually have entries are shown.
644When t, all days between the first and the last date are shown.
645When an integer, show also empty dates, but if there is a gap of more than
646N days, just insert a special line indicating the size of the gap."
647 :group 'org-agenda-skip
648 :type '(choice
649 (const :tag "None" nil)
650 (const :tag "All" t)
c8d0cf5c 651 (integer :tag "at most")))
20908596 652
20908596
CD
653(defgroup org-agenda-startup nil
654 "Options concerning initial settings in the Agenda in Org Mode."
655 :tag "Org Agenda Startup"
656 :group 'org-agenda)
657
658(defcustom org-finalize-agenda-hook nil
659 "Hook run just before displaying an agenda buffer."
660 :group 'org-agenda-startup
661 :type 'hook)
662
663(defcustom org-agenda-mouse-1-follows-link nil
664 "Non-nil means, mouse-1 on a link will follow the link in the agenda.
665A longer mouse click will still set point. Does not work on XEmacs.
666Needs to be set before org.el is loaded."
667 :group 'org-agenda-startup
668 :type 'boolean)
669
670(defcustom org-agenda-start-with-follow-mode nil
671 "The initial value of follow-mode in a newly created agenda window."
672 :group 'org-agenda-startup
673 :type 'boolean)
674
1bcdebed
CD
675(defcustom org-agenda-show-outline-path t
676 "Non-il means, show outline path in echo area after line motion."
677 :group 'org-agenda-startup
678 :type 'boolean)
679
54a0dee5
CD
680(defcustom org-agenda-start-with-entry-text-mode nil
681 "The initial value of entry-text-mode in a newly created agenda window."
682 :group 'org-agenda-startup
683 :type 'boolean)
684
685(defcustom org-agenda-entry-text-maxlines 5
8bfe682a 686 "Number of text lines to be added when `E' is pressed in the agenda.
54a0dee5
CD
687
688Note that this variable only used during agenda display. Add add entry text
689when exporting the agenda, configure the variable
690`org-agenda-add-entry-ext-maxlines'."
691 :group 'org-agenda
692 :type 'integer)
693
8d642074
CD
694(defcustom org-agenda-entry-text-exclude-regexps nil
695 "List of regular expressions to clean up entry text.
696The complete matches of all regular expressions in this list will be
697removed from entry text before it is shown in the agenda."
698 :group 'org-agenda
699 :type '(repeat (regexp)))
700
701(defvar org-agenda-entry-text-cleanup-hook nil
702 "Hook that is run after basic cleanup of entry text to be shown in agenda.
703This cleanup is done in a temporary buffer, so the function may inspect and
704change the entire buffer.
705Some default stuff like drawers and scheduling/deadline dates will already
706have been removed when this is called, as will any matches for regular
707expressions listed in `org-agenda-entry-text-exclude-regexps'.")
708
20908596
CD
709(defvar org-agenda-include-inactive-timestamps nil
710 "Non-nil means, include inactive time stamps in agenda and timeline.")
711
712(defgroup org-agenda-windows nil
713 "Options concerning the windows used by the Agenda in Org Mode."
714 :tag "Org Agenda Windows"
715 :group 'org-agenda)
716
717(defcustom org-agenda-window-setup 'reorganize-frame
718 "How the agenda buffer should be displayed.
719Possible values for this option are:
720
721current-window Show agenda in the current window, keeping all other windows.
20908596
CD
722other-window Use `switch-to-buffer-other-window' to display agenda.
723reorganize-frame Show only two windows on the current frame, the current
724 window and the agenda.
8d642074
CD
725other-frame Use `switch-to-buffer-other-frame' to display agenda.
726 Also, when exiting the agenda, kill that frame.
20908596
CD
727See also the variable `org-agenda-restore-windows-after-quit'."
728 :group 'org-agenda-windows
729 :type '(choice
730 (const current-window)
731 (const other-frame)
732 (const other-window)
733 (const reorganize-frame)))
734
735(defcustom org-agenda-window-frame-fractions '(0.5 . 0.75)
736 "The min and max height of the agenda window as a fraction of frame height.
737The value of the variable is a cons cell with two numbers between 0 and 1.
738It only matters if `org-agenda-window-setup' is `reorganize-frame'."
739 :group 'org-agenda-windows
740 :type '(cons (number :tag "Minimum") (number :tag "Maximum")))
741
742(defcustom org-agenda-restore-windows-after-quit nil
743 "Non-nil means, restore window configuration open exiting agenda.
744Before the window configuration is changed for displaying the agenda,
745the current status is recorded. When the agenda is exited with
746`q' or `x' and this option is set, the old state is restored. If
747`org-agenda-window-setup' is `other-frame', the value of this
baf0cb84 748option will be ignored."
20908596
CD
749 :group 'org-agenda-windows
750 :type 'boolean)
751
20908596
CD
752(defcustom org-agenda-ndays 7
753 "Number of days to include in overview display.
c8d0cf5c
CD
754Should be 1 or 7.
755Custom commands can set this variable in the options section."
20908596 756 :group 'org-agenda-daily/weekly
c8d0cf5c 757 :type 'integer)
20908596
CD
758
759(defcustom org-agenda-start-on-weekday 1
760 "Non-nil means, start the overview always on the specified weekday.
7610 denotes Sunday, 1 denotes Monday etc.
c8d0cf5c
CD
762When nil, always start on the current day.
763Custom commands can set this variable in the options section."
20908596
CD
764 :group 'org-agenda-daily/weekly
765 :type '(choice (const :tag "Today" nil)
c8d0cf5c 766 (integer :tag "Weekday No.")))
20908596
CD
767
768(defcustom org-agenda-show-all-dates t
769 "Non-nil means, `org-agenda' shows every day in the selected range.
770When nil, only the days which actually have entries are shown."
771 :group 'org-agenda-daily/weekly
772 :type 'boolean)
773
774(defcustom org-agenda-format-date 'org-agenda-format-date-aligned
775 "Format string for displaying dates in the agenda.
776Used by the daily/weekly agenda and by the timeline. This should be
777a format string understood by `format-time-string', or a function returning
778the formatted date as a string. The function must take a single argument,
779a calendar-style date list like (month day year)."
780 :group 'org-agenda-daily/weekly
781 :type '(choice
782 (string :tag "Format string")
783 (function :tag "Function")))
784
785(defun org-agenda-format-date-aligned (date)
786 "Format a date string for display in the daily/weekly agenda, or timeline.
787This function makes sure that dates are aligned for easy reading."
788 (require 'cal-iso)
789 (let* ((dayname (calendar-day-name date))
790 (day (cadr date))
791 (day-of-week (calendar-day-of-week date))
792 (month (car date))
793 (monthname (calendar-month-name month))
794 (year (nth 2 date))
795 (iso-week (org-days-to-iso-week
796 (calendar-absolute-from-gregorian date)))
797 (weekyear (cond ((and (= month 1) (>= iso-week 52))
798 (1- year))
799 ((and (= month 12) (<= iso-week 1))
800 (1+ year))
801 (t year)))
802 (weekstring (if (= day-of-week 1)
803 (format " W%02d" iso-week)
804 "")))
805 (format "%-10s %2d %s %4d%s"
806 dayname day monthname year weekstring)))
807
808(defcustom org-agenda-weekend-days '(6 0)
809 "Which days are weekend?
810These days get the special face `org-agenda-date-weekend' in the agenda
811and timeline buffers."
812 :group 'org-agenda-daily/weekly
813 :type '(set :greedy t
814 (const :tag "Monday" 1)
815 (const :tag "Tuesday" 2)
816 (const :tag "Wednesday" 3)
817 (const :tag "Thursday" 4)
818 (const :tag "Friday" 5)
819 (const :tag "Saturday" 6)
820 (const :tag "Sunday" 0)))
821
822(defcustom org-agenda-include-diary nil
c8d0cf5c
CD
823 "If non-nil, include in the agenda entries from the Emacs Calendar's diary.
824Custom commands can set this variable in the options section."
20908596
CD
825 :group 'org-agenda-daily/weekly
826 :type 'boolean)
827
828(defcustom org-agenda-include-all-todo nil
829 "Set means weekly/daily agenda will always contain all TODO entries.
830The TODO entries will be listed at the top of the agenda, before
0bd48b37
CD
831the entries for specific days.
832This option is deprecated, it is better to define a block agenda instead."
20908596
CD
833 :group 'org-agenda-daily/weekly
834 :type 'boolean)
835
836(defcustom org-agenda-repeating-timestamp-show-all t
33306645
CD
837 "Non-nil means, show all occurrences of a repeating stamp in the agenda.
838When nil, only one occurrence is shown, either today or the
20908596
CD
839nearest into the future."
840 :group 'org-agenda-daily/weekly
841 :type 'boolean)
842
843(defcustom org-scheduled-past-days 10000
844 "No. of days to continue listing scheduled items that are not marked DONE.
845When an item is scheduled on a date, it shows up in the agenda on this
846day and will be listed until it is marked done for the number of days
847given here."
848 :group 'org-agenda-daily/weekly
c8d0cf5c 849 :type 'integer)
20908596 850
93b62de8
CD
851(defcustom org-agenda-log-mode-items '(closed clock)
852 "List of items that should be shown in agenda log mode.
853This list may contain the following symbols:
854
855 closed Show entries that have been closed on that day.
856 clock Show entries that have received clocked time on that day.
c8d0cf5c
CD
857 state Show all logged state changes.
858Note that instead of changing this variable, you can also press `C-u l' in
859the agenda to display all available LOG items temporarily."
93b62de8
CD
860 :group 'org-agenda-daily/weekly
861 :type '(set :greedy t (const closed) (const clock) (const state)))
862
c8d0cf5c
CD
863(defcustom org-agenda-log-mode-add-notes t
864 "Non-nil means, add first line of notes to log entries in agenda views.
865If a log item like a state change or a clock entry is associated with
866notes, the first line of these notes will be added to the entry in the
867agenda display."
868 :group 'org-agenda-daily/weekly
869 :type 'boolean)
870
871(defcustom org-agenda-start-with-log-mode nil
872 "The initial value of log-mode in a newly created agenda window."
873 :group 'org-agenda-startup
874 :group 'org-agenda-daily/weekly
875 :type 'boolean)
876
20908596
CD
877(defcustom org-agenda-start-with-clockreport-mode nil
878 "The initial value of clockreport-mode in a newly created agenda window."
879 :group 'org-agenda-startup
880 :group 'org-agenda-daily/weekly
881 :type 'boolean)
882
883(defcustom org-agenda-clockreport-parameter-plist '(:link t :maxlevel 2)
884 "Property list with parameters for the clocktable in clockreport mode.
885This is the display mode that shows a clock table in the daily/weekly
886agenda, the properties for this dynamic block can be set here.
887The usual clocktable parameters are allowed here, but you cannot set
888the properties :name, :tstart, :tend, :block, and :scope - these will
889be overwritten to make sure the content accurately reflects the
890current display in the agenda."
891 :group 'org-agenda-daily/weekly
892 :type 'plist)
893
8bfe682a
CD
894(defcustom org-agenda-search-view-search-words-only nil
895 "Non-nil means, the search string is interpreted as individual words
896The search then looks for each word separately in each entry and
897selects entries that have matches for all words.
898When nil, matching as loose words will only take place if the first
899word is preceded by + or -. If that is not the case, the search
900string will just be matched as a substring in the entry, but with
901each space character allowing for any whitespace, including newlines."
902 :group 'org-agenda-search-view
903 :type 'boolean)
20908596
CD
904
905(defgroup org-agenda-time-grid nil
906 "Options concerning the time grid in the Org-mode Agenda."
907 :tag "Org Agenda Time Grid"
908 :group 'org-agenda)
909
c8d0cf5c
CD
910(defcustom org-agenda-search-headline-for-time t
911 "Non-nil means, search headline for a time-of-day.
912If the headline contains a time-of-day in one format or another, it will
913be used to sort the entry into the time sequence of items for a day.
914Some people have time stamps in the headline that refer to the creation
915time or so, and then this produces an unwanted side effect. If this is
916the case for your, use this variable to turn off searching the headline
917for a time."
918 :group 'org-agenda-time-grid
919 :type 'boolean)
920
20908596
CD
921(defcustom org-agenda-use-time-grid t
922 "Non-nil means, show a time grid in the agenda schedule.
923A time grid is a set of lines for specific times (like every two hours between
9248:00 and 20:00). The items scheduled for a day at specific times are
925sorted in between these lines.
926For details about when the grid will be shown, and what it will look like, see
927the variable `org-agenda-time-grid'."
928 :group 'org-agenda-time-grid
929 :type 'boolean)
930
931(defcustom org-agenda-time-grid
932 '((daily today require-timed)
933 "----------------"
934 (800 1000 1200 1400 1600 1800 2000))
935
936 "The settings for time grid for agenda display.
937This is a list of three items. The first item is again a list. It contains
938symbols specifying conditions when the grid should be displayed:
939
940 daily if the agenda shows a single day
941 weekly if the agenda shows an entire week
942 today show grid on current date, independent of daily/weekly display
943 require-timed show grid only if at least one item has a time specification
944
b349f79f 945The second item is a string which will be placed behind the grid time.
20908596
CD
946
947The third item is a list of integers, indicating the times that should have
948a grid line."
949 :group 'org-agenda-time-grid
950 :type
951 '(list
952 (set :greedy t :tag "Grid Display Options"
953 (const :tag "Show grid in single day agenda display" daily)
954 (const :tag "Show grid in weekly agenda display" weekly)
955 (const :tag "Always show grid for today" today)
956 (const :tag "Show grid only if any timed entries are present"
957 require-timed)
958 (const :tag "Skip grid times already present in an entry"
959 remove-match))
960 (string :tag "Grid String")
961 (repeat :tag "Grid Times" (integer :tag "Time"))))
962
963(defgroup org-agenda-sorting nil
964 "Options concerning sorting in the Org-mode Agenda."
965 :tag "Org Agenda Sorting"
966 :group 'org-agenda)
967
968(defcustom org-agenda-sorting-strategy
8bfe682a
CD
969 '((agenda habit-down time-up priority-down category-keep)
970 (todo priority-down category-keep)
971 (tags priority-down category-keep)
20908596
CD
972 (search category-keep))
973 "Sorting structure for the agenda items of a single day.
974This is a list of symbols which will be used in sequence to determine
975if an entry should be listed before another entry. The following
976symbols are recognized:
977
c8d0cf5c
CD
978time-up Put entries with time-of-day indications first, early first
979time-down Put entries with time-of-day indications first, late first
980category-keep Keep the default order of categories, corresponding to the
981 sequence in `org-agenda-files'.
982category-up Sort alphabetically by category, A-Z.
983category-down Sort alphabetically by category, Z-A.
984tag-up Sort alphabetically by last tag, A-Z.
985tag-down Sort alphabetically by last tag, Z-A.
986priority-up Sort numerically by priority, high priority last.
987priority-down Sort numerically by priority, high priority first.
988todo-state-up Sort by todo state, tasks that are done last.
989todo-state-down Sort by todo state, tasks that are done first.
990effort-up Sort numerically by estimated effort, high effort last.
991effort-down Sort numerically by estimated effort, high effort first.
992user-defined-up Sort according to `org-agenda-cmp-user-defined', high last.
993user-defined-down Sort according to `org-agenda-cmp-user-defined', high first.
8bfe682a
CD
994habit-up Put entries that are habits first
995habit-down Put entries that are habits last
20908596
CD
996
997The different possibilities will be tried in sequence, and testing stops
998if one comparison returns a \"not-equal\". For example, the default
999 '(time-up category-keep priority-down)
1000means: Pull out all entries having a specified time of day and sort them,
1001in order to make a time schedule for the current day the first thing in the
1002agenda listing for the day. Of the entries without a time indication, keep
1003the grouped in categories, don't sort the categories, but keep them in
1004the sequence given in `org-agenda-files'. Within each category sort by
1005priority.
1006
1007Leaving out `category-keep' would mean that items will be sorted across
1008categories by priority.
1009
1010Instead of a single list, this can also be a set of list for specific
1011contents, with a context symbol in the car of the list, any of
8bfe682a 1012`agenda', `todo', `tags', `search' for the corresponding agenda views.
c8d0cf5c
CD
1013
1014Custom commands can bind this variable in the options section."
20908596
CD
1015 :group 'org-agenda-sorting
1016 :type `(choice
1017 (repeat :tag "General" ,org-sorting-choice)
1018 (list :tag "Individually"
1019 (cons (const :tag "Strategy for Weekly/Daily agenda" agenda)
1020 (repeat ,org-sorting-choice))
1021 (cons (const :tag "Strategy for TODO lists" todo)
1022 (repeat ,org-sorting-choice))
1023 (cons (const :tag "Strategy for Tags matches" tags)
8bfe682a
CD
1024 (repeat ,org-sorting-choice))
1025 (cons (const :tag "Strategy for search matches" search)
20908596
CD
1026 (repeat ,org-sorting-choice)))))
1027
c8d0cf5c
CD
1028(defcustom org-agenda-cmp-user-defined nil
1029 "A function to define the comparison `user-defined'.
1030This function must receive two arguments, agenda entry a and b.
1031If a>b, return +1. If a<b, return -1. If they are equal as seen by
1032the user comparison, return nil.
1033When this is defined, you can make `user-defined-up' and `user-defined-down'
1034part of an agenda sorting strategy."
1035 :group 'org-agenda-sorting
1036 :type 'symbol)
1037
20908596
CD
1038(defcustom org-sort-agenda-notime-is-late t
1039 "Non-nil means, items without time are considered late.
1040This is only relevant for sorting. When t, items which have no explicit
1041time like 15:30 will be considered as 99:01, i.e. later than any items which
1042do have a time. When nil, the default time is before 0:00. You can use this
1043option to decide if the schedule for today should come before or after timeless
1044agenda entries."
1045 :group 'org-agenda-sorting
1046 :type 'boolean)
1047
1048(defcustom org-sort-agenda-noeffort-is-high t
1049 "Non-nil means, items without effort estimate are sorted as high effort.
c8d0cf5c
CD
1050This also applies when filtering an agenda view with respect to the
1051< or > effort operator. Then, tasks with no effort defined will be treated
1052as tasks with high effort.
20908596
CD
1053When nil, such items are sorted as 0 minutes effort."
1054 :group 'org-agenda-sorting
1055 :type 'boolean)
1056
1057(defgroup org-agenda-line-format nil
1058 "Options concerning the entry prefix in the Org-mode agenda display."
1059 :tag "Org Agenda Line Format"
1060 :group 'org-agenda)
1061
1062(defcustom org-agenda-prefix-format
1063 '((agenda . " %-12:c%?-12t% s")
1064 (timeline . " % s")
1065 (todo . " %-12:c")
1066 (tags . " %-12:c")
1067 (search . " %-12:c"))
1068 "Format specifications for the prefix of items in the agenda views.
1069An alist with four entries, for the different agenda types. The keys to the
1070sublists are `agenda', `timeline', `todo', and `tags'. The values
1071are format strings.
1072This format works similar to a printf format, with the following meaning:
1073
1074 %c the category of the item, \"Diary\" for entries from the diary, or
1075 as given by the CATEGORY keyword or derived from the file name.
1076 %T the *last* tag of the item. Last because inherited tags come
1077 first in the list.
1078 %t the time-of-day specification if one applies to the entry, in the
1079 format HH:MM
1080 %s Scheduling/Deadline information, a short string
1081
1082All specifiers work basically like the standard `%s' of printf, but may
1083contain two additional characters: A question mark just after the `%' and
1084a whitespace/punctuation character just before the final letter.
1085
1086If the first character after `%' is a question mark, the entire field
1087will only be included if the corresponding value applies to the
1088current entry. This is useful for fields which should have fixed
1089width when present, but zero width when absent. For example,
1090\"%?-12t\" will result in a 12 character time field if a time of the
1091day is specified, but will completely disappear in entries which do
1092not contain a time.
1093
1094If there is punctuation or whitespace character just before the final
1095format letter, this character will be appended to the field value if
1096the value is not empty. For example, the format \"%-12:c\" leads to
1097\"Diary: \" if the category is \"Diary\". If the category were be
8bfe682a 1098empty, no additional colon would be inserted.
20908596
CD
1099
1100The default value of this option is \" %-12:c%?-12t% s\", meaning:
1101- Indent the line with two space characters
1102- Give the category in a 12 chars wide field, padded with whitespace on
1103 the right (because of `-'). Append a colon if there is a category
1104 (because of `:').
1105- If there is a time-of-day, put it into a 12 chars wide field. If no
1106 time, don't put in an empty field, just skip it (because of '?').
1107- Finally, put the scheduling information and append a whitespace.
1108
1109As another example, if you don't want the time-of-day of entries in
1110the prefix, you could use:
1111
1112 (setq org-agenda-prefix-format \" %-11:c% s\")
1113
1114See also the variables `org-agenda-remove-times-when-in-prefix' and
c8d0cf5c
CD
1115`org-agenda-remove-tags'.
1116
1117Custom commands can set this variable in the options section."
20908596
CD
1118 :type '(choice
1119 (string :tag "General format")
1120 (list :greedy t :tag "View dependent"
1121 (cons (const agenda) (string :tag "Format"))
1122 (cons (const timeline) (string :tag "Format"))
1123 (cons (const todo) (string :tag "Format"))
1124 (cons (const tags) (string :tag "Format"))
1125 (cons (const search) (string :tag "Format"))))
1126 :group 'org-agenda-line-format)
1127
1128(defvar org-prefix-format-compiled nil
1129 "The compiled version of the most recently used prefix format.
1130See the variable `org-agenda-prefix-format'.")
1131
1132(defcustom org-agenda-todo-keyword-format "%-1s"
1133 "Format for the TODO keyword in agenda lines.
1134Set this to something like \"%-12s\" if you want all TODO keywords
1135to occupy a fixed space in the agenda display."
1136 :group 'org-agenda-line-format
1137 :type 'string)
1138
ce4fdcb9
CD
1139(defcustom org-agenda-timerange-leaders '("" "(%d/%d): ")
1140 "Text preceding timerange entries in the agenda view.
1141This is a list with two strings. The first applies when the range
1142is entirely on one day. The second applies if the range spans several days.
1143The strings may have two \"%d\" format specifiers which will be filled
1144with the sequence number of the days, and the total number of days in the
1145range, respectively."
1146 :group 'org-agenda-line-format
1147 :type '(list
1148 (string :tag "Deadline today ")
1149 (choice :tag "Deadline relative"
1150 (string :tag "Format string")
1151 (function))))
1152
20908596
CD
1153(defcustom org-agenda-scheduled-leaders '("Scheduled: " "Sched.%2dx: ")
1154 "Text preceeding scheduled items in the agenda view.
1155This is a list with two strings. The first applies when the item is
1156scheduled on the current day. The second applies when it has been scheduled
b349f79f
CD
1157previously, it may contain a %d indicating that this is the nth time that
1158this item is scheduled, due to automatic rescheduling of unfinished items
1159for the following day. So this number is one larger than the number of days
1160that passed since this item was scheduled first."
20908596
CD
1161 :group 'org-agenda-line-format
1162 :type '(list
1163 (string :tag "Scheduled today ")
1164 (string :tag "Scheduled previously")))
1165
1166(defcustom org-agenda-deadline-leaders '("Deadline: " "In %3d d.: ")
1167 "Text preceeding deadline items in the agenda view.
1168This is a list with two strings. The first applies when the item has its
1169deadline on the current day. The second applies when it is in the past or
1170in the future, it may contain %d to capture how many days away the deadline
1171is (was)."
1172 :group 'org-agenda-line-format
1173 :type '(list
1174 (string :tag "Deadline today ")
1175 (choice :tag "Deadline relative"
1176 (string :tag "Format string")
1177 (function))))
1178
1179(defcustom org-agenda-remove-times-when-in-prefix t
1180 "Non-nil means, remove duplicate time specifications in agenda items.
1181When the format `org-agenda-prefix-format' contains a `%t' specifier, a
1182time-of-day specification in a headline or diary entry is extracted and
1183placed into the prefix. If this option is non-nil, the original specification
1184\(a timestamp or -range, or just a plain time(range) specification like
118511:30-4pm) will be removed for agenda display. This makes the agenda less
1186cluttered.
1187The option can be t or nil. It may also be the symbol `beg', indicating
1188that the time should only be removed what it is located at the beginning of
1189the headline/diary entry."
1190 :group 'org-agenda-line-format
1191 :type '(choice
1192 (const :tag "Always" t)
1193 (const :tag "Never" nil)
1194 (const :tag "When at beginning of entry" beg)))
1195
1196
1197(defcustom org-agenda-default-appointment-duration nil
1198 "Default duration for appointments that only have a starting time.
1199When nil, no duration is specified in such cases.
1200When non-nil, this must be the number of minutes, e.g. 60 for one hour."
1201 :group 'org-agenda-line-format
1202 :type '(choice
1203 (integer :tag "Minutes")
1204 (const :tag "No default duration")))
1205
ff4be292
CD
1206(defcustom org-agenda-show-inherited-tags t
1207 "Non-nil means, show inherited tags in each agenda line."
1208 :group 'org-agenda-line-format
1209 :type 'boolean)
20908596
CD
1210
1211(defcustom org-agenda-remove-tags nil
1212 "Non-nil means, remove the tags from the headline copy in the agenda.
1213When this is the symbol `prefix', only remove tags when
1214`org-agenda-prefix-format' contains a `%T' specifier."
1215 :group 'org-agenda-line-format
1216 :type '(choice
1217 (const :tag "Always" t)
1218 (const :tag "Never" nil)
1219 (const :tag "When prefix format contains %T" prefix)))
1220
1221(if (fboundp 'defvaralias)
1222 (defvaralias 'org-agenda-remove-tags-when-in-prefix
1223 'org-agenda-remove-tags))
1224
5ace2fe5 1225(defcustom org-agenda-tags-column (if (featurep 'xemacs) -79 -80)
20908596
CD
1226 "Shift tags in agenda items to this column.
1227If this number is positive, it specifies the column. If it is negative,
1228it means that the tags should be flushright to that column. For example,
1229-80 works well for a normal 80 character screen."
1230 :group 'org-agenda-line-format
1231 :type 'integer)
1232
1233(if (fboundp 'defvaralias)
1234 (defvaralias 'org-agenda-align-tags-to-column 'org-agenda-tags-column))
1235
c8d0cf5c 1236(defcustom org-agenda-fontify-priorities 'cookies
20908596
CD
1237 "Non-nil means, highlight low and high priorities in agenda.
1238When t, the highest priority entries are bold, lowest priority italic.
c8d0cf5c
CD
1239However, settings in org-priority-faces will overrule these faces.
1240When this variable is the symbol `cookies', only fontify the
1241cookies, not the entire task.
621f83e4
CD
1242This may also be an association list of priority faces, whose
1243keys are the character values of `org-highest-priority',
1244`org-default-priority', and `org-lowest-priority' (the default values
c8d0cf5c 1245are ?A, ?B, and ?C, respectively). The face may be a named face,
621f83e4 1246or a list like `(:background \"Red\")'."
20908596
CD
1247 :group 'org-agenda-line-format
1248 :type '(choice
1249 (const :tag "Never" nil)
1250 (const :tag "Defaults" t)
c8d0cf5c 1251 (const :tag "Cookies only" cookies)
20908596
CD
1252 (repeat :tag "Specify"
1253 (list (character :tag "Priority" :value ?A)
1254 (sexp :tag "face")))))
1255
20908596
CD
1256(defgroup org-agenda-column-view nil
1257 "Options concerning column view in the agenda."
1258 :tag "Org Agenda Column View"
1259 :group 'org-agenda)
1260
1261(defcustom org-agenda-columns-show-summaries t
1262 "Non-nil means, show summaries for columns displayed in the agenda view."
1263 :group 'org-agenda-column-view
1264 :type 'boolean)
1265
b349f79f
CD
1266(defcustom org-agenda-columns-remove-prefix-from-item t
1267 "Non-nil means, remove the prefix from a headline for agenda column view.
1268The special ITEM field in the columns format contains the current line, with
1269all information shown in other columns (like the TODO state or a tag).
1270When this variable is non-nil, also the agenda prefix will be removed from
1271the content of the ITEM field, to make sure as much as possible of the
1272headline can be shown in the limited width of the field."
1273 :group 'org-agenda
1274 :type 'boolean)
1275
20908596
CD
1276(defcustom org-agenda-columns-compute-summary-properties t
1277 "Non-nil means, recompute all summary properties before column view.
1278When column view in the agenda is listing properties that have a summary
1279operator, it can go to all relevant buffers and recompute the summaries
1280there. This can mean overhead for the agenda column view, but is necessary
1281to have thing up to date.
1282As a special case, a CLOCKSUM property also makes sure that the clock
1283computations are current."
1284 :group 'org-agenda-column-view
1285 :type 'boolean)
1286
1287(defcustom org-agenda-columns-add-appointments-to-effort-sum nil
1288 "Non-nil means, the duration of an appointment will add to day effort.
1289The property to which appointment durations will be added is the one given
1290in the option `org-effort-property'. If an appointment does not have
1291an end time, `org-agenda-default-appointment-duration' will be used. If that
1292is not set, an appointment without end time will not contribute to the time
1293estimate."
1294 :group 'org-agenda-column-view
1295 :type 'boolean)
1296
8bfe682a
CD
1297(defcustom org-agenda-auto-exclude-function nil
1298 "A function called with a tag to decide if it is filtered on '/ RET'.
1299The sole argument to the function, which is called once for each
1300possible tag, is a string giving the name of the tag. The
1301function should return either nil if the tag should be included
1302as normal, or \"-<TAG>\" to exclude the tag."
1303 :group 'org-agenda
1304 :type 'function)
1305
20908596
CD
1306(eval-when-compile
1307 (require 'cl))
1308(require 'org)
1309
1310(defun org-add-agenda-custom-command (entry)
1311 "Replace or add a command in `org-agenda-custom-commands'.
1312This is mostly for hacking and trying a new command - once the command
1313works you probably want to add it to `org-agenda-custom-commands' for good."
1314 (let ((ass (assoc (car entry) org-agenda-custom-commands)))
1315 (if ass
1316 (setcdr ass (cdr entry))
1317 (push entry org-agenda-custom-commands))))
1318
1319;;; Define the Org-agenda-mode
1320
1321(defvar org-agenda-mode-map (make-sparse-keymap)
1322 "Keymap for `org-agenda-mode'.")
8bfe682a
CD
1323(if (fboundp 'defvaralias)
1324 (defvaralias 'org-agenda-keymap 'org-agenda-mode-map))
20908596
CD
1325
1326(defvar org-agenda-menu) ; defined later in this file.
c8d0cf5c 1327(defvar org-agenda-restrict) ; defined later in this file.
20908596 1328(defvar org-agenda-follow-mode nil)
54a0dee5 1329(defvar org-agenda-entry-text-mode nil)
20908596
CD
1330(defvar org-agenda-clockreport-mode nil)
1331(defvar org-agenda-show-log nil)
1332(defvar org-agenda-redo-command nil)
1333(defvar org-agenda-query-string nil)
0bd48b37
CD
1334(defvar org-agenda-mode-hook nil
1335 "Hook for org-agenda-mode, run after the mode is turned on.")
20908596
CD
1336(defvar org-agenda-type nil)
1337(defvar org-agenda-force-single-file nil)
c8d0cf5c 1338(defvar org-agenda-bulk-marked-entries) ;; Defined further down in this file
20908596
CD
1339
1340(defun org-agenda-mode ()
1341 "Mode for time-sorted view on action items in Org-mode files.
1342
1343The following commands are available:
1344
1345\\{org-agenda-mode-map}"
1346 (interactive)
1347 (kill-all-local-variables)
1348 (setq org-agenda-undo-list nil
c8d0cf5c
CD
1349 org-agenda-pending-undo-list nil
1350 org-agenda-bulk-marked-entries nil)
20908596
CD
1351 (setq major-mode 'org-agenda-mode)
1352 ;; Keep global-font-lock-mode from turning on font-lock-mode
1353 (org-set-local 'font-lock-global-modes (list 'not major-mode))
1354 (setq mode-name "Org-Agenda")
1355 (use-local-map org-agenda-mode-map)
1356 (easy-menu-add org-agenda-menu)
1357 (if org-startup-truncated (setq truncate-lines t))
54a0dee5 1358 (org-set-local 'line-move-visual nil)
20908596
CD
1359 (org-add-hook 'post-command-hook 'org-agenda-post-command-hook nil 'local)
1360 (org-add-hook 'pre-command-hook 'org-unhighlight nil 'local)
1361 ;; Make sure properties are removed when copying text
1362 (when (boundp 'buffer-substring-filters)
1363 (org-set-local 'buffer-substring-filters
1364 (cons (lambda (x)
1365 (set-text-properties 0 (length x) nil x) x)
1366 buffer-substring-filters)))
1367 (unless org-agenda-keep-modes
1368 (setq org-agenda-follow-mode org-agenda-start-with-follow-mode
54a0dee5 1369 org-agenda-entry-text-mode org-agenda-start-with-entry-text-mode
20908596 1370 org-agenda-clockreport-mode org-agenda-start-with-clockreport-mode
c8d0cf5c
CD
1371 org-agenda-show-log org-agenda-start-with-log-mode))
1372
20908596
CD
1373 (easy-menu-change
1374 '("Agenda") "Agenda Files"
1375 (append
1376 (list
1377 (vector
1378 (if (get 'org-agenda-files 'org-restrict)
1379 "Restricted to single file"
1380 "Edit File List")
1381 '(org-edit-agenda-file-list)
1382 (not (get 'org-agenda-files 'org-restrict)))
1383 "--")
1384 (mapcar 'org-file-menu-entry (org-agenda-files))))
1385 (org-agenda-set-mode-name)
1386 (apply
1387 (if (fboundp 'run-mode-hooks) 'run-mode-hooks 'run-hooks)
1388 (list 'org-agenda-mode-hook)))
1389
1390(substitute-key-definition 'undo 'org-agenda-undo
1391 org-agenda-mode-map global-map)
1392(org-defkey org-agenda-mode-map "\C-i" 'org-agenda-goto)
1393(org-defkey org-agenda-mode-map [(tab)] 'org-agenda-goto)
1394(org-defkey org-agenda-mode-map "\C-m" 'org-agenda-switch-to)
1395(org-defkey org-agenda-mode-map "\C-k" 'org-agenda-kill)
c8d0cf5c
CD
1396(org-defkey org-agenda-mode-map "\C-c\C-w" 'org-agenda-refile)
1397(org-defkey org-agenda-mode-map "m" 'org-agenda-bulk-mark)
1398(org-defkey org-agenda-mode-map "u" 'org-agenda-bulk-unmark)
1399(org-defkey org-agenda-mode-map "U" 'org-agenda-bulk-remove-all-marks)
1400(org-defkey org-agenda-mode-map "B" 'org-agenda-bulk-action)
1401(org-defkey org-agenda-mode-map "\C-c\C-x!" 'org-reload)
8bfe682a
CD
1402(org-defkey org-agenda-mode-map "\C-c\C-x\C-a" 'org-agenda-archive-default)
1403(org-defkey org-agenda-mode-map "\C-c\C-xa" 'org-agenda-toggle-archive-tag)
1404(org-defkey org-agenda-mode-map "\C-c\C-xA" 'org-agenda-archive-to-archive-sibling)
54a0dee5 1405(org-defkey org-agenda-mode-map "\C-c\C-x\C-s" 'org-agenda-archive)
8bfe682a 1406(org-defkey org-agenda-mode-map "\C-c$" 'org-agenda-archive)
20908596 1407(org-defkey org-agenda-mode-map "$" 'org-agenda-archive)
20908596 1408(org-defkey org-agenda-mode-map "\C-c\C-o" 'org-agenda-open-link)
8bfe682a
CD
1409(org-defkey org-agenda-mode-map " " 'org-agenda-show-and-scroll-up)
1410(org-defkey org-agenda-mode-map [backspace] 'org-agenda-show-scroll-down)
1411(org-defkey org-agenda-mode-map "\d" 'org-agenda-show-scroll-down)
20908596
CD
1412(org-defkey org-agenda-mode-map [(control shift right)] 'org-agenda-todo-nextset)
1413(org-defkey org-agenda-mode-map [(control shift left)] 'org-agenda-todo-previousset)
1414(org-defkey org-agenda-mode-map "\C-c\C-xb" 'org-agenda-tree-to-indirect-buffer)
20908596
CD
1415(org-defkey org-agenda-mode-map "o" 'delete-other-windows)
1416(org-defkey org-agenda-mode-map "L" 'org-agenda-recenter)
54a0dee5 1417(org-defkey org-agenda-mode-map "\C-c\C-t" 'org-agenda-todo)
20908596 1418(org-defkey org-agenda-mode-map "t" 'org-agenda-todo)
8bfe682a 1419(org-defkey org-agenda-mode-map "a" 'org-agenda-archive-default-with-confirmation)
20908596 1420(org-defkey org-agenda-mode-map ":" 'org-agenda-set-tags)
71d35b24 1421(org-defkey org-agenda-mode-map "\C-c\C-q" 'org-agenda-set-tags)
20908596
CD
1422(org-defkey org-agenda-mode-map "." 'org-agenda-goto-today)
1423(org-defkey org-agenda-mode-map "j" 'org-agenda-goto-date)
1424(org-defkey org-agenda-mode-map "d" 'org-agenda-day-view)
1425(org-defkey org-agenda-mode-map "w" 'org-agenda-week-view)
20908596
CD
1426(org-defkey org-agenda-mode-map "y" 'org-agenda-year-view)
1427(org-defkey org-agenda-mode-map "\C-c\C-z" 'org-agenda-add-note)
1428(org-defkey org-agenda-mode-map "z" 'org-agenda-add-note)
b349f79f
CD
1429(org-defkey org-agenda-mode-map "k" 'org-agenda-action)
1430(org-defkey org-agenda-mode-map "\C-c\C-x\C-k" 'org-agenda-action)
c8d0cf5c
CD
1431(org-defkey org-agenda-mode-map [(shift right)] 'org-agenda-do-date-later)
1432(org-defkey org-agenda-mode-map [(shift left)] 'org-agenda-do-date-earlier)
1433(org-defkey org-agenda-mode-map [?\C-c ?\C-x (right)] 'org-agenda-do-date-later)
1434(org-defkey org-agenda-mode-map [?\C-c ?\C-x (left)] 'org-agenda-do-date-earlier)
20908596
CD
1435
1436(org-defkey org-agenda-mode-map ">" 'org-agenda-date-prompt)
1437(org-defkey org-agenda-mode-map "\C-c\C-s" 'org-agenda-schedule)
1438(org-defkey org-agenda-mode-map "\C-c\C-d" 'org-agenda-deadline)
1439(let ((l '(1 2 3 4 5 6 7 8 9 0)))
1440 (while l (org-defkey org-agenda-mode-map
1441 (int-to-string (pop l)) 'digit-argument)))
1442
54a0dee5 1443(org-defkey org-agenda-mode-map "F" 'org-agenda-follow-mode)
20908596 1444(org-defkey org-agenda-mode-map "R" 'org-agenda-clockreport-mode)
54a0dee5 1445(org-defkey org-agenda-mode-map "E" 'org-agenda-entry-text-mode)
20908596 1446(org-defkey org-agenda-mode-map "l" 'org-agenda-log-mode)
c8d0cf5c 1447(org-defkey org-agenda-mode-map "v" 'org-agenda-view-mode-dispatch)
20908596
CD
1448(org-defkey org-agenda-mode-map "D" 'org-agenda-toggle-diary)
1449(org-defkey org-agenda-mode-map "G" 'org-agenda-toggle-time-grid)
1450(org-defkey org-agenda-mode-map "r" 'org-agenda-redo)
1451(org-defkey org-agenda-mode-map "g" 'org-agenda-redo)
54a0dee5
CD
1452(org-defkey org-agenda-mode-map "e" 'org-agenda-set-effort)
1453(org-defkey org-agenda-mode-map "\C-c\C-xe" 'org-agenda-set-effort)
1454(org-defkey org-agenda-mode-map "\C-c\C-x\C-e"
1455 'org-clock-modify-effort-estimate)
1456(org-defkey org-agenda-mode-map "\C-c\C-xp" 'org-agenda-set-property)
20908596
CD
1457(org-defkey org-agenda-mode-map "q" 'org-agenda-quit)
1458(org-defkey org-agenda-mode-map "x" 'org-agenda-exit)
1459(org-defkey org-agenda-mode-map "\C-x\C-w" 'org-write-agenda)
20908596 1460(org-defkey org-agenda-mode-map "\C-x\C-s" 'org-save-all-org-buffers)
c8d0cf5c 1461(org-defkey org-agenda-mode-map "s" 'org-save-all-org-buffers)
20908596
CD
1462(org-defkey org-agenda-mode-map "P" 'org-agenda-show-priority)
1463(org-defkey org-agenda-mode-map "T" 'org-agenda-show-tags)
8bfe682a
CD
1464(org-defkey org-agenda-mode-map "n" 'org-agenda-next-line)
1465(org-defkey org-agenda-mode-map "p" 'org-agenda-previous-line)
1466(substitute-key-definition 'next-line 'org-agenda-next-line
1467 org-agenda-mode-map global-map)
1468(substitute-key-definition 'previous-line 'org-agenda-previous-line
1469 org-agenda-mode-map global-map)
621f83e4 1470(org-defkey org-agenda-mode-map "\C-c\C-a" 'org-attach)
20908596
CD
1471(org-defkey org-agenda-mode-map "\C-c\C-n" 'org-agenda-next-date-line)
1472(org-defkey org-agenda-mode-map "\C-c\C-p" 'org-agenda-previous-date-line)
1473(org-defkey org-agenda-mode-map "," 'org-agenda-priority)
1474(org-defkey org-agenda-mode-map "\C-c," 'org-agenda-priority)
1475(org-defkey org-agenda-mode-map "i" 'org-agenda-diary-entry)
1476(org-defkey org-agenda-mode-map "c" 'org-agenda-goto-calendar)
1477(org-defkey org-agenda-mode-map "C" 'org-agenda-convert-date)
1478(org-defkey org-agenda-mode-map "M" 'org-agenda-phases-of-moon)
1479(org-defkey org-agenda-mode-map "S" 'org-agenda-sunrise-sunset)
1480(org-defkey org-agenda-mode-map "h" 'org-agenda-holidays)
1481(org-defkey org-agenda-mode-map "H" 'org-agenda-holidays)
1482(org-defkey org-agenda-mode-map "\C-c\C-x\C-i" 'org-agenda-clock-in)
1483(org-defkey org-agenda-mode-map "I" 'org-agenda-clock-in)
1484(org-defkey org-agenda-mode-map "\C-c\C-x\C-o" 'org-agenda-clock-out)
1485(org-defkey org-agenda-mode-map "O" 'org-agenda-clock-out)
1486(org-defkey org-agenda-mode-map "\C-c\C-x\C-x" 'org-agenda-clock-cancel)
1487(org-defkey org-agenda-mode-map "X" 'org-agenda-clock-cancel)
1488(org-defkey org-agenda-mode-map "\C-c\C-x\C-j" 'org-clock-goto)
1489(org-defkey org-agenda-mode-map "J" 'org-clock-goto)
1490(org-defkey org-agenda-mode-map "+" 'org-agenda-priority-up)
1491(org-defkey org-agenda-mode-map "-" 'org-agenda-priority-down)
1492(org-defkey org-agenda-mode-map [(shift up)] 'org-agenda-priority-up)
1493(org-defkey org-agenda-mode-map [(shift down)] 'org-agenda-priority-down)
1494(org-defkey org-agenda-mode-map [?\C-c ?\C-x (up)] 'org-agenda-priority-up)
1495(org-defkey org-agenda-mode-map [?\C-c ?\C-x (down)] 'org-agenda-priority-down)
54a0dee5
CD
1496(org-defkey org-agenda-mode-map "f" 'org-agenda-later)
1497(org-defkey org-agenda-mode-map "b" 'org-agenda-earlier)
20908596 1498(org-defkey org-agenda-mode-map "\C-c\C-x\C-c" 'org-agenda-columns)
c8d0cf5c 1499(org-defkey org-agenda-mode-map "\C-c\C-x>" 'org-agenda-remove-restriction-lock)
20908596
CD
1500
1501(org-defkey org-agenda-mode-map "[" 'org-agenda-manipulate-query-add)
1502(org-defkey org-agenda-mode-map "]" 'org-agenda-manipulate-query-subtract)
1503(org-defkey org-agenda-mode-map "{" 'org-agenda-manipulate-query-add-re)
1504(org-defkey org-agenda-mode-map "}" 'org-agenda-manipulate-query-subtract-re)
621f83e4 1505(org-defkey org-agenda-mode-map "/" 'org-agenda-filter-by-tag)
71d35b24 1506(org-defkey org-agenda-mode-map "\\" 'org-agenda-filter-by-tag-refine)
c8d0cf5c 1507(org-defkey org-agenda-mode-map ";" 'org-timer-set-timer)
8d642074
CD
1508(define-key org-agenda-mode-map "?" 'org-agenda-show-the-flagging-note)
1509(org-defkey org-agenda-mode-map "\C-c\C-x\C-mg" 'org-mobile-pull)
1510(org-defkey org-agenda-mode-map "\C-c\C-x\C-mp" 'org-mobile-push)
20908596 1511
8bfe682a 1512(org-defkey org-agenda-mode-map
20908596 1513 (if (featurep 'xemacs) [(button2)] [(mouse-2)]) 'org-agenda-goto-mouse)
8bfe682a 1514(org-defkey org-agenda-mode-map
20908596
CD
1515 (if (featurep 'xemacs) [(button3)] [(mouse-3)]) 'org-agenda-show-mouse)
1516(when org-agenda-mouse-1-follows-link
8bfe682a 1517 (org-defkey org-agenda-mode-map [follow-link] 'mouse-face))
20908596
CD
1518(easy-menu-define org-agenda-menu org-agenda-mode-map "Agenda menu"
1519 '("Agenda"
1520 ("Agenda Files")
1521 "--"
8d642074
CD
1522 ("Agenda Dates"
1523 ["Goto Today" org-agenda-goto-today (org-agenda-check-type nil 'agenda 'timeline)]
1524 ["Next Dates" org-agenda-later (org-agenda-check-type nil 'agenda)]
1525 ["Previous Dates" org-agenda-earlier (org-agenda-check-type nil 'agenda)]
1526 ["Jump to date" org-agenda-goto-date (org-agenda-check-type nil 'agenda)])
1527 "--"
1528 ("View"
1529 ["Day View" org-agenda-day-view
1530 :active (org-agenda-check-type nil 'agenda)
1531 :style radio :selected (equal org-agenda-ndays 1)
1532 :keys "v d (or just d)"]
1533 ["Week View" org-agenda-week-view
1534 :active (org-agenda-check-type nil 'agenda)
1535 :style radio :selected (equal org-agenda-ndays 7)
1536 :keys "v w (or just w)"]
1537 ["Month View" org-agenda-month-view
1538 :active (org-agenda-check-type nil 'agenda)
1539 :style radio :selected (member org-agenda-ndays '(28 29 30 31))
1540 :keys "v m"]
1541 ["Year View" org-agenda-year-view
1542 :active (org-agenda-check-type nil 'agenda)
1543 :style radio :selected (member org-agenda-ndays '(365 366))
1544 :keys "v y"]
1545 "--"
1546 ["Include Diary" org-agenda-toggle-diary
1547 :style toggle :selected org-agenda-include-diary
1548 :active (org-agenda-check-type nil 'agenda)]
1549 ["Use Time Grid" org-agenda-toggle-time-grid
1550 :style toggle :selected org-agenda-use-time-grid
1551 :active (org-agenda-check-type nil 'agenda)]
1552 "--"
1553 ["Show clock report" org-agenda-clockreport-mode
1554 :style toggle :selected org-agenda-clockreport-mode
1555 :active (org-agenda-check-type nil 'agenda)]
1556 ["Show some entry text" org-agenda-entry-text-mode
1557 :style toggle :selected org-agenda-entry-text-mode
1558 :active t]
1559 "--"
1560 ["Show Logbook entries" org-agenda-log-mode
1561 :style toggle :selected org-agenda-show-log
1562 :active (org-agenda-check-type nil 'agenda 'timeline)
1563 :keys "v l (or just l)"]
1564 ["Include archived trees" org-agenda-archives-mode
1565 :style toggle :selected org-agenda-archives-mode :active t
1566 :keys "v a"]
1567 ["Include archive files" (org-agenda-archives-mode t)
1568 :style toggle :selected (eq org-agenda-archives-mode t) :active t
1569 :keys "v A"]
1570 "--"
1571 ["Remove Restriction" org-agenda-remove-restriction-lock org-agenda-restrict])
1572 ["Write view to file" org-write-agenda t]
1573 ["Rebuild buffer" org-agenda-redo t]
1574 ["Save all Org-mode Buffers" org-save-all-org-buffers t]
1575 "--"
1576 ["Show original entry" org-agenda-show t]
20908596
CD
1577 ["Go To (other window)" org-agenda-goto t]
1578 ["Go To (this window)" org-agenda-switch-to t]
1579 ["Follow Mode" org-agenda-follow-mode
1580 :style toggle :selected org-agenda-follow-mode :active t]
8d642074 1581; ["Tree to indirect frame" org-agenda-tree-to-indirect-buffer t]
20908596 1582 "--"
8d642074
CD
1583 ("TODO"
1584 ["Cycle TODO" org-agenda-todo t]
1585 ["Next TODO set" org-agenda-todo-nextset t]
1586 ["Previous TODO set" org-agenda-todo-previousset t]
1587 ["Add note" org-agenda-add-note t])
1588 ("Archive/Refile/Delete"
8bfe682a
CD
1589 ["Archive default" org-agenda-archive-default t]
1590 ["Archive default" org-agenda-archive-default-with-confirmation t]
20908596
CD
1591 ["Toggle ARCHIVE tag" org-agenda-toggle-archive-tag t]
1592 ["Move to archive sibling" org-agenda-archive-to-archive-sibling t]
c8d0cf5c 1593 ["Archive subtree" org-agenda-archive t]
8d642074
CD
1594 "--"
1595 ["Refile" org-agenda-refile t]
1596 "--"
1597 ["Delete subtree" org-agenda-kill t])
c8d0cf5c 1598 ("Bulk action"
8d642074
CD
1599 ["Mark entry" org-agenda-bulk-mark t]
1600 ["Unmark entry" org-agenda-bulk-unmark t]
c8d0cf5c
CD
1601 ["Act on all marked" org-agenda-bulk-action t]
1602 ["Unmark all entries" org-agenda-bulk-remove-all-marks :active t :keys "C-u s"])
1603 "--"
20908596
CD
1604 ("Tags and Properties"
1605 ["Show all Tags" org-agenda-show-tags t]
1606 ["Set Tags current line" org-agenda-set-tags (not (org-region-active-p))]
1607 ["Change tag in region" org-agenda-set-tags (org-region-active-p)]
1608 "--"
1609 ["Column View" org-columns t])
8d642074 1610 ("Deadline/Schedule"
20908596
CD
1611 ["Schedule" org-agenda-schedule t]
1612 ["Set Deadline" org-agenda-deadline t]
1613 "--"
b349f79f
CD
1614 ["Mark item" org-agenda-action :active t :keys "k m"]
1615 ["Show mark item" org-agenda-action :active t :keys "k v"]
1616 ["Schedule marked item" org-agenda-action :active t :keys "k s"]
1617 ["Set Deadline for marked item" org-agenda-action :active t :keys "k d"]
1618 "--"
20908596
CD
1619 ["Change Date +1 day" org-agenda-date-later (org-agenda-check-type nil 'agenda 'timeline)]
1620 ["Change Date -1 day" org-agenda-date-earlier (org-agenda-check-type nil 'agenda 'timeline)]
c8d0cf5c
CD
1621 ["Change Time +1 hour" org-agenda-do-date-later :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u S-right"]
1622 ["Change Time -1 hour" org-agenda-do-date-earlier :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u S-left"]
1623 ["Change Time + min" org-agenda-date-later :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u C-u S-right"]
1624 ["Change Time - min" org-agenda-date-earlier :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u C-u S-left"]
20908596 1625 ["Change Date to ..." org-agenda-date-prompt (org-agenda-check-type nil 'agenda 'timeline)])
54a0dee5 1626 ("Clock and Effort"
20908596
CD
1627 ["Clock in" org-agenda-clock-in t]
1628 ["Clock out" org-agenda-clock-out t]
1629 ["Clock cancel" org-agenda-clock-cancel t]
54a0dee5
CD
1630 ["Goto running clock" org-clock-goto t]
1631 "--"
1632 ["Set Effort" org-agenda-set-effort t]
1633 ["Change clocked effort" org-clock-modify-effort-estimate
1634 (org-clock-is-active)])
20908596
CD
1635 ("Priority"
1636 ["Set Priority" org-agenda-priority t]
1637 ["Increase Priority" org-agenda-priority-up t]
1638 ["Decrease Priority" org-agenda-priority-down t]
1639 ["Show Priority" org-agenda-show-priority t])
1640 ("Calendar/Diary"
1641 ["New Diary Entry" org-agenda-diary-entry (org-agenda-check-type nil 'agenda 'timeline)]
1642 ["Goto Calendar" org-agenda-goto-calendar (org-agenda-check-type nil 'agenda 'timeline)]
1643 ["Phases of the Moon" org-agenda-phases-of-moon (org-agenda-check-type nil 'agenda 'timeline)]
1644 ["Sunrise/Sunset" org-agenda-sunrise-sunset (org-agenda-check-type nil 'agenda 'timeline)]
1645 ["Holidays" org-agenda-holidays (org-agenda-check-type nil 'agenda 'timeline)]
1646 ["Convert" org-agenda-convert-date (org-agenda-check-type nil 'agenda 'timeline)]
1647 "--"
8d642074 1648 ["Create iCalendar File" org-export-icalendar-combine-agenda-files t])
20908596 1649 "--"
8d642074 1650 ["Undo Remote Editing" org-agenda-undo org-agenda-undo-list]
2c3ad40d 1651 "--"
8d642074
CD
1652 ("MobileOrg"
1653 ["Push Files and Views" org-mobile-push t]
1654 ["Get Captured and Flagged" org-mobile-pull t]
1655 ["Find FLAGGED Tasks" (org-agenda nil "?") :active t :keys "C-c a ?"]
1656 ["Show note / unflag" org-agenda-show-the-flagging-note t]
c8d0cf5c 1657 "--"
8d642074 1658 ["Setup" (progn (require 'org-mobile) (customize-group 'org-mobile)) t])
20908596
CD
1659 "--"
1660 ["Quit" org-agenda-quit t]
1661 ["Exit and Release Buffers" org-agenda-exit t]
1662 ))
1663
1664;;; Agenda undo
1665
1666(defvar org-agenda-allow-remote-undo t
1667 "Non-nil means, allow remote undo from the agenda buffer.")
1668(defvar org-agenda-undo-list nil
1669 "List of undoable operations in the agenda since last refresh.")
1670(defvar org-agenda-undo-has-started-in nil
1671 "Buffers that have already seen `undo-start' in the current undo sequence.")
1672(defvar org-agenda-pending-undo-list nil
33306645 1673 "In a series of undo commands, this is the list of remaining undo items.")
20908596
CD
1674
1675
1676(defun org-agenda-undo ()
1677 "Undo a remote editing step in the agenda.
1678This undoes changes both in the agenda buffer and in the remote buffer
1679that have been changed along."
1680 (interactive)
1681 (or org-agenda-allow-remote-undo
f924a367 1682 (error "Check the variable `org-agenda-allow-remote-undo' to activate remote undo"))
20908596
CD
1683 (if (not (eq this-command last-command))
1684 (setq org-agenda-undo-has-started-in nil
1685 org-agenda-pending-undo-list org-agenda-undo-list))
1686 (if (not org-agenda-pending-undo-list)
1687 (error "No further undo information"))
1688 (let* ((entry (pop org-agenda-pending-undo-list))
1689 buf line cmd rembuf)
1690 (setq cmd (pop entry) line (pop entry))
1691 (setq rembuf (nth 2 entry))
1692 (org-with-remote-undo rembuf
1693 (while (bufferp (setq buf (pop entry)))
1694 (if (pop entry)
1695 (with-current-buffer buf
1696 (let ((last-undo-buffer buf)
1697 (inhibit-read-only t))
1698 (unless (memq buf org-agenda-undo-has-started-in)
1699 (push buf org-agenda-undo-has-started-in)
1700 (make-local-variable 'pending-undo-list)
1701 (undo-start))
1702 (while (and pending-undo-list
1703 (listp pending-undo-list)
1704 (not (car pending-undo-list)))
1705 (pop pending-undo-list))
1706 (undo-more 1))))))
54a0dee5 1707 (org-goto-line line)
20908596
CD
1708 (message "`%s' undone (buffer %s)" cmd (buffer-name rembuf))))
1709
1710(defun org-verify-change-for-undo (l1 l2)
1711 "Verify that a real change occurred between the undo lists L1 and L2."
1712 (while (and l1 (listp l1) (null (car l1))) (pop l1))
1713 (while (and l2 (listp l2) (null (car l2))) (pop l2))
1714 (not (eq l1 l2)))
1715
1716;;; Agenda dispatch
1717
1718(defvar org-agenda-restrict nil)
1719(defvar org-agenda-restrict-begin (make-marker))
1720(defvar org-agenda-restrict-end (make-marker))
1721(defvar org-agenda-last-dispatch-buffer nil)
1722(defvar org-agenda-overriding-restriction nil)
1723
1724;;;###autoload
c8d0cf5c 1725(defun org-agenda (&optional arg keys restriction)
20908596
CD
1726 "Dispatch agenda commands to collect entries to the agenda buffer.
1727Prompts for a command to execute. Any prefix arg will be passed
1728on to the selected command. The default selections are:
1729
1730a Call `org-agenda-list' to display the agenda for current day or week.
1731t Call `org-todo-list' to display the global todo list.
1732T Call `org-todo-list' to display the global todo list, select only
1733 entries with a specific TODO keyword (the user gets a prompt).
1734m Call `org-tags-view' to display headlines with tags matching
1735 a condition (the user is prompted for the condition).
1736M Like `m', but select only TODO entries, no ordinary headlines.
1737L Create a timeline for the current buffer.
1738e Export views to associated files.
c8d0cf5c 1739s Search entries for keywords.
8bfe682a 1740/ Multi occur across all agenda files and also files listed
c8d0cf5c
CD
1741 in `org-agenda-text-search-extra-files'.
1742< Restrict agenda commands to buffer, subtree, or region.
1743 Press several times to get the desired effect.
1744> Remove a previous restriction.
1745# List \"stuck\" projects.
1746! Configure what \"stuck\" means.
1747C Configure custom agenda commands.
20908596
CD
1748
1749More commands can be added by configuring the variable
1750`org-agenda-custom-commands'. In particular, specific tags and TODO keyword
1751searches can be pre-defined in this way.
1752
1753If the current buffer is in Org-mode and visiting a file, you can also
1754first press `<' once to indicate that the agenda should be temporarily
1755\(until the next use of \\[org-agenda]) restricted to the current file.
1756Pressing `<' twice means to restrict to the current subtree or region
1757\(if active)."
1758 (interactive "P")
1759 (catch 'exit
1760 (let* ((prefix-descriptions nil)
54a0dee5
CD
1761 (org-agenda-window-setup (if (equal (buffer-name)
1762 org-agenda-buffer-name)
1763 'current-window
1764 org-agenda-window-setup))
20908596
CD
1765 (org-agenda-custom-commands-orig org-agenda-custom-commands)
1766 (org-agenda-custom-commands
1767 ;; normalize different versions
1768 (delq nil
1769 (mapcar
1770 (lambda (x)
1771 (cond ((stringp (cdr x))
1772 (push x prefix-descriptions)
1773 nil)
1774 ((stringp (nth 1 x)) x)
1775 ((not (nth 1 x)) (cons (car x) (cons "" (cddr x))))
1776 (t (cons (car x) (cons "" (cdr x))))))
1777 org-agenda-custom-commands)))
1778 (buf (current-buffer))
1779 (bfn (buffer-file-name (buffer-base-buffer)))
1780 entry key type match lprops ans)
8d642074 1781 ;; Turn off restriction unless there is an overriding one,
20908596 1782 (unless org-agenda-overriding-restriction
8bfe682a 1783 (unless (org-bound-and-true-p org-agenda-keep-restricted-file-list)
8d642074
CD
1784 ;; There is a request to keep the file list in place
1785 (put 'org-agenda-files 'org-restrict nil))
20908596
CD
1786 (setq org-agenda-restrict nil)
1787 (move-marker org-agenda-restrict-begin nil)
1788 (move-marker org-agenda-restrict-end nil))
1789 ;; Delete old local properties
1790 (put 'org-agenda-redo-command 'org-lprops nil)
1791 ;; Remember where this call originated
1792 (setq org-agenda-last-dispatch-buffer (current-buffer))
1793 (unless keys
1794 (setq ans (org-agenda-get-restriction-and-command prefix-descriptions)
1795 keys (car ans)
1796 restriction (cdr ans)))
8bfe682a 1797 ;; Establish the restriction, if any
20908596
CD
1798 (when (and (not org-agenda-overriding-restriction) restriction)
1799 (put 'org-agenda-files 'org-restrict (list bfn))
1800 (cond
1801 ((eq restriction 'region)
1802 (setq org-agenda-restrict t)
1803 (move-marker org-agenda-restrict-begin (region-beginning))
1804 (move-marker org-agenda-restrict-end (region-end)))
1805 ((eq restriction 'subtree)
1806 (save-excursion
1807 (setq org-agenda-restrict t)
1808 (org-back-to-heading t)
1809 (move-marker org-agenda-restrict-begin (point))
1810 (move-marker org-agenda-restrict-end
1811 (progn (org-end-of-subtree t)))))))
1812
1813 (require 'calendar) ; FIXME: can we avoid this for some commands?
1814 ;; For example the todo list should not need it (but does...)
1815 (cond
1816 ((setq entry (assoc keys org-agenda-custom-commands))
1817 (if (or (symbolp (nth 2 entry)) (functionp (nth 2 entry)))
1818 (progn
8bfe682a
CD
1819 (setq type (nth 2 entry) match (eval (nth 3 entry))
1820 lprops (nth 4 entry))
20908596
CD
1821 (put 'org-agenda-redo-command 'org-lprops lprops)
1822 (cond
1823 ((eq type 'agenda)
1824 (org-let lprops '(org-agenda-list current-prefix-arg)))
1825 ((eq type 'alltodo)
1826 (org-let lprops '(org-todo-list current-prefix-arg)))
1827 ((eq type 'search)
1828 (org-let lprops '(org-search-view current-prefix-arg match nil)))
1829 ((eq type 'stuck)
1830 (org-let lprops '(org-agenda-list-stuck-projects
1831 current-prefix-arg)))
1832 ((eq type 'tags)
1833 (org-let lprops '(org-tags-view current-prefix-arg match)))
1834 ((eq type 'tags-todo)
1835 (org-let lprops '(org-tags-view '(4) match)))
1836 ((eq type 'todo)
1837 (org-let lprops '(org-todo-list match)))
1838 ((eq type 'tags-tree)
1839 (org-check-for-org-mode)
c8d0cf5c 1840 (org-let lprops '(org-match-sparse-tree current-prefix-arg match)))
20908596
CD
1841 ((eq type 'todo-tree)
1842 (org-check-for-org-mode)
1843 (org-let lprops
1844 '(org-occur (concat "^" outline-regexp "[ \t]*"
1845 (regexp-quote match) "\\>"))))
1846 ((eq type 'occur-tree)
1847 (org-check-for-org-mode)
1848 (org-let lprops '(org-occur match)))
1849 ((functionp type)
1850 (org-let lprops '(funcall type match)))
1851 ((fboundp type)
1852 (org-let lprops '(funcall type match)))
1853 (t (error "Invalid custom agenda command type %s" type))))
1854 (org-run-agenda-series (nth 1 entry) (cddr entry))))
1855 ((equal keys "C")
1856 (setq org-agenda-custom-commands org-agenda-custom-commands-orig)
1857 (customize-variable 'org-agenda-custom-commands))
1858 ((equal keys "a") (call-interactively 'org-agenda-list))
1859 ((equal keys "s") (call-interactively 'org-search-view))
1860 ((equal keys "t") (call-interactively 'org-todo-list))
1861 ((equal keys "T") (org-call-with-arg 'org-todo-list (or arg '(4))))
1862 ((equal keys "m") (call-interactively 'org-tags-view))
1863 ((equal keys "M") (org-call-with-arg 'org-tags-view (or arg '(4))))
1864 ((equal keys "e") (call-interactively 'org-store-agenda-views))
8d642074
CD
1865 ((equal keys "?") (org-tags-view nil "+FLAGGED")
1866 (org-add-hook
1867 'post-command-hook
1868 (lambda ()
1869 (unless (current-message)
1870 (let* ((m (org-agenda-get-any-marker))
1871 (note (and m (org-entry-get m "THEFLAGGINGNOTE"))))
1872 (when note
1873 (message (concat
1874 "FLAGGING-NOTE ([?] for more info): "
1875 (org-add-props
1876 (replace-regexp-in-string
1877 "\\\\n" "//"
1878 (copy-sequence note))
1879 nil 'face 'org-warning)))))))
1880 t t))
20908596
CD
1881 ((equal keys "L")
1882 (unless (org-mode-p)
1883 (error "This is not an Org-mode file"))
1884 (unless restriction
1885 (put 'org-agenda-files 'org-restrict (list bfn))
1886 (org-call-with-arg 'org-timeline arg)))
1887 ((equal keys "#") (call-interactively 'org-agenda-list-stuck-projects))
1888 ((equal keys "/") (call-interactively 'org-occur-in-agenda-files))
1889 ((equal keys "!") (customize-variable 'org-stuck-projects))
1890 (t (error "Invalid agenda key"))))))
1891
1892(defun org-agenda-normalize-custom-commands (cmds)
1893 (delq nil
1894 (mapcar
1895 (lambda (x)
1896 (cond ((stringp (cdr x)) nil)
1897 ((stringp (nth 1 x)) x)
1898 ((not (nth 1 x)) (cons (car x) (cons "" (cddr x))))
1899 (t (cons (car x) (cons "" (cdr x))))))
1900 cmds)))
1901
1902(defun org-agenda-get-restriction-and-command (prefix-descriptions)
1903 "The user interface for selecting an agenda command."
1904 (catch 'exit
1905 (let* ((bfn (buffer-file-name (buffer-base-buffer)))
1906 (restrict-ok (and bfn (org-mode-p)))
1907 (region-p (org-region-active-p))
1908 (custom org-agenda-custom-commands)
1909 (selstring "")
1910 restriction second-time
1911 c entry key type match prefixes rmheader header-end custom1 desc)
1912 (save-window-excursion
1913 (delete-other-windows)
1914 (org-switch-to-buffer-other-window " *Agenda Commands*")
1915 (erase-buffer)
1916 (insert (eval-when-compile
1917 (let ((header
1918"
2c3ad40d 1919Press key for an agenda command: < Buffer, subtree/region restriction
20908596
CD
1920-------------------------------- > Remove restriction
1921a Agenda for current week or day e Export agenda views
1922t List of all TODO entries T Entries with special TODO kwd
621f83e4 1923m Match a TAGS/PROP/TODO query M Like m, but only TODO entries
20908596
CD
1924L Timeline for current buffer # List stuck projects (!=configure)
1925s Search for keywords C Configure custom agenda commands
8d642074 1926/ Multi-occur ? Find :FLAGGED: entries
20908596
CD
1927")
1928 (start 0))
1929 (while (string-match
1930 "\\(^\\| \\|(\\)\\(\\S-\\)\\( \\|=\\)"
1931 header start)
1932 (setq start (match-end 0))
1933 (add-text-properties (match-beginning 2) (match-end 2)
1934 '(face bold) header))
1935 header)))
1936 (setq header-end (move-marker (make-marker) (point)))
1937 (while t
1938 (setq custom1 custom)
1939 (when (eq rmheader t)
54a0dee5 1940 (org-goto-line 1)
20908596
CD
1941 (re-search-forward ":" nil t)
1942 (delete-region (match-end 0) (point-at-eol))
1943 (forward-char 1)
1944 (looking-at "-+")
1945 (delete-region (match-end 0) (point-at-eol))
1946 (move-marker header-end (match-end 0)))
1947 (goto-char header-end)
1948 (delete-region (point) (point-max))
1949 (while (setq entry (pop custom1))
1950 (setq key (car entry) desc (nth 1 entry)
54a0dee5
CD
1951 type (nth 2 entry)
1952 match (nth 3 entry))
20908596
CD
1953 (if (> (length key) 1)
1954 (add-to-list 'prefixes (string-to-char key))
1955 (insert
1956 (format
1957 "\n%-4s%-14s: %s"
1958 (org-add-props (copy-sequence key)
1959 '(face bold))
1960 (cond
1961 ((string-match "\\S-" desc) desc)
1962 ((eq type 'agenda) "Agenda for current week or day")
1963 ((eq type 'alltodo) "List of all TODO entries")
1964 ((eq type 'search) "Word search")
1965 ((eq type 'stuck) "List of stuck projects")
1966 ((eq type 'todo) "TODO keyword")
1967 ((eq type 'tags) "Tags query")
1968 ((eq type 'tags-todo) "Tags (TODO)")
1969 ((eq type 'tags-tree) "Tags tree")
1970 ((eq type 'todo-tree) "TODO kwd tree")
1971 ((eq type 'occur-tree) "Occur tree")
1972 ((functionp type) (if (symbolp type)
1973 (symbol-name type)
1974 "Lambda expression"))
1975 (t "???"))
1976 (cond
1977 ((stringp match)
54a0dee5 1978 (setq match (copy-sequence match))
20908596
CD
1979 (org-add-props match nil 'face 'org-warning))
1980 (match
1981 (format "set of %d commands" (length match)))
1982 (t ""))))))
1983 (when prefixes
1984 (mapc (lambda (x)
1985 (insert
1986 (format "\n%s %s"
1987 (org-add-props (char-to-string x)
1988 nil 'face 'bold)
1989 (or (cdr (assoc (concat selstring (char-to-string x))
1990 prefix-descriptions))
1991 "Prefix key"))))
1992 prefixes))
1993 (goto-char (point-min))
93b62de8
CD
1994 (if second-time
1995 (if (not (pos-visible-in-window-p (point-max)))
1996 (org-fit-window-to-buffer))
1997 (setq second-time t)
1998 (org-fit-window-to-buffer))
20908596
CD
1999 (message "Press key for agenda command%s:"
2000 (if (or restrict-ok org-agenda-overriding-restriction)
2001 (if org-agenda-overriding-restriction
2002 " (restriction lock active)"
2003 (if restriction
2004 (format " (restricted to %s)" restriction)
2005 " (unrestricted)"))
2006 ""))
2007 (setq c (read-char-exclusive))
2008 (message "")
2009 (cond
2010 ((assoc (char-to-string c) custom)
2011 (setq selstring (concat selstring (char-to-string c)))
2012 (throw 'exit (cons selstring restriction)))
2013 ((memq c prefixes)
2014 (setq selstring (concat selstring (char-to-string c))
2015 prefixes nil
2016 rmheader (or rmheader t)
2017 custom (delq nil (mapcar
2018 (lambda (x)
2019 (if (or (= (length (car x)) 1)
2020 (/= (string-to-char (car x)) c))
2021 nil
2022 (cons (substring (car x) 1) (cdr x))))
2023 custom))))
2024 ((and (not restrict-ok) (memq c '(?1 ?0 ?<)))
2025 (message "Restriction is only possible in Org-mode buffers")
2026 (ding) (sit-for 1))
2027 ((eq c ?1)
2028 (org-agenda-remove-restriction-lock 'noupdate)
2029 (setq restriction 'buffer))
2030 ((eq c ?0)
2031 (org-agenda-remove-restriction-lock 'noupdate)
2032 (setq restriction (if region-p 'region 'subtree)))
2033 ((eq c ?<)
2034 (org-agenda-remove-restriction-lock 'noupdate)
2035 (setq restriction
2036 (cond
2037 ((eq restriction 'buffer)
2038 (if region-p 'region 'subtree))
2039 ((memq restriction '(subtree region))
2040 nil)
2041 (t 'buffer))))
2042 ((eq c ?>)
2043 (org-agenda-remove-restriction-lock 'noupdate)
2044 (setq restriction nil))
8d642074 2045 ((and (equal selstring "") (memq c '(?s ?a ?t ?m ?L ?C ?e ?T ?M ?# ?! ?/ ??)))
20908596
CD
2046 (throw 'exit (cons (setq selstring (char-to-string c)) restriction)))
2047 ((and (> (length selstring) 0) (eq c ?\d))
2048 (delete-window)
2049 (org-agenda-get-restriction-and-command prefix-descriptions))
2050
2051 ((equal c ?q) (error "Abort"))
2052 (t (error "Invalid key %c" c))))))))
2053
2054(defun org-run-agenda-series (name series)
c8d0cf5c 2055 (org-let (nth 1 series) '(org-prepare-agenda name))
20908596
CD
2056 (let* ((org-agenda-multi t)
2057 (redo (list 'org-run-agenda-series name (list 'quote series)))
2058 (cmds (car series))
2059 (gprops (nth 1 series))
2060 match ;; The byte compiler incorrectly complains about this. Keep it!
2061 cmd type lprops)
2062 (while (setq cmd (pop cmds))
8bfe682a 2063 (setq type (car cmd) match (eval (nth 1 cmd)) lprops (nth 2 cmd))
20908596
CD
2064 (cond
2065 ((eq type 'agenda)
2066 (org-let2 gprops lprops
2067 '(call-interactively 'org-agenda-list)))
2068 ((eq type 'alltodo)
2069 (org-let2 gprops lprops
2070 '(call-interactively 'org-todo-list)))
2071 ((eq type 'search)
2072 (org-let2 gprops lprops
2073 '(org-search-view current-prefix-arg match nil)))
2074 ((eq type 'stuck)
2075 (org-let2 gprops lprops
2076 '(call-interactively 'org-agenda-list-stuck-projects)))
2077 ((eq type 'tags)
2078 (org-let2 gprops lprops
2079 '(org-tags-view current-prefix-arg match)))
2080 ((eq type 'tags-todo)
2081 (org-let2 gprops lprops
2082 '(org-tags-view '(4) match)))
2083 ((eq type 'todo)
2084 (org-let2 gprops lprops
2085 '(org-todo-list match)))
2086 ((fboundp type)
2087 (org-let2 gprops lprops
2088 '(funcall type match)))
2089 (t (error "Invalid type in command series"))))
2090 (widen)
2091 (setq org-agenda-redo-command redo)
2092 (goto-char (point-min)))
c8d0cf5c 2093 (org-fit-agenda-window)
0bd48b37 2094 (org-let (nth 1 series) '(org-finalize-agenda)))
20908596
CD
2095
2096;;;###autoload
2097(defmacro org-batch-agenda (cmd-key &rest parameters)
2098 "Run an agenda command in batch mode and send the result to STDOUT.
2099If CMD-KEY is a string of length 1, it is used as a key in
2100`org-agenda-custom-commands' and triggers this command. If it is a
2101longer string it is used as a tags/todo match string.
2102Paramters are alternating variable names and values that will be bound
2103before running the agenda command."
2104 (let (pars)
2105 (while parameters
2106 (push (list (pop parameters) (if parameters (pop parameters))) pars))
2107 (if (> (length cmd-key) 2)
2108 (eval (list 'let (nreverse pars)
2109 (list 'org-tags-view nil cmd-key)))
2110 (eval (list 'let (nreverse pars) (list 'org-agenda nil cmd-key))))
2111 (set-buffer org-agenda-buffer-name)
2112 (princ (org-encode-for-stdout (buffer-string)))))
2113
8bfe682a
CD
2114;(defun org-encode-for-stdout (string)
2115; (if (fboundp 'encode-coding-string)
2116; (encode-coding-string string buffer-file-coding-system)
2117; string))
2118
20908596 2119(defun org-encode-for-stdout (string)
8bfe682a 2120 string)
20908596
CD
2121
2122(defvar org-agenda-info nil)
2123
2124;;;###autoload
2125(defmacro org-batch-agenda-csv (cmd-key &rest parameters)
2126 "Run an agenda command in batch mode and send the result to STDOUT.
2127If CMD-KEY is a string of length 1, it is used as a key in
2128`org-agenda-custom-commands' and triggers this command. If it is a
2129longer string it is used as a tags/todo match string.
2130Paramters are alternating variable names and values that will be bound
2131before running the agenda command.
2132
2133The output gives a line for each selected agenda item. Each
2134item is a list of comma-separated values, like this:
2135
2136category,head,type,todo,tags,date,time,extra,priority-l,priority-n
2137
2138category The category of the item
2139head The headline, without TODO kwd, TAGS and PRIORITY
2140type The type of the agenda entry, can be
2141 todo selected in TODO match
2142 tagsmatch selected in tags match
2143 diary imported from diary
2144 deadline a deadline on given date
2145 scheduled scheduled on given date
2146 timestamp entry has timestamp on given date
2147 closed entry was closed on given date
2148 upcoming-deadline warning about deadline
2149 past-scheduled forwarded scheduled item
2150 block entry has date block including g. date
2151todo The todo keyword, if any
2152tags All tags including inherited ones, separated by colons
2153date The relevant date, like 2007-2-14
2154time The time, like 15:00-16:50
2155extra Sting with extra planning info
2156priority-l The priority letter if any was given
2157priority-n The computed numerical priority
2158agenda-day The day in the agenda where this is listed"
2159
2160 (let (pars)
2161 (while parameters
2162 (push (list (pop parameters) (if parameters (pop parameters))) pars))
2163 (push (list 'org-agenda-remove-tags t) pars)
2164 (if (> (length cmd-key) 2)
2165 (eval (list 'let (nreverse pars)
2166 (list 'org-tags-view nil cmd-key)))
2167 (eval (list 'let (nreverse pars) (list 'org-agenda nil cmd-key))))
2168 (set-buffer org-agenda-buffer-name)
2169 (let* ((lines (org-split-string (buffer-string) "\n"))
2170 line)
2171 (while (setq line (pop lines))
2172 (catch 'next
2173 (if (not (get-text-property 0 'org-category line)) (throw 'next nil))
2174 (setq org-agenda-info
2175 (org-fix-agenda-info (text-properties-at 0 line)))
2176 (princ
2177 (org-encode-for-stdout
2178 (mapconcat 'org-agenda-export-csv-mapper
2179 '(org-category txt type todo tags date time-of-day extra
2180 priority-letter priority agenda-day)
2181 ",")))
2182 (princ "\n"))))))
2183
2184(defun org-fix-agenda-info (props)
2185 "Make sure all properties on an agenda item have a canonical form,
2186so the export commands can easily use it."
2187 (let (tmp re)
2188 (when (setq tmp (plist-get props 'tags))
2189 (setq props (plist-put props 'tags (mapconcat 'identity tmp ":"))))
2190 (when (setq tmp (plist-get props 'date))
2191 (if (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
2192 (let ((calendar-date-display-form '(year "-" month "-" day)))
2193 '((format "%4d, %9s %2s, %4s" dayname monthname day year))
2194
2195 (setq tmp (calendar-date-string tmp)))
2196 (setq props (plist-put props 'date tmp)))
2197 (when (setq tmp (plist-get props 'day))
2198 (if (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
2199 (let ((calendar-date-display-form '(year "-" month "-" day)))
2200 (setq tmp (calendar-date-string tmp)))
2201 (setq props (plist-put props 'day tmp))
2202 (setq props (plist-put props 'agenda-day tmp)))
2203 (when (setq tmp (plist-get props 'txt))
2204 (when (string-match "\\[#\\([A-Z0-9]\\)\\] ?" tmp)
2205 (plist-put props 'priority-letter (match-string 1 tmp))
2206 (setq tmp (replace-match "" t t tmp)))
2207 (when (and (setq re (plist-get props 'org-todo-regexp))
2208 (setq re (concat "\\`\\.*" re " ?"))
2209 (string-match re tmp))
2210 (plist-put props 'todo (match-string 1 tmp))
2211 (setq tmp (replace-match "" t t tmp)))
2212 (plist-put props 'txt tmp)))
2213 props)
2214
2215(defun org-agenda-export-csv-mapper (prop)
2216 (let ((res (plist-get org-agenda-info prop)))
2217 (setq res
2218 (cond
2219 ((not res) "")
2220 ((stringp res) res)
2221 (t (prin1-to-string res))))
2222 (while (string-match "," res)
2223 (setq res (replace-match ";" t t res)))
2224 (org-trim res)))
2225
2226
2227;;;###autoload
2228(defun org-store-agenda-views (&rest parameters)
2229 (interactive)
2230 (eval (list 'org-batch-store-agenda-views)))
2231
2232;; FIXME, why is this a macro?????
2233;;;###autoload
2234(defmacro org-batch-store-agenda-views (&rest parameters)
2235 "Run all custom agenda commands that have a file argument."
2236 (let ((cmds (org-agenda-normalize-custom-commands org-agenda-custom-commands))
2237 (pop-up-frames nil)
2238 (dir default-directory)
2c3ad40d 2239 pars cmd thiscmdkey files opts cmd-or-set)
20908596
CD
2240 (while parameters
2241 (push (list (pop parameters) (if parameters (pop parameters))) pars))
2242 (setq pars (reverse pars))
2243 (save-window-excursion
2244 (while cmds
2245 (setq cmd (pop cmds)
2246 thiscmdkey (car cmd)
2c3ad40d
CD
2247 cmd-or-set (nth 2 cmd)
2248 opts (nth (if (listp cmd-or-set) 3 4) cmd)
2249 files (nth (if (listp cmd-or-set) 4 5) cmd))
20908596
CD
2250 (if (stringp files) (setq files (list files)))
2251 (when files
2252 (eval (list 'let (append org-agenda-exporter-settings opts pars)
2253 (list 'org-agenda nil thiscmdkey)))
2254 (set-buffer org-agenda-buffer-name)
2255 (while files
2256 (eval (list 'let (append org-agenda-exporter-settings opts pars)
2257 (list 'org-write-agenda
c8d0cf5c 2258 (expand-file-name (pop files) dir) nil t))))
20908596
CD
2259 (and (get-buffer org-agenda-buffer-name)
2260 (kill-buffer org-agenda-buffer-name)))))))
2261
8d642074
CD
2262(defun org-agenda-mark-header-line (pos)
2263 "Mark the line at POS as an agenda structure header."
2264 (save-excursion
2265 (goto-char pos)
2266 (put-text-property (point-at-bol) (point-at-eol)
2267 'org-agenda-structural-header t)
2268 (when org-agenda-title-append
2269 (put-text-property (point-at-bol) (point-at-eol)
2270 'org-agenda-title-append org-agenda-title-append))))
2271
8bfe682a 2272(defvar org-mobile-creating-agendas)
c8d0cf5c 2273(defun org-write-agenda (file &optional open nosettings)
20908596
CD
2274 "Write the current buffer (an agenda view) as a file.
2275Depending on the extension of the file name, plain text (.txt),
2276HTML (.html or .htm) or Postscript (.ps) is produced.
2277If the extension is .ics, run icalendar export over all files used
2278to construct the agenda and limit the export to entries listed in the
2279agenda now.
8bfe682a 2280With prefix argument OPEN, open the new file immediately.
20908596
CD
2281If NOSETTINGS is given, do not scope the settings of
2282`org-agenda-exporter-settings' into the export commands. This is used when
2283the settings have already been scoped and we do not wish to overrule other,
2284higher priority settings."
c8d0cf5c 2285 (interactive "FWrite agenda to file: \nP")
20908596
CD
2286 (if (not (file-writable-p file))
2287 (error "Cannot write agenda to file %s" file))
2288 (cond
2289 ((string-match "\\.html?\\'" file) (require 'htmlize))
2290 ((string-match "\\.ps\\'" file) (require 'ps-print)))
2291 (org-let (if nosettings nil org-agenda-exporter-settings)
2292 '(save-excursion
2293 (save-window-excursion
93b62de8 2294 (org-agenda-mark-filtered-text)
8bfe682a 2295 (let ((bs (copy-sequence (buffer-string))) beg)
93b62de8
CD
2296 (org-agenda-unmark-filtered-text)
2297 (with-temp-buffer
20908596 2298 (insert bs)
93b62de8
CD
2299 (org-agenda-remove-marked-text 'org-filtered)
2300 (while (setq beg (text-property-any (point-min) (point-max)
2301 'org-filtered t))
2302 (delete-region
2303 beg (or (next-single-property-change beg 'org-filtered)
2304 (point-max))))
c8d0cf5c 2305 (run-hooks 'org-agenda-before-write-hook)
93b62de8 2306 (cond
8bfe682a
CD
2307 ((org-bound-and-true-p org-mobile-creating-agendas)
2308 (org-mobile-write-agenda-for-mobile file))
93b62de8
CD
2309 ((string-match "\\.html?\\'" file)
2310 (set-buffer (htmlize-buffer (current-buffer)))
ff4be292 2311
93b62de8
CD
2312 (when (and org-agenda-export-html-style
2313 (string-match "<style>" org-agenda-export-html-style))
2314 ;; replace <style> section with org-agenda-export-html-style
2315 (goto-char (point-min))
2316 (kill-region (- (search-forward "<style") 6)
2317 (search-forward "</style>"))
2318 (insert org-agenda-export-html-style))
2319 (write-file file)
2320 (kill-buffer (current-buffer))
2321 (message "HTML written to %s" file))
2322 ((string-match "\\.ps\\'" file)
c8d0cf5c
CD
2323 (require 'ps-print)
2324 (flet ((ps-get-buffer-name () "Agenda View"))
2325 (ps-print-buffer-with-faces file))
93b62de8 2326 (message "Postscript written to %s" file))
c8d0cf5c
CD
2327 ((string-match "\\.pdf\\'" file)
2328 (require 'ps-print)
2329 (flet ((ps-get-buffer-name () "Agenda View"))
2330 (ps-print-buffer-with-faces
2331 (concat (file-name-sans-extension file) ".ps")))
2332 (call-process "ps2pdf" nil nil nil
2333 (expand-file-name
2334 (concat (file-name-sans-extension file) ".ps"))
2335 (expand-file-name file))
2336 (message "PDF written to %s" file))
93b62de8 2337 ((string-match "\\.ics\\'" file)
c8d0cf5c 2338 (require 'org-icalendar)
93b62de8
CD
2339 (let ((org-agenda-marker-table
2340 (org-create-marker-find-array
2341 (org-agenda-collect-markers)))
2342 (org-icalendar-verify-function 'org-check-agenda-marker-table)
2343 (org-combined-agenda-icalendar-file file))
2344 (apply 'org-export-icalendar 'combine
2345 (org-agenda-files nil 'ifmode))))
2346 (t
2347 (let ((bs (buffer-string)))
2348 (find-file file)
2349 (erase-buffer)
2350 (insert bs)
2351 (save-buffer 0)
2352 (kill-buffer (current-buffer))
2353 (message "Plain text written to %s" file))))))))
c8d0cf5c
CD
2354 (set-buffer org-agenda-buffer-name))
2355 (when open (org-open-file file)))
2356
93b62de8
CD
2357(defvar org-agenda-filter-overlays nil)
2358
2359(defun org-agenda-mark-filtered-text ()
2360 "Mark all text hidden by filtering with a text property."
2361 (let ((inhibit-read-only t))
2362 (mapc
2363 (lambda (o)
2364 (when (equal (org-overlay-buffer o) (current-buffer))
2365 (put-text-property
2366 (org-overlay-start o) (org-overlay-end o)
2367 'org-filtered t)))
2368 org-agenda-filter-overlays)))
2369
2370(defun org-agenda-unmark-filtered-text ()
2371 "Remove the filtering text property."
2372 (let ((inhibit-read-only t))
2373 (remove-text-properties (point-min) (point-max) '(org-filtered t))))
2374
2375(defun org-agenda-remove-marked-text (property &optional value)
2376 "Delete all text marked with VALUE of PROPERTY.
2377VALUE defaults to t."
2378 (let (beg)
2379 (setq value (or value t))
2380 (while (setq beg (text-property-any (point-min) (point-max)
2381 property value))
2382 (delete-region
2383 beg (or (next-single-property-change beg 'org-filtered)
2384 (point-max))))))
20908596 2385
c8d0cf5c
CD
2386(defun org-agenda-add-entry-text ()
2387 "Add entry text to agenda lines.
2388This will add a maximum of `org-agenda-add-entry-text-maxlines' lines of the
2389entry text following headings shown in the agenda.
2390Drawers will be excluded, also the line with scheduling/deadline info."
8bfe682a
CD
2391 (when (and (> org-agenda-add-entry-text-maxlines 0)
2392 (not (org-bound-and-true-p org-mobile-creating-agendas)))
54a0dee5 2393 (let (m txt)
c8d0cf5c
CD
2394 (goto-char (point-min))
2395 (while (not (eobp))
8d642074 2396 (if (not (setq m (org-get-at-bol 'org-hd-marker)))
c8d0cf5c 2397 (beginning-of-line 2)
54a0dee5 2398 (setq txt (org-agenda-get-some-entry-text
8d642074 2399 m org-agenda-add-entry-text-maxlines " > "))
c8d0cf5c
CD
2400 (end-of-line 1)
2401 (if (string-match "\\S-" txt) (insert "\n" txt)))))))
2402
8d642074
CD
2403(defun org-agenda-get-some-entry-text (marker n-lines &optional indent
2404 &rest keep)
54a0dee5 2405 "Extract entry text from MARKER, at most N-LINES lines.
8d642074
CD
2406This will ignore drawers etc, just get the text.
2407If INDENT is given, prefix every line with this string. If KEEP is
8bfe682a 2408given, it is a list of symbols, defining stuff that should not be
8d642074 2409removed from the entry content. Currently only `planning' is allowed here."
54a0dee5
CD
2410 (let (txt drawer-re kwd-time-re ind)
2411 (save-excursion
2412 (with-current-buffer (marker-buffer marker)
2413 (if (not (org-mode-p))
2414 (setq txt "")
2415 (save-excursion
2416 (save-restriction
2417 (widen)
2418 (goto-char marker)
8d642074 2419 (end-of-line 1)
54a0dee5 2420 (setq txt (buffer-substring
8d642074 2421 (min (1+ (point)) (point-max))
54a0dee5
CD
2422 (progn (outline-next-heading) (point)))
2423 drawer-re org-drawer-regexp
2424 kwd-time-re (concat "^[ \t]*" org-keyword-time-regexp
2425 ".*\n?"))
2426 (with-temp-buffer
2427 (insert txt)
2428 (when org-agenda-add-entry-text-descriptive-links
2429 (goto-char (point-min))
2430 (while (org-activate-bracket-links (point-max))
2431 (add-text-properties (match-beginning 0) (match-end 0)
2432 '(face org-link))))
2433 (goto-char (point-min))
2434 (while (re-search-forward org-bracket-link-regexp (point-max) t)
2435 (set-text-properties (match-beginning 0) (match-end 0)
2436 nil))
2437 (goto-char (point-min))
2438 (while (re-search-forward drawer-re nil t)
2439 (delete-region
2440 (match-beginning 0)
2441 (progn (re-search-forward
2442 "^[ \t]*:END:.*\n?" nil 'move)
2443 (point))))
8d642074
CD
2444 (unless (member 'planning keep)
2445 (goto-char (point-min))
2446 (while (re-search-forward kwd-time-re nil t)
2447 (replace-match "")))
54a0dee5 2448 (goto-char (point-min))
8d642074
CD
2449 (when org-agenda-entry-text-exclude-regexps
2450 (let ((re-list org-agenda-entry-text-exclude-regexps) re)
2451 (while (setq re (pop re-list))
2452 (goto-char (point-min))
2453 (while (re-search-forward re nil t)
2454 (replace-match "")))))
2455 (goto-char (point-max))
2456 (skip-chars-backward " \t\n")
2457 (if (looking-at "[ \t\n]+\\'") (replace-match ""))
2458
2459 ;; find and remove min common indentation
54a0dee5
CD
2460 (goto-char (point-min))
2461 (untabify (point-min) (point-max))
2462 (setq ind (org-get-indentation))
2463 (while (not (eobp))
2464 (unless (looking-at "[ \t]*$")
2465 (setq ind (min ind (org-get-indentation))))
2466 (beginning-of-line 2))
2467 (goto-char (point-min))
2468 (while (not (eobp))
2469 (unless (looking-at "[ \t]*$")
2470 (move-to-column ind)
2471 (delete-region (point-at-bol) (point)))
2472 (beginning-of-line 2))
8d642074
CD
2473
2474 (run-hooks 'org-agenda-entry-text-cleanup-hook)
2475
54a0dee5 2476 (goto-char (point-min))
8d642074
CD
2477 (when indent
2478 (while (and (not (eobp)) (re-search-forward "^" nil t))
2479 (replace-match indent t t)))
54a0dee5
CD
2480 (goto-char (point-min))
2481 (while (looking-at "[ \t]*\n") (replace-match ""))
2482 (goto-char (point-max))
2483 (when (> (org-current-line)
2484 n-lines)
2485 (org-goto-line (1+ n-lines))
2486 (backward-char 1))
2487 (setq txt (buffer-substring (point-min) (point)))))))))
2488 txt))
2489
20908596
CD
2490(defun org-agenda-collect-markers ()
2491 "Collect the markers pointing to entries in the agenda buffer."
2492 (let (m markers)
2493 (save-excursion
2494 (goto-char (point-min))
2495 (while (not (eobp))
8d642074
CD
2496 (when (setq m (or (org-get-at-bol 'org-hd-marker)
2497 (org-get-at-bol 'org-marker)))
20908596
CD
2498 (push m markers))
2499 (beginning-of-line 2)))
2500 (nreverse markers)))
2501
2502(defun org-create-marker-find-array (marker-list)
2503 "Create a alist of files names with all marker positions in that file."
2504 (let (f tbl m a p)
2505 (while (setq m (pop marker-list))
2506 (setq p (marker-position m)
2507 f (buffer-file-name (or (buffer-base-buffer
2508 (marker-buffer m))
2509 (marker-buffer m))))
2510 (if (setq a (assoc f tbl))
2511 (push (marker-position m) (cdr a))
2512 (push (list f p) tbl)))
2513 (mapcar (lambda (x) (setcdr x (sort (copy-sequence (cdr x)) '<)) x)
2514 tbl)))
2515
33306645 2516(defvar org-agenda-marker-table nil) ; dynamically scoped parameter
20908596
CD
2517(defun org-check-agenda-marker-table ()
2518 "Check of the current entry is on the marker list."
2519 (let ((file (buffer-file-name (or (buffer-base-buffer) (current-buffer))))
2520 a)
2521 (and (setq a (assoc file org-agenda-marker-table))
2522 (save-match-data
2523 (save-excursion
2524 (org-back-to-heading t)
2525 (member (point) (cdr a)))))))
2526
2527(defun org-check-for-org-mode ()
2528 "Make sure current buffer is in org-mode. Error if not."
2529 (or (org-mode-p)
f924a367 2530 (error "Cannot execute org-mode agenda command on buffer in %s"
20908596
CD
2531 major-mode)))
2532
2533(defun org-fit-agenda-window ()
2534 "Fit the window to the buffer size."
2535 (and (memq org-agenda-window-setup '(reorganize-frame))
2536 (fboundp 'fit-window-to-buffer)
93b62de8 2537 (org-fit-window-to-buffer
20908596
CD
2538 nil
2539 (floor (* (frame-height) (cdr org-agenda-window-frame-fractions)))
2540 (floor (* (frame-height) (car org-agenda-window-frame-fractions))))))
2541
2542;;; Agenda prepare and finalize
2543
33306645 2544(defvar org-agenda-multi nil) ; dynamically scoped
20908596
CD
2545(defvar org-agenda-buffer-name "*Org Agenda*")
2546(defvar org-pre-agenda-window-conf nil)
2547(defvar org-agenda-columns-active nil)
2548(defvar org-agenda-name nil)
71d35b24 2549(defvar org-agenda-filter nil)
c8d0cf5c
CD
2550(defvar org-agenda-filter-preset nil
2551 "A preset of the tags filter used for secondary agenda filtering.
2552This must be a list of strings, each string must be a single tag preceeded
2553by \"+\" or \"-\".
2554This variable should not be set directly, but agenda custom commands can
2555bind it in the options section.")
2556
20908596
CD
2557(defun org-prepare-agenda (&optional name)
2558 (setq org-todo-keywords-for-agenda nil)
2559 (setq org-done-keywords-for-agenda nil)
8d642074 2560 (setq org-drawers-for-agenda nil)
71d35b24 2561 (setq org-agenda-filter nil)
c8d0cf5c 2562 (put 'org-agenda-filter :preset-filter org-agenda-filter-preset)
20908596
CD
2563 (if org-agenda-multi
2564 (progn
2565 (setq buffer-read-only nil)
2566 (goto-char (point-max))
2567 (unless (or (bobp) org-agenda-compact-blocks)
0bd48b37
CD
2568 (insert "\n"
2569 (if (stringp org-agenda-block-separator)
2570 org-agenda-block-separator
2571 (make-string (window-width) org-agenda-block-separator))
2572 "\n"))
20908596
CD
2573 (narrow-to-region (point) (point-max)))
2574 (org-agenda-reset-markers)
2575 (setq org-agenda-contributing-files nil)
2576 (setq org-agenda-columns-active nil)
2c3ad40d 2577 (org-prepare-agenda-buffers (org-agenda-files nil 'ifmode))
20908596
CD
2578 (setq org-todo-keywords-for-agenda
2579 (org-uniquify org-todo-keywords-for-agenda))
2580 (setq org-done-keywords-for-agenda
2581 (org-uniquify org-done-keywords-for-agenda))
8d642074 2582 (setq org-drawers-for-agenda (org-uniquify org-drawers-for-agenda))
20908596
CD
2583 (let* ((abuf (get-buffer-create org-agenda-buffer-name))
2584 (awin (get-buffer-window abuf)))
2585 (cond
2586 ((equal (current-buffer) abuf) nil)
2587 (awin (select-window awin))
2588 ((not (setq org-pre-agenda-window-conf (current-window-configuration))))
2589 ((equal org-agenda-window-setup 'current-window)
2590 (switch-to-buffer abuf))
2591 ((equal org-agenda-window-setup 'other-window)
2592 (org-switch-to-buffer-other-window abuf))
2593 ((equal org-agenda-window-setup 'other-frame)
8d642074 2594 (switch-to-buffer-other-frame abuf))
20908596
CD
2595 ((equal org-agenda-window-setup 'reorganize-frame)
2596 (delete-other-windows)
2597 (org-switch-to-buffer-other-window abuf))))
2598 (setq buffer-read-only nil)
2599 (let ((inhibit-read-only t)) (erase-buffer))
2600 (org-agenda-mode)
2601 (and name (not org-agenda-name)
2602 (org-set-local 'org-agenda-name name)))
2603 (setq buffer-read-only nil))
2604
2605(defun org-finalize-agenda ()
2606 "Finishing touch for the agenda buffer, called just before displaying it."
2607 (unless org-agenda-multi
2608 (save-excursion
2609 (let ((inhibit-read-only t))
2610 (goto-char (point-min))
2611 (while (org-activate-bracket-links (point-max))
2612 (add-text-properties (match-beginning 0) (match-end 0)
2613 '(face org-link)))
2614 (org-agenda-align-tags)
2615 (unless org-agenda-with-colors
2616 (remove-text-properties (point-min) (point-max) '(face nil))))
33306645
CD
2617 (if (and (boundp 'org-agenda-overriding-columns-format)
2618 org-agenda-overriding-columns-format)
2619 (org-set-local 'org-agenda-overriding-columns-format
2620 org-agenda-overriding-columns-format))
20908596
CD
2621 (if (and (boundp 'org-agenda-view-columns-initially)
2622 org-agenda-view-columns-initially)
2623 (org-agenda-columns))
2624 (when org-agenda-fontify-priorities
c8d0cf5c 2625 (org-agenda-fontify-priorities))
d6685abc
CD
2626 (when (and org-agenda-dim-blocked-tasks org-blocker-hook)
2627 (org-agenda-dim-blocked-tasks))
54a0dee5
CD
2628 (org-agenda-mark-clocking-task)
2629 (when org-agenda-entry-text-mode
2630 (org-agenda-entry-text-hide)
f924a367 2631 (org-agenda-entry-text-show))
8bfe682a
CD
2632 (if (functionp 'org-habit-insert-consistency-graphs)
2633 (org-habit-insert-consistency-graphs))
20908596 2634 (run-hooks 'org-finalize-agenda-hook)
8d642074 2635 (setq org-agenda-type (org-get-at-bol 'org-agenda-type))
c8d0cf5c
CD
2636 (when (get 'org-agenda-filter :preset-filter)
2637 (org-agenda-filter-apply org-agenda-filter))
20908596
CD
2638 )))
2639
54a0dee5
CD
2640(defun org-agenda-mark-clocking-task ()
2641 "Mark the current clock entry in the agenda if it is present."
2642 (mapc (lambda (o)
2643 (if (eq (org-overlay-get o 'type) 'org-agenda-clocking)
2644 (org-delete-overlay o)))
2645 (org-overlays-in (point-min) (point-max)))
2646 (when (marker-buffer org-clock-hd-marker)
2647 (save-excursion
2648 (goto-char (point-min))
2649 (let (s ov)
2650 (while (setq s (next-single-property-change (point) 'org-hd-marker))
2651 (goto-char s)
8d642074 2652 (when (equal (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
2653 org-clock-hd-marker)
2654 (setq ov (org-make-overlay (point-at-bol) (1+ (point-at-eol))))
2655 (org-overlay-put ov 'type 'org-agenda-clocking)
2656 (org-overlay-put ov 'face 'org-agenda-clocking)
2657 (org-overlay-put ov 'help-echo
2658 "The clock is running in this item")))))))
2659
c8d0cf5c 2660(defun org-agenda-fontify-priorities ()
20908596
CD
2661 "Make highest priority lines bold, and lowest italic."
2662 (interactive)
2663 (mapc (lambda (o) (if (eq (org-overlay-get o 'org-type) 'org-priority)
2664 (org-delete-overlay o)))
2665 (org-overlays-in (point-min) (point-max)))
2666 (save-excursion
2667 (let ((inhibit-read-only t)
2668 b e p ov h l)
2669 (goto-char (point-min))
2670 (while (re-search-forward "\\[#\\(.\\)\\]" nil t)
2671 (setq h (or (get-char-property (point) 'org-highest-priority)
2672 org-highest-priority)
2673 l (or (get-char-property (point) 'org-lowest-priority)
2674 org-lowest-priority)
2675 p (string-to-char (match-string 1))
c8d0cf5c
CD
2676 b (match-beginning 0)
2677 e (if (eq org-agenda-fontify-priorities 'cookies)
2678 (match-end 0)
2679 (point-at-eol))
20908596
CD
2680 ov (org-make-overlay b e))
2681 (org-overlay-put
2682 ov 'face
c8d0cf5c
CD
2683 (cond ((cdr (assoc p org-priority-faces)))
2684 ((and (listp org-agenda-fontify-priorities)
2685 (cdr (assoc p org-agenda-fontify-priorities))))
20908596
CD
2686 ((equal p l) 'italic)
2687 ((equal p h) 'bold)))
2688 (org-overlay-put ov 'org-type 'org-priority)))))
2689
d6685abc
CD
2690(defun org-agenda-dim-blocked-tasks ()
2691 "Dim currently blocked TODO's in the agenda display."
2692 (mapc (lambda (o) (if (eq (org-overlay-get o 'org-type) 'org-blocked-todo)
2693 (org-delete-overlay o)))
2694 (org-overlays-in (point-min) (point-max)))
2695 (save-excursion
2696 (let ((inhibit-read-only t)
72d06d81 2697 (org-depend-tag-blocked nil)
d6685abc 2698 (invis (eq org-agenda-dim-blocked-tasks 'invisible))
c8d0cf5c
CD
2699 org-blocked-by-checkboxes
2700 invis1 b e p ov h l)
d6685abc
CD
2701 (goto-char (point-min))
2702 (while (let ((pos (next-single-property-change (point) 'todo-state)))
2703 (and pos (goto-char (1+ pos))))
c8d0cf5c 2704 (setq org-blocked-by-checkboxes nil invis1 invis)
8d642074 2705 (let ((marker (org-get-at-bol 'org-hd-marker)))
d6685abc
CD
2706 (when (and marker
2707 (not (with-current-buffer (marker-buffer marker)
2708 (save-excursion
2709 (goto-char marker)
c8d0cf5c
CD
2710 (if (org-entry-get nil "NOBLOCKING")
2711 t ;; Never block this entry
2712 (run-hook-with-args-until-failure
2713 'org-blocker-hook
2714 (list :type 'todo-state-change
2715 :position marker
2716 :from 'todo
2717 :to 'done)))))))
2718 (if org-blocked-by-checkboxes (setq invis1 nil))
53e31a31
CD
2719 (setq b (if invis1
2720 (max (point-min) (1- (point-at-bol)))
2721 (point-at-bol))
d6685abc
CD
2722 e (point-at-eol)
2723 ov (org-make-overlay b e))
c8d0cf5c 2724 (if invis1
d6685abc
CD
2725 (org-overlay-put ov 'invisible t)
2726 (org-overlay-put ov 'face 'org-agenda-dimmed-todo-face))
2727 (org-overlay-put ov 'org-type 'org-blocked-todo)))))))
20908596
CD
2728
2729(defvar org-agenda-skip-function nil
2730 "Function to be called at each match during agenda construction.
2731If this function returns nil, the current match should not be skipped.
2732Otherwise, the function must return a position from where the search
2733should be continued.
2734This may also be a Lisp form, it will be evaluated.
2735Never set this variable using `setq' or so, because then it will apply
2736to all future agenda commands. Instead, bind it with `let' to scope
2737it dynamically into the agenda-constructing command. A good way to set
2738it is through options in org-agenda-custom-commands.")
2739
2740(defun org-agenda-skip ()
2741 "Throw to `:skip' in places that should be skipped.
2742Also moves point to the end of the skipped region, so that search can
2743continue from there."
2744 (let ((p (point-at-bol)) to fp)
2c3ad40d 2745 (and org-agenda-skip-archived-trees (not org-agenda-archives-mode)
20908596
CD
2746 (get-text-property p :org-archived)
2747 (org-end-of-subtree t)
2748 (throw :skip t))
b349f79f
CD
2749 (and org-agenda-skip-comment-trees
2750 (get-text-property p :org-comment)
20908596
CD
2751 (org-end-of-subtree t)
2752 (throw :skip t))
2753 (if (equal (char-after p) ?#) (throw :skip t))
2754 (when (and (or (setq fp (functionp org-agenda-skip-function))
2755 (consp org-agenda-skip-function))
2756 (setq to (save-excursion
2757 (save-match-data
2758 (if fp
2759 (funcall org-agenda-skip-function)
2760 (eval org-agenda-skip-function))))))
2761 (goto-char to)
2762 (throw :skip t))))
2763
2764(defvar org-agenda-markers nil
2765 "List of all currently active markers created by `org-agenda'.")
54a0dee5 2766(defvar org-agenda-last-marker-time (org-float-time)
20908596
CD
2767 "Creation time of the last agenda marker.")
2768
2769(defun org-agenda-new-marker (&optional pos)
2770 "Return a new agenda marker.
2771Org-mode keeps a list of these markers and resets them when they are
2772no longer in use."
2773 (let ((m (copy-marker (or pos (point)))))
54a0dee5 2774 (setq org-agenda-last-marker-time (org-float-time))
20908596
CD
2775 (push m org-agenda-markers)
2776 m))
2777
2778(defun org-agenda-reset-markers ()
2779 "Reset markers created by `org-agenda'."
2780 (while org-agenda-markers
2781 (move-marker (pop org-agenda-markers) nil)))
2782
b349f79f
CD
2783(defun org-agenda-save-markers-for-cut-and-paste (beg end)
2784 "Save relative positions of markers in region."
2785 (mapc (lambda (m) (org-check-and-save-marker m beg end))
2786 org-agenda-markers))
2787
54a0dee5
CD
2788;;; Entry text mode
2789
2790(defun org-agenda-entry-text-show-here ()
8bfe682a 2791 "Add some text from the entry as context to the current line."
54a0dee5 2792 (let (m txt o)
8d642074 2793 (setq m (org-get-at-bol 'org-hd-marker))
54a0dee5
CD
2794 (unless (marker-buffer m)
2795 (error "No marker points to an entry here"))
2796 (setq txt (concat "\n" (org-no-properties
2797 (org-agenda-get-some-entry-text
8d642074 2798 m org-agenda-entry-text-maxlines " > "))))
54a0dee5
CD
2799 (when (string-match "\\S-" txt)
2800 (setq o (org-make-overlay (point-at-bol) (point-at-eol)))
2801 (org-overlay-put o 'evaporate t)
2802 (org-overlay-put o 'org-overlay-type 'agenda-entry-content)
2803 (org-overlay-put o 'after-string txt))))
2804
2805(defun org-agenda-entry-text-show ()
2806 "Add entry context for all agenda lines."
2807 (interactive)
2808 (save-excursion
2809 (goto-char (point-max))
2810 (beginning-of-line 1)
2811 (while (not (bobp))
8d642074 2812 (when (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
2813 (org-agenda-entry-text-show-here))
2814 (beginning-of-line 0))))
2815
2816(defun org-agenda-entry-text-hide ()
2817 "Remove any shown entry context."
2818 (delq nil
2819 (mapcar (lambda (o)
2820 (if (eq (org-overlay-get o 'org-overlay-type)
2821 'agenda-entry-content)
2822 (progn (org-delete-overlay o) t)))
2823 (org-overlays-in (point-min) (point-max)))))
2824
20908596
CD
2825;;; Agenda timeline
2826
2827(defvar org-agenda-only-exact-dates nil) ; dynamically scoped
2828
2829(defun org-timeline (&optional include-all)
2830 "Show a time-sorted view of the entries in the current org file.
2831Only entries with a time stamp of today or later will be listed. With
2832\\[universal-argument] prefix, all unfinished TODO items will also be shown,
2833under the current date.
2834If the buffer contains an active region, only check the region for
2835dates."
2836 (interactive "P")
2837 (require 'calendar)
2838 (org-compile-prefix-format 'timeline)
2839 (org-set-sorting-strategy 'timeline)
2840 (let* ((dopast t)
2841 (dotodo include-all)
2842 (doclosed org-agenda-show-log)
2843 (entry buffer-file-name)
2844 (date (calendar-current-date))
2845 (beg (if (org-region-active-p) (region-beginning) (point-min)))
2846 (end (if (org-region-active-p) (region-end) (point-max)))
2847 (day-numbers (org-get-all-dates beg end 'no-ranges
2848 t doclosed ; always include today
2849 org-timeline-show-empty-dates))
2850 (org-deadline-warning-days 0)
2851 (org-agenda-only-exact-dates t)
2852 (today (time-to-days (current-time)))
2853 (past t)
2854 args
2855 s e rtn d emptyp wd)
2856 (setq org-agenda-redo-command
2857 (list 'progn
2858 (list 'org-switch-to-buffer-other-window (current-buffer))
2859 (list 'org-timeline (list 'quote include-all))))
2860 (if (not dopast)
2861 ;; Remove past dates from the list of dates.
2862 (setq day-numbers (delq nil (mapcar (lambda(x)
2863 (if (>= x today) x nil))
2864 day-numbers))))
2865 (org-prepare-agenda (concat "Timeline "
2866 (file-name-nondirectory buffer-file-name)))
2867 (if doclosed (push :closed args))
2868 (push :timestamp args)
2869 (push :deadline args)
2870 (push :scheduled args)
2871 (push :sexp args)
2872 (if dotodo (push :todo args))
8d642074
CD
2873 (insert "Timeline of file " entry "\n")
2874 (add-text-properties (point-min) (point)
2875 (list 'face 'org-agenda-structure))
2876 (org-agenda-mark-header-line (point-min))
20908596
CD
2877 (while (setq d (pop day-numbers))
2878 (if (and (listp d) (eq (car d) :omitted))
2879 (progn
2880 (setq s (point))
2881 (insert (format "\n[... %d empty days omitted]\n\n" (cdr d)))
2882 (put-text-property s (1- (point)) 'face 'org-agenda-structure))
2883 (if (listp d) (setq d (car d) emptyp t) (setq emptyp nil))
2884 (if (and (>= d today)
2885 dopast
2886 past)
2887 (progn
2888 (setq past nil)
2889 (insert (make-string 79 ?-) "\n")))
2890 (setq date (calendar-gregorian-from-absolute d)
2891 wd (calendar-day-of-week date))
2892 (setq s (point))
2893 (setq rtn (and (not emptyp)
2894 (apply 'org-agenda-get-day-entries entry
2895 date args)))
2896 (if (or rtn (equal d today) org-timeline-show-empty-dates)
2897 (progn
2898 (insert
2899 (if (stringp org-agenda-format-date)
2900 (format-time-string org-agenda-format-date
2901 (org-time-from-absolute date))
2902 (funcall org-agenda-format-date date))
2903 "\n")
2904 (put-text-property s (1- (point)) 'face
2905 (if (member wd org-agenda-weekend-days)
2906 'org-agenda-date-weekend
2907 'org-agenda-date))
2908 (put-text-property s (1- (point)) 'org-date-line t)
8d642074 2909 (put-text-property s (1- (point)) 'org-agenda-date-header t)
20908596
CD
2910 (if (equal d today)
2911 (put-text-property s (1- (point)) 'org-today t))
2912 (and rtn (insert (org-finalize-agenda-entries rtn) "\n"))
2913 (put-text-property s (1- (point)) 'day d)))))
2914 (goto-char (point-min))
2915 (goto-char (or (text-property-any (point-min) (point-max) 'org-today t)
2916 (point-min)))
2917 (add-text-properties (point-min) (point-max) '(org-agenda-type timeline))
2918 (org-finalize-agenda)
2919 (setq buffer-read-only t)))
2920
2921(defun org-get-all-dates (beg end &optional no-ranges force-today inactive empty pre-re)
2922 "Return a list of all relevant day numbers from BEG to END buffer positions.
2923If NO-RANGES is non-nil, include only the start and end dates of a range,
2924not every single day in the range. If FORCE-TODAY is non-nil, make
2925sure that TODAY is included in the list. If INACTIVE is non-nil, also
2926inactive time stamps (those in square brackets) are included.
2927When EMPTY is non-nil, also include days without any entries."
2928 (let ((re (concat
2929 (if pre-re pre-re "")
2930 (if inactive org-ts-regexp-both org-ts-regexp)))
2931 dates dates1 date day day1 day2 ts1 ts2)
2932 (if force-today
2933 (setq dates (list (time-to-days (current-time)))))
2934 (save-excursion
2935 (goto-char beg)
2936 (while (re-search-forward re end t)
2937 (setq day (time-to-days (org-time-string-to-time
2938 (substring (match-string 1) 0 10))))
2939 (or (memq day dates) (push day dates)))
2940 (unless no-ranges
2941 (goto-char beg)
2942 (while (re-search-forward org-tr-regexp end t)
2943 (setq ts1 (substring (match-string 1) 0 10)
2944 ts2 (substring (match-string 2) 0 10)
2945 day1 (time-to-days (org-time-string-to-time ts1))
2946 day2 (time-to-days (org-time-string-to-time ts2)))
2947 (while (< (setq day1 (1+ day1)) day2)
2948 (or (memq day1 dates) (push day1 dates)))))
2949 (setq dates (sort dates '<))
2950 (when empty
2951 (while (setq day (pop dates))
2952 (setq day2 (car dates))
2953 (push day dates1)
2954 (when (and day2 empty)
2955 (if (or (eq empty t)
2956 (and (numberp empty) (<= (- day2 day) empty)))
2957 (while (< (setq day (1+ day)) day2)
2958 (push (list day) dates1))
2959 (push (cons :omitted (- day2 day)) dates1))))
2960 (setq dates (nreverse dates1)))
2961 dates)))
2962
2963;;; Agenda Daily/Weekly
2964
2965(defvar org-agenda-overriding-arguments nil) ; dynamically scoped parameter
c8d0cf5c
CD
2966(defvar org-agenda-start-day nil ; dynamically scoped parameter
2967"Custom commands can set this variable in the options section.")
20908596
CD
2968(defvar org-agenda-last-arguments nil
2969 "The arguments of the previous call to org-agenda")
2970(defvar org-starting-day nil) ; local variable in the agenda buffer
2971(defvar org-agenda-span nil) ; local variable in the agenda buffer
2972(defvar org-include-all-loc nil) ; local variable
2973(defvar org-agenda-remove-date nil) ; dynamically scoped FIXME: not used???
2974
2975;;;###autoload
2976(defun org-agenda-list (&optional include-all start-day ndays)
2977 "Produce a daily/weekly view from all files in variable `org-agenda-files'.
2978The view will be for the current day or week, but from the overview buffer
2979you will be able to go to other days/weeks.
2980
2981With one \\[universal-argument] prefix argument INCLUDE-ALL,
2982all unfinished TODO items will also be shown, before the agenda.
2983This feature is considered obsolete, please use the TODO list or a block
2984agenda instead.
2985
2986With a numeric prefix argument in an interactive call, the agenda will
2987span INCLUDE-ALL days. Lisp programs should instead specify NDAYS to change
2988the number of days. NDAYS defaults to `org-agenda-ndays'.
2989
2990START-DAY defaults to TODAY, or to the most recent match for the weekday
2991given in `org-agenda-start-on-weekday'."
2992 (interactive "P")
2993 (if (and (integerp include-all) (> include-all 0))
2994 (setq ndays include-all include-all nil))
2995 (setq ndays (or ndays org-agenda-ndays)
2996 start-day (or start-day org-agenda-start-day))
2997 (if org-agenda-overriding-arguments
2998 (setq include-all (car org-agenda-overriding-arguments)
2999 start-day (nth 1 org-agenda-overriding-arguments)
3000 ndays (nth 2 org-agenda-overriding-arguments)))
3001 (if (stringp start-day)
3002 ;; Convert to an absolute day number
3003 (setq start-day (time-to-days (org-read-date nil t start-day))))
3004 (setq org-agenda-last-arguments (list include-all start-day ndays))
3005 (org-compile-prefix-format 'agenda)
3006 (org-set-sorting-strategy 'agenda)
3007 (require 'calendar)
3008 (let* ((org-agenda-start-on-weekday
3009 (if (or (equal ndays 7) (and (null ndays) (equal 7 org-agenda-ndays)))
3010 org-agenda-start-on-weekday nil))
2c3ad40d 3011 (thefiles (org-agenda-files nil 'ifmode))
20908596
CD
3012 (files thefiles)
3013 (today (time-to-days
3014 (time-subtract (current-time)
3015 (list 0 (* 3600 org-extend-today-until) 0))))
3016 (sd (or start-day today))
3017 (start (if (or (null org-agenda-start-on-weekday)
3018 (< org-agenda-ndays 7))
3019 sd
3020 (let* ((nt (calendar-day-of-week
3021 (calendar-gregorian-from-absolute sd)))
3022 (n1 org-agenda-start-on-weekday)
3023 (d (- nt n1)))
3024 (- sd (+ (if (< d 0) 7 0) d)))))
3025 (day-numbers (list start))
3026 (day-cnt 0)
3027 (inhibit-redisplay (not debug-on-error))
3028 s e rtn rtnall file date d start-pos end-pos todayp nd wd
3029 clocktable-start clocktable-end)
3030 (setq org-agenda-redo-command
3031 (list 'org-agenda-list (list 'quote include-all) start-day ndays))
3032 ;; Make the list of days
3033 (setq ndays (or ndays org-agenda-ndays)
3034 nd ndays)
3035 (while (> ndays 1)
3036 (push (1+ (car day-numbers)) day-numbers)
3037 (setq ndays (1- ndays)))
3038 (setq day-numbers (nreverse day-numbers))
3039 (setq clocktable-start (car day-numbers)
3040 clocktable-end (1+ (or (org-last day-numbers) 0)))
3041 (org-prepare-agenda "Day/Week")
3042 (org-set-local 'org-starting-day (car day-numbers))
3043 (org-set-local 'org-include-all-loc include-all)
3044 (org-set-local 'org-agenda-span
3045 (org-agenda-ndays-to-span nd))
3046 (when (and (or include-all org-agenda-include-all-todo)
3047 (member today day-numbers))
3048 (setq files thefiles
3049 rtnall nil)
3050 (while (setq file (pop files))
3051 (catch 'nextfile
3052 (org-check-agenda-file file)
3053 (setq date (calendar-gregorian-from-absolute today)
3054 rtn (org-agenda-get-day-entries
3055 file date :todo))
3056 (setq rtnall (append rtnall rtn))))
3057 (when rtnall
8d642074 3058 (insert "All currently open TODO items:\n")
20908596 3059 (add-text-properties (point-min) (1- (point))
8d642074
CD
3060 (list 'face 'org-agenda-structure
3061 'short-heading "All TODO items"))
8bfe682a 3062 (org-agenda-mark-header-line (point-min))
20908596
CD
3063 (insert (org-finalize-agenda-entries rtnall) "\n")))
3064 (unless org-agenda-compact-blocks
3065 (let* ((d1 (car day-numbers))
3066 (d2 (org-last day-numbers))
3067 (w1 (org-days-to-iso-week d1))
3068 (w2 (org-days-to-iso-week d2)))
3069 (setq s (point))
c8d0cf5c
CD
3070 (if org-agenda-overriding-header
3071 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
3072 nil 'face 'org-agenda-structure) "\n")
3073 (insert (capitalize (symbol-name (org-agenda-ndays-to-span nd)))
3074 "-agenda"
3075 (if (< (- d2 d1) 350)
3076 (if (= w1 w2)
3077 (format " (W%02d)" w1)
3078 (format " (W%02d-W%02d)" w1 w2))
3079 "")
3080 ":\n")))
20908596 3081 (add-text-properties s (1- (point)) (list 'face 'org-agenda-structure
8d642074
CD
3082 'org-date-line t))
3083 (org-agenda-mark-header-line s))
20908596
CD
3084 (while (setq d (pop day-numbers))
3085 (setq date (calendar-gregorian-from-absolute d)
3086 wd (calendar-day-of-week date)
3087 s (point))
3088 (if (or (setq todayp (= d today))
3089 (and (not start-pos) (= d sd)))
3090 (setq start-pos (point))
3091 (if (and start-pos (not end-pos))
3092 (setq end-pos (point))))
3093 (setq files thefiles
3094 rtnall nil)
3095 (while (setq file (pop files))
3096 (catch 'nextfile
3097 (org-check-agenda-file file)
93b62de8
CD
3098 (cond
3099 ((eq org-agenda-show-log 'only)
3100 (setq rtn (org-agenda-get-day-entries
3101 file date :closed)))
3102 (org-agenda-show-log
3103 (setq rtn (org-agenda-get-day-entries
3104 file date
3105 :deadline :scheduled :timestamp :sexp :closed)))
3106 (t
20908596
CD
3107 (setq rtn (org-agenda-get-day-entries
3108 file date
93b62de8 3109 :deadline :scheduled :sexp :timestamp))))
20908596
CD
3110 (setq rtnall (append rtnall rtn))))
3111 (if org-agenda-include-diary
c8d0cf5c 3112 (let ((org-agenda-search-headline-for-time t))
20908596
CD
3113 (require 'diary-lib)
3114 (setq rtn (org-get-entries-from-diary date))
3115 (setq rtnall (append rtnall rtn))))
3116 (if (or rtnall org-agenda-show-all-dates)
3117 (progn
3118 (setq day-cnt (1+ day-cnt))
3119 (insert
3120 (if (stringp org-agenda-format-date)
3121 (format-time-string org-agenda-format-date
3122 (org-time-from-absolute date))
3123 (funcall org-agenda-format-date date))
3124 "\n")
3125 (put-text-property s (1- (point)) 'face
3126 (if (member wd org-agenda-weekend-days)
3127 'org-agenda-date-weekend
3128 'org-agenda-date))
3129 (put-text-property s (1- (point)) 'org-date-line t)
8d642074 3130 (put-text-property s (1- (point)) 'org-agenda-date-header t)
20908596 3131 (put-text-property s (1- (point)) 'org-day-cnt day-cnt)
c8d0cf5c
CD
3132 (when todayp
3133 (put-text-property s (1- (point)) 'org-today t)
3134 (put-text-property s (1- (point)) 'face 'org-agenda-date-today))
20908596
CD
3135 (if rtnall (insert
3136 (org-finalize-agenda-entries
3137 (org-agenda-add-time-grid-maybe
3138 rtnall nd todayp))
3139 "\n"))
3140 (put-text-property s (1- (point)) 'day d)
3141 (put-text-property s (1- (point)) 'org-day-cnt day-cnt))))
3142 (when (and org-agenda-clockreport-mode clocktable-start)
2c3ad40d 3143 (let ((org-agenda-files (org-agenda-files nil 'ifmode))
20908596
CD
3144 ;; the above line is to ensure the restricted range!
3145 (p org-agenda-clockreport-parameter-plist)
3146 tbl)
3147 (setq p (org-plist-delete p :block))
3148 (setq p (plist-put p :tstart clocktable-start))
3149 (setq p (plist-put p :tend clocktable-end))
3150 (setq p (plist-put p :scope 'agenda))
3151 (setq tbl (apply 'org-get-clocktable p))
3152 (insert tbl)))
3153 (goto-char (point-min))
c8d0cf5c 3154 (or org-agenda-multi (org-fit-agenda-window))
20908596
CD
3155 (unless (and (pos-visible-in-window-p (point-min))
3156 (pos-visible-in-window-p (point-max)))
3157 (goto-char (1- (point-max)))
3158 (recenter -1)
3159 (if (not (pos-visible-in-window-p (or start-pos 1)))
3160 (progn
3161 (goto-char (or start-pos 1))
3162 (recenter 1))))
3163 (goto-char (or start-pos 1))
3164 (add-text-properties (point-min) (point-max) '(org-agenda-type agenda))
3165 (org-finalize-agenda)
3166 (setq buffer-read-only t)
3167 (message "")))
3168
3169(defun org-agenda-ndays-to-span (n)
3170 (cond ((< n 7) 'day) ((= n 7) 'week) ((< n 32) 'month) (t 'year)))
3171
3172;;; Agenda word search
3173
3174(defvar org-agenda-search-history nil)
3175(defvar org-todo-only nil)
3176
3177(defvar org-search-syntax-table nil
3178 "Special syntax table for org-mode search.
3179In this table, we have single quotes not as word constituents, to
33306645 3180that when \"+Ameli\" is searched as a work, it will also match \"Ameli's\"")
20908596
CD
3181
3182(defun org-search-syntax-table ()
3183 (unless org-search-syntax-table
3184 (setq org-search-syntax-table (copy-syntax-table org-mode-syntax-table))
3185 (modify-syntax-entry ?' "." org-search-syntax-table)
3186 (modify-syntax-entry ?` "." org-search-syntax-table))
3187 org-search-syntax-table)
3188
3189;;;###autoload
3190(defun org-search-view (&optional todo-only string edit-at)
3191 "Show all entries that contain words or regular expressions.
3192If the first character of the search string is an asterisks,
3193search only the headlines.
3194
3195With optional prefix argument TODO-ONLY, only consider entries that are
3196TODO entries. The argument STRING can be used to pass a default search
3197string into this function. If EDIT-AT is non-nil, it means that the
3198user should get a chance to edit this string, with cursor at position
3199EDIT-AT.
3200
3201The search string is broken into \"words\" by splitting at whitespace.
8bfe682a
CD
3202Depending on the variable `org-agenda-search-view-search-words-only'
3203and on whether the first character in the search string is \"+\" or \"-\",
3204The string is then interpreted either as a substring with variable amounts
3205of whitespace, or as a list or individual words that should be matched.
3206
3207The default is a substring match, where each space in the search string
3208can expand to an arbitrary amount of whitespace, including newlines.
3209
3210If matching individual words, these words are then interpreted as a
3211boolean expression with logical AND. Words prefixed with a minus must
3212not occur in the entry. Words without a prefix or prefixed with a plus
3213must occur in the entry. Matching is case-insensitive and the words
3214are enclosed by word delimiters.
20908596
CD
3215
3216Words enclosed by curly braces are interpreted as regular expressions
3217that must or must not match in the entry.
3218
3219If the search string starts with an asterisk, search only in headlines.
3220If (possibly after the leading star) the search string starts with an
3221exclamation mark, this also means to look at TODO entries only, an effect
3222that can also be achieved with a prefix argument.
3223
3224This command searches the agenda files, and in addition the files listed
3225in `org-agenda-text-search-extra-files'."
3226 (interactive "P")
3227 (org-compile-prefix-format 'search)
3228 (org-set-sorting-strategy 'search)
3229 (org-prepare-agenda "SEARCH")
3230 (let* ((props (list 'face nil
c8d0cf5c 3231 'done-face 'org-agenda-done
20908596
CD
3232 'org-not-done-regexp org-not-done-regexp
3233 'org-todo-regexp org-todo-regexp
b349f79f 3234 'org-complex-heading-regexp org-complex-heading-regexp
20908596 3235 'mouse-face 'highlight
20908596
CD
3236 'help-echo (format "mouse-2 or RET jump to location")))
3237 regexp rtn rtnall files file pos
8bfe682a 3238 marker category tags c neg re as-words
20908596
CD
3239 ee txt beg end words regexps+ regexps- hdl-only buffer beg1 str)
3240 (unless (and (not edit-at)
3241 (stringp string)
3242 (string-match "\\S-" string))
3243 (setq string (read-string "[+-]Word/{Regexp} ...: "
3244 (cond
3245 ((integerp edit-at) (cons string edit-at))
3246 (edit-at string))
3247 'org-agenda-search-history)))
3248 (org-set-local 'org-todo-only todo-only)
3249 (setq org-agenda-redo-command
3250 (list 'org-search-view (if todo-only t nil) string
3251 '(if current-prefix-arg 1 nil)))
3252 (setq org-agenda-query-string string)
3253
3254 (if (equal (string-to-char string) ?*)
3255 (setq hdl-only t
3256 words (substring string 1))
3257 (setq words string))
3258 (when (equal (string-to-char words) ?!)
3259 (setq todo-only t
3260 words (substring words 1)))
8bfe682a
CD
3261 (if (or org-agenda-search-view-search-words-only
3262 (member (string-to-char string) '(?- ?+)))
3263 (setq as-words t))
20908596 3264 (setq words (org-split-string words))
8bfe682a
CD
3265 (if as-words
3266 (mapc (lambda (w)
3267 (setq c (string-to-char w))
3268 (if (equal c ?-)
3269 (setq neg t w (substring w 1))
3270 (if (equal c ?+)
3271 (setq neg nil w (substring w 1))
3272 (setq neg nil)))
3273 (if (string-match "\\`{.*}\\'" w)
3274 (setq re (substring w 1 -1))
3275 (setq re (concat "\\<" (regexp-quote (downcase w)) "\\>")))
3276 (if neg (push re regexps-) (push re regexps+)))
3277 words)
3278 (push (mapconcat (lambda (w) (regexp-quote w)) words "\\s-+")
3279 regexps+))
20908596
CD
3280 (setq regexps+ (sort regexps+ (lambda (a b) (> (length a) (length b)))))
3281 (if (not regexps+)
3282 (setq regexp (concat "^" org-outline-regexp))
3283 (setq regexp (pop regexps+))
3284 (if hdl-only (setq regexp (concat "^" org-outline-regexp ".*?"
3285 regexp))))
2c3ad40d 3286 (setq files (org-agenda-files nil 'ifmode))
20908596
CD
3287 (when (eq (car org-agenda-text-search-extra-files) 'agenda-archives)
3288 (pop org-agenda-text-search-extra-files)
3289 (setq files (org-add-archive-files files)))
3290 (setq files (append files org-agenda-text-search-extra-files)
3291 rtnall nil)
3292 (while (setq file (pop files))
3293 (setq ee nil)
3294 (catch 'nextfile
3295 (org-check-agenda-file file)
3296 (setq buffer (if (file-exists-p file)
3297 (org-get-agenda-file-buffer file)
3298 (error "No such file %s" file)))
3299 (if (not buffer)
3300 ;; If file does not exist, make sure an error message is sent
3301 (setq rtn (list (format "ORG-AGENDA-ERROR: No such org-file %s"
3302 file))))
3303 (with-current-buffer buffer
3304 (with-syntax-table (org-search-syntax-table)
3305 (unless (org-mode-p)
3306 (error "Agenda file %s is not in `org-mode'" file))
3307 (let ((case-fold-search t))
3308 (save-excursion
3309 (save-restriction
3310 (if org-agenda-restrict
3311 (narrow-to-region org-agenda-restrict-begin
3312 org-agenda-restrict-end)
3313 (widen))
3314 (goto-char (point-min))
3315 (unless (or (org-on-heading-p)
3316 (outline-next-heading))
3317 (throw 'nextfile t))
3318 (goto-char (max (point-min) (1- (point))))
3319 (while (re-search-forward regexp nil t)
3320 (org-back-to-heading t)
3321 (skip-chars-forward "* ")
3322 (setq beg (point-at-bol)
3323 beg1 (point)
3324 end (progn (outline-next-heading) (point)))
3325 (catch :skip
3326 (goto-char beg)
3327 (org-agenda-skip)
3328 (setq str (buffer-substring-no-properties
3329 (point-at-bol)
3330 (if hdl-only (point-at-eol) end)))
3331 (mapc (lambda (wr) (when (string-match wr str)
3332 (goto-char (1- end))
3333 (throw :skip t)))
3334 regexps-)
3335 (mapc (lambda (wr) (unless (string-match wr str)
3336 (goto-char (1- end))
3337 (throw :skip t)))
3338 (if todo-only
3339 (cons (concat "^\*+[ \t]+" org-not-done-regexp)
3340 regexps+)
3341 regexps+))
3342 (goto-char beg)
3343 (setq marker (org-agenda-new-marker (point))
3344 category (org-get-category)
3345 tags (org-get-tags-at (point))
3346 txt (org-format-agenda-item
3347 ""
3348 (buffer-substring-no-properties
3349 beg1 (point-at-eol))
3350 category tags))
3351 (org-add-props txt props
3352 'org-marker marker 'org-hd-marker marker
3353 'org-todo-regexp org-todo-regexp
b349f79f 3354 'org-complex-heading-regexp org-complex-heading-regexp
20908596
CD
3355 'priority 1000 'org-category category
3356 'type "search")
3357 (push txt ee)
3358 (goto-char (1- end))))))))))
3359 (setq rtn (nreverse ee))
3360 (setq rtnall (append rtnall rtn)))
3361 (if org-agenda-overriding-header
3362 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
3363 nil 'face 'org-agenda-structure) "\n")
3364 (insert "Search words: ")
3365 (add-text-properties (point-min) (1- (point))
3366 (list 'face 'org-agenda-structure))
3367 (setq pos (point))
3368 (insert string "\n")
3369 (add-text-properties pos (1- (point)) (list 'face 'org-warning))
3370 (setq pos (point))
3371 (unless org-agenda-multi
3372 (insert "Press `[', `]' to add/sub word, `{', `}' to add/sub regexp, `C-u r' to edit\n")
3373 (add-text-properties pos (1- (point))
3374 (list 'face 'org-agenda-structure))))
8d642074 3375 (org-agenda-mark-header-line (point-min))
20908596
CD
3376 (when rtnall
3377 (insert (org-finalize-agenda-entries rtnall) "\n"))
3378 (goto-char (point-min))
c8d0cf5c 3379 (or org-agenda-multi (org-fit-agenda-window))
20908596
CD
3380 (add-text-properties (point-min) (point-max) '(org-agenda-type search))
3381 (org-finalize-agenda)
3382 (setq buffer-read-only t)))
3383
3384;;; Agenda TODO list
3385
3386(defvar org-select-this-todo-keyword nil)
3387(defvar org-last-arg nil)
3388
3389;;;###autoload
3390(defun org-todo-list (arg)
3391 "Show all TODO entries from all agenda file in a single list.
3392The prefix arg can be used to select a specific TODO keyword and limit
3393the list to these. When using \\[universal-argument], you will be prompted
3394for a keyword. A numeric prefix directly selects the Nth keyword in
3395`org-todo-keywords-1'."
3396 (interactive "P")
3397 (require 'calendar)
3398 (org-compile-prefix-format 'todo)
3399 (org-set-sorting-strategy 'todo)
3400 (org-prepare-agenda "TODO")
3401 (let* ((today (time-to-days (current-time)))
3402 (date (calendar-gregorian-from-absolute today))
3403 (kwds org-todo-keywords-for-agenda)
3404 (completion-ignore-case t)
3405 (org-select-this-todo-keyword
3406 (if (stringp arg) arg
3407 (and arg (integerp arg) (> arg 0)
3408 (nth (1- arg) kwds))))
3409 rtn rtnall files file pos)
3410 (when (equal arg '(4))
3411 (setq org-select-this-todo-keyword
54a0dee5 3412 (org-icompleting-read "Keyword (or KWD1|K2D2|...): "
20908596
CD
3413 (mapcar 'list kwds) nil nil)))
3414 (and (equal 0 arg) (setq org-select-this-todo-keyword nil))
3415 (org-set-local 'org-last-arg arg)
3416 (setq org-agenda-redo-command
3417 '(org-todo-list (or current-prefix-arg org-last-arg)))
2c3ad40d 3418 (setq files (org-agenda-files nil 'ifmode)
20908596
CD
3419 rtnall nil)
3420 (while (setq file (pop files))
3421 (catch 'nextfile
3422 (org-check-agenda-file file)
3423 (setq rtn (org-agenda-get-day-entries file date :todo))
3424 (setq rtnall (append rtnall rtn))))
3425 (if org-agenda-overriding-header
3426 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
3427 nil 'face 'org-agenda-structure) "\n")
3428 (insert "Global list of TODO items of type: ")
3429 (add-text-properties (point-min) (1- (point))
8d642074
CD
3430 (list 'face 'org-agenda-structure
3431 'short-heading
3432 (concat "ToDo: "
3433 (or org-select-this-todo-keyword "ALL"))))
3434 (org-agenda-mark-header-line (point-min))
20908596
CD
3435 (setq pos (point))
3436 (insert (or org-select-this-todo-keyword "ALL") "\n")
3437 (add-text-properties pos (1- (point)) (list 'face 'org-warning))
3438 (setq pos (point))
3439 (unless org-agenda-multi
3440 (insert "Available with `N r': (0)ALL")
3441 (let ((n 0) s)
3442 (mapc (lambda (x)
3443 (setq s (format "(%d)%s" (setq n (1+ n)) x))
3444 (if (> (+ (current-column) (string-width s) 1) (frame-width))
3445 (insert "\n "))
3446 (insert " " s))
3447 kwds))
3448 (insert "\n"))
3449 (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure)))
8d642074 3450 (org-agenda-mark-header-line (point-min))
20908596
CD
3451 (when rtnall
3452 (insert (org-finalize-agenda-entries rtnall) "\n"))
3453 (goto-char (point-min))
c8d0cf5c 3454 (or org-agenda-multi (org-fit-agenda-window))
20908596
CD
3455 (add-text-properties (point-min) (point-max) '(org-agenda-type todo))
3456 (org-finalize-agenda)
3457 (setq buffer-read-only t)))
3458
3459;;; Agenda tags match
3460
3461;;;###autoload
3462(defun org-tags-view (&optional todo-only match)
3463 "Show all headlines for all `org-agenda-files' matching a TAGS criterion.
3464The prefix arg TODO-ONLY limits the search to TODO entries."
3465 (interactive "P")
3466 (org-compile-prefix-format 'tags)
3467 (org-set-sorting-strategy 'tags)
3468 (let* ((org-tags-match-list-sublevels
c8d0cf5c
CD
3469;?????? (if todo-only t org-tags-match-list-sublevels))
3470 org-tags-match-list-sublevels)
20908596
CD
3471 (completion-ignore-case t)
3472 rtn rtnall files file pos matcher
3473 buffer)
3474 (setq matcher (org-make-tags-matcher match)
3475 match (car matcher) matcher (cdr matcher))
3476 (org-prepare-agenda (concat "TAGS " match))
3477 (setq org-agenda-query-string match)
3478 (setq org-agenda-redo-command
3479 (list 'org-tags-view (list 'quote todo-only)
3480 (list 'if 'current-prefix-arg nil 'org-agenda-query-string)))
2c3ad40d 3481 (setq files (org-agenda-files nil 'ifmode)
20908596
CD
3482 rtnall nil)
3483 (while (setq file (pop files))
3484 (catch 'nextfile
3485 (org-check-agenda-file file)
3486 (setq buffer (if (file-exists-p file)
3487 (org-get-agenda-file-buffer file)
3488 (error "No such file %s" file)))
3489 (if (not buffer)
33306645 3490 ;; If file does not exist, error message to agenda
20908596
CD
3491 (setq rtn (list
3492 (format "ORG-AGENDA-ERROR: No such org-file %s" file))
3493 rtnall (append rtnall rtn))
3494 (with-current-buffer buffer
3495 (unless (org-mode-p)
3496 (error "Agenda file %s is not in `org-mode'" file))
3497 (save-excursion
3498 (save-restriction
3499 (if org-agenda-restrict
3500 (narrow-to-region org-agenda-restrict-begin
3501 org-agenda-restrict-end)
3502 (widen))
3503 (setq rtn (org-scan-tags 'agenda matcher todo-only))
3504 (setq rtnall (append rtnall rtn))))))))
3505 (if org-agenda-overriding-header
3506 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
3507 nil 'face 'org-agenda-structure) "\n")
3508 (insert "Headlines with TAGS match: ")
3509 (add-text-properties (point-min) (1- (point))
8d642074
CD
3510 (list 'face 'org-agenda-structure
3511 'short-heading
3512 (concat "Match: " match)))
20908596
CD
3513 (setq pos (point))
3514 (insert match "\n")
3515 (add-text-properties pos (1- (point)) (list 'face 'org-warning))
3516 (setq pos (point))
3517 (unless org-agenda-multi
3518 (insert "Press `C-u r' to search again with new search string\n"))
3519 (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure)))
8d642074 3520 (org-agenda-mark-header-line (point-min))
20908596
CD
3521 (when rtnall
3522 (insert (org-finalize-agenda-entries rtnall) "\n"))
3523 (goto-char (point-min))
c8d0cf5c 3524 (or org-agenda-multi (org-fit-agenda-window))
20908596
CD
3525 (add-text-properties (point-min) (point-max) '(org-agenda-type tags))
3526 (org-finalize-agenda)
3527 (setq buffer-read-only t)))
3528
3529;;; Agenda Finding stuck projects
3530
3531(defvar org-agenda-skip-regexp nil
3532 "Regular expression used in skipping subtrees for the agenda.
3533This is basically a temporary global variable that can be set and then
3534used by user-defined selections using `org-agenda-skip-function'.")
3535
3536(defvar org-agenda-overriding-header nil
c8d0cf5c
CD
3537 "When this is set during todo and tags searches, will replace header.
3538This variable should not be set directly, but custom commands can bind it
3539in the options section.")
3540
3541(defun org-agenda-skip-entry-when-regexp-matches ()
3542 "Checks if the current entry contains match for `org-agenda-skip-regexp'.
3543If yes, it returns the end position of this entry, causing agenda commands
3544to skip the entry but continuing the search in the subtree. This is a
3545function that can be put into `org-agenda-skip-function' for the duration
3546of a command."
3547 (let ((end (save-excursion (org-end-of-subtree t)))
3548 skip)
3549 (save-excursion
3550 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
3551 (and skip end)))
20908596
CD
3552
3553(defun org-agenda-skip-subtree-when-regexp-matches ()
3554 "Checks if the current subtree contains match for `org-agenda-skip-regexp'.
3555If yes, it returns the end position of this tree, causing agenda commands
3556to skip this subtree. This is a function that can be put into
3557`org-agenda-skip-function' for the duration of a command."
3558 (let ((end (save-excursion (org-end-of-subtree t)))
3559 skip)
3560 (save-excursion
3561 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
3562 (and skip end)))
3563
c8d0cf5c
CD
3564(defun org-agenda-skip-entry-when-regexp-matches-in-subtree ()
3565 "Checks if the current subtree contains match for `org-agenda-skip-regexp'.
3566If yes, it returns the end position of the current entry (NOT the tree),
3567causing agenda commands to skip the entry but continuing the search in
3568the subtree. This is a function that can be put into
3569`org-agenda-skip-function' for the duration of a command. An important
3570use of this function is for the stuck project list."
3571 (let ((end (save-excursion (org-end-of-subtree t)))
3572 (entry-end (save-excursion (outline-next-heading) (1- (point))))
3573 skip)
3574 (save-excursion
3575 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
3576 (and skip entry-end)))
3577
20908596
CD
3578(defun org-agenda-skip-entry-if (&rest conditions)
3579 "Skip entry if any of CONDITIONS is true.
3580See `org-agenda-skip-if' for details."
3581 (org-agenda-skip-if nil conditions))
3582
3583(defun org-agenda-skip-subtree-if (&rest conditions)
3584 "Skip entry if any of CONDITIONS is true.
3585See `org-agenda-skip-if' for details."
3586 (org-agenda-skip-if t conditions))
3587
3588(defun org-agenda-skip-if (subtree conditions)
3589 "Checks current entity for CONDITIONS.
3590If SUBTREE is non-nil, the entire subtree is checked. Otherwise, only
3591the entry, i.e. the text before the next heading is checked.
3592
3593CONDITIONS is a list of symbols, boolean OR is used to combine the results
3594from different tests. Valid conditions are:
3595
3596scheduled Check if there is a scheduled cookie
3597notscheduled Check if there is no scheduled cookie
3598deadline Check if there is a deadline
3599notdeadline Check if there is no deadline
c8d0cf5c
CD
3600timestamp Check if there is a timestamp (also deadline or scheduled)
3601nottimestamp Check if there is no timestamp (also deadline or scheduled)
20908596
CD
3602regexp Check if regexp matches
3603notregexp Check if regexp does not match.
3604
3605The regexp is taken from the conditions list, it must come right after
3606the `regexp' or `notregexp' element.
3607
3608If any of these conditions is met, this function returns the end point of
3609the entity, causing the search to continue from there. This is a function
3610that can be put into `org-agenda-skip-function' for the duration of a command."
3611 (let (beg end m)
3612 (org-back-to-heading t)
3613 (setq beg (point)
3614 end (if subtree
3615 (progn (org-end-of-subtree t) (point))
3616 (progn (outline-next-heading) (1- (point)))))
3617 (goto-char beg)
3618 (and
3619 (or
3620 (and (memq 'scheduled conditions)
3621 (re-search-forward org-scheduled-time-regexp end t))
3622 (and (memq 'notscheduled conditions)
3623 (not (re-search-forward org-scheduled-time-regexp end t)))
3624 (and (memq 'deadline conditions)
3625 (re-search-forward org-deadline-time-regexp end t))
3626 (and (memq 'notdeadline conditions)
3627 (not (re-search-forward org-deadline-time-regexp end t)))
c8d0cf5c
CD
3628 (and (memq 'timestamp conditions)
3629 (re-search-forward org-ts-regexp end t))
3630 (and (memq 'nottimestamp conditions)
3631 (not (re-search-forward org-ts-regexp end t)))
20908596
CD
3632 (and (setq m (memq 'regexp conditions))
3633 (stringp (nth 1 m))
3634 (re-search-forward (nth 1 m) end t))
3635 (and (setq m (memq 'notregexp conditions))
3636 (stringp (nth 1 m))
3637 (not (re-search-forward (nth 1 m) end t))))
3638 end)))
3639
3640;;;###autoload
3641(defun org-agenda-list-stuck-projects (&rest ignore)
3642 "Create agenda view for projects that are stuck.
3643Stuck projects are project that have no next actions. For the definitions
3644of what a project is and how to check if it stuck, customize the variable
3645`org-stuck-projects'.
3646MATCH is being ignored."
3647 (interactive)
c8d0cf5c
CD
3648 (let* ((org-agenda-skip-function
3649 'org-agenda-skip-entry-when-regexp-matches-in-subtree)
20908596 3650 ;; We could have used org-agenda-skip-if here.
c8d0cf5c
CD
3651 (org-agenda-overriding-header
3652 (or org-agenda-overriding-header "List of stuck projects: "))
20908596
CD
3653 (matcher (nth 0 org-stuck-projects))
3654 (todo (nth 1 org-stuck-projects))
3655 (todo-wds (if (member "*" todo)
3656 (progn
2c3ad40d
CD
3657 (org-prepare-agenda-buffers (org-agenda-files
3658 nil 'ifmode))
20908596
CD
3659 (org-delete-all
3660 org-done-keywords-for-agenda
3661 (copy-sequence org-todo-keywords-for-agenda)))
3662 todo))
3663 (todo-re (concat "^\\*+[ \t]+\\("
3664 (mapconcat 'identity todo-wds "\\|")
3665 "\\)\\>"))
3666 (tags (nth 2 org-stuck-projects))
3667 (tags-re (if (member "*" tags)
3668 (org-re "^\\*+ .*:[[:alnum:]_@]+:[ \t]*$")
c8d0cf5c
CD
3669 (if tags
3670 (concat "^\\*+ .*:\\("
3671 (mapconcat 'identity tags "\\|")
3672 (org-re "\\):[[:alnum:]_@:]*[ \t]*$")))))
20908596
CD
3673 (gen-re (nth 3 org-stuck-projects))
3674 (re-list
3675 (delq nil
3676 (list
3677 (if todo todo-re)
3678 (if tags tags-re)
3679 (and gen-re (stringp gen-re) (string-match "\\S-" gen-re)
3680 gen-re)))))
3681 (setq org-agenda-skip-regexp
3682 (if re-list
3683 (mapconcat 'identity re-list "\\|")
3684 (error "No information how to identify unstuck projects")))
3685 (org-tags-view nil matcher)
3686 (with-current-buffer org-agenda-buffer-name
3687 (setq org-agenda-redo-command
3688 '(org-agenda-list-stuck-projects
3689 (or current-prefix-arg org-last-arg))))))
3690
3691;;; Diary integration
3692
3693(defvar org-disable-agenda-to-diary nil) ;Dynamically-scoped param.
3694(defvar list-diary-entries-hook)
3695
3696(defun org-get-entries-from-diary (date)
3697 "Get the (Emacs Calendar) diary entries for DATE."
3698 (require 'diary-lib)
3699 (let* ((diary-fancy-buffer "*temporary-fancy-diary-buffer*")
ff4be292 3700 (fancy-diary-buffer diary-fancy-buffer)
20908596 3701 (diary-display-hook '(fancy-diary-display))
ca8ef0dc 3702 (diary-display-function 'fancy-diary-display)
20908596
CD
3703 (pop-up-frames nil)
3704 (list-diary-entries-hook
3705 (cons 'org-diary-default-entry list-diary-entries-hook))
3706 (diary-file-name-prefix-function nil) ; turn this feature off
3707 (diary-modify-entry-list-string-function 'org-modify-diary-entry-string)
3708 entries
3709 (org-disable-agenda-to-diary t))
3710 (save-excursion
3711 (save-window-excursion
3712 (funcall (if (fboundp 'diary-list-entries)
3713 'diary-list-entries 'list-diary-entries)
3714 date 1)))
3715 (if (not (get-buffer diary-fancy-buffer))
3716 (setq entries nil)
3717 (with-current-buffer diary-fancy-buffer
3718 (setq buffer-read-only nil)
3719 (if (zerop (buffer-size))
3720 ;; No entries
3721 (setq entries nil)
3722 ;; Omit the date and other unnecessary stuff
3723 (org-agenda-cleanup-fancy-diary)
3724 ;; Add prefix to each line and extend the text properties
3725 (if (zerop (buffer-size))
3726 (setq entries nil)
3727 (setq entries (buffer-substring (point-min) (- (point-max) 1)))))
3728 (set-buffer-modified-p nil)
3729 (kill-buffer diary-fancy-buffer)))
3730 (when entries
3731 (setq entries (org-split-string entries "\n"))
3732 (setq entries
3733 (mapcar
3734 (lambda (x)
3735 (setq x (org-format-agenda-item "" x "Diary" nil 'time))
3736 ;; Extend the text properties to the beginning of the line
3737 (org-add-props x (text-properties-at (1- (length x)) x)
3738 'type "diary" 'date date))
3739 entries)))))
3740
c8d0cf5c
CD
3741(defvar org-agenda-cleanup-fancy-diary-hook nil
3742 "Hook run when the fancy diary buffer is cleaned up.")
3743
20908596
CD
3744(defun org-agenda-cleanup-fancy-diary ()
3745 "Remove unwanted stuff in buffer created by `fancy-diary-display'.
3746This gets rid of the date, the underline under the date, and
3747the dummy entry installed by `org-mode' to ensure non-empty diary for each
3748date. It also removes lines that contain only whitespace."
3749 (goto-char (point-min))
3750 (if (looking-at ".*?:[ \t]*")
3751 (progn
3752 (replace-match "")
3753 (re-search-forward "\n=+$" nil t)
3754 (replace-match "")
3755 (while (re-search-backward "^ +\n?" nil t) (replace-match "")))
3756 (re-search-forward "\n=+$" nil t)
3757 (delete-region (point-min) (min (point-max) (1+ (match-end 0)))))
3758 (goto-char (point-min))
3759 (while (re-search-forward "^ +\n" nil t)
3760 (replace-match ""))
3761 (goto-char (point-min))
3762 (if (re-search-forward "^Org-mode dummy\n?" nil t)
c8d0cf5c
CD
3763 (replace-match ""))
3764 (run-hooks 'org-agenda-cleanup-fancy-diary-hook))
20908596
CD
3765
3766;; Make sure entries from the diary have the right text properties.
3767(eval-after-load "diary-lib"
3768 '(if (boundp 'diary-modify-entry-list-string-function)
3769 ;; We can rely on the hook, nothing to do
3770 nil
33306645 3771 ;; Hook not available, must use advice to make this work
20908596
CD
3772 (defadvice add-to-diary-list (before org-mark-diary-entry activate)
3773 "Make the position visible."
3774 (if (and org-disable-agenda-to-diary ;; called from org-agenda
3775 (stringp string)
3776 buffer-file-name)
3777 (setq string (org-modify-diary-entry-string string))))))
3778
3779(defun org-modify-diary-entry-string (string)
3780 "Add text properties to string, allowing org-mode to act on it."
3781 (org-add-props string nil
3782 'mouse-face 'highlight
20908596
CD
3783 'help-echo (if buffer-file-name
3784 (format "mouse-2 or RET jump to diary file %s"
3785 (abbreviate-file-name buffer-file-name))
3786 "")
3787 'org-agenda-diary-link t
3788 'org-marker (org-agenda-new-marker (point-at-bol))))
3789
3790(defun org-diary-default-entry ()
3791 "Add a dummy entry to the diary.
3792Needed to avoid empty dates which mess up holiday display."
3793 ;; Catch the error if dealing with the new add-to-diary-alist
3794 (when org-disable-agenda-to-diary
3795 (condition-case nil
3796 (org-add-to-diary-list original-date "Org-mode dummy" "")
3797 (error
3798 (org-add-to-diary-list original-date "Org-mode dummy" "" nil)))))
3799
3800(defun org-add-to-diary-list (&rest args)
3801 (if (fboundp 'diary-add-to-list)
3802 (apply 'diary-add-to-list args)
3803 (apply 'add-to-diary-list args)))
3804
3805;;;###autoload
3806(defun org-diary (&rest args)
3807 "Return diary information from org-files.
3808This function can be used in a \"sexp\" diary entry in the Emacs calendar.
3809It accesses org files and extracts information from those files to be
3810listed in the diary. The function accepts arguments specifying what
3811items should be listed. The following arguments are allowed:
3812
3813 :timestamp List the headlines of items containing a date stamp or
3814 date range matching the selected date. Deadlines will
3815 also be listed, on the expiration day.
3816
3817 :sexp List entries resulting from diary-like sexps.
3818
3819 :deadline List any deadlines past due, or due within
3820 `org-deadline-warning-days'. The listing occurs only
3821 in the diary for *today*, not at any other date. If
3822 an entry is marked DONE, it is no longer listed.
3823
3824 :scheduled List all items which are scheduled for the given date.
3825 The diary for *today* also contains items which were
3826 scheduled earlier and are not yet marked DONE.
3827
3828 :todo List all TODO items from the org-file. This may be a
3829 long list - so this is not turned on by default.
3830 Like deadlines, these entries only show up in the
3831 diary for *today*, not at any other date.
3832
3833The call in the diary file should look like this:
3834
3835 &%%(org-diary) ~/path/to/some/orgfile.org
3836
3837Use a separate line for each org file to check. Or, if you omit the file name,
3838all files listed in `org-agenda-files' will be checked automatically:
3839
3840 &%%(org-diary)
3841
3842If you don't give any arguments (as in the example above), the default
3843arguments (:deadline :scheduled :timestamp :sexp) are used.
3844So the example above may also be written as
3845
3846 &%%(org-diary :deadline :timestamp :sexp :scheduled)
3847
3848The function expects the lisp variables `entry' and `date' to be provided
3849by the caller, because this is how the calendar works. Don't use this
3850function from a program - use `org-agenda-get-day-entries' instead."
54a0dee5 3851 (when (> (- (org-float-time)
20908596
CD
3852 org-agenda-last-marker-time)
3853 5)
3854 (org-agenda-reset-markers))
3855 (org-compile-prefix-format 'agenda)
3856 (org-set-sorting-strategy 'agenda)
3857 (setq args (or args '(:deadline :scheduled :timestamp :sexp)))
3858 (let* ((files (if (and entry (stringp entry) (string-match "\\S-" entry))
3859 (list entry)
3860 (org-agenda-files t)))
3861 file rtn results)
3862 (org-prepare-agenda-buffers files)
3863 ;; If this is called during org-agenda, don't return any entries to
3864 ;; the calendar. Org Agenda will list these entries itself.
3865 (if org-disable-agenda-to-diary (setq files nil))
3866 (while (setq file (pop files))
3867 (setq rtn (apply 'org-agenda-get-day-entries file date args))
3868 (setq results (append results rtn)))
3869 (if results
3870 (concat (org-finalize-agenda-entries results) "\n"))))
3871
3872;;; Agenda entry finders
3873
3874(defun org-agenda-get-day-entries (file date &rest args)
3875 "Does the work for `org-diary' and `org-agenda'.
3876FILE is the path to a file to be checked for entries. DATE is date like
3877the one returned by `calendar-current-date'. ARGS are symbols indicating
3878which kind of entries should be extracted. For details about these, see
3879the documentation of `org-diary'."
3880 (setq args (or args '(:deadline :scheduled :timestamp :sexp)))
3881 (let* ((org-startup-folded nil)
3882 (org-startup-align-all-tables nil)
3883 (buffer (if (file-exists-p file)
3884 (org-get-agenda-file-buffer file)
3885 (error "No such file %s" file)))
54a0dee5 3886 arg results rtn deadline-results)
20908596
CD
3887 (if (not buffer)
3888 ;; If file does not exist, make sure an error message ends up in diary
3889 (list (format "ORG-AGENDA-ERROR: No such org-file %s" file))
3890 (with-current-buffer buffer
3891 (unless (org-mode-p)
3892 (error "Agenda file %s is not in `org-mode'" file))
3893 (let ((case-fold-search nil))
3894 (save-excursion
3895 (save-restriction
3896 (if org-agenda-restrict
3897 (narrow-to-region org-agenda-restrict-begin
3898 org-agenda-restrict-end)
3899 (widen))
3900 ;; The way we repeatedly append to `results' makes it O(n^2) :-(
3901 (while (setq arg (pop args))
3902 (cond
3903 ((and (eq arg :todo)
3904 (equal date (calendar-current-date)))
3905 (setq rtn (org-agenda-get-todos))
3906 (setq results (append results rtn)))
3907 ((eq arg :timestamp)
3908 (setq rtn (org-agenda-get-blocks))
3909 (setq results (append results rtn))
3910 (setq rtn (org-agenda-get-timestamps))
3911 (setq results (append results rtn)))
3912 ((eq arg :sexp)
3913 (setq rtn (org-agenda-get-sexps))
3914 (setq results (append results rtn)))
3915 ((eq arg :scheduled)
54a0dee5 3916 (setq rtn (org-agenda-get-scheduled deadline-results))
20908596
CD
3917 (setq results (append results rtn)))
3918 ((eq arg :closed)
93b62de8 3919 (setq rtn (org-agenda-get-progress))
20908596
CD
3920 (setq results (append results rtn)))
3921 ((eq arg :deadline)
3922 (setq rtn (org-agenda-get-deadlines))
54a0dee5 3923 (setq deadline-results (copy-sequence rtn))
20908596
CD
3924 (setq results (append results rtn))))))))
3925 results))))
3926
3927(defun org-agenda-get-todos ()
3928 "Return the TODO information for agenda display."
3929 (let* ((props (list 'face nil
c8d0cf5c 3930 'done-face 'org-agenda-done
20908596
CD
3931 'org-not-done-regexp org-not-done-regexp
3932 'org-todo-regexp org-todo-regexp
b349f79f 3933 'org-complex-heading-regexp org-complex-heading-regexp
20908596 3934 'mouse-face 'highlight
20908596
CD
3935 'help-echo
3936 (format "mouse-2 or RET jump to org file %s"
3937 (abbreviate-file-name buffer-file-name))))
3938 (regexp (concat "^\\*+[ \t]+\\("
3939 (if org-select-this-todo-keyword
3940 (if (equal org-select-this-todo-keyword "*")
3941 org-todo-regexp
3942 (concat "\\<\\("
3943 (mapconcat 'identity (org-split-string org-select-this-todo-keyword "|") "\\|")
3944 "\\)\\>"))
3945 org-not-done-regexp)
3946 "[^\n\r]*\\)"))
621f83e4 3947 marker priority category tags todo-state
20908596
CD
3948 ee txt beg end)
3949 (goto-char (point-min))
3950 (while (re-search-forward regexp nil t)
3951 (catch :skip
3952 (save-match-data
3953 (beginning-of-line)
d6685abc 3954 (setq beg (point) end (save-excursion (outline-next-heading) (point)))
0bd48b37 3955 (when (org-agenda-check-for-timestamp-as-reason-to-ignore-todo-item end)
20908596
CD
3956 (goto-char (1+ beg))
3957 (or org-agenda-todo-list-sublevels (org-end-of-subtree 'invisible))
3958 (throw :skip nil)))
3959 (goto-char beg)
3960 (org-agenda-skip)
3961 (goto-char (match-beginning 1))
3962 (setq marker (org-agenda-new-marker (match-beginning 0))
3963 category (org-get-category)
c8d0cf5c 3964 txt (match-string 1)
20908596 3965 tags (org-get-tags-at (point))
c8d0cf5c 3966 txt (org-format-agenda-item "" txt category tags)
621f83e4
CD
3967 priority (1+ (org-get-priority txt))
3968 todo-state (org-get-todo-state))
20908596
CD
3969 (org-add-props txt props
3970 'org-marker marker 'org-hd-marker marker
3971 'priority priority 'org-category category
621f83e4 3972 'type "todo" 'todo-state todo-state)
20908596
CD
3973 (push txt ee)
3974 (if org-agenda-todo-list-sublevels
3975 (goto-char (match-end 1))
3976 (org-end-of-subtree 'invisible))))
3977 (nreverse ee)))
3978
0bd48b37
CD
3979;;;###autoload
3980(defun org-agenda-check-for-timestamp-as-reason-to-ignore-todo-item (&optional end)
3981 "Do we have a reason to ignore this todo entry because it has a time stamp?"
3982 (when (or org-agenda-todo-ignore-with-date
3983 org-agenda-todo-ignore-scheduled
3984 org-agenda-todo-ignore-deadlines)
3985 (setq end (or end (save-excursion (outline-next-heading) (point))))
3986 (save-excursion
3987 (or (and org-agenda-todo-ignore-with-date
3988 (re-search-forward org-ts-regexp end t))
3989 (and org-agenda-todo-ignore-scheduled
3990 (re-search-forward org-scheduled-time-regexp end t))
3991 (and org-agenda-todo-ignore-deadlines
3992 (re-search-forward org-deadline-time-regexp end t)
3993 (org-deadline-close (match-string 1)))))))
3994
20908596
CD
3995(defconst org-agenda-no-heading-message
3996 "No heading for this item in buffer or region.")
3997
3998(defun org-agenda-get-timestamps ()
3999 "Return the date stamp information for agenda display."
4000 (let* ((props (list 'face nil
4001 'org-not-done-regexp org-not-done-regexp
4002 'org-todo-regexp org-todo-regexp
b349f79f 4003 'org-complex-heading-regexp org-complex-heading-regexp
20908596 4004 'mouse-face 'highlight
20908596
CD
4005 'help-echo
4006 (format "mouse-2 or RET jump to org file %s"
4007 (abbreviate-file-name buffer-file-name))))
4008 (d1 (calendar-absolute-from-gregorian date))
4009 (remove-re
4010 (concat
4011 (regexp-quote
4012 (format-time-string
4013 "<%Y-%m-%d"
4014 (encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date))))
4015 ".*?>"))
4016 (regexp
4017 (concat
4018 (if org-agenda-include-inactive-timestamps "[[<]" "<")
4019 (regexp-quote
4020 (substring
4021 (format-time-string
4022 (car org-time-stamp-formats)
4023 (apply 'encode-time ; DATE bound by calendar
4024 (list 0 0 0 (nth 1 date) (car date) (nth 2 date))))
4025 1 11))
4026 "\\|\\(<[0-9]+-[0-9]+-[0-9]+[^>\n]+?\\+[0-9]+[dwmy]>\\)"
4027 "\\|\\(<%%\\(([^>\n]+)\\)>\\)"))
4028 marker hdmarker deadlinep scheduledp clockp closedp inactivep
621f83e4 4029 donep tmp priority category ee txt timestr tags b0 b3 e3 head
c8d0cf5c 4030 todo-state end-of-match)
20908596 4031 (goto-char (point-min))
c8d0cf5c 4032 (while (setq end-of-match (re-search-forward regexp nil t))
20908596
CD
4033 (setq b0 (match-beginning 0)
4034 b3 (match-beginning 3) e3 (match-end 3))
4035 (catch :skip
4036 (and (org-at-date-range-p) (throw :skip nil))
4037 (org-agenda-skip)
4038 (if (and (match-end 1)
4039 (not (= d1 (org-time-string-to-absolute
4040 (match-string 1) d1 nil
4041 org-agenda-repeating-timestamp-show-all))))
4042 (throw :skip nil))
4043 (if (and e3
4044 (not (org-diary-sexp-entry (buffer-substring b3 e3) "" date)))
4045 (throw :skip nil))
c8d0cf5c 4046 (setq tmp (buffer-substring (max (point-min)
20908596
CD
4047 (- b0 org-ds-keyword-length))
4048 b0)
4049 timestr (if b3 "" (buffer-substring b0 (point-at-eol)))
4050 inactivep (= (char-after b0) ?\[)
4051 deadlinep (string-match org-deadline-regexp tmp)
4052 scheduledp (string-match org-scheduled-regexp tmp)
4053 closedp (and org-agenda-include-inactive-timestamps
4054 (string-match org-closed-string tmp))
4055 clockp (and org-agenda-include-inactive-timestamps
4056 (or (string-match org-clock-string tmp)
4057 (string-match "]-+\\'" tmp)))
621f83e4
CD
4058 todo-state (org-get-todo-state)
4059 donep (member todo-state org-done-keywords))
c8d0cf5c
CD
4060 (if (or scheduledp deadlinep closedp clockp
4061 (and donep org-agenda-skip-timestamp-if-done))
20908596
CD
4062 (throw :skip t))
4063 (if (string-match ">" timestr)
4064 ;; substring should only run to end of time stamp
4065 (setq timestr (substring timestr 0 (match-end 0))))
c8d0cf5c
CD
4066 (setq marker (org-agenda-new-marker b0)
4067 category (org-get-category b0))
20908596 4068 (save-excursion
c8d0cf5c
CD
4069 (if (not (re-search-backward "^\\*+ " nil t))
4070 (setq txt org-agenda-no-heading-message)
4071 (goto-char (match-beginning 0))
4072 (setq hdmarker (org-agenda-new-marker)
4073 tags (org-get-tags-at))
4074 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
4075 (setq head (match-string 1))
4076 (setq txt (org-format-agenda-item
4077 (if inactivep "[" nil)
4078 head category tags timestr nil
4079 remove-re)))
20908596
CD
4080 (setq priority (org-get-priority txt))
4081 (org-add-props txt props
4082 'org-marker marker 'org-hd-marker hdmarker)
4083 (org-add-props txt nil 'priority priority
4084 'org-category category 'date date
621f83e4 4085 'todo-state todo-state
20908596
CD
4086 'type "timestamp")
4087 (push txt ee))
c8d0cf5c
CD
4088 (if org-agenda-skip-additional-timestamps-same-entry
4089 (outline-next-heading)
4090 (goto-char end-of-match))))
20908596
CD
4091 (nreverse ee)))
4092
4093(defun org-agenda-get-sexps ()
4094 "Return the sexp information for agenda display."
4095 (require 'diary-lib)
4096 (let* ((props (list 'face nil
4097 'mouse-face 'highlight
20908596
CD
4098 'help-echo
4099 (format "mouse-2 or RET jump to org file %s"
4100 (abbreviate-file-name buffer-file-name))))
4101 (regexp "^&?%%(")
c8d0cf5c
CD
4102 marker category ee txt tags entry result beg b sexp sexp-entry
4103 todo-state)
20908596
CD
4104 (goto-char (point-min))
4105 (while (re-search-forward regexp nil t)
4106 (catch :skip
4107 (org-agenda-skip)
4108 (setq beg (match-beginning 0))
4109 (goto-char (1- (match-end 0)))
4110 (setq b (point))
4111 (forward-sexp 1)
4112 (setq sexp (buffer-substring b (point)))
4113 (setq sexp-entry (if (looking-at "[ \t]*\\(\\S-.*\\)")
4114 (org-trim (match-string 1))
4115 ""))
4116 (setq result (org-diary-sexp-entry sexp sexp-entry date))
4117 (when result
4118 (setq marker (org-agenda-new-marker beg)
c8d0cf5c
CD
4119 category (org-get-category beg)
4120 todo-state (org-get-todo-state))
20908596
CD
4121
4122 (if (string-match "\\S-" result)
4123 (setq txt result)
4124 (setq txt "SEXP entry returned empty string"))
4125
4126 (setq txt (org-format-agenda-item
4127 "" txt category tags 'time))
4128 (org-add-props txt props 'org-marker marker)
4129 (org-add-props txt nil
c8d0cf5c 4130 'org-category category 'date date 'todo-state todo-state
20908596
CD
4131 'type "sexp")
4132 (push txt ee))))
4133 (nreverse ee)))
4134
d60b1ba1 4135(defalias 'org-get-closed 'org-agenda-get-progress)
93b62de8 4136(defun org-agenda-get-progress ()
20908596
CD
4137 "Return the logged TODO entries for agenda display."
4138 (let* ((props (list 'mouse-face 'highlight
4139 'org-not-done-regexp org-not-done-regexp
4140 'org-todo-regexp org-todo-regexp
b349f79f 4141 'org-complex-heading-regexp org-complex-heading-regexp
20908596
CD
4142 'help-echo
4143 (format "mouse-2 or RET jump to org file %s"
4144 (abbreviate-file-name buffer-file-name))))
93b62de8
CD
4145 (items (if (consp org-agenda-show-log)
4146 org-agenda-show-log
4147 org-agenda-log-mode-items))
ff4be292 4148 (parts
93b62de8
CD
4149 (delq nil
4150 (list
4151 (if (memq 'closed items) (concat "\\<" org-closed-string))
4152 (if (memq 'clock items) (concat "\\<" org-clock-string))
c8d0cf5c 4153 (if (memq 'state items) "- State \"\\([a-zA-Z0-9]+\\)\".*?"))))
93b62de8
CD
4154 (parts-re (if parts (mapconcat 'identity parts "\\|")
4155 (error "`org-agenda-log-mode-items' is empty")))
20908596 4156 (regexp (concat
93b62de8
CD
4157 "\\(" parts-re "\\)"
4158 " *\\["
20908596
CD
4159 (regexp-quote
4160 (substring
4161 (format-time-string
4162 (car org-time-stamp-formats)
4163 (apply 'encode-time ; DATE bound by calendar
4164 (list 0 0 0 (nth 1 date) (car date) (nth 2 date))))
4165 1 11))))
c8d0cf5c
CD
4166 (org-agenda-search-headline-for-time nil)
4167 marker hdmarker priority category tags closedp statep clockp state
4168 ee txt extra timestr rest clocked)
20908596
CD
4169 (goto-char (point-min))
4170 (while (re-search-forward regexp nil t)
4171 (catch :skip
4172 (org-agenda-skip)
4173 (setq marker (org-agenda-new-marker (match-beginning 0))
4174 closedp (equal (match-string 1) org-closed-string)
93b62de8 4175 statep (equal (string-to-char (match-string 1)) ?-)
c8d0cf5c 4176 clockp (not (or closedp statep))
93b62de8 4177 state (and statep (match-string 2))
20908596
CD
4178 category (org-get-category (match-beginning 0))
4179 timestr (buffer-substring (match-beginning 0) (point-at-eol))
20908596 4180 )
b349f79f
CD
4181 (when (string-match "\\]" timestr)
4182 ;; substring should only run to end of time stamp
4183 (setq rest (substring timestr (match-end 0))
4184 timestr (substring timestr 0 (match-end 0)))
93b62de8 4185 (if (and (not closedp) (not statep)
c8d0cf5c 4186 (string-match "\\([0-9]\\{1,2\\}:[0-9]\\{2\\}\\)\\].*?\\([0-9]\\{1,2\\}:[0-9]\\{2\\}\\)" rest))
621f83e4
CD
4187 (progn (setq timestr (concat (substring timestr 0 -1)
4188 "-" (match-string 1 rest) "]"))
4189 (setq clocked (match-string 2 rest)))
4190 (setq clocked "-")))
20908596 4191 (save-excursion
c8d0cf5c
CD
4192 (cond
4193 ((not org-agenda-log-mode-add-notes) (setq extra nil))
4194 (statep
4195 (and (looking-at ".*\n[ \t]*\\([^-\n \t].*?\\)[ \t]*$")
4196 (setq extra (match-string 1))))
4197 (clockp
4198 (and (looking-at ".*\n[ \t]*-[ \t]+\\([^-\n \t].*?\\)[ \t]*$")
4199 (setq extra (match-string 1))))
4200 (t (setq extra nil)))
4201 (if (not (re-search-backward "^\\*+ " nil t))
4202 (setq txt org-agenda-no-heading-message)
4203 (goto-char (match-beginning 0))
4204 (setq hdmarker (org-agenda-new-marker)
4205 tags (org-get-tags-at))
4206 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
4207 (setq txt (match-string 1))
4208 (when extra
4209 (if (string-match "\\([ \t]+\\)\\(:[^ \n\t]*?:\\)[ \t]*$" txt)
4210 (setq txt (concat (substring txt 0 (match-beginning 1))
4211 " - " extra " " (match-string 2 txt)))
4212 (setq txt (concat txt " - " extra))))
4213 (setq txt (org-format-agenda-item
4214 (cond
4215 (closedp "Closed: ")
93b62de8
CD
4216 (statep (concat "State: (" state ")"))
4217 (t (concat "Clocked: (" clocked ")")))
c8d0cf5c 4218 txt category tags timestr)))
20908596
CD
4219 (setq priority 100000)
4220 (org-add-props txt props
c8d0cf5c 4221 'org-marker marker 'org-hd-marker hdmarker 'face 'org-agenda-done
20908596
CD
4222 'priority priority 'org-category category
4223 'type "closed" 'date date
c8d0cf5c 4224 'undone-face 'org-warning 'done-face 'org-agenda-done)
20908596
CD
4225 (push txt ee))
4226 (goto-char (point-at-eol))))
4227 (nreverse ee)))
4228
4229(defun org-agenda-get-deadlines ()
4230 "Return the deadline information for agenda display."
4231 (let* ((props (list 'mouse-face 'highlight
4232 'org-not-done-regexp org-not-done-regexp
4233 'org-todo-regexp org-todo-regexp
b349f79f 4234 'org-complex-heading-regexp org-complex-heading-regexp
20908596
CD
4235 'help-echo
4236 (format "mouse-2 or RET jump to org file %s"
4237 (abbreviate-file-name buffer-file-name))))
4238 (regexp org-deadline-time-regexp)
621f83e4 4239 (todayp (org-agenda-todayp date)) ; DATE bound by calendar
20908596
CD
4240 (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar
4241 d2 diff dfrac wdays pos pos1 category tags
621f83e4 4242 ee txt head face s todo-state upcomingp donep timestr)
20908596
CD
4243 (goto-char (point-min))
4244 (while (re-search-forward regexp nil t)
4245 (catch :skip
4246 (org-agenda-skip)
4247 (setq s (match-string 1)
c8d0cf5c 4248 txt nil
20908596
CD
4249 pos (1- (match-beginning 1))
4250 d2 (org-time-string-to-absolute
4251 (match-string 1) d1 'past
4252 org-agenda-repeating-timestamp-show-all)
4253 diff (- d2 d1)
4254 wdays (org-get-wdays s)
4255 dfrac (/ (* 1.0 (- wdays diff)) (max wdays 1))
4256 upcomingp (and todayp (> diff 0)))
4257 ;; When to show a deadline in the calendar:
4258 ;; If the expiration is within wdays warning time.
4259 ;; Past-due deadlines are only shown on the current date
8bfe682a
CD
4260 (if (and (or (and (<= diff wdays)
4261 (and todayp (not org-agenda-only-exact-dates)))
4262 (= diff 0)))
20908596 4263 (save-excursion
621f83e4 4264 (setq todo-state (org-get-todo-state))
c8d0cf5c
CD
4265 (setq donep (member todo-state org-done-keywords))
4266 (if (and donep
4267 (or org-agenda-skip-deadline-if-done
4268 (not (= diff 0))))
4269 (setq txt nil)
4270 (setq category (org-get-category))
4271 (if (not (re-search-backward "^\\*+[ \t]+" nil t))
4272 (setq txt org-agenda-no-heading-message)
4273 (goto-char (match-end 0))
4274 (setq pos1 (match-beginning 0))
4275 (setq tags (org-get-tags-at pos1))
4276 (setq head (buffer-substring-no-properties
4277 (point)
4278 (progn (skip-chars-forward "^\r\n")
4279 (point))))
4280 (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
4281 (setq timestr
4282 (concat (substring s (match-beginning 1)) " "))
4283 (setq timestr 'time))
4284 (setq txt (org-format-agenda-item
4285 (if (= diff 0)
4286 (car org-agenda-deadline-leaders)
4287 (if (functionp
4288 (nth 1 org-agenda-deadline-leaders))
4289 (funcall
4290 (nth 1 org-agenda-deadline-leaders)
4291 diff date)
4292 (format (nth 1 org-agenda-deadline-leaders)
4293 diff)))
4294 head category tags
4295 (if (not (= diff 0)) nil timestr)))))
20908596
CD
4296 (when txt
4297 (setq face (org-agenda-deadline-face dfrac wdays))
4298 (org-add-props txt props
4299 'org-marker (org-agenda-new-marker pos)
4300 'org-hd-marker (org-agenda-new-marker pos1)
4301 'priority (+ (- diff)
4302 (org-get-priority txt))
4303 'org-category category
621f83e4 4304 'todo-state todo-state
20908596
CD
4305 'type (if upcomingp "upcoming-deadline" "deadline")
4306 'date (if upcomingp date d2)
c8d0cf5c
CD
4307 'face (if donep 'org-agenda-done face)
4308 'undone-face face 'done-face 'org-agenda-done)
20908596
CD
4309 (push txt ee))))))
4310 (nreverse ee)))
4311
4312(defun org-agenda-deadline-face (fraction &optional wdays)
4313 "Return the face to displaying a deadline item.
4314FRACTION is what fraction of the head-warning time has passed."
4315 (if (equal wdays 0) (setq fraction 1.))
4316 (let ((faces org-agenda-deadline-faces) f)
4317 (catch 'exit
4318 (while (setq f (pop faces))
4319 (if (>= fraction (car f)) (throw 'exit (cdr f)))))))
4320
54a0dee5 4321(defun org-agenda-get-scheduled (&optional deadline-results)
20908596
CD
4322 "Return the scheduled information for agenda display."
4323 (let* ((props (list 'org-not-done-regexp org-not-done-regexp
4324 'org-todo-regexp org-todo-regexp
b349f79f 4325 'org-complex-heading-regexp org-complex-heading-regexp
c8d0cf5c 4326 'done-face 'org-agenda-done
20908596 4327 'mouse-face 'highlight
20908596
CD
4328 'help-echo
4329 (format "mouse-2 or RET jump to org file %s"
4330 (abbreviate-file-name buffer-file-name))))
4331 (regexp org-scheduled-time-regexp)
621f83e4 4332 (todayp (org-agenda-todayp date)) ; DATE bound by calendar
20908596 4333 (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar
54a0dee5
CD
4334 mm
4335 (deadline-position-alist
4336 (mapcar (lambda (a) (and (setq mm (get-text-property
8bfe682a
CD
4337 0 'org-hd-marker a))
4338 (cons (marker-position mm) a)))
54a0dee5 4339 deadline-results))
621f83e4 4340 d2 diff pos pos1 category tags donep
8bfe682a 4341 ee txt head pastschedp todo-state face timestr s habitp)
20908596
CD
4342 (goto-char (point-min))
4343 (while (re-search-forward regexp nil t)
4344 (catch :skip
4345 (org-agenda-skip)
4346 (setq s (match-string 1)
c8d0cf5c 4347 txt nil
20908596
CD
4348 pos (1- (match-beginning 1))
4349 d2 (org-time-string-to-absolute
4350 (match-string 1) d1 'past
4351 org-agenda-repeating-timestamp-show-all)
4352 diff (- d2 d1))
4353 (setq pastschedp (and todayp (< diff 0)))
4354 ;; When to show a scheduled item in the calendar:
4355 ;; If it is on or past the date.
8bfe682a
CD
4356 (when (or (and (< diff 0)
4357 (< (abs diff) org-scheduled-past-days)
4358 (and todayp (not org-agenda-only-exact-dates)))
4359 (= diff 0))
4360 (save-excursion
4361 (setq todo-state (org-get-todo-state))
4362 (setq donep (member todo-state org-done-keywords))
4363 (setq habitp (and (functionp 'org-is-habit-p)
4364 (org-is-habit-p)))
4365 (if (and donep
4366 (or habitp org-agenda-skip-scheduled-if-done
4367 (not (= diff 0))))
4368 (setq txt nil)
4369 (setq category (org-get-category))
4370 (if (not (re-search-backward "^\\*+[ \t]+" nil t))
4371 (setq txt org-agenda-no-heading-message)
4372 (goto-char (match-end 0))
4373 (setq pos1 (match-beginning 0))
4374 (if habitp
4375 (if (or (not org-habit-show-habits)
4376 (and (not todayp)
4377 org-habit-show-habits-only-for-today))
4378 (throw :skip nil))
54a0dee5
CD
4379 (if (and
4380 (or (eq t org-agenda-skip-scheduled-if-deadline-is-shown)
4381 (and org-agenda-skip-scheduled-if-deadline-is-shown
4382 pastschedp))
4383 (setq mm (assoc pos1 deadline-position-alist)))
8bfe682a
CD
4384 (throw :skip nil)))
4385 (setq tags (org-get-tags-at))
4386 (setq head (buffer-substring-no-properties
4387 (point)
4388 (progn (skip-chars-forward "^\r\n") (point))))
4389 (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
4390 (setq timestr
4391 (concat (substring s (match-beginning 1)) " "))
4392 (setq timestr 'time))
4393 (setq txt (org-format-agenda-item
4394 (if (= diff 0)
4395 (car org-agenda-scheduled-leaders)
4396 (format (nth 1 org-agenda-scheduled-leaders)
4397 (- 1 diff)))
4398 head category tags
4399 (if (not (= diff 0)) nil timestr)
4400 nil nil habitp))))
4401 (when txt
4402 (setq face
4403 (cond
4404 ((and (not habitp) pastschedp)
4405 'org-scheduled-previously)
4406 (todayp 'org-scheduled-today)
4407 (t 'org-scheduled))
4408 habitp (and habitp (org-habit-parse-todo)))
4409 (org-add-props txt props
4410 'undone-face face
4411 'face (if donep 'org-agenda-done face)
4412 'org-marker (org-agenda-new-marker pos)
4413 'org-hd-marker (org-agenda-new-marker pos1)
4414 'type (if pastschedp "past-scheduled" "scheduled")
4415 'date (if pastschedp d2 date)
4416 'priority (if habitp
4417 (org-habit-get-priority habitp)
4418 (+ 94 (- 5 diff) (org-get-priority txt)))
4419 'org-category category
4420 'org-habit-p habitp
4421 'todo-state todo-state)
4422 (push txt ee))))))
20908596
CD
4423 (nreverse ee)))
4424
4425(defun org-agenda-get-blocks ()
4426 "Return the date-range information for agenda display."
4427 (let* ((props (list 'face nil
4428 'org-not-done-regexp org-not-done-regexp
4429 'org-todo-regexp org-todo-regexp
b349f79f 4430 'org-complex-heading-regexp org-complex-heading-regexp
20908596 4431 'mouse-face 'highlight
20908596
CD
4432 'help-echo
4433 (format "mouse-2 or RET jump to org file %s"
4434 (abbreviate-file-name buffer-file-name))))
4435 (regexp org-tr-regexp)
4436 (d0 (calendar-absolute-from-gregorian date))
621f83e4 4437 marker hdmarker ee txt d1 d2 s1 s2 timestr category todo-state tags pos
c8d0cf5c 4438 head donep)
20908596
CD
4439 (goto-char (point-min))
4440 (while (re-search-forward regexp nil t)
4441 (catch :skip
4442 (org-agenda-skip)
4443 (setq pos (point))
4444 (setq timestr (match-string 0)
4445 s1 (match-string 1)
4446 s2 (match-string 2)
4447 d1 (time-to-days (org-time-string-to-time s1))
4448 d2 (time-to-days (org-time-string-to-time s2)))
4449 (if (and (> (- d0 d1) -1) (> (- d2 d0) -1))
4450 ;; Only allow days between the limits, because the normal
4451 ;; date stamps will catch the limits.
4452 (save-excursion
c8d0cf5c
CD
4453 (setq todo-state (org-get-todo-state))
4454 (setq donep (member todo-state org-done-keywords))
4455 (if (and donep org-agenda-skip-timestamp-if-done)
4456 (throw :skip t))
20908596
CD
4457 (setq marker (org-agenda-new-marker (point)))
4458 (setq category (org-get-category))
c8d0cf5c
CD
4459 (if (not (re-search-backward "^\\*+ " nil t))
4460 (setq txt org-agenda-no-heading-message)
4461 (goto-char (match-beginning 0))
4462 (setq hdmarker (org-agenda-new-marker (point)))
4463 (setq tags (org-get-tags-at))
4464 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
4465 (setq head (match-string 1))
4466 (setq txt (org-format-agenda-item
4467 (format
4468 (nth (if (= d1 d2) 0 1)
4469 org-agenda-timerange-leaders)
4470 (1+ (- d0 d1)) (1+ (- d2 d1)))
4471 head category tags
4472 (if (= d0 d1) timestr))))
20908596
CD
4473 (org-add-props txt props
4474 'org-marker marker 'org-hd-marker hdmarker
4475 'type "block" 'date date
621f83e4 4476 'todo-state todo-state
20908596
CD
4477 'priority (org-get-priority txt) 'org-category category)
4478 (push txt ee)))
4479 (goto-char pos)))
4480 ;; Sort the entries by expiration date.
4481 (nreverse ee)))
4482
4483;;; Agenda presentation and sorting
4484
4485(defvar org-prefix-has-time nil
4486 "A flag, set by `org-compile-prefix-format'.
4487The flag is set if the currently compiled format contains a `%t'.")
4488(defvar org-prefix-has-tag nil
4489 "A flag, set by `org-compile-prefix-format'.
4490The flag is set if the currently compiled format contains a `%T'.")
4491(defvar org-prefix-has-effort nil
4492 "A flag, set by `org-compile-prefix-format'.
4493The flag is set if the currently compiled format contains a `%e'.")
8d642074
CD
4494(defvar org-prefix-category-length nil
4495 "Used by `org-compile-prefix-format' to remember the category field widh.")
8bfe682a
CD
4496(defvar org-prefix-category-max-length nil
4497 "Used by `org-compile-prefix-format' to remember the category field widh.")
20908596
CD
4498
4499(defun org-format-agenda-item (extra txt &optional category tags dotime
8bfe682a 4500 noprefix remove-re habitp)
20908596
CD
4501 "Format TXT to be inserted into the agenda buffer.
4502In particular, it adds the prefix and corresponding text properties. EXTRA
4503must be a string and replaces the `%s' specifier in the prefix format.
4504CATEGORY (string, symbol or nil) may be used to overrule the default
4505category taken from local variable or file name. It will replace the `%c'
4506specifier in the format. DOTIME, when non-nil, indicates that a
4507time-of-day should be extracted from TXT for sorting of this entry, and for
4508the `%t' specifier in the format. When DOTIME is a string, this string is
4509searched for a time before TXT is. NOPREFIX is a flag and indicates that
4510only the correctly processes TXT should be returned - this is used by
4511`org-agenda-change-all-lines'. TAGS can be the tags of the headline.
4512Any match of REMOVE-RE will be removed from TXT."
4513 (save-match-data
4514 ;; Diary entries sometimes have extra whitespace at the beginning
4515 (if (string-match "^ +" txt) (setq txt (replace-match "" nil nil txt)))
ff4be292
CD
4516 (when org-agenda-show-inherited-tags
4517 ;; Fix the tags part in txt
4518 (setq txt (org-agenda-add-inherited-tags txt tags)))
20908596
CD
4519 (let* ((category (or category
4520 org-category
4521 (if buffer-file-name
4522 (file-name-sans-extension
4523 (file-name-nondirectory buffer-file-name))
4524 "")))
4525 ;; time, tag, effort are needed for the eval of the prefix format
4526 (tag (if tags (nth (1- (length tags)) tags) ""))
4527 time effort neffort
c8d0cf5c
CD
4528 (ts (if dotime (concat
4529 (if (stringp dotime) dotime "")
4530 (and org-agenda-search-headline-for-time txt))))
20908596 4531 (time-of-day (and dotime (org-get-time-of-day ts)))
8d642074 4532 stamp plain s0 s1 s2 t1 t2 rtn srp l
8bfe682a 4533 duration thecategory)
20908596
CD
4534 (and (org-mode-p) buffer-file-name
4535 (add-to-list 'org-agenda-contributing-files buffer-file-name))
4536 (when (and dotime time-of-day)
4537 ;; Extract starting and ending time and move them to prefix
4538 (when (or (setq stamp (string-match org-stamp-time-of-day-regexp ts))
4539 (setq plain (string-match org-plain-time-of-day-regexp ts)))
4540 (setq s0 (match-string 0 ts)
4541 srp (and stamp (match-end 3))
4542 s1 (match-string (if plain 1 2) ts)
4543 s2 (match-string (if plain 8 (if srp 4 6)) ts))
4544
4545 ;; If the times are in TXT (not in DOTIMES), and the prefix will list
4546 ;; them, we might want to remove them there to avoid duplication.
4547 ;; The user can turn this off with a variable.
4548 (if (and org-prefix-has-time
4549 org-agenda-remove-times-when-in-prefix (or stamp plain)
4550 (string-match (concat (regexp-quote s0) " *") txt)
4551 (not (equal ?\] (string-to-char (substring txt (match-end 0)))))
4552 (if (eq org-agenda-remove-times-when-in-prefix 'beg)
4553 (= (match-beginning 0) 0)
4554 t))
4555 (setq txt (replace-match "" nil nil txt))))
4556 ;; Normalize the time(s) to 24 hour
4557 (if s1 (setq s1 (org-get-time-of-day s1 'string t)))
4558 (if s2 (setq s2 (org-get-time-of-day s2 'string t)))
4559 ;; Compute the duration
4560 (when s1
4561 (setq t1 (+ (* 60 (string-to-number (substring s1 0 2)))
4562 (string-to-number (substring s1 3)))
4563 t2 (cond
4564 (s2 (+ (* 60 (string-to-number (substring s2 0 2)))
4565 (string-to-number (substring s2 3))))
4566 (org-agenda-default-appointment-duration
4567 (+ t1 org-agenda-default-appointment-duration))
4568 (t nil)))
4569 (setq duration (if t2 (- t2 t1)))))
4570
4571 (when (and s1 (not s2) org-agenda-default-appointment-duration
4572 (string-match "\\([0-9]+\\):\\([0-9]+\\)" s1))
4573 (let ((m (+ (string-to-number (match-string 2 s1))
4574 (* 60 (string-to-number (match-string 1 s1)))
4575 org-agenda-default-appointment-duration))
4576 h)
4577 (setq h (/ m 60) m (- m (* h 60)))
4578 (setq s2 (format "%02d:%02d" h m))))
4579
4580 (when (string-match (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@:]+:\\)[ \t]*$")
4581 txt)
4582 ;; Tags are in the string
4583 (if (or (eq org-agenda-remove-tags t)
4584 (and org-agenda-remove-tags
4585 org-prefix-has-tag))
4586 (setq txt (replace-match "" t t txt))
4587 (setq txt (replace-match
4588 (concat (make-string (max (- 50 (length txt)) 1) ?\ )
4589 (match-string 2 txt))
4590 t t txt))))
4591 (when (org-mode-p)
4592 (setq effort
4593 (condition-case nil
4594 (org-get-effort
4595 (or (get-text-property 0 'org-hd-marker txt)
4596 (get-text-property 0 'org-marker txt)))
4597 (error nil)))
4598 (when effort
4599 (setq neffort (org-hh:mm-string-to-minutes effort)
54a0dee5 4600 effort (setq effort (concat "[" effort "]" )))))
20908596
CD
4601
4602 (when remove-re
4603 (while (string-match remove-re txt)
4604 (setq txt (replace-match "" t t txt))))
4605
4606 ;; Create the final string
4607 (if noprefix
4608 (setq rtn txt)
4609 ;; Prepare the variables needed in the eval of the compiled format
4610 (setq time (cond (s2 (concat s1 "-" s2))
4611 (s1 (concat s1 "......"))
4612 (t ""))
8bfe682a
CD
4613 extra (or (and (not habitp) extra) "")
4614 category (if (symbolp category) (symbol-name category) category)
4615 thecategory (copy-sequence category))
4616 (if (string-match org-bracket-link-regexp category)
4617 (progn
4618 (setq l (if (match-end 3)
4619 (- (match-end 3) (match-beginning 3))
4620 (- (match-end 1) (match-beginning 1))))
4621 (when (< l (or org-prefix-category-length 0))
4622 (setq category (copy-sequence category))
4623 (org-add-props category nil
4624 'extra-space (make-string
4625 (- org-prefix-category-length l 1) ?\ ))))
4626 (if (and org-prefix-category-max-length
4627 (>= (length category) org-prefix-category-max-length))
4628 (setq category (substring category 0 (1- org-prefix-category-max-length)))))
20908596
CD
4629 ;; Evaluate the compiled format
4630 (setq rtn (concat (eval org-prefix-format-compiled) txt)))
4631
4632 ;; And finally add the text properties
c8d0cf5c 4633 (remove-text-properties 0 (length rtn) '(line-prefix t wrap-prefix t) rtn)
20908596 4634 (org-add-props rtn nil
8bfe682a 4635 'org-category (if thecategory (downcase thecategory) category)
ff4be292 4636 'tags (mapcar 'org-downcase-keep-props tags)
20908596
CD
4637 'org-highest-priority org-highest-priority
4638 'org-lowest-priority org-lowest-priority
4639 'prefix-length (- (length rtn) (length txt))
4640 'time-of-day time-of-day
4641 'duration duration
4642 'effort effort
4643 'effort-minutes neffort
4644 'txt txt
4645 'time time
4646 'extra extra
4647 'dotime dotime))))
4648
ff4be292
CD
4649(defun org-agenda-add-inherited-tags (txt tags)
4650 "Remove tags string from TXT, and add complete list of tags.
4651The new list includes inherited tags. If any inherited tags are present,
4652a double colon separates inherited tags from local tags."
4653 (if (string-match (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@:]+:\\)[ \t]*$") txt)
4654 (setq txt (substring txt 0 (match-beginning 0))))
4655 (when tags
4656 (let ((have-i (get-text-property 0 'inherited (car tags)))
4657 i)
4658 (setq txt (concat txt " :"
4659 (mapconcat
4660 (lambda (x)
4661 (setq i (get-text-property 0 'inherited x))
4662 (if (and have-i (not i))
4663 (progn
4664 (setq have-i nil)
4665 (concat ":" x))
4666 x))
4667 tags ":")
4668 (if have-i "::" ":")))))
4669 txt)
4670
4671(defun org-downcase-keep-props (s)
4672 (let ((props (text-properties-at 0 s)))
4673 (setq s (downcase s))
4674 (add-text-properties 0 (length s) props s)
4675 s))
4676
20908596
CD
4677(defvar org-agenda-sorting-strategy) ;; because the def is in a let form
4678(defvar org-agenda-sorting-strategy-selected nil)
4679
4680(defun org-agenda-add-time-grid-maybe (list ndays todayp)
4681 (catch 'exit
4682 (cond ((not org-agenda-use-time-grid) (throw 'exit list))
4683 ((and todayp (member 'today (car org-agenda-time-grid))))
4684 ((and (= ndays 1) (member 'daily (car org-agenda-time-grid))))
4685 ((member 'weekly (car org-agenda-time-grid)))
4686 (t (throw 'exit list)))
4687 (let* ((have (delq nil (mapcar
4688 (lambda (x) (get-text-property 1 'time-of-day x))
4689 list)))
4690 (string (nth 1 org-agenda-time-grid))
4691 (gridtimes (nth 2 org-agenda-time-grid))
4692 (req (car org-agenda-time-grid))
4693 (remove (member 'remove-match req))
4694 new time)
4695 (if (and (member 'require-timed req) (not have))
4696 ;; don't show empty grid
4697 (throw 'exit list))
4698 (while (setq time (pop gridtimes))
4699 (unless (and remove (member time have))
4700 (setq time (int-to-string time))
4701 (push (org-format-agenda-item
4702 nil string "" nil
4703 (concat (substring time 0 -2) ":" (substring time -2)))
4704 new)
4705 (put-text-property
4706 1 (length (car new)) 'face 'org-time-grid (car new))))
4707 (if (member 'time-up org-agenda-sorting-strategy-selected)
4708 (append new list)
4709 (append list new)))))
4710
4711(defun org-compile-prefix-format (key)
4712 "Compile the prefix format into a Lisp form that can be evaluated.
4713The resulting form is returned and stored in the variable
4714`org-prefix-format-compiled'."
4715 (setq org-prefix-has-time nil org-prefix-has-tag nil
8d642074 4716 org-prefix-category-length nil org-prefix-has-effort nil)
20908596
CD
4717 (let ((s (cond
4718 ((stringp org-agenda-prefix-format)
4719 org-agenda-prefix-format)
4720 ((assq key org-agenda-prefix-format)
4721 (cdr (assq key org-agenda-prefix-format)))
4722 (t " %-12:c%?-12t% s")))
4723 (start 0)
4724 varform vars var e c f opt)
4725 (while (string-match "%\\(\\?\\)?\\([-+]?[0-9.]*\\)\\([ .;,:!?=|/<>]?\\)\\([ctse]\\)"
4726 s start)
4727 (setq var (cdr (assoc (match-string 4 s)
4728 '(("c" . category) ("t" . time) ("s" . extra)
4729 ("T" . tag) ("e" . effort))))
4730 c (or (match-string 3 s) "")
4731 opt (match-beginning 1)
4732 start (1+ (match-beginning 0)))
4733 (if (equal var 'time) (setq org-prefix-has-time t))
4734 (if (equal var 'tag) (setq org-prefix-has-tag t))
4735 (if (equal var 'effort) (setq org-prefix-has-effort t))
4736 (setq f (concat "%" (match-string 2 s) "s"))
8bfe682a
CD
4737 (when (equal var 'category)
4738 (setq org-prefix-category-length
4739 (floor (abs (string-to-number (match-string 2 s)))))
4740 (setq org-prefix-category-max-length
4741 (let ((x (match-string 2 s)))
4742 (save-match-data
4743 (if (string-match "\\.[0-9]+" x)
4744 (string-to-number (substring (match-string 0 x) 1)))))))
20908596
CD
4745 (if opt
4746 (setq varform
4747 `(if (equal "" ,var)
4748 ""
4749 (format ,f (if (equal "" ,var) "" (concat ,var ,c)))))
8d642074 4750 (setq varform `(format ,f (if (equal ,var "") "" (concat ,var ,c (get-text-property 0 'extra-space ,var))))))
20908596
CD
4751 (setq s (replace-match "%s" t nil s))
4752 (push varform vars))
4753 (setq vars (nreverse vars))
4754 (setq org-prefix-format-compiled `(format ,s ,@vars))))
4755
4756(defun org-set-sorting-strategy (key)
4757 (if (symbolp (car org-agenda-sorting-strategy))
4758 ;; the old format
4759 (setq org-agenda-sorting-strategy-selected org-agenda-sorting-strategy)
4760 (setq org-agenda-sorting-strategy-selected
4761 (or (cdr (assq key org-agenda-sorting-strategy))
4762 (cdr (assq 'agenda org-agenda-sorting-strategy))
4763 '(time-up category-keep priority-down)))))
4764
4765(defun org-get-time-of-day (s &optional string mod24)
4766 "Check string S for a time of day.
4767If found, return it as a military time number between 0 and 2400.
4768If not found, return nil.
4769The optional STRING argument forces conversion into a 5 character wide string
4770HH:MM."
4771 (save-match-data
4772 (when
4773 (or (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)\\([AaPp][Mm]\\)?\\> *" s)
4774 (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?\\([AaPp][Mm]\\)\\> *" s))
4775 (let* ((h (string-to-number (match-string 1 s)))
4776 (m (if (match-end 3) (string-to-number (match-string 3 s)) 0))
4777 (ampm (if (match-end 4) (downcase (match-string 4 s))))
4778 (am-p (equal ampm "am"))
4779 (h1 (cond ((not ampm) h)
4780 ((= h 12) (if am-p 0 12))
4781 (t (+ h (if am-p 0 12)))))
4782 (h2 (if (and string mod24 (not (and (= m 0) (= h1 24))))
4783 (mod h1 24) h1))
4784 (t0 (+ (* 100 h2) m))
4785 (t1 (concat (if (>= h1 24) "+" " ")
4786 (if (< t0 100) "0" "")
4787 (if (< t0 10) "0" "")
4788 (int-to-string t0))))
4789 (if string (concat (substring t1 -4 -2) ":" (substring t1 -2)) t0)))))
4790
4791(defun org-finalize-agenda-entries (list &optional nosort)
4792 "Sort and concatenate the agenda items."
4793 (setq list (mapcar 'org-agenda-highlight-todo list))
4794 (if nosort
4795 list
4796 (mapconcat 'identity (sort list 'org-entries-lessp) "\n")))
4797
4798(defun org-agenda-highlight-todo (x)
621f83e4
CD
4799 (let ((org-done-keywords org-done-keywords-for-agenda)
4800 re pl)
20908596
CD
4801 (if (eq x 'line)
4802 (save-excursion
4803 (beginning-of-line 1)
8d642074
CD
4804 (setq re (org-get-at-bol 'org-todo-regexp))
4805 (goto-char (+ (point) (or (org-get-at-bol 'prefix-length) 0)))
621f83e4 4806 (when (looking-at (concat "[ \t]*\\.*\\(" re "\\) +"))
c8d0cf5c 4807 (add-text-properties (match-beginning 0) (match-end 1)
621f83e4 4808 (list 'face (org-get-todo-face 1)))
20908596
CD
4809 (let ((s (buffer-substring (match-beginning 1) (match-end 1))))
4810 (delete-region (match-beginning 1) (1- (match-end 0)))
4811 (goto-char (match-beginning 1))
4812 (insert (format org-agenda-todo-keyword-format s)))))
4813 (setq re (concat (get-text-property 0 'org-todo-regexp x))
4814 pl (get-text-property 0 'prefix-length x))
4815 (when (and re
4816 (equal (string-match (concat "\\(\\.*\\)" re "\\( +\\)")
4817 x (or pl 0)) pl))
4818 (add-text-properties
4819 (or (match-end 1) (match-end 0)) (match-end 0)
4820 (list 'face (org-get-todo-face (match-string 2 x)))
4821 x)
4822 (setq x (concat (substring x 0 (match-end 1))
4823 (format org-agenda-todo-keyword-format
4824 (match-string 2 x))
8d642074 4825 (org-add-props " " (text-properties-at 0 x))
20908596
CD
4826 (substring x (match-end 3)))))
4827 x)))
4828
4829(defsubst org-cmp-priority (a b)
4830 "Compare the priorities of string A and B."
4831 (let ((pa (or (get-text-property 1 'priority a) 0))
4832 (pb (or (get-text-property 1 'priority b) 0)))
4833 (cond ((> pa pb) +1)
4834 ((< pa pb) -1)
4835 (t nil))))
4836
4837(defsubst org-cmp-effort (a b)
4838 "Compare the priorities of string A and B."
4839 (let* ((def (if org-sort-agenda-noeffort-is-high 32767 -1))
4840 (ea (or (get-text-property 1 'effort-minutes a) def))
4841 (eb (or (get-text-property 1 'effort-minutes b) def)))
4842 (cond ((> ea eb) +1)
4843 ((< ea eb) -1)
4844 (t nil))))
4845
4846(defsubst org-cmp-category (a b)
4847 "Compare the string values of categories of strings A and B."
4848 (let ((ca (or (get-text-property 1 'org-category a) ""))
4849 (cb (or (get-text-property 1 'org-category b) "")))
4850 (cond ((string-lessp ca cb) -1)
4851 ((string-lessp cb ca) +1)
4852 (t nil))))
4853
621f83e4
CD
4854(defsubst org-cmp-todo-state (a b)
4855 "Compare the todo states of strings A and B."
c8d0cf5c
CD
4856 (let* ((ma (or (get-text-property 1 'org-marker a)
4857 (get-text-property 1 'org-hd-marker a)))
4858 (mb (or (get-text-property 1 'org-marker b)
4859 (get-text-property 1 'org-hd-marker b)))
4860 (fa (and ma (marker-buffer ma)))
4861 (fb (and mb (marker-buffer mb)))
4862 (todo-kwds
4863 (or (and fa (with-current-buffer fa org-todo-keywords-1))
4864 (and fb (with-current-buffer fb org-todo-keywords-1))))
4865 (ta (or (get-text-property 1 'todo-state a) ""))
621f83e4 4866 (tb (or (get-text-property 1 'todo-state b) ""))
c8d0cf5c
CD
4867 (la (- (length (member ta todo-kwds))))
4868 (lb (- (length (member tb todo-kwds))))
ff4be292 4869 (donepa (member ta org-done-keywords-for-agenda))
621f83e4
CD
4870 (donepb (member tb org-done-keywords-for-agenda)))
4871 (cond ((and donepa (not donepb)) -1)
4872 ((and (not donepa) donepb) +1)
4873 ((< la lb) -1)
4874 ((< lb la) +1)
4875 (t nil))))
4876
20908596 4877(defsubst org-cmp-tag (a b)
71d35b24 4878 "Compare the string values of the first tags of A and B."
20908596
CD
4879 (let ((ta (car (last (get-text-property 1 'tags a))))
4880 (tb (car (last (get-text-property 1 'tags b)))))
4881 (cond ((not ta) +1)
4882 ((not tb) -1)
4883 ((string-lessp ta tb) -1)
4884 ((string-lessp tb ta) +1)
4885 (t nil))))
4886
4887(defsubst org-cmp-time (a b)
4888 "Compare the time-of-day values of strings A and B."
4889 (let* ((def (if org-sort-agenda-notime-is-late 9901 -1))
4890 (ta (or (get-text-property 1 'time-of-day a) def))
4891 (tb (or (get-text-property 1 'time-of-day b) def)))
4892 (cond ((< ta tb) -1)
4893 ((< tb ta) +1)
4894 (t nil))))
4895
8bfe682a
CD
4896(defsubst org-cmp-habit-p (a b)
4897 "Compare the todo states of strings A and B."
4898 (let ((ha (get-text-property 1 'org-habit-p a))
4899 (hb (get-text-property 1 'org-habit-p b)))
4900 (cond ((and ha (not hb)) -1)
4901 ((and (not ha) hb) +1)
4902 (t nil))))
4903
20908596
CD
4904(defun org-entries-lessp (a b)
4905 "Predicate for sorting agenda entries."
4906 ;; The following variables will be used when the form is evaluated.
4907 ;; So even though the compiler complains, keep them.
4908 (let* ((time-up (org-cmp-time a b))
4909 (time-down (if time-up (- time-up) nil))
4910 (priority-up (org-cmp-priority a b))
4911 (priority-down (if priority-up (- priority-up) nil))
4912 (effort-up (org-cmp-effort a b))
4913 (effort-down (if effort-up (- effort-up) nil))
4914 (category-up (org-cmp-category a b))
4915 (category-down (if category-up (- category-up) nil))
4916 (category-keep (if category-up +1 nil))
4917 (tag-up (org-cmp-tag a b))
621f83e4
CD
4918 (tag-down (if tag-up (- tag-up) nil))
4919 (todo-state-up (org-cmp-todo-state a b))
c8d0cf5c 4920 (todo-state-down (if todo-state-up (- todo-state-up) nil))
8bfe682a
CD
4921 (habit-up (org-cmp-habit-p a b))
4922 (habit-down (if habit-up (- habit-up) nil))
c8d0cf5c
CD
4923 user-defined-up user-defined-down)
4924 (if (and org-agenda-cmp-user-defined
4925 (functionp org-agenda-cmp-user-defined))
4926 (setq user-defined-up
4927 (funcall org-agenda-cmp-user-defined a b)
4928 user-defined-down (if user-defined-up (- user-defined-up) nil)))
20908596
CD
4929 (cdr (assoc
4930 (eval (cons 'or org-agenda-sorting-strategy-selected))
4931 '((-1 . t) (1 . nil) (nil . nil))))))
4932
4933;;; Agenda restriction lock
4934
4935(defvar org-agenda-restriction-lock-overlay (org-make-overlay 1 1)
8bfe682a 4936 "Overlay to mark the headline to which agenda commands are restricted.")
20908596
CD
4937(org-overlay-put org-agenda-restriction-lock-overlay
4938 'face 'org-agenda-restriction-lock)
4939(org-overlay-put org-agenda-restriction-lock-overlay
4940 'help-echo "Agendas are currently limited to this subtree.")
4941(org-detach-overlay org-agenda-restriction-lock-overlay)
4942
4943(defun org-agenda-set-restriction-lock (&optional type)
4944 "Set restriction lock for agenda, to current subtree or file.
4945Restriction will be the file if TYPE is `file', or if type is the
4946universal prefix '(4), or if the cursor is before the first headline
4947in the file. Otherwise, restriction will be to the current subtree."
4948 (interactive "P")
4949 (and (equal type '(4)) (setq type 'file))
4950 (setq type (cond
4951 (type type)
4952 ((org-at-heading-p) 'subtree)
4953 ((condition-case nil (org-back-to-heading t) (error nil))
4954 'subtree)
4955 (t 'file)))
4956 (if (eq type 'subtree)
4957 (progn
4958 (setq org-agenda-restrict t)
4959 (setq org-agenda-overriding-restriction 'subtree)
4960 (put 'org-agenda-files 'org-restrict
4961 (list (buffer-file-name (buffer-base-buffer))))
4962 (org-back-to-heading t)
4963 (org-move-overlay org-agenda-restriction-lock-overlay (point) (point-at-eol))
4964 (move-marker org-agenda-restrict-begin (point))
4965 (move-marker org-agenda-restrict-end
4966 (save-excursion (org-end-of-subtree t)))
4967 (message "Locking agenda restriction to subtree"))
4968 (put 'org-agenda-files 'org-restrict
4969 (list (buffer-file-name (buffer-base-buffer))))
4970 (setq org-agenda-restrict nil)
4971 (setq org-agenda-overriding-restriction 'file)
4972 (move-marker org-agenda-restrict-begin nil)
4973 (move-marker org-agenda-restrict-end nil)
4974 (message "Locking agenda restriction to file"))
4975 (setq current-prefix-arg nil)
4976 (org-agenda-maybe-redo))
4977
4978(defun org-agenda-remove-restriction-lock (&optional noupdate)
4979 "Remove the agenda restriction lock."
4980 (interactive "P")
4981 (org-detach-overlay org-agenda-restriction-lock-overlay)
4982 (org-detach-overlay org-speedbar-restriction-lock-overlay)
4983 (setq org-agenda-overriding-restriction nil)
4984 (setq org-agenda-restrict nil)
4985 (put 'org-agenda-files 'org-restrict nil)
4986 (move-marker org-agenda-restrict-begin nil)
4987 (move-marker org-agenda-restrict-end nil)
4988 (setq current-prefix-arg nil)
4989 (message "Agenda restriction lock removed")
4990 (or noupdate (org-agenda-maybe-redo)))
4991
4992(defun org-agenda-maybe-redo ()
4993 "If there is any window showing the agenda view, update it."
4994 (let ((w (get-buffer-window org-agenda-buffer-name t))
4995 (w0 (selected-window)))
4996 (when w
4997 (select-window w)
4998 (org-agenda-redo)
4999 (select-window w0)
5000 (if org-agenda-overriding-restriction
5001 (message "Agenda view shifted to new %s restriction"
5002 org-agenda-overriding-restriction)
5003 (message "Agenda restriction lock removed")))))
5004
5005;;; Agenda commands
5006
5007(defun org-agenda-check-type (error &rest types)
5008 "Check if agenda buffer is of allowed type.
5009If ERROR is non-nil, throw an error, otherwise just return nil."
5010 (if (memq org-agenda-type types)
5011 t
5012 (if error
5013 (error "Not allowed in %s-type agenda buffers" org-agenda-type)
5014 nil)))
5015
5016(defun org-agenda-quit ()
5017 "Exit agenda by removing the window or the buffer."
5018 (interactive)
5019 (if org-agenda-columns-active
5020 (org-columns-quit)
5021 (let ((buf (current-buffer)))
8d642074
CD
5022 (if (eq org-agenda-window-setup 'other-frame)
5023 (progn
5024 (kill-buffer buf)
5025 (org-agenda-reset-markers)
5026 (org-columns-remove-overlays)
5027 (setq org-agenda-archives-mode nil)
5028 (delete-frame))
5029 (and (not (eq org-agenda-window-setup 'current-window))
5030 (not (one-window-p))
5031 (delete-window))
5032 (kill-buffer buf)
5033 (org-agenda-reset-markers)
5034 (org-columns-remove-overlays)
5035 (setq org-agenda-archives-mode nil)))
20908596
CD
5036 ;; Maybe restore the pre-agenda window configuration.
5037 (and org-agenda-restore-windows-after-quit
5038 (not (eq org-agenda-window-setup 'other-frame))
5039 org-pre-agenda-window-conf
5040 (set-window-configuration org-pre-agenda-window-conf))))
5041
5042(defun org-agenda-exit ()
5043 "Exit agenda by removing the window or the buffer.
5044Also kill all Org-mode buffers which have been loaded by `org-agenda'.
5045Org-mode buffers visited directly by the user will not be touched."
5046 (interactive)
5047 (org-release-buffers org-agenda-new-buffers)
5048 (setq org-agenda-new-buffers nil)
5049 (org-agenda-quit))
5050
5051(defun org-agenda-execute (arg)
5052 "Execute another agenda command, keeping same window.\\<global-map>
5053So this is just a shortcut for `\\[org-agenda]', available in the agenda."
5054 (interactive "P")
5055 (let ((org-agenda-window-setup 'current-window))
5056 (org-agenda arg)))
5057
20908596
CD
5058(defun org-agenda-redo ()
5059 "Rebuild Agenda.
5060When this is the global TODO list, a prefix argument will be interpreted."
5061 (interactive)
5062 (let* ((org-agenda-keep-modes t)
71d35b24 5063 (filter org-agenda-filter)
c8d0cf5c 5064 (preset (get 'org-agenda-filter :preset-filter))
20908596
CD
5065 (cols org-agenda-columns-active)
5066 (line (org-current-line))
5067 (window-line (- line (org-current-line (window-start))))
5068 (lprops (get 'org-agenda-redo-command 'org-lprops)))
c8d0cf5c 5069 (put 'org-agenda-filter :preset-filter nil)
20908596
CD
5070 (and cols (org-columns-quit))
5071 (message "Rebuilding agenda buffer...")
5072 (org-let lprops '(eval org-agenda-redo-command))
5073 (setq org-agenda-undo-list nil
5074 org-agenda-pending-undo-list nil)
5075 (message "Rebuilding agenda buffer...done")
c8d0cf5c
CD
5076 (put 'org-agenda-filter :preset-filter preset)
5077 (and (or filter preset) (org-agenda-filter-apply filter))
20908596 5078 (and cols (interactive-p) (org-agenda-columns))
54a0dee5 5079 (org-goto-line line)
20908596
CD
5080 (recenter window-line)))
5081
71d35b24 5082
621f83e4 5083(defvar org-global-tags-completion-table nil)
71d35b24
CD
5084(defvar org-agenda-filter-form nil)
5085(defun org-agenda-filter-by-tag (strip &optional char narrow)
621f83e4
CD
5086 "Keep only those lines in the agenda buffer that have a specific tag.
5087The tag is selected with its fast selection letter, as configured.
71d35b24
CD
5088With prefix argument STRIP, remove all lines that do have the tag.
5089A lisp caller can specify CHAR. NARROW means that the new tag should be
5090used to narrow the search - the interactive user can also press `-' or `+'
5091to switch to narrowing."
621f83e4 5092 (interactive "P")
71d35b24 5093 (let* ((alist org-tag-alist-for-agenda)
8bfe682a
CD
5094 (tag-chars (mapconcat
5095 (lambda (x) (if (and (not (symbolp (car x)))
5096 (cdr x))
5097 (char-to-string (cdr x))
5098 ""))
5099 alist ""))
5100 (efforts (org-split-string
5101 (or (cdr (assoc (concat org-effort-property "_ALL")
5102 org-global-properties))
5103 "0 0:10 0:30 1:00 2:00 3:00 4:00 5:00 6:00 7:00 8:00" "")))
5104 (effort-op org-agenda-filter-effort-default-operator)
5105 (effort-prompt "")
5106 (inhibit-read-only t)
5107 (current org-agenda-filter)
5108 char a n tag)
71d35b24 5109 (unless char
ff4be292 5110 (message
8bfe682a
CD
5111 "%s by tag [%s ], [TAB], %s[/]:off, [+-]:narrow, [>=<?]:effort: "
5112 (if narrow "Narrow" "Filter") tag-chars
5113 (if org-agenda-auto-exclude-function "[RET], " ""))
71d35b24
CD
5114 (setq char (read-char)))
5115 (when (member char '(?+ ?-))
5116 ;; Narrowing down
5117 (cond ((equal char ?-) (setq strip t narrow t))
5118 ((equal char ?+) (setq strip nil narrow t)))
ff4be292 5119 (message
71d35b24
CD
5120 "Narrow by tag [%s ], [TAB], [/]:off, [>=<]:effort: " tag-chars)
5121 (setq char (read-char)))
c8d0cf5c 5122 (when (member char '(?< ?> ?= ??))
71d35b24
CD
5123 ;; An effort operator
5124 (setq effort-op (char-to-string char))
71d35b24 5125 (setq alist nil) ; to make sure it will be interpreted as effort.
c8d0cf5c
CD
5126 (unless (equal char ??)
5127 (loop for i from 0 to 9 do
5128 (setq effort-prompt
5129 (concat
5130 effort-prompt " ["
5131 (if (= i 9) "0" (int-to-string (1+ i)))
5132 "]" (nth i efforts))))
5133 (message "Effort%s: %s " effort-op effort-prompt)
5134 (setq char (read-char))
5135 (when (or (< char ?0) (> char ?9))
5136 (error "Need 1-9,0 to select effort" ))))
71d35b24
CD
5137 (when (equal char ?\t)
5138 (unless (local-variable-p 'org-global-tags-completion-table (current-buffer))
5139 (org-set-local 'org-global-tags-completion-table
5140 (org-global-tags-completion-table)))
5141 (let ((completion-ignore-case t))
54a0dee5 5142 (setq tag (org-icompleting-read
71d35b24
CD
5143 "Tag: " org-global-tags-completion-table))))
5144 (cond
8bfe682a
CD
5145 ((equal char ?\r)
5146 (org-agenda-filter-by-tag-show-all)
5147 (when org-agenda-auto-exclude-function
5148 (setq org-agenda-filter '())
5149 (dolist (tag org-tag-alist-for-agenda)
5150 (let ((modifier (funcall org-agenda-auto-exclude-function
5151 (car tag))))
5152 (if modifier
5153 (push modifier org-agenda-filter))))
5154 (if (not (null org-agenda-filter))
5155 (org-agenda-filter-apply org-agenda-filter))))
c8d0cf5c
CD
5156 ((equal char ?/)
5157 (org-agenda-filter-by-tag-show-all)
5158 (when (get 'org-agenda-filter :preset-filter)
5159 (org-agenda-filter-apply org-agenda-filter)))
71d35b24
CD
5160 ((or (equal char ?\ )
5161 (setq a (rassoc char alist))
5162 (and (>= char ?0) (<= char ?9)
5163 (setq n (if (= char ?0) 9 (- char ?0 1))
5164 tag (concat effort-op (nth n efforts))
5165 a (cons tag nil)))
c8d0cf5c
CD
5166 (and (= char ??)
5167 (setq tag "?eff")
5168 a (cons tag nil))
71d35b24
CD
5169 (and tag (setq a (cons tag nil))))
5170 (org-agenda-filter-by-tag-show-all)
5171 (setq tag (car a))
5172 (setq org-agenda-filter
5173 (cons (concat (if strip "-" "+") tag)
5174 (if narrow current nil)))
5175 (org-agenda-filter-apply org-agenda-filter))
5176 (t (error "Invalid tag selection character %c" char)))))
5177
5178(defun org-agenda-filter-by-tag-refine (strip &optional char)
5179 "Refine the current filter. See `org-agenda-filter-by-tag."
5180 (interactive "P")
5181 (org-agenda-filter-by-tag strip char 'refine))
5182
5183(defun org-agenda-filter-make-matcher ()
5184 "Create the form that tests a line for the agenda filter."
5185 (let (f f1)
c8d0cf5c
CD
5186 (dolist (x (append (get 'org-agenda-filter :preset-filter)
5187 org-agenda-filter))
71d35b24 5188 (if (member x '("-" "+"))
8bfe682a 5189 (setq f1 (if (equal x "-") 'tags '(not tags)))
c8d0cf5c 5190 (if (string-match "[<=>?]" x)
71d35b24
CD
5191 (setq f1 (org-agenda-filter-effort-form x))
5192 (setq f1 (list 'member (downcase (substring x 1)) 'tags)))
5193 (if (equal (string-to-char x) ?-)
5194 (setq f1 (list 'not f1))))
5195 (push f1 f))
5196 (cons 'and (nreverse f))))
5197
5198(defun org-agenda-filter-effort-form (e)
5199 "Return the form to compare the effort of the current line with what E says.
5200E looks line \"+<2:25\"."
5201 (let (op)
5202 (setq e (substring e 1))
5203 (setq op (string-to-char e) e (substring e 1))
c8d0cf5c
CD
5204 (setq op (cond ((equal op ?<) '<=)
5205 ((equal op ?>) '>=)
5206 ((equal op ??) op)
5207 (t '=)))
71d35b24
CD
5208 (list 'org-agenda-compare-effort (list 'quote op)
5209 (org-hh:mm-string-to-minutes e))))
5210
5211(defun org-agenda-compare-effort (op value)
5212 "Compare the effort of the current line with VALUE, using OP.
5213If the line does not have an effort defined, return nil."
8d642074 5214 (let ((eff (org-get-at-bol 'effort-minutes)))
c8d0cf5c
CD
5215 (if (equal op ??)
5216 (not eff)
5217 (funcall op (or eff (if org-sort-agenda-noeffort-is-high 32767 0))
5218 value))))
71d35b24
CD
5219
5220(defun org-agenda-filter-apply (filter)
5221 "Set FILTER as the new agenda filter and apply it."
5222 (let (tags)
5223 (setq org-agenda-filter filter
5224 org-agenda-filter-form (org-agenda-filter-make-matcher))
5225 (org-agenda-set-mode-name)
5226 (save-excursion
5227 (goto-char (point-min))
5228 (while (not (eobp))
8d642074 5229 (if (org-get-at-bol 'org-marker)
71d35b24 5230 (progn
8d642074 5231 (setq tags (org-get-at-bol 'tags)) ; used in eval
71d35b24
CD
5232 (if (not (eval org-agenda-filter-form))
5233 (org-agenda-filter-by-tag-hide-line))
5234 (beginning-of-line 2))
5235 (beginning-of-line 2))))))
621f83e4 5236
621f83e4
CD
5237(defun org-agenda-filter-by-tag-hide-line ()
5238 (let (ov)
5239 (setq ov (org-make-overlay (max (point-min) (1- (point-at-bol)))
5240 (point-at-eol)))
5241 (org-overlay-put ov 'invisible t)
5242 (org-overlay-put ov 'type 'tags-filter)
5243 (push ov org-agenda-filter-overlays)))
5244
71d35b24
CD
5245(defun org-agenda-fix-tags-filter-overlays-at (&optional pos)
5246 (setq pos (or pos (point)))
5247 (save-excursion
5248 (dolist (ov (org-overlays-at pos))
5249 (when (and (org-overlay-get ov 'invisible)
5250 (eq (org-overlay-get ov 'type) 'tags-filter))
5251 (goto-char pos)
5252 (if (< (org-overlay-start ov) (point-at-eol))
5253 (org-move-overlay ov (point-at-eol)
5254 (org-overlay-end ov)))))))
5255
621f83e4
CD
5256(defun org-agenda-filter-by-tag-show-all ()
5257 (mapc 'org-delete-overlay org-agenda-filter-overlays)
71d35b24
CD
5258 (setq org-agenda-filter-overlays nil)
5259 (setq org-agenda-filter nil)
5260 (setq org-agenda-filter-form nil)
5261 (org-agenda-set-mode-name))
621f83e4 5262
20908596
CD
5263(defun org-agenda-manipulate-query-add ()
5264 "Manipulate the query by adding a search term with positive selection.
5265Positive selection means, the term must be matched for selection of an entry."
5266 (interactive)
5267 (org-agenda-manipulate-query ?\[))
5268(defun org-agenda-manipulate-query-subtract ()
5269 "Manipulate the query by adding a search term with negative selection.
5270Negative selection means, term must not be matched for selection of an entry."
5271 (interactive)
5272 (org-agenda-manipulate-query ?\]))
5273(defun org-agenda-manipulate-query-add-re ()
5274 "Manipulate the query by adding a search regexp with positive selection.
5275Positive selection means, the regexp must match for selection of an entry."
5276 (interactive)
5277 (org-agenda-manipulate-query ?\{))
5278(defun org-agenda-manipulate-query-subtract-re ()
5279 "Manipulate the query by adding a search regexp with negative selection.
5280Negative selection means, regexp must not match for selection of an entry."
5281 (interactive)
5282 (org-agenda-manipulate-query ?\}))
5283(defun org-agenda-manipulate-query (char)
5284 (cond
5285 ((memq org-agenda-type '(timeline agenda))
54a0dee5
CD
5286 (let ((org-agenda-include-inactive-timestamps t))
5287 (org-agenda-redo))
5288 (message "Display now includes inactive timestamps as well"))
20908596
CD
5289 ((eq org-agenda-type 'search)
5290 (org-add-to-string
5291 'org-agenda-query-string
5292 (cdr (assoc char '((?\[ . " +") (?\] . " -")
5293 (?\{ . " +{}") (?\} . " -{}")))))
5294 (setq org-agenda-redo-command
5295 (list 'org-search-view
5296 org-todo-only
5297 org-agenda-query-string
5298 (+ (length org-agenda-query-string)
5299 (if (member char '(?\{ ?\})) 0 1))))
5300 (set-register org-agenda-query-register org-agenda-query-string)
5301 (org-agenda-redo))
5302 (t (error "Cannot manipulate query for %s-type agenda buffers"
5303 org-agenda-type))))
5304
5305(defun org-add-to-string (var string)
5306 (set var (concat (symbol-value var) string)))
5307
5308(defun org-agenda-goto-date (date)
5309 "Jump to DATE in agenda."
5310 (interactive (list (org-read-date)))
5311 (org-agenda-list nil date))
5312
5313(defun org-agenda-goto-today ()
5314 "Go to today."
5315 (interactive)
5316 (org-agenda-check-type t 'timeline 'agenda)
5317 (let ((tdpos (text-property-any (point-min) (point-max) 'org-today t)))
5318 (cond
5319 (tdpos (goto-char tdpos))
5320 ((eq org-agenda-type 'agenda)
5321 (let* ((sd (time-to-days
5322 (time-subtract (current-time)
5323 (list 0 (* 3600 org-extend-today-until) 0))))
5324 (comp (org-agenda-compute-time-span sd org-agenda-span))
5325 (org-agenda-overriding-arguments org-agenda-last-arguments))
5326 (setf (nth 1 org-agenda-overriding-arguments) (car comp))
5327 (setf (nth 2 org-agenda-overriding-arguments) (cdr comp))
5328 (org-agenda-redo)
5329 (org-agenda-find-same-or-today-or-agenda)))
5330 (t (error "Cannot find today")))))
5331
5332(defun org-agenda-find-same-or-today-or-agenda (&optional cnt)
5333 (goto-char
5334 (or (and cnt (text-property-any (point-min) (point-max) 'org-day-cnt cnt))
5335 (text-property-any (point-min) (point-max) 'org-today t)
5336 (text-property-any (point-min) (point-max) 'org-agenda-type 'agenda)
5337 (point-min))))
5338
5339(defun org-agenda-later (arg)
5340 "Go forward in time by thee current span.
5341With prefix ARG, go forward that many times the current span."
5342 (interactive "p")
5343 (org-agenda-check-type t 'agenda)
5344 (let* ((span org-agenda-span)
5345 (sd org-starting-day)
5346 (greg (calendar-gregorian-from-absolute sd))
8d642074 5347 (cnt (org-get-at-bol 'org-day-cnt))
20908596
CD
5348 greg2 nd)
5349 (cond
5350 ((eq span 'day)
5351 (setq sd (+ arg sd) nd 1))
5352 ((eq span 'week)
5353 (setq sd (+ (* 7 arg) sd) nd 7))
5354 ((eq span 'month)
5355 (setq greg2 (list (+ (car greg) arg) (nth 1 greg) (nth 2 greg))
5356 sd (calendar-absolute-from-gregorian greg2))
5357 (setcar greg2 (1+ (car greg2)))
5358 (setq nd (- (calendar-absolute-from-gregorian greg2) sd)))
5359 ((eq span 'year)
5360 (setq greg2 (list (car greg) (nth 1 greg) (+ arg (nth 2 greg)))
5361 sd (calendar-absolute-from-gregorian greg2))
5362 (setcar (nthcdr 2 greg2) (1+ (nth 2 greg2)))
5363 (setq nd (- (calendar-absolute-from-gregorian greg2) sd))))
5364 (let ((org-agenda-overriding-arguments
5365 (list (car org-agenda-last-arguments) sd nd t)))
5366 (org-agenda-redo)
5367 (org-agenda-find-same-or-today-or-agenda cnt))))
5368
5369(defun org-agenda-earlier (arg)
5370 "Go backward in time by the current span.
5371With prefix ARG, go backward that many times the current span."
5372 (interactive "p")
5373 (org-agenda-later (- arg)))
5374
c8d0cf5c
CD
5375(defun org-agenda-view-mode-dispatch ()
5376 "Call one of the view mode commands."
5377 (interactive)
5378 (message "View: [d]ay [w]eek [m]onth [y]ear [l]og [L]og-all [a]rch-trees [A]rch-files
54a0dee5 5379 clock[R]eport time[G]rid [[]inactive [E]ntryText include[D]iary")
c8d0cf5c
CD
5380 (let ((a (read-char-exclusive)))
5381 (case a
5382 (?d (call-interactively 'org-agenda-day-view))
5383 (?w (call-interactively 'org-agenda-week-view))
5384 (?m (call-interactively 'org-agenda-month-view))
5385 (?y (call-interactively 'org-agenda-year-view))
5386 (?l (call-interactively 'org-agenda-log-mode))
54a0dee5 5387 ((?F ?f) (call-interactively 'org-agenda-follow-mode))
c8d0cf5c
CD
5388 (?a (call-interactively 'org-agenda-archives-mode))
5389 (?A (org-agenda-archives-mode 'files))
54a0dee5
CD
5390 ((?R ?r) (call-interactively 'org-agenda-clockreport-mode))
5391 ((?E ?e) (call-interactively 'org-agenda-entry-text-mode))
c8d0cf5c
CD
5392 (?G (call-interactively 'org-agenda-toggle-time-grid))
5393 (?D (call-interactively 'org-agenda-toggle-diary))
54a0dee5
CD
5394 (?\[ (let ((org-agenda-include-inactive-timestamps t))
5395 (org-agenda-check-type t 'timeline 'agenda)
5396 (org-agenda-redo))
5397 (message "Display now includes inactive timestamps as well"))
c8d0cf5c
CD
5398 (?q (message "Abort"))
5399 (otherwise (error "Invalid key" )))))
5400
20908596
CD
5401(defun org-agenda-day-view (&optional day-of-year)
5402 "Switch to daily view for agenda.
5403With argument DAY-OF-YEAR, switch to that day of the year."
5404 (interactive "P")
5405 (setq org-agenda-ndays 1)
5406 (org-agenda-change-time-span 'day day-of-year))
5407(defun org-agenda-week-view (&optional iso-week)
5408 "Switch to daily view for agenda.
5409With argument ISO-WEEK, switch to the corresponding ISO week.
5410If ISO-WEEK has more then 2 digits, only the last two encode the
5411week. Any digits before this encode a year. So 200712 means
5412week 12 of year 2007. Years in the range 1938-2037 can also be
5413written as 2-digit years."
5414 (interactive "P")
5415 (setq org-agenda-ndays 7)
5416 (org-agenda-change-time-span 'week iso-week))
5417(defun org-agenda-month-view (&optional month)
b349f79f 5418 "Switch to monthly view for agenda.
20908596
CD
5419With argument MONTH, switch to that month."
5420 (interactive "P")
5421 (org-agenda-change-time-span 'month month))
5422(defun org-agenda-year-view (&optional year)
b349f79f 5423 "Switch to yearly view for agenda.
20908596
CD
5424With argument YEAR, switch to that year.
5425If MONTH has more then 2 digits, only the last two encode the
5426month. Any digits before this encode a year. So 200712 means
5427December year 2007. Years in the range 1938-2037 can also be
5428written as 2-digit years."
5429 (interactive "P")
5430 (when year
5431 (setq year (org-small-year-to-year year)))
5432 (if (y-or-n-p "Are you sure you want to compute the agenda for an entire year? ")
5433 (org-agenda-change-time-span 'year year)
5434 (error "Abort")))
5435
5436(defun org-agenda-change-time-span (span &optional n)
5437 "Change the agenda view to SPAN.
5438SPAN may be `day', `week', `month', `year'."
5439 (org-agenda-check-type t 'agenda)
5440 (if (and (not n) (equal org-agenda-span span))
5441 (error "Viewing span is already \"%s\"" span))
8d642074 5442 (let* ((sd (or (org-get-at-bol 'day)
20908596
CD
5443 org-starting-day))
5444 (computed (org-agenda-compute-time-span sd span n))
5445 (org-agenda-overriding-arguments
5446 (list (car org-agenda-last-arguments)
5447 (car computed) (cdr computed) t)))
5448 (org-agenda-redo)
5449 (org-agenda-find-same-or-today-or-agenda))
5450 (org-agenda-set-mode-name)
5451 (message "Switched to %s view" span))
5452
5453(defun org-agenda-compute-time-span (sd span &optional n)
5454 "Compute starting date and number of days for agenda.
5455SPAN may be `day', `week', `month', `year'. The return value
5456is a cons cell with the starting date and the number of days,
5457so that the date SD will be in that range."
5458 (let* ((greg (calendar-gregorian-from-absolute sd))
5459 (dg (nth 1 greg))
5460 (mg (car greg))
5461 (yg (nth 2 greg))
5462 nd w1 y1 m1 thisweek)
5463 (cond
5464 ((eq span 'day)
5465 (when n
5466 (setq sd (+ (calendar-absolute-from-gregorian
5467 (list mg 1 yg))
5468 n -1)))
5469 (setq nd 1))
5470 ((eq span 'week)
5471 (let* ((nt (calendar-day-of-week
5472 (calendar-gregorian-from-absolute sd)))
5473 (d (if org-agenda-start-on-weekday
5474 (- nt org-agenda-start-on-weekday)
5475 0)))
5476 (setq sd (- sd (+ (if (< d 0) 7 0) d)))
5477 (when n
5478 (require 'cal-iso)
5479 (setq thisweek (car (calendar-iso-from-absolute sd)))
5480 (when (> n 99)
5481 (setq y1 (org-small-year-to-year (/ n 100))
5482 n (mod n 100)))
5483 (setq sd
5484 (calendar-absolute-from-iso
5485 (list n 1
5486 (or y1 (nth 2 (calendar-iso-from-absolute sd)))))))
5487 (setq nd 7)))
5488 ((eq span 'month)
5489 (when (and n (> n 99))
5490 (setq y1 (org-small-year-to-year (/ n 100))
5491 n (mod n 100)))
5492 (setq sd (calendar-absolute-from-gregorian
5493 (list (or n mg) 1 (or y1 yg)))
5494 nd (- (calendar-absolute-from-gregorian
5495 (list (1+ (or n mg)) 1 (or y1 yg)))
5496 sd)))
5497 ((eq span 'year)
5498 (setq sd (calendar-absolute-from-gregorian
5499 (list 1 1 (or n yg)))
5500 nd (- (calendar-absolute-from-gregorian
5501 (list 1 1 (1+ (or n yg))))
5502 sd))))
5503 (cons sd nd)))
5504
5505(defun org-agenda-next-date-line (&optional arg)
5506 "Jump to the next line indicating a date in agenda buffer."
5507 (interactive "p")
5508 (org-agenda-check-type t 'agenda 'timeline)
5509 (beginning-of-line 1)
5510 ;; This does not work if user makes date format that starts with a blank
5511 (if (looking-at "^\\S-") (forward-char 1))
5512 (if (not (re-search-forward "^\\S-" nil t arg))
5513 (progn
5514 (backward-char 1)
5515 (error "No next date after this line in this buffer")))
5516 (goto-char (match-beginning 0)))
5517
5518(defun org-agenda-previous-date-line (&optional arg)
5519 "Jump to the previous line indicating a date in agenda buffer."
5520 (interactive "p")
5521 (org-agenda-check-type t 'agenda 'timeline)
5522 (beginning-of-line 1)
5523 (if (not (re-search-backward "^\\S-" nil t arg))
5524 (error "No previous date before this line in this buffer")))
5525
5526;; Initialize the highlight
5527(defvar org-hl (org-make-overlay 1 1))
5528(org-overlay-put org-hl 'face 'highlight)
5529
5530(defun org-highlight (begin end &optional buffer)
5531 "Highlight a region with overlay."
5532 (funcall (if (featurep 'xemacs) 'set-extent-endpoints 'move-overlay)
5533 org-hl begin end (or buffer (current-buffer))))
5534
5535(defun org-unhighlight ()
5536 "Detach overlay INDEX."
5537 (funcall (if (featurep 'xemacs) 'detach-extent 'delete-overlay) org-hl))
5538
5539;; FIXME this is currently not used.
5540(defun org-highlight-until-next-command (beg end &optional buffer)
5541 "Move the highlight overlay to BEG/END, remove it before the next command."
5542 (org-highlight beg end buffer)
5543 (add-hook 'pre-command-hook 'org-unhighlight-once))
5544(defun org-unhighlight-once ()
5545 "Remove the highlight from its position, and this function from the hook."
5546 (remove-hook 'pre-command-hook 'org-unhighlight-once)
5547 (org-unhighlight))
5548
5549(defun org-agenda-follow-mode ()
5550 "Toggle follow mode in an agenda buffer."
5551 (interactive)
5552 (setq org-agenda-follow-mode (not org-agenda-follow-mode))
5553 (org-agenda-set-mode-name)
8bfe682a
CD
5554 (if (and org-agenda-follow-mode (org-get-at-bol 'org-marker))
5555 (org-agenda-show))
20908596
CD
5556 (message "Follow mode is %s"
5557 (if org-agenda-follow-mode "on" "off")))
5558
54a0dee5
CD
5559(defun org-agenda-entry-text-mode (&optional arg)
5560 "Toggle entry text mode in an agenda buffer."
5561 (interactive "P")
5562 (if (integerp arg)
5563 (setq org-agenda-entry-text-mode t)
5564 (setq org-agenda-entry-text-mode (not org-agenda-entry-text-mode)))
5565 (org-agenda-entry-text-hide)
5566 (and org-agenda-entry-text-mode
5567 (let ((org-agenda-entry-text-maxlines
5568 (if (integerp arg) arg org-agenda-entry-text-maxlines)))
5569 (org-agenda-entry-text-show)))
5570 (org-agenda-set-mode-name)
5571 (message "Entry text mode is %s. Maximum number of lines is %d"
5572 (if org-agenda-entry-text-mode "on" "off")
5573 (if (integerp arg) arg org-agenda-entry-text-maxlines)))
5574
20908596
CD
5575(defun org-agenda-clockreport-mode ()
5576 "Toggle clocktable mode in an agenda buffer."
5577 (interactive)
5578 (org-agenda-check-type t 'agenda)
5579 (setq org-agenda-clockreport-mode (not org-agenda-clockreport-mode))
5580 (org-agenda-set-mode-name)
5581 (org-agenda-redo)
5582 (message "Clocktable mode is %s"
5583 (if org-agenda-clockreport-mode "on" "off")))
5584
93b62de8
CD
5585(defun org-agenda-log-mode (&optional special)
5586 "Toggle log mode in an agenda buffer.
5587With argument SPECIAL, show all possible log items, not only the ones
5588configured in `org-agenda-log-mode-items'.
5589With a double `C-u' prefix arg, show *only* log items, nothing else."
5590 (interactive "P")
20908596 5591 (org-agenda-check-type t 'agenda 'timeline)
93b62de8
CD
5592 (setq org-agenda-show-log
5593 (if (equal special '(16))
5594 'only
5595 (if special '(closed clock state)
5596 (not org-agenda-show-log))))
20908596
CD
5597 (org-agenda-set-mode-name)
5598 (org-agenda-redo)
5599 (message "Log mode is %s"
5600 (if org-agenda-show-log "on" "off")))
5601
2c3ad40d 5602(defun org-agenda-archives-mode (&optional with-files)
c8d0cf5c
CD
5603 "Toggle inclusion of items in trees marked with :ARCHIVE:.
5604When called with a prefix argument, include all archive files as well."
2c3ad40d
CD
5605 (interactive "P")
5606 (setq org-agenda-archives-mode
5607 (if with-files t (if org-agenda-archives-mode nil 'trees)))
5608 (org-agenda-set-mode-name)
5609 (org-agenda-redo)
5610 (message
5611 "%s"
5612 (cond
5613 ((eq org-agenda-archives-mode nil)
5614 "No archives are included")
5615 ((eq org-agenda-archives-mode 'trees)
5616 (format "Trees with :%s: tag are included" org-archive-tag))
5617 ((eq org-agenda-archives-mode t)
5618 (format "Trees with :%s: tag and all active archive files are included"
5619 org-archive-tag)))))
5620
20908596
CD
5621(defun org-agenda-toggle-diary ()
5622 "Toggle diary inclusion in an agenda buffer."
5623 (interactive)
5624 (org-agenda-check-type t 'agenda)
5625 (setq org-agenda-include-diary (not org-agenda-include-diary))
5626 (org-agenda-redo)
5627 (org-agenda-set-mode-name)
5628 (message "Diary inclusion turned %s"
5629 (if org-agenda-include-diary "on" "off")))
5630
5631(defun org-agenda-toggle-time-grid ()
5632 "Toggle time grid in an agenda buffer."
5633 (interactive)
5634 (org-agenda-check-type t 'agenda)
5635 (setq org-agenda-use-time-grid (not org-agenda-use-time-grid))
5636 (org-agenda-redo)
5637 (org-agenda-set-mode-name)
5638 (message "Time-grid turned %s"
5639 (if org-agenda-use-time-grid "on" "off")))
5640
5641(defun org-agenda-set-mode-name ()
5642 "Set the mode name to indicate all the small mode settings."
5643 (setq mode-name
5644 (concat "Org-Agenda"
5645 (if (equal org-agenda-ndays 1) " Day" "")
5646 (if (equal org-agenda-ndays 7) " Week" "")
5647 (if org-agenda-follow-mode " Follow" "")
54a0dee5 5648 (if org-agenda-entry-text-mode " ETxt" "")
20908596
CD
5649 (if org-agenda-include-diary " Diary" "")
5650 (if org-agenda-use-time-grid " Grid" "")
8bfe682a
CD
5651 (if (and (boundp 'org-habit-show-habits)
5652 org-habit-show-habits) " Habit" "")
93b62de8 5653 (if (consp org-agenda-show-log) " LogAll"
8bfe682a 5654 (if org-agenda-show-log " Log" ""))
c8d0cf5c
CD
5655 (if (or org-agenda-filter (get 'org-agenda-filter
5656 :preset-filter))
5657 (concat " {" (mapconcat
5658 'identity
5659 (append (get 'org-agenda-filter
5660 :preset-filter)
5661 org-agenda-filter) "") "}")
71d35b24 5662 "")
2c3ad40d
CD
5663 (if org-agenda-archives-mode
5664 (if (eq org-agenda-archives-mode t)
5665 " Archives"
5666 (format " :%s:" org-archive-tag))
5667 "")
20908596
CD
5668 (if org-agenda-clockreport-mode " Clock" "")))
5669 (force-mode-line-update))
5670
5671(defun org-agenda-post-command-hook ()
b349f79f
CD
5672 (setq org-agenda-type
5673 (or (get-text-property (point) 'org-agenda-type)
5674 (get-text-property (max (point-min) (1- (point)))
8bfe682a
CD
5675 'org-agenda-type))))
5676
5677(defun org-agenda-next-line ()
5678 "Move cursor to the next line, and show if follow-mode is active."
5679 (interactive)
5680 (call-interactively 'next-line)
1bcdebed
CD
5681 (org-agenda-do-context-action))
5682
8bfe682a
CD
5683(defun org-agenda-previous-line ()
5684 "Move cursor to the previous line, and show if follow-mode is active."
5685
5686 (interactive)
5687 (call-interactively 'previous-line)
1bcdebed
CD
5688 (org-agenda-do-context-action))
5689
5690(defun org-agenda-do-context-action ()
5691 "Show outline path and, maybe, follow-mode window."
5692 (let ((m (org-get-at-bol 'org-marker)))
5693 (if (and org-agenda-follow-mode m)
5694 (org-agenda-show))
5695 (if (and m org-agenda-show-outline-path)
5696 (message (org-with-point-at m
5697 (org-display-outline-path t))))))
20908596
CD
5698
5699(defun org-agenda-show-priority ()
5700 "Show the priority of the current item.
5701This priority is composed of the main priority given with the [#A] cookies,
5702and by additional input from the age of a schedules or deadline entry."
5703 (interactive)
8d642074 5704 (let* ((pri (org-get-at-bol 'priority)))
20908596
CD
5705 (message "Priority is %d" (if pri pri -1000))))
5706
5707(defun org-agenda-show-tags ()
5708 "Show the tags applicable to the current item."
5709 (interactive)
8d642074 5710 (let* ((tags (org-get-at-bol 'tags)))
20908596
CD
5711 (if tags
5712 (message "Tags are :%s:"
5713 (org-no-properties (mapconcat 'identity tags ":")))
5714 (message "No tags associated with this line"))))
5715
5716(defun org-agenda-goto (&optional highlight)
5717 "Go to the Org-mode file which contains the item at point."
5718 (interactive)
8d642074 5719 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
5720 (org-agenda-error)))
5721 (buffer (marker-buffer marker))
5722 (pos (marker-position marker)))
5723 (switch-to-buffer-other-window buffer)
5724 (widen)
5725 (goto-char pos)
5726 (when (org-mode-p)
5727 (org-show-context 'agenda)
5728 (save-excursion
5729 (and (outline-next-heading)
5730 (org-flag-heading nil)))) ; show the next heading
5731 (recenter (/ (window-height) 2))
5732 (run-hooks 'org-agenda-after-show-hook)
5733 (and highlight (org-highlight (point-at-bol) (point-at-eol)))))
5734
5735(defvar org-agenda-after-show-hook nil
5736 "Normal hook run after an item has been shown from the agenda.
5737Point is in the buffer where the item originated.")
5738
5739(defun org-agenda-kill ()
5740 "Kill the entry or subtree belonging to the current agenda entry."
5741 (interactive)
5742 (or (eq major-mode 'org-agenda-mode) (error "Not in agenda"))
8d642074 5743 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
5744 (org-agenda-error)))
5745 (buffer (marker-buffer marker))
5746 (pos (marker-position marker))
8d642074 5747 (type (org-get-at-bol 'type))
20908596
CD
5748 dbeg dend (n 0) conf)
5749 (org-with-remote-undo buffer
5750 (with-current-buffer buffer
5751 (save-excursion
5752 (goto-char pos)
5753 (if (and (org-mode-p) (not (member type '("sexp"))))
5754 (setq dbeg (progn (org-back-to-heading t) (point))
5755 dend (org-end-of-subtree t t))
5756 (setq dbeg (point-at-bol)
5757 dend (min (point-max) (1+ (point-at-eol)))))
5758 (goto-char dbeg)
5759 (while (re-search-forward "^[ \t]*\\S-" dend t) (setq n (1+ n)))))
5760 (setq conf (or (eq t org-agenda-confirm-kill)
5761 (and (numberp org-agenda-confirm-kill)
5762 (> n org-agenda-confirm-kill))))
5763 (and conf
5764 (not (y-or-n-p
5765 (format "Delete entry with %d lines in buffer \"%s\"? "
5766 n (buffer-name buffer))))
5767 (error "Abort"))
5768 (org-remove-subtree-entries-from-agenda buffer dbeg dend)
5769 (with-current-buffer buffer (delete-region dbeg dend))
5770 (message "Agenda item and source killed"))))
5771
8bfe682a
CD
5772(defvar org-archive-default-command)
5773(defun org-agenda-archive-default ()
5774 "Archive the entry or subtree belonging to the current agenda entry."
5775 (interactive)
5776 (require 'org-archive)
5777 (org-agenda-archive-with org-archive-default-command))
5778
5779(defun org-agenda-archive-default-with-confirmation ()
5780 "Archive the entry or subtree belonging to the current agenda entry."
5781 (interactive)
5782 (require 'org-archive)
5783 (org-agenda-archive-with org-archive-default-command 'confirm))
5784
20908596
CD
5785(defun org-agenda-archive ()
5786 "Archive the entry or subtree belonging to the current agenda entry."
5787 (interactive)
8bfe682a 5788 (org-agenda-archive-with 'org-archive-subtree))
20908596
CD
5789
5790(defun org-agenda-archive-to-archive-sibling ()
8bfe682a
CD
5791 "Move the entry to the archive sibling."
5792 (interactive)
5793 (org-agenda-archive-with 'org-archive-to-archive-sibling))
5794
5795(defun org-agenda-archive-with (cmd &optional confirm)
20908596
CD
5796 "Move the entry to the archive sibling."
5797 (interactive)
5798 (or (eq major-mode 'org-agenda-mode) (error "Not in agenda"))
8d642074 5799 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
5800 (org-agenda-error)))
5801 (buffer (marker-buffer marker))
5802 (pos (marker-position marker)))
5803 (org-with-remote-undo buffer
5804 (with-current-buffer buffer
5805 (if (org-mode-p)
8bfe682a
CD
5806 (if (and confirm
5807 (not (y-or-n-p "Archive this subtree or entry? ")))
5808 (error "Abort")
5809 (save-excursion
5810 (goto-char pos)
5811 (org-remove-subtree-entries-from-agenda)
5812 (org-back-to-heading t)
5813 (funcall cmd)))
20908596
CD
5814 (error "Archiving works only in Org-mode files"))))))
5815
5816(defun org-remove-subtree-entries-from-agenda (&optional buf beg end)
5817 "Remove all lines in the agenda that correspond to a given subtree.
5818The subtree is the one in buffer BUF, starting at BEG and ending at END.
5819If this information is not given, the function uses the tree at point."
5820 (let ((buf (or buf (current-buffer))) m p)
5821 (save-excursion
5822 (unless (and beg end)
5823 (org-back-to-heading t)
5824 (setq beg (point))
5825 (org-end-of-subtree t)
5826 (setq end (point)))
5827 (set-buffer (get-buffer org-agenda-buffer-name))
5828 (save-excursion
5829 (goto-char (point-max))
5830 (beginning-of-line 1)
5831 (while (not (bobp))
8d642074 5832 (when (and (setq m (org-get-at-bol 'org-marker))
20908596
CD
5833 (equal buf (marker-buffer m))
5834 (setq p (marker-position m))
5835 (>= p beg)
c8d0cf5c 5836 (< p end))
20908596
CD
5837 (let ((inhibit-read-only t))
5838 (delete-region (point-at-bol) (1+ (point-at-eol)))))
5839 (beginning-of-line 0))))))
5840
c8d0cf5c
CD
5841(defun org-agenda-refile (&optional goto rfloc)
5842 "Refile the item at point."
54a0dee5
CD
5843 (interactive "P")
5844 (if (equal goto '(16))
5845 (org-refile-goto-last-stored)
8d642074 5846 (let* ((marker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
5847 (org-agenda-error)))
5848 (buffer (marker-buffer marker))
5849 (pos (marker-position marker))
5850 (rfloc (or rfloc
5851 (org-refile-get-location
5852 (if goto "Goto: " "Refile to: ") buffer
5853 org-refile-allow-creating-parent-nodes))))
5854 (with-current-buffer buffer
5855 (save-excursion
5856 (save-restriction
5857 (widen)
5858 (goto-char marker)
5859 (org-remove-subtree-entries-from-agenda)
5860 (org-refile goto buffer rfloc)))))))
5861
5862(defun org-agenda-open-link (&optional arg)
5863 "Follow the link in the current line, if any.
8bfe682a 5864This looks for a link in the displayed line in the agenda. It also looks
54a0dee5 5865at the text of the entry itself."
c8d0cf5c 5866 (interactive "P")
8d642074
CD
5867 (let* ((marker (or (org-get-at-bol 'org-hd-marker)
5868 (org-get-at-bol 'org-marker)))
5869 (buffer (and marker (marker-buffer marker)))
5870 (prefix (buffer-substring
5871 (point-at-bol)
5872 (+ (point-at-bol)
8bfe682a
CD
5873 (or (org-get-at-bol 'prefix-length) 0)))))
5874 (cond
5875 (buffer
5876 (with-current-buffer buffer
5877 (save-excursion
5878 (save-restriction
5879 (widen)
5880 (goto-char marker)
5881 (org-offer-links-in-entry arg prefix)))))
5882 ((or (org-in-regexp (concat "\\(" org-bracket-link-regexp "\\)"))
5883 (save-excursion
5884 (beginning-of-line 1)
5885 (looking-at (concat ".*?\\(" org-bracket-link-regexp "\\)"))))
5886 (org-open-link-from-string (match-string 1)))
5887 (t (error "No link to open here")))))
20908596
CD
5888
5889(defun org-agenda-copy-local-variable (var)
5890 "Get a variable from a referenced buffer and install it here."
8d642074 5891 (let ((m (org-get-at-bol 'org-marker)))
20908596
CD
5892 (when (and m (buffer-live-p (marker-buffer m)))
5893 (org-set-local var (with-current-buffer (marker-buffer m)
5894 (symbol-value var))))))
5895
5896(defun org-agenda-switch-to (&optional delete-other-windows)
5897 "Go to the Org-mode file which contains the item at point."
5898 (interactive)
8bfe682a
CD
5899 (if (and org-return-follows-link
5900 (not (org-get-at-bol 'org-marker))
5901 (org-in-regexp org-bracket-link-regexp))
5902 (org-open-link-from-string (match-string 0))
5903 (let* ((marker (or (org-get-at-bol 'org-marker)
5904 (org-agenda-error)))
5905 (buffer (marker-buffer marker))
5906 (pos (marker-position marker)))
5907 (switch-to-buffer buffer)
5908 (and delete-other-windows (delete-other-windows))
5909 (widen)
5910 (goto-char pos)
5911 (when (org-mode-p)
5912 (org-show-context 'agenda)
5913 (save-excursion
5914 (and (outline-next-heading)
5915 (org-flag-heading nil))))))) ; show the next heading
20908596
CD
5916
5917(defun org-agenda-goto-mouse (ev)
5918 "Go to the Org-mode file which contains the item at the mouse click."
5919 (interactive "e")
5920 (mouse-set-point ev)
5921 (org-agenda-goto))
5922
fdf730ed
CD
5923(defun org-agenda-show (&optional full-entry)
5924 "Display the Org-mode file which contains the item at point.
5925With prefix argument FULL-ENTRY, make the entire entry visible
5926if it was hidden in the outline."
5927 (interactive "P")
20908596 5928 (let ((win (selected-window)))
fdf730ed
CD
5929 (if full-entry
5930 (let ((org-show-entry-below t))
5931 (org-agenda-goto t))
5932 (org-agenda-goto t))
20908596
CD
5933 (select-window win)))
5934
8bfe682a
CD
5935(defvar org-agenda-show-window nil)
5936(defun org-agenda-show-and-scroll-up ()
5937 "Display the Org-mode file which contains the item at point.
5938When called repeatedly, scroll the window that is displaying the buffer."
5939 (interactive)
5940 (let ((win (selected-window)))
5941 (if (and (window-live-p org-agenda-show-window)
5942 (eq this-command last-command))
5943 (progn
5944 (select-window org-agenda-show-window)
5945 (ignore-errors (scroll-up)))
5946 (org-agenda-goto t)
5947 (show-subtree)
5948 (setq org-agenda-show-window (selected-window)))
5949 (select-window win)))
5950
5951(defun org-agenda-show-scroll-down ()
5952 "Scroll down the window showing the agenda."
5953 (interactive)
5954 (let ((win (selected-window)))
5955 (when (window-live-p org-agenda-show-window)
5956 (select-window org-agenda-show-window)
5957 (ignore-errors (scroll-down))
5958 (select-window win))))
5959
c8d0cf5c
CD
5960(defun org-agenda-show-1 (&optional more)
5961 "Display the Org-mode file which contains the item at point.
8bfe682a 5962The prefix arg selects the amount of information to display:
c8d0cf5c
CD
5963
59640 hide the subtree
59651 just show the entry according to defaults.
54a0dee5
CD
59662 show the children view
59673 show the subtree view
c8d0cf5c
CD
59684 show the entire subtree and any LOGBOOK drawers
59695 show the entire subtree and any drawers
5970With prefix argument FULL-ENTRY, make the entire entry visible
5971if it was hidden in the outline."
5972 (interactive "p")
5973 (let ((win (selected-window)))
5974 (org-agenda-goto t)
5975 (org-recenter-heading 1)
5976 (cond
5977 ((= more 0)
5978 (hide-subtree)
54a0dee5
CD
5979 (save-excursion
5980 (org-back-to-heading)
5981 (run-hook-with-args 'org-cycle-hook 'folded))
5982 (message "Remote: FOLDED"))
c8d0cf5c
CD
5983 ((and (interactive-p) (= more 1))
5984 (message "Remote: show with default settings"))
5985 ((= more 2)
5986 (show-entry)
54a0dee5 5987 (show-children)
c8d0cf5c
CD
5988 (save-excursion
5989 (org-back-to-heading)
54a0dee5
CD
5990 (run-hook-with-args 'org-cycle-hook 'children))
5991 (message "Remote: CHILDREN"))
c8d0cf5c
CD
5992 ((= more 3)
5993 (show-subtree)
5994 (save-excursion
5995 (org-back-to-heading)
54a0dee5
CD
5996 (run-hook-with-args 'org-cycle-hook 'subtree))
5997 (message "Remote: SUBTREE"))
c8d0cf5c
CD
5998 ((= more 4)
5999 (let* ((org-drawers (delete "LOGBOOK" (copy-sequence org-drawers)))
6000 (org-drawer-regexp
6001 (concat "^[ \t]*:\\("
6002 (mapconcat 'regexp-quote org-drawers "\\|")
6003 "\\):[ \t]*$")))
6004 (show-subtree)
6005 (save-excursion
6006 (org-back-to-heading)
6007 (org-cycle-hide-drawers 'subtree)))
54a0dee5 6008 (message "Remote: SUBTREE AND LOGBOOK"))
c8d0cf5c
CD
6009 ((> more 4)
6010 (show-subtree)
54a0dee5 6011 (message "Remote: SUBTREE AND ALL DRAWERS")))
c8d0cf5c
CD
6012 (select-window win)))
6013
6014(defun org-recenter-heading (n)
6015 (save-excursion
6016 (org-back-to-heading)
6017 (recenter n)))
6018
6019(defvar org-agenda-cycle-counter nil)
54a0dee5 6020(defun org-agenda-cycle-show (&optional n)
c8d0cf5c
CD
6021 "Show the current entry in another window, with default settings.
6022Default settings are taken from `org-show-hierarchy-above' and siblings.
54a0dee5 6023When use repeatedly in immediate succession, the remote entry will cycle
c8d0cf5c
CD
6024through visibility
6025
54a0dee5
CD
6026children -> subtree -> folded
6027
6028When called with a numeric prefix arg, that arg will be passed through to
6029`org-agenda-show-1'. For the interpretation of that argument, see the
6030docstring of `org-agenda-show-1'."
6031 (interactive "P")
6032 (if (integerp n)
6033 (setq org-agenda-cycle-counter n)
6034 (if (not (eq last-command this-command))
6035 (setq org-agenda-cycle-counter 1)
6036 (if (equal org-agenda-cycle-counter 0)
6037 (setq org-agenda-cycle-counter 2)
6038 (setq org-agenda-cycle-counter (1+ org-agenda-cycle-counter))
6039 (if (> org-agenda-cycle-counter 3)
6040 (setq org-agenda-cycle-counter 0)))))
c8d0cf5c
CD
6041 (org-agenda-show-1 org-agenda-cycle-counter))
6042
20908596
CD
6043(defun org-agenda-recenter (arg)
6044 "Display the Org-mode file which contains the item at point and recenter."
6045 (interactive "P")
6046 (let ((win (selected-window)))
6047 (org-agenda-goto t)
6048 (recenter arg)
6049 (select-window win)))
6050
6051(defun org-agenda-show-mouse (ev)
6052 "Display the Org-mode file which contains the item at the mouse click."
6053 (interactive "e")
6054 (mouse-set-point ev)
6055 (org-agenda-show))
6056
6057(defun org-agenda-check-no-diary ()
6058 "Check if the entry is a diary link and abort if yes."
8d642074 6059 (if (org-get-at-bol 'org-agenda-diary-link)
20908596
CD
6060 (org-agenda-error)))
6061
6062(defun org-agenda-error ()
6063 (error "Command not allowed in this line"))
6064
6065(defun org-agenda-tree-to-indirect-buffer ()
6066 "Show the subtree corresponding to the current entry in an indirect buffer.
6067This calls the command `org-tree-to-indirect-buffer' from the original
6068Org-mode buffer.
6069With numerical prefix arg ARG, go up to this level and then take that tree.
6070With a C-u prefix, make a separate frame for this tree (i.e. don't use the
6071dedicated frame)."
6072 (interactive)
6073 (org-agenda-check-no-diary)
8d642074 6074 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
6075 (org-agenda-error)))
6076 (buffer (marker-buffer marker))
6077 (pos (marker-position marker)))
6078 (with-current-buffer buffer
6079 (save-excursion
6080 (goto-char pos)
6081 (call-interactively 'org-tree-to-indirect-buffer)))))
6082
6083(defvar org-last-heading-marker (make-marker)
6084 "Marker pointing to the headline that last changed its TODO state
6085by a remote command from the agenda.")
6086
6087(defun org-agenda-todo-nextset ()
6088 "Switch TODO entry to next sequence."
6089 (interactive)
6090 (org-agenda-todo 'nextset))
6091
6092(defun org-agenda-todo-previousset ()
6093 "Switch TODO entry to previous sequence."
6094 (interactive)
6095 (org-agenda-todo 'previousset))
6096
6097(defun org-agenda-todo (&optional arg)
6098 "Cycle TODO state of line at point, also in Org-mode file.
6099This changes the line at point, all other lines in the agenda referring to
6100the same tree node, and the headline of the tree node in the Org-mode file."
6101 (interactive "P")
6102 (org-agenda-check-no-diary)
6103 (let* ((col (current-column))
8d642074 6104 (marker (or (org-get-at-bol 'org-marker)
20908596
CD
6105 (org-agenda-error)))
6106 (buffer (marker-buffer marker))
6107 (pos (marker-position marker))
8d642074
CD
6108 (hdmarker (org-get-at-bol 'org-hd-marker))
6109 (todayp (equal (org-get-at-bol 'day)
93b62de8 6110 (time-to-days (current-time))))
20908596 6111 (inhibit-read-only t)
93b62de8 6112 org-agenda-headline-snapshot-before-repeat newhead just-one)
20908596
CD
6113 (org-with-remote-undo buffer
6114 (with-current-buffer buffer
6115 (widen)
6116 (goto-char pos)
6117 (org-show-context 'agenda)
6118 (save-excursion
6119 (and (outline-next-heading)
6120 (org-flag-heading nil))) ; show the next heading
a2a2e7fb
CD
6121 (let ((current-prefix-arg arg))
6122 (call-interactively 'org-todo))
20908596
CD
6123 (and (bolp) (forward-char 1))
6124 (setq newhead (org-get-heading))
93b62de8
CD
6125 (when (and (org-bound-and-true-p
6126 org-agenda-headline-snapshot-before-repeat)
6127 (not (equal org-agenda-headline-snapshot-before-repeat
6128 newhead))
6129 todayp)
6130 (setq newhead org-agenda-headline-snapshot-before-repeat
6131 just-one t))
20908596
CD
6132 (save-excursion
6133 (org-back-to-heading)
6134 (move-marker org-last-heading-marker (point))))
6135 (beginning-of-line 1)
6136 (save-excursion
93b62de8 6137 (org-agenda-change-all-lines newhead hdmarker 'fixface just-one))
20908596
CD
6138 (org-move-to-column col))))
6139
6140(defun org-agenda-add-note (&optional arg)
6141 "Add a time-stamped note to the entry at point."
6142 (interactive "P")
6143 (org-agenda-check-no-diary)
8d642074 6144 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
6145 (org-agenda-error)))
6146 (buffer (marker-buffer marker))
6147 (pos (marker-position marker))
8d642074 6148 (hdmarker (org-get-at-bol 'org-hd-marker))
20908596
CD
6149 (inhibit-read-only t))
6150 (with-current-buffer buffer
6151 (widen)
6152 (goto-char pos)
6153 (org-show-context 'agenda)
6154 (save-excursion
6155 (and (outline-next-heading)
6156 (org-flag-heading nil))) ; show the next heading
6157 (org-add-note))))
6158
db55f368 6159(defun org-agenda-change-all-lines (newhead hdmarker
4ed008de 6160 &optional fixface just-this)
20908596
CD
6161 "Change all lines in the agenda buffer which match HDMARKER.
6162The new content of the line will be NEWHEAD (as modified by
6163`org-format-agenda-item'). HDMARKER is checked with
6164`equal' against all `org-hd-marker' text properties in the file.
33306645 6165If FIXFACE is non-nil, the face of each item is modified according to
db55f368
CD
6166the new TODO state.
6167If JUST-THIS is non-nil, change just the current line, not all.
33306645 6168If FORCE-TAGS is non nil, the car of it returns the new tags."
20908596 6169 (let* ((inhibit-read-only t)
93b62de8 6170 (line (org-current-line))
fdf730ed 6171 (thetags (with-current-buffer (marker-buffer hdmarker)
4ed008de
CD
6172 (save-excursion (save-restriction (widen)
6173 (goto-char hdmarker)
fdf730ed 6174 (org-get-tags-at)))))
20908596
CD
6175 props m pl undone-face done-face finish new dotime cat tags)
6176 (save-excursion
6177 (goto-char (point-max))
6178 (beginning-of-line 1)
6179 (while (not finish)
6180 (setq finish (bobp))
8d642074 6181 (when (and (setq m (org-get-at-bol 'org-hd-marker))
93b62de8 6182 (or (not just-this) (= (org-current-line) line))
20908596
CD
6183 (equal m hdmarker))
6184 (setq props (text-properties-at (point))
8d642074
CD
6185 dotime (org-get-at-bol 'dotime)
6186 cat (org-get-at-bol 'org-category)
4ed008de 6187 tags thetags
20908596 6188 new (org-format-agenda-item "x" newhead cat tags dotime 'noprefix)
8d642074
CD
6189 pl (org-get-at-bol 'prefix-length)
6190 undone-face (org-get-at-bol 'undone-face)
6191 done-face (org-get-at-bol 'done-face))
6192 (goto-char (+ (point) pl))
6193 ;; (org-move-to-column pl) FIXME: does the above line work correctly?
20908596
CD
6194 (cond
6195 ((equal new "")
6196 (beginning-of-line 1)
6197 (and (looking-at ".*\n?") (replace-match "")))
6198 ((looking-at ".*")
6199 (replace-match new t t)
6200 (beginning-of-line 1)
6201 (add-text-properties (point-at-bol) (point-at-eol) props)
6202 (when fixface
6203 (add-text-properties
6204 (point-at-bol) (point-at-eol)
6205 (list 'face
6206 (if org-last-todo-state-is-todo
6207 undone-face done-face))))
6208 (org-agenda-highlight-todo 'line)
6209 (beginning-of-line 1))
6210 (t (error "Line update did not work"))))
6211 (beginning-of-line 0)))
6212 (org-finalize-agenda)))
6213
6214(defun org-agenda-align-tags (&optional line)
6215 "Align all tags in agenda items to `org-agenda-tags-column'."
6216 (let ((inhibit-read-only t) l c)
6217 (save-excursion
6218 (goto-char (if line (point-at-bol) (point-min)))
6219 (while (re-search-forward (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@:]+:\\)[ \t]*$")
6220 (if line (point-at-eol) nil) t)
6221 (add-text-properties
6222 (match-beginning 2) (match-end 2)
30ab4580
GM
6223 (list 'face (delq nil (let ((prop (get-text-property
6224 (match-beginning 2) 'face)))
6225 (or (listp prop) (setq prop (list prop)))
6226 (if (memq 'org-tag prop)
6227 prop
6228 (cons 'org-tag prop))))))
20908596
CD
6229 (setq l (- (match-end 2) (match-beginning 2))
6230 c (if (< org-agenda-tags-column 0)
6231 (- (abs org-agenda-tags-column) l)
6232 org-agenda-tags-column))
6233 (delete-region (match-beginning 1) (match-end 1))
6234 (goto-char (match-beginning 1))
6235 (insert (org-add-props
6236 (make-string (max 1 (- c (current-column))) ?\ )
ff4be292
CD
6237 (text-properties-at (point)))))
6238 (goto-char (point-min))
6239 (org-font-lock-add-tag-faces (point-max)))))
20908596
CD
6240
6241(defun org-agenda-priority-up ()
6242 "Increase the priority of line at point, also in Org-mode file."
6243 (interactive)
6244 (org-agenda-priority 'up))
6245
6246(defun org-agenda-priority-down ()
6247 "Decrease the priority of line at point, also in Org-mode file."
6248 (interactive)
6249 (org-agenda-priority 'down))
6250
6251(defun org-agenda-priority (&optional force-direction)
6252 "Set the priority of line at point, also in Org-mode file.
6253This changes the line at point, all other lines in the agenda referring to
6254the same tree node, and the headline of the tree node in the Org-mode file."
6255 (interactive)
c8d0cf5c
CD
6256 (unless org-enable-priority-commands
6257 (error "Priority commands are disabled"))
20908596 6258 (org-agenda-check-no-diary)
8d642074 6259 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596 6260 (org-agenda-error)))
8d642074 6261 (hdmarker (org-get-at-bol 'org-hd-marker))
20908596
CD
6262 (buffer (marker-buffer hdmarker))
6263 (pos (marker-position hdmarker))
6264 (inhibit-read-only t)
6265 newhead)
6266 (org-with-remote-undo buffer
6267 (with-current-buffer buffer
6268 (widen)
6269 (goto-char pos)
6270 (org-show-context 'agenda)
6271 (save-excursion
6272 (and (outline-next-heading)
6273 (org-flag-heading nil))) ; show the next heading
6274 (funcall 'org-priority force-direction)
6275 (end-of-line 1)
6276 (setq newhead (org-get-heading)))
6277 (org-agenda-change-all-lines newhead hdmarker)
6278 (beginning-of-line 1))))
6279
6280;; FIXME: should fix the tags property of the agenda line.
c8d0cf5c 6281(defun org-agenda-set-tags (&optional tag onoff)
20908596
CD
6282 "Set tags for the current headline."
6283 (interactive)
6284 (org-agenda-check-no-diary)
6285 (if (and (org-region-active-p) (interactive-p))
6286 (call-interactively 'org-change-tag-in-region)
6287 (org-agenda-show) ;;; FIXME This is a stupid hack and should not be needed
8d642074 6288 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
20908596
CD
6289 (org-agenda-error)))
6290 (buffer (marker-buffer hdmarker))
6291 (pos (marker-position hdmarker))
6292 (inhibit-read-only t)
4ed008de 6293 newhead)
20908596
CD
6294 (org-with-remote-undo buffer
6295 (with-current-buffer buffer
6296 (widen)
6297 (goto-char pos)
6298 (save-excursion
6299 (org-show-context 'agenda))
6300 (save-excursion
6301 (and (outline-next-heading)
6302 (org-flag-heading nil))) ; show the next heading
6303 (goto-char pos)
c8d0cf5c
CD
6304 (if tag
6305 (org-toggle-tag tag onoff)
6306 (call-interactively 'org-set-tags))
20908596
CD
6307 (end-of-line 1)
6308 (setq newhead (org-get-heading)))
4ed008de 6309 (org-agenda-change-all-lines newhead hdmarker)
20908596
CD
6310 (beginning-of-line 1)))))
6311
54a0dee5
CD
6312(defun org-agenda-set-property ()
6313 "Set a property for the current headline."
6314 (interactive)
6315 (org-agenda-check-no-diary)
6316 (org-agenda-show) ;;; FIXME This is a stupid hack and should not be needed
8d642074 6317 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
6318 (org-agenda-error)))
6319 (buffer (marker-buffer hdmarker))
6320 (pos (marker-position hdmarker))
6321 (inhibit-read-only t)
6322 newhead)
6323 (org-with-remote-undo buffer
6324 (with-current-buffer buffer
6325 (widen)
6326 (goto-char pos)
6327 (save-excursion
6328 (org-show-context 'agenda))
6329 (save-excursion
6330 (and (outline-next-heading)
6331 (org-flag-heading nil))) ; show the next heading
6332 (goto-char pos)
6333 (call-interactively 'org-set-property)))))
6334
6335(defun org-agenda-set-effort ()
6336 "Set the effort property for the current headline."
6337 (interactive)
6338 (org-agenda-check-no-diary)
6339 (org-agenda-show) ;;; FIXME This is a stupid hack and should not be needed
8d642074 6340 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
6341 (org-agenda-error)))
6342 (buffer (marker-buffer hdmarker))
6343 (pos (marker-position hdmarker))
6344 (inhibit-read-only t)
6345 newhead)
6346 (org-with-remote-undo buffer
6347 (with-current-buffer buffer
6348 (widen)
6349 (goto-char pos)
6350 (save-excursion
6351 (org-show-context 'agenda))
6352 (save-excursion
6353 (and (outline-next-heading)
6354 (org-flag-heading nil))) ; show the next heading
6355 (goto-char pos)
6356 (call-interactively 'org-set-effort)
6357 (end-of-line 1)))))
6358
20908596
CD
6359(defun org-agenda-toggle-archive-tag ()
6360 "Toggle the archive tag for the current entry."
6361 (interactive)
6362 (org-agenda-check-no-diary)
6363 (org-agenda-show) ;;; FIXME This is a stupid hack and should not be needed
8d642074 6364 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
20908596
CD
6365 (org-agenda-error)))
6366 (buffer (marker-buffer hdmarker))
6367 (pos (marker-position hdmarker))
6368 (inhibit-read-only t)
6369 newhead)
6370 (org-with-remote-undo buffer
6371 (with-current-buffer buffer
6372 (widen)
6373 (goto-char pos)
6374 (org-show-context 'agenda)
6375 (save-excursion
6376 (and (outline-next-heading)
6377 (org-flag-heading nil))) ; show the next heading
6378 (call-interactively 'org-toggle-archive-tag)
6379 (end-of-line 1)
6380 (setq newhead (org-get-heading)))
6381 (org-agenda-change-all-lines newhead hdmarker)
6382 (beginning-of-line 1))))
6383
c8d0cf5c
CD
6384(defun org-agenda-do-date-later (arg)
6385 (interactive "P")
6386 (cond
6387 ((or (equal arg '(16))
6388 (memq last-command
6389 '(org-agenda-date-later-minutes org-agenda-date-earlier-minutes)))
6390 (setq this-command 'org-agenda-date-later-minutes)
6391 (org-agenda-date-later-minutes 1))
6392 ((or (equal arg '(4))
6393 (memq last-command
6394 '(org-agenda-date-later-hours org-agenda-date-earlier-hours)))
6395 (setq this-command 'org-agenda-date-later-hours)
6396 (org-agenda-date-later-hours 1))
6397 (t
6398 (org-agenda-date-later (prefix-numeric-value arg)))))
6399
6400(defun org-agenda-do-date-earlier (arg)
6401 (interactive "P")
6402 (cond
6403 ((or (equal arg '(16))
6404 (memq last-command
6405 '(org-agenda-date-later-minutes org-agenda-date-earlier-minutes)))
6406 (setq this-command 'org-agenda-date-earlier-minutes)
6407 (org-agenda-date-earlier-minutes 1))
6408 ((or (equal arg '(4))
6409 (memq last-command
6410 '(org-agenda-date-later-hours org-agenda-date-earlier-hours)))
6411 (setq this-command 'org-agenda-date-earlier-hours)
6412 (org-agenda-date-earlier-hours 1))
6413 (t
6414 (org-agenda-date-earlier (prefix-numeric-value arg)))))
6415
20908596
CD
6416(defun org-agenda-date-later (arg &optional what)
6417 "Change the date of this item to one day later."
6418 (interactive "p")
6419 (org-agenda-check-type t 'agenda 'timeline)
6420 (org-agenda-check-no-diary)
8d642074 6421 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
6422 (org-agenda-error)))
6423 (buffer (marker-buffer marker))
6424 (pos (marker-position marker)))
6425 (org-with-remote-undo buffer
6426 (with-current-buffer buffer
6427 (widen)
6428 (goto-char pos)
6429 (if (not (org-at-timestamp-p))
6430 (error "Cannot find time stamp"))
6431 (org-timestamp-change arg (or what 'day)))
6432 (org-agenda-show-new-time marker org-last-changed-timestamp))
6433 (message "Time stamp changed to %s" org-last-changed-timestamp)))
6434
6435(defun org-agenda-date-earlier (arg &optional what)
6436 "Change the date of this item to one day earlier."
6437 (interactive "p")
6438 (org-agenda-date-later (- arg) what))
6439
c8d0cf5c
CD
6440(defun org-agenda-date-later-minutes (arg)
6441 "Change the time of this item, in units of `org-time-stamp-rounding-minutes'."
6442 (interactive "p")
6443 (setq arg (* arg (cadr org-time-stamp-rounding-minutes)))
6444 (org-agenda-date-later arg 'minute))
6445
6446(defun org-agenda-date-earlier-minutes (arg)
6447 "Change the time of this item, in units of `org-time-stamp-rounding-minutes'."
6448 (interactive "p")
6449 (setq arg (* arg (cadr org-time-stamp-rounding-minutes)))
6450 (org-agenda-date-earlier arg 'minute))
6451
6452(defun org-agenda-date-later-hours (arg)
6453 "Change the time of this item, in hour steps."
6454 (interactive "p")
6455 (org-agenda-date-later arg 'hour))
6456
6457(defun org-agenda-date-earlier-hours (arg)
6458 "Change the time of this item, in hour steps."
6459 (interactive "p")
6460 (org-agenda-date-earlier arg 'hour))
6461
20908596
CD
6462(defun org-agenda-show-new-time (marker stamp &optional prefix)
6463 "Show new date stamp via text properties."
6464 ;; We use text properties to make this undoable
71d35b24
CD
6465 (let ((inhibit-read-only t)
6466 (buffer-invisibility-spec))
20908596
CD
6467 (setq stamp (concat " " prefix " => " stamp))
6468 (save-excursion
6469 (goto-char (point-max))
6470 (while (not (bobp))
8d642074 6471 (when (equal marker (org-get-at-bol 'org-marker))
20908596 6472 (org-move-to-column (- (window-width) (length stamp)) t)
71d35b24 6473 (org-agenda-fix-tags-filter-overlays-at (point))
20908596
CD
6474 (if (featurep 'xemacs)
6475 ;; Use `duplicable' property to trigger undo recording
6476 (let ((ex (make-extent nil nil))
6477 (gl (make-glyph stamp)))
6478 (set-glyph-face gl 'secondary-selection)
6479 (set-extent-properties
6480 ex (list 'invisible t 'end-glyph gl 'duplicable t))
6481 (insert-extent ex (1- (point)) (point-at-eol)))
6482 (add-text-properties
6483 (1- (point)) (point-at-eol)
6484 (list 'display (org-add-props stamp nil
6485 'face 'secondary-selection))))
6486 (beginning-of-line 1))
6487 (beginning-of-line 0)))))
6488
6489(defun org-agenda-date-prompt (arg)
6490 "Change the date of this item. Date is prompted for, with default today.
6491The prefix ARG is passed to the `org-time-stamp' command and can therefore
6492be used to request time specification in the time stamp."
6493 (interactive "P")
6494 (org-agenda-check-type t 'agenda 'timeline)
6495 (org-agenda-check-no-diary)
8d642074 6496 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
6497 (org-agenda-error)))
6498 (buffer (marker-buffer marker))
6499 (pos (marker-position marker)))
6500 (org-with-remote-undo buffer
6501 (with-current-buffer buffer
6502 (widen)
6503 (goto-char pos)
6504 (if (not (org-at-timestamp-p))
6505 (error "Cannot find time stamp"))
8d642074
CD
6506 (org-time-stamp arg))
6507 (org-agenda-show-new-time marker org-last-changed-timestamp))
6508 (message "Time stamp changed to %s" org-last-changed-timestamp)))
20908596
CD
6509
6510(defun org-agenda-schedule (arg)
6511 "Schedule the item at point."
6512 (interactive "P")
6513 (org-agenda-check-type t 'agenda 'timeline 'todo 'tags 'search)
6514 (org-agenda-check-no-diary)
8d642074 6515 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
6516 (org-agenda-error)))
6517 (type (marker-insertion-type marker))
6518 (buffer (marker-buffer marker))
6519 (pos (marker-position marker))
6520 (org-insert-labeled-timestamps-at-point nil)
6521 ts)
20908596
CD
6522 (set-marker-insertion-type marker t)
6523 (org-with-remote-undo buffer
6524 (with-current-buffer buffer
6525 (widen)
6526 (goto-char pos)
6527 (setq ts (org-schedule arg)))
6528 (org-agenda-show-new-time marker ts "S"))
6529 (message "Item scheduled for %s" ts)))
6530
6531(defun org-agenda-deadline (arg)
6532 "Schedule the item at point."
6533 (interactive "P")
6534 (org-agenda-check-type t 'agenda 'timeline 'todo 'tags 'search)
6535 (org-agenda-check-no-diary)
8d642074 6536 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
6537 (org-agenda-error)))
6538 (buffer (marker-buffer marker))
6539 (pos (marker-position marker))
6540 (org-insert-labeled-timestamps-at-point nil)
6541 ts)
6542 (org-with-remote-undo buffer
6543 (with-current-buffer buffer
6544 (widen)
6545 (goto-char pos)
6546 (setq ts (org-deadline arg)))
8d642074 6547 (org-agenda-show-new-time marker ts "D"))
20908596
CD
6548 (message "Deadline for this item set to %s" ts)))
6549
b349f79f
CD
6550(defun org-agenda-action ()
6551 "Select entry for agenda action, or execute an agenda action.
6552This command prompts for another letter. Valid inputs are:
6553
6554m Mark the entry at point for an agenda action
6555s Schedule the marked entry to the date at the cursor
6556d Set the deadline of the marked entry to the date at the cursor
6557r Call `org-remember' with cursor date as the default date
6558SPC Show marked entry in other window
6559TAB Visit marked entry in other window
6560
6561The cursor may be at a date in the calendar, or in the Org agenda."
6562 (interactive)
65c439fd 6563 (let (ans)
b349f79f
CD
6564 (message "Select action: [m]ark | [s]chedule [d]eadline [r]emember [ ]show")
6565 (setq ans (read-char-exclusive))
6566 (cond
6567 ((equal ans ?m)
6568 ;; Mark this entry
6569 (if (eq major-mode 'org-agenda-mode)
8d642074
CD
6570 (let ((m (or (org-get-at-bol 'org-hd-marker)
6571 (org-get-at-bol 'org-marker))))
b349f79f
CD
6572 (if m
6573 (progn
6574 (move-marker org-agenda-action-marker
6575 (marker-position m) (marker-buffer m))
6576 (message "Entry marked for action; press `k' at desired date in agenda or calendar"))
6577 (error "Don't know which entry to mark")))
6578 (error "This command works only in the agenda")))
6579 ((equal ans ?s)
6580 (org-agenda-do-action '(org-schedule nil org-overriding-default-time)))
6581 ((equal ans ?d)
6582 (org-agenda-do-action '(org-deadline nil org-overriding-default-time)))
6583 ((equal ans ?r)
6584 (org-agenda-do-action '(org-remember) t))
6585 ((equal ans ?\ )
6586 (let ((cw (selected-window)))
6587 (org-switch-to-buffer-other-window
6588 (marker-buffer org-agenda-action-marker))
6589 (goto-char org-agenda-action-marker)
6590 (org-show-context 'agenda)
6591 (select-window cw)))
6592 ((equal ans ?\C-i)
6593 (org-switch-to-buffer-other-window
6594 (marker-buffer org-agenda-action-marker))
6595 (goto-char org-agenda-action-marker)
6596 (org-show-context 'agenda))
6597 (t (error "Invalid agenda action %c" ans)))))
6598
6599(defun org-agenda-do-action (form &optional current-buffer)
6600 "Evaluate FORM at the entry pointed to by `org-agenda-action-marker'."
6601 (let ((org-overriding-default-time (org-get-cursor-date)))
6602 (if current-buffer
6603 (eval form)
6604 (if (not (marker-buffer org-agenda-action-marker))
8bfe682a 6605 (error "No entry has been selected for agenda action")
b349f79f
CD
6606 (with-current-buffer (marker-buffer org-agenda-action-marker)
6607 (save-excursion
6608 (save-restriction
6609 (widen)
6610 (goto-char org-agenda-action-marker)
6611 (eval form))))))))
ff4be292 6612
20908596
CD
6613(defun org-agenda-clock-in (&optional arg)
6614 "Start the clock on the currently selected item."
6615 (interactive "P")
6616 (org-agenda-check-no-diary)
6617 (if (equal arg '(4))
6618 (org-clock-in arg)
8d642074 6619 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596 6620 (org-agenda-error)))
8d642074 6621 (hdmarker (or (org-get-at-bol 'org-hd-marker)
b349f79f
CD
6622 marker))
6623 (pos (marker-position marker))
6624 newhead)
20908596
CD
6625 (org-with-remote-undo (marker-buffer marker)
6626 (with-current-buffer (marker-buffer marker)
6627 (widen)
6628 (goto-char pos)
b349f79f
CD
6629 (org-show-context 'agenda)
6630 (org-show-entry)
6631 (org-cycle-hide-drawers 'children)
6632 (org-clock-in arg)
6633 (setq newhead (org-get-heading)))
c8d0cf5c 6634 (org-agenda-change-all-lines newhead hdmarker)))))
20908596
CD
6635
6636(defun org-agenda-clock-out (&optional arg)
6637 "Stop the currently running clock."
6638 (interactive "P")
6639 (unless (marker-buffer org-clock-marker)
6640 (error "No running clock"))
c8d0cf5c
CD
6641 (let ((marker (make-marker)) newhead)
6642 (org-with-remote-undo (marker-buffer org-clock-marker)
6643 (with-current-buffer (marker-buffer org-clock-marker)
6644 (save-excursion
6645 (save-restriction
6646 (widen)
6647 (goto-char org-clock-marker)
6648 (org-back-to-heading t)
6649 (move-marker marker (point))
6650 (org-clock-out)
6651 (setq newhead (org-get-heading))))))
6652 (org-agenda-change-all-lines newhead marker)
6653 (move-marker marker nil)))
20908596
CD
6654
6655(defun org-agenda-clock-cancel (&optional arg)
6656 "Cancel the currently running clock."
6657 (interactive "P")
6658 (unless (marker-buffer org-clock-marker)
6659 (error "No running clock"))
6660 (org-with-remote-undo (marker-buffer org-clock-marker)
6661 (org-clock-cancel)))
6662
8bfe682a
CD
6663(defun org-agenda-diary-entry-in-org-file ()
6664 "Make a diary entry in the file `org-agenda-diary-file'."
6665 (let (d1 d2 char (text ""))
6666 (if (equal (buffer-name) "*Calendar*")
6667 (setq d1 (calendar-cursor-to-date t)
6668 d2 (car calendar-mark-ring))
6669 (setq d1 (calendar-gregorian-from-absolute
6670 (get-text-property (point) 'day))
6671 d2 (and (mark) (get-text-property (mark) 'day)
6672 (calendar-gregorian-from-absolute
6673 (get-text-property (mark) 'day)))))
6674 (message "Diary entry: [d]ay [a]nniversary [b]lock [j]ump to date tree")
6675 (setq char (read-char-exclusive))
6676 (cond
6677 ((equal char ?d)
6678 (setq text (read-string "Day entry: "))
6679 (org-agenda-add-entry-to-org-agenda-diary-file 'day text d1))
6680 ((equal char ?a)
6681 (setq d1 (list (car d1) (nth 1 d1)
6682 (read-number (format "Reference year [%d]: " (nth 2 d1))
6683 (nth 2 d1))))
6684 (setq text (read-string "Anniversary (use %d to show years): "))
6685 (org-agenda-add-entry-to-org-agenda-diary-file 'anniversary text d1))
6686 ((equal char ?b)
6687 (setq text (read-string "Block entry: "))
6688 (unless (and d1 d2 (not (equal d1 d2)))
6689 (error "No block of days selected"))
6690 (org-agenda-add-entry-to-org-agenda-diary-file 'block text d1 d2))
6691 ((equal char ?j)
6692 (org-switch-to-buffer-other-window
6693 (find-file-noselect org-agenda-diary-file))
6694 (org-datetree-find-date-create d1)
6695 (org-reveal t))
6696 (t (error "Invalid selection character `%c'" char)))))
6697
6698(defun org-agenda-add-entry-to-org-agenda-diary-file (type text &optional d1 d2)
6699 "Add a diary entry with TYPE to `org-agenda-diary-file'.
6700If TEXT is not empty, it will become the headline of the new entry, and
6701the resulting entry will not be shown. When TEXT is empty, switch to
6702`org-agenda-diary-file' and let the user finish the entry there."
6703 (let ((cw (current-window-configuration)))
6704 (org-switch-to-buffer-other-window
6705 (find-file-noselect org-agenda-diary-file))
6706 (widen)
6707 (goto-char (point-min))
6708 (cond
6709 ((eq type 'anniversary)
6710 (or (re-search-forward "^*[ \t]+Anniversaries" nil t)
6711 (progn
6712 (or (org-on-heading-p t)
6713 (progn
6714 (outline-next-heading)
6715 (insert "* Anniversaries\n\n")
6716 (beginning-of-line -1)))))
6717 (outline-next-heading)
6718 (org-back-over-empty-lines)
6719 (backward-char 1)
6720 (insert "\n")
6721 (require 'diary-lib)
6722 (let ((calendar-date-display-form
6723 (if (if (boundp 'calendar-date-style)
6724 (eq calendar-date-style 'european)
6725 european-calendar-style) ; Emacs 22
6726 '(day " " month " " year)
6727 '(month " " day " " year))))
6728
6729 (insert (format "%%%%(diary-anniversary %s) %s"
6730 (calendar-date-string d1 nil t) text))))
6731 ((eq type 'day)
6732 (require 'org-datetree)
6733 (org-datetree-find-date-create d1)
6734 (org-agenda-insert-diary-make-new-entry text)
6735 (org-insert-time-stamp (org-time-from-absolute
6736 (calendar-absolute-from-gregorian d1)))
6737 (end-of-line 0))
6738 ((eq type 'block)
6739 (if (> (calendar-absolute-from-gregorian d1)
6740 (calendar-absolute-from-gregorian d2))
6741 (setq d1 (prog1 d2 (setq d2 d1))))
6742 (require 'org-datetree)
6743 (org-datetree-find-date-create d1)
6744 (org-agenda-insert-diary-make-new-entry text)
6745 (org-insert-time-stamp (org-time-from-absolute
6746 (calendar-absolute-from-gregorian d1)))
6747 (insert "--")
6748 (org-insert-time-stamp (org-time-from-absolute
6749 (calendar-absolute-from-gregorian d2)))
6750 (end-of-line 0)))
6751 (if (string-match "\\S-" text)
6752 (progn
6753 (set-window-configuration cw)
6754 (message "%s entry added to %s"
6755 (capitalize (symbol-name type))
6756 (abbreviate-file-name org-agenda-diary-file)))
6757 (org-reveal t)
6758 (message "Please finish entry here"))))
6759
6760(defun org-agenda-insert-diary-make-new-entry (text)
6761 "Make new entry as last child of current entry.
6762Add TEXT as headline, and position the cursor in the second line so that
6763a timestamp can be added there."
6764 (let ((org-show-following-heading t)
6765 (org-show-siblings t)
6766 (org-show-hierarchy-above t)
6767 (org-show-entry-below t)
6768 col)
6769 (outline-next-heading)
6770 (org-back-over-empty-lines)
6771 (or (looking-at "[ \t]*$")
6772 (progn (insert "\n") (backward-char 1)))
6773 (org-insert-heading)
6774 (org-do-demote)
6775 (setq col (current-column))
6776 (insert text "\n")
6777 (if org-adapt-indentation (org-indent-to-column col))
6778 (let ((org-show-following-heading t)
6779 (org-show-siblings t)
6780 (org-show-hierarchy-above t)
6781 (org-show-entry-below t))
6782 (org-show-context))))
6783
20908596
CD
6784(defun org-agenda-diary-entry ()
6785 "Make a diary entry, like the `i' command from the calendar.
8bfe682a
CD
6786All the standard commands work: block, weekly etc.
6787When `org-agenda-diary-file' points to a file,
6788`org-agenda-diary-entry-in-org-file' is called instead to create
6789entries in that Org-mode file."
20908596
CD
6790 (interactive)
6791 (org-agenda-check-type t 'agenda 'timeline)
8bfe682a
CD
6792 (if (not (eq org-agenda-diary-file 'diary-file))
6793 (org-agenda-diary-entry-in-org-file)
6794 (require 'diary-lib)
6795 (let* ((char (progn
6796 (message "Diary entry: [d]ay [w]eekly [m]onthly [y]early [a]nniversary [b]lock [c]yclic")
6797 (read-char-exclusive)))
6798 (cmd (cdr (assoc char
6799 '((?d . insert-diary-entry)
6800 (?w . insert-weekly-diary-entry)
6801 (?m . insert-monthly-diary-entry)
6802 (?y . insert-yearly-diary-entry)
6803 (?a . insert-anniversary-diary-entry)
6804 (?b . insert-block-diary-entry)
6805 (?c . insert-cyclic-diary-entry)))))
6806 (oldf (symbol-function 'calendar-cursor-to-date))
6807 ;; (buf (get-file-buffer (substitute-in-file-name diary-file)))
6808 (point (point))
6809 (mark (or (mark t) (point))))
6810 (unless cmd
6811 (error "No command associated with <%c>" char))
6812 (unless (and (get-text-property point 'day)
6813 (or (not (equal ?b char))
6814 (get-text-property mark 'day)))
6815 (error "Don't know which date to use for diary entry"))
6816 ;; We implement this by hacking the `calendar-cursor-to-date' function
6817 ;; and the `calendar-mark-ring' variable. Saves a lot of code.
6818 (let ((calendar-mark-ring
6819 (list (calendar-gregorian-from-absolute
6820 (or (get-text-property mark 'day)
6821 (get-text-property point 'day))))))
6822 (unwind-protect
6823 (progn
6824 (fset 'calendar-cursor-to-date
6825 (lambda (&optional error dummy)
6826 (calendar-gregorian-from-absolute
6827 (get-text-property point 'day))))
20908596 6828 (call-interactively cmd))
8bfe682a 6829 (fset 'calendar-cursor-to-date oldf))))))
20908596 6830
20908596
CD
6831(defun org-agenda-execute-calendar-command (cmd)
6832 "Execute a calendar command from the agenda, with the date associated to
6833the cursor position."
6834 (org-agenda-check-type t 'agenda 'timeline)
6835 (require 'diary-lib)
6836 (unless (get-text-property (point) 'day)
6837 (error "Don't know which date to use for calendar command"))
6838 (let* ((oldf (symbol-function 'calendar-cursor-to-date))
6839 (point (point))
6840 (date (calendar-gregorian-from-absolute
6841 (get-text-property point 'day)))
6842 ;; the following 2 vars are needed in the calendar
6843 (displayed-month (car date))
6844 (displayed-year (nth 2 date)))
6845 (unwind-protect
6846 (progn
6847 (fset 'calendar-cursor-to-date
0627c265 6848 (lambda (&optional error dummy)
20908596
CD
6849 (calendar-gregorian-from-absolute
6850 (get-text-property point 'day))))
6851 (call-interactively cmd))
6852 (fset 'calendar-cursor-to-date oldf))))
6853
6854(defun org-agenda-phases-of-moon ()
6855 "Display the phases of the moon for the 3 months around the cursor date."
6856 (interactive)
6857 (org-agenda-execute-calendar-command 'calendar-phases-of-moon))
6858
6859(defun org-agenda-holidays ()
6860 "Display the holidays for the 3 months around the cursor date."
6861 (interactive)
6862 (org-agenda-execute-calendar-command 'list-calendar-holidays))
6863
6864(defvar calendar-longitude)
6865(defvar calendar-latitude)
6866(defvar calendar-location-name)
6867
6868(defun org-agenda-sunrise-sunset (arg)
6869 "Display sunrise and sunset for the cursor date.
6870Latitude and longitude can be specified with the variables
6871`calendar-latitude' and `calendar-longitude'. When called with prefix
6872argument, latitude and longitude will be prompted for."
6873 (interactive "P")
6874 (require 'solar)
6875 (let ((calendar-longitude (if arg nil calendar-longitude))
6876 (calendar-latitude (if arg nil calendar-latitude))
6877 (calendar-location-name
6878 (if arg "the given coordinates" calendar-location-name)))
6879 (org-agenda-execute-calendar-command 'calendar-sunrise-sunset)))
6880
6881(defun org-agenda-goto-calendar ()
6882 "Open the Emacs calendar with the date at the cursor."
6883 (interactive)
6884 (org-agenda-check-type t 'agenda 'timeline)
6885 (let* ((day (or (get-text-property (point) 'day)
6886 (error "Don't know which date to open in calendar")))
6887 (date (calendar-gregorian-from-absolute day))
6888 (calendar-move-hook nil)
6889 (calendar-view-holidays-initially-flag nil)
6890 (calendar-view-diary-initially-flag nil)
6891 (view-calendar-holidays-initially nil)
20908596
CD
6892 (view-diary-entries-initially nil))
6893 (calendar)
6894 (calendar-goto-date date)))
6895
6896;;;###autoload
6897(defun org-calendar-goto-agenda ()
6898 "Compute the Org-mode agenda for the calendar date displayed at the cursor.
6899This is a command that has to be installed in `calendar-mode-map'."
6900 (interactive)
6901 (org-agenda-list nil (calendar-absolute-from-gregorian
6902 (calendar-cursor-to-date))
6903 nil))
6904
6905(defun org-agenda-convert-date ()
6906 (interactive)
6907 (org-agenda-check-type t 'agenda 'timeline)
6908 (let ((day (get-text-property (point) 'day))
6909 date s)
6910 (unless day
6911 (error "Don't know which date to convert"))
6912 (setq date (calendar-gregorian-from-absolute day))
6913 (setq s (concat
6914 "Gregorian: " (calendar-date-string date) "\n"
6915 "ISO: " (calendar-iso-date-string date) "\n"
6916 "Day of Yr: " (calendar-day-of-year-string date) "\n"
6917 "Julian: " (calendar-julian-date-string date) "\n"
6918 "Astron. JD: " (calendar-astro-date-string date)
6919 " (Julian date number at noon UTC)\n"
6920 "Hebrew: " (calendar-hebrew-date-string date) " (until sunset)\n"
6921 "Islamic: " (calendar-islamic-date-string date) " (until sunset)\n"
6922 "French: " (calendar-french-date-string date) "\n"
6923 "Baha'i: " (calendar-bahai-date-string date) " (until sunset)\n"
6924 "Mayan: " (calendar-mayan-date-string date) "\n"
6925 "Coptic: " (calendar-coptic-date-string date) "\n"
6926 "Ethiopic: " (calendar-ethiopic-date-string date) "\n"
6927 "Persian: " (calendar-persian-date-string date) "\n"
6928 "Chinese: " (calendar-chinese-date-string date) "\n"))
6929 (with-output-to-temp-buffer "*Dates*"
6930 (princ s))
93b62de8 6931 (org-fit-window-to-buffer (get-buffer-window "*Dates*"))))
20908596 6932
c8d0cf5c
CD
6933;;; Bulk commands
6934
6935(defvar org-agenda-bulk-marked-entries nil
6936 "List of markers that refer to marked entries in the agenda.")
6937
54a0dee5
CD
6938(defun org-agenda-bulk-marked-p ()
6939 (eq (get-char-property (point-at-bol) 'type)
6940 'org-marked-entry-overlay))
6941
c8d0cf5c
CD
6942(defun org-agenda-bulk-mark ()
6943 "Mark the entry at point for future bulk action."
6944 (interactive)
6945 (org-agenda-check-no-diary)
8d642074 6946 (let* ((m (org-get-at-bol 'org-hd-marker))
c8d0cf5c 6947 ov)
54a0dee5 6948 (unless (org-agenda-bulk-marked-p)
c8d0cf5c
CD
6949 (unless m (error "Nothing to mark at point"))
6950 (push m org-agenda-bulk-marked-entries)
6951 (setq ov (org-make-overlay (point-at-bol) (+ 2 (point-at-bol))))
8d642074 6952 (org-overlay-display ov "> "
c8d0cf5c
CD
6953 (org-get-todo-face "TODO")
6954 'evaporate)
6955 (org-overlay-put ov 'type 'org-marked-entry-overlay))
6956 (beginning-of-line 2)
6957 (message "%d entries marked for bulk action"
6958 (length org-agenda-bulk-marked-entries))))
6959
6960(defun org-agenda-bulk-unmark ()
6961 "Unmark the entry at point for future bulk action."
6962 (interactive)
54a0dee5 6963 (when (org-agenda-bulk-marked-p)
c8d0cf5c
CD
6964 (org-agenda-bulk-remove-overlays
6965 (point-at-bol) (+ 2 (point-at-bol)))
6966 (setq org-agenda-bulk-marked-entries
8d642074 6967 (delete (org-get-at-bol 'org-hd-marker)
c8d0cf5c
CD
6968 org-agenda-bulk-marked-entries)))
6969 (beginning-of-line 2)
6970 (message "%d entries marked for bulk action"
6971 (length org-agenda-bulk-marked-entries)))
6972
54a0dee5
CD
6973(defun org-agenda-bulk-toggle ()
6974 "Toggle marking the entry at point for bulk action."
6975 (interactive)
6976 (if (org-agenda-bulk-marked-p)
6977 (org-agenda-bulk-unmark)
6978 (org-agenda-bulk-mark)))
c8d0cf5c
CD
6979
6980(defun org-agenda-bulk-remove-overlays (&optional beg end)
6981 "Remove the mark overlays between BEG and END in the agenda buffer.
6982BEG and END default to the buffer limits.
6983
6984This only removes the overlays, it does not remove the markers
6985from the list in `org-agenda-bulk-marked-entries'."
6986 (interactive)
6987 (mapc (lambda (ov)
6988 (and (eq (org-overlay-get ov 'type) 'org-marked-entry-overlay)
6989 (org-delete-overlay ov)))
6990 (org-overlays-in (or beg (point-min)) (or end (point-max)))))
6991
6992(defun org-agenda-bulk-remove-all-marks ()
6993 "Remove all marks in the agenda buffer.
6994This will remove the markers, and the overlays."
6995 (interactive)
6996 (mapc (lambda (m) (move-marker m nil)) org-agenda-bulk-marked-entries)
6997 (setq org-agenda-bulk-marked-entries nil)
6998 (org-agenda-bulk-remove-overlays (point-min) (point-max)))
6999
7000(defun org-agenda-bulk-action ()
7001 "Execute an remote-editing action on all marked entries."
7002 (interactive)
7003 (unless org-agenda-bulk-marked-entries
7004 (error "No entries are marked"))
7005 (message "Bulk: [r]efile [$]archive [A]rch->sib [t]odo [+/-]tag [s]chedule [d]eadline")
7006 (let* ((action (read-char-exclusive))
7007 (entries (reverse org-agenda-bulk-marked-entries))
7008 cmd rfloc state e tag pos (cnt 0) (cntskip 0))
7009 (cond
7010 ((equal action ?$)
7011 (setq cmd '(org-agenda-archive)))
7012
7013 ((equal action ?A)
7014 (setq cmd '(org-agenda-archive-to-archive-sibling)))
7015
7016 ((member action '(?r ?w))
7017 (setq rfloc (org-refile-get-location
7018 "Refile to: "
7019 (marker-buffer (car org-agenda-bulk-marked-entries))
7020 org-refile-allow-creating-parent-nodes))
7021 (setcar (nthcdr 3 rfloc)
7022 (move-marker (make-marker) (nth 3 rfloc)
7023 (or (get-file-buffer (nth 1 rfloc))
7024 (find-buffer-visiting (nth 1 rfloc))
7025 (error "This should not happen"))))
7026
7027 (setq cmd (list 'org-agenda-refile nil (list 'quote rfloc))))
7028
7029 ((equal action ?t)
54a0dee5 7030 (setq state (org-icompleting-read
c8d0cf5c
CD
7031 "Todo state: "
7032 (with-current-buffer (marker-buffer (car entries))
7033 (mapcar 'list org-todo-keywords-1))))
7034 (setq cmd `(let ((org-inhibit-blocking t)
7035 (org-inhibit-logging 'note))
7036 (org-agenda-todo ,state))))
7037
7038 ((memq action '(?- ?+))
54a0dee5 7039 (setq tag (org-icompleting-read
c8d0cf5c
CD
7040 (format "Tag to %s: " (if (eq action ?+) "add" "remove"))
7041 (with-current-buffer (marker-buffer (car entries))
7042 (delq nil
7043 (mapcar (lambda (x)
7044 (if (stringp (car x)) x)) org-tag-alist)))))
7045 (setq cmd `(org-agenda-set-tags ,tag ,(if (eq action ?+) ''on ''off))))
7046
7047 ((memq action '(?s ?d))
7048 (let* ((date (org-read-date
7049 nil nil nil
7050 (if (eq action ?s) "(Re)Schedule to" "Set Deadline to")))
7051 (ans org-read-date-final-answer)
7052 (c1 (if (eq action ?s) 'org-agenda-schedule 'org-agenda-deadline)))
7053 (setq cmd `(let* ((bound (fboundp 'read-string))
7054 (old (and bound (symbol-function 'read-string))))
7055 (unwind-protect
7056 (progn
7057 (fset 'read-string (lambda (&rest ignore) ,ans))
7058 (call-interactively ',c1))
7059 (if bound
7060 (fset 'read-string old)
7061 (fmakunbound 'read-string)))))))
7062 (t (error "Invalid bulk action")))
7063
7064 ;; Sort the markers, to make sure that parents are handled before children
7065 (setq entries (sort entries
7066 (lambda (a b)
7067 (cond
7068 ((equal (marker-buffer a) (marker-buffer b))
7069 (< (marker-position a) (marker-position b)))
7070 (t
7071 (string< (buffer-name (marker-buffer a))
7072 (buffer-name (marker-buffer b))))))))
7073
7074 ;; Now loop over all markers and apply cmd
7075 (while (setq e (pop entries))
7076 (setq pos (text-property-any (point-min) (point-max) 'org-hd-marker e))
7077 (if (not pos)
7078 (progn (message "Skipping removed entry at %s" e)
7079 (setq cntskip (1+ cntskip)))
7080 (goto-char pos)
7081 (eval cmd)
7082 (setq org-agenda-bulk-marked-entries
7083 (delete e org-agenda-bulk-marked-entries))
7084 (setq cnt (1+ cnt))))
7085 (setq org-agenda-bulk-marked-entries nil)
7086 (org-agenda-bulk-remove-all-marks)
7087 (message "Acted on %d entries%s"
7088 cnt
7089 (if (= cntskip 0)
7090 ""
7091 (format ", skipped %d (disappeared before their turn)"
7092 cntskip)))))
8d642074
CD
7093
7094;;; Flagging notes
7095
7096(defun org-agenda-show-the-flagging-note ()
7097 "Display the flagging note in the other window.
7098When called a second time in direct sequence, offer to remove the FLAGGING
7099tag and (if present) the flagging note."
7100 (interactive)
7101 (let ((hdmarker (org-get-at-bol 'org-hd-marker))
7102 (win (selected-window))
7103 note heading newhead)
7104 (unless hdmarker
7105 (error "No linked entry at point"))
7106 (if (and (eq this-command last-command)
7107 (y-or-n-p "Unflag and remove any flagging note? "))
7108 (progn
7109 (org-agenda-remove-flag hdmarker)
7110 (let ((win (get-buffer-window "*Flagging Note*")))
7111 (and win (delete-window win)))
7112 (message "Entry unflaged"))
7113 (setq note (org-entry-get hdmarker "THEFLAGGINGNOTE"))
7114 (unless note
7115 (error "No flagging note"))
7116 (org-kill-new note)
7117 (org-switch-to-buffer-other-window "*Flagging Note*")
7118 (erase-buffer)
7119 (insert note)
7120 (goto-char (point-min))
7121 (while (re-search-forward "\\\\n" nil t)
7122 (replace-match "\n" t t))
7123 (goto-char (point-min))
7124 (select-window win)
7125 (message "Flagging note pushed to kill ring. Press [?] again to remove tag and note"))))
7126
7127(defun org-agenda-remove-flag (marker)
8bfe682a 7128 "Remove the FLAGGED tag and any flagging note in the entry."
8d642074
CD
7129 (let (newhead)
7130 (org-with-point-at marker
7131 (org-toggle-tag "FLAGGED" 'off)
7132 (org-entry-delete nil "THEFLAGGINGNOTE")
7133 (setq newhead (org-get-heading)))
7134 (org-agenda-change-all-lines newhead marker)
7135 (message "Entry unflaged")))
7136
7137(defun org-agenda-get-any-marker (&optional pos)
7138 (or (get-text-property (or pos (point-at-bol)) 'org-hd-marker)
7139 (get-text-property (or pos (point-at-bol)) 'org-marker)))
c8d0cf5c 7140
20908596
CD
7141;;; Appointment reminders
7142
7143(defvar appt-time-msg-list)
7144
7145;;;###autoload
7146(defun org-agenda-to-appt (&optional refresh filter)
7147 "Activate appointments found in `org-agenda-files'.
7148With a \\[universal-argument] prefix, refresh the list of
33306645 7149appointments.
20908596
CD
7150
7151If FILTER is t, interactively prompt the user for a regular
7152expression, and filter out entries that don't match it.
7153
7154If FILTER is a string, use this string as a regular expression
7155for filtering entries out.
7156
7157FILTER can also be an alist with the car of each cell being
7158either 'headline or 'category. For example:
7159
7160 '((headline \"IMPORTANT\")
7161 (category \"Work\"))
7162
7163will only add headlines containing IMPORTANT or headlines
7164belonging to the \"Work\" category."
7165 (interactive "P")
7166 (require 'calendar)
7167 (if refresh (setq appt-time-msg-list nil))
7168 (if (eq filter t)
7169 (setq filter (read-from-minibuffer "Regexp filter: ")))
7170 (let* ((cnt 0) ; count added events
7171 (org-agenda-new-buffers nil)
7172 (org-deadline-warning-days 0)
7173 (today (org-date-to-gregorian
7174 (time-to-days (current-time))))
c8d0cf5c 7175 (org-agenda-restrict nil)
621f83e4 7176 (files (org-agenda-files 'unrestricted)) entries file)
20908596 7177 ;; Get all entries which may contain an appt
db55f368 7178 (org-prepare-agenda-buffers files)
20908596
CD
7179 (while (setq file (pop files))
7180 (setq entries
7181 (append entries
7182 (org-agenda-get-day-entries
7183 file today :timestamp :scheduled :deadline))))
7184 (setq entries (delq nil entries))
7185 ;; Map thru entries and find if we should filter them out
7186 (mapc
7187 (lambda(x)
621f83e4 7188 (let* ((evt (org-trim (or (get-text-property 1 'txt x) "")))
20908596
CD
7189 (cat (get-text-property 1 'org-category x))
7190 (tod (get-text-property 1 'time-of-day x))
7191 (ok (or (null filter)
7192 (and (stringp filter) (string-match filter evt))
7193 (and (listp filter)
7194 (or (string-match
7195 (cadr (assoc 'category filter)) cat)
7196 (string-match
7197 (cadr (assoc 'headline filter)) evt))))))
7198 ;; FIXME: Shall we remove text-properties for the appt text?
7199 ;; (setq evt (set-text-properties 0 (length evt) nil evt))
7200 (when (and ok tod)
621f83e4 7201 (setq tod (concat "00" (number-to-string tod))
20908596 7202 tod (when (string-match
621f83e4 7203 "\\([0-9]\\{1,2\\}\\)\\([0-9]\\{2\\}\\)\\'" tod)
20908596
CD
7204 (concat (match-string 1 tod) ":"
7205 (match-string 2 tod))))
7206 (appt-add tod evt)
7207 (setq cnt (1+ cnt))))) entries)
7208 (org-release-buffers org-agenda-new-buffers)
7209 (if (eq cnt 0)
7210 (message "No event to add")
7211 (message "Added %d event%s for today" cnt (if (> cnt 1) "s" "")))))
7212
621f83e4
CD
7213(defun org-agenda-todayp (date)
7214 "Does DATE mean today, when considering `org-extend-today-until'?"
7215 (let (today h)
7216 (if (listp date) (setq date (calendar-absolute-from-gregorian date)))
7217 (setq today (calendar-absolute-from-gregorian (calendar-current-date)))
7218 (setq h (nth 2 (decode-time (current-time))))
7219 (or (and (>= h org-extend-today-until)
7220 (= date today))
7221 (and (< h org-extend-today-until)
7222 (= date (1- today))))))
7223
20908596
CD
7224(provide 'org-agenda)
7225
b349f79f
CD
7226;; arch-tag: 77f7565d-7c4b-44af-a2df-9f6f7070cff1
7227
20908596 7228;;; org-agenda.el ends here