Fix typos in ChangeLogs.
[bpt/emacs.git] / lisp / org / org-agenda.el
CommitLineData
b349f79f 1;;; org-agenda.el --- Dynamic task and appointment lists for Org
20908596 2
ab422c4d 3;; Copyright (C) 2004-2013 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
8223b1d2 32;; line. The Lisp does not evaluate parameters of a macro call; thus
e66ba1df 33;; it is not necessary to quote the parameters passed to one of those
8223b1d2 34;; functions. E.g. you can write:
e66ba1df
BG
35;;
36;; emacs -batch -l ~/.emacs -eval '(org-batch-agenda "a" org-agenda-span 7)'
37;;
8223b1d2 38;; To export an agenda spanning 7 days. If `org-batch-agenda' would
e66ba1df 39;; have been implemented as a regular function you'd have to quote the
8223b1d2 40;; symbol org-agenda-span. Moreover: To use a symbol as parameter
e66ba1df
BG
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)
8223b1d2 49(require 'org-macs)
20908596 50(eval-when-compile
86fbb8ca 51 (require 'cl))
20908596 52
b349f79f 53(declare-function diary-add-to-list "diary-lib"
20908596
CD
54 (date string specifier &optional marker globcolor literal))
55(declare-function calendar-absolute-from-iso "cal-iso" (date))
56(declare-function calendar-astro-date-string "cal-julian" (&optional date))
57(declare-function calendar-bahai-date-string "cal-bahai" (&optional date))
20908596
CD
58(declare-function calendar-chinese-date-string "cal-china" (&optional date))
59(declare-function calendar-coptic-date-string "cal-coptic" (&optional date))
60(declare-function calendar-ethiopic-date-string "cal-coptic" (&optional date))
61(declare-function calendar-french-date-string "cal-french" (&optional date))
62(declare-function calendar-goto-date "cal-move" (date))
63(declare-function calendar-hebrew-date-string "cal-hebrew" (&optional date))
64(declare-function calendar-islamic-date-string "cal-islam" (&optional date))
65(declare-function calendar-iso-date-string "cal-iso" (&optional date))
f6aafbed 66(declare-function calendar-iso-from-absolute "cal-iso" (date))
20908596
CD
67(declare-function calendar-julian-date-string "cal-julian" (&optional date))
68(declare-function calendar-mayan-date-string "cal-mayan" (&optional date))
69(declare-function calendar-persian-date-string "cal-persia" (&optional date))
e66ba1df
BG
70(declare-function calendar-check-holidays "holidays" (date))
71
68a1b090
GM
72(declare-function org-datetree-find-date-create "org-datetree"
73 (date &optional keep-restriction))
20908596 74(declare-function org-columns-quit "org-colview" ())
8bfe682a
CD
75(declare-function diary-date-display-form "diary-lib" (&optional type))
76(declare-function org-mobile-write-agenda-for-mobile "org-mobile" (file))
77(declare-function org-habit-insert-consistency-graphs
78 "org-habit" (&optional line))
79(declare-function org-is-habit-p "org-habit" (&optional pom))
80(declare-function org-habit-parse-todo "org-habit" (&optional pom))
68a1b090 81(declare-function org-habit-get-priority "org-habit" (habit &optional moment))
e66ba1df
BG
82(declare-function org-pop-to-buffer-same-window "org-compat"
83 (&optional buffer-or-name norecord label))
8223b1d2
BG
84(declare-function org-agenda-columns "org-colview" ())
85(declare-function org-add-archive-files "org-archive" (files))
86(declare-function org-capture "org-capture" (&optional goto keys))
87
88(defvar calendar-mode-map) ; defined in calendar.el
89(defvar org-clock-current-task nil) ; defined in org-clock.el
90(defvar org-mobile-force-id-on-agenda-items) ; defined in org-mobile.el
91(defvar org-habit-show-habits) ; defined in org-habit.el
8bfe682a 92(defvar org-habit-show-habits-only-for-today)
8223b1d2 93(defvar org-habit-show-all-today)
20908596
CD
94
95;; Defined somewhere in this file, but used before definition.
8223b1d2
BG
96(defvar org-agenda-buffer-name "*Org Agenda*")
97(defvar org-agenda-overriding-header nil)
8d642074 98(defvar org-agenda-title-append nil)
8223b1d2
BG
99(org-no-warnings (defvar entry)) ;; unprefixed, from calendar.el
100(org-no-warnings (defvar date)) ;; unprefixed, from calendar.el
20908596
CD
101(defvar original-date) ; dynamically scoped, calendar.el does scope this
102
8223b1d2
BG
103(defvar org-agenda-undo-list nil
104 "List of undoable operations in the agenda since last refresh.")
105(defvar org-agenda-pending-undo-list nil
106 "In a series of undo commands, this is the list of remaining undo items.")
107
20908596
CD
108(defcustom org-agenda-confirm-kill 1
109 "When set, remote killing from the agenda buffer needs confirmation.
110When t, a confirmation is always needed. When a number N, confirmation is
111only needed when the text to be killed contains more than N non-white lines."
112 :group 'org-agenda
113 :type '(choice
114 (const :tag "Never" nil)
115 (const :tag "Always" t)
c8d0cf5c 116 (integer :tag "When more than N lines")))
20908596
CD
117
118(defcustom org-agenda-compact-blocks nil
ed21c5c8 119 "Non-nil means make the block agenda more compact.
3ab2c837
BG
120This is done globally by leaving out lines like the agenda span
121name and week number or the separator lines."
20908596
CD
122 :group 'org-agenda
123 :type 'boolean)
124
0bd48b37
CD
125(defcustom org-agenda-block-separator ?=
126 "The separator between blocks in the agenda.
127If this is a string, it will be used as the separator, with a newline added.
3ab2c837
BG
128If it is a character, it will be repeated to fill the window width.
129If nil the separator is disabled. In `org-agenda-custom-commands' this
130addresses the separator between the current and the previous block."
0bd48b37
CD
131 :group 'org-agenda
132 :type '(choice
3ab2c837 133 (const :tag "Disabled" nil)
0bd48b37
CD
134 (character)
135 (string)))
136
20908596 137(defgroup org-agenda-export nil
8223b1d2
BG
138 "Options concerning exporting agenda views in Org-mode."
139 :tag "Org Agenda Export"
140 :group 'org-agenda)
20908596
CD
141
142(defcustom org-agenda-with-colors t
ed21c5c8 143 "Non-nil means use colors in agenda views."
20908596
CD
144 :group 'org-agenda-export
145 :type 'boolean)
146
147(defcustom org-agenda-exporter-settings nil
148 "Alist of variable/value pairs that should be active during agenda export.
c8d0cf5c
CD
149This is a good place to set options for ps-print and for htmlize.
150Note that the way this is implemented, the values will be evaluated
151before assigned to the variables. So make sure to quote values you do
152*not* want evaluated, for example
153
154 (setq org-agenda-exporter-settings
155 '((ps-print-color-p 'black-white)))"
20908596
CD
156 :group 'org-agenda-export
157 :type '(repeat
158 (list
159 (variable)
160 (sexp :tag "Value"))))
161
c8d0cf5c 162(defcustom org-agenda-before-write-hook '(org-agenda-add-entry-text)
8223b1d2
BG
163 "Hook run in a temporary buffer before writing the agenda to an export file.
164A useful function for this hook is `org-agenda-add-entry-text'."
c8d0cf5c
CD
165 :group 'org-agenda-export
166 :type 'hook
167 :options '(org-agenda-add-entry-text))
168
169(defcustom org-agenda-add-entry-text-maxlines 0
170 "Maximum number of entry text lines to be added to agenda.
171This is only relevant when `org-agenda-add-entry-text' is part of
8223b1d2 172`org-agenda-before-write-hook', which is the default.
c8d0cf5c
CD
173When this is 0, nothing will happen. When it is greater than 0, it
174specifies the maximum number of lines that will be added for each entry
54a0dee5
CD
175that is listed in the agenda view.
176
177Note that this variable is not used during display, only when exporting
86fbb8ca
CD
178the agenda. For agenda display, see the variables `org-agenda-entry-text-mode'
179and `org-agenda-entry-text-maxlines'."
c8d0cf5c
CD
180 :group 'org-agenda
181 :type 'integer)
182
183(defcustom org-agenda-add-entry-text-descriptive-links t
ed21c5c8 184 "Non-nil means export org-links as descriptive links in agenda added text.
c8d0cf5c
CD
185This variable applies to the text added to the agenda when
186`org-agenda-add-entry-text-maxlines' is larger than 0.
e66ba1df 187When this variable nil, the URL will (also) be shown."
c8d0cf5c
CD
188 :group 'org-agenda
189 :type 'boolean)
190
8223b1d2 191(defcustom org-agenda-export-html-style nil
20908596
CD
192 "The style specification for exported HTML Agenda files.
193If this variable contains a string, it will replace the default <style>
194section as produced by `htmlize'.
195Since there are different ways of setting style information, this variable
196needs to contain the full HTML structure to provide a style, including the
197surrounding HTML tags. The style specifications should include definitions
198the fonts used by the agenda, here is an example:
199
200 <style type=\"text/css\">
201 p { font-weight: normal; color: gray; }
202 .org-agenda-structure {
203 font-size: 110%;
204 color: #003399;
205 font-weight: 600;
206 }
207 .org-todo {
208 color: #cc6666;
209 font-weight: bold;
210 }
c8d0cf5c
CD
211 .org-agenda-done {
212 color: #339933;
213 }
20908596
CD
214 .org-done {
215 color: #339933;
216 }
217 .title { text-align: center; }
218 .todo, .deadline { color: red; }
219 .done { color: green; }
220 </style>
221
222or, if you want to keep the style in a file,
223
224 <link rel=\"stylesheet\" type=\"text/css\" href=\"mystyles.css\">
225
226As the value of this option simply gets inserted into the HTML <head> header,
8223b1d2 227you can \"misuse\" it to also add other text to the header."
20908596
CD
228 :group 'org-agenda-export
229 :group 'org-export-html
230 :type 'string)
231
86fbb8ca
CD
232(defcustom org-agenda-persistent-filter nil
233 "When set, keep filters from one agenda view to the next."
234 :group 'org-agenda
235 :type 'boolean)
236
20908596 237(defgroup org-agenda-custom-commands nil
8223b1d2
BG
238 "Options concerning agenda views in Org-mode."
239 :tag "Org Agenda Custom Commands"
240 :group 'org-agenda)
20908596
CD
241
242(defconst org-sorting-choice
243 '(choice
244 (const time-up) (const time-down)
245 (const category-keep) (const category-up) (const category-down)
246 (const tag-down) (const tag-up)
247 (const priority-up) (const priority-down)
621f83e4 248 (const todo-state-up) (const todo-state-down)
c8d0cf5c 249 (const effort-up) (const effort-down)
8bfe682a 250 (const habit-up) (const habit-down)
86fbb8ca 251 (const alpha-up) (const alpha-down)
c8d0cf5c 252 (const user-defined-up) (const user-defined-down))
20908596
CD
253 "Sorting choices.")
254
e66ba1df
BG
255;; Keep custom values for `org-agenda-filter-preset' compatible with
256;; the new variable `org-agenda-tag-filter-preset'.
8223b1d2
BG
257(if (fboundp 'defvaralias)
258 (defvaralias 'org-agenda-filter-preset 'org-agenda-tag-filter-preset)
259 (defvaralias 'org-agenda-filter 'org-agenda-tag-filter))
e66ba1df 260
20908596 261(defconst org-agenda-custom-commands-local-options
8223b1d2 262 `(repeat :tag "Local settings for this command. Remember to quote values"
20908596 263 (choice :tag "Setting"
8223b1d2
BG
264 (list :tag "Heading for this block"
265 (const org-agenda-overriding-header)
266 (string :tag "Headline"))
267 (list :tag "Files to be searched"
268 (const org-agenda-files)
269 (list
270 (const :format "" quote)
271 (repeat (file))))
272 (list :tag "Sorting strategy"
273 (const org-agenda-sorting-strategy)
274 (list
275 (const :format "" quote)
276 (repeat
277 ,org-sorting-choice)))
278 (list :tag "Prefix format"
279 (const org-agenda-prefix-format :value " %-12:c%?-12t% s")
280 (string))
281 (list :tag "Number of days in agenda"
282 (const org-agenda-span)
283 (choice (const :tag "Day" 'day)
284 (const :tag "Week" 'week)
285 (const :tag "Month" 'month)
286 (const :tag "Year" 'year)
287 (integer :tag "Custom")))
288 (list :tag "Fixed starting date"
289 (const org-agenda-start-day)
290 (string :value "2007-11-01"))
291 (list :tag "Start on day of week"
292 (const org-agenda-start-on-weekday)
293 (choice :value 1
294 (const :tag "Today" nil)
295 (integer :tag "Weekday No.")))
296 (list :tag "Include data from diary"
297 (const org-agenda-include-diary)
298 (boolean))
299 (list :tag "Deadline Warning days"
300 (const org-deadline-warning-days)
301 (integer :value 1))
302 (list :tag "Category filter preset"
303 (const org-agenda-category-filter-preset)
304 (list
305 (const :format "" quote)
306 (repeat
307 (string :tag "+category or -category"))))
308 (list :tag "Tags filter preset"
309 (const org-agenda-tag-filter-preset)
310 (list
311 (const :format "" quote)
312 (repeat
313 (string :tag "+tag or -tag"))))
314 (list :tag "Set daily/weekly entry types"
315 (const org-agenda-entry-types)
316 (list
317 (const :format "" quote)
318 (set :greedy t :value (:deadline :scheduled :timestamp :sexp)
319 (const :deadline)
320 (const :scheduled)
321 (const :timestamp)
322 (const :sexp))))
323 (list :tag "Standard skipping condition"
324 :value (org-agenda-skip-function '(org-agenda-skip-entry-if))
325 (const org-agenda-skip-function)
326 (list
327 (const :format "" quote)
328 (list
329 (choice
330 :tag "Skipping range"
331 (const :tag "Skip entry" org-agenda-skip-entry-if)
332 (const :tag "Skip subtree" org-agenda-skip-subtree-if))
333 (repeat :inline t :tag "Conditions for skipping"
ed21c5c8 334 (choice
8223b1d2
BG
335 :tag "Condition type"
336 (list :tag "Regexp matches" :inline t (const :format "" 'regexp) (regexp))
337 (list :tag "Regexp does not match" :inline t (const :format "" 'notregexp) (regexp))
338 (list :tag "TODO state is" :inline t
339 (const 'todo)
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")))))
347 (list :tag "TODO state is not" :inline t
348 (const 'nottodo)
349 (choice
350 (const :tag "any not-done state" 'todo)
351 (const :tag "any done state" 'done)
352 (const :tag "any state" 'any)
353 (list :tag "Keyword list"
354 (const :format "" quote)
355 (repeat (string :tag "Keyword")))))
356 (const :tag "scheduled" 'scheduled)
357 (const :tag "not scheduled" 'notscheduled)
358 (const :tag "deadline" 'deadline)
359 (const :tag "no deadline" 'notdeadline)
360 (const :tag "timestamp" 'timestamp)
361 (const :tag "no timestamp" 'nottimestamp))))))
362 (list :tag "Non-standard skipping condition"
363 :value (org-agenda-skip-function)
364 (const org-agenda-skip-function)
365 (sexp :tag "Function or form (quoted!)"))
366 (list :tag "Any variable"
367 (variable :tag "Variable")
368 (sexp :tag "Value (sexp)"))))
20908596
CD
369 "Selection of examples for agenda command settings.
370This will be spliced into the custom type of
371`org-agenda-custom-commands'.")
372
373
e66ba1df
BG
374(defcustom org-agenda-custom-commands '(("n" "Agenda and all TODO's"
375 ((agenda "") (alltodo))))
20908596
CD
376 "Custom commands for the agenda.
377These commands will be offered on the splash screen displayed by the
378agenda dispatcher \\[org-agenda]. Each entry is a list like this:
379
380 (key desc type match settings files)
381
382key The key (one or more characters as a string) to be associated
383 with the command.
e66ba1df 384desc A description of the command, when omitted or nil, a default
20908596
CD
385 description is built using MATCH.
386type The command type, any of the following symbols:
387 agenda The daily/weekly agenda.
388 todo Entries with a specific TODO keyword, in all agenda files.
389 search Entries containing search words entry or headline.
390 tags Tags/Property/TODO match in all agenda files.
391 tags-todo Tags/P/T match in all agenda files, TODO entries only.
392 todo-tree Sparse tree of specific TODO keyword in *current* file.
393 tags-tree Sparse tree with all tags matches in *current* file.
394 occur-tree Occur sparse tree for *current* file.
395 ... A user-defined function.
396match What to search for:
397 - a single keyword for TODO keyword searches
398 - a tags match expression for tags searches
e66ba1df 399 - a word search expression for text searches.
20908596
CD
400 - a regular expression for occur searches
401 For all other commands, this should be the empty string.
402settings A list of option settings, similar to that in a let form, so like
403 this: ((opt1 val1) (opt2 val2) ...). The values will be
404 evaluated at the moment of execution, so quote them when needed.
405files A list of files file to write the produced agenda buffer to
406 with the command `org-store-agenda-views'.
407 If a file name ends in \".html\", an HTML version of the buffer
e66ba1df 408 is written out. If it ends in \".ps\", a postscript version is
33306645 409 produced. Otherwise, only the plain text is written to the file.
20908596
CD
410
411You can also define a set of commands, to create a composite agenda buffer.
412In this case, an entry looks like this:
413
414 (key desc (cmd1 cmd2 ...) general-settings-for-whole-set files)
415
416where
417
418desc A description string to be displayed in the dispatcher menu.
419cmd An agenda command, similar to the above. However, tree commands
153ae947 420 are not allowed, but instead you can get agenda and global todo list.
20908596
CD
421 So valid commands for a set are:
422 (agenda \"\" settings)
423 (alltodo \"\" settings)
424 (stuck \"\" settings)
425 (todo \"match\" settings files)
426 (search \"match\" settings files)
427 (tags \"match\" settings files)
428 (tags-todo \"match\" settings files)
429
430Each command can carry a list of options, and another set of options can be
431given for the whole set of commands. Individual command options take
432precedence over the general options.
433
434When using several characters as key to a command, the first characters
435are prefix commands. For the dispatcher to display useful information, you
436should provide a description for the prefix, like
437
438 (setq org-agenda-custom-commands
439 '((\"h\" . \"HOME + Name tag searches\") ; describe prefix \"h\"
440 (\"hl\" tags \"+HOME+Lisa\")
441 (\"hp\" tags \"+HOME+Peter\")
442 (\"hk\" tags \"+HOME+Kim\")))"
443 :group 'org-agenda-custom-commands
444 :type `(repeat
445 (choice :value ("x" "Describe command here" tags "" nil)
8223b1d2
BG
446 (list :tag "Single command"
447 (string :tag "Access Key(s) ")
448 (option (string :tag "Description"))
449 (choice
450 (const :tag "Agenda" agenda)
451 (const :tag "TODO list" alltodo)
452 (const :tag "Search words" search)
453 (const :tag "Stuck projects" stuck)
454 (const :tag "Tags/Property match (all agenda files)" tags)
455 (const :tag "Tags/Property match of TODO entries (all agenda files)" tags-todo)
456 (const :tag "TODO keyword search (all agenda files)" todo)
457 (const :tag "Tags sparse tree (current buffer)" tags-tree)
458 (const :tag "TODO keyword tree (current buffer)" todo-tree)
459 (const :tag "Occur tree (current buffer)" occur-tree)
460 (sexp :tag "Other, user-defined function"))
461 (string :tag "Match (only for some commands)")
462 ,org-agenda-custom-commands-local-options
463 (option (repeat :tag "Export" (file :tag "Export to"))))
464 (list :tag "Command series, all agenda files"
465 (string :tag "Access Key(s)")
466 (string :tag "Description ")
467 (repeat :tag "Component"
468 (choice
469 (list :tag "Agenda"
470 (const :format "" agenda)
471 (const :tag "" :format "" "")
472 ,org-agenda-custom-commands-local-options)
473 (list :tag "TODO list (all keywords)"
474 (const :format "" alltodo)
475 (const :tag "" :format "" "")
476 ,org-agenda-custom-commands-local-options)
477 (list :tag "Search words"
478 (const :format "" search)
479 (string :tag "Match")
480 ,org-agenda-custom-commands-local-options)
481 (list :tag "Stuck projects"
482 (const :format "" stuck)
483 (const :tag "" :format "" "")
484 ,org-agenda-custom-commands-local-options)
485 (list :tag "Tags search"
486 (const :format "" tags)
487 (string :tag "Match")
488 ,org-agenda-custom-commands-local-options)
489 (list :tag "Tags search, TODO entries only"
490 (const :format "" tags-todo)
491 (string :tag "Match")
492 ,org-agenda-custom-commands-local-options)
493 (list :tag "TODO keyword search"
494 (const :format "" todo)
495 (string :tag "Match")
496 ,org-agenda-custom-commands-local-options)
497 (list :tag "Other, user-defined function"
498 (symbol :tag "function")
499 (string :tag "Match")
500 ,org-agenda-custom-commands-local-options)))
501
502 (repeat :tag "Settings for entire command set"
503 (list (variable :tag "Any variable")
504 (sexp :tag "Value")))
505 (option (repeat :tag "Export" (file :tag "Export to"))))
506 (cons :tag "Prefix key documentation"
507 (string :tag "Access Key(s)")
508 (string :tag "Description ")))))
20908596
CD
509
510(defcustom org-agenda-query-register ?o
511 "The register holding the current query string.
33306645 512The purpose of this is that if you construct a query string interactively,
20908596
CD
513you can then use it to define a custom command."
514 :group 'org-agenda-custom-commands
515 :type 'character)
516
517(defcustom org-stuck-projects
518 '("+LEVEL=2/-DONE" ("TODO" "NEXT" "NEXTACTION") nil "")
519 "How to identify stuck projects.
520This is a list of four items:
c8d0cf5c
CD
5211. A tags/todo/property matcher string that is used to identify a project.
522 See the manual for a description of tag and property searches.
20908596
CD
523 The entire tree below a headline matched by this is considered one project.
5242. A list of TODO keywords identifying non-stuck projects.
525 If the project subtree contains any headline with one of these todo
526 keywords, the project is considered to be not stuck. If you specify
527 \"*\" as a keyword, any TODO keyword will mark the project unstuck.
5283. A list of tags identifying non-stuck projects.
529 If the project subtree contains any headline with one of these tags,
530 the project is considered to be not stuck. If you specify \"*\" as
c8d0cf5c
CD
531 a tag, any tag will mark the project unstuck. Note that this is about
532 the explicit presence of a tag somewhere in the subtree, inherited
d3517077 533 tags do not count here. If inherited tags make a project not stuck,
c8d0cf5c 534 use \"-TAG\" in the tags part of the matcher under (1.) above.
20908596
CD
5354. An arbitrary regular expression matching non-stuck projects.
536
c8d0cf5c
CD
537If the project turns out to be not stuck, search continues also in the
538subtree to see if any of the subtasks have project status.
539
540See also the variable `org-tags-match-list-sublevels' which applies
541to projects matched by this search as well.
542
20908596
CD
543After defining this variable, you may use \\[org-agenda-list-stuck-projects]
544or `C-c a #' to produce the list."
545 :group 'org-agenda-custom-commands
546 :type '(list
547 (string :tag "Tags/TODO match to identify a project")
548 (repeat :tag "Projects are *not* stuck if they have an entry with TODO keyword any of" (string))
549 (repeat :tag "Projects are *not* stuck if they have an entry with TAG being any of" (string))
c8d0cf5c 550 (regexp :tag "Projects are *not* stuck if this regexp matches inside the subtree")))
20908596 551
71d35b24
CD
552(defcustom org-agenda-filter-effort-default-operator "<"
553 "The default operator for effort estimate filtering.
93b62de8 554If you select an effort estimate limit without first pressing an operator,
71d35b24
CD
555this one will be used."
556 :group 'org-agenda-custom-commands
557 :type '(choice (const :tag "less or equal" "<")
558 (const :tag "greater or equal"">")
559 (const :tag "equal" "=")))
20908596
CD
560
561(defgroup org-agenda-skip nil
8223b1d2
BG
562 "Options concerning skipping parts of agenda files."
563 :tag "Org Agenda Skip"
564 :group 'org-agenda)
3ab2c837
BG
565
566(defcustom org-agenda-skip-function-global nil
567 "Function to be called at each match during agenda construction.
568If this function returns nil, the current match should not be skipped.
569If the function decided to skip an agenda match, is must return the
570buffer position from which the search should be continued.
571This may also be a Lisp form, which will be evaluated.
572
573This variable will be applied to every agenda match, including
574tags/property searches and TODO lists. So try to make the test function
575do its checking as efficiently as possible. To implement a skipping
576condition just for specific agenda commands, use the variable
577`org-agenda-skip-function' which can be set in the options section
578of custom agenda commands."
579 :group 'org-agenda-skip
580 :type 'sexp)
581
0bd48b37
CD
582(defgroup org-agenda-daily/weekly nil
583 "Options concerning the daily/weekly agenda."
584 :tag "Org Agenda Daily/Weekly"
585 :group 'org-agenda)
586(defgroup org-agenda-todo-list nil
587 "Options concerning the global todo list agenda view."
588 :tag "Org Agenda Todo List"
589 :group 'org-agenda)
590(defgroup org-agenda-match-view nil
591 "Options concerning the general tags/property/todo match agenda view."
592 :tag "Org Agenda Match View"
593 :group 'org-agenda)
8bfe682a
CD
594(defgroup org-agenda-search-view nil
595 "Options concerning the general tags/property/todo match agenda view."
596 :tag "Org Agenda Match View"
597 :group 'org-agenda)
20908596 598
2c3ad40d 599(defvar org-agenda-archives-mode nil
ed21c5c8 600 "Non-nil means the agenda will include archived items.
2c3ad40d
CD
601If this is the symbol `trees', trees in the selected agenda scope
602that are marked with the ARCHIVE tag will be included anyway. When this is
603t, also all archive files associated with the current selection of agenda
604files will be included.")
605
b349f79f 606(defcustom org-agenda-skip-comment-trees t
ed21c5c8 607 "Non-nil means skip trees that start with the COMMENT keyword.
33306645 608When nil, these trees are also scanned by agenda commands."
b349f79f
CD
609 :group 'org-agenda-skip
610 :type 'boolean)
611
20908596 612(defcustom org-agenda-todo-list-sublevels t
ed21c5c8 613 "Non-nil means check also the sublevels of a TODO entry for TODO entries.
20908596
CD
614When nil, the sublevels of a TODO entry are not checked, resulting in
615potentially much shorter TODO lists."
616 :group 'org-agenda-skip
0bd48b37 617 :group 'org-agenda-todo-list
20908596
CD
618 :type 'boolean)
619
620(defcustom org-agenda-todo-ignore-with-date nil
ed21c5c8 621 "Non-nil means don't show entries with a date in the global todo list.
20908596
CD
622You can use this if you prefer to mark mere appointments with a TODO keyword,
623but don't want them to show up in the TODO list.
624When this is set, it also covers deadlines and scheduled items, the settings
625of `org-agenda-todo-ignore-scheduled' and `org-agenda-todo-ignore-deadlines'
c8d0cf5c
CD
626will be ignored.
627See also the variable `org-agenda-tags-todo-honor-ignore-options'."
20908596 628 :group 'org-agenda-skip
0bd48b37 629 :group 'org-agenda-todo-list
20908596
CD
630 :type 'boolean)
631
acedf35c
CD
632(defcustom org-agenda-todo-ignore-timestamp nil
633 "Non-nil means don't show entries with a timestamp.
634This applies when creating the global todo list.
635Valid values are:
636
637past Don't show entries for today or in the past.
638
639future Don't show entries with a timestamp in the future.
640 The idea behind this is that if it has a future
641 timestamp, you don't want to think about it until the
642 date.
643
644all Don't show any entries with a timestamp in the global todo list.
645 The idea behind this is that by setting a timestamp, you
646 have already \"taken care\" of this item.
647
8223b1d2
BG
648This variable can also have an integer as a value. If positive (N),
649todos with a timestamp N or more days in the future will be ignored. If
3ab2c837 650negative (-N), todos with a timestamp N or more days in the past will be
8223b1d2
BG
651ignored. If 0, todos with a timestamp either today or in the future will
652be ignored. For example, a value of -1 will exclude todos with a
3ab2c837
BG
653timestamp in the past (yesterday or earlier), while a value of 7 will
654exclude todos with a timestamp a week or more in the future.
655
acedf35c
CD
656See also `org-agenda-todo-ignore-with-date'.
657See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want
658to make his option also apply to the tags-todo list."
659 :group 'org-agenda-skip
660 :group 'org-agenda-todo-list
372d7b21 661 :version "24.1"
acedf35c
CD
662 :type '(choice
663 (const :tag "Ignore future timestamp todos" future)
664 (const :tag "Ignore past or present timestamp todos" past)
665 (const :tag "Ignore all timestamp todos" all)
3ab2c837
BG
666 (const :tag "Show timestamp todos" nil)
667 (integer :tag "Ignore if N or more days in past(-) or future(+).")))
acedf35c 668
20908596 669(defcustom org-agenda-todo-ignore-scheduled nil
ed21c5c8
CD
670 "Non-nil means, ignore some scheduled TODO items when making TODO list.
671This applies when creating the global todo list.
672Valid values are:
673
674past Don't show entries scheduled today or in the past.
675
676future Don't show entries scheduled in the future.
677 The idea behind this is that by scheduling it, you don't want to
678 think about it until the scheduled date.
679
680all Don't show any scheduled entries in the global todo list.
681 The idea behind this is that by scheduling it, you have already
682 \"taken care\" of this item.
683
684t Same as `all', for backward compatibility.
685
8223b1d2 686This variable can also have an integer as a value. See
3ab2c837
BG
687`org-agenda-todo-ignore-timestamp' for more details.
688
c8d0cf5c 689See also `org-agenda-todo-ignore-with-date'.
ed21c5c8
CD
690See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want
691to make his option also apply to the tags-todo list."
20908596 692 :group 'org-agenda-skip
0bd48b37 693 :group 'org-agenda-todo-list
ed21c5c8
CD
694 :type '(choice
695 (const :tag "Ignore future-scheduled todos" future)
696 (const :tag "Ignore past- or present-scheduled todos" past)
697 (const :tag "Ignore all scheduled todos" all)
698 (const :tag "Ignore all scheduled todos (compatibility)" t)
3ab2c837
BG
699 (const :tag "Show scheduled todos" nil)
700 (integer :tag "Ignore if N or more days in past(-) or future(+).")))
20908596
CD
701
702(defcustom org-agenda-todo-ignore-deadlines nil
ed21c5c8
CD
703 "Non-nil means ignore some deadlined TODO items when making TODO list.
704There are different motivations for using different values, please think
705carefully when configuring this variable.
706
86fbb8ca 707This applies when creating the global todo list.
ed21c5c8
CD
708Valid values are:
709
710near Don't show near deadline entries. A deadline is near when it is
711 closer than `org-deadline-warning-days' days. The idea behind this
712 is that such items will appear in the agenda anyway.
713
714far Don't show TODO entries where a deadline has been defined, but
715 the deadline is not near. This is useful if you don't want to
716 use the todo list to figure out what to do now.
717
718past Don't show entries with a deadline timestamp for today or in the past.
719
720future Don't show entries with a deadline timestamp in the future, not even
721 when they become `near' ones. Use it with caution.
722
723all Ignore all TODO entries that do have a deadline.
724
725t Same as `near', for backward compatibility.
726
8223b1d2 727This variable can also have an integer as a value. See
3ab2c837
BG
728`org-agenda-todo-ignore-timestamp' for more details.
729
c8d0cf5c 730See also `org-agenda-todo-ignore-with-date'.
ed21c5c8
CD
731See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want
732to make his option also apply to the tags-todo list."
20908596 733 :group 'org-agenda-skip
0bd48b37 734 :group 'org-agenda-todo-list
ed21c5c8
CD
735 :type '(choice
736 (const :tag "Ignore near deadlines" near)
737 (const :tag "Ignore near deadlines (compatibility)" t)
738 (const :tag "Ignore far deadlines" far)
739 (const :tag "Ignore all TODOs with a deadlines" all)
3ab2c837
BG
740 (const :tag "Show all TODOs, even if they have a deadline" nil)
741 (integer :tag "Ignore if N or more days in past(-) or future(+).")))
0bd48b37
CD
742
743(defcustom org-agenda-tags-todo-honor-ignore-options nil
ed21c5c8 744 "Non-nil means honor todo-list ...ignore options also in tags-todo search.
0bd48b37
CD
745The variables
746 `org-agenda-todo-ignore-with-date',
acedf35c
CD
747 `org-agenda-todo-ignore-timestamp',
748 `org-agenda-todo-ignore-scheduled',
0bd48b37
CD
749 `org-agenda-todo-ignore-deadlines'
750make the global TODO list skip entries that have time stamps of certain
751kinds. If this option is set, the same options will also apply for the
752tags-todo search, which is the general tags/property matcher
753restricted to unfinished TODO entries only."
754 :group 'org-agenda-skip
755 :group 'org-agenda-todo-list
756 :group 'org-agenda-match-view
20908596
CD
757 :type 'boolean)
758
759(defcustom org-agenda-skip-scheduled-if-done nil
760 "Non-nil means don't show scheduled items in agenda when they are done.
761This is relevant for the daily/weekly agenda, not for the TODO list. And
762it applies only to the actual date of the scheduling. Warnings about
763an item with a past scheduling dates are always turned off when the item
764is DONE."
765 :group 'org-agenda-skip
0bd48b37 766 :group 'org-agenda-daily/weekly
20908596
CD
767 :type 'boolean)
768
54a0dee5
CD
769(defcustom org-agenda-skip-scheduled-if-deadline-is-shown nil
770 "Non-nil means skip scheduling line if same entry shows because of deadline.
771In the agenda of today, an entry can show up multiple times because
772it is both scheduled and has a nearby deadline, and maybe a plain time
773stamp as well.
774When this variable is t, then only the deadline is shown and the fact that
775the entry is scheduled today or was scheduled previously is not shown.
776When this variable is nil, the entry will be shown several times. When
777the variable is the symbol `not-today', then skip scheduled previously,
778but not scheduled today."
779 :group 'org-agenda-skip
780 :group 'org-agenda-daily/weekly
781 :type '(choice
782 (const :tag "Never" nil)
783 (const :tag "Always" t)
784 (const :tag "Not when scheduled today" not-today)))
785
8223b1d2
BG
786(defcustom org-agenda-skip-timestamp-if-deadline-is-shown nil
787 "Non-nil means skip timestamp line if same entry shows because of deadline.
788In the agenda of today, an entry can show up multiple times
789because it has both a plain timestamp and has a nearby deadline.
790When this variable is t, then only the deadline is shown and the
791fact that the entry has a timestamp for or including today is not
792shown. When this variable is nil, the entry will be shown
793several times."
794 :group 'org-agenda-skip
795 :group 'org-agenda-daily/weekly
796 :version "24.1"
797 :type '(choice
798 (const :tag "Never" nil)
799 (const :tag "Always" t)))
800
20908596 801(defcustom org-agenda-skip-deadline-if-done nil
33306645 802 "Non-nil means don't show deadlines when the corresponding item is done.
20908596
CD
803When nil, the deadline is still shown and should give you a happy feeling.
804This is relevant for the daily/weekly agenda. And it applied only to the
33306645 805actually date of the deadline. Warnings about approaching and past-due
20908596
CD
806deadlines are always turned off when the item is DONE."
807 :group 'org-agenda-skip
0bd48b37 808 :group 'org-agenda-daily/weekly
20908596
CD
809 :type 'boolean)
810
ed21c5c8
CD
811(defcustom org-agenda-skip-deadline-prewarning-if-scheduled nil
812 "Non-nil means skip deadline prewarning when entry is also scheduled.
813This will apply on all days where a prewarning for the deadline would
814be shown, but not at the day when the entry is actually due. On that day,
815the deadline will be shown anyway.
816This variable may be set to nil, t, or a number which will then give
817the number of days before the actual deadline when the prewarnings
818should resume.
819This can be used in a workflow where the first showing of the deadline will
820trigger you to schedule it, and then you don't want to be reminded of it
821because you will take care of it on the day when scheduled."
822 :group 'org-agenda-skip
823 :group 'org-agenda-daily/weekly
372d7b21 824 :version "24.1"
ed21c5c8 825 :type '(choice
735135f9 826 (const :tag "Always show prewarning" nil)
ed21c5c8
CD
827 (const :tag "Remove prewarning if entry is scheduled" t)
828 (integer :tag "Restart prewarning N days before deadline")))
829
e66ba1df 830(defcustom org-agenda-skip-additional-timestamps-same-entry nil
c8d0cf5c
CD
831 "When nil, multiple same-day timestamps in entry make multiple agenda lines.
832When non-nil, after the search for timestamps has matched once in an
833entry, the rest of the entry will not be searched."
834 :group 'org-agenda-skip
835 :type 'boolean)
836
20908596
CD
837(defcustom org-agenda-skip-timestamp-if-done nil
838 "Non-nil means don't select item by timestamp or -range if it is DONE."
839 :group 'org-agenda-skip
0bd48b37 840 :group 'org-agenda-daily/weekly
20908596
CD
841 :type 'boolean)
842
c7cf0ebc 843(defcustom org-agenda-dim-blocked-tasks nil
ed21c5c8 844 "Non-nil means dim blocked tasks in the agenda display.
c8d0cf5c
CD
845This causes some overhead during agenda construction, but if you
846have turned on `org-enforce-todo-dependencies',
847`org-enforce-todo-checkbox-dependencies', or any other blocking
848mechanism, this will create useful feedback in the agenda.
849
8bfe682a 850Instead of t, this variable can also have the value `invisible'.
c8d0cf5c
CD
851Then blocked tasks will be invisible and only become visible when
852they become unblocked. An exemption to this behavior is when a task is
853blocked because of unchecked checkboxes below it. Since checkboxes do
854not show up in the agenda views, making this task invisible you remove any
855trace from agenda views that there is something to do. Therefore, a task
856that is blocked because of checkboxes will never be made invisible, it
857will only be dimmed."
d6685abc
CD
858 :group 'org-agenda-daily/weekly
859 :group 'org-agenda-todo-list
c7cf0ebc 860 :version "24.3"
d6685abc
CD
861 :type '(choice
862 (const :tag "Do not dim" nil)
e4769531 863 (const :tag "Dim to a gray face" t)
8bfe682a 864 (const :tag "Make invisible" invisible)))
d6685abc 865
20908596 866(defcustom org-timeline-show-empty-dates 3
ed21c5c8 867 "Non-nil means `org-timeline' also shows dates without an entry.
20908596
CD
868When nil, only the days which actually have entries are shown.
869When t, all days between the first and the last date are shown.
870When an integer, show also empty dates, but if there is a gap of more than
871N days, just insert a special line indicating the size of the gap."
872 :group 'org-agenda-skip
873 :type '(choice
874 (const :tag "None" nil)
875 (const :tag "All" t)
c8d0cf5c 876 (integer :tag "at most")))
20908596 877
20908596
CD
878(defgroup org-agenda-startup nil
879 "Options concerning initial settings in the Agenda in Org Mode."
880 :tag "Org Agenda Startup"
881 :group 'org-agenda)
882
afe98dfa 883(defcustom org-agenda-menu-show-matcher t
3ab2c837 884 "Non-nil means show the match string in the agenda dispatcher menu.
afe98dfa
CD
885When nil, the matcher string is not shown, but is put into the help-echo
886property so than moving the mouse over the command shows it.
887Setting it to nil is good if matcher strings are very long and/or if
8223b1d2 888you want to use two-columns display (see `org-agenda-menu-two-columns')."
afe98dfa 889 :group 'org-agenda
372d7b21 890 :version "24.1"
afe98dfa
CD
891 :type 'boolean)
892
a89c8ef0 893(define-obsolete-variable-alias 'org-agenda-menu-two-column 'org-agenda-menu-two-columns "24.3")
8223b1d2
BG
894
895(defcustom org-agenda-menu-two-columns nil
afe98dfa
CD
896 "Non-nil means, use two columns to show custom commands in the dispatcher.
897If you use this, you probably want to set `org-agenda-menu-show-matcher'
898to nil."
899 :group 'org-agenda
372d7b21 900 :version "24.1"
afe98dfa
CD
901 :type 'boolean)
902
a89c8ef0 903(define-obsolete-variable-alias 'org-finalize-agenda-hook 'org-agenda-finalize-hook "24.3")
8223b1d2
BG
904(defcustom org-agenda-finalize-hook nil
905 "Hook run just before displaying an agenda buffer.
906The buffer is still writable when the hook is called.
907
908You can modify some of the buffer substrings but you should be
909extra careful not to modify the text properties of the agenda
910headlines as the agenda display heavily relies on them."
20908596
CD
911 :group 'org-agenda-startup
912 :type 'hook)
913
914(defcustom org-agenda-mouse-1-follows-link nil
ed21c5c8 915 "Non-nil means mouse-1 on a link will follow the link in the agenda.
20908596
CD
916A longer mouse click will still set point. Does not work on XEmacs.
917Needs to be set before org.el is loaded."
918 :group 'org-agenda-startup
919 :type 'boolean)
920
921(defcustom org-agenda-start-with-follow-mode nil
86fbb8ca 922 "The initial value of follow mode in a newly created agenda window."
20908596
CD
923 :group 'org-agenda-startup
924 :type 'boolean)
925
e66ba1df
BG
926(defcustom org-agenda-follow-indirect nil
927 "Non-nil means `org-agenda-follow-mode' displays only the
928current item's tree, in an indirect buffer."
929 :group 'org-agenda
372d7b21 930 :version "24.1"
e66ba1df
BG
931 :type 'boolean)
932
1bcdebed 933(defcustom org-agenda-show-outline-path t
ed21c5c8 934 "Non-nil means show outline path in echo area after line motion."
1bcdebed
CD
935 :group 'org-agenda-startup
936 :type 'boolean)
937
54a0dee5
CD
938(defcustom org-agenda-start-with-entry-text-mode nil
939 "The initial value of entry-text-mode in a newly created agenda window."
940 :group 'org-agenda-startup
941 :type 'boolean)
942
943(defcustom org-agenda-entry-text-maxlines 5
8bfe682a 944 "Number of text lines to be added when `E' is pressed in the agenda.
54a0dee5
CD
945
946Note that this variable only used during agenda display. Add add entry text
947when exporting the agenda, configure the variable
948`org-agenda-add-entry-ext-maxlines'."
949 :group 'org-agenda
950 :type 'integer)
951
8d642074
CD
952(defcustom org-agenda-entry-text-exclude-regexps nil
953 "List of regular expressions to clean up entry text.
954The complete matches of all regular expressions in this list will be
955removed from entry text before it is shown in the agenda."
956 :group 'org-agenda
957 :type '(repeat (regexp)))
958
959(defvar org-agenda-entry-text-cleanup-hook nil
960 "Hook that is run after basic cleanup of entry text to be shown in agenda.
961This cleanup is done in a temporary buffer, so the function may inspect and
962change the entire buffer.
963Some default stuff like drawers and scheduling/deadline dates will already
964have been removed when this is called, as will any matches for regular
965expressions listed in `org-agenda-entry-text-exclude-regexps'.")
966
20908596 967(defvar org-agenda-include-inactive-timestamps nil
8223b1d2
BG
968 "Non-nil means include inactive time stamps in agenda and timeline.
969Dynamically scoped.")
20908596
CD
970
971(defgroup org-agenda-windows nil
972 "Options concerning the windows used by the Agenda in Org Mode."
973 :tag "Org Agenda Windows"
974 :group 'org-agenda)
975
976(defcustom org-agenda-window-setup 'reorganize-frame
977 "How the agenda buffer should be displayed.
978Possible values for this option are:
979
980current-window Show agenda in the current window, keeping all other windows.
20908596
CD
981other-window Use `switch-to-buffer-other-window' to display agenda.
982reorganize-frame Show only two windows on the current frame, the current
983 window and the agenda.
8d642074
CD
984other-frame Use `switch-to-buffer-other-frame' to display agenda.
985 Also, when exiting the agenda, kill that frame.
20908596
CD
986See also the variable `org-agenda-restore-windows-after-quit'."
987 :group 'org-agenda-windows
988 :type '(choice
989 (const current-window)
990 (const other-frame)
991 (const other-window)
992 (const reorganize-frame)))
993
994(defcustom org-agenda-window-frame-fractions '(0.5 . 0.75)
995 "The min and max height of the agenda window as a fraction of frame height.
996The value of the variable is a cons cell with two numbers between 0 and 1.
997It only matters if `org-agenda-window-setup' is `reorganize-frame'."
998 :group 'org-agenda-windows
999 :type '(cons (number :tag "Minimum") (number :tag "Maximum")))
1000
1001(defcustom org-agenda-restore-windows-after-quit nil
3ab2c837 1002 "Non-nil means restore window configuration upon exiting agenda.
20908596
CD
1003Before the window configuration is changed for displaying the agenda,
1004the current status is recorded. When the agenda is exited with
1005`q' or `x' and this option is set, the old state is restored. If
1006`org-agenda-window-setup' is `other-frame', the value of this
baf0cb84 1007option will be ignored."
20908596
CD
1008 :group 'org-agenda-windows
1009 :type 'boolean)
1010
acedf35c 1011(defcustom org-agenda-ndays nil
8223b1d2 1012 "Number of days to include in overview display.
c8d0cf5c 1013Should be 1 or 7.
acedf35c 1014Obsolete, see `org-agenda-span'."
8223b1d2
BG
1015 :group 'org-agenda-daily/weekly
1016 :type 'integer)
acedf35c
CD
1017
1018(make-obsolete-variable 'org-agenda-ndays 'org-agenda-span "24.1")
1019
1020(defcustom org-agenda-span 'week
1021 "Number of days to include in overview display.
1022Can be day, week, month, year, or any number of days.
c8d0cf5c 1023Custom commands can set this variable in the options section."
20908596 1024 :group 'org-agenda-daily/weekly
acedf35c
CD
1025 :type '(choice (const :tag "Day" day)
1026 (const :tag "Week" week)
1027 (const :tag "Month" month)
1028 (const :tag "Year" year)
1029 (integer :tag "Custom")))
20908596
CD
1030
1031(defcustom org-agenda-start-on-weekday 1
ed21c5c8 1032 "Non-nil means start the overview always on the specified weekday.
20908596 10330 denotes Sunday, 1 denotes Monday etc.
c8d0cf5c
CD
1034When nil, always start on the current day.
1035Custom commands can set this variable in the options section."
20908596
CD
1036 :group 'org-agenda-daily/weekly
1037 :type '(choice (const :tag "Today" nil)
c8d0cf5c 1038 (integer :tag "Weekday No.")))
20908596
CD
1039
1040(defcustom org-agenda-show-all-dates t
ed21c5c8 1041 "Non-nil means `org-agenda' shows every day in the selected range.
20908596
CD
1042When nil, only the days which actually have entries are shown."
1043 :group 'org-agenda-daily/weekly
1044 :type 'boolean)
1045
1046(defcustom org-agenda-format-date 'org-agenda-format-date-aligned
1047 "Format string for displaying dates in the agenda.
1048Used by the daily/weekly agenda and by the timeline. This should be
1049a format string understood by `format-time-string', or a function returning
1050the formatted date as a string. The function must take a single argument,
1051a calendar-style date list like (month day year)."
1052 :group 'org-agenda-daily/weekly
1053 :type '(choice
1054 (string :tag "Format string")
1055 (function :tag "Function")))
1056
1057(defun org-agenda-format-date-aligned (date)
1058 "Format a date string for display in the daily/weekly agenda, or timeline.
1059This function makes sure that dates are aligned for easy reading."
1060 (require 'cal-iso)
1061 (let* ((dayname (calendar-day-name date))
1062 (day (cadr date))
1063 (day-of-week (calendar-day-of-week date))
1064 (month (car date))
1065 (monthname (calendar-month-name month))
1066 (year (nth 2 date))
1067 (iso-week (org-days-to-iso-week
1068 (calendar-absolute-from-gregorian date)))
1069 (weekyear (cond ((and (= month 1) (>= iso-week 52))
1070 (1- year))
1071 ((and (= month 12) (<= iso-week 1))
1072 (1+ year))
1073 (t year)))
1074 (weekstring (if (= day-of-week 1)
1075 (format " W%02d" iso-week)
1076 "")))
1077 (format "%-10s %2d %s %4d%s"
1078 dayname day monthname year weekstring)))
1079
ed21c5c8
CD
1080(defcustom org-agenda-time-leading-zero nil
1081 "Non-nil means use leading zero for military times in agenda.
1082For example, 9:30am would become 09:30 rather than 9:30."
1083 :group 'org-agenda-daily/weekly
372d7b21 1084 :version "24.1"
ed21c5c8
CD
1085 :type 'boolean)
1086
acedf35c
CD
1087(defcustom org-agenda-timegrid-use-ampm nil
1088 "When set, show AM/PM style timestamps on the timegrid."
1089 :group 'org-agenda
372d7b21 1090 :version "24.1"
acedf35c
CD
1091 :type 'boolean)
1092
1093(defun org-agenda-time-of-day-to-ampm (time)
1094 "Convert TIME of a string like '13:45' to an AM/PM style time string."
1095 (let* ((hour-number (string-to-number (substring time 0 -3)))
1096 (minute (substring time -2))
1097 (ampm "am"))
1098 (cond
1099 ((equal hour-number 12)
1100 (setq ampm "pm"))
1101 ((> hour-number 12)
1102 (setq ampm "pm")
1103 (setq hour-number (- hour-number 12))))
1104 (concat
1105 (if org-agenda-time-leading-zero
1106 (format "%02d" hour-number)
1107 (format "%02s" (number-to-string hour-number)))
1108 ":" minute ampm)))
1109
1110(defun org-agenda-time-of-day-to-ampm-maybe (time)
1111 "Conditionally convert TIME to AM/PM format
1112based on `org-agenda-timegrid-use-ampm'"
1113 (if org-agenda-timegrid-use-ampm
1114 (org-agenda-time-of-day-to-ampm time)
1115 time))
1116
20908596
CD
1117(defcustom org-agenda-weekend-days '(6 0)
1118 "Which days are weekend?
1119These days get the special face `org-agenda-date-weekend' in the agenda
1120and timeline buffers."
1121 :group 'org-agenda-daily/weekly
1122 :type '(set :greedy t
1123 (const :tag "Monday" 1)
1124 (const :tag "Tuesday" 2)
1125 (const :tag "Wednesday" 3)
1126 (const :tag "Thursday" 4)
1127 (const :tag "Friday" 5)
1128 (const :tag "Saturday" 6)
1129 (const :tag "Sunday" 0)))
1130
e66ba1df 1131(defcustom org-agenda-move-date-from-past-immediately-to-today t
27e428e7 1132 "Non-nil means jump to today when moving a past date forward in time.
e66ba1df
BG
1133When using S-right in the agenda to move a a date forward, and the date
1134stamp currently points to the past, the first key press will move it
1135to today. WHen nil, just move one day forward even if the date stays
1136in the past."
1137 :group 'org-agenda-daily/weekly
372d7b21 1138 :version "24.1"
e66ba1df
BG
1139 :type 'boolean)
1140
20908596 1141(defcustom org-agenda-include-diary nil
c8d0cf5c
CD
1142 "If non-nil, include in the agenda entries from the Emacs Calendar's diary.
1143Custom commands can set this variable in the options section."
20908596
CD
1144 :group 'org-agenda-daily/weekly
1145 :type 'boolean)
1146
ed21c5c8
CD
1147(defcustom org-agenda-include-deadlines t
1148 "If non-nil, include entries within their deadline warning period.
1149Custom commands can set this variable in the options section."
1150 :group 'org-agenda-daily/weekly
372d7b21 1151 :version "24.1"
ed21c5c8
CD
1152 :type 'boolean)
1153
20908596 1154(defcustom org-agenda-repeating-timestamp-show-all t
ed21c5c8 1155 "Non-nil means show all occurrences of a repeating stamp in the agenda.
3ab2c837
BG
1156When set to a list of strings, only show occurrences of repeating
1157stamps for these TODO keywords. When nil, only one occurrence is
1158shown, either today or the nearest into the future."
20908596 1159 :group 'org-agenda-daily/weekly
3ab2c837
BG
1160 :type '(choice
1161 (const :tag "Show repeating stamps" t)
1162 (repeat :tag "Show repeating stamps for these TODO keywords"
1163 (string :tag "TODO Keyword"))
1164 (const :tag "Don't show repeating stamps" nil)))
20908596
CD
1165
1166(defcustom org-scheduled-past-days 10000
1167 "No. of days to continue listing scheduled items that are not marked DONE.
1168When an item is scheduled on a date, it shows up in the agenda on this
1169day and will be listed until it is marked done for the number of days
1170given here."
1171 :group 'org-agenda-daily/weekly
c8d0cf5c 1172 :type 'integer)
20908596 1173
93b62de8
CD
1174(defcustom org-agenda-log-mode-items '(closed clock)
1175 "List of items that should be shown in agenda log mode.
1176This list may contain the following symbols:
1177
1178 closed Show entries that have been closed on that day.
1179 clock Show entries that have received clocked time on that day.
c8d0cf5c
CD
1180 state Show all logged state changes.
1181Note that instead of changing this variable, you can also press `C-u l' in
1182the agenda to display all available LOG items temporarily."
93b62de8
CD
1183 :group 'org-agenda-daily/weekly
1184 :type '(set :greedy t (const closed) (const clock) (const state)))
1185
3ab2c837
BG
1186(defcustom org-agenda-clock-consistency-checks
1187 '(:max-duration "10:00" :min-duration 0 :max-gap "0:05"
1188 :gap-ok-around ("4:00")
1189 :default-face ((:background "DarkRed") (:foreground "white"))
1190 :overlap-face nil :gap-face nil :no-end-time-face nil
1191 :long-face nil :short-face nil)
1192 "This is a property list, with the following keys:
1193
1194:max-duration Mark clocking chunks that are longer than this time.
1195 This is a time string like \"HH:MM\", or the number
1196 of minutes as an integer.
1197
1198:min-duration Mark clocking chunks that are shorter that this.
1199 This is a time string like \"HH:MM\", or the number
1200 of minutes as an integer.
1201
1202:max-gap Mark gaps between clocking chunks that are longer than
1203 this duration. A number of minutes, or a string
1204 like \"HH:MM\".
1205
1206:gap-ok-around List of times during the day which are usually not working
1207 times. When a gap is detected, but the gap contains any
1208 of these times, the gap is *not* reported. For example,
1209 if this is (\"4:00\" \"13:00\") then gaps that contain
1210 4:00 in the morning (i.e. the night) and 13:00
1211 (i.e. a typical lunch time) do not cause a warning.
1212 You should have at least one time during the night in this
1213 list, or otherwise the first task each morning will trigger
1214 a warning because it follows a long gap.
1215
1216Furthermore, the following properties can be used to define faces for
1217issue display.
1218
1219:default-face the default face, if the specific face is undefined
1220:overlap-face face for overlapping clocks
1221:gap-face face for gaps between clocks
1222:no-end-time-face face for incomplete clocks
1223:long-face face for clock intervals that are too long
1224:short-face face for clock intervals that are too short"
1225 :group 'org-agenda-daily/weekly
1226 :group 'org-clock
372d7b21 1227 :version "24.1"
3ab2c837
BG
1228 :type 'plist)
1229
c8d0cf5c 1230(defcustom org-agenda-log-mode-add-notes t
ed21c5c8 1231 "Non-nil means add first line of notes to log entries in agenda views.
c8d0cf5c
CD
1232If a log item like a state change or a clock entry is associated with
1233notes, the first line of these notes will be added to the entry in the
1234agenda display."
1235 :group 'org-agenda-daily/weekly
1236 :type 'boolean)
1237
1238(defcustom org-agenda-start-with-log-mode nil
8223b1d2
BG
1239 "The initial value of log-mode in a newly created agenda window.
1240See `org-agenda-log-mode' and `org-agenda-log-mode-items' for further
1241explanations on the possible values."
c8d0cf5c
CD
1242 :group 'org-agenda-startup
1243 :group 'org-agenda-daily/weekly
8223b1d2
BG
1244 :type '(choice (const :tag "Don't show log items" nil)
1245 (const :tag "Show only log items" 'only)
1246 (const :tag "Show all possible log items" 'clockcheck)
1247 (repeat :tag "Choose among possible values for `org-agenda-log-mode-items'"
1248 (choice (const :tag "Show closed log items" 'closed)
1249 (const :tag "Show clocked log items" 'clock)
1250 (const :tag "Show all logged state changes" 'state)))))
c8d0cf5c 1251
20908596
CD
1252(defcustom org-agenda-start-with-clockreport-mode nil
1253 "The initial value of clockreport-mode in a newly created agenda window."
1254 :group 'org-agenda-startup
1255 :group 'org-agenda-daily/weekly
1256 :type 'boolean)
1257
1258(defcustom org-agenda-clockreport-parameter-plist '(:link t :maxlevel 2)
1259 "Property list with parameters for the clocktable in clockreport mode.
1260This is the display mode that shows a clock table in the daily/weekly
1261agenda, the properties for this dynamic block can be set here.
1262The usual clocktable parameters are allowed here, but you cannot set
1263the properties :name, :tstart, :tend, :block, and :scope - these will
1264be overwritten to make sure the content accurately reflects the
1265current display in the agenda."
1266 :group 'org-agenda-daily/weekly
1267 :type 'plist)
1268
ed21c5c8
CD
1269(defcustom org-agenda-search-view-always-boolean nil
1270 "Non-nil means the search string is interpreted as individual parts.
1271
1272The search string for search view can either be interpreted as a phrase,
1273or as a list of snippets that define a boolean search for a number of
1274strings.
1275
1276When this is non-nil, the string will be split on whitespace, and each
1277snippet will be searched individually, and all must match in order to
1278select an entry. A snippet is then a single string of non-white
1279characters, or a string in double quotes, or a regexp in {} braces.
86fbb8ca 1280If a snippet is preceded by \"-\", the snippet must *not* match.
ed21c5c8
CD
1281\"+\" is syntactic sugar for positive selection. Each snippet may
1282be found as a full word or a partial word, but see the variable
1283`org-agenda-search-view-force-full-words'.
1284
1285When this is nil, search will look for the entire search phrase as one,
1286with each space character matching any amount of whitespace, including
1287line breaks.
1288
1289Even when this is nil, you can still switch to Boolean search dynamically
86fbb8ca 1290by preceding the first snippet with \"+\" or \"-\". If the first snippet
ed21c5c8
CD
1291is a regexp marked with braces like \"{abc}\", this will also switch to
1292boolean search."
1293 :group 'org-agenda-search-view
372d7b21 1294 :version "24.1"
ed21c5c8
CD
1295 :type 'boolean)
1296
1297(if (fboundp 'defvaralias)
1298 (defvaralias 'org-agenda-search-view-search-words-only
1299 'org-agenda-search-view-always-boolean))
1300
1301(defcustom org-agenda-search-view-force-full-words nil
86fbb8ca 1302 "Non-nil means, search words must be matches as complete words.
ed21c5c8 1303When nil, they may also match part of a word."
8bfe682a 1304 :group 'org-agenda-search-view
372d7b21 1305 :version "24.1"
8bfe682a 1306 :type 'boolean)
20908596
CD
1307
1308(defgroup org-agenda-time-grid nil
1309 "Options concerning the time grid in the Org-mode Agenda."
1310 :tag "Org Agenda Time Grid"
1311 :group 'org-agenda)
1312
c8d0cf5c 1313(defcustom org-agenda-search-headline-for-time t
ed21c5c8 1314 "Non-nil means search headline for a time-of-day.
c8d0cf5c
CD
1315If the headline contains a time-of-day in one format or another, it will
1316be used to sort the entry into the time sequence of items for a day.
1317Some people have time stamps in the headline that refer to the creation
1318time or so, and then this produces an unwanted side effect. If this is
1319the case for your, use this variable to turn off searching the headline
1320for a time."
1321 :group 'org-agenda-time-grid
1322 :type 'boolean)
1323
20908596 1324(defcustom org-agenda-use-time-grid t
ed21c5c8 1325 "Non-nil means show a time grid in the agenda schedule.
20908596
CD
1326A time grid is a set of lines for specific times (like every two hours between
13278:00 and 20:00). The items scheduled for a day at specific times are
1328sorted in between these lines.
1329For details about when the grid will be shown, and what it will look like, see
1330the variable `org-agenda-time-grid'."
1331 :group 'org-agenda-time-grid
1332 :type 'boolean)
1333
1334(defcustom org-agenda-time-grid
1335 '((daily today require-timed)
1336 "----------------"
1337 (800 1000 1200 1400 1600 1800 2000))
1338
1339 "The settings for time grid for agenda display.
1340This is a list of three items. The first item is again a list. It contains
1341symbols specifying conditions when the grid should be displayed:
1342
1343 daily if the agenda shows a single day
1344 weekly if the agenda shows an entire week
1345 today show grid on current date, independent of daily/weekly display
1346 require-timed show grid only if at least one item has a time specification
1347
b349f79f 1348The second item is a string which will be placed behind the grid time.
20908596
CD
1349
1350The third item is a list of integers, indicating the times that should have
1351a grid line."
1352 :group 'org-agenda-time-grid
1353 :type
1354 '(list
1355 (set :greedy t :tag "Grid Display Options"
1356 (const :tag "Show grid in single day agenda display" daily)
1357 (const :tag "Show grid in weekly agenda display" weekly)
1358 (const :tag "Always show grid for today" today)
1359 (const :tag "Show grid only if any timed entries are present"
1360 require-timed)
1361 (const :tag "Skip grid times already present in an entry"
1362 remove-match))
1363 (string :tag "Grid String")
1364 (repeat :tag "Grid Times" (integer :tag "Time"))))
1365
3ab2c837
BG
1366(defcustom org-agenda-show-current-time-in-grid t
1367 "Non-nil means show the current time in the time grid."
1368 :group 'org-agenda-time-grid
372d7b21 1369 :version "24.1"
3ab2c837
BG
1370 :type 'boolean)
1371
1372(defcustom org-agenda-current-time-string
1373 "now - - - - - - - - - - - - - - - - - - - - - - - - -"
1374 "The string for the current time marker in the agenda."
1375 :group 'org-agenda-time-grid
372d7b21 1376 :version "24.1"
3ab2c837
BG
1377 :type 'string)
1378
20908596
CD
1379(defgroup org-agenda-sorting nil
1380 "Options concerning sorting in the Org-mode Agenda."
1381 :tag "Org Agenda Sorting"
1382 :group 'org-agenda)
1383
1384(defcustom org-agenda-sorting-strategy
8bfe682a
CD
1385 '((agenda habit-down time-up priority-down category-keep)
1386 (todo priority-down category-keep)
1387 (tags priority-down category-keep)
20908596
CD
1388 (search category-keep))
1389 "Sorting structure for the agenda items of a single day.
1390This is a list of symbols which will be used in sequence to determine
1391if an entry should be listed before another entry. The following
1392symbols are recognized:
1393
c8d0cf5c
CD
1394time-up Put entries with time-of-day indications first, early first
1395time-down Put entries with time-of-day indications first, late first
1396category-keep Keep the default order of categories, corresponding to the
1397 sequence in `org-agenda-files'.
1398category-up Sort alphabetically by category, A-Z.
1399category-down Sort alphabetically by category, Z-A.
1400tag-up Sort alphabetically by last tag, A-Z.
1401tag-down Sort alphabetically by last tag, Z-A.
1402priority-up Sort numerically by priority, high priority last.
1403priority-down Sort numerically by priority, high priority first.
1404todo-state-up Sort by todo state, tasks that are done last.
1405todo-state-down Sort by todo state, tasks that are done first.
1406effort-up Sort numerically by estimated effort, high effort last.
1407effort-down Sort numerically by estimated effort, high effort first.
1408user-defined-up Sort according to `org-agenda-cmp-user-defined', high last.
1409user-defined-down Sort according to `org-agenda-cmp-user-defined', high first.
8bfe682a
CD
1410habit-up Put entries that are habits first
1411habit-down Put entries that are habits last
86fbb8ca
CD
1412alpha-up Sort headlines alphabetically
1413alpha-down Sort headlines alphabetically, reversed
20908596
CD
1414
1415The different possibilities will be tried in sequence, and testing stops
1416if one comparison returns a \"not-equal\". For example, the default
1417 '(time-up category-keep priority-down)
1418means: Pull out all entries having a specified time of day and sort them,
1419in order to make a time schedule for the current day the first thing in the
1420agenda listing for the day. Of the entries without a time indication, keep
1421the grouped in categories, don't sort the categories, but keep them in
1422the sequence given in `org-agenda-files'. Within each category sort by
1423priority.
1424
1425Leaving out `category-keep' would mean that items will be sorted across
1426categories by priority.
1427
1428Instead of a single list, this can also be a set of list for specific
1429contents, with a context symbol in the car of the list, any of
8bfe682a 1430`agenda', `todo', `tags', `search' for the corresponding agenda views.
c8d0cf5c
CD
1431
1432Custom commands can bind this variable in the options section."
20908596
CD
1433 :group 'org-agenda-sorting
1434 :type `(choice
1435 (repeat :tag "General" ,org-sorting-choice)
1436 (list :tag "Individually"
1437 (cons (const :tag "Strategy for Weekly/Daily agenda" agenda)
1438 (repeat ,org-sorting-choice))
1439 (cons (const :tag "Strategy for TODO lists" todo)
1440 (repeat ,org-sorting-choice))
1441 (cons (const :tag "Strategy for Tags matches" tags)
8bfe682a
CD
1442 (repeat ,org-sorting-choice))
1443 (cons (const :tag "Strategy for search matches" search)
20908596
CD
1444 (repeat ,org-sorting-choice)))))
1445
c8d0cf5c
CD
1446(defcustom org-agenda-cmp-user-defined nil
1447 "A function to define the comparison `user-defined'.
1448This function must receive two arguments, agenda entry a and b.
1449If a>b, return +1. If a<b, return -1. If they are equal as seen by
1450the user comparison, return nil.
1451When this is defined, you can make `user-defined-up' and `user-defined-down'
1452part of an agenda sorting strategy."
1453 :group 'org-agenda-sorting
1454 :type 'symbol)
1455
20908596 1456(defcustom org-sort-agenda-notime-is-late t
ed21c5c8 1457 "Non-nil means items without time are considered late.
20908596
CD
1458This is only relevant for sorting. When t, items which have no explicit
1459time like 15:30 will be considered as 99:01, i.e. later than any items which
1460do have a time. When nil, the default time is before 0:00. You can use this
1461option to decide if the schedule for today should come before or after timeless
1462agenda entries."
1463 :group 'org-agenda-sorting
1464 :type 'boolean)
1465
1466(defcustom org-sort-agenda-noeffort-is-high t
ed21c5c8 1467 "Non-nil means items without effort estimate are sorted as high effort.
c8d0cf5c
CD
1468This also applies when filtering an agenda view with respect to the
1469< or > effort operator. Then, tasks with no effort defined will be treated
1470as tasks with high effort.
20908596
CD
1471When nil, such items are sorted as 0 minutes effort."
1472 :group 'org-agenda-sorting
1473 :type 'boolean)
1474
1475(defgroup org-agenda-line-format nil
1476 "Options concerning the entry prefix in the Org-mode agenda display."
1477 :tag "Org Agenda Line Format"
1478 :group 'org-agenda)
1479
1480(defcustom org-agenda-prefix-format
acedf35c 1481 '((agenda . " %i %-12:c%?-12t% s")
20908596 1482 (timeline . " % s")
acedf35c
CD
1483 (todo . " %i %-12:c")
1484 (tags . " %i %-12:c")
1485 (search . " %i %-12:c"))
20908596 1486 "Format specifications for the prefix of items in the agenda views.
fe3c5669
PE
1487An alist with five entries, each for the different agenda types. The
1488keys of the sublists are `agenda', `timeline', `todo', `search' and `tags'.
3ab2c837
BG
1489The values are format strings.
1490
20908596
CD
1491This format works similar to a printf format, with the following meaning:
1492
fe3c5669 1493 %c the category of the item, \"Diary\" for entries from the diary,
3ab2c837 1494 or as given by the CATEGORY keyword or derived from the file name
e66ba1df 1495 %e the effort required by the item
3ab2c837
BG
1496 %i the icon category of the item, see `org-agenda-category-icon-alist'
1497 %T the last tag of the item (ignore inherited tags, which come first)
1498 %t the HH:MM time-of-day specification if one applies to the entry
20908596 1499 %s Scheduling/Deadline information, a short string
3ab2c837
BG
1500 %(expression) Eval EXPRESSION and replace the control string
1501 by the result
20908596
CD
1502
1503All specifiers work basically like the standard `%s' of printf, but may
3ab2c837
BG
1504contain two additional characters: a question mark just after the `%'
1505and a whitespace/punctuation character just before the final letter.
20908596
CD
1506
1507If the first character after `%' is a question mark, the entire field
fe3c5669
PE
1508will only be included if the corresponding value applies to the current
1509entry. This is useful for fields which should have fixed width when
1510present, but zero width when absent. For example, \"%?-12t\" will
1511result in a 12 character time field if a time of the day is specified,
3ab2c837 1512but will completely disappear in entries which do not contain a time.
20908596
CD
1513
1514If there is punctuation or whitespace character just before the final
1515format letter, this character will be appended to the field value if
1516the value is not empty. For example, the format \"%-12:c\" leads to
1517\"Diary: \" if the category is \"Diary\". If the category were be
8bfe682a 1518empty, no additional colon would be inserted.
20908596 1519
fe3c5669 1520The default value for the agenda sublist is \" %-12:c%?-12t% s\",
3ab2c837
BG
1521which means:
1522
20908596 1523- Indent the line with two space characters
3ab2c837 1524- Give the category a 12 chars wide field, padded with whitespace on
20908596
CD
1525 the right (because of `-'). Append a colon if there is a category
1526 (because of `:').
1527- If there is a time-of-day, put it into a 12 chars wide field. If no
1528 time, don't put in an empty field, just skip it (because of '?').
3ab2c837 1529- Finally, put the scheduling information.
20908596
CD
1530
1531See also the variables `org-agenda-remove-times-when-in-prefix' and
c8d0cf5c
CD
1532`org-agenda-remove-tags'.
1533
1534Custom commands can set this variable in the options section."
20908596
CD
1535 :type '(choice
1536 (string :tag "General format")
1537 (list :greedy t :tag "View dependent"
1538 (cons (const agenda) (string :tag "Format"))
1539 (cons (const timeline) (string :tag "Format"))
1540 (cons (const todo) (string :tag "Format"))
1541 (cons (const tags) (string :tag "Format"))
1542 (cons (const search) (string :tag "Format"))))
1543 :group 'org-agenda-line-format)
1544
1545(defvar org-prefix-format-compiled nil
8223b1d2
BG
1546 "The compiled prefix format and associated variables.
1547This is a list where first element is a list of variable bindings, and second
1548element is the compiled format expression. See the variable
1549`org-agenda-prefix-format'.")
20908596
CD
1550
1551(defcustom org-agenda-todo-keyword-format "%-1s"
1552 "Format for the TODO keyword in agenda lines.
1553Set this to something like \"%-12s\" if you want all TODO keywords
1554to occupy a fixed space in the agenda display."
1555 :group 'org-agenda-line-format
1556 :type 'string)
1557
8223b1d2
BG
1558(defcustom org-agenda-diary-sexp-prefix nil
1559 "A regexp that matches part of a diary sexp entry
1560which should be treated as scheduling/deadline information in
1561`org-agenda'.
1562
1563For example, you can use this to extract the `diary-remind-message' from
1564`diary-remind' entries."
1565 :group 'org-agenda-line-format
1566 :type '(choice (const :tag "None" nil) (regexp :tag "Regexp")))
1567
ce4fdcb9
CD
1568(defcustom org-agenda-timerange-leaders '("" "(%d/%d): ")
1569 "Text preceding timerange entries in the agenda view.
1570This is a list with two strings. The first applies when the range
1571is entirely on one day. The second applies if the range spans several days.
1572The strings may have two \"%d\" format specifiers which will be filled
1573with the sequence number of the days, and the total number of days in the
1574range, respectively."
1575 :group 'org-agenda-line-format
1576 :type '(list
1577 (string :tag "Deadline today ")
1578 (choice :tag "Deadline relative"
1579 (string :tag "Format string")
1580 (function))))
1581
20908596 1582(defcustom org-agenda-scheduled-leaders '("Scheduled: " "Sched.%2dx: ")
86fbb8ca 1583 "Text preceding scheduled items in the agenda view.
20908596
CD
1584This is a list with two strings. The first applies when the item is
1585scheduled on the current day. The second applies when it has been scheduled
b349f79f
CD
1586previously, it may contain a %d indicating that this is the nth time that
1587this item is scheduled, due to automatic rescheduling of unfinished items
1588for the following day. So this number is one larger than the number of days
1589that passed since this item was scheduled first."
20908596
CD
1590 :group 'org-agenda-line-format
1591 :type '(list
1592 (string :tag "Scheduled today ")
1593 (string :tag "Scheduled previously")))
1594
ed21c5c8 1595(defcustom org-agenda-inactive-leader "["
86fbb8ca 1596 "Text preceding item pulled into the agenda by inactive time stamps.
ed21c5c8
CD
1597These entries are added to the agenda when pressing \"[\"."
1598 :group 'org-agenda-line-format
372d7b21 1599 :version "24.1"
ed21c5c8
CD
1600 :type '(list
1601 (string :tag "Scheduled today ")
1602 (string :tag "Scheduled previously")))
1603
20908596 1604(defcustom org-agenda-deadline-leaders '("Deadline: " "In %3d d.: ")
86fbb8ca 1605 "Text preceding deadline items in the agenda view.
20908596
CD
1606This is a list with two strings. The first applies when the item has its
1607deadline on the current day. The second applies when it is in the past or
1608in the future, it may contain %d to capture how many days away the deadline
1609is (was)."
1610 :group 'org-agenda-line-format
1611 :type '(list
1612 (string :tag "Deadline today ")
1613 (choice :tag "Deadline relative"
1614 (string :tag "Format string")
1615 (function))))
1616
1617(defcustom org-agenda-remove-times-when-in-prefix t
ed21c5c8 1618 "Non-nil means remove duplicate time specifications in agenda items.
20908596
CD
1619When the format `org-agenda-prefix-format' contains a `%t' specifier, a
1620time-of-day specification in a headline or diary entry is extracted and
1621placed into the prefix. If this option is non-nil, the original specification
1622\(a timestamp or -range, or just a plain time(range) specification like
162311:30-4pm) will be removed for agenda display. This makes the agenda less
1624cluttered.
1625The option can be t or nil. It may also be the symbol `beg', indicating
86fbb8ca 1626that the time should only be removed when it is located at the beginning of
20908596
CD
1627the headline/diary entry."
1628 :group 'org-agenda-line-format
1629 :type '(choice
1630 (const :tag "Always" t)
1631 (const :tag "Never" nil)
1632 (const :tag "When at beginning of entry" beg)))
1633
86fbb8ca
CD
1634(defcustom org-agenda-remove-timeranges-from-blocks nil
1635 "Non-nil means remove time ranges specifications in agenda
1636items that span on several days."
1637 :group 'org-agenda-line-format
372d7b21 1638 :version "24.1"
86fbb8ca 1639 :type 'boolean)
20908596
CD
1640
1641(defcustom org-agenda-default-appointment-duration nil
1642 "Default duration for appointments that only have a starting time.
1643When nil, no duration is specified in such cases.
1644When non-nil, this must be the number of minutes, e.g. 60 for one hour."
1645 :group 'org-agenda-line-format
1646 :type '(choice
1647 (integer :tag "Minutes")
1648 (const :tag "No default duration")))
1649
ff4be292 1650(defcustom org-agenda-show-inherited-tags t
a89c8ef0
BG
1651 "Non-nil means show inherited tags in each agenda line.
1652
1653When this option is set to 'always, it take precedences over
1654`org-agenda-use-tag-inheritance' and inherited tags are shown
1655in every agenda.
1656
1657When this option is set to t (the default), inherited tags are
1658shown when they are available, i.e. when the value of
1659`org-agenda-use-tag-inheritance' has been taken into account.
1660
1661This can be set to a list of agenda types in which the agenda
1662must display the inherited tags. Available types are 'todo,
1663'agenda, 'search and 'timeline.
1664
1665When set to nil, never show inherited tags in agenda lines."
ff4be292 1666 :group 'org-agenda-line-format
a89c8ef0
BG
1667 :group 'org-agenda
1668 :version "24.3"
1669 :type '(choice
1670 (const :tag "Show inherited tags when available" t)
1671 (const :tag "Always show inherited tags" 'always)
1672 (repeat :tag "Show inherited tags only in selected agenda types"
1673 (symbol :tag "Agenda type"))))
20908596 1674
c7cf0ebc
BG
1675(defcustom org-agenda-use-tag-inheritance '(todo search timeline agenda)
1676 "List of agenda view types where to use tag inheritance.
1677
1678In tags/tags-todo/tags-tree agenda views, tag inheritance is
1679controlled by `org-use-tag-inheritance'. In other agenda types,
a89c8ef0
BG
1680`org-use-tag-inheritance' is not used for the selection of the
1681agenda entries. Still, you may want the agenda to be aware of
1682the inherited tags anyway, e.g. for later tag filtering.
c7cf0ebc 1683
a89c8ef0 1684Allowed value are 'todo, 'search, 'timeline and 'agenda.
c7cf0ebc 1685
a89c8ef0
BG
1686This variable has no effect if `org-agenda-show-inherited-tags'
1687is set to 'always. In that case, the agenda is aware of those
1688tags.
1689
1690The default value sets tags in every agenda type. Setting this
1691option to nil will speed up non-tags agenda view a lot."
c7cf0ebc 1692 :group 'org-agenda
a89c8ef0
BG
1693 :version "24.3"
1694 :type '(choice
1695 (const :tag "Use tag inheritance in all agenda types" t)
1696 (repeat :tag "Use tag inheritance in selected agenda types"
1697 (symbol :tag "Agenda type"))))
c7cf0ebc 1698
5dec9555
CD
1699(defcustom org-agenda-hide-tags-regexp nil
1700 "Regular expression used to filter away specific tags in agenda views.
1701This means that these tags will be present, but not be shown in the agenda
86fbb8ca 1702line. Secondary filtering will still work on the hidden tags.
afe98dfa 1703Nil means don't hide any tags."
5dec9555
CD
1704 :group 'org-agenda-line-format
1705 :type '(choice
1706 (const :tag "Hide none" nil)
1707 (string :tag "Regexp ")))
1708
20908596 1709(defcustom org-agenda-remove-tags nil
ed21c5c8 1710 "Non-nil means remove the tags from the headline copy in the agenda.
20908596
CD
1711When this is the symbol `prefix', only remove tags when
1712`org-agenda-prefix-format' contains a `%T' specifier."
1713 :group 'org-agenda-line-format
1714 :type '(choice
1715 (const :tag "Always" t)
1716 (const :tag "Never" nil)
1717 (const :tag "When prefix format contains %T" prefix)))
1718
1719(if (fboundp 'defvaralias)
1720 (defvaralias 'org-agenda-remove-tags-when-in-prefix
1721 'org-agenda-remove-tags))
1722
5ace2fe5 1723(defcustom org-agenda-tags-column (if (featurep 'xemacs) -79 -80)
20908596
CD
1724 "Shift tags in agenda items to this column.
1725If this number is positive, it specifies the column. If it is negative,
1726it means that the tags should be flushright to that column. For example,
1727-80 works well for a normal 80 character screen."
1728 :group 'org-agenda-line-format
1729 :type 'integer)
1730
1731(if (fboundp 'defvaralias)
1732 (defvaralias 'org-agenda-align-tags-to-column 'org-agenda-tags-column))
1733
c8d0cf5c 1734(defcustom org-agenda-fontify-priorities 'cookies
ed21c5c8 1735 "Non-nil means highlight low and high priorities in agenda.
20908596 1736When t, the highest priority entries are bold, lowest priority italic.
86fbb8ca 1737However, settings in `org-priority-faces' will overrule these faces.
c8d0cf5c
CD
1738When this variable is the symbol `cookies', only fontify the
1739cookies, not the entire task.
621f83e4
CD
1740This may also be an association list of priority faces, whose
1741keys are the character values of `org-highest-priority',
1742`org-default-priority', and `org-lowest-priority' (the default values
ed21c5c8
CD
1743are ?A, ?B, and ?C, respectively). The face may be a named face, a
1744color as a string, or a list like `(:background \"Red\")'.
1745If it is a color, the variable `org-faces-easy-properties'
1746determines if it is a foreground or a background color."
20908596
CD
1747 :group 'org-agenda-line-format
1748 :type '(choice
1749 (const :tag "Never" nil)
1750 (const :tag "Defaults" t)
c8d0cf5c 1751 (const :tag "Cookies only" cookies)
20908596
CD
1752 (repeat :tag "Specify"
1753 (list (character :tag "Priority" :value ?A)
ed21c5c8
CD
1754 (choice :tag "Face "
1755 (string :tag "Color")
1756 (sexp :tag "Face"))))))
20908596 1757
acedf35c
CD
1758(defcustom org-agenda-day-face-function nil
1759 "Function called to determine what face should be used to display a day.
8223b1d2 1760The only argument passed to that function is the day. It should
acedf35c
CD
1761returns a face, or nil if does not want to specify a face and let
1762the normal rules apply."
1763 :group 'org-agenda-line-format
372d7b21 1764 :version "24.1"
acedf35c
CD
1765 :type 'function)
1766
1767(defcustom org-agenda-category-icon-alist nil
1768 "Alist of category icon to be displayed in agenda views.
1769
1770Each entry should have the following format:
1771
1772 (CATEGORY-REGEXP FILE-OR-DATA TYPE DATA-P PROPS)
1773
1774Where CATEGORY-REGEXP is a regexp matching the categories where
1775the icon should be displayed.
1776FILE-OR-DATA either a file path or a string containing image data.
1777
27e428e7 1778The other fields can be omitted safely if not needed:
acedf35c
CD
1779TYPE indicates the image type.
1780DATA-P is a boolean indicating whether the FILE-OR-DATA string is
1781image data.
1782PROPS are additional image attributes to assign to the image,
1783like, e.g. `:ascent center'.
1784
1785 (\"Org\" \"/path/to/icon.png\" nil nil :ascent center)
1786
1787If you want to set the display properties yourself, just put a
1788list as second element:
1789
1790 (CATEGORY-REGEXP (MY PROPERTY LIST))
1791
1792For example, to display a 16px horizontal space for Emacs
1793category, you can use:
1794
1795 (\"Emacs\" '(space . (:width (16))))"
1796 :group 'org-agenda-line-format
372d7b21 1797 :version "24.1"
acedf35c
CD
1798 :type '(alist :key-type (string :tag "Regexp matching category")
1799 :value-type (choice (list :tag "Icon"
1800 (string :tag "File or data")
1801 (symbol :tag "Type")
1802 (boolean :tag "Data?")
1803 (repeat :tag "Extra image properties" :inline t symbol))
1804 (list :tag "Display properties" sexp))))
1805
20908596
CD
1806(defgroup org-agenda-column-view nil
1807 "Options concerning column view in the agenda."
1808 :tag "Org Agenda Column View"
1809 :group 'org-agenda)
1810
1811(defcustom org-agenda-columns-show-summaries t
ed21c5c8 1812 "Non-nil means show summaries for columns displayed in the agenda view."
20908596
CD
1813 :group 'org-agenda-column-view
1814 :type 'boolean)
1815
1816(defcustom org-agenda-columns-compute-summary-properties t
ed21c5c8 1817 "Non-nil means recompute all summary properties before column view.
20908596
CD
1818When column view in the agenda is listing properties that have a summary
1819operator, it can go to all relevant buffers and recompute the summaries
1820there. This can mean overhead for the agenda column view, but is necessary
1821to have thing up to date.
1822As a special case, a CLOCKSUM property also makes sure that the clock
1823computations are current."
1824 :group 'org-agenda-column-view
1825 :type 'boolean)
1826
1827(defcustom org-agenda-columns-add-appointments-to-effort-sum nil
ed21c5c8 1828 "Non-nil means the duration of an appointment will add to day effort.
20908596
CD
1829The property to which appointment durations will be added is the one given
1830in the option `org-effort-property'. If an appointment does not have
1831an end time, `org-agenda-default-appointment-duration' will be used. If that
1832is not set, an appointment without end time will not contribute to the time
1833estimate."
1834 :group 'org-agenda-column-view
1835 :type 'boolean)
1836
8bfe682a
CD
1837(defcustom org-agenda-auto-exclude-function nil
1838 "A function called with a tag to decide if it is filtered on '/ RET'.
1839The sole argument to the function, which is called once for each
1840possible tag, is a string giving the name of the tag. The
1841function should return either nil if the tag should be included
ed21c5c8
CD
1842as normal, or \"-<TAG>\" to exclude the tag.
1843Note that for the purpose of tag filtering, only the lower-case version of
1844all tags will be considered, so that this function will only ever see
1845the lower-case version of all tags."
8bfe682a
CD
1846 :group 'org-agenda
1847 :type 'function)
1848
3ab2c837
BG
1849(defcustom org-agenda-bulk-custom-functions nil
1850 "Alist of characters and custom functions for bulk actions.
1851For example, this value makes those two functions available:
1852
1853 '((?R set-category)
1854 (?C bulk-cut))
1855
1856With selected entries in an agenda buffer, `B R' will call
fe3c5669 1857the custom function `set-category' on the selected entries.
3ab2c837
BG
1858Note that functions in this alist don't need to be quoted."
1859 :type 'alist
372d7b21 1860 :version "24.1"
3ab2c837
BG
1861 :group 'org-agenda)
1862
afe98dfa
CD
1863(defmacro org-agenda-with-point-at-orig-entry (string &rest body)
1864 "Execute BODY with point at location given by `org-hd-marker' property.
1865If STRING is non-nil, the text property will be fetched from position 0
1866in that string. If STRING is nil, it will be fetched from the beginning
1867of the current line."
e66ba1df
BG
1868 (org-with-gensyms (marker)
1869 `(let ((,marker (get-text-property (if string 0 (point-at-bol))
1870 'org-hd-marker ,string)))
1871 (with-current-buffer (marker-buffer ,marker)
1872 (save-excursion
1873 (goto-char ,marker)
1874 ,@body)))))
1875(def-edebug-spec org-agenda-with-point-at-orig-entry (form body))
afe98dfa 1876
20908596
CD
1877(defun org-add-agenda-custom-command (entry)
1878 "Replace or add a command in `org-agenda-custom-commands'.
1879This is mostly for hacking and trying a new command - once the command
1880works you probably want to add it to `org-agenda-custom-commands' for good."
1881 (let ((ass (assoc (car entry) org-agenda-custom-commands)))
1882 (if ass
1883 (setcdr ass (cdr entry))
1884 (push entry org-agenda-custom-commands))))
1885
8223b1d2 1886;;; Define the org-agenda-mode
20908596
CD
1887
1888(defvar org-agenda-mode-map (make-sparse-keymap)
1889 "Keymap for `org-agenda-mode'.")
8bfe682a
CD
1890(if (fboundp 'defvaralias)
1891 (defvaralias 'org-agenda-keymap 'org-agenda-mode-map))
20908596
CD
1892
1893(defvar org-agenda-menu) ; defined later in this file.
8223b1d2 1894(defvar org-agenda-restrict nil) ; defined later in this file.
20908596 1895(defvar org-agenda-follow-mode nil)
54a0dee5 1896(defvar org-agenda-entry-text-mode nil)
20908596
CD
1897(defvar org-agenda-clockreport-mode nil)
1898(defvar org-agenda-show-log nil)
1899(defvar org-agenda-redo-command nil)
1900(defvar org-agenda-query-string nil)
0bd48b37 1901(defvar org-agenda-mode-hook nil
8223b1d2
BG
1902 "Hook run after `org-agenda-mode' is turned on.
1903The buffer is still writable when this hook is called.")
20908596
CD
1904(defvar org-agenda-type nil)
1905(defvar org-agenda-force-single-file nil)
8223b1d2
BG
1906(defvar org-agenda-bulk-marked-entries nil
1907 "List of markers that refer to marked entries in the agenda.")
1908
1909;;; Multiple agenda buffers support
1910
1911(defcustom org-agenda-sticky nil
1912 "Non-nil means agenda q key will bury agenda buffers.
1913Agenda commands will then show existing buffer instead of generating new ones.
1914When nil, `q' will kill the single agenda buffer."
1915 :group 'org-agenda
1916 :version "24.3"
1917 :type 'boolean)
1918
bdebdb64 1919\f
8223b1d2
BG
1920;;;###autoload
1921(defun org-toggle-sticky-agenda (&optional arg)
1922 "Toggle `org-agenda-sticky'."
1923 (interactive "P")
1924 (let ((new-value (if arg
1925 (> (prefix-numeric-value arg) 0)
1926 (not org-agenda-sticky))))
1927 (if (equal new-value org-agenda-sticky)
1928 (and (org-called-interactively-p 'interactive)
1929 (message "Sticky agenda was already %s"
1930 (if org-agenda-sticky "enabled" "disabled")))
1931 (setq org-agenda-sticky new-value)
1932 (org-agenda-kill-all-agenda-buffers)
1933 (and (org-called-interactively-p 'interactive)
1934 (message "Sticky agenda was %s"
1935 (if org-agenda-sticky "enabled" "disabled"))))))
1936
1937(defvar org-agenda-buffer nil
1938 "Agenda buffer currently being generated.")
1939
1940(defvar org-agenda-last-prefix-arg nil)
1941(defvar org-agenda-this-buffer-name nil)
1942(defvar org-agenda-doing-sticky-redo nil)
1943(defvar org-agenda-this-buffer-is-sticky nil)
1944
1945(defconst org-agenda-local-vars
1946 '(org-agenda-this-buffer-name
1947 org-agenda-undo-list
1948 org-agenda-pending-undo-list
1949 org-agenda-follow-mode
1950 org-agenda-entry-text-mode
1951 org-agenda-clockreport-mode
1952 org-agenda-show-log
1953 org-agenda-redo-command
1954 org-agenda-query-string
1955 org-agenda-type
1956 org-agenda-bulk-marked-entries
1957 org-agenda-undo-has-started-in
1958 org-agenda-info
1959 org-agenda-tag-filter-overlays
1960 org-agenda-cat-filter-overlays
1961 org-agenda-pre-window-conf
1962 org-agenda-columns-active
1963 org-agenda-tag-filter
1964 org-agenda-category-filter
1965 org-agenda-markers
1966 org-agenda-last-search-view-search-was-boolean
1967 org-agenda-filtered-by-category
1968 org-agenda-filter-form
8223b1d2
BG
1969 org-agenda-cycle-counter
1970 org-agenda-last-prefix-arg)
1971 "Variables that must be local in agenda buffers to allow multiple buffers.")
20908596
CD
1972
1973(defun org-agenda-mode ()
1974 "Mode for time-sorted view on action items in Org-mode files.
1975
1976The following commands are available:
1977
1978\\{org-agenda-mode-map}"
1979 (interactive)
8223b1d2
BG
1980 (cond (org-agenda-doing-sticky-redo
1981 ;; Refreshing sticky agenda-buffer
1982 ;;
1983 ;; Preserve the value of `org-agenda-local-vars' variables,
1984 ;; while letting `kill-all-local-variables' kill the rest
1985 (let ((save (buffer-local-variables)))
1986 (kill-all-local-variables)
1987 (mapc 'make-local-variable org-agenda-local-vars)
1988 (dolist (elem save)
1989 (let ((var (car elem))
1990 (val (cdr elem)))
1991 (when (and val
1992 (member var org-agenda-local-vars))
1993 (set var val)))))
1994 (set (make-local-variable 'org-agenda-this-buffer-is-sticky) t))
1995 (org-agenda-sticky
1996 ;; Creating a sticky Agenda buffer for the first time
1997 (kill-all-local-variables)
1998 (mapc 'make-local-variable org-agenda-local-vars)
1999 (set (make-local-variable 'org-agenda-this-buffer-is-sticky) t))
2000 (t
2001 ;; Creating a non-sticky agenda buffer
2002 (kill-all-local-variables)
2003 (set (make-local-variable 'org-agenda-this-buffer-is-sticky) nil)))
20908596 2004 (setq org-agenda-undo-list nil
c8d0cf5c
CD
2005 org-agenda-pending-undo-list nil
2006 org-agenda-bulk-marked-entries nil)
20908596
CD
2007 (setq major-mode 'org-agenda-mode)
2008 ;; Keep global-font-lock-mode from turning on font-lock-mode
2009 (org-set-local 'font-lock-global-modes (list 'not major-mode))
2010 (setq mode-name "Org-Agenda")
2011 (use-local-map org-agenda-mode-map)
2012 (easy-menu-add org-agenda-menu)
2013 (if org-startup-truncated (setq truncate-lines t))
54a0dee5 2014 (org-set-local 'line-move-visual nil)
8223b1d2 2015 (org-add-hook 'post-command-hook 'org-agenda-update-agenda-type nil 'local)
20908596
CD
2016 (org-add-hook 'pre-command-hook 'org-unhighlight nil 'local)
2017 ;; Make sure properties are removed when copying text
8223b1d2
BG
2018 (add-hook 'filter-buffer-substring-functions
2019 (lambda (fun start end delete)
d36ed1c8
SM
2020 (substring-no-properties (funcall fun start end delete)))
2021 nil t)
20908596
CD
2022 (unless org-agenda-keep-modes
2023 (setq org-agenda-follow-mode org-agenda-start-with-follow-mode
54a0dee5 2024 org-agenda-entry-text-mode org-agenda-start-with-entry-text-mode
20908596 2025 org-agenda-clockreport-mode org-agenda-start-with-clockreport-mode
c8d0cf5c
CD
2026 org-agenda-show-log org-agenda-start-with-log-mode))
2027
20908596
CD
2028 (easy-menu-change
2029 '("Agenda") "Agenda Files"
2030 (append
2031 (list
2032 (vector
2033 (if (get 'org-agenda-files 'org-restrict)
2034 "Restricted to single file"
2035 "Edit File List")
2036 '(org-edit-agenda-file-list)
2037 (not (get 'org-agenda-files 'org-restrict)))
2038 "--")
2039 (mapcar 'org-file-menu-entry (org-agenda-files))))
2040 (org-agenda-set-mode-name)
2041 (apply
2042 (if (fboundp 'run-mode-hooks) 'run-mode-hooks 'run-hooks)
2043 (list 'org-agenda-mode-hook)))
2044
2045(substitute-key-definition 'undo 'org-agenda-undo
2046 org-agenda-mode-map global-map)
2047(org-defkey org-agenda-mode-map "\C-i" 'org-agenda-goto)
2048(org-defkey org-agenda-mode-map [(tab)] 'org-agenda-goto)
2049(org-defkey org-agenda-mode-map "\C-m" 'org-agenda-switch-to)
2050(org-defkey org-agenda-mode-map "\C-k" 'org-agenda-kill)
c8d0cf5c
CD
2051(org-defkey org-agenda-mode-map "\C-c\C-w" 'org-agenda-refile)
2052(org-defkey org-agenda-mode-map "m" 'org-agenda-bulk-mark)
8223b1d2 2053(org-defkey org-agenda-mode-map "*" 'org-agenda-bulk-mark-all)
c7cf0ebc 2054(org-defkey org-agenda-mode-map "#" 'org-agenda-dim-blocked-tasks)
3ab2c837 2055(org-defkey org-agenda-mode-map "%" 'org-agenda-bulk-mark-regexp)
c8d0cf5c 2056(org-defkey org-agenda-mode-map "u" 'org-agenda-bulk-unmark)
8223b1d2 2057(org-defkey org-agenda-mode-map "U" 'org-agenda-bulk-unmark-all)
c8d0cf5c 2058(org-defkey org-agenda-mode-map "B" 'org-agenda-bulk-action)
8223b1d2
BG
2059(org-defkey org-agenda-mode-map "k" 'org-agenda-capture)
2060(org-defkey org-agenda-mode-map "A" 'org-agenda-append-agenda)
c8d0cf5c 2061(org-defkey org-agenda-mode-map "\C-c\C-x!" 'org-reload)
8bfe682a
CD
2062(org-defkey org-agenda-mode-map "\C-c\C-x\C-a" 'org-agenda-archive-default)
2063(org-defkey org-agenda-mode-map "\C-c\C-xa" 'org-agenda-toggle-archive-tag)
2064(org-defkey org-agenda-mode-map "\C-c\C-xA" 'org-agenda-archive-to-archive-sibling)
54a0dee5 2065(org-defkey org-agenda-mode-map "\C-c\C-x\C-s" 'org-agenda-archive)
8bfe682a 2066(org-defkey org-agenda-mode-map "\C-c$" 'org-agenda-archive)
20908596 2067(org-defkey org-agenda-mode-map "$" 'org-agenda-archive)
20908596 2068(org-defkey org-agenda-mode-map "\C-c\C-o" 'org-agenda-open-link)
8bfe682a
CD
2069(org-defkey org-agenda-mode-map " " 'org-agenda-show-and-scroll-up)
2070(org-defkey org-agenda-mode-map [backspace] 'org-agenda-show-scroll-down)
2071(org-defkey org-agenda-mode-map "\d" 'org-agenda-show-scroll-down)
20908596
CD
2072(org-defkey org-agenda-mode-map [(control shift right)] 'org-agenda-todo-nextset)
2073(org-defkey org-agenda-mode-map [(control shift left)] 'org-agenda-todo-previousset)
2074(org-defkey org-agenda-mode-map "\C-c\C-xb" 'org-agenda-tree-to-indirect-buffer)
20908596
CD
2075(org-defkey org-agenda-mode-map "o" 'delete-other-windows)
2076(org-defkey org-agenda-mode-map "L" 'org-agenda-recenter)
54a0dee5 2077(org-defkey org-agenda-mode-map "\C-c\C-t" 'org-agenda-todo)
20908596 2078(org-defkey org-agenda-mode-map "t" 'org-agenda-todo)
8bfe682a 2079(org-defkey org-agenda-mode-map "a" 'org-agenda-archive-default-with-confirmation)
20908596 2080(org-defkey org-agenda-mode-map ":" 'org-agenda-set-tags)
71d35b24 2081(org-defkey org-agenda-mode-map "\C-c\C-q" 'org-agenda-set-tags)
20908596
CD
2082(org-defkey org-agenda-mode-map "." 'org-agenda-goto-today)
2083(org-defkey org-agenda-mode-map "j" 'org-agenda-goto-date)
2084(org-defkey org-agenda-mode-map "d" 'org-agenda-day-view)
2085(org-defkey org-agenda-mode-map "w" 'org-agenda-week-view)
20908596
CD
2086(org-defkey org-agenda-mode-map "y" 'org-agenda-year-view)
2087(org-defkey org-agenda-mode-map "\C-c\C-z" 'org-agenda-add-note)
2088(org-defkey org-agenda-mode-map "z" 'org-agenda-add-note)
c8d0cf5c
CD
2089(org-defkey org-agenda-mode-map [(shift right)] 'org-agenda-do-date-later)
2090(org-defkey org-agenda-mode-map [(shift left)] 'org-agenda-do-date-earlier)
2091(org-defkey org-agenda-mode-map [?\C-c ?\C-x (right)] 'org-agenda-do-date-later)
2092(org-defkey org-agenda-mode-map [?\C-c ?\C-x (left)] 'org-agenda-do-date-earlier)
20908596
CD
2093
2094(org-defkey org-agenda-mode-map ">" 'org-agenda-date-prompt)
2095(org-defkey org-agenda-mode-map "\C-c\C-s" 'org-agenda-schedule)
2096(org-defkey org-agenda-mode-map "\C-c\C-d" 'org-agenda-deadline)
2097(let ((l '(1 2 3 4 5 6 7 8 9 0)))
2098 (while l (org-defkey org-agenda-mode-map
8223b1d2 2099 (int-to-string (pop l)) 'digit-argument)))
20908596 2100
54a0dee5 2101(org-defkey org-agenda-mode-map "F" 'org-agenda-follow-mode)
20908596 2102(org-defkey org-agenda-mode-map "R" 'org-agenda-clockreport-mode)
54a0dee5 2103(org-defkey org-agenda-mode-map "E" 'org-agenda-entry-text-mode)
20908596 2104(org-defkey org-agenda-mode-map "l" 'org-agenda-log-mode)
c8d0cf5c 2105(org-defkey org-agenda-mode-map "v" 'org-agenda-view-mode-dispatch)
20908596 2106(org-defkey org-agenda-mode-map "D" 'org-agenda-toggle-diary)
ed21c5c8 2107(org-defkey org-agenda-mode-map "!" 'org-agenda-toggle-deadlines)
20908596
CD
2108(org-defkey org-agenda-mode-map "G" 'org-agenda-toggle-time-grid)
2109(org-defkey org-agenda-mode-map "r" 'org-agenda-redo)
8223b1d2 2110(org-defkey org-agenda-mode-map "g" (lambda () (interactive) (org-agenda-redo t)))
54a0dee5
CD
2111(org-defkey org-agenda-mode-map "e" 'org-agenda-set-effort)
2112(org-defkey org-agenda-mode-map "\C-c\C-xe" 'org-agenda-set-effort)
2113(org-defkey org-agenda-mode-map "\C-c\C-x\C-e"
2114 'org-clock-modify-effort-estimate)
2115(org-defkey org-agenda-mode-map "\C-c\C-xp" 'org-agenda-set-property)
20908596 2116(org-defkey org-agenda-mode-map "q" 'org-agenda-quit)
8223b1d2 2117(org-defkey org-agenda-mode-map "Q" 'org-agenda-Quit)
20908596 2118(org-defkey org-agenda-mode-map "x" 'org-agenda-exit)
e66ba1df 2119(org-defkey org-agenda-mode-map "\C-x\C-w" 'org-agenda-write)
20908596 2120(org-defkey org-agenda-mode-map "\C-x\C-s" 'org-save-all-org-buffers)
c8d0cf5c 2121(org-defkey org-agenda-mode-map "s" 'org-save-all-org-buffers)
20908596 2122(org-defkey org-agenda-mode-map "T" 'org-agenda-show-tags)
8bfe682a
CD
2123(org-defkey org-agenda-mode-map "n" 'org-agenda-next-line)
2124(org-defkey org-agenda-mode-map "p" 'org-agenda-previous-line)
8223b1d2
BG
2125(org-defkey org-agenda-mode-map "N" 'org-agenda-next-item)
2126(org-defkey org-agenda-mode-map "P" 'org-agenda-previous-item)
8bfe682a
CD
2127(substitute-key-definition 'next-line 'org-agenda-next-line
2128 org-agenda-mode-map global-map)
2129(substitute-key-definition 'previous-line 'org-agenda-previous-line
2130 org-agenda-mode-map global-map)
621f83e4 2131(org-defkey org-agenda-mode-map "\C-c\C-a" 'org-attach)
20908596
CD
2132(org-defkey org-agenda-mode-map "\C-c\C-n" 'org-agenda-next-date-line)
2133(org-defkey org-agenda-mode-map "\C-c\C-p" 'org-agenda-previous-date-line)
20908596 2134(org-defkey org-agenda-mode-map "\C-c," 'org-agenda-priority)
8223b1d2 2135(org-defkey org-agenda-mode-map "," 'org-agenda-priority)
20908596
CD
2136(org-defkey org-agenda-mode-map "i" 'org-agenda-diary-entry)
2137(org-defkey org-agenda-mode-map "c" 'org-agenda-goto-calendar)
2138(org-defkey org-agenda-mode-map "C" 'org-agenda-convert-date)
2139(org-defkey org-agenda-mode-map "M" 'org-agenda-phases-of-moon)
2140(org-defkey org-agenda-mode-map "S" 'org-agenda-sunrise-sunset)
2141(org-defkey org-agenda-mode-map "h" 'org-agenda-holidays)
2142(org-defkey org-agenda-mode-map "H" 'org-agenda-holidays)
2143(org-defkey org-agenda-mode-map "\C-c\C-x\C-i" 'org-agenda-clock-in)
2144(org-defkey org-agenda-mode-map "I" 'org-agenda-clock-in)
2145(org-defkey org-agenda-mode-map "\C-c\C-x\C-o" 'org-agenda-clock-out)
2146(org-defkey org-agenda-mode-map "O" 'org-agenda-clock-out)
2147(org-defkey org-agenda-mode-map "\C-c\C-x\C-x" 'org-agenda-clock-cancel)
2148(org-defkey org-agenda-mode-map "X" 'org-agenda-clock-cancel)
2149(org-defkey org-agenda-mode-map "\C-c\C-x\C-j" 'org-clock-goto)
afe98dfa 2150(org-defkey org-agenda-mode-map "J" 'org-agenda-clock-goto)
20908596
CD
2151(org-defkey org-agenda-mode-map "+" 'org-agenda-priority-up)
2152(org-defkey org-agenda-mode-map "-" 'org-agenda-priority-down)
2153(org-defkey org-agenda-mode-map [(shift up)] 'org-agenda-priority-up)
2154(org-defkey org-agenda-mode-map [(shift down)] 'org-agenda-priority-down)
2155(org-defkey org-agenda-mode-map [?\C-c ?\C-x (up)] 'org-agenda-priority-up)
2156(org-defkey org-agenda-mode-map [?\C-c ?\C-x (down)] 'org-agenda-priority-down)
54a0dee5
CD
2157(org-defkey org-agenda-mode-map "f" 'org-agenda-later)
2158(org-defkey org-agenda-mode-map "b" 'org-agenda-earlier)
20908596 2159(org-defkey org-agenda-mode-map "\C-c\C-x\C-c" 'org-agenda-columns)
c8d0cf5c 2160(org-defkey org-agenda-mode-map "\C-c\C-x>" 'org-agenda-remove-restriction-lock)
20908596
CD
2161
2162(org-defkey org-agenda-mode-map "[" 'org-agenda-manipulate-query-add)
2163(org-defkey org-agenda-mode-map "]" 'org-agenda-manipulate-query-subtract)
2164(org-defkey org-agenda-mode-map "{" 'org-agenda-manipulate-query-add-re)
2165(org-defkey org-agenda-mode-map "}" 'org-agenda-manipulate-query-subtract-re)
621f83e4 2166(org-defkey org-agenda-mode-map "/" 'org-agenda-filter-by-tag)
71d35b24 2167(org-defkey org-agenda-mode-map "\\" 'org-agenda-filter-by-tag-refine)
e66ba1df 2168(org-defkey org-agenda-mode-map "<" 'org-agenda-filter-by-category)
8223b1d2 2169(org-defkey org-agenda-mode-map "^" 'org-agenda-filter-by-top-category)
c8d0cf5c 2170(org-defkey org-agenda-mode-map ";" 'org-timer-set-timer)
8d642074
CD
2171(define-key org-agenda-mode-map "?" 'org-agenda-show-the-flagging-note)
2172(org-defkey org-agenda-mode-map "\C-c\C-x\C-mg" 'org-mobile-pull)
2173(org-defkey org-agenda-mode-map "\C-c\C-x\C-mp" 'org-mobile-push)
20908596 2174
86fbb8ca
CD
2175(org-defkey org-agenda-mode-map [mouse-2] 'org-agenda-goto-mouse)
2176(org-defkey org-agenda-mode-map [mouse-3] 'org-agenda-show-mouse)
20908596 2177(when org-agenda-mouse-1-follows-link
8bfe682a 2178 (org-defkey org-agenda-mode-map [follow-link] 'mouse-face))
20908596
CD
2179(easy-menu-define org-agenda-menu org-agenda-mode-map "Agenda menu"
2180 '("Agenda"
2181 ("Agenda Files")
2182 "--"
8d642074
CD
2183 ("Agenda Dates"
2184 ["Goto Today" org-agenda-goto-today (org-agenda-check-type nil 'agenda 'timeline)]
2185 ["Next Dates" org-agenda-later (org-agenda-check-type nil 'agenda)]
2186 ["Previous Dates" org-agenda-earlier (org-agenda-check-type nil 'agenda)]
2187 ["Jump to date" org-agenda-goto-date (org-agenda-check-type nil 'agenda)])
2188 "--"
2189 ("View"
2190 ["Day View" org-agenda-day-view
2191 :active (org-agenda-check-type nil 'agenda)
acedf35c 2192 :style radio :selected (eq org-agenda-current-span 'day)
8d642074
CD
2193 :keys "v d (or just d)"]
2194 ["Week View" org-agenda-week-view
2195 :active (org-agenda-check-type nil 'agenda)
acedf35c 2196 :style radio :selected (eq org-agenda-current-span 'week)
8d642074
CD
2197 :keys "v w (or just w)"]
2198 ["Month View" org-agenda-month-view
2199 :active (org-agenda-check-type nil 'agenda)
acedf35c 2200 :style radio :selected (eq org-agenda-current-span 'month)
8d642074
CD
2201 :keys "v m"]
2202 ["Year View" org-agenda-year-view
2203 :active (org-agenda-check-type nil 'agenda)
acedf35c 2204 :style radio :selected (eq org-agenda-current-span 'year)
8d642074
CD
2205 :keys "v y"]
2206 "--"
2207 ["Include Diary" org-agenda-toggle-diary
2208 :style toggle :selected org-agenda-include-diary
2209 :active (org-agenda-check-type nil 'agenda)]
ed21c5c8
CD
2210 ["Include Deadlines" org-agenda-toggle-deadlines
2211 :style toggle :selected org-agenda-include-deadlines
2212 :active (org-agenda-check-type nil 'agenda)]
8d642074
CD
2213 ["Use Time Grid" org-agenda-toggle-time-grid
2214 :style toggle :selected org-agenda-use-time-grid
2215 :active (org-agenda-check-type nil 'agenda)]
2216 "--"
2217 ["Show clock report" org-agenda-clockreport-mode
2218 :style toggle :selected org-agenda-clockreport-mode
2219 :active (org-agenda-check-type nil 'agenda)]
2220 ["Show some entry text" org-agenda-entry-text-mode
2221 :style toggle :selected org-agenda-entry-text-mode
2222 :active t]
8223b1d2 2223 "--"
8d642074
CD
2224 ["Show Logbook entries" org-agenda-log-mode
2225 :style toggle :selected org-agenda-show-log
2226 :active (org-agenda-check-type nil 'agenda 'timeline)
2227 :keys "v l (or just l)"]
2228 ["Include archived trees" org-agenda-archives-mode
2229 :style toggle :selected org-agenda-archives-mode :active t
2230 :keys "v a"]
2231 ["Include archive files" (org-agenda-archives-mode t)
2232 :style toggle :selected (eq org-agenda-archives-mode t) :active t
2233 :keys "v A"]
2234 "--"
2235 ["Remove Restriction" org-agenda-remove-restriction-lock org-agenda-restrict])
e66ba1df 2236 ["Write view to file" org-agenda-write t]
8d642074
CD
2237 ["Rebuild buffer" org-agenda-redo t]
2238 ["Save all Org-mode Buffers" org-save-all-org-buffers t]
2239 "--"
2240 ["Show original entry" org-agenda-show t]
20908596
CD
2241 ["Go To (other window)" org-agenda-goto t]
2242 ["Go To (this window)" org-agenda-switch-to t]
8223b1d2 2243 ["Capture with cursor date" org-agenda-capture t]
20908596
CD
2244 ["Follow Mode" org-agenda-follow-mode
2245 :style toggle :selected org-agenda-follow-mode :active t]
8223b1d2 2246 ;; ["Tree to indirect frame" org-agenda-tree-to-indirect-buffer t]
20908596 2247 "--"
8d642074
CD
2248 ("TODO"
2249 ["Cycle TODO" org-agenda-todo t]
2250 ["Next TODO set" org-agenda-todo-nextset t]
2251 ["Previous TODO set" org-agenda-todo-previousset t]
2252 ["Add note" org-agenda-add-note t])
2253 ("Archive/Refile/Delete"
8bfe682a
CD
2254 ["Archive default" org-agenda-archive-default t]
2255 ["Archive default" org-agenda-archive-default-with-confirmation t]
20908596
CD
2256 ["Toggle ARCHIVE tag" org-agenda-toggle-archive-tag t]
2257 ["Move to archive sibling" org-agenda-archive-to-archive-sibling t]
c8d0cf5c 2258 ["Archive subtree" org-agenda-archive t]
8d642074
CD
2259 "--"
2260 ["Refile" org-agenda-refile t]
2261 "--"
2262 ["Delete subtree" org-agenda-kill t])
c8d0cf5c 2263 ("Bulk action"
8d642074 2264 ["Mark entry" org-agenda-bulk-mark t]
8223b1d2 2265 ["Mark all" org-agenda-bulk-mark-all t]
3ab2c837 2266 ["Mark matching regexp" org-agenda-bulk-mark-regexp t]
8d642074 2267 ["Unmark entry" org-agenda-bulk-unmark t]
8223b1d2
BG
2268 ["Unmark all entries" org-agenda-bulk-unmark-all :active t :keys "U"])
2269 ["Act on all marked" org-agenda-bulk-action t]
c8d0cf5c 2270 "--"
20908596
CD
2271 ("Tags and Properties"
2272 ["Show all Tags" org-agenda-show-tags t]
2273 ["Set Tags current line" org-agenda-set-tags (not (org-region-active-p))]
2274 ["Change tag in region" org-agenda-set-tags (org-region-active-p)]
2275 "--"
2276 ["Column View" org-columns t])
8d642074 2277 ("Deadline/Schedule"
20908596
CD
2278 ["Schedule" org-agenda-schedule t]
2279 ["Set Deadline" org-agenda-deadline t]
2280 "--"
2281 ["Change Date +1 day" org-agenda-date-later (org-agenda-check-type nil 'agenda 'timeline)]
2282 ["Change Date -1 day" org-agenda-date-earlier (org-agenda-check-type nil 'agenda 'timeline)]
c8d0cf5c
CD
2283 ["Change Time +1 hour" org-agenda-do-date-later :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u S-right"]
2284 ["Change Time -1 hour" org-agenda-do-date-earlier :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u S-left"]
2285 ["Change Time + min" org-agenda-date-later :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u C-u S-right"]
2286 ["Change Time - min" org-agenda-date-earlier :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u C-u S-left"]
20908596 2287 ["Change Date to ..." org-agenda-date-prompt (org-agenda-check-type nil 'agenda 'timeline)])
54a0dee5 2288 ("Clock and Effort"
20908596
CD
2289 ["Clock in" org-agenda-clock-in t]
2290 ["Clock out" org-agenda-clock-out t]
2291 ["Clock cancel" org-agenda-clock-cancel t]
54a0dee5
CD
2292 ["Goto running clock" org-clock-goto t]
2293 "--"
2294 ["Set Effort" org-agenda-set-effort t]
2295 ["Change clocked effort" org-clock-modify-effort-estimate
2296 (org-clock-is-active)])
20908596
CD
2297 ("Priority"
2298 ["Set Priority" org-agenda-priority t]
2299 ["Increase Priority" org-agenda-priority-up t]
2300 ["Decrease Priority" org-agenda-priority-down t]
8223b1d2 2301 ["Show Priority" org-show-priority t])
20908596
CD
2302 ("Calendar/Diary"
2303 ["New Diary Entry" org-agenda-diary-entry (org-agenda-check-type nil 'agenda 'timeline)]
2304 ["Goto Calendar" org-agenda-goto-calendar (org-agenda-check-type nil 'agenda 'timeline)]
2305 ["Phases of the Moon" org-agenda-phases-of-moon (org-agenda-check-type nil 'agenda 'timeline)]
2306 ["Sunrise/Sunset" org-agenda-sunrise-sunset (org-agenda-check-type nil 'agenda 'timeline)]
2307 ["Holidays" org-agenda-holidays (org-agenda-check-type nil 'agenda 'timeline)]
2308 ["Convert" org-agenda-convert-date (org-agenda-check-type nil 'agenda 'timeline)]
2309 "--"
8d642074 2310 ["Create iCalendar File" org-export-icalendar-combine-agenda-files t])
20908596 2311 "--"
8d642074 2312 ["Undo Remote Editing" org-agenda-undo org-agenda-undo-list]
2c3ad40d 2313 "--"
8d642074
CD
2314 ("MobileOrg"
2315 ["Push Files and Views" org-mobile-push t]
2316 ["Get Captured and Flagged" org-mobile-pull t]
2317 ["Find FLAGGED Tasks" (org-agenda nil "?") :active t :keys "C-c a ?"]
2318 ["Show note / unflag" org-agenda-show-the-flagging-note t]
c8d0cf5c 2319 "--"
8d642074 2320 ["Setup" (progn (require 'org-mobile) (customize-group 'org-mobile)) t])
20908596
CD
2321 "--"
2322 ["Quit" org-agenda-quit t]
2323 ["Exit and Release Buffers" org-agenda-exit t]
2324 ))
2325
2326;;; Agenda undo
2327
2328(defvar org-agenda-allow-remote-undo t
ed21c5c8 2329 "Non-nil means allow remote undo from the agenda buffer.")
20908596
CD
2330(defvar org-agenda-undo-has-started-in nil
2331 "Buffers that have already seen `undo-start' in the current undo sequence.")
20908596 2332
20908596
CD
2333(defun org-agenda-undo ()
2334 "Undo a remote editing step in the agenda.
2335This undoes changes both in the agenda buffer and in the remote buffer
2336that have been changed along."
2337 (interactive)
2338 (or org-agenda-allow-remote-undo
f924a367 2339 (error "Check the variable `org-agenda-allow-remote-undo' to activate remote undo"))
20908596
CD
2340 (if (not (eq this-command last-command))
2341 (setq org-agenda-undo-has-started-in nil
2342 org-agenda-pending-undo-list org-agenda-undo-list))
2343 (if (not org-agenda-pending-undo-list)
2344 (error "No further undo information"))
2345 (let* ((entry (pop org-agenda-pending-undo-list))
2346 buf line cmd rembuf)
2347 (setq cmd (pop entry) line (pop entry))
2348 (setq rembuf (nth 2 entry))
2349 (org-with-remote-undo rembuf
2350 (while (bufferp (setq buf (pop entry)))
2351 (if (pop entry)
2352 (with-current-buffer buf
2353 (let ((last-undo-buffer buf)
2354 (inhibit-read-only t))
2355 (unless (memq buf org-agenda-undo-has-started-in)
2356 (push buf org-agenda-undo-has-started-in)
2357 (make-local-variable 'pending-undo-list)
2358 (undo-start))
2359 (while (and pending-undo-list
2360 (listp pending-undo-list)
2361 (not (car pending-undo-list)))
2362 (pop pending-undo-list))
2363 (undo-more 1))))))
54a0dee5 2364 (org-goto-line line)
20908596
CD
2365 (message "`%s' undone (buffer %s)" cmd (buffer-name rembuf))))
2366
2367(defun org-verify-change-for-undo (l1 l2)
2368 "Verify that a real change occurred between the undo lists L1 and L2."
2369 (while (and l1 (listp l1) (null (car l1))) (pop l1))
2370 (while (and l2 (listp l2) (null (car l2))) (pop l2))
2371 (not (eq l1 l2)))
2372
2373;;; Agenda dispatch
2374
20908596
CD
2375(defvar org-agenda-restrict-begin (make-marker))
2376(defvar org-agenda-restrict-end (make-marker))
2377(defvar org-agenda-last-dispatch-buffer nil)
2378(defvar org-agenda-overriding-restriction nil)
2379
8223b1d2
BG
2380(defcustom org-agenda-custom-commands-contexts nil
2381 "Alist of custom agenda keys and contextual rules.
2382
2383For example, if you have a custom agenda command \"p\" and you
2384want this command to be accessible only from plain text files,
2385use this:
2386
a89c8ef0 2387 '((\"p\" ((in-file . \"\\.txt\"))))
8223b1d2
BG
2388
2389Here are the available contexts definitions:
2390
2391 in-file: command displayed only in matching files
2392 in-mode: command displayed only in matching modes
2393 not-in-file: command not displayed in matching files
2394 not-in-mode: command not displayed in matching modes
2395 [function]: a custom function taking no argument
2396
2397If you define several checks, the agenda command will be
2398accessible if there is at least one valid check.
2399
2400You can also bind a key to another agenda custom command
2401depending on contextual rules.
2402
a89c8ef0 2403 '((\"p\" \"q\" ((in-file . \"\\.txt\"))))
8223b1d2
BG
2404
2405Here it means: in .txt files, use \"p\" as the key for the
2406agenda command otherwise associated with \"q\". (The command
2407originally associated with \"q\" is not displayed to avoid
2408duplicates.)"
2409 :version "24.3"
2410 :group 'org-agenda-custom-commands
2411 :type '(repeat (list :tag "Rule"
2412 (string :tag " Agenda key")
2413 (string :tag "Replace by command")
2414 (repeat :tag "Available when"
2415 (choice
2416 (cons :tag "Condition"
2417 (choice
2418 (const :tag "In file" in-file)
2419 (const :tag "Not in file" not-in-file)
2420 (const :tag "In mode" in-mode)
2421 (const :tag "Not in mode" not-in-mode))
2422 (regexp))
2423 (function :tag "Custom function"))))))
2424
2425(defvar org-keys nil)
2426(defvar org-match nil)
20908596 2427;;;###autoload
8223b1d2 2428(defun org-agenda (&optional arg org-keys restriction)
20908596
CD
2429 "Dispatch agenda commands to collect entries to the agenda buffer.
2430Prompts for a command to execute. Any prefix arg will be passed
2431on to the selected command. The default selections are:
2432
2433a Call `org-agenda-list' to display the agenda for current day or week.
2434t Call `org-todo-list' to display the global todo list.
2435T Call `org-todo-list' to display the global todo list, select only
2436 entries with a specific TODO keyword (the user gets a prompt).
2437m Call `org-tags-view' to display headlines with tags matching
2438 a condition (the user is prompted for the condition).
2439M Like `m', but select only TODO entries, no ordinary headlines.
2440L Create a timeline for the current buffer.
2441e Export views to associated files.
c8d0cf5c 2442s Search entries for keywords.
8223b1d2 2443S Search entries for keywords, only with TODO keywords.
8bfe682a 2444/ Multi occur across all agenda files and also files listed
c8d0cf5c
CD
2445 in `org-agenda-text-search-extra-files'.
2446< Restrict agenda commands to buffer, subtree, or region.
2447 Press several times to get the desired effect.
2448> Remove a previous restriction.
2449# List \"stuck\" projects.
2450! Configure what \"stuck\" means.
2451C Configure custom agenda commands.
20908596
CD
2452
2453More commands can be added by configuring the variable
2454`org-agenda-custom-commands'. In particular, specific tags and TODO keyword
2455searches can be pre-defined in this way.
2456
2457If the current buffer is in Org-mode and visiting a file, you can also
2458first press `<' once to indicate that the agenda should be temporarily
2459\(until the next use of \\[org-agenda]) restricted to the current file.
2460Pressing `<' twice means to restrict to the current subtree or region
2461\(if active)."
2462 (interactive "P")
2463 (catch 'exit
2464 (let* ((prefix-descriptions nil)
8223b1d2 2465 (org-agenda-buffer-name org-agenda-buffer-name)
54a0dee5
CD
2466 (org-agenda-window-setup (if (equal (buffer-name)
2467 org-agenda-buffer-name)
2468 'current-window
2469 org-agenda-window-setup))
20908596
CD
2470 (org-agenda-custom-commands-orig org-agenda-custom-commands)
2471 (org-agenda-custom-commands
2472 ;; normalize different versions
2473 (delq nil
2474 (mapcar
2475 (lambda (x)
2476 (cond ((stringp (cdr x))
2477 (push x prefix-descriptions)
2478 nil)
2479 ((stringp (nth 1 x)) x)
2480 ((not (nth 1 x)) (cons (car x) (cons "" (cddr x))))
2481 (t (cons (car x) (cons "" (cdr x))))))
2482 org-agenda-custom-commands)))
8223b1d2
BG
2483 (org-agenda-custom-commands
2484 (org-contextualize-keys
2485 org-agenda-custom-commands org-agenda-custom-commands-contexts))
20908596
CD
2486 (buf (current-buffer))
2487 (bfn (buffer-file-name (buffer-base-buffer)))
8223b1d2 2488 entry key type org-match lprops ans)
8d642074 2489 ;; Turn off restriction unless there is an overriding one,
20908596 2490 (unless org-agenda-overriding-restriction
8bfe682a 2491 (unless (org-bound-and-true-p org-agenda-keep-restricted-file-list)
8d642074
CD
2492 ;; There is a request to keep the file list in place
2493 (put 'org-agenda-files 'org-restrict nil))
20908596
CD
2494 (setq org-agenda-restrict nil)
2495 (move-marker org-agenda-restrict-begin nil)
2496 (move-marker org-agenda-restrict-end nil))
2497 ;; Delete old local properties
2498 (put 'org-agenda-redo-command 'org-lprops nil)
3ab2c837
BG
2499 ;; Delete previously set last-arguments
2500 (put 'org-agenda-redo-command 'last-args nil)
20908596
CD
2501 ;; Remember where this call originated
2502 (setq org-agenda-last-dispatch-buffer (current-buffer))
8223b1d2 2503 (unless org-keys
20908596 2504 (setq ans (org-agenda-get-restriction-and-command prefix-descriptions)
8223b1d2 2505 org-keys (car ans)
20908596 2506 restriction (cdr ans)))
8223b1d2
BG
2507 ;; If we have sticky agenda buffers, set a name for the buffer,
2508 ;; depending on the invoking keys. The user may still set this
2509 ;; as a command option, which will overwrite what we do here.
2510 (if org-agenda-sticky
2511 (setq org-agenda-buffer-name
2512 (format "*Org Agenda(%s)*" org-keys)))
8bfe682a 2513 ;; Establish the restriction, if any
20908596
CD
2514 (when (and (not org-agenda-overriding-restriction) restriction)
2515 (put 'org-agenda-files 'org-restrict (list bfn))
2516 (cond
2517 ((eq restriction 'region)
2518 (setq org-agenda-restrict t)
2519 (move-marker org-agenda-restrict-begin (region-beginning))
2520 (move-marker org-agenda-restrict-end (region-end)))
2521 ((eq restriction 'subtree)
2522 (save-excursion
2523 (setq org-agenda-restrict t)
2524 (org-back-to-heading t)
2525 (move-marker org-agenda-restrict-begin (point))
2526 (move-marker org-agenda-restrict-end
2527 (progn (org-end-of-subtree t)))))))
2528
20908596
CD
2529 ;; For example the todo list should not need it (but does...)
2530 (cond
8223b1d2 2531 ((setq entry (assoc org-keys org-agenda-custom-commands))
20908596
CD
2532 (if (or (symbolp (nth 2 entry)) (functionp (nth 2 entry)))
2533 (progn
8223b1d2 2534 (setq type (nth 2 entry) org-match (eval (nth 3 entry))
8bfe682a 2535 lprops (nth 4 entry))
8223b1d2
BG
2536 (if org-agenda-sticky
2537 (setq org-agenda-buffer-name
2538 (or (and (stringp org-match) (format "*Org Agenda(%s:%s)*" org-keys org-match))
2539 (format "*Org Agenda(%s)*" org-keys))))
20908596
CD
2540 (put 'org-agenda-redo-command 'org-lprops lprops)
2541 (cond
2542 ((eq type 'agenda)
2543 (org-let lprops '(org-agenda-list current-prefix-arg)))
2544 ((eq type 'alltodo)
2545 (org-let lprops '(org-todo-list current-prefix-arg)))
2546 ((eq type 'search)
8223b1d2 2547 (org-let lprops '(org-search-view current-prefix-arg org-match nil)))
20908596
CD
2548 ((eq type 'stuck)
2549 (org-let lprops '(org-agenda-list-stuck-projects
2550 current-prefix-arg)))
2551 ((eq type 'tags)
8223b1d2 2552 (org-let lprops '(org-tags-view current-prefix-arg org-match)))
20908596 2553 ((eq type 'tags-todo)
8223b1d2 2554 (org-let lprops '(org-tags-view '(4) org-match)))
20908596 2555 ((eq type 'todo)
8223b1d2 2556 (org-let lprops '(org-todo-list org-match)))
20908596
CD
2557 ((eq type 'tags-tree)
2558 (org-check-for-org-mode)
8223b1d2 2559 (org-let lprops '(org-match-sparse-tree current-prefix-arg org-match)))
20908596
CD
2560 ((eq type 'todo-tree)
2561 (org-check-for-org-mode)
2562 (org-let lprops
3ab2c837 2563 '(org-occur (concat "^" org-outline-regexp "[ \t]*"
8223b1d2 2564 (regexp-quote org-match) "\\>"))))
20908596
CD
2565 ((eq type 'occur-tree)
2566 (org-check-for-org-mode)
8223b1d2 2567 (org-let lprops '(org-occur org-match)))
20908596 2568 ((functionp type)
8223b1d2 2569 (org-let lprops '(funcall type org-match)))
20908596 2570 ((fboundp type)
8223b1d2 2571 (org-let lprops '(funcall type org-match)))
20908596 2572 (t (error "Invalid custom agenda command type %s" type))))
3ab2c837 2573 (org-agenda-run-series (nth 1 entry) (cddr entry))))
8223b1d2 2574 ((equal org-keys "C")
20908596
CD
2575 (setq org-agenda-custom-commands org-agenda-custom-commands-orig)
2576 (customize-variable 'org-agenda-custom-commands))
8223b1d2
BG
2577 ((equal org-keys "a") (call-interactively 'org-agenda-list))
2578 ((equal org-keys "s") (call-interactively 'org-search-view))
2579 ((equal org-keys "S") (org-call-with-arg 'org-search-view (or arg '(4))))
2580 ((equal org-keys "t") (call-interactively 'org-todo-list))
2581 ((equal org-keys "T") (org-call-with-arg 'org-todo-list (or arg '(4))))
2582 ((equal org-keys "m") (call-interactively 'org-tags-view))
2583 ((equal org-keys "M") (org-call-with-arg 'org-tags-view (or arg '(4))))
2584 ((equal org-keys "e") (call-interactively 'org-store-agenda-views))
2585 ((equal org-keys "?") (org-tags-view nil "+FLAGGED")
8d642074
CD
2586 (org-add-hook
2587 'post-command-hook
2588 (lambda ()
2589 (unless (current-message)
2590 (let* ((m (org-agenda-get-any-marker))
2591 (note (and m (org-entry-get m "THEFLAGGINGNOTE"))))
2592 (when note
2593 (message (concat
2594 "FLAGGING-NOTE ([?] for more info): "
2595 (org-add-props
2596 (replace-regexp-in-string
2597 "\\\\n" "//"
2598 (copy-sequence note))
2599 nil 'face 'org-warning)))))))
2600 t t))
8223b1d2
BG
2601 ((equal org-keys "L")
2602 (unless (derived-mode-p 'org-mode)
20908596
CD
2603 (error "This is not an Org-mode file"))
2604 (unless restriction
2605 (put 'org-agenda-files 'org-restrict (list bfn))
2606 (org-call-with-arg 'org-timeline arg)))
8223b1d2
BG
2607 ((equal org-keys "#") (call-interactively 'org-agenda-list-stuck-projects))
2608 ((equal org-keys "/") (call-interactively 'org-occur-in-agenda-files))
2609 ((equal org-keys "!") (customize-variable 'org-stuck-projects))
20908596
CD
2610 (t (error "Invalid agenda key"))))))
2611
3ab2c837
BG
2612(defun org-agenda-append-agenda ()
2613 "Append another agenda view to the current one.
2614This function allows interactive building of block agendas.
2615Agenda views are separated by `org-agenda-block-separator'."
2616 (interactive)
8223b1d2 2617 (unless (derived-mode-p 'org-agenda-mode)
3ab2c837
BG
2618 (error "Can only append from within agenda buffer"))
2619 (let ((org-agenda-multi t))
2620 (org-agenda)
8223b1d2
BG
2621 (widen)
2622 (org-agenda-finalize)
2623 (org-agenda-fit-window-to-buffer)))
3ab2c837 2624
20908596
CD
2625(defun org-agenda-normalize-custom-commands (cmds)
2626 (delq nil
2627 (mapcar
2628 (lambda (x)
2629 (cond ((stringp (cdr x)) nil)
2630 ((stringp (nth 1 x)) x)
2631 ((not (nth 1 x)) (cons (car x) (cons "" (cddr x))))
2632 (t (cons (car x) (cons "" (cdr x))))))
2633 cmds)))
2634
2635(defun org-agenda-get-restriction-and-command (prefix-descriptions)
2636 "The user interface for selecting an agenda command."
2637 (catch 'exit
2638 (let* ((bfn (buffer-file-name (buffer-base-buffer)))
8223b1d2 2639 (restrict-ok (and bfn (derived-mode-p 'org-mode)))
20908596
CD
2640 (region-p (org-region-active-p))
2641 (custom org-agenda-custom-commands)
2642 (selstring "")
2643 restriction second-time
afe98dfa
CD
2644 c entry key type match prefixes rmheader header-end custom1 desc
2645 line lines left right n n1)
20908596
CD
2646 (save-window-excursion
2647 (delete-other-windows)
2648 (org-switch-to-buffer-other-window " *Agenda Commands*")
2649 (erase-buffer)
2650 (insert (eval-when-compile
2651 (let ((header
8223b1d2 2652 "Press key for an agenda command: < Buffer, subtree/region restriction
20908596
CD
2653-------------------------------- > Remove restriction
2654a Agenda for current week or day e Export agenda views
2655t List of all TODO entries T Entries with special TODO kwd
621f83e4 2656m Match a TAGS/PROP/TODO query M Like m, but only TODO entries
8223b1d2 2657s Search for keywords S Like s, but only TODO entries
20908596 2658L Timeline for current buffer # List stuck projects (!=configure)
8223b1d2
BG
2659/ Multi-occur C Configure custom agenda commands
2660? Find :FLAGGED: entries * Toggle sticky agenda views
20908596
CD
2661")
2662 (start 0))
2663 (while (string-match
2664 "\\(^\\| \\|(\\)\\(\\S-\\)\\( \\|=\\)"
2665 header start)
2666 (setq start (match-end 0))
2667 (add-text-properties (match-beginning 2) (match-end 2)
2668 '(face bold) header))
2669 header)))
c7cf0ebc 2670 (setq header-end (point-marker))
20908596
CD
2671 (while t
2672 (setq custom1 custom)
2673 (when (eq rmheader t)
54a0dee5 2674 (org-goto-line 1)
20908596
CD
2675 (re-search-forward ":" nil t)
2676 (delete-region (match-end 0) (point-at-eol))
2677 (forward-char 1)
2678 (looking-at "-+")
2679 (delete-region (match-end 0) (point-at-eol))
2680 (move-marker header-end (match-end 0)))
2681 (goto-char header-end)
2682 (delete-region (point) (point-max))
afe98dfa
CD
2683
2684 ;; Produce all the lines that describe custom commands and prefixes
2685 (setq lines nil)
20908596
CD
2686 (while (setq entry (pop custom1))
2687 (setq key (car entry) desc (nth 1 entry)
54a0dee5
CD
2688 type (nth 2 entry)
2689 match (nth 3 entry))
20908596
CD
2690 (if (> (length key) 1)
2691 (add-to-list 'prefixes (string-to-char key))
afe98dfa
CD
2692 (setq line
2693 (format
2694 "%-4s%-14s"
2695 (org-add-props (copy-sequence key)
2696 '(face bold))
2697 (cond
2698 ((string-match "\\S-" desc) desc)
2699 ((eq type 'agenda) "Agenda for current week or day")
2700 ((eq type 'alltodo) "List of all TODO entries")
2701 ((eq type 'search) "Word search")
2702 ((eq type 'stuck) "List of stuck projects")
2703 ((eq type 'todo) "TODO keyword")
2704 ((eq type 'tags) "Tags query")
2705 ((eq type 'tags-todo) "Tags (TODO)")
2706 ((eq type 'tags-tree) "Tags tree")
2707 ((eq type 'todo-tree) "TODO kwd tree")
2708 ((eq type 'occur-tree) "Occur tree")
2709 ((functionp type) (if (symbolp type)
2710 (symbol-name type)
2711 "Lambda expression"))
2712 (t "???"))))
2713 (if org-agenda-menu-show-matcher
2714 (setq line
2715 (concat line ": "
2716 (cond
2717 ((stringp match)
2718 (setq match (copy-sequence match))
2719 (org-add-props match nil 'face 'org-warning))
8223b1d2
BG
2720 ((listp type)
2721 (format "set of %d commands" (length type))))))
afe98dfa
CD
2722 (if (org-string-nw-p match)
2723 (add-text-properties
2724 0 (length line) (list 'help-echo
8223b1d2 2725 (concat "Matcher: " match)) line)))
afe98dfa
CD
2726 (push line lines)))
2727 (setq lines (nreverse lines))
20908596
CD
2728 (when prefixes
2729 (mapc (lambda (x)
afe98dfa
CD
2730 (push
2731 (format "%s %s"
20908596 2732 (org-add-props (char-to-string x)
afe98dfa
CD
2733 nil 'face 'bold)
2734 (or (cdr (assoc (concat selstring
2735 (char-to-string x))
20908596 2736 prefix-descriptions))
afe98dfa
CD
2737 "Prefix key"))
2738 lines))
20908596 2739 prefixes))
afe98dfa
CD
2740
2741 ;; Check if we should display in two columns
8223b1d2 2742 (if org-agenda-menu-two-columns
afe98dfa
CD
2743 (progn
2744 (setq n (length lines)
2745 n1 (+ (/ n 2) (mod n 2))
2746 right (nthcdr n1 lines)
2747 left (copy-sequence lines))
2748 (setcdr (nthcdr (1- n1) left) nil))
2749 (setq left lines right nil))
2750 (while left
2751 (insert "\n" (pop left))
2752 (when right
2753 (if (< (current-column) 40)
2754 (move-to-column 40 t)
2755 (insert " "))
2756 (insert (pop right))))
2757
2758 ;; Make the window the right size
20908596 2759 (goto-char (point-min))
93b62de8
CD
2760 (if second-time
2761 (if (not (pos-visible-in-window-p (point-max)))
2762 (org-fit-window-to-buffer))
2763 (setq second-time t)
2764 (org-fit-window-to-buffer))
afe98dfa
CD
2765
2766 ;; Ask for selection
20908596
CD
2767 (message "Press key for agenda command%s:"
2768 (if (or restrict-ok org-agenda-overriding-restriction)
2769 (if org-agenda-overriding-restriction
2770 " (restriction lock active)"
2771 (if restriction
2772 (format " (restricted to %s)" restriction)
2773 " (unrestricted)"))
2774 ""))
2775 (setq c (read-char-exclusive))
2776 (message "")
2777 (cond
2778 ((assoc (char-to-string c) custom)
2779 (setq selstring (concat selstring (char-to-string c)))
2780 (throw 'exit (cons selstring restriction)))
2781 ((memq c prefixes)
2782 (setq selstring (concat selstring (char-to-string c))
2783 prefixes nil
2784 rmheader (or rmheader t)
2785 custom (delq nil (mapcar
2786 (lambda (x)
2787 (if (or (= (length (car x)) 1)
2788 (/= (string-to-char (car x)) c))
2789 nil
2790 (cons (substring (car x) 1) (cdr x))))
2791 custom))))
8223b1d2
BG
2792 ((eq c ?*)
2793 (call-interactively 'org-toggle-sticky-agenda)
2794 (sit-for 2))
20908596
CD
2795 ((and (not restrict-ok) (memq c '(?1 ?0 ?<)))
2796 (message "Restriction is only possible in Org-mode buffers")
2797 (ding) (sit-for 1))
2798 ((eq c ?1)
2799 (org-agenda-remove-restriction-lock 'noupdate)
2800 (setq restriction 'buffer))
2801 ((eq c ?0)
2802 (org-agenda-remove-restriction-lock 'noupdate)
2803 (setq restriction (if region-p 'region 'subtree)))
2804 ((eq c ?<)
2805 (org-agenda-remove-restriction-lock 'noupdate)
2806 (setq restriction
2807 (cond
2808 ((eq restriction 'buffer)
2809 (if region-p 'region 'subtree))
2810 ((memq restriction '(subtree region))
2811 nil)
2812 (t 'buffer))))
2813 ((eq c ?>)
2814 (org-agenda-remove-restriction-lock 'noupdate)
2815 (setq restriction nil))
8223b1d2 2816 ((and (equal selstring "") (memq c '(?s ?S ?a ?t ?m ?L ?C ?e ?T ?M ?# ?! ?/ ??)))
20908596
CD
2817 (throw 'exit (cons (setq selstring (char-to-string c)) restriction)))
2818 ((and (> (length selstring) 0) (eq c ?\d))
2819 (delete-window)
2820 (org-agenda-get-restriction-and-command prefix-descriptions))
2821
2822 ((equal c ?q) (error "Abort"))
2823 (t (error "Invalid key %c" c))))))))
2824
8223b1d2
BG
2825(defun org-agenda-fit-window-to-buffer ()
2826 "Fit the window to the buffer size."
2827 (and (memq org-agenda-window-setup '(reorganize-frame))
2828 (fboundp 'fit-window-to-buffer)
2829 (org-fit-window-to-buffer
2830 nil
2831 (floor (* (frame-height) (cdr org-agenda-window-frame-fractions)))
2832 (floor (* (frame-height) (car org-agenda-window-frame-fractions))))))
2833
2834(defvar org-cmd nil)
2835(defvar org-agenda-overriding-cmd nil)
2836(defvar org-agenda-overriding-arguments nil)
2837(defvar org-agenda-overriding-cmd-arguments nil)
3ab2c837 2838(defun org-agenda-run-series (name series)
8223b1d2
BG
2839 (org-let (nth 1 series) '(org-agenda-prepare name))
2840 ;; We need to reset agenda markers here, because when constructing a
2841 ;; block agenda, the individual blocks do not do that.
2842 (org-agenda-reset-markers)
20908596 2843 (let* ((org-agenda-multi t)
3ab2c837 2844 (redo (list 'org-agenda-run-series name (list 'quote series)))
20908596
CD
2845 (cmds (car series))
2846 (gprops (nth 1 series))
2847 match ;; The byte compiler incorrectly complains about this. Keep it!
8223b1d2
BG
2848 org-cmd type lprops)
2849 (while (setq org-cmd (pop cmds))
2850 (setq type (car org-cmd)
2851 match (eval (nth 1 org-cmd))
2852 lprops (nth 2 org-cmd))
2853 (let ((org-agenda-overriding-arguments
2854 (if (eq org-agenda-overriding-cmd org-cmd)
2855 (or org-agenda-overriding-arguments
2856 org-agenda-overriding-cmd-arguments))))
2857 (cond
2858 ((eq type 'agenda)
2859 (org-let2 gprops lprops
2860 '(call-interactively 'org-agenda-list)))
2861 ((eq type 'alltodo)
2862 (org-let2 gprops lprops
2863 '(call-interactively 'org-todo-list)))
2864 ((eq type 'search)
2865 (org-let2 gprops lprops
2866 '(org-search-view current-prefix-arg match nil)))
2867 ((eq type 'stuck)
2868 (org-let2 gprops lprops
2869 '(call-interactively 'org-agenda-list-stuck-projects)))
2870 ((eq type 'tags)
2871 (org-let2 gprops lprops
2872 '(org-tags-view current-prefix-arg match)))
2873 ((eq type 'tags-todo)
2874 (org-let2 gprops lprops
2875 '(org-tags-view '(4) match)))
2876 ((eq type 'todo)
2877 (org-let2 gprops lprops
2878 '(org-todo-list match)))
2879 ((fboundp type)
2880 (org-let2 gprops lprops
2881 '(funcall type match)))
2882 (t (error "Invalid type in command series")))))
20908596 2883 (widen)
8223b1d2
BG
2884 (let ((inhibit-read-only t))
2885 (add-text-properties (point-min) (point-max)
735135f9 2886 `(org-series t org-series-redo-cmd ,redo)))
20908596
CD
2887 (setq org-agenda-redo-command redo)
2888 (goto-char (point-min)))
8223b1d2
BG
2889 (org-agenda-fit-window-to-buffer)
2890 (org-let (nth 1 series) '(org-agenda-finalize)))
20908596
CD
2891
2892;;;###autoload
2893(defmacro org-batch-agenda (cmd-key &rest parameters)
2894 "Run an agenda command in batch mode and send the result to STDOUT.
2895If CMD-KEY is a string of length 1, it is used as a key in
2896`org-agenda-custom-commands' and triggers this command. If it is a
2897longer string it is used as a tags/todo match string.
86fbb8ca 2898Parameters are alternating variable names and values that will be bound
20908596 2899before running the agenda command."
e66ba1df 2900 (org-eval-in-environment (org-make-parameter-alist parameters)
20908596 2901 (if (> (length cmd-key) 2)
e66ba1df
BG
2902 (org-tags-view nil cmd-key)
2903 (org-agenda nil cmd-key)))
2904 (set-buffer org-agenda-buffer-name)
2905 (princ (buffer-string)))
bdebdb64 2906
20908596
CD
2907(defvar org-agenda-info nil)
2908
2909;;;###autoload
2910(defmacro org-batch-agenda-csv (cmd-key &rest parameters)
2911 "Run an agenda command in batch mode and send the result to STDOUT.
2912If CMD-KEY is a string of length 1, it is used as a key in
2913`org-agenda-custom-commands' and triggers this command. If it is a
2914longer string it is used as a tags/todo match string.
86fbb8ca 2915Parameters are alternating variable names and values that will be bound
20908596
CD
2916before running the agenda command.
2917
2918The output gives a line for each selected agenda item. Each
2919item is a list of comma-separated values, like this:
2920
2921category,head,type,todo,tags,date,time,extra,priority-l,priority-n
2922
2923category The category of the item
2924head The headline, without TODO kwd, TAGS and PRIORITY
2925type The type of the agenda entry, can be
2926 todo selected in TODO match
2927 tagsmatch selected in tags match
2928 diary imported from diary
2929 deadline a deadline on given date
2930 scheduled scheduled on given date
2931 timestamp entry has timestamp on given date
2932 closed entry was closed on given date
2933 upcoming-deadline warning about deadline
2934 past-scheduled forwarded scheduled item
2935 block entry has date block including g. date
2936todo The todo keyword, if any
2937tags All tags including inherited ones, separated by colons
2938date The relevant date, like 2007-2-14
2939time The time, like 15:00-16:50
2940extra Sting with extra planning info
2941priority-l The priority letter if any was given
2942priority-n The computed numerical priority
2943agenda-day The day in the agenda where this is listed"
e66ba1df
BG
2944 (org-eval-in-environment (append '((org-agenda-remove-tags t))
2945 (org-make-parameter-alist parameters))
20908596 2946 (if (> (length cmd-key) 2)
e66ba1df
BG
2947 (org-tags-view nil cmd-key)
2948 (org-agenda nil cmd-key)))
2949 (set-buffer org-agenda-buffer-name)
2950 (let* ((lines (org-split-string (buffer-string) "\n"))
2951 line)
2952 (while (setq line (pop lines))
2953 (catch 'next
2954 (if (not (get-text-property 0 'org-category line)) (throw 'next nil))
2955 (setq org-agenda-info
2956 (org-fix-agenda-info (text-properties-at 0 line)))
2957 (princ
2958 (mapconcat 'org-agenda-export-csv-mapper
2959 '(org-category txt type todo tags date time extra
2960 priority-letter priority agenda-day)
2961 ","))
2962 (princ "\n")))))
bdebdb64 2963
20908596 2964(defun org-fix-agenda-info (props)
86fbb8ca
CD
2965 "Make sure all properties on an agenda item have a canonical form.
2966This ensures the export commands can easily use it."
20908596
CD
2967 (let (tmp re)
2968 (when (setq tmp (plist-get props 'tags))
2969 (setq props (plist-put props 'tags (mapconcat 'identity tmp ":"))))
2970 (when (setq tmp (plist-get props 'date))
2971 (if (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
2972 (let ((calendar-date-display-form '(year "-" month "-" day)))
2973 '((format "%4d, %9s %2s, %4s" dayname monthname day year))
2974
2975 (setq tmp (calendar-date-string tmp)))
2976 (setq props (plist-put props 'date tmp)))
2977 (when (setq tmp (plist-get props 'day))
2978 (if (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
2979 (let ((calendar-date-display-form '(year "-" month "-" day)))
2980 (setq tmp (calendar-date-string tmp)))
2981 (setq props (plist-put props 'day tmp))
2982 (setq props (plist-put props 'agenda-day tmp)))
2983 (when (setq tmp (plist-get props 'txt))
2984 (when (string-match "\\[#\\([A-Z0-9]\\)\\] ?" tmp)
2985 (plist-put props 'priority-letter (match-string 1 tmp))
2986 (setq tmp (replace-match "" t t tmp)))
2987 (when (and (setq re (plist-get props 'org-todo-regexp))
2988 (setq re (concat "\\`\\.*" re " ?"))
2989 (string-match re tmp))
2990 (plist-put props 'todo (match-string 1 tmp))
2991 (setq tmp (replace-match "" t t tmp)))
2992 (plist-put props 'txt tmp)))
2993 props)
2994
2995(defun org-agenda-export-csv-mapper (prop)
2996 (let ((res (plist-get org-agenda-info prop)))
2997 (setq res
2998 (cond
2999 ((not res) "")
3000 ((stringp res) res)
3001 (t (prin1-to-string res))))
3002 (while (string-match "," res)
3003 (setq res (replace-match ";" t t res)))
3004 (org-trim res)))
3005
20908596
CD
3006;;;###autoload
3007(defun org-store-agenda-views (&rest parameters)
3008 (interactive)
3009 (eval (list 'org-batch-store-agenda-views)))
3010
20908596
CD
3011;;;###autoload
3012(defmacro org-batch-store-agenda-views (&rest parameters)
3013 "Run all custom agenda commands that have a file argument."
3014 (let ((cmds (org-agenda-normalize-custom-commands org-agenda-custom-commands))
3015 (pop-up-frames nil)
3016 (dir default-directory)
e66ba1df 3017 (pars (org-make-parameter-alist parameters))
8223b1d2 3018 cmd thiscmdkey thiscmdcmd match files opts cmd-or-set bufname)
20908596
CD
3019 (save-window-excursion
3020 (while cmds
3021 (setq cmd (pop cmds)
3022 thiscmdkey (car cmd)
8223b1d2
BG
3023 thiscmdcmd (cdr cmd)
3024 match (nth 2 thiscmdcmd)
3025 bufname (if org-agenda-sticky
3026 (or (and (stringp match)
3027 (format "*Org Agenda(%s:%s)*" thiscmdkey match))
3028 (format "*Org Agenda(%s)*" thiscmdkey))
3029 org-agenda-buffer-name)
2c3ad40d
CD
3030 cmd-or-set (nth 2 cmd)
3031 opts (nth (if (listp cmd-or-set) 3 4) cmd)
3032 files (nth (if (listp cmd-or-set) 4 5) cmd))
20908596
CD
3033 (if (stringp files) (setq files (list files)))
3034 (when files
e66ba1df
BG
3035 (org-eval-in-environment (append org-agenda-exporter-settings
3036 opts pars)
3037 (org-agenda nil thiscmdkey))
8223b1d2 3038 (set-buffer bufname)
20908596 3039 (while files
e66ba1df
BG
3040 (org-eval-in-environment (append org-agenda-exporter-settings
3041 opts pars)
8223b1d2
BG
3042 (org-agenda-write (expand-file-name (pop files) dir) nil t bufname)))
3043 (and (get-buffer bufname)
3044 (kill-buffer bufname)))))))
bdebdb64 3045
8223b1d2
BG
3046(defvar org-agenda-current-span nil
3047 "The current span used in the agenda view.") ; local variable in the agenda buffer
8d642074
CD
3048(defun org-agenda-mark-header-line (pos)
3049 "Mark the line at POS as an agenda structure header."
3050 (save-excursion
3051 (goto-char pos)
3052 (put-text-property (point-at-bol) (point-at-eol)
3053 'org-agenda-structural-header t)
3054 (when org-agenda-title-append
3055 (put-text-property (point-at-bol) (point-at-eol)
3056 'org-agenda-title-append org-agenda-title-append))))
3057
8223b1d2 3058(defvar org-mobile-creating-agendas) ; defined in org-mobile.el
e66ba1df 3059(defvar org-agenda-write-buffer-name "Agenda View")
8223b1d2 3060(defun org-agenda-write (file &optional open nosettings agenda-bufname)
20908596
CD
3061 "Write the current buffer (an agenda view) as a file.
3062Depending on the extension of the file name, plain text (.txt),
e66ba1df
BG
3063HTML (.html or .htm) or Postscript (.ps) is produced.
3064If the extension is .ics, run icalendar export over all files used
20908596
CD
3065to construct the agenda and limit the export to entries listed in the
3066agenda now.
8bfe682a 3067With prefix argument OPEN, open the new file immediately.
20908596
CD
3068If NOSETTINGS is given, do not scope the settings of
3069`org-agenda-exporter-settings' into the export commands. This is used when
3070the settings have already been scoped and we do not wish to overrule other,
8223b1d2
BG
3071higher priority settings.
3072If AGENDA-BUFFER-NAME, use this as the buffer name for the agenda to write."
c8d0cf5c 3073 (interactive "FWrite agenda to file: \nP")
20908596
CD
3074 (if (not (file-writable-p file))
3075 (error "Cannot write agenda to file %s" file))
20908596 3076 (org-let (if nosettings nil org-agenda-exporter-settings)
afe98dfa 3077 '(save-excursion
20908596 3078 (save-window-excursion
93b62de8 3079 (org-agenda-mark-filtered-text)
8bfe682a 3080 (let ((bs (copy-sequence (buffer-string))) beg)
93b62de8
CD
3081 (org-agenda-unmark-filtered-text)
3082 (with-temp-buffer
e66ba1df 3083 (rename-buffer org-agenda-write-buffer-name t)
afe98dfa 3084 (set-buffer-modified-p nil)
20908596 3085 (insert bs)
93b62de8
CD
3086 (org-agenda-remove-marked-text 'org-filtered)
3087 (while (setq beg (text-property-any (point-min) (point-max)
3088 'org-filtered t))
3089 (delete-region
3090 beg (or (next-single-property-change beg 'org-filtered)
3091 (point-max))))
c8d0cf5c 3092 (run-hooks 'org-agenda-before-write-hook)
93b62de8 3093 (cond
8bfe682a
CD
3094 ((org-bound-and-true-p org-mobile-creating-agendas)
3095 (org-mobile-write-agenda-for-mobile file))
93b62de8 3096 ((string-match "\\.html?\\'" file)
afe98dfa 3097 (require 'htmlize)
93b62de8 3098 (set-buffer (htmlize-buffer (current-buffer)))
8223b1d2 3099 (when org-agenda-export-html-style
93b62de8
CD
3100 ;; replace <style> section with org-agenda-export-html-style
3101 (goto-char (point-min))
3102 (kill-region (- (search-forward "<style") 6)
3103 (search-forward "</style>"))
3104 (insert org-agenda-export-html-style))
3105 (write-file file)
3106 (kill-buffer (current-buffer))
3107 (message "HTML written to %s" file))
3108 ((string-match "\\.ps\\'" file)
c8d0cf5c 3109 (require 'ps-print)
afe98dfa 3110 (ps-print-buffer-with-faces file)
e66ba1df 3111 (message "Postscript written to %s" file))
c8d0cf5c
CD
3112 ((string-match "\\.pdf\\'" file)
3113 (require 'ps-print)
afe98dfa
CD
3114 (ps-print-buffer-with-faces
3115 (concat (file-name-sans-extension file) ".ps"))
c8d0cf5c
CD
3116 (call-process "ps2pdf" nil nil nil
3117 (expand-file-name
3118 (concat (file-name-sans-extension file) ".ps"))
3119 (expand-file-name file))
afe98dfa 3120 (delete-file (concat (file-name-sans-extension file) ".ps"))
c8d0cf5c 3121 (message "PDF written to %s" file))
93b62de8 3122 ((string-match "\\.ics\\'" file)
c8d0cf5c 3123 (require 'org-icalendar)
93b62de8
CD
3124 (let ((org-agenda-marker-table
3125 (org-create-marker-find-array
3126 (org-agenda-collect-markers)))
3127 (org-icalendar-verify-function 'org-check-agenda-marker-table)
3128 (org-combined-agenda-icalendar-file file))
3129 (apply 'org-export-icalendar 'combine
3130 (org-agenda-files nil 'ifmode))))
3131 (t
3132 (let ((bs (buffer-string)))
3133 (find-file file)
3134 (erase-buffer)
3135 (insert bs)
3136 (save-buffer 0)
3137 (kill-buffer (current-buffer))
3138 (message "Plain text written to %s" file))))))))
8223b1d2 3139 (set-buffer (or agenda-bufname
c7cf0ebc 3140 (and (org-called-interactively-p 'any) (buffer-name))
8223b1d2 3141 org-agenda-buffer-name)))
c8d0cf5c
CD
3142 (when open (org-open-file file)))
3143
e66ba1df
BG
3144(defvar org-agenda-tag-filter-overlays nil)
3145(defvar org-agenda-cat-filter-overlays nil)
93b62de8
CD
3146
3147(defun org-agenda-mark-filtered-text ()
3148 "Mark all text hidden by filtering with a text property."
3149 (let ((inhibit-read-only t))
3150 (mapc
3151 (lambda (o)
86fbb8ca 3152 (when (equal (overlay-buffer o) (current-buffer))
93b62de8 3153 (put-text-property
86fbb8ca 3154 (overlay-start o) (overlay-end o)
93b62de8 3155 'org-filtered t)))
e66ba1df
BG
3156 (append org-agenda-tag-filter-overlays
3157 org-agenda-cat-filter-overlays))))
93b62de8
CD
3158
3159(defun org-agenda-unmark-filtered-text ()
3160 "Remove the filtering text property."
3161 (let ((inhibit-read-only t))
3162 (remove-text-properties (point-min) (point-max) '(org-filtered t))))
3163
3164(defun org-agenda-remove-marked-text (property &optional value)
3165 "Delete all text marked with VALUE of PROPERTY.
3166VALUE defaults to t."
3167 (let (beg)
3168 (setq value (or value t))
3169 (while (setq beg (text-property-any (point-min) (point-max)
3170 property value))
3171 (delete-region
3172 beg (or (next-single-property-change beg 'org-filtered)
3173 (point-max))))))
20908596 3174
c8d0cf5c
CD
3175(defun org-agenda-add-entry-text ()
3176 "Add entry text to agenda lines.
3177This will add a maximum of `org-agenda-add-entry-text-maxlines' lines of the
3178entry text following headings shown in the agenda.
3179Drawers will be excluded, also the line with scheduling/deadline info."
8bfe682a
CD
3180 (when (and (> org-agenda-add-entry-text-maxlines 0)
3181 (not (org-bound-and-true-p org-mobile-creating-agendas)))
54a0dee5 3182 (let (m txt)
c8d0cf5c
CD
3183 (goto-char (point-min))
3184 (while (not (eobp))
8d642074 3185 (if (not (setq m (org-get-at-bol 'org-hd-marker)))
c8d0cf5c 3186 (beginning-of-line 2)
54a0dee5 3187 (setq txt (org-agenda-get-some-entry-text
8d642074 3188 m org-agenda-add-entry-text-maxlines " > "))
c8d0cf5c 3189 (end-of-line 1)
afe98dfa
CD
3190 (if (string-match "\\S-" txt)
3191 (insert "\n" txt)
3192 (or (eobp) (forward-char 1))))))))
c8d0cf5c 3193
8d642074
CD
3194(defun org-agenda-get-some-entry-text (marker n-lines &optional indent
3195 &rest keep)
54a0dee5 3196 "Extract entry text from MARKER, at most N-LINES lines.
8d642074
CD
3197This will ignore drawers etc, just get the text.
3198If INDENT is given, prefix every line with this string. If KEEP is
8bfe682a 3199given, it is a list of symbols, defining stuff that should not be
8d642074 3200removed from the entry content. Currently only `planning' is allowed here."
54a0dee5
CD
3201 (let (txt drawer-re kwd-time-re ind)
3202 (save-excursion
3203 (with-current-buffer (marker-buffer marker)
8223b1d2 3204 (if (not (derived-mode-p 'org-mode))
54a0dee5
CD
3205 (setq txt "")
3206 (save-excursion
3207 (save-restriction
3208 (widen)
3209 (goto-char marker)
8d642074 3210 (end-of-line 1)
54a0dee5 3211 (setq txt (buffer-substring
8d642074 3212 (min (1+ (point)) (point-max))
54a0dee5
CD
3213 (progn (outline-next-heading) (point)))
3214 drawer-re org-drawer-regexp
3215 kwd-time-re (concat "^[ \t]*" org-keyword-time-regexp
3216 ".*\n?"))
3217 (with-temp-buffer
3218 (insert txt)
3219 (when org-agenda-add-entry-text-descriptive-links
3220 (goto-char (point-min))
3221 (while (org-activate-bracket-links (point-max))
3222 (add-text-properties (match-beginning 0) (match-end 0)
3223 '(face org-link))))
3224 (goto-char (point-min))
3225 (while (re-search-forward org-bracket-link-regexp (point-max) t)
3226 (set-text-properties (match-beginning 0) (match-end 0)
3227 nil))
3228 (goto-char (point-min))
3229 (while (re-search-forward drawer-re nil t)
3230 (delete-region
3231 (match-beginning 0)
3232 (progn (re-search-forward
3233 "^[ \t]*:END:.*\n?" nil 'move)
3234 (point))))
8d642074
CD
3235 (unless (member 'planning keep)
3236 (goto-char (point-min))
3237 (while (re-search-forward kwd-time-re nil t)
3238 (replace-match "")))
54a0dee5 3239 (goto-char (point-min))
8d642074
CD
3240 (when org-agenda-entry-text-exclude-regexps
3241 (let ((re-list org-agenda-entry-text-exclude-regexps) re)
3242 (while (setq re (pop re-list))
3243 (goto-char (point-min))
3244 (while (re-search-forward re nil t)
3245 (replace-match "")))))
3246 (goto-char (point-max))
3247 (skip-chars-backward " \t\n")
3248 (if (looking-at "[ \t\n]+\\'") (replace-match ""))
3249
3250 ;; find and remove min common indentation
54a0dee5
CD
3251 (goto-char (point-min))
3252 (untabify (point-min) (point-max))
3253 (setq ind (org-get-indentation))
3254 (while (not (eobp))
3255 (unless (looking-at "[ \t]*$")
3256 (setq ind (min ind (org-get-indentation))))
3257 (beginning-of-line 2))
3258 (goto-char (point-min))
3259 (while (not (eobp))
3260 (unless (looking-at "[ \t]*$")
3261 (move-to-column ind)
3262 (delete-region (point-at-bol) (point)))
3263 (beginning-of-line 2))
8d642074
CD
3264
3265 (run-hooks 'org-agenda-entry-text-cleanup-hook)
3266
54a0dee5 3267 (goto-char (point-min))
8d642074
CD
3268 (when indent
3269 (while (and (not (eobp)) (re-search-forward "^" nil t))
3270 (replace-match indent t t)))
54a0dee5
CD
3271 (goto-char (point-min))
3272 (while (looking-at "[ \t]*\n") (replace-match ""))
3273 (goto-char (point-max))
3274 (when (> (org-current-line)
3275 n-lines)
3276 (org-goto-line (1+ n-lines))
3277 (backward-char 1))
3278 (setq txt (buffer-substring (point-min) (point)))))))))
3279 txt))
3280
20908596
CD
3281(defun org-agenda-collect-markers ()
3282 "Collect the markers pointing to entries in the agenda buffer."
3283 (let (m markers)
3284 (save-excursion
3285 (goto-char (point-min))
3286 (while (not (eobp))
8d642074
CD
3287 (when (setq m (or (org-get-at-bol 'org-hd-marker)
3288 (org-get-at-bol 'org-marker)))
20908596
CD
3289 (push m markers))
3290 (beginning-of-line 2)))
3291 (nreverse markers)))
3292
3293(defun org-create-marker-find-array (marker-list)
e66ba1df 3294 "Create a alist of files names with all marker positions in that file."
20908596
CD
3295 (let (f tbl m a p)
3296 (while (setq m (pop marker-list))
3297 (setq p (marker-position m)
3298 f (buffer-file-name (or (buffer-base-buffer
3299 (marker-buffer m))
3300 (marker-buffer m))))
3301 (if (setq a (assoc f tbl))
3302 (push (marker-position m) (cdr a))
3303 (push (list f p) tbl)))
3304 (mapcar (lambda (x) (setcdr x (sort (copy-sequence (cdr x)) '<)) x)
3305 tbl)))
3306
33306645 3307(defvar org-agenda-marker-table nil) ; dynamically scoped parameter
20908596
CD
3308(defun org-check-agenda-marker-table ()
3309 "Check of the current entry is on the marker list."
3310 (let ((file (buffer-file-name (or (buffer-base-buffer) (current-buffer))))
3311 a)
3312 (and (setq a (assoc file org-agenda-marker-table))
3313 (save-match-data
3314 (save-excursion
3315 (org-back-to-heading t)
3316 (member (point) (cdr a)))))))
3317
3318(defun org-check-for-org-mode ()
e66ba1df 3319 "Make sure current buffer is in org-mode. Error if not."
8223b1d2 3320 (or (derived-mode-p 'org-mode)
f924a367 3321 (error "Cannot execute org-mode agenda command on buffer in %s"
20908596
CD
3322 major-mode)))
3323
20908596
CD
3324;;; Agenda prepare and finalize
3325
33306645 3326(defvar org-agenda-multi nil) ; dynamically scoped
8223b1d2 3327(defvar org-agenda-pre-window-conf nil)
20908596
CD
3328(defvar org-agenda-columns-active nil)
3329(defvar org-agenda-name nil)
e66ba1df
BG
3330(defvar org-agenda-tag-filter nil)
3331(defvar org-agenda-category-filter nil)
8223b1d2 3332(defvar org-agenda-top-category-filter nil)
e66ba1df
BG
3333(defvar org-agenda-tag-filter-while-redo nil)
3334(defvar org-agenda-tag-filter-preset nil
c8d0cf5c 3335 "A preset of the tags filter used for secondary agenda filtering.
86fbb8ca 3336This must be a list of strings, each string must be a single tag preceded
c8d0cf5c
CD
3337by \"+\" or \"-\".
3338This variable should not be set directly, but agenda custom commands can
afe98dfa
CD
3339bind it in the options section. The preset filter is a global property of
3340the entire agenda view. In a block agenda, it will not work reliably to
3341define a filter for one of the individual blocks. You need to set it in
3342the global options and expect it to be applied to the entire view.")
c8d0cf5c 3343
e66ba1df 3344(defvar org-agenda-category-filter-preset nil
27e428e7 3345 "A preset of the category filter used for secondary agenda filtering.
e66ba1df
BG
3346This must be a list of strings, each string must be a single category
3347preceded by \"+\" or \"-\".
3348This variable should not be set directly, but agenda custom commands can
3349bind it in the options section. The preset filter is a global property of
3350the entire agenda view. In a block agenda, it will not work reliably to
3351define a filter for one of the individual blocks. You need to set it in
3352the global options and expect it to be applied to the entire view.")
3353
8223b1d2
BG
3354
3355(defun org-agenda-use-sticky-p ()
3356 "Return non-nil if an agenda buffer named
3357`org-agenda-buffer-name' exists and should be shown instead of
3358generating a new one."
3359 (and
3360 ;; turned off by user
3361 org-agenda-sticky
3362 ;; For multi-agenda buffer already exists
3363 (not org-agenda-multi)
3364 ;; buffer found
3365 (get-buffer org-agenda-buffer-name)
3366 ;; C-u parameter is same as last call
3367 (with-current-buffer (get-buffer org-agenda-buffer-name)
3368 (and
3369 (equal current-prefix-arg
3370 org-agenda-last-prefix-arg)
3371 ;; In case user turned stickiness on, while having existing
3372 ;; Agenda buffer active, don't reuse that buffer, because it
3373 ;; does not have org variables local
3374 org-agenda-this-buffer-is-sticky))))
3375
3376(defun org-agenda-prepare-window (abuf)
3377 "Setup agenda buffer in the window."
3378 (let* ((awin (get-buffer-window abuf))
3379 wconf)
3380 (cond
3381 ((equal (current-buffer) abuf) nil)
3382 (awin (select-window awin))
3383 ((not (setq wconf (current-window-configuration))))
3384 ((equal org-agenda-window-setup 'current-window)
3385 (org-pop-to-buffer-same-window abuf))
3386 ((equal org-agenda-window-setup 'other-window)
3387 (org-switch-to-buffer-other-window abuf))
3388 ((equal org-agenda-window-setup 'other-frame)
3389 (switch-to-buffer-other-frame abuf))
3390 ((equal org-agenda-window-setup 'reorganize-frame)
3391 (delete-other-windows)
3392 (org-switch-to-buffer-other-window abuf)))
3393 ;; additional test in case agenda is invoked from within agenda
3394 ;; buffer via elisp link
3395 (unless (equal (current-buffer) abuf)
3396 (org-pop-to-buffer-same-window abuf))
3397 (setq org-agenda-pre-window-conf
3398 (or org-agenda-pre-window-conf wconf))))
3399
3400(defun org-agenda-prepare (&optional name)
3401 (if (org-agenda-use-sticky-p)
20908596 3402 (progn
8223b1d2
BG
3403 ;; Popup existing buffer
3404 (org-agenda-prepare-window (get-buffer org-agenda-buffer-name))
3405 (message "Sticky Agenda buffer, use `r' to refresh")
3406 (or org-agenda-multi (org-agenda-fit-window-to-buffer))
3407 (throw 'exit "Sticky Agenda buffer, use `r' to refresh"))
3408 (setq org-todo-keywords-for-agenda nil)
3409 (setq org-drawers-for-agenda nil)
3410 (unless org-agenda-persistent-filter
3411 (setq org-agenda-tag-filter nil
3412 org-agenda-category-filter nil))
3413 (put 'org-agenda-tag-filter :preset-filter
3414 org-agenda-tag-filter-preset)
3415 (put 'org-agenda-category-filter :preset-filter
3416 org-agenda-category-filter-preset)
3417 (if org-agenda-multi
3418 (progn
3419 (setq buffer-read-only nil)
3420 (goto-char (point-max))
3421 (unless (or (bobp) org-agenda-compact-blocks
3422 (not org-agenda-block-separator))
3423 (insert "\n"
3424 (if (stringp org-agenda-block-separator)
3425 org-agenda-block-separator
3426 (make-string (window-width) org-agenda-block-separator))
3427 "\n"))
3428 (narrow-to-region (point) (point-max)))
3429 (setq org-done-keywords-for-agenda nil)
3430
3431 ;; Setting any org variables that are in org-agenda-local-vars
3432 ;; list need to be done after the prepare call
3433 (org-agenda-prepare-window (get-buffer-create org-agenda-buffer-name))
3434 (setq buffer-read-only nil)
3435 (org-agenda-reset-markers)
3436 (let ((inhibit-read-only t)) (erase-buffer))
3437 (org-agenda-mode)
3438 (setq org-agenda-buffer (current-buffer))
3439 (setq org-agenda-contributing-files nil)
3440 (setq org-agenda-columns-active nil)
3441 (org-agenda-prepare-buffers (org-agenda-files nil 'ifmode))
3442 (setq org-todo-keywords-for-agenda
3443 (org-uniquify org-todo-keywords-for-agenda))
3444 (setq org-done-keywords-for-agenda
3445 (org-uniquify org-done-keywords-for-agenda))
3446 (setq org-drawers-for-agenda (org-uniquify org-drawers-for-agenda))
3447 (setq org-agenda-last-prefix-arg current-prefix-arg)
3448 (setq org-agenda-this-buffer-name org-agenda-buffer-name)
3449 (and name (not org-agenda-name)
3450 (org-set-local 'org-agenda-name name)))
3451 (setq buffer-read-only nil)))
3452
3453(defvar org-agenda-overriding-columns-format) ; From org-colview.el
3454(defun org-agenda-finalize ()
20908596
CD
3455 "Finishing touch for the agenda buffer, called just before displaying it."
3456 (unless org-agenda-multi
3457 (save-excursion
3458 (let ((inhibit-read-only t))
3459 (goto-char (point-min))
c7cf0ebc
BG
3460 (save-excursion
3461 (while (org-activate-bracket-links (point-max))
3462 (add-text-properties (match-beginning 0) (match-end 0)
3463 '(face org-link))))
3464 (save-excursion
3465 (while (org-activate-plain-links (point-max))
3466 (add-text-properties (match-beginning 0) (match-end 0)
3467 '(face org-link))))
3468 (unless (eq org-agenda-remove-tags t)
3469 (org-agenda-align-tags))
20908596 3470 (unless org-agenda-with-colors
2e3c2398
BG
3471 (remove-text-properties (point-min) (point-max) '(face nil)))
3472 (if (and (boundp 'org-agenda-overriding-columns-format)
3473 org-agenda-overriding-columns-format)
3474 (org-set-local 'org-agenda-overriding-columns-format
3475 org-agenda-overriding-columns-format))
3476 (if (and (boundp 'org-agenda-view-columns-initially)
3477 org-agenda-view-columns-initially)
3478 (org-agenda-columns))
3479 (when org-agenda-fontify-priorities
3480 (org-agenda-fontify-priorities))
3481 (when (and org-agenda-dim-blocked-tasks org-blocker-hook)
3482 (org-agenda-dim-blocked-tasks))
3483 ;; We need to widen when `org-agenda-finalize' is called from
3484 ;; `org-agenda-change-all-lines' (e.g. in `org-agenda-clock-in')
3485 (when org-clock-current-task
3486 (save-restriction
3487 (widen)
3488 (org-agenda-mark-clocking-task)))
3489 (when org-agenda-entry-text-mode
3490 (org-agenda-entry-text-hide)
3491 (org-agenda-entry-text-show))
3492 (if (and (functionp 'org-habit-insert-consistency-graphs)
3493 (save-excursion (next-single-property-change (point-min) 'org-habit-p)))
3494 (org-habit-insert-consistency-graphs))
3495 (setq org-agenda-type (org-get-at-bol 'org-agenda-type))
a89c8ef0
BG
3496 (unless (or (eq org-agenda-show-inherited-tags 'always)
3497 (and (listp org-agenda-show-inherited-tags)
3498 (memq org-agenda-type org-agenda-show-inherited-tags))
3499 (and (eq org-agenda-show-inherited-tags t)
3500 (or (eq org-agenda-use-tag-inheritance t)
3501 (and (listp org-agenda-use-tag-inheritance)
3502 (not (memq org-agenda-type
3503 org-agenda-use-tag-inheritance))))))
2e3c2398
BG
3504 (let (mrk)
3505 (save-excursion
3506 (goto-char (point-min))
3507 (while (equal (forward-line) 0)
3508 (when (setq mrk (or (get-text-property (point) 'org-hd-marker)
3509 (get-text-property (point) 'org-hd-marker)))
3510 (put-text-property (point-at-bol) (point-at-eol)
3511 'tags (org-with-point-at mrk
3512 (delete-dups
3513 (mapcar 'downcase (org-get-tags-at))))))))))
3514 (run-hooks 'org-agenda-finalize-hook)
3515 (when (or org-agenda-tag-filter (get 'org-agenda-tag-filter :preset-filter))
3516 (org-agenda-filter-apply org-agenda-tag-filter 'tag))
3517 (when (or org-agenda-category-filter (get 'org-agenda-category-filter :preset-filter))
3518 (org-agenda-filter-apply org-agenda-category-filter 'category))
3519 (org-add-hook 'kill-buffer-hook 'org-agenda-reset-markers 'append 'local)))))
20908596 3520
54a0dee5
CD
3521(defun org-agenda-mark-clocking-task ()
3522 "Mark the current clock entry in the agenda if it is present."
3523 (mapc (lambda (o)
86fbb8ca
CD
3524 (if (eq (overlay-get o 'type) 'org-agenda-clocking)
3525 (delete-overlay o)))
3526 (overlays-in (point-min) (point-max)))
54a0dee5
CD
3527 (when (marker-buffer org-clock-hd-marker)
3528 (save-excursion
3529 (goto-char (point-min))
3530 (let (s ov)
3531 (while (setq s (next-single-property-change (point) 'org-hd-marker))
3532 (goto-char s)
8d642074 3533 (when (equal (org-get-at-bol 'org-hd-marker)
54a0dee5 3534 org-clock-hd-marker)
86fbb8ca
CD
3535 (setq ov (make-overlay (point-at-bol) (1+ (point-at-eol))))
3536 (overlay-put ov 'type 'org-agenda-clocking)
3537 (overlay-put ov 'face 'org-agenda-clocking)
3538 (overlay-put ov 'help-echo
8223b1d2 3539 "The clock is running in this item")))))))
54a0dee5 3540
c8d0cf5c 3541(defun org-agenda-fontify-priorities ()
20908596
CD
3542 "Make highest priority lines bold, and lowest italic."
3543 (interactive)
86fbb8ca
CD
3544 (mapc (lambda (o) (if (eq (overlay-get o 'org-type) 'org-priority)
3545 (delete-overlay o)))
3546 (overlays-in (point-min) (point-max)))
20908596
CD
3547 (save-excursion
3548 (let ((inhibit-read-only t)
3549 b e p ov h l)
3550 (goto-char (point-min))
3551 (while (re-search-forward "\\[#\\(.\\)\\]" nil t)
3552 (setq h (or (get-char-property (point) 'org-highest-priority)
3553 org-highest-priority)
3554 l (or (get-char-property (point) 'org-lowest-priority)
3555 org-lowest-priority)
3556 p (string-to-char (match-string 1))
c8d0cf5c
CD
3557 b (match-beginning 0)
3558 e (if (eq org-agenda-fontify-priorities 'cookies)
3559 (match-end 0)
3560 (point-at-eol))
86fbb8ca
CD
3561 ov (make-overlay b e))
3562 (overlay-put
20908596 3563 ov 'face
ed21c5c8
CD
3564 (cond ((org-face-from-face-or-color
3565 'priority nil
3566 (cdr (assoc p org-priority-faces))))
c8d0cf5c 3567 ((and (listp org-agenda-fontify-priorities)
ed21c5c8
CD
3568 (org-face-from-face-or-color
3569 'priority nil
3570 (cdr (assoc p org-agenda-fontify-priorities)))))
20908596
CD
3571 ((equal p l) 'italic)
3572 ((equal p h) 'bold)))
86fbb8ca 3573 (overlay-put ov 'org-type 'org-priority)))))
20908596 3574
c7cf0ebc
BG
3575(defun org-agenda-dim-blocked-tasks (&optional invisible)
3576 (interactive "P")
d6685abc 3577 "Dim currently blocked TODO's in the agenda display."
c7cf0ebc 3578 (message "Dim or hide blocked tasks...")
86fbb8ca
CD
3579 (mapc (lambda (o) (if (eq (overlay-get o 'org-type) 'org-blocked-todo)
3580 (delete-overlay o)))
3581 (overlays-in (point-min) (point-max)))
d6685abc
CD
3582 (save-excursion
3583 (let ((inhibit-read-only t)
72d06d81 3584 (org-depend-tag-blocked nil)
c7cf0ebc
BG
3585 (invis (or (not (null invisible))
3586 (eq org-agenda-dim-blocked-tasks 'invisible)))
c8d0cf5c
CD
3587 org-blocked-by-checkboxes
3588 invis1 b e p ov h l)
d6685abc
CD
3589 (goto-char (point-min))
3590 (while (let ((pos (next-single-property-change (point) 'todo-state)))
3591 (and pos (goto-char (1+ pos))))
c8d0cf5c 3592 (setq org-blocked-by-checkboxes nil invis1 invis)
8d642074 3593 (let ((marker (org-get-at-bol 'org-hd-marker)))
d6685abc 3594 (when (and marker
e66ba1df
BG
3595 (with-current-buffer (marker-buffer marker)
3596 (save-excursion (goto-char marker)
3597 (org-entry-blocked-p))))
c8d0cf5c 3598 (if org-blocked-by-checkboxes (setq invis1 nil))
53e31a31
CD
3599 (setq b (if invis1
3600 (max (point-min) (1- (point-at-bol)))
3601 (point-at-bol))
d6685abc 3602 e (point-at-eol)
86fbb8ca 3603 ov (make-overlay b e))
c8d0cf5c 3604 (if invis1
86fbb8ca
CD
3605 (overlay-put ov 'invisible t)
3606 (overlay-put ov 'face 'org-agenda-dimmed-todo-face))
c7cf0ebc
BG
3607 (overlay-put ov 'org-type 'org-blocked-todo))))))
3608 (message "Dim or hide blocked tasks...done"))
20908596
CD
3609
3610(defvar org-agenda-skip-function nil
3611 "Function to be called at each match during agenda construction.
3612If this function returns nil, the current match should not be skipped.
3613Otherwise, the function must return a position from where the search
3614should be continued.
3615This may also be a Lisp form, it will be evaluated.
3616Never set this variable using `setq' or so, because then it will apply
3ab2c837
BG
3617to all future agenda commands. If you do want a global skipping condition,
3618use the option `org-agenda-skip-function-global' instead.
3619The correct usage for `org-agenda-skip-function' is to bind it with
3620`let' to scope it dynamically into the agenda-constructing command.
3621A good way to set it is through options in `org-agenda-custom-commands'.")
20908596
CD
3622
3623(defun org-agenda-skip ()
3624 "Throw to `:skip' in places that should be skipped.
3625Also moves point to the end of the skipped region, so that search can
3626continue from there."
3ab2c837 3627 (let ((p (point-at-bol)) to)
d3517077
BG
3628 (when (or
3629 (save-excursion (goto-char p) (looking-at comment-start-skip))
3630 (and org-agenda-skip-archived-trees (not org-agenda-archives-mode)
3631 (get-text-property p :org-archived)
3632 (org-end-of-subtree t))
3633 (and org-agenda-skip-comment-trees
3634 (get-text-property p :org-comment)
3635 (org-end-of-subtree t))
3636 (and (setq to (or (org-agenda-skip-eval org-agenda-skip-function-global)
3637 (org-agenda-skip-eval org-agenda-skip-function)))
3638 (goto-char to))
3639 (org-in-src-block-p t))
20908596
CD
3640 (throw :skip t))))
3641
3ab2c837
BG
3642(defun org-agenda-skip-eval (form)
3643 "If FORM is a function or a list, call (or eval) is and return result.
3644`save-excursion' and `save-match-data' are wrapped around the call, so point
3645and match data are returned to the previous state no matter what these
3646functions do."
3647 (let (fp)
3648 (and form
3649 (or (setq fp (functionp form))
3650 (consp form))
3651 (save-excursion
3652 (save-match-data
3653 (if fp
3654 (funcall form)
3655 (eval form)))))))
3656
20908596
CD
3657(defvar org-agenda-markers nil
3658 "List of all currently active markers created by `org-agenda'.")
54a0dee5 3659(defvar org-agenda-last-marker-time (org-float-time)
20908596
CD
3660 "Creation time of the last agenda marker.")
3661
3662(defun org-agenda-new-marker (&optional pos)
3663 "Return a new agenda marker.
3664Org-mode keeps a list of these markers and resets them when they are
3665no longer in use."
3666 (let ((m (copy-marker (or pos (point)))))
54a0dee5 3667 (setq org-agenda-last-marker-time (org-float-time))
8223b1d2
BG
3668 (if org-agenda-buffer
3669 (with-current-buffer org-agenda-buffer
3670 (push m org-agenda-markers))
3671 (push m org-agenda-markers))
20908596
CD
3672 m))
3673
3674(defun org-agenda-reset-markers ()
3675 "Reset markers created by `org-agenda'."
3676 (while org-agenda-markers
3677 (move-marker (pop org-agenda-markers) nil)))
3678
b349f79f 3679(defun org-agenda-save-markers-for-cut-and-paste (beg end)
8223b1d2
BG
3680 "Save relative positions of markers in region.
3681This check for agenda markers in all agenda buffers currently active."
3682 (dolist (buf (buffer-list))
3683 (with-current-buffer buf
3684 (when (eq major-mode 'org-agenda-mode)
3685 (mapc (lambda (m) (org-check-and-save-marker m beg end))
3686 org-agenda-markers)))))
b349f79f 3687
54a0dee5
CD
3688;;; Entry text mode
3689
3690(defun org-agenda-entry-text-show-here ()
8bfe682a 3691 "Add some text from the entry as context to the current line."
54a0dee5 3692 (let (m txt o)
8d642074 3693 (setq m (org-get-at-bol 'org-hd-marker))
54a0dee5
CD
3694 (unless (marker-buffer m)
3695 (error "No marker points to an entry here"))
3696 (setq txt (concat "\n" (org-no-properties
3697 (org-agenda-get-some-entry-text
8d642074 3698 m org-agenda-entry-text-maxlines " > "))))
54a0dee5 3699 (when (string-match "\\S-" txt)
86fbb8ca
CD
3700 (setq o (make-overlay (point-at-bol) (point-at-eol)))
3701 (overlay-put o 'evaporate t)
3702 (overlay-put o 'org-overlay-type 'agenda-entry-content)
3703 (overlay-put o 'after-string txt))))
54a0dee5
CD
3704
3705(defun org-agenda-entry-text-show ()
3706 "Add entry context for all agenda lines."
3707 (interactive)
3708 (save-excursion
3709 (goto-char (point-max))
3710 (beginning-of-line 1)
3711 (while (not (bobp))
8d642074 3712 (when (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
3713 (org-agenda-entry-text-show-here))
3714 (beginning-of-line 0))))
3715
3716(defun org-agenda-entry-text-hide ()
3717 "Remove any shown entry context."
3718 (delq nil
3719 (mapcar (lambda (o)
86fbb8ca 3720 (if (eq (overlay-get o 'org-overlay-type)
54a0dee5 3721 'agenda-entry-content)
86fbb8ca
CD
3722 (progn (delete-overlay o) t)))
3723 (overlays-in (point-min) (point-max)))))
54a0dee5 3724
acedf35c
CD
3725(defun org-agenda-get-day-face (date)
3726 "Return the face DATE should be displayed with."
3727 (or (and (functionp org-agenda-day-face-function)
3728 (funcall org-agenda-day-face-function date))
3729 (cond ((org-agenda-todayp date)
3730 'org-agenda-date-today)
3731 ((member (calendar-day-of-week date) org-agenda-weekend-days)
3732 'org-agenda-date-weekend)
3733 (t 'org-agenda-date))))
3734
20908596
CD
3735;;; Agenda timeline
3736
3737(defvar org-agenda-only-exact-dates nil) ; dynamically scoped
3738
e66ba1df 3739(defun org-timeline (&optional dotodo)
20908596
CD
3740 "Show a time-sorted view of the entries in the current org file.
3741Only entries with a time stamp of today or later will be listed. With
3742\\[universal-argument] prefix, all unfinished TODO items will also be shown,
3743under the current date.
3744If the buffer contains an active region, only check the region for
3745dates."
3746 (interactive "P")
20908596 3747 (let* ((dopast t)
8223b1d2 3748 (org-agenda-show-log-scoped org-agenda-show-log)
afe98dfa
CD
3749 (entry (buffer-file-name (or (buffer-base-buffer (current-buffer))
3750 (current-buffer))))
20908596
CD
3751 (date (calendar-current-date))
3752 (beg (if (org-region-active-p) (region-beginning) (point-min)))
3753 (end (if (org-region-active-p) (region-end) (point-max)))
8223b1d2
BG
3754 (day-numbers (org-get-all-dates
3755 beg end 'no-ranges
3756 t org-agenda-show-log-scoped ; always include today
3757 org-timeline-show-empty-dates))
20908596
CD
3758 (org-deadline-warning-days 0)
3759 (org-agenda-only-exact-dates t)
acedf35c 3760 (today (org-today))
20908596
CD
3761 (past t)
3762 args
acedf35c 3763 s e rtn d emptyp)
20908596
CD
3764 (setq org-agenda-redo-command
3765 (list 'progn
3766 (list 'org-switch-to-buffer-other-window (current-buffer))
e66ba1df 3767 (list 'org-timeline (list 'quote dotodo))))
20908596
CD
3768 (if (not dopast)
3769 ;; Remove past dates from the list of dates.
3770 (setq day-numbers (delq nil (mapcar (lambda(x)
3771 (if (>= x today) x nil))
3772 day-numbers))))
8223b1d2
BG
3773 (org-agenda-prepare (concat "Timeline " (file-name-nondirectory entry)))
3774 (org-compile-prefix-format 'timeline)
3775 (org-set-sorting-strategy 'timeline)
3776 (if org-agenda-show-log-scoped (push :closed args))
20908596
CD
3777 (push :timestamp args)
3778 (push :deadline args)
3779 (push :scheduled args)
3780 (push :sexp args)
3781 (if dotodo (push :todo args))
8d642074
CD
3782 (insert "Timeline of file " entry "\n")
3783 (add-text-properties (point-min) (point)
3784 (list 'face 'org-agenda-structure))
3785 (org-agenda-mark-header-line (point-min))
20908596
CD
3786 (while (setq d (pop day-numbers))
3787 (if (and (listp d) (eq (car d) :omitted))
3788 (progn
3789 (setq s (point))
3790 (insert (format "\n[... %d empty days omitted]\n\n" (cdr d)))
3791 (put-text-property s (1- (point)) 'face 'org-agenda-structure))
3792 (if (listp d) (setq d (car d) emptyp t) (setq emptyp nil))
3793 (if (and (>= d today)
3794 dopast
3795 past)
3796 (progn
3797 (setq past nil)
3798 (insert (make-string 79 ?-) "\n")))
acedf35c 3799 (setq date (calendar-gregorian-from-absolute d))
20908596
CD
3800 (setq s (point))
3801 (setq rtn (and (not emptyp)
3802 (apply 'org-agenda-get-day-entries entry
3803 date args)))
3804 (if (or rtn (equal d today) org-timeline-show-empty-dates)
3805 (progn
3806 (insert
3807 (if (stringp org-agenda-format-date)
3808 (format-time-string org-agenda-format-date
3809 (org-time-from-absolute date))
3810 (funcall org-agenda-format-date date))
3811 "\n")
3812 (put-text-property s (1- (point)) 'face
acedf35c 3813 (org-agenda-get-day-face date))
20908596 3814 (put-text-property s (1- (point)) 'org-date-line t)
8d642074 3815 (put-text-property s (1- (point)) 'org-agenda-date-header t)
20908596
CD
3816 (if (equal d today)
3817 (put-text-property s (1- (point)) 'org-today t))
8223b1d2 3818 (and rtn (insert (org-agenda-finalize-entries rtn) "\n"))
20908596
CD
3819 (put-text-property s (1- (point)) 'day d)))))
3820 (goto-char (point-min))
3821 (goto-char (or (text-property-any (point-min) (point-max) 'org-today t)
3822 (point-min)))
3823 (add-text-properties (point-min) (point-max) '(org-agenda-type timeline))
8223b1d2 3824 (org-agenda-finalize)
20908596
CD
3825 (setq buffer-read-only t)))
3826
3827(defun org-get-all-dates (beg end &optional no-ranges force-today inactive empty pre-re)
3828 "Return a list of all relevant day numbers from BEG to END buffer positions.
3829If NO-RANGES is non-nil, include only the start and end dates of a range,
3830not every single day in the range. If FORCE-TODAY is non-nil, make
3831sure that TODAY is included in the list. If INACTIVE is non-nil, also
3832inactive time stamps (those in square brackets) are included.
3833When EMPTY is non-nil, also include days without any entries."
3834 (let ((re (concat
3835 (if pre-re pre-re "")
3836 (if inactive org-ts-regexp-both org-ts-regexp)))
8223b1d2 3837 dates dates1 date day day1 day2 ts1 ts2 pos)
20908596 3838 (if force-today
acedf35c 3839 (setq dates (list (org-today))))
20908596
CD
3840 (save-excursion
3841 (goto-char beg)
3842 (while (re-search-forward re end t)
3843 (setq day (time-to-days (org-time-string-to-time
e66ba1df
BG
3844 (substring (match-string 1) 0 10)
3845 (current-buffer) (match-beginning 0))))
20908596
CD
3846 (or (memq day dates) (push day dates)))
3847 (unless no-ranges
3848 (goto-char beg)
3849 (while (re-search-forward org-tr-regexp end t)
e66ba1df 3850 (setq pos (match-beginning 0))
20908596
CD
3851 (setq ts1 (substring (match-string 1) 0 10)
3852 ts2 (substring (match-string 2) 0 10)
e66ba1df
BG
3853 day1 (time-to-days (org-time-string-to-time
3854 ts1 (current-buffer) pos))
3855 day2 (time-to-days (org-time-string-to-time
3856 ts2 (current-buffer) pos)))
20908596
CD
3857 (while (< (setq day1 (1+ day1)) day2)
3858 (or (memq day1 dates) (push day1 dates)))))
3859 (setq dates (sort dates '<))
3860 (when empty
3861 (while (setq day (pop dates))
3862 (setq day2 (car dates))
3863 (push day dates1)
3864 (when (and day2 empty)
3865 (if (or (eq empty t)
3866 (and (numberp empty) (<= (- day2 day) empty)))
3867 (while (< (setq day (1+ day)) day2)
3868 (push (list day) dates1))
3869 (push (cons :omitted (- day2 day)) dates1))))
3870 (setq dates (nreverse dates1)))
3871 dates)))
3872
3873;;; Agenda Daily/Weekly
3874
c8d0cf5c 3875(defvar org-agenda-start-day nil ; dynamically scoped parameter
8223b1d2 3876 "Start day for the agenda view.
3ab2c837 3877Custom commands can set this variable in the options section.")
20908596 3878(defvar org-starting-day nil) ; local variable in the agenda buffer
e66ba1df 3879(defvar org-arg-loc nil) ; local variable
20908596 3880
ed21c5c8
CD
3881(defvar org-agenda-entry-types '(:deadline :scheduled :timestamp :sexp)
3882 "List of types searched for when creating the daily/weekly agenda.
3883This variable is a list of symbols that controls the types of
3884items that appear in the daily/weekly agenda. Allowed symbols in this
3885list are are
3886
3887 :timestamp List items containing a date stamp or date range matching
3888 the selected date. This includes sexp entries in
3889 angular brackets.
3890
3891 :sexp List entries resulting from plain diary-like sexps.
3892
3893 :deadline List deadline due on that date. When the date is today,
3894 also list any deadlines past due, or due within
3895 `org-deadline-warning-days'. `:deadline' must appear before
3896 `:scheduled' if the setting of
3897 `org-agenda-skip-scheduled-if-deadline-is-shown' is to have
3898 any effect.
3899
3900 :scheduled List all items which are scheduled for the given date.
3901 The diary for *today* also contains items which were
3902 scheduled earlier and are not yet marked DONE.
3903
3904By default, all four types are turned on.
3905
3906Never set this variable globally using `setq', because then it
3907will apply to all future agenda commands. Instead, bind it with
9b053e76 3908`let' to scope it dynamically into the agenda-constructing
ed21c5c8
CD
3909command. A good way to set it is through options in
3910`org-agenda-custom-commands'. For a more flexible (though
3911somewhat less efficient) way of determining what is included in
3912the daily/weekly agenda, see `org-agenda-skip-function'.")
3913
8223b1d2 3914(defvar org-agenda-buffer-tmp-name nil)
20908596 3915;;;###autoload
e66ba1df 3916(defun org-agenda-list (&optional arg start-day span)
20908596
CD
3917 "Produce a daily/weekly view from all files in variable `org-agenda-files'.
3918The view will be for the current day or week, but from the overview buffer
3919you will be able to go to other days/weeks.
3920
20908596 3921With a numeric prefix argument in an interactive call, the agenda will
e66ba1df 3922span ARG days. Lisp programs should instead specify SPAN to change
acedf35c 3923the number of days. SPAN defaults to `org-agenda-span'.
20908596
CD
3924
3925START-DAY defaults to TODAY, or to the most recent match for the weekday
3926given in `org-agenda-start-on-weekday'."
3927 (interactive "P")
20908596 3928 (if org-agenda-overriding-arguments
e66ba1df 3929 (setq arg (car org-agenda-overriding-arguments)
20908596 3930 start-day (nth 1 org-agenda-overriding-arguments)
acedf35c 3931 span (nth 2 org-agenda-overriding-arguments)))
8223b1d2
BG
3932 (if (and (integerp arg) (> arg 0))
3933 (setq span arg arg nil))
3934 (catch 'exit
3935 (setq org-agenda-buffer-name
3936 (or org-agenda-buffer-tmp-name
3937 (if org-agenda-sticky
3938 (cond ((and org-keys (stringp org-match))
3939 (format "*Org Agenda(%s:%s)*" org-keys org-match))
3940 (org-keys
3941 (format "*Org Agenda(%s)*" org-keys))
3942 (t "*Org Agenda(a)*")))
3943 org-agenda-buffer-name))
3944 (org-agenda-prepare "Day/Week")
3945 (setq start-day (or start-day org-agenda-start-day))
3946 (if (stringp start-day)
3947 ;; Convert to an absolute day number
3948 (setq start-day (time-to-days (org-read-date nil t start-day))))
3949 (org-compile-prefix-format 'agenda)
3950 (org-set-sorting-strategy 'agenda)
3951 (let* ((span (org-agenda-ndays-to-span
3952 (or span org-agenda-ndays org-agenda-span)))
3953 (today (org-today))
3954 (sd (or start-day today))
3955 (ndays (org-agenda-span-to-ndays span sd))
3956 (org-agenda-start-on-weekday
3957 (if (eq ndays 7)
3958 org-agenda-start-on-weekday))
3959 (thefiles (org-agenda-files nil 'ifmode))
3960 (files thefiles)
3961 (start (if (or (null org-agenda-start-on-weekday)
3962 (< ndays 7))
3963 sd
3964 (let* ((nt (calendar-day-of-week
3965 (calendar-gregorian-from-absolute sd)))
3966 (n1 org-agenda-start-on-weekday)
3967 (d (- nt n1)))
3968 (- sd (+ (if (< d 0) 7 0) d)))))
3969 (day-numbers (list start))
3970 (day-cnt 0)
3971 (inhibit-redisplay (not debug-on-error))
3972 (org-agenda-show-log-scoped org-agenda-show-log)
3973 s e rtn rtnall file date d start-pos end-pos todayp
3974 clocktable-start clocktable-end filter)
3975 (setq org-agenda-redo-command
3976 (list 'org-agenda-list (list 'quote arg) start-day (list 'quote span)))
3977 (dotimes (n (1- ndays))
3978 (push (1+ (car day-numbers)) day-numbers))
3979 (setq day-numbers (nreverse day-numbers))
3980 (setq clocktable-start (car day-numbers)
3981 clocktable-end (1+ (or (org-last day-numbers) 0)))
3982 (org-set-local 'org-starting-day (car day-numbers))
3983 (org-set-local 'org-arg-loc arg)
3984 (org-set-local 'org-agenda-current-span (org-agenda-ndays-to-span span))
3985 (unless org-agenda-compact-blocks
3986 (let* ((d1 (car day-numbers))
3987 (d2 (org-last day-numbers))
3988 (w1 (org-days-to-iso-week d1))
3989 (w2 (org-days-to-iso-week d2)))
3990 (setq s (point))
3991 (if org-agenda-overriding-header
3992 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
3993 nil 'face 'org-agenda-structure) "\n")
3994 (insert (org-agenda-span-name span)
3995 "-agenda"
3996 (if (< (- d2 d1) 350)
3997 (if (= w1 w2)
3998 (format " (W%02d)" w1)
3999 (format " (W%02d-W%02d)" w1 w2))
4000 "")
4001 ":\n")))
4002 (add-text-properties s (1- (point)) (list 'face 'org-agenda-structure
4003 'org-date-line t))
4004 (org-agenda-mark-header-line s))
4005 (while (setq d (pop day-numbers))
4006 (setq date (calendar-gregorian-from-absolute d)
4007 s (point))
4008 (if (or (setq todayp (= d today))
4009 (and (not start-pos) (= d sd)))
4010 (setq start-pos (point))
4011 (if (and start-pos (not end-pos))
4012 (setq end-pos (point))))
4013 (setq files thefiles
4014 rtnall nil)
4015 (while (setq file (pop files))
4016 (catch 'nextfile
4017 (org-check-agenda-file file)
4018 (let ((org-agenda-entry-types org-agenda-entry-types))
4019 (unless org-agenda-include-deadlines
4020 (setq org-agenda-entry-types
4021 (delq :deadline org-agenda-entry-types)))
4022 (cond
4023 ((memq org-agenda-show-log-scoped '(only clockcheck))
4024 (setq rtn (org-agenda-get-day-entries
4025 file date :closed)))
4026 (org-agenda-show-log-scoped
4027 (setq rtn (apply 'org-agenda-get-day-entries
4028 file date
4029 (append '(:closed) org-agenda-entry-types))))
4030 (t
4031 (setq rtn (apply 'org-agenda-get-day-entries
4032 file date
4033 org-agenda-entry-types)))))
4034 (setq rtnall (append rtnall rtn)))) ;; all entries
4035 (if org-agenda-include-diary
4036 (let ((org-agenda-search-headline-for-time t))
4037 (require 'diary-lib)
4038 (setq rtn (org-get-entries-from-diary date))
4039 (setq rtnall (append rtnall rtn))))
4040 (if (or rtnall org-agenda-show-all-dates)
4041 (progn
4042 (setq day-cnt (1+ day-cnt))
4043 (insert
4044 (if (stringp org-agenda-format-date)
4045 (format-time-string org-agenda-format-date
4046 (org-time-from-absolute date))
4047 (funcall org-agenda-format-date date))
4048 "\n")
4049 (put-text-property s (1- (point)) 'face
4050 (org-agenda-get-day-face date))
4051 (put-text-property s (1- (point)) 'org-date-line t)
4052 (put-text-property s (1- (point)) 'org-agenda-date-header t)
4053 (put-text-property s (1- (point)) 'org-day-cnt day-cnt)
4054 (when todayp
4055 (put-text-property s (1- (point)) 'org-today t))
4056 (setq rtnall
4057 (org-agenda-add-time-grid-maybe rtnall ndays todayp))
4058 (if rtnall (insert ;; all entries
4059 (org-agenda-finalize-entries rtnall)
4060 "\n"))
4061 (put-text-property s (1- (point)) 'day d)
4062 (put-text-property s (1- (point)) 'org-day-cnt day-cnt))))
4063 (when (and org-agenda-clockreport-mode clocktable-start)
4064 (let ((org-agenda-files (org-agenda-files nil 'ifmode))
4065 ;; the above line is to ensure the restricted range!
4066 (p (copy-sequence org-agenda-clockreport-parameter-plist))
4067 tbl)
4068 (setq p (org-plist-delete p :block))
4069 (setq p (plist-put p :tstart clocktable-start))
4070 (setq p (plist-put p :tend clocktable-end))
4071 (setq p (plist-put p :scope 'agenda))
4072 (when (and (eq org-agenda-clockreport-mode 'with-filter)
4073 (setq filter (or org-agenda-tag-filter-while-redo
4074 (get 'org-agenda-tag-filter :preset-filter))))
4075 (setq p (plist-put p :tags (mapconcat (lambda (x)
4076 (if (string-match "[<>=]" x)
4077 ""
4078 x))
4079 filter ""))))
bdebdb64 4080 (setq tbl (apply 'org-clock-get-clocktable p))
8223b1d2
BG
4081 (insert tbl)))
4082 (goto-char (point-min))
4083 (or org-agenda-multi (org-agenda-fit-window-to-buffer))
4084 (unless (and (pos-visible-in-window-p (point-min))
4085 (pos-visible-in-window-p (point-max)))
4086 (goto-char (1- (point-max)))
4087 (recenter -1)
4088 (if (not (pos-visible-in-window-p (or start-pos 1)))
4089 (progn
4090 (goto-char (or start-pos 1))
4091 (recenter 1))))
4092 (goto-char (or start-pos 1))
4093 (add-text-properties (point-min) (point-max)
4094 `(org-agenda-type agenda
4095 org-last-args (,arg ,start-day ,span)
4096 org-redo-cmd ,org-agenda-redo-command
735135f9 4097 org-series-cmd ,org-cmd))
8223b1d2
BG
4098 (if (eq org-agenda-show-log-scoped 'clockcheck)
4099 (org-agenda-show-clocking-issues))
4100 (org-agenda-finalize)
4101 (setq buffer-read-only t)
4102 (message ""))))
20908596
CD
4103
4104(defun org-agenda-ndays-to-span (n)
acedf35c
CD
4105 "Return a span symbol for a span of N days, or N if none matches."
4106 (cond ((symbolp n) n)
4107 ((= n 1) 'day)
4108 ((= n 7) 'week)
4109 (t n)))
4110
8223b1d2
BG
4111(defun org-agenda-span-to-ndays (span &optional start-day)
4112 "Return ndays from SPAN, possibly starting at START-DAY."
acedf35c
CD
4113 (cond ((numberp span) span)
4114 ((eq span 'day) 1)
4115 ((eq span 'week) 7)
4116 ((eq span 'month)
4117 (let ((date (calendar-gregorian-from-absolute start-day)))
4118 (calendar-last-day-of-month (car date) (caddr date))))
4119 ((eq span 'year)
4120 (let ((date (calendar-gregorian-from-absolute start-day)))
4121 (if (calendar-leap-year-p (caddr date)) 366 365)))))
4122
4123(defun org-agenda-span-name (span)
4124 "Return a SPAN name."
4125 (if (null span)
4126 ""
4127 (if (symbolp span)
4128 (capitalize (symbol-name span))
4129 (format "%d days" span))))
20908596
CD
4130
4131;;; Agenda word search
4132
4133(defvar org-agenda-search-history nil)
20908596
CD
4134
4135(defvar org-search-syntax-table nil
e66ba1df
BG
4136 "Special syntax table for org-mode search.
4137In this table, we have single quotes not as word constituents, to
4138that when \"+Ameli\" is searched as a work, it will also match \"Ameli's\"")
20908596 4139
8223b1d2 4140(defvar org-mode-syntax-table) ; From org.el
20908596
CD
4141(defun org-search-syntax-table ()
4142 (unless org-search-syntax-table
4143 (setq org-search-syntax-table (copy-syntax-table org-mode-syntax-table))
4144 (modify-syntax-entry ?' "." org-search-syntax-table)
4145 (modify-syntax-entry ?` "." org-search-syntax-table))
4146 org-search-syntax-table)
4147
ed21c5c8
CD
4148(defvar org-agenda-last-search-view-search-was-boolean nil)
4149
20908596
CD
4150;;;###autoload
4151(defun org-search-view (&optional todo-only string edit-at)
ed21c5c8 4152 "Show all entries that contain a phrase or words or regular expressions.
20908596
CD
4153
4154With optional prefix argument TODO-ONLY, only consider entries that are
4155TODO entries. The argument STRING can be used to pass a default search
4156string into this function. If EDIT-AT is non-nil, it means that the
4157user should get a chance to edit this string, with cursor at position
4158EDIT-AT.
4159
ed21c5c8
CD
4160The search string can be viewed either as a phrase that should be found as
4161is, or it can be broken into a number of snippets, each of which must match
4162in a Boolean way to select an entry. The default depends on the variable
4163`org-agenda-search-view-always-boolean'.
4164Even if this is turned off (the default) you can always switch to
86fbb8ca 4165Boolean search dynamically by preceding the first word with \"+\" or \"-\".
ed21c5c8
CD
4166
4167The default is a direct search of the whole phrase, where each space in
4168the search string can expand to an arbitrary amount of whitespace,
4169including newlines.
4170
4171If using a Boolean search, the search string is split on whitespace and
4172each snippet is searched separately, with logical AND to select an entry.
4173Words prefixed with a minus must *not* occur in the entry. Words without
4174a prefix or prefixed with a plus must occur in the entry. Matching is
4175case-insensitive. Words are enclosed by word delimiters (i.e. they must
4176match whole words, not parts of a word) if
4177`org-agenda-search-view-force-full-words' is set (default is nil).
4178
4179Boolean search snippets enclosed by curly braces are interpreted as
86fbb8ca 4180regular expressions that must or (when preceded with \"-\") must not
ed21c5c8 4181match in the entry. Snippets enclosed into double quotes will be taken
86fbb8ca 4182as a whole, to include whitespace.
ed21c5c8
CD
4183
4184- If the search string starts with an asterisk, search only in headlines.
4185- If (possibly after the leading star) the search string starts with an
4186 exclamation mark, this also means to look at TODO entries only, an effect
4187 that can also be achieved with a prefix argument.
4188- If (possibly after star and exclamation mark) the search string starts
4189 with a colon, this will mean that the (non-regexp) snippets of the
4190 Boolean search must match as full words.
20908596
CD
4191
4192This command searches the agenda files, and in addition the files listed
4193in `org-agenda-text-search-extra-files'."
4194 (interactive "P")
8223b1d2
BG
4195 (if org-agenda-overriding-arguments
4196 (setq todo-only (car org-agenda-overriding-arguments)
4197 string (nth 1 org-agenda-overriding-arguments)
4198 edit-at (nth 2 org-agenda-overriding-arguments)))
20908596 4199 (let* ((props (list 'face nil
c8d0cf5c 4200 'done-face 'org-agenda-done
20908596
CD
4201 'org-not-done-regexp org-not-done-regexp
4202 'org-todo-regexp org-todo-regexp
b349f79f 4203 'org-complex-heading-regexp org-complex-heading-regexp
20908596 4204 'mouse-face 'highlight
20908596 4205 'help-echo (format "mouse-2 or RET jump to location")))
ed21c5c8 4206 (full-words org-agenda-search-view-force-full-words)
86fbb8ca 4207 (org-agenda-text-search-extra-files org-agenda-text-search-extra-files)
a89c8ef0 4208 regexp rtn rtnall files file pos inherited-tags
8223b1d2 4209 marker category category-pos tags c neg re boolean
20908596
CD
4210 ee txt beg end words regexps+ regexps- hdl-only buffer beg1 str)
4211 (unless (and (not edit-at)
4212 (stringp string)
4213 (string-match "\\S-" string))
ed21c5c8
CD
4214 (setq string (read-string
4215 (if org-agenda-search-view-always-boolean
4216 "[+-]Word/{Regexp} ...: "
8223b1d2 4217 "Phrase or [+-]Word/{Regexp} ...: ")
ed21c5c8
CD
4218 (cond
4219 ((integerp edit-at) (cons string edit-at))
4220 (edit-at string))
4221 'org-agenda-search-history)))
8223b1d2
BG
4222 (catch 'exit
4223 (if org-agenda-sticky
4224 (setq org-agenda-buffer-name
4225 (if (stringp string)
4226 (format "*Org Agenda(%s:%s)*"
4227 (or org-keys (or (and todo-only "S") "s")) string)
4228 (format "*Org Agenda(%s)*" (or (and todo-only "S") "s")))))
4229 (org-agenda-prepare "SEARCH")
4230 (org-compile-prefix-format 'search)
4231 (org-set-sorting-strategy 'search)
4232 (setq org-agenda-redo-command
4233 (list 'org-search-view (if todo-only t nil)
4234 (list 'if 'current-prefix-arg nil string)))
4235 (setq org-agenda-query-string string)
4236 (if (equal (string-to-char string) ?*)
4237 (setq hdl-only t
4238 words (substring string 1))
4239 (setq words string))
4240 (when (equal (string-to-char words) ?!)
4241 (setq todo-only t
4242 words (substring words 1)))
4243 (when (equal (string-to-char words) ?:)
4244 (setq full-words t
4245 words (substring words 1)))
4246 (if (or org-agenda-search-view-always-boolean
4247 (member (string-to-char words) '(?- ?+ ?\{)))
4248 (setq boolean t))
4249 (setq words (org-split-string words))
4250 (let (www w)
ed21c5c8 4251 (while (setq w (pop words))
8223b1d2
BG
4252 (while (and (string-match "\\\\\\'" w) words)
4253 (setq w (concat (substring w 0 -1) " " (pop words))))
4254 (push w www))
4255 (setq words (nreverse www) www nil)
4256 (while (setq w (pop words))
4257 (when (and (string-match "\\`[-+]?{" w)
4258 (not (string-match "}\\'" w)))
4259 (while (and words (not (string-match "}\\'" (car words))))
4260 (setq w (concat w " " (pop words))))
4261 (setq w (concat w " " (pop words))))
4262 (push w www))
4263 (setq words (nreverse www)))
4264 (setq org-agenda-last-search-view-search-was-boolean boolean)
4265 (when boolean
4266 (let (wds w)
4267 (while (setq w (pop words))
4268 (if (or (equal (substring w 0 1) "\"")
4269 (and (> (length w) 1)
4270 (member (substring w 0 1) '("+" "-"))
4271 (equal (substring w 1 2) "\"")))
4272 (while (and words (not (equal (substring w -1) "\"")))
4273 (setq w (concat w " " (pop words)))))
4274 (and (string-match "\\`\\([-+]?\\)\"" w)
4275 (setq w (replace-match "\\1" nil nil w)))
4276 (and (equal (substring w -1) "\"") (setq w (substring w 0 -1)))
4277 (push w wds))
4278 (setq words (nreverse wds))))
4279 (if boolean
4280 (mapc (lambda (w)
4281 (setq c (string-to-char w))
4282 (if (equal c ?-)
4283 (setq neg t w (substring w 1))
4284 (if (equal c ?+)
4285 (setq neg nil w (substring w 1))
4286 (setq neg nil)))
4287 (if (string-match "\\`{.*}\\'" w)
4288 (setq re (substring w 1 -1))
4289 (if full-words
4290 (setq re (concat "\\<" (regexp-quote (downcase w)) "\\>"))
4291 (setq re (regexp-quote (downcase w)))))
4292 (if neg (push re regexps-) (push re regexps+)))
4293 words)
4294 (push (mapconcat (lambda (w) (regexp-quote w)) words "\\s-+")
4295 regexps+))
4296 (setq regexps+ (sort regexps+ (lambda (a b) (> (length a) (length b)))))
4297 (if (not regexps+)
4298 (setq regexp org-outline-regexp-bol)
4299 (setq regexp (pop regexps+))
4300 (if hdl-only (setq regexp (concat org-outline-regexp-bol ".*?"
4301 regexp))))
4302 (setq files (org-agenda-files nil 'ifmode))
4303 (when (eq (car org-agenda-text-search-extra-files) 'agenda-archives)
4304 (pop org-agenda-text-search-extra-files)
4305 (setq files (org-add-archive-files files)))
4306 (setq files (append files org-agenda-text-search-extra-files)
4307 rtnall nil)
4308 (while (setq file (pop files))
4309 (setq ee nil)
4310 (catch 'nextfile
4311 (org-check-agenda-file file)
4312 (setq buffer (if (file-exists-p file)
4313 (org-get-agenda-file-buffer file)
4314 (error "No such file %s" file)))
4315 (if (not buffer)
4316 ;; If file does not exist, make sure an error message is sent
4317 (setq rtn (list (format "ORG-AGENDA-ERROR: No such org-file %s"
4318 file))))
4319 (with-current-buffer buffer
4320 (with-syntax-table (org-search-syntax-table)
4321 (unless (derived-mode-p 'org-mode)
4322 (error "Agenda file %s is not in `org-mode'" file))
4323 (let ((case-fold-search t))
4324 (save-excursion
4325 (save-restriction
4326 (if org-agenda-restrict
4327 (narrow-to-region org-agenda-restrict-begin
4328 org-agenda-restrict-end)
4329 (widen))
4330 (goto-char (point-min))
4331 (unless (or (org-at-heading-p)
4332 (outline-next-heading))
4333 (throw 'nextfile t))
4334 (goto-char (max (point-min) (1- (point))))
4335 (while (re-search-forward regexp nil t)
4336 (org-back-to-heading t)
4337 (skip-chars-forward "* ")
4338 (setq beg (point-at-bol)
4339 beg1 (point)
4340 end (progn (outline-next-heading) (point)))
4341 (catch :skip
4342 (goto-char beg)
4343 (org-agenda-skip)
4344 (setq str (buffer-substring-no-properties
4345 (point-at-bol)
4346 (if hdl-only (point-at-eol) end)))
4347 (mapc (lambda (wr) (when (string-match wr str)
4348 (goto-char (1- end))
4349 (throw :skip t)))
4350 regexps-)
4351 (mapc (lambda (wr) (unless (string-match wr str)
4352 (goto-char (1- end))
4353 (throw :skip t)))
4354 (if todo-only
4355 (cons (concat "^\*+[ \t]+" org-not-done-regexp)
4356 regexps+)
4357 regexps+))
4358 (goto-char beg)
4359 (setq marker (org-agenda-new-marker (point))
4360 category (org-get-category)
4361 category-pos (get-text-property (point) 'org-category-position)
a89c8ef0
BG
4362 inherited-tags
4363 (or (eq org-agenda-show-inherited-tags 'always)
d3517077
BG
4364 (and (listp org-agenda-show-inherited-tags)
4365 (memq 'todo org-agenda-show-inherited-tags))
a89c8ef0
BG
4366 (and (eq org-agenda-show-inherited-tags t)
4367 (or (eq org-agenda-use-tag-inheritance t)
4368 (memq 'todo org-agenda-use-tag-inheritance))))
4369 tags (org-get-tags-at nil (not inherited-tags))
8223b1d2
BG
4370 txt (org-agenda-format-item
4371 ""
4372 (buffer-substring-no-properties
4373 beg1 (point-at-eol))
4374 category tags t))
4375 (org-add-props txt props
4376 'org-marker marker 'org-hd-marker marker
4377 'org-todo-regexp org-todo-regexp
4378 'org-complex-heading-regexp org-complex-heading-regexp
4379 'priority 1000 'org-category category
4380 'org-category-position category-pos
4381 'type "search")
4382 (push txt ee)
4383 (goto-char (1- end))))))))))
4384 (setq rtn (nreverse ee))
4385 (setq rtnall (append rtnall rtn)))
4386 (if org-agenda-overriding-header
4387 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
4388 nil 'face 'org-agenda-structure) "\n")
4389 (insert "Search words: ")
4390 (add-text-properties (point-min) (1- (point))
4391 (list 'face 'org-agenda-structure))
4392 (setq pos (point))
4393 (insert string "\n")
4394 (add-text-properties pos (1- (point)) (list 'face 'org-warning))
4395 (setq pos (point))
4396 (unless org-agenda-multi
4397 (insert "Press `[', `]' to add/sub word, `{', `}' to add/sub regexp, `C-u r' to edit\n")
4398 (add-text-properties pos (1- (point))
4399 (list 'face 'org-agenda-structure))))
4400 (org-agenda-mark-header-line (point-min))
4401 (when rtnall
4402 (insert (org-agenda-finalize-entries rtnall) "\n"))
4403 (goto-char (point-min))
4404 (or org-agenda-multi (org-agenda-fit-window-to-buffer))
4405 (add-text-properties (point-min) (point-max)
4406 `(org-agenda-type search
4407 org-last-args (,todo-only ,string ,edit-at)
4408 org-redo-cmd ,org-agenda-redo-command
735135f9 4409 org-series-cmd ,org-cmd))
8223b1d2
BG
4410 (org-agenda-finalize)
4411 (setq buffer-read-only t))))
20908596
CD
4412
4413;;; Agenda TODO list
4414
4415(defvar org-select-this-todo-keyword nil)
4416(defvar org-last-arg nil)
4417
4418;;;###autoload
8223b1d2 4419(defun org-todo-list (&optional arg)
86fbb8ca 4420 "Show all (not done) TODO entries from all agenda file in a single list.
20908596
CD
4421The prefix arg can be used to select a specific TODO keyword and limit
4422the list to these. When using \\[universal-argument], you will be prompted
4423for a keyword. A numeric prefix directly selects the Nth keyword in
4424`org-todo-keywords-1'."
4425 (interactive "P")
8223b1d2
BG
4426 (if org-agenda-overriding-arguments
4427 (setq arg org-agenda-overriding-arguments))
ed21c5c8 4428 (if (and (stringp arg) (not (string-match "\\S-" arg))) (setq arg nil))
acedf35c 4429 (let* ((today (org-today))
20908596
CD
4430 (date (calendar-gregorian-from-absolute today))
4431 (kwds org-todo-keywords-for-agenda)
4432 (completion-ignore-case t)
4433 (org-select-this-todo-keyword
4434 (if (stringp arg) arg
4435 (and arg (integerp arg) (> arg 0)
4436 (nth (1- arg) kwds))))
4437 rtn rtnall files file pos)
4438 (when (equal arg '(4))
4439 (setq org-select-this-todo-keyword
54a0dee5 4440 (org-icompleting-read "Keyword (or KWD1|K2D2|...): "
8223b1d2 4441 (mapcar 'list kwds) nil nil)))
20908596 4442 (and (equal 0 arg) (setq org-select-this-todo-keyword nil))
8223b1d2
BG
4443 (catch 'exit
4444 (if org-agenda-sticky
4445 (setq org-agenda-buffer-name
4446 (if (stringp org-select-this-todo-keyword)
4447 (format "*Org Agenda(%s:%s)*" (or org-keys "t")
4448 org-select-this-todo-keyword)
4449 (format "*Org Agenda(%s)*" (or org-keys "t")))))
4450 (org-agenda-prepare "TODO")
4451 (org-compile-prefix-format 'todo)
4452 (org-set-sorting-strategy 'todo)
4453 (setq org-agenda-redo-command
4454 `(org-todo-list (or (and (numberp current-prefix-arg)
4455 current-prefix-arg)
4456 ,org-select-this-todo-keyword
4457 current-prefix-arg ,arg)))
4458 (setq files (org-agenda-files nil 'ifmode)
4459 rtnall nil)
4460 (while (setq file (pop files))
4461 (catch 'nextfile
4462 (org-check-agenda-file file)
4463 (setq rtn (org-agenda-get-day-entries file date :todo))
4464 (setq rtnall (append rtnall rtn))))
4465 (if org-agenda-overriding-header
4466 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
4467 nil 'face 'org-agenda-structure) "\n")
4468 (insert "Global list of TODO items of type: ")
4469 (add-text-properties (point-min) (1- (point))
4470 (list 'face 'org-agenda-structure
4471 'short-heading
4472 (concat "ToDo: "
4473 (or org-select-this-todo-keyword "ALL"))))
4474 (org-agenda-mark-header-line (point-min))
4475 (setq pos (point))
4476 (insert (or org-select-this-todo-keyword "ALL") "\n")
4477 (add-text-properties pos (1- (point)) (list 'face 'org-warning))
4478 (setq pos (point))
4479 (unless org-agenda-multi
4480 (insert "Available with `N r': (0)[ALL]")
4481 (let ((n 0) s)
4482 (mapc (lambda (x)
4483 (setq s (format "(%d)%s" (setq n (1+ n)) x))
4484 (if (> (+ (current-column) (string-width s) 1) (frame-width))
4485 (insert "\n "))
4486 (insert " " s))
4487 kwds))
4488 (insert "\n"))
4489 (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure)))
8d642074 4490 (org-agenda-mark-header-line (point-min))
8223b1d2
BG
4491 (when rtnall
4492 (insert (org-agenda-finalize-entries rtnall) "\n"))
4493 (goto-char (point-min))
4494 (or org-agenda-multi (org-agenda-fit-window-to-buffer))
4495 (add-text-properties (point-min) (point-max)
4496 `(org-agenda-type todo
4497 org-last-args ,arg
4498 org-redo-cmd ,org-agenda-redo-command
735135f9 4499 org-series-cmd ,org-cmd))
8223b1d2
BG
4500 (org-agenda-finalize)
4501 (setq buffer-read-only t))))
20908596
CD
4502
4503;;; Agenda tags match
4504
4505;;;###autoload
4506(defun org-tags-view (&optional todo-only match)
4507 "Show all headlines for all `org-agenda-files' matching a TAGS criterion.
4508The prefix arg TODO-ONLY limits the search to TODO entries."
4509 (interactive "P")
8223b1d2
BG
4510 (if org-agenda-overriding-arguments
4511 (setq todo-only (car org-agenda-overriding-arguments)
4512 match (nth 1 org-agenda-overriding-arguments)))
20908596 4513 (let* ((org-tags-match-list-sublevels
c8d0cf5c 4514 org-tags-match-list-sublevels)
20908596
CD
4515 (completion-ignore-case t)
4516 rtn rtnall files file pos matcher
4517 buffer)
ed21c5c8
CD
4518 (when (and (stringp match) (not (string-match "\\S-" match)))
4519 (setq match nil))
20908596
CD
4520 (setq matcher (org-make-tags-matcher match)
4521 match (car matcher) matcher (cdr matcher))
8223b1d2
BG
4522 (catch 'exit
4523 (if org-agenda-sticky
4524 (setq org-agenda-buffer-name
4525 (if (stringp match)
4526 (format "*Org Agenda(%s:%s)*"
4527 (or org-keys (or (and todo-only "M") "m")) match)
4528 (format "*Org Agenda(%s)*" (or (and todo-only "M") "m")))))
4529 (org-agenda-prepare (concat "TAGS " match))
4530 (org-compile-prefix-format 'tags)
4531 (org-set-sorting-strategy 'tags)
4532 (setq org-agenda-query-string match)
4533 (setq org-agenda-redo-command
4534 (list 'org-tags-view `(quote ,todo-only)
4535 (list 'if 'current-prefix-arg nil `(quote ,org-agenda-query-string))))
4536 (setq files (org-agenda-files nil 'ifmode)
4537 rtnall nil)
4538 (while (setq file (pop files))
4539 (catch 'nextfile
4540 (org-check-agenda-file file)
4541 (setq buffer (if (file-exists-p file)
4542 (org-get-agenda-file-buffer file)
4543 (error "No such file %s" file)))
4544 (if (not buffer)
4545 ;; If file does not exist, error message to agenda
4546 (setq rtn (list
4547 (format "ORG-AGENDA-ERROR: No such org-file %s" file))
4548 rtnall (append rtnall rtn))
4549 (with-current-buffer buffer
4550 (unless (derived-mode-p 'org-mode)
4551 (error "Agenda file %s is not in `org-mode'" file))
4552 (save-excursion
4553 (save-restriction
4554 (if org-agenda-restrict
4555 (narrow-to-region org-agenda-restrict-begin
4556 org-agenda-restrict-end)
4557 (widen))
4558 (setq rtn (org-scan-tags 'agenda matcher todo-only))
4559 (setq rtnall (append rtnall rtn))))))))
4560 (if org-agenda-overriding-header
4561 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
4562 nil 'face 'org-agenda-structure) "\n")
4563 (insert "Headlines with TAGS match: ")
4564 (add-text-properties (point-min) (1- (point))
4565 (list 'face 'org-agenda-structure
4566 'short-heading
4567 (concat "Match: " match)))
4568 (setq pos (point))
4569 (insert match "\n")
4570 (add-text-properties pos (1- (point)) (list 'face 'org-warning))
4571 (setq pos (point))
4572 (unless org-agenda-multi
4573 (insert "Press `C-u r' to search again with new search string\n"))
4574 (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure)))
4575 (org-agenda-mark-header-line (point-min))
4576 (when rtnall
4577 (insert (org-agenda-finalize-entries rtnall) "\n"))
4578 (goto-char (point-min))
4579 (or org-agenda-multi (org-agenda-fit-window-to-buffer))
4580 (add-text-properties (point-min) (point-max)
4581 `(org-agenda-type tags
4582 org-last-args (,todo-only ,match)
4583 org-redo-cmd ,org-agenda-redo-command
735135f9 4584 org-series-cmd ,org-cmd))
8223b1d2
BG
4585 (org-agenda-finalize)
4586 (setq buffer-read-only t))))
20908596
CD
4587
4588;;; Agenda Finding stuck projects
4589
4590(defvar org-agenda-skip-regexp nil
4591 "Regular expression used in skipping subtrees for the agenda.
4592This is basically a temporary global variable that can be set and then
4593used by user-defined selections using `org-agenda-skip-function'.")
4594
4595(defvar org-agenda-overriding-header nil
3ab2c837 4596 "When set during agenda, todo and tags searches it replaces the header.
c8d0cf5c
CD
4597This variable should not be set directly, but custom commands can bind it
4598in the options section.")
4599
4600(defun org-agenda-skip-entry-when-regexp-matches ()
86fbb8ca 4601 "Check if the current entry contains match for `org-agenda-skip-regexp'.
c8d0cf5c
CD
4602If yes, it returns the end position of this entry, causing agenda commands
4603to skip the entry but continuing the search in the subtree. This is a
4604function that can be put into `org-agenda-skip-function' for the duration
4605of a command."
4606 (let ((end (save-excursion (org-end-of-subtree t)))
4607 skip)
4608 (save-excursion
4609 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
4610 (and skip end)))
20908596
CD
4611
4612(defun org-agenda-skip-subtree-when-regexp-matches ()
86fbb8ca 4613 "Check if the current subtree contains match for `org-agenda-skip-regexp'.
20908596
CD
4614If yes, it returns the end position of this tree, causing agenda commands
4615to skip this subtree. This is a function that can be put into
4616`org-agenda-skip-function' for the duration of a command."
4617 (let ((end (save-excursion (org-end-of-subtree t)))
4618 skip)
4619 (save-excursion
4620 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
4621 (and skip end)))
4622
c8d0cf5c 4623(defun org-agenda-skip-entry-when-regexp-matches-in-subtree ()
86fbb8ca 4624 "Check if the current subtree contains match for `org-agenda-skip-regexp'.
c8d0cf5c
CD
4625If yes, it returns the end position of the current entry (NOT the tree),
4626causing agenda commands to skip the entry but continuing the search in
4627the subtree. This is a function that can be put into
4628`org-agenda-skip-function' for the duration of a command. An important
4629use of this function is for the stuck project list."
4630 (let ((end (save-excursion (org-end-of-subtree t)))
4631 (entry-end (save-excursion (outline-next-heading) (1- (point))))
4632 skip)
4633 (save-excursion
4634 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
4635 (and skip entry-end)))
4636
20908596
CD
4637(defun org-agenda-skip-entry-if (&rest conditions)
4638 "Skip entry if any of CONDITIONS is true.
4639See `org-agenda-skip-if' for details."
4640 (org-agenda-skip-if nil conditions))
4641
4642(defun org-agenda-skip-subtree-if (&rest conditions)
4643 "Skip entry if any of CONDITIONS is true.
4644See `org-agenda-skip-if' for details."
4645 (org-agenda-skip-if t conditions))
4646
4647(defun org-agenda-skip-if (subtree conditions)
4648 "Checks current entity for CONDITIONS.
4649If SUBTREE is non-nil, the entire subtree is checked. Otherwise, only
153ae947 4650the entry (i.e. the text before the next heading) is checked.
20908596
CD
4651
4652CONDITIONS is a list of symbols, boolean OR is used to combine the results
4653from different tests. Valid conditions are:
4654
4655scheduled Check if there is a scheduled cookie
4656notscheduled Check if there is no scheduled cookie
4657deadline Check if there is a deadline
4658notdeadline Check if there is no deadline
c8d0cf5c
CD
4659timestamp Check if there is a timestamp (also deadline or scheduled)
4660nottimestamp Check if there is no timestamp (also deadline or scheduled)
20908596
CD
4661regexp Check if regexp matches
4662notregexp Check if regexp does not match.
ed21c5c8
CD
4663todo Check if TODO keyword matches
4664nottodo Check if TODO keyword does not match
20908596
CD
4665
4666The regexp is taken from the conditions list, it must come right after
4667the `regexp' or `notregexp' element.
4668
ed21c5c8
CD
4669`todo' and `nottodo' accept as an argument a list of todo
4670keywords, which may include \"*\" to match any todo keyword.
4671
4672 (org-agenda-skip-entry-if 'todo '(\"TODO\" \"WAITING\"))
4673
4674would skip all entries with \"TODO\" or \"WAITING\" keywords.
4675
153ae947 4676Instead of a list, a keyword class may be given. For example:
ed21c5c8
CD
4677
4678 (org-agenda-skip-entry-if 'nottodo 'done)
4679
4680would skip entries that haven't been marked with any of \"DONE\"
153ae947 4681keywords. Possible classes are: `todo', `done', `any'.
ed21c5c8 4682
20908596
CD
4683If any of these conditions is met, this function returns the end point of
4684the entity, causing the search to continue from there. This is a function
4685that can be put into `org-agenda-skip-function' for the duration of a command."
4686 (let (beg end m)
4687 (org-back-to-heading t)
4688 (setq beg (point)
4689 end (if subtree
4690 (progn (org-end-of-subtree t) (point))
4691 (progn (outline-next-heading) (1- (point)))))
4692 (goto-char beg)
4693 (and
4694 (or
4695 (and (memq 'scheduled conditions)
4696 (re-search-forward org-scheduled-time-regexp end t))
4697 (and (memq 'notscheduled conditions)
4698 (not (re-search-forward org-scheduled-time-regexp end t)))
4699 (and (memq 'deadline conditions)
4700 (re-search-forward org-deadline-time-regexp end t))
4701 (and (memq 'notdeadline conditions)
4702 (not (re-search-forward org-deadline-time-regexp end t)))
c8d0cf5c
CD
4703 (and (memq 'timestamp conditions)
4704 (re-search-forward org-ts-regexp end t))
4705 (and (memq 'nottimestamp conditions)
4706 (not (re-search-forward org-ts-regexp end t)))
20908596
CD
4707 (and (setq m (memq 'regexp conditions))
4708 (stringp (nth 1 m))
4709 (re-search-forward (nth 1 m) end t))
4710 (and (setq m (memq 'notregexp conditions))
4711 (stringp (nth 1 m))
ed21c5c8
CD
4712 (not (re-search-forward (nth 1 m) end t)))
4713 (and (or
153ae947 4714 (setq m (memq 'nottodo conditions))
8223b1d2
BG
4715 (setq m (memq 'todo-unblocked conditions))
4716 (setq m (memq 'nottodo-unblocked conditions))
153ae947 4717 (setq m (memq 'todo conditions)))
ed21c5c8 4718 (org-agenda-skip-if-todo m end)))
20908596
CD
4719 end)))
4720
ed21c5c8
CD
4721(defun org-agenda-skip-if-todo (args end)
4722 "Helper function for `org-agenda-skip-if', do not use it directly.
8223b1d2
BG
4723ARGS is a list with first element either `todo', `nottodo',
4724`todo-unblocked' or `nottodo-unblocked'. The remainder is either
4725a list of TODO keywords, or a state symbol `todo' or `done' or
4726`any'."
ed21c5c8
CD
4727 (let ((kw (car args))
4728 (arg (cadr args))
4729 todo-wds todo-re)
4730 (setq todo-wds
4731 (org-uniquify
4732 (cond
4733 ((listp arg) ;; list of keywords
4734 (if (member "*" arg)
4735 (mapcar 'substring-no-properties org-todo-keywords-1)
4736 arg))
4737 ((symbolp arg) ;; keyword class name
4738 (cond
4739 ((eq arg 'todo)
4740 (org-delete-all org-done-keywords
4741 (mapcar 'substring-no-properties
4742 org-todo-keywords-1)))
4743 ((eq arg 'done) org-done-keywords)
4744 ((eq arg 'any)
4745 (mapcar 'substring-no-properties org-todo-keywords-1)))))))
4746 (setq todo-re
4747 (concat "^\\*+[ \t]+\\<\\("
4748 (mapconcat 'identity todo-wds "\\|")
4749 "\\)\\>"))
8223b1d2
BG
4750 (cond
4751 ((eq kw 'todo) (re-search-forward todo-re end t))
4752 ((eq kw 'nottodo) (not (re-search-forward todo-re end t)))
4753 ((eq kw 'todo-unblocked)
4754 (catch 'unblocked
4755 (while (re-search-forward todo-re end t)
4756 (or (org-entry-blocked-p) (throw 'unblocked t)))
4757 nil))
4758 ((eq kw 'nottodo-unblocked)
4759 (catch 'unblocked
4760 (while (re-search-forward todo-re end t)
4761 (or (org-entry-blocked-p) (throw 'unblocked nil)))
4762 t))
4763 )))
ed21c5c8 4764
20908596
CD
4765;;;###autoload
4766(defun org-agenda-list-stuck-projects (&rest ignore)
4767 "Create agenda view for projects that are stuck.
4768Stuck projects are project that have no next actions. For the definitions
4769of what a project is and how to check if it stuck, customize the variable
afe98dfa 4770`org-stuck-projects'."
20908596 4771 (interactive)
c8d0cf5c
CD
4772 (let* ((org-agenda-skip-function
4773 'org-agenda-skip-entry-when-regexp-matches-in-subtree)
20908596 4774 ;; We could have used org-agenda-skip-if here.
c8d0cf5c
CD
4775 (org-agenda-overriding-header
4776 (or org-agenda-overriding-header "List of stuck projects: "))
20908596
CD
4777 (matcher (nth 0 org-stuck-projects))
4778 (todo (nth 1 org-stuck-projects))
4779 (todo-wds (if (member "*" todo)
4780 (progn
8223b1d2 4781 (org-agenda-prepare-buffers (org-agenda-files
2c3ad40d 4782 nil 'ifmode))
20908596
CD
4783 (org-delete-all
4784 org-done-keywords-for-agenda
4785 (copy-sequence org-todo-keywords-for-agenda)))
4786 todo))
4787 (todo-re (concat "^\\*+[ \t]+\\("
4788 (mapconcat 'identity todo-wds "\\|")
4789 "\\)\\>"))
4790 (tags (nth 2 org-stuck-projects))
4791 (tags-re (if (member "*" tags)
e66ba1df
BG
4792 (concat org-outline-regexp-bol
4793 (org-re ".*:[[:alnum:]_@#%]+:[ \t]*$"))
c8d0cf5c 4794 (if tags
3ab2c837
BG
4795 (concat org-outline-regexp-bol
4796 ".*:\\("
c8d0cf5c 4797 (mapconcat 'identity tags "\\|")
afe98dfa 4798 (org-re "\\):[[:alnum:]_@#%:]*[ \t]*$")))))
20908596
CD
4799 (gen-re (nth 3 org-stuck-projects))
4800 (re-list
4801 (delq nil
4802 (list
4803 (if todo todo-re)
4804 (if tags tags-re)
4805 (and gen-re (stringp gen-re) (string-match "\\S-" gen-re)
4806 gen-re)))))
4807 (setq org-agenda-skip-regexp
4808 (if re-list
4809 (mapconcat 'identity re-list "\\|")
4810 (error "No information how to identify unstuck projects")))
4811 (org-tags-view nil matcher)
4812 (with-current-buffer org-agenda-buffer-name
4813 (setq org-agenda-redo-command
8223b1d2 4814 `(org-agenda-list-stuck-projects ,current-prefix-arg)))))
20908596
CD
4815
4816;;; Diary integration
4817
4818(defvar org-disable-agenda-to-diary nil) ;Dynamically-scoped param.
8223b1d2 4819(defvar diary-list-entries-hook)
3ab2c837 4820(defvar diary-time-regexp)
20908596
CD
4821(defun org-get-entries-from-diary (date)
4822 "Get the (Emacs Calendar) diary entries for DATE."
4823 (require 'diary-lib)
4824 (let* ((diary-fancy-buffer "*temporary-fancy-diary-buffer*")
20908596 4825 (diary-display-hook '(fancy-diary-display))
ca8ef0dc 4826 (diary-display-function 'fancy-diary-display)
20908596 4827 (pop-up-frames nil)
8223b1d2
BG
4828 (diary-list-entries-hook
4829 (cons 'org-diary-default-entry diary-list-entries-hook))
a89c8ef0 4830 (diary-file-name-prefix nil) ; turn this feature off
20908596
CD
4831 (diary-modify-entry-list-string-function 'org-modify-diary-entry-string)
4832 entries
4833 (org-disable-agenda-to-diary t))
4834 (save-excursion
4835 (save-window-excursion
4836 (funcall (if (fboundp 'diary-list-entries)
4837 'diary-list-entries 'list-diary-entries)
4838 date 1)))
4839 (if (not (get-buffer diary-fancy-buffer))
4840 (setq entries nil)
4841 (with-current-buffer diary-fancy-buffer
4842 (setq buffer-read-only nil)
4843 (if (zerop (buffer-size))
4844 ;; No entries
4845 (setq entries nil)
4846 ;; Omit the date and other unnecessary stuff
4847 (org-agenda-cleanup-fancy-diary)
4848 ;; Add prefix to each line and extend the text properties
4849 (if (zerop (buffer-size))
4850 (setq entries nil)
3ab2c837
BG
4851 (setq entries (buffer-substring (point-min) (- (point-max) 1)))
4852 (setq entries
4853 (with-temp-buffer
4854 (insert entries) (goto-char (point-min))
4855 (while (re-search-forward "\n[ \t]+\\(.+\\)$" nil t)
4856 (unless (save-match-data (string-match diary-time-regexp (match-string 1)))
4857 (replace-match (concat "; " (match-string 1)))))
4858 (buffer-string)))))
20908596
CD
4859 (set-buffer-modified-p nil)
4860 (kill-buffer diary-fancy-buffer)))
4861 (when entries
4862 (setq entries (org-split-string entries "\n"))
4863 (setq entries
4864 (mapcar
4865 (lambda (x)
e66ba1df 4866 (setq x (org-agenda-format-item "" x "Diary" nil 'time))
20908596
CD
4867 ;; Extend the text properties to the beginning of the line
4868 (org-add-props x (text-properties-at (1- (length x)) x)
ed21c5c8 4869 'type "diary" 'date date 'face 'org-agenda-diary))
20908596
CD
4870 entries)))))
4871
c8d0cf5c
CD
4872(defvar org-agenda-cleanup-fancy-diary-hook nil
4873 "Hook run when the fancy diary buffer is cleaned up.")
4874
20908596
CD
4875(defun org-agenda-cleanup-fancy-diary ()
4876 "Remove unwanted stuff in buffer created by `fancy-diary-display'.
4877This gets rid of the date, the underline under the date, and
4878the dummy entry installed by `org-mode' to ensure non-empty diary for each
4879date. It also removes lines that contain only whitespace."
4880 (goto-char (point-min))
4881 (if (looking-at ".*?:[ \t]*")
4882 (progn
4883 (replace-match "")
4884 (re-search-forward "\n=+$" nil t)
4885 (replace-match "")
4886 (while (re-search-backward "^ +\n?" nil t) (replace-match "")))
4887 (re-search-forward "\n=+$" nil t)
4888 (delete-region (point-min) (min (point-max) (1+ (match-end 0)))))
4889 (goto-char (point-min))
4890 (while (re-search-forward "^ +\n" nil t)
4891 (replace-match ""))
4892 (goto-char (point-min))
4893 (if (re-search-forward "^Org-mode dummy\n?" nil t)
c8d0cf5c
CD
4894 (replace-match ""))
4895 (run-hooks 'org-agenda-cleanup-fancy-diary-hook))
20908596
CD
4896
4897;; Make sure entries from the diary have the right text properties.
4898(eval-after-load "diary-lib"
4899 '(if (boundp 'diary-modify-entry-list-string-function)
4900 ;; We can rely on the hook, nothing to do
4901 nil
33306645 4902 ;; Hook not available, must use advice to make this work
20908596
CD
4903 (defadvice add-to-diary-list (before org-mark-diary-entry activate)
4904 "Make the position visible."
4905 (if (and org-disable-agenda-to-diary ;; called from org-agenda
4906 (stringp string)
4907 buffer-file-name)
4908 (setq string (org-modify-diary-entry-string string))))))
4909
4910(defun org-modify-diary-entry-string (string)
e66ba1df 4911 "Add text properties to string, allowing org-mode to act on it."
20908596
CD
4912 (org-add-props string nil
4913 'mouse-face 'highlight
20908596
CD
4914 'help-echo (if buffer-file-name
4915 (format "mouse-2 or RET jump to diary file %s"
4916 (abbreviate-file-name buffer-file-name))
4917 "")
4918 'org-agenda-diary-link t
4919 'org-marker (org-agenda-new-marker (point-at-bol))))
4920
4921(defun org-diary-default-entry ()
4922 "Add a dummy entry to the diary.
4923Needed to avoid empty dates which mess up holiday display."
4924 ;; Catch the error if dealing with the new add-to-diary-alist
4925 (when org-disable-agenda-to-diary
4926 (condition-case nil
4927 (org-add-to-diary-list original-date "Org-mode dummy" "")
4928 (error
4929 (org-add-to-diary-list original-date "Org-mode dummy" "" nil)))))
4930
4931(defun org-add-to-diary-list (&rest args)
4932 (if (fboundp 'diary-add-to-list)
4933 (apply 'diary-add-to-list args)
4934 (apply 'add-to-diary-list args)))
4935
ed21c5c8
CD
4936(defvar org-diary-last-run-time nil)
4937
20908596
CD
4938;;;###autoload
4939(defun org-diary (&rest args)
8223b1d2 4940 "Return diary information from org files.
20908596
CD
4941This function can be used in a \"sexp\" diary entry in the Emacs calendar.
4942It accesses org files and extracts information from those files to be
4943listed in the diary. The function accepts arguments specifying what
ed21c5c8
CD
4944items should be listed. For a list of arguments allowed here, see the
4945variable `org-agenda-entry-types'.
20908596
CD
4946
4947The call in the diary file should look like this:
4948
4949 &%%(org-diary) ~/path/to/some/orgfile.org
4950
4951Use a separate line for each org file to check. Or, if you omit the file name,
4952all files listed in `org-agenda-files' will be checked automatically:
4953
4954 &%%(org-diary)
4955
4956If you don't give any arguments (as in the example above), the default
4957arguments (:deadline :scheduled :timestamp :sexp) are used.
4958So the example above may also be written as
4959
4960 &%%(org-diary :deadline :timestamp :sexp :scheduled)
4961
4962The function expects the lisp variables `entry' and `date' to be provided
4963by the caller, because this is how the calendar works. Don't use this
4964function from a program - use `org-agenda-get-day-entries' instead."
54a0dee5 4965 (when (> (- (org-float-time)
20908596
CD
4966 org-agenda-last-marker-time)
4967 5)
8223b1d2
BG
4968 ;; I am not sure if this works with sticky agendas, because the marker
4969 ;; list is then no longer a global variable.
20908596
CD
4970 (org-agenda-reset-markers))
4971 (org-compile-prefix-format 'agenda)
4972 (org-set-sorting-strategy 'agenda)
4973 (setq args (or args '(:deadline :scheduled :timestamp :sexp)))
23f6720e
BG
4974 (let* ((files (if (and entry (stringp entry) (string-match "\\S-" entry))
4975 (list entry)
20908596 4976 (org-agenda-files t)))
ed21c5c8 4977 (time (org-float-time))
20908596 4978 file rtn results)
ed21c5c8
CD
4979 (when (or (not org-diary-last-run-time)
4980 (> (- time
4981 org-diary-last-run-time)
4982 3))
8223b1d2 4983 (org-agenda-prepare-buffers files))
ed21c5c8 4984 (setq org-diary-last-run-time time)
20908596
CD
4985 ;; If this is called during org-agenda, don't return any entries to
4986 ;; the calendar. Org Agenda will list these entries itself.
4987 (if org-disable-agenda-to-diary (setq files nil))
4988 (while (setq file (pop files))
4989 (setq rtn (apply 'org-agenda-get-day-entries file date args))
4990 (setq results (append results rtn)))
4991 (if results
8223b1d2 4992 (concat (org-agenda-finalize-entries results) "\n"))))
20908596
CD
4993
4994;;; Agenda entry finders
4995
4996(defun org-agenda-get-day-entries (file date &rest args)
4997 "Does the work for `org-diary' and `org-agenda'.
4998FILE is the path to a file to be checked for entries. DATE is date like
4999the one returned by `calendar-current-date'. ARGS are symbols indicating
5000which kind of entries should be extracted. For details about these, see
5001the documentation of `org-diary'."
5002 (setq args (or args '(:deadline :scheduled :timestamp :sexp)))
5003 (let* ((org-startup-folded nil)
5004 (org-startup-align-all-tables nil)
5005 (buffer (if (file-exists-p file)
5006 (org-get-agenda-file-buffer file)
5007 (error "No such file %s" file)))
54a0dee5 5008 arg results rtn deadline-results)
20908596
CD
5009 (if (not buffer)
5010 ;; If file does not exist, make sure an error message ends up in diary
5011 (list (format "ORG-AGENDA-ERROR: No such org-file %s" file))
5012 (with-current-buffer buffer
8223b1d2 5013 (unless (derived-mode-p 'org-mode)
20908596 5014 (error "Agenda file %s is not in `org-mode'" file))
8223b1d2 5015 (setq org-agenda-buffer (or org-agenda-buffer buffer))
20908596
CD
5016 (let ((case-fold-search nil))
5017 (save-excursion
5018 (save-restriction
5019 (if org-agenda-restrict
5020 (narrow-to-region org-agenda-restrict-begin
5021 org-agenda-restrict-end)
5022 (widen))
5023 ;; The way we repeatedly append to `results' makes it O(n^2) :-(
5024 (while (setq arg (pop args))
5025 (cond
5026 ((and (eq arg :todo)
3ab2c837
BG
5027 (equal date (calendar-gregorian-from-absolute
5028 (org-today))))
20908596
CD
5029 (setq rtn (org-agenda-get-todos))
5030 (setq results (append results rtn)))
5031 ((eq arg :timestamp)
5032 (setq rtn (org-agenda-get-blocks))
5033 (setq results (append results rtn))
8223b1d2 5034 (setq rtn (org-agenda-get-timestamps deadline-results))
20908596
CD
5035 (setq results (append results rtn)))
5036 ((eq arg :sexp)
5037 (setq rtn (org-agenda-get-sexps))
5038 (setq results (append results rtn)))
5039 ((eq arg :scheduled)
54a0dee5 5040 (setq rtn (org-agenda-get-scheduled deadline-results))
20908596
CD
5041 (setq results (append results rtn)))
5042 ((eq arg :closed)
93b62de8 5043 (setq rtn (org-agenda-get-progress))
20908596
CD
5044 (setq results (append results rtn)))
5045 ((eq arg :deadline)
5046 (setq rtn (org-agenda-get-deadlines))
54a0dee5 5047 (setq deadline-results (copy-sequence rtn))
20908596
CD
5048 (setq results (append results rtn))))))))
5049 results))))
5050
e66ba1df 5051(defvar org-heading-keyword-regexp-format) ; defined in org.el
20908596
CD
5052(defun org-agenda-get-todos ()
5053 "Return the TODO information for agenda display."
5054 (let* ((props (list 'face nil
c8d0cf5c 5055 'done-face 'org-agenda-done
20908596
CD
5056 'org-not-done-regexp org-not-done-regexp
5057 'org-todo-regexp org-todo-regexp
b349f79f 5058 'org-complex-heading-regexp org-complex-heading-regexp
20908596 5059 'mouse-face 'highlight
20908596
CD
5060 'help-echo
5061 (format "mouse-2 or RET jump to org file %s"
5062 (abbreviate-file-name buffer-file-name))))
e66ba1df
BG
5063 (regexp (format org-heading-keyword-regexp-format
5064 (cond
5065 ((and org-select-this-todo-keyword
5066 (equal org-select-this-todo-keyword "*"))
5067 org-todo-regexp)
5068 (org-select-this-todo-keyword
5069 (concat "\\("
5070 (mapconcat 'identity
5071 (org-split-string
5072 org-select-this-todo-keyword
5073 "|")
5074 "\\|") "\\)"))
5075 (t org-not-done-regexp))))
8223b1d2 5076 marker priority category category-pos tags todo-state
a89c8ef0 5077 ee txt beg end inherited-tags)
20908596
CD
5078 (goto-char (point-min))
5079 (while (re-search-forward regexp nil t)
5080 (catch :skip
5081 (save-match-data
5082 (beginning-of-line)
3ab2c837 5083 (org-agenda-skip)
d6685abc 5084 (setq beg (point) end (save-excursion (outline-next-heading) (point)))
0bd48b37 5085 (when (org-agenda-check-for-timestamp-as-reason-to-ignore-todo-item end)
20908596
CD
5086 (goto-char (1+ beg))
5087 (or org-agenda-todo-list-sublevels (org-end-of-subtree 'invisible))
5088 (throw :skip nil)))
e66ba1df 5089 (goto-char (match-beginning 2))
20908596
CD
5090 (setq marker (org-agenda-new-marker (match-beginning 0))
5091 category (org-get-category)
8223b1d2 5092 category-pos (get-text-property (point) 'org-category-position)
e66ba1df
BG
5093 txt (org-trim
5094 (buffer-substring (match-beginning 2) (match-end 0)))
a89c8ef0
BG
5095 inherited-tags
5096 (or (eq org-agenda-show-inherited-tags 'always)
5097 (and (listp org-agenda-show-inherited-tags)
5098 (memq 'todo org-agenda-show-inherited-tags))
5099 (and (eq org-agenda-show-inherited-tags t)
5100 (or (eq org-agenda-use-tag-inheritance t)
5101 (memq 'todo org-agenda-use-tag-inheritance))))
5102 tags (org-get-tags-at nil (not inherited-tags))
8223b1d2 5103 txt (org-agenda-format-item "" txt category tags t)
621f83e4
CD
5104 priority (1+ (org-get-priority txt))
5105 todo-state (org-get-todo-state))
20908596
CD
5106 (org-add-props txt props
5107 'org-marker marker 'org-hd-marker marker
5108 'priority priority 'org-category category
8223b1d2 5109 'org-category-position category-pos
621f83e4 5110 'type "todo" 'todo-state todo-state)
20908596
CD
5111 (push txt ee)
5112 (if org-agenda-todo-list-sublevels
e66ba1df 5113 (goto-char (match-end 2))
20908596
CD
5114 (org-end-of-subtree 'invisible))))
5115 (nreverse ee)))
5116
3ab2c837 5117(defun org-agenda-todo-custom-ignore-p (time n)
8223b1d2 5118 "Check whether timestamp is farther away than n number of days.
3ab2c837
BG
5119This function is invoked if `org-agenda-todo-ignore-deadlines',
5120`org-agenda-todo-ignore-scheduled' or
5121`org-agenda-todo-ignore-timestamp' is set to an integer."
5122 (let ((days (org-days-to-time time)))
5123 (if (>= n 0)
5124 (>= days n)
5125 (<= days n))))
5126
ed21c5c8
CD
5127(defun org-agenda-check-for-timestamp-as-reason-to-ignore-todo-item
5128 (&optional end)
5129 "Do we have a reason to ignore this TODO entry because it has a time stamp?"
0bd48b37
CD
5130 (when (or org-agenda-todo-ignore-with-date
5131 org-agenda-todo-ignore-scheduled
acedf35c
CD
5132 org-agenda-todo-ignore-deadlines
5133 org-agenda-todo-ignore-timestamp)
0bd48b37
CD
5134 (setq end (or end (save-excursion (outline-next-heading) (point))))
5135 (save-excursion
5136 (or (and org-agenda-todo-ignore-with-date
5137 (re-search-forward org-ts-regexp end t))
5138 (and org-agenda-todo-ignore-scheduled
ed21c5c8
CD
5139 (re-search-forward org-scheduled-time-regexp end t)
5140 (cond
5141 ((eq org-agenda-todo-ignore-scheduled 'future)
5142 (> (org-days-to-time (match-string 1)) 0))
5143 ((eq org-agenda-todo-ignore-scheduled 'past)
5144 (<= (org-days-to-time (match-string 1)) 0))
3ab2c837
BG
5145 ((numberp org-agenda-todo-ignore-scheduled)
5146 (org-agenda-todo-custom-ignore-p
5147 (match-string 1) org-agenda-todo-ignore-scheduled))
ed21c5c8 5148 (t)))
0bd48b37
CD
5149 (and org-agenda-todo-ignore-deadlines
5150 (re-search-forward org-deadline-time-regexp end t)
ed21c5c8
CD
5151 (cond
5152 ((memq org-agenda-todo-ignore-deadlines '(t all)) t)
5153 ((eq org-agenda-todo-ignore-deadlines 'far)
5154 (not (org-deadline-close (match-string 1))))
5155 ((eq org-agenda-todo-ignore-deadlines 'future)
5156 (> (org-days-to-time (match-string 1)) 0))
5157 ((eq org-agenda-todo-ignore-deadlines 'past)
5158 (<= (org-days-to-time (match-string 1)) 0))
3ab2c837
BG
5159 ((numberp org-agenda-todo-ignore-deadlines)
5160 (org-agenda-todo-custom-ignore-p
5161 (match-string 1) org-agenda-todo-ignore-deadlines))
acedf35c
CD
5162 (t (org-deadline-close (match-string 1)))))
5163 (and org-agenda-todo-ignore-timestamp
5164 (let ((buffer (current-buffer))
5165 (regexp
5166 (concat
5167 org-scheduled-time-regexp "\\|" org-deadline-time-regexp))
5168 (start (point)))
5169 ;; Copy current buffer into a temporary one
5170 (with-temp-buffer
5171 (insert-buffer-substring buffer start end)
5172 (goto-char (point-min))
5173 ;; Delete SCHEDULED and DEADLINE items
5174 (while (re-search-forward regexp end t)
5175 (delete-region (match-beginning 0) (match-end 0)))
5176 (goto-char (point-min))
5177 ;; No search for timestamp left
5178 (when (re-search-forward org-ts-regexp nil t)
5179 (cond
5180 ((eq org-agenda-todo-ignore-timestamp 'future)
5181 (> (org-days-to-time (match-string 1)) 0))
5182 ((eq org-agenda-todo-ignore-timestamp 'past)
5183 (<= (org-days-to-time (match-string 1)) 0))
3ab2c837
BG
5184 ((numberp org-agenda-todo-ignore-timestamp)
5185 (org-agenda-todo-custom-ignore-p
5186 (match-string 1) org-agenda-todo-ignore-timestamp))
acedf35c 5187 (t))))))))))
0bd48b37 5188
8223b1d2 5189(defun org-agenda-get-timestamps (&optional deadline-results)
20908596 5190 "Return the date stamp information for agenda display."
e66ba1df 5191 (let* ((props (list 'face 'org-agenda-calendar-event
20908596
CD
5192 'org-not-done-regexp org-not-done-regexp
5193 'org-todo-regexp org-todo-regexp
b349f79f 5194 'org-complex-heading-regexp org-complex-heading-regexp
20908596 5195 'mouse-face 'highlight
20908596
CD
5196 'help-echo
5197 (format "mouse-2 or RET jump to org file %s"
5198 (abbreviate-file-name buffer-file-name))))
5199 (d1 (calendar-absolute-from-gregorian date))
8223b1d2
BG
5200 mm
5201 (deadline-position-alist
5202 (mapcar (lambda (a) (and (setq mm (get-text-property
5203 0 'org-hd-marker a))
5204 (cons (marker-position mm) a)))
5205 deadline-results))
5206 (remove-re org-ts-regexp)
20908596
CD
5207 (regexp
5208 (concat
5209 (if org-agenda-include-inactive-timestamps "[[<]" "<")
5210 (regexp-quote
5211 (substring
5212 (format-time-string
5213 (car org-time-stamp-formats)
5214 (apply 'encode-time ; DATE bound by calendar
5215 (list 0 0 0 (nth 1 date) (car date) (nth 2 date))))
5216 1 11))
8223b1d2 5217 "\\|\\(<[0-9]+-[0-9]+-[0-9]+[^>\n]+?\\+[0-9]+[hdwmy]>\\)"
20908596
CD
5218 "\\|\\(<%%\\(([^>\n]+)\\)>\\)"))
5219 marker hdmarker deadlinep scheduledp clockp closedp inactivep
8223b1d2 5220 donep tmp priority category category-pos ee txt timestr tags
a89c8ef0
BG
5221 b0 b3 e3 head todo-state end-of-match show-all warntime habitp
5222 inherited-tags)
20908596 5223 (goto-char (point-min))
c8d0cf5c 5224 (while (setq end-of-match (re-search-forward regexp nil t))
20908596 5225 (setq b0 (match-beginning 0)
3ab2c837
BG
5226 b3 (match-beginning 3) e3 (match-end 3)
5227 todo-state (save-match-data (ignore-errors (org-get-todo-state)))
bdebdb64 5228 habitp (and (functionp 'org-is-habit-p) (save-match-data (org-is-habit-p)))
3ab2c837
BG
5229 show-all (or (eq org-agenda-repeating-timestamp-show-all t)
5230 (member todo-state
5231 org-agenda-repeating-timestamp-show-all)))
20908596
CD
5232 (catch :skip
5233 (and (org-at-date-range-p) (throw :skip nil))
5234 (org-agenda-skip)
5235 (if (and (match-end 1)
5236 (not (= d1 (org-time-string-to-absolute
e66ba1df
BG
5237 (match-string 1) d1 nil show-all
5238 (current-buffer) b0))))
20908596
CD
5239 (throw :skip nil))
5240 (if (and e3
5241 (not (org-diary-sexp-entry (buffer-substring b3 e3) "" date)))
5242 (throw :skip nil))
c8d0cf5c 5243 (setq tmp (buffer-substring (max (point-min)
20908596
CD
5244 (- b0 org-ds-keyword-length))
5245 b0)
5246 timestr (if b3 "" (buffer-substring b0 (point-at-eol)))
5247 inactivep (= (char-after b0) ?\[)
5248 deadlinep (string-match org-deadline-regexp tmp)
5249 scheduledp (string-match org-scheduled-regexp tmp)
5250 closedp (and org-agenda-include-inactive-timestamps
5251 (string-match org-closed-string tmp))
5252 clockp (and org-agenda-include-inactive-timestamps
5253 (or (string-match org-clock-string tmp)
5254 (string-match "]-+\\'" tmp)))
c7cf0ebc 5255 warntime (get-text-property (point) 'org-appt-warntime)
621f83e4 5256 donep (member todo-state org-done-keywords))
c8d0cf5c
CD
5257 (if (or scheduledp deadlinep closedp clockp
5258 (and donep org-agenda-skip-timestamp-if-done))
20908596
CD
5259 (throw :skip t))
5260 (if (string-match ">" timestr)
5261 ;; substring should only run to end of time stamp
5262 (setq timestr (substring timestr 0 (match-end 0))))
c8d0cf5c 5263 (setq marker (org-agenda-new-marker b0)
e66ba1df 5264 category (org-get-category b0)
8223b1d2 5265 category-pos (get-text-property b0 'org-category-position))
20908596 5266 (save-excursion
3ab2c837 5267 (if (not (re-search-backward org-outline-regexp-bol nil t))
d3517077 5268 (throw :skip nil)
c8d0cf5c 5269 (goto-char (match-beginning 0))
8223b1d2
BG
5270 (if (and (eq t org-agenda-skip-timestamp-if-deadline-is-shown)
5271 (assoc (point) deadline-position-alist))
5272 (throw :skip nil))
c8d0cf5c 5273 (setq hdmarker (org-agenda-new-marker)
a89c8ef0
BG
5274 inherited-tags
5275 (or (eq org-agenda-show-inherited-tags 'always)
5276 (and (listp org-agenda-show-inherited-tags)
5277 (memq 'agenda org-agenda-show-inherited-tags))
5278 (and (eq org-agenda-show-inherited-tags t)
5279 (or (eq org-agenda-use-tag-inheritance t)
5280 (memq 'agenda org-agenda-use-tag-inheritance))))
5281 tags (org-get-tags-at nil (not inherited-tags)))
c8d0cf5c 5282 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
3ab2c837 5283 (setq head (or (match-string 1) ""))
e66ba1df 5284 (setq txt (org-agenda-format-item
ed21c5c8 5285 (if inactivep org-agenda-inactive-leader nil)
3ab2c837 5286 head category tags timestr
bdebdb64 5287 remove-re habitp)))
20908596
CD
5288 (setq priority (org-get-priority txt))
5289 (org-add-props txt props
5290 'org-marker marker 'org-hd-marker hdmarker)
5291 (org-add-props txt nil 'priority priority
5292 'org-category category 'date date
8223b1d2 5293 'org-category-position category-pos
621f83e4 5294 'todo-state todo-state
8223b1d2 5295 'warntime warntime
20908596
CD
5296 'type "timestamp")
5297 (push txt ee))
c8d0cf5c
CD
5298 (if org-agenda-skip-additional-timestamps-same-entry
5299 (outline-next-heading)
5300 (goto-char end-of-match))))
20908596
CD
5301 (nreverse ee)))
5302
5303(defun org-agenda-get-sexps ()
5304 "Return the sexp information for agenda display."
5305 (require 'diary-lib)
e66ba1df
BG
5306 (let* ((props (list 'face 'org-agenda-calendar-sexp
5307 'mouse-face 'highlight
20908596
CD
5308 'help-echo
5309 (format "mouse-2 or RET jump to org file %s"
5310 (abbreviate-file-name buffer-file-name))))
5311 (regexp "^&?%%(")
8223b1d2 5312 marker category extra category-pos ee txt tags entry
a89c8ef0 5313 result beg b sexp sexp-entry todo-state warntime inherited-tags)
20908596
CD
5314 (goto-char (point-min))
5315 (while (re-search-forward regexp nil t)
5316 (catch :skip
5317 (org-agenda-skip)
5318 (setq beg (match-beginning 0))
5319 (goto-char (1- (match-end 0)))
5320 (setq b (point))
5321 (forward-sexp 1)
5322 (setq sexp (buffer-substring b (point)))
5323 (setq sexp-entry (if (looking-at "[ \t]*\\(\\S-.*\\)")
5324 (org-trim (match-string 1))
5325 ""))
5326 (setq result (org-diary-sexp-entry sexp sexp-entry date))
5327 (when result
5328 (setq marker (org-agenda-new-marker beg)
c8d0cf5c 5329 category (org-get-category beg)
8223b1d2 5330 category-pos (get-text-property beg 'org-category-position)
a89c8ef0
BG
5331 inherited-tags
5332 (or (eq org-agenda-show-inherited-tags 'always)
5333 (and (listp org-agenda-show-inherited-tags)
5334 (memq 'agenda org-agenda-show-inherited-tags))
5335 (and (eq org-agenda-show-inherited-tags t)
5336 (or (eq org-agenda-use-tag-inheritance t)
5337 (memq 'agenda org-agenda-use-tag-inheritance))))
5338 tags (org-get-tags-at nil (not inherited-tags))
8223b1d2 5339 todo-state (org-get-todo-state)
c7cf0ebc 5340 warntime (get-text-property (point) 'org-appt-warntime)
bdebdb64 5341 extra nil)
20908596 5342
afe98dfa
CD
5343 (dolist (r (if (stringp result)
5344 (list result)
5345 result)) ;; we expect a list here
8223b1d2
BG
5346 (when (and org-agenda-diary-sexp-prefix
5347 (string-match org-agenda-diary-sexp-prefix r))
5348 (setq extra (match-string 0 r)
5349 r (replace-match "" nil nil r)))
afe98dfa
CD
5350 (if (string-match "\\S-" r)
5351 (setq txt r)
5352 (setq txt "SEXP entry returned empty string"))
5353
e66ba1df 5354 (setq txt (org-agenda-format-item
8223b1d2 5355 extra txt category tags 'time))
afe98dfa
CD
5356 (org-add-props txt props 'org-marker marker)
5357 (org-add-props txt nil
5358 'org-category category 'date date 'todo-state todo-state
8223b1d2
BG
5359 'org-category-position category-pos 'tags tags
5360 'type "sexp" 'warntime warntime)
afe98dfa 5361 (push txt ee)))))
20908596
CD
5362 (nreverse ee)))
5363
3ab2c837
BG
5364;; Calendar sanity: define some functions that are independent of
5365;; `calendar-date-style'.
5366;; Normally I would like to use ISO format when calling the diary functions,
5367;; but to make sure we still have Emacs 22 compatibility we bind
5368;; also `european-calendar-style' and use european format
5369(defun org-anniversary (year month day &optional mark)
5370 "Like `diary-anniversary', but with fixed (ISO) order of arguments."
5371 (org-no-warnings
5372 (let ((calendar-date-style 'european) (european-calendar-style t))
5373 (diary-anniversary day month year mark))))
5374(defun org-cyclic (N year month day &optional mark)
5375 "Like `diary-cyclic', but with fixed (ISO) order of arguments."
5376 (org-no-warnings
5377 (let ((calendar-date-style 'european) (european-calendar-style t))
5378 (diary-cyclic N day month year mark))))
5379(defun org-block (Y1 M1 D1 Y2 M2 D2 &optional mark)
5380 "Like `diary-block', but with fixed (ISO) order of arguments."
5381 (org-no-warnings
5382 (let ((calendar-date-style 'european) (european-calendar-style t))
5383 (diary-block D1 M1 Y1 D2 M2 Y2 mark))))
5384(defun org-date (year month day &optional mark)
5385 "Like `diary-date', but with fixed (ISO) order of arguments."
5386 (org-no-warnings
5387 (let ((calendar-date-style 'european) (european-calendar-style t))
5388 (diary-date day month year mark))))
3ab2c837
BG
5389
5390;; Define the` org-class' function
5391(defun org-class (y1 m1 d1 y2 m2 d2 dayname &rest skip-weeks)
ed21c5c8 5392 "Entry applies if date is between dates on DAYNAME, but skips SKIP-WEEKS.
e66ba1df
BG
5393DAYNAME is a number between 0 (Sunday) and 6 (Saturday).
5394SKIP-WEEKS is any number of ISO weeks in the block period for which the
5395item should be skipped. If any of the SKIP-WEEKS arguments is the symbol
5396`holidays', then any date that is known by the Emacs calendar to be a
27e428e7 5397holiday will also be skipped."
3ab2c837
BG
5398 (let* ((date1 (calendar-absolute-from-gregorian (list m1 d1 y1)))
5399 (date2 (calendar-absolute-from-gregorian (list m2 d2 y2)))
ed21c5c8
CD
5400 (d (calendar-absolute-from-gregorian date)))
5401 (and
5402 (<= date1 d)
5403 (<= d date2)
5404 (= (calendar-day-of-week date) dayname)
5405 (or (not skip-weeks)
5406 (progn
5407 (require 'cal-iso)
5408 (not (member (car (calendar-iso-from-absolute d)) skip-weeks))))
e66ba1df
BG
5409 (not (and (memq 'holidays skip-weeks)
5410 (calendar-check-holidays date)))
23f6720e 5411 entry)))
ed21c5c8 5412
3ab2c837
BG
5413(defun org-diary-class (m1 d1 y1 m2 d2 y2 dayname &rest skip-weeks)
5414 "Like `org-class', but honor `calendar-date-style'.
5415The order of the first 2 times 3 arguments depends on the variable
5416`calendar-date-style' or, if that is not defined, on `european-calendar-style'.
5417So for American calendars, give this as MONTH DAY YEAR, for European as
5418DAY MONTH YEAR, and for ISO as YEAR MONTH DAY.
5419DAYNAME is a number between 0 (Sunday) and 6 (Saturday). SKIP-WEEKS
5420is any number of ISO weeks in the block period for which the item should
5421be skipped.
5422
5423This function is here only for backward compatibility and it is deprecated,
5424please use `org-class' instead."
5425 (let* ((date1 (org-order-calendar-date-args m1 d1 y1))
5426 (date2 (org-order-calendar-date-args m2 d2 y2)))
5427 (org-class
5428 (nth 2 date1) (car date1) (nth 1 date1)
5429 (nth 2 date2) (car date2) (nth 1 date2)
5430 dayname skip-weeks)))
e66ba1df 5431(make-obsolete 'org-diary-class 'org-class "")
3ab2c837 5432
8223b1d2 5433(defvar org-agenda-show-log-scoped) ;; dynamically scope in `org-timeline' or `org-agenda-list'
d60b1ba1 5434(defalias 'org-get-closed 'org-agenda-get-progress)
93b62de8 5435(defun org-agenda-get-progress ()
20908596
CD
5436 "Return the logged TODO entries for agenda display."
5437 (let* ((props (list 'mouse-face 'highlight
5438 'org-not-done-regexp org-not-done-regexp
5439 'org-todo-regexp org-todo-regexp
b349f79f 5440 'org-complex-heading-regexp org-complex-heading-regexp
20908596
CD
5441 'help-echo
5442 (format "mouse-2 or RET jump to org file %s"
5443 (abbreviate-file-name buffer-file-name))))
8223b1d2
BG
5444 (items (if (consp org-agenda-show-log-scoped)
5445 org-agenda-show-log-scoped
5446 (if (eq org-agenda-show-log-scoped 'clockcheck)
3ab2c837
BG
5447 '(clock)
5448 org-agenda-log-mode-items)))
ff4be292 5449 (parts
93b62de8
CD
5450 (delq nil
5451 (list
5452 (if (memq 'closed items) (concat "\\<" org-closed-string))
5453 (if (memq 'clock items) (concat "\\<" org-clock-string))
c8d0cf5c 5454 (if (memq 'state items) "- State \"\\([a-zA-Z0-9]+\\)\".*?"))))
93b62de8
CD
5455 (parts-re (if parts (mapconcat 'identity parts "\\|")
5456 (error "`org-agenda-log-mode-items' is empty")))
20908596 5457 (regexp (concat
93b62de8
CD
5458 "\\(" parts-re "\\)"
5459 " *\\["
20908596
CD
5460 (regexp-quote
5461 (substring
5462 (format-time-string
5463 (car org-time-stamp-formats)
5464 (apply 'encode-time ; DATE bound by calendar
5465 (list 0 0 0 (nth 1 date) (car date) (nth 2 date))))
5466 1 11))))
c8d0cf5c 5467 (org-agenda-search-headline-for-time nil)
8223b1d2 5468 marker hdmarker priority category category-pos tags closedp
a89c8ef0 5469 statep clockp state ee txt extra timestr rest clocked inherited-tags)
20908596
CD
5470 (goto-char (point-min))
5471 (while (re-search-forward regexp nil t)
5472 (catch :skip
5473 (org-agenda-skip)
5474 (setq marker (org-agenda-new-marker (match-beginning 0))
5475 closedp (equal (match-string 1) org-closed-string)
93b62de8 5476 statep (equal (string-to-char (match-string 1)) ?-)
c8d0cf5c 5477 clockp (not (or closedp statep))
93b62de8 5478 state (and statep (match-string 2))
20908596 5479 category (org-get-category (match-beginning 0))
8223b1d2 5480 category-pos (get-text-property (match-beginning 0) 'org-category-position)
e66ba1df 5481 timestr (buffer-substring (match-beginning 0) (point-at-eol)))
b349f79f
CD
5482 (when (string-match "\\]" timestr)
5483 ;; substring should only run to end of time stamp
5484 (setq rest (substring timestr (match-end 0))
5485 timestr (substring timestr 0 (match-end 0)))
93b62de8 5486 (if (and (not closedp) (not statep)
e66ba1df
BG
5487 (string-match "\\([0-9]\\{1,2\\}:[0-9]\\{2\\}\\)\\].*?\\([0-9]\\{1,2\\}:[0-9]\\{2\\}\\)"
5488 rest))
621f83e4
CD
5489 (progn (setq timestr (concat (substring timestr 0 -1)
5490 "-" (match-string 1 rest) "]"))
5491 (setq clocked (match-string 2 rest)))
5492 (setq clocked "-")))
20908596 5493 (save-excursion
3ab2c837
BG
5494 (setq extra
5495 (cond
5496 ((not org-agenda-log-mode-add-notes) nil)
5497 (statep
5498 (and (looking-at ".*\\\\\n[ \t]*\\([^-\n \t].*?\\)[ \t]*$")
5499 (match-string 1)))
5500 (clockp
5501 (and (looking-at ".*\n[ \t]*-[ \t]+\\([^-\n \t].*?\\)[ \t]*$")
5502 (match-string 1)))))
5503 (if (not (re-search-backward org-outline-regexp-bol nil t))
d3517077 5504 (throw :skip nil)
c8d0cf5c
CD
5505 (goto-char (match-beginning 0))
5506 (setq hdmarker (org-agenda-new-marker)
a89c8ef0
BG
5507 inherited-tags
5508 (or (eq org-agenda-show-inherited-tags 'always)
5509 (and (listp org-agenda-show-inherited-tags)
5510 (memq 'todo org-agenda-show-inherited-tags))
5511 (and (eq org-agenda-show-inherited-tags t)
5512 (or (eq org-agenda-use-tag-inheritance t)
5513 (memq 'todo org-agenda-use-tag-inheritance))))
5514 tags (org-get-tags-at nil (not inherited-tags)))
c8d0cf5c
CD
5515 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
5516 (setq txt (match-string 1))
5517 (when extra
5518 (if (string-match "\\([ \t]+\\)\\(:[^ \n\t]*?:\\)[ \t]*$" txt)
5519 (setq txt (concat (substring txt 0 (match-beginning 1))
5520 " - " extra " " (match-string 2 txt)))
5521 (setq txt (concat txt " - " extra))))
e66ba1df 5522 (setq txt (org-agenda-format-item
c8d0cf5c
CD
5523 (cond
5524 (closedp "Closed: ")
8223b1d2
BG
5525 (statep (concat "State: (" state ")"))
5526 (t (concat "Clocked: (" clocked ")")))
c8d0cf5c 5527 txt category tags timestr)))
20908596
CD
5528 (setq priority 100000)
5529 (org-add-props txt props
c8d0cf5c 5530 'org-marker marker 'org-hd-marker hdmarker 'face 'org-agenda-done
20908596 5531 'priority priority 'org-category category
8223b1d2 5532 'org-category-position category-pos
20908596 5533 'type "closed" 'date date
c8d0cf5c 5534 'undone-face 'org-warning 'done-face 'org-agenda-done)
20908596
CD
5535 (push txt ee))
5536 (goto-char (point-at-eol))))
5537 (nreverse ee)))
5538
3ab2c837
BG
5539(defun org-agenda-show-clocking-issues ()
5540 "Add overlays, showing issues with clocking.
5541See also the user option `org-agenda-clock-consistency-checks'."
5542 (interactive)
5543 (let* ((pl org-agenda-clock-consistency-checks)
5544 (re (concat "^[ \t]*"
5545 org-clock-string
5546 "[ \t]+"
5547 "\\(\\[.*?\\]\\)" ; group 1 is first stamp
5548 "\\(-\\{1,3\\}\\(\\[.*?\\]\\)\\)?")) ; group 3 is second
5549 (tlstart 0.)
5550 (tlend 0.)
fe3c5669 5551 (maxtime (org-hh:mm-string-to-minutes
3ab2c837 5552 (or (plist-get pl :max-duration) "24:00")))
fe3c5669 5553 (mintime (org-hh:mm-string-to-minutes
3ab2c837
BG
5554 (or (plist-get pl :min-duration) 0)))
5555 (maxgap (org-hh:mm-string-to-minutes
5556 ;; default 30:00 means never complain
5557 (or (plist-get pl :max-gap) "30:00")))
5558 (gapok (mapcar 'org-hh:mm-string-to-minutes
5559 (plist-get pl :gap-ok-around)))
5560 (def-face (or (plist-get pl :default-face)
5561 '((:background "DarkRed") (:foreground "white"))))
5562 issue face m te ts dt ov)
5563 (goto-char (point-min))
5564 (while (re-search-forward " Clocked: +(-\\|\\([0-9]+:[0-9]+\\))" nil t)
5565 (setq issue nil face def-face)
5566 (catch 'next
5567 (setq m (org-get-at-bol 'org-marker)
5568 te nil ts nil)
5569 (unless (and m (markerp m))
5570 (setq issue "No valid clock line") (throw 'next t))
5571 (org-with-point-at m
5572 (save-excursion
5573 (goto-char (point-at-bol))
5574 (unless (looking-at re)
5575 (error "No valid Clock line")
5576 (throw 'next t))
5577 (unless (match-end 3)
5578 (setq issue "No end time"
5579 face (or (plist-get pl :no-end-time-face) face))
5580 (throw 'next t))
5581 (setq ts (match-string 1)
5582 te (match-string 3)
5583 ts (org-float-time
5584 (apply 'encode-time (org-parse-time-string ts)))
5585 te (org-float-time
5586 (apply 'encode-time (org-parse-time-string te)))
5587 dt (- te ts))))
5588 (cond
5589 ((> dt (* 60 maxtime))
5590 ;; a very long clocking chunk
5591 (setq issue (format "Clocking interval is very long: %s"
5592 (org-minutes-to-hh:mm-string
5593 (floor (/ (float dt) 60.))))
5594 face (or (plist-get pl :long-face) face)))
5595 ((< dt (* 60 mintime))
5596 ;; a very short clocking chunk
5597 (setq issue (format "Clocking interval is very short: %s"
5598 (org-minutes-to-hh:mm-string
5599 (floor (/ (float dt) 60.))))
5600 face (or (plist-get pl :short-face) face)))
5601 ((and (> tlend 0) (< ts tlend))
5602 ;; Two clock entries are overlapping
5603 (setq issue (format "Clocking overlap: %d minutes"
5604 (/ (- tlend ts) 60))
5605 face (or (plist-get pl :overlap-face) face)))
5606 ((and (> tlend 0) (> ts (+ tlend (* 60 maxgap))))
e66ba1df 5607 ;; There is a gap, lets see if we need to report it
3ab2c837
BG
5608 (unless (org-agenda-check-clock-gap tlend ts gapok)
5609 (setq issue (format "Clocking gap: %d minutes"
8223b1d2 5610 (/ (- ts tlend) 60))
3ab2c837
BG
5611 face (or (plist-get pl :gap-face) face))))
5612 (t nil)))
5613 (setq tlend (or te tlend) tlstart (or ts tlstart))
5614 (when issue
5615 ;; OK, there was some issue, add an overlay to show the issue
5616 (setq ov (make-overlay (point-at-bol) (point-at-eol)))
5617 (overlay-put ov 'before-string
5618 (concat
5619 (org-add-props
5620 (format "%-43s" (concat " " issue))
5621 nil
5622 'face face)
5623 "\n"))
5624 (overlay-put ov 'evaporate t)))))
5625
5626(defun org-agenda-check-clock-gap (t1 t2 ok-list)
5627 "Check if gap T1 -> T2 contains one of the OK-LIST time-of-day values."
5628 (catch 'exit
5629 (unless ok-list
5630 ;; there are no OK times for gaps...
5631 (throw 'exit nil))
5632 (if (> (- (/ t2 36000) (/ t1 36000)) 24)
5633 ;; This is more than 24 hours, so it is OK.
5634 ;; because we have at least one OK time, that must be in the
5635 ;; 24 hour interval.
5636 (throw 'exit t))
5637 ;; We have a shorter gap.
5638 ;; Now we have to get the minute of the day when these times are
5639 (let* ((t1dec (decode-time (seconds-to-time t1)))
5640 (t2dec (decode-time (seconds-to-time t2)))
5641 ;; compute the minute on the day
5642 (min1 (+ (nth 1 t1dec) (* 60 (nth 2 t1dec))))
5643 (min2 (+ (nth 1 t2dec) (* 60 (nth 2 t2dec)))))
5644 (when (< min2 min1)
5645 ;; if min2 is smaller than min1, this means it is on the next day.
5646 ;; Wrap it to after midnight.
5647 (setq min2 (+ min2 1440)))
5648 ;; Now check if any of the OK times is in the gap
5649 (mapc (lambda (x)
5650 ;; Wrap the time to after midnight if necessary
5651 (if (< x min1) (setq x (+ x 1440)))
5652 ;; Check if in interval
5653 (and (<= min1 x) (>= min2 x) (throw 'exit t)))
5654 ok-list)
5655 ;; Nope, this gap is not OK
5656 nil)))
5657
20908596
CD
5658(defun org-agenda-get-deadlines ()
5659 "Return the deadline information for agenda display."
5660 (let* ((props (list 'mouse-face 'highlight
5661 'org-not-done-regexp org-not-done-regexp
5662 'org-todo-regexp org-todo-regexp
b349f79f 5663 'org-complex-heading-regexp org-complex-heading-regexp
20908596
CD
5664 'help-echo
5665 (format "mouse-2 or RET jump to org file %s"
5666 (abbreviate-file-name buffer-file-name))))
5667 (regexp org-deadline-time-regexp)
621f83e4 5668 (todayp (org-agenda-todayp date)) ; DATE bound by calendar
20908596 5669 (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar
8223b1d2 5670 d2 diff dfrac wdays pos pos1 category category-pos
e66ba1df 5671 tags suppress-prewarning ee txt head face s todo-state
d3517077 5672 show-all upcomingp donep timestr warntime inherited-tags)
20908596
CD
5673 (goto-char (point-min))
5674 (while (re-search-forward regexp nil t)
ed21c5c8 5675 (setq suppress-prewarning nil)
20908596
CD
5676 (catch :skip
5677 (org-agenda-skip)
ed21c5c8
CD
5678 (when (and org-agenda-skip-deadline-prewarning-if-scheduled
5679 (save-match-data
5680 (string-match org-scheduled-time-regexp
5681 (buffer-substring (point-at-bol)
5682 (point-at-eol)))))
5683 (setq suppress-prewarning
5684 (if (integerp org-agenda-skip-deadline-prewarning-if-scheduled)
5685 org-agenda-skip-deadline-prewarning-if-scheduled
5686 0)))
20908596 5687 (setq s (match-string 1)
c8d0cf5c 5688 txt nil
20908596 5689 pos (1- (match-beginning 1))
3ab2c837
BG
5690 todo-state (save-match-data (org-get-todo-state))
5691 show-all (or (eq org-agenda-repeating-timestamp-show-all t)
5692 (member todo-state
8223b1d2 5693 org-agenda-repeating-timestamp-show-all))
20908596 5694 d2 (org-time-string-to-absolute
e66ba1df
BG
5695 (match-string 1) d1 'past show-all
5696 (current-buffer) pos)
20908596 5697 diff (- d2 d1)
ed21c5c8
CD
5698 wdays (if suppress-prewarning
5699 (let ((org-deadline-warning-days suppress-prewarning))
5700 (org-get-wdays s))
5701 (org-get-wdays s))
e66ba1df 5702 dfrac (- 1 (/ (* 1.0 diff) (max wdays 1)))
20908596
CD
5703 upcomingp (and todayp (> diff 0)))
5704 ;; When to show a deadline in the calendar:
5705 ;; If the expiration is within wdays warning time.
5706 ;; Past-due deadlines are only shown on the current date
8bfe682a
CD
5707 (if (and (or (and (<= diff wdays)
5708 (and todayp (not org-agenda-only-exact-dates)))
5709 (= diff 0)))
20908596 5710 (save-excursion
3ab2c837 5711 ;; (setq todo-state (org-get-todo-state))
c8d0cf5c
CD
5712 (setq donep (member todo-state org-done-keywords))
5713 (if (and donep
5714 (or org-agenda-skip-deadline-if-done
5715 (not (= diff 0))))
5716 (setq txt nil)
e66ba1df 5717 (setq category (org-get-category)
c7cf0ebc 5718 warntime (get-text-property (point) 'org-appt-warntime)
8223b1d2 5719 category-pos (get-text-property (point) 'org-category-position))
c8d0cf5c 5720 (if (not (re-search-backward "^\\*+[ \t]+" nil t))
d3517077 5721 (throw :skip nil)
c8d0cf5c
CD
5722 (goto-char (match-end 0))
5723 (setq pos1 (match-beginning 0))
d3517077
BG
5724 (setq inherited-tags
5725 (or (eq org-agenda-show-inherited-tags 'always)
5726 (and (listp org-agenda-show-inherited-tags)
5727 (memq 'agenda org-agenda-show-inherited-tags))
5728 (and (eq org-agenda-show-inherited-tags t)
5729 (or (eq org-agenda-use-tag-inheritance t)
5730 (memq 'agenda org-agenda-use-tag-inheritance))))
5731 tags (org-get-tags-at pos1 (not inherited-tags)))
5732 (setq head (buffer-substring
c8d0cf5c
CD
5733 (point)
5734 (progn (skip-chars-forward "^\r\n")
5735 (point))))
5736 (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
5737 (setq timestr
5738 (concat (substring s (match-beginning 1)) " "))
5739 (setq timestr 'time))
e66ba1df 5740 (setq txt (org-agenda-format-item
c8d0cf5c
CD
5741 (if (= diff 0)
5742 (car org-agenda-deadline-leaders)
5743 (if (functionp
5744 (nth 1 org-agenda-deadline-leaders))
5745 (funcall
5746 (nth 1 org-agenda-deadline-leaders)
5747 diff date)
5748 (format (nth 1 org-agenda-deadline-leaders)
5749 diff)))
5750 head category tags
5751 (if (not (= diff 0)) nil timestr)))))
20908596 5752 (when txt
e66ba1df 5753 (setq face (org-agenda-deadline-face dfrac))
20908596
CD
5754 (org-add-props txt props
5755 'org-marker (org-agenda-new-marker pos)
8223b1d2 5756 'warntime warntime
20908596
CD
5757 'org-hd-marker (org-agenda-new-marker pos1)
5758 'priority (+ (- diff)
5759 (org-get-priority txt))
5760 'org-category category
8223b1d2 5761 'org-category-position category-pos
621f83e4 5762 'todo-state todo-state
20908596
CD
5763 'type (if upcomingp "upcoming-deadline" "deadline")
5764 'date (if upcomingp date d2)
c8d0cf5c
CD
5765 'face (if donep 'org-agenda-done face)
5766 'undone-face face 'done-face 'org-agenda-done)
20908596
CD
5767 (push txt ee))))))
5768 (nreverse ee)))
5769
e66ba1df 5770(defun org-agenda-deadline-face (fraction)
20908596
CD
5771 "Return the face to displaying a deadline item.
5772FRACTION is what fraction of the head-warning time has passed."
20908596
CD
5773 (let ((faces org-agenda-deadline-faces) f)
5774 (catch 'exit
5775 (while (setq f (pop faces))
5776 (if (>= fraction (car f)) (throw 'exit (cdr f)))))))
5777
54a0dee5 5778(defun org-agenda-get-scheduled (&optional deadline-results)
20908596
CD
5779 "Return the scheduled information for agenda display."
5780 (let* ((props (list 'org-not-done-regexp org-not-done-regexp
5781 'org-todo-regexp org-todo-regexp
b349f79f 5782 'org-complex-heading-regexp org-complex-heading-regexp
c8d0cf5c 5783 'done-face 'org-agenda-done
20908596 5784 'mouse-face 'highlight
20908596
CD
5785 'help-echo
5786 (format "mouse-2 or RET jump to org file %s"
5787 (abbreviate-file-name buffer-file-name))))
5788 (regexp org-scheduled-time-regexp)
621f83e4 5789 (todayp (org-agenda-todayp date)) ; DATE bound by calendar
20908596 5790 (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar
54a0dee5
CD
5791 mm
5792 (deadline-position-alist
5793 (mapcar (lambda (a) (and (setq mm (get-text-property
8223b1d2
BG
5794 0 'org-hd-marker a))
5795 (cons (marker-position mm) a)))
54a0dee5 5796 deadline-results))
8223b1d2
BG
5797 d2 diff pos pos1 category category-pos tags donep
5798 ee txt head pastschedp todo-state face timestr s habitp show-all
a89c8ef0 5799 did-habit-check-p warntime inherited-tags)
20908596
CD
5800 (goto-char (point-min))
5801 (while (re-search-forward regexp nil t)
5802 (catch :skip
5803 (org-agenda-skip)
5804 (setq s (match-string 1)
c8d0cf5c 5805 txt nil
20908596 5806 pos (1- (match-beginning 1))
3ab2c837
BG
5807 todo-state (save-match-data (org-get-todo-state))
5808 show-all (or (eq org-agenda-repeating-timestamp-show-all t)
5809 (member todo-state
5810 org-agenda-repeating-timestamp-show-all))
20908596 5811 d2 (org-time-string-to-absolute
e66ba1df
BG
5812 (match-string 1) d1 'past show-all
5813 (current-buffer) pos)
8223b1d2 5814 diff (- d2 d1)
c7cf0ebc 5815 warntime (get-text-property (point) 'org-appt-warntime))
20908596 5816 (setq pastschedp (and todayp (< diff 0)))
8223b1d2 5817 (setq did-habit-check-p nil)
20908596
CD
5818 ;; When to show a scheduled item in the calendar:
5819 ;; If it is on or past the date.
8bfe682a
CD
5820 (when (or (and (< diff 0)
5821 (< (abs diff) org-scheduled-past-days)
5822 (and todayp (not org-agenda-only-exact-dates)))
8223b1d2
BG
5823 (= diff 0)
5824 ;; org-is-habit-p uses org-entry-get, which is expansive
5825 ;; so we go extra mile to only call it once
5826 (and todayp
5827 (boundp 'org-habit-show-all-today)
5828 org-habit-show-all-today
5829 (setq did-habit-check-p t)
5830 (setq habitp (and (functionp 'org-is-habit-p)
5831 (org-is-habit-p)))))
8bfe682a 5832 (save-excursion
8bfe682a 5833 (setq donep (member todo-state org-done-keywords))
8bfe682a 5834 (if (and donep
3ab2c837
BG
5835 (or org-agenda-skip-scheduled-if-done
5836 (not (= diff 0))
5837 (and (functionp 'org-is-habit-p)
5838 (org-is-habit-p))))
8bfe682a 5839 (setq txt nil)
8223b1d2
BG
5840 (setq habitp (if did-habit-check-p habitp
5841 (and (functionp 'org-is-habit-p)
5842 (org-is-habit-p))))
e66ba1df 5843 (setq category (org-get-category)
8223b1d2 5844 category-pos (get-text-property (point) 'org-category-position))
8bfe682a 5845 (if (not (re-search-backward "^\\*+[ \t]+" nil t))
d3517077 5846 (throw :skip nil)
8bfe682a
CD
5847 (goto-char (match-end 0))
5848 (setq pos1 (match-beginning 0))
5849 (if habitp
5850 (if (or (not org-habit-show-habits)
5851 (and (not todayp)
8223b1d2 5852 (boundp 'org-habit-show-habits-only-for-today)
8bfe682a
CD
5853 org-habit-show-habits-only-for-today))
5854 (throw :skip nil))
54a0dee5
CD
5855 (if (and
5856 (or (eq t org-agenda-skip-scheduled-if-deadline-is-shown)
5857 (and org-agenda-skip-scheduled-if-deadline-is-shown
5858 pastschedp))
5859 (setq mm (assoc pos1 deadline-position-alist)))
8bfe682a 5860 (throw :skip nil)))
a89c8ef0
BG
5861 (setq inherited-tags
5862 (or (eq org-agenda-show-inherited-tags 'always)
5863 (and (listp org-agenda-show-inherited-tags)
5864 (memq 'agenda org-agenda-show-inherited-tags))
5865 (and (eq org-agenda-show-inherited-tags t)
5866 (or (eq org-agenda-use-tag-inheritance t)
5867 (memq 'agenda org-agenda-use-tag-inheritance))))
5868 tags (org-get-tags-at nil (not inherited-tags)))
d3517077 5869 (setq head (buffer-substring
8bfe682a
CD
5870 (point)
5871 (progn (skip-chars-forward "^\r\n") (point))))
5872 (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
5873 (setq timestr
5874 (concat (substring s (match-beginning 1)) " "))
5875 (setq timestr 'time))
e66ba1df 5876 (setq txt (org-agenda-format-item
8bfe682a
CD
5877 (if (= diff 0)
5878 (car org-agenda-scheduled-leaders)
5879 (format (nth 1 org-agenda-scheduled-leaders)
5880 (- 1 diff)))
5881 head category tags
5882 (if (not (= diff 0)) nil timestr)
3ab2c837 5883 nil habitp))))
8bfe682a
CD
5884 (when txt
5885 (setq face
5886 (cond
5887 ((and (not habitp) pastschedp)
5888 'org-scheduled-previously)
5889 (todayp 'org-scheduled-today)
5890 (t 'org-scheduled))
5891 habitp (and habitp (org-habit-parse-todo)))
5892 (org-add-props txt props
5893 'undone-face face
5894 'face (if donep 'org-agenda-done face)
5895 'org-marker (org-agenda-new-marker pos)
5896 'org-hd-marker (org-agenda-new-marker pos1)
5897 'type (if pastschedp "past-scheduled" "scheduled")
5898 'date (if pastschedp d2 date)
8223b1d2 5899 'warntime warntime
8bfe682a
CD
5900 'priority (if habitp
5901 (org-habit-get-priority habitp)
5902 (+ 94 (- 5 diff) (org-get-priority txt)))
5903 'org-category category
8223b1d2 5904 'category-position category-pos
8bfe682a
CD
5905 'org-habit-p habitp
5906 'todo-state todo-state)
5907 (push txt ee))))))
20908596
CD
5908 (nreverse ee)))
5909
5910(defun org-agenda-get-blocks ()
5911 "Return the date-range information for agenda display."
5912 (let* ((props (list 'face nil
5913 'org-not-done-regexp org-not-done-regexp
5914 'org-todo-regexp org-todo-regexp
b349f79f 5915 'org-complex-heading-regexp org-complex-heading-regexp
20908596 5916 'mouse-face 'highlight
20908596
CD
5917 'help-echo
5918 (format "mouse-2 or RET jump to org file %s"
5919 (abbreviate-file-name buffer-file-name))))
5920 (regexp org-tr-regexp)
5921 (d0 (calendar-absolute-from-gregorian date))
8223b1d2 5922 marker hdmarker ee txt d1 d2 s1 s2 category category-pos
a89c8ef0 5923 todo-state tags pos head donep inherited-tags)
20908596
CD
5924 (goto-char (point-min))
5925 (while (re-search-forward regexp nil t)
5926 (catch :skip
5927 (org-agenda-skip)
5928 (setq pos (point))
3ab2c837
BG
5929 (let ((start-time (match-string 1))
5930 (end-time (match-string 2)))
5931 (setq s1 (match-string 1)
5932 s2 (match-string 2)
e66ba1df
BG
5933 d1 (time-to-days (org-time-string-to-time s1 (current-buffer) pos))
5934 d2 (time-to-days (org-time-string-to-time s2 (current-buffer) pos)))
3ab2c837
BG
5935 (if (and (> (- d0 d1) -1) (> (- d2 d0) -1))
5936 ;; Only allow days between the limits, because the normal
5937 ;; date stamps will catch the limits.
5938 (save-excursion
5939 (setq todo-state (org-get-todo-state))
5940 (setq donep (member todo-state org-done-keywords))
5941 (if (and donep org-agenda-skip-timestamp-if-done)
5942 (throw :skip t))
5943 (setq marker (org-agenda-new-marker (point)))
e66ba1df 5944 (setq category (org-get-category)
8223b1d2 5945 category-pos (get-text-property (point) 'org-category-position))
3ab2c837 5946 (if (not (re-search-backward org-outline-regexp-bol nil t))
d3517077 5947 (throw :skip nil)
3ab2c837 5948 (goto-char (match-beginning 0))
a89c8ef0
BG
5949 (setq hdmarker (org-agenda-new-marker (point))
5950 inherited-tags
5951 (or (eq org-agenda-show-inherited-tags 'always)
5952 (and (listp org-agenda-show-inherited-tags)
5953 (memq 'agenda org-agenda-show-inherited-tags))
5954 (and (eq org-agenda-show-inherited-tags t)
5955 (or (eq org-agenda-use-tag-inheritance t)
5956 (memq 'agenda org-agenda-use-tag-inheritance))))
5957 tags (org-get-tags-at nil (not inherited-tags)))
3ab2c837
BG
5958 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
5959 (setq head (match-string 1))
5960 (let ((remove-re
5961 (if org-agenda-remove-timeranges-from-blocks
5962 (concat
5963 "<" (regexp-quote s1) ".*?>"
5964 "--"
5965 "<" (regexp-quote s2) ".*?>")
5966 nil)))
e66ba1df 5967 (setq txt (org-agenda-format-item
3ab2c837
BG
5968 (format
5969 (nth (if (= d1 d2) 0 1)
5970 org-agenda-timerange-leaders)
5971 (1+ (- d0 d1)) (1+ (- d2 d1)))
5972 head category tags
e66ba1df
BG
5973 (cond ((and (= d1 d0) (= d2 d0))
5974 (concat "<" start-time ">--<" end-time ">"))
5975 ((= d1 d0)
3ab2c837
BG
5976 (concat "<" start-time ">"))
5977 ((= d2 d0)
8223b1d2 5978 (concat "<" end-time ">")))
bdebdb64 5979 remove-re))))
3ab2c837
BG
5980 (org-add-props txt props
5981 'org-marker marker 'org-hd-marker hdmarker
5982 'type "block" 'date date
5983 'todo-state todo-state
e66ba1df 5984 'priority (org-get-priority txt) 'org-category category
8223b1d2 5985 'org-category-position category-pos)
3ab2c837 5986 (push txt ee))))
20908596
CD
5987 (goto-char pos)))
5988 ;; Sort the entries by expiration date.
5989 (nreverse ee)))
5990
5991;;; Agenda presentation and sorting
5992
5993(defvar org-prefix-has-time nil
5994 "A flag, set by `org-compile-prefix-format'.
5995The flag is set if the currently compiled format contains a `%t'.")
5996(defvar org-prefix-has-tag nil
5997 "A flag, set by `org-compile-prefix-format'.
5998The flag is set if the currently compiled format contains a `%T'.")
5999(defvar org-prefix-has-effort nil
6000 "A flag, set by `org-compile-prefix-format'.
6001The flag is set if the currently compiled format contains a `%e'.")
8d642074 6002(defvar org-prefix-category-length nil
86fbb8ca 6003 "Used by `org-compile-prefix-format' to remember the category field width.")
8bfe682a 6004(defvar org-prefix-category-max-length nil
86fbb8ca 6005 "Used by `org-compile-prefix-format' to remember the category field width.")
20908596 6006
acedf35c
CD
6007(defun org-agenda-get-category-icon (category)
6008 "Return an image for CATEGORY according to `org-agenda-category-icon-alist'."
6009 (dolist (entry org-agenda-category-icon-alist)
6010 (when (org-string-match-p (car entry) category)
6011 (if (listp (cadr entry))
6012 (return (cadr entry))
8223b1d2 6013 (return (apply 'create-image (cdr entry)))))))
acedf35c 6014
e66ba1df 6015(defun org-agenda-format-item (extra txt &optional category tags dotime
3ab2c837 6016 remove-re habitp)
20908596
CD
6017 "Format TXT to be inserted into the agenda buffer.
6018In particular, it adds the prefix and corresponding text properties. EXTRA
6019must be a string and replaces the `%s' specifier in the prefix format.
6020CATEGORY (string, symbol or nil) may be used to overrule the default
6021category taken from local variable or file name. It will replace the `%c'
6022specifier in the format. DOTIME, when non-nil, indicates that a
6023time-of-day should be extracted from TXT for sorting of this entry, and for
6024the `%t' specifier in the format. When DOTIME is a string, this string is
3ab2c837 6025searched for a time before TXT is. TAGS can be the tags of the headline.
20908596 6026Any match of REMOVE-RE will be removed from TXT."
8223b1d2
BG
6027 ;; We keep the org-prefix-* variable values along with a compiled
6028 ;; formatter, so that multiple agendas existing at the same time, do
6029 ;; not step on each other toes.
6030 ;;
6031 ;; It was inconvenient to make these variables buffer local in
6032 ;; Agenda buffers, because this function expects to be called with
6033 ;; the buffer where item comes from being current, and not agenda
6034 ;; buffer
6035 (let* ((bindings (car org-prefix-format-compiled))
6036 (formatter (cadr org-prefix-format-compiled)))
6037 (loop for (var value) in bindings
6038 do (set var value))
6039 (save-match-data
6040 ;; Diary entries sometimes have extra whitespace at the beginning
6041 (if (string-match "^ +" txt) (setq txt (replace-match "" nil nil txt)))
6042
6043 ;; Fix the tags part in txt
6044 (setq txt (org-agenda-fix-displayed-tags
6045 txt tags
6046 org-agenda-show-inherited-tags
6047 org-agenda-hide-tags-regexp))
6048 (let* ((category (or category
6049 (if (stringp org-category)
6050 org-category
6051 (and org-category (symbol-name org-category)))
6052 (if buffer-file-name
6053 (file-name-sans-extension
6054 (file-name-nondirectory buffer-file-name))
6055 "")))
6056 (category-icon (org-agenda-get-category-icon category))
6057 (category-icon (if category-icon
6058 (propertize " " 'display category-icon)
6059 ""))
6060 ;; time, tag, effort are needed for the eval of the prefix format
6061 (tag (if tags (nth (1- (length tags)) tags) ""))
6062 time effort neffort
6063 (ts (if dotime (concat
6064 (if (stringp dotime) dotime "")
6065 (and org-agenda-search-headline-for-time txt))))
6066 (time-of-day (and dotime (org-get-time-of-day ts)))
6067 stamp plain s0 s1 s2 rtn srp l
6068 duration thecategory)
6069 (and (derived-mode-p 'org-mode) buffer-file-name
6070 (add-to-list 'org-agenda-contributing-files buffer-file-name))
6071 (when (and dotime time-of-day)
6072 ;; Extract starting and ending time and move them to prefix
6073 (when (or (setq stamp (string-match org-stamp-time-of-day-regexp ts))
6074 (setq plain (string-match org-plain-time-of-day-regexp ts)))
6075 (setq s0 (match-string 0 ts)
6076 srp (and stamp (match-end 3))
6077 s1 (match-string (if plain 1 2) ts)
6078 s2 (match-string (if plain 8 (if srp 4 6)) ts))
6079
6080 ;; If the times are in TXT (not in DOTIMES), and the prefix will list
6081 ;; them, we might want to remove them there to avoid duplication.
6082 ;; The user can turn this off with a variable.
6083 (if (and org-prefix-has-time
6084 org-agenda-remove-times-when-in-prefix (or stamp plain)
6085 (string-match (concat (regexp-quote s0) " *") txt)
6086 (not (equal ?\] (string-to-char (substring txt (match-end 0)))))
6087 (if (eq org-agenda-remove-times-when-in-prefix 'beg)
6088 (= (match-beginning 0) 0)
6089 t))
6090 (setq txt (replace-match "" nil nil txt))))
6091 ;; Normalize the time(s) to 24 hour
6092 (if s1 (setq s1 (org-get-time-of-day s1 'string t)))
6093 (if s2 (setq s2 (org-get-time-of-day s2 'string t)))
6094
6095 ;; Try to set s2 if s1 and `org-agenda-default-appointment-duration' are set
6096 (when (and s1 (not s2) org-agenda-default-appointment-duration)
6097 (setq s2
6098 (org-minutes-to-hh:mm-string
6099 (+ (org-hh:mm-string-to-minutes s1) org-agenda-default-appointment-duration))))
6100
6101 ;; Compute the duration
6102 (when s2
6103 (setq duration (- (org-hh:mm-string-to-minutes s2)
6104 (org-hh:mm-string-to-minutes s1)))))
6105
6106 (when (string-match (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@#%:]+:\\)[ \t]*$")
6107 txt)
6108 ;; Tags are in the string
6109 (if (or (eq org-agenda-remove-tags t)
6110 (and org-agenda-remove-tags
6111 org-prefix-has-tag))
6112 (setq txt (replace-match "" t t txt))
6113 (setq txt (replace-match
6114 (concat (make-string (max (- 50 (length txt)) 1) ?\ )
6115 (match-string 2 txt))
6116 t t txt))))
6117 (when (derived-mode-p 'org-mode)
c7cf0ebc 6118 (setq effort (ignore-errors (get-text-property 0 'org-effort txt)))
8223b1d2
BG
6119 (when effort
6120 (setq neffort (org-duration-string-to-minutes effort)
6121 effort (setq effort (concat "[" effort "]")))))
6122 ;; prevent erroring out with %e format when there is no effort
6123 (or effort (setq effort ""))
6124
6125 (when remove-re
6126 (while (string-match remove-re txt)
6127 (setq txt (replace-match "" t t txt))))
6128
6129 ;; Set org-heading property on `txt' to mark the start of the
6130 ;; heading.
6131 (add-text-properties 0 (length txt) '(org-heading t) txt)
6132
6133 ;; Prepare the variables needed in the eval of the compiled format
6134 (setq time (cond (s2 (concat
6135 (org-agenda-time-of-day-to-ampm-maybe s1)
6136 "-" (org-agenda-time-of-day-to-ampm-maybe s2)
6137 (if org-agenda-timegrid-use-ampm " ")))
6138 (s1 (concat
6139 (org-agenda-time-of-day-to-ampm-maybe s1)
6140 (if org-agenda-timegrid-use-ampm
6141 "........ "
6142 "......")))
6143 (t ""))
6144 extra (or (and (not habitp) extra) "")
6145 category (if (symbolp category) (symbol-name category) category)
6146 thecategory (copy-sequence category))
6147 (if (string-match org-bracket-link-regexp category)
6148 (progn
6149 (setq l (if (match-end 3)
6150 (- (match-end 3) (match-beginning 3))
6151 (- (match-end 1) (match-beginning 1))))
6152 (when (< l (or org-prefix-category-length 0))
6153 (setq category (copy-sequence category))
6154 (org-add-props category nil
6155 'extra-space (make-string
6156 (- org-prefix-category-length l 1) ?\ ))))
6157 (if (and org-prefix-category-max-length
6158 (>= (length category) org-prefix-category-max-length))
6159 (setq category (substring category 0 (1- org-prefix-category-max-length)))))
6160 ;; Evaluate the compiled format
6161 (setq rtn (concat (eval formatter) txt))
6162
6163 ;; And finally add the text properties
6164 (remove-text-properties 0 (length rtn) '(line-prefix t wrap-prefix t) rtn)
6165 (org-add-props rtn nil
6166 'org-category (if thecategory (downcase thecategory) category)
6167 'tags (mapcar 'org-downcase-keep-props tags)
6168 'org-highest-priority org-highest-priority
6169 'org-lowest-priority org-lowest-priority
6170 'time-of-day time-of-day
6171 'duration duration
6172 'effort effort
6173 'effort-minutes neffort
6174 'txt txt
6175 'time time
6176 'extra extra
6177 'format org-prefix-format-compiled
6178 'dotime dotime)))))
20908596 6179
5dec9555
CD
6180(defun org-agenda-fix-displayed-tags (txt tags add-inherited hide-re)
6181 "Remove tags string from TXT, and add a modified list of tags.
6182The modified list may contain inherited tags, and tags matched by
6183`org-agenda-hide-tags-regexp' will be removed."
6184 (when (or add-inherited hide-re)
afe98dfa 6185 (if (string-match (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@#%:]+:\\)[ \t]*$") txt)
5dec9555 6186 (setq txt (substring txt 0 (match-beginning 0))))
ed21c5c8
CD
6187 (setq tags
6188 (delq nil
6189 (mapcar (lambda (tg)
6190 (if (or (and hide-re (string-match hide-re tg))
6191 (and (not add-inherited)
6192 (get-text-property 0 'inherited tg)))
6193 nil
6194 tg))
6195 tags)))
5dec9555 6196 (when tags
5dec9555
CD
6197 (let ((have-i (get-text-property 0 'inherited (car tags)))
6198 i)
6199 (setq txt (concat txt " :"
6200 (mapconcat
6201 (lambda (x)
6202 (setq i (get-text-property 0 'inherited x))
6203 (if (and have-i (not i))
6204 (progn
6205 (setq have-i nil)
6206 (concat ":" x))
6207 x))
6208 tags ":")
6209 (if have-i "::" ":"))))))
8223b1d2 6210 txt)
ff4be292
CD
6211
6212(defun org-downcase-keep-props (s)
6213 (let ((props (text-properties-at 0 s)))
6214 (setq s (downcase s))
6215 (add-text-properties 0 (length s) props s)
6216 s))
6217
20908596
CD
6218(defvar org-agenda-sorting-strategy) ;; because the def is in a let form
6219(defvar org-agenda-sorting-strategy-selected nil)
6220
6221(defun org-agenda-add-time-grid-maybe (list ndays todayp)
6222 (catch 'exit
6223 (cond ((not org-agenda-use-time-grid) (throw 'exit list))
6224 ((and todayp (member 'today (car org-agenda-time-grid))))
6225 ((and (= ndays 1) (member 'daily (car org-agenda-time-grid))))
6226 ((member 'weekly (car org-agenda-time-grid)))
6227 (t (throw 'exit list)))
6228 (let* ((have (delq nil (mapcar
6229 (lambda (x) (get-text-property 1 'time-of-day x))
6230 list)))
6231 (string (nth 1 org-agenda-time-grid))
6232 (gridtimes (nth 2 org-agenda-time-grid))
6233 (req (car org-agenda-time-grid))
6234 (remove (member 'remove-match req))
6235 new time)
6236 (if (and (member 'require-timed req) (not have))
6237 ;; don't show empty grid
6238 (throw 'exit list))
6239 (while (setq time (pop gridtimes))
6240 (unless (and remove (member time have))
afe98dfa 6241 (setq time (replace-regexp-in-string " " "0" (format "%04s" time)))
e66ba1df 6242 (push (org-agenda-format-item
20908596
CD
6243 nil string "" nil
6244 (concat (substring time 0 -2) ":" (substring time -2)))
6245 new)
6246 (put-text-property
afe98dfa 6247 2 (length (car new)) 'face 'org-time-grid (car new))))
3ab2c837 6248 (when (and todayp org-agenda-show-current-time-in-grid)
e66ba1df 6249 (push (org-agenda-format-item
3ab2c837
BG
6250 nil
6251 org-agenda-current-time-string
6252 "" nil
6253 (format-time-string "%H:%M "))
6254 new)
6255 (put-text-property
6256 2 (length (car new)) 'face 'org-agenda-current-time (car new)))
6257
20908596
CD
6258 (if (member 'time-up org-agenda-sorting-strategy-selected)
6259 (append new list)
6260 (append list new)))))
6261
6262(defun org-compile-prefix-format (key)
6263 "Compile the prefix format into a Lisp form that can be evaluated.
8223b1d2
BG
6264The resulting form and associated variable bindings is returned
6265and stored in the variable `org-prefix-format-compiled'."
20908596 6266 (setq org-prefix-has-time nil org-prefix-has-tag nil
e66ba1df
BG
6267 org-prefix-category-length nil
6268 org-prefix-has-effort nil)
20908596
CD
6269 (let ((s (cond
6270 ((stringp org-agenda-prefix-format)
6271 org-agenda-prefix-format)
6272 ((assq key org-agenda-prefix-format)
6273 (cdr (assq key org-agenda-prefix-format)))
6274 (t " %-12:c%?-12t% s")))
6275 (start 0)
6276 varform vars var e c f opt)
3ab2c837 6277 (while (string-match "%\\(\\?\\)?\\([-+]?[0-9.]*\\)\\([ .;,:!?=|/<>]?\\)\\([ctsei]\\|(.+)\\)"
20908596 6278 s start)
3ab2c837
BG
6279 (setq var (or (cdr (assoc (match-string 4 s)
6280 '(("c" . category) ("t" . time) ("s" . extra)
6281 ("i" . category-icon) ("T" . tag) ("e" . effort))))
6282 'eval)
20908596
CD
6283 c (or (match-string 3 s) "")
6284 opt (match-beginning 1)
6285 start (1+ (match-beginning 0)))
6286 (if (equal var 'time) (setq org-prefix-has-time t))
6287 (if (equal var 'tag) (setq org-prefix-has-tag t))
6288 (if (equal var 'effort) (setq org-prefix-has-effort t))
6289 (setq f (concat "%" (match-string 2 s) "s"))
8bfe682a
CD
6290 (when (equal var 'category)
6291 (setq org-prefix-category-length
6292 (floor (abs (string-to-number (match-string 2 s)))))
6293 (setq org-prefix-category-max-length
6294 (let ((x (match-string 2 s)))
6295 (save-match-data
6296 (if (string-match "\\.[0-9]+" x)
6297 (string-to-number (substring (match-string 0 x) 1)))))))
3ab2c837
BG
6298 (if (eq var 'eval)
6299 (setq varform `(format ,f (org-eval ,(read (match-string 4 s)))))
6300 (if opt
6301 (setq varform
6302 `(if (equal "" ,var)
6303 ""
6304 (format ,f (if (equal "" ,var) "" (concat ,var ,c)))))
6305 (setq varform `(format ,f (if (equal ,var "") "" (concat ,var ,c (get-text-property 0 'extra-space ,var)))))))
20908596
CD
6306 (setq s (replace-match "%s" t nil s))
6307 (push varform vars))
6308 (setq vars (nreverse vars))
8223b1d2
BG
6309 (with-current-buffer (or org-agenda-buffer (current-buffer))
6310 (setq org-prefix-format-compiled
6311 (list
6312 `((org-prefix-has-time ,org-prefix-has-time)
6313 (org-prefix-has-tag ,org-prefix-has-tag)
6314 (org-prefix-category-length ,org-prefix-category-length)
6315 (org-prefix-has-effort ,org-prefix-has-effort))
6316 `(format ,s ,@vars))))))
20908596
CD
6317
6318(defun org-set-sorting-strategy (key)
6319 (if (symbolp (car org-agenda-sorting-strategy))
6320 ;; the old format
6321 (setq org-agenda-sorting-strategy-selected org-agenda-sorting-strategy)
6322 (setq org-agenda-sorting-strategy-selected
6323 (or (cdr (assq key org-agenda-sorting-strategy))
6324 (cdr (assq 'agenda org-agenda-sorting-strategy))
6325 '(time-up category-keep priority-down)))))
6326
6327(defun org-get-time-of-day (s &optional string mod24)
6328 "Check string S for a time of day.
6329If found, return it as a military time number between 0 and 2400.
6330If not found, return nil.
6331The optional STRING argument forces conversion into a 5 character wide string
6332HH:MM."
6333 (save-match-data
6334 (when
6335 (or (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)\\([AaPp][Mm]\\)?\\> *" s)
6336 (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?\\([AaPp][Mm]\\)\\> *" s))
8223b1d2
BG
6337 (let* ((h (string-to-number (match-string 1 s)))
6338 (m (if (match-end 3) (string-to-number (match-string 3 s)) 0))
6339 (ampm (if (match-end 4) (downcase (match-string 4 s))))
6340 (am-p (equal ampm "am"))
6341 (h1 (cond ((not ampm) h)
6342 ((= h 12) (if am-p 0 12))
6343 (t (+ h (if am-p 0 12)))))
6344 (h2 (if (and string mod24 (not (and (= m 0) (= h1 24))))
6345 (mod h1 24) h1))
6346 (t0 (+ (* 100 h2) m))
6347 (t1 (concat (if (>= h1 24) "+" " ")
6348 (if (and org-agenda-time-leading-zero
6349 (< t0 1000)) "0" "")
6350 (if (< t0 100) "0" "")
6351 (if (< t0 10) "0" "")
6352 (int-to-string t0))))
6353 (if string (concat (substring t1 -4 -2) ":" (substring t1 -2)) t0)))))
20908596 6354
afe98dfa
CD
6355(defvar org-agenda-before-sorting-filter-function nil
6356 "Function to be applied to agenda items prior to sorting.
6357Prior to sorting also means just before they are inserted into the agenda.
6358
6359To aid sorting, you may revisit the original entries and add more text
6360properties which will later be used by the sorting functions.
6361
6362The function should take a string argument, an agenda line.
6363It has access to the text properties in that line, which contain among
6364other things, the property `org-hd-marker' that points to the entry
6365where the line comes from. Note that not all lines going into the agenda
6366have this property, only most.
6367
6368The function should return the modified string. It is probably best
6369to ONLY change text properties.
6370
6371You can also use this function as a filter, by returning nil for lines
6372you don't want to have in the agenda at all. For this application, you
6373could bind the variable in the options section of a custom command.")
6374
8223b1d2 6375(defun org-agenda-finalize-entries (list &optional nosort)
20908596
CD
6376 "Sort and concatenate the agenda items."
6377 (setq list (mapcar 'org-agenda-highlight-todo list))
6378 (if nosort
6379 list
afe98dfa
CD
6380 (when org-agenda-before-sorting-filter-function
6381 (setq list (delq nil (mapcar org-agenda-before-sorting-filter-function list))))
20908596
CD
6382 (mapconcat 'identity (sort list 'org-entries-lessp) "\n")))
6383
6384(defun org-agenda-highlight-todo (x)
621f83e4 6385 (let ((org-done-keywords org-done-keywords-for-agenda)
ed21c5c8 6386 (case-fold-search nil)
e66ba1df 6387 re)
20908596
CD
6388 (if (eq x 'line)
6389 (save-excursion
6390 (beginning-of-line 1)
8d642074 6391 (setq re (org-get-at-bol 'org-todo-regexp))
3ab2c837 6392 (goto-char (or (text-property-any (point-at-bol) (point-at-eol) 'org-heading t) (point)))
621f83e4 6393 (when (looking-at (concat "[ \t]*\\.*\\(" re "\\) +"))
c8d0cf5c 6394 (add-text-properties (match-beginning 0) (match-end 1)
621f83e4 6395 (list 'face (org-get-todo-face 1)))
20908596
CD
6396 (let ((s (buffer-substring (match-beginning 1) (match-end 1))))
6397 (delete-region (match-beginning 1) (1- (match-end 0)))
6398 (goto-char (match-beginning 1))
6399 (insert (format org-agenda-todo-keyword-format s)))))
3ab2c837
BG
6400 (let ((pl (text-property-any 0 (length x) 'org-heading t x)))
6401 (setq re (get-text-property 0 'org-todo-regexp x))
6402 (when (and re
153ae947
BG
6403 ;; Test `pl' because if there's no heading content,
6404 ;; there's no point matching to highlight. Note
6405 ;; that if we didn't test `pl' first, and there
6406 ;; happened to be no keyword from `org-todo-regexp'
6407 ;; on this heading line, then the `equal' comparison
6408 ;; afterwards would spuriously succeed in the case
6409 ;; where `pl' is nil -- causing an args-out-of-range
6410 ;; error when we try to add text properties to text
6411 ;; that isn't there.
6412 pl
3ab2c837 6413 (equal (string-match (concat "\\(\\.*\\)" re "\\( +\\)")
153ae947 6414 x pl) pl))
3ab2c837
BG
6415 (add-text-properties
6416 (or (match-end 1) (match-end 0)) (match-end 0)
6417 (list 'face (org-get-todo-face (match-string 2 x)))
e66ba1df 6418 x)
3ab2c837
BG
6419 (when (match-end 1)
6420 (setq x (concat (substring x 0 (match-end 1))
6421 (format org-agenda-todo-keyword-format
6422 (match-string 2 x))
e66ba1df
BG
6423 (org-add-props " " (text-properties-at 0 x))
6424 (substring x (match-end 3)))))))
20908596
CD
6425 x)))
6426
6427(defsubst org-cmp-priority (a b)
6428 "Compare the priorities of string A and B."
6429 (let ((pa (or (get-text-property 1 'priority a) 0))
6430 (pb (or (get-text-property 1 'priority b) 0)))
6431 (cond ((> pa pb) +1)
8223b1d2 6432 ((< pa pb) -1))))
20908596
CD
6433
6434(defsubst org-cmp-effort (a b)
e66ba1df 6435 "Compare the effort values of string A and B."
20908596
CD
6436 (let* ((def (if org-sort-agenda-noeffort-is-high 32767 -1))
6437 (ea (or (get-text-property 1 'effort-minutes a) def))
6438 (eb (or (get-text-property 1 'effort-minutes b) def)))
6439 (cond ((> ea eb) +1)
8223b1d2 6440 ((< ea eb) -1))))
20908596
CD
6441
6442(defsubst org-cmp-category (a b)
6443 "Compare the string values of categories of strings A and B."
6444 (let ((ca (or (get-text-property 1 'org-category a) ""))
6445 (cb (or (get-text-property 1 'org-category b) "")))
6446 (cond ((string-lessp ca cb) -1)
8223b1d2 6447 ((string-lessp cb ca) +1))))
20908596 6448
621f83e4
CD
6449(defsubst org-cmp-todo-state (a b)
6450 "Compare the todo states of strings A and B."
c8d0cf5c
CD
6451 (let* ((ma (or (get-text-property 1 'org-marker a)
6452 (get-text-property 1 'org-hd-marker a)))
6453 (mb (or (get-text-property 1 'org-marker b)
6454 (get-text-property 1 'org-hd-marker b)))
6455 (fa (and ma (marker-buffer ma)))
6456 (fb (and mb (marker-buffer mb)))
6457 (todo-kwds
6458 (or (and fa (with-current-buffer fa org-todo-keywords-1))
6459 (and fb (with-current-buffer fb org-todo-keywords-1))))
6460 (ta (or (get-text-property 1 'todo-state a) ""))
621f83e4 6461 (tb (or (get-text-property 1 'todo-state b) ""))
c8d0cf5c
CD
6462 (la (- (length (member ta todo-kwds))))
6463 (lb (- (length (member tb todo-kwds))))
ff4be292 6464 (donepa (member ta org-done-keywords-for-agenda))
621f83e4
CD
6465 (donepb (member tb org-done-keywords-for-agenda)))
6466 (cond ((and donepa (not donepb)) -1)
6467 ((and (not donepa) donepb) +1)
6468 ((< la lb) -1)
8223b1d2 6469 ((< lb la) +1))))
621f83e4 6470
86fbb8ca
CD
6471(defsubst org-cmp-alpha (a b)
6472 "Compare the headlines, alphabetically."
3ab2c837
BG
6473 (let* ((pla (text-property-any 0 (length a) 'org-heading t a))
6474 (plb (text-property-any 0 (length b) 'org-heading t b))
86fbb8ca
CD
6475 (ta (and pla (substring a pla)))
6476 (tb (and plb (substring b plb))))
6477 (when pla
6478 (if (string-match (concat "\\`[ \t]*" (or (get-text-property 0 'org-todo-regexp a) "")
6479 "\\([ \t]*\\[[a-zA-Z0-9]\\]\\)? *") ta)
6480 (setq ta (substring ta (match-end 0))))
6481 (setq ta (downcase ta)))
6482 (when plb
6483 (if (string-match (concat "\\`[ \t]*" (or (get-text-property 0 'org-todo-regexp b) "")
6484 "\\([ \t]*\\[[a-zA-Z0-9]\\]\\)? *") tb)
6485 (setq tb (substring tb (match-end 0))))
6486 (setq tb (downcase tb)))
6487 (cond ((not ta) +1)
6488 ((not tb) -1)
6489 ((string-lessp ta tb) -1)
8223b1d2 6490 ((string-lessp tb ta) +1))))
86fbb8ca 6491
20908596 6492(defsubst org-cmp-tag (a b)
71d35b24 6493 "Compare the string values of the first tags of A and B."
20908596
CD
6494 (let ((ta (car (last (get-text-property 1 'tags a))))
6495 (tb (car (last (get-text-property 1 'tags b)))))
6496 (cond ((not ta) +1)
6497 ((not tb) -1)
6498 ((string-lessp ta tb) -1)
8223b1d2 6499 ((string-lessp tb ta) +1))))
20908596
CD
6500
6501(defsubst org-cmp-time (a b)
6502 "Compare the time-of-day values of strings A and B."
6503 (let* ((def (if org-sort-agenda-notime-is-late 9901 -1))
6504 (ta (or (get-text-property 1 'time-of-day a) def))
6505 (tb (or (get-text-property 1 'time-of-day b) def)))
6506 (cond ((< ta tb) -1)
8223b1d2 6507 ((< tb ta) +1))))
20908596 6508
8bfe682a
CD
6509(defsubst org-cmp-habit-p (a b)
6510 "Compare the todo states of strings A and B."
6511 (let ((ha (get-text-property 1 'org-habit-p a))
6512 (hb (get-text-property 1 'org-habit-p b)))
6513 (cond ((and ha (not hb)) -1)
8223b1d2 6514 ((and (not ha) hb) +1))))
8bfe682a 6515
86fbb8ca
CD
6516(defsubst org-em (x y list) (or (memq x list) (memq y list)))
6517
20908596
CD
6518(defun org-entries-lessp (a b)
6519 "Predicate for sorting agenda entries."
6520 ;; The following variables will be used when the form is evaluated.
6521 ;; So even though the compiler complains, keep them.
86fbb8ca
CD
6522 (let* ((ss org-agenda-sorting-strategy-selected)
6523 (time-up (and (org-em 'time-up 'time-down ss)
6524 (org-cmp-time a b)))
6525 (time-down (if time-up (- time-up) nil))
6526 (priority-up (and (org-em 'priority-up 'priority-down ss)
6527 (org-cmp-priority a b)))
6528 (priority-down (if priority-up (- priority-up) nil))
6529 (effort-up (and (org-em 'effort-up 'effort-down ss)
6530 (org-cmp-effort a b)))
6531 (effort-down (if effort-up (- effort-up) nil))
6532 (category-up (and (or (org-em 'category-up 'category-down ss)
6533 (memq 'category-keep ss))
6534 (org-cmp-category a b)))
6535 (category-down (if category-up (- category-up) nil))
6536 (category-keep (if category-up +1 nil))
6537 (tag-up (and (org-em 'tag-up 'tag-down ss)
6538 (org-cmp-tag a b)))
6539 (tag-down (if tag-up (- tag-up) nil))
6540 (todo-state-up (and (org-em 'todo-state-up 'todo-state-down ss)
6541 (org-cmp-todo-state a b)))
c8d0cf5c 6542 (todo-state-down (if todo-state-up (- todo-state-up) nil))
86fbb8ca
CD
6543 (habit-up (and (org-em 'habit-up 'habit-down ss)
6544 (org-cmp-habit-p a b)))
6545 (habit-down (if habit-up (- habit-up) nil))
6546 (alpha-up (and (org-em 'alpha-up 'alpha-down ss)
6547 (org-cmp-alpha a b)))
6548 (alpha-down (if alpha-up (- alpha-up) nil))
afe98dfa 6549 (need-user-cmp (org-em 'user-defined-up 'user-defined-down ss))
c8d0cf5c 6550 user-defined-up user-defined-down)
afe98dfa 6551 (if (and need-user-cmp org-agenda-cmp-user-defined
c8d0cf5c
CD
6552 (functionp org-agenda-cmp-user-defined))
6553 (setq user-defined-up
6554 (funcall org-agenda-cmp-user-defined a b)
6555 user-defined-down (if user-defined-up (- user-defined-up) nil)))
20908596
CD
6556 (cdr (assoc
6557 (eval (cons 'or org-agenda-sorting-strategy-selected))
6558 '((-1 . t) (1 . nil) (nil . nil))))))
6559
6560;;; Agenda restriction lock
6561
86fbb8ca 6562(defvar org-agenda-restriction-lock-overlay (make-overlay 1 1)
8bfe682a 6563 "Overlay to mark the headline to which agenda commands are restricted.")
86fbb8ca
CD
6564(overlay-put org-agenda-restriction-lock-overlay
6565 'face 'org-agenda-restriction-lock)
6566(overlay-put org-agenda-restriction-lock-overlay
6567 'help-echo "Agendas are currently limited to this subtree.")
20908596
CD
6568(org-detach-overlay org-agenda-restriction-lock-overlay)
6569
6570(defun org-agenda-set-restriction-lock (&optional type)
6571 "Set restriction lock for agenda, to current subtree or file.
6572Restriction will be the file if TYPE is `file', or if type is the
6573universal prefix '(4), or if the cursor is before the first headline
6574in the file. Otherwise, restriction will be to the current subtree."
6575 (interactive "P")
6576 (and (equal type '(4)) (setq type 'file))
6577 (setq type (cond
6578 (type type)
6579 ((org-at-heading-p) 'subtree)
6580 ((condition-case nil (org-back-to-heading t) (error nil))
6581 'subtree)
6582 (t 'file)))
6583 (if (eq type 'subtree)
6584 (progn
6585 (setq org-agenda-restrict t)
6586 (setq org-agenda-overriding-restriction 'subtree)
6587 (put 'org-agenda-files 'org-restrict
6588 (list (buffer-file-name (buffer-base-buffer))))
6589 (org-back-to-heading t)
86fbb8ca 6590 (move-overlay org-agenda-restriction-lock-overlay (point) (point-at-eol))
20908596
CD
6591 (move-marker org-agenda-restrict-begin (point))
6592 (move-marker org-agenda-restrict-end
6593 (save-excursion (org-end-of-subtree t)))
6594 (message "Locking agenda restriction to subtree"))
6595 (put 'org-agenda-files 'org-restrict
6596 (list (buffer-file-name (buffer-base-buffer))))
6597 (setq org-agenda-restrict nil)
6598 (setq org-agenda-overriding-restriction 'file)
6599 (move-marker org-agenda-restrict-begin nil)
6600 (move-marker org-agenda-restrict-end nil)
6601 (message "Locking agenda restriction to file"))
6602 (setq current-prefix-arg nil)
6603 (org-agenda-maybe-redo))
6604
6605(defun org-agenda-remove-restriction-lock (&optional noupdate)
6606 "Remove the agenda restriction lock."
6607 (interactive "P")
6608 (org-detach-overlay org-agenda-restriction-lock-overlay)
6609 (org-detach-overlay org-speedbar-restriction-lock-overlay)
6610 (setq org-agenda-overriding-restriction nil)
6611 (setq org-agenda-restrict nil)
6612 (put 'org-agenda-files 'org-restrict nil)
6613 (move-marker org-agenda-restrict-begin nil)
6614 (move-marker org-agenda-restrict-end nil)
6615 (setq current-prefix-arg nil)
6616 (message "Agenda restriction lock removed")
6617 (or noupdate (org-agenda-maybe-redo)))
6618
6619(defun org-agenda-maybe-redo ()
6620 "If there is any window showing the agenda view, update it."
6621 (let ((w (get-buffer-window org-agenda-buffer-name t))
6622 (w0 (selected-window)))
6623 (when w
6624 (select-window w)
6625 (org-agenda-redo)
6626 (select-window w0)
6627 (if org-agenda-overriding-restriction
6628 (message "Agenda view shifted to new %s restriction"
6629 org-agenda-overriding-restriction)
6630 (message "Agenda restriction lock removed")))))
6631
6632;;; Agenda commands
6633
6634(defun org-agenda-check-type (error &rest types)
6635 "Check if agenda buffer is of allowed type.
c7cf0ebc
BG
6636If ERROR is non-nil, throw an error, otherwise just return nil.
6637Allowed types are 'agenda 'timeline 'todo 'tags 'search."
8223b1d2
BG
6638 (if (not org-agenda-type)
6639 (error "No Org agenda currently displayed")
6640 (if (memq org-agenda-type types)
6641 t
6642 (if error
6643 (error "Not allowed in %s-type agenda buffers" org-agenda-type)
6644 nil))))
6645
6646(defun org-agenda-Quit (&optional arg)
20908596
CD
6647 "Exit agenda by removing the window or the buffer."
6648 (interactive)
6649 (if org-agenda-columns-active
6650 (org-columns-quit)
6651 (let ((buf (current-buffer)))
8d642074
CD
6652 (if (eq org-agenda-window-setup 'other-frame)
6653 (progn
8d642074 6654 (org-agenda-reset-markers)
8223b1d2 6655 (kill-buffer buf)
8d642074
CD
6656 (org-columns-remove-overlays)
6657 (setq org-agenda-archives-mode nil)
6658 (delete-frame))
6659 (and (not (eq org-agenda-window-setup 'current-window))
6660 (not (one-window-p))
6661 (delete-window))
8d642074 6662 (org-agenda-reset-markers)
8223b1d2 6663 (kill-buffer buf)
8d642074
CD
6664 (org-columns-remove-overlays)
6665 (setq org-agenda-archives-mode nil)))
20908596
CD
6666 ;; Maybe restore the pre-agenda window configuration.
6667 (and org-agenda-restore-windows-after-quit
6668 (not (eq org-agenda-window-setup 'other-frame))
8223b1d2
BG
6669 org-agenda-pre-window-conf
6670 (set-window-configuration org-agenda-pre-window-conf)
6671 (setq org-agenda-pre-window-conf nil))))
6672
6673(defun org-agenda-quit ()
6674 "Exit agenda by killing agenda buffer or burying it when
6675`org-agenda-sticky' is non-NIL"
6676 (interactive)
6677 (if (and (eq org-indirect-buffer-display 'other-window)
6678 org-last-indirect-buffer)
d3517077
BG
6679 (let ((org-last-indirect-window
6680 (get-buffer-window org-last-indirect-buffer)))
6681 (if org-last-indirect-window
6682 (delete-window org-last-indirect-window))))
8223b1d2
BG
6683 (if org-agenda-columns-active
6684 (org-columns-quit)
6685 (if org-agenda-sticky
6686 (let ((buf (current-buffer)))
6687 (if (eq org-agenda-window-setup 'other-frame)
6688 (progn
6689 (delete-frame))
6690 (and (not (eq org-agenda-window-setup 'current-window))
6691 (not (one-window-p))
6692 (delete-window)))
6693 (with-current-buffer buf
6694 (bury-buffer)
6695 ;; Maybe restore the pre-agenda window configuration.
6696 (and org-agenda-restore-windows-after-quit
6697 (not (eq org-agenda-window-setup 'other-frame))
6698 org-agenda-pre-window-conf
6699 (set-window-configuration org-agenda-pre-window-conf)
6700 (setq org-agenda-pre-window-conf nil))))
6701 (org-agenda-Quit))))
20908596
CD
6702
6703(defun org-agenda-exit ()
6704 "Exit agenda by removing the window or the buffer.
6705Also kill all Org-mode buffers which have been loaded by `org-agenda'.
6706Org-mode buffers visited directly by the user will not be touched."
6707 (interactive)
6708 (org-release-buffers org-agenda-new-buffers)
6709 (setq org-agenda-new-buffers nil)
8223b1d2
BG
6710 (org-agenda-Quit))
6711
6712(defun org-agenda-kill-all-agenda-buffers ()
735135f9 6713 "Kill all buffers in `org-agenda-mode'.
8223b1d2
BG
6714This is used when toggling sticky agendas. You can also explicitly invoke it
6715with `C-c a C-k'."
6716 (interactive)
6717 (let (blist)
6718 (dolist (buf (buffer-list))
6719 (when (with-current-buffer buf (eq major-mode 'org-agenda-mode))
6720 (push buf blist)))
6721 (mapc 'kill-buffer blist)))
20908596
CD
6722
6723(defun org-agenda-execute (arg)
86fbb8ca
CD
6724 "Execute another agenda command, keeping same window.
6725So this is just a shortcut for \\<global-map>`\\[org-agenda]', available
6726in the agenda."
20908596
CD
6727 (interactive "P")
6728 (let ((org-agenda-window-setup 'current-window))
6729 (org-agenda arg)))
6730
8223b1d2
BG
6731(defun org-agenda-redo (&optional all)
6732 "Rebuild possibly ALL agenda view(s) in the current buffer."
6733 (interactive "P")
6734 (let* ((p (or (and (looking-at "\\'") (1- (point))) (point)))
6735 (cpa (unless (eq all t) current-prefix-arg))
6736 (org-agenda-doing-sticky-redo org-agenda-sticky)
6737 (org-agenda-sticky nil)
6738 (org-agenda-buffer-name (or org-agenda-this-buffer-name
6739 org-agenda-buffer-name))
6740 (org-agenda-keep-modes t)
e66ba1df
BG
6741 (tag-filter org-agenda-tag-filter)
6742 (tag-preset (get 'org-agenda-tag-filter :preset-filter))
8223b1d2 6743 (top-cat-filter org-agenda-top-category-filter)
e66ba1df
BG
6744 (cat-filter org-agenda-category-filter)
6745 (cat-preset (get 'org-agenda-category-filter :preset-filter))
6746 (org-agenda-tag-filter-while-redo (or tag-filter tag-preset))
20908596
CD
6747 (cols org-agenda-columns-active)
6748 (line (org-current-line))
6749 (window-line (- line (org-current-line (window-start))))
8223b1d2
BG
6750 (lprops (get 'org-agenda-redo-command 'org-lprops))
6751 (redo-cmd (get-text-property p 'org-redo-cmd))
6752 (last-args (get-text-property p 'org-last-args))
735135f9 6753 (org-agenda-overriding-cmd (get-text-property p 'org-series-cmd))
8223b1d2
BG
6754 (org-agenda-overriding-cmd-arguments
6755 (unless (eq all t)
6756 (cond ((listp last-args)
6757 (cons (or cpa (car last-args)) (cdr last-args)))
6758 ((stringp last-args)
6759 last-args))))
735135f9 6760 (series-redo-cmd (get-text-property p 'org-series-redo-cmd)))
e66ba1df
BG
6761 (put 'org-agenda-tag-filter :preset-filter nil)
6762 (put 'org-agenda-category-filter :preset-filter nil)
20908596
CD
6763 (and cols (org-columns-quit))
6764 (message "Rebuilding agenda buffer...")
735135f9
PE
6765 (if series-redo-cmd
6766 (eval series-redo-cmd)
8223b1d2 6767 (org-let lprops '(eval redo-cmd)))
20908596
CD
6768 (setq org-agenda-undo-list nil
6769 org-agenda-pending-undo-list nil)
6770 (message "Rebuilding agenda buffer...done")
e66ba1df
BG
6771 (put 'org-agenda-tag-filter :preset-filter tag-preset)
6772 (put 'org-agenda-category-filter :preset-filter cat-preset)
6773 (and (or tag-filter tag-preset) (org-agenda-filter-apply tag-filter 'tag))
6774 (and (or cat-filter cat-preset) (org-agenda-filter-apply cat-filter 'category))
8223b1d2 6775 (and top-cat-filter (org-agenda-filter-top-category-apply top-cat-filter))
3ab2c837 6776 (and cols (org-called-interactively-p 'any) (org-agenda-columns))
54a0dee5 6777 (org-goto-line line)
20908596
CD
6778 (recenter window-line)))
6779
621f83e4 6780(defvar org-global-tags-completion-table nil)
71d35b24 6781(defvar org-agenda-filter-form nil)
153ae947 6782(defvar org-agenda-filtered-by-category nil)
e66ba1df
BG
6783
6784(defun org-agenda-filter-by-category (strip)
6785 "Keep only those lines in the agenda buffer that have a specific category.
6786The category is that of the current line."
6787 (interactive "P")
8223b1d2
BG
6788 (if (and org-agenda-filtered-by-category
6789 org-agenda-category-filter)
e66ba1df
BG
6790 (org-agenda-filter-show-all-cat)
6791 (let ((cat (org-no-properties (get-text-property (point) 'org-category))))
6792 (if cat (org-agenda-filter-apply
6793 (list (concat (if strip "-" "+") cat)) 'category)
6794 (error "No category at point")))))
6795
8223b1d2
BG
6796(defun org-find-top-category (&optional pos)
6797 (save-excursion
6798 (with-current-buffer (if pos (marker-buffer pos) (current-buffer))
6799 (if pos (goto-char pos))
6800 ;; Skip up to the topmost parent
6801 (while (ignore-errors (outline-up-heading 1) t))
6802 (ignore-errors
6803 (nth 4 (org-heading-components))))))
6804
6805(defvar org-agenda-filtered-by-top-category nil)
6806
6807(defun org-agenda-filter-by-top-category (strip)
6808 "Keep only those lines in the agenda buffer that have a specific category.
6809The category is that of the current line."
6810 (interactive "P")
6811 (if org-agenda-filtered-by-top-category
6812 (progn
6813 (setq org-agenda-filtered-by-top-category nil
6814 org-agenda-top-category-filter nil)
6815 (org-agenda-filter-show-all-cat))
6816 (let ((cat (org-find-top-category (org-get-at-bol 'org-hd-marker))))
6817 (if cat (org-agenda-filter-top-category-apply cat strip)
6818 (error "No top-level category at point")))))
6819
71d35b24 6820(defun org-agenda-filter-by-tag (strip &optional char narrow)
621f83e4
CD
6821 "Keep only those lines in the agenda buffer that have a specific tag.
6822The tag is selected with its fast selection letter, as configured.
71d35b24
CD
6823With prefix argument STRIP, remove all lines that do have the tag.
6824A lisp caller can specify CHAR. NARROW means that the new tag should be
6825used to narrow the search - the interactive user can also press `-' or `+'
6826to switch to narrowing."
621f83e4 6827 (interactive "P")
71d35b24 6828 (let* ((alist org-tag-alist-for-agenda)
8bfe682a
CD
6829 (tag-chars (mapconcat
6830 (lambda (x) (if (and (not (symbolp (car x)))
6831 (cdr x))
6832 (char-to-string (cdr x))
6833 ""))
6834 alist ""))
6835 (efforts (org-split-string
6836 (or (cdr (assoc (concat org-effort-property "_ALL")
6837 org-global-properties))
3ab2c837
BG
6838 "0 0:10 0:30 1:00 2:00 3:00 4:00 5:00 6:00 7:00 8:00"
6839 "")))
8bfe682a
CD
6840 (effort-op org-agenda-filter-effort-default-operator)
6841 (effort-prompt "")
6842 (inhibit-read-only t)
e66ba1df 6843 (current org-agenda-tag-filter)
3ab2c837 6844 maybe-refresh a n tag)
71d35b24 6845 (unless char
ff4be292 6846 (message
8bfe682a
CD
6847 "%s by tag [%s ], [TAB], %s[/]:off, [+-]:narrow, [>=<?]:effort: "
6848 (if narrow "Narrow" "Filter") tag-chars
6849 (if org-agenda-auto-exclude-function "[RET], " ""))
e66ba1df 6850 (setq char (read-char-exclusive)))
71d35b24
CD
6851 (when (member char '(?+ ?-))
6852 ;; Narrowing down
6853 (cond ((equal char ?-) (setq strip t narrow t))
6854 ((equal char ?+) (setq strip nil narrow t)))
ff4be292 6855 (message
71d35b24 6856 "Narrow by tag [%s ], [TAB], [/]:off, [>=<]:effort: " tag-chars)
e66ba1df 6857 (setq char (read-char-exclusive)))
c8d0cf5c 6858 (when (member char '(?< ?> ?= ??))
71d35b24
CD
6859 ;; An effort operator
6860 (setq effort-op (char-to-string char))
71d35b24 6861 (setq alist nil) ; to make sure it will be interpreted as effort.
c8d0cf5c
CD
6862 (unless (equal char ??)
6863 (loop for i from 0 to 9 do
6864 (setq effort-prompt
6865 (concat
6866 effort-prompt " ["
6867 (if (= i 9) "0" (int-to-string (1+ i)))
6868 "]" (nth i efforts))))
6869 (message "Effort%s: %s " effort-op effort-prompt)
e66ba1df 6870 (setq char (read-char-exclusive))
c8d0cf5c 6871 (when (or (< char ?0) (> char ?9))
8223b1d2 6872 (error "Need 1-9,0 to select effort"))))
71d35b24
CD
6873 (when (equal char ?\t)
6874 (unless (local-variable-p 'org-global-tags-completion-table (current-buffer))
6875 (org-set-local 'org-global-tags-completion-table
6876 (org-global-tags-completion-table)))
6877 (let ((completion-ignore-case t))
54a0dee5 6878 (setq tag (org-icompleting-read
71d35b24
CD
6879 "Tag: " org-global-tags-completion-table))))
6880 (cond
8bfe682a 6881 ((equal char ?\r)
e66ba1df 6882 (org-agenda-filter-show-all-tag)
8bfe682a 6883 (when org-agenda-auto-exclude-function
e66ba1df 6884 (setq org-agenda-tag-filter '())
ed21c5c8
CD
6885 (dolist (tag (org-agenda-get-represented-tags))
6886 (let ((modifier (funcall org-agenda-auto-exclude-function tag)))
8bfe682a 6887 (if modifier
e66ba1df
BG
6888 (push modifier org-agenda-tag-filter))))
6889 (if (not (null org-agenda-tag-filter))
6890 (org-agenda-filter-apply org-agenda-tag-filter 'tag)))
3ab2c837 6891 (setq maybe-refresh t))
c8d0cf5c 6892 ((equal char ?/)
e66ba1df
BG
6893 (org-agenda-filter-show-all-tag)
6894 (when (get 'org-agenda-tag-filter :preset-filter)
6895 (org-agenda-filter-apply org-agenda-tag-filter 'tag))
6896 (setq maybe-refresh t))
6897 ((equal char ?. )
6898 (setq org-agenda-tag-filter
6899 (mapcar (lambda(tag) (concat "+" tag))
6900 (org-get-at-bol 'tags)))
6901 (org-agenda-filter-apply org-agenda-tag-filter 'tag)
3ab2c837 6902 (setq maybe-refresh t))
71d35b24
CD
6903 ((or (equal char ?\ )
6904 (setq a (rassoc char alist))
6905 (and (>= char ?0) (<= char ?9)
6906 (setq n (if (= char ?0) 9 (- char ?0 1))
6907 tag (concat effort-op (nth n efforts))
6908 a (cons tag nil)))
c8d0cf5c
CD
6909 (and (= char ??)
6910 (setq tag "?eff")
6911 a (cons tag nil))
71d35b24 6912 (and tag (setq a (cons tag nil))))
e66ba1df 6913 (org-agenda-filter-show-all-tag)
71d35b24 6914 (setq tag (car a))
e66ba1df 6915 (setq org-agenda-tag-filter
71d35b24
CD
6916 (cons (concat (if strip "-" "+") tag)
6917 (if narrow current nil)))
e66ba1df 6918 (org-agenda-filter-apply org-agenda-tag-filter 'tag)
3ab2c837
BG
6919 (setq maybe-refresh t))
6920 (t (error "Invalid tag selection character %c" char)))
58e9b49a
BG
6921 (when (and maybe-refresh
6922 (eq org-agenda-clockreport-mode 'with-filter))
3ab2c837 6923 (org-agenda-redo))))
71d35b24 6924
ed21c5c8
CD
6925(defun org-agenda-get-represented-tags ()
6926 "Get a list of all tags currently represented in the agenda."
6927 (let (p tags)
6928 (save-excursion
6929 (goto-char (point-min))
6930 (while (setq p (next-single-property-change (point) 'tags))
6931 (goto-char p)
6932 (mapc (lambda (x) (add-to-list 'tags x))
6933 (get-text-property (point) 'tags))))
6934 tags))
6935
71d35b24 6936(defun org-agenda-filter-by-tag-refine (strip &optional char)
e66ba1df 6937 "Refine the current filter. See `org-agenda-filter-by-tag'."
71d35b24
CD
6938 (interactive "P")
6939 (org-agenda-filter-by-tag strip char 'refine))
6940
6941(defun org-agenda-filter-make-matcher ()
e66ba1df 6942 "Create the form that tests a line for agenda filter."
71d35b24 6943 (let (f f1)
e66ba1df
BG
6944 ;; first compute the tag-filter matcher
6945 (dolist (x (delete-dups
6946 (append (get 'org-agenda-tag-filter
6947 :preset-filter) org-agenda-tag-filter)))
71d35b24 6948 (if (member x '("-" "+"))
8bfe682a 6949 (setq f1 (if (equal x "-") 'tags '(not tags)))
c8d0cf5c 6950 (if (string-match "[<=>?]" x)
71d35b24
CD
6951 (setq f1 (org-agenda-filter-effort-form x))
6952 (setq f1 (list 'member (downcase (substring x 1)) 'tags)))
6953 (if (equal (string-to-char x) ?-)
6954 (setq f1 (list 'not f1))))
6955 (push f1 f))
e66ba1df
BG
6956 ;; then compute the category-filter matcher
6957 (dolist (x (delete-dups
6958 (append (get 'org-agenda-category-filter
6959 :preset-filter) org-agenda-category-filter)))
801a68c8
BG
6960 (if (equal "-" (substring x 0 1))
6961 (setq f1 (list 'not (list 'equal (substring x 1) 'cat)))
6962 (setq f1 (list 'equal (substring x 1) 'cat)))
e66ba1df 6963 (push f1 f))
71d35b24
CD
6964 (cons 'and (nreverse f))))
6965
6966(defun org-agenda-filter-effort-form (e)
6967 "Return the form to compare the effort of the current line with what E says.
86fbb8ca 6968E looks like \"+<2:25\"."
71d35b24
CD
6969 (let (op)
6970 (setq e (substring e 1))
6971 (setq op (string-to-char e) e (substring e 1))
c8d0cf5c
CD
6972 (setq op (cond ((equal op ?<) '<=)
6973 ((equal op ?>) '>=)
6974 ((equal op ??) op)
6975 (t '=)))
71d35b24 6976 (list 'org-agenda-compare-effort (list 'quote op)
3ab2c837 6977 (org-duration-string-to-minutes e))))
71d35b24
CD
6978
6979(defun org-agenda-compare-effort (op value)
6980 "Compare the effort of the current line with VALUE, using OP.
6981If the line does not have an effort defined, return nil."
8d642074 6982 (let ((eff (org-get-at-bol 'effort-minutes)))
c8d0cf5c
CD
6983 (if (equal op ??)
6984 (not eff)
6985 (funcall op (or eff (if org-sort-agenda-noeffort-is-high 32767 0))
6986 value))))
71d35b24 6987
e66ba1df 6988(defun org-agenda-filter-apply (filter type)
71d35b24 6989 "Set FILTER as the new agenda filter and apply it."
c74587e6 6990 (let (tags cat)
e66ba1df
BG
6991 (if (eq type 'tag)
6992 (setq org-agenda-tag-filter filter)
801a68c8 6993 (setq org-agenda-category-filter filter))
e66ba1df 6994 (setq org-agenda-filter-form (org-agenda-filter-make-matcher))
801a68c8
BG
6995 (if (and (eq type 'category)
6996 (not (equal (substring (car filter) 0 1) "-")))
6997 ;; Only set `org-agenda-filtered-by-category' to t
6998 ;; when a unique category is used as the filter
6999 (setq org-agenda-filtered-by-category t))
71d35b24
CD
7000 (org-agenda-set-mode-name)
7001 (save-excursion
7002 (goto-char (point-min))
7003 (while (not (eobp))
8d642074 7004 (if (org-get-at-bol 'org-marker)
71d35b24 7005 (progn
e66ba1df
BG
7006 (setq tags (org-get-at-bol 'tags) ; used in eval
7007 cat (get-text-property (point) 'org-category))
71d35b24 7008 (if (not (eval org-agenda-filter-form))
e66ba1df 7009 (org-agenda-filter-hide-line type))
71d35b24 7010 (beginning-of-line 2))
afe98dfa
CD
7011 (beginning-of-line 2))))
7012 (if (get-char-property (point) 'invisible)
801a68c8 7013 (ignore-errors (org-agenda-previous-line)))))
621f83e4 7014
8223b1d2
BG
7015(defun org-agenda-filter-top-category-apply (category &optional negative)
7016 "Set FILTER as the new agenda filter and apply it."
7017 (org-agenda-set-mode-name)
7018 (save-excursion
7019 (goto-char (point-min))
7020 (while (not (eobp))
7021 (let* ((pos (org-get-at-bol 'org-hd-marker))
7022 (topcat (and pos (org-find-top-category pos))))
7023 (if (and topcat (funcall (if negative 'identity 'not)
7024 (string= category topcat)))
7025 (org-agenda-filter-hide-line 'category)))
7026 (beginning-of-line 2)))
7027 (if (get-char-property (point) 'invisible)
7028 (org-agenda-previous-line))
7029 (setq org-agenda-top-category-filter category
7030 org-agenda-filtered-by-top-category t))
7031
e66ba1df 7032(defun org-agenda-filter-hide-line (type)
621f83e4 7033 (let (ov)
86fbb8ca 7034 (setq ov (make-overlay (max (point-min) (1- (point-at-bol)))
8223b1d2 7035 (point-at-eol)))
86fbb8ca 7036 (overlay-put ov 'invisible t)
e66ba1df
BG
7037 (overlay-put ov 'type type)
7038 (if (eq type 'tag)
7039 (push ov org-agenda-tag-filter-overlays)
7040 (push ov org-agenda-cat-filter-overlays))))
621f83e4 7041
71d35b24
CD
7042(defun org-agenda-fix-tags-filter-overlays-at (&optional pos)
7043 (setq pos (or pos (point)))
7044 (save-excursion
86fbb8ca
CD
7045 (dolist (ov (overlays-at pos))
7046 (when (and (overlay-get ov 'invisible)
e66ba1df 7047 (eq (overlay-get ov 'type) 'tag))
71d35b24 7048 (goto-char pos)
86fbb8ca
CD
7049 (if (< (overlay-start ov) (point-at-eol))
7050 (move-overlay ov (point-at-eol)
8223b1d2 7051 (overlay-end ov)))))))
71d35b24 7052
e66ba1df
BG
7053(defun org-agenda-filter-show-all-tag nil
7054 (mapc 'delete-overlay org-agenda-tag-filter-overlays)
7055 (setq org-agenda-tag-filter-overlays nil
7056 org-agenda-tag-filter nil
7057 org-agenda-filter-form nil)
7058 (org-agenda-set-mode-name))
7059
7060(defun org-agenda-filter-show-all-cat nil
7061 (mapc 'delete-overlay org-agenda-cat-filter-overlays)
7062 (setq org-agenda-cat-filter-overlays nil
7063 org-agenda-filtered-by-category nil
7064 org-agenda-category-filter nil
7065 org-agenda-filter-form nil)
71d35b24 7066 (org-agenda-set-mode-name))
621f83e4 7067
20908596
CD
7068(defun org-agenda-manipulate-query-add ()
7069 "Manipulate the query by adding a search term with positive selection.
ed21c5c8 7070Positive selection means the term must be matched for selection of an entry."
20908596
CD
7071 (interactive)
7072 (org-agenda-manipulate-query ?\[))
7073(defun org-agenda-manipulate-query-subtract ()
7074 "Manipulate the query by adding a search term with negative selection.
ed21c5c8 7075Negative selection means term must not be matched for selection of an entry."
20908596
CD
7076 (interactive)
7077 (org-agenda-manipulate-query ?\]))
7078(defun org-agenda-manipulate-query-add-re ()
7079 "Manipulate the query by adding a search regexp with positive selection.
ed21c5c8 7080Positive selection means the regexp must match for selection of an entry."
20908596
CD
7081 (interactive)
7082 (org-agenda-manipulate-query ?\{))
7083(defun org-agenda-manipulate-query-subtract-re ()
7084 "Manipulate the query by adding a search regexp with negative selection.
ed21c5c8 7085Negative selection means regexp must not match for selection of an entry."
20908596
CD
7086 (interactive)
7087 (org-agenda-manipulate-query ?\}))
7088(defun org-agenda-manipulate-query (char)
7089 (cond
7090 ((memq org-agenda-type '(timeline agenda))
54a0dee5
CD
7091 (let ((org-agenda-include-inactive-timestamps t))
7092 (org-agenda-redo))
7093 (message "Display now includes inactive timestamps as well"))
20908596
CD
7094 ((eq org-agenda-type 'search)
7095 (org-add-to-string
7096 'org-agenda-query-string
ed21c5c8
CD
7097 (if org-agenda-last-search-view-search-was-boolean
7098 (cdr (assoc char '((?\[ . " +") (?\] . " -")
7099 (?\{ . " +{}") (?\} . " -{}"))))
7100 " "))
20908596
CD
7101 (setq org-agenda-redo-command
7102 (list 'org-search-view
8223b1d2
BG
7103 (car (get-text-property (min (1- (point-max)) (point))
7104 'org-last-args))
20908596
CD
7105 org-agenda-query-string
7106 (+ (length org-agenda-query-string)
7107 (if (member char '(?\{ ?\})) 0 1))))
7108 (set-register org-agenda-query-register org-agenda-query-string)
8223b1d2
BG
7109 (let ((org-agenda-overriding-arguments
7110 (cdr org-agenda-redo-command)))
7111 (org-agenda-redo)))
20908596
CD
7112 (t (error "Cannot manipulate query for %s-type agenda buffers"
7113 org-agenda-type))))
7114
7115(defun org-add-to-string (var string)
7116 (set var (concat (symbol-value var) string)))
7117
8223b1d2 7118(defun org-agenda-goto-date (span)
20908596 7119 "Jump to DATE in agenda."
8223b1d2
BG
7120 (interactive "P")
7121 (let* ((org-read-date-prefer-future
7122 (eval org-agenda-jump-prefer-future))
7123 (date (org-read-date))
7124 (org-agenda-sticky-orig org-agenda-sticky)
7125 (org-agenda-buffer-tmp-name (buffer-name))
7126 (args (get-text-property (min (1- (point-max)) (point)) 'org-last-args))
7127 (0-arg (or current-prefix-arg (car args)))
7128 (2-arg (nth 2 args))
7129 (newcmd (list 'org-agenda-list 0-arg date
7130 (org-agenda-span-to-ndays 2-arg)))
7131 (newargs (cdr newcmd))
7132 (inhibit-read-only t)
7133 org-agenda-sticky)
7134 (if (not (org-agenda-check-type t 'agenda))
7135 (error "Not available in non-agenda blocks")
7136 (add-text-properties (point-min) (point-max)
7137 `(org-redo-cmd ,newcmd org-last-args ,newargs))
7138 (org-agenda-redo)
7139 (setq org-agenda-sticky org-agenda-sticky-orig
7140 org-agenda-this-buffer-is-sticky org-agenda-sticky))))
20908596
CD
7141
7142(defun org-agenda-goto-today ()
7143 "Go to today."
7144 (interactive)
7145 (org-agenda-check-type t 'timeline 'agenda)
8223b1d2
BG
7146 (let* ((args (get-text-property (min (1- (point-max)) (point)) 'org-last-args))
7147 (curspan (nth 2 args))
7148 (tdpos (text-property-any (point-min) (point-max) 'org-today t)))
20908596
CD
7149 (cond
7150 (tdpos (goto-char tdpos))
7151 ((eq org-agenda-type 'agenda)
acedf35c 7152 (let* ((sd (org-agenda-compute-starting-span
8223b1d2
BG
7153 (org-today) (or curspan org-agenda-ndays org-agenda-span)))
7154 (org-agenda-overriding-arguments args))
acedf35c 7155 (setf (nth 1 org-agenda-overriding-arguments) sd)
20908596
CD
7156 (org-agenda-redo)
7157 (org-agenda-find-same-or-today-or-agenda)))
7158 (t (error "Cannot find today")))))
7159
7160(defun org-agenda-find-same-or-today-or-agenda (&optional cnt)
7161 (goto-char
7162 (or (and cnt (text-property-any (point-min) (point-max) 'org-day-cnt cnt))
7163 (text-property-any (point-min) (point-max) 'org-today t)
7164 (text-property-any (point-min) (point-max) 'org-agenda-type 'agenda)
735135f9 7165 (and (get-text-property (min (1- (point-max)) (point)) 'org-series)
8223b1d2 7166 (org-agenda-goto-block-beginning))
20908596
CD
7167 (point-min))))
7168
8223b1d2
BG
7169(defun org-agenda-goto-block-beginning ()
7170 "Go the agenda block beginning."
7171 (interactive)
7172 (if (not (derived-mode-p 'org-agenda-mode))
7173 (error "Cannot execute this command outside of org-agenda-mode buffers")
7174 (let (dest)
7175 (save-excursion
7176 (unless (looking-at "\\'")
7177 (forward-char))
7178 (let* ((prop 'org-agenda-structural-header)
7179 (p (previous-single-property-change (point) prop))
7180 (n (next-single-property-change (or (and (looking-at "\\`") 1)
7181 (1- (point))) prop)))
7182 (setq dest (cond ((eq n (point-at-eol)) (1- n)) (p (1- p))))))
7183 (if (not dest)
7184 (error "Cannot find the beginning of the blog")
7185 (goto-char dest)
7186 (move-beginning-of-line 1)))))
7187
20908596 7188(defun org-agenda-later (arg)
bdebdb64 7189 "Go forward in time by the current span.
20908596
CD
7190With prefix ARG, go forward that many times the current span."
7191 (interactive "p")
7192 (org-agenda-check-type t 'agenda)
8223b1d2
BG
7193 (let* ((args (get-text-property (min (1- (point-max)) (point)) 'org-last-args))
7194 (span (or (nth 2 args) org-agenda-current-span))
7195 (sd (or (nth 1 args) (org-get-at-bol 'day) org-starting-day))
20908596 7196 (greg (calendar-gregorian-from-absolute sd))
8d642074 7197 (cnt (org-get-at-bol 'org-day-cnt))
acedf35c 7198 greg2)
20908596 7199 (cond
8223b1d2 7200 ((numberp span)
bdebdb64 7201 (setq sd (+ (* span arg) sd)))
20908596 7202 ((eq span 'day)
acedf35c 7203 (setq sd (+ arg sd)))
20908596 7204 ((eq span 'week)
acedf35c 7205 (setq sd (+ (* 7 arg) sd)))
20908596
CD
7206 ((eq span 'month)
7207 (setq greg2 (list (+ (car greg) arg) (nth 1 greg) (nth 2 greg))
7208 sd (calendar-absolute-from-gregorian greg2))
acedf35c 7209 (setcar greg2 (1+ (car greg2))))
20908596
CD
7210 ((eq span 'year)
7211 (setq greg2 (list (car greg) (nth 1 greg) (+ arg (nth 2 greg)))
7212 sd (calendar-absolute-from-gregorian greg2))
acedf35c
CD
7213 (setcar (nthcdr 2 greg2) (1+ (nth 2 greg2))))
7214 (t
7215 (setq sd (+ (* span arg) sd))))
8223b1d2
BG
7216 (let ((org-agenda-overriding-cmd
7217 ;; `cmd' may have been set by `org-agenda-run-series' which
7218 ;; uses `org-agenda-overriding-cmd' to decide whether
7219 ;; overriding is allowed for `cmd'
735135f9 7220 (get-text-property (min (1- (point-max)) (point)) 'org-series-cmd))
8223b1d2
BG
7221 (org-agenda-overriding-arguments
7222 (list (car args) sd span)))
20908596
CD
7223 (org-agenda-redo)
7224 (org-agenda-find-same-or-today-or-agenda cnt))))
7225
7226(defun org-agenda-earlier (arg)
7227 "Go backward in time by the current span.
7228With prefix ARG, go backward that many times the current span."
7229 (interactive "p")
7230 (org-agenda-later (- arg)))
7231
c8d0cf5c
CD
7232(defun org-agenda-view-mode-dispatch ()
7233 "Call one of the view mode commands."
7234 (interactive)
8223b1d2
BG
7235 (message "View: [d]ay [w]eek [m]onth [y]ear [SPC]reset [q]uit/abort
7236 time[G]rid [[]inactive [f]ollow [l]og [L]og-all [c]lockcheck
7237 [a]rch-trees [A]rch-files clock[R]eport include[D]iary [E]ntryText")
c8d0cf5c
CD
7238 (let ((a (read-char-exclusive)))
7239 (case a
3ab2c837 7240 (?\ (call-interactively 'org-agenda-reset-view))
c8d0cf5c
CD
7241 (?d (call-interactively 'org-agenda-day-view))
7242 (?w (call-interactively 'org-agenda-week-view))
7243 (?m (call-interactively 'org-agenda-month-view))
7244 (?y (call-interactively 'org-agenda-year-view))
7245 (?l (call-interactively 'org-agenda-log-mode))
ed21c5c8 7246 (?L (org-agenda-log-mode '(4)))
3ab2c837 7247 (?c (org-agenda-log-mode 'clockcheck))
54a0dee5 7248 ((?F ?f) (call-interactively 'org-agenda-follow-mode))
c8d0cf5c
CD
7249 (?a (call-interactively 'org-agenda-archives-mode))
7250 (?A (org-agenda-archives-mode 'files))
54a0dee5
CD
7251 ((?R ?r) (call-interactively 'org-agenda-clockreport-mode))
7252 ((?E ?e) (call-interactively 'org-agenda-entry-text-mode))
c8d0cf5c
CD
7253 (?G (call-interactively 'org-agenda-toggle-time-grid))
7254 (?D (call-interactively 'org-agenda-toggle-diary))
ed21c5c8 7255 (?\! (call-interactively 'org-agenda-toggle-deadlines))
54a0dee5
CD
7256 (?\[ (let ((org-agenda-include-inactive-timestamps t))
7257 (org-agenda-check-type t 'timeline 'agenda)
7258 (org-agenda-redo))
7259 (message "Display now includes inactive timestamps as well"))
c8d0cf5c
CD
7260 (?q (message "Abort"))
7261 (otherwise (error "Invalid key" )))))
7262
3ab2c837
BG
7263(defun org-agenda-reset-view ()
7264 "Switch to default view for agenda."
7265 (interactive)
7266 (org-agenda-change-time-span (or org-agenda-ndays org-agenda-span)))
20908596
CD
7267(defun org-agenda-day-view (&optional day-of-year)
7268 "Switch to daily view for agenda.
7269With argument DAY-OF-YEAR, switch to that day of the year."
7270 (interactive "P")
20908596
CD
7271 (org-agenda-change-time-span 'day day-of-year))
7272(defun org-agenda-week-view (&optional iso-week)
7273 "Switch to daily view for agenda.
7274With argument ISO-WEEK, switch to the corresponding ISO week.
7275If ISO-WEEK has more then 2 digits, only the last two encode the
7276week. Any digits before this encode a year. So 200712 means
7277week 12 of year 2007. Years in the range 1938-2037 can also be
7278written as 2-digit years."
7279 (interactive "P")
20908596
CD
7280 (org-agenda-change-time-span 'week iso-week))
7281(defun org-agenda-month-view (&optional month)
b349f79f 7282 "Switch to monthly view for agenda.
20908596
CD
7283With argument MONTH, switch to that month."
7284 (interactive "P")
7285 (org-agenda-change-time-span 'month month))
7286(defun org-agenda-year-view (&optional year)
b349f79f 7287 "Switch to yearly view for agenda.
20908596
CD
7288With argument YEAR, switch to that year.
7289If MONTH has more then 2 digits, only the last two encode the
7290month. Any digits before this encode a year. So 200712 means
7291December year 2007. Years in the range 1938-2037 can also be
7292written as 2-digit years."
7293 (interactive "P")
7294 (when year
7295 (setq year (org-small-year-to-year year)))
7296 (if (y-or-n-p "Are you sure you want to compute the agenda for an entire year? ")
7297 (org-agenda-change-time-span 'year year)
7298 (error "Abort")))
7299
7300(defun org-agenda-change-time-span (span &optional n)
7301 "Change the agenda view to SPAN.
7302SPAN may be `day', `week', `month', `year'."
7303 (org-agenda-check-type t 'agenda)
8223b1d2
BG
7304 (let* ((args (get-text-property (min (1- (point-max)) (point)) 'org-last-args))
7305 (curspan (nth 2 args)))
7306 (if (and (not n) (equal curspan span))
7307 (error "Viewing span is already \"%s\"" span))
7308 (let* ((sd (or (org-get-at-bol 'day)
7309 (nth 1 args)
7310 org-starting-day))
7311 (sd (org-agenda-compute-starting-span sd span n))
7312 (org-agenda-overriding-cmd
735135f9 7313 (get-text-property (min (1- (point-max)) (point)) 'org-series-cmd))
8223b1d2
BG
7314 (org-agenda-overriding-arguments
7315 (list (car args) sd span)))
7316 (org-agenda-redo)
7317 (org-agenda-find-same-or-today-or-agenda))
7318 (org-agenda-set-mode-name)
7319 (message "Switched to %s view" span)))
20908596 7320
acedf35c
CD
7321(defun org-agenda-compute-starting-span (sd span &optional n)
7322 "Compute starting date for agenda.
20908596
CD
7323SPAN may be `day', `week', `month', `year'. The return value
7324is a cons cell with the starting date and the number of days,
7325so that the date SD will be in that range."
7326 (let* ((greg (calendar-gregorian-from-absolute sd))
7327 (dg (nth 1 greg))
7328 (mg (car greg))
acedf35c 7329 (yg (nth 2 greg)))
20908596
CD
7330 (cond
7331 ((eq span 'day)
7332 (when n
7333 (setq sd (+ (calendar-absolute-from-gregorian
7334 (list mg 1 yg))
acedf35c 7335 n -1))))
20908596
CD
7336 ((eq span 'week)
7337 (let* ((nt (calendar-day-of-week
7338 (calendar-gregorian-from-absolute sd)))
7339 (d (if org-agenda-start-on-weekday
7340 (- nt org-agenda-start-on-weekday)
acedf35c
CD
7341 0))
7342 y1)
20908596
CD
7343 (setq sd (- sd (+ (if (< d 0) 7 0) d)))
7344 (when n
7345 (require 'cal-iso)
20908596
CD
7346 (when (> n 99)
7347 (setq y1 (org-small-year-to-year (/ n 100))
7348 n (mod n 100)))
7349 (setq sd
7350 (calendar-absolute-from-iso
7351 (list n 1
acedf35c 7352 (or y1 (nth 2 (calendar-iso-from-absolute sd)))))))))
20908596 7353 ((eq span 'month)
acedf35c
CD
7354 (let (y1)
7355 (when (and n (> n 99))
7356 (setq y1 (org-small-year-to-year (/ n 100))
7357 n (mod n 100)))
7358 (setq sd (calendar-absolute-from-gregorian
7359 (list (or n mg) 1 (or y1 yg))))))
20908596
CD
7360 ((eq span 'year)
7361 (setq sd (calendar-absolute-from-gregorian
acedf35c
CD
7362 (list 1 1 (or n yg))))))
7363 sd))
20908596
CD
7364
7365(defun org-agenda-next-date-line (&optional arg)
7366 "Jump to the next line indicating a date in agenda buffer."
7367 (interactive "p")
7368 (org-agenda-check-type t 'agenda 'timeline)
7369 (beginning-of-line 1)
7370 ;; This does not work if user makes date format that starts with a blank
7371 (if (looking-at "^\\S-") (forward-char 1))
7372 (if (not (re-search-forward "^\\S-" nil t arg))
7373 (progn
7374 (backward-char 1)
7375 (error "No next date after this line in this buffer")))
7376 (goto-char (match-beginning 0)))
7377
7378(defun org-agenda-previous-date-line (&optional arg)
7379 "Jump to the previous line indicating a date in agenda buffer."
7380 (interactive "p")
7381 (org-agenda-check-type t 'agenda 'timeline)
7382 (beginning-of-line 1)
7383 (if (not (re-search-backward "^\\S-" nil t arg))
7384 (error "No previous date before this line in this buffer")))
7385
7386;; Initialize the highlight
86fbb8ca
CD
7387(defvar org-hl (make-overlay 1 1))
7388(overlay-put org-hl 'face 'highlight)
20908596
CD
7389
7390(defun org-highlight (begin end &optional buffer)
7391 "Highlight a region with overlay."
86fbb8ca 7392 (move-overlay org-hl begin end (or buffer (current-buffer))))
20908596
CD
7393
7394(defun org-unhighlight ()
7395 "Detach overlay INDEX."
86fbb8ca 7396 (org-detach-overlay org-hl))
20908596 7397
20908596
CD
7398(defun org-unhighlight-once ()
7399 "Remove the highlight from its position, and this function from the hook."
7400 (remove-hook 'pre-command-hook 'org-unhighlight-once)
7401 (org-unhighlight))
7402
8223b1d2 7403(defvar org-agenda-pre-follow-window-conf nil)
20908596
CD
7404(defun org-agenda-follow-mode ()
7405 "Toggle follow mode in an agenda buffer."
7406 (interactive)
8223b1d2
BG
7407 (unless org-agenda-follow-mode
7408 (setq org-agenda-pre-follow-window-conf
7409 (current-window-configuration)))
20908596 7410 (setq org-agenda-follow-mode (not org-agenda-follow-mode))
8223b1d2
BG
7411 (unless org-agenda-follow-mode
7412 (set-window-configuration org-agenda-pre-follow-window-conf))
20908596 7413 (org-agenda-set-mode-name)
e66ba1df 7414 (org-agenda-do-context-action)
20908596
CD
7415 (message "Follow mode is %s"
7416 (if org-agenda-follow-mode "on" "off")))
7417
54a0dee5
CD
7418(defun org-agenda-entry-text-mode (&optional arg)
7419 "Toggle entry text mode in an agenda buffer."
7420 (interactive "P")
365f8d85
SM
7421 (setq org-agenda-entry-text-mode (or (integerp arg)
7422 (not org-agenda-entry-text-mode)))
54a0dee5
CD
7423 (org-agenda-entry-text-hide)
7424 (and org-agenda-entry-text-mode
7425 (let ((org-agenda-entry-text-maxlines
7426 (if (integerp arg) arg org-agenda-entry-text-maxlines)))
7427 (org-agenda-entry-text-show)))
7428 (org-agenda-set-mode-name)
7429 (message "Entry text mode is %s. Maximum number of lines is %d"
7430 (if org-agenda-entry-text-mode "on" "off")
7431 (if (integerp arg) arg org-agenda-entry-text-maxlines)))
7432
acedf35c
CD
7433(defun org-agenda-clockreport-mode (&optional with-filter)
7434 "Toggle clocktable mode in an agenda buffer.
7435With prefix arg WITH-FILTER, make the clocktable respect the current
7436agenda filter."
7437 (interactive "P")
20908596 7438 (org-agenda-check-type t 'agenda)
acedf35c
CD
7439 (if with-filter
7440 (setq org-agenda-clockreport-mode 'with-filter)
7441 (setq org-agenda-clockreport-mode (not org-agenda-clockreport-mode)))
20908596
CD
7442 (org-agenda-set-mode-name)
7443 (org-agenda-redo)
7444 (message "Clocktable mode is %s"
7445 (if org-agenda-clockreport-mode "on" "off")))
7446
93b62de8
CD
7447(defun org-agenda-log-mode (&optional special)
7448 "Toggle log mode in an agenda buffer.
7449With argument SPECIAL, show all possible log items, not only the ones
7450configured in `org-agenda-log-mode-items'.
7451With a double `C-u' prefix arg, show *only* log items, nothing else."
7452 (interactive "P")
20908596 7453 (org-agenda-check-type t 'agenda 'timeline)
93b62de8 7454 (setq org-agenda-show-log
3ab2c837
BG
7455 (cond
7456 ((equal special '(16)) 'only)
7457 ((eq special 'clockcheck)
7458 (if (eq org-agenda-show-log 'clockcheck)
7459 nil 'clockcheck))
7460 (special '(closed clock state))
7461 (t (not org-agenda-show-log))))
20908596
CD
7462 (org-agenda-set-mode-name)
7463 (org-agenda-redo)
7464 (message "Log mode is %s"
7465 (if org-agenda-show-log "on" "off")))
7466
2c3ad40d 7467(defun org-agenda-archives-mode (&optional with-files)
c8d0cf5c
CD
7468 "Toggle inclusion of items in trees marked with :ARCHIVE:.
7469When called with a prefix argument, include all archive files as well."
2c3ad40d
CD
7470 (interactive "P")
7471 (setq org-agenda-archives-mode
7472 (if with-files t (if org-agenda-archives-mode nil 'trees)))
7473 (org-agenda-set-mode-name)
7474 (org-agenda-redo)
7475 (message
7476 "%s"
7477 (cond
7478 ((eq org-agenda-archives-mode nil)
7479 "No archives are included")
7480 ((eq org-agenda-archives-mode 'trees)
7481 (format "Trees with :%s: tag are included" org-archive-tag))
7482 ((eq org-agenda-archives-mode t)
7483 (format "Trees with :%s: tag and all active archive files are included"
7484 org-archive-tag)))))
7485
20908596
CD
7486(defun org-agenda-toggle-diary ()
7487 "Toggle diary inclusion in an agenda buffer."
7488 (interactive)
7489 (org-agenda-check-type t 'agenda)
7490 (setq org-agenda-include-diary (not org-agenda-include-diary))
7491 (org-agenda-redo)
7492 (org-agenda-set-mode-name)
7493 (message "Diary inclusion turned %s"
7494 (if org-agenda-include-diary "on" "off")))
7495
ed21c5c8 7496(defun org-agenda-toggle-deadlines ()
acedf35c 7497 "Toggle inclusion of entries with a deadline in an agenda buffer."
ed21c5c8
CD
7498 (interactive)
7499 (org-agenda-check-type t 'agenda)
7500 (setq org-agenda-include-deadlines (not org-agenda-include-deadlines))
7501 (org-agenda-redo)
7502 (org-agenda-set-mode-name)
7503 (message "Deadlines inclusion turned %s"
7504 (if org-agenda-include-deadlines "on" "off")))
7505
20908596
CD
7506(defun org-agenda-toggle-time-grid ()
7507 "Toggle time grid in an agenda buffer."
7508 (interactive)
7509 (org-agenda-check-type t 'agenda)
7510 (setq org-agenda-use-time-grid (not org-agenda-use-time-grid))
7511 (org-agenda-redo)
7512 (org-agenda-set-mode-name)
7513 (message "Time-grid turned %s"
7514 (if org-agenda-use-time-grid "on" "off")))
7515
7516(defun org-agenda-set-mode-name ()
7517 "Set the mode name to indicate all the small mode settings."
7518 (setq mode-name
acedf35c
CD
7519 (list "Org-Agenda"
7520 (if (get 'org-agenda-files 'org-restrict) " []" "")
7521 " "
7522 '(:eval (org-agenda-span-name org-agenda-current-span))
7523 (if org-agenda-follow-mode " Follow" "")
7524 (if org-agenda-entry-text-mode " ETxt" "")
7525 (if org-agenda-include-diary " Diary" "")
7526 (if org-agenda-include-deadlines " Ddl" "")
7527 (if org-agenda-use-time-grid " Grid" "")
7528 (if (and (boundp 'org-habit-show-habits)
7529 org-habit-show-habits) " Habit" "")
3ab2c837
BG
7530 (cond
7531 ((consp org-agenda-show-log) " LogAll")
7532 ((eq org-agenda-show-log 'clockcheck) " ClkCk")
7533 (org-agenda-show-log " Log")
7534 (t ""))
e66ba1df
BG
7535 (if (or org-agenda-category-filter (get 'org-agenda-category-filter
7536 :preset-filter))
7537 '(:eval (org-propertize
7538 (concat " <"
7539 (mapconcat
7540 'identity
7541 (append
7542 (get 'org-agenda-category-filter :preset-filter)
7543 org-agenda-category-filter)
7544 "")
7545 ">")
7546 'face 'org-agenda-filter-category
7547 'help-echo "Category used in filtering"))
7548 "")
7549 (if (or org-agenda-tag-filter (get 'org-agenda-tag-filter
8223b1d2 7550 :preset-filter))
e66ba1df
BG
7551 '(:eval (org-propertize
7552 (concat " {"
7553 (mapconcat
7554 'identity
7555 (append
7556 (get 'org-agenda-tag-filter :preset-filter)
7557 org-agenda-tag-filter)
7558 "")
7559 "}")
7560 'face 'org-agenda-filter-tags
7561 'help-echo "Tags used in filtering"))
acedf35c
CD
7562 "")
7563 (if org-agenda-archives-mode
7564 (if (eq org-agenda-archives-mode t)
7565 " Archives"
7566 (format " :%s:" org-archive-tag))
7567 "")
7568 (if org-agenda-clockreport-mode
7569 (if (eq org-agenda-clockreport-mode 'with-filter)
7570 " Clock{}" " Clock")
7571 "")))
20908596
CD
7572 (force-mode-line-update))
7573
a89c8ef0 7574(define-obsolete-function-alias
8223b1d2
BG
7575 'org-agenda-post-command-hook 'org-agenda-update-agenda-type "24.3")
7576
7577(defun org-agenda-update-agenda-type ()
7578 "Update the agenda type after each command."
b349f79f
CD
7579 (setq org-agenda-type
7580 (or (get-text-property (point) 'org-agenda-type)
8223b1d2 7581 (get-text-property (max (point-min) (1- (point))) 'org-agenda-type))))
8bfe682a
CD
7582
7583(defun org-agenda-next-line ()
86fbb8ca 7584 "Move cursor to the next line, and show if follow mode is active."
8bfe682a
CD
7585 (interactive)
7586 (call-interactively 'next-line)
1bcdebed
CD
7587 (org-agenda-do-context-action))
7588
8bfe682a
CD
7589(defun org-agenda-previous-line ()
7590 "Move cursor to the previous line, and show if follow-mode is active."
8bfe682a
CD
7591 (interactive)
7592 (call-interactively 'previous-line)
1bcdebed
CD
7593 (org-agenda-do-context-action))
7594
8223b1d2
BG
7595(defun org-agenda-next-item (n)
7596 "Move cursor to next agenda item."
7597 (interactive "p")
7598 (let ((col (current-column)))
7599 (dotimes (c n)
7600 (when (next-single-property-change (point-at-eol) 'org-marker)
7601 (move-end-of-line 1)
7602 (goto-char (next-single-property-change (point) 'org-marker))))
7603 (org-move-to-column col))
7604 (org-agenda-do-context-action))
7605
7606(defun org-agenda-previous-item (n)
7607 "Move cursor to next agenda item."
7608 (interactive "p")
7609 (dotimes (c n)
7610 (let ((col (current-column))
7611 (goto (save-excursion
7612 (move-end-of-line 0)
7613 (previous-single-property-change (point) 'org-marker))))
7614 (if goto (goto-char goto))
7615 (org-move-to-column col)))
7616 (org-agenda-do-context-action))
7617
1bcdebed 7618(defun org-agenda-do-context-action ()
86fbb8ca 7619 "Show outline path and, maybe, follow mode window."
1bcdebed 7620 (let ((m (org-get-at-bol 'org-marker)))
e66ba1df
BG
7621 (when (and (markerp m) (marker-buffer m))
7622 (and org-agenda-follow-mode
7623 (if org-agenda-follow-indirect
8223b1d2 7624 (org-agenda-tree-to-indirect-buffer nil)
e66ba1df
BG
7625 (org-agenda-show)))
7626 (and org-agenda-show-outline-path
7627 (org-with-point-at m (org-display-outline-path t))))))
20908596 7628
20908596
CD
7629(defun org-agenda-show-tags ()
7630 "Show the tags applicable to the current item."
7631 (interactive)
8d642074 7632 (let* ((tags (org-get-at-bol 'tags)))
20908596
CD
7633 (if tags
7634 (message "Tags are :%s:"
7635 (org-no-properties (mapconcat 'identity tags ":")))
7636 (message "No tags associated with this line"))))
7637
7638(defun org-agenda-goto (&optional highlight)
7639 "Go to the Org-mode file which contains the item at point."
7640 (interactive)
8d642074 7641 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
7642 (org-agenda-error)))
7643 (buffer (marker-buffer marker))
7644 (pos (marker-position marker)))
7645 (switch-to-buffer-other-window buffer)
7646 (widen)
86fbb8ca 7647 (push-mark)
20908596 7648 (goto-char pos)
8223b1d2 7649 (when (derived-mode-p 'org-mode)
20908596
CD
7650 (org-show-context 'agenda)
7651 (save-excursion
7652 (and (outline-next-heading)
3ab2c837
BG
7653 (org-flag-heading nil)))) ; show the next heading
7654 (when (outline-invisible-p)
7655 (show-entry)) ; display invisible text
20908596
CD
7656 (recenter (/ (window-height) 2))
7657 (run-hooks 'org-agenda-after-show-hook)
7658 (and highlight (org-highlight (point-at-bol) (point-at-eol)))))
7659
7660(defvar org-agenda-after-show-hook nil
7661 "Normal hook run after an item has been shown from the agenda.
7662Point is in the buffer where the item originated.")
7663
7664(defun org-agenda-kill ()
7665 "Kill the entry or subtree belonging to the current agenda entry."
7666 (interactive)
7667 (or (eq major-mode 'org-agenda-mode) (error "Not in agenda"))
8223b1d2
BG
7668 (let* ((bufname-orig (buffer-name))
7669 (marker (or (org-get-at-bol 'org-marker)
20908596
CD
7670 (org-agenda-error)))
7671 (buffer (marker-buffer marker))
7672 (pos (marker-position marker))
8d642074 7673 (type (org-get-at-bol 'type))
20908596
CD
7674 dbeg dend (n 0) conf)
7675 (org-with-remote-undo buffer
8223b1d2
BG
7676 (with-current-buffer buffer
7677 (save-excursion
7678 (goto-char pos)
7679 (if (and (derived-mode-p 'org-mode) (not (member type '("sexp"))))
7680 (setq dbeg (progn (org-back-to-heading t) (point))
7681 dend (org-end-of-subtree t t))
7682 (setq dbeg (point-at-bol)
7683 dend (min (point-max) (1+ (point-at-eol)))))
7684 (goto-char dbeg)
7685 (while (re-search-forward "^[ \t]*\\S-" dend t) (setq n (1+ n)))))
7686 (setq conf (or (eq t org-agenda-confirm-kill)
7687 (and (numberp org-agenda-confirm-kill)
7688 (> n org-agenda-confirm-kill))))
7689 (and conf
7690 (not (y-or-n-p
7691 (format "Delete entry with %d lines in buffer \"%s\"? "
7692 n (buffer-name buffer))))
7693 (error "Abort"))
7694 (let ((org-agenda-buffer-name bufname-orig))
7695 (org-remove-subtree-entries-from-agenda buffer dbeg dend))
7696 (with-current-buffer buffer (delete-region dbeg dend))
7697 (message "Agenda item and source killed"))))
7698
7699(defvar org-archive-default-command) ; defined in org-archive.el
8bfe682a
CD
7700(defun org-agenda-archive-default ()
7701 "Archive the entry or subtree belonging to the current agenda entry."
7702 (interactive)
7703 (require 'org-archive)
7704 (org-agenda-archive-with org-archive-default-command))
7705
7706(defun org-agenda-archive-default-with-confirmation ()
7707 "Archive the entry or subtree belonging to the current agenda entry."
7708 (interactive)
7709 (require 'org-archive)
7710 (org-agenda-archive-with org-archive-default-command 'confirm))
7711
20908596
CD
7712(defun org-agenda-archive ()
7713 "Archive the entry or subtree belonging to the current agenda entry."
7714 (interactive)
8bfe682a 7715 (org-agenda-archive-with 'org-archive-subtree))
20908596
CD
7716
7717(defun org-agenda-archive-to-archive-sibling ()
8bfe682a
CD
7718 "Move the entry to the archive sibling."
7719 (interactive)
7720 (org-agenda-archive-with 'org-archive-to-archive-sibling))
7721
7722(defun org-agenda-archive-with (cmd &optional confirm)
20908596
CD
7723 "Move the entry to the archive sibling."
7724 (interactive)
7725 (or (eq major-mode 'org-agenda-mode) (error "Not in agenda"))
8223b1d2
BG
7726 (let* ((bufname-orig (buffer-name))
7727 (marker (or (org-get-at-bol 'org-marker)
20908596
CD
7728 (org-agenda-error)))
7729 (buffer (marker-buffer marker))
7730 (pos (marker-position marker)))
7731 (org-with-remote-undo buffer
7732 (with-current-buffer buffer
8223b1d2 7733 (if (derived-mode-p 'org-mode)
8bfe682a
CD
7734 (if (and confirm
7735 (not (y-or-n-p "Archive this subtree or entry? ")))
7736 (error "Abort")
7737 (save-excursion
7738 (goto-char pos)
8223b1d2
BG
7739 (let ((org-agenda-buffer-name bufname-orig))
7740 (org-remove-subtree-entries-from-agenda))
8bfe682a
CD
7741 (org-back-to-heading t)
7742 (funcall cmd)))
20908596
CD
7743 (error "Archiving works only in Org-mode files"))))))
7744
7745(defun org-remove-subtree-entries-from-agenda (&optional buf beg end)
7746 "Remove all lines in the agenda that correspond to a given subtree.
7747The subtree is the one in buffer BUF, starting at BEG and ending at END.
7748If this information is not given, the function uses the tree at point."
7749 (let ((buf (or buf (current-buffer))) m p)
7750 (save-excursion
7751 (unless (and beg end)
7752 (org-back-to-heading t)
7753 (setq beg (point))
7754 (org-end-of-subtree t)
7755 (setq end (point)))
7756 (set-buffer (get-buffer org-agenda-buffer-name))
7757 (save-excursion
7758 (goto-char (point-max))
7759 (beginning-of-line 1)
7760 (while (not (bobp))
8d642074 7761 (when (and (setq m (org-get-at-bol 'org-marker))
20908596
CD
7762 (equal buf (marker-buffer m))
7763 (setq p (marker-position m))
7764 (>= p beg)
c8d0cf5c 7765 (< p end))
20908596
CD
7766 (let ((inhibit-read-only t))
7767 (delete-region (point-at-bol) (1+ (point-at-eol)))))
7768 (beginning-of-line 0))))))
7769
86fbb8ca 7770(defun org-agenda-refile (&optional goto rfloc no-update)
c8d0cf5c 7771 "Refile the item at point."
54a0dee5
CD
7772 (interactive "P")
7773 (if (equal goto '(16))
7774 (org-refile-goto-last-stored)
8223b1d2
BG
7775 (let* ((buffer-orig (buffer-name))
7776 (marker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
7777 (org-agenda-error)))
7778 (buffer (marker-buffer marker))
7779 (pos (marker-position marker))
7780 (rfloc (or rfloc
7781 (org-refile-get-location
3ab2c837 7782 (if goto "Goto" "Refile to") buffer
54a0dee5
CD
7783 org-refile-allow-creating-parent-nodes))))
7784 (with-current-buffer buffer
7785 (save-excursion
7786 (save-restriction
7787 (widen)
7788 (goto-char marker)
8223b1d2
BG
7789 (let ((org-agenda-buffer-name buffer-orig))
7790 (org-remove-subtree-entries-from-agenda))
86fbb8ca
CD
7791 (org-refile goto buffer rfloc)))))
7792 (unless no-update (org-agenda-redo))))
54a0dee5
CD
7793
7794(defun org-agenda-open-link (&optional arg)
c7cf0ebc
BG
7795 "Open the link(s) in the current entry, if any.
7796This looks for a link in the displayed line in the agenda.
7797It also looks at the text of the entry itself."
c8d0cf5c 7798 (interactive "P")
8d642074
CD
7799 (let* ((marker (or (org-get-at-bol 'org-hd-marker)
7800 (org-get-at-bol 'org-marker)))
7801 (buffer (and marker (marker-buffer marker)))
d3517077 7802 (prefix (buffer-substring (point-at-bol) (point-at-eol)))
c7cf0ebc 7803 (lkall (org-offer-links-in-entry buffer marker arg prefix))
d3517077
BG
7804 (lk0 (car lkall))
7805 (lk (if (stringp lk0) (list lk0) lk0))
c7cf0ebc
BG
7806 (lkend (cdr lkall))
7807 trg)
8bfe682a 7808 (cond
d3517077
BG
7809 ((and buffer lk)
7810 (mapcar (lambda(l)
7811 (with-current-buffer buffer
7812 (setq trg (and (string-match org-bracket-link-regexp l)
7813 (match-string 1 l)))
7814 (if (or (not trg) (string-match org-any-link-re trg))
7815 (save-excursion
7816 (save-restriction
7817 (widen)
7818 (goto-char marker)
7819 (when (search-forward l nil lkend)
7820 (goto-char (match-beginning 0))
7821 (org-open-at-point))))
7822 ;; This is an internal link, widen the buffer
7823 (switch-to-buffer-other-window buffer)
7824 (widen)
7825 (goto-char marker)
7826 (when (search-forward l nil lkend)
7827 (goto-char (match-beginning 0))
7828 (org-open-at-point)))))
7829 lk))
8bfe682a
CD
7830 ((or (org-in-regexp (concat "\\(" org-bracket-link-regexp "\\)"))
7831 (save-excursion
7832 (beginning-of-line 1)
7833 (looking-at (concat ".*?\\(" org-bracket-link-regexp "\\)"))))
7834 (org-open-link-from-string (match-string 1)))
c7cf0ebc 7835 (t (message "No link to open here")))))
20908596
CD
7836
7837(defun org-agenda-copy-local-variable (var)
7838 "Get a variable from a referenced buffer and install it here."
8d642074 7839 (let ((m (org-get-at-bol 'org-marker)))
20908596
CD
7840 (when (and m (buffer-live-p (marker-buffer m)))
7841 (org-set-local var (with-current-buffer (marker-buffer m)
7842 (symbol-value var))))))
7843
7844(defun org-agenda-switch-to (&optional delete-other-windows)
7845 "Go to the Org-mode file which contains the item at point."
7846 (interactive)
8bfe682a
CD
7847 (if (and org-return-follows-link
7848 (not (org-get-at-bol 'org-marker))
7849 (org-in-regexp org-bracket-link-regexp))
7850 (org-open-link-from-string (match-string 0))
7851 (let* ((marker (or (org-get-at-bol 'org-marker)
7852 (org-agenda-error)))
7853 (buffer (marker-buffer marker))
7854 (pos (marker-position marker)))
e66ba1df 7855 (org-pop-to-buffer-same-window buffer)
8bfe682a
CD
7856 (and delete-other-windows (delete-other-windows))
7857 (widen)
7858 (goto-char pos)
8223b1d2 7859 (when (derived-mode-p 'org-mode)
8bfe682a
CD
7860 (org-show-context 'agenda)
7861 (save-excursion
7862 (and (outline-next-heading)
3ab2c837
BG
7863 (org-flag-heading nil))) ; show the next heading
7864 (when (outline-invisible-p)
8223b1d2
BG
7865 (show-entry)) ; display invisible text
7866 (run-hooks 'org-agenda-after-show-hook)))))
20908596
CD
7867
7868(defun org-agenda-goto-mouse (ev)
7869 "Go to the Org-mode file which contains the item at the mouse click."
7870 (interactive "e")
7871 (mouse-set-point ev)
7872 (org-agenda-goto))
7873
fdf730ed
CD
7874(defun org-agenda-show (&optional full-entry)
7875 "Display the Org-mode file which contains the item at point.
7876With prefix argument FULL-ENTRY, make the entire entry visible
7877if it was hidden in the outline."
7878 (interactive "P")
20908596 7879 (let ((win (selected-window)))
fdf730ed
CD
7880 (if full-entry
7881 (let ((org-show-entry-below t))
7882 (org-agenda-goto t))
7883 (org-agenda-goto t))
20908596
CD
7884 (select-window win)))
7885
8bfe682a 7886(defvar org-agenda-show-window nil)
8223b1d2 7887(defun org-agenda-show-and-scroll-up (&optional arg)
8bfe682a 7888 "Display the Org-mode file which contains the item at point.
8223b1d2
BG
7889When called repeatedly, scroll the window that is displaying the buffer.
7890With a \\[universal-argument] prefix, use `org-show-entry' instead of
7891`show-subtree' to display the item, so that drawers and logbooks stay
7892folded."
7893 (interactive "P")
8bfe682a
CD
7894 (let ((win (selected-window)))
7895 (if (and (window-live-p org-agenda-show-window)
7896 (eq this-command last-command))
7897 (progn
7898 (select-window org-agenda-show-window)
7899 (ignore-errors (scroll-up)))
7900 (org-agenda-goto t)
8223b1d2 7901 (if arg (org-show-entry) (show-subtree))
8bfe682a
CD
7902 (setq org-agenda-show-window (selected-window)))
7903 (select-window win)))
7904
7905(defun org-agenda-show-scroll-down ()
7906 "Scroll down the window showing the agenda."
7907 (interactive)
7908 (let ((win (selected-window)))
7909 (when (window-live-p org-agenda-show-window)
7910 (select-window org-agenda-show-window)
7911 (ignore-errors (scroll-down))
7912 (select-window win))))
7913
c8d0cf5c
CD
7914(defun org-agenda-show-1 (&optional more)
7915 "Display the Org-mode file which contains the item at point.
8bfe682a 7916The prefix arg selects the amount of information to display:
c8d0cf5c
CD
7917
79180 hide the subtree
79191 just show the entry according to defaults.
54a0dee5
CD
79202 show the children view
79213 show the subtree view
c8d0cf5c
CD
79224 show the entire subtree and any LOGBOOK drawers
79235 show the entire subtree and any drawers
7924With prefix argument FULL-ENTRY, make the entire entry visible
7925if it was hidden in the outline."
7926 (interactive "p")
7927 (let ((win (selected-window)))
7928 (org-agenda-goto t)
7929 (org-recenter-heading 1)
7930 (cond
7931 ((= more 0)
7932 (hide-subtree)
54a0dee5
CD
7933 (save-excursion
7934 (org-back-to-heading)
7935 (run-hook-with-args 'org-cycle-hook 'folded))
7936 (message "Remote: FOLDED"))
3ab2c837 7937 ((and (org-called-interactively-p 'any) (= more 1))
c8d0cf5c
CD
7938 (message "Remote: show with default settings"))
7939 ((= more 2)
7940 (show-entry)
54a0dee5 7941 (show-children)
c8d0cf5c
CD
7942 (save-excursion
7943 (org-back-to-heading)
54a0dee5
CD
7944 (run-hook-with-args 'org-cycle-hook 'children))
7945 (message "Remote: CHILDREN"))
c8d0cf5c
CD
7946 ((= more 3)
7947 (show-subtree)
7948 (save-excursion
7949 (org-back-to-heading)
54a0dee5
CD
7950 (run-hook-with-args 'org-cycle-hook 'subtree))
7951 (message "Remote: SUBTREE"))
c8d0cf5c
CD
7952 ((= more 4)
7953 (let* ((org-drawers (delete "LOGBOOK" (copy-sequence org-drawers)))
7954 (org-drawer-regexp
7955 (concat "^[ \t]*:\\("
7956 (mapconcat 'regexp-quote org-drawers "\\|")
7957 "\\):[ \t]*$")))
7958 (show-subtree)
7959 (save-excursion
7960 (org-back-to-heading)
7961 (org-cycle-hide-drawers 'subtree)))
54a0dee5 7962 (message "Remote: SUBTREE AND LOGBOOK"))
c8d0cf5c
CD
7963 ((> more 4)
7964 (show-subtree)
54a0dee5 7965 (message "Remote: SUBTREE AND ALL DRAWERS")))
c8d0cf5c
CD
7966 (select-window win)))
7967
7968(defun org-recenter-heading (n)
7969 (save-excursion
7970 (org-back-to-heading)
7971 (recenter n)))
7972
7973(defvar org-agenda-cycle-counter nil)
54a0dee5 7974(defun org-agenda-cycle-show (&optional n)
c8d0cf5c
CD
7975 "Show the current entry in another window, with default settings.
7976Default settings are taken from `org-show-hierarchy-above' and siblings.
54a0dee5 7977When use repeatedly in immediate succession, the remote entry will cycle
c8d0cf5c
CD
7978through visibility
7979
54a0dee5
CD
7980children -> subtree -> folded
7981
7982When called with a numeric prefix arg, that arg will be passed through to
7983`org-agenda-show-1'. For the interpretation of that argument, see the
7984docstring of `org-agenda-show-1'."
7985 (interactive "P")
7986 (if (integerp n)
7987 (setq org-agenda-cycle-counter n)
7988 (if (not (eq last-command this-command))
7989 (setq org-agenda-cycle-counter 1)
7990 (if (equal org-agenda-cycle-counter 0)
7991 (setq org-agenda-cycle-counter 2)
7992 (setq org-agenda-cycle-counter (1+ org-agenda-cycle-counter))
7993 (if (> org-agenda-cycle-counter 3)
7994 (setq org-agenda-cycle-counter 0)))))
c8d0cf5c
CD
7995 (org-agenda-show-1 org-agenda-cycle-counter))
7996
20908596
CD
7997(defun org-agenda-recenter (arg)
7998 "Display the Org-mode file which contains the item at point and recenter."
7999 (interactive "P")
8000 (let ((win (selected-window)))
8001 (org-agenda-goto t)
8002 (recenter arg)
8003 (select-window win)))
8004
8005(defun org-agenda-show-mouse (ev)
8006 "Display the Org-mode file which contains the item at the mouse click."
8007 (interactive "e")
8008 (mouse-set-point ev)
8009 (org-agenda-show))
8010
8011(defun org-agenda-check-no-diary ()
8012 "Check if the entry is a diary link and abort if yes."
8d642074 8013 (if (org-get-at-bol 'org-agenda-diary-link)
20908596
CD
8014 (org-agenda-error)))
8015
8016(defun org-agenda-error ()
8017 (error "Command not allowed in this line"))
8018
8223b1d2 8019(defun org-agenda-tree-to-indirect-buffer (arg)
20908596 8020 "Show the subtree corresponding to the current entry in an indirect buffer.
8223b1d2
BG
8021This calls the command `org-tree-to-indirect-buffer' from the original buffer.
8022
8023With a numerical prefix ARG, go up to this level and then take that tree.
8024With a negative numeric ARG, go up by this number of levels.
86fbb8ca
CD
8025With a \\[universal-argument] prefix, make a separate frame for this tree (i.e. don't
8026use the dedicated frame)."
8223b1d2
BG
8027 (interactive "P")
8028 (if current-prefix-arg
8029 (org-agenda-do-tree-to-indirect-buffer arg)
8030 (let ((agenda-buffer (buffer-name))
8031 (agenda-window (selected-window))
153ae947
BG
8032 (indirect-window
8033 (and org-last-indirect-buffer
8034 (get-buffer-window org-last-indirect-buffer))))
8223b1d2
BG
8035 (save-window-excursion (org-agenda-do-tree-to-indirect-buffer arg))
8036 (unless (or (eq org-indirect-buffer-display 'new-frame)
8037 (eq org-indirect-buffer-display 'dedicated-frame))
8038 (unwind-protect
8039 (unless (and indirect-window (window-live-p indirect-window))
8040 (setq indirect-window (split-window agenda-window)))
8041 (and indirect-window (select-window indirect-window))
8042 (switch-to-buffer org-last-indirect-buffer :norecord)
8043 (fit-window-to-buffer indirect-window)))
8044 (select-window (get-buffer-window agenda-buffer)))))
8045
8046(defun org-agenda-do-tree-to-indirect-buffer (arg)
e66ba1df 8047 "Same as `org-agenda-tree-to-indirect-buffer' without saving window."
20908596 8048 (org-agenda-check-no-diary)
8d642074 8049 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
8050 (org-agenda-error)))
8051 (buffer (marker-buffer marker))
8052 (pos (marker-position marker)))
8053 (with-current-buffer buffer
8054 (save-excursion
8055 (goto-char pos)
8223b1d2 8056 (funcall 'org-tree-to-indirect-buffer arg)))))
20908596
CD
8057
8058(defvar org-last-heading-marker (make-marker)
8059 "Marker pointing to the headline that last changed its TODO state
8060by a remote command from the agenda.")
8061
8062(defun org-agenda-todo-nextset ()
8063 "Switch TODO entry to next sequence."
8064 (interactive)
8065 (org-agenda-todo 'nextset))
8066
8067(defun org-agenda-todo-previousset ()
8068 "Switch TODO entry to previous sequence."
8069 (interactive)
8070 (org-agenda-todo 'previousset))
8071
8072(defun org-agenda-todo (&optional arg)
8073 "Cycle TODO state of line at point, also in Org-mode file.
8074This changes the line at point, all other lines in the agenda referring to
8075the same tree node, and the headline of the tree node in the Org-mode file."
8076 (interactive "P")
8077 (org-agenda-check-no-diary)
8078 (let* ((col (current-column))
8d642074 8079 (marker (or (org-get-at-bol 'org-marker)
20908596
CD
8080 (org-agenda-error)))
8081 (buffer (marker-buffer marker))
8082 (pos (marker-position marker))
8d642074 8083 (hdmarker (org-get-at-bol 'org-hd-marker))
acedf35c 8084 (todayp (org-agenda-todayp (org-get-at-bol 'day)))
20908596 8085 (inhibit-read-only t)
93b62de8 8086 org-agenda-headline-snapshot-before-repeat newhead just-one)
20908596
CD
8087 (org-with-remote-undo buffer
8088 (with-current-buffer buffer
8089 (widen)
8090 (goto-char pos)
8091 (org-show-context 'agenda)
8092 (save-excursion
8093 (and (outline-next-heading)
8094 (org-flag-heading nil))) ; show the next heading
a2a2e7fb
CD
8095 (let ((current-prefix-arg arg))
8096 (call-interactively 'org-todo))
20908596
CD
8097 (and (bolp) (forward-char 1))
8098 (setq newhead (org-get-heading))
93b62de8
CD
8099 (when (and (org-bound-and-true-p
8100 org-agenda-headline-snapshot-before-repeat)
8101 (not (equal org-agenda-headline-snapshot-before-repeat
8102 newhead))
8103 todayp)
8104 (setq newhead org-agenda-headline-snapshot-before-repeat
8105 just-one t))
20908596
CD
8106 (save-excursion
8107 (org-back-to-heading)
8108 (move-marker org-last-heading-marker (point))))
8109 (beginning-of-line 1)
8110 (save-excursion
93b62de8 8111 (org-agenda-change-all-lines newhead hdmarker 'fixface just-one))
20908596
CD
8112 (org-move-to-column col))))
8113
8114(defun org-agenda-add-note (&optional arg)
8115 "Add a time-stamped note to the entry at point."
8116 (interactive "P")
8117 (org-agenda-check-no-diary)
8d642074 8118 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
8119 (org-agenda-error)))
8120 (buffer (marker-buffer marker))
8121 (pos (marker-position marker))
8d642074 8122 (hdmarker (org-get-at-bol 'org-hd-marker))
20908596
CD
8123 (inhibit-read-only t))
8124 (with-current-buffer buffer
8125 (widen)
8126 (goto-char pos)
8127 (org-show-context 'agenda)
8128 (save-excursion
8129 (and (outline-next-heading)
8130 (org-flag-heading nil))) ; show the next heading
8131 (org-add-note))))
8132
db55f368 8133(defun org-agenda-change-all-lines (newhead hdmarker
4ed008de 8134 &optional fixface just-this)
20908596
CD
8135 "Change all lines in the agenda buffer which match HDMARKER.
8136The new content of the line will be NEWHEAD (as modified by
e66ba1df 8137`org-agenda-format-item'). HDMARKER is checked with
20908596 8138`equal' against all `org-hd-marker' text properties in the file.
33306645 8139If FIXFACE is non-nil, the face of each item is modified according to
db55f368
CD
8140the new TODO state.
8141If JUST-THIS is non-nil, change just the current line, not all.
33306645 8142If FORCE-TAGS is non nil, the car of it returns the new tags."
20908596 8143 (let* ((inhibit-read-only t)
93b62de8 8144 (line (org-current-line))
8223b1d2 8145 (org-agenda-buffer (current-buffer))
fdf730ed 8146 (thetags (with-current-buffer (marker-buffer hdmarker)
4ed008de
CD
8147 (save-excursion (save-restriction (widen)
8148 (goto-char hdmarker)
fdf730ed 8149 (org-get-tags-at)))))
20908596
CD
8150 props m pl undone-face done-face finish new dotime cat tags)
8151 (save-excursion
8152 (goto-char (point-max))
8153 (beginning-of-line 1)
8154 (while (not finish)
8155 (setq finish (bobp))
8d642074 8156 (when (and (setq m (org-get-at-bol 'org-hd-marker))
93b62de8 8157 (or (not just-this) (= (org-current-line) line))
20908596
CD
8158 (equal m hdmarker))
8159 (setq props (text-properties-at (point))
8d642074
CD
8160 dotime (org-get-at-bol 'dotime)
8161 cat (org-get-at-bol 'org-category)
4ed008de 8162 tags thetags
3ab2c837
BG
8163 new
8164 (let ((org-prefix-format-compiled
8223b1d2
BG
8165 (or (get-text-property (min (1- (point-max)) (point)) 'format)
8166 org-prefix-format-compiled))
8167 (extra (org-get-at-bol 'extra)))
3ab2c837
BG
8168 (with-current-buffer (marker-buffer hdmarker)
8169 (save-excursion
8170 (save-restriction
8171 (widen)
8223b1d2 8172 (org-agenda-format-item extra newhead cat tags dotime)))))
3ab2c837 8173 pl (text-property-any (point-at-bol) (point-at-eol) 'org-heading t)
8d642074
CD
8174 undone-face (org-get-at-bol 'undone-face)
8175 done-face (org-get-at-bol 'done-face))
3ab2c837 8176 (beginning-of-line 1)
20908596
CD
8177 (cond
8178 ((equal new "")
20908596
CD
8179 (and (looking-at ".*\n?") (replace-match "")))
8180 ((looking-at ".*")
8181 (replace-match new t t)
8182 (beginning-of-line 1)
8183 (add-text-properties (point-at-bol) (point-at-eol) props)
8184 (when fixface
8185 (add-text-properties
8186 (point-at-bol) (point-at-eol)
8187 (list 'face
8188 (if org-last-todo-state-is-todo
8189 undone-face done-face))))
8190 (org-agenda-highlight-todo 'line)
8191 (beginning-of-line 1))
8223b1d2
BG
8192 (t (error "Line update did not work")))
8193 (save-restriction
8194 (narrow-to-region (point-at-bol) (point-at-eol))
8195 (org-agenda-finalize)))
8196 (beginning-of-line 0)))))
20908596
CD
8197
8198(defun org-agenda-align-tags (&optional line)
8199 "Align all tags in agenda items to `org-agenda-tags-column'."
8200 (let ((inhibit-read-only t) l c)
8201 (save-excursion
8202 (goto-char (if line (point-at-bol) (point-min)))
afe98dfa 8203 (while (re-search-forward (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@#%:]+:\\)[ \t]*$")
20908596
CD
8204 (if line (point-at-eol) nil) t)
8205 (add-text-properties
8206 (match-beginning 2) (match-end 2)
30ab4580
GM
8207 (list 'face (delq nil (let ((prop (get-text-property
8208 (match-beginning 2) 'face)))
8209 (or (listp prop) (setq prop (list prop)))
8210 (if (memq 'org-tag prop)
8211 prop
8212 (cons 'org-tag prop))))))
20908596
CD
8213 (setq l (- (match-end 2) (match-beginning 2))
8214 c (if (< org-agenda-tags-column 0)
8215 (- (abs org-agenda-tags-column) l)
8216 org-agenda-tags-column))
8217 (delete-region (match-beginning 1) (match-end 1))
8218 (goto-char (match-beginning 1))
8219 (insert (org-add-props
8220 (make-string (max 1 (- c (current-column))) ?\ )
ed21c5c8
CD
8221 (plist-put (copy-sequence (text-properties-at (point)))
8222 'face nil))))
ff4be292
CD
8223 (goto-char (point-min))
8224 (org-font-lock-add-tag-faces (point-max)))))
20908596
CD
8225
8226(defun org-agenda-priority-up ()
8227 "Increase the priority of line at point, also in Org-mode file."
8228 (interactive)
8229 (org-agenda-priority 'up))
8230
8231(defun org-agenda-priority-down ()
8232 "Decrease the priority of line at point, also in Org-mode file."
8233 (interactive)
8234 (org-agenda-priority 'down))
8235
c7cf0ebc 8236(defun org-agenda-priority (&optional force-direction)
20908596
CD
8237 "Set the priority of line at point, also in Org-mode file.
8238This changes the line at point, all other lines in the agenda referring to
c7cf0ebc
BG
8239the same tree node, and the headline of the tree node in the Org-mode file.
8240Called with a universal prefix arg, show the priority instead of setting it."
8223b1d2 8241 (interactive "P")
c7cf0ebc
BG
8242 (if (equal force-direction '(4))
8243 (org-show-priority)
8244 (unless org-enable-priority-commands
8245 (error "Priority commands are disabled"))
8246 (org-agenda-check-no-diary)
8247 (let* ((marker (or (org-get-at-bol 'org-marker)
8248 (org-agenda-error)))
8249 (hdmarker (org-get-at-bol 'org-hd-marker))
8250 (buffer (marker-buffer hdmarker))
8251 (pos (marker-position hdmarker))
8252 (inhibit-read-only t)
8253 newhead)
8254 (org-with-remote-undo buffer
8255 (with-current-buffer buffer
8256 (widen)
8257 (goto-char pos)
8258 (org-show-context 'agenda)
8259 (save-excursion
8260 (and (outline-next-heading)
8261 (org-flag-heading nil))) ; show the next heading
8262 (funcall 'org-priority force-direction)
8263 (end-of-line 1)
8264 (setq newhead (org-get-heading)))
8265 (org-agenda-change-all-lines newhead hdmarker)
8266 (beginning-of-line 1)))))
20908596
CD
8267
8268;; FIXME: should fix the tags property of the agenda line.
c8d0cf5c 8269(defun org-agenda-set-tags (&optional tag onoff)
20908596
CD
8270 "Set tags for the current headline."
8271 (interactive)
8272 (org-agenda-check-no-diary)
3ab2c837 8273 (if (and (org-region-active-p) (org-called-interactively-p 'any))
20908596 8274 (call-interactively 'org-change-tag-in-region)
8d642074 8275 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
20908596
CD
8276 (org-agenda-error)))
8277 (buffer (marker-buffer hdmarker))
8278 (pos (marker-position hdmarker))
8279 (inhibit-read-only t)
4ed008de 8280 newhead)
20908596
CD
8281 (org-with-remote-undo buffer
8282 (with-current-buffer buffer
8283 (widen)
8284 (goto-char pos)
8285 (save-excursion
8286 (org-show-context 'agenda))
8287 (save-excursion
8288 (and (outline-next-heading)
8289 (org-flag-heading nil))) ; show the next heading
8290 (goto-char pos)
c8d0cf5c
CD
8291 (if tag
8292 (org-toggle-tag tag onoff)
8293 (call-interactively 'org-set-tags))
20908596
CD
8294 (end-of-line 1)
8295 (setq newhead (org-get-heading)))
4ed008de 8296 (org-agenda-change-all-lines newhead hdmarker)
20908596
CD
8297 (beginning-of-line 1)))))
8298
54a0dee5
CD
8299(defun org-agenda-set-property ()
8300 "Set a property for the current headline."
8301 (interactive)
8302 (org-agenda-check-no-diary)
8d642074 8303 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
8304 (org-agenda-error)))
8305 (buffer (marker-buffer hdmarker))
8306 (pos (marker-position hdmarker))
8307 (inhibit-read-only t)
8308 newhead)
8309 (org-with-remote-undo buffer
8310 (with-current-buffer buffer
8311 (widen)
8312 (goto-char pos)
8313 (save-excursion
8314 (org-show-context 'agenda))
8315 (save-excursion
8316 (and (outline-next-heading)
8317 (org-flag-heading nil))) ; show the next heading
8318 (goto-char pos)
8319 (call-interactively 'org-set-property)))))
8320
8321(defun org-agenda-set-effort ()
8322 "Set the effort property for the current headline."
8323 (interactive)
8324 (org-agenda-check-no-diary)
8d642074 8325 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
8326 (org-agenda-error)))
8327 (buffer (marker-buffer hdmarker))
8328 (pos (marker-position hdmarker))
8329 (inhibit-read-only t)
8330 newhead)
8331 (org-with-remote-undo buffer
8332 (with-current-buffer buffer
8333 (widen)
8334 (goto-char pos)
8335 (save-excursion
8336 (org-show-context 'agenda))
8337 (save-excursion
8338 (and (outline-next-heading)
3ab2c837 8339 (org-flag-heading nil))) ; show the next heading
54a0dee5
CD
8340 (goto-char pos)
8341 (call-interactively 'org-set-effort)
3ab2c837
BG
8342 (end-of-line 1)
8343 (setq newhead (org-get-heading)))
8344 (org-agenda-change-all-lines newhead hdmarker))))
54a0dee5 8345
20908596
CD
8346(defun org-agenda-toggle-archive-tag ()
8347 "Toggle the archive tag for the current entry."
8348 (interactive)
8349 (org-agenda-check-no-diary)
8d642074 8350 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
20908596
CD
8351 (org-agenda-error)))
8352 (buffer (marker-buffer hdmarker))
8353 (pos (marker-position hdmarker))
8354 (inhibit-read-only t)
8355 newhead)
8356 (org-with-remote-undo buffer
8357 (with-current-buffer buffer
8358 (widen)
8359 (goto-char pos)
8360 (org-show-context 'agenda)
8361 (save-excursion
8362 (and (outline-next-heading)
8363 (org-flag-heading nil))) ; show the next heading
8364 (call-interactively 'org-toggle-archive-tag)
8365 (end-of-line 1)
8366 (setq newhead (org-get-heading)))
8367 (org-agenda-change-all-lines newhead hdmarker)
8368 (beginning-of-line 1))))
8369
c8d0cf5c
CD
8370(defun org-agenda-do-date-later (arg)
8371 (interactive "P")
8372 (cond
8373 ((or (equal arg '(16))
8374 (memq last-command
8375 '(org-agenda-date-later-minutes org-agenda-date-earlier-minutes)))
8376 (setq this-command 'org-agenda-date-later-minutes)
8377 (org-agenda-date-later-minutes 1))
8378 ((or (equal arg '(4))
8379 (memq last-command
8380 '(org-agenda-date-later-hours org-agenda-date-earlier-hours)))
8381 (setq this-command 'org-agenda-date-later-hours)
8382 (org-agenda-date-later-hours 1))
8383 (t
8384 (org-agenda-date-later (prefix-numeric-value arg)))))
8385
8386(defun org-agenda-do-date-earlier (arg)
8387 (interactive "P")
8388 (cond
8389 ((or (equal arg '(16))
8390 (memq last-command
8391 '(org-agenda-date-later-minutes org-agenda-date-earlier-minutes)))
8392 (setq this-command 'org-agenda-date-earlier-minutes)
8393 (org-agenda-date-earlier-minutes 1))
8394 ((or (equal arg '(4))
8395 (memq last-command
8396 '(org-agenda-date-later-hours org-agenda-date-earlier-hours)))
8397 (setq this-command 'org-agenda-date-earlier-hours)
8398 (org-agenda-date-earlier-hours 1))
8399 (t
8400 (org-agenda-date-earlier (prefix-numeric-value arg)))))
8401
20908596 8402(defun org-agenda-date-later (arg &optional what)
3ab2c837 8403 "Change the date of this item to ARG day(s) later."
20908596
CD
8404 (interactive "p")
8405 (org-agenda-check-type t 'agenda 'timeline)
8406 (org-agenda-check-no-diary)
8d642074 8407 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
8408 (org-agenda-error)))
8409 (buffer (marker-buffer marker))
e66ba1df
BG
8410 (pos (marker-position marker))
8411 cdate today)
20908596 8412 (org-with-remote-undo buffer
e66ba1df
BG
8413 (with-current-buffer buffer
8414 (widen)
8415 (goto-char pos)
8416 (if (not (org-at-timestamp-p))
8417 (error "Cannot find time stamp"))
8418 (when (and org-agenda-move-date-from-past-immediately-to-today
8419 (equal arg 1)
8420 (or (not what) (eq what 'day))
8421 (not (save-match-data (org-at-date-range-p))))
8422 (setq cdate (org-parse-time-string (match-string 0) 'nodefault)
8423 cdate (calendar-absolute-from-gregorian
8424 (list (nth 4 cdate) (nth 3 cdate) (nth 5 cdate)))
8425 today (org-today))
8426 (if (> today cdate)
8427 ;; immediately shift to today
8428 (setq arg (- today cdate))))
8429 (org-timestamp-change arg (or what 'day))
8430 (when (and (org-at-date-range-p)
8431 (re-search-backward org-tr-regexp-both (point-at-bol)))
8432 (let ((end org-last-changed-timestamp))
8433 (org-timestamp-change arg (or what 'day))
8434 (setq org-last-changed-timestamp
8435 (concat org-last-changed-timestamp "--" end)))))
8436 (org-agenda-show-new-time marker org-last-changed-timestamp))
20908596
CD
8437 (message "Time stamp changed to %s" org-last-changed-timestamp)))
8438
8439(defun org-agenda-date-earlier (arg &optional what)
3ab2c837 8440 "Change the date of this item to ARG day(s) earlier."
20908596
CD
8441 (interactive "p")
8442 (org-agenda-date-later (- arg) what))
8443
c8d0cf5c
CD
8444(defun org-agenda-date-later-minutes (arg)
8445 "Change the time of this item, in units of `org-time-stamp-rounding-minutes'."
8446 (interactive "p")
8447 (setq arg (* arg (cadr org-time-stamp-rounding-minutes)))
8448 (org-agenda-date-later arg 'minute))
8449
8450(defun org-agenda-date-earlier-minutes (arg)
8451 "Change the time of this item, in units of `org-time-stamp-rounding-minutes'."
8452 (interactive "p")
8453 (setq arg (* arg (cadr org-time-stamp-rounding-minutes)))
8454 (org-agenda-date-earlier arg 'minute))
8455
8456(defun org-agenda-date-later-hours (arg)
8457 "Change the time of this item, in hour steps."
8458 (interactive "p")
8459 (org-agenda-date-later arg 'hour))
8460
8461(defun org-agenda-date-earlier-hours (arg)
8462 "Change the time of this item, in hour steps."
8463 (interactive "p")
8464 (org-agenda-date-earlier arg 'hour))
8465
20908596
CD
8466(defun org-agenda-show-new-time (marker stamp &optional prefix)
8467 "Show new date stamp via text properties."
8468 ;; We use text properties to make this undoable
8a28a5b8
BG
8469 (let ((inhibit-read-only t))
8470 (setq stamp (concat prefix " => " stamp " "))
20908596
CD
8471 (save-excursion
8472 (goto-char (point-max))
8473 (while (not (bobp))
8d642074 8474 (when (equal marker (org-get-at-bol 'org-marker))
20908596 8475 (org-move-to-column (- (window-width) (length stamp)) t)
71d35b24 8476 (org-agenda-fix-tags-filter-overlays-at (point))
20908596
CD
8477 (if (featurep 'xemacs)
8478 ;; Use `duplicable' property to trigger undo recording
8479 (let ((ex (make-extent nil nil))
8480 (gl (make-glyph stamp)))
8481 (set-glyph-face gl 'secondary-selection)
8482 (set-extent-properties
8483 ex (list 'invisible t 'end-glyph gl 'duplicable t))
8484 (insert-extent ex (1- (point)) (point-at-eol)))
8485 (add-text-properties
8486 (1- (point)) (point-at-eol)
8487 (list 'display (org-add-props stamp nil
8488 'face 'secondary-selection))))
8489 (beginning-of-line 1))
8490 (beginning-of-line 0)))))
8491
8492(defun org-agenda-date-prompt (arg)
8493 "Change the date of this item. Date is prompted for, with default today.
8494The prefix ARG is passed to the `org-time-stamp' command and can therefore
8495be used to request time specification in the time stamp."
8496 (interactive "P")
8497 (org-agenda-check-type t 'agenda 'timeline)
8498 (org-agenda-check-no-diary)
8d642074 8499 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
8500 (org-agenda-error)))
8501 (buffer (marker-buffer marker))
8502 (pos (marker-position marker)))
8503 (org-with-remote-undo buffer
8504 (with-current-buffer buffer
8505 (widen)
8506 (goto-char pos)
ed21c5c8 8507 (if (not (org-at-timestamp-p t))
20908596 8508 (error "Cannot find time stamp"))
ed21c5c8 8509 (org-time-stamp arg (equal (char-after (match-beginning 0)) ?\[)))
8d642074
CD
8510 (org-agenda-show-new-time marker org-last-changed-timestamp))
8511 (message "Time stamp changed to %s" org-last-changed-timestamp)))
20908596 8512
3ab2c837 8513(defun org-agenda-schedule (arg &optional time)
ed21c5c8 8514 "Schedule the item at point.
3ab2c837 8515ARG is passed through to `org-schedule'."
20908596
CD
8516 (interactive "P")
8517 (org-agenda-check-type t 'agenda 'timeline 'todo 'tags 'search)
8518 (org-agenda-check-no-diary)
8d642074 8519 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
8520 (org-agenda-error)))
8521 (type (marker-insertion-type marker))
8522 (buffer (marker-buffer marker))
8523 (pos (marker-position marker))
8524 (org-insert-labeled-timestamps-at-point nil)
8525 ts)
20908596
CD
8526 (set-marker-insertion-type marker t)
8527 (org-with-remote-undo buffer
8528 (with-current-buffer buffer
8529 (widen)
8530 (goto-char pos)
3ab2c837 8531 (setq ts (org-schedule arg time)))
8a28a5b8 8532 (org-agenda-show-new-time marker ts " S"))
63aa0982 8533 (message "%s" ts)))
20908596 8534
3ab2c837 8535(defun org-agenda-deadline (arg &optional time)
ed21c5c8 8536 "Schedule the item at point.
3ab2c837 8537ARG is passed through to `org-deadline'."
20908596
CD
8538 (interactive "P")
8539 (org-agenda-check-type t 'agenda 'timeline 'todo 'tags 'search)
8540 (org-agenda-check-no-diary)
8d642074 8541 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
8542 (org-agenda-error)))
8543 (buffer (marker-buffer marker))
8544 (pos (marker-position marker))
8545 (org-insert-labeled-timestamps-at-point nil)
8546 ts)
8547 (org-with-remote-undo buffer
8548 (with-current-buffer buffer
8549 (widen)
8550 (goto-char pos)
3ab2c837 8551 (setq ts (org-deadline arg time)))
8a28a5b8 8552 (org-agenda-show-new-time marker ts " D"))
63aa0982 8553 (message "%s" ts)))
ff4be292 8554
20908596
CD
8555(defun org-agenda-clock-in (&optional arg)
8556 "Start the clock on the currently selected item."
8557 (interactive "P")
8558 (org-agenda-check-no-diary)
8559 (if (equal arg '(4))
8560 (org-clock-in arg)
8d642074 8561 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596 8562 (org-agenda-error)))
8d642074 8563 (hdmarker (or (org-get-at-bol 'org-hd-marker)
b349f79f
CD
8564 marker))
8565 (pos (marker-position marker))
8566 newhead)
20908596
CD
8567 (org-with-remote-undo (marker-buffer marker)
8568 (with-current-buffer (marker-buffer marker)
8569 (widen)
8570 (goto-char pos)
b349f79f
CD
8571 (org-show-context 'agenda)
8572 (org-show-entry)
8573 (org-cycle-hide-drawers 'children)
8574 (org-clock-in arg)
8575 (setq newhead (org-get-heading)))
c8d0cf5c 8576 (org-agenda-change-all-lines newhead hdmarker)))))
20908596 8577
afe98dfa 8578(defun org-agenda-clock-out ()
20908596 8579 "Stop the currently running clock."
afe98dfa 8580 (interactive)
20908596
CD
8581 (unless (marker-buffer org-clock-marker)
8582 (error "No running clock"))
c8d0cf5c
CD
8583 (let ((marker (make-marker)) newhead)
8584 (org-with-remote-undo (marker-buffer org-clock-marker)
8585 (with-current-buffer (marker-buffer org-clock-marker)
8586 (save-excursion
8587 (save-restriction
8588 (widen)
8589 (goto-char org-clock-marker)
8590 (org-back-to-heading t)
8591 (move-marker marker (point))
8592 (org-clock-out)
8593 (setq newhead (org-get-heading))))))
8594 (org-agenda-change-all-lines newhead marker)
8595 (move-marker marker nil)))
20908596
CD
8596
8597(defun org-agenda-clock-cancel (&optional arg)
8598 "Cancel the currently running clock."
8599 (interactive "P")
8600 (unless (marker-buffer org-clock-marker)
8601 (error "No running clock"))
8602 (org-with-remote-undo (marker-buffer org-clock-marker)
8603 (org-clock-cancel)))
8604
afe98dfa
CD
8605(defun org-agenda-clock-goto ()
8606 "Jump to the currently clocked in task within the agenda.
8607If the currently clocked in task is not listed in the agenda
8608buffer, display it in another window."
8609 (interactive)
8610 (let (pos)
8611 (mapc (lambda (o)
8612 (if (eq (overlay-get o 'type) 'org-agenda-clocking)
8613 (setq pos (overlay-start o))))
8614 (overlays-in (point-min) (point-max)))
8615 (cond (pos (goto-char pos))
8616 ;; If the currently clocked entry is not in the agenda
8617 ;; buffer, we visit it in another window:
8618 (org-clock-current-task
8619 (org-switch-to-buffer-other-window (org-clock-goto)))
8620 (t (message "No running clock, use `C-c C-x C-j' to jump to the most recent one")))))
8621
8bfe682a
CD
8622(defun org-agenda-diary-entry-in-org-file ()
8623 "Make a diary entry in the file `org-agenda-diary-file'."
5dec9555 8624 (let (d1 d2 char (text "") dp1 dp2)
8bfe682a
CD
8625 (if (equal (buffer-name) "*Calendar*")
8626 (setq d1 (calendar-cursor-to-date t)
8627 d2 (car calendar-mark-ring))
5dec9555
CD
8628 (setq dp1 (get-text-property (point-at-bol) 'day))
8629 (unless dp1 (error "No date defined in current line"))
8630 (setq d1 (calendar-gregorian-from-absolute dp1)
8631 d2 (and (ignore-errors (mark))
8632 (save-excursion
8633 (goto-char (mark))
8634 (setq dp2 (get-text-property (point-at-bol) 'day)))
8635 (calendar-gregorian-from-absolute dp2))))
8bfe682a
CD
8636 (message "Diary entry: [d]ay [a]nniversary [b]lock [j]ump to date tree")
8637 (setq char (read-char-exclusive))
8638 (cond
8639 ((equal char ?d)
8640 (setq text (read-string "Day entry: "))
5dec9555
CD
8641 (org-agenda-add-entry-to-org-agenda-diary-file 'day text d1)
8642 (and (equal (buffer-name) org-agenda-buffer-name) (org-agenda-redo)))
8bfe682a
CD
8643 ((equal char ?a)
8644 (setq d1 (list (car d1) (nth 1 d1)
8645 (read-number (format "Reference year [%d]: " (nth 2 d1))
8646 (nth 2 d1))))
8647 (setq text (read-string "Anniversary (use %d to show years): "))
5dec9555
CD
8648 (org-agenda-add-entry-to-org-agenda-diary-file 'anniversary text d1)
8649 (and (equal (buffer-name) org-agenda-buffer-name) (org-agenda-redo)))
8bfe682a
CD
8650 ((equal char ?b)
8651 (setq text (read-string "Block entry: "))
8652 (unless (and d1 d2 (not (equal d1 d2)))
8653 (error "No block of days selected"))
5dec9555
CD
8654 (org-agenda-add-entry-to-org-agenda-diary-file 'block text d1 d2)
8655 (and (equal (buffer-name) org-agenda-buffer-name) (org-agenda-redo)))
8bfe682a
CD
8656 ((equal char ?j)
8657 (org-switch-to-buffer-other-window
8658 (find-file-noselect org-agenda-diary-file))
ed21c5c8 8659 (require 'org-datetree)
8bfe682a
CD
8660 (org-datetree-find-date-create d1)
8661 (org-reveal t))
8662 (t (error "Invalid selection character `%c'" char)))))
8663
5dec9555
CD
8664(defcustom org-agenda-insert-diary-strategy 'date-tree
8665 "Where in `org-agenda-diary-file' should new entries be added?
8666Valid values:
8667
8668date-tree in the date tree, as child of the date
8669top-level as top-level entries at the end of the file."
8670 :group 'org-agenda
8671 :type '(choice
8672 (const :tag "in a date tree" date-tree)
8673 (const :tag "as top level at end of file" top-level)))
8674
ed21c5c8
CD
8675(defcustom org-agenda-insert-diary-extract-time nil
8676 "Non-nil means extract any time specification from the diary entry."
8677 :group 'org-agenda
372d7b21 8678 :version "24.1"
ed21c5c8
CD
8679 :type 'boolean)
8680
8223b1d2
BG
8681(defcustom org-agenda-bulk-mark-char ">"
8682 "A single-character string to be used as the bulk mark."
8683 :group 'org-agenda
8684 :version "24.1"
8685 :type 'string)
8686
8bfe682a
CD
8687(defun org-agenda-add-entry-to-org-agenda-diary-file (type text &optional d1 d2)
8688 "Add a diary entry with TYPE to `org-agenda-diary-file'.
8689If TEXT is not empty, it will become the headline of the new entry, and
8690the resulting entry will not be shown. When TEXT is empty, switch to
8691`org-agenda-diary-file' and let the user finish the entry there."
8692 (let ((cw (current-window-configuration)))
8693 (org-switch-to-buffer-other-window
8694 (find-file-noselect org-agenda-diary-file))
8695 (widen)
8696 (goto-char (point-min))
8697 (cond
8698 ((eq type 'anniversary)
8699 (or (re-search-forward "^*[ \t]+Anniversaries" nil t)
8223b1d2
BG
8700 (progn
8701 (or (org-at-heading-p t)
8702 (progn
8703 (outline-next-heading)
8704 (insert "* Anniversaries\n\n")
8705 (beginning-of-line -1)))))
8bfe682a
CD
8706 (outline-next-heading)
8707 (org-back-over-empty-lines)
8708 (backward-char 1)
8709 (insert "\n")
3ab2c837
BG
8710 (insert (format "%%%%(org-anniversary %d %2d %2d) %s"
8711 (nth 2 d1) (car d1) (nth 1 d1) text)))
8bfe682a 8712 ((eq type 'day)
ed21c5c8
CD
8713 (let ((org-prefix-has-time t)
8714 (org-agenda-time-leading-zero t)
8715 fmt time time2)
8716 (if org-agenda-insert-diary-extract-time
e66ba1df 8717 ;; Use org-agenda-format-item to parse text for a time-range and
ed21c5c8
CD
8718 ;; remove it. FIXME: This is a hack, we should refactor
8719 ;; that function to make time extraction available separately
e66ba1df 8720 (setq fmt (org-agenda-format-item nil text nil nil t)
ed21c5c8
CD
8721 time (get-text-property 0 'time fmt)
8722 time2 (if (> (length time) 0)
8723 ;; split-string removes trailing ...... if
8724 ;; no end time given. First space
8725 ;; separates time from date.
8726 (concat " " (car (split-string time "\\.")))
8727 nil)
8728 text (get-text-property 0 'txt fmt)))
8729 (if (eq org-agenda-insert-diary-strategy 'top-level)
8730 (org-agenda-insert-diary-as-top-level text)
8731 (require 'org-datetree)
8732 (org-datetree-find-date-create d1)
8733 (org-agenda-insert-diary-make-new-entry text))
8734 (org-insert-time-stamp (org-time-from-absolute
8735 (calendar-absolute-from-gregorian d1))
8736 nil nil nil nil time2))
8bfe682a
CD
8737 (end-of-line 0))
8738 ((eq type 'block)
8739 (if (> (calendar-absolute-from-gregorian d1)
8740 (calendar-absolute-from-gregorian d2))
8741 (setq d1 (prog1 d2 (setq d2 d1))))
5dec9555
CD
8742 (if (eq org-agenda-insert-diary-strategy 'top-level)
8743 (org-agenda-insert-diary-as-top-level text)
8744 (require 'org-datetree)
8745 (org-datetree-find-date-create d1)
8746 (org-agenda-insert-diary-make-new-entry text))
8bfe682a
CD
8747 (org-insert-time-stamp (org-time-from-absolute
8748 (calendar-absolute-from-gregorian d1)))
8749 (insert "--")
8750 (org-insert-time-stamp (org-time-from-absolute
8751 (calendar-absolute-from-gregorian d2)))
8752 (end-of-line 0)))
8753 (if (string-match "\\S-" text)
8754 (progn
8755 (set-window-configuration cw)
8756 (message "%s entry added to %s"
8757 (capitalize (symbol-name type))
8758 (abbreviate-file-name org-agenda-diary-file)))
8759 (org-reveal t)
8760 (message "Please finish entry here"))))
8761
5dec9555
CD
8762(defun org-agenda-insert-diary-as-top-level (text)
8763 "Make new entry as a top-level entry at the end of the file.
8764Add TEXT as headline, and position the cursor in the second line so that
8765a timestamp can be added there."
8766 (widen)
8767 (goto-char (point-max))
8768 (or (bolp) (insert "\n"))
8769 (insert "* " text "\n")
8770 (if org-adapt-indentation (org-indent-to-column 2)))
8771
8bfe682a
CD
8772(defun org-agenda-insert-diary-make-new-entry (text)
8773 "Make new entry as last child of current entry.
8774Add TEXT as headline, and position the cursor in the second line so that
8775a timestamp can be added there."
8776 (let ((org-show-following-heading t)
8777 (org-show-siblings t)
8778 (org-show-hierarchy-above t)
8779 (org-show-entry-below t)
8780 col)
8781 (outline-next-heading)
8782 (org-back-over-empty-lines)
8783 (or (looking-at "[ \t]*$")
8784 (progn (insert "\n") (backward-char 1)))
ed21c5c8 8785 (org-insert-heading nil t)
8bfe682a
CD
8786 (org-do-demote)
8787 (setq col (current-column))
8788 (insert text "\n")
8789 (if org-adapt-indentation (org-indent-to-column col))
8790 (let ((org-show-following-heading t)
8791 (org-show-siblings t)
8792 (org-show-hierarchy-above t)
8793 (org-show-entry-below t))
8794 (org-show-context))))
8795
20908596
CD
8796(defun org-agenda-diary-entry ()
8797 "Make a diary entry, like the `i' command from the calendar.
8bfe682a
CD
8798All the standard commands work: block, weekly etc.
8799When `org-agenda-diary-file' points to a file,
8800`org-agenda-diary-entry-in-org-file' is called instead to create
8801entries in that Org-mode file."
20908596 8802 (interactive)
8bfe682a
CD
8803 (if (not (eq org-agenda-diary-file 'diary-file))
8804 (org-agenda-diary-entry-in-org-file)
8805 (require 'diary-lib)
8806 (let* ((char (progn
8807 (message "Diary entry: [d]ay [w]eekly [m]onthly [y]early [a]nniversary [b]lock [c]yclic")
8808 (read-char-exclusive)))
8809 (cmd (cdr (assoc char
8810 '((?d . insert-diary-entry)
8811 (?w . insert-weekly-diary-entry)
8812 (?m . insert-monthly-diary-entry)
8813 (?y . insert-yearly-diary-entry)
8814 (?a . insert-anniversary-diary-entry)
8815 (?b . insert-block-diary-entry)
8816 (?c . insert-cyclic-diary-entry)))))
8817 (oldf (symbol-function 'calendar-cursor-to-date))
8818 ;; (buf (get-file-buffer (substitute-in-file-name diary-file)))
8819 (point (point))
8820 (mark (or (mark t) (point))))
8821 (unless cmd
8822 (error "No command associated with <%c>" char))
8823 (unless (and (get-text-property point 'day)
8824 (or (not (equal ?b char))
8825 (get-text-property mark 'day)))
8826 (error "Don't know which date to use for diary entry"))
8827 ;; We implement this by hacking the `calendar-cursor-to-date' function
8828 ;; and the `calendar-mark-ring' variable. Saves a lot of code.
8829 (let ((calendar-mark-ring
8830 (list (calendar-gregorian-from-absolute
8831 (or (get-text-property mark 'day)
8832 (get-text-property point 'day))))))
8833 (unwind-protect
8834 (progn
8835 (fset 'calendar-cursor-to-date
8836 (lambda (&optional error dummy)
8837 (calendar-gregorian-from-absolute
8838 (get-text-property point 'day))))
20908596 8839 (call-interactively cmd))
8bfe682a 8840 (fset 'calendar-cursor-to-date oldf))))))
20908596 8841
20908596 8842(defun org-agenda-execute-calendar-command (cmd)
8223b1d2 8843 "Execute a calendar command from the agenda with date from cursor."
20908596
CD
8844 (org-agenda-check-type t 'agenda 'timeline)
8845 (require 'diary-lib)
8223b1d2
BG
8846 (unless (get-text-property (min (1- (point-max)) (point)) 'day)
8847 (error "Don't know which date to use for the calendar command"))
20908596
CD
8848 (let* ((oldf (symbol-function 'calendar-cursor-to-date))
8849 (point (point))
8850 (date (calendar-gregorian-from-absolute
8851 (get-text-property point 'day)))
8852 ;; the following 2 vars are needed in the calendar
8853 (displayed-month (car date))
8854 (displayed-year (nth 2 date)))
8223b1d2
BG
8855 (unwind-protect
8856 (progn
8857 (fset 'calendar-cursor-to-date
8858 (lambda (&optional error dummy)
8859 (calendar-gregorian-from-absolute
8860 (get-text-property point 'day))))
8861 (call-interactively cmd))
8862 (fset 'calendar-cursor-to-date oldf))))
20908596
CD
8863
8864(defun org-agenda-phases-of-moon ()
8865 "Display the phases of the moon for the 3 months around the cursor date."
8866 (interactive)
8867 (org-agenda-execute-calendar-command 'calendar-phases-of-moon))
8868
8869(defun org-agenda-holidays ()
8870 "Display the holidays for the 3 months around the cursor date."
8871 (interactive)
8872 (org-agenda-execute-calendar-command 'list-calendar-holidays))
8873
8223b1d2
BG
8874(defvar calendar-longitude) ; defined in calendar.el
8875(defvar calendar-latitude) ; defined in calendar.el
8876(defvar calendar-location-name) ; defined in calendar.el
20908596
CD
8877
8878(defun org-agenda-sunrise-sunset (arg)
8879 "Display sunrise and sunset for the cursor date.
8880Latitude and longitude can be specified with the variables
8881`calendar-latitude' and `calendar-longitude'. When called with prefix
8882argument, latitude and longitude will be prompted for."
8883 (interactive "P")
8884 (require 'solar)
8885 (let ((calendar-longitude (if arg nil calendar-longitude))
8886 (calendar-latitude (if arg nil calendar-latitude))
8887 (calendar-location-name
8888 (if arg "the given coordinates" calendar-location-name)))
8889 (org-agenda-execute-calendar-command 'calendar-sunrise-sunset)))
8890
8891(defun org-agenda-goto-calendar ()
8892 "Open the Emacs calendar with the date at the cursor."
8893 (interactive)
8894 (org-agenda-check-type t 'agenda 'timeline)
8223b1d2 8895 (let* ((day (or (get-text-property (min (1- (point-max)) (point)) 'day)
20908596
CD
8896 (error "Don't know which date to open in calendar")))
8897 (date (calendar-gregorian-from-absolute day))
8898 (calendar-move-hook nil)
8899 (calendar-view-holidays-initially-flag nil)
3820f429 8900 (calendar-view-diary-initially-flag nil))
20908596
CD
8901 (calendar)
8902 (calendar-goto-date date)))
8903
8904;;;###autoload
8905(defun org-calendar-goto-agenda ()
8906 "Compute the Org-mode agenda for the calendar date displayed at the cursor.
8907This is a command that has to be installed in `calendar-mode-map'."
8908 (interactive)
8909 (org-agenda-list nil (calendar-absolute-from-gregorian
8910 (calendar-cursor-to-date))
8911 nil))
8912
8913(defun org-agenda-convert-date ()
8914 (interactive)
8915 (org-agenda-check-type t 'agenda 'timeline)
8223b1d2 8916 (let ((day (get-text-property (min (1- (point-max)) (point)) 'day))
20908596
CD
8917 date s)
8918 (unless day
8919 (error "Don't know which date to convert"))
8920 (setq date (calendar-gregorian-from-absolute day))
8921 (setq s (concat
8922 "Gregorian: " (calendar-date-string date) "\n"
8923 "ISO: " (calendar-iso-date-string date) "\n"
8924 "Day of Yr: " (calendar-day-of-year-string date) "\n"
8925 "Julian: " (calendar-julian-date-string date) "\n"
8926 "Astron. JD: " (calendar-astro-date-string date)
8927 " (Julian date number at noon UTC)\n"
8928 "Hebrew: " (calendar-hebrew-date-string date) " (until sunset)\n"
8929 "Islamic: " (calendar-islamic-date-string date) " (until sunset)\n"
8930 "French: " (calendar-french-date-string date) "\n"
8931 "Baha'i: " (calendar-bahai-date-string date) " (until sunset)\n"
8932 "Mayan: " (calendar-mayan-date-string date) "\n"
8933 "Coptic: " (calendar-coptic-date-string date) "\n"
8934 "Ethiopic: " (calendar-ethiopic-date-string date) "\n"
8935 "Persian: " (calendar-persian-date-string date) "\n"
8936 "Chinese: " (calendar-chinese-date-string date) "\n"))
8937 (with-output-to-temp-buffer "*Dates*"
8938 (princ s))
93b62de8 8939 (org-fit-window-to-buffer (get-buffer-window "*Dates*"))))
20908596 8940
c8d0cf5c
CD
8941;;; Bulk commands
8942
54a0dee5
CD
8943(defun org-agenda-bulk-marked-p ()
8944 (eq (get-char-property (point-at-bol) 'type)
8945 'org-marked-entry-overlay))
8946
acedf35c 8947(defun org-agenda-bulk-mark (&optional arg)
c8d0cf5c 8948 "Mark the entry at point for future bulk action."
acedf35c 8949 (interactive "p")
2f885dca 8950 (dotimes (i (or arg 1))
acedf35c
CD
8951 (unless (org-get-at-bol 'org-agenda-diary-link)
8952 (let* ((m (org-get-at-bol 'org-hd-marker))
8953 ov)
8954 (unless (org-agenda-bulk-marked-p)
8955 (unless m (error "Nothing to mark at point"))
8956 (push m org-agenda-bulk-marked-entries)
8957 (setq ov (make-overlay (point-at-bol) (+ 2 (point-at-bol))))
8223b1d2 8958 (org-overlay-display ov (concat org-agenda-bulk-mark-char " ")
acedf35c
CD
8959 (org-get-todo-face "TODO")
8960 'evaporate)
8961 (overlay-put ov 'type 'org-marked-entry-overlay))
8962 (beginning-of-line 2)
8963 (while (and (get-char-property (point) 'invisible) (not (eobp)))
8964 (beginning-of-line 2))
8965 (message "%d entries marked for bulk action"
8966 (length org-agenda-bulk-marked-entries))))))
c8d0cf5c 8967
8223b1d2
BG
8968(defun org-agenda-bulk-mark-all ()
8969 "Mark all entries for future agenda bulk action."
8970 (interactive)
8971 (org-agenda-bulk-mark-regexp "."))
8972
3ab2c837 8973(defun org-agenda-bulk-mark-regexp (regexp)
8223b1d2 8974 "Mark entries matching REGEXP for future agenda bulk action."
3ab2c837 8975 (interactive "sMark entries matching regexp: ")
8c8b834f 8976 (let ((entries-marked 0))
3ab2c837
BG
8977 (save-excursion
8978 (goto-char (point-min))
8979 (goto-char (next-single-property-change (point) 'txt))
8980 (while (re-search-forward regexp nil t)
8981 (when (string-match regexp (get-text-property (point) 'txt))
8c8b834f 8982 (setq entries-marked (1+ entries-marked))
3ab2c837
BG
8983 (call-interactively 'org-agenda-bulk-mark))))
8984 (if (not entries-marked)
8985 (message "No entry matching this regexp."))))
8986
8223b1d2 8987(defun org-agenda-bulk-unmark (&optional arg)
c8d0cf5c 8988 "Unmark the entry at point for future bulk action."
8223b1d2
BG
8989 (interactive "P")
8990 (if arg
8991 (org-agenda-bulk-unmark-all)
8992 (cond ((org-agenda-bulk-marked-p)
8993 (org-agenda-bulk-remove-overlays
8994 (point-at-bol) (+ 2 (point-at-bol)))
8995 (setq org-agenda-bulk-marked-entries
8996 (delete (org-get-at-bol 'org-hd-marker)
8997 org-agenda-bulk-marked-entries))
8998 (beginning-of-line 2)
8999 (while (and (get-char-property (point) 'invisible) (not (eobp)))
9000 (beginning-of-line 2))
9001 (message "%d entries left marked for bulk action"
9002 (length org-agenda-bulk-marked-entries)))
9003 (t (message "No entry to unmark here")))))
c8d0cf5c 9004
54a0dee5 9005(defun org-agenda-bulk-toggle ()
8223b1d2
BG
9006 "Toggle marking the entry at point for bulk action."
9007 (interactive)
9008 (if (org-agenda-bulk-marked-p)
9009 (org-agenda-bulk-unmark)
9010 (org-agenda-bulk-mark)))
c8d0cf5c
CD
9011
9012(defun org-agenda-bulk-remove-overlays (&optional beg end)
9013 "Remove the mark overlays between BEG and END in the agenda buffer.
9014BEG and END default to the buffer limits.
9015
9016This only removes the overlays, it does not remove the markers
9017from the list in `org-agenda-bulk-marked-entries'."
9018 (interactive)
9019 (mapc (lambda (ov)
86fbb8ca
CD
9020 (and (eq (overlay-get ov 'type) 'org-marked-entry-overlay)
9021 (delete-overlay ov)))
9022 (overlays-in (or beg (point-min)) (or end (point-max)))))
c8d0cf5c 9023
8223b1d2 9024(defun org-agenda-bulk-unmark-all ()
c8d0cf5c 9025 "Remove all marks in the agenda buffer.
8223b1d2 9026This will remove the markers and the overlays."
c8d0cf5c 9027 (interactive)
8223b1d2
BG
9028 (if (null org-agenda-bulk-marked-entries)
9029 (message "No entry to unmark")
9030 (mapc (lambda (m) (move-marker m nil)) org-agenda-bulk-marked-entries)
9031 (setq org-agenda-bulk-marked-entries nil)
9032 (org-agenda-bulk-remove-overlays (point-min) (point-max))))
9033
9034(defcustom org-agenda-persistent-marks nil
9035 "Non-nil means marked items will stay marked after a bulk action.
9036You can toggle this interactively by typing `p' when prompted for a
9037bulk action."
9038 :group 'org-agenda
9039 :version "24.1"
9040 :type 'boolean)
c8d0cf5c 9041
ed21c5c8
CD
9042(defun org-agenda-bulk-action (&optional arg)
9043 "Execute an remote-editing action on all marked entries.
9044The prefix arg is passed through to the command if possible."
9045 (interactive "P")
3ab2c837
BG
9046 ;; Make sure we have markers, and only valid ones
9047 (unless org-agenda-bulk-marked-entries (error "No entries are marked"))
9048 (mapc
9049 (lambda (m)
9050 (unless (and (markerp m)
9051 (marker-buffer m)
9052 (buffer-live-p (marker-buffer m))
9053 (marker-position m))
9054 (error "Marker %s for bulk command is invalid" m)))
9055 org-agenda-bulk-marked-entries)
9056
9057 ;; Prompt for the bulk command
8223b1d2
BG
9058 (let* ((msg (if org-agenda-persistent-marks "Bulk (persistent): " "Bulk: ")))
9059 (message (concat msg "[$]arch [A]rch->sib [t]odo [+/-]tag [s]chd [d]eadline [r]efile "
9060 "[S]catter [f]unction "
9061 (when org-agenda-bulk-custom-functions
9062 (concat " Custom: ["
9063 (mapconcat (lambda(f) (char-to-string (car f)))
9064 org-agenda-bulk-custom-functions "")
9065 "]"))))
9066 (catch 'exit
9067 (let* ((action (read-char-exclusive))
9068 (org-log-refile (if org-log-refile 'time nil))
9069 (entries (reverse org-agenda-bulk-marked-entries))
9070 (org-overriding-default-time
9071 (if (get-text-property (point) 'org-agenda-date-header)
9072 (org-get-cursor-date)))
9073 redo-at-end
9074 cmd rfloc state e tag pos (cnt 0) (cntskip 0))
9075 (cond
9076 ((equal action ?p)
9077 (let ((org-agenda-persistent-marks
9078 (not org-agenda-persistent-marks)))
9079 (org-agenda-bulk-action)
9080 (throw 'exit nil)))
9081
9082 ((equal action ?$)
9083 (setq cmd '(org-agenda-archive)))
9084
9085 ((equal action ?A)
9086 (setq cmd '(org-agenda-archive-to-archive-sibling)))
9087
9088 ((member action '(?r ?w))
9089 (setq rfloc (org-refile-get-location
9090 "Refile to"
9091 (marker-buffer (car entries))
9092 org-refile-allow-creating-parent-nodes))
9093 (if (nth 3 rfloc)
9094 (setcar (nthcdr 3 rfloc)
9095 (move-marker (make-marker) (nth 3 rfloc)
9096 (or (get-file-buffer (nth 1 rfloc))
9097 (find-buffer-visiting (nth 1 rfloc))
9098 (error "This should not happen")))))
9099
9100 (setq cmd (list 'org-agenda-refile nil (list 'quote rfloc) t)
9101 redo-at-end t))
9102
9103 ((equal action ?t)
9104 (setq state (org-icompleting-read
9105 "Todo state: "
9106 (with-current-buffer (marker-buffer (car entries))
9107 (mapcar 'list org-todo-keywords-1))))
9108 (setq cmd `(let ((org-inhibit-blocking t)
9109 (org-inhibit-logging 'note))
9110 (org-agenda-todo ,state))))
9111
9112 ((memq action '(?- ?+))
9113 (setq tag (org-icompleting-read
9114 (format "Tag to %s: " (if (eq action ?+) "add" "remove"))
9115 (with-current-buffer (marker-buffer (car entries))
9116 (delq nil
9117 (mapcar (lambda (x)
9118 (if (stringp (car x)) x)) org-tag-alist)))))
9119 (setq cmd `(org-agenda-set-tags ,tag ,(if (eq action ?+) ''on ''off))))
9120
9121 ((memq action '(?s ?d))
9122 (let* ((time
9123 (unless arg
9124 (org-read-date
9125 nil nil nil
9126 (if (eq action ?s) "(Re)Schedule to" "(Re)Set Deadline to")
9127 org-overriding-default-time)))
9128 (c1 (if (eq action ?s) 'org-agenda-schedule 'org-agenda-deadline)))
9129 (setq cmd `(eval '(,c1 arg ,time)))))
9130
9131 ((equal action ?S)
9132 (if (not (org-agenda-check-type nil 'agenda 'timeline 'todo))
9133 (error "Can't scatter tasks in \"%s\" agenda view" org-agenda-type)
9134 (let ((days (read-number
9135 (format "Scatter tasks across how many %sdays: "
9136 (if arg "week" "")) 7)))
9137 (setq cmd
9138 `(let ((distance (1+ (random ,days))))
9139 (if arg
9140 (let ((dist distance)
9141 (day-of-week
9142 (calendar-day-of-week
9143 (calendar-gregorian-from-absolute (org-today)))))
9144 (dotimes (i (1+ dist))
9145 (while (member day-of-week org-agenda-weekend-days)
9146 (incf distance)
9147 (incf day-of-week)
9148 (if (= day-of-week 7)
9149 (setq day-of-week 0)))
9150 (incf day-of-week)
9151 (if (= day-of-week 7)
9152 (setq day-of-week 0)))))
9153 ;; silently fail when try to replan a sexp entry
9154 (condition-case nil
9155 (let* ((date (calendar-gregorian-from-absolute
9156 (+ (org-today) distance)))
9157 (time (encode-time 0 0 0 (nth 1 date) (nth 0 date)
9158 (nth 2 date))))
9159 (org-agenda-schedule nil time))
9160 (error nil)))))))
9161
9162 ((assoc action org-agenda-bulk-custom-functions)
9163 (setq cmd (list (cadr (assoc action org-agenda-bulk-custom-functions)))
9164 redo-at-end t))
9165
9166 ((equal action ?f)
9167 (setq cmd (list (intern
9168 (org-icompleting-read "Function: "
9169 obarray 'fboundp t nil nil)))))
9170
9171 (t (error "Invalid bulk action")))
9172
9173 ;; Sort the markers, to make sure that parents are handled before children
9174 (setq entries (sort entries
9175 (lambda (a b)
9176 (cond
9177 ((equal (marker-buffer a) (marker-buffer b))
9178 (< (marker-position a) (marker-position b)))
9179 (t
9180 (string< (buffer-name (marker-buffer a))
9181 (buffer-name (marker-buffer b))))))))
9182
9183 ;; Now loop over all markers and apply cmd
9184 (while (setq e (pop entries))
9185 (setq pos (text-property-any (point-min) (point-max) 'org-hd-marker e))
9186 (if (not pos)
9187 (progn (message "Skipping removed entry at %s" e)
9188 (setq cntskip (1+ cntskip)))
9189 (goto-char pos)
9190 (let (org-loop-over-headlines-in-active-region)
9191 (eval cmd))
9192 (setq cnt (1+ cnt))))
9193 (when redo-at-end (org-agenda-redo))
9194 (unless org-agenda-persistent-marks
9195 (org-agenda-bulk-unmark-all))
9196 (message "Acted on %d entries%s%s"
9197 cnt
9198 (if (= cntskip 0)
9199 ""
9200 (format ", skipped %d (disappeared before their turn)"
9201 cntskip))
9202 (if (not org-agenda-persistent-marks)
9203 "" " (kept marked)"))))))
9204
9205(defun org-agenda-capture ()
9206 "Call `org-capture' with the date at point."
9207 (interactive)
9208 (if (not (eq major-mode 'org-agenda-mode))
9209 (error "You cannot do this outside of agenda buffers")
9210 (let ((org-overriding-default-time
9211 (org-get-cursor-date)))
9212 (call-interactively 'org-capture))))
8d642074
CD
9213
9214;;; Flagging notes
9215
9216(defun org-agenda-show-the-flagging-note ()
9217 "Display the flagging note in the other window.
9218When called a second time in direct sequence, offer to remove the FLAGGING
9219tag and (if present) the flagging note."
9220 (interactive)
9221 (let ((hdmarker (org-get-at-bol 'org-hd-marker))
9222 (win (selected-window))
9223 note heading newhead)
9224 (unless hdmarker
9225 (error "No linked entry at point"))
9226 (if (and (eq this-command last-command)
9227 (y-or-n-p "Unflag and remove any flagging note? "))
9228 (progn
9229 (org-agenda-remove-flag hdmarker)
9230 (let ((win (get-buffer-window "*Flagging Note*")))
9231 (and win (delete-window win)))
27e428e7 9232 (message "Entry unflagged"))
8d642074
CD
9233 (setq note (org-entry-get hdmarker "THEFLAGGINGNOTE"))
9234 (unless note
9235 (error "No flagging note"))
9236 (org-kill-new note)
9237 (org-switch-to-buffer-other-window "*Flagging Note*")
9238 (erase-buffer)
9239 (insert note)
9240 (goto-char (point-min))
9241 (while (re-search-forward "\\\\n" nil t)
9242 (replace-match "\n" t t))
9243 (goto-char (point-min))
9244 (select-window win)
9245 (message "Flagging note pushed to kill ring. Press [?] again to remove tag and note"))))
9246
9247(defun org-agenda-remove-flag (marker)
8bfe682a 9248 "Remove the FLAGGED tag and any flagging note in the entry."
8d642074
CD
9249 (let (newhead)
9250 (org-with-point-at marker
9251 (org-toggle-tag "FLAGGED" 'off)
9252 (org-entry-delete nil "THEFLAGGINGNOTE")
9253 (setq newhead (org-get-heading)))
9254 (org-agenda-change-all-lines newhead marker)
27e428e7 9255 (message "Entry unflagged")))
8d642074
CD
9256
9257(defun org-agenda-get-any-marker (&optional pos)
9258 (or (get-text-property (or pos (point-at-bol)) 'org-hd-marker)
9259 (get-text-property (or pos (point-at-bol)) 'org-marker)))
c8d0cf5c 9260
20908596
CD
9261;;; Appointment reminders
9262
8223b1d2 9263(defvar appt-time-msg-list) ; defined in appt.el
20908596
CD
9264
9265;;;###autoload
e66ba1df 9266(defun org-agenda-to-appt (&optional refresh filter &rest args)
20908596
CD
9267 "Activate appointments found in `org-agenda-files'.
9268With a \\[universal-argument] prefix, refresh the list of
33306645 9269appointments.
20908596
CD
9270
9271If FILTER is t, interactively prompt the user for a regular
9272expression, and filter out entries that don't match it.
9273
9274If FILTER is a string, use this string as a regular expression
9275for filtering entries out.
9276
e66ba1df
BG
9277If FILTER is a function, filter out entries against which
9278calling the function returns nil. This function takes one
9279argument: an entry from `org-agenda-get-day-entries'.
9280
20908596
CD
9281FILTER can also be an alist with the car of each cell being
9282either 'headline or 'category. For example:
9283
9284 '((headline \"IMPORTANT\")
9285 (category \"Work\"))
9286
9287will only add headlines containing IMPORTANT or headlines
e66ba1df
BG
9288belonging to the \"Work\" category.
9289
9290ARGS are symbols indicating what kind of entries to consider.
9291By default `org-agenda-to-appt' will use :deadline, :scheduled
9292and :timestamp entries. See the docstring of `org-diary' for
8223b1d2
BG
9293details and examples.
9294
8a28a5b8 9295If an entry has a APPT_WARNTIME property, its value will be used
8223b1d2 9296to override `appt-message-warning-time'."
20908596 9297 (interactive "P")
20908596
CD
9298 (if refresh (setq appt-time-msg-list nil))
9299 (if (eq filter t)
9300 (setq filter (read-from-minibuffer "Regexp filter: ")))
9301 (let* ((cnt 0) ; count added events
e66ba1df 9302 (scope (or args '(:deadline :scheduled :timestamp)))
20908596
CD
9303 (org-agenda-new-buffers nil)
9304 (org-deadline-warning-days 0)
acedf35c
CD
9305 ;; Do not use `org-today' here because appt only takes
9306 ;; time and without date as argument, so it may pass wrong
9307 ;; information otherwise
20908596
CD
9308 (today (org-date-to-gregorian
9309 (time-to-days (current-time))))
c8d0cf5c 9310 (org-agenda-restrict nil)
8223b1d2
BG
9311 (files (org-agenda-files 'unrestricted)) entries file
9312 (org-agenda-buffer nil))
20908596 9313 ;; Get all entries which may contain an appt
8223b1d2 9314 (org-agenda-prepare-buffers files)
20908596
CD
9315 (while (setq file (pop files))
9316 (setq entries
e66ba1df
BG
9317 (delq nil
9318 (append entries
9319 (apply 'org-agenda-get-day-entries
9320 file today scope)))))
20908596
CD
9321 ;; Map thru entries and find if we should filter them out
9322 (mapc
9323 (lambda(x)
621f83e4 9324 (let* ((evt (org-trim (or (get-text-property 1 'txt x) "")))
20908596
CD
9325 (cat (get-text-property 1 'org-category x))
9326 (tod (get-text-property 1 'time-of-day x))
9327 (ok (or (null filter)
9328 (and (stringp filter) (string-match filter evt))
e66ba1df 9329 (and (functionp filter) (funcall filter x))
20908596 9330 (and (listp filter)
e66ba1df
BG
9331 (let ((cat-filter (cadr (assoc 'category filter)))
9332 (evt-filter (cadr (assoc 'headline filter))))
9333 (or (and (stringp cat-filter)
9334 (string-match cat-filter cat))
9335 (and (stringp evt-filter)
8223b1d2
BG
9336 (string-match evt-filter evt)))))))
9337 (wrn (get-text-property 1 'warntime x)))
20908596
CD
9338 ;; FIXME: Shall we remove text-properties for the appt text?
9339 ;; (setq evt (set-text-properties 0 (length evt) nil evt))
9340 (when (and ok tod)
621f83e4 9341 (setq tod (concat "00" (number-to-string tod))
20908596 9342 tod (when (string-match
621f83e4 9343 "\\([0-9]\\{1,2\\}\\)\\([0-9]\\{2\\}\\)\\'" tod)
20908596
CD
9344 (concat (match-string 1 tod) ":"
9345 (match-string 2 tod))))
8223b1d2
BG
9346 (if (version< emacs-version "23.3")
9347 (appt-add tod evt)
9348 (appt-add tod evt wrn))
20908596
CD
9349 (setq cnt (1+ cnt))))) entries)
9350 (org-release-buffers org-agenda-new-buffers)
9351 (if (eq cnt 0)
9352 (message "No event to add")
9353 (message "Added %d event%s for today" cnt (if (> cnt 1) "s" "")))))
9354
621f83e4
CD
9355(defun org-agenda-todayp (date)
9356 "Does DATE mean today, when considering `org-extend-today-until'?"
acedf35c
CD
9357 (let ((today (org-today))
9358 (date (if (and date (listp date)) (calendar-absolute-from-gregorian date)
9359 date)))
9360 (eq date today)))
621f83e4 9361
e66ba1df 9362(defun org-agenda-todo-yesterday (&optional arg)
8223b1d2 9363 "Like `org-agenda-todo' but the time of change will be 23:59 of yesterday."
e66ba1df
BG
9364 (interactive "P")
9365 (let* ((hour (third (decode-time
9366 (org-current-time))))
9367 (org-extend-today-until (1+ hour)))
9368 (org-agenda-todo arg)))
5b409b39 9369
e66ba1df 9370(provide 'org-agenda)
b349f79f 9371
20908596 9372;;; org-agenda.el ends here