Spelling fixes.
[bpt/emacs.git] / lisp / org / org-agenda.el
CommitLineData
b349f79f 1;;; org-agenda.el --- Dynamic task and appointment lists for Org
20908596 2
b73f1974 3;; Copyright (C) 2004-2012 Free Software Foundation, Inc.
20908596
CD
4
5;; Author: Carsten Dominik <carsten at orgmode dot org>
6;; Keywords: outlines, hypermedia, calendar, wp
7;; Homepage: http://orgmode.org
20908596
CD
8;;
9;; This file is part of GNU Emacs.
10;;
b1fc2b50 11;; GNU Emacs is free software: you can redistribute it and/or modify
20908596 12;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
20908596
CD
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
b1fc2b50 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
20908596
CD
23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24;;
25;;; Commentary:
26
27;; This file contains the code for creating and using the Agenda for Org-mode.
e66ba1df
BG
28;;
29;; The functions `org-batch-agenda', `org-batch-agenda-csv', and
30;; `org-batch-store-agenda-views' are implemented as macros to provide
27e428e7 31;; a convenient way for extracting agenda information from the command
e66ba1df
BG
32;; line. The Lisp does not evaluate parameters of a macro call; thus
33;; it is not necessary to quote the parameters passed to one of those
34;; functions. E.g. you can write:
35;;
36;; emacs -batch -l ~/.emacs -eval '(org-batch-agenda "a" org-agenda-span 7)'
37;;
38;; To export an agenda spanning 7 days. If `org-batch-agenda' would
39;; have been implemented as a regular function you'd have to quote the
40;; symbol org-agenda-span. Moreover: To use a symbol as parameter
41;; value you would have to double quote the symbol.
42;;
43;; This is a hack, but it works even when running Org byte-compiled.
44;;
20908596
CD
45
46;;; Code:
47
48(require 'org)
49(eval-when-compile
86fbb8ca 50 (require 'cl))
20908596 51
b349f79f 52(declare-function diary-add-to-list "diary-lib"
20908596
CD
53 (date string specifier &optional marker globcolor literal))
54(declare-function calendar-absolute-from-iso "cal-iso" (date))
55(declare-function calendar-astro-date-string "cal-julian" (&optional date))
56(declare-function calendar-bahai-date-string "cal-bahai" (&optional date))
20908596
CD
57(declare-function calendar-chinese-date-string "cal-china" (&optional date))
58(declare-function calendar-coptic-date-string "cal-coptic" (&optional date))
59(declare-function calendar-ethiopic-date-string "cal-coptic" (&optional date))
60(declare-function calendar-french-date-string "cal-french" (&optional date))
61(declare-function calendar-goto-date "cal-move" (date))
62(declare-function calendar-hebrew-date-string "cal-hebrew" (&optional date))
63(declare-function calendar-islamic-date-string "cal-islam" (&optional date))
64(declare-function calendar-iso-date-string "cal-iso" (&optional date))
f6aafbed 65(declare-function calendar-iso-from-absolute "cal-iso" (date))
20908596
CD
66(declare-function calendar-julian-date-string "cal-julian" (&optional date))
67(declare-function calendar-mayan-date-string "cal-mayan" (&optional date))
68(declare-function calendar-persian-date-string "cal-persia" (&optional date))
e66ba1df
BG
69(declare-function calendar-check-holidays "holidays" (date))
70
68a1b090
GM
71(declare-function org-datetree-find-date-create "org-datetree"
72 (date &optional keep-restriction))
20908596 73(declare-function org-columns-quit "org-colview" ())
8bfe682a
CD
74(declare-function diary-date-display-form "diary-lib" (&optional type))
75(declare-function org-mobile-write-agenda-for-mobile "org-mobile" (file))
76(declare-function org-habit-insert-consistency-graphs
77 "org-habit" (&optional line))
78(declare-function org-is-habit-p "org-habit" (&optional pom))
79(declare-function org-habit-parse-todo "org-habit" (&optional pom))
68a1b090 80(declare-function org-habit-get-priority "org-habit" (habit &optional moment))
e66ba1df
BG
81(declare-function org-pop-to-buffer-same-window "org-compat"
82 (&optional buffer-or-name norecord label))
3ab2c837 83
20908596 84(defvar calendar-mode-map)
afe98dfa 85(defvar org-clock-current-task) ; defined in org-clock.el
8d642074 86(defvar org-mobile-force-id-on-agenda-items) ; defined in org-mobile.el
8bfe682a
CD
87(defvar org-habit-show-habits)
88(defvar org-habit-show-habits-only-for-today)
20908596
CD
89
90;; Defined somewhere in this file, but used before definition.
91(defvar org-agenda-buffer-name)
92(defvar org-agenda-overriding-header)
8d642074 93(defvar org-agenda-title-append nil)
23f6720e 94(defvar entry)
20908596
CD
95(defvar date)
96(defvar org-agenda-undo-list)
97(defvar org-agenda-pending-undo-list)
98(defvar original-date) ; dynamically scoped, calendar.el does scope this
99
100(defcustom org-agenda-confirm-kill 1
101 "When set, remote killing from the agenda buffer needs confirmation.
102When t, a confirmation is always needed. When a number N, confirmation is
103only needed when the text to be killed contains more than N non-white lines."
104 :group 'org-agenda
105 :type '(choice
106 (const :tag "Never" nil)
107 (const :tag "Always" t)
c8d0cf5c 108 (integer :tag "When more than N lines")))
20908596
CD
109
110(defcustom org-agenda-compact-blocks nil
ed21c5c8 111 "Non-nil means make the block agenda more compact.
3ab2c837
BG
112This is done globally by leaving out lines like the agenda span
113name and week number or the separator lines."
20908596
CD
114 :group 'org-agenda
115 :type 'boolean)
116
0bd48b37
CD
117(defcustom org-agenda-block-separator ?=
118 "The separator between blocks in the agenda.
119If this is a string, it will be used as the separator, with a newline added.
3ab2c837
BG
120If it is a character, it will be repeated to fill the window width.
121If nil the separator is disabled. In `org-agenda-custom-commands' this
122addresses the separator between the current and the previous block."
0bd48b37
CD
123 :group 'org-agenda
124 :type '(choice
3ab2c837 125 (const :tag "Disabled" nil)
0bd48b37
CD
126 (character)
127 (string)))
128
20908596
CD
129(defgroup org-agenda-export nil
130 "Options concerning exporting agenda views in Org-mode."
131 :tag "Org Agenda Export"
132 :group 'org-agenda)
133
134(defcustom org-agenda-with-colors t
ed21c5c8 135 "Non-nil means use colors in agenda views."
20908596
CD
136 :group 'org-agenda-export
137 :type 'boolean)
138
139(defcustom org-agenda-exporter-settings nil
140 "Alist of variable/value pairs that should be active during agenda export.
c8d0cf5c
CD
141This is a good place to set options for ps-print and for htmlize.
142Note that the way this is implemented, the values will be evaluated
143before assigned to the variables. So make sure to quote values you do
144*not* want evaluated, for example
145
146 (setq org-agenda-exporter-settings
147 '((ps-print-color-p 'black-white)))"
20908596
CD
148 :group 'org-agenda-export
149 :type '(repeat
150 (list
151 (variable)
152 (sexp :tag "Value"))))
153
c8d0cf5c
CD
154(defcustom org-agenda-before-write-hook '(org-agenda-add-entry-text)
155 "Hook run in temporary buffer before writing it to an export file.
156A useful function is `org-agenda-add-entry-text'."
157 :group 'org-agenda-export
158 :type 'hook
159 :options '(org-agenda-add-entry-text))
160
161(defcustom org-agenda-add-entry-text-maxlines 0
162 "Maximum number of entry text lines to be added to agenda.
163This is only relevant when `org-agenda-add-entry-text' is part of
164`org-agenda-before-write-hook', which it is by default.
165When this is 0, nothing will happen. When it is greater than 0, it
166specifies the maximum number of lines that will be added for each entry
54a0dee5
CD
167that is listed in the agenda view.
168
169Note that this variable is not used during display, only when exporting
86fbb8ca
CD
170the agenda. For agenda display, see the variables `org-agenda-entry-text-mode'
171and `org-agenda-entry-text-maxlines'."
c8d0cf5c
CD
172 :group 'org-agenda
173 :type 'integer)
174
175(defcustom org-agenda-add-entry-text-descriptive-links t
ed21c5c8 176 "Non-nil means export org-links as descriptive links in agenda added text.
c8d0cf5c
CD
177This variable applies to the text added to the agenda when
178`org-agenda-add-entry-text-maxlines' is larger than 0.
e66ba1df 179When this variable nil, the URL will (also) be shown."
c8d0cf5c
CD
180 :group 'org-agenda
181 :type 'boolean)
182
20908596
CD
183(defcustom org-agenda-export-html-style ""
184 "The style specification for exported HTML Agenda files.
185If this variable contains a string, it will replace the default <style>
186section as produced by `htmlize'.
187Since there are different ways of setting style information, this variable
188needs to contain the full HTML structure to provide a style, including the
189surrounding HTML tags. The style specifications should include definitions
190the fonts used by the agenda, here is an example:
191
192 <style type=\"text/css\">
193 p { font-weight: normal; color: gray; }
194 .org-agenda-structure {
195 font-size: 110%;
196 color: #003399;
197 font-weight: 600;
198 }
199 .org-todo {
200 color: #cc6666;
201 font-weight: bold;
202 }
c8d0cf5c
CD
203 .org-agenda-done {
204 color: #339933;
205 }
20908596
CD
206 .org-done {
207 color: #339933;
208 }
209 .title { text-align: center; }
210 .todo, .deadline { color: red; }
211 .done { color: green; }
212 </style>
213
214or, if you want to keep the style in a file,
215
216 <link rel=\"stylesheet\" type=\"text/css\" href=\"mystyles.css\">
217
218As the value of this option simply gets inserted into the HTML <head> header,
219you can \"misuse\" it to also add other text to the header. However,
220<style>...</style> is required, if not present the variable will be ignored."
221 :group 'org-agenda-export
222 :group 'org-export-html
223 :type 'string)
224
86fbb8ca
CD
225(defcustom org-agenda-persistent-filter nil
226 "When set, keep filters from one agenda view to the next."
227 :group 'org-agenda
228 :type 'boolean)
229
20908596
CD
230(defgroup org-agenda-custom-commands nil
231 "Options concerning agenda views in Org-mode."
232 :tag "Org Agenda Custom Commands"
233 :group 'org-agenda)
234
235(defconst org-sorting-choice
236 '(choice
237 (const time-up) (const time-down)
238 (const category-keep) (const category-up) (const category-down)
239 (const tag-down) (const tag-up)
240 (const priority-up) (const priority-down)
621f83e4 241 (const todo-state-up) (const todo-state-down)
c8d0cf5c 242 (const effort-up) (const effort-down)
8bfe682a 243 (const habit-up) (const habit-down)
86fbb8ca 244 (const alpha-up) (const alpha-down)
c8d0cf5c 245 (const user-defined-up) (const user-defined-down))
20908596
CD
246 "Sorting choices.")
247
e66ba1df
BG
248;; Keep custom values for `org-agenda-filter-preset' compatible with
249;; the new variable `org-agenda-tag-filter-preset'.
153ae947 250(defvaralias 'org-agenda-filter-preset 'org-agenda-tag-filter-preset)
e66ba1df 251
20908596
CD
252(defconst org-agenda-custom-commands-local-options
253 `(repeat :tag "Local settings for this command. Remember to quote values"
254 (choice :tag "Setting"
c8d0cf5c
CD
255 (list :tag "Heading for this block"
256 (const org-agenda-overriding-header)
257 (string :tag "Headline"))
20908596
CD
258 (list :tag "Files to be searched"
259 (const org-agenda-files)
260 (list
261 (const :format "" quote)
c8d0cf5c 262 (repeat (file))))
20908596
CD
263 (list :tag "Sorting strategy"
264 (const org-agenda-sorting-strategy)
265 (list
266 (const :format "" quote)
267 (repeat
268 ,org-sorting-choice)))
269 (list :tag "Prefix format"
270 (const org-agenda-prefix-format :value " %-12:c%?-12t% s")
271 (string))
272 (list :tag "Number of days in agenda"
acedf35c
CD
273 (const org-agenda-span)
274 (choice (const :tag "Day" 'day)
275 (const :tag "Week" 'week)
276 (const :tag "Month" 'month)
277 (const :tag "Year" 'year)
278 (integer :tag "Custom")))
20908596
CD
279 (list :tag "Fixed starting date"
280 (const org-agenda-start-day)
281 (string :value "2007-11-01"))
282 (list :tag "Start on day of week"
283 (const org-agenda-start-on-weekday)
284 (choice :value 1
285 (const :tag "Today" nil)
c8d0cf5c 286 (integer :tag "Weekday No.")))
20908596
CD
287 (list :tag "Include data from diary"
288 (const org-agenda-include-diary)
289 (boolean))
290 (list :tag "Deadline Warning days"
291 (const org-deadline-warning-days)
292 (integer :value 1))
e66ba1df
BG
293 (list :tag "Category filter preset"
294 (const org-agenda-category-filter-preset)
295 (list
296 (const :format "" quote)
297 (repeat
298 (string :tag "+category or -category"))))
c8d0cf5c 299 (list :tag "Tags filter preset"
e66ba1df 300 (const org-agenda-tag-filter-preset)
c8d0cf5c
CD
301 (list
302 (const :format "" quote)
303 (repeat
304 (string :tag "+tag or -tag"))))
ed21c5c8
CD
305 (list :tag "Set daily/weekly entry types"
306 (const org-agenda-entry-types)
153ae947
BG
307 (list
308 (const :format "" quote)
309 (set :greedy t :value (:deadline :scheduled :timestamp :sexp)
310 (const :deadline)
311 (const :scheduled)
312 (const :timestamp)
313 (const :sexp))))
20908596
CD
314 (list :tag "Standard skipping condition"
315 :value (org-agenda-skip-function '(org-agenda-skip-entry-if))
316 (const org-agenda-skip-function)
317 (list
318 (const :format "" quote)
319 (list
320 (choice
33306645 321 :tag "Skipping range"
20908596
CD
322 (const :tag "Skip entry" org-agenda-skip-entry-if)
323 (const :tag "Skip subtree" org-agenda-skip-subtree-if))
324 (repeat :inline t :tag "Conditions for skipping"
325 (choice
326 :tag "Condition type"
327 (list :tag "Regexp matches" :inline t (const :format "" 'regexp) (regexp))
328 (list :tag "Regexp does not match" :inline t (const :format "" 'notregexp) (regexp))
ed21c5c8
CD
329 (list :tag "TODO state is" :inline t
330 (const 'todo)
331 (choice
332 (const :tag "any not-done state" 'todo)
333 (const :tag "any done state" 'done)
334 (const :tag "any state" 'any)
335 (list :tag "Keyword list"
336 (const :format "" quote)
337 (repeat (string :tag "Keyword")))))
338 (list :tag "TODO state is not" :inline t
339 (const 'nottodo)
340 (choice
341 (const :tag "any not-done state" 'todo)
342 (const :tag "any done state" 'done)
343 (const :tag "any state" 'any)
344 (list :tag "Keyword list"
345 (const :format "" quote)
346 (repeat (string :tag "Keyword")))))
20908596
CD
347 (const :tag "scheduled" 'scheduled)
348 (const :tag "not scheduled" 'notscheduled)
349 (const :tag "deadline" 'deadline)
c8d0cf5c
CD
350 (const :tag "no deadline" 'notdeadline)
351 (const :tag "timestamp" 'timestamp)
352 (const :tag "no timestamp" 'nottimestamp))))))
20908596
CD
353 (list :tag "Non-standard skipping condition"
354 :value (org-agenda-skip-function)
2c3ad40d 355 (const org-agenda-skip-function)
c8d0cf5c
CD
356 (sexp :tag "Function or form (quoted!)"))
357 (list :tag "Any variable"
358 (variable :tag "Variable")
359 (sexp :tag "Value (sexp)"))))
20908596
CD
360 "Selection of examples for agenda command settings.
361This will be spliced into the custom type of
362`org-agenda-custom-commands'.")
363
364
e66ba1df
BG
365(defcustom org-agenda-custom-commands '(("n" "Agenda and all TODO's"
366 ((agenda "") (alltodo))))
20908596
CD
367 "Custom commands for the agenda.
368These commands will be offered on the splash screen displayed by the
369agenda dispatcher \\[org-agenda]. Each entry is a list like this:
370
371 (key desc type match settings files)
372
373key The key (one or more characters as a string) to be associated
374 with the command.
e66ba1df 375desc A description of the command, when omitted or nil, a default
20908596
CD
376 description is built using MATCH.
377type The command type, any of the following symbols:
378 agenda The daily/weekly agenda.
379 todo Entries with a specific TODO keyword, in all agenda files.
380 search Entries containing search words entry or headline.
381 tags Tags/Property/TODO match in all agenda files.
382 tags-todo Tags/P/T match in all agenda files, TODO entries only.
383 todo-tree Sparse tree of specific TODO keyword in *current* file.
384 tags-tree Sparse tree with all tags matches in *current* file.
385 occur-tree Occur sparse tree for *current* file.
386 ... A user-defined function.
387match What to search for:
388 - a single keyword for TODO keyword searches
389 - a tags match expression for tags searches
e66ba1df 390 - a word search expression for text searches.
20908596
CD
391 - a regular expression for occur searches
392 For all other commands, this should be the empty string.
393settings A list of option settings, similar to that in a let form, so like
394 this: ((opt1 val1) (opt2 val2) ...). The values will be
395 evaluated at the moment of execution, so quote them when needed.
396files A list of files file to write the produced agenda buffer to
397 with the command `org-store-agenda-views'.
398 If a file name ends in \".html\", an HTML version of the buffer
e66ba1df 399 is written out. If it ends in \".ps\", a postscript version is
33306645 400 produced. Otherwise, only the plain text is written to the file.
20908596
CD
401
402You can also define a set of commands, to create a composite agenda buffer.
403In this case, an entry looks like this:
404
405 (key desc (cmd1 cmd2 ...) general-settings-for-whole-set files)
406
407where
408
409desc A description string to be displayed in the dispatcher menu.
410cmd An agenda command, similar to the above. However, tree commands
153ae947 411 are not allowed, but instead you can get agenda and global todo list.
20908596
CD
412 So valid commands for a set are:
413 (agenda \"\" settings)
414 (alltodo \"\" settings)
415 (stuck \"\" settings)
416 (todo \"match\" settings files)
417 (search \"match\" settings files)
418 (tags \"match\" settings files)
419 (tags-todo \"match\" settings files)
420
421Each command can carry a list of options, and another set of options can be
422given for the whole set of commands. Individual command options take
423precedence over the general options.
424
425When using several characters as key to a command, the first characters
426are prefix commands. For the dispatcher to display useful information, you
427should provide a description for the prefix, like
428
429 (setq org-agenda-custom-commands
430 '((\"h\" . \"HOME + Name tag searches\") ; describe prefix \"h\"
431 (\"hl\" tags \"+HOME+Lisa\")
432 (\"hp\" tags \"+HOME+Peter\")
433 (\"hk\" tags \"+HOME+Kim\")))"
434 :group 'org-agenda-custom-commands
435 :type `(repeat
436 (choice :value ("x" "Describe command here" tags "" nil)
437 (list :tag "Single command"
438 (string :tag "Access Key(s) ")
439 (option (string :tag "Description"))
440 (choice
441 (const :tag "Agenda" agenda)
442 (const :tag "TODO list" alltodo)
443 (const :tag "Search words" search)
444 (const :tag "Stuck projects" stuck)
c8d0cf5c
CD
445 (const :tag "Tags/Property match (all agenda files)" tags)
446 (const :tag "Tags/Property match of TODO entries (all agenda files)" tags-todo)
20908596
CD
447 (const :tag "TODO keyword search (all agenda files)" todo)
448 (const :tag "Tags sparse tree (current buffer)" tags-tree)
449 (const :tag "TODO keyword tree (current buffer)" todo-tree)
450 (const :tag "Occur tree (current buffer)" occur-tree)
451 (sexp :tag "Other, user-defined function"))
452 (string :tag "Match (only for some commands)")
453 ,org-agenda-custom-commands-local-options
454 (option (repeat :tag "Export" (file :tag "Export to"))))
455 (list :tag "Command series, all agenda files"
456 (string :tag "Access Key(s)")
457 (string :tag "Description ")
458 (repeat :tag "Component"
459 (choice
460 (list :tag "Agenda"
461 (const :format "" agenda)
462 (const :tag "" :format "" "")
463 ,org-agenda-custom-commands-local-options)
464 (list :tag "TODO list (all keywords)"
465 (const :format "" alltodo)
466 (const :tag "" :format "" "")
467 ,org-agenda-custom-commands-local-options)
468 (list :tag "Search words"
469 (const :format "" search)
470 (string :tag "Match")
471 ,org-agenda-custom-commands-local-options)
472 (list :tag "Stuck projects"
473 (const :format "" stuck)
474 (const :tag "" :format "" "")
475 ,org-agenda-custom-commands-local-options)
476 (list :tag "Tags search"
477 (const :format "" tags)
478 (string :tag "Match")
479 ,org-agenda-custom-commands-local-options)
480 (list :tag "Tags search, TODO entries only"
481 (const :format "" tags-todo)
482 (string :tag "Match")
483 ,org-agenda-custom-commands-local-options)
484 (list :tag "TODO keyword search"
485 (const :format "" todo)
486 (string :tag "Match")
487 ,org-agenda-custom-commands-local-options)
488 (list :tag "Other, user-defined function"
489 (symbol :tag "function")
490 (string :tag "Match")
491 ,org-agenda-custom-commands-local-options)))
492
493 (repeat :tag "Settings for entire command set"
494 (list (variable :tag "Any variable")
495 (sexp :tag "Value")))
496 (option (repeat :tag "Export" (file :tag "Export to"))))
497 (cons :tag "Prefix key documentation"
498 (string :tag "Access Key(s)")
499 (string :tag "Description ")))))
500
501(defcustom org-agenda-query-register ?o
502 "The register holding the current query string.
33306645 503The purpose of this is that if you construct a query string interactively,
20908596
CD
504you can then use it to define a custom command."
505 :group 'org-agenda-custom-commands
506 :type 'character)
507
508(defcustom org-stuck-projects
509 '("+LEVEL=2/-DONE" ("TODO" "NEXT" "NEXTACTION") nil "")
510 "How to identify stuck projects.
511This is a list of four items:
c8d0cf5c
CD
5121. A tags/todo/property matcher string that is used to identify a project.
513 See the manual for a description of tag and property searches.
20908596
CD
514 The entire tree below a headline matched by this is considered one project.
5152. A list of TODO keywords identifying non-stuck projects.
516 If the project subtree contains any headline with one of these todo
517 keywords, the project is considered to be not stuck. If you specify
518 \"*\" as a keyword, any TODO keyword will mark the project unstuck.
5193. A list of tags identifying non-stuck projects.
520 If the project subtree contains any headline with one of these tags,
521 the project is considered to be not stuck. If you specify \"*\" as
c8d0cf5c
CD
522 a tag, any tag will mark the project unstuck. Note that this is about
523 the explicit presence of a tag somewhere in the subtree, inherited
524 tags to not count here. If inherited tags make a project not stuck,
525 use \"-TAG\" in the tags part of the matcher under (1.) above.
20908596
CD
5264. An arbitrary regular expression matching non-stuck projects.
527
c8d0cf5c
CD
528If the project turns out to be not stuck, search continues also in the
529subtree to see if any of the subtasks have project status.
530
531See also the variable `org-tags-match-list-sublevels' which applies
532to projects matched by this search as well.
533
20908596
CD
534After defining this variable, you may use \\[org-agenda-list-stuck-projects]
535or `C-c a #' to produce the list."
536 :group 'org-agenda-custom-commands
537 :type '(list
538 (string :tag "Tags/TODO match to identify a project")
539 (repeat :tag "Projects are *not* stuck if they have an entry with TODO keyword any of" (string))
540 (repeat :tag "Projects are *not* stuck if they have an entry with TAG being any of" (string))
c8d0cf5c 541 (regexp :tag "Projects are *not* stuck if this regexp matches inside the subtree")))
20908596 542
71d35b24
CD
543(defcustom org-agenda-filter-effort-default-operator "<"
544 "The default operator for effort estimate filtering.
93b62de8 545If you select an effort estimate limit without first pressing an operator,
71d35b24
CD
546this one will be used."
547 :group 'org-agenda-custom-commands
548 :type '(choice (const :tag "less or equal" "<")
549 (const :tag "greater or equal"">")
550 (const :tag "equal" "=")))
20908596
CD
551
552(defgroup org-agenda-skip nil
553 "Options concerning skipping parts of agenda files."
554 :tag "Org Agenda Skip"
555 :group 'org-agenda)
3ab2c837
BG
556
557(defcustom org-agenda-skip-function-global nil
558 "Function to be called at each match during agenda construction.
559If this function returns nil, the current match should not be skipped.
560If the function decided to skip an agenda match, is must return the
561buffer position from which the search should be continued.
562This may also be a Lisp form, which will be evaluated.
563
564This variable will be applied to every agenda match, including
565tags/property searches and TODO lists. So try to make the test function
566do its checking as efficiently as possible. To implement a skipping
567condition just for specific agenda commands, use the variable
568`org-agenda-skip-function' which can be set in the options section
569of custom agenda commands."
570 :group 'org-agenda-skip
571 :type 'sexp)
572
0bd48b37
CD
573(defgroup org-agenda-daily/weekly nil
574 "Options concerning the daily/weekly agenda."
575 :tag "Org Agenda Daily/Weekly"
576 :group 'org-agenda)
577(defgroup org-agenda-todo-list nil
578 "Options concerning the global todo list agenda view."
579 :tag "Org Agenda Todo List"
580 :group 'org-agenda)
581(defgroup org-agenda-match-view nil
582 "Options concerning the general tags/property/todo match agenda view."
583 :tag "Org Agenda Match View"
584 :group 'org-agenda)
8bfe682a
CD
585(defgroup org-agenda-search-view nil
586 "Options concerning the general tags/property/todo match agenda view."
587 :tag "Org Agenda Match View"
588 :group 'org-agenda)
20908596 589
2c3ad40d 590(defvar org-agenda-archives-mode nil
ed21c5c8 591 "Non-nil means the agenda will include archived items.
2c3ad40d
CD
592If this is the symbol `trees', trees in the selected agenda scope
593that are marked with the ARCHIVE tag will be included anyway. When this is
594t, also all archive files associated with the current selection of agenda
595files will be included.")
596
b349f79f 597(defcustom org-agenda-skip-comment-trees t
ed21c5c8 598 "Non-nil means skip trees that start with the COMMENT keyword.
33306645 599When nil, these trees are also scanned by agenda commands."
b349f79f
CD
600 :group 'org-agenda-skip
601 :type 'boolean)
602
20908596 603(defcustom org-agenda-todo-list-sublevels t
ed21c5c8 604 "Non-nil means check also the sublevels of a TODO entry for TODO entries.
20908596
CD
605When nil, the sublevels of a TODO entry are not checked, resulting in
606potentially much shorter TODO lists."
607 :group 'org-agenda-skip
0bd48b37 608 :group 'org-agenda-todo-list
20908596
CD
609 :type 'boolean)
610
611(defcustom org-agenda-todo-ignore-with-date nil
ed21c5c8 612 "Non-nil means don't show entries with a date in the global todo list.
20908596
CD
613You can use this if you prefer to mark mere appointments with a TODO keyword,
614but don't want them to show up in the TODO list.
615When this is set, it also covers deadlines and scheduled items, the settings
616of `org-agenda-todo-ignore-scheduled' and `org-agenda-todo-ignore-deadlines'
c8d0cf5c
CD
617will be ignored.
618See also the variable `org-agenda-tags-todo-honor-ignore-options'."
20908596 619 :group 'org-agenda-skip
0bd48b37 620 :group 'org-agenda-todo-list
20908596
CD
621 :type 'boolean)
622
acedf35c
CD
623(defcustom org-agenda-todo-ignore-timestamp nil
624 "Non-nil means don't show entries with a timestamp.
625This applies when creating the global todo list.
626Valid values are:
627
628past Don't show entries for today or in the past.
629
630future Don't show entries with a timestamp in the future.
631 The idea behind this is that if it has a future
632 timestamp, you don't want to think about it until the
633 date.
634
635all Don't show any entries with a timestamp in the global todo list.
636 The idea behind this is that by setting a timestamp, you
637 have already \"taken care\" of this item.
638
3ab2c837
BG
639This variable can also have an integer as a value. If positive (N),
640todos with a timestamp N or more days in the future will be ignored. If
641negative (-N), todos with a timestamp N or more days in the past will be
642ignored. If 0, todos with a timestamp either today or in the future will
643be ignored. For example, a value of -1 will exclude todos with a
644timestamp in the past (yesterday or earlier), while a value of 7 will
645exclude todos with a timestamp a week or more in the future.
646
acedf35c
CD
647See also `org-agenda-todo-ignore-with-date'.
648See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want
649to make his option also apply to the tags-todo list."
650 :group 'org-agenda-skip
651 :group 'org-agenda-todo-list
372d7b21 652 :version "24.1"
acedf35c
CD
653 :type '(choice
654 (const :tag "Ignore future timestamp todos" future)
655 (const :tag "Ignore past or present timestamp todos" past)
656 (const :tag "Ignore all timestamp todos" all)
3ab2c837
BG
657 (const :tag "Show timestamp todos" nil)
658 (integer :tag "Ignore if N or more days in past(-) or future(+).")))
acedf35c 659
20908596 660(defcustom org-agenda-todo-ignore-scheduled nil
ed21c5c8
CD
661 "Non-nil means, ignore some scheduled TODO items when making TODO list.
662This applies when creating the global todo list.
663Valid values are:
664
665past Don't show entries scheduled today or in the past.
666
667future Don't show entries scheduled in the future.
668 The idea behind this is that by scheduling it, you don't want to
669 think about it until the scheduled date.
670
671all Don't show any scheduled entries in the global todo list.
672 The idea behind this is that by scheduling it, you have already
673 \"taken care\" of this item.
674
675t Same as `all', for backward compatibility.
676
3ab2c837
BG
677This variable can also have an integer as a value. See
678`org-agenda-todo-ignore-timestamp' for more details.
679
c8d0cf5c 680See also `org-agenda-todo-ignore-with-date'.
ed21c5c8
CD
681See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want
682to make his option also apply to the tags-todo list."
20908596 683 :group 'org-agenda-skip
0bd48b37 684 :group 'org-agenda-todo-list
ed21c5c8
CD
685 :type '(choice
686 (const :tag "Ignore future-scheduled todos" future)
687 (const :tag "Ignore past- or present-scheduled todos" past)
688 (const :tag "Ignore all scheduled todos" all)
689 (const :tag "Ignore all scheduled todos (compatibility)" t)
3ab2c837
BG
690 (const :tag "Show scheduled todos" nil)
691 (integer :tag "Ignore if N or more days in past(-) or future(+).")))
20908596
CD
692
693(defcustom org-agenda-todo-ignore-deadlines nil
ed21c5c8
CD
694 "Non-nil means ignore some deadlined TODO items when making TODO list.
695There are different motivations for using different values, please think
696carefully when configuring this variable.
697
86fbb8ca 698This applies when creating the global todo list.
ed21c5c8
CD
699Valid values are:
700
701near Don't show near deadline entries. A deadline is near when it is
702 closer than `org-deadline-warning-days' days. The idea behind this
703 is that such items will appear in the agenda anyway.
704
705far Don't show TODO entries where a deadline has been defined, but
706 the deadline is not near. This is useful if you don't want to
707 use the todo list to figure out what to do now.
708
709past Don't show entries with a deadline timestamp for today or in the past.
710
711future Don't show entries with a deadline timestamp in the future, not even
712 when they become `near' ones. Use it with caution.
713
714all Ignore all TODO entries that do have a deadline.
715
716t Same as `near', for backward compatibility.
717
3ab2c837
BG
718This variable can also have an integer as a value. See
719`org-agenda-todo-ignore-timestamp' for more details.
720
c8d0cf5c 721See also `org-agenda-todo-ignore-with-date'.
ed21c5c8
CD
722See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want
723to make his option also apply to the tags-todo list."
20908596 724 :group 'org-agenda-skip
0bd48b37 725 :group 'org-agenda-todo-list
ed21c5c8
CD
726 :type '(choice
727 (const :tag "Ignore near deadlines" near)
728 (const :tag "Ignore near deadlines (compatibility)" t)
729 (const :tag "Ignore far deadlines" far)
730 (const :tag "Ignore all TODOs with a deadlines" all)
3ab2c837
BG
731 (const :tag "Show all TODOs, even if they have a deadline" nil)
732 (integer :tag "Ignore if N or more days in past(-) or future(+).")))
0bd48b37
CD
733
734(defcustom org-agenda-tags-todo-honor-ignore-options nil
ed21c5c8 735 "Non-nil means honor todo-list ...ignore options also in tags-todo search.
0bd48b37
CD
736The variables
737 `org-agenda-todo-ignore-with-date',
acedf35c
CD
738 `org-agenda-todo-ignore-timestamp',
739 `org-agenda-todo-ignore-scheduled',
0bd48b37
CD
740 `org-agenda-todo-ignore-deadlines'
741make the global TODO list skip entries that have time stamps of certain
742kinds. If this option is set, the same options will also apply for the
743tags-todo search, which is the general tags/property matcher
744restricted to unfinished TODO entries only."
745 :group 'org-agenda-skip
746 :group 'org-agenda-todo-list
747 :group 'org-agenda-match-view
20908596
CD
748 :type 'boolean)
749
750(defcustom org-agenda-skip-scheduled-if-done nil
751 "Non-nil means don't show scheduled items in agenda when they are done.
752This is relevant for the daily/weekly agenda, not for the TODO list. And
753it applies only to the actual date of the scheduling. Warnings about
754an item with a past scheduling dates are always turned off when the item
755is DONE."
756 :group 'org-agenda-skip
0bd48b37 757 :group 'org-agenda-daily/weekly
20908596
CD
758 :type 'boolean)
759
54a0dee5
CD
760(defcustom org-agenda-skip-scheduled-if-deadline-is-shown nil
761 "Non-nil means skip scheduling line if same entry shows because of deadline.
762In the agenda of today, an entry can show up multiple times because
763it is both scheduled and has a nearby deadline, and maybe a plain time
764stamp as well.
765When this variable is t, then only the deadline is shown and the fact that
766the entry is scheduled today or was scheduled previously is not shown.
767When this variable is nil, the entry will be shown several times. When
768the variable is the symbol `not-today', then skip scheduled previously,
769but not scheduled today."
770 :group 'org-agenda-skip
771 :group 'org-agenda-daily/weekly
772 :type '(choice
773 (const :tag "Never" nil)
774 (const :tag "Always" t)
775 (const :tag "Not when scheduled today" not-today)))
776
20908596 777(defcustom org-agenda-skip-deadline-if-done nil
33306645 778 "Non-nil means don't show deadlines when the corresponding item is done.
20908596
CD
779When nil, the deadline is still shown and should give you a happy feeling.
780This is relevant for the daily/weekly agenda. And it applied only to the
33306645 781actually date of the deadline. Warnings about approaching and past-due
20908596
CD
782deadlines are always turned off when the item is DONE."
783 :group 'org-agenda-skip
0bd48b37 784 :group 'org-agenda-daily/weekly
20908596
CD
785 :type 'boolean)
786
ed21c5c8
CD
787(defcustom org-agenda-skip-deadline-prewarning-if-scheduled nil
788 "Non-nil means skip deadline prewarning when entry is also scheduled.
789This will apply on all days where a prewarning for the deadline would
790be shown, but not at the day when the entry is actually due. On that day,
791the deadline will be shown anyway.
792This variable may be set to nil, t, or a number which will then give
793the number of days before the actual deadline when the prewarnings
794should resume.
795This can be used in a workflow where the first showing of the deadline will
796trigger you to schedule it, and then you don't want to be reminded of it
797because you will take care of it on the day when scheduled."
798 :group 'org-agenda-skip
799 :group 'org-agenda-daily/weekly
372d7b21 800 :version "24.1"
ed21c5c8 801 :type '(choice
c846da43 802 (const :tag "Always show prewarning" nil)
ed21c5c8
CD
803 (const :tag "Remove prewarning if entry is scheduled" t)
804 (integer :tag "Restart prewarning N days before deadline")))
805
e66ba1df 806(defcustom org-agenda-skip-additional-timestamps-same-entry nil
c8d0cf5c
CD
807 "When nil, multiple same-day timestamps in entry make multiple agenda lines.
808When non-nil, after the search for timestamps has matched once in an
809entry, the rest of the entry will not be searched."
810 :group 'org-agenda-skip
811 :type 'boolean)
812
20908596
CD
813(defcustom org-agenda-skip-timestamp-if-done nil
814 "Non-nil means don't select item by timestamp or -range if it is DONE."
815 :group 'org-agenda-skip
0bd48b37 816 :group 'org-agenda-daily/weekly
20908596
CD
817 :type 'boolean)
818
d6685abc 819(defcustom org-agenda-dim-blocked-tasks t
ed21c5c8 820 "Non-nil means dim blocked tasks in the agenda display.
c8d0cf5c
CD
821This causes some overhead during agenda construction, but if you
822have turned on `org-enforce-todo-dependencies',
823`org-enforce-todo-checkbox-dependencies', or any other blocking
824mechanism, this will create useful feedback in the agenda.
825
8bfe682a 826Instead of t, this variable can also have the value `invisible'.
c8d0cf5c
CD
827Then blocked tasks will be invisible and only become visible when
828they become unblocked. An exemption to this behavior is when a task is
829blocked because of unchecked checkboxes below it. Since checkboxes do
830not show up in the agenda views, making this task invisible you remove any
831trace from agenda views that there is something to do. Therefore, a task
832that is blocked because of checkboxes will never be made invisible, it
833will only be dimmed."
d6685abc
CD
834 :group 'org-agenda-daily/weekly
835 :group 'org-agenda-todo-list
836 :type '(choice
837 (const :tag "Do not dim" nil)
e4769531 838 (const :tag "Dim to a gray face" t)
8bfe682a 839 (const :tag "Make invisible" invisible)))
d6685abc 840
20908596 841(defcustom org-timeline-show-empty-dates 3
ed21c5c8 842 "Non-nil means `org-timeline' also shows dates without an entry.
20908596
CD
843When nil, only the days which actually have entries are shown.
844When t, all days between the first and the last date are shown.
845When an integer, show also empty dates, but if there is a gap of more than
846N days, just insert a special line indicating the size of the gap."
847 :group 'org-agenda-skip
848 :type '(choice
849 (const :tag "None" nil)
850 (const :tag "All" t)
c8d0cf5c 851 (integer :tag "at most")))
20908596 852
20908596
CD
853(defgroup org-agenda-startup nil
854 "Options concerning initial settings in the Agenda in Org Mode."
855 :tag "Org Agenda Startup"
856 :group 'org-agenda)
857
afe98dfa 858(defcustom org-agenda-menu-show-matcher t
3ab2c837 859 "Non-nil means show the match string in the agenda dispatcher menu.
afe98dfa
CD
860When nil, the matcher string is not shown, but is put into the help-echo
861property so than moving the mouse over the command shows it.
862Setting it to nil is good if matcher strings are very long and/or if
3ab2c837 863you want to use two-column display (see `org-agenda-menu-two-column')."
afe98dfa 864 :group 'org-agenda
372d7b21 865 :version "24.1"
afe98dfa
CD
866 :type 'boolean)
867
868(defcustom org-agenda-menu-two-column nil
869 "Non-nil means, use two columns to show custom commands in the dispatcher.
870If you use this, you probably want to set `org-agenda-menu-show-matcher'
871to nil."
872 :group 'org-agenda
372d7b21 873 :version "24.1"
afe98dfa
CD
874 :type 'boolean)
875
20908596
CD
876(defcustom org-finalize-agenda-hook nil
877 "Hook run just before displaying an agenda buffer."
878 :group 'org-agenda-startup
879 :type 'hook)
880
881(defcustom org-agenda-mouse-1-follows-link nil
ed21c5c8 882 "Non-nil means mouse-1 on a link will follow the link in the agenda.
20908596
CD
883A longer mouse click will still set point. Does not work on XEmacs.
884Needs to be set before org.el is loaded."
885 :group 'org-agenda-startup
886 :type 'boolean)
887
888(defcustom org-agenda-start-with-follow-mode nil
86fbb8ca 889 "The initial value of follow mode in a newly created agenda window."
20908596
CD
890 :group 'org-agenda-startup
891 :type 'boolean)
892
e66ba1df
BG
893(defcustom org-agenda-follow-indirect nil
894 "Non-nil means `org-agenda-follow-mode' displays only the
895current item's tree, in an indirect buffer."
896 :group 'org-agenda
372d7b21 897 :version "24.1"
e66ba1df
BG
898 :type 'boolean)
899
1bcdebed 900(defcustom org-agenda-show-outline-path t
ed21c5c8 901 "Non-nil means show outline path in echo area after line motion."
1bcdebed
CD
902 :group 'org-agenda-startup
903 :type 'boolean)
904
54a0dee5
CD
905(defcustom org-agenda-start-with-entry-text-mode nil
906 "The initial value of entry-text-mode in a newly created agenda window."
907 :group 'org-agenda-startup
908 :type 'boolean)
909
910(defcustom org-agenda-entry-text-maxlines 5
8bfe682a 911 "Number of text lines to be added when `E' is pressed in the agenda.
54a0dee5
CD
912
913Note that this variable only used during agenda display. Add add entry text
914when exporting the agenda, configure the variable
915`org-agenda-add-entry-ext-maxlines'."
916 :group 'org-agenda
917 :type 'integer)
918
8d642074
CD
919(defcustom org-agenda-entry-text-exclude-regexps nil
920 "List of regular expressions to clean up entry text.
921The complete matches of all regular expressions in this list will be
922removed from entry text before it is shown in the agenda."
923 :group 'org-agenda
924 :type '(repeat (regexp)))
925
926(defvar org-agenda-entry-text-cleanup-hook nil
927 "Hook that is run after basic cleanup of entry text to be shown in agenda.
928This cleanup is done in a temporary buffer, so the function may inspect and
929change the entire buffer.
930Some default stuff like drawers and scheduling/deadline dates will already
931have been removed when this is called, as will any matches for regular
932expressions listed in `org-agenda-entry-text-exclude-regexps'.")
933
20908596 934(defvar org-agenda-include-inactive-timestamps nil
ed21c5c8 935 "Non-nil means include inactive time stamps in agenda and timeline.")
20908596
CD
936
937(defgroup org-agenda-windows nil
938 "Options concerning the windows used by the Agenda in Org Mode."
939 :tag "Org Agenda Windows"
940 :group 'org-agenda)
941
942(defcustom org-agenda-window-setup 'reorganize-frame
943 "How the agenda buffer should be displayed.
944Possible values for this option are:
945
946current-window Show agenda in the current window, keeping all other windows.
20908596
CD
947other-window Use `switch-to-buffer-other-window' to display agenda.
948reorganize-frame Show only two windows on the current frame, the current
949 window and the agenda.
8d642074
CD
950other-frame Use `switch-to-buffer-other-frame' to display agenda.
951 Also, when exiting the agenda, kill that frame.
20908596
CD
952See also the variable `org-agenda-restore-windows-after-quit'."
953 :group 'org-agenda-windows
954 :type '(choice
955 (const current-window)
956 (const other-frame)
957 (const other-window)
958 (const reorganize-frame)))
959
960(defcustom org-agenda-window-frame-fractions '(0.5 . 0.75)
961 "The min and max height of the agenda window as a fraction of frame height.
962The value of the variable is a cons cell with two numbers between 0 and 1.
963It only matters if `org-agenda-window-setup' is `reorganize-frame'."
964 :group 'org-agenda-windows
965 :type '(cons (number :tag "Minimum") (number :tag "Maximum")))
966
967(defcustom org-agenda-restore-windows-after-quit nil
3ab2c837 968 "Non-nil means restore window configuration upon exiting agenda.
20908596
CD
969Before the window configuration is changed for displaying the agenda,
970the current status is recorded. When the agenda is exited with
971`q' or `x' and this option is set, the old state is restored. If
972`org-agenda-window-setup' is `other-frame', the value of this
baf0cb84 973option will be ignored."
20908596
CD
974 :group 'org-agenda-windows
975 :type 'boolean)
976
acedf35c
CD
977(defcustom org-agenda-ndays nil
978 "Number of days to include in overview display.
c8d0cf5c 979Should be 1 or 7.
acedf35c
CD
980Obsolete, see `org-agenda-span'."
981 :group 'org-agenda-daily/weekly
982 :type 'integer)
983
984(make-obsolete-variable 'org-agenda-ndays 'org-agenda-span "24.1")
985
986(defcustom org-agenda-span 'week
987 "Number of days to include in overview display.
988Can be day, week, month, year, or any number of days.
c8d0cf5c 989Custom commands can set this variable in the options section."
20908596 990 :group 'org-agenda-daily/weekly
acedf35c
CD
991 :type '(choice (const :tag "Day" day)
992 (const :tag "Week" week)
993 (const :tag "Month" month)
994 (const :tag "Year" year)
995 (integer :tag "Custom")))
20908596
CD
996
997(defcustom org-agenda-start-on-weekday 1
ed21c5c8 998 "Non-nil means start the overview always on the specified weekday.
20908596 9990 denotes Sunday, 1 denotes Monday etc.
c8d0cf5c
CD
1000When nil, always start on the current day.
1001Custom commands can set this variable in the options section."
20908596
CD
1002 :group 'org-agenda-daily/weekly
1003 :type '(choice (const :tag "Today" nil)
c8d0cf5c 1004 (integer :tag "Weekday No.")))
20908596
CD
1005
1006(defcustom org-agenda-show-all-dates t
ed21c5c8 1007 "Non-nil means `org-agenda' shows every day in the selected range.
20908596
CD
1008When nil, only the days which actually have entries are shown."
1009 :group 'org-agenda-daily/weekly
1010 :type 'boolean)
1011
1012(defcustom org-agenda-format-date 'org-agenda-format-date-aligned
1013 "Format string for displaying dates in the agenda.
1014Used by the daily/weekly agenda and by the timeline. This should be
1015a format string understood by `format-time-string', or a function returning
1016the formatted date as a string. The function must take a single argument,
1017a calendar-style date list like (month day year)."
1018 :group 'org-agenda-daily/weekly
1019 :type '(choice
1020 (string :tag "Format string")
1021 (function :tag "Function")))
1022
1023(defun org-agenda-format-date-aligned (date)
1024 "Format a date string for display in the daily/weekly agenda, or timeline.
1025This function makes sure that dates are aligned for easy reading."
1026 (require 'cal-iso)
1027 (let* ((dayname (calendar-day-name date))
1028 (day (cadr date))
1029 (day-of-week (calendar-day-of-week date))
1030 (month (car date))
1031 (monthname (calendar-month-name month))
1032 (year (nth 2 date))
1033 (iso-week (org-days-to-iso-week
1034 (calendar-absolute-from-gregorian date)))
1035 (weekyear (cond ((and (= month 1) (>= iso-week 52))
1036 (1- year))
1037 ((and (= month 12) (<= iso-week 1))
1038 (1+ year))
1039 (t year)))
1040 (weekstring (if (= day-of-week 1)
1041 (format " W%02d" iso-week)
1042 "")))
1043 (format "%-10s %2d %s %4d%s"
1044 dayname day monthname year weekstring)))
1045
ed21c5c8
CD
1046(defcustom org-agenda-time-leading-zero nil
1047 "Non-nil means use leading zero for military times in agenda.
1048For example, 9:30am would become 09:30 rather than 9:30."
1049 :group 'org-agenda-daily/weekly
372d7b21 1050 :version "24.1"
ed21c5c8
CD
1051 :type 'boolean)
1052
acedf35c
CD
1053(defcustom org-agenda-timegrid-use-ampm nil
1054 "When set, show AM/PM style timestamps on the timegrid."
1055 :group 'org-agenda
372d7b21 1056 :version "24.1"
acedf35c
CD
1057 :type 'boolean)
1058
1059(defun org-agenda-time-of-day-to-ampm (time)
1060 "Convert TIME of a string like '13:45' to an AM/PM style time string."
1061 (let* ((hour-number (string-to-number (substring time 0 -3)))
1062 (minute (substring time -2))
1063 (ampm "am"))
1064 (cond
1065 ((equal hour-number 12)
1066 (setq ampm "pm"))
1067 ((> hour-number 12)
1068 (setq ampm "pm")
1069 (setq hour-number (- hour-number 12))))
1070 (concat
1071 (if org-agenda-time-leading-zero
1072 (format "%02d" hour-number)
1073 (format "%02s" (number-to-string hour-number)))
1074 ":" minute ampm)))
1075
1076(defun org-agenda-time-of-day-to-ampm-maybe (time)
1077 "Conditionally convert TIME to AM/PM format
1078based on `org-agenda-timegrid-use-ampm'"
1079 (if org-agenda-timegrid-use-ampm
1080 (org-agenda-time-of-day-to-ampm time)
1081 time))
1082
20908596
CD
1083(defcustom org-agenda-weekend-days '(6 0)
1084 "Which days are weekend?
1085These days get the special face `org-agenda-date-weekend' in the agenda
1086and timeline buffers."
1087 :group 'org-agenda-daily/weekly
1088 :type '(set :greedy t
1089 (const :tag "Monday" 1)
1090 (const :tag "Tuesday" 2)
1091 (const :tag "Wednesday" 3)
1092 (const :tag "Thursday" 4)
1093 (const :tag "Friday" 5)
1094 (const :tag "Saturday" 6)
1095 (const :tag "Sunday" 0)))
1096
e66ba1df 1097(defcustom org-agenda-move-date-from-past-immediately-to-today t
27e428e7 1098 "Non-nil means jump to today when moving a past date forward in time.
e66ba1df
BG
1099When using S-right in the agenda to move a a date forward, and the date
1100stamp currently points to the past, the first key press will move it
1101to today. WHen nil, just move one day forward even if the date stays
1102in the past."
1103 :group 'org-agenda-daily/weekly
372d7b21 1104 :version "24.1"
e66ba1df
BG
1105 :type 'boolean)
1106
20908596 1107(defcustom org-agenda-include-diary nil
c8d0cf5c
CD
1108 "If non-nil, include in the agenda entries from the Emacs Calendar's diary.
1109Custom commands can set this variable in the options section."
20908596
CD
1110 :group 'org-agenda-daily/weekly
1111 :type 'boolean)
1112
ed21c5c8
CD
1113(defcustom org-agenda-include-deadlines t
1114 "If non-nil, include entries within their deadline warning period.
1115Custom commands can set this variable in the options section."
1116 :group 'org-agenda-daily/weekly
372d7b21 1117 :version "24.1"
ed21c5c8
CD
1118 :type 'boolean)
1119
20908596 1120(defcustom org-agenda-repeating-timestamp-show-all t
ed21c5c8 1121 "Non-nil means show all occurrences of a repeating stamp in the agenda.
3ab2c837
BG
1122When set to a list of strings, only show occurrences of repeating
1123stamps for these TODO keywords. When nil, only one occurrence is
1124shown, either today or the nearest into the future."
20908596 1125 :group 'org-agenda-daily/weekly
3ab2c837
BG
1126 :type '(choice
1127 (const :tag "Show repeating stamps" t)
1128 (repeat :tag "Show repeating stamps for these TODO keywords"
1129 (string :tag "TODO Keyword"))
1130 (const :tag "Don't show repeating stamps" nil)))
20908596
CD
1131
1132(defcustom org-scheduled-past-days 10000
1133 "No. of days to continue listing scheduled items that are not marked DONE.
1134When an item is scheduled on a date, it shows up in the agenda on this
1135day and will be listed until it is marked done for the number of days
1136given here."
1137 :group 'org-agenda-daily/weekly
c8d0cf5c 1138 :type 'integer)
20908596 1139
93b62de8
CD
1140(defcustom org-agenda-log-mode-items '(closed clock)
1141 "List of items that should be shown in agenda log mode.
1142This list may contain the following symbols:
1143
1144 closed Show entries that have been closed on that day.
1145 clock Show entries that have received clocked time on that day.
c8d0cf5c
CD
1146 state Show all logged state changes.
1147Note that instead of changing this variable, you can also press `C-u l' in
1148the agenda to display all available LOG items temporarily."
93b62de8
CD
1149 :group 'org-agenda-daily/weekly
1150 :type '(set :greedy t (const closed) (const clock) (const state)))
1151
3ab2c837
BG
1152(defcustom org-agenda-clock-consistency-checks
1153 '(:max-duration "10:00" :min-duration 0 :max-gap "0:05"
1154 :gap-ok-around ("4:00")
1155 :default-face ((:background "DarkRed") (:foreground "white"))
1156 :overlap-face nil :gap-face nil :no-end-time-face nil
1157 :long-face nil :short-face nil)
1158 "This is a property list, with the following keys:
1159
1160:max-duration Mark clocking chunks that are longer than this time.
1161 This is a time string like \"HH:MM\", or the number
1162 of minutes as an integer.
1163
1164:min-duration Mark clocking chunks that are shorter that this.
1165 This is a time string like \"HH:MM\", or the number
1166 of minutes as an integer.
1167
1168:max-gap Mark gaps between clocking chunks that are longer than
1169 this duration. A number of minutes, or a string
1170 like \"HH:MM\".
1171
1172:gap-ok-around List of times during the day which are usually not working
1173 times. When a gap is detected, but the gap contains any
1174 of these times, the gap is *not* reported. For example,
1175 if this is (\"4:00\" \"13:00\") then gaps that contain
1176 4:00 in the morning (i.e. the night) and 13:00
1177 (i.e. a typical lunch time) do not cause a warning.
1178 You should have at least one time during the night in this
1179 list, or otherwise the first task each morning will trigger
1180 a warning because it follows a long gap.
1181
1182Furthermore, the following properties can be used to define faces for
1183issue display.
1184
1185:default-face the default face, if the specific face is undefined
1186:overlap-face face for overlapping clocks
1187:gap-face face for gaps between clocks
1188:no-end-time-face face for incomplete clocks
1189:long-face face for clock intervals that are too long
1190:short-face face for clock intervals that are too short"
1191 :group 'org-agenda-daily/weekly
1192 :group 'org-clock
372d7b21 1193 :version "24.1"
3ab2c837
BG
1194 :type 'plist)
1195
c8d0cf5c 1196(defcustom org-agenda-log-mode-add-notes t
ed21c5c8 1197 "Non-nil means add first line of notes to log entries in agenda views.
c8d0cf5c
CD
1198If a log item like a state change or a clock entry is associated with
1199notes, the first line of these notes will be added to the entry in the
1200agenda display."
1201 :group 'org-agenda-daily/weekly
1202 :type 'boolean)
1203
1204(defcustom org-agenda-start-with-log-mode nil
1205 "The initial value of log-mode in a newly created agenda window."
1206 :group 'org-agenda-startup
1207 :group 'org-agenda-daily/weekly
1208 :type 'boolean)
1209
20908596
CD
1210(defcustom org-agenda-start-with-clockreport-mode nil
1211 "The initial value of clockreport-mode in a newly created agenda window."
1212 :group 'org-agenda-startup
1213 :group 'org-agenda-daily/weekly
1214 :type 'boolean)
1215
1216(defcustom org-agenda-clockreport-parameter-plist '(:link t :maxlevel 2)
1217 "Property list with parameters for the clocktable in clockreport mode.
1218This is the display mode that shows a clock table in the daily/weekly
1219agenda, the properties for this dynamic block can be set here.
1220The usual clocktable parameters are allowed here, but you cannot set
1221the properties :name, :tstart, :tend, :block, and :scope - these will
1222be overwritten to make sure the content accurately reflects the
1223current display in the agenda."
1224 :group 'org-agenda-daily/weekly
1225 :type 'plist)
1226
ed21c5c8
CD
1227(defcustom org-agenda-search-view-always-boolean nil
1228 "Non-nil means the search string is interpreted as individual parts.
1229
1230The search string for search view can either be interpreted as a phrase,
1231or as a list of snippets that define a boolean search for a number of
1232strings.
1233
1234When this is non-nil, the string will be split on whitespace, and each
1235snippet will be searched individually, and all must match in order to
1236select an entry. A snippet is then a single string of non-white
1237characters, or a string in double quotes, or a regexp in {} braces.
86fbb8ca 1238If a snippet is preceded by \"-\", the snippet must *not* match.
ed21c5c8
CD
1239\"+\" is syntactic sugar for positive selection. Each snippet may
1240be found as a full word or a partial word, but see the variable
1241`org-agenda-search-view-force-full-words'.
1242
1243When this is nil, search will look for the entire search phrase as one,
1244with each space character matching any amount of whitespace, including
1245line breaks.
1246
1247Even when this is nil, you can still switch to Boolean search dynamically
86fbb8ca 1248by preceding the first snippet with \"+\" or \"-\". If the first snippet
ed21c5c8
CD
1249is a regexp marked with braces like \"{abc}\", this will also switch to
1250boolean search."
1251 :group 'org-agenda-search-view
372d7b21 1252 :version "24.1"
ed21c5c8
CD
1253 :type 'boolean)
1254
1255(if (fboundp 'defvaralias)
1256 (defvaralias 'org-agenda-search-view-search-words-only
1257 'org-agenda-search-view-always-boolean))
1258
1259(defcustom org-agenda-search-view-force-full-words nil
86fbb8ca 1260 "Non-nil means, search words must be matches as complete words.
ed21c5c8 1261When nil, they may also match part of a word."
8bfe682a 1262 :group 'org-agenda-search-view
372d7b21 1263 :version "24.1"
8bfe682a 1264 :type 'boolean)
20908596
CD
1265
1266(defgroup org-agenda-time-grid nil
1267 "Options concerning the time grid in the Org-mode Agenda."
1268 :tag "Org Agenda Time Grid"
1269 :group 'org-agenda)
1270
c8d0cf5c 1271(defcustom org-agenda-search-headline-for-time t
ed21c5c8 1272 "Non-nil means search headline for a time-of-day.
c8d0cf5c
CD
1273If the headline contains a time-of-day in one format or another, it will
1274be used to sort the entry into the time sequence of items for a day.
1275Some people have time stamps in the headline that refer to the creation
1276time or so, and then this produces an unwanted side effect. If this is
1277the case for your, use this variable to turn off searching the headline
1278for a time."
1279 :group 'org-agenda-time-grid
1280 :type 'boolean)
1281
20908596 1282(defcustom org-agenda-use-time-grid t
ed21c5c8 1283 "Non-nil means show a time grid in the agenda schedule.
20908596
CD
1284A time grid is a set of lines for specific times (like every two hours between
12858:00 and 20:00). The items scheduled for a day at specific times are
1286sorted in between these lines.
1287For details about when the grid will be shown, and what it will look like, see
1288the variable `org-agenda-time-grid'."
1289 :group 'org-agenda-time-grid
1290 :type 'boolean)
1291
1292(defcustom org-agenda-time-grid
1293 '((daily today require-timed)
1294 "----------------"
1295 (800 1000 1200 1400 1600 1800 2000))
1296
1297 "The settings for time grid for agenda display.
1298This is a list of three items. The first item is again a list. It contains
1299symbols specifying conditions when the grid should be displayed:
1300
1301 daily if the agenda shows a single day
1302 weekly if the agenda shows an entire week
1303 today show grid on current date, independent of daily/weekly display
1304 require-timed show grid only if at least one item has a time specification
1305
b349f79f 1306The second item is a string which will be placed behind the grid time.
20908596
CD
1307
1308The third item is a list of integers, indicating the times that should have
1309a grid line."
1310 :group 'org-agenda-time-grid
1311 :type
1312 '(list
1313 (set :greedy t :tag "Grid Display Options"
1314 (const :tag "Show grid in single day agenda display" daily)
1315 (const :tag "Show grid in weekly agenda display" weekly)
1316 (const :tag "Always show grid for today" today)
1317 (const :tag "Show grid only if any timed entries are present"
1318 require-timed)
1319 (const :tag "Skip grid times already present in an entry"
1320 remove-match))
1321 (string :tag "Grid String")
1322 (repeat :tag "Grid Times" (integer :tag "Time"))))
1323
3ab2c837
BG
1324(defcustom org-agenda-show-current-time-in-grid t
1325 "Non-nil means show the current time in the time grid."
1326 :group 'org-agenda-time-grid
372d7b21 1327 :version "24.1"
3ab2c837
BG
1328 :type 'boolean)
1329
1330(defcustom org-agenda-current-time-string
1331 "now - - - - - - - - - - - - - - - - - - - - - - - - -"
1332 "The string for the current time marker in the agenda."
1333 :group 'org-agenda-time-grid
372d7b21 1334 :version "24.1"
3ab2c837
BG
1335 :type 'string)
1336
20908596
CD
1337(defgroup org-agenda-sorting nil
1338 "Options concerning sorting in the Org-mode Agenda."
1339 :tag "Org Agenda Sorting"
1340 :group 'org-agenda)
1341
1342(defcustom org-agenda-sorting-strategy
8bfe682a
CD
1343 '((agenda habit-down time-up priority-down category-keep)
1344 (todo priority-down category-keep)
1345 (tags priority-down category-keep)
20908596
CD
1346 (search category-keep))
1347 "Sorting structure for the agenda items of a single day.
1348This is a list of symbols which will be used in sequence to determine
1349if an entry should be listed before another entry. The following
1350symbols are recognized:
1351
c8d0cf5c
CD
1352time-up Put entries with time-of-day indications first, early first
1353time-down Put entries with time-of-day indications first, late first
1354category-keep Keep the default order of categories, corresponding to the
1355 sequence in `org-agenda-files'.
1356category-up Sort alphabetically by category, A-Z.
1357category-down Sort alphabetically by category, Z-A.
1358tag-up Sort alphabetically by last tag, A-Z.
1359tag-down Sort alphabetically by last tag, Z-A.
1360priority-up Sort numerically by priority, high priority last.
1361priority-down Sort numerically by priority, high priority first.
1362todo-state-up Sort by todo state, tasks that are done last.
1363todo-state-down Sort by todo state, tasks that are done first.
1364effort-up Sort numerically by estimated effort, high effort last.
1365effort-down Sort numerically by estimated effort, high effort first.
1366user-defined-up Sort according to `org-agenda-cmp-user-defined', high last.
1367user-defined-down Sort according to `org-agenda-cmp-user-defined', high first.
8bfe682a
CD
1368habit-up Put entries that are habits first
1369habit-down Put entries that are habits last
86fbb8ca
CD
1370alpha-up Sort headlines alphabetically
1371alpha-down Sort headlines alphabetically, reversed
20908596
CD
1372
1373The different possibilities will be tried in sequence, and testing stops
1374if one comparison returns a \"not-equal\". For example, the default
1375 '(time-up category-keep priority-down)
1376means: Pull out all entries having a specified time of day and sort them,
1377in order to make a time schedule for the current day the first thing in the
1378agenda listing for the day. Of the entries without a time indication, keep
1379the grouped in categories, don't sort the categories, but keep them in
1380the sequence given in `org-agenda-files'. Within each category sort by
1381priority.
1382
1383Leaving out `category-keep' would mean that items will be sorted across
1384categories by priority.
1385
1386Instead of a single list, this can also be a set of list for specific
1387contents, with a context symbol in the car of the list, any of
8bfe682a 1388`agenda', `todo', `tags', `search' for the corresponding agenda views.
c8d0cf5c
CD
1389
1390Custom commands can bind this variable in the options section."
20908596
CD
1391 :group 'org-agenda-sorting
1392 :type `(choice
1393 (repeat :tag "General" ,org-sorting-choice)
1394 (list :tag "Individually"
1395 (cons (const :tag "Strategy for Weekly/Daily agenda" agenda)
1396 (repeat ,org-sorting-choice))
1397 (cons (const :tag "Strategy for TODO lists" todo)
1398 (repeat ,org-sorting-choice))
1399 (cons (const :tag "Strategy for Tags matches" tags)
8bfe682a
CD
1400 (repeat ,org-sorting-choice))
1401 (cons (const :tag "Strategy for search matches" search)
20908596
CD
1402 (repeat ,org-sorting-choice)))))
1403
c8d0cf5c
CD
1404(defcustom org-agenda-cmp-user-defined nil
1405 "A function to define the comparison `user-defined'.
1406This function must receive two arguments, agenda entry a and b.
1407If a>b, return +1. If a<b, return -1. If they are equal as seen by
1408the user comparison, return nil.
1409When this is defined, you can make `user-defined-up' and `user-defined-down'
1410part of an agenda sorting strategy."
1411 :group 'org-agenda-sorting
1412 :type 'symbol)
1413
20908596 1414(defcustom org-sort-agenda-notime-is-late t
ed21c5c8 1415 "Non-nil means items without time are considered late.
20908596
CD
1416This is only relevant for sorting. When t, items which have no explicit
1417time like 15:30 will be considered as 99:01, i.e. later than any items which
1418do have a time. When nil, the default time is before 0:00. You can use this
1419option to decide if the schedule for today should come before or after timeless
1420agenda entries."
1421 :group 'org-agenda-sorting
1422 :type 'boolean)
1423
1424(defcustom org-sort-agenda-noeffort-is-high t
ed21c5c8 1425 "Non-nil means items without effort estimate are sorted as high effort.
c8d0cf5c
CD
1426This also applies when filtering an agenda view with respect to the
1427< or > effort operator. Then, tasks with no effort defined will be treated
1428as tasks with high effort.
20908596
CD
1429When nil, such items are sorted as 0 minutes effort."
1430 :group 'org-agenda-sorting
1431 :type 'boolean)
1432
1433(defgroup org-agenda-line-format nil
1434 "Options concerning the entry prefix in the Org-mode agenda display."
1435 :tag "Org Agenda Line Format"
1436 :group 'org-agenda)
1437
1438(defcustom org-agenda-prefix-format
acedf35c 1439 '((agenda . " %i %-12:c%?-12t% s")
20908596 1440 (timeline . " % s")
acedf35c
CD
1441 (todo . " %i %-12:c")
1442 (tags . " %i %-12:c")
1443 (search . " %i %-12:c"))
20908596 1444 "Format specifications for the prefix of items in the agenda views.
fe3c5669
PE
1445An alist with five entries, each for the different agenda types. The
1446keys of the sublists are `agenda', `timeline', `todo', `search' and `tags'.
3ab2c837
BG
1447The values are format strings.
1448
20908596
CD
1449This format works similar to a printf format, with the following meaning:
1450
fe3c5669 1451 %c the category of the item, \"Diary\" for entries from the diary,
3ab2c837 1452 or as given by the CATEGORY keyword or derived from the file name
e66ba1df 1453 %e the effort required by the item
3ab2c837
BG
1454 %i the icon category of the item, see `org-agenda-category-icon-alist'
1455 %T the last tag of the item (ignore inherited tags, which come first)
1456 %t the HH:MM time-of-day specification if one applies to the entry
20908596 1457 %s Scheduling/Deadline information, a short string
3ab2c837
BG
1458 %(expression) Eval EXPRESSION and replace the control string
1459 by the result
20908596
CD
1460
1461All specifiers work basically like the standard `%s' of printf, but may
3ab2c837
BG
1462contain two additional characters: a question mark just after the `%'
1463and a whitespace/punctuation character just before the final letter.
20908596
CD
1464
1465If the first character after `%' is a question mark, the entire field
fe3c5669
PE
1466will only be included if the corresponding value applies to the current
1467entry. This is useful for fields which should have fixed width when
1468present, but zero width when absent. For example, \"%?-12t\" will
1469result in a 12 character time field if a time of the day is specified,
3ab2c837 1470but will completely disappear in entries which do not contain a time.
20908596
CD
1471
1472If there is punctuation or whitespace character just before the final
1473format letter, this character will be appended to the field value if
1474the value is not empty. For example, the format \"%-12:c\" leads to
1475\"Diary: \" if the category is \"Diary\". If the category were be
8bfe682a 1476empty, no additional colon would be inserted.
20908596 1477
fe3c5669 1478The default value for the agenda sublist is \" %-12:c%?-12t% s\",
3ab2c837
BG
1479which means:
1480
20908596 1481- Indent the line with two space characters
3ab2c837 1482- Give the category a 12 chars wide field, padded with whitespace on
20908596
CD
1483 the right (because of `-'). Append a colon if there is a category
1484 (because of `:').
1485- If there is a time-of-day, put it into a 12 chars wide field. If no
1486 time, don't put in an empty field, just skip it (because of '?').
3ab2c837 1487- Finally, put the scheduling information.
20908596
CD
1488
1489See also the variables `org-agenda-remove-times-when-in-prefix' and
c8d0cf5c
CD
1490`org-agenda-remove-tags'.
1491
1492Custom commands can set this variable in the options section."
20908596
CD
1493 :type '(choice
1494 (string :tag "General format")
1495 (list :greedy t :tag "View dependent"
1496 (cons (const agenda) (string :tag "Format"))
1497 (cons (const timeline) (string :tag "Format"))
1498 (cons (const todo) (string :tag "Format"))
1499 (cons (const tags) (string :tag "Format"))
1500 (cons (const search) (string :tag "Format"))))
1501 :group 'org-agenda-line-format)
1502
1503(defvar org-prefix-format-compiled nil
1504 "The compiled version of the most recently used prefix format.
1505See the variable `org-agenda-prefix-format'.")
1506
1507(defcustom org-agenda-todo-keyword-format "%-1s"
1508 "Format for the TODO keyword in agenda lines.
1509Set this to something like \"%-12s\" if you want all TODO keywords
1510to occupy a fixed space in the agenda display."
1511 :group 'org-agenda-line-format
1512 :type 'string)
1513
ce4fdcb9
CD
1514(defcustom org-agenda-timerange-leaders '("" "(%d/%d): ")
1515 "Text preceding timerange entries in the agenda view.
1516This is a list with two strings. The first applies when the range
1517is entirely on one day. The second applies if the range spans several days.
1518The strings may have two \"%d\" format specifiers which will be filled
1519with the sequence number of the days, and the total number of days in the
1520range, respectively."
1521 :group 'org-agenda-line-format
1522 :type '(list
1523 (string :tag "Deadline today ")
1524 (choice :tag "Deadline relative"
1525 (string :tag "Format string")
1526 (function))))
1527
20908596 1528(defcustom org-agenda-scheduled-leaders '("Scheduled: " "Sched.%2dx: ")
86fbb8ca 1529 "Text preceding scheduled items in the agenda view.
20908596
CD
1530This is a list with two strings. The first applies when the item is
1531scheduled on the current day. The second applies when it has been scheduled
b349f79f
CD
1532previously, it may contain a %d indicating that this is the nth time that
1533this item is scheduled, due to automatic rescheduling of unfinished items
1534for the following day. So this number is one larger than the number of days
1535that passed since this item was scheduled first."
20908596
CD
1536 :group 'org-agenda-line-format
1537 :type '(list
1538 (string :tag "Scheduled today ")
1539 (string :tag "Scheduled previously")))
1540
ed21c5c8 1541(defcustom org-agenda-inactive-leader "["
86fbb8ca 1542 "Text preceding item pulled into the agenda by inactive time stamps.
ed21c5c8
CD
1543These entries are added to the agenda when pressing \"[\"."
1544 :group 'org-agenda-line-format
372d7b21 1545 :version "24.1"
ed21c5c8
CD
1546 :type '(list
1547 (string :tag "Scheduled today ")
1548 (string :tag "Scheduled previously")))
1549
20908596 1550(defcustom org-agenda-deadline-leaders '("Deadline: " "In %3d d.: ")
86fbb8ca 1551 "Text preceding deadline items in the agenda view.
20908596
CD
1552This is a list with two strings. The first applies when the item has its
1553deadline on the current day. The second applies when it is in the past or
1554in the future, it may contain %d to capture how many days away the deadline
1555is (was)."
1556 :group 'org-agenda-line-format
1557 :type '(list
1558 (string :tag "Deadline today ")
1559 (choice :tag "Deadline relative"
1560 (string :tag "Format string")
1561 (function))))
1562
1563(defcustom org-agenda-remove-times-when-in-prefix t
ed21c5c8 1564 "Non-nil means remove duplicate time specifications in agenda items.
20908596
CD
1565When the format `org-agenda-prefix-format' contains a `%t' specifier, a
1566time-of-day specification in a headline or diary entry is extracted and
1567placed into the prefix. If this option is non-nil, the original specification
1568\(a timestamp or -range, or just a plain time(range) specification like
156911:30-4pm) will be removed for agenda display. This makes the agenda less
1570cluttered.
1571The option can be t or nil. It may also be the symbol `beg', indicating
86fbb8ca 1572that the time should only be removed when it is located at the beginning of
20908596
CD
1573the headline/diary entry."
1574 :group 'org-agenda-line-format
1575 :type '(choice
1576 (const :tag "Always" t)
1577 (const :tag "Never" nil)
1578 (const :tag "When at beginning of entry" beg)))
1579
86fbb8ca
CD
1580(defcustom org-agenda-remove-timeranges-from-blocks nil
1581 "Non-nil means remove time ranges specifications in agenda
1582items that span on several days."
1583 :group 'org-agenda-line-format
372d7b21 1584 :version "24.1"
86fbb8ca 1585 :type 'boolean)
20908596
CD
1586
1587(defcustom org-agenda-default-appointment-duration nil
1588 "Default duration for appointments that only have a starting time.
1589When nil, no duration is specified in such cases.
1590When non-nil, this must be the number of minutes, e.g. 60 for one hour."
1591 :group 'org-agenda-line-format
1592 :type '(choice
1593 (integer :tag "Minutes")
1594 (const :tag "No default duration")))
1595
ff4be292 1596(defcustom org-agenda-show-inherited-tags t
ed21c5c8 1597 "Non-nil means show inherited tags in each agenda line."
ff4be292
CD
1598 :group 'org-agenda-line-format
1599 :type 'boolean)
20908596 1600
5dec9555
CD
1601(defcustom org-agenda-hide-tags-regexp nil
1602 "Regular expression used to filter away specific tags in agenda views.
1603This means that these tags will be present, but not be shown in the agenda
86fbb8ca 1604line. Secondary filtering will still work on the hidden tags.
afe98dfa 1605Nil means don't hide any tags."
5dec9555
CD
1606 :group 'org-agenda-line-format
1607 :type '(choice
1608 (const :tag "Hide none" nil)
1609 (string :tag "Regexp ")))
1610
20908596 1611(defcustom org-agenda-remove-tags nil
ed21c5c8 1612 "Non-nil means remove the tags from the headline copy in the agenda.
20908596
CD
1613When this is the symbol `prefix', only remove tags when
1614`org-agenda-prefix-format' contains a `%T' specifier."
1615 :group 'org-agenda-line-format
1616 :type '(choice
1617 (const :tag "Always" t)
1618 (const :tag "Never" nil)
1619 (const :tag "When prefix format contains %T" prefix)))
1620
1621(if (fboundp 'defvaralias)
1622 (defvaralias 'org-agenda-remove-tags-when-in-prefix
1623 'org-agenda-remove-tags))
1624
5ace2fe5 1625(defcustom org-agenda-tags-column (if (featurep 'xemacs) -79 -80)
20908596
CD
1626 "Shift tags in agenda items to this column.
1627If this number is positive, it specifies the column. If it is negative,
1628it means that the tags should be flushright to that column. For example,
1629-80 works well for a normal 80 character screen."
1630 :group 'org-agenda-line-format
1631 :type 'integer)
1632
1633(if (fboundp 'defvaralias)
1634 (defvaralias 'org-agenda-align-tags-to-column 'org-agenda-tags-column))
1635
c8d0cf5c 1636(defcustom org-agenda-fontify-priorities 'cookies
ed21c5c8 1637 "Non-nil means highlight low and high priorities in agenda.
20908596 1638When t, the highest priority entries are bold, lowest priority italic.
86fbb8ca 1639However, settings in `org-priority-faces' will overrule these faces.
c8d0cf5c
CD
1640When this variable is the symbol `cookies', only fontify the
1641cookies, not the entire task.
621f83e4
CD
1642This may also be an association list of priority faces, whose
1643keys are the character values of `org-highest-priority',
1644`org-default-priority', and `org-lowest-priority' (the default values
ed21c5c8
CD
1645are ?A, ?B, and ?C, respectively). The face may be a named face, a
1646color as a string, or a list like `(:background \"Red\")'.
1647If it is a color, the variable `org-faces-easy-properties'
1648determines if it is a foreground or a background color."
20908596
CD
1649 :group 'org-agenda-line-format
1650 :type '(choice
1651 (const :tag "Never" nil)
1652 (const :tag "Defaults" t)
c8d0cf5c 1653 (const :tag "Cookies only" cookies)
20908596
CD
1654 (repeat :tag "Specify"
1655 (list (character :tag "Priority" :value ?A)
ed21c5c8
CD
1656 (choice :tag "Face "
1657 (string :tag "Color")
1658 (sexp :tag "Face"))))))
20908596 1659
acedf35c
CD
1660(defcustom org-agenda-day-face-function nil
1661 "Function called to determine what face should be used to display a day.
1662The only argument passed to that function is the day. It should
1663returns a face, or nil if does not want to specify a face and let
1664the normal rules apply."
1665 :group 'org-agenda-line-format
372d7b21 1666 :version "24.1"
acedf35c
CD
1667 :type 'function)
1668
1669(defcustom org-agenda-category-icon-alist nil
1670 "Alist of category icon to be displayed in agenda views.
1671
1672Each entry should have the following format:
1673
1674 (CATEGORY-REGEXP FILE-OR-DATA TYPE DATA-P PROPS)
1675
1676Where CATEGORY-REGEXP is a regexp matching the categories where
1677the icon should be displayed.
1678FILE-OR-DATA either a file path or a string containing image data.
1679
27e428e7 1680The other fields can be omitted safely if not needed:
acedf35c
CD
1681TYPE indicates the image type.
1682DATA-P is a boolean indicating whether the FILE-OR-DATA string is
1683image data.
1684PROPS are additional image attributes to assign to the image,
1685like, e.g. `:ascent center'.
1686
1687 (\"Org\" \"/path/to/icon.png\" nil nil :ascent center)
1688
1689If you want to set the display properties yourself, just put a
1690list as second element:
1691
1692 (CATEGORY-REGEXP (MY PROPERTY LIST))
1693
1694For example, to display a 16px horizontal space for Emacs
1695category, you can use:
1696
1697 (\"Emacs\" '(space . (:width (16))))"
1698 :group 'org-agenda-line-format
372d7b21 1699 :version "24.1"
acedf35c
CD
1700 :type '(alist :key-type (string :tag "Regexp matching category")
1701 :value-type (choice (list :tag "Icon"
1702 (string :tag "File or data")
1703 (symbol :tag "Type")
1704 (boolean :tag "Data?")
1705 (repeat :tag "Extra image properties" :inline t symbol))
1706 (list :tag "Display properties" sexp))))
1707
20908596
CD
1708(defgroup org-agenda-column-view nil
1709 "Options concerning column view in the agenda."
1710 :tag "Org Agenda Column View"
1711 :group 'org-agenda)
1712
1713(defcustom org-agenda-columns-show-summaries t
ed21c5c8 1714 "Non-nil means show summaries for columns displayed in the agenda view."
20908596
CD
1715 :group 'org-agenda-column-view
1716 :type 'boolean)
1717
1718(defcustom org-agenda-columns-compute-summary-properties t
ed21c5c8 1719 "Non-nil means recompute all summary properties before column view.
20908596
CD
1720When column view in the agenda is listing properties that have a summary
1721operator, it can go to all relevant buffers and recompute the summaries
1722there. This can mean overhead for the agenda column view, but is necessary
1723to have thing up to date.
1724As a special case, a CLOCKSUM property also makes sure that the clock
1725computations are current."
1726 :group 'org-agenda-column-view
1727 :type 'boolean)
1728
1729(defcustom org-agenda-columns-add-appointments-to-effort-sum nil
ed21c5c8 1730 "Non-nil means the duration of an appointment will add to day effort.
20908596
CD
1731The property to which appointment durations will be added is the one given
1732in the option `org-effort-property'. If an appointment does not have
1733an end time, `org-agenda-default-appointment-duration' will be used. If that
1734is not set, an appointment without end time will not contribute to the time
1735estimate."
1736 :group 'org-agenda-column-view
1737 :type 'boolean)
1738
8bfe682a
CD
1739(defcustom org-agenda-auto-exclude-function nil
1740 "A function called with a tag to decide if it is filtered on '/ RET'.
1741The sole argument to the function, which is called once for each
1742possible tag, is a string giving the name of the tag. The
1743function should return either nil if the tag should be included
ed21c5c8
CD
1744as normal, or \"-<TAG>\" to exclude the tag.
1745Note that for the purpose of tag filtering, only the lower-case version of
1746all tags will be considered, so that this function will only ever see
1747the lower-case version of all tags."
8bfe682a
CD
1748 :group 'org-agenda
1749 :type 'function)
1750
3ab2c837
BG
1751(defcustom org-agenda-bulk-custom-functions nil
1752 "Alist of characters and custom functions for bulk actions.
1753For example, this value makes those two functions available:
1754
1755 '((?R set-category)
1756 (?C bulk-cut))
1757
1758With selected entries in an agenda buffer, `B R' will call
fe3c5669 1759the custom function `set-category' on the selected entries.
3ab2c837
BG
1760Note that functions in this alist don't need to be quoted."
1761 :type 'alist
372d7b21 1762 :version "24.1"
3ab2c837
BG
1763 :group 'org-agenda)
1764
20908596
CD
1765(eval-when-compile
1766 (require 'cl))
1767(require 'org)
1768
afe98dfa
CD
1769(defmacro org-agenda-with-point-at-orig-entry (string &rest body)
1770 "Execute BODY with point at location given by `org-hd-marker' property.
1771If STRING is non-nil, the text property will be fetched from position 0
1772in that string. If STRING is nil, it will be fetched from the beginning
1773of the current line."
e66ba1df
BG
1774 (org-with-gensyms (marker)
1775 `(let ((,marker (get-text-property (if string 0 (point-at-bol))
1776 'org-hd-marker ,string)))
1777 (with-current-buffer (marker-buffer ,marker)
1778 (save-excursion
1779 (goto-char ,marker)
1780 ,@body)))))
1781(def-edebug-spec org-agenda-with-point-at-orig-entry (form body))
afe98dfa 1782
20908596
CD
1783(defun org-add-agenda-custom-command (entry)
1784 "Replace or add a command in `org-agenda-custom-commands'.
1785This is mostly for hacking and trying a new command - once the command
1786works you probably want to add it to `org-agenda-custom-commands' for good."
1787 (let ((ass (assoc (car entry) org-agenda-custom-commands)))
1788 (if ass
1789 (setcdr ass (cdr entry))
1790 (push entry org-agenda-custom-commands))))
1791
153ae947 1792;;; Define the Org-agenda-mode
20908596
CD
1793
1794(defvar org-agenda-mode-map (make-sparse-keymap)
1795 "Keymap for `org-agenda-mode'.")
8bfe682a
CD
1796(if (fboundp 'defvaralias)
1797 (defvaralias 'org-agenda-keymap 'org-agenda-mode-map))
20908596
CD
1798
1799(defvar org-agenda-menu) ; defined later in this file.
c8d0cf5c 1800(defvar org-agenda-restrict) ; defined later in this file.
20908596 1801(defvar org-agenda-follow-mode nil)
54a0dee5 1802(defvar org-agenda-entry-text-mode nil)
20908596
CD
1803(defvar org-agenda-clockreport-mode nil)
1804(defvar org-agenda-show-log nil)
1805(defvar org-agenda-redo-command nil)
1806(defvar org-agenda-query-string nil)
0bd48b37 1807(defvar org-agenda-mode-hook nil
86fbb8ca 1808 "Hook for `org-agenda-mode', run after the mode is turned on.")
20908596
CD
1809(defvar org-agenda-type nil)
1810(defvar org-agenda-force-single-file nil)
c8d0cf5c 1811(defvar org-agenda-bulk-marked-entries) ;; Defined further down in this file
20908596
CD
1812
1813(defun org-agenda-mode ()
1814 "Mode for time-sorted view on action items in Org-mode files.
1815
1816The following commands are available:
1817
1818\\{org-agenda-mode-map}"
1819 (interactive)
1820 (kill-all-local-variables)
1821 (setq org-agenda-undo-list nil
c8d0cf5c
CD
1822 org-agenda-pending-undo-list nil
1823 org-agenda-bulk-marked-entries nil)
20908596
CD
1824 (setq major-mode 'org-agenda-mode)
1825 ;; Keep global-font-lock-mode from turning on font-lock-mode
1826 (org-set-local 'font-lock-global-modes (list 'not major-mode))
1827 (setq mode-name "Org-Agenda")
1828 (use-local-map org-agenda-mode-map)
1829 (easy-menu-add org-agenda-menu)
1830 (if org-startup-truncated (setq truncate-lines t))
54a0dee5 1831 (org-set-local 'line-move-visual nil)
20908596
CD
1832 (org-add-hook 'post-command-hook 'org-agenda-post-command-hook nil 'local)
1833 (org-add-hook 'pre-command-hook 'org-unhighlight nil 'local)
1834 ;; Make sure properties are removed when copying text
1835 (when (boundp 'buffer-substring-filters)
1836 (org-set-local 'buffer-substring-filters
1837 (cons (lambda (x)
1838 (set-text-properties 0 (length x) nil x) x)
1839 buffer-substring-filters)))
1840 (unless org-agenda-keep-modes
1841 (setq org-agenda-follow-mode org-agenda-start-with-follow-mode
54a0dee5 1842 org-agenda-entry-text-mode org-agenda-start-with-entry-text-mode
20908596 1843 org-agenda-clockreport-mode org-agenda-start-with-clockreport-mode
c8d0cf5c
CD
1844 org-agenda-show-log org-agenda-start-with-log-mode))
1845
20908596
CD
1846 (easy-menu-change
1847 '("Agenda") "Agenda Files"
1848 (append
1849 (list
1850 (vector
1851 (if (get 'org-agenda-files 'org-restrict)
1852 "Restricted to single file"
1853 "Edit File List")
1854 '(org-edit-agenda-file-list)
1855 (not (get 'org-agenda-files 'org-restrict)))
1856 "--")
1857 (mapcar 'org-file-menu-entry (org-agenda-files))))
1858 (org-agenda-set-mode-name)
1859 (apply
1860 (if (fboundp 'run-mode-hooks) 'run-mode-hooks 'run-hooks)
1861 (list 'org-agenda-mode-hook)))
1862
1863(substitute-key-definition 'undo 'org-agenda-undo
1864 org-agenda-mode-map global-map)
1865(org-defkey org-agenda-mode-map "\C-i" 'org-agenda-goto)
1866(org-defkey org-agenda-mode-map [(tab)] 'org-agenda-goto)
1867(org-defkey org-agenda-mode-map "\C-m" 'org-agenda-switch-to)
1868(org-defkey org-agenda-mode-map "\C-k" 'org-agenda-kill)
c8d0cf5c
CD
1869(org-defkey org-agenda-mode-map "\C-c\C-w" 'org-agenda-refile)
1870(org-defkey org-agenda-mode-map "m" 'org-agenda-bulk-mark)
3ab2c837 1871(org-defkey org-agenda-mode-map "%" 'org-agenda-bulk-mark-regexp)
c8d0cf5c
CD
1872(org-defkey org-agenda-mode-map "u" 'org-agenda-bulk-unmark)
1873(org-defkey org-agenda-mode-map "U" 'org-agenda-bulk-remove-all-marks)
3ab2c837 1874(org-defkey org-agenda-mode-map "A" 'org-agenda-append-agenda)
c8d0cf5c
CD
1875(org-defkey org-agenda-mode-map "B" 'org-agenda-bulk-action)
1876(org-defkey org-agenda-mode-map "\C-c\C-x!" 'org-reload)
8bfe682a
CD
1877(org-defkey org-agenda-mode-map "\C-c\C-x\C-a" 'org-agenda-archive-default)
1878(org-defkey org-agenda-mode-map "\C-c\C-xa" 'org-agenda-toggle-archive-tag)
1879(org-defkey org-agenda-mode-map "\C-c\C-xA" 'org-agenda-archive-to-archive-sibling)
54a0dee5 1880(org-defkey org-agenda-mode-map "\C-c\C-x\C-s" 'org-agenda-archive)
8bfe682a 1881(org-defkey org-agenda-mode-map "\C-c$" 'org-agenda-archive)
20908596 1882(org-defkey org-agenda-mode-map "$" 'org-agenda-archive)
20908596 1883(org-defkey org-agenda-mode-map "\C-c\C-o" 'org-agenda-open-link)
8bfe682a
CD
1884(org-defkey org-agenda-mode-map " " 'org-agenda-show-and-scroll-up)
1885(org-defkey org-agenda-mode-map [backspace] 'org-agenda-show-scroll-down)
1886(org-defkey org-agenda-mode-map "\d" 'org-agenda-show-scroll-down)
20908596
CD
1887(org-defkey org-agenda-mode-map [(control shift right)] 'org-agenda-todo-nextset)
1888(org-defkey org-agenda-mode-map [(control shift left)] 'org-agenda-todo-previousset)
1889(org-defkey org-agenda-mode-map "\C-c\C-xb" 'org-agenda-tree-to-indirect-buffer)
20908596
CD
1890(org-defkey org-agenda-mode-map "o" 'delete-other-windows)
1891(org-defkey org-agenda-mode-map "L" 'org-agenda-recenter)
54a0dee5 1892(org-defkey org-agenda-mode-map "\C-c\C-t" 'org-agenda-todo)
20908596 1893(org-defkey org-agenda-mode-map "t" 'org-agenda-todo)
8bfe682a 1894(org-defkey org-agenda-mode-map "a" 'org-agenda-archive-default-with-confirmation)
20908596 1895(org-defkey org-agenda-mode-map ":" 'org-agenda-set-tags)
71d35b24 1896(org-defkey org-agenda-mode-map "\C-c\C-q" 'org-agenda-set-tags)
20908596
CD
1897(org-defkey org-agenda-mode-map "." 'org-agenda-goto-today)
1898(org-defkey org-agenda-mode-map "j" 'org-agenda-goto-date)
1899(org-defkey org-agenda-mode-map "d" 'org-agenda-day-view)
1900(org-defkey org-agenda-mode-map "w" 'org-agenda-week-view)
20908596
CD
1901(org-defkey org-agenda-mode-map "y" 'org-agenda-year-view)
1902(org-defkey org-agenda-mode-map "\C-c\C-z" 'org-agenda-add-note)
1903(org-defkey org-agenda-mode-map "z" 'org-agenda-add-note)
b349f79f
CD
1904(org-defkey org-agenda-mode-map "k" 'org-agenda-action)
1905(org-defkey org-agenda-mode-map "\C-c\C-x\C-k" 'org-agenda-action)
c8d0cf5c
CD
1906(org-defkey org-agenda-mode-map [(shift right)] 'org-agenda-do-date-later)
1907(org-defkey org-agenda-mode-map [(shift left)] 'org-agenda-do-date-earlier)
1908(org-defkey org-agenda-mode-map [?\C-c ?\C-x (right)] 'org-agenda-do-date-later)
1909(org-defkey org-agenda-mode-map [?\C-c ?\C-x (left)] 'org-agenda-do-date-earlier)
20908596
CD
1910
1911(org-defkey org-agenda-mode-map ">" 'org-agenda-date-prompt)
1912(org-defkey org-agenda-mode-map "\C-c\C-s" 'org-agenda-schedule)
1913(org-defkey org-agenda-mode-map "\C-c\C-d" 'org-agenda-deadline)
1914(let ((l '(1 2 3 4 5 6 7 8 9 0)))
1915 (while l (org-defkey org-agenda-mode-map
1916 (int-to-string (pop l)) 'digit-argument)))
1917
54a0dee5 1918(org-defkey org-agenda-mode-map "F" 'org-agenda-follow-mode)
20908596 1919(org-defkey org-agenda-mode-map "R" 'org-agenda-clockreport-mode)
54a0dee5 1920(org-defkey org-agenda-mode-map "E" 'org-agenda-entry-text-mode)
20908596 1921(org-defkey org-agenda-mode-map "l" 'org-agenda-log-mode)
c8d0cf5c 1922(org-defkey org-agenda-mode-map "v" 'org-agenda-view-mode-dispatch)
20908596 1923(org-defkey org-agenda-mode-map "D" 'org-agenda-toggle-diary)
ed21c5c8 1924(org-defkey org-agenda-mode-map "!" 'org-agenda-toggle-deadlines)
20908596
CD
1925(org-defkey org-agenda-mode-map "G" 'org-agenda-toggle-time-grid)
1926(org-defkey org-agenda-mode-map "r" 'org-agenda-redo)
1927(org-defkey org-agenda-mode-map "g" 'org-agenda-redo)
54a0dee5
CD
1928(org-defkey org-agenda-mode-map "e" 'org-agenda-set-effort)
1929(org-defkey org-agenda-mode-map "\C-c\C-xe" 'org-agenda-set-effort)
1930(org-defkey org-agenda-mode-map "\C-c\C-x\C-e"
1931 'org-clock-modify-effort-estimate)
1932(org-defkey org-agenda-mode-map "\C-c\C-xp" 'org-agenda-set-property)
20908596
CD
1933(org-defkey org-agenda-mode-map "q" 'org-agenda-quit)
1934(org-defkey org-agenda-mode-map "x" 'org-agenda-exit)
e66ba1df 1935(org-defkey org-agenda-mode-map "\C-x\C-w" 'org-agenda-write)
20908596 1936(org-defkey org-agenda-mode-map "\C-x\C-s" 'org-save-all-org-buffers)
c8d0cf5c 1937(org-defkey org-agenda-mode-map "s" 'org-save-all-org-buffers)
20908596
CD
1938(org-defkey org-agenda-mode-map "P" 'org-agenda-show-priority)
1939(org-defkey org-agenda-mode-map "T" 'org-agenda-show-tags)
8bfe682a
CD
1940(org-defkey org-agenda-mode-map "n" 'org-agenda-next-line)
1941(org-defkey org-agenda-mode-map "p" 'org-agenda-previous-line)
1942(substitute-key-definition 'next-line 'org-agenda-next-line
1943 org-agenda-mode-map global-map)
1944(substitute-key-definition 'previous-line 'org-agenda-previous-line
1945 org-agenda-mode-map global-map)
621f83e4 1946(org-defkey org-agenda-mode-map "\C-c\C-a" 'org-attach)
20908596
CD
1947(org-defkey org-agenda-mode-map "\C-c\C-n" 'org-agenda-next-date-line)
1948(org-defkey org-agenda-mode-map "\C-c\C-p" 'org-agenda-previous-date-line)
1949(org-defkey org-agenda-mode-map "," 'org-agenda-priority)
1950(org-defkey org-agenda-mode-map "\C-c," 'org-agenda-priority)
1951(org-defkey org-agenda-mode-map "i" 'org-agenda-diary-entry)
1952(org-defkey org-agenda-mode-map "c" 'org-agenda-goto-calendar)
1953(org-defkey org-agenda-mode-map "C" 'org-agenda-convert-date)
1954(org-defkey org-agenda-mode-map "M" 'org-agenda-phases-of-moon)
1955(org-defkey org-agenda-mode-map "S" 'org-agenda-sunrise-sunset)
1956(org-defkey org-agenda-mode-map "h" 'org-agenda-holidays)
1957(org-defkey org-agenda-mode-map "H" 'org-agenda-holidays)
1958(org-defkey org-agenda-mode-map "\C-c\C-x\C-i" 'org-agenda-clock-in)
1959(org-defkey org-agenda-mode-map "I" 'org-agenda-clock-in)
1960(org-defkey org-agenda-mode-map "\C-c\C-x\C-o" 'org-agenda-clock-out)
1961(org-defkey org-agenda-mode-map "O" 'org-agenda-clock-out)
1962(org-defkey org-agenda-mode-map "\C-c\C-x\C-x" 'org-agenda-clock-cancel)
1963(org-defkey org-agenda-mode-map "X" 'org-agenda-clock-cancel)
1964(org-defkey org-agenda-mode-map "\C-c\C-x\C-j" 'org-clock-goto)
afe98dfa 1965(org-defkey org-agenda-mode-map "J" 'org-agenda-clock-goto)
20908596
CD
1966(org-defkey org-agenda-mode-map "+" 'org-agenda-priority-up)
1967(org-defkey org-agenda-mode-map "-" 'org-agenda-priority-down)
1968(org-defkey org-agenda-mode-map [(shift up)] 'org-agenda-priority-up)
1969(org-defkey org-agenda-mode-map [(shift down)] 'org-agenda-priority-down)
1970(org-defkey org-agenda-mode-map [?\C-c ?\C-x (up)] 'org-agenda-priority-up)
1971(org-defkey org-agenda-mode-map [?\C-c ?\C-x (down)] 'org-agenda-priority-down)
54a0dee5
CD
1972(org-defkey org-agenda-mode-map "f" 'org-agenda-later)
1973(org-defkey org-agenda-mode-map "b" 'org-agenda-earlier)
20908596 1974(org-defkey org-agenda-mode-map "\C-c\C-x\C-c" 'org-agenda-columns)
c8d0cf5c 1975(org-defkey org-agenda-mode-map "\C-c\C-x>" 'org-agenda-remove-restriction-lock)
20908596
CD
1976
1977(org-defkey org-agenda-mode-map "[" 'org-agenda-manipulate-query-add)
1978(org-defkey org-agenda-mode-map "]" 'org-agenda-manipulate-query-subtract)
1979(org-defkey org-agenda-mode-map "{" 'org-agenda-manipulate-query-add-re)
1980(org-defkey org-agenda-mode-map "}" 'org-agenda-manipulate-query-subtract-re)
621f83e4 1981(org-defkey org-agenda-mode-map "/" 'org-agenda-filter-by-tag)
71d35b24 1982(org-defkey org-agenda-mode-map "\\" 'org-agenda-filter-by-tag-refine)
e66ba1df 1983(org-defkey org-agenda-mode-map "<" 'org-agenda-filter-by-category)
c8d0cf5c 1984(org-defkey org-agenda-mode-map ";" 'org-timer-set-timer)
8d642074
CD
1985(define-key org-agenda-mode-map "?" 'org-agenda-show-the-flagging-note)
1986(org-defkey org-agenda-mode-map "\C-c\C-x\C-mg" 'org-mobile-pull)
1987(org-defkey org-agenda-mode-map "\C-c\C-x\C-mp" 'org-mobile-push)
20908596 1988
86fbb8ca
CD
1989(org-defkey org-agenda-mode-map [mouse-2] 'org-agenda-goto-mouse)
1990(org-defkey org-agenda-mode-map [mouse-3] 'org-agenda-show-mouse)
20908596 1991(when org-agenda-mouse-1-follows-link
8bfe682a 1992 (org-defkey org-agenda-mode-map [follow-link] 'mouse-face))
20908596
CD
1993(easy-menu-define org-agenda-menu org-agenda-mode-map "Agenda menu"
1994 '("Agenda"
1995 ("Agenda Files")
1996 "--"
8d642074
CD
1997 ("Agenda Dates"
1998 ["Goto Today" org-agenda-goto-today (org-agenda-check-type nil 'agenda 'timeline)]
1999 ["Next Dates" org-agenda-later (org-agenda-check-type nil 'agenda)]
2000 ["Previous Dates" org-agenda-earlier (org-agenda-check-type nil 'agenda)]
2001 ["Jump to date" org-agenda-goto-date (org-agenda-check-type nil 'agenda)])
2002 "--"
2003 ("View"
2004 ["Day View" org-agenda-day-view
2005 :active (org-agenda-check-type nil 'agenda)
acedf35c 2006 :style radio :selected (eq org-agenda-current-span 'day)
8d642074
CD
2007 :keys "v d (or just d)"]
2008 ["Week View" org-agenda-week-view
2009 :active (org-agenda-check-type nil 'agenda)
acedf35c 2010 :style radio :selected (eq org-agenda-current-span 'week)
8d642074
CD
2011 :keys "v w (or just w)"]
2012 ["Month View" org-agenda-month-view
2013 :active (org-agenda-check-type nil 'agenda)
acedf35c 2014 :style radio :selected (eq org-agenda-current-span 'month)
8d642074
CD
2015 :keys "v m"]
2016 ["Year View" org-agenda-year-view
2017 :active (org-agenda-check-type nil 'agenda)
acedf35c 2018 :style radio :selected (eq org-agenda-current-span 'year)
8d642074
CD
2019 :keys "v y"]
2020 "--"
2021 ["Include Diary" org-agenda-toggle-diary
2022 :style toggle :selected org-agenda-include-diary
2023 :active (org-agenda-check-type nil 'agenda)]
ed21c5c8
CD
2024 ["Include Deadlines" org-agenda-toggle-deadlines
2025 :style toggle :selected org-agenda-include-deadlines
2026 :active (org-agenda-check-type nil 'agenda)]
8d642074
CD
2027 ["Use Time Grid" org-agenda-toggle-time-grid
2028 :style toggle :selected org-agenda-use-time-grid
2029 :active (org-agenda-check-type nil 'agenda)]
2030 "--"
2031 ["Show clock report" org-agenda-clockreport-mode
2032 :style toggle :selected org-agenda-clockreport-mode
2033 :active (org-agenda-check-type nil 'agenda)]
2034 ["Show some entry text" org-agenda-entry-text-mode
2035 :style toggle :selected org-agenda-entry-text-mode
2036 :active t]
2037 "--"
2038 ["Show Logbook entries" org-agenda-log-mode
2039 :style toggle :selected org-agenda-show-log
2040 :active (org-agenda-check-type nil 'agenda 'timeline)
2041 :keys "v l (or just l)"]
2042 ["Include archived trees" org-agenda-archives-mode
2043 :style toggle :selected org-agenda-archives-mode :active t
2044 :keys "v a"]
2045 ["Include archive files" (org-agenda-archives-mode t)
2046 :style toggle :selected (eq org-agenda-archives-mode t) :active t
2047 :keys "v A"]
2048 "--"
2049 ["Remove Restriction" org-agenda-remove-restriction-lock org-agenda-restrict])
e66ba1df 2050 ["Write view to file" org-agenda-write t]
8d642074
CD
2051 ["Rebuild buffer" org-agenda-redo t]
2052 ["Save all Org-mode Buffers" org-save-all-org-buffers t]
2053 "--"
2054 ["Show original entry" org-agenda-show t]
20908596
CD
2055 ["Go To (other window)" org-agenda-goto t]
2056 ["Go To (this window)" org-agenda-switch-to t]
2057 ["Follow Mode" org-agenda-follow-mode
2058 :style toggle :selected org-agenda-follow-mode :active t]
8d642074 2059; ["Tree to indirect frame" org-agenda-tree-to-indirect-buffer t]
20908596 2060 "--"
8d642074
CD
2061 ("TODO"
2062 ["Cycle TODO" org-agenda-todo t]
2063 ["Next TODO set" org-agenda-todo-nextset t]
2064 ["Previous TODO set" org-agenda-todo-previousset t]
2065 ["Add note" org-agenda-add-note t])
2066 ("Archive/Refile/Delete"
8bfe682a
CD
2067 ["Archive default" org-agenda-archive-default t]
2068 ["Archive default" org-agenda-archive-default-with-confirmation t]
20908596
CD
2069 ["Toggle ARCHIVE tag" org-agenda-toggle-archive-tag t]
2070 ["Move to archive sibling" org-agenda-archive-to-archive-sibling t]
c8d0cf5c 2071 ["Archive subtree" org-agenda-archive t]
8d642074
CD
2072 "--"
2073 ["Refile" org-agenda-refile t]
2074 "--"
2075 ["Delete subtree" org-agenda-kill t])
c8d0cf5c 2076 ("Bulk action"
8d642074 2077 ["Mark entry" org-agenda-bulk-mark t]
3ab2c837 2078 ["Mark matching regexp" org-agenda-bulk-mark-regexp t]
8d642074 2079 ["Unmark entry" org-agenda-bulk-unmark t]
c8d0cf5c 2080 ["Unmark all entries" org-agenda-bulk-remove-all-marks :active t :keys "C-u s"])
3ab2c837 2081 ["Act on all marked" org-agenda-bulk-action t]
c8d0cf5c 2082 "--"
20908596
CD
2083 ("Tags and Properties"
2084 ["Show all Tags" org-agenda-show-tags t]
2085 ["Set Tags current line" org-agenda-set-tags (not (org-region-active-p))]
2086 ["Change tag in region" org-agenda-set-tags (org-region-active-p)]
2087 "--"
2088 ["Column View" org-columns t])
8d642074 2089 ("Deadline/Schedule"
20908596
CD
2090 ["Schedule" org-agenda-schedule t]
2091 ["Set Deadline" org-agenda-deadline t]
2092 "--"
b349f79f
CD
2093 ["Mark item" org-agenda-action :active t :keys "k m"]
2094 ["Show mark item" org-agenda-action :active t :keys "k v"]
2095 ["Schedule marked item" org-agenda-action :active t :keys "k s"]
2096 ["Set Deadline for marked item" org-agenda-action :active t :keys "k d"]
2097 "--"
20908596
CD
2098 ["Change Date +1 day" org-agenda-date-later (org-agenda-check-type nil 'agenda 'timeline)]
2099 ["Change Date -1 day" org-agenda-date-earlier (org-agenda-check-type nil 'agenda 'timeline)]
c8d0cf5c
CD
2100 ["Change Time +1 hour" org-agenda-do-date-later :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u S-right"]
2101 ["Change Time -1 hour" org-agenda-do-date-earlier :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u S-left"]
2102 ["Change Time + min" org-agenda-date-later :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u C-u S-right"]
2103 ["Change Time - min" org-agenda-date-earlier :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u C-u S-left"]
20908596 2104 ["Change Date to ..." org-agenda-date-prompt (org-agenda-check-type nil 'agenda 'timeline)])
54a0dee5 2105 ("Clock and Effort"
20908596
CD
2106 ["Clock in" org-agenda-clock-in t]
2107 ["Clock out" org-agenda-clock-out t]
2108 ["Clock cancel" org-agenda-clock-cancel t]
54a0dee5
CD
2109 ["Goto running clock" org-clock-goto t]
2110 "--"
2111 ["Set Effort" org-agenda-set-effort t]
2112 ["Change clocked effort" org-clock-modify-effort-estimate
2113 (org-clock-is-active)])
20908596
CD
2114 ("Priority"
2115 ["Set Priority" org-agenda-priority t]
2116 ["Increase Priority" org-agenda-priority-up t]
2117 ["Decrease Priority" org-agenda-priority-down t]
2118 ["Show Priority" org-agenda-show-priority t])
2119 ("Calendar/Diary"
2120 ["New Diary Entry" org-agenda-diary-entry (org-agenda-check-type nil 'agenda 'timeline)]
2121 ["Goto Calendar" org-agenda-goto-calendar (org-agenda-check-type nil 'agenda 'timeline)]
2122 ["Phases of the Moon" org-agenda-phases-of-moon (org-agenda-check-type nil 'agenda 'timeline)]
2123 ["Sunrise/Sunset" org-agenda-sunrise-sunset (org-agenda-check-type nil 'agenda 'timeline)]
2124 ["Holidays" org-agenda-holidays (org-agenda-check-type nil 'agenda 'timeline)]
2125 ["Convert" org-agenda-convert-date (org-agenda-check-type nil 'agenda 'timeline)]
2126 "--"
8d642074 2127 ["Create iCalendar File" org-export-icalendar-combine-agenda-files t])
20908596 2128 "--"
8d642074 2129 ["Undo Remote Editing" org-agenda-undo org-agenda-undo-list]
2c3ad40d 2130 "--"
8d642074
CD
2131 ("MobileOrg"
2132 ["Push Files and Views" org-mobile-push t]
2133 ["Get Captured and Flagged" org-mobile-pull t]
2134 ["Find FLAGGED Tasks" (org-agenda nil "?") :active t :keys "C-c a ?"]
2135 ["Show note / unflag" org-agenda-show-the-flagging-note t]
c8d0cf5c 2136 "--"
8d642074 2137 ["Setup" (progn (require 'org-mobile) (customize-group 'org-mobile)) t])
20908596
CD
2138 "--"
2139 ["Quit" org-agenda-quit t]
2140 ["Exit and Release Buffers" org-agenda-exit t]
2141 ))
2142
2143;;; Agenda undo
2144
2145(defvar org-agenda-allow-remote-undo t
ed21c5c8 2146 "Non-nil means allow remote undo from the agenda buffer.")
20908596
CD
2147(defvar org-agenda-undo-list nil
2148 "List of undoable operations in the agenda since last refresh.")
2149(defvar org-agenda-undo-has-started-in nil
2150 "Buffers that have already seen `undo-start' in the current undo sequence.")
2151(defvar org-agenda-pending-undo-list nil
33306645 2152 "In a series of undo commands, this is the list of remaining undo items.")
20908596 2153
20908596
CD
2154(defun org-agenda-undo ()
2155 "Undo a remote editing step in the agenda.
2156This undoes changes both in the agenda buffer and in the remote buffer
2157that have been changed along."
2158 (interactive)
2159 (or org-agenda-allow-remote-undo
f924a367 2160 (error "Check the variable `org-agenda-allow-remote-undo' to activate remote undo"))
20908596
CD
2161 (if (not (eq this-command last-command))
2162 (setq org-agenda-undo-has-started-in nil
2163 org-agenda-pending-undo-list org-agenda-undo-list))
2164 (if (not org-agenda-pending-undo-list)
2165 (error "No further undo information"))
2166 (let* ((entry (pop org-agenda-pending-undo-list))
2167 buf line cmd rembuf)
2168 (setq cmd (pop entry) line (pop entry))
2169 (setq rembuf (nth 2 entry))
2170 (org-with-remote-undo rembuf
2171 (while (bufferp (setq buf (pop entry)))
2172 (if (pop entry)
2173 (with-current-buffer buf
2174 (let ((last-undo-buffer buf)
2175 (inhibit-read-only t))
2176 (unless (memq buf org-agenda-undo-has-started-in)
2177 (push buf org-agenda-undo-has-started-in)
2178 (make-local-variable 'pending-undo-list)
2179 (undo-start))
2180 (while (and pending-undo-list
2181 (listp pending-undo-list)
2182 (not (car pending-undo-list)))
2183 (pop pending-undo-list))
2184 (undo-more 1))))))
54a0dee5 2185 (org-goto-line line)
20908596
CD
2186 (message "`%s' undone (buffer %s)" cmd (buffer-name rembuf))))
2187
2188(defun org-verify-change-for-undo (l1 l2)
2189 "Verify that a real change occurred between the undo lists L1 and L2."
2190 (while (and l1 (listp l1) (null (car l1))) (pop l1))
2191 (while (and l2 (listp l2) (null (car l2))) (pop l2))
2192 (not (eq l1 l2)))
2193
2194;;; Agenda dispatch
2195
2196(defvar org-agenda-restrict nil)
2197(defvar org-agenda-restrict-begin (make-marker))
2198(defvar org-agenda-restrict-end (make-marker))
2199(defvar org-agenda-last-dispatch-buffer nil)
2200(defvar org-agenda-overriding-restriction nil)
2201
2202;;;###autoload
c8d0cf5c 2203(defun org-agenda (&optional arg keys restriction)
20908596
CD
2204 "Dispatch agenda commands to collect entries to the agenda buffer.
2205Prompts for a command to execute. Any prefix arg will be passed
2206on to the selected command. The default selections are:
2207
2208a Call `org-agenda-list' to display the agenda for current day or week.
2209t Call `org-todo-list' to display the global todo list.
2210T Call `org-todo-list' to display the global todo list, select only
2211 entries with a specific TODO keyword (the user gets a prompt).
2212m Call `org-tags-view' to display headlines with tags matching
2213 a condition (the user is prompted for the condition).
2214M Like `m', but select only TODO entries, no ordinary headlines.
2215L Create a timeline for the current buffer.
2216e Export views to associated files.
c8d0cf5c 2217s Search entries for keywords.
8bfe682a 2218/ Multi occur across all agenda files and also files listed
c8d0cf5c
CD
2219 in `org-agenda-text-search-extra-files'.
2220< Restrict agenda commands to buffer, subtree, or region.
2221 Press several times to get the desired effect.
2222> Remove a previous restriction.
2223# List \"stuck\" projects.
2224! Configure what \"stuck\" means.
2225C Configure custom agenda commands.
20908596
CD
2226
2227More commands can be added by configuring the variable
2228`org-agenda-custom-commands'. In particular, specific tags and TODO keyword
2229searches can be pre-defined in this way.
2230
2231If the current buffer is in Org-mode and visiting a file, you can also
2232first press `<' once to indicate that the agenda should be temporarily
2233\(until the next use of \\[org-agenda]) restricted to the current file.
2234Pressing `<' twice means to restrict to the current subtree or region
2235\(if active)."
2236 (interactive "P")
2237 (catch 'exit
2238 (let* ((prefix-descriptions nil)
54a0dee5
CD
2239 (org-agenda-window-setup (if (equal (buffer-name)
2240 org-agenda-buffer-name)
2241 'current-window
2242 org-agenda-window-setup))
20908596
CD
2243 (org-agenda-custom-commands-orig org-agenda-custom-commands)
2244 (org-agenda-custom-commands
2245 ;; normalize different versions
2246 (delq nil
2247 (mapcar
2248 (lambda (x)
2249 (cond ((stringp (cdr x))
2250 (push x prefix-descriptions)
2251 nil)
2252 ((stringp (nth 1 x)) x)
2253 ((not (nth 1 x)) (cons (car x) (cons "" (cddr x))))
2254 (t (cons (car x) (cons "" (cdr x))))))
2255 org-agenda-custom-commands)))
2256 (buf (current-buffer))
2257 (bfn (buffer-file-name (buffer-base-buffer)))
2258 entry key type match lprops ans)
8d642074 2259 ;; Turn off restriction unless there is an overriding one,
20908596 2260 (unless org-agenda-overriding-restriction
8bfe682a 2261 (unless (org-bound-and-true-p org-agenda-keep-restricted-file-list)
8d642074
CD
2262 ;; There is a request to keep the file list in place
2263 (put 'org-agenda-files 'org-restrict nil))
20908596
CD
2264 (setq org-agenda-restrict nil)
2265 (move-marker org-agenda-restrict-begin nil)
2266 (move-marker org-agenda-restrict-end nil))
2267 ;; Delete old local properties
2268 (put 'org-agenda-redo-command 'org-lprops nil)
3ab2c837
BG
2269 ;; Delete previously set last-arguments
2270 (put 'org-agenda-redo-command 'last-args nil)
20908596
CD
2271 ;; Remember where this call originated
2272 (setq org-agenda-last-dispatch-buffer (current-buffer))
2273 (unless keys
2274 (setq ans (org-agenda-get-restriction-and-command prefix-descriptions)
2275 keys (car ans)
2276 restriction (cdr ans)))
8bfe682a 2277 ;; Establish the restriction, if any
20908596
CD
2278 (when (and (not org-agenda-overriding-restriction) restriction)
2279 (put 'org-agenda-files 'org-restrict (list bfn))
2280 (cond
2281 ((eq restriction 'region)
2282 (setq org-agenda-restrict t)
2283 (move-marker org-agenda-restrict-begin (region-beginning))
2284 (move-marker org-agenda-restrict-end (region-end)))
2285 ((eq restriction 'subtree)
2286 (save-excursion
2287 (setq org-agenda-restrict t)
2288 (org-back-to-heading t)
2289 (move-marker org-agenda-restrict-begin (point))
2290 (move-marker org-agenda-restrict-end
2291 (progn (org-end-of-subtree t)))))))
2292
20908596
CD
2293 ;; For example the todo list should not need it (but does...)
2294 (cond
2295 ((setq entry (assoc keys org-agenda-custom-commands))
2296 (if (or (symbolp (nth 2 entry)) (functionp (nth 2 entry)))
2297 (progn
8bfe682a
CD
2298 (setq type (nth 2 entry) match (eval (nth 3 entry))
2299 lprops (nth 4 entry))
20908596
CD
2300 (put 'org-agenda-redo-command 'org-lprops lprops)
2301 (cond
2302 ((eq type 'agenda)
2303 (org-let lprops '(org-agenda-list current-prefix-arg)))
2304 ((eq type 'alltodo)
2305 (org-let lprops '(org-todo-list current-prefix-arg)))
2306 ((eq type 'search)
2307 (org-let lprops '(org-search-view current-prefix-arg match nil)))
2308 ((eq type 'stuck)
2309 (org-let lprops '(org-agenda-list-stuck-projects
2310 current-prefix-arg)))
2311 ((eq type 'tags)
2312 (org-let lprops '(org-tags-view current-prefix-arg match)))
2313 ((eq type 'tags-todo)
2314 (org-let lprops '(org-tags-view '(4) match)))
2315 ((eq type 'todo)
2316 (org-let lprops '(org-todo-list match)))
2317 ((eq type 'tags-tree)
2318 (org-check-for-org-mode)
c8d0cf5c 2319 (org-let lprops '(org-match-sparse-tree current-prefix-arg match)))
20908596
CD
2320 ((eq type 'todo-tree)
2321 (org-check-for-org-mode)
2322 (org-let lprops
3ab2c837 2323 '(org-occur (concat "^" org-outline-regexp "[ \t]*"
20908596
CD
2324 (regexp-quote match) "\\>"))))
2325 ((eq type 'occur-tree)
2326 (org-check-for-org-mode)
2327 (org-let lprops '(org-occur match)))
2328 ((functionp type)
2329 (org-let lprops '(funcall type match)))
2330 ((fboundp type)
2331 (org-let lprops '(funcall type match)))
2332 (t (error "Invalid custom agenda command type %s" type))))
3ab2c837 2333 (org-agenda-run-series (nth 1 entry) (cddr entry))))
20908596
CD
2334 ((equal keys "C")
2335 (setq org-agenda-custom-commands org-agenda-custom-commands-orig)
2336 (customize-variable 'org-agenda-custom-commands))
2337 ((equal keys "a") (call-interactively 'org-agenda-list))
2338 ((equal keys "s") (call-interactively 'org-search-view))
2339 ((equal keys "t") (call-interactively 'org-todo-list))
2340 ((equal keys "T") (org-call-with-arg 'org-todo-list (or arg '(4))))
2341 ((equal keys "m") (call-interactively 'org-tags-view))
2342 ((equal keys "M") (org-call-with-arg 'org-tags-view (or arg '(4))))
2343 ((equal keys "e") (call-interactively 'org-store-agenda-views))
8d642074
CD
2344 ((equal keys "?") (org-tags-view nil "+FLAGGED")
2345 (org-add-hook
2346 'post-command-hook
2347 (lambda ()
2348 (unless (current-message)
2349 (let* ((m (org-agenda-get-any-marker))
2350 (note (and m (org-entry-get m "THEFLAGGINGNOTE"))))
2351 (when note
2352 (message (concat
2353 "FLAGGING-NOTE ([?] for more info): "
2354 (org-add-props
2355 (replace-regexp-in-string
2356 "\\\\n" "//"
2357 (copy-sequence note))
2358 nil 'face 'org-warning)))))))
2359 t t))
20908596 2360 ((equal keys "L")
e66ba1df 2361 (unless (eq major-mode 'org-mode)
20908596
CD
2362 (error "This is not an Org-mode file"))
2363 (unless restriction
2364 (put 'org-agenda-files 'org-restrict (list bfn))
2365 (org-call-with-arg 'org-timeline arg)))
2366 ((equal keys "#") (call-interactively 'org-agenda-list-stuck-projects))
2367 ((equal keys "/") (call-interactively 'org-occur-in-agenda-files))
2368 ((equal keys "!") (customize-variable 'org-stuck-projects))
2369 (t (error "Invalid agenda key"))))))
2370
3ab2c837
BG
2371(defun org-agenda-append-agenda ()
2372 "Append another agenda view to the current one.
2373This function allows interactive building of block agendas.
2374Agenda views are separated by `org-agenda-block-separator'."
2375 (interactive)
2376 (unless (string= (buffer-name) org-agenda-buffer-name)
2377 (error "Can only append from within agenda buffer"))
2378 (let ((org-agenda-multi t))
2379 (org-agenda)
2380 (widen)))
2381
20908596
CD
2382(defun org-agenda-normalize-custom-commands (cmds)
2383 (delq nil
2384 (mapcar
2385 (lambda (x)
2386 (cond ((stringp (cdr x)) nil)
2387 ((stringp (nth 1 x)) x)
2388 ((not (nth 1 x)) (cons (car x) (cons "" (cddr x))))
2389 (t (cons (car x) (cons "" (cdr x))))))
2390 cmds)))
2391
2392(defun org-agenda-get-restriction-and-command (prefix-descriptions)
2393 "The user interface for selecting an agenda command."
2394 (catch 'exit
2395 (let* ((bfn (buffer-file-name (buffer-base-buffer)))
e66ba1df 2396 (restrict-ok (and bfn (eq major-mode 'org-mode)))
20908596
CD
2397 (region-p (org-region-active-p))
2398 (custom org-agenda-custom-commands)
2399 (selstring "")
2400 restriction second-time
afe98dfa
CD
2401 c entry key type match prefixes rmheader header-end custom1 desc
2402 line lines left right n n1)
20908596
CD
2403 (save-window-excursion
2404 (delete-other-windows)
2405 (org-switch-to-buffer-other-window " *Agenda Commands*")
2406 (erase-buffer)
2407 (insert (eval-when-compile
2408 (let ((header
2409"
2c3ad40d 2410Press key for an agenda command: < Buffer, subtree/region restriction
20908596
CD
2411-------------------------------- > Remove restriction
2412a Agenda for current week or day e Export agenda views
2413t List of all TODO entries T Entries with special TODO kwd
621f83e4 2414m Match a TAGS/PROP/TODO query M Like m, but only TODO entries
20908596
CD
2415L Timeline for current buffer # List stuck projects (!=configure)
2416s Search for keywords C Configure custom agenda commands
8d642074 2417/ Multi-occur ? Find :FLAGGED: entries
20908596
CD
2418")
2419 (start 0))
2420 (while (string-match
2421 "\\(^\\| \\|(\\)\\(\\S-\\)\\( \\|=\\)"
2422 header start)
2423 (setq start (match-end 0))
2424 (add-text-properties (match-beginning 2) (match-end 2)
2425 '(face bold) header))
2426 header)))
2427 (setq header-end (move-marker (make-marker) (point)))
2428 (while t
2429 (setq custom1 custom)
2430 (when (eq rmheader t)
54a0dee5 2431 (org-goto-line 1)
20908596
CD
2432 (re-search-forward ":" nil t)
2433 (delete-region (match-end 0) (point-at-eol))
2434 (forward-char 1)
2435 (looking-at "-+")
2436 (delete-region (match-end 0) (point-at-eol))
2437 (move-marker header-end (match-end 0)))
2438 (goto-char header-end)
2439 (delete-region (point) (point-max))
afe98dfa
CD
2440
2441 ;; Produce all the lines that describe custom commands and prefixes
2442 (setq lines nil)
20908596
CD
2443 (while (setq entry (pop custom1))
2444 (setq key (car entry) desc (nth 1 entry)
54a0dee5
CD
2445 type (nth 2 entry)
2446 match (nth 3 entry))
20908596
CD
2447 (if (> (length key) 1)
2448 (add-to-list 'prefixes (string-to-char key))
afe98dfa
CD
2449 (setq line
2450 (format
2451 "%-4s%-14s"
2452 (org-add-props (copy-sequence key)
2453 '(face bold))
2454 (cond
2455 ((string-match "\\S-" desc) desc)
2456 ((eq type 'agenda) "Agenda for current week or day")
2457 ((eq type 'alltodo) "List of all TODO entries")
2458 ((eq type 'search) "Word search")
2459 ((eq type 'stuck) "List of stuck projects")
2460 ((eq type 'todo) "TODO keyword")
2461 ((eq type 'tags) "Tags query")
2462 ((eq type 'tags-todo) "Tags (TODO)")
2463 ((eq type 'tags-tree) "Tags tree")
2464 ((eq type 'todo-tree) "TODO kwd tree")
2465 ((eq type 'occur-tree) "Occur tree")
2466 ((functionp type) (if (symbolp type)
2467 (symbol-name type)
2468 "Lambda expression"))
2469 (t "???"))))
2470 (if org-agenda-menu-show-matcher
2471 (setq line
2472 (concat line ": "
2473 (cond
2474 ((stringp match)
2475 (setq match (copy-sequence match))
2476 (org-add-props match nil 'face 'org-warning))
2477 (match
2478 (format "set of %d commands" (length match)))
2479 (t ""))))
2480 (if (org-string-nw-p match)
2481 (add-text-properties
2482 0 (length line) (list 'help-echo
2483 (concat "Matcher: "match)) line)))
2484 (push line lines)))
2485 (setq lines (nreverse lines))
20908596
CD
2486 (when prefixes
2487 (mapc (lambda (x)
afe98dfa
CD
2488 (push
2489 (format "%s %s"
20908596 2490 (org-add-props (char-to-string x)
afe98dfa
CD
2491 nil 'face 'bold)
2492 (or (cdr (assoc (concat selstring
2493 (char-to-string x))
20908596 2494 prefix-descriptions))
afe98dfa
CD
2495 "Prefix key"))
2496 lines))
20908596 2497 prefixes))
afe98dfa
CD
2498
2499 ;; Check if we should display in two columns
2500 (if org-agenda-menu-two-column
2501 (progn
2502 (setq n (length lines)
2503 n1 (+ (/ n 2) (mod n 2))
2504 right (nthcdr n1 lines)
2505 left (copy-sequence lines))
2506 (setcdr (nthcdr (1- n1) left) nil))
2507 (setq left lines right nil))
2508 (while left
2509 (insert "\n" (pop left))
2510 (when right
2511 (if (< (current-column) 40)
2512 (move-to-column 40 t)
2513 (insert " "))
2514 (insert (pop right))))
2515
2516 ;; Make the window the right size
20908596 2517 (goto-char (point-min))
93b62de8
CD
2518 (if second-time
2519 (if (not (pos-visible-in-window-p (point-max)))
2520 (org-fit-window-to-buffer))
2521 (setq second-time t)
2522 (org-fit-window-to-buffer))
afe98dfa
CD
2523
2524 ;; Ask for selection
20908596
CD
2525 (message "Press key for agenda command%s:"
2526 (if (or restrict-ok org-agenda-overriding-restriction)
2527 (if org-agenda-overriding-restriction
2528 " (restriction lock active)"
2529 (if restriction
2530 (format " (restricted to %s)" restriction)
2531 " (unrestricted)"))
2532 ""))
2533 (setq c (read-char-exclusive))
2534 (message "")
2535 (cond
2536 ((assoc (char-to-string c) custom)
2537 (setq selstring (concat selstring (char-to-string c)))
2538 (throw 'exit (cons selstring restriction)))
2539 ((memq c prefixes)
2540 (setq selstring (concat selstring (char-to-string c))
2541 prefixes nil
2542 rmheader (or rmheader t)
2543 custom (delq nil (mapcar
2544 (lambda (x)
2545 (if (or (= (length (car x)) 1)
2546 (/= (string-to-char (car x)) c))
2547 nil
2548 (cons (substring (car x) 1) (cdr x))))
2549 custom))))
2550 ((and (not restrict-ok) (memq c '(?1 ?0 ?<)))
2551 (message "Restriction is only possible in Org-mode buffers")
2552 (ding) (sit-for 1))
2553 ((eq c ?1)
2554 (org-agenda-remove-restriction-lock 'noupdate)
2555 (setq restriction 'buffer))
2556 ((eq c ?0)
2557 (org-agenda-remove-restriction-lock 'noupdate)
2558 (setq restriction (if region-p 'region 'subtree)))
2559 ((eq c ?<)
2560 (org-agenda-remove-restriction-lock 'noupdate)
2561 (setq restriction
2562 (cond
2563 ((eq restriction 'buffer)
2564 (if region-p 'region 'subtree))
2565 ((memq restriction '(subtree region))
2566 nil)
2567 (t 'buffer))))
2568 ((eq c ?>)
2569 (org-agenda-remove-restriction-lock 'noupdate)
2570 (setq restriction nil))
8d642074 2571 ((and (equal selstring "") (memq c '(?s ?a ?t ?m ?L ?C ?e ?T ?M ?# ?! ?/ ??)))
20908596
CD
2572 (throw 'exit (cons (setq selstring (char-to-string c)) restriction)))
2573 ((and (> (length selstring) 0) (eq c ?\d))
2574 (delete-window)
2575 (org-agenda-get-restriction-and-command prefix-descriptions))
2576
2577 ((equal c ?q) (error "Abort"))
2578 (t (error "Invalid key %c" c))))))))
2579
3ab2c837
BG
2580(defvar org-agenda-overriding-arguments nil) ; dynamically scoped parameter
2581(defvar org-agenda-last-arguments nil
2582 "The arguments of the previous call to `org-agenda'.")
2583(defun org-agenda-run-series (name series)
c8d0cf5c 2584 (org-let (nth 1 series) '(org-prepare-agenda name))
20908596 2585 (let* ((org-agenda-multi t)
3ab2c837
BG
2586 (redo (list 'org-agenda-run-series name (list 'quote series)))
2587 (org-agenda-overriding-arguments
2588 (or org-agenda-overriding-arguments
2589 (unless (null (delq nil (get 'org-agenda-redo-command 'last-args)))
2590 (get 'org-agenda-redo-command 'last-args))))
20908596
CD
2591 (cmds (car series))
2592 (gprops (nth 1 series))
2593 match ;; The byte compiler incorrectly complains about this. Keep it!
2594 cmd type lprops)
2595 (while (setq cmd (pop cmds))
8bfe682a 2596 (setq type (car cmd) match (eval (nth 1 cmd)) lprops (nth 2 cmd))
20908596
CD
2597 (cond
2598 ((eq type 'agenda)
2599 (org-let2 gprops lprops
2600 '(call-interactively 'org-agenda-list)))
2601 ((eq type 'alltodo)
2602 (org-let2 gprops lprops
2603 '(call-interactively 'org-todo-list)))
2604 ((eq type 'search)
2605 (org-let2 gprops lprops
2606 '(org-search-view current-prefix-arg match nil)))
2607 ((eq type 'stuck)
2608 (org-let2 gprops lprops
2609 '(call-interactively 'org-agenda-list-stuck-projects)))
2610 ((eq type 'tags)
2611 (org-let2 gprops lprops
2612 '(org-tags-view current-prefix-arg match)))
2613 ((eq type 'tags-todo)
2614 (org-let2 gprops lprops
2615 '(org-tags-view '(4) match)))
2616 ((eq type 'todo)
2617 (org-let2 gprops lprops
2618 '(org-todo-list match)))
2619 ((fboundp type)
2620 (org-let2 gprops lprops
2621 '(funcall type match)))
2622 (t (error "Invalid type in command series"))))
2623 (widen)
2624 (setq org-agenda-redo-command redo)
3ab2c837 2625 (put 'org-agenda-redo-command 'last-args org-agenda-last-arguments)
20908596 2626 (goto-char (point-min)))
c8d0cf5c 2627 (org-fit-agenda-window)
0bd48b37 2628 (org-let (nth 1 series) '(org-finalize-agenda)))
20908596
CD
2629
2630;;;###autoload
2631(defmacro org-batch-agenda (cmd-key &rest parameters)
2632 "Run an agenda command in batch mode and send the result to STDOUT.
2633If CMD-KEY is a string of length 1, it is used as a key in
2634`org-agenda-custom-commands' and triggers this command. If it is a
2635longer string it is used as a tags/todo match string.
86fbb8ca 2636Parameters are alternating variable names and values that will be bound
20908596 2637before running the agenda command."
e66ba1df 2638 (org-eval-in-environment (org-make-parameter-alist parameters)
20908596 2639 (if (> (length cmd-key) 2)
e66ba1df
BG
2640 (org-tags-view nil cmd-key)
2641 (org-agenda nil cmd-key)))
2642 (set-buffer org-agenda-buffer-name)
2643 (princ (buffer-string)))
2644(def-edebug-spec org-batch-agenda (form &rest sexp))
20908596
CD
2645
2646(defvar org-agenda-info nil)
2647
2648;;;###autoload
2649(defmacro org-batch-agenda-csv (cmd-key &rest parameters)
2650 "Run an agenda command in batch mode and send the result to STDOUT.
2651If CMD-KEY is a string of length 1, it is used as a key in
2652`org-agenda-custom-commands' and triggers this command. If it is a
2653longer string it is used as a tags/todo match string.
86fbb8ca 2654Parameters are alternating variable names and values that will be bound
20908596
CD
2655before running the agenda command.
2656
2657The output gives a line for each selected agenda item. Each
2658item is a list of comma-separated values, like this:
2659
2660category,head,type,todo,tags,date,time,extra,priority-l,priority-n
2661
2662category The category of the item
2663head The headline, without TODO kwd, TAGS and PRIORITY
2664type The type of the agenda entry, can be
2665 todo selected in TODO match
2666 tagsmatch selected in tags match
2667 diary imported from diary
2668 deadline a deadline on given date
2669 scheduled scheduled on given date
2670 timestamp entry has timestamp on given date
2671 closed entry was closed on given date
2672 upcoming-deadline warning about deadline
2673 past-scheduled forwarded scheduled item
2674 block entry has date block including g. date
2675todo The todo keyword, if any
2676tags All tags including inherited ones, separated by colons
2677date The relevant date, like 2007-2-14
2678time The time, like 15:00-16:50
2679extra Sting with extra planning info
2680priority-l The priority letter if any was given
2681priority-n The computed numerical priority
2682agenda-day The day in the agenda where this is listed"
e66ba1df
BG
2683 (org-eval-in-environment (append '((org-agenda-remove-tags t))
2684 (org-make-parameter-alist parameters))
20908596 2685 (if (> (length cmd-key) 2)
e66ba1df
BG
2686 (org-tags-view nil cmd-key)
2687 (org-agenda nil cmd-key)))
2688 (set-buffer org-agenda-buffer-name)
2689 (let* ((lines (org-split-string (buffer-string) "\n"))
2690 line)
2691 (while (setq line (pop lines))
2692 (catch 'next
2693 (if (not (get-text-property 0 'org-category line)) (throw 'next nil))
2694 (setq org-agenda-info
2695 (org-fix-agenda-info (text-properties-at 0 line)))
2696 (princ
2697 (mapconcat 'org-agenda-export-csv-mapper
2698 '(org-category txt type todo tags date time extra
2699 priority-letter priority agenda-day)
2700 ","))
2701 (princ "\n")))))
2702(def-edebug-spec org-batch-agenda-csv (form &rest sexp))
20908596
CD
2703
2704(defun org-fix-agenda-info (props)
86fbb8ca
CD
2705 "Make sure all properties on an agenda item have a canonical form.
2706This ensures the export commands can easily use it."
20908596
CD
2707 (let (tmp re)
2708 (when (setq tmp (plist-get props 'tags))
2709 (setq props (plist-put props 'tags (mapconcat 'identity tmp ":"))))
2710 (when (setq tmp (plist-get props 'date))
2711 (if (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
2712 (let ((calendar-date-display-form '(year "-" month "-" day)))
2713 '((format "%4d, %9s %2s, %4s" dayname monthname day year))
2714
2715 (setq tmp (calendar-date-string tmp)))
2716 (setq props (plist-put props 'date tmp)))
2717 (when (setq tmp (plist-get props 'day))
2718 (if (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
2719 (let ((calendar-date-display-form '(year "-" month "-" day)))
2720 (setq tmp (calendar-date-string tmp)))
2721 (setq props (plist-put props 'day tmp))
2722 (setq props (plist-put props 'agenda-day tmp)))
2723 (when (setq tmp (plist-get props 'txt))
2724 (when (string-match "\\[#\\([A-Z0-9]\\)\\] ?" tmp)
2725 (plist-put props 'priority-letter (match-string 1 tmp))
2726 (setq tmp (replace-match "" t t tmp)))
2727 (when (and (setq re (plist-get props 'org-todo-regexp))
2728 (setq re (concat "\\`\\.*" re " ?"))
2729 (string-match re tmp))
2730 (plist-put props 'todo (match-string 1 tmp))
2731 (setq tmp (replace-match "" t t tmp)))
2732 (plist-put props 'txt tmp)))
2733 props)
2734
2735(defun org-agenda-export-csv-mapper (prop)
2736 (let ((res (plist-get org-agenda-info prop)))
2737 (setq res
2738 (cond
2739 ((not res) "")
2740 ((stringp res) res)
2741 (t (prin1-to-string res))))
2742 (while (string-match "," res)
2743 (setq res (replace-match ";" t t res)))
2744 (org-trim res)))
2745
2746
2747;;;###autoload
2748(defun org-store-agenda-views (&rest parameters)
2749 (interactive)
2750 (eval (list 'org-batch-store-agenda-views)))
2751
20908596
CD
2752;;;###autoload
2753(defmacro org-batch-store-agenda-views (&rest parameters)
2754 "Run all custom agenda commands that have a file argument."
2755 (let ((cmds (org-agenda-normalize-custom-commands org-agenda-custom-commands))
2756 (pop-up-frames nil)
2757 (dir default-directory)
e66ba1df
BG
2758 (pars (org-make-parameter-alist parameters))
2759 cmd thiscmdkey files opts cmd-or-set)
20908596
CD
2760 (save-window-excursion
2761 (while cmds
2762 (setq cmd (pop cmds)
2763 thiscmdkey (car cmd)
2c3ad40d
CD
2764 cmd-or-set (nth 2 cmd)
2765 opts (nth (if (listp cmd-or-set) 3 4) cmd)
2766 files (nth (if (listp cmd-or-set) 4 5) cmd))
20908596
CD
2767 (if (stringp files) (setq files (list files)))
2768 (when files
e66ba1df
BG
2769 (org-eval-in-environment (append org-agenda-exporter-settings
2770 opts pars)
2771 (org-agenda nil thiscmdkey))
20908596
CD
2772 (set-buffer org-agenda-buffer-name)
2773 (while files
e66ba1df
BG
2774 (org-eval-in-environment (append org-agenda-exporter-settings
2775 opts pars)
2776 (org-agenda-write (expand-file-name (pop files) dir) nil t)))
20908596
CD
2777 (and (get-buffer org-agenda-buffer-name)
2778 (kill-buffer org-agenda-buffer-name)))))))
e66ba1df 2779(def-edebug-spec org-batch-store-agenda-views (&rest sexp))
20908596 2780
8d642074
CD
2781(defun org-agenda-mark-header-line (pos)
2782 "Mark the line at POS as an agenda structure header."
2783 (save-excursion
2784 (goto-char pos)
2785 (put-text-property (point-at-bol) (point-at-eol)
2786 'org-agenda-structural-header t)
2787 (when org-agenda-title-append
2788 (put-text-property (point-at-bol) (point-at-eol)
2789 'org-agenda-title-append org-agenda-title-append))))
2790
8bfe682a 2791(defvar org-mobile-creating-agendas)
e66ba1df
BG
2792(defvar org-agenda-write-buffer-name "Agenda View")
2793(defun org-agenda-write (file &optional open nosettings)
20908596
CD
2794 "Write the current buffer (an agenda view) as a file.
2795Depending on the extension of the file name, plain text (.txt),
e66ba1df
BG
2796HTML (.html or .htm) or Postscript (.ps) is produced.
2797If the extension is .ics, run icalendar export over all files used
20908596
CD
2798to construct the agenda and limit the export to entries listed in the
2799agenda now.
8bfe682a 2800With prefix argument OPEN, open the new file immediately.
20908596
CD
2801If NOSETTINGS is given, do not scope the settings of
2802`org-agenda-exporter-settings' into the export commands. This is used when
2803the settings have already been scoped and we do not wish to overrule other,
2804higher priority settings."
c8d0cf5c 2805 (interactive "FWrite agenda to file: \nP")
20908596
CD
2806 (if (not (file-writable-p file))
2807 (error "Cannot write agenda to file %s" file))
20908596 2808 (org-let (if nosettings nil org-agenda-exporter-settings)
afe98dfa 2809 '(save-excursion
20908596 2810 (save-window-excursion
93b62de8 2811 (org-agenda-mark-filtered-text)
8bfe682a 2812 (let ((bs (copy-sequence (buffer-string))) beg)
93b62de8
CD
2813 (org-agenda-unmark-filtered-text)
2814 (with-temp-buffer
e66ba1df 2815 (rename-buffer org-agenda-write-buffer-name t)
afe98dfa 2816 (set-buffer-modified-p nil)
20908596 2817 (insert bs)
93b62de8
CD
2818 (org-agenda-remove-marked-text 'org-filtered)
2819 (while (setq beg (text-property-any (point-min) (point-max)
2820 'org-filtered t))
2821 (delete-region
2822 beg (or (next-single-property-change beg 'org-filtered)
2823 (point-max))))
c8d0cf5c 2824 (run-hooks 'org-agenda-before-write-hook)
93b62de8 2825 (cond
8bfe682a
CD
2826 ((org-bound-and-true-p org-mobile-creating-agendas)
2827 (org-mobile-write-agenda-for-mobile file))
93b62de8 2828 ((string-match "\\.html?\\'" file)
afe98dfa 2829 (require 'htmlize)
93b62de8 2830 (set-buffer (htmlize-buffer (current-buffer)))
ff4be292 2831
93b62de8
CD
2832 (when (and org-agenda-export-html-style
2833 (string-match "<style>" org-agenda-export-html-style))
2834 ;; replace <style> section with org-agenda-export-html-style
2835 (goto-char (point-min))
2836 (kill-region (- (search-forward "<style") 6)
2837 (search-forward "</style>"))
2838 (insert org-agenda-export-html-style))
2839 (write-file file)
2840 (kill-buffer (current-buffer))
2841 (message "HTML written to %s" file))
2842 ((string-match "\\.ps\\'" file)
c8d0cf5c 2843 (require 'ps-print)
afe98dfa 2844 (ps-print-buffer-with-faces file)
e66ba1df 2845 (message "Postscript written to %s" file))
c8d0cf5c
CD
2846 ((string-match "\\.pdf\\'" file)
2847 (require 'ps-print)
afe98dfa
CD
2848 (ps-print-buffer-with-faces
2849 (concat (file-name-sans-extension file) ".ps"))
c8d0cf5c
CD
2850 (call-process "ps2pdf" nil nil nil
2851 (expand-file-name
2852 (concat (file-name-sans-extension file) ".ps"))
2853 (expand-file-name file))
afe98dfa 2854 (delete-file (concat (file-name-sans-extension file) ".ps"))
c8d0cf5c 2855 (message "PDF written to %s" file))
93b62de8 2856 ((string-match "\\.ics\\'" file)
c8d0cf5c 2857 (require 'org-icalendar)
93b62de8
CD
2858 (let ((org-agenda-marker-table
2859 (org-create-marker-find-array
2860 (org-agenda-collect-markers)))
2861 (org-icalendar-verify-function 'org-check-agenda-marker-table)
2862 (org-combined-agenda-icalendar-file file))
2863 (apply 'org-export-icalendar 'combine
2864 (org-agenda-files nil 'ifmode))))
2865 (t
2866 (let ((bs (buffer-string)))
2867 (find-file file)
2868 (erase-buffer)
2869 (insert bs)
2870 (save-buffer 0)
2871 (kill-buffer (current-buffer))
2872 (message "Plain text written to %s" file))))))))
c8d0cf5c
CD
2873 (set-buffer org-agenda-buffer-name))
2874 (when open (org-open-file file)))
2875
e66ba1df
BG
2876(defvar org-agenda-tag-filter-overlays nil)
2877(defvar org-agenda-cat-filter-overlays nil)
93b62de8
CD
2878
2879(defun org-agenda-mark-filtered-text ()
2880 "Mark all text hidden by filtering with a text property."
2881 (let ((inhibit-read-only t))
2882 (mapc
2883 (lambda (o)
86fbb8ca 2884 (when (equal (overlay-buffer o) (current-buffer))
93b62de8 2885 (put-text-property
86fbb8ca 2886 (overlay-start o) (overlay-end o)
93b62de8 2887 'org-filtered t)))
e66ba1df
BG
2888 (append org-agenda-tag-filter-overlays
2889 org-agenda-cat-filter-overlays))))
93b62de8
CD
2890
2891(defun org-agenda-unmark-filtered-text ()
2892 "Remove the filtering text property."
2893 (let ((inhibit-read-only t))
2894 (remove-text-properties (point-min) (point-max) '(org-filtered t))))
2895
2896(defun org-agenda-remove-marked-text (property &optional value)
2897 "Delete all text marked with VALUE of PROPERTY.
2898VALUE defaults to t."
2899 (let (beg)
2900 (setq value (or value t))
2901 (while (setq beg (text-property-any (point-min) (point-max)
2902 property value))
2903 (delete-region
2904 beg (or (next-single-property-change beg 'org-filtered)
2905 (point-max))))))
20908596 2906
c8d0cf5c
CD
2907(defun org-agenda-add-entry-text ()
2908 "Add entry text to agenda lines.
2909This will add a maximum of `org-agenda-add-entry-text-maxlines' lines of the
2910entry text following headings shown in the agenda.
2911Drawers will be excluded, also the line with scheduling/deadline info."
8bfe682a
CD
2912 (when (and (> org-agenda-add-entry-text-maxlines 0)
2913 (not (org-bound-and-true-p org-mobile-creating-agendas)))
54a0dee5 2914 (let (m txt)
c8d0cf5c
CD
2915 (goto-char (point-min))
2916 (while (not (eobp))
8d642074 2917 (if (not (setq m (org-get-at-bol 'org-hd-marker)))
c8d0cf5c 2918 (beginning-of-line 2)
54a0dee5 2919 (setq txt (org-agenda-get-some-entry-text
8d642074 2920 m org-agenda-add-entry-text-maxlines " > "))
c8d0cf5c 2921 (end-of-line 1)
afe98dfa
CD
2922 (if (string-match "\\S-" txt)
2923 (insert "\n" txt)
2924 (or (eobp) (forward-char 1))))))))
c8d0cf5c 2925
8d642074
CD
2926(defun org-agenda-get-some-entry-text (marker n-lines &optional indent
2927 &rest keep)
54a0dee5 2928 "Extract entry text from MARKER, at most N-LINES lines.
8d642074
CD
2929This will ignore drawers etc, just get the text.
2930If INDENT is given, prefix every line with this string. If KEEP is
8bfe682a 2931given, it is a list of symbols, defining stuff that should not be
8d642074 2932removed from the entry content. Currently only `planning' is allowed here."
54a0dee5
CD
2933 (let (txt drawer-re kwd-time-re ind)
2934 (save-excursion
2935 (with-current-buffer (marker-buffer marker)
e66ba1df 2936 (if (not (eq major-mode 'org-mode))
54a0dee5
CD
2937 (setq txt "")
2938 (save-excursion
2939 (save-restriction
2940 (widen)
2941 (goto-char marker)
8d642074 2942 (end-of-line 1)
54a0dee5 2943 (setq txt (buffer-substring
8d642074 2944 (min (1+ (point)) (point-max))
54a0dee5
CD
2945 (progn (outline-next-heading) (point)))
2946 drawer-re org-drawer-regexp
2947 kwd-time-re (concat "^[ \t]*" org-keyword-time-regexp
2948 ".*\n?"))
2949 (with-temp-buffer
2950 (insert txt)
2951 (when org-agenda-add-entry-text-descriptive-links
2952 (goto-char (point-min))
2953 (while (org-activate-bracket-links (point-max))
2954 (add-text-properties (match-beginning 0) (match-end 0)
2955 '(face org-link))))
2956 (goto-char (point-min))
2957 (while (re-search-forward org-bracket-link-regexp (point-max) t)
2958 (set-text-properties (match-beginning 0) (match-end 0)
2959 nil))
2960 (goto-char (point-min))
2961 (while (re-search-forward drawer-re nil t)
2962 (delete-region
2963 (match-beginning 0)
2964 (progn (re-search-forward
2965 "^[ \t]*:END:.*\n?" nil 'move)
2966 (point))))
8d642074
CD
2967 (unless (member 'planning keep)
2968 (goto-char (point-min))
2969 (while (re-search-forward kwd-time-re nil t)
2970 (replace-match "")))
54a0dee5 2971 (goto-char (point-min))
8d642074
CD
2972 (when org-agenda-entry-text-exclude-regexps
2973 (let ((re-list org-agenda-entry-text-exclude-regexps) re)
2974 (while (setq re (pop re-list))
2975 (goto-char (point-min))
2976 (while (re-search-forward re nil t)
2977 (replace-match "")))))
2978 (goto-char (point-max))
2979 (skip-chars-backward " \t\n")
2980 (if (looking-at "[ \t\n]+\\'") (replace-match ""))
2981
2982 ;; find and remove min common indentation
54a0dee5
CD
2983 (goto-char (point-min))
2984 (untabify (point-min) (point-max))
2985 (setq ind (org-get-indentation))
2986 (while (not (eobp))
2987 (unless (looking-at "[ \t]*$")
2988 (setq ind (min ind (org-get-indentation))))
2989 (beginning-of-line 2))
2990 (goto-char (point-min))
2991 (while (not (eobp))
2992 (unless (looking-at "[ \t]*$")
2993 (move-to-column ind)
2994 (delete-region (point-at-bol) (point)))
2995 (beginning-of-line 2))
8d642074
CD
2996
2997 (run-hooks 'org-agenda-entry-text-cleanup-hook)
2998
54a0dee5 2999 (goto-char (point-min))
8d642074
CD
3000 (when indent
3001 (while (and (not (eobp)) (re-search-forward "^" nil t))
3002 (replace-match indent t t)))
54a0dee5
CD
3003 (goto-char (point-min))
3004 (while (looking-at "[ \t]*\n") (replace-match ""))
3005 (goto-char (point-max))
3006 (when (> (org-current-line)
3007 n-lines)
3008 (org-goto-line (1+ n-lines))
3009 (backward-char 1))
3010 (setq txt (buffer-substring (point-min) (point)))))))))
3011 txt))
3012
20908596
CD
3013(defun org-agenda-collect-markers ()
3014 "Collect the markers pointing to entries in the agenda buffer."
3015 (let (m markers)
3016 (save-excursion
3017 (goto-char (point-min))
3018 (while (not (eobp))
8d642074
CD
3019 (when (setq m (or (org-get-at-bol 'org-hd-marker)
3020 (org-get-at-bol 'org-marker)))
20908596
CD
3021 (push m markers))
3022 (beginning-of-line 2)))
3023 (nreverse markers)))
3024
3025(defun org-create-marker-find-array (marker-list)
e66ba1df 3026 "Create a alist of files names with all marker positions in that file."
20908596
CD
3027 (let (f tbl m a p)
3028 (while (setq m (pop marker-list))
3029 (setq p (marker-position m)
3030 f (buffer-file-name (or (buffer-base-buffer
3031 (marker-buffer m))
3032 (marker-buffer m))))
3033 (if (setq a (assoc f tbl))
3034 (push (marker-position m) (cdr a))
3035 (push (list f p) tbl)))
3036 (mapcar (lambda (x) (setcdr x (sort (copy-sequence (cdr x)) '<)) x)
3037 tbl)))
3038
33306645 3039(defvar org-agenda-marker-table nil) ; dynamically scoped parameter
20908596
CD
3040(defun org-check-agenda-marker-table ()
3041 "Check of the current entry is on the marker list."
3042 (let ((file (buffer-file-name (or (buffer-base-buffer) (current-buffer))))
3043 a)
3044 (and (setq a (assoc file org-agenda-marker-table))
3045 (save-match-data
3046 (save-excursion
3047 (org-back-to-heading t)
3048 (member (point) (cdr a)))))))
3049
3050(defun org-check-for-org-mode ()
e66ba1df
BG
3051 "Make sure current buffer is in org-mode. Error if not."
3052 (or (eq major-mode 'org-mode)
f924a367 3053 (error "Cannot execute org-mode agenda command on buffer in %s"
20908596
CD
3054 major-mode)))
3055
3056(defun org-fit-agenda-window ()
3057 "Fit the window to the buffer size."
3058 (and (memq org-agenda-window-setup '(reorganize-frame))
3059 (fboundp 'fit-window-to-buffer)
93b62de8 3060 (org-fit-window-to-buffer
20908596
CD
3061 nil
3062 (floor (* (frame-height) (cdr org-agenda-window-frame-fractions)))
3063 (floor (* (frame-height) (car org-agenda-window-frame-fractions))))))
3064
3065;;; Agenda prepare and finalize
3066
33306645 3067(defvar org-agenda-multi nil) ; dynamically scoped
20908596
CD
3068(defvar org-agenda-buffer-name "*Org Agenda*")
3069(defvar org-pre-agenda-window-conf nil)
3070(defvar org-agenda-columns-active nil)
3071(defvar org-agenda-name nil)
e66ba1df
BG
3072(defvar org-agenda-tag-filter nil)
3073(defvar org-agenda-category-filter nil)
3074(defvar org-agenda-tag-filter-while-redo nil)
3075(defvar org-agenda-tag-filter-preset nil
c8d0cf5c 3076 "A preset of the tags filter used for secondary agenda filtering.
86fbb8ca 3077This must be a list of strings, each string must be a single tag preceded
c8d0cf5c
CD
3078by \"+\" or \"-\".
3079This variable should not be set directly, but agenda custom commands can
afe98dfa
CD
3080bind it in the options section. The preset filter is a global property of
3081the entire agenda view. In a block agenda, it will not work reliably to
3082define a filter for one of the individual blocks. You need to set it in
3083the global options and expect it to be applied to the entire view.")
c8d0cf5c 3084
e66ba1df 3085(defvar org-agenda-category-filter-preset nil
27e428e7 3086 "A preset of the category filter used for secondary agenda filtering.
e66ba1df
BG
3087This must be a list of strings, each string must be a single category
3088preceded by \"+\" or \"-\".
3089This variable should not be set directly, but agenda custom commands can
3090bind it in the options section. The preset filter is a global property of
3091the entire agenda view. In a block agenda, it will not work reliably to
3092define a filter for one of the individual blocks. You need to set it in
3093the global options and expect it to be applied to the entire view.")
3094
20908596
CD
3095(defun org-prepare-agenda (&optional name)
3096 (setq org-todo-keywords-for-agenda nil)
8d642074 3097 (setq org-drawers-for-agenda nil)
86fbb8ca 3098 (unless org-agenda-persistent-filter
e66ba1df
BG
3099 (setq org-agenda-tag-filter nil
3100 org-agenda-category-filter nil))
3101 (put 'org-agenda-tag-filter :preset-filter org-agenda-tag-filter-preset)
3102 (put 'org-agenda-category-filter :preset-filter org-agenda-category-filter-preset)
20908596
CD
3103 (if org-agenda-multi
3104 (progn
3105 (setq buffer-read-only nil)
3106 (goto-char (point-max))
3ab2c837
BG
3107 (unless (or (bobp) org-agenda-compact-blocks
3108 (not org-agenda-block-separator))
0bd48b37
CD
3109 (insert "\n"
3110 (if (stringp org-agenda-block-separator)
3111 org-agenda-block-separator
3112 (make-string (window-width) org-agenda-block-separator))
3113 "\n"))
20908596 3114 (narrow-to-region (point) (point-max)))
153ae947 3115 (setq org-done-keywords-for-agenda nil)
20908596
CD
3116 (org-agenda-reset-markers)
3117 (setq org-agenda-contributing-files nil)
3118 (setq org-agenda-columns-active nil)
2c3ad40d 3119 (org-prepare-agenda-buffers (org-agenda-files nil 'ifmode))
20908596
CD
3120 (setq org-todo-keywords-for-agenda
3121 (org-uniquify org-todo-keywords-for-agenda))
3122 (setq org-done-keywords-for-agenda
3123 (org-uniquify org-done-keywords-for-agenda))
8d642074 3124 (setq org-drawers-for-agenda (org-uniquify org-drawers-for-agenda))
20908596
CD
3125 (let* ((abuf (get-buffer-create org-agenda-buffer-name))
3126 (awin (get-buffer-window abuf)))
3127 (cond
3128 ((equal (current-buffer) abuf) nil)
3129 (awin (select-window awin))
3130 ((not (setq org-pre-agenda-window-conf (current-window-configuration))))
3131 ((equal org-agenda-window-setup 'current-window)
e66ba1df 3132 (org-pop-to-buffer-same-window abuf))
20908596
CD
3133 ((equal org-agenda-window-setup 'other-window)
3134 (org-switch-to-buffer-other-window abuf))
3135 ((equal org-agenda-window-setup 'other-frame)
8d642074 3136 (switch-to-buffer-other-frame abuf))
20908596
CD
3137 ((equal org-agenda-window-setup 'reorganize-frame)
3138 (delete-other-windows)
afe98dfa
CD
3139 (org-switch-to-buffer-other-window abuf)))
3140 ;; additional test in case agenda is invoked from within agenda
3141 ;; buffer via elisp link
3142 (unless (equal (current-buffer) abuf)
e66ba1df 3143 (org-pop-to-buffer-same-window abuf)))
20908596
CD
3144 (setq buffer-read-only nil)
3145 (let ((inhibit-read-only t)) (erase-buffer))
3146 (org-agenda-mode)
3147 (and name (not org-agenda-name)
3148 (org-set-local 'org-agenda-name name)))
3149 (setq buffer-read-only nil))
3150
3151(defun org-finalize-agenda ()
3152 "Finishing touch for the agenda buffer, called just before displaying it."
3153 (unless org-agenda-multi
3154 (save-excursion
3155 (let ((inhibit-read-only t))
3156 (goto-char (point-min))
3157 (while (org-activate-bracket-links (point-max))
3158 (add-text-properties (match-beginning 0) (match-end 0)
3159 '(face org-link)))
3160 (org-agenda-align-tags)
3161 (unless org-agenda-with-colors
3162 (remove-text-properties (point-min) (point-max) '(face nil))))
33306645
CD
3163 (if (and (boundp 'org-agenda-overriding-columns-format)
3164 org-agenda-overriding-columns-format)
3165 (org-set-local 'org-agenda-overriding-columns-format
3166 org-agenda-overriding-columns-format))
20908596
CD
3167 (if (and (boundp 'org-agenda-view-columns-initially)
3168 org-agenda-view-columns-initially)
3169 (org-agenda-columns))
3170 (when org-agenda-fontify-priorities
c8d0cf5c 3171 (org-agenda-fontify-priorities))
d6685abc
CD
3172 (when (and org-agenda-dim-blocked-tasks org-blocker-hook)
3173 (org-agenda-dim-blocked-tasks))
54a0dee5
CD
3174 (org-agenda-mark-clocking-task)
3175 (when org-agenda-entry-text-mode
3176 (org-agenda-entry-text-hide)
f924a367 3177 (org-agenda-entry-text-show))
8bfe682a
CD
3178 (if (functionp 'org-habit-insert-consistency-graphs)
3179 (org-habit-insert-consistency-graphs))
20908596 3180 (run-hooks 'org-finalize-agenda-hook)
8d642074 3181 (setq org-agenda-type (org-get-at-bol 'org-agenda-type))
e66ba1df
BG
3182 (when (or org-agenda-tag-filter (get 'org-agenda-tag-filter :preset-filter))
3183 (org-agenda-filter-apply org-agenda-tag-filter 'tag))
3184 (when (or org-agenda-category-filter (get 'org-agenda-category-filter :preset-filter))
3185 (org-agenda-filter-apply org-agenda-category-filter 'category))
20908596
CD
3186 )))
3187
54a0dee5
CD
3188(defun org-agenda-mark-clocking-task ()
3189 "Mark the current clock entry in the agenda if it is present."
3190 (mapc (lambda (o)
86fbb8ca
CD
3191 (if (eq (overlay-get o 'type) 'org-agenda-clocking)
3192 (delete-overlay o)))
3193 (overlays-in (point-min) (point-max)))
54a0dee5
CD
3194 (when (marker-buffer org-clock-hd-marker)
3195 (save-excursion
3196 (goto-char (point-min))
3197 (let (s ov)
3198 (while (setq s (next-single-property-change (point) 'org-hd-marker))
3199 (goto-char s)
8d642074 3200 (when (equal (org-get-at-bol 'org-hd-marker)
54a0dee5 3201 org-clock-hd-marker)
86fbb8ca
CD
3202 (setq ov (make-overlay (point-at-bol) (1+ (point-at-eol))))
3203 (overlay-put ov 'type 'org-agenda-clocking)
3204 (overlay-put ov 'face 'org-agenda-clocking)
3205 (overlay-put ov 'help-echo
54a0dee5
CD
3206 "The clock is running in this item")))))))
3207
c8d0cf5c 3208(defun org-agenda-fontify-priorities ()
20908596
CD
3209 "Make highest priority lines bold, and lowest italic."
3210 (interactive)
86fbb8ca
CD
3211 (mapc (lambda (o) (if (eq (overlay-get o 'org-type) 'org-priority)
3212 (delete-overlay o)))
3213 (overlays-in (point-min) (point-max)))
20908596
CD
3214 (save-excursion
3215 (let ((inhibit-read-only t)
3216 b e p ov h l)
3217 (goto-char (point-min))
3218 (while (re-search-forward "\\[#\\(.\\)\\]" nil t)
3219 (setq h (or (get-char-property (point) 'org-highest-priority)
3220 org-highest-priority)
3221 l (or (get-char-property (point) 'org-lowest-priority)
3222 org-lowest-priority)
3223 p (string-to-char (match-string 1))
c8d0cf5c
CD
3224 b (match-beginning 0)
3225 e (if (eq org-agenda-fontify-priorities 'cookies)
3226 (match-end 0)
3227 (point-at-eol))
86fbb8ca
CD
3228 ov (make-overlay b e))
3229 (overlay-put
20908596 3230 ov 'face
ed21c5c8
CD
3231 (cond ((org-face-from-face-or-color
3232 'priority nil
3233 (cdr (assoc p org-priority-faces))))
c8d0cf5c 3234 ((and (listp org-agenda-fontify-priorities)
ed21c5c8
CD
3235 (org-face-from-face-or-color
3236 'priority nil
3237 (cdr (assoc p org-agenda-fontify-priorities)))))
20908596
CD
3238 ((equal p l) 'italic)
3239 ((equal p h) 'bold)))
86fbb8ca 3240 (overlay-put ov 'org-type 'org-priority)))))
20908596 3241
d6685abc
CD
3242(defun org-agenda-dim-blocked-tasks ()
3243 "Dim currently blocked TODO's in the agenda display."
86fbb8ca
CD
3244 (mapc (lambda (o) (if (eq (overlay-get o 'org-type) 'org-blocked-todo)
3245 (delete-overlay o)))
3246 (overlays-in (point-min) (point-max)))
d6685abc
CD
3247 (save-excursion
3248 (let ((inhibit-read-only t)
72d06d81 3249 (org-depend-tag-blocked nil)
d6685abc 3250 (invis (eq org-agenda-dim-blocked-tasks 'invisible))
c8d0cf5c
CD
3251 org-blocked-by-checkboxes
3252 invis1 b e p ov h l)
d6685abc
CD
3253 (goto-char (point-min))
3254 (while (let ((pos (next-single-property-change (point) 'todo-state)))
3255 (and pos (goto-char (1+ pos))))
c8d0cf5c 3256 (setq org-blocked-by-checkboxes nil invis1 invis)
8d642074 3257 (let ((marker (org-get-at-bol 'org-hd-marker)))
d6685abc 3258 (when (and marker
e66ba1df
BG
3259 (with-current-buffer (marker-buffer marker)
3260 (save-excursion (goto-char marker)
3261 (org-entry-blocked-p))))
c8d0cf5c 3262 (if org-blocked-by-checkboxes (setq invis1 nil))
53e31a31
CD
3263 (setq b (if invis1
3264 (max (point-min) (1- (point-at-bol)))
3265 (point-at-bol))
d6685abc 3266 e (point-at-eol)
86fbb8ca 3267 ov (make-overlay b e))
c8d0cf5c 3268 (if invis1
86fbb8ca
CD
3269 (overlay-put ov 'invisible t)
3270 (overlay-put ov 'face 'org-agenda-dimmed-todo-face))
3271 (overlay-put ov 'org-type 'org-blocked-todo)))))))
20908596
CD
3272
3273(defvar org-agenda-skip-function nil
3274 "Function to be called at each match during agenda construction.
3275If this function returns nil, the current match should not be skipped.
3276Otherwise, the function must return a position from where the search
3277should be continued.
3278This may also be a Lisp form, it will be evaluated.
3279Never set this variable using `setq' or so, because then it will apply
3ab2c837
BG
3280to all future agenda commands. If you do want a global skipping condition,
3281use the option `org-agenda-skip-function-global' instead.
3282The correct usage for `org-agenda-skip-function' is to bind it with
3283`let' to scope it dynamically into the agenda-constructing command.
3284A good way to set it is through options in `org-agenda-custom-commands'.")
20908596
CD
3285
3286(defun org-agenda-skip ()
3287 "Throw to `:skip' in places that should be skipped.
3288Also moves point to the end of the skipped region, so that search can
3289continue from there."
3ab2c837 3290 (let ((p (point-at-bol)) to)
2c3ad40d 3291 (and org-agenda-skip-archived-trees (not org-agenda-archives-mode)
20908596
CD
3292 (get-text-property p :org-archived)
3293 (org-end-of-subtree t)
3294 (throw :skip t))
b349f79f
CD
3295 (and org-agenda-skip-comment-trees
3296 (get-text-property p :org-comment)
20908596
CD
3297 (org-end-of-subtree t)
3298 (throw :skip t))
3299 (if (equal (char-after p) ?#) (throw :skip t))
3ab2c837
BG
3300 (when (setq to (or (org-agenda-skip-eval org-agenda-skip-function-global)
3301 (org-agenda-skip-eval org-agenda-skip-function)))
20908596
CD
3302 (goto-char to)
3303 (throw :skip t))))
3304
3ab2c837
BG
3305(defun org-agenda-skip-eval (form)
3306 "If FORM is a function or a list, call (or eval) is and return result.
3307`save-excursion' and `save-match-data' are wrapped around the call, so point
3308and match data are returned to the previous state no matter what these
3309functions do."
3310 (let (fp)
3311 (and form
3312 (or (setq fp (functionp form))
3313 (consp form))
3314 (save-excursion
3315 (save-match-data
3316 (if fp
3317 (funcall form)
3318 (eval form)))))))
3319
20908596
CD
3320(defvar org-agenda-markers nil
3321 "List of all currently active markers created by `org-agenda'.")
54a0dee5 3322(defvar org-agenda-last-marker-time (org-float-time)
20908596
CD
3323 "Creation time of the last agenda marker.")
3324
3325(defun org-agenda-new-marker (&optional pos)
3326 "Return a new agenda marker.
3327Org-mode keeps a list of these markers and resets them when they are
3328no longer in use."
3329 (let ((m (copy-marker (or pos (point)))))
54a0dee5 3330 (setq org-agenda-last-marker-time (org-float-time))
20908596
CD
3331 (push m org-agenda-markers)
3332 m))
3333
3334(defun org-agenda-reset-markers ()
3335 "Reset markers created by `org-agenda'."
3336 (while org-agenda-markers
3337 (move-marker (pop org-agenda-markers) nil)))
3338
b349f79f
CD
3339(defun org-agenda-save-markers-for-cut-and-paste (beg end)
3340 "Save relative positions of markers in region."
3341 (mapc (lambda (m) (org-check-and-save-marker m beg end))
3342 org-agenda-markers))
3343
54a0dee5
CD
3344;;; Entry text mode
3345
3346(defun org-agenda-entry-text-show-here ()
8bfe682a 3347 "Add some text from the entry as context to the current line."
54a0dee5 3348 (let (m txt o)
8d642074 3349 (setq m (org-get-at-bol 'org-hd-marker))
54a0dee5
CD
3350 (unless (marker-buffer m)
3351 (error "No marker points to an entry here"))
3352 (setq txt (concat "\n" (org-no-properties
3353 (org-agenda-get-some-entry-text
8d642074 3354 m org-agenda-entry-text-maxlines " > "))))
54a0dee5 3355 (when (string-match "\\S-" txt)
86fbb8ca
CD
3356 (setq o (make-overlay (point-at-bol) (point-at-eol)))
3357 (overlay-put o 'evaporate t)
3358 (overlay-put o 'org-overlay-type 'agenda-entry-content)
3359 (overlay-put o 'after-string txt))))
54a0dee5
CD
3360
3361(defun org-agenda-entry-text-show ()
3362 "Add entry context for all agenda lines."
3363 (interactive)
3364 (save-excursion
3365 (goto-char (point-max))
3366 (beginning-of-line 1)
3367 (while (not (bobp))
8d642074 3368 (when (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
3369 (org-agenda-entry-text-show-here))
3370 (beginning-of-line 0))))
3371
3372(defun org-agenda-entry-text-hide ()
3373 "Remove any shown entry context."
3374 (delq nil
3375 (mapcar (lambda (o)
86fbb8ca 3376 (if (eq (overlay-get o 'org-overlay-type)
54a0dee5 3377 'agenda-entry-content)
86fbb8ca
CD
3378 (progn (delete-overlay o) t)))
3379 (overlays-in (point-min) (point-max)))))
54a0dee5 3380
acedf35c
CD
3381(defun org-agenda-get-day-face (date)
3382 "Return the face DATE should be displayed with."
3383 (or (and (functionp org-agenda-day-face-function)
3384 (funcall org-agenda-day-face-function date))
3385 (cond ((org-agenda-todayp date)
3386 'org-agenda-date-today)
3387 ((member (calendar-day-of-week date) org-agenda-weekend-days)
3388 'org-agenda-date-weekend)
3389 (t 'org-agenda-date))))
3390
20908596
CD
3391;;; Agenda timeline
3392
3393(defvar org-agenda-only-exact-dates nil) ; dynamically scoped
3394
e66ba1df 3395(defun org-timeline (&optional dotodo)
20908596
CD
3396 "Show a time-sorted view of the entries in the current org file.
3397Only entries with a time stamp of today or later will be listed. With
3398\\[universal-argument] prefix, all unfinished TODO items will also be shown,
3399under the current date.
3400If the buffer contains an active region, only check the region for
3401dates."
3402 (interactive "P")
20908596
CD
3403 (org-compile-prefix-format 'timeline)
3404 (org-set-sorting-strategy 'timeline)
3405 (let* ((dopast t)
20908596 3406 (doclosed org-agenda-show-log)
afe98dfa
CD
3407 (entry (buffer-file-name (or (buffer-base-buffer (current-buffer))
3408 (current-buffer))))
20908596
CD
3409 (date (calendar-current-date))
3410 (beg (if (org-region-active-p) (region-beginning) (point-min)))
3411 (end (if (org-region-active-p) (region-end) (point-max)))
3412 (day-numbers (org-get-all-dates beg end 'no-ranges
3413 t doclosed ; always include today
3414 org-timeline-show-empty-dates))
3415 (org-deadline-warning-days 0)
3416 (org-agenda-only-exact-dates t)
acedf35c 3417 (today (org-today))
20908596
CD
3418 (past t)
3419 args
acedf35c 3420 s e rtn d emptyp)
20908596
CD
3421 (setq org-agenda-redo-command
3422 (list 'progn
3423 (list 'org-switch-to-buffer-other-window (current-buffer))
e66ba1df 3424 (list 'org-timeline (list 'quote dotodo))))
20908596
CD
3425 (if (not dopast)
3426 ;; Remove past dates from the list of dates.
3427 (setq day-numbers (delq nil (mapcar (lambda(x)
3428 (if (>= x today) x nil))
3429 day-numbers))))
afe98dfa 3430 (org-prepare-agenda (concat "Timeline " (file-name-nondirectory entry)))
20908596
CD
3431 (if doclosed (push :closed args))
3432 (push :timestamp args)
3433 (push :deadline args)
3434 (push :scheduled args)
3435 (push :sexp args)
3436 (if dotodo (push :todo args))
8d642074
CD
3437 (insert "Timeline of file " entry "\n")
3438 (add-text-properties (point-min) (point)
3439 (list 'face 'org-agenda-structure))
3440 (org-agenda-mark-header-line (point-min))
20908596
CD
3441 (while (setq d (pop day-numbers))
3442 (if (and (listp d) (eq (car d) :omitted))
3443 (progn
3444 (setq s (point))
3445 (insert (format "\n[... %d empty days omitted]\n\n" (cdr d)))
3446 (put-text-property s (1- (point)) 'face 'org-agenda-structure))
3447 (if (listp d) (setq d (car d) emptyp t) (setq emptyp nil))
3448 (if (and (>= d today)
3449 dopast
3450 past)
3451 (progn
3452 (setq past nil)
3453 (insert (make-string 79 ?-) "\n")))
acedf35c 3454 (setq date (calendar-gregorian-from-absolute d))
20908596
CD
3455 (setq s (point))
3456 (setq rtn (and (not emptyp)
3457 (apply 'org-agenda-get-day-entries entry
3458 date args)))
3459 (if (or rtn (equal d today) org-timeline-show-empty-dates)
3460 (progn
3461 (insert
3462 (if (stringp org-agenda-format-date)
3463 (format-time-string org-agenda-format-date
3464 (org-time-from-absolute date))
3465 (funcall org-agenda-format-date date))
3466 "\n")
3467 (put-text-property s (1- (point)) 'face
acedf35c 3468 (org-agenda-get-day-face date))
20908596 3469 (put-text-property s (1- (point)) 'org-date-line t)
8d642074 3470 (put-text-property s (1- (point)) 'org-agenda-date-header t)
20908596
CD
3471 (if (equal d today)
3472 (put-text-property s (1- (point)) 'org-today t))
3473 (and rtn (insert (org-finalize-agenda-entries rtn) "\n"))
3474 (put-text-property s (1- (point)) 'day d)))))
3475 (goto-char (point-min))
3476 (goto-char (or (text-property-any (point-min) (point-max) 'org-today t)
3477 (point-min)))
3478 (add-text-properties (point-min) (point-max) '(org-agenda-type timeline))
3479 (org-finalize-agenda)
3480 (setq buffer-read-only t)))
3481
3482(defun org-get-all-dates (beg end &optional no-ranges force-today inactive empty pre-re)
3483 "Return a list of all relevant day numbers from BEG to END buffer positions.
3484If NO-RANGES is non-nil, include only the start and end dates of a range,
3485not every single day in the range. If FORCE-TODAY is non-nil, make
3486sure that TODAY is included in the list. If INACTIVE is non-nil, also
3487inactive time stamps (those in square brackets) are included.
3488When EMPTY is non-nil, also include days without any entries."
3489 (let ((re (concat
3490 (if pre-re pre-re "")
3491 (if inactive org-ts-regexp-both org-ts-regexp)))
e66ba1df 3492 dates dates1 date day day1 day2 ts1 ts2 pos)
20908596 3493 (if force-today
acedf35c 3494 (setq dates (list (org-today))))
20908596
CD
3495 (save-excursion
3496 (goto-char beg)
3497 (while (re-search-forward re end t)
3498 (setq day (time-to-days (org-time-string-to-time
e66ba1df
BG
3499 (substring (match-string 1) 0 10)
3500 (current-buffer) (match-beginning 0))))
20908596
CD
3501 (or (memq day dates) (push day dates)))
3502 (unless no-ranges
3503 (goto-char beg)
3504 (while (re-search-forward org-tr-regexp end t)
e66ba1df 3505 (setq pos (match-beginning 0))
20908596
CD
3506 (setq ts1 (substring (match-string 1) 0 10)
3507 ts2 (substring (match-string 2) 0 10)
e66ba1df
BG
3508 day1 (time-to-days (org-time-string-to-time
3509 ts1 (current-buffer) pos))
3510 day2 (time-to-days (org-time-string-to-time
3511 ts2 (current-buffer) pos)))
20908596
CD
3512 (while (< (setq day1 (1+ day1)) day2)
3513 (or (memq day1 dates) (push day1 dates)))))
3514 (setq dates (sort dates '<))
3515 (when empty
3516 (while (setq day (pop dates))
3517 (setq day2 (car dates))
3518 (push day dates1)
3519 (when (and day2 empty)
3520 (if (or (eq empty t)
3521 (and (numberp empty) (<= (- day2 day) empty)))
3522 (while (< (setq day (1+ day)) day2)
3523 (push (list day) dates1))
3524 (push (cons :omitted (- day2 day)) dates1))))
3525 (setq dates (nreverse dates1)))
3526 dates)))
3527
3528;;; Agenda Daily/Weekly
3529
c8d0cf5c 3530(defvar org-agenda-start-day nil ; dynamically scoped parameter
3ab2c837
BG
3531"Start day for the agenda view.
3532Custom commands can set this variable in the options section.")
20908596 3533(defvar org-starting-day nil) ; local variable in the agenda buffer
acedf35c
CD
3534(defvar org-agenda-current-span nil
3535 "The current span used in the agenda view.") ; local variable in the agenda buffer
e66ba1df 3536(defvar org-arg-loc nil) ; local variable
20908596 3537
ed21c5c8
CD
3538(defvar org-agenda-entry-types '(:deadline :scheduled :timestamp :sexp)
3539 "List of types searched for when creating the daily/weekly agenda.
3540This variable is a list of symbols that controls the types of
3541items that appear in the daily/weekly agenda. Allowed symbols in this
3542list are are
3543
3544 :timestamp List items containing a date stamp or date range matching
3545 the selected date. This includes sexp entries in
3546 angular brackets.
3547
3548 :sexp List entries resulting from plain diary-like sexps.
3549
3550 :deadline List deadline due on that date. When the date is today,
3551 also list any deadlines past due, or due within
3552 `org-deadline-warning-days'. `:deadline' must appear before
3553 `:scheduled' if the setting of
3554 `org-agenda-skip-scheduled-if-deadline-is-shown' is to have
3555 any effect.
3556
3557 :scheduled List all items which are scheduled for the given date.
3558 The diary for *today* also contains items which were
3559 scheduled earlier and are not yet marked DONE.
3560
3561By default, all four types are turned on.
3562
3563Never set this variable globally using `setq', because then it
3564will apply to all future agenda commands. Instead, bind it with
9b053e76 3565`let' to scope it dynamically into the agenda-constructing
ed21c5c8
CD
3566command. A good way to set it is through options in
3567`org-agenda-custom-commands'. For a more flexible (though
3568somewhat less efficient) way of determining what is included in
3569the daily/weekly agenda, see `org-agenda-skip-function'.")
3570
20908596 3571;;;###autoload
e66ba1df 3572(defun org-agenda-list (&optional arg start-day span)
20908596
CD
3573 "Produce a daily/weekly view from all files in variable `org-agenda-files'.
3574The view will be for the current day or week, but from the overview buffer
3575you will be able to go to other days/weeks.
3576
20908596 3577With a numeric prefix argument in an interactive call, the agenda will
e66ba1df 3578span ARG days. Lisp programs should instead specify SPAN to change
acedf35c 3579the number of days. SPAN defaults to `org-agenda-span'.
20908596
CD
3580
3581START-DAY defaults to TODAY, or to the most recent match for the weekday
3582given in `org-agenda-start-on-weekday'."
3583 (interactive "P")
e66ba1df
BG
3584 (if (and (integerp arg) (> arg 0))
3585 (setq span arg arg nil))
acedf35c 3586 (setq start-day (or start-day org-agenda-start-day))
20908596 3587 (if org-agenda-overriding-arguments
e66ba1df 3588 (setq arg (car org-agenda-overriding-arguments)
20908596 3589 start-day (nth 1 org-agenda-overriding-arguments)
acedf35c 3590 span (nth 2 org-agenda-overriding-arguments)))
20908596
CD
3591 (if (stringp start-day)
3592 ;; Convert to an absolute day number
3593 (setq start-day (time-to-days (org-read-date nil t start-day))))
e66ba1df 3594 (setq org-agenda-last-arguments (list arg start-day span))
20908596
CD
3595 (org-compile-prefix-format 'agenda)
3596 (org-set-sorting-strategy 'agenda)
3ab2c837
BG
3597 (let* ((span (org-agenda-ndays-to-span
3598 (or span org-agenda-ndays org-agenda-span)))
acedf35c
CD
3599 (today (org-today))
3600 (sd (or start-day today))
3601 (ndays (org-agenda-span-to-ndays span sd))
3602 (org-agenda-start-on-weekday
3603 (if (eq ndays 7)
3604 org-agenda-start-on-weekday))
2c3ad40d 3605 (thefiles (org-agenda-files nil 'ifmode))
20908596 3606 (files thefiles)
20908596 3607 (start (if (or (null org-agenda-start-on-weekday)
acedf35c 3608 (< ndays 7))
20908596
CD
3609 sd
3610 (let* ((nt (calendar-day-of-week
3611 (calendar-gregorian-from-absolute sd)))
3612 (n1 org-agenda-start-on-weekday)
3613 (d (- nt n1)))
3614 (- sd (+ (if (< d 0) 7 0) d)))))
3615 (day-numbers (list start))
3616 (day-cnt 0)
3617 (inhibit-redisplay (not debug-on-error))
acedf35c
CD
3618 s e rtn rtnall file date d start-pos end-pos todayp
3619 clocktable-start clocktable-end filter)
20908596 3620 (setq org-agenda-redo-command
e66ba1df 3621 (list 'org-agenda-list (list 'quote arg) start-day (list 'quote span)))
acedf35c
CD
3622 (dotimes (n (1- ndays))
3623 (push (1+ (car day-numbers)) day-numbers))
20908596
CD
3624 (setq day-numbers (nreverse day-numbers))
3625 (setq clocktable-start (car day-numbers)
3626 clocktable-end (1+ (or (org-last day-numbers) 0)))
3627 (org-prepare-agenda "Day/Week")
3628 (org-set-local 'org-starting-day (car day-numbers))
e66ba1df 3629 (org-set-local 'org-arg-loc arg)
acedf35c 3630 (org-set-local 'org-agenda-current-span (org-agenda-ndays-to-span span))
20908596
CD
3631 (unless org-agenda-compact-blocks
3632 (let* ((d1 (car day-numbers))
3633 (d2 (org-last day-numbers))
3634 (w1 (org-days-to-iso-week d1))
3635 (w2 (org-days-to-iso-week d2)))
3636 (setq s (point))
c8d0cf5c
CD
3637 (if org-agenda-overriding-header
3638 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
3639 nil 'face 'org-agenda-structure) "\n")
acedf35c 3640 (insert (org-agenda-span-name span)
c8d0cf5c
CD
3641 "-agenda"
3642 (if (< (- d2 d1) 350)
3643 (if (= w1 w2)
3644 (format " (W%02d)" w1)
3645 (format " (W%02d-W%02d)" w1 w2))
3646 "")
3647 ":\n")))
20908596 3648 (add-text-properties s (1- (point)) (list 'face 'org-agenda-structure
8d642074
CD
3649 'org-date-line t))
3650 (org-agenda-mark-header-line s))
20908596
CD
3651 (while (setq d (pop day-numbers))
3652 (setq date (calendar-gregorian-from-absolute d)
20908596
CD
3653 s (point))
3654 (if (or (setq todayp (= d today))
3655 (and (not start-pos) (= d sd)))
3656 (setq start-pos (point))
3657 (if (and start-pos (not end-pos))
3658 (setq end-pos (point))))
3659 (setq files thefiles
3660 rtnall nil)
3661 (while (setq file (pop files))
3662 (catch 'nextfile
3663 (org-check-agenda-file file)
ed21c5c8
CD
3664 (let ((org-agenda-entry-types org-agenda-entry-types))
3665 (unless org-agenda-include-deadlines
3666 (setq org-agenda-entry-types
3667 (delq :deadline org-agenda-entry-types)))
3668 (cond
3ab2c837 3669 ((memq org-agenda-show-log '(only clockcheck))
ed21c5c8
CD
3670 (setq rtn (org-agenda-get-day-entries
3671 file date :closed)))
3672 (org-agenda-show-log
3673 (setq rtn (apply 'org-agenda-get-day-entries
3674 file date
3675 (append '(:closed) org-agenda-entry-types))))
3676 (t
3677 (setq rtn (apply 'org-agenda-get-day-entries
3678 file date
3679 org-agenda-entry-types)))))
e66ba1df 3680 (setq rtnall (append rtnall rtn)))) ;; all entries
20908596 3681 (if org-agenda-include-diary
c8d0cf5c 3682 (let ((org-agenda-search-headline-for-time t))
20908596
CD
3683 (require 'diary-lib)
3684 (setq rtn (org-get-entries-from-diary date))
3685 (setq rtnall (append rtnall rtn))))
3686 (if (or rtnall org-agenda-show-all-dates)
3687 (progn
3688 (setq day-cnt (1+ day-cnt))
3689 (insert
3690 (if (stringp org-agenda-format-date)
3691 (format-time-string org-agenda-format-date
3692 (org-time-from-absolute date))
3693 (funcall org-agenda-format-date date))
3694 "\n")
3695 (put-text-property s (1- (point)) 'face
acedf35c 3696 (org-agenda-get-day-face date))
20908596 3697 (put-text-property s (1- (point)) 'org-date-line t)
8d642074 3698 (put-text-property s (1- (point)) 'org-agenda-date-header t)
20908596 3699 (put-text-property s (1- (point)) 'org-day-cnt day-cnt)
c8d0cf5c 3700 (when todayp
acedf35c 3701 (put-text-property s (1- (point)) 'org-today t))
e66ba1df 3702 (if rtnall (insert ;; all entries
20908596
CD
3703 (org-finalize-agenda-entries
3704 (org-agenda-add-time-grid-maybe
acedf35c 3705 rtnall ndays todayp))
20908596
CD
3706 "\n"))
3707 (put-text-property s (1- (point)) 'day d)
3708 (put-text-property s (1- (point)) 'org-day-cnt day-cnt))))
3709 (when (and org-agenda-clockreport-mode clocktable-start)
2c3ad40d 3710 (let ((org-agenda-files (org-agenda-files nil 'ifmode))
20908596 3711 ;; the above line is to ensure the restricted range!
3ab2c837 3712 (p (copy-sequence org-agenda-clockreport-parameter-plist))
20908596
CD
3713 tbl)
3714 (setq p (org-plist-delete p :block))
3715 (setq p (plist-put p :tstart clocktable-start))
3716 (setq p (plist-put p :tend clocktable-end))
3717 (setq p (plist-put p :scope 'agenda))
acedf35c 3718 (when (and (eq org-agenda-clockreport-mode 'with-filter)
e66ba1df
BG
3719 (setq filter (or org-agenda-tag-filter-while-redo
3720 (get 'org-agenda-tag-filter :preset-filter))))
acedf35c
CD
3721 (setq p (plist-put p :tags (mapconcat (lambda (x)
3722 (if (string-match "[<>=]" x)
3723 ""
3724 x))
3725 filter ""))))
20908596
CD
3726 (setq tbl (apply 'org-get-clocktable p))
3727 (insert tbl)))
3728 (goto-char (point-min))
c8d0cf5c 3729 (or org-agenda-multi (org-fit-agenda-window))
20908596
CD
3730 (unless (and (pos-visible-in-window-p (point-min))
3731 (pos-visible-in-window-p (point-max)))
3732 (goto-char (1- (point-max)))
3733 (recenter -1)
3734 (if (not (pos-visible-in-window-p (or start-pos 1)))
3735 (progn
3736 (goto-char (or start-pos 1))
3737 (recenter 1))))
3738 (goto-char (or start-pos 1))
3739 (add-text-properties (point-min) (point-max) '(org-agenda-type agenda))
3ab2c837
BG
3740 (if (eq org-agenda-show-log 'clockcheck)
3741 (org-agenda-show-clocking-issues))
20908596
CD
3742 (org-finalize-agenda)
3743 (setq buffer-read-only t)
3744 (message "")))
3745
3746(defun org-agenda-ndays-to-span (n)
acedf35c
CD
3747 "Return a span symbol for a span of N days, or N if none matches."
3748 (cond ((symbolp n) n)
3749 ((= n 1) 'day)
3750 ((= n 7) 'week)
3751 (t n)))
3752
3753(defun org-agenda-span-to-ndays (span start-day)
3754 "Return ndays from SPAN starting at START-DAY."
3755 (cond ((numberp span) span)
3756 ((eq span 'day) 1)
3757 ((eq span 'week) 7)
3758 ((eq span 'month)
3759 (let ((date (calendar-gregorian-from-absolute start-day)))
3760 (calendar-last-day-of-month (car date) (caddr date))))
3761 ((eq span 'year)
3762 (let ((date (calendar-gregorian-from-absolute start-day)))
3763 (if (calendar-leap-year-p (caddr date)) 366 365)))))
3764
3765(defun org-agenda-span-name (span)
3766 "Return a SPAN name."
3767 (if (null span)
3768 ""
3769 (if (symbolp span)
3770 (capitalize (symbol-name span))
3771 (format "%d days" span))))
20908596
CD
3772
3773;;; Agenda word search
3774
3775(defvar org-agenda-search-history nil)
3776(defvar org-todo-only nil)
3777
3778(defvar org-search-syntax-table nil
e66ba1df
BG
3779 "Special syntax table for org-mode search.
3780In this table, we have single quotes not as word constituents, to
3781that when \"+Ameli\" is searched as a work, it will also match \"Ameli's\"")
20908596
CD
3782
3783(defun org-search-syntax-table ()
3784 (unless org-search-syntax-table
3785 (setq org-search-syntax-table (copy-syntax-table org-mode-syntax-table))
3786 (modify-syntax-entry ?' "." org-search-syntax-table)
3787 (modify-syntax-entry ?` "." org-search-syntax-table))
3788 org-search-syntax-table)
3789
ed21c5c8
CD
3790(defvar org-agenda-last-search-view-search-was-boolean nil)
3791
20908596
CD
3792;;;###autoload
3793(defun org-search-view (&optional todo-only string edit-at)
ed21c5c8 3794 "Show all entries that contain a phrase or words or regular expressions.
20908596
CD
3795
3796With optional prefix argument TODO-ONLY, only consider entries that are
3797TODO entries. The argument STRING can be used to pass a default search
3798string into this function. If EDIT-AT is non-nil, it means that the
3799user should get a chance to edit this string, with cursor at position
3800EDIT-AT.
3801
ed21c5c8
CD
3802The search string can be viewed either as a phrase that should be found as
3803is, or it can be broken into a number of snippets, each of which must match
3804in a Boolean way to select an entry. The default depends on the variable
3805`org-agenda-search-view-always-boolean'.
3806Even if this is turned off (the default) you can always switch to
86fbb8ca 3807Boolean search dynamically by preceding the first word with \"+\" or \"-\".
ed21c5c8
CD
3808
3809The default is a direct search of the whole phrase, where each space in
3810the search string can expand to an arbitrary amount of whitespace,
3811including newlines.
3812
3813If using a Boolean search, the search string is split on whitespace and
3814each snippet is searched separately, with logical AND to select an entry.
3815Words prefixed with a minus must *not* occur in the entry. Words without
3816a prefix or prefixed with a plus must occur in the entry. Matching is
3817case-insensitive. Words are enclosed by word delimiters (i.e. they must
3818match whole words, not parts of a word) if
3819`org-agenda-search-view-force-full-words' is set (default is nil).
3820
3821Boolean search snippets enclosed by curly braces are interpreted as
86fbb8ca 3822regular expressions that must or (when preceded with \"-\") must not
ed21c5c8 3823match in the entry. Snippets enclosed into double quotes will be taken
86fbb8ca 3824as a whole, to include whitespace.
ed21c5c8
CD
3825
3826- If the search string starts with an asterisk, search only in headlines.
3827- If (possibly after the leading star) the search string starts with an
3828 exclamation mark, this also means to look at TODO entries only, an effect
3829 that can also be achieved with a prefix argument.
3830- If (possibly after star and exclamation mark) the search string starts
3831 with a colon, this will mean that the (non-regexp) snippets of the
3832 Boolean search must match as full words.
20908596
CD
3833
3834This command searches the agenda files, and in addition the files listed
3835in `org-agenda-text-search-extra-files'."
3836 (interactive "P")
3837 (org-compile-prefix-format 'search)
3838 (org-set-sorting-strategy 'search)
3839 (org-prepare-agenda "SEARCH")
3840 (let* ((props (list 'face nil
c8d0cf5c 3841 'done-face 'org-agenda-done
20908596
CD
3842 'org-not-done-regexp org-not-done-regexp
3843 'org-todo-regexp org-todo-regexp
b349f79f 3844 'org-complex-heading-regexp org-complex-heading-regexp
20908596 3845 'mouse-face 'highlight
20908596 3846 'help-echo (format "mouse-2 or RET jump to location")))
ed21c5c8 3847 (full-words org-agenda-search-view-force-full-words)
86fbb8ca 3848 (org-agenda-text-search-extra-files org-agenda-text-search-extra-files)
20908596 3849 regexp rtn rtnall files file pos
e66ba1df 3850 marker category org-category-pos tags c neg re boolean
20908596
CD
3851 ee txt beg end words regexps+ regexps- hdl-only buffer beg1 str)
3852 (unless (and (not edit-at)
3853 (stringp string)
3854 (string-match "\\S-" string))
ed21c5c8
CD
3855 (setq string (read-string
3856 (if org-agenda-search-view-always-boolean
3857 "[+-]Word/{Regexp} ...: "
3858 "Phrase, or [+-]Word/{Regexp} ...: ")
3859 (cond
3860 ((integerp edit-at) (cons string edit-at))
3861 (edit-at string))
3862 'org-agenda-search-history)))
20908596
CD
3863 (org-set-local 'org-todo-only todo-only)
3864 (setq org-agenda-redo-command
3865 (list 'org-search-view (if todo-only t nil) string
3866 '(if current-prefix-arg 1 nil)))
3867 (setq org-agenda-query-string string)
3868
3869 (if (equal (string-to-char string) ?*)
3870 (setq hdl-only t
3871 words (substring string 1))
3872 (setq words string))
3873 (when (equal (string-to-char words) ?!)
3874 (setq todo-only t
3875 words (substring words 1)))
ed21c5c8
CD
3876 (when (equal (string-to-char words) ?:)
3877 (setq full-words t
3878 words (substring words 1)))
3879 (if (or org-agenda-search-view-always-boolean
3880 (member (string-to-char words) '(?- ?+ ?\{)))
3881 (setq boolean t))
20908596 3882 (setq words (org-split-string words))
afe98dfa
CD
3883 (let (www w)
3884 (while (setq w (pop words))
3885 (while (and (string-match "\\\\\\'" w) words)
3886 (setq w (concat (substring w 0 -1) " " (pop words))))
3887 (push w www))
3888 (setq words (nreverse www) www nil)
3889 (while (setq w (pop words))
3890 (when (and (string-match "\\`[-+]?{" w)
3891 (not (string-match "}\\'" w)))
3892 (while (and words (not (string-match "}\\'" (car words))))
3893 (setq w (concat w " " (pop words))))
3894 (setq w (concat w " " (pop words))))
3895 (push w www))
3896 (setq words (nreverse www)))
ed21c5c8
CD
3897 (setq org-agenda-last-search-view-search-was-boolean boolean)
3898 (when boolean
3899 (let (wds w)
3900 (while (setq w (pop words))
3901 (if (or (equal (substring w 0 1) "\"")
3902 (and (> (length w) 1)
3903 (member (substring w 0 1) '("+" "-"))
3904 (equal (substring w 1 2) "\"")))
3905 (while (and words (not (equal (substring w -1) "\"")))
3906 (setq w (concat w " " (pop words)))))
3907 (and (string-match "\\`\\([-+]?\\)\"" w)
3908 (setq w (replace-match "\\1" nil nil w)))
3909 (and (equal (substring w -1) "\"") (setq w (substring w 0 -1)))
3910 (push w wds))
3911 (setq words (nreverse wds))))
3912 (if boolean
8bfe682a
CD
3913 (mapc (lambda (w)
3914 (setq c (string-to-char w))
3915 (if (equal c ?-)
3916 (setq neg t w (substring w 1))
3917 (if (equal c ?+)
3918 (setq neg nil w (substring w 1))
ed21c5c8 3919 (setq neg nil)))
8bfe682a
CD
3920 (if (string-match "\\`{.*}\\'" w)
3921 (setq re (substring w 1 -1))
ed21c5c8
CD
3922 (if full-words
3923 (setq re (concat "\\<" (regexp-quote (downcase w)) "\\>"))
3924 (setq re (regexp-quote (downcase w)))))
8bfe682a
CD
3925 (if neg (push re regexps-) (push re regexps+)))
3926 words)
3927 (push (mapconcat (lambda (w) (regexp-quote w)) words "\\s-+")
3928 regexps+))
20908596
CD
3929 (setq regexps+ (sort regexps+ (lambda (a b) (> (length a) (length b)))))
3930 (if (not regexps+)
3ab2c837 3931 (setq regexp org-outline-regexp-bol)
20908596 3932 (setq regexp (pop regexps+))
e66ba1df 3933 (if hdl-only (setq regexp (concat org-outline-regexp-bol ".*?"
20908596 3934 regexp))))
2c3ad40d 3935 (setq files (org-agenda-files nil 'ifmode))
20908596
CD
3936 (when (eq (car org-agenda-text-search-extra-files) 'agenda-archives)
3937 (pop org-agenda-text-search-extra-files)
3938 (setq files (org-add-archive-files files)))
3939 (setq files (append files org-agenda-text-search-extra-files)
3940 rtnall nil)
3941 (while (setq file (pop files))
3942 (setq ee nil)
3943 (catch 'nextfile
3944 (org-check-agenda-file file)
3945 (setq buffer (if (file-exists-p file)
3946 (org-get-agenda-file-buffer file)
3947 (error "No such file %s" file)))
3948 (if (not buffer)
3949 ;; If file does not exist, make sure an error message is sent
3950 (setq rtn (list (format "ORG-AGENDA-ERROR: No such org-file %s"
3951 file))))
3952 (with-current-buffer buffer
3953 (with-syntax-table (org-search-syntax-table)
e66ba1df 3954 (unless (eq major-mode 'org-mode)
20908596
CD
3955 (error "Agenda file %s is not in `org-mode'" file))
3956 (let ((case-fold-search t))
3957 (save-excursion
3958 (save-restriction
3959 (if org-agenda-restrict
3960 (narrow-to-region org-agenda-restrict-begin
3961 org-agenda-restrict-end)
3962 (widen))
3963 (goto-char (point-min))
e66ba1df 3964 (unless (or (org-at-heading-p)
20908596
CD
3965 (outline-next-heading))
3966 (throw 'nextfile t))
3967 (goto-char (max (point-min) (1- (point))))
3968 (while (re-search-forward regexp nil t)
3969 (org-back-to-heading t)
3970 (skip-chars-forward "* ")
3971 (setq beg (point-at-bol)
3972 beg1 (point)
3973 end (progn (outline-next-heading) (point)))
3974 (catch :skip
3975 (goto-char beg)
3976 (org-agenda-skip)
3977 (setq str (buffer-substring-no-properties
3978 (point-at-bol)
3979 (if hdl-only (point-at-eol) end)))
3980 (mapc (lambda (wr) (when (string-match wr str)
3981 (goto-char (1- end))
3982 (throw :skip t)))
3983 regexps-)
3984 (mapc (lambda (wr) (unless (string-match wr str)
3985 (goto-char (1- end))
3986 (throw :skip t)))
3987 (if todo-only
3988 (cons (concat "^\*+[ \t]+" org-not-done-regexp)
3989 regexps+)
3990 regexps+))
3991 (goto-char beg)
3992 (setq marker (org-agenda-new-marker (point))
3993 category (org-get-category)
e66ba1df 3994 org-category-pos (get-text-property (point) 'org-category-position)
20908596 3995 tags (org-get-tags-at (point))
e66ba1df 3996 txt (org-agenda-format-item
20908596
CD
3997 ""
3998 (buffer-substring-no-properties
3999 beg1 (point-at-eol))
4000 category tags))
4001 (org-add-props txt props
4002 'org-marker marker 'org-hd-marker marker
4003 'org-todo-regexp org-todo-regexp
b349f79f 4004 'org-complex-heading-regexp org-complex-heading-regexp
20908596 4005 'priority 1000 'org-category category
e66ba1df 4006 'org-category-position org-category-pos
20908596
CD
4007 'type "search")
4008 (push txt ee)
4009 (goto-char (1- end))))))))))
4010 (setq rtn (nreverse ee))
4011 (setq rtnall (append rtnall rtn)))
4012 (if org-agenda-overriding-header
4013 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
4014 nil 'face 'org-agenda-structure) "\n")
4015 (insert "Search words: ")
4016 (add-text-properties (point-min) (1- (point))
4017 (list 'face 'org-agenda-structure))
4018 (setq pos (point))
4019 (insert string "\n")
4020 (add-text-properties pos (1- (point)) (list 'face 'org-warning))
4021 (setq pos (point))
4022 (unless org-agenda-multi
4023 (insert "Press `[', `]' to add/sub word, `{', `}' to add/sub regexp, `C-u r' to edit\n")
4024 (add-text-properties pos (1- (point))
4025 (list 'face 'org-agenda-structure))))
8d642074 4026 (org-agenda-mark-header-line (point-min))
20908596
CD
4027 (when rtnall
4028 (insert (org-finalize-agenda-entries rtnall) "\n"))
4029 (goto-char (point-min))
c8d0cf5c 4030 (or org-agenda-multi (org-fit-agenda-window))
20908596
CD
4031 (add-text-properties (point-min) (point-max) '(org-agenda-type search))
4032 (org-finalize-agenda)
4033 (setq buffer-read-only t)))
4034
4035;;; Agenda TODO list
4036
4037(defvar org-select-this-todo-keyword nil)
4038(defvar org-last-arg nil)
4039
4040;;;###autoload
4041(defun org-todo-list (arg)
86fbb8ca 4042 "Show all (not done) TODO entries from all agenda file in a single list.
20908596
CD
4043The prefix arg can be used to select a specific TODO keyword and limit
4044the list to these. When using \\[universal-argument], you will be prompted
4045for a keyword. A numeric prefix directly selects the Nth keyword in
4046`org-todo-keywords-1'."
4047 (interactive "P")
20908596
CD
4048 (org-compile-prefix-format 'todo)
4049 (org-set-sorting-strategy 'todo)
4050 (org-prepare-agenda "TODO")
ed21c5c8 4051 (if (and (stringp arg) (not (string-match "\\S-" arg))) (setq arg nil))
acedf35c 4052 (let* ((today (org-today))
20908596
CD
4053 (date (calendar-gregorian-from-absolute today))
4054 (kwds org-todo-keywords-for-agenda)
4055 (completion-ignore-case t)
4056 (org-select-this-todo-keyword
4057 (if (stringp arg) arg
4058 (and arg (integerp arg) (> arg 0)
4059 (nth (1- arg) kwds))))
4060 rtn rtnall files file pos)
4061 (when (equal arg '(4))
4062 (setq org-select-this-todo-keyword
54a0dee5 4063 (org-icompleting-read "Keyword (or KWD1|K2D2|...): "
20908596
CD
4064 (mapcar 'list kwds) nil nil)))
4065 (and (equal 0 arg) (setq org-select-this-todo-keyword nil))
4066 (org-set-local 'org-last-arg arg)
4067 (setq org-agenda-redo-command
4068 '(org-todo-list (or current-prefix-arg org-last-arg)))
2c3ad40d 4069 (setq files (org-agenda-files nil 'ifmode)
20908596
CD
4070 rtnall nil)
4071 (while (setq file (pop files))
4072 (catch 'nextfile
4073 (org-check-agenda-file file)
4074 (setq rtn (org-agenda-get-day-entries file date :todo))
4075 (setq rtnall (append rtnall rtn))))
4076 (if org-agenda-overriding-header
4077 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
4078 nil 'face 'org-agenda-structure) "\n")
4079 (insert "Global list of TODO items of type: ")
4080 (add-text-properties (point-min) (1- (point))
8d642074
CD
4081 (list 'face 'org-agenda-structure
4082 'short-heading
4083 (concat "ToDo: "
4084 (or org-select-this-todo-keyword "ALL"))))
4085 (org-agenda-mark-header-line (point-min))
20908596
CD
4086 (setq pos (point))
4087 (insert (or org-select-this-todo-keyword "ALL") "\n")
4088 (add-text-properties pos (1- (point)) (list 'face 'org-warning))
4089 (setq pos (point))
4090 (unless org-agenda-multi
4091 (insert "Available with `N r': (0)ALL")
4092 (let ((n 0) s)
4093 (mapc (lambda (x)
4094 (setq s (format "(%d)%s" (setq n (1+ n)) x))
4095 (if (> (+ (current-column) (string-width s) 1) (frame-width))
4096 (insert "\n "))
4097 (insert " " s))
4098 kwds))
4099 (insert "\n"))
4100 (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure)))
8d642074 4101 (org-agenda-mark-header-line (point-min))
20908596
CD
4102 (when rtnall
4103 (insert (org-finalize-agenda-entries rtnall) "\n"))
4104 (goto-char (point-min))
c8d0cf5c 4105 (or org-agenda-multi (org-fit-agenda-window))
20908596
CD
4106 (add-text-properties (point-min) (point-max) '(org-agenda-type todo))
4107 (org-finalize-agenda)
4108 (setq buffer-read-only t)))
4109
4110;;; Agenda tags match
4111
4112;;;###autoload
4113(defun org-tags-view (&optional todo-only match)
4114 "Show all headlines for all `org-agenda-files' matching a TAGS criterion.
4115The prefix arg TODO-ONLY limits the search to TODO entries."
4116 (interactive "P")
4117 (org-compile-prefix-format 'tags)
4118 (org-set-sorting-strategy 'tags)
4119 (let* ((org-tags-match-list-sublevels
c8d0cf5c 4120 org-tags-match-list-sublevels)
20908596
CD
4121 (completion-ignore-case t)
4122 rtn rtnall files file pos matcher
4123 buffer)
ed21c5c8
CD
4124 (when (and (stringp match) (not (string-match "\\S-" match)))
4125 (setq match nil))
20908596
CD
4126 (setq matcher (org-make-tags-matcher match)
4127 match (car matcher) matcher (cdr matcher))
4128 (org-prepare-agenda (concat "TAGS " match))
4129 (setq org-agenda-query-string match)
4130 (setq org-agenda-redo-command
4131 (list 'org-tags-view (list 'quote todo-only)
4132 (list 'if 'current-prefix-arg nil 'org-agenda-query-string)))
2c3ad40d 4133 (setq files (org-agenda-files nil 'ifmode)
20908596
CD
4134 rtnall nil)
4135 (while (setq file (pop files))
4136 (catch 'nextfile
4137 (org-check-agenda-file file)
4138 (setq buffer (if (file-exists-p file)
4139 (org-get-agenda-file-buffer file)
4140 (error "No such file %s" file)))
4141 (if (not buffer)
33306645 4142 ;; If file does not exist, error message to agenda
20908596
CD
4143 (setq rtn (list
4144 (format "ORG-AGENDA-ERROR: No such org-file %s" file))
4145 rtnall (append rtnall rtn))
4146 (with-current-buffer buffer
e66ba1df 4147 (unless (eq major-mode 'org-mode)
20908596
CD
4148 (error "Agenda file %s is not in `org-mode'" file))
4149 (save-excursion
4150 (save-restriction
4151 (if org-agenda-restrict
4152 (narrow-to-region org-agenda-restrict-begin
4153 org-agenda-restrict-end)
4154 (widen))
4155 (setq rtn (org-scan-tags 'agenda matcher todo-only))
4156 (setq rtnall (append rtnall rtn))))))))
4157 (if org-agenda-overriding-header
4158 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
4159 nil 'face 'org-agenda-structure) "\n")
4160 (insert "Headlines with TAGS match: ")
4161 (add-text-properties (point-min) (1- (point))
8d642074
CD
4162 (list 'face 'org-agenda-structure
4163 'short-heading
4164 (concat "Match: " match)))
20908596
CD
4165 (setq pos (point))
4166 (insert match "\n")
4167 (add-text-properties pos (1- (point)) (list 'face 'org-warning))
4168 (setq pos (point))
4169 (unless org-agenda-multi
4170 (insert "Press `C-u r' to search again with new search string\n"))
4171 (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure)))
8d642074 4172 (org-agenda-mark-header-line (point-min))
20908596
CD
4173 (when rtnall
4174 (insert (org-finalize-agenda-entries rtnall) "\n"))
4175 (goto-char (point-min))
c8d0cf5c 4176 (or org-agenda-multi (org-fit-agenda-window))
20908596
CD
4177 (add-text-properties (point-min) (point-max) '(org-agenda-type tags))
4178 (org-finalize-agenda)
4179 (setq buffer-read-only t)))
4180
4181;;; Agenda Finding stuck projects
4182
4183(defvar org-agenda-skip-regexp nil
4184 "Regular expression used in skipping subtrees for the agenda.
4185This is basically a temporary global variable that can be set and then
4186used by user-defined selections using `org-agenda-skip-function'.")
4187
4188(defvar org-agenda-overriding-header nil
3ab2c837 4189 "When set during agenda, todo and tags searches it replaces the header.
c8d0cf5c
CD
4190This variable should not be set directly, but custom commands can bind it
4191in the options section.")
4192
4193(defun org-agenda-skip-entry-when-regexp-matches ()
86fbb8ca 4194 "Check if the current entry contains match for `org-agenda-skip-regexp'.
c8d0cf5c
CD
4195If yes, it returns the end position of this entry, causing agenda commands
4196to skip the entry but continuing the search in the subtree. This is a
4197function that can be put into `org-agenda-skip-function' for the duration
4198of a command."
4199 (let ((end (save-excursion (org-end-of-subtree t)))
4200 skip)
4201 (save-excursion
4202 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
4203 (and skip end)))
20908596
CD
4204
4205(defun org-agenda-skip-subtree-when-regexp-matches ()
86fbb8ca 4206 "Check if the current subtree contains match for `org-agenda-skip-regexp'.
20908596
CD
4207If yes, it returns the end position of this tree, causing agenda commands
4208to skip this subtree. This is a function that can be put into
4209`org-agenda-skip-function' for the duration of a command."
4210 (let ((end (save-excursion (org-end-of-subtree t)))
4211 skip)
4212 (save-excursion
4213 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
4214 (and skip end)))
4215
c8d0cf5c 4216(defun org-agenda-skip-entry-when-regexp-matches-in-subtree ()
86fbb8ca 4217 "Check if the current subtree contains match for `org-agenda-skip-regexp'.
c8d0cf5c
CD
4218If yes, it returns the end position of the current entry (NOT the tree),
4219causing agenda commands to skip the entry but continuing the search in
4220the subtree. This is a function that can be put into
4221`org-agenda-skip-function' for the duration of a command. An important
4222use of this function is for the stuck project list."
4223 (let ((end (save-excursion (org-end-of-subtree t)))
4224 (entry-end (save-excursion (outline-next-heading) (1- (point))))
4225 skip)
4226 (save-excursion
4227 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
4228 (and skip entry-end)))
4229
20908596
CD
4230(defun org-agenda-skip-entry-if (&rest conditions)
4231 "Skip entry if any of CONDITIONS is true.
4232See `org-agenda-skip-if' for details."
4233 (org-agenda-skip-if nil conditions))
4234
4235(defun org-agenda-skip-subtree-if (&rest conditions)
4236 "Skip entry if any of CONDITIONS is true.
4237See `org-agenda-skip-if' for details."
4238 (org-agenda-skip-if t conditions))
4239
4240(defun org-agenda-skip-if (subtree conditions)
4241 "Checks current entity for CONDITIONS.
4242If SUBTREE is non-nil, the entire subtree is checked. Otherwise, only
153ae947 4243the entry (i.e. the text before the next heading) is checked.
20908596
CD
4244
4245CONDITIONS is a list of symbols, boolean OR is used to combine the results
4246from different tests. Valid conditions are:
4247
4248scheduled Check if there is a scheduled cookie
4249notscheduled Check if there is no scheduled cookie
4250deadline Check if there is a deadline
4251notdeadline Check if there is no deadline
c8d0cf5c
CD
4252timestamp Check if there is a timestamp (also deadline or scheduled)
4253nottimestamp Check if there is no timestamp (also deadline or scheduled)
20908596
CD
4254regexp Check if regexp matches
4255notregexp Check if regexp does not match.
ed21c5c8
CD
4256todo Check if TODO keyword matches
4257nottodo Check if TODO keyword does not match
20908596
CD
4258
4259The regexp is taken from the conditions list, it must come right after
4260the `regexp' or `notregexp' element.
4261
ed21c5c8
CD
4262`todo' and `nottodo' accept as an argument a list of todo
4263keywords, which may include \"*\" to match any todo keyword.
4264
4265 (org-agenda-skip-entry-if 'todo '(\"TODO\" \"WAITING\"))
4266
4267would skip all entries with \"TODO\" or \"WAITING\" keywords.
4268
153ae947 4269Instead of a list, a keyword class may be given. For example:
ed21c5c8
CD
4270
4271 (org-agenda-skip-entry-if 'nottodo 'done)
4272
4273would skip entries that haven't been marked with any of \"DONE\"
153ae947 4274keywords. Possible classes are: `todo', `done', `any'.
ed21c5c8 4275
20908596
CD
4276If any of these conditions is met, this function returns the end point of
4277the entity, causing the search to continue from there. This is a function
4278that can be put into `org-agenda-skip-function' for the duration of a command."
4279 (let (beg end m)
4280 (org-back-to-heading t)
4281 (setq beg (point)
4282 end (if subtree
4283 (progn (org-end-of-subtree t) (point))
4284 (progn (outline-next-heading) (1- (point)))))
4285 (goto-char beg)
4286 (and
4287 (or
4288 (and (memq 'scheduled conditions)
4289 (re-search-forward org-scheduled-time-regexp end t))
4290 (and (memq 'notscheduled conditions)
4291 (not (re-search-forward org-scheduled-time-regexp end t)))
4292 (and (memq 'deadline conditions)
4293 (re-search-forward org-deadline-time-regexp end t))
4294 (and (memq 'notdeadline conditions)
4295 (not (re-search-forward org-deadline-time-regexp end t)))
c8d0cf5c
CD
4296 (and (memq 'timestamp conditions)
4297 (re-search-forward org-ts-regexp end t))
4298 (and (memq 'nottimestamp conditions)
4299 (not (re-search-forward org-ts-regexp end t)))
20908596
CD
4300 (and (setq m (memq 'regexp conditions))
4301 (stringp (nth 1 m))
4302 (re-search-forward (nth 1 m) end t))
4303 (and (setq m (memq 'notregexp conditions))
4304 (stringp (nth 1 m))
ed21c5c8
CD
4305 (not (re-search-forward (nth 1 m) end t)))
4306 (and (or
153ae947
BG
4307 (setq m (memq 'nottodo conditions))
4308 (setq m (memq 'todo conditions)))
ed21c5c8 4309 (org-agenda-skip-if-todo m end)))
20908596
CD
4310 end)))
4311
ed21c5c8
CD
4312(defun org-agenda-skip-if-todo (args end)
4313 "Helper function for `org-agenda-skip-if', do not use it directly.
4314ARGS is a list with first element either `todo' or `nottodo'.
4315The remainder is either a list of TODO keywords, or a state symbol
4316`todo' or `done' or `any'."
4317 (let ((kw (car args))
4318 (arg (cadr args))
4319 todo-wds todo-re)
4320 (setq todo-wds
4321 (org-uniquify
4322 (cond
4323 ((listp arg) ;; list of keywords
4324 (if (member "*" arg)
4325 (mapcar 'substring-no-properties org-todo-keywords-1)
4326 arg))
4327 ((symbolp arg) ;; keyword class name
4328 (cond
4329 ((eq arg 'todo)
4330 (org-delete-all org-done-keywords
4331 (mapcar 'substring-no-properties
4332 org-todo-keywords-1)))
4333 ((eq arg 'done) org-done-keywords)
4334 ((eq arg 'any)
4335 (mapcar 'substring-no-properties org-todo-keywords-1)))))))
4336 (setq todo-re
4337 (concat "^\\*+[ \t]+\\<\\("
4338 (mapconcat 'identity todo-wds "\\|")
4339 "\\)\\>"))
4340 (if (eq kw 'todo)
4341 (re-search-forward todo-re end t)
4342 (not (re-search-forward todo-re end t)))))
4343
20908596
CD
4344;;;###autoload
4345(defun org-agenda-list-stuck-projects (&rest ignore)
4346 "Create agenda view for projects that are stuck.
4347Stuck projects are project that have no next actions. For the definitions
4348of what a project is and how to check if it stuck, customize the variable
afe98dfa 4349`org-stuck-projects'."
20908596 4350 (interactive)
c8d0cf5c
CD
4351 (let* ((org-agenda-skip-function
4352 'org-agenda-skip-entry-when-regexp-matches-in-subtree)
20908596 4353 ;; We could have used org-agenda-skip-if here.
c8d0cf5c
CD
4354 (org-agenda-overriding-header
4355 (or org-agenda-overriding-header "List of stuck projects: "))
20908596
CD
4356 (matcher (nth 0 org-stuck-projects))
4357 (todo (nth 1 org-stuck-projects))
4358 (todo-wds (if (member "*" todo)
4359 (progn
2c3ad40d
CD
4360 (org-prepare-agenda-buffers (org-agenda-files
4361 nil 'ifmode))
20908596
CD
4362 (org-delete-all
4363 org-done-keywords-for-agenda
4364 (copy-sequence org-todo-keywords-for-agenda)))
4365 todo))
4366 (todo-re (concat "^\\*+[ \t]+\\("
4367 (mapconcat 'identity todo-wds "\\|")
4368 "\\)\\>"))
4369 (tags (nth 2 org-stuck-projects))
4370 (tags-re (if (member "*" tags)
e66ba1df
BG
4371 (concat org-outline-regexp-bol
4372 (org-re ".*:[[:alnum:]_@#%]+:[ \t]*$"))
c8d0cf5c 4373 (if tags
3ab2c837
BG
4374 (concat org-outline-regexp-bol
4375 ".*:\\("
c8d0cf5c 4376 (mapconcat 'identity tags "\\|")
afe98dfa 4377 (org-re "\\):[[:alnum:]_@#%:]*[ \t]*$")))))
20908596
CD
4378 (gen-re (nth 3 org-stuck-projects))
4379 (re-list
4380 (delq nil
4381 (list
4382 (if todo todo-re)
4383 (if tags tags-re)
4384 (and gen-re (stringp gen-re) (string-match "\\S-" gen-re)
4385 gen-re)))))
4386 (setq org-agenda-skip-regexp
4387 (if re-list
4388 (mapconcat 'identity re-list "\\|")
4389 (error "No information how to identify unstuck projects")))
4390 (org-tags-view nil matcher)
4391 (with-current-buffer org-agenda-buffer-name
4392 (setq org-agenda-redo-command
4393 '(org-agenda-list-stuck-projects
4394 (or current-prefix-arg org-last-arg))))))
4395
4396;;; Diary integration
4397
4398(defvar org-disable-agenda-to-diary nil) ;Dynamically-scoped param.
153ae947 4399(defvar list-diary-entries-hook)
3ab2c837 4400(defvar diary-time-regexp)
20908596
CD
4401(defun org-get-entries-from-diary (date)
4402 "Get the (Emacs Calendar) diary entries for DATE."
4403 (require 'diary-lib)
4404 (let* ((diary-fancy-buffer "*temporary-fancy-diary-buffer*")
20908596 4405 (diary-display-hook '(fancy-diary-display))
ca8ef0dc 4406 (diary-display-function 'fancy-diary-display)
20908596 4407 (pop-up-frames nil)
153ae947
BG
4408 (list-diary-entries-hook
4409 (cons 'org-diary-default-entry list-diary-entries-hook))
20908596
CD
4410 (diary-file-name-prefix-function nil) ; turn this feature off
4411 (diary-modify-entry-list-string-function 'org-modify-diary-entry-string)
4412 entries
4413 (org-disable-agenda-to-diary t))
4414 (save-excursion
4415 (save-window-excursion
4416 (funcall (if (fboundp 'diary-list-entries)
4417 'diary-list-entries 'list-diary-entries)
4418 date 1)))
4419 (if (not (get-buffer diary-fancy-buffer))
4420 (setq entries nil)
4421 (with-current-buffer diary-fancy-buffer
4422 (setq buffer-read-only nil)
4423 (if (zerop (buffer-size))
4424 ;; No entries
4425 (setq entries nil)
4426 ;; Omit the date and other unnecessary stuff
4427 (org-agenda-cleanup-fancy-diary)
4428 ;; Add prefix to each line and extend the text properties
4429 (if (zerop (buffer-size))
4430 (setq entries nil)
3ab2c837
BG
4431 (setq entries (buffer-substring (point-min) (- (point-max) 1)))
4432 (setq entries
4433 (with-temp-buffer
4434 (insert entries) (goto-char (point-min))
4435 (while (re-search-forward "\n[ \t]+\\(.+\\)$" nil t)
4436 (unless (save-match-data (string-match diary-time-regexp (match-string 1)))
4437 (replace-match (concat "; " (match-string 1)))))
4438 (buffer-string)))))
20908596
CD
4439 (set-buffer-modified-p nil)
4440 (kill-buffer diary-fancy-buffer)))
4441 (when entries
4442 (setq entries (org-split-string entries "\n"))
4443 (setq entries
4444 (mapcar
4445 (lambda (x)
e66ba1df 4446 (setq x (org-agenda-format-item "" x "Diary" nil 'time))
20908596
CD
4447 ;; Extend the text properties to the beginning of the line
4448 (org-add-props x (text-properties-at (1- (length x)) x)
ed21c5c8 4449 'type "diary" 'date date 'face 'org-agenda-diary))
20908596
CD
4450 entries)))))
4451
c8d0cf5c
CD
4452(defvar org-agenda-cleanup-fancy-diary-hook nil
4453 "Hook run when the fancy diary buffer is cleaned up.")
4454
20908596
CD
4455(defun org-agenda-cleanup-fancy-diary ()
4456 "Remove unwanted stuff in buffer created by `fancy-diary-display'.
4457This gets rid of the date, the underline under the date, and
4458the dummy entry installed by `org-mode' to ensure non-empty diary for each
4459date. It also removes lines that contain only whitespace."
4460 (goto-char (point-min))
4461 (if (looking-at ".*?:[ \t]*")
4462 (progn
4463 (replace-match "")
4464 (re-search-forward "\n=+$" nil t)
4465 (replace-match "")
4466 (while (re-search-backward "^ +\n?" nil t) (replace-match "")))
4467 (re-search-forward "\n=+$" nil t)
4468 (delete-region (point-min) (min (point-max) (1+ (match-end 0)))))
4469 (goto-char (point-min))
4470 (while (re-search-forward "^ +\n" nil t)
4471 (replace-match ""))
4472 (goto-char (point-min))
4473 (if (re-search-forward "^Org-mode dummy\n?" nil t)
c8d0cf5c
CD
4474 (replace-match ""))
4475 (run-hooks 'org-agenda-cleanup-fancy-diary-hook))
20908596
CD
4476
4477;; Make sure entries from the diary have the right text properties.
4478(eval-after-load "diary-lib"
4479 '(if (boundp 'diary-modify-entry-list-string-function)
4480 ;; We can rely on the hook, nothing to do
4481 nil
33306645 4482 ;; Hook not available, must use advice to make this work
20908596
CD
4483 (defadvice add-to-diary-list (before org-mark-diary-entry activate)
4484 "Make the position visible."
4485 (if (and org-disable-agenda-to-diary ;; called from org-agenda
4486 (stringp string)
4487 buffer-file-name)
4488 (setq string (org-modify-diary-entry-string string))))))
4489
4490(defun org-modify-diary-entry-string (string)
e66ba1df 4491 "Add text properties to string, allowing org-mode to act on it."
20908596
CD
4492 (org-add-props string nil
4493 'mouse-face 'highlight
20908596
CD
4494 'help-echo (if buffer-file-name
4495 (format "mouse-2 or RET jump to diary file %s"
4496 (abbreviate-file-name buffer-file-name))
4497 "")
4498 'org-agenda-diary-link t
4499 'org-marker (org-agenda-new-marker (point-at-bol))))
4500
4501(defun org-diary-default-entry ()
4502 "Add a dummy entry to the diary.
4503Needed to avoid empty dates which mess up holiday display."
4504 ;; Catch the error if dealing with the new add-to-diary-alist
4505 (when org-disable-agenda-to-diary
4506 (condition-case nil
4507 (org-add-to-diary-list original-date "Org-mode dummy" "")
4508 (error
4509 (org-add-to-diary-list original-date "Org-mode dummy" "" nil)))))
4510
4511(defun org-add-to-diary-list (&rest args)
4512 (if (fboundp 'diary-add-to-list)
4513 (apply 'diary-add-to-list args)
4514 (apply 'add-to-diary-list args)))
4515
ed21c5c8
CD
4516(defvar org-diary-last-run-time nil)
4517
20908596
CD
4518;;;###autoload
4519(defun org-diary (&rest args)
4520 "Return diary information from org-files.
4521This function can be used in a \"sexp\" diary entry in the Emacs calendar.
4522It accesses org files and extracts information from those files to be
4523listed in the diary. The function accepts arguments specifying what
ed21c5c8
CD
4524items should be listed. For a list of arguments allowed here, see the
4525variable `org-agenda-entry-types'.
20908596
CD
4526
4527The call in the diary file should look like this:
4528
4529 &%%(org-diary) ~/path/to/some/orgfile.org
4530
4531Use a separate line for each org file to check. Or, if you omit the file name,
4532all files listed in `org-agenda-files' will be checked automatically:
4533
4534 &%%(org-diary)
4535
4536If you don't give any arguments (as in the example above), the default
4537arguments (:deadline :scheduled :timestamp :sexp) are used.
4538So the example above may also be written as
4539
4540 &%%(org-diary :deadline :timestamp :sexp :scheduled)
4541
4542The function expects the lisp variables `entry' and `date' to be provided
4543by the caller, because this is how the calendar works. Don't use this
4544function from a program - use `org-agenda-get-day-entries' instead."
54a0dee5 4545 (when (> (- (org-float-time)
20908596
CD
4546 org-agenda-last-marker-time)
4547 5)
4548 (org-agenda-reset-markers))
4549 (org-compile-prefix-format 'agenda)
4550 (org-set-sorting-strategy 'agenda)
4551 (setq args (or args '(:deadline :scheduled :timestamp :sexp)))
23f6720e
BG
4552 (let* ((files (if (and entry (stringp entry) (string-match "\\S-" entry))
4553 (list entry)
20908596 4554 (org-agenda-files t)))
ed21c5c8 4555 (time (org-float-time))
20908596 4556 file rtn results)
ed21c5c8
CD
4557 (when (or (not org-diary-last-run-time)
4558 (> (- time
4559 org-diary-last-run-time)
4560 3))
4561 (org-prepare-agenda-buffers files))
4562 (setq org-diary-last-run-time time)
20908596
CD
4563 ;; If this is called during org-agenda, don't return any entries to
4564 ;; the calendar. Org Agenda will list these entries itself.
4565 (if org-disable-agenda-to-diary (setq files nil))
4566 (while (setq file (pop files))
4567 (setq rtn (apply 'org-agenda-get-day-entries file date args))
4568 (setq results (append results rtn)))
4569 (if results
4570 (concat (org-finalize-agenda-entries results) "\n"))))
4571
4572;;; Agenda entry finders
4573
4574(defun org-agenda-get-day-entries (file date &rest args)
4575 "Does the work for `org-diary' and `org-agenda'.
4576FILE is the path to a file to be checked for entries. DATE is date like
4577the one returned by `calendar-current-date'. ARGS are symbols indicating
4578which kind of entries should be extracted. For details about these, see
4579the documentation of `org-diary'."
4580 (setq args (or args '(:deadline :scheduled :timestamp :sexp)))
4581 (let* ((org-startup-folded nil)
4582 (org-startup-align-all-tables nil)
4583 (buffer (if (file-exists-p file)
4584 (org-get-agenda-file-buffer file)
4585 (error "No such file %s" file)))
54a0dee5 4586 arg results rtn deadline-results)
20908596
CD
4587 (if (not buffer)
4588 ;; If file does not exist, make sure an error message ends up in diary
4589 (list (format "ORG-AGENDA-ERROR: No such org-file %s" file))
4590 (with-current-buffer buffer
e66ba1df 4591 (unless (eq major-mode 'org-mode)
20908596
CD
4592 (error "Agenda file %s is not in `org-mode'" file))
4593 (let ((case-fold-search nil))
4594 (save-excursion
4595 (save-restriction
4596 (if org-agenda-restrict
4597 (narrow-to-region org-agenda-restrict-begin
4598 org-agenda-restrict-end)
4599 (widen))
4600 ;; The way we repeatedly append to `results' makes it O(n^2) :-(
4601 (while (setq arg (pop args))
4602 (cond
4603 ((and (eq arg :todo)
3ab2c837
BG
4604 (equal date (calendar-gregorian-from-absolute
4605 (org-today))))
20908596
CD
4606 (setq rtn (org-agenda-get-todos))
4607 (setq results (append results rtn)))
4608 ((eq arg :timestamp)
4609 (setq rtn (org-agenda-get-blocks))
4610 (setq results (append results rtn))
4611 (setq rtn (org-agenda-get-timestamps))
4612 (setq results (append results rtn)))
4613 ((eq arg :sexp)
4614 (setq rtn (org-agenda-get-sexps))
4615 (setq results (append results rtn)))
4616 ((eq arg :scheduled)
54a0dee5 4617 (setq rtn (org-agenda-get-scheduled deadline-results))
20908596
CD
4618 (setq results (append results rtn)))
4619 ((eq arg :closed)
93b62de8 4620 (setq rtn (org-agenda-get-progress))
20908596
CD
4621 (setq results (append results rtn)))
4622 ((eq arg :deadline)
4623 (setq rtn (org-agenda-get-deadlines))
54a0dee5 4624 (setq deadline-results (copy-sequence rtn))
20908596
CD
4625 (setq results (append results rtn))))))))
4626 results))))
4627
e66ba1df 4628(defvar org-heading-keyword-regexp-format) ; defined in org.el
20908596
CD
4629(defun org-agenda-get-todos ()
4630 "Return the TODO information for agenda display."
4631 (let* ((props (list 'face nil
c8d0cf5c 4632 'done-face 'org-agenda-done
20908596
CD
4633 'org-not-done-regexp org-not-done-regexp
4634 'org-todo-regexp org-todo-regexp
b349f79f 4635 'org-complex-heading-regexp org-complex-heading-regexp
20908596 4636 'mouse-face 'highlight
20908596
CD
4637 'help-echo
4638 (format "mouse-2 or RET jump to org file %s"
4639 (abbreviate-file-name buffer-file-name))))
e66ba1df
BG
4640 (regexp (format org-heading-keyword-regexp-format
4641 (cond
4642 ((and org-select-this-todo-keyword
4643 (equal org-select-this-todo-keyword "*"))
4644 org-todo-regexp)
4645 (org-select-this-todo-keyword
4646 (concat "\\("
4647 (mapconcat 'identity
4648 (org-split-string
4649 org-select-this-todo-keyword
4650 "|")
4651 "\\|") "\\)"))
4652 (t org-not-done-regexp))))
4653 marker priority category org-category-pos tags todo-state
20908596
CD
4654 ee txt beg end)
4655 (goto-char (point-min))
4656 (while (re-search-forward regexp nil t)
4657 (catch :skip
4658 (save-match-data
4659 (beginning-of-line)
3ab2c837 4660 (org-agenda-skip)
d6685abc 4661 (setq beg (point) end (save-excursion (outline-next-heading) (point)))
0bd48b37 4662 (when (org-agenda-check-for-timestamp-as-reason-to-ignore-todo-item end)
20908596
CD
4663 (goto-char (1+ beg))
4664 (or org-agenda-todo-list-sublevels (org-end-of-subtree 'invisible))
4665 (throw :skip nil)))
e66ba1df 4666 (goto-char (match-beginning 2))
20908596
CD
4667 (setq marker (org-agenda-new-marker (match-beginning 0))
4668 category (org-get-category)
e66ba1df
BG
4669 org-category-pos (get-text-property (point) 'org-category-position)
4670 txt (org-trim
4671 (buffer-substring (match-beginning 2) (match-end 0)))
20908596 4672 tags (org-get-tags-at (point))
e66ba1df 4673 txt (org-agenda-format-item "" txt category tags)
621f83e4
CD
4674 priority (1+ (org-get-priority txt))
4675 todo-state (org-get-todo-state))
20908596
CD
4676 (org-add-props txt props
4677 'org-marker marker 'org-hd-marker marker
4678 'priority priority 'org-category category
e66ba1df 4679 'org-category-position org-category-pos
621f83e4 4680 'type "todo" 'todo-state todo-state)
20908596
CD
4681 (push txt ee)
4682 (if org-agenda-todo-list-sublevels
e66ba1df 4683 (goto-char (match-end 2))
20908596
CD
4684 (org-end-of-subtree 'invisible))))
4685 (nreverse ee)))
4686
3ab2c837
BG
4687(defun org-agenda-todo-custom-ignore-p (time n)
4688 "Check whether timestamp is farther away then n number of days.
4689This function is invoked if `org-agenda-todo-ignore-deadlines',
4690`org-agenda-todo-ignore-scheduled' or
4691`org-agenda-todo-ignore-timestamp' is set to an integer."
4692 (let ((days (org-days-to-time time)))
4693 (if (>= n 0)
4694 (>= days n)
4695 (<= days n))))
4696
0bd48b37 4697;;;###autoload
ed21c5c8
CD
4698(defun org-agenda-check-for-timestamp-as-reason-to-ignore-todo-item
4699 (&optional end)
4700 "Do we have a reason to ignore this TODO entry because it has a time stamp?"
0bd48b37
CD
4701 (when (or org-agenda-todo-ignore-with-date
4702 org-agenda-todo-ignore-scheduled
acedf35c
CD
4703 org-agenda-todo-ignore-deadlines
4704 org-agenda-todo-ignore-timestamp)
0bd48b37
CD
4705 (setq end (or end (save-excursion (outline-next-heading) (point))))
4706 (save-excursion
4707 (or (and org-agenda-todo-ignore-with-date
4708 (re-search-forward org-ts-regexp end t))
4709 (and org-agenda-todo-ignore-scheduled
ed21c5c8
CD
4710 (re-search-forward org-scheduled-time-regexp end t)
4711 (cond
4712 ((eq org-agenda-todo-ignore-scheduled 'future)
4713 (> (org-days-to-time (match-string 1)) 0))
4714 ((eq org-agenda-todo-ignore-scheduled 'past)
4715 (<= (org-days-to-time (match-string 1)) 0))
3ab2c837
BG
4716 ((numberp org-agenda-todo-ignore-scheduled)
4717 (org-agenda-todo-custom-ignore-p
4718 (match-string 1) org-agenda-todo-ignore-scheduled))
ed21c5c8 4719 (t)))
0bd48b37
CD
4720 (and org-agenda-todo-ignore-deadlines
4721 (re-search-forward org-deadline-time-regexp end t)
ed21c5c8
CD
4722 (cond
4723 ((memq org-agenda-todo-ignore-deadlines '(t all)) t)
4724 ((eq org-agenda-todo-ignore-deadlines 'far)
4725 (not (org-deadline-close (match-string 1))))
4726 ((eq org-agenda-todo-ignore-deadlines 'future)
4727 (> (org-days-to-time (match-string 1)) 0))
4728 ((eq org-agenda-todo-ignore-deadlines 'past)
4729 (<= (org-days-to-time (match-string 1)) 0))
3ab2c837
BG
4730 ((numberp org-agenda-todo-ignore-deadlines)
4731 (org-agenda-todo-custom-ignore-p
4732 (match-string 1) org-agenda-todo-ignore-deadlines))
acedf35c
CD
4733 (t (org-deadline-close (match-string 1)))))
4734 (and org-agenda-todo-ignore-timestamp
4735 (let ((buffer (current-buffer))
4736 (regexp
4737 (concat
4738 org-scheduled-time-regexp "\\|" org-deadline-time-regexp))
4739 (start (point)))
4740 ;; Copy current buffer into a temporary one
4741 (with-temp-buffer
4742 (insert-buffer-substring buffer start end)
4743 (goto-char (point-min))
4744 ;; Delete SCHEDULED and DEADLINE items
4745 (while (re-search-forward regexp end t)
4746 (delete-region (match-beginning 0) (match-end 0)))
4747 (goto-char (point-min))
4748 ;; No search for timestamp left
4749 (when (re-search-forward org-ts-regexp nil t)
4750 (cond
4751 ((eq org-agenda-todo-ignore-timestamp 'future)
4752 (> (org-days-to-time (match-string 1)) 0))
4753 ((eq org-agenda-todo-ignore-timestamp 'past)
4754 (<= (org-days-to-time (match-string 1)) 0))
3ab2c837
BG
4755 ((numberp org-agenda-todo-ignore-timestamp)
4756 (org-agenda-todo-custom-ignore-p
4757 (match-string 1) org-agenda-todo-ignore-timestamp))
acedf35c 4758 (t))))))))))
0bd48b37 4759
20908596
CD
4760(defconst org-agenda-no-heading-message
4761 "No heading for this item in buffer or region.")
4762
4763(defun org-agenda-get-timestamps ()
4764 "Return the date stamp information for agenda display."
e66ba1df 4765 (let* ((props (list 'face 'org-agenda-calendar-event
20908596
CD
4766 'org-not-done-regexp org-not-done-regexp
4767 'org-todo-regexp org-todo-regexp
b349f79f 4768 'org-complex-heading-regexp org-complex-heading-regexp
20908596 4769 'mouse-face 'highlight
20908596
CD
4770 'help-echo
4771 (format "mouse-2 or RET jump to org file %s"
4772 (abbreviate-file-name buffer-file-name))))
4773 (d1 (calendar-absolute-from-gregorian date))
4774 (remove-re
4775 (concat
4776 (regexp-quote
4777 (format-time-string
4778 "<%Y-%m-%d"
4779 (encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date))))
4780 ".*?>"))
4781 (regexp
4782 (concat
4783 (if org-agenda-include-inactive-timestamps "[[<]" "<")
4784 (regexp-quote
4785 (substring
4786 (format-time-string
4787 (car org-time-stamp-formats)
4788 (apply 'encode-time ; DATE bound by calendar
4789 (list 0 0 0 (nth 1 date) (car date) (nth 2 date))))
4790 1 11))
4791 "\\|\\(<[0-9]+-[0-9]+-[0-9]+[^>\n]+?\\+[0-9]+[dwmy]>\\)"
4792 "\\|\\(<%%\\(([^>\n]+)\\)>\\)"))
4793 marker hdmarker deadlinep scheduledp clockp closedp inactivep
e66ba1df
BG
4794 donep tmp priority category org-category-pos ee txt timestr tags
4795 b0 b3 e3 head todo-state end-of-match show-all)
20908596 4796 (goto-char (point-min))
c8d0cf5c 4797 (while (setq end-of-match (re-search-forward regexp nil t))
20908596 4798 (setq b0 (match-beginning 0)
3ab2c837
BG
4799 b3 (match-beginning 3) e3 (match-end 3)
4800 todo-state (save-match-data (ignore-errors (org-get-todo-state)))
4801 show-all (or (eq org-agenda-repeating-timestamp-show-all t)
4802 (member todo-state
4803 org-agenda-repeating-timestamp-show-all)))
20908596
CD
4804 (catch :skip
4805 (and (org-at-date-range-p) (throw :skip nil))
4806 (org-agenda-skip)
4807 (if (and (match-end 1)
4808 (not (= d1 (org-time-string-to-absolute
e66ba1df
BG
4809 (match-string 1) d1 nil show-all
4810 (current-buffer) b0))))
20908596
CD
4811 (throw :skip nil))
4812 (if (and e3
4813 (not (org-diary-sexp-entry (buffer-substring b3 e3) "" date)))
4814 (throw :skip nil))
c8d0cf5c 4815 (setq tmp (buffer-substring (max (point-min)
20908596
CD
4816 (- b0 org-ds-keyword-length))
4817 b0)
4818 timestr (if b3 "" (buffer-substring b0 (point-at-eol)))
4819 inactivep (= (char-after b0) ?\[)
4820 deadlinep (string-match org-deadline-regexp tmp)
4821 scheduledp (string-match org-scheduled-regexp tmp)
4822 closedp (and org-agenda-include-inactive-timestamps
4823 (string-match org-closed-string tmp))
4824 clockp (and org-agenda-include-inactive-timestamps
4825 (or (string-match org-clock-string tmp)
4826 (string-match "]-+\\'" tmp)))
621f83e4 4827 donep (member todo-state org-done-keywords))
c8d0cf5c
CD
4828 (if (or scheduledp deadlinep closedp clockp
4829 (and donep org-agenda-skip-timestamp-if-done))
20908596
CD
4830 (throw :skip t))
4831 (if (string-match ">" timestr)
4832 ;; substring should only run to end of time stamp
4833 (setq timestr (substring timestr 0 (match-end 0))))
c8d0cf5c 4834 (setq marker (org-agenda-new-marker b0)
e66ba1df
BG
4835 category (org-get-category b0)
4836 org-category-pos (get-text-property b0 'org-category-position))
20908596 4837 (save-excursion
3ab2c837 4838 (if (not (re-search-backward org-outline-regexp-bol nil t))
c8d0cf5c
CD
4839 (setq txt org-agenda-no-heading-message)
4840 (goto-char (match-beginning 0))
4841 (setq hdmarker (org-agenda-new-marker)
4842 tags (org-get-tags-at))
4843 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
3ab2c837 4844 (setq head (or (match-string 1) ""))
e66ba1df 4845 (setq txt (org-agenda-format-item
ed21c5c8 4846 (if inactivep org-agenda-inactive-leader nil)
3ab2c837 4847 head category tags timestr
c8d0cf5c 4848 remove-re)))
20908596
CD
4849 (setq priority (org-get-priority txt))
4850 (org-add-props txt props
4851 'org-marker marker 'org-hd-marker hdmarker)
4852 (org-add-props txt nil 'priority priority
4853 'org-category category 'date date
e66ba1df 4854 'org-category-position org-category-pos
621f83e4 4855 'todo-state todo-state
20908596
CD
4856 'type "timestamp")
4857 (push txt ee))
c8d0cf5c
CD
4858 (if org-agenda-skip-additional-timestamps-same-entry
4859 (outline-next-heading)
4860 (goto-char end-of-match))))
20908596
CD
4861 (nreverse ee)))
4862
4863(defun org-agenda-get-sexps ()
4864 "Return the sexp information for agenda display."
4865 (require 'diary-lib)
e66ba1df
BG
4866 (let* ((props (list 'face 'org-agenda-calendar-sexp
4867 'mouse-face 'highlight
20908596
CD
4868 'help-echo
4869 (format "mouse-2 or RET jump to org file %s"
4870 (abbreviate-file-name buffer-file-name))))
4871 (regexp "^&?%%(")
e66ba1df
BG
4872 marker category org-category-pos ee txt tags entry
4873 result beg b sexp sexp-entry todo-state)
20908596
CD
4874 (goto-char (point-min))
4875 (while (re-search-forward regexp nil t)
4876 (catch :skip
4877 (org-agenda-skip)
4878 (setq beg (match-beginning 0))
4879 (goto-char (1- (match-end 0)))
4880 (setq b (point))
4881 (forward-sexp 1)
4882 (setq sexp (buffer-substring b (point)))
4883 (setq sexp-entry (if (looking-at "[ \t]*\\(\\S-.*\\)")
4884 (org-trim (match-string 1))
4885 ""))
4886 (setq result (org-diary-sexp-entry sexp sexp-entry date))
4887 (when result
4888 (setq marker (org-agenda-new-marker beg)
c8d0cf5c 4889 category (org-get-category beg)
e66ba1df 4890 org-category-pos (get-text-property beg 'org-category-position)
c8d0cf5c 4891 todo-state (org-get-todo-state))
20908596 4892
afe98dfa
CD
4893 (dolist (r (if (stringp result)
4894 (list result)
4895 result)) ;; we expect a list here
4896 (if (string-match "\\S-" r)
4897 (setq txt r)
4898 (setq txt "SEXP entry returned empty string"))
4899
e66ba1df 4900 (setq txt (org-agenda-format-item
afe98dfa
CD
4901 "" txt category tags 'time))
4902 (org-add-props txt props 'org-marker marker)
4903 (org-add-props txt nil
4904 'org-category category 'date date 'todo-state todo-state
e66ba1df 4905 'org-category-position org-category-pos
afe98dfa
CD
4906 'type "sexp")
4907 (push txt ee)))))
20908596
CD
4908 (nreverse ee)))
4909
3ab2c837
BG
4910;; Calendar sanity: define some functions that are independent of
4911;; `calendar-date-style'.
4912;; Normally I would like to use ISO format when calling the diary functions,
4913;; but to make sure we still have Emacs 22 compatibility we bind
4914;; also `european-calendar-style' and use european format
4915(defun org-anniversary (year month day &optional mark)
4916 "Like `diary-anniversary', but with fixed (ISO) order of arguments."
4917 (org-no-warnings
4918 (let ((calendar-date-style 'european) (european-calendar-style t))
4919 (diary-anniversary day month year mark))))
4920(defun org-cyclic (N year month day &optional mark)
4921 "Like `diary-cyclic', but with fixed (ISO) order of arguments."
4922 (org-no-warnings
4923 (let ((calendar-date-style 'european) (european-calendar-style t))
4924 (diary-cyclic N day month year mark))))
4925(defun org-block (Y1 M1 D1 Y2 M2 D2 &optional mark)
4926 "Like `diary-block', but with fixed (ISO) order of arguments."
4927 (org-no-warnings
4928 (let ((calendar-date-style 'european) (european-calendar-style t))
4929 (diary-block D1 M1 Y1 D2 M2 Y2 mark))))
4930(defun org-date (year month day &optional mark)
4931 "Like `diary-date', but with fixed (ISO) order of arguments."
4932 (org-no-warnings
4933 (let ((calendar-date-style 'european) (european-calendar-style t))
4934 (diary-date day month year mark))))
4935(defalias 'org-float 'diary-float)
4936
4937;; Define the` org-class' function
4938(defun org-class (y1 m1 d1 y2 m2 d2 dayname &rest skip-weeks)
ed21c5c8 4939 "Entry applies if date is between dates on DAYNAME, but skips SKIP-WEEKS.
e66ba1df
BG
4940DAYNAME is a number between 0 (Sunday) and 6 (Saturday).
4941SKIP-WEEKS is any number of ISO weeks in the block period for which the
4942item should be skipped. If any of the SKIP-WEEKS arguments is the symbol
4943`holidays', then any date that is known by the Emacs calendar to be a
27e428e7 4944holiday will also be skipped."
3ab2c837
BG
4945 (let* ((date1 (calendar-absolute-from-gregorian (list m1 d1 y1)))
4946 (date2 (calendar-absolute-from-gregorian (list m2 d2 y2)))
ed21c5c8
CD
4947 (d (calendar-absolute-from-gregorian date)))
4948 (and
4949 (<= date1 d)
4950 (<= d date2)
4951 (= (calendar-day-of-week date) dayname)
4952 (or (not skip-weeks)
4953 (progn
4954 (require 'cal-iso)
4955 (not (member (car (calendar-iso-from-absolute d)) skip-weeks))))
e66ba1df
BG
4956 (not (and (memq 'holidays skip-weeks)
4957 (calendar-check-holidays date)))
23f6720e 4958 entry)))
ed21c5c8 4959
3ab2c837
BG
4960(defun org-diary-class (m1 d1 y1 m2 d2 y2 dayname &rest skip-weeks)
4961 "Like `org-class', but honor `calendar-date-style'.
4962The order of the first 2 times 3 arguments depends on the variable
4963`calendar-date-style' or, if that is not defined, on `european-calendar-style'.
4964So for American calendars, give this as MONTH DAY YEAR, for European as
4965DAY MONTH YEAR, and for ISO as YEAR MONTH DAY.
4966DAYNAME is a number between 0 (Sunday) and 6 (Saturday). SKIP-WEEKS
4967is any number of ISO weeks in the block period for which the item should
4968be skipped.
4969
4970This function is here only for backward compatibility and it is deprecated,
4971please use `org-class' instead."
4972 (let* ((date1 (org-order-calendar-date-args m1 d1 y1))
4973 (date2 (org-order-calendar-date-args m2 d2 y2)))
4974 (org-class
4975 (nth 2 date1) (car date1) (nth 1 date1)
4976 (nth 2 date2) (car date2) (nth 1 date2)
4977 dayname skip-weeks)))
e66ba1df 4978(make-obsolete 'org-diary-class 'org-class "")
3ab2c837 4979
d60b1ba1 4980(defalias 'org-get-closed 'org-agenda-get-progress)
93b62de8 4981(defun org-agenda-get-progress ()
20908596
CD
4982 "Return the logged TODO entries for agenda display."
4983 (let* ((props (list 'mouse-face 'highlight
4984 'org-not-done-regexp org-not-done-regexp
4985 'org-todo-regexp org-todo-regexp
b349f79f 4986 'org-complex-heading-regexp org-complex-heading-regexp
20908596
CD
4987 'help-echo
4988 (format "mouse-2 or RET jump to org file %s"
4989 (abbreviate-file-name buffer-file-name))))
93b62de8
CD
4990 (items (if (consp org-agenda-show-log)
4991 org-agenda-show-log
3ab2c837
BG
4992 (if (eq org-agenda-show-log 'clockcheck)
4993 '(clock)
4994 org-agenda-log-mode-items)))
ff4be292 4995 (parts
93b62de8
CD
4996 (delq nil
4997 (list
4998 (if (memq 'closed items) (concat "\\<" org-closed-string))
4999 (if (memq 'clock items) (concat "\\<" org-clock-string))
c8d0cf5c 5000 (if (memq 'state items) "- State \"\\([a-zA-Z0-9]+\\)\".*?"))))
93b62de8
CD
5001 (parts-re (if parts (mapconcat 'identity parts "\\|")
5002 (error "`org-agenda-log-mode-items' is empty")))
20908596 5003 (regexp (concat
93b62de8
CD
5004 "\\(" parts-re "\\)"
5005 " *\\["
20908596
CD
5006 (regexp-quote
5007 (substring
5008 (format-time-string
5009 (car org-time-stamp-formats)
5010 (apply 'encode-time ; DATE bound by calendar
5011 (list 0 0 0 (nth 1 date) (car date) (nth 2 date))))
5012 1 11))))
c8d0cf5c 5013 (org-agenda-search-headline-for-time nil)
e66ba1df
BG
5014 marker hdmarker priority category org-category-pos tags closedp
5015 statep clockp state ee txt extra timestr rest clocked)
20908596
CD
5016 (goto-char (point-min))
5017 (while (re-search-forward regexp nil t)
5018 (catch :skip
5019 (org-agenda-skip)
5020 (setq marker (org-agenda-new-marker (match-beginning 0))
5021 closedp (equal (match-string 1) org-closed-string)
93b62de8 5022 statep (equal (string-to-char (match-string 1)) ?-)
c8d0cf5c 5023 clockp (not (or closedp statep))
93b62de8 5024 state (and statep (match-string 2))
20908596 5025 category (org-get-category (match-beginning 0))
e66ba1df
BG
5026 org-category-pos (get-text-property (match-beginning 0) 'org-category-position)
5027 timestr (buffer-substring (match-beginning 0) (point-at-eol)))
b349f79f
CD
5028 (when (string-match "\\]" timestr)
5029 ;; substring should only run to end of time stamp
5030 (setq rest (substring timestr (match-end 0))
5031 timestr (substring timestr 0 (match-end 0)))
93b62de8 5032 (if (and (not closedp) (not statep)
e66ba1df
BG
5033 (string-match "\\([0-9]\\{1,2\\}:[0-9]\\{2\\}\\)\\].*?\\([0-9]\\{1,2\\}:[0-9]\\{2\\}\\)"
5034 rest))
621f83e4
CD
5035 (progn (setq timestr (concat (substring timestr 0 -1)
5036 "-" (match-string 1 rest) "]"))
5037 (setq clocked (match-string 2 rest)))
5038 (setq clocked "-")))
20908596 5039 (save-excursion
3ab2c837
BG
5040 (setq extra
5041 (cond
5042 ((not org-agenda-log-mode-add-notes) nil)
5043 (statep
5044 (and (looking-at ".*\\\\\n[ \t]*\\([^-\n \t].*?\\)[ \t]*$")
5045 (match-string 1)))
5046 (clockp
5047 (and (looking-at ".*\n[ \t]*-[ \t]+\\([^-\n \t].*?\\)[ \t]*$")
5048 (match-string 1)))))
5049 (if (not (re-search-backward org-outline-regexp-bol nil t))
c8d0cf5c
CD
5050 (setq txt org-agenda-no-heading-message)
5051 (goto-char (match-beginning 0))
5052 (setq hdmarker (org-agenda-new-marker)
5053 tags (org-get-tags-at))
5054 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
5055 (setq txt (match-string 1))
5056 (when extra
5057 (if (string-match "\\([ \t]+\\)\\(:[^ \n\t]*?:\\)[ \t]*$" txt)
5058 (setq txt (concat (substring txt 0 (match-beginning 1))
5059 " - " extra " " (match-string 2 txt)))
5060 (setq txt (concat txt " - " extra))))
e66ba1df 5061 (setq txt (org-agenda-format-item
c8d0cf5c
CD
5062 (cond
5063 (closedp "Closed: ")
93b62de8
CD
5064 (statep (concat "State: (" state ")"))
5065 (t (concat "Clocked: (" clocked ")")))
c8d0cf5c 5066 txt category tags timestr)))
20908596
CD
5067 (setq priority 100000)
5068 (org-add-props txt props
c8d0cf5c 5069 'org-marker marker 'org-hd-marker hdmarker 'face 'org-agenda-done
20908596 5070 'priority priority 'org-category category
e66ba1df 5071 'org-category-position org-category-pos
20908596 5072 'type "closed" 'date date
c8d0cf5c 5073 'undone-face 'org-warning 'done-face 'org-agenda-done)
20908596
CD
5074 (push txt ee))
5075 (goto-char (point-at-eol))))
5076 (nreverse ee)))
5077
3ab2c837
BG
5078(defun org-agenda-show-clocking-issues ()
5079 "Add overlays, showing issues with clocking.
5080See also the user option `org-agenda-clock-consistency-checks'."
5081 (interactive)
5082 (let* ((pl org-agenda-clock-consistency-checks)
5083 (re (concat "^[ \t]*"
5084 org-clock-string
5085 "[ \t]+"
5086 "\\(\\[.*?\\]\\)" ; group 1 is first stamp
5087 "\\(-\\{1,3\\}\\(\\[.*?\\]\\)\\)?")) ; group 3 is second
5088 (tlstart 0.)
5089 (tlend 0.)
fe3c5669 5090 (maxtime (org-hh:mm-string-to-minutes
3ab2c837 5091 (or (plist-get pl :max-duration) "24:00")))
fe3c5669 5092 (mintime (org-hh:mm-string-to-minutes
3ab2c837
BG
5093 (or (plist-get pl :min-duration) 0)))
5094 (maxgap (org-hh:mm-string-to-minutes
5095 ;; default 30:00 means never complain
5096 (or (plist-get pl :max-gap) "30:00")))
5097 (gapok (mapcar 'org-hh:mm-string-to-minutes
5098 (plist-get pl :gap-ok-around)))
5099 (def-face (or (plist-get pl :default-face)
5100 '((:background "DarkRed") (:foreground "white"))))
5101 issue face m te ts dt ov)
5102 (goto-char (point-min))
5103 (while (re-search-forward " Clocked: +(-\\|\\([0-9]+:[0-9]+\\))" nil t)
5104 (setq issue nil face def-face)
5105 (catch 'next
5106 (setq m (org-get-at-bol 'org-marker)
5107 te nil ts nil)
5108 (unless (and m (markerp m))
5109 (setq issue "No valid clock line") (throw 'next t))
5110 (org-with-point-at m
5111 (save-excursion
5112 (goto-char (point-at-bol))
5113 (unless (looking-at re)
5114 (error "No valid Clock line")
5115 (throw 'next t))
5116 (unless (match-end 3)
5117 (setq issue "No end time"
5118 face (or (plist-get pl :no-end-time-face) face))
5119 (throw 'next t))
5120 (setq ts (match-string 1)
5121 te (match-string 3)
5122 ts (org-float-time
5123 (apply 'encode-time (org-parse-time-string ts)))
5124 te (org-float-time
5125 (apply 'encode-time (org-parse-time-string te)))
5126 dt (- te ts))))
5127 (cond
5128 ((> dt (* 60 maxtime))
5129 ;; a very long clocking chunk
5130 (setq issue (format "Clocking interval is very long: %s"
5131 (org-minutes-to-hh:mm-string
5132 (floor (/ (float dt) 60.))))
5133 face (or (plist-get pl :long-face) face)))
5134 ((< dt (* 60 mintime))
5135 ;; a very short clocking chunk
5136 (setq issue (format "Clocking interval is very short: %s"
5137 (org-minutes-to-hh:mm-string
5138 (floor (/ (float dt) 60.))))
5139 face (or (plist-get pl :short-face) face)))
5140 ((and (> tlend 0) (< ts tlend))
5141 ;; Two clock entries are overlapping
5142 (setq issue (format "Clocking overlap: %d minutes"
5143 (/ (- tlend ts) 60))
5144 face (or (plist-get pl :overlap-face) face)))
5145 ((and (> tlend 0) (> ts (+ tlend (* 60 maxgap))))
e66ba1df 5146 ;; There is a gap, lets see if we need to report it
3ab2c837
BG
5147 (unless (org-agenda-check-clock-gap tlend ts gapok)
5148 (setq issue (format "Clocking gap: %d minutes"
5149 (/ (- ts tlend) 60))
5150 face (or (plist-get pl :gap-face) face))))
5151 (t nil)))
5152 (setq tlend (or te tlend) tlstart (or ts tlstart))
5153 (when issue
5154 ;; OK, there was some issue, add an overlay to show the issue
5155 (setq ov (make-overlay (point-at-bol) (point-at-eol)))
5156 (overlay-put ov 'before-string
5157 (concat
5158 (org-add-props
5159 (format "%-43s" (concat " " issue))
5160 nil
5161 'face face)
5162 "\n"))
5163 (overlay-put ov 'evaporate t)))))
5164
5165(defun org-agenda-check-clock-gap (t1 t2 ok-list)
5166 "Check if gap T1 -> T2 contains one of the OK-LIST time-of-day values."
5167 (catch 'exit
5168 (unless ok-list
5169 ;; there are no OK times for gaps...
5170 (throw 'exit nil))
5171 (if (> (- (/ t2 36000) (/ t1 36000)) 24)
5172 ;; This is more than 24 hours, so it is OK.
5173 ;; because we have at least one OK time, that must be in the
5174 ;; 24 hour interval.
5175 (throw 'exit t))
5176 ;; We have a shorter gap.
5177 ;; Now we have to get the minute of the day when these times are
5178 (let* ((t1dec (decode-time (seconds-to-time t1)))
5179 (t2dec (decode-time (seconds-to-time t2)))
5180 ;; compute the minute on the day
5181 (min1 (+ (nth 1 t1dec) (* 60 (nth 2 t1dec))))
5182 (min2 (+ (nth 1 t2dec) (* 60 (nth 2 t2dec)))))
5183 (when (< min2 min1)
5184 ;; if min2 is smaller than min1, this means it is on the next day.
5185 ;; Wrap it to after midnight.
5186 (setq min2 (+ min2 1440)))
5187 ;; Now check if any of the OK times is in the gap
5188 (mapc (lambda (x)
5189 ;; Wrap the time to after midnight if necessary
5190 (if (< x min1) (setq x (+ x 1440)))
5191 ;; Check if in interval
5192 (and (<= min1 x) (>= min2 x) (throw 'exit t)))
5193 ok-list)
5194 ;; Nope, this gap is not OK
5195 nil)))
5196
20908596
CD
5197(defun org-agenda-get-deadlines ()
5198 "Return the deadline information for agenda display."
5199 (let* ((props (list 'mouse-face 'highlight
5200 'org-not-done-regexp org-not-done-regexp
5201 'org-todo-regexp org-todo-regexp
b349f79f 5202 'org-complex-heading-regexp org-complex-heading-regexp
20908596
CD
5203 'help-echo
5204 (format "mouse-2 or RET jump to org file %s"
5205 (abbreviate-file-name buffer-file-name))))
5206 (regexp org-deadline-time-regexp)
621f83e4 5207 (todayp (org-agenda-todayp date)) ; DATE bound by calendar
20908596 5208 (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar
e66ba1df
BG
5209 d2 diff dfrac wdays pos pos1 category org-category-pos
5210 tags suppress-prewarning ee txt head face s todo-state
5211 show-all upcomingp donep timestr)
20908596
CD
5212 (goto-char (point-min))
5213 (while (re-search-forward regexp nil t)
ed21c5c8 5214 (setq suppress-prewarning nil)
20908596
CD
5215 (catch :skip
5216 (org-agenda-skip)
ed21c5c8
CD
5217 (when (and org-agenda-skip-deadline-prewarning-if-scheduled
5218 (save-match-data
5219 (string-match org-scheduled-time-regexp
5220 (buffer-substring (point-at-bol)
5221 (point-at-eol)))))
5222 (setq suppress-prewarning
5223 (if (integerp org-agenda-skip-deadline-prewarning-if-scheduled)
5224 org-agenda-skip-deadline-prewarning-if-scheduled
5225 0)))
20908596 5226 (setq s (match-string 1)
c8d0cf5c 5227 txt nil
20908596 5228 pos (1- (match-beginning 1))
3ab2c837
BG
5229 todo-state (save-match-data (org-get-todo-state))
5230 show-all (or (eq org-agenda-repeating-timestamp-show-all t)
5231 (member todo-state
5232 org-agenda-repeating-timestamp-show-all))
20908596 5233 d2 (org-time-string-to-absolute
e66ba1df
BG
5234 (match-string 1) d1 'past show-all
5235 (current-buffer) pos)
20908596 5236 diff (- d2 d1)
ed21c5c8
CD
5237 wdays (if suppress-prewarning
5238 (let ((org-deadline-warning-days suppress-prewarning))
5239 (org-get-wdays s))
5240 (org-get-wdays s))
e66ba1df 5241 dfrac (- 1 (/ (* 1.0 diff) (max wdays 1)))
20908596
CD
5242 upcomingp (and todayp (> diff 0)))
5243 ;; When to show a deadline in the calendar:
5244 ;; If the expiration is within wdays warning time.
5245 ;; Past-due deadlines are only shown on the current date
8bfe682a
CD
5246 (if (and (or (and (<= diff wdays)
5247 (and todayp (not org-agenda-only-exact-dates)))
5248 (= diff 0)))
20908596 5249 (save-excursion
3ab2c837 5250 ;; (setq todo-state (org-get-todo-state))
c8d0cf5c
CD
5251 (setq donep (member todo-state org-done-keywords))
5252 (if (and donep
5253 (or org-agenda-skip-deadline-if-done
5254 (not (= diff 0))))
5255 (setq txt nil)
e66ba1df
BG
5256 (setq category (org-get-category)
5257 org-category-pos (get-text-property (point) 'org-category-position))
c8d0cf5c
CD
5258 (if (not (re-search-backward "^\\*+[ \t]+" nil t))
5259 (setq txt org-agenda-no-heading-message)
5260 (goto-char (match-end 0))
5261 (setq pos1 (match-beginning 0))
5262 (setq tags (org-get-tags-at pos1))
5263 (setq head (buffer-substring-no-properties
5264 (point)
5265 (progn (skip-chars-forward "^\r\n")
5266 (point))))
5267 (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
5268 (setq timestr
5269 (concat (substring s (match-beginning 1)) " "))
5270 (setq timestr 'time))
e66ba1df 5271 (setq txt (org-agenda-format-item
c8d0cf5c
CD
5272 (if (= diff 0)
5273 (car org-agenda-deadline-leaders)
5274 (if (functionp
5275 (nth 1 org-agenda-deadline-leaders))
5276 (funcall
5277 (nth 1 org-agenda-deadline-leaders)
5278 diff date)
5279 (format (nth 1 org-agenda-deadline-leaders)
5280 diff)))
5281 head category tags
5282 (if (not (= diff 0)) nil timestr)))))
20908596 5283 (when txt
e66ba1df 5284 (setq face (org-agenda-deadline-face dfrac))
20908596
CD
5285 (org-add-props txt props
5286 'org-marker (org-agenda-new-marker pos)
5287 'org-hd-marker (org-agenda-new-marker pos1)
5288 'priority (+ (- diff)
5289 (org-get-priority txt))
5290 'org-category category
e66ba1df 5291 'org-category-position org-category-pos
621f83e4 5292 'todo-state todo-state
20908596
CD
5293 'type (if upcomingp "upcoming-deadline" "deadline")
5294 'date (if upcomingp date d2)
c8d0cf5c
CD
5295 'face (if donep 'org-agenda-done face)
5296 'undone-face face 'done-face 'org-agenda-done)
20908596
CD
5297 (push txt ee))))))
5298 (nreverse ee)))
5299
e66ba1df 5300(defun org-agenda-deadline-face (fraction)
20908596
CD
5301 "Return the face to displaying a deadline item.
5302FRACTION is what fraction of the head-warning time has passed."
20908596
CD
5303 (let ((faces org-agenda-deadline-faces) f)
5304 (catch 'exit
5305 (while (setq f (pop faces))
5306 (if (>= fraction (car f)) (throw 'exit (cdr f)))))))
5307
54a0dee5 5308(defun org-agenda-get-scheduled (&optional deadline-results)
20908596
CD
5309 "Return the scheduled information for agenda display."
5310 (let* ((props (list 'org-not-done-regexp org-not-done-regexp
5311 'org-todo-regexp org-todo-regexp
b349f79f 5312 'org-complex-heading-regexp org-complex-heading-regexp
c8d0cf5c 5313 'done-face 'org-agenda-done
20908596 5314 'mouse-face 'highlight
20908596
CD
5315 'help-echo
5316 (format "mouse-2 or RET jump to org file %s"
5317 (abbreviate-file-name buffer-file-name))))
5318 (regexp org-scheduled-time-regexp)
621f83e4 5319 (todayp (org-agenda-todayp date)) ; DATE bound by calendar
20908596 5320 (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar
54a0dee5
CD
5321 mm
5322 (deadline-position-alist
5323 (mapcar (lambda (a) (and (setq mm (get-text-property
8bfe682a
CD
5324 0 'org-hd-marker a))
5325 (cons (marker-position mm) a)))
54a0dee5 5326 deadline-results))
e66ba1df 5327 d2 diff pos pos1 category org-category-pos tags donep
3ab2c837 5328 ee txt head pastschedp todo-state face timestr s habitp show-all)
20908596
CD
5329 (goto-char (point-min))
5330 (while (re-search-forward regexp nil t)
5331 (catch :skip
5332 (org-agenda-skip)
5333 (setq s (match-string 1)
c8d0cf5c 5334 txt nil
20908596 5335 pos (1- (match-beginning 1))
3ab2c837
BG
5336 todo-state (save-match-data (org-get-todo-state))
5337 show-all (or (eq org-agenda-repeating-timestamp-show-all t)
5338 (member todo-state
5339 org-agenda-repeating-timestamp-show-all))
20908596 5340 d2 (org-time-string-to-absolute
e66ba1df
BG
5341 (match-string 1) d1 'past show-all
5342 (current-buffer) pos)
20908596
CD
5343 diff (- d2 d1))
5344 (setq pastschedp (and todayp (< diff 0)))
5345 ;; When to show a scheduled item in the calendar:
5346 ;; If it is on or past the date.
8bfe682a
CD
5347 (when (or (and (< diff 0)
5348 (< (abs diff) org-scheduled-past-days)
5349 (and todayp (not org-agenda-only-exact-dates)))
5350 (= diff 0))
5351 (save-excursion
8bfe682a 5352 (setq donep (member todo-state org-done-keywords))
8bfe682a 5353 (if (and donep
3ab2c837
BG
5354 (or org-agenda-skip-scheduled-if-done
5355 (not (= diff 0))
5356 (and (functionp 'org-is-habit-p)
5357 (org-is-habit-p))))
8bfe682a 5358 (setq txt nil)
3ab2c837
BG
5359 (setq habitp (and (functionp 'org-is-habit-p)
5360 (org-is-habit-p)))
e66ba1df
BG
5361 (setq category (org-get-category)
5362 org-category-pos (get-text-property (point) 'org-category-position))
8bfe682a
CD
5363 (if (not (re-search-backward "^\\*+[ \t]+" nil t))
5364 (setq txt org-agenda-no-heading-message)
5365 (goto-char (match-end 0))
5366 (setq pos1 (match-beginning 0))
5367 (if habitp
5368 (if (or (not org-habit-show-habits)
5369 (and (not todayp)
5370 org-habit-show-habits-only-for-today))
5371 (throw :skip nil))
54a0dee5
CD
5372 (if (and
5373 (or (eq t org-agenda-skip-scheduled-if-deadline-is-shown)
5374 (and org-agenda-skip-scheduled-if-deadline-is-shown
5375 pastschedp))
5376 (setq mm (assoc pos1 deadline-position-alist)))
8bfe682a
CD
5377 (throw :skip nil)))
5378 (setq tags (org-get-tags-at))
5379 (setq head (buffer-substring-no-properties
5380 (point)
5381 (progn (skip-chars-forward "^\r\n") (point))))
5382 (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
5383 (setq timestr
5384 (concat (substring s (match-beginning 1)) " "))
5385 (setq timestr 'time))
e66ba1df 5386 (setq txt (org-agenda-format-item
8bfe682a
CD
5387 (if (= diff 0)
5388 (car org-agenda-scheduled-leaders)
5389 (format (nth 1 org-agenda-scheduled-leaders)
5390 (- 1 diff)))
5391 head category tags
5392 (if (not (= diff 0)) nil timestr)
3ab2c837 5393 nil habitp))))
8bfe682a
CD
5394 (when txt
5395 (setq face
5396 (cond
5397 ((and (not habitp) pastschedp)
5398 'org-scheduled-previously)
5399 (todayp 'org-scheduled-today)
5400 (t 'org-scheduled))
5401 habitp (and habitp (org-habit-parse-todo)))
5402 (org-add-props txt props
5403 'undone-face face
5404 'face (if donep 'org-agenda-done face)
5405 'org-marker (org-agenda-new-marker pos)
5406 'org-hd-marker (org-agenda-new-marker pos1)
5407 'type (if pastschedp "past-scheduled" "scheduled")
5408 'date (if pastschedp d2 date)
5409 'priority (if habitp
5410 (org-habit-get-priority habitp)
5411 (+ 94 (- 5 diff) (org-get-priority txt)))
5412 'org-category category
e66ba1df 5413 'org-category-position org-category-pos
8bfe682a
CD
5414 'org-habit-p habitp
5415 'todo-state todo-state)
5416 (push txt ee))))))
20908596
CD
5417 (nreverse ee)))
5418
5419(defun org-agenda-get-blocks ()
5420 "Return the date-range information for agenda display."
5421 (let* ((props (list 'face nil
5422 'org-not-done-regexp org-not-done-regexp
5423 'org-todo-regexp org-todo-regexp
b349f79f 5424 'org-complex-heading-regexp org-complex-heading-regexp
20908596 5425 'mouse-face 'highlight
20908596
CD
5426 'help-echo
5427 (format "mouse-2 or RET jump to org file %s"
5428 (abbreviate-file-name buffer-file-name))))
5429 (regexp org-tr-regexp)
5430 (d0 (calendar-absolute-from-gregorian date))
e66ba1df
BG
5431 marker hdmarker ee txt d1 d2 s1 s2 category org-category-pos
5432 todo-state tags pos head donep)
20908596
CD
5433 (goto-char (point-min))
5434 (while (re-search-forward regexp nil t)
5435 (catch :skip
5436 (org-agenda-skip)
5437 (setq pos (point))
3ab2c837
BG
5438 (let ((start-time (match-string 1))
5439 (end-time (match-string 2)))
5440 (setq s1 (match-string 1)
5441 s2 (match-string 2)
e66ba1df
BG
5442 d1 (time-to-days (org-time-string-to-time s1 (current-buffer) pos))
5443 d2 (time-to-days (org-time-string-to-time s2 (current-buffer) pos)))
3ab2c837
BG
5444 (if (and (> (- d0 d1) -1) (> (- d2 d0) -1))
5445 ;; Only allow days between the limits, because the normal
5446 ;; date stamps will catch the limits.
5447 (save-excursion
5448 (setq todo-state (org-get-todo-state))
5449 (setq donep (member todo-state org-done-keywords))
5450 (if (and donep org-agenda-skip-timestamp-if-done)
5451 (throw :skip t))
5452 (setq marker (org-agenda-new-marker (point)))
e66ba1df
BG
5453 (setq category (org-get-category)
5454 org-category-pos (get-text-property (point) 'org-category-position))
3ab2c837
BG
5455 (if (not (re-search-backward org-outline-regexp-bol nil t))
5456 (setq txt org-agenda-no-heading-message)
5457 (goto-char (match-beginning 0))
5458 (setq hdmarker (org-agenda-new-marker (point)))
5459 (setq tags (org-get-tags-at))
5460 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
5461 (setq head (match-string 1))
5462 (let ((remove-re
5463 (if org-agenda-remove-timeranges-from-blocks
5464 (concat
5465 "<" (regexp-quote s1) ".*?>"
5466 "--"
5467 "<" (regexp-quote s2) ".*?>")
5468 nil)))
e66ba1df 5469 (setq txt (org-agenda-format-item
3ab2c837
BG
5470 (format
5471 (nth (if (= d1 d2) 0 1)
5472 org-agenda-timerange-leaders)
5473 (1+ (- d0 d1)) (1+ (- d2 d1)))
5474 head category tags
e66ba1df
BG
5475 (cond ((and (= d1 d0) (= d2 d0))
5476 (concat "<" start-time ">--<" end-time ">"))
5477 ((= d1 d0)
3ab2c837
BG
5478 (concat "<" start-time ">"))
5479 ((= d2 d0)
5480 (concat "<" end-time ">"))
5481 (t nil))
5482 remove-re))))
5483 (org-add-props txt props
5484 'org-marker marker 'org-hd-marker hdmarker
5485 'type "block" 'date date
5486 'todo-state todo-state
e66ba1df
BG
5487 'priority (org-get-priority txt) 'org-category category
5488 'org-category-position org-category-pos)
3ab2c837 5489 (push txt ee))))
20908596
CD
5490 (goto-char pos)))
5491 ;; Sort the entries by expiration date.
5492 (nreverse ee)))
5493
5494;;; Agenda presentation and sorting
5495
5496(defvar org-prefix-has-time nil
5497 "A flag, set by `org-compile-prefix-format'.
5498The flag is set if the currently compiled format contains a `%t'.")
5499(defvar org-prefix-has-tag nil
5500 "A flag, set by `org-compile-prefix-format'.
5501The flag is set if the currently compiled format contains a `%T'.")
5502(defvar org-prefix-has-effort nil
5503 "A flag, set by `org-compile-prefix-format'.
5504The flag is set if the currently compiled format contains a `%e'.")
8d642074 5505(defvar org-prefix-category-length nil
86fbb8ca 5506 "Used by `org-compile-prefix-format' to remember the category field width.")
8bfe682a 5507(defvar org-prefix-category-max-length nil
86fbb8ca 5508 "Used by `org-compile-prefix-format' to remember the category field width.")
20908596 5509
acedf35c
CD
5510(defun org-agenda-get-category-icon (category)
5511 "Return an image for CATEGORY according to `org-agenda-category-icon-alist'."
5512 (dolist (entry org-agenda-category-icon-alist)
5513 (when (org-string-match-p (car entry) category)
5514 (if (listp (cadr entry))
5515 (return (cadr entry))
5516 (return (apply 'create-image (cdr entry)))))))
5517
e66ba1df 5518(defun org-agenda-format-item (extra txt &optional category tags dotime
3ab2c837 5519 remove-re habitp)
20908596
CD
5520 "Format TXT to be inserted into the agenda buffer.
5521In particular, it adds the prefix and corresponding text properties. EXTRA
5522must be a string and replaces the `%s' specifier in the prefix format.
5523CATEGORY (string, symbol or nil) may be used to overrule the default
5524category taken from local variable or file name. It will replace the `%c'
5525specifier in the format. DOTIME, when non-nil, indicates that a
5526time-of-day should be extracted from TXT for sorting of this entry, and for
5527the `%t' specifier in the format. When DOTIME is a string, this string is
3ab2c837 5528searched for a time before TXT is. TAGS can be the tags of the headline.
20908596
CD
5529Any match of REMOVE-RE will be removed from TXT."
5530 (save-match-data
5531 ;; Diary entries sometimes have extra whitespace at the beginning
5532 (if (string-match "^ +" txt) (setq txt (replace-match "" nil nil txt)))
5dec9555
CD
5533
5534 ;; Fix the tags part in txt
5535 (setq txt (org-agenda-fix-displayed-tags
5536 txt tags
5537 org-agenda-show-inherited-tags
5538 org-agenda-hide-tags-regexp))
20908596 5539 (let* ((category (or category
acedf35c
CD
5540 (if (stringp org-category)
5541 org-category
5542 (and org-category (symbol-name org-category)))
20908596
CD
5543 (if buffer-file-name
5544 (file-name-sans-extension
5545 (file-name-nondirectory buffer-file-name))
5546 "")))
acedf35c
CD
5547 (category-icon (org-agenda-get-category-icon category))
5548 (category-icon (if category-icon
5549 (propertize " " 'display category-icon)
5550 ""))
20908596
CD
5551 ;; time, tag, effort are needed for the eval of the prefix format
5552 (tag (if tags (nth (1- (length tags)) tags) ""))
5553 time effort neffort
c8d0cf5c
CD
5554 (ts (if dotime (concat
5555 (if (stringp dotime) dotime "")
5556 (and org-agenda-search-headline-for-time txt))))
20908596 5557 (time-of-day (and dotime (org-get-time-of-day ts)))
3ab2c837 5558 stamp plain s0 s1 s2 rtn srp l
8bfe682a 5559 duration thecategory)
e66ba1df 5560 (and (eq major-mode 'org-mode) buffer-file-name
20908596
CD
5561 (add-to-list 'org-agenda-contributing-files buffer-file-name))
5562 (when (and dotime time-of-day)
5563 ;; Extract starting and ending time and move them to prefix
5564 (when (or (setq stamp (string-match org-stamp-time-of-day-regexp ts))
5565 (setq plain (string-match org-plain-time-of-day-regexp ts)))
5566 (setq s0 (match-string 0 ts)
5567 srp (and stamp (match-end 3))
5568 s1 (match-string (if plain 1 2) ts)
5569 s2 (match-string (if plain 8 (if srp 4 6)) ts))
5570
5571 ;; If the times are in TXT (not in DOTIMES), and the prefix will list
5572 ;; them, we might want to remove them there to avoid duplication.
5573 ;; The user can turn this off with a variable.
5574 (if (and org-prefix-has-time
5575 org-agenda-remove-times-when-in-prefix (or stamp plain)
5576 (string-match (concat (regexp-quote s0) " *") txt)
5577 (not (equal ?\] (string-to-char (substring txt (match-end 0)))))
5578 (if (eq org-agenda-remove-times-when-in-prefix 'beg)
5579 (= (match-beginning 0) 0)
5580 t))
5581 (setq txt (replace-match "" nil nil txt))))
5582 ;; Normalize the time(s) to 24 hour
5583 (if s1 (setq s1 (org-get-time-of-day s1 'string t)))
5584 (if s2 (setq s2 (org-get-time-of-day s2 'string t)))
3ab2c837
BG
5585
5586 ;; Try to set s2 if s1 and `org-agenda-default-appointment-duration' are set
5587 (when (and s1 (not s2) org-agenda-default-appointment-duration)
5588 (setq s2
5589 (org-minutes-to-hh:mm-string
5590 (+ (org-hh:mm-string-to-minutes s1) org-agenda-default-appointment-duration))))
5591
20908596 5592 ;; Compute the duration
3ab2c837
BG
5593 (when s2
5594 (setq duration (- (org-hh:mm-string-to-minutes s2)
5595 (org-hh:mm-string-to-minutes s1)))))
20908596 5596
afe98dfa 5597 (when (string-match (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@#%:]+:\\)[ \t]*$")
20908596
CD
5598 txt)
5599 ;; Tags are in the string
5600 (if (or (eq org-agenda-remove-tags t)
5601 (and org-agenda-remove-tags
5602 org-prefix-has-tag))
5603 (setq txt (replace-match "" t t txt))
5604 (setq txt (replace-match
5605 (concat (make-string (max (- 50 (length txt)) 1) ?\ )
5606 (match-string 2 txt))
5607 t t txt))))
e66ba1df 5608 (when (eq major-mode 'org-mode)
20908596
CD
5609 (setq effort
5610 (condition-case nil
5611 (org-get-effort
5612 (or (get-text-property 0 'org-hd-marker txt)
5613 (get-text-property 0 'org-marker txt)))
5614 (error nil)))
5615 (when effort
3ab2c837
BG
5616 (setq neffort (org-duration-string-to-minutes effort)
5617 effort (setq effort (concat "[" effort "]")))))
5618 ;; prevent erroring out with %e format when there is no effort
5619 (or effort (setq effort ""))
20908596
CD
5620
5621 (when remove-re
5622 (while (string-match remove-re txt)
5623 (setq txt (replace-match "" t t txt))))
5624
3ab2c837
BG
5625 ;; Set org-heading property on `txt' to mark the start of the
5626 ;; heading.
5627 (add-text-properties 0 (length txt) '(org-heading t) txt)
5628
5629 ;; Prepare the variables needed in the eval of the compiled format
5630 (setq time (cond (s2 (concat
5631 (org-agenda-time-of-day-to-ampm-maybe s1)
5632 "-" (org-agenda-time-of-day-to-ampm-maybe s2)
5633 (if org-agenda-timegrid-use-ampm " ")))
5634 (s1 (concat
5635 (org-agenda-time-of-day-to-ampm-maybe s1)
5636 (if org-agenda-timegrid-use-ampm
5637 "........ "
5638 "......")))
5639 (t ""))
5640 extra (or (and (not habitp) extra) "")
5641 category (if (symbolp category) (symbol-name category) category)
5642 thecategory (copy-sequence category))
5643 (if (string-match org-bracket-link-regexp category)
5644 (progn
5645 (setq l (if (match-end 3)
5646 (- (match-end 3) (match-beginning 3))
5647 (- (match-end 1) (match-beginning 1))))
5648 (when (< l (or org-prefix-category-length 0))
5649 (setq category (copy-sequence category))
5650 (org-add-props category nil
5651 'extra-space (make-string
5652 (- org-prefix-category-length l 1) ?\ ))))
5653 (if (and org-prefix-category-max-length
5654 (>= (length category) org-prefix-category-max-length))
5655 (setq category (substring category 0 (1- org-prefix-category-max-length)))))
5656 ;; Evaluate the compiled format
5657 (setq rtn (concat (eval org-prefix-format-compiled) txt))
20908596
CD
5658
5659 ;; And finally add the text properties
c8d0cf5c 5660 (remove-text-properties 0 (length rtn) '(line-prefix t wrap-prefix t) rtn)
20908596 5661 (org-add-props rtn nil
8bfe682a 5662 'org-category (if thecategory (downcase thecategory) category)
ff4be292 5663 'tags (mapcar 'org-downcase-keep-props tags)
20908596
CD
5664 'org-highest-priority org-highest-priority
5665 'org-lowest-priority org-lowest-priority
20908596
CD
5666 'time-of-day time-of-day
5667 'duration duration
5668 'effort effort
5669 'effort-minutes neffort
5670 'txt txt
5671 'time time
5672 'extra extra
3ab2c837 5673 'format org-prefix-format-compiled
20908596
CD
5674 'dotime dotime))))
5675
5dec9555
CD
5676(defun org-agenda-fix-displayed-tags (txt tags add-inherited hide-re)
5677 "Remove tags string from TXT, and add a modified list of tags.
5678The modified list may contain inherited tags, and tags matched by
5679`org-agenda-hide-tags-regexp' will be removed."
5680 (when (or add-inherited hide-re)
afe98dfa 5681 (if (string-match (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@#%:]+:\\)[ \t]*$") txt)
5dec9555 5682 (setq txt (substring txt 0 (match-beginning 0))))
ed21c5c8
CD
5683 (setq tags
5684 (delq nil
5685 (mapcar (lambda (tg)
5686 (if (or (and hide-re (string-match hide-re tg))
5687 (and (not add-inherited)
5688 (get-text-property 0 'inherited tg)))
5689 nil
5690 tg))
5691 tags)))
5dec9555 5692 (when tags
5dec9555
CD
5693 (let ((have-i (get-text-property 0 'inherited (car tags)))
5694 i)
5695 (setq txt (concat txt " :"
5696 (mapconcat
5697 (lambda (x)
5698 (setq i (get-text-property 0 'inherited x))
5699 (if (and have-i (not i))
5700 (progn
5701 (setq have-i nil)
5702 (concat ":" x))
5703 x))
5704 tags ":")
5705 (if have-i "::" ":"))))))
5706 txt)
ff4be292
CD
5707
5708(defun org-downcase-keep-props (s)
5709 (let ((props (text-properties-at 0 s)))
5710 (setq s (downcase s))
5711 (add-text-properties 0 (length s) props s)
5712 s))
5713
20908596
CD
5714(defvar org-agenda-sorting-strategy) ;; because the def is in a let form
5715(defvar org-agenda-sorting-strategy-selected nil)
5716
5717(defun org-agenda-add-time-grid-maybe (list ndays todayp)
5718 (catch 'exit
5719 (cond ((not org-agenda-use-time-grid) (throw 'exit list))
5720 ((and todayp (member 'today (car org-agenda-time-grid))))
5721 ((and (= ndays 1) (member 'daily (car org-agenda-time-grid))))
5722 ((member 'weekly (car org-agenda-time-grid)))
5723 (t (throw 'exit list)))
5724 (let* ((have (delq nil (mapcar
5725 (lambda (x) (get-text-property 1 'time-of-day x))
5726 list)))
5727 (string (nth 1 org-agenda-time-grid))
5728 (gridtimes (nth 2 org-agenda-time-grid))
5729 (req (car org-agenda-time-grid))
5730 (remove (member 'remove-match req))
5731 new time)
5732 (if (and (member 'require-timed req) (not have))
5733 ;; don't show empty grid
5734 (throw 'exit list))
5735 (while (setq time (pop gridtimes))
5736 (unless (and remove (member time have))
afe98dfa 5737 (setq time (replace-regexp-in-string " " "0" (format "%04s" time)))
e66ba1df 5738 (push (org-agenda-format-item
20908596
CD
5739 nil string "" nil
5740 (concat (substring time 0 -2) ":" (substring time -2)))
5741 new)
5742 (put-text-property
afe98dfa 5743 2 (length (car new)) 'face 'org-time-grid (car new))))
3ab2c837 5744 (when (and todayp org-agenda-show-current-time-in-grid)
e66ba1df 5745 (push (org-agenda-format-item
3ab2c837
BG
5746 nil
5747 org-agenda-current-time-string
5748 "" nil
5749 (format-time-string "%H:%M "))
5750 new)
5751 (put-text-property
5752 2 (length (car new)) 'face 'org-agenda-current-time (car new)))
5753
20908596
CD
5754 (if (member 'time-up org-agenda-sorting-strategy-selected)
5755 (append new list)
5756 (append list new)))))
5757
5758(defun org-compile-prefix-format (key)
5759 "Compile the prefix format into a Lisp form that can be evaluated.
5760The resulting form is returned and stored in the variable
5761`org-prefix-format-compiled'."
5762 (setq org-prefix-has-time nil org-prefix-has-tag nil
e66ba1df
BG
5763 org-prefix-category-length nil
5764 org-prefix-has-effort nil)
20908596
CD
5765 (let ((s (cond
5766 ((stringp org-agenda-prefix-format)
5767 org-agenda-prefix-format)
5768 ((assq key org-agenda-prefix-format)
5769 (cdr (assq key org-agenda-prefix-format)))
5770 (t " %-12:c%?-12t% s")))
5771 (start 0)
5772 varform vars var e c f opt)
3ab2c837 5773 (while (string-match "%\\(\\?\\)?\\([-+]?[0-9.]*\\)\\([ .;,:!?=|/<>]?\\)\\([ctsei]\\|(.+)\\)"
20908596 5774 s start)
3ab2c837
BG
5775 (setq var (or (cdr (assoc (match-string 4 s)
5776 '(("c" . category) ("t" . time) ("s" . extra)
5777 ("i" . category-icon) ("T" . tag) ("e" . effort))))
5778 'eval)
20908596
CD
5779 c (or (match-string 3 s) "")
5780 opt (match-beginning 1)
5781 start (1+ (match-beginning 0)))
5782 (if (equal var 'time) (setq org-prefix-has-time t))
5783 (if (equal var 'tag) (setq org-prefix-has-tag t))
5784 (if (equal var 'effort) (setq org-prefix-has-effort t))
5785 (setq f (concat "%" (match-string 2 s) "s"))
8bfe682a
CD
5786 (when (equal var 'category)
5787 (setq org-prefix-category-length
5788 (floor (abs (string-to-number (match-string 2 s)))))
5789 (setq org-prefix-category-max-length
5790 (let ((x (match-string 2 s)))
5791 (save-match-data
5792 (if (string-match "\\.[0-9]+" x)
5793 (string-to-number (substring (match-string 0 x) 1)))))))
3ab2c837
BG
5794 (if (eq var 'eval)
5795 (setq varform `(format ,f (org-eval ,(read (match-string 4 s)))))
5796 (if opt
5797 (setq varform
5798 `(if (equal "" ,var)
5799 ""
5800 (format ,f (if (equal "" ,var) "" (concat ,var ,c)))))
5801 (setq varform `(format ,f (if (equal ,var "") "" (concat ,var ,c (get-text-property 0 'extra-space ,var)))))))
20908596
CD
5802 (setq s (replace-match "%s" t nil s))
5803 (push varform vars))
5804 (setq vars (nreverse vars))
5805 (setq org-prefix-format-compiled `(format ,s ,@vars))))
5806
5807(defun org-set-sorting-strategy (key)
5808 (if (symbolp (car org-agenda-sorting-strategy))
5809 ;; the old format
5810 (setq org-agenda-sorting-strategy-selected org-agenda-sorting-strategy)
5811 (setq org-agenda-sorting-strategy-selected
5812 (or (cdr (assq key org-agenda-sorting-strategy))
5813 (cdr (assq 'agenda org-agenda-sorting-strategy))
5814 '(time-up category-keep priority-down)))))
5815
5816(defun org-get-time-of-day (s &optional string mod24)
5817 "Check string S for a time of day.
5818If found, return it as a military time number between 0 and 2400.
5819If not found, return nil.
5820The optional STRING argument forces conversion into a 5 character wide string
5821HH:MM."
5822 (save-match-data
5823 (when
5824 (or (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)\\([AaPp][Mm]\\)?\\> *" s)
5825 (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?\\([AaPp][Mm]\\)\\> *" s))
5826 (let* ((h (string-to-number (match-string 1 s)))
5827 (m (if (match-end 3) (string-to-number (match-string 3 s)) 0))
5828 (ampm (if (match-end 4) (downcase (match-string 4 s))))
5829 (am-p (equal ampm "am"))
5830 (h1 (cond ((not ampm) h)
5831 ((= h 12) (if am-p 0 12))
5832 (t (+ h (if am-p 0 12)))))
5833 (h2 (if (and string mod24 (not (and (= m 0) (= h1 24))))
5834 (mod h1 24) h1))
5835 (t0 (+ (* 100 h2) m))
5836 (t1 (concat (if (>= h1 24) "+" " ")
ed21c5c8
CD
5837 (if (and org-agenda-time-leading-zero
5838 (< t0 1000)) "0" "")
20908596
CD
5839 (if (< t0 100) "0" "")
5840 (if (< t0 10) "0" "")
5841 (int-to-string t0))))
5842 (if string (concat (substring t1 -4 -2) ":" (substring t1 -2)) t0)))))
5843
afe98dfa
CD
5844(defvar org-agenda-before-sorting-filter-function nil
5845 "Function to be applied to agenda items prior to sorting.
5846Prior to sorting also means just before they are inserted into the agenda.
5847
5848To aid sorting, you may revisit the original entries and add more text
5849properties which will later be used by the sorting functions.
5850
5851The function should take a string argument, an agenda line.
5852It has access to the text properties in that line, which contain among
5853other things, the property `org-hd-marker' that points to the entry
5854where the line comes from. Note that not all lines going into the agenda
5855have this property, only most.
5856
5857The function should return the modified string. It is probably best
5858to ONLY change text properties.
5859
5860You can also use this function as a filter, by returning nil for lines
5861you don't want to have in the agenda at all. For this application, you
5862could bind the variable in the options section of a custom command.")
5863
20908596
CD
5864(defun org-finalize-agenda-entries (list &optional nosort)
5865 "Sort and concatenate the agenda items."
5866 (setq list (mapcar 'org-agenda-highlight-todo list))
5867 (if nosort
5868 list
afe98dfa
CD
5869 (when org-agenda-before-sorting-filter-function
5870 (setq list (delq nil (mapcar org-agenda-before-sorting-filter-function list))))
20908596
CD
5871 (mapconcat 'identity (sort list 'org-entries-lessp) "\n")))
5872
5873(defun org-agenda-highlight-todo (x)
621f83e4 5874 (let ((org-done-keywords org-done-keywords-for-agenda)
ed21c5c8 5875 (case-fold-search nil)
e66ba1df 5876 re)
20908596
CD
5877 (if (eq x 'line)
5878 (save-excursion
5879 (beginning-of-line 1)
8d642074 5880 (setq re (org-get-at-bol 'org-todo-regexp))
3ab2c837 5881 (goto-char (or (text-property-any (point-at-bol) (point-at-eol) 'org-heading t) (point)))
621f83e4 5882 (when (looking-at (concat "[ \t]*\\.*\\(" re "\\) +"))
c8d0cf5c 5883 (add-text-properties (match-beginning 0) (match-end 1)
621f83e4 5884 (list 'face (org-get-todo-face 1)))
20908596
CD
5885 (let ((s (buffer-substring (match-beginning 1) (match-end 1))))
5886 (delete-region (match-beginning 1) (1- (match-end 0)))
5887 (goto-char (match-beginning 1))
5888 (insert (format org-agenda-todo-keyword-format s)))))
3ab2c837
BG
5889 (let ((pl (text-property-any 0 (length x) 'org-heading t x)))
5890 (setq re (get-text-property 0 'org-todo-regexp x))
5891 (when (and re
153ae947
BG
5892 ;; Test `pl' because if there's no heading content,
5893 ;; there's no point matching to highlight. Note
5894 ;; that if we didn't test `pl' first, and there
5895 ;; happened to be no keyword from `org-todo-regexp'
5896 ;; on this heading line, then the `equal' comparison
5897 ;; afterwards would spuriously succeed in the case
5898 ;; where `pl' is nil -- causing an args-out-of-range
5899 ;; error when we try to add text properties to text
5900 ;; that isn't there.
5901 pl
3ab2c837 5902 (equal (string-match (concat "\\(\\.*\\)" re "\\( +\\)")
153ae947 5903 x pl) pl))
3ab2c837
BG
5904 (add-text-properties
5905 (or (match-end 1) (match-end 0)) (match-end 0)
5906 (list 'face (org-get-todo-face (match-string 2 x)))
e66ba1df 5907 x)
3ab2c837
BG
5908 (when (match-end 1)
5909 (setq x (concat (substring x 0 (match-end 1))
5910 (format org-agenda-todo-keyword-format
5911 (match-string 2 x))
e66ba1df
BG
5912 (org-add-props " " (text-properties-at 0 x))
5913 (substring x (match-end 3)))))))
20908596
CD
5914 x)))
5915
5916(defsubst org-cmp-priority (a b)
5917 "Compare the priorities of string A and B."
5918 (let ((pa (or (get-text-property 1 'priority a) 0))
5919 (pb (or (get-text-property 1 'priority b) 0)))
5920 (cond ((> pa pb) +1)
5921 ((< pa pb) -1)
5922 (t nil))))
5923
5924(defsubst org-cmp-effort (a b)
e66ba1df 5925 "Compare the effort values of string A and B."
20908596
CD
5926 (let* ((def (if org-sort-agenda-noeffort-is-high 32767 -1))
5927 (ea (or (get-text-property 1 'effort-minutes a) def))
5928 (eb (or (get-text-property 1 'effort-minutes b) def)))
5929 (cond ((> ea eb) +1)
5930 ((< ea eb) -1)
5931 (t nil))))
5932
5933(defsubst org-cmp-category (a b)
5934 "Compare the string values of categories of strings A and B."
5935 (let ((ca (or (get-text-property 1 'org-category a) ""))
5936 (cb (or (get-text-property 1 'org-category b) "")))
5937 (cond ((string-lessp ca cb) -1)
5938 ((string-lessp cb ca) +1)
5939 (t nil))))
5940
621f83e4
CD
5941(defsubst org-cmp-todo-state (a b)
5942 "Compare the todo states of strings A and B."
c8d0cf5c
CD
5943 (let* ((ma (or (get-text-property 1 'org-marker a)
5944 (get-text-property 1 'org-hd-marker a)))
5945 (mb (or (get-text-property 1 'org-marker b)
5946 (get-text-property 1 'org-hd-marker b)))
5947 (fa (and ma (marker-buffer ma)))
5948 (fb (and mb (marker-buffer mb)))
5949 (todo-kwds
5950 (or (and fa (with-current-buffer fa org-todo-keywords-1))
5951 (and fb (with-current-buffer fb org-todo-keywords-1))))
5952 (ta (or (get-text-property 1 'todo-state a) ""))
621f83e4 5953 (tb (or (get-text-property 1 'todo-state b) ""))
c8d0cf5c
CD
5954 (la (- (length (member ta todo-kwds))))
5955 (lb (- (length (member tb todo-kwds))))
ff4be292 5956 (donepa (member ta org-done-keywords-for-agenda))
621f83e4
CD
5957 (donepb (member tb org-done-keywords-for-agenda)))
5958 (cond ((and donepa (not donepb)) -1)
5959 ((and (not donepa) donepb) +1)
5960 ((< la lb) -1)
5961 ((< lb la) +1)
5962 (t nil))))
5963
86fbb8ca
CD
5964(defsubst org-cmp-alpha (a b)
5965 "Compare the headlines, alphabetically."
3ab2c837
BG
5966 (let* ((pla (text-property-any 0 (length a) 'org-heading t a))
5967 (plb (text-property-any 0 (length b) 'org-heading t b))
86fbb8ca
CD
5968 (ta (and pla (substring a pla)))
5969 (tb (and plb (substring b plb))))
5970 (when pla
5971 (if (string-match (concat "\\`[ \t]*" (or (get-text-property 0 'org-todo-regexp a) "")
5972 "\\([ \t]*\\[[a-zA-Z0-9]\\]\\)? *") ta)
5973 (setq ta (substring ta (match-end 0))))
5974 (setq ta (downcase ta)))
5975 (when plb
5976 (if (string-match (concat "\\`[ \t]*" (or (get-text-property 0 'org-todo-regexp b) "")
5977 "\\([ \t]*\\[[a-zA-Z0-9]\\]\\)? *") tb)
5978 (setq tb (substring tb (match-end 0))))
5979 (setq tb (downcase tb)))
5980 (cond ((not ta) +1)
5981 ((not tb) -1)
5982 ((string-lessp ta tb) -1)
5983 ((string-lessp tb ta) +1)
5984 (t nil))))
5985
20908596 5986(defsubst org-cmp-tag (a b)
71d35b24 5987 "Compare the string values of the first tags of A and B."
20908596
CD
5988 (let ((ta (car (last (get-text-property 1 'tags a))))
5989 (tb (car (last (get-text-property 1 'tags b)))))
5990 (cond ((not ta) +1)
5991 ((not tb) -1)
5992 ((string-lessp ta tb) -1)
5993 ((string-lessp tb ta) +1)
5994 (t nil))))
5995
5996(defsubst org-cmp-time (a b)
5997 "Compare the time-of-day values of strings A and B."
5998 (let* ((def (if org-sort-agenda-notime-is-late 9901 -1))
5999 (ta (or (get-text-property 1 'time-of-day a) def))
6000 (tb (or (get-text-property 1 'time-of-day b) def)))
6001 (cond ((< ta tb) -1)
6002 ((< tb ta) +1)
6003 (t nil))))
6004
8bfe682a
CD
6005(defsubst org-cmp-habit-p (a b)
6006 "Compare the todo states of strings A and B."
6007 (let ((ha (get-text-property 1 'org-habit-p a))
6008 (hb (get-text-property 1 'org-habit-p b)))
6009 (cond ((and ha (not hb)) -1)
6010 ((and (not ha) hb) +1)
6011 (t nil))))
6012
86fbb8ca
CD
6013(defsubst org-em (x y list) (or (memq x list) (memq y list)))
6014
20908596
CD
6015(defun org-entries-lessp (a b)
6016 "Predicate for sorting agenda entries."
6017 ;; The following variables will be used when the form is evaluated.
6018 ;; So even though the compiler complains, keep them.
86fbb8ca
CD
6019 (let* ((ss org-agenda-sorting-strategy-selected)
6020 (time-up (and (org-em 'time-up 'time-down ss)
6021 (org-cmp-time a b)))
6022 (time-down (if time-up (- time-up) nil))
6023 (priority-up (and (org-em 'priority-up 'priority-down ss)
6024 (org-cmp-priority a b)))
6025 (priority-down (if priority-up (- priority-up) nil))
6026 (effort-up (and (org-em 'effort-up 'effort-down ss)
6027 (org-cmp-effort a b)))
6028 (effort-down (if effort-up (- effort-up) nil))
6029 (category-up (and (or (org-em 'category-up 'category-down ss)
6030 (memq 'category-keep ss))
6031 (org-cmp-category a b)))
6032 (category-down (if category-up (- category-up) nil))
6033 (category-keep (if category-up +1 nil))
6034 (tag-up (and (org-em 'tag-up 'tag-down ss)
6035 (org-cmp-tag a b)))
6036 (tag-down (if tag-up (- tag-up) nil))
6037 (todo-state-up (and (org-em 'todo-state-up 'todo-state-down ss)
6038 (org-cmp-todo-state a b)))
c8d0cf5c 6039 (todo-state-down (if todo-state-up (- todo-state-up) nil))
86fbb8ca
CD
6040 (habit-up (and (org-em 'habit-up 'habit-down ss)
6041 (org-cmp-habit-p a b)))
6042 (habit-down (if habit-up (- habit-up) nil))
6043 (alpha-up (and (org-em 'alpha-up 'alpha-down ss)
6044 (org-cmp-alpha a b)))
6045 (alpha-down (if alpha-up (- alpha-up) nil))
afe98dfa 6046 (need-user-cmp (org-em 'user-defined-up 'user-defined-down ss))
c8d0cf5c 6047 user-defined-up user-defined-down)
afe98dfa 6048 (if (and need-user-cmp org-agenda-cmp-user-defined
c8d0cf5c
CD
6049 (functionp org-agenda-cmp-user-defined))
6050 (setq user-defined-up
6051 (funcall org-agenda-cmp-user-defined a b)
6052 user-defined-down (if user-defined-up (- user-defined-up) nil)))
20908596
CD
6053 (cdr (assoc
6054 (eval (cons 'or org-agenda-sorting-strategy-selected))
6055 '((-1 . t) (1 . nil) (nil . nil))))))
6056
6057;;; Agenda restriction lock
6058
86fbb8ca 6059(defvar org-agenda-restriction-lock-overlay (make-overlay 1 1)
8bfe682a 6060 "Overlay to mark the headline to which agenda commands are restricted.")
86fbb8ca
CD
6061(overlay-put org-agenda-restriction-lock-overlay
6062 'face 'org-agenda-restriction-lock)
6063(overlay-put org-agenda-restriction-lock-overlay
6064 'help-echo "Agendas are currently limited to this subtree.")
20908596
CD
6065(org-detach-overlay org-agenda-restriction-lock-overlay)
6066
6067(defun org-agenda-set-restriction-lock (&optional type)
6068 "Set restriction lock for agenda, to current subtree or file.
6069Restriction will be the file if TYPE is `file', or if type is the
6070universal prefix '(4), or if the cursor is before the first headline
6071in the file. Otherwise, restriction will be to the current subtree."
6072 (interactive "P")
6073 (and (equal type '(4)) (setq type 'file))
6074 (setq type (cond
6075 (type type)
6076 ((org-at-heading-p) 'subtree)
6077 ((condition-case nil (org-back-to-heading t) (error nil))
6078 'subtree)
6079 (t 'file)))
6080 (if (eq type 'subtree)
6081 (progn
6082 (setq org-agenda-restrict t)
6083 (setq org-agenda-overriding-restriction 'subtree)
6084 (put 'org-agenda-files 'org-restrict
6085 (list (buffer-file-name (buffer-base-buffer))))
6086 (org-back-to-heading t)
86fbb8ca 6087 (move-overlay org-agenda-restriction-lock-overlay (point) (point-at-eol))
20908596
CD
6088 (move-marker org-agenda-restrict-begin (point))
6089 (move-marker org-agenda-restrict-end
6090 (save-excursion (org-end-of-subtree t)))
6091 (message "Locking agenda restriction to subtree"))
6092 (put 'org-agenda-files 'org-restrict
6093 (list (buffer-file-name (buffer-base-buffer))))
6094 (setq org-agenda-restrict nil)
6095 (setq org-agenda-overriding-restriction 'file)
6096 (move-marker org-agenda-restrict-begin nil)
6097 (move-marker org-agenda-restrict-end nil)
6098 (message "Locking agenda restriction to file"))
6099 (setq current-prefix-arg nil)
6100 (org-agenda-maybe-redo))
6101
6102(defun org-agenda-remove-restriction-lock (&optional noupdate)
6103 "Remove the agenda restriction lock."
6104 (interactive "P")
6105 (org-detach-overlay org-agenda-restriction-lock-overlay)
6106 (org-detach-overlay org-speedbar-restriction-lock-overlay)
6107 (setq org-agenda-overriding-restriction nil)
6108 (setq org-agenda-restrict nil)
6109 (put 'org-agenda-files 'org-restrict nil)
6110 (move-marker org-agenda-restrict-begin nil)
6111 (move-marker org-agenda-restrict-end nil)
6112 (setq current-prefix-arg nil)
6113 (message "Agenda restriction lock removed")
6114 (or noupdate (org-agenda-maybe-redo)))
6115
6116(defun org-agenda-maybe-redo ()
6117 "If there is any window showing the agenda view, update it."
6118 (let ((w (get-buffer-window org-agenda-buffer-name t))
6119 (w0 (selected-window)))
6120 (when w
6121 (select-window w)
6122 (org-agenda-redo)
6123 (select-window w0)
6124 (if org-agenda-overriding-restriction
6125 (message "Agenda view shifted to new %s restriction"
6126 org-agenda-overriding-restriction)
6127 (message "Agenda restriction lock removed")))))
6128
6129;;; Agenda commands
6130
6131(defun org-agenda-check-type (error &rest types)
6132 "Check if agenda buffer is of allowed type.
6133If ERROR is non-nil, throw an error, otherwise just return nil."
6134 (if (memq org-agenda-type types)
6135 t
6136 (if error
6137 (error "Not allowed in %s-type agenda buffers" org-agenda-type)
6138 nil)))
6139
6140(defun org-agenda-quit ()
6141 "Exit agenda by removing the window or the buffer."
6142 (interactive)
6143 (if org-agenda-columns-active
6144 (org-columns-quit)
6145 (let ((buf (current-buffer)))
8d642074
CD
6146 (if (eq org-agenda-window-setup 'other-frame)
6147 (progn
6148 (kill-buffer buf)
6149 (org-agenda-reset-markers)
6150 (org-columns-remove-overlays)
6151 (setq org-agenda-archives-mode nil)
6152 (delete-frame))
6153 (and (not (eq org-agenda-window-setup 'current-window))
6154 (not (one-window-p))
6155 (delete-window))
6156 (kill-buffer buf)
6157 (org-agenda-reset-markers)
6158 (org-columns-remove-overlays)
6159 (setq org-agenda-archives-mode nil)))
20908596
CD
6160 ;; Maybe restore the pre-agenda window configuration.
6161 (and org-agenda-restore-windows-after-quit
6162 (not (eq org-agenda-window-setup 'other-frame))
6163 org-pre-agenda-window-conf
6164 (set-window-configuration org-pre-agenda-window-conf))))
6165
6166(defun org-agenda-exit ()
6167 "Exit agenda by removing the window or the buffer.
6168Also kill all Org-mode buffers which have been loaded by `org-agenda'.
6169Org-mode buffers visited directly by the user will not be touched."
6170 (interactive)
6171 (org-release-buffers org-agenda-new-buffers)
6172 (setq org-agenda-new-buffers nil)
6173 (org-agenda-quit))
6174
6175(defun org-agenda-execute (arg)
86fbb8ca
CD
6176 "Execute another agenda command, keeping same window.
6177So this is just a shortcut for \\<global-map>`\\[org-agenda]', available
6178in the agenda."
20908596
CD
6179 (interactive "P")
6180 (let ((org-agenda-window-setup 'current-window))
6181 (org-agenda arg)))
6182
20908596
CD
6183(defun org-agenda-redo ()
6184 "Rebuild Agenda.
6185When this is the global TODO list, a prefix argument will be interpreted."
6186 (interactive)
6187 (let* ((org-agenda-keep-modes t)
e66ba1df
BG
6188 (tag-filter org-agenda-tag-filter)
6189 (tag-preset (get 'org-agenda-tag-filter :preset-filter))
6190 (cat-filter org-agenda-category-filter)
6191 (cat-preset (get 'org-agenda-category-filter :preset-filter))
6192 (org-agenda-tag-filter-while-redo (or tag-filter tag-preset))
20908596
CD
6193 (cols org-agenda-columns-active)
6194 (line (org-current-line))
6195 (window-line (- line (org-current-line (window-start))))
6196 (lprops (get 'org-agenda-redo-command 'org-lprops)))
e66ba1df
BG
6197 (put 'org-agenda-tag-filter :preset-filter nil)
6198 (put 'org-agenda-category-filter :preset-filter nil)
20908596
CD
6199 (and cols (org-columns-quit))
6200 (message "Rebuilding agenda buffer...")
6201 (org-let lprops '(eval org-agenda-redo-command))
6202 (setq org-agenda-undo-list nil
6203 org-agenda-pending-undo-list nil)
6204 (message "Rebuilding agenda buffer...done")
e66ba1df
BG
6205 (put 'org-agenda-tag-filter :preset-filter tag-preset)
6206 (put 'org-agenda-category-filter :preset-filter cat-preset)
6207 (and (or tag-filter tag-preset) (org-agenda-filter-apply tag-filter 'tag))
6208 (and (or cat-filter cat-preset) (org-agenda-filter-apply cat-filter 'category))
3ab2c837 6209 (and cols (org-called-interactively-p 'any) (org-agenda-columns))
54a0dee5 6210 (org-goto-line line)
20908596
CD
6211 (recenter window-line)))
6212
621f83e4 6213(defvar org-global-tags-completion-table nil)
71d35b24 6214(defvar org-agenda-filter-form nil)
153ae947 6215(defvar org-agenda-filtered-by-category nil)
e66ba1df
BG
6216
6217(defun org-agenda-filter-by-category (strip)
6218 "Keep only those lines in the agenda buffer that have a specific category.
6219The category is that of the current line."
6220 (interactive "P")
6221 (if org-agenda-filtered-by-category
6222 (org-agenda-filter-show-all-cat)
6223 (let ((cat (org-no-properties (get-text-property (point) 'org-category))))
6224 (if cat (org-agenda-filter-apply
6225 (list (concat (if strip "-" "+") cat)) 'category)
6226 (error "No category at point")))))
6227
71d35b24 6228(defun org-agenda-filter-by-tag (strip &optional char narrow)
621f83e4
CD
6229 "Keep only those lines in the agenda buffer that have a specific tag.
6230The tag is selected with its fast selection letter, as configured.
71d35b24
CD
6231With prefix argument STRIP, remove all lines that do have the tag.
6232A lisp caller can specify CHAR. NARROW means that the new tag should be
6233used to narrow the search - the interactive user can also press `-' or `+'
6234to switch to narrowing."
621f83e4 6235 (interactive "P")
71d35b24 6236 (let* ((alist org-tag-alist-for-agenda)
8bfe682a
CD
6237 (tag-chars (mapconcat
6238 (lambda (x) (if (and (not (symbolp (car x)))
6239 (cdr x))
6240 (char-to-string (cdr x))
6241 ""))
6242 alist ""))
6243 (efforts (org-split-string
6244 (or (cdr (assoc (concat org-effort-property "_ALL")
6245 org-global-properties))
3ab2c837
BG
6246 "0 0:10 0:30 1:00 2:00 3:00 4:00 5:00 6:00 7:00 8:00"
6247 "")))
8bfe682a
CD
6248 (effort-op org-agenda-filter-effort-default-operator)
6249 (effort-prompt "")
6250 (inhibit-read-only t)
e66ba1df 6251 (current org-agenda-tag-filter)
3ab2c837 6252 maybe-refresh a n tag)
71d35b24 6253 (unless char
ff4be292 6254 (message
8bfe682a
CD
6255 "%s by tag [%s ], [TAB], %s[/]:off, [+-]:narrow, [>=<?]:effort: "
6256 (if narrow "Narrow" "Filter") tag-chars
6257 (if org-agenda-auto-exclude-function "[RET], " ""))
e66ba1df 6258 (setq char (read-char-exclusive)))
71d35b24
CD
6259 (when (member char '(?+ ?-))
6260 ;; Narrowing down
6261 (cond ((equal char ?-) (setq strip t narrow t))
6262 ((equal char ?+) (setq strip nil narrow t)))
ff4be292 6263 (message
71d35b24 6264 "Narrow by tag [%s ], [TAB], [/]:off, [>=<]:effort: " tag-chars)
e66ba1df 6265 (setq char (read-char-exclusive)))
c8d0cf5c 6266 (when (member char '(?< ?> ?= ??))
71d35b24
CD
6267 ;; An effort operator
6268 (setq effort-op (char-to-string char))
71d35b24 6269 (setq alist nil) ; to make sure it will be interpreted as effort.
c8d0cf5c
CD
6270 (unless (equal char ??)
6271 (loop for i from 0 to 9 do
6272 (setq effort-prompt
6273 (concat
6274 effort-prompt " ["
6275 (if (= i 9) "0" (int-to-string (1+ i)))
6276 "]" (nth i efforts))))
6277 (message "Effort%s: %s " effort-op effort-prompt)
e66ba1df 6278 (setq char (read-char-exclusive))
c8d0cf5c
CD
6279 (when (or (< char ?0) (> char ?9))
6280 (error "Need 1-9,0 to select effort" ))))
71d35b24
CD
6281 (when (equal char ?\t)
6282 (unless (local-variable-p 'org-global-tags-completion-table (current-buffer))
6283 (org-set-local 'org-global-tags-completion-table
6284 (org-global-tags-completion-table)))
6285 (let ((completion-ignore-case t))
54a0dee5 6286 (setq tag (org-icompleting-read
71d35b24
CD
6287 "Tag: " org-global-tags-completion-table))))
6288 (cond
8bfe682a 6289 ((equal char ?\r)
e66ba1df 6290 (org-agenda-filter-show-all-tag)
8bfe682a 6291 (when org-agenda-auto-exclude-function
e66ba1df 6292 (setq org-agenda-tag-filter '())
ed21c5c8
CD
6293 (dolist (tag (org-agenda-get-represented-tags))
6294 (let ((modifier (funcall org-agenda-auto-exclude-function tag)))
8bfe682a 6295 (if modifier
e66ba1df
BG
6296 (push modifier org-agenda-tag-filter))))
6297 (if (not (null org-agenda-tag-filter))
6298 (org-agenda-filter-apply org-agenda-tag-filter 'tag)))
3ab2c837 6299 (setq maybe-refresh t))
c8d0cf5c 6300 ((equal char ?/)
e66ba1df
BG
6301 (org-agenda-filter-show-all-tag)
6302 (when (get 'org-agenda-tag-filter :preset-filter)
6303 (org-agenda-filter-apply org-agenda-tag-filter 'tag))
6304 (setq maybe-refresh t))
6305 ((equal char ?. )
6306 (setq org-agenda-tag-filter
6307 (mapcar (lambda(tag) (concat "+" tag))
6308 (org-get-at-bol 'tags)))
6309 (org-agenda-filter-apply org-agenda-tag-filter 'tag)
3ab2c837 6310 (setq maybe-refresh t))
71d35b24
CD
6311 ((or (equal char ?\ )
6312 (setq a (rassoc char alist))
6313 (and (>= char ?0) (<= char ?9)
6314 (setq n (if (= char ?0) 9 (- char ?0 1))
6315 tag (concat effort-op (nth n efforts))
6316 a (cons tag nil)))
c8d0cf5c
CD
6317 (and (= char ??)
6318 (setq tag "?eff")
6319 a (cons tag nil))
71d35b24 6320 (and tag (setq a (cons tag nil))))
e66ba1df 6321 (org-agenda-filter-show-all-tag)
71d35b24 6322 (setq tag (car a))
e66ba1df 6323 (setq org-agenda-tag-filter
71d35b24
CD
6324 (cons (concat (if strip "-" "+") tag)
6325 (if narrow current nil)))
e66ba1df 6326 (org-agenda-filter-apply org-agenda-tag-filter 'tag)
3ab2c837
BG
6327 (setq maybe-refresh t))
6328 (t (error "Invalid tag selection character %c" char)))
58e9b49a
BG
6329 (when (and maybe-refresh
6330 (eq org-agenda-clockreport-mode 'with-filter))
3ab2c837 6331 (org-agenda-redo))))
71d35b24 6332
ed21c5c8
CD
6333(defun org-agenda-get-represented-tags ()
6334 "Get a list of all tags currently represented in the agenda."
6335 (let (p tags)
6336 (save-excursion
6337 (goto-char (point-min))
6338 (while (setq p (next-single-property-change (point) 'tags))
6339 (goto-char p)
6340 (mapc (lambda (x) (add-to-list 'tags x))
6341 (get-text-property (point) 'tags))))
6342 tags))
6343
71d35b24 6344(defun org-agenda-filter-by-tag-refine (strip &optional char)
e66ba1df 6345 "Refine the current filter. See `org-agenda-filter-by-tag'."
71d35b24
CD
6346 (interactive "P")
6347 (org-agenda-filter-by-tag strip char 'refine))
6348
6349(defun org-agenda-filter-make-matcher ()
e66ba1df 6350 "Create the form that tests a line for agenda filter."
71d35b24 6351 (let (f f1)
e66ba1df
BG
6352 ;; first compute the tag-filter matcher
6353 (dolist (x (delete-dups
6354 (append (get 'org-agenda-tag-filter
6355 :preset-filter) org-agenda-tag-filter)))
71d35b24 6356 (if (member x '("-" "+"))
8bfe682a 6357 (setq f1 (if (equal x "-") 'tags '(not tags)))
c8d0cf5c 6358 (if (string-match "[<=>?]" x)
71d35b24
CD
6359 (setq f1 (org-agenda-filter-effort-form x))
6360 (setq f1 (list 'member (downcase (substring x 1)) 'tags)))
6361 (if (equal (string-to-char x) ?-)
6362 (setq f1 (list 'not f1))))
6363 (push f1 f))
e66ba1df
BG
6364 ;; then compute the category-filter matcher
6365 (dolist (x (delete-dups
6366 (append (get 'org-agenda-category-filter
6367 :preset-filter) org-agenda-category-filter)))
801a68c8
BG
6368 (if (equal "-" (substring x 0 1))
6369 (setq f1 (list 'not (list 'equal (substring x 1) 'cat)))
6370 (setq f1 (list 'equal (substring x 1) 'cat)))
e66ba1df 6371 (push f1 f))
71d35b24
CD
6372 (cons 'and (nreverse f))))
6373
6374(defun org-agenda-filter-effort-form (e)
6375 "Return the form to compare the effort of the current line with what E says.
86fbb8ca 6376E looks like \"+<2:25\"."
71d35b24
CD
6377 (let (op)
6378 (setq e (substring e 1))
6379 (setq op (string-to-char e) e (substring e 1))
c8d0cf5c
CD
6380 (setq op (cond ((equal op ?<) '<=)
6381 ((equal op ?>) '>=)
6382 ((equal op ??) op)
6383 (t '=)))
71d35b24 6384 (list 'org-agenda-compare-effort (list 'quote op)
3ab2c837 6385 (org-duration-string-to-minutes e))))
71d35b24
CD
6386
6387(defun org-agenda-compare-effort (op value)
6388 "Compare the effort of the current line with VALUE, using OP.
6389If the line does not have an effort defined, return nil."
8d642074 6390 (let ((eff (org-get-at-bol 'effort-minutes)))
c8d0cf5c
CD
6391 (if (equal op ??)
6392 (not eff)
6393 (funcall op (or eff (if org-sort-agenda-noeffort-is-high 32767 0))
6394 value))))
71d35b24 6395
e66ba1df 6396(defun org-agenda-filter-apply (filter type)
71d35b24 6397 "Set FILTER as the new agenda filter and apply it."
c74587e6 6398 (let (tags cat)
e66ba1df
BG
6399 (if (eq type 'tag)
6400 (setq org-agenda-tag-filter filter)
801a68c8 6401 (setq org-agenda-category-filter filter))
e66ba1df 6402 (setq org-agenda-filter-form (org-agenda-filter-make-matcher))
801a68c8
BG
6403 (if (and (eq type 'category)
6404 (not (equal (substring (car filter) 0 1) "-")))
6405 ;; Only set `org-agenda-filtered-by-category' to t
6406 ;; when a unique category is used as the filter
6407 (setq org-agenda-filtered-by-category t))
71d35b24
CD
6408 (org-agenda-set-mode-name)
6409 (save-excursion
6410 (goto-char (point-min))
6411 (while (not (eobp))
8d642074 6412 (if (org-get-at-bol 'org-marker)
71d35b24 6413 (progn
e66ba1df
BG
6414 (setq tags (org-get-at-bol 'tags) ; used in eval
6415 cat (get-text-property (point) 'org-category))
71d35b24 6416 (if (not (eval org-agenda-filter-form))
e66ba1df 6417 (org-agenda-filter-hide-line type))
71d35b24 6418 (beginning-of-line 2))
afe98dfa
CD
6419 (beginning-of-line 2))))
6420 (if (get-char-property (point) 'invisible)
801a68c8 6421 (ignore-errors (org-agenda-previous-line)))))
621f83e4 6422
e66ba1df 6423(defun org-agenda-filter-hide-line (type)
621f83e4 6424 (let (ov)
86fbb8ca 6425 (setq ov (make-overlay (max (point-min) (1- (point-at-bol)))
621f83e4 6426 (point-at-eol)))
86fbb8ca 6427 (overlay-put ov 'invisible t)
e66ba1df
BG
6428 (overlay-put ov 'type type)
6429 (if (eq type 'tag)
6430 (push ov org-agenda-tag-filter-overlays)
6431 (push ov org-agenda-cat-filter-overlays))))
621f83e4 6432
71d35b24
CD
6433(defun org-agenda-fix-tags-filter-overlays-at (&optional pos)
6434 (setq pos (or pos (point)))
6435 (save-excursion
86fbb8ca
CD
6436 (dolist (ov (overlays-at pos))
6437 (when (and (overlay-get ov 'invisible)
e66ba1df 6438 (eq (overlay-get ov 'type) 'tag))
71d35b24 6439 (goto-char pos)
86fbb8ca
CD
6440 (if (< (overlay-start ov) (point-at-eol))
6441 (move-overlay ov (point-at-eol)
6442 (overlay-end ov)))))))
71d35b24 6443
e66ba1df
BG
6444(defun org-agenda-filter-show-all-tag nil
6445 (mapc 'delete-overlay org-agenda-tag-filter-overlays)
6446 (setq org-agenda-tag-filter-overlays nil
6447 org-agenda-tag-filter nil
6448 org-agenda-filter-form nil)
6449 (org-agenda-set-mode-name))
6450
6451(defun org-agenda-filter-show-all-cat nil
6452 (mapc 'delete-overlay org-agenda-cat-filter-overlays)
6453 (setq org-agenda-cat-filter-overlays nil
6454 org-agenda-filtered-by-category nil
6455 org-agenda-category-filter nil
6456 org-agenda-filter-form nil)
71d35b24 6457 (org-agenda-set-mode-name))
621f83e4 6458
20908596
CD
6459(defun org-agenda-manipulate-query-add ()
6460 "Manipulate the query by adding a search term with positive selection.
ed21c5c8 6461Positive selection means the term must be matched for selection of an entry."
20908596
CD
6462 (interactive)
6463 (org-agenda-manipulate-query ?\[))
6464(defun org-agenda-manipulate-query-subtract ()
6465 "Manipulate the query by adding a search term with negative selection.
ed21c5c8 6466Negative selection means term must not be matched for selection of an entry."
20908596
CD
6467 (interactive)
6468 (org-agenda-manipulate-query ?\]))
6469(defun org-agenda-manipulate-query-add-re ()
6470 "Manipulate the query by adding a search regexp with positive selection.
ed21c5c8 6471Positive selection means the regexp must match for selection of an entry."
20908596
CD
6472 (interactive)
6473 (org-agenda-manipulate-query ?\{))
6474(defun org-agenda-manipulate-query-subtract-re ()
6475 "Manipulate the query by adding a search regexp with negative selection.
ed21c5c8 6476Negative selection means regexp must not match for selection of an entry."
20908596
CD
6477 (interactive)
6478 (org-agenda-manipulate-query ?\}))
6479(defun org-agenda-manipulate-query (char)
6480 (cond
6481 ((memq org-agenda-type '(timeline agenda))
54a0dee5
CD
6482 (let ((org-agenda-include-inactive-timestamps t))
6483 (org-agenda-redo))
6484 (message "Display now includes inactive timestamps as well"))
20908596
CD
6485 ((eq org-agenda-type 'search)
6486 (org-add-to-string
6487 'org-agenda-query-string
ed21c5c8
CD
6488 (if org-agenda-last-search-view-search-was-boolean
6489 (cdr (assoc char '((?\[ . " +") (?\] . " -")
6490 (?\{ . " +{}") (?\} . " -{}"))))
6491 " "))
20908596
CD
6492 (setq org-agenda-redo-command
6493 (list 'org-search-view
6494 org-todo-only
6495 org-agenda-query-string
6496 (+ (length org-agenda-query-string)
6497 (if (member char '(?\{ ?\})) 0 1))))
6498 (set-register org-agenda-query-register org-agenda-query-string)
6499 (org-agenda-redo))
6500 (t (error "Cannot manipulate query for %s-type agenda buffers"
6501 org-agenda-type))))
6502
6503(defun org-add-to-string (var string)
6504 (set var (concat (symbol-value var) string)))
6505
6506(defun org-agenda-goto-date (date)
6507 "Jump to DATE in agenda."
afe98dfa
CD
6508 (interactive (list (let ((org-read-date-prefer-future
6509 (eval org-agenda-jump-prefer-future)))
6510 (org-read-date))))
20908596
CD
6511 (org-agenda-list nil date))
6512
6513(defun org-agenda-goto-today ()
6514 "Go to today."
6515 (interactive)
6516 (org-agenda-check-type t 'timeline 'agenda)
6517 (let ((tdpos (text-property-any (point-min) (point-max) 'org-today t)))
6518 (cond
6519 (tdpos (goto-char tdpos))
6520 ((eq org-agenda-type 'agenda)
acedf35c 6521 (let* ((sd (org-agenda-compute-starting-span
3ab2c837 6522 (org-today) (or org-agenda-current-span org-agenda-ndays org-agenda-span)))
20908596 6523 (org-agenda-overriding-arguments org-agenda-last-arguments))
acedf35c 6524 (setf (nth 1 org-agenda-overriding-arguments) sd)
20908596
CD
6525 (org-agenda-redo)
6526 (org-agenda-find-same-or-today-or-agenda)))
6527 (t (error "Cannot find today")))))
6528
6529(defun org-agenda-find-same-or-today-or-agenda (&optional cnt)
6530 (goto-char
6531 (or (and cnt (text-property-any (point-min) (point-max) 'org-day-cnt cnt))
6532 (text-property-any (point-min) (point-max) 'org-today t)
6533 (text-property-any (point-min) (point-max) 'org-agenda-type 'agenda)
6534 (point-min))))
6535
6536(defun org-agenda-later (arg)
6537 "Go forward in time by thee current span.
6538With prefix ARG, go forward that many times the current span."
6539 (interactive "p")
6540 (org-agenda-check-type t 'agenda)
acedf35c 6541 (let* ((span org-agenda-current-span)
20908596
CD
6542 (sd org-starting-day)
6543 (greg (calendar-gregorian-from-absolute sd))
8d642074 6544 (cnt (org-get-at-bol 'org-day-cnt))
acedf35c 6545 greg2)
20908596
CD
6546 (cond
6547 ((eq span 'day)
acedf35c 6548 (setq sd (+ arg sd)))
20908596 6549 ((eq span 'week)
acedf35c 6550 (setq sd (+ (* 7 arg) sd)))
20908596
CD
6551 ((eq span 'month)
6552 (setq greg2 (list (+ (car greg) arg) (nth 1 greg) (nth 2 greg))
6553 sd (calendar-absolute-from-gregorian greg2))
acedf35c 6554 (setcar greg2 (1+ (car greg2))))
20908596
CD
6555 ((eq span 'year)
6556 (setq greg2 (list (car greg) (nth 1 greg) (+ arg (nth 2 greg)))
6557 sd (calendar-absolute-from-gregorian greg2))
acedf35c
CD
6558 (setcar (nthcdr 2 greg2) (1+ (nth 2 greg2))))
6559 (t
6560 (setq sd (+ (* span arg) sd))))
20908596 6561 (let ((org-agenda-overriding-arguments
acedf35c 6562 (list (car org-agenda-last-arguments) sd span t)))
20908596
CD
6563 (org-agenda-redo)
6564 (org-agenda-find-same-or-today-or-agenda cnt))))
6565
6566(defun org-agenda-earlier (arg)
6567 "Go backward in time by the current span.
6568With prefix ARG, go backward that many times the current span."
6569 (interactive "p")
6570 (org-agenda-later (- arg)))
6571
c8d0cf5c
CD
6572(defun org-agenda-view-mode-dispatch ()
6573 "Call one of the view mode commands."
6574 (interactive)
3ab2c837
BG
6575 (message "View: [d]ay [w]eek [m]onth [y]ear [SPC]reset [q]uit/abort
6576 time[G]rid [[]inactive [f]ollow [l]og [L]og-all [c]lockcheck
6577 [a]rch-trees [A]rch-files clock[R]eport include[D]iary
6578 [E]ntryText")
c8d0cf5c
CD
6579 (let ((a (read-char-exclusive)))
6580 (case a
3ab2c837 6581 (?\ (call-interactively 'org-agenda-reset-view))
c8d0cf5c
CD
6582 (?d (call-interactively 'org-agenda-day-view))
6583 (?w (call-interactively 'org-agenda-week-view))
6584 (?m (call-interactively 'org-agenda-month-view))
6585 (?y (call-interactively 'org-agenda-year-view))
6586 (?l (call-interactively 'org-agenda-log-mode))
ed21c5c8 6587 (?L (org-agenda-log-mode '(4)))
3ab2c837 6588 (?c (org-agenda-log-mode 'clockcheck))
54a0dee5 6589 ((?F ?f) (call-interactively 'org-agenda-follow-mode))
c8d0cf5c
CD
6590 (?a (call-interactively 'org-agenda-archives-mode))
6591 (?A (org-agenda-archives-mode 'files))
54a0dee5
CD
6592 ((?R ?r) (call-interactively 'org-agenda-clockreport-mode))
6593 ((?E ?e) (call-interactively 'org-agenda-entry-text-mode))
c8d0cf5c
CD
6594 (?G (call-interactively 'org-agenda-toggle-time-grid))
6595 (?D (call-interactively 'org-agenda-toggle-diary))
ed21c5c8 6596 (?\! (call-interactively 'org-agenda-toggle-deadlines))
54a0dee5
CD
6597 (?\[ (let ((org-agenda-include-inactive-timestamps t))
6598 (org-agenda-check-type t 'timeline 'agenda)
6599 (org-agenda-redo))
6600 (message "Display now includes inactive timestamps as well"))
c8d0cf5c
CD
6601 (?q (message "Abort"))
6602 (otherwise (error "Invalid key" )))))
6603
3ab2c837
BG
6604(defun org-agenda-reset-view ()
6605 "Switch to default view for agenda."
6606 (interactive)
6607 (org-agenda-change-time-span (or org-agenda-ndays org-agenda-span)))
20908596
CD
6608(defun org-agenda-day-view (&optional day-of-year)
6609 "Switch to daily view for agenda.
6610With argument DAY-OF-YEAR, switch to that day of the year."
6611 (interactive "P")
20908596
CD
6612 (org-agenda-change-time-span 'day day-of-year))
6613(defun org-agenda-week-view (&optional iso-week)
6614 "Switch to daily view for agenda.
6615With argument ISO-WEEK, switch to the corresponding ISO week.
6616If ISO-WEEK has more then 2 digits, only the last two encode the
6617week. Any digits before this encode a year. So 200712 means
6618week 12 of year 2007. Years in the range 1938-2037 can also be
6619written as 2-digit years."
6620 (interactive "P")
20908596
CD
6621 (org-agenda-change-time-span 'week iso-week))
6622(defun org-agenda-month-view (&optional month)
b349f79f 6623 "Switch to monthly view for agenda.
20908596
CD
6624With argument MONTH, switch to that month."
6625 (interactive "P")
6626 (org-agenda-change-time-span 'month month))
6627(defun org-agenda-year-view (&optional year)
b349f79f 6628 "Switch to yearly view for agenda.
20908596
CD
6629With argument YEAR, switch to that year.
6630If MONTH has more then 2 digits, only the last two encode the
6631month. Any digits before this encode a year. So 200712 means
6632December year 2007. Years in the range 1938-2037 can also be
6633written as 2-digit years."
6634 (interactive "P")
6635 (when year
6636 (setq year (org-small-year-to-year year)))
6637 (if (y-or-n-p "Are you sure you want to compute the agenda for an entire year? ")
6638 (org-agenda-change-time-span 'year year)
6639 (error "Abort")))
6640
6641(defun org-agenda-change-time-span (span &optional n)
6642 "Change the agenda view to SPAN.
6643SPAN may be `day', `week', `month', `year'."
6644 (org-agenda-check-type t 'agenda)
acedf35c 6645 (if (and (not n) (equal org-agenda-current-span span))
20908596 6646 (error "Viewing span is already \"%s\"" span))
8d642074 6647 (let* ((sd (or (org-get-at-bol 'day)
20908596 6648 org-starting-day))
acedf35c 6649 (sd (org-agenda-compute-starting-span sd span n))
20908596 6650 (org-agenda-overriding-arguments
3ab2c837
BG
6651 (or org-agenda-overriding-arguments
6652 (list (car org-agenda-last-arguments) sd span t))))
20908596
CD
6653 (org-agenda-redo)
6654 (org-agenda-find-same-or-today-or-agenda))
6655 (org-agenda-set-mode-name)
6656 (message "Switched to %s view" span))
6657
acedf35c
CD
6658(defun org-agenda-compute-starting-span (sd span &optional n)
6659 "Compute starting date for agenda.
20908596
CD
6660SPAN may be `day', `week', `month', `year'. The return value
6661is a cons cell with the starting date and the number of days,
6662so that the date SD will be in that range."
6663 (let* ((greg (calendar-gregorian-from-absolute sd))
6664 (dg (nth 1 greg))
6665 (mg (car greg))
acedf35c 6666 (yg (nth 2 greg)))
20908596
CD
6667 (cond
6668 ((eq span 'day)
6669 (when n
6670 (setq sd (+ (calendar-absolute-from-gregorian
6671 (list mg 1 yg))
acedf35c 6672 n -1))))
20908596
CD
6673 ((eq span 'week)
6674 (let* ((nt (calendar-day-of-week
6675 (calendar-gregorian-from-absolute sd)))
6676 (d (if org-agenda-start-on-weekday
6677 (- nt org-agenda-start-on-weekday)
acedf35c
CD
6678 0))
6679 y1)
20908596
CD
6680 (setq sd (- sd (+ (if (< d 0) 7 0) d)))
6681 (when n
6682 (require 'cal-iso)
20908596
CD
6683 (when (> n 99)
6684 (setq y1 (org-small-year-to-year (/ n 100))
6685 n (mod n 100)))
6686 (setq sd
6687 (calendar-absolute-from-iso
6688 (list n 1
acedf35c 6689 (or y1 (nth 2 (calendar-iso-from-absolute sd)))))))))
20908596 6690 ((eq span 'month)
acedf35c
CD
6691 (let (y1)
6692 (when (and n (> n 99))
6693 (setq y1 (org-small-year-to-year (/ n 100))
6694 n (mod n 100)))
6695 (setq sd (calendar-absolute-from-gregorian
6696 (list (or n mg) 1 (or y1 yg))))))
20908596
CD
6697 ((eq span 'year)
6698 (setq sd (calendar-absolute-from-gregorian
acedf35c
CD
6699 (list 1 1 (or n yg))))))
6700 sd))
20908596
CD
6701
6702(defun org-agenda-next-date-line (&optional arg)
6703 "Jump to the next line indicating a date in agenda buffer."
6704 (interactive "p")
6705 (org-agenda-check-type t 'agenda 'timeline)
6706 (beginning-of-line 1)
6707 ;; This does not work if user makes date format that starts with a blank
6708 (if (looking-at "^\\S-") (forward-char 1))
6709 (if (not (re-search-forward "^\\S-" nil t arg))
6710 (progn
6711 (backward-char 1)
6712 (error "No next date after this line in this buffer")))
6713 (goto-char (match-beginning 0)))
6714
6715(defun org-agenda-previous-date-line (&optional arg)
6716 "Jump to the previous line indicating a date in agenda buffer."
6717 (interactive "p")
6718 (org-agenda-check-type t 'agenda 'timeline)
6719 (beginning-of-line 1)
6720 (if (not (re-search-backward "^\\S-" nil t arg))
6721 (error "No previous date before this line in this buffer")))
6722
6723;; Initialize the highlight
86fbb8ca
CD
6724(defvar org-hl (make-overlay 1 1))
6725(overlay-put org-hl 'face 'highlight)
20908596
CD
6726
6727(defun org-highlight (begin end &optional buffer)
6728 "Highlight a region with overlay."
86fbb8ca 6729 (move-overlay org-hl begin end (or buffer (current-buffer))))
20908596
CD
6730
6731(defun org-unhighlight ()
6732 "Detach overlay INDEX."
86fbb8ca 6733 (org-detach-overlay org-hl))
20908596
CD
6734
6735;; FIXME this is currently not used.
6736(defun org-highlight-until-next-command (beg end &optional buffer)
6737 "Move the highlight overlay to BEG/END, remove it before the next command."
6738 (org-highlight beg end buffer)
6739 (add-hook 'pre-command-hook 'org-unhighlight-once))
6740(defun org-unhighlight-once ()
6741 "Remove the highlight from its position, and this function from the hook."
6742 (remove-hook 'pre-command-hook 'org-unhighlight-once)
6743 (org-unhighlight))
6744
6745(defun org-agenda-follow-mode ()
6746 "Toggle follow mode in an agenda buffer."
6747 (interactive)
6748 (setq org-agenda-follow-mode (not org-agenda-follow-mode))
6749 (org-agenda-set-mode-name)
e66ba1df 6750 (org-agenda-do-context-action)
20908596
CD
6751 (message "Follow mode is %s"
6752 (if org-agenda-follow-mode "on" "off")))
6753
54a0dee5
CD
6754(defun org-agenda-entry-text-mode (&optional arg)
6755 "Toggle entry text mode in an agenda buffer."
6756 (interactive "P")
365f8d85
SM
6757 (setq org-agenda-entry-text-mode (or (integerp arg)
6758 (not org-agenda-entry-text-mode)))
54a0dee5
CD
6759 (org-agenda-entry-text-hide)
6760 (and org-agenda-entry-text-mode
6761 (let ((org-agenda-entry-text-maxlines
6762 (if (integerp arg) arg org-agenda-entry-text-maxlines)))
6763 (org-agenda-entry-text-show)))
6764 (org-agenda-set-mode-name)
6765 (message "Entry text mode is %s. Maximum number of lines is %d"
6766 (if org-agenda-entry-text-mode "on" "off")
6767 (if (integerp arg) arg org-agenda-entry-text-maxlines)))
6768
acedf35c
CD
6769(defun org-agenda-clockreport-mode (&optional with-filter)
6770 "Toggle clocktable mode in an agenda buffer.
6771With prefix arg WITH-FILTER, make the clocktable respect the current
6772agenda filter."
6773 (interactive "P")
20908596 6774 (org-agenda-check-type t 'agenda)
acedf35c
CD
6775 (if with-filter
6776 (setq org-agenda-clockreport-mode 'with-filter)
6777 (setq org-agenda-clockreport-mode (not org-agenda-clockreport-mode)))
20908596
CD
6778 (org-agenda-set-mode-name)
6779 (org-agenda-redo)
6780 (message "Clocktable mode is %s"
6781 (if org-agenda-clockreport-mode "on" "off")))
6782
93b62de8
CD
6783(defun org-agenda-log-mode (&optional special)
6784 "Toggle log mode in an agenda buffer.
6785With argument SPECIAL, show all possible log items, not only the ones
6786configured in `org-agenda-log-mode-items'.
6787With a double `C-u' prefix arg, show *only* log items, nothing else."
6788 (interactive "P")
20908596 6789 (org-agenda-check-type t 'agenda 'timeline)
93b62de8 6790 (setq org-agenda-show-log
3ab2c837
BG
6791 (cond
6792 ((equal special '(16)) 'only)
6793 ((eq special 'clockcheck)
6794 (if (eq org-agenda-show-log 'clockcheck)
6795 nil 'clockcheck))
6796 (special '(closed clock state))
6797 (t (not org-agenda-show-log))))
20908596
CD
6798 (org-agenda-set-mode-name)
6799 (org-agenda-redo)
6800 (message "Log mode is %s"
6801 (if org-agenda-show-log "on" "off")))
6802
2c3ad40d 6803(defun org-agenda-archives-mode (&optional with-files)
c8d0cf5c
CD
6804 "Toggle inclusion of items in trees marked with :ARCHIVE:.
6805When called with a prefix argument, include all archive files as well."
2c3ad40d
CD
6806 (interactive "P")
6807 (setq org-agenda-archives-mode
6808 (if with-files t (if org-agenda-archives-mode nil 'trees)))
6809 (org-agenda-set-mode-name)
6810 (org-agenda-redo)
6811 (message
6812 "%s"
6813 (cond
6814 ((eq org-agenda-archives-mode nil)
6815 "No archives are included")
6816 ((eq org-agenda-archives-mode 'trees)
6817 (format "Trees with :%s: tag are included" org-archive-tag))
6818 ((eq org-agenda-archives-mode t)
6819 (format "Trees with :%s: tag and all active archive files are included"
6820 org-archive-tag)))))
6821
20908596
CD
6822(defun org-agenda-toggle-diary ()
6823 "Toggle diary inclusion in an agenda buffer."
6824 (interactive)
6825 (org-agenda-check-type t 'agenda)
6826 (setq org-agenda-include-diary (not org-agenda-include-diary))
6827 (org-agenda-redo)
6828 (org-agenda-set-mode-name)
6829 (message "Diary inclusion turned %s"
6830 (if org-agenda-include-diary "on" "off")))
6831
ed21c5c8 6832(defun org-agenda-toggle-deadlines ()
acedf35c 6833 "Toggle inclusion of entries with a deadline in an agenda buffer."
ed21c5c8
CD
6834 (interactive)
6835 (org-agenda-check-type t 'agenda)
6836 (setq org-agenda-include-deadlines (not org-agenda-include-deadlines))
6837 (org-agenda-redo)
6838 (org-agenda-set-mode-name)
6839 (message "Deadlines inclusion turned %s"
6840 (if org-agenda-include-deadlines "on" "off")))
6841
20908596
CD
6842(defun org-agenda-toggle-time-grid ()
6843 "Toggle time grid in an agenda buffer."
6844 (interactive)
6845 (org-agenda-check-type t 'agenda)
6846 (setq org-agenda-use-time-grid (not org-agenda-use-time-grid))
6847 (org-agenda-redo)
6848 (org-agenda-set-mode-name)
6849 (message "Time-grid turned %s"
6850 (if org-agenda-use-time-grid "on" "off")))
6851
6852(defun org-agenda-set-mode-name ()
6853 "Set the mode name to indicate all the small mode settings."
6854 (setq mode-name
acedf35c
CD
6855 (list "Org-Agenda"
6856 (if (get 'org-agenda-files 'org-restrict) " []" "")
6857 " "
6858 '(:eval (org-agenda-span-name org-agenda-current-span))
6859 (if org-agenda-follow-mode " Follow" "")
6860 (if org-agenda-entry-text-mode " ETxt" "")
6861 (if org-agenda-include-diary " Diary" "")
6862 (if org-agenda-include-deadlines " Ddl" "")
6863 (if org-agenda-use-time-grid " Grid" "")
6864 (if (and (boundp 'org-habit-show-habits)
6865 org-habit-show-habits) " Habit" "")
3ab2c837
BG
6866 (cond
6867 ((consp org-agenda-show-log) " LogAll")
6868 ((eq org-agenda-show-log 'clockcheck) " ClkCk")
6869 (org-agenda-show-log " Log")
6870 (t ""))
e66ba1df
BG
6871 (if (or org-agenda-category-filter (get 'org-agenda-category-filter
6872 :preset-filter))
6873 '(:eval (org-propertize
6874 (concat " <"
6875 (mapconcat
6876 'identity
6877 (append
6878 (get 'org-agenda-category-filter :preset-filter)
6879 org-agenda-category-filter)
6880 "")
6881 ">")
6882 'face 'org-agenda-filter-category
6883 'help-echo "Category used in filtering"))
6884 "")
6885 (if (or org-agenda-tag-filter (get 'org-agenda-tag-filter
acedf35c 6886 :preset-filter))
e66ba1df
BG
6887 '(:eval (org-propertize
6888 (concat " {"
6889 (mapconcat
6890 'identity
6891 (append
6892 (get 'org-agenda-tag-filter :preset-filter)
6893 org-agenda-tag-filter)
6894 "")
6895 "}")
6896 'face 'org-agenda-filter-tags
6897 'help-echo "Tags used in filtering"))
acedf35c
CD
6898 "")
6899 (if org-agenda-archives-mode
6900 (if (eq org-agenda-archives-mode t)
6901 " Archives"
6902 (format " :%s:" org-archive-tag))
6903 "")
6904 (if org-agenda-clockreport-mode
6905 (if (eq org-agenda-clockreport-mode 'with-filter)
6906 " Clock{}" " Clock")
6907 "")))
20908596
CD
6908 (force-mode-line-update))
6909
6910(defun org-agenda-post-command-hook ()
b349f79f
CD
6911 (setq org-agenda-type
6912 (or (get-text-property (point) 'org-agenda-type)
6913 (get-text-property (max (point-min) (1- (point)))
8bfe682a
CD
6914 'org-agenda-type))))
6915
6916(defun org-agenda-next-line ()
86fbb8ca 6917 "Move cursor to the next line, and show if follow mode is active."
8bfe682a
CD
6918 (interactive)
6919 (call-interactively 'next-line)
1bcdebed
CD
6920 (org-agenda-do-context-action))
6921
8bfe682a
CD
6922(defun org-agenda-previous-line ()
6923 "Move cursor to the previous line, and show if follow-mode is active."
8bfe682a
CD
6924 (interactive)
6925 (call-interactively 'previous-line)
1bcdebed
CD
6926 (org-agenda-do-context-action))
6927
6928(defun org-agenda-do-context-action ()
86fbb8ca 6929 "Show outline path and, maybe, follow mode window."
1bcdebed 6930 (let ((m (org-get-at-bol 'org-marker)))
e66ba1df
BG
6931 (when (and (markerp m) (marker-buffer m))
6932 (and org-agenda-follow-mode
6933 (if org-agenda-follow-indirect
6934 (org-agenda-tree-to-indirect-buffer)
6935 (org-agenda-show)))
6936 (and org-agenda-show-outline-path
6937 (org-with-point-at m (org-display-outline-path t))))))
20908596
CD
6938
6939(defun org-agenda-show-priority ()
6940 "Show the priority of the current item.
6941This priority is composed of the main priority given with the [#A] cookies,
6942and by additional input from the age of a schedules or deadline entry."
6943 (interactive)
8d642074 6944 (let* ((pri (org-get-at-bol 'priority)))
20908596
CD
6945 (message "Priority is %d" (if pri pri -1000))))
6946
6947(defun org-agenda-show-tags ()
6948 "Show the tags applicable to the current item."
6949 (interactive)
8d642074 6950 (let* ((tags (org-get-at-bol 'tags)))
20908596
CD
6951 (if tags
6952 (message "Tags are :%s:"
6953 (org-no-properties (mapconcat 'identity tags ":")))
6954 (message "No tags associated with this line"))))
6955
6956(defun org-agenda-goto (&optional highlight)
6957 "Go to the Org-mode file which contains the item at point."
6958 (interactive)
8d642074 6959 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
6960 (org-agenda-error)))
6961 (buffer (marker-buffer marker))
6962 (pos (marker-position marker)))
6963 (switch-to-buffer-other-window buffer)
6964 (widen)
86fbb8ca 6965 (push-mark)
20908596 6966 (goto-char pos)
e66ba1df 6967 (when (eq major-mode 'org-mode)
20908596
CD
6968 (org-show-context 'agenda)
6969 (save-excursion
6970 (and (outline-next-heading)
3ab2c837
BG
6971 (org-flag-heading nil)))) ; show the next heading
6972 (when (outline-invisible-p)
6973 (show-entry)) ; display invisible text
20908596
CD
6974 (recenter (/ (window-height) 2))
6975 (run-hooks 'org-agenda-after-show-hook)
6976 (and highlight (org-highlight (point-at-bol) (point-at-eol)))))
6977
6978(defvar org-agenda-after-show-hook nil
6979 "Normal hook run after an item has been shown from the agenda.
6980Point is in the buffer where the item originated.")
6981
6982(defun org-agenda-kill ()
6983 "Kill the entry or subtree belonging to the current agenda entry."
6984 (interactive)
6985 (or (eq major-mode 'org-agenda-mode) (error "Not in agenda"))
8d642074 6986 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
6987 (org-agenda-error)))
6988 (buffer (marker-buffer marker))
6989 (pos (marker-position marker))
8d642074 6990 (type (org-get-at-bol 'type))
20908596
CD
6991 dbeg dend (n 0) conf)
6992 (org-with-remote-undo buffer
6993 (with-current-buffer buffer
6994 (save-excursion
6995 (goto-char pos)
e66ba1df 6996 (if (and (eq major-mode 'org-mode) (not (member type '("sexp"))))
20908596
CD
6997 (setq dbeg (progn (org-back-to-heading t) (point))
6998 dend (org-end-of-subtree t t))
6999 (setq dbeg (point-at-bol)
7000 dend (min (point-max) (1+ (point-at-eol)))))
7001 (goto-char dbeg)
7002 (while (re-search-forward "^[ \t]*\\S-" dend t) (setq n (1+ n)))))
7003 (setq conf (or (eq t org-agenda-confirm-kill)
7004 (and (numberp org-agenda-confirm-kill)
7005 (> n org-agenda-confirm-kill))))
7006 (and conf
7007 (not (y-or-n-p
7008 (format "Delete entry with %d lines in buffer \"%s\"? "
7009 n (buffer-name buffer))))
7010 (error "Abort"))
7011 (org-remove-subtree-entries-from-agenda buffer dbeg dend)
7012 (with-current-buffer buffer (delete-region dbeg dend))
7013 (message "Agenda item and source killed"))))
7014
8bfe682a
CD
7015(defvar org-archive-default-command)
7016(defun org-agenda-archive-default ()
7017 "Archive the entry or subtree belonging to the current agenda entry."
7018 (interactive)
7019 (require 'org-archive)
7020 (org-agenda-archive-with org-archive-default-command))
7021
7022(defun org-agenda-archive-default-with-confirmation ()
7023 "Archive the entry or subtree belonging to the current agenda entry."
7024 (interactive)
7025 (require 'org-archive)
7026 (org-agenda-archive-with org-archive-default-command 'confirm))
7027
20908596
CD
7028(defun org-agenda-archive ()
7029 "Archive the entry or subtree belonging to the current agenda entry."
7030 (interactive)
8bfe682a 7031 (org-agenda-archive-with 'org-archive-subtree))
20908596
CD
7032
7033(defun org-agenda-archive-to-archive-sibling ()
8bfe682a
CD
7034 "Move the entry to the archive sibling."
7035 (interactive)
7036 (org-agenda-archive-with 'org-archive-to-archive-sibling))
7037
7038(defun org-agenda-archive-with (cmd &optional confirm)
20908596
CD
7039 "Move the entry to the archive sibling."
7040 (interactive)
7041 (or (eq major-mode 'org-agenda-mode) (error "Not in agenda"))
8d642074 7042 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
7043 (org-agenda-error)))
7044 (buffer (marker-buffer marker))
7045 (pos (marker-position marker)))
7046 (org-with-remote-undo buffer
7047 (with-current-buffer buffer
e66ba1df 7048 (if (eq major-mode 'org-mode)
8bfe682a
CD
7049 (if (and confirm
7050 (not (y-or-n-p "Archive this subtree or entry? ")))
7051 (error "Abort")
7052 (save-excursion
7053 (goto-char pos)
7054 (org-remove-subtree-entries-from-agenda)
7055 (org-back-to-heading t)
7056 (funcall cmd)))
20908596
CD
7057 (error "Archiving works only in Org-mode files"))))))
7058
7059(defun org-remove-subtree-entries-from-agenda (&optional buf beg end)
7060 "Remove all lines in the agenda that correspond to a given subtree.
7061The subtree is the one in buffer BUF, starting at BEG and ending at END.
7062If this information is not given, the function uses the tree at point."
7063 (let ((buf (or buf (current-buffer))) m p)
7064 (save-excursion
7065 (unless (and beg end)
7066 (org-back-to-heading t)
7067 (setq beg (point))
7068 (org-end-of-subtree t)
7069 (setq end (point)))
7070 (set-buffer (get-buffer org-agenda-buffer-name))
7071 (save-excursion
7072 (goto-char (point-max))
7073 (beginning-of-line 1)
7074 (while (not (bobp))
8d642074 7075 (when (and (setq m (org-get-at-bol 'org-marker))
20908596
CD
7076 (equal buf (marker-buffer m))
7077 (setq p (marker-position m))
7078 (>= p beg)
c8d0cf5c 7079 (< p end))
20908596
CD
7080 (let ((inhibit-read-only t))
7081 (delete-region (point-at-bol) (1+ (point-at-eol)))))
7082 (beginning-of-line 0))))))
7083
86fbb8ca 7084(defun org-agenda-refile (&optional goto rfloc no-update)
c8d0cf5c 7085 "Refile the item at point."
54a0dee5
CD
7086 (interactive "P")
7087 (if (equal goto '(16))
7088 (org-refile-goto-last-stored)
8d642074 7089 (let* ((marker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
7090 (org-agenda-error)))
7091 (buffer (marker-buffer marker))
7092 (pos (marker-position marker))
7093 (rfloc (or rfloc
7094 (org-refile-get-location
3ab2c837 7095 (if goto "Goto" "Refile to") buffer
54a0dee5
CD
7096 org-refile-allow-creating-parent-nodes))))
7097 (with-current-buffer buffer
7098 (save-excursion
7099 (save-restriction
7100 (widen)
7101 (goto-char marker)
7102 (org-remove-subtree-entries-from-agenda)
86fbb8ca
CD
7103 (org-refile goto buffer rfloc)))))
7104 (unless no-update (org-agenda-redo))))
54a0dee5
CD
7105
7106(defun org-agenda-open-link (&optional arg)
7107 "Follow the link in the current line, if any.
8bfe682a 7108This looks for a link in the displayed line in the agenda. It also looks
54a0dee5 7109at the text of the entry itself."
c8d0cf5c 7110 (interactive "P")
8d642074
CD
7111 (let* ((marker (or (org-get-at-bol 'org-hd-marker)
7112 (org-get-at-bol 'org-marker)))
7113 (buffer (and marker (marker-buffer marker)))
7114 (prefix (buffer-substring
3ab2c837 7115 (point-at-bol) (point-at-eol))))
8bfe682a
CD
7116 (cond
7117 (buffer
7118 (with-current-buffer buffer
7119 (save-excursion
7120 (save-restriction
7121 (widen)
7122 (goto-char marker)
7123 (org-offer-links-in-entry arg prefix)))))
7124 ((or (org-in-regexp (concat "\\(" org-bracket-link-regexp "\\)"))
7125 (save-excursion
7126 (beginning-of-line 1)
7127 (looking-at (concat ".*?\\(" org-bracket-link-regexp "\\)"))))
7128 (org-open-link-from-string (match-string 1)))
7129 (t (error "No link to open here")))))
20908596
CD
7130
7131(defun org-agenda-copy-local-variable (var)
7132 "Get a variable from a referenced buffer and install it here."
8d642074 7133 (let ((m (org-get-at-bol 'org-marker)))
20908596
CD
7134 (when (and m (buffer-live-p (marker-buffer m)))
7135 (org-set-local var (with-current-buffer (marker-buffer m)
7136 (symbol-value var))))))
7137
7138(defun org-agenda-switch-to (&optional delete-other-windows)
7139 "Go to the Org-mode file which contains the item at point."
7140 (interactive)
8bfe682a
CD
7141 (if (and org-return-follows-link
7142 (not (org-get-at-bol 'org-marker))
7143 (org-in-regexp org-bracket-link-regexp))
7144 (org-open-link-from-string (match-string 0))
7145 (let* ((marker (or (org-get-at-bol 'org-marker)
7146 (org-agenda-error)))
7147 (buffer (marker-buffer marker))
7148 (pos (marker-position marker)))
e66ba1df 7149 (org-pop-to-buffer-same-window buffer)
8bfe682a
CD
7150 (and delete-other-windows (delete-other-windows))
7151 (widen)
7152 (goto-char pos)
e66ba1df 7153 (when (eq major-mode 'org-mode)
8bfe682a
CD
7154 (org-show-context 'agenda)
7155 (save-excursion
7156 (and (outline-next-heading)
3ab2c837
BG
7157 (org-flag-heading nil))) ; show the next heading
7158 (when (outline-invisible-p)
7159 (show-entry)))))) ; display invisible text
20908596
CD
7160
7161(defun org-agenda-goto-mouse (ev)
7162 "Go to the Org-mode file which contains the item at the mouse click."
7163 (interactive "e")
7164 (mouse-set-point ev)
7165 (org-agenda-goto))
7166
fdf730ed
CD
7167(defun org-agenda-show (&optional full-entry)
7168 "Display the Org-mode file which contains the item at point.
7169With prefix argument FULL-ENTRY, make the entire entry visible
7170if it was hidden in the outline."
7171 (interactive "P")
20908596 7172 (let ((win (selected-window)))
fdf730ed
CD
7173 (if full-entry
7174 (let ((org-show-entry-below t))
7175 (org-agenda-goto t))
7176 (org-agenda-goto t))
20908596
CD
7177 (select-window win)))
7178
8bfe682a
CD
7179(defvar org-agenda-show-window nil)
7180(defun org-agenda-show-and-scroll-up ()
7181 "Display the Org-mode file which contains the item at point.
7182When called repeatedly, scroll the window that is displaying the buffer."
7183 (interactive)
7184 (let ((win (selected-window)))
7185 (if (and (window-live-p org-agenda-show-window)
7186 (eq this-command last-command))
7187 (progn
7188 (select-window org-agenda-show-window)
7189 (ignore-errors (scroll-up)))
7190 (org-agenda-goto t)
7191 (show-subtree)
7192 (setq org-agenda-show-window (selected-window)))
7193 (select-window win)))
7194
7195(defun org-agenda-show-scroll-down ()
7196 "Scroll down the window showing the agenda."
7197 (interactive)
7198 (let ((win (selected-window)))
7199 (when (window-live-p org-agenda-show-window)
7200 (select-window org-agenda-show-window)
7201 (ignore-errors (scroll-down))
7202 (select-window win))))
7203
c8d0cf5c
CD
7204(defun org-agenda-show-1 (&optional more)
7205 "Display the Org-mode file which contains the item at point.
8bfe682a 7206The prefix arg selects the amount of information to display:
c8d0cf5c
CD
7207
72080 hide the subtree
72091 just show the entry according to defaults.
54a0dee5
CD
72102 show the children view
72113 show the subtree view
c8d0cf5c
CD
72124 show the entire subtree and any LOGBOOK drawers
72135 show the entire subtree and any drawers
7214With prefix argument FULL-ENTRY, make the entire entry visible
7215if it was hidden in the outline."
7216 (interactive "p")
7217 (let ((win (selected-window)))
7218 (org-agenda-goto t)
7219 (org-recenter-heading 1)
7220 (cond
7221 ((= more 0)
7222 (hide-subtree)
54a0dee5
CD
7223 (save-excursion
7224 (org-back-to-heading)
7225 (run-hook-with-args 'org-cycle-hook 'folded))
7226 (message "Remote: FOLDED"))
3ab2c837 7227 ((and (org-called-interactively-p 'any) (= more 1))
c8d0cf5c
CD
7228 (message "Remote: show with default settings"))
7229 ((= more 2)
7230 (show-entry)
54a0dee5 7231 (show-children)
c8d0cf5c
CD
7232 (save-excursion
7233 (org-back-to-heading)
54a0dee5
CD
7234 (run-hook-with-args 'org-cycle-hook 'children))
7235 (message "Remote: CHILDREN"))
c8d0cf5c
CD
7236 ((= more 3)
7237 (show-subtree)
7238 (save-excursion
7239 (org-back-to-heading)
54a0dee5
CD
7240 (run-hook-with-args 'org-cycle-hook 'subtree))
7241 (message "Remote: SUBTREE"))
c8d0cf5c
CD
7242 ((= more 4)
7243 (let* ((org-drawers (delete "LOGBOOK" (copy-sequence org-drawers)))
7244 (org-drawer-regexp
7245 (concat "^[ \t]*:\\("
7246 (mapconcat 'regexp-quote org-drawers "\\|")
7247 "\\):[ \t]*$")))
7248 (show-subtree)
7249 (save-excursion
7250 (org-back-to-heading)
7251 (org-cycle-hide-drawers 'subtree)))
54a0dee5 7252 (message "Remote: SUBTREE AND LOGBOOK"))
c8d0cf5c
CD
7253 ((> more 4)
7254 (show-subtree)
54a0dee5 7255 (message "Remote: SUBTREE AND ALL DRAWERS")))
c8d0cf5c
CD
7256 (select-window win)))
7257
7258(defun org-recenter-heading (n)
7259 (save-excursion
7260 (org-back-to-heading)
7261 (recenter n)))
7262
7263(defvar org-agenda-cycle-counter nil)
54a0dee5 7264(defun org-agenda-cycle-show (&optional n)
c8d0cf5c
CD
7265 "Show the current entry in another window, with default settings.
7266Default settings are taken from `org-show-hierarchy-above' and siblings.
54a0dee5 7267When use repeatedly in immediate succession, the remote entry will cycle
c8d0cf5c
CD
7268through visibility
7269
54a0dee5
CD
7270children -> subtree -> folded
7271
7272When called with a numeric prefix arg, that arg will be passed through to
7273`org-agenda-show-1'. For the interpretation of that argument, see the
7274docstring of `org-agenda-show-1'."
7275 (interactive "P")
7276 (if (integerp n)
7277 (setq org-agenda-cycle-counter n)
7278 (if (not (eq last-command this-command))
7279 (setq org-agenda-cycle-counter 1)
7280 (if (equal org-agenda-cycle-counter 0)
7281 (setq org-agenda-cycle-counter 2)
7282 (setq org-agenda-cycle-counter (1+ org-agenda-cycle-counter))
7283 (if (> org-agenda-cycle-counter 3)
7284 (setq org-agenda-cycle-counter 0)))))
c8d0cf5c
CD
7285 (org-agenda-show-1 org-agenda-cycle-counter))
7286
20908596
CD
7287(defun org-agenda-recenter (arg)
7288 "Display the Org-mode file which contains the item at point and recenter."
7289 (interactive "P")
7290 (let ((win (selected-window)))
7291 (org-agenda-goto t)
7292 (recenter arg)
7293 (select-window win)))
7294
7295(defun org-agenda-show-mouse (ev)
7296 "Display the Org-mode file which contains the item at the mouse click."
7297 (interactive "e")
7298 (mouse-set-point ev)
7299 (org-agenda-show))
7300
7301(defun org-agenda-check-no-diary ()
7302 "Check if the entry is a diary link and abort if yes."
8d642074 7303 (if (org-get-at-bol 'org-agenda-diary-link)
20908596
CD
7304 (org-agenda-error)))
7305
7306(defun org-agenda-error ()
7307 (error "Command not allowed in this line"))
7308
7309(defun org-agenda-tree-to-indirect-buffer ()
7310 "Show the subtree corresponding to the current entry in an indirect buffer.
7311This calls the command `org-tree-to-indirect-buffer' from the original
7312Org-mode buffer.
7313With numerical prefix arg ARG, go up to this level and then take that tree.
86fbb8ca
CD
7314With a \\[universal-argument] prefix, make a separate frame for this tree (i.e. don't
7315use the dedicated frame)."
20908596 7316 (interactive)
e66ba1df
BG
7317 (if (and current-prefix-arg (listp current-prefix-arg))
7318 (org-agenda-do-tree-to-indirect-buffer)
7319 (let ((agenda-window (selected-window))
153ae947
BG
7320 (indirect-window
7321 (and org-last-indirect-buffer
7322 (get-buffer-window org-last-indirect-buffer))))
e66ba1df
BG
7323 (save-window-excursion (org-agenda-do-tree-to-indirect-buffer))
7324 (unwind-protect
7325 (progn
153ae947 7326 (unless (and indirect-window (window-live-p indirect-window))
e66ba1df
BG
7327 (setq indirect-window (split-window agenda-window)))
7328 (select-window indirect-window)
7329 (switch-to-buffer org-last-indirect-buffer :norecord)
7330 (fit-window-to-buffer indirect-window))
153ae947 7331 (select-window (get-buffer-window org-agenda-buffer-name))))))
e66ba1df
BG
7332
7333(defun org-agenda-do-tree-to-indirect-buffer ()
7334 "Same as `org-agenda-tree-to-indirect-buffer' without saving window."
20908596 7335 (org-agenda-check-no-diary)
8d642074 7336 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
7337 (org-agenda-error)))
7338 (buffer (marker-buffer marker))
7339 (pos (marker-position marker)))
7340 (with-current-buffer buffer
7341 (save-excursion
7342 (goto-char pos)
7343 (call-interactively 'org-tree-to-indirect-buffer)))))
7344
7345(defvar org-last-heading-marker (make-marker)
7346 "Marker pointing to the headline that last changed its TODO state
7347by a remote command from the agenda.")
7348
7349(defun org-agenda-todo-nextset ()
7350 "Switch TODO entry to next sequence."
7351 (interactive)
7352 (org-agenda-todo 'nextset))
7353
7354(defun org-agenda-todo-previousset ()
7355 "Switch TODO entry to previous sequence."
7356 (interactive)
7357 (org-agenda-todo 'previousset))
7358
7359(defun org-agenda-todo (&optional arg)
7360 "Cycle TODO state of line at point, also in Org-mode file.
7361This changes the line at point, all other lines in the agenda referring to
7362the same tree node, and the headline of the tree node in the Org-mode file."
7363 (interactive "P")
7364 (org-agenda-check-no-diary)
7365 (let* ((col (current-column))
8d642074 7366 (marker (or (org-get-at-bol 'org-marker)
20908596
CD
7367 (org-agenda-error)))
7368 (buffer (marker-buffer marker))
7369 (pos (marker-position marker))
8d642074 7370 (hdmarker (org-get-at-bol 'org-hd-marker))
acedf35c 7371 (todayp (org-agenda-todayp (org-get-at-bol 'day)))
20908596 7372 (inhibit-read-only t)
93b62de8 7373 org-agenda-headline-snapshot-before-repeat newhead just-one)
20908596
CD
7374 (org-with-remote-undo buffer
7375 (with-current-buffer buffer
7376 (widen)
7377 (goto-char pos)
7378 (org-show-context 'agenda)
7379 (save-excursion
7380 (and (outline-next-heading)
7381 (org-flag-heading nil))) ; show the next heading
a2a2e7fb
CD
7382 (let ((current-prefix-arg arg))
7383 (call-interactively 'org-todo))
20908596
CD
7384 (and (bolp) (forward-char 1))
7385 (setq newhead (org-get-heading))
93b62de8
CD
7386 (when (and (org-bound-and-true-p
7387 org-agenda-headline-snapshot-before-repeat)
7388 (not (equal org-agenda-headline-snapshot-before-repeat
7389 newhead))
7390 todayp)
7391 (setq newhead org-agenda-headline-snapshot-before-repeat
7392 just-one t))
20908596
CD
7393 (save-excursion
7394 (org-back-to-heading)
7395 (move-marker org-last-heading-marker (point))))
7396 (beginning-of-line 1)
7397 (save-excursion
93b62de8 7398 (org-agenda-change-all-lines newhead hdmarker 'fixface just-one))
20908596
CD
7399 (org-move-to-column col))))
7400
7401(defun org-agenda-add-note (&optional arg)
7402 "Add a time-stamped note to the entry at point."
7403 (interactive "P")
7404 (org-agenda-check-no-diary)
8d642074 7405 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
7406 (org-agenda-error)))
7407 (buffer (marker-buffer marker))
7408 (pos (marker-position marker))
8d642074 7409 (hdmarker (org-get-at-bol 'org-hd-marker))
20908596
CD
7410 (inhibit-read-only t))
7411 (with-current-buffer buffer
7412 (widen)
7413 (goto-char pos)
7414 (org-show-context 'agenda)
7415 (save-excursion
7416 (and (outline-next-heading)
7417 (org-flag-heading nil))) ; show the next heading
7418 (org-add-note))))
7419
db55f368 7420(defun org-agenda-change-all-lines (newhead hdmarker
4ed008de 7421 &optional fixface just-this)
20908596
CD
7422 "Change all lines in the agenda buffer which match HDMARKER.
7423The new content of the line will be NEWHEAD (as modified by
e66ba1df 7424`org-agenda-format-item'). HDMARKER is checked with
20908596 7425`equal' against all `org-hd-marker' text properties in the file.
33306645 7426If FIXFACE is non-nil, the face of each item is modified according to
db55f368
CD
7427the new TODO state.
7428If JUST-THIS is non-nil, change just the current line, not all.
33306645 7429If FORCE-TAGS is non nil, the car of it returns the new tags."
20908596 7430 (let* ((inhibit-read-only t)
93b62de8 7431 (line (org-current-line))
fdf730ed 7432 (thetags (with-current-buffer (marker-buffer hdmarker)
4ed008de
CD
7433 (save-excursion (save-restriction (widen)
7434 (goto-char hdmarker)
fdf730ed 7435 (org-get-tags-at)))))
20908596
CD
7436 props m pl undone-face done-face finish new dotime cat tags)
7437 (save-excursion
7438 (goto-char (point-max))
7439 (beginning-of-line 1)
7440 (while (not finish)
7441 (setq finish (bobp))
8d642074 7442 (when (and (setq m (org-get-at-bol 'org-hd-marker))
93b62de8 7443 (or (not just-this) (= (org-current-line) line))
20908596
CD
7444 (equal m hdmarker))
7445 (setq props (text-properties-at (point))
8d642074
CD
7446 dotime (org-get-at-bol 'dotime)
7447 cat (org-get-at-bol 'org-category)
4ed008de 7448 tags thetags
3ab2c837
BG
7449 new
7450 (let ((org-prefix-format-compiled
7451 (or (get-text-property (point) 'format)
7452 org-prefix-format-compiled)))
7453 (with-current-buffer (marker-buffer hdmarker)
7454 (save-excursion
7455 (save-restriction
7456 (widen)
e66ba1df 7457 (org-agenda-format-item (org-get-at-bol 'extra)
3ab2c837
BG
7458 newhead cat tags dotime)))))
7459 pl (text-property-any (point-at-bol) (point-at-eol) 'org-heading t)
8d642074
CD
7460 undone-face (org-get-at-bol 'undone-face)
7461 done-face (org-get-at-bol 'done-face))
3ab2c837 7462 (beginning-of-line 1)
20908596
CD
7463 (cond
7464 ((equal new "")
20908596
CD
7465 (and (looking-at ".*\n?") (replace-match "")))
7466 ((looking-at ".*")
7467 (replace-match new t t)
7468 (beginning-of-line 1)
7469 (add-text-properties (point-at-bol) (point-at-eol) props)
7470 (when fixface
7471 (add-text-properties
7472 (point-at-bol) (point-at-eol)
7473 (list 'face
7474 (if org-last-todo-state-is-todo
7475 undone-face done-face))))
7476 (org-agenda-highlight-todo 'line)
7477 (beginning-of-line 1))
7478 (t (error "Line update did not work"))))
7479 (beginning-of-line 0)))
7480 (org-finalize-agenda)))
7481
7482(defun org-agenda-align-tags (&optional line)
7483 "Align all tags in agenda items to `org-agenda-tags-column'."
7484 (let ((inhibit-read-only t) l c)
7485 (save-excursion
7486 (goto-char (if line (point-at-bol) (point-min)))
afe98dfa 7487 (while (re-search-forward (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@#%:]+:\\)[ \t]*$")
20908596
CD
7488 (if line (point-at-eol) nil) t)
7489 (add-text-properties
7490 (match-beginning 2) (match-end 2)
30ab4580
GM
7491 (list 'face (delq nil (let ((prop (get-text-property
7492 (match-beginning 2) 'face)))
7493 (or (listp prop) (setq prop (list prop)))
7494 (if (memq 'org-tag prop)
7495 prop
7496 (cons 'org-tag prop))))))
20908596
CD
7497 (setq l (- (match-end 2) (match-beginning 2))
7498 c (if (< org-agenda-tags-column 0)
7499 (- (abs org-agenda-tags-column) l)
7500 org-agenda-tags-column))
7501 (delete-region (match-beginning 1) (match-end 1))
7502 (goto-char (match-beginning 1))
7503 (insert (org-add-props
7504 (make-string (max 1 (- c (current-column))) ?\ )
ed21c5c8
CD
7505 (plist-put (copy-sequence (text-properties-at (point)))
7506 'face nil))))
ff4be292
CD
7507 (goto-char (point-min))
7508 (org-font-lock-add-tag-faces (point-max)))))
20908596
CD
7509
7510(defun org-agenda-priority-up ()
7511 "Increase the priority of line at point, also in Org-mode file."
7512 (interactive)
7513 (org-agenda-priority 'up))
7514
7515(defun org-agenda-priority-down ()
7516 "Decrease the priority of line at point, also in Org-mode file."
7517 (interactive)
7518 (org-agenda-priority 'down))
7519
7520(defun org-agenda-priority (&optional force-direction)
7521 "Set the priority of line at point, also in Org-mode file.
7522This changes the line at point, all other lines in the agenda referring to
7523the same tree node, and the headline of the tree node in the Org-mode file."
7524 (interactive)
c8d0cf5c
CD
7525 (unless org-enable-priority-commands
7526 (error "Priority commands are disabled"))
20908596 7527 (org-agenda-check-no-diary)
8d642074 7528 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596 7529 (org-agenda-error)))
8d642074 7530 (hdmarker (org-get-at-bol 'org-hd-marker))
20908596
CD
7531 (buffer (marker-buffer hdmarker))
7532 (pos (marker-position hdmarker))
7533 (inhibit-read-only t)
7534 newhead)
7535 (org-with-remote-undo buffer
7536 (with-current-buffer buffer
7537 (widen)
7538 (goto-char pos)
7539 (org-show-context 'agenda)
7540 (save-excursion
7541 (and (outline-next-heading)
7542 (org-flag-heading nil))) ; show the next heading
7543 (funcall 'org-priority force-direction)
7544 (end-of-line 1)
7545 (setq newhead (org-get-heading)))
7546 (org-agenda-change-all-lines newhead hdmarker)
7547 (beginning-of-line 1))))
7548
7549;; FIXME: should fix the tags property of the agenda line.
c8d0cf5c 7550(defun org-agenda-set-tags (&optional tag onoff)
20908596
CD
7551 "Set tags for the current headline."
7552 (interactive)
7553 (org-agenda-check-no-diary)
3ab2c837 7554 (if (and (org-region-active-p) (org-called-interactively-p 'any))
20908596 7555 (call-interactively 'org-change-tag-in-region)
8d642074 7556 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
20908596
CD
7557 (org-agenda-error)))
7558 (buffer (marker-buffer hdmarker))
7559 (pos (marker-position hdmarker))
7560 (inhibit-read-only t)
4ed008de 7561 newhead)
20908596
CD
7562 (org-with-remote-undo buffer
7563 (with-current-buffer buffer
7564 (widen)
7565 (goto-char pos)
7566 (save-excursion
7567 (org-show-context 'agenda))
7568 (save-excursion
7569 (and (outline-next-heading)
7570 (org-flag-heading nil))) ; show the next heading
7571 (goto-char pos)
c8d0cf5c
CD
7572 (if tag
7573 (org-toggle-tag tag onoff)
7574 (call-interactively 'org-set-tags))
20908596
CD
7575 (end-of-line 1)
7576 (setq newhead (org-get-heading)))
4ed008de 7577 (org-agenda-change-all-lines newhead hdmarker)
20908596
CD
7578 (beginning-of-line 1)))))
7579
54a0dee5
CD
7580(defun org-agenda-set-property ()
7581 "Set a property for the current headline."
7582 (interactive)
7583 (org-agenda-check-no-diary)
8d642074 7584 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
7585 (org-agenda-error)))
7586 (buffer (marker-buffer hdmarker))
7587 (pos (marker-position hdmarker))
7588 (inhibit-read-only t)
7589 newhead)
7590 (org-with-remote-undo buffer
7591 (with-current-buffer buffer
7592 (widen)
7593 (goto-char pos)
7594 (save-excursion
7595 (org-show-context 'agenda))
7596 (save-excursion
7597 (and (outline-next-heading)
7598 (org-flag-heading nil))) ; show the next heading
7599 (goto-char pos)
7600 (call-interactively 'org-set-property)))))
7601
7602(defun org-agenda-set-effort ()
7603 "Set the effort property for the current headline."
7604 (interactive)
7605 (org-agenda-check-no-diary)
8d642074 7606 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
7607 (org-agenda-error)))
7608 (buffer (marker-buffer hdmarker))
7609 (pos (marker-position hdmarker))
7610 (inhibit-read-only t)
7611 newhead)
7612 (org-with-remote-undo buffer
7613 (with-current-buffer buffer
7614 (widen)
7615 (goto-char pos)
7616 (save-excursion
7617 (org-show-context 'agenda))
7618 (save-excursion
7619 (and (outline-next-heading)
3ab2c837 7620 (org-flag-heading nil))) ; show the next heading
54a0dee5
CD
7621 (goto-char pos)
7622 (call-interactively 'org-set-effort)
3ab2c837
BG
7623 (end-of-line 1)
7624 (setq newhead (org-get-heading)))
7625 (org-agenda-change-all-lines newhead hdmarker))))
54a0dee5 7626
20908596
CD
7627(defun org-agenda-toggle-archive-tag ()
7628 "Toggle the archive tag for the current entry."
7629 (interactive)
7630 (org-agenda-check-no-diary)
8d642074 7631 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
20908596
CD
7632 (org-agenda-error)))
7633 (buffer (marker-buffer hdmarker))
7634 (pos (marker-position hdmarker))
7635 (inhibit-read-only t)
7636 newhead)
7637 (org-with-remote-undo buffer
7638 (with-current-buffer buffer
7639 (widen)
7640 (goto-char pos)
7641 (org-show-context 'agenda)
7642 (save-excursion
7643 (and (outline-next-heading)
7644 (org-flag-heading nil))) ; show the next heading
7645 (call-interactively 'org-toggle-archive-tag)
7646 (end-of-line 1)
7647 (setq newhead (org-get-heading)))
7648 (org-agenda-change-all-lines newhead hdmarker)
7649 (beginning-of-line 1))))
7650
c8d0cf5c
CD
7651(defun org-agenda-do-date-later (arg)
7652 (interactive "P")
7653 (cond
7654 ((or (equal arg '(16))
7655 (memq last-command
7656 '(org-agenda-date-later-minutes org-agenda-date-earlier-minutes)))
7657 (setq this-command 'org-agenda-date-later-minutes)
7658 (org-agenda-date-later-minutes 1))
7659 ((or (equal arg '(4))
7660 (memq last-command
7661 '(org-agenda-date-later-hours org-agenda-date-earlier-hours)))
7662 (setq this-command 'org-agenda-date-later-hours)
7663 (org-agenda-date-later-hours 1))
7664 (t
7665 (org-agenda-date-later (prefix-numeric-value arg)))))
7666
7667(defun org-agenda-do-date-earlier (arg)
7668 (interactive "P")
7669 (cond
7670 ((or (equal arg '(16))
7671 (memq last-command
7672 '(org-agenda-date-later-minutes org-agenda-date-earlier-minutes)))
7673 (setq this-command 'org-agenda-date-earlier-minutes)
7674 (org-agenda-date-earlier-minutes 1))
7675 ((or (equal arg '(4))
7676 (memq last-command
7677 '(org-agenda-date-later-hours org-agenda-date-earlier-hours)))
7678 (setq this-command 'org-agenda-date-earlier-hours)
7679 (org-agenda-date-earlier-hours 1))
7680 (t
7681 (org-agenda-date-earlier (prefix-numeric-value arg)))))
7682
20908596 7683(defun org-agenda-date-later (arg &optional what)
3ab2c837 7684 "Change the date of this item to ARG day(s) later."
20908596
CD
7685 (interactive "p")
7686 (org-agenda-check-type t 'agenda 'timeline)
7687 (org-agenda-check-no-diary)
8d642074 7688 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
7689 (org-agenda-error)))
7690 (buffer (marker-buffer marker))
e66ba1df
BG
7691 (pos (marker-position marker))
7692 cdate today)
20908596 7693 (org-with-remote-undo buffer
e66ba1df
BG
7694 (with-current-buffer buffer
7695 (widen)
7696 (goto-char pos)
7697 (if (not (org-at-timestamp-p))
7698 (error "Cannot find time stamp"))
7699 (when (and org-agenda-move-date-from-past-immediately-to-today
7700 (equal arg 1)
7701 (or (not what) (eq what 'day))
7702 (not (save-match-data (org-at-date-range-p))))
7703 (setq cdate (org-parse-time-string (match-string 0) 'nodefault)
7704 cdate (calendar-absolute-from-gregorian
7705 (list (nth 4 cdate) (nth 3 cdate) (nth 5 cdate)))
7706 today (org-today))
7707 (if (> today cdate)
7708 ;; immediately shift to today
7709 (setq arg (- today cdate))))
7710 (org-timestamp-change arg (or what 'day))
7711 (when (and (org-at-date-range-p)
7712 (re-search-backward org-tr-regexp-both (point-at-bol)))
7713 (let ((end org-last-changed-timestamp))
7714 (org-timestamp-change arg (or what 'day))
7715 (setq org-last-changed-timestamp
7716 (concat org-last-changed-timestamp "--" end)))))
7717 (org-agenda-show-new-time marker org-last-changed-timestamp))
20908596
CD
7718 (message "Time stamp changed to %s" org-last-changed-timestamp)))
7719
7720(defun org-agenda-date-earlier (arg &optional what)
3ab2c837 7721 "Change the date of this item to ARG day(s) earlier."
20908596
CD
7722 (interactive "p")
7723 (org-agenda-date-later (- arg) what))
7724
c8d0cf5c
CD
7725(defun org-agenda-date-later-minutes (arg)
7726 "Change the time of this item, in units of `org-time-stamp-rounding-minutes'."
7727 (interactive "p")
7728 (setq arg (* arg (cadr org-time-stamp-rounding-minutes)))
7729 (org-agenda-date-later arg 'minute))
7730
7731(defun org-agenda-date-earlier-minutes (arg)
7732 "Change the time of this item, in units of `org-time-stamp-rounding-minutes'."
7733 (interactive "p")
7734 (setq arg (* arg (cadr org-time-stamp-rounding-minutes)))
7735 (org-agenda-date-earlier arg 'minute))
7736
7737(defun org-agenda-date-later-hours (arg)
7738 "Change the time of this item, in hour steps."
7739 (interactive "p")
7740 (org-agenda-date-later arg 'hour))
7741
7742(defun org-agenda-date-earlier-hours (arg)
7743 "Change the time of this item, in hour steps."
7744 (interactive "p")
7745 (org-agenda-date-earlier arg 'hour))
7746
20908596
CD
7747(defun org-agenda-show-new-time (marker stamp &optional prefix)
7748 "Show new date stamp via text properties."
7749 ;; We use text properties to make this undoable
71d35b24
CD
7750 (let ((inhibit-read-only t)
7751 (buffer-invisibility-spec))
20908596
CD
7752 (setq stamp (concat " " prefix " => " stamp))
7753 (save-excursion
7754 (goto-char (point-max))
7755 (while (not (bobp))
8d642074 7756 (when (equal marker (org-get-at-bol 'org-marker))
20908596 7757 (org-move-to-column (- (window-width) (length stamp)) t)
71d35b24 7758 (org-agenda-fix-tags-filter-overlays-at (point))
20908596
CD
7759 (if (featurep 'xemacs)
7760 ;; Use `duplicable' property to trigger undo recording
7761 (let ((ex (make-extent nil nil))
7762 (gl (make-glyph stamp)))
7763 (set-glyph-face gl 'secondary-selection)
7764 (set-extent-properties
7765 ex (list 'invisible t 'end-glyph gl 'duplicable t))
7766 (insert-extent ex (1- (point)) (point-at-eol)))
7767 (add-text-properties
7768 (1- (point)) (point-at-eol)
7769 (list 'display (org-add-props stamp nil
7770 'face 'secondary-selection))))
7771 (beginning-of-line 1))
7772 (beginning-of-line 0)))))
7773
7774(defun org-agenda-date-prompt (arg)
7775 "Change the date of this item. Date is prompted for, with default today.
7776The prefix ARG is passed to the `org-time-stamp' command and can therefore
7777be used to request time specification in the time stamp."
7778 (interactive "P")
7779 (org-agenda-check-type t 'agenda 'timeline)
7780 (org-agenda-check-no-diary)
8d642074 7781 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
7782 (org-agenda-error)))
7783 (buffer (marker-buffer marker))
7784 (pos (marker-position marker)))
7785 (org-with-remote-undo buffer
7786 (with-current-buffer buffer
7787 (widen)
7788 (goto-char pos)
ed21c5c8 7789 (if (not (org-at-timestamp-p t))
20908596 7790 (error "Cannot find time stamp"))
ed21c5c8 7791 (org-time-stamp arg (equal (char-after (match-beginning 0)) ?\[)))
8d642074
CD
7792 (org-agenda-show-new-time marker org-last-changed-timestamp))
7793 (message "Time stamp changed to %s" org-last-changed-timestamp)))
20908596 7794
3ab2c837 7795(defun org-agenda-schedule (arg &optional time)
ed21c5c8 7796 "Schedule the item at point.
3ab2c837 7797ARG is passed through to `org-schedule'."
20908596
CD
7798 (interactive "P")
7799 (org-agenda-check-type t 'agenda 'timeline 'todo 'tags 'search)
7800 (org-agenda-check-no-diary)
8d642074 7801 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
7802 (org-agenda-error)))
7803 (type (marker-insertion-type marker))
7804 (buffer (marker-buffer marker))
7805 (pos (marker-position marker))
7806 (org-insert-labeled-timestamps-at-point nil)
7807 ts)
20908596
CD
7808 (set-marker-insertion-type marker t)
7809 (org-with-remote-undo buffer
7810 (with-current-buffer buffer
7811 (widen)
7812 (goto-char pos)
3ab2c837 7813 (setq ts (org-schedule arg time)))
20908596
CD
7814 (org-agenda-show-new-time marker ts "S"))
7815 (message "Item scheduled for %s" ts)))
7816
3ab2c837 7817(defun org-agenda-deadline (arg &optional time)
ed21c5c8 7818 "Schedule the item at point.
3ab2c837 7819ARG is passed through to `org-deadline'."
20908596
CD
7820 (interactive "P")
7821 (org-agenda-check-type t 'agenda 'timeline 'todo 'tags 'search)
7822 (org-agenda-check-no-diary)
8d642074 7823 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
7824 (org-agenda-error)))
7825 (buffer (marker-buffer marker))
7826 (pos (marker-position marker))
7827 (org-insert-labeled-timestamps-at-point nil)
7828 ts)
7829 (org-with-remote-undo buffer
7830 (with-current-buffer buffer
7831 (widen)
7832 (goto-char pos)
3ab2c837 7833 (setq ts (org-deadline arg time)))
8d642074 7834 (org-agenda-show-new-time marker ts "D"))
20908596
CD
7835 (message "Deadline for this item set to %s" ts)))
7836
b349f79f
CD
7837(defun org-agenda-action ()
7838 "Select entry for agenda action, or execute an agenda action.
7839This command prompts for another letter. Valid inputs are:
7840
7841m Mark the entry at point for an agenda action
7842s Schedule the marked entry to the date at the cursor
7843d Set the deadline of the marked entry to the date at the cursor
7844r Call `org-remember' with cursor date as the default date
86fbb8ca 7845c Call `org-capture' with cursor date as the default date
b349f79f
CD
7846SPC Show marked entry in other window
7847TAB Visit marked entry in other window
7848
7849The cursor may be at a date in the calendar, or in the Org agenda."
7850 (interactive)
65c439fd 7851 (let (ans)
86fbb8ca 7852 (message "Select action: [m]ark | [s]chedule [d]eadline [r]emember [c]apture [ ]show")
b349f79f
CD
7853 (setq ans (read-char-exclusive))
7854 (cond
7855 ((equal ans ?m)
7856 ;; Mark this entry
7857 (if (eq major-mode 'org-agenda-mode)
8d642074
CD
7858 (let ((m (or (org-get-at-bol 'org-hd-marker)
7859 (org-get-at-bol 'org-marker))))
b349f79f
CD
7860 (if m
7861 (progn
7862 (move-marker org-agenda-action-marker
7863 (marker-position m) (marker-buffer m))
7864 (message "Entry marked for action; press `k' at desired date in agenda or calendar"))
7865 (error "Don't know which entry to mark")))
7866 (error "This command works only in the agenda")))
7867 ((equal ans ?s)
7868 (org-agenda-do-action '(org-schedule nil org-overriding-default-time)))
7869 ((equal ans ?d)
7870 (org-agenda-do-action '(org-deadline nil org-overriding-default-time)))
7871 ((equal ans ?r)
7872 (org-agenda-do-action '(org-remember) t))
86fbb8ca
CD
7873 ((equal ans ?c)
7874 (org-agenda-do-action '(org-capture) t))
b349f79f
CD
7875 ((equal ans ?\ )
7876 (let ((cw (selected-window)))
7877 (org-switch-to-buffer-other-window
7878 (marker-buffer org-agenda-action-marker))
7879 (goto-char org-agenda-action-marker)
7880 (org-show-context 'agenda)
7881 (select-window cw)))
7882 ((equal ans ?\C-i)
7883 (org-switch-to-buffer-other-window
7884 (marker-buffer org-agenda-action-marker))
7885 (goto-char org-agenda-action-marker)
7886 (org-show-context 'agenda))
7887 (t (error "Invalid agenda action %c" ans)))))
7888
7889(defun org-agenda-do-action (form &optional current-buffer)
7890 "Evaluate FORM at the entry pointed to by `org-agenda-action-marker'."
7891 (let ((org-overriding-default-time (org-get-cursor-date)))
7892 (if current-buffer
7893 (eval form)
7894 (if (not (marker-buffer org-agenda-action-marker))
8bfe682a 7895 (error "No entry has been selected for agenda action")
b349f79f
CD
7896 (with-current-buffer (marker-buffer org-agenda-action-marker)
7897 (save-excursion
7898 (save-restriction
7899 (widen)
7900 (goto-char org-agenda-action-marker)
7901 (eval form))))))))
ff4be292 7902
20908596
CD
7903(defun org-agenda-clock-in (&optional arg)
7904 "Start the clock on the currently selected item."
7905 (interactive "P")
7906 (org-agenda-check-no-diary)
7907 (if (equal arg '(4))
7908 (org-clock-in arg)
8d642074 7909 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596 7910 (org-agenda-error)))
8d642074 7911 (hdmarker (or (org-get-at-bol 'org-hd-marker)
b349f79f
CD
7912 marker))
7913 (pos (marker-position marker))
7914 newhead)
20908596
CD
7915 (org-with-remote-undo (marker-buffer marker)
7916 (with-current-buffer (marker-buffer marker)
7917 (widen)
7918 (goto-char pos)
b349f79f
CD
7919 (org-show-context 'agenda)
7920 (org-show-entry)
7921 (org-cycle-hide-drawers 'children)
7922 (org-clock-in arg)
7923 (setq newhead (org-get-heading)))
c8d0cf5c 7924 (org-agenda-change-all-lines newhead hdmarker)))))
20908596 7925
afe98dfa 7926(defun org-agenda-clock-out ()
20908596 7927 "Stop the currently running clock."
afe98dfa 7928 (interactive)
20908596
CD
7929 (unless (marker-buffer org-clock-marker)
7930 (error "No running clock"))
c8d0cf5c
CD
7931 (let ((marker (make-marker)) newhead)
7932 (org-with-remote-undo (marker-buffer org-clock-marker)
7933 (with-current-buffer (marker-buffer org-clock-marker)
7934 (save-excursion
7935 (save-restriction
7936 (widen)
7937 (goto-char org-clock-marker)
7938 (org-back-to-heading t)
7939 (move-marker marker (point))
7940 (org-clock-out)
7941 (setq newhead (org-get-heading))))))
7942 (org-agenda-change-all-lines newhead marker)
7943 (move-marker marker nil)))
20908596
CD
7944
7945(defun org-agenda-clock-cancel (&optional arg)
7946 "Cancel the currently running clock."
7947 (interactive "P")
7948 (unless (marker-buffer org-clock-marker)
7949 (error "No running clock"))
7950 (org-with-remote-undo (marker-buffer org-clock-marker)
7951 (org-clock-cancel)))
7952
afe98dfa
CD
7953(defun org-agenda-clock-goto ()
7954 "Jump to the currently clocked in task within the agenda.
7955If the currently clocked in task is not listed in the agenda
7956buffer, display it in another window."
7957 (interactive)
7958 (let (pos)
7959 (mapc (lambda (o)
7960 (if (eq (overlay-get o 'type) 'org-agenda-clocking)
7961 (setq pos (overlay-start o))))
7962 (overlays-in (point-min) (point-max)))
7963 (cond (pos (goto-char pos))
7964 ;; If the currently clocked entry is not in the agenda
7965 ;; buffer, we visit it in another window:
7966 (org-clock-current-task
7967 (org-switch-to-buffer-other-window (org-clock-goto)))
7968 (t (message "No running clock, use `C-c C-x C-j' to jump to the most recent one")))))
7969
8bfe682a
CD
7970(defun org-agenda-diary-entry-in-org-file ()
7971 "Make a diary entry in the file `org-agenda-diary-file'."
5dec9555 7972 (let (d1 d2 char (text "") dp1 dp2)
8bfe682a
CD
7973 (if (equal (buffer-name) "*Calendar*")
7974 (setq d1 (calendar-cursor-to-date t)
7975 d2 (car calendar-mark-ring))
5dec9555
CD
7976 (setq dp1 (get-text-property (point-at-bol) 'day))
7977 (unless dp1 (error "No date defined in current line"))
7978 (setq d1 (calendar-gregorian-from-absolute dp1)
7979 d2 (and (ignore-errors (mark))
7980 (save-excursion
7981 (goto-char (mark))
7982 (setq dp2 (get-text-property (point-at-bol) 'day)))
7983 (calendar-gregorian-from-absolute dp2))))
8bfe682a
CD
7984 (message "Diary entry: [d]ay [a]nniversary [b]lock [j]ump to date tree")
7985 (setq char (read-char-exclusive))
7986 (cond
7987 ((equal char ?d)
7988 (setq text (read-string "Day entry: "))
5dec9555
CD
7989 (org-agenda-add-entry-to-org-agenda-diary-file 'day text d1)
7990 (and (equal (buffer-name) org-agenda-buffer-name) (org-agenda-redo)))
8bfe682a
CD
7991 ((equal char ?a)
7992 (setq d1 (list (car d1) (nth 1 d1)
7993 (read-number (format "Reference year [%d]: " (nth 2 d1))
7994 (nth 2 d1))))
7995 (setq text (read-string "Anniversary (use %d to show years): "))
5dec9555
CD
7996 (org-agenda-add-entry-to-org-agenda-diary-file 'anniversary text d1)
7997 (and (equal (buffer-name) org-agenda-buffer-name) (org-agenda-redo)))
8bfe682a
CD
7998 ((equal char ?b)
7999 (setq text (read-string "Block entry: "))
8000 (unless (and d1 d2 (not (equal d1 d2)))
8001 (error "No block of days selected"))
5dec9555
CD
8002 (org-agenda-add-entry-to-org-agenda-diary-file 'block text d1 d2)
8003 (and (equal (buffer-name) org-agenda-buffer-name) (org-agenda-redo)))
8bfe682a
CD
8004 ((equal char ?j)
8005 (org-switch-to-buffer-other-window
8006 (find-file-noselect org-agenda-diary-file))
ed21c5c8 8007 (require 'org-datetree)
8bfe682a
CD
8008 (org-datetree-find-date-create d1)
8009 (org-reveal t))
8010 (t (error "Invalid selection character `%c'" char)))))
8011
5dec9555
CD
8012(defcustom org-agenda-insert-diary-strategy 'date-tree
8013 "Where in `org-agenda-diary-file' should new entries be added?
8014Valid values:
8015
8016date-tree in the date tree, as child of the date
8017top-level as top-level entries at the end of the file."
8018 :group 'org-agenda
8019 :type '(choice
8020 (const :tag "in a date tree" date-tree)
8021 (const :tag "as top level at end of file" top-level)))
8022
ed21c5c8
CD
8023(defcustom org-agenda-insert-diary-extract-time nil
8024 "Non-nil means extract any time specification from the diary entry."
8025 :group 'org-agenda
372d7b21 8026 :version "24.1"
ed21c5c8
CD
8027 :type 'boolean)
8028
8bfe682a
CD
8029(defun org-agenda-add-entry-to-org-agenda-diary-file (type text &optional d1 d2)
8030 "Add a diary entry with TYPE to `org-agenda-diary-file'.
8031If TEXT is not empty, it will become the headline of the new entry, and
8032the resulting entry will not be shown. When TEXT is empty, switch to
8033`org-agenda-diary-file' and let the user finish the entry there."
8034 (let ((cw (current-window-configuration)))
8035 (org-switch-to-buffer-other-window
8036 (find-file-noselect org-agenda-diary-file))
8037 (widen)
8038 (goto-char (point-min))
8039 (cond
8040 ((eq type 'anniversary)
8041 (or (re-search-forward "^*[ \t]+Anniversaries" nil t)
8042 (progn
e66ba1df 8043 (or (org-at-heading-p t)
8bfe682a
CD
8044 (progn
8045 (outline-next-heading)
8046 (insert "* Anniversaries\n\n")
8047 (beginning-of-line -1)))))
8048 (outline-next-heading)
8049 (org-back-over-empty-lines)
8050 (backward-char 1)
8051 (insert "\n")
3ab2c837
BG
8052 (insert (format "%%%%(org-anniversary %d %2d %2d) %s"
8053 (nth 2 d1) (car d1) (nth 1 d1) text)))
8bfe682a 8054 ((eq type 'day)
ed21c5c8
CD
8055 (let ((org-prefix-has-time t)
8056 (org-agenda-time-leading-zero t)
8057 fmt time time2)
8058 (if org-agenda-insert-diary-extract-time
e66ba1df 8059 ;; Use org-agenda-format-item to parse text for a time-range and
ed21c5c8
CD
8060 ;; remove it. FIXME: This is a hack, we should refactor
8061 ;; that function to make time extraction available separately
e66ba1df 8062 (setq fmt (org-agenda-format-item nil text nil nil t)
ed21c5c8
CD
8063 time (get-text-property 0 'time fmt)
8064 time2 (if (> (length time) 0)
8065 ;; split-string removes trailing ...... if
8066 ;; no end time given. First space
8067 ;; separates time from date.
8068 (concat " " (car (split-string time "\\.")))
8069 nil)
8070 text (get-text-property 0 'txt fmt)))
8071 (if (eq org-agenda-insert-diary-strategy 'top-level)
8072 (org-agenda-insert-diary-as-top-level text)
8073 (require 'org-datetree)
8074 (org-datetree-find-date-create d1)
8075 (org-agenda-insert-diary-make-new-entry text))
8076 (org-insert-time-stamp (org-time-from-absolute
8077 (calendar-absolute-from-gregorian d1))
8078 nil nil nil nil time2))
8bfe682a
CD
8079 (end-of-line 0))
8080 ((eq type 'block)
8081 (if (> (calendar-absolute-from-gregorian d1)
8082 (calendar-absolute-from-gregorian d2))
8083 (setq d1 (prog1 d2 (setq d2 d1))))
5dec9555
CD
8084 (if (eq org-agenda-insert-diary-strategy 'top-level)
8085 (org-agenda-insert-diary-as-top-level text)
8086 (require 'org-datetree)
8087 (org-datetree-find-date-create d1)
8088 (org-agenda-insert-diary-make-new-entry text))
8bfe682a
CD
8089 (org-insert-time-stamp (org-time-from-absolute
8090 (calendar-absolute-from-gregorian d1)))
8091 (insert "--")
8092 (org-insert-time-stamp (org-time-from-absolute
8093 (calendar-absolute-from-gregorian d2)))
8094 (end-of-line 0)))
8095 (if (string-match "\\S-" text)
8096 (progn
8097 (set-window-configuration cw)
8098 (message "%s entry added to %s"
8099 (capitalize (symbol-name type))
8100 (abbreviate-file-name org-agenda-diary-file)))
8101 (org-reveal t)
8102 (message "Please finish entry here"))))
8103
5dec9555
CD
8104(defun org-agenda-insert-diary-as-top-level (text)
8105 "Make new entry as a top-level entry at the end of the file.
8106Add TEXT as headline, and position the cursor in the second line so that
8107a timestamp can be added there."
8108 (widen)
8109 (goto-char (point-max))
8110 (or (bolp) (insert "\n"))
8111 (insert "* " text "\n")
8112 (if org-adapt-indentation (org-indent-to-column 2)))
8113
8bfe682a
CD
8114(defun org-agenda-insert-diary-make-new-entry (text)
8115 "Make new entry as last child of current entry.
8116Add TEXT as headline, and position the cursor in the second line so that
8117a timestamp can be added there."
8118 (let ((org-show-following-heading t)
8119 (org-show-siblings t)
8120 (org-show-hierarchy-above t)
8121 (org-show-entry-below t)
8122 col)
8123 (outline-next-heading)
8124 (org-back-over-empty-lines)
8125 (or (looking-at "[ \t]*$")
8126 (progn (insert "\n") (backward-char 1)))
ed21c5c8 8127 (org-insert-heading nil t)
8bfe682a
CD
8128 (org-do-demote)
8129 (setq col (current-column))
8130 (insert text "\n")
8131 (if org-adapt-indentation (org-indent-to-column col))
8132 (let ((org-show-following-heading t)
8133 (org-show-siblings t)
8134 (org-show-hierarchy-above t)
8135 (org-show-entry-below t))
8136 (org-show-context))))
8137
20908596
CD
8138(defun org-agenda-diary-entry ()
8139 "Make a diary entry, like the `i' command from the calendar.
8bfe682a
CD
8140All the standard commands work: block, weekly etc.
8141When `org-agenda-diary-file' points to a file,
8142`org-agenda-diary-entry-in-org-file' is called instead to create
8143entries in that Org-mode file."
20908596
CD
8144 (interactive)
8145 (org-agenda-check-type t 'agenda 'timeline)
8bfe682a
CD
8146 (if (not (eq org-agenda-diary-file 'diary-file))
8147 (org-agenda-diary-entry-in-org-file)
8148 (require 'diary-lib)
8149 (let* ((char (progn
8150 (message "Diary entry: [d]ay [w]eekly [m]onthly [y]early [a]nniversary [b]lock [c]yclic")
8151 (read-char-exclusive)))
8152 (cmd (cdr (assoc char
8153 '((?d . insert-diary-entry)
8154 (?w . insert-weekly-diary-entry)
8155 (?m . insert-monthly-diary-entry)
8156 (?y . insert-yearly-diary-entry)
8157 (?a . insert-anniversary-diary-entry)
8158 (?b . insert-block-diary-entry)
8159 (?c . insert-cyclic-diary-entry)))))
8160 (oldf (symbol-function 'calendar-cursor-to-date))
8161 ;; (buf (get-file-buffer (substitute-in-file-name diary-file)))
8162 (point (point))
8163 (mark (or (mark t) (point))))
8164 (unless cmd
8165 (error "No command associated with <%c>" char))
8166 (unless (and (get-text-property point 'day)
8167 (or (not (equal ?b char))
8168 (get-text-property mark 'day)))
8169 (error "Don't know which date to use for diary entry"))
8170 ;; We implement this by hacking the `calendar-cursor-to-date' function
8171 ;; and the `calendar-mark-ring' variable. Saves a lot of code.
8172 (let ((calendar-mark-ring
8173 (list (calendar-gregorian-from-absolute
8174 (or (get-text-property mark 'day)
8175 (get-text-property point 'day))))))
8176 (unwind-protect
8177 (progn
8178 (fset 'calendar-cursor-to-date
8179 (lambda (&optional error dummy)
8180 (calendar-gregorian-from-absolute
8181 (get-text-property point 'day))))
20908596 8182 (call-interactively cmd))
8bfe682a 8183 (fset 'calendar-cursor-to-date oldf))))))
20908596 8184
20908596
CD
8185(defun org-agenda-execute-calendar-command (cmd)
8186 "Execute a calendar command from the agenda, with the date associated to
8187the cursor position."
8188 (org-agenda-check-type t 'agenda 'timeline)
8189 (require 'diary-lib)
8190 (unless (get-text-property (point) 'day)
8191 (error "Don't know which date to use for calendar command"))
8192 (let* ((oldf (symbol-function 'calendar-cursor-to-date))
8193 (point (point))
8194 (date (calendar-gregorian-from-absolute
8195 (get-text-property point 'day)))
8196 ;; the following 2 vars are needed in the calendar
8197 (displayed-month (car date))
8198 (displayed-year (nth 2 date)))
8199 (unwind-protect
8200 (progn
8201 (fset 'calendar-cursor-to-date
0627c265 8202 (lambda (&optional error dummy)
20908596
CD
8203 (calendar-gregorian-from-absolute
8204 (get-text-property point 'day))))
8205 (call-interactively cmd))
8206 (fset 'calendar-cursor-to-date oldf))))
8207
8208(defun org-agenda-phases-of-moon ()
8209 "Display the phases of the moon for the 3 months around the cursor date."
8210 (interactive)
8211 (org-agenda-execute-calendar-command 'calendar-phases-of-moon))
8212
8213(defun org-agenda-holidays ()
8214 "Display the holidays for the 3 months around the cursor date."
8215 (interactive)
8216 (org-agenda-execute-calendar-command 'list-calendar-holidays))
8217
8218(defvar calendar-longitude)
8219(defvar calendar-latitude)
8220(defvar calendar-location-name)
8221
8222(defun org-agenda-sunrise-sunset (arg)
8223 "Display sunrise and sunset for the cursor date.
8224Latitude and longitude can be specified with the variables
8225`calendar-latitude' and `calendar-longitude'. When called with prefix
8226argument, latitude and longitude will be prompted for."
8227 (interactive "P")
8228 (require 'solar)
8229 (let ((calendar-longitude (if arg nil calendar-longitude))
8230 (calendar-latitude (if arg nil calendar-latitude))
8231 (calendar-location-name
8232 (if arg "the given coordinates" calendar-location-name)))
8233 (org-agenda-execute-calendar-command 'calendar-sunrise-sunset)))
8234
8235(defun org-agenda-goto-calendar ()
8236 "Open the Emacs calendar with the date at the cursor."
8237 (interactive)
8238 (org-agenda-check-type t 'agenda 'timeline)
8239 (let* ((day (or (get-text-property (point) 'day)
8240 (error "Don't know which date to open in calendar")))
8241 (date (calendar-gregorian-from-absolute day))
8242 (calendar-move-hook nil)
8243 (calendar-view-holidays-initially-flag nil)
3820f429 8244 (calendar-view-diary-initially-flag nil))
20908596
CD
8245 (calendar)
8246 (calendar-goto-date date)))
8247
8248;;;###autoload
8249(defun org-calendar-goto-agenda ()
8250 "Compute the Org-mode agenda for the calendar date displayed at the cursor.
8251This is a command that has to be installed in `calendar-mode-map'."
8252 (interactive)
8253 (org-agenda-list nil (calendar-absolute-from-gregorian
8254 (calendar-cursor-to-date))
8255 nil))
8256
8257(defun org-agenda-convert-date ()
8258 (interactive)
8259 (org-agenda-check-type t 'agenda 'timeline)
8260 (let ((day (get-text-property (point) 'day))
8261 date s)
8262 (unless day
8263 (error "Don't know which date to convert"))
8264 (setq date (calendar-gregorian-from-absolute day))
8265 (setq s (concat
8266 "Gregorian: " (calendar-date-string date) "\n"
8267 "ISO: " (calendar-iso-date-string date) "\n"
8268 "Day of Yr: " (calendar-day-of-year-string date) "\n"
8269 "Julian: " (calendar-julian-date-string date) "\n"
8270 "Astron. JD: " (calendar-astro-date-string date)
8271 " (Julian date number at noon UTC)\n"
8272 "Hebrew: " (calendar-hebrew-date-string date) " (until sunset)\n"
8273 "Islamic: " (calendar-islamic-date-string date) " (until sunset)\n"
8274 "French: " (calendar-french-date-string date) "\n"
8275 "Baha'i: " (calendar-bahai-date-string date) " (until sunset)\n"
8276 "Mayan: " (calendar-mayan-date-string date) "\n"
8277 "Coptic: " (calendar-coptic-date-string date) "\n"
8278 "Ethiopic: " (calendar-ethiopic-date-string date) "\n"
8279 "Persian: " (calendar-persian-date-string date) "\n"
8280 "Chinese: " (calendar-chinese-date-string date) "\n"))
8281 (with-output-to-temp-buffer "*Dates*"
8282 (princ s))
93b62de8 8283 (org-fit-window-to-buffer (get-buffer-window "*Dates*"))))
20908596 8284
c8d0cf5c
CD
8285;;; Bulk commands
8286
8287(defvar org-agenda-bulk-marked-entries nil
8288 "List of markers that refer to marked entries in the agenda.")
8289
54a0dee5
CD
8290(defun org-agenda-bulk-marked-p ()
8291 (eq (get-char-property (point-at-bol) 'type)
8292 'org-marked-entry-overlay))
8293
acedf35c 8294(defun org-agenda-bulk-mark (&optional arg)
c8d0cf5c 8295 "Mark the entry at point for future bulk action."
acedf35c 8296 (interactive "p")
2f885dca 8297 (dotimes (i (or arg 1))
acedf35c
CD
8298 (unless (org-get-at-bol 'org-agenda-diary-link)
8299 (let* ((m (org-get-at-bol 'org-hd-marker))
8300 ov)
8301 (unless (org-agenda-bulk-marked-p)
8302 (unless m (error "Nothing to mark at point"))
8303 (push m org-agenda-bulk-marked-entries)
8304 (setq ov (make-overlay (point-at-bol) (+ 2 (point-at-bol))))
8305 (org-overlay-display ov "> "
8306 (org-get-todo-face "TODO")
8307 'evaporate)
8308 (overlay-put ov 'type 'org-marked-entry-overlay))
8309 (beginning-of-line 2)
8310 (while (and (get-char-property (point) 'invisible) (not (eobp)))
8311 (beginning-of-line 2))
8312 (message "%d entries marked for bulk action"
8313 (length org-agenda-bulk-marked-entries))))))
c8d0cf5c 8314
3ab2c837
BG
8315(defun org-agenda-bulk-mark-regexp (regexp)
8316 "Mark entries match REGEXP."
8317 (interactive "sMark entries matching regexp: ")
8c8b834f 8318 (let ((entries-marked 0))
3ab2c837
BG
8319 (save-excursion
8320 (goto-char (point-min))
8321 (goto-char (next-single-property-change (point) 'txt))
8322 (while (re-search-forward regexp nil t)
8323 (when (string-match regexp (get-text-property (point) 'txt))
8c8b834f 8324 (setq entries-marked (1+ entries-marked))
3ab2c837
BG
8325 (call-interactively 'org-agenda-bulk-mark))))
8326 (if (not entries-marked)
8327 (message "No entry matching this regexp."))))
8328
c8d0cf5c
CD
8329(defun org-agenda-bulk-unmark ()
8330 "Unmark the entry at point for future bulk action."
8331 (interactive)
54a0dee5 8332 (when (org-agenda-bulk-marked-p)
c8d0cf5c
CD
8333 (org-agenda-bulk-remove-overlays
8334 (point-at-bol) (+ 2 (point-at-bol)))
8335 (setq org-agenda-bulk-marked-entries
8d642074 8336 (delete (org-get-at-bol 'org-hd-marker)
c8d0cf5c
CD
8337 org-agenda-bulk-marked-entries)))
8338 (beginning-of-line 2)
ed21c5c8
CD
8339 (while (and (get-char-property (point) 'invisible) (not (eobp)))
8340 (beginning-of-line 2))
c8d0cf5c
CD
8341 (message "%d entries marked for bulk action"
8342 (length org-agenda-bulk-marked-entries)))
8343
54a0dee5
CD
8344(defun org-agenda-bulk-toggle ()
8345 "Toggle marking the entry at point for bulk action."
8346 (interactive)
8347 (if (org-agenda-bulk-marked-p)
8348 (org-agenda-bulk-unmark)
8349 (org-agenda-bulk-mark)))
c8d0cf5c
CD
8350
8351(defun org-agenda-bulk-remove-overlays (&optional beg end)
8352 "Remove the mark overlays between BEG and END in the agenda buffer.
8353BEG and END default to the buffer limits.
8354
8355This only removes the overlays, it does not remove the markers
8356from the list in `org-agenda-bulk-marked-entries'."
8357 (interactive)
8358 (mapc (lambda (ov)
86fbb8ca
CD
8359 (and (eq (overlay-get ov 'type) 'org-marked-entry-overlay)
8360 (delete-overlay ov)))
8361 (overlays-in (or beg (point-min)) (or end (point-max)))))
c8d0cf5c
CD
8362
8363(defun org-agenda-bulk-remove-all-marks ()
8364 "Remove all marks in the agenda buffer.
8365This will remove the markers, and the overlays."
8366 (interactive)
8367 (mapc (lambda (m) (move-marker m nil)) org-agenda-bulk-marked-entries)
8368 (setq org-agenda-bulk-marked-entries nil)
8369 (org-agenda-bulk-remove-overlays (point-min) (point-max)))
8370
ed21c5c8
CD
8371(defun org-agenda-bulk-action (&optional arg)
8372 "Execute an remote-editing action on all marked entries.
8373The prefix arg is passed through to the command if possible."
8374 (interactive "P")
3ab2c837
BG
8375 ;; Make sure we have markers, and only valid ones
8376 (unless org-agenda-bulk-marked-entries (error "No entries are marked"))
8377 (mapc
8378 (lambda (m)
8379 (unless (and (markerp m)
8380 (marker-buffer m)
8381 (buffer-live-p (marker-buffer m))
8382 (marker-position m))
8383 (error "Marker %s for bulk command is invalid" m)))
8384 org-agenda-bulk-marked-entries)
8385
8386 ;; Prompt for the bulk command
8387 (message (concat "Bulk: [r]efile [$]arch [A]rch->sib [t]odo"
8388 " [+/-]tag [s]chd [S]catter [d]eadline [f]unction"
8389 (when org-agenda-bulk-custom-functions
8390 (concat " Custom: ["
8391 (mapconcat (lambda(f) (char-to-string (car f)))
8392 org-agenda-bulk-custom-functions "")
8393 "]"))))
c8d0cf5c 8394 (let* ((action (read-char-exclusive))
ed21c5c8 8395 (org-log-refile (if org-log-refile 'time nil))
c8d0cf5c 8396 (entries (reverse org-agenda-bulk-marked-entries))
86fbb8ca 8397 redo-at-end
c8d0cf5c
CD
8398 cmd rfloc state e tag pos (cnt 0) (cntskip 0))
8399 (cond
8400 ((equal action ?$)
8401 (setq cmd '(org-agenda-archive)))
8402
8403 ((equal action ?A)
8404 (setq cmd '(org-agenda-archive-to-archive-sibling)))
8405
8406 ((member action '(?r ?w))
8407 (setq rfloc (org-refile-get-location
3ab2c837 8408 "Refile to"
c8d0cf5c
CD
8409 (marker-buffer (car org-agenda-bulk-marked-entries))
8410 org-refile-allow-creating-parent-nodes))
86fbb8ca
CD
8411 (if (nth 3 rfloc)
8412 (setcar (nthcdr 3 rfloc)
8413 (move-marker (make-marker) (nth 3 rfloc)
8414 (or (get-file-buffer (nth 1 rfloc))
8415 (find-buffer-visiting (nth 1 rfloc))
8416 (error "This should not happen")))))
c8d0cf5c 8417
86fbb8ca
CD
8418 (setq cmd (list 'org-agenda-refile nil (list 'quote rfloc) t)
8419 redo-at-end t))
c8d0cf5c
CD
8420
8421 ((equal action ?t)
54a0dee5 8422 (setq state (org-icompleting-read
c8d0cf5c
CD
8423 "Todo state: "
8424 (with-current-buffer (marker-buffer (car entries))
8425 (mapcar 'list org-todo-keywords-1))))
8426 (setq cmd `(let ((org-inhibit-blocking t)
8427 (org-inhibit-logging 'note))
8428 (org-agenda-todo ,state))))
8429
8430 ((memq action '(?- ?+))
54a0dee5 8431 (setq tag (org-icompleting-read
c8d0cf5c
CD
8432 (format "Tag to %s: " (if (eq action ?+) "add" "remove"))
8433 (with-current-buffer (marker-buffer (car entries))
8434 (delq nil
8435 (mapcar (lambda (x)
8436 (if (stringp (car x)) x)) org-tag-alist)))))
8437 (setq cmd `(org-agenda-set-tags ,tag ,(if (eq action ?+) ''on ''off))))
8438
8439 ((memq action '(?s ?d))
ed21c5c8
CD
8440 (let* ((date (unless arg
8441 (org-read-date
8442 nil nil nil
8443 (if (eq action ?s) "(Re)Schedule to" "Set Deadline to"))))
8444 (ans (if arg nil org-read-date-final-answer))
c8d0cf5c
CD
8445 (c1 (if (eq action ?s) 'org-agenda-schedule 'org-agenda-deadline)))
8446 (setq cmd `(let* ((bound (fboundp 'read-string))
8447 (old (and bound (symbol-function 'read-string))))
8448 (unwind-protect
8449 (progn
8450 (fset 'read-string (lambda (&rest ignore) ,ans))
ed21c5c8 8451 (eval '(,c1 arg)))
c8d0cf5c
CD
8452 (if bound
8453 (fset 'read-string old)
8454 (fmakunbound 'read-string)))))))
acedf35c 8455
3ab2c837
BG
8456 ((equal action ?S)
8457 (if (not (org-agenda-check-type nil 'agenda 'timeline 'todo))
8458 (error "Can't scatter tasks in \"%s\" agenda view" org-agenda-type)
8459 (let ((days (read-number
8460 (format "Scatter tasks across how many %sdays: "
8461 (if arg "week" "")) 7)))
8462 (setq cmd
8463 `(let ((distance (1+ (random ,days))))
8464 (if arg
8465 (let ((dist distance)
8466 (day-of-week
8467 (calendar-day-of-week
8468 (calendar-gregorian-from-absolute (org-today)))))
8469 (dotimes (i (1+ dist))
8470 (while (member day-of-week org-agenda-weekend-days)
8471 (incf distance)
8472 (incf day-of-week)
8473 (if (= day-of-week 7)
8474 (setq day-of-week 0)))
acedf35c
CD
8475 (incf day-of-week)
8476 (if (= day-of-week 7)
3ab2c837
BG
8477 (setq day-of-week 0)))))
8478 ;; silently fail when try to replan a sexp entry
8479 (condition-case nil
8480 (let* ((date (calendar-gregorian-from-absolute
8481 (+ (org-today) distance)))
8482 (time (encode-time 0 0 0 (nth 1 date) (nth 0 date)
8483 (nth 2 date))))
8484 (org-agenda-schedule nil time))
8485 (error nil)))))))
8486
8487 ((assoc action org-agenda-bulk-custom-functions)
8488 (setq cmd (list (cadr (assoc action org-agenda-bulk-custom-functions)))
8489 redo-at-end t))
8490
8491 ((equal action ?f)
8492 (setq cmd (list (intern
8493 (org-icompleting-read "Function: "
8494 obarray 'fboundp t nil nil)))))
acedf35c 8495
c8d0cf5c
CD
8496 (t (error "Invalid bulk action")))
8497
8498 ;; Sort the markers, to make sure that parents are handled before children
8499 (setq entries (sort entries
8500 (lambda (a b)
8501 (cond
8502 ((equal (marker-buffer a) (marker-buffer b))
8503 (< (marker-position a) (marker-position b)))
8504 (t
8505 (string< (buffer-name (marker-buffer a))
8506 (buffer-name (marker-buffer b))))))))
8507
8508 ;; Now loop over all markers and apply cmd
8509 (while (setq e (pop entries))
8510 (setq pos (text-property-any (point-min) (point-max) 'org-hd-marker e))
8511 (if (not pos)
8512 (progn (message "Skipping removed entry at %s" e)
8513 (setq cntskip (1+ cntskip)))
8514 (goto-char pos)
e66ba1df
BG
8515 (let (org-loop-over-headlines-in-active-region)
8516 (eval cmd))
c8d0cf5c
CD
8517 (setq org-agenda-bulk-marked-entries
8518 (delete e org-agenda-bulk-marked-entries))
8519 (setq cnt (1+ cnt))))
8520 (setq org-agenda-bulk-marked-entries nil)
8521 (org-agenda-bulk-remove-all-marks)
86fbb8ca 8522 (when redo-at-end (org-agenda-redo))
c8d0cf5c
CD
8523 (message "Acted on %d entries%s"
8524 cnt
8525 (if (= cntskip 0)
8526 ""
8527 (format ", skipped %d (disappeared before their turn)"
8528 cntskip)))))
8d642074
CD
8529
8530;;; Flagging notes
8531
8532(defun org-agenda-show-the-flagging-note ()
8533 "Display the flagging note in the other window.
8534When called a second time in direct sequence, offer to remove the FLAGGING
8535tag and (if present) the flagging note."
8536 (interactive)
8537 (let ((hdmarker (org-get-at-bol 'org-hd-marker))
8538 (win (selected-window))
8539 note heading newhead)
8540 (unless hdmarker
8541 (error "No linked entry at point"))
8542 (if (and (eq this-command last-command)
8543 (y-or-n-p "Unflag and remove any flagging note? "))
8544 (progn
8545 (org-agenda-remove-flag hdmarker)
8546 (let ((win (get-buffer-window "*Flagging Note*")))
8547 (and win (delete-window win)))
27e428e7 8548 (message "Entry unflagged"))
8d642074
CD
8549 (setq note (org-entry-get hdmarker "THEFLAGGINGNOTE"))
8550 (unless note
8551 (error "No flagging note"))
8552 (org-kill-new note)
8553 (org-switch-to-buffer-other-window "*Flagging Note*")
8554 (erase-buffer)
8555 (insert note)
8556 (goto-char (point-min))
8557 (while (re-search-forward "\\\\n" nil t)
8558 (replace-match "\n" t t))
8559 (goto-char (point-min))
8560 (select-window win)
8561 (message "Flagging note pushed to kill ring. Press [?] again to remove tag and note"))))
8562
8563(defun org-agenda-remove-flag (marker)
8bfe682a 8564 "Remove the FLAGGED tag and any flagging note in the entry."
8d642074
CD
8565 (let (newhead)
8566 (org-with-point-at marker
8567 (org-toggle-tag "FLAGGED" 'off)
8568 (org-entry-delete nil "THEFLAGGINGNOTE")
8569 (setq newhead (org-get-heading)))
8570 (org-agenda-change-all-lines newhead marker)
27e428e7 8571 (message "Entry unflagged")))
8d642074
CD
8572
8573(defun org-agenda-get-any-marker (&optional pos)
8574 (or (get-text-property (or pos (point-at-bol)) 'org-hd-marker)
8575 (get-text-property (or pos (point-at-bol)) 'org-marker)))
c8d0cf5c 8576
20908596
CD
8577;;; Appointment reminders
8578
8579(defvar appt-time-msg-list)
8580
8581;;;###autoload
e66ba1df 8582(defun org-agenda-to-appt (&optional refresh filter &rest args)
20908596
CD
8583 "Activate appointments found in `org-agenda-files'.
8584With a \\[universal-argument] prefix, refresh the list of
33306645 8585appointments.
20908596
CD
8586
8587If FILTER is t, interactively prompt the user for a regular
8588expression, and filter out entries that don't match it.
8589
8590If FILTER is a string, use this string as a regular expression
8591for filtering entries out.
8592
e66ba1df
BG
8593If FILTER is a function, filter out entries against which
8594calling the function returns nil. This function takes one
8595argument: an entry from `org-agenda-get-day-entries'.
8596
20908596
CD
8597FILTER can also be an alist with the car of each cell being
8598either 'headline or 'category. For example:
8599
8600 '((headline \"IMPORTANT\")
8601 (category \"Work\"))
8602
8603will only add headlines containing IMPORTANT or headlines
e66ba1df
BG
8604belonging to the \"Work\" category.
8605
8606ARGS are symbols indicating what kind of entries to consider.
8607By default `org-agenda-to-appt' will use :deadline, :scheduled
8608and :timestamp entries. See the docstring of `org-diary' for
8609details and examples."
20908596 8610 (interactive "P")
20908596
CD
8611 (if refresh (setq appt-time-msg-list nil))
8612 (if (eq filter t)
8613 (setq filter (read-from-minibuffer "Regexp filter: ")))
8614 (let* ((cnt 0) ; count added events
e66ba1df 8615 (scope (or args '(:deadline :scheduled :timestamp)))
20908596
CD
8616 (org-agenda-new-buffers nil)
8617 (org-deadline-warning-days 0)
acedf35c
CD
8618 ;; Do not use `org-today' here because appt only takes
8619 ;; time and without date as argument, so it may pass wrong
8620 ;; information otherwise
20908596
CD
8621 (today (org-date-to-gregorian
8622 (time-to-days (current-time))))
c8d0cf5c 8623 (org-agenda-restrict nil)
621f83e4 8624 (files (org-agenda-files 'unrestricted)) entries file)
20908596 8625 ;; Get all entries which may contain an appt
db55f368 8626 (org-prepare-agenda-buffers files)
20908596
CD
8627 (while (setq file (pop files))
8628 (setq entries
e66ba1df
BG
8629 (delq nil
8630 (append entries
8631 (apply 'org-agenda-get-day-entries
8632 file today scope)))))
20908596
CD
8633 ;; Map thru entries and find if we should filter them out
8634 (mapc
8635 (lambda(x)
621f83e4 8636 (let* ((evt (org-trim (or (get-text-property 1 'txt x) "")))
20908596
CD
8637 (cat (get-text-property 1 'org-category x))
8638 (tod (get-text-property 1 'time-of-day x))
8639 (ok (or (null filter)
8640 (and (stringp filter) (string-match filter evt))
e66ba1df 8641 (and (functionp filter) (funcall filter x))
20908596 8642 (and (listp filter)
e66ba1df
BG
8643 (let ((cat-filter (cadr (assoc 'category filter)))
8644 (evt-filter (cadr (assoc 'headline filter))))
8645 (or (and (stringp cat-filter)
8646 (string-match cat-filter cat))
8647 (and (stringp evt-filter)
8648 (string-match evt-filter evt))))))))
20908596
CD
8649 ;; FIXME: Shall we remove text-properties for the appt text?
8650 ;; (setq evt (set-text-properties 0 (length evt) nil evt))
8651 (when (and ok tod)
621f83e4 8652 (setq tod (concat "00" (number-to-string tod))
20908596 8653 tod (when (string-match
621f83e4 8654 "\\([0-9]\\{1,2\\}\\)\\([0-9]\\{2\\}\\)\\'" tod)
20908596
CD
8655 (concat (match-string 1 tod) ":"
8656 (match-string 2 tod))))
8657 (appt-add tod evt)
8658 (setq cnt (1+ cnt))))) entries)
8659 (org-release-buffers org-agenda-new-buffers)
8660 (if (eq cnt 0)
8661 (message "No event to add")
8662 (message "Added %d event%s for today" cnt (if (> cnt 1) "s" "")))))
8663
621f83e4
CD
8664(defun org-agenda-todayp (date)
8665 "Does DATE mean today, when considering `org-extend-today-until'?"
acedf35c
CD
8666 (let ((today (org-today))
8667 (date (if (and date (listp date)) (calendar-absolute-from-gregorian date)
8668 date)))
8669 (eq date today)))
621f83e4 8670
e66ba1df
BG
8671(defun org-agenda-todo-yesterday (&optional arg)
8672 "Like `org-agenda-todo' but the time of change will be 23:59 of yesterday"
8673 (interactive "P")
8674 (let* ((hour (third (decode-time
8675 (org-current-time))))
8676 (org-extend-today-until (1+ hour)))
8677 (org-agenda-todo arg)))
5b409b39 8678
e66ba1df 8679(provide 'org-agenda)
b349f79f 8680
20908596 8681;;; org-agenda.el ends here