* etc/publicsuffix.txt: Update from source.
[bpt/emacs.git] / lisp / org / org-agenda.el
CommitLineData
b349f79f 1;;; org-agenda.el --- Dynamic task and appointment lists for Org
20908596 2
ba318903 3;; Copyright (C) 2004-2014 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
271672fa
BG
230 :type '(choice
231 (const nil)
232 (string)))
20908596 233
86fbb8ca
CD
234(defcustom org-agenda-persistent-filter nil
235 "When set, keep filters from one agenda view to the next."
236 :group 'org-agenda
237 :type 'boolean)
238
20908596 239(defgroup org-agenda-custom-commands nil
8223b1d2
BG
240 "Options concerning agenda views in Org-mode."
241 :tag "Org Agenda Custom Commands"
242 :group 'org-agenda)
20908596
CD
243
244(defconst org-sorting-choice
245 '(choice
246 (const time-up) (const time-down)
271672fa
BG
247 (const timestamp-up) (const timestamp-down)
248 (const scheduled-up) (const scheduled-down)
249 (const deadline-up) (const deadline-down)
250 (const ts-up) (const ts-down)
251 (const tsia-up) (const tsia-down)
20908596
CD
252 (const category-keep) (const category-up) (const category-down)
253 (const tag-down) (const tag-up)
254 (const priority-up) (const priority-down)
621f83e4 255 (const todo-state-up) (const todo-state-down)
c8d0cf5c 256 (const effort-up) (const effort-down)
8bfe682a 257 (const habit-up) (const habit-down)
86fbb8ca 258 (const alpha-up) (const alpha-down)
c8d0cf5c 259 (const user-defined-up) (const user-defined-down))
20908596
CD
260 "Sorting choices.")
261
e66ba1df
BG
262;; Keep custom values for `org-agenda-filter-preset' compatible with
263;; the new variable `org-agenda-tag-filter-preset'.
271672fa
BG
264(org-defvaralias 'org-agenda-filter-preset 'org-agenda-tag-filter-preset)
265(org-defvaralias 'org-agenda-filter 'org-agenda-tag-filter)
266
267(defvar org-agenda-entry-types '(:deadline :scheduled :timestamp :sexp)
268 "List of types searched for when creating the daily/weekly agenda.
269This variable is a list of symbols that controls the types of
270items that appear in the daily/weekly agenda. Allowed symbols in this
271list are are
272
273 :timestamp List items containing a date stamp or date range matching
274 the selected date. This includes sexp entries in angular
275 brackets.
276
277 :sexp List entries resulting from plain diary-like sexps.
278
279 :deadline List deadline due on that date. When the date is today,
280 also list any deadlines past due, or due within
281 `org-deadline-warning-days'. `:deadline' must appear before
282 `:scheduled' if the setting of
283 `org-agenda-skip-scheduled-if-deadline-is-shown' is to have
284 any effect.
285
286 :deadline* Same as above, but only include the deadline if it has an
287 hour specification as [h]h:mm.
288
289 :scheduled List all items which are scheduled for the given date.
290 The diary for *today* also contains items which were
291 scheduled earlier and are not yet marked DONE.
292
293 :scheduled* Same as above, but only include the scheduled item if it
294 has an hour specification as [h]h:mm.
295
296By default, all four non-starred types are turned on.
297
298When :scheduled* or :deadline* are included, :schedule or :deadline
299will be ignored.
300
301Never set this variable globally using `setq', because then it
302will apply to all future agenda commands. Instead, bind it with
303`let' to scope it dynamically into the agenda-constructing
304command. A good way to set it is through options in
305`org-agenda-custom-commands'. For a more flexible (though
306somewhat less efficient) way of determining what is included in
307the daily/weekly agenda, see `org-agenda-skip-function'.")
e66ba1df 308
20908596 309(defconst org-agenda-custom-commands-local-options
8223b1d2 310 `(repeat :tag "Local settings for this command. Remember to quote values"
20908596 311 (choice :tag "Setting"
8223b1d2
BG
312 (list :tag "Heading for this block"
313 (const org-agenda-overriding-header)
314 (string :tag "Headline"))
315 (list :tag "Files to be searched"
316 (const org-agenda-files)
317 (list
318 (const :format "" quote)
319 (repeat (file))))
320 (list :tag "Sorting strategy"
321 (const org-agenda-sorting-strategy)
322 (list
323 (const :format "" quote)
324 (repeat
325 ,org-sorting-choice)))
326 (list :tag "Prefix format"
327 (const org-agenda-prefix-format :value " %-12:c%?-12t% s")
328 (string))
329 (list :tag "Number of days in agenda"
330 (const org-agenda-span)
3c8b09ca
BG
331 (choice (const :tag "Day" day)
332 (const :tag "Week" week)
333 (const :tag "Fortnight" fortnight)
334 (const :tag "Month" month)
335 (const :tag "Year" year)
8223b1d2
BG
336 (integer :tag "Custom")))
337 (list :tag "Fixed starting date"
338 (const org-agenda-start-day)
339 (string :value "2007-11-01"))
340 (list :tag "Start on day of week"
341 (const org-agenda-start-on-weekday)
342 (choice :value 1
343 (const :tag "Today" nil)
344 (integer :tag "Weekday No.")))
345 (list :tag "Include data from diary"
346 (const org-agenda-include-diary)
347 (boolean))
348 (list :tag "Deadline Warning days"
349 (const org-deadline-warning-days)
350 (integer :value 1))
351 (list :tag "Category filter preset"
352 (const org-agenda-category-filter-preset)
353 (list
354 (const :format "" quote)
355 (repeat
356 (string :tag "+category or -category"))))
357 (list :tag "Tags filter preset"
358 (const org-agenda-tag-filter-preset)
359 (list
360 (const :format "" quote)
361 (repeat
362 (string :tag "+tag or -tag"))))
271672fa
BG
363 (list :tag "Regexp filter preset"
364 (const org-agenda-regexp-filter-preset)
365 (list
366 (const :format "" quote)
367 (repeat
368 (string :tag "+regexp or -regexp"))))
8223b1d2
BG
369 (list :tag "Set daily/weekly entry types"
370 (const org-agenda-entry-types)
371 (list
372 (const :format "" quote)
271672fa 373 (set :greedy t :value ,org-agenda-entry-types
8223b1d2
BG
374 (const :deadline)
375 (const :scheduled)
271672fa
BG
376 (const :deadline*)
377 (const :scheduled*)
8223b1d2
BG
378 (const :timestamp)
379 (const :sexp))))
380 (list :tag "Standard skipping condition"
381 :value (org-agenda-skip-function '(org-agenda-skip-entry-if))
382 (const org-agenda-skip-function)
383 (list
384 (const :format "" quote)
385 (list
386 (choice
387 :tag "Skipping range"
388 (const :tag "Skip entry" org-agenda-skip-entry-if)
389 (const :tag "Skip subtree" org-agenda-skip-subtree-if))
390 (repeat :inline t :tag "Conditions for skipping"
ed21c5c8 391 (choice
8223b1d2 392 :tag "Condition type"
3c8b09ca
BG
393 (list :tag "Regexp matches" :inline t (const :format "" regexp) (regexp))
394 (list :tag "Regexp does not match" :inline t (const :format "" notregexp) (regexp))
8223b1d2 395 (list :tag "TODO state is" :inline t
3c8b09ca 396 (const todo)
8223b1d2 397 (choice
3c8b09ca
BG
398 (const :tag "any not-done state" todo)
399 (const :tag "any done state" done)
400 (const :tag "any state" any)
8223b1d2
BG
401 (list :tag "Keyword list"
402 (const :format "" quote)
403 (repeat (string :tag "Keyword")))))
404 (list :tag "TODO state is not" :inline t
3c8b09ca 405 (const nottodo)
8223b1d2 406 (choice
3c8b09ca
BG
407 (const :tag "any not-done state" todo)
408 (const :tag "any done state" done)
409 (const :tag "any state" any)
8223b1d2
BG
410 (list :tag "Keyword list"
411 (const :format "" quote)
412 (repeat (string :tag "Keyword")))))
3c8b09ca
BG
413 (const :tag "scheduled" scheduled)
414 (const :tag "not scheduled" notscheduled)
415 (const :tag "deadline" deadline)
416 (const :tag "no deadline" notdeadline)
417 (const :tag "timestamp" timestamp)
418 (const :tag "no timestamp" nottimestamp))))))
8223b1d2
BG
419 (list :tag "Non-standard skipping condition"
420 :value (org-agenda-skip-function)
421 (const org-agenda-skip-function)
422 (sexp :tag "Function or form (quoted!)"))
423 (list :tag "Any variable"
424 (variable :tag "Variable")
425 (sexp :tag "Value (sexp)"))))
20908596
CD
426 "Selection of examples for agenda command settings.
427This will be spliced into the custom type of
428`org-agenda-custom-commands'.")
429
430
271672fa
BG
431(defcustom org-agenda-custom-commands
432 '(("n" "Agenda and all TODO's" ((agenda "") (alltodo ""))))
20908596
CD
433 "Custom commands for the agenda.
434These commands will be offered on the splash screen displayed by the
435agenda dispatcher \\[org-agenda]. Each entry is a list like this:
436
437 (key desc type match settings files)
438
439key The key (one or more characters as a string) to be associated
440 with the command.
e66ba1df 441desc A description of the command, when omitted or nil, a default
20908596
CD
442 description is built using MATCH.
443type The command type, any of the following symbols:
444 agenda The daily/weekly agenda.
445 todo Entries with a specific TODO keyword, in all agenda files.
446 search Entries containing search words entry or headline.
447 tags Tags/Property/TODO match in all agenda files.
448 tags-todo Tags/P/T match in all agenda files, TODO entries only.
449 todo-tree Sparse tree of specific TODO keyword in *current* file.
450 tags-tree Sparse tree with all tags matches in *current* file.
451 occur-tree Occur sparse tree for *current* file.
452 ... A user-defined function.
453match What to search for:
454 - a single keyword for TODO keyword searches
455 - a tags match expression for tags searches
e66ba1df 456 - a word search expression for text searches.
20908596
CD
457 - a regular expression for occur searches
458 For all other commands, this should be the empty string.
459settings A list of option settings, similar to that in a let form, so like
460 this: ((opt1 val1) (opt2 val2) ...). The values will be
461 evaluated at the moment of execution, so quote them when needed.
462files A list of files file to write the produced agenda buffer to
463 with the command `org-store-agenda-views'.
464 If a file name ends in \".html\", an HTML version of the buffer
e66ba1df 465 is written out. If it ends in \".ps\", a postscript version is
33306645 466 produced. Otherwise, only the plain text is written to the file.
20908596
CD
467
468You can also define a set of commands, to create a composite agenda buffer.
469In this case, an entry looks like this:
470
471 (key desc (cmd1 cmd2 ...) general-settings-for-whole-set files)
472
473where
474
475desc A description string to be displayed in the dispatcher menu.
476cmd An agenda command, similar to the above. However, tree commands
153ae947 477 are not allowed, but instead you can get agenda and global todo list.
20908596
CD
478 So valid commands for a set are:
479 (agenda \"\" settings)
480 (alltodo \"\" settings)
481 (stuck \"\" settings)
482 (todo \"match\" settings files)
483 (search \"match\" settings files)
484 (tags \"match\" settings files)
485 (tags-todo \"match\" settings files)
486
487Each command can carry a list of options, and another set of options can be
488given for the whole set of commands. Individual command options take
489precedence over the general options.
490
491When using several characters as key to a command, the first characters
492are prefix commands. For the dispatcher to display useful information, you
493should provide a description for the prefix, like
494
495 (setq org-agenda-custom-commands
496 '((\"h\" . \"HOME + Name tag searches\") ; describe prefix \"h\"
497 (\"hl\" tags \"+HOME+Lisa\")
498 (\"hp\" tags \"+HOME+Peter\")
499 (\"hk\" tags \"+HOME+Kim\")))"
500 :group 'org-agenda-custom-commands
501 :type `(repeat
502 (choice :value ("x" "Describe command here" tags "" nil)
8223b1d2
BG
503 (list :tag "Single command"
504 (string :tag "Access Key(s) ")
505 (option (string :tag "Description"))
506 (choice
507 (const :tag "Agenda" agenda)
508 (const :tag "TODO list" alltodo)
509 (const :tag "Search words" search)
510 (const :tag "Stuck projects" stuck)
511 (const :tag "Tags/Property match (all agenda files)" tags)
512 (const :tag "Tags/Property match of TODO entries (all agenda files)" tags-todo)
513 (const :tag "TODO keyword search (all agenda files)" todo)
514 (const :tag "Tags sparse tree (current buffer)" tags-tree)
515 (const :tag "TODO keyword tree (current buffer)" todo-tree)
516 (const :tag "Occur tree (current buffer)" occur-tree)
517 (sexp :tag "Other, user-defined function"))
518 (string :tag "Match (only for some commands)")
519 ,org-agenda-custom-commands-local-options
520 (option (repeat :tag "Export" (file :tag "Export to"))))
521 (list :tag "Command series, all agenda files"
522 (string :tag "Access Key(s)")
523 (string :tag "Description ")
524 (repeat :tag "Component"
525 (choice
526 (list :tag "Agenda"
527 (const :format "" agenda)
528 (const :tag "" :format "" "")
529 ,org-agenda-custom-commands-local-options)
530 (list :tag "TODO list (all keywords)"
531 (const :format "" alltodo)
532 (const :tag "" :format "" "")
533 ,org-agenda-custom-commands-local-options)
534 (list :tag "Search words"
535 (const :format "" search)
536 (string :tag "Match")
537 ,org-agenda-custom-commands-local-options)
538 (list :tag "Stuck projects"
539 (const :format "" stuck)
540 (const :tag "" :format "" "")
541 ,org-agenda-custom-commands-local-options)
542 (list :tag "Tags search"
543 (const :format "" tags)
544 (string :tag "Match")
545 ,org-agenda-custom-commands-local-options)
546 (list :tag "Tags search, TODO entries only"
547 (const :format "" tags-todo)
548 (string :tag "Match")
549 ,org-agenda-custom-commands-local-options)
550 (list :tag "TODO keyword search"
551 (const :format "" todo)
552 (string :tag "Match")
553 ,org-agenda-custom-commands-local-options)
554 (list :tag "Other, user-defined function"
555 (symbol :tag "function")
556 (string :tag "Match")
557 ,org-agenda-custom-commands-local-options)))
558
559 (repeat :tag "Settings for entire command set"
560 (list (variable :tag "Any variable")
561 (sexp :tag "Value")))
562 (option (repeat :tag "Export" (file :tag "Export to"))))
563 (cons :tag "Prefix key documentation"
564 (string :tag "Access Key(s)")
565 (string :tag "Description ")))))
20908596
CD
566
567(defcustom org-agenda-query-register ?o
568 "The register holding the current query string.
33306645 569The purpose of this is that if you construct a query string interactively,
20908596
CD
570you can then use it to define a custom command."
571 :group 'org-agenda-custom-commands
572 :type 'character)
573
574(defcustom org-stuck-projects
575 '("+LEVEL=2/-DONE" ("TODO" "NEXT" "NEXTACTION") nil "")
576 "How to identify stuck projects.
577This is a list of four items:
c8d0cf5c
CD
5781. A tags/todo/property matcher string that is used to identify a project.
579 See the manual for a description of tag and property searches.
20908596
CD
580 The entire tree below a headline matched by this is considered one project.
5812. A list of TODO keywords identifying non-stuck projects.
582 If the project subtree contains any headline with one of these todo
583 keywords, the project is considered to be not stuck. If you specify
584 \"*\" as a keyword, any TODO keyword will mark the project unstuck.
5853. A list of tags identifying non-stuck projects.
586 If the project subtree contains any headline with one of these tags,
587 the project is considered to be not stuck. If you specify \"*\" as
c8d0cf5c
CD
588 a tag, any tag will mark the project unstuck. Note that this is about
589 the explicit presence of a tag somewhere in the subtree, inherited
d3517077 590 tags do not count here. If inherited tags make a project not stuck,
c8d0cf5c 591 use \"-TAG\" in the tags part of the matcher under (1.) above.
20908596
CD
5924. An arbitrary regular expression matching non-stuck projects.
593
c8d0cf5c
CD
594If the project turns out to be not stuck, search continues also in the
595subtree to see if any of the subtasks have project status.
596
597See also the variable `org-tags-match-list-sublevels' which applies
598to projects matched by this search as well.
599
20908596
CD
600After defining this variable, you may use \\[org-agenda-list-stuck-projects]
601or `C-c a #' to produce the list."
602 :group 'org-agenda-custom-commands
603 :type '(list
604 (string :tag "Tags/TODO match to identify a project")
605 (repeat :tag "Projects are *not* stuck if they have an entry with TODO keyword any of" (string))
606 (repeat :tag "Projects are *not* stuck if they have an entry with TAG being any of" (string))
c8d0cf5c 607 (regexp :tag "Projects are *not* stuck if this regexp matches inside the subtree")))
20908596 608
71d35b24
CD
609(defcustom org-agenda-filter-effort-default-operator "<"
610 "The default operator for effort estimate filtering.
93b62de8 611If you select an effort estimate limit without first pressing an operator,
71d35b24
CD
612this one will be used."
613 :group 'org-agenda-custom-commands
614 :type '(choice (const :tag "less or equal" "<")
615 (const :tag "greater or equal"">")
616 (const :tag "equal" "=")))
20908596
CD
617
618(defgroup org-agenda-skip nil
8223b1d2
BG
619 "Options concerning skipping parts of agenda files."
620 :tag "Org Agenda Skip"
621 :group 'org-agenda)
3ab2c837
BG
622
623(defcustom org-agenda-skip-function-global nil
624 "Function to be called at each match during agenda construction.
625If this function returns nil, the current match should not be skipped.
626If the function decided to skip an agenda match, is must return the
627buffer position from which the search should be continued.
628This may also be a Lisp form, which will be evaluated.
629
630This variable will be applied to every agenda match, including
631tags/property searches and TODO lists. So try to make the test function
632do its checking as efficiently as possible. To implement a skipping
633condition just for specific agenda commands, use the variable
634`org-agenda-skip-function' which can be set in the options section
635of custom agenda commands."
636 :group 'org-agenda-skip
637 :type 'sexp)
638
0bd48b37
CD
639(defgroup org-agenda-daily/weekly nil
640 "Options concerning the daily/weekly agenda."
641 :tag "Org Agenda Daily/Weekly"
642 :group 'org-agenda)
643(defgroup org-agenda-todo-list nil
644 "Options concerning the global todo list agenda view."
645 :tag "Org Agenda Todo List"
646 :group 'org-agenda)
647(defgroup org-agenda-match-view nil
648 "Options concerning the general tags/property/todo match agenda view."
649 :tag "Org Agenda Match View"
650 :group 'org-agenda)
8bfe682a 651(defgroup org-agenda-search-view nil
30cb51f1
BG
652 "Options concerning the search agenda view."
653 :tag "Org Agenda Search View"
8bfe682a 654 :group 'org-agenda)
20908596 655
2c3ad40d 656(defvar org-agenda-archives-mode nil
ed21c5c8 657 "Non-nil means the agenda will include archived items.
2c3ad40d
CD
658If this is the symbol `trees', trees in the selected agenda scope
659that are marked with the ARCHIVE tag will be included anyway. When this is
660t, also all archive files associated with the current selection of agenda
661files will be included.")
662
271672fa
BG
663(defcustom org-agenda-restriction-lock-highlight-subtree t
664 "Non-nil means highlight the whole subtree when restriction is active.
665Otherwise only highlight the headline. Highlighting the whole subtree is
666useful to ensure no edits happen beyond the restricted region."
667 :group 'org-agenda
668 :type 'boolean)
669
b349f79f 670(defcustom org-agenda-skip-comment-trees t
ed21c5c8 671 "Non-nil means skip trees that start with the COMMENT keyword.
33306645 672When nil, these trees are also scanned by agenda commands."
b349f79f
CD
673 :group 'org-agenda-skip
674 :type 'boolean)
675
20908596 676(defcustom org-agenda-todo-list-sublevels t
ed21c5c8 677 "Non-nil means check also the sublevels of a TODO entry for TODO entries.
20908596
CD
678When nil, the sublevels of a TODO entry are not checked, resulting in
679potentially much shorter TODO lists."
680 :group 'org-agenda-skip
0bd48b37 681 :group 'org-agenda-todo-list
20908596
CD
682 :type 'boolean)
683
684(defcustom org-agenda-todo-ignore-with-date nil
ed21c5c8 685 "Non-nil means don't show entries with a date in the global todo list.
20908596
CD
686You can use this if you prefer to mark mere appointments with a TODO keyword,
687but don't want them to show up in the TODO list.
688When this is set, it also covers deadlines and scheduled items, the settings
689of `org-agenda-todo-ignore-scheduled' and `org-agenda-todo-ignore-deadlines'
c8d0cf5c
CD
690will be ignored.
691See also the variable `org-agenda-tags-todo-honor-ignore-options'."
20908596 692 :group 'org-agenda-skip
0bd48b37 693 :group 'org-agenda-todo-list
20908596
CD
694 :type 'boolean)
695
acedf35c
CD
696(defcustom org-agenda-todo-ignore-timestamp nil
697 "Non-nil means don't show entries with a timestamp.
698This applies when creating the global todo list.
699Valid values are:
700
701past Don't show entries for today or in the past.
702
703future Don't show entries with a timestamp in the future.
704 The idea behind this is that if it has a future
705 timestamp, you don't want to think about it until the
706 date.
707
708all Don't show any entries with a timestamp in the global todo list.
709 The idea behind this is that by setting a timestamp, you
710 have already \"taken care\" of this item.
711
8223b1d2
BG
712This variable can also have an integer as a value. If positive (N),
713todos with a timestamp N or more days in the future will be ignored. If
3ab2c837 714negative (-N), todos with a timestamp N or more days in the past will be
8223b1d2
BG
715ignored. If 0, todos with a timestamp either today or in the future will
716be ignored. For example, a value of -1 will exclude todos with a
3ab2c837
BG
717timestamp in the past (yesterday or earlier), while a value of 7 will
718exclude todos with a timestamp a week or more in the future.
719
acedf35c
CD
720See also `org-agenda-todo-ignore-with-date'.
721See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want
722to make his option also apply to the tags-todo list."
723 :group 'org-agenda-skip
724 :group 'org-agenda-todo-list
372d7b21 725 :version "24.1"
acedf35c
CD
726 :type '(choice
727 (const :tag "Ignore future timestamp todos" future)
728 (const :tag "Ignore past or present timestamp todos" past)
729 (const :tag "Ignore all timestamp todos" all)
3ab2c837
BG
730 (const :tag "Show timestamp todos" nil)
731 (integer :tag "Ignore if N or more days in past(-) or future(+).")))
acedf35c 732
20908596 733(defcustom org-agenda-todo-ignore-scheduled nil
ed21c5c8
CD
734 "Non-nil means, ignore some scheduled TODO items when making TODO list.
735This applies when creating the global todo list.
736Valid values are:
737
738past Don't show entries scheduled today or in the past.
739
740future Don't show entries scheduled in the future.
741 The idea behind this is that by scheduling it, you don't want to
742 think about it until the scheduled date.
743
744all Don't show any scheduled entries in the global todo list.
745 The idea behind this is that by scheduling it, you have already
746 \"taken care\" of this item.
747
748t Same as `all', for backward compatibility.
749
8223b1d2 750This variable can also have an integer as a value. See
3ab2c837
BG
751`org-agenda-todo-ignore-timestamp' for more details.
752
c8d0cf5c 753See also `org-agenda-todo-ignore-with-date'.
ed21c5c8
CD
754See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want
755to make his option also apply to the tags-todo list."
20908596 756 :group 'org-agenda-skip
0bd48b37 757 :group 'org-agenda-todo-list
ed21c5c8
CD
758 :type '(choice
759 (const :tag "Ignore future-scheduled todos" future)
760 (const :tag "Ignore past- or present-scheduled todos" past)
761 (const :tag "Ignore all scheduled todos" all)
762 (const :tag "Ignore all scheduled todos (compatibility)" t)
3ab2c837
BG
763 (const :tag "Show scheduled todos" nil)
764 (integer :tag "Ignore if N or more days in past(-) or future(+).")))
20908596
CD
765
766(defcustom org-agenda-todo-ignore-deadlines nil
136b74c5 767 "Non-nil means ignore some deadline TODO items when making TODO list.
ed21c5c8
CD
768There are different motivations for using different values, please think
769carefully when configuring this variable.
770
86fbb8ca 771This applies when creating the global todo list.
ed21c5c8
CD
772Valid values are:
773
774near Don't show near deadline entries. A deadline is near when it is
775 closer than `org-deadline-warning-days' days. The idea behind this
776 is that such items will appear in the agenda anyway.
777
778far Don't show TODO entries where a deadline has been defined, but
779 the deadline is not near. This is useful if you don't want to
780 use the todo list to figure out what to do now.
781
782past Don't show entries with a deadline timestamp for today or in the past.
783
784future Don't show entries with a deadline timestamp in the future, not even
785 when they become `near' ones. Use it with caution.
786
787all Ignore all TODO entries that do have a deadline.
788
789t Same as `near', for backward compatibility.
790
8223b1d2 791This variable can also have an integer as a value. See
3ab2c837
BG
792`org-agenda-todo-ignore-timestamp' for more details.
793
c8d0cf5c 794See also `org-agenda-todo-ignore-with-date'.
ed21c5c8
CD
795See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want
796to make his option also apply to the tags-todo list."
20908596 797 :group 'org-agenda-skip
0bd48b37 798 :group 'org-agenda-todo-list
ed21c5c8
CD
799 :type '(choice
800 (const :tag "Ignore near deadlines" near)
801 (const :tag "Ignore near deadlines (compatibility)" t)
802 (const :tag "Ignore far deadlines" far)
803 (const :tag "Ignore all TODOs with a deadlines" all)
3ab2c837
BG
804 (const :tag "Show all TODOs, even if they have a deadline" nil)
805 (integer :tag "Ignore if N or more days in past(-) or future(+).")))
0bd48b37 806
271672fa
BG
807(defcustom org-agenda-todo-ignore-time-comparison-use-seconds nil
808 "Time unit to use when possibly ignoring an agenda item.
809
810See the docstring of various `org-agenda-todo-ignore-*' options.
811The default is to compare time stamps using days. An item is thus
812considered to be in the future if it is at least one day after today.
813Non-nil means to compare time stamps using seconds. An item is then
814considered future if it has a time value later than current time."
815 :group 'org-agenda-skip
816 :group 'org-agenda-todo-list
817 :version "24.4"
818 :package-version '(Org . "8.0")
819 :type '(choice
820 (const :tag "Compare time with days" nil)
821 (const :tag "Compare time with seconds" t)))
822
0bd48b37 823(defcustom org-agenda-tags-todo-honor-ignore-options nil
271672fa 824 "Non-nil means honor todo-list ignores options also in tags-todo search.
0bd48b37
CD
825The variables
826 `org-agenda-todo-ignore-with-date',
acedf35c
CD
827 `org-agenda-todo-ignore-timestamp',
828 `org-agenda-todo-ignore-scheduled',
0bd48b37
CD
829 `org-agenda-todo-ignore-deadlines'
830make the global TODO list skip entries that have time stamps of certain
831kinds. If this option is set, the same options will also apply for the
832tags-todo search, which is the general tags/property matcher
833restricted to unfinished TODO entries only."
834 :group 'org-agenda-skip
835 :group 'org-agenda-todo-list
836 :group 'org-agenda-match-view
20908596
CD
837 :type 'boolean)
838
839(defcustom org-agenda-skip-scheduled-if-done nil
840 "Non-nil means don't show scheduled items in agenda when they are done.
841This is relevant for the daily/weekly agenda, not for the TODO list. And
842it applies only to the actual date of the scheduling. Warnings about
843an item with a past scheduling dates are always turned off when the item
844is DONE."
845 :group 'org-agenda-skip
0bd48b37 846 :group 'org-agenda-daily/weekly
20908596
CD
847 :type 'boolean)
848
54a0dee5
CD
849(defcustom org-agenda-skip-scheduled-if-deadline-is-shown nil
850 "Non-nil means skip scheduling line if same entry shows because of deadline.
271672fa
BG
851
852In the agenda of today, an entry can show up multiple times
853because it is both scheduled and has a nearby deadline, and maybe
854a plain time stamp as well.
855
856When this variable is nil, the entry will be shown several times.
857
858When set to t, then only the deadline is shown and the fact that
859the entry is scheduled today or was scheduled previously is not
860shown.
861
862When set to the symbol `not-today', skip scheduled previously,
863but not scheduled today.
864
865When set to the symbol `repeated-after-deadline', skip scheduled
d1389828 866items if they are repeated beyond the current deadline."
54a0dee5
CD
867 :group 'org-agenda-skip
868 :group 'org-agenda-daily/weekly
869 :type '(choice
870 (const :tag "Never" nil)
871 (const :tag "Always" t)
271672fa
BG
872 (const :tag "Not when scheduled today" not-today)
873 (const :tag "When repeated past deadline" repeated-after-deadline)))
54a0dee5 874
8223b1d2
BG
875(defcustom org-agenda-skip-timestamp-if-deadline-is-shown nil
876 "Non-nil means skip timestamp line if same entry shows because of deadline.
877In the agenda of today, an entry can show up multiple times
878because it has both a plain timestamp and has a nearby deadline.
879When this variable is t, then only the deadline is shown and the
880fact that the entry has a timestamp for or including today is not
881shown. When this variable is nil, the entry will be shown
882several times."
883 :group 'org-agenda-skip
884 :group 'org-agenda-daily/weekly
885 :version "24.1"
886 :type '(choice
887 (const :tag "Never" nil)
888 (const :tag "Always" t)))
889
20908596 890(defcustom org-agenda-skip-deadline-if-done nil
33306645 891 "Non-nil means don't show deadlines when the corresponding item is done.
20908596
CD
892When nil, the deadline is still shown and should give you a happy feeling.
893This is relevant for the daily/weekly agenda. And it applied only to the
33306645 894actually date of the deadline. Warnings about approaching and past-due
20908596
CD
895deadlines are always turned off when the item is DONE."
896 :group 'org-agenda-skip
0bd48b37 897 :group 'org-agenda-daily/weekly
20908596
CD
898 :type 'boolean)
899
ed21c5c8
CD
900(defcustom org-agenda-skip-deadline-prewarning-if-scheduled nil
901 "Non-nil means skip deadline prewarning when entry is also scheduled.
902This will apply on all days where a prewarning for the deadline would
903be shown, but not at the day when the entry is actually due. On that day,
904the deadline will be shown anyway.
271672fa
BG
905This variable may be set to nil, t, the symbol `pre-scheduled',
906or a number which will then give the number of days before the actual
907deadline when the prewarnings should resume. The symbol `pre-scheduled'
908eliminates the deadline prewarning only prior to the scheduled date.
ed21c5c8
CD
909This can be used in a workflow where the first showing of the deadline will
910trigger you to schedule it, and then you don't want to be reminded of it
911because you will take care of it on the day when scheduled."
912 :group 'org-agenda-skip
913 :group 'org-agenda-daily/weekly
372d7b21 914 :version "24.1"
ed21c5c8 915 :type '(choice
735135f9 916 (const :tag "Always show prewarning" nil)
271672fa 917 (const :tag "Remove prewarning prior to scheduled date" pre-scheduled)
ed21c5c8
CD
918 (const :tag "Remove prewarning if entry is scheduled" t)
919 (integer :tag "Restart prewarning N days before deadline")))
920
271672fa
BG
921(defcustom org-agenda-skip-scheduled-delay-if-deadline nil
922 "Non-nil means skip scheduled delay when entry also has a deadline.
923This variable may be set to nil, t, the symbol `post-deadline',
924or a number which will then give the number of days after the actual
925scheduled date when the delay should expire. The symbol `post-deadline'
926eliminates the schedule delay when the date is posterior to the deadline."
927 :group 'org-agenda-skip
928 :group 'org-agenda-daily/weekly
929 :version "24.4"
930 :package-version '(Org . "8.0")
931 :type '(choice
932 (const :tag "Always honor delay" nil)
933 (const :tag "Ignore delay if posterior to the deadline" post-deadline)
934 (const :tag "Ignore delay if entry has a deadline" t)
935 (integer :tag "Honor delay up until N days after the scheduled date")))
936
e66ba1df 937(defcustom org-agenda-skip-additional-timestamps-same-entry nil
c8d0cf5c
CD
938 "When nil, multiple same-day timestamps in entry make multiple agenda lines.
939When non-nil, after the search for timestamps has matched once in an
940entry, the rest of the entry will not be searched."
941 :group 'org-agenda-skip
942 :type 'boolean)
943
20908596
CD
944(defcustom org-agenda-skip-timestamp-if-done nil
945 "Non-nil means don't select item by timestamp or -range if it is DONE."
946 :group 'org-agenda-skip
0bd48b37 947 :group 'org-agenda-daily/weekly
20908596
CD
948 :type 'boolean)
949
271672fa 950(defcustom org-agenda-dim-blocked-tasks t
ed21c5c8 951 "Non-nil means dim blocked tasks in the agenda display.
c8d0cf5c
CD
952This causes some overhead during agenda construction, but if you
953have turned on `org-enforce-todo-dependencies',
954`org-enforce-todo-checkbox-dependencies', or any other blocking
955mechanism, this will create useful feedback in the agenda.
956
8bfe682a 957Instead of t, this variable can also have the value `invisible'.
c8d0cf5c
CD
958Then blocked tasks will be invisible and only become visible when
959they become unblocked. An exemption to this behavior is when a task is
960blocked because of unchecked checkboxes below it. Since checkboxes do
961not show up in the agenda views, making this task invisible you remove any
962trace from agenda views that there is something to do. Therefore, a task
963that is blocked because of checkboxes will never be made invisible, it
964will only be dimmed."
d6685abc
CD
965 :group 'org-agenda-daily/weekly
966 :group 'org-agenda-todo-list
c7cf0ebc 967 :version "24.3"
d6685abc
CD
968 :type '(choice
969 (const :tag "Do not dim" nil)
e4769531 970 (const :tag "Dim to a gray face" t)
8bfe682a 971 (const :tag "Make invisible" invisible)))
d6685abc 972
20908596 973(defcustom org-timeline-show-empty-dates 3
ed21c5c8 974 "Non-nil means `org-timeline' also shows dates without an entry.
20908596
CD
975When nil, only the days which actually have entries are shown.
976When t, all days between the first and the last date are shown.
977When an integer, show also empty dates, but if there is a gap of more than
978N days, just insert a special line indicating the size of the gap."
979 :group 'org-agenda-skip
980 :type '(choice
981 (const :tag "None" nil)
982 (const :tag "All" t)
c8d0cf5c 983 (integer :tag "at most")))
20908596 984
20908596
CD
985(defgroup org-agenda-startup nil
986 "Options concerning initial settings in the Agenda in Org Mode."
987 :tag "Org Agenda Startup"
988 :group 'org-agenda)
989
afe98dfa 990(defcustom org-agenda-menu-show-matcher t
3ab2c837 991 "Non-nil means show the match string in the agenda dispatcher menu.
afe98dfa
CD
992When nil, the matcher string is not shown, but is put into the help-echo
993property so than moving the mouse over the command shows it.
994Setting it to nil is good if matcher strings are very long and/or if
8223b1d2 995you want to use two-columns display (see `org-agenda-menu-two-columns')."
afe98dfa 996 :group 'org-agenda
372d7b21 997 :version "24.1"
afe98dfa
CD
998 :type 'boolean)
999
a89c8ef0 1000(define-obsolete-variable-alias 'org-agenda-menu-two-column 'org-agenda-menu-two-columns "24.3")
8223b1d2
BG
1001
1002(defcustom org-agenda-menu-two-columns nil
afe98dfa
CD
1003 "Non-nil means, use two columns to show custom commands in the dispatcher.
1004If you use this, you probably want to set `org-agenda-menu-show-matcher'
1005to nil."
1006 :group 'org-agenda
372d7b21 1007 :version "24.1"
afe98dfa
CD
1008 :type 'boolean)
1009
a89c8ef0 1010(define-obsolete-variable-alias 'org-finalize-agenda-hook 'org-agenda-finalize-hook "24.3")
8223b1d2
BG
1011(defcustom org-agenda-finalize-hook nil
1012 "Hook run just before displaying an agenda buffer.
1013The buffer is still writable when the hook is called.
1014
1015You can modify some of the buffer substrings but you should be
1016extra careful not to modify the text properties of the agenda
1017headlines as the agenda display heavily relies on them."
20908596
CD
1018 :group 'org-agenda-startup
1019 :type 'hook)
1020
1021(defcustom org-agenda-mouse-1-follows-link nil
ed21c5c8 1022 "Non-nil means mouse-1 on a link will follow the link in the agenda.
20908596
CD
1023A longer mouse click will still set point. Does not work on XEmacs.
1024Needs to be set before org.el is loaded."
1025 :group 'org-agenda-startup
1026 :type 'boolean)
1027
1028(defcustom org-agenda-start-with-follow-mode nil
86fbb8ca 1029 "The initial value of follow mode in a newly created agenda window."
20908596
CD
1030 :group 'org-agenda-startup
1031 :type 'boolean)
1032
e66ba1df
BG
1033(defcustom org-agenda-follow-indirect nil
1034 "Non-nil means `org-agenda-follow-mode' displays only the
1035current item's tree, in an indirect buffer."
1036 :group 'org-agenda
372d7b21 1037 :version "24.1"
e66ba1df
BG
1038 :type 'boolean)
1039
1bcdebed 1040(defcustom org-agenda-show-outline-path t
ed21c5c8 1041 "Non-nil means show outline path in echo area after line motion."
1bcdebed
CD
1042 :group 'org-agenda-startup
1043 :type 'boolean)
1044
54a0dee5
CD
1045(defcustom org-agenda-start-with-entry-text-mode nil
1046 "The initial value of entry-text-mode in a newly created agenda window."
1047 :group 'org-agenda-startup
1048 :type 'boolean)
1049
1050(defcustom org-agenda-entry-text-maxlines 5
8bfe682a 1051 "Number of text lines to be added when `E' is pressed in the agenda.
54a0dee5
CD
1052
1053Note that this variable only used during agenda display. Add add entry text
1054when exporting the agenda, configure the variable
1055`org-agenda-add-entry-ext-maxlines'."
1056 :group 'org-agenda
1057 :type 'integer)
1058
8d642074
CD
1059(defcustom org-agenda-entry-text-exclude-regexps nil
1060 "List of regular expressions to clean up entry text.
1061The complete matches of all regular expressions in this list will be
1062removed from entry text before it is shown in the agenda."
1063 :group 'org-agenda
1064 :type '(repeat (regexp)))
1065
271672fa
BG
1066(defcustom org-agenda-entry-text-leaders " > "
1067 "Text prepended to the entry text in agenda buffers."
1068 :version "24.4"
1069 :package-version '(Org . "8.0")
1070 :group 'org-agenda
1071 :type 'string)
1072
8d642074
CD
1073(defvar org-agenda-entry-text-cleanup-hook nil
1074 "Hook that is run after basic cleanup of entry text to be shown in agenda.
1075This cleanup is done in a temporary buffer, so the function may inspect and
1076change the entire buffer.
1077Some default stuff like drawers and scheduling/deadline dates will already
1078have been removed when this is called, as will any matches for regular
1079expressions listed in `org-agenda-entry-text-exclude-regexps'.")
1080
20908596 1081(defvar org-agenda-include-inactive-timestamps nil
8223b1d2
BG
1082 "Non-nil means include inactive time stamps in agenda and timeline.
1083Dynamically scoped.")
20908596
CD
1084
1085(defgroup org-agenda-windows nil
1086 "Options concerning the windows used by the Agenda in Org Mode."
1087 :tag "Org Agenda Windows"
1088 :group 'org-agenda)
1089
1090(defcustom org-agenda-window-setup 'reorganize-frame
1091 "How the agenda buffer should be displayed.
1092Possible values for this option are:
1093
1094current-window Show agenda in the current window, keeping all other windows.
20908596
CD
1095other-window Use `switch-to-buffer-other-window' to display agenda.
1096reorganize-frame Show only two windows on the current frame, the current
1097 window and the agenda.
8d642074
CD
1098other-frame Use `switch-to-buffer-other-frame' to display agenda.
1099 Also, when exiting the agenda, kill that frame.
20908596
CD
1100See also the variable `org-agenda-restore-windows-after-quit'."
1101 :group 'org-agenda-windows
1102 :type '(choice
1103 (const current-window)
1104 (const other-frame)
1105 (const other-window)
1106 (const reorganize-frame)))
1107
1108(defcustom org-agenda-window-frame-fractions '(0.5 . 0.75)
1109 "The min and max height of the agenda window as a fraction of frame height.
1110The value of the variable is a cons cell with two numbers between 0 and 1.
1111It only matters if `org-agenda-window-setup' is `reorganize-frame'."
1112 :group 'org-agenda-windows
1113 :type '(cons (number :tag "Minimum") (number :tag "Maximum")))
1114
1115(defcustom org-agenda-restore-windows-after-quit nil
3ab2c837 1116 "Non-nil means restore window configuration upon exiting agenda.
20908596
CD
1117Before the window configuration is changed for displaying the agenda,
1118the current status is recorded. When the agenda is exited with
1119`q' or `x' and this option is set, the old state is restored. If
1120`org-agenda-window-setup' is `other-frame', the value of this
baf0cb84 1121option will be ignored."
20908596
CD
1122 :group 'org-agenda-windows
1123 :type 'boolean)
1124
acedf35c 1125(defcustom org-agenda-ndays nil
8223b1d2 1126 "Number of days to include in overview display.
c8d0cf5c 1127Should be 1 or 7.
acedf35c 1128Obsolete, see `org-agenda-span'."
8223b1d2 1129 :group 'org-agenda-daily/weekly
271672fa
BG
1130 :type '(choice (const nil)
1131 (integer)))
acedf35c
CD
1132
1133(make-obsolete-variable 'org-agenda-ndays 'org-agenda-span "24.1")
1134
1135(defcustom org-agenda-span 'week
1136 "Number of days to include in overview display.
1137Can be day, week, month, year, or any number of days.
c8d0cf5c 1138Custom commands can set this variable in the options section."
20908596 1139 :group 'org-agenda-daily/weekly
acedf35c
CD
1140 :type '(choice (const :tag "Day" day)
1141 (const :tag "Week" week)
271672fa 1142 (const :tag "Fortnight" fortnight)
acedf35c
CD
1143 (const :tag "Month" month)
1144 (const :tag "Year" year)
1145 (integer :tag "Custom")))
20908596
CD
1146
1147(defcustom org-agenda-start-on-weekday 1
ed21c5c8 1148 "Non-nil means start the overview always on the specified weekday.
271672fa 11490 denotes Sunday, 1 denotes Monday, etc.
c8d0cf5c
CD
1150When nil, always start on the current day.
1151Custom commands can set this variable in the options section."
20908596
CD
1152 :group 'org-agenda-daily/weekly
1153 :type '(choice (const :tag "Today" nil)
c8d0cf5c 1154 (integer :tag "Weekday No.")))
20908596
CD
1155
1156(defcustom org-agenda-show-all-dates t
ed21c5c8 1157 "Non-nil means `org-agenda' shows every day in the selected range.
20908596
CD
1158When nil, only the days which actually have entries are shown."
1159 :group 'org-agenda-daily/weekly
1160 :type 'boolean)
1161
1162(defcustom org-agenda-format-date 'org-agenda-format-date-aligned
1163 "Format string for displaying dates in the agenda.
1164Used by the daily/weekly agenda and by the timeline. This should be
1165a format string understood by `format-time-string', or a function returning
1166the formatted date as a string. The function must take a single argument,
1167a calendar-style date list like (month day year)."
1168 :group 'org-agenda-daily/weekly
1169 :type '(choice
1170 (string :tag "Format string")
1171 (function :tag "Function")))
1172
1173(defun org-agenda-format-date-aligned (date)
271672fa 1174 "Format a DATE string for display in the daily/weekly agenda, or timeline.
20908596
CD
1175This function makes sure that dates are aligned for easy reading."
1176 (require 'cal-iso)
1177 (let* ((dayname (calendar-day-name date))
1178 (day (cadr date))
1179 (day-of-week (calendar-day-of-week date))
1180 (month (car date))
1181 (monthname (calendar-month-name month))
1182 (year (nth 2 date))
1183 (iso-week (org-days-to-iso-week
1184 (calendar-absolute-from-gregorian date)))
1185 (weekyear (cond ((and (= month 1) (>= iso-week 52))
1186 (1- year))
1187 ((and (= month 12) (<= iso-week 1))
1188 (1+ year))
1189 (t year)))
1190 (weekstring (if (= day-of-week 1)
1191 (format " W%02d" iso-week)
1192 "")))
1193 (format "%-10s %2d %s %4d%s"
1194 dayname day monthname year weekstring)))
1195
ed21c5c8
CD
1196(defcustom org-agenda-time-leading-zero nil
1197 "Non-nil means use leading zero for military times in agenda.
1198For example, 9:30am would become 09:30 rather than 9:30."
1199 :group 'org-agenda-daily/weekly
372d7b21 1200 :version "24.1"
ed21c5c8
CD
1201 :type 'boolean)
1202
acedf35c
CD
1203(defcustom org-agenda-timegrid-use-ampm nil
1204 "When set, show AM/PM style timestamps on the timegrid."
1205 :group 'org-agenda
372d7b21 1206 :version "24.1"
acedf35c
CD
1207 :type 'boolean)
1208
1209(defun org-agenda-time-of-day-to-ampm (time)
1210 "Convert TIME of a string like '13:45' to an AM/PM style time string."
1211 (let* ((hour-number (string-to-number (substring time 0 -3)))
1212 (minute (substring time -2))
1213 (ampm "am"))
1214 (cond
1215 ((equal hour-number 12)
1216 (setq ampm "pm"))
1217 ((> hour-number 12)
1218 (setq ampm "pm")
1219 (setq hour-number (- hour-number 12))))
1220 (concat
1221 (if org-agenda-time-leading-zero
1222 (format "%02d" hour-number)
1223 (format "%02s" (number-to-string hour-number)))
1224 ":" minute ampm)))
1225
1226(defun org-agenda-time-of-day-to-ampm-maybe (time)
271672fa 1227 "Conditionally convert TIME to AM/PM format based on `org-agenda-timegrid-use-ampm'."
acedf35c
CD
1228 (if org-agenda-timegrid-use-ampm
1229 (org-agenda-time-of-day-to-ampm time)
1230 time))
1231
20908596
CD
1232(defcustom org-agenda-weekend-days '(6 0)
1233 "Which days are weekend?
1234These days get the special face `org-agenda-date-weekend' in the agenda
1235and timeline buffers."
1236 :group 'org-agenda-daily/weekly
1237 :type '(set :greedy t
1238 (const :tag "Monday" 1)
1239 (const :tag "Tuesday" 2)
1240 (const :tag "Wednesday" 3)
1241 (const :tag "Thursday" 4)
1242 (const :tag "Friday" 5)
1243 (const :tag "Saturday" 6)
1244 (const :tag "Sunday" 0)))
1245
e66ba1df 1246(defcustom org-agenda-move-date-from-past-immediately-to-today t
27e428e7 1247 "Non-nil means jump to today when moving a past date forward in time.
e66ba1df
BG
1248When using S-right in the agenda to move a a date forward, and the date
1249stamp currently points to the past, the first key press will move it
1250to today. WHen nil, just move one day forward even if the date stays
1251in the past."
1252 :group 'org-agenda-daily/weekly
372d7b21 1253 :version "24.1"
e66ba1df
BG
1254 :type 'boolean)
1255
20908596 1256(defcustom org-agenda-include-diary nil
c8d0cf5c
CD
1257 "If non-nil, include in the agenda entries from the Emacs Calendar's diary.
1258Custom commands can set this variable in the options section."
20908596
CD
1259 :group 'org-agenda-daily/weekly
1260 :type 'boolean)
1261
ed21c5c8
CD
1262(defcustom org-agenda-include-deadlines t
1263 "If non-nil, include entries within their deadline warning period.
1264Custom commands can set this variable in the options section."
1265 :group 'org-agenda-daily/weekly
372d7b21 1266 :version "24.1"
ed21c5c8
CD
1267 :type 'boolean)
1268
20908596 1269(defcustom org-agenda-repeating-timestamp-show-all t
ed21c5c8 1270 "Non-nil means show all occurrences of a repeating stamp in the agenda.
3ab2c837
BG
1271When set to a list of strings, only show occurrences of repeating
1272stamps for these TODO keywords. When nil, only one occurrence is
1273shown, either today or the nearest into the future."
20908596 1274 :group 'org-agenda-daily/weekly
3ab2c837
BG
1275 :type '(choice
1276 (const :tag "Show repeating stamps" t)
1277 (repeat :tag "Show repeating stamps for these TODO keywords"
1278 (string :tag "TODO Keyword"))
1279 (const :tag "Don't show repeating stamps" nil)))
20908596
CD
1280
1281(defcustom org-scheduled-past-days 10000
271672fa 1282 "Number of days to continue listing scheduled items not marked DONE.
20908596
CD
1283When an item is scheduled on a date, it shows up in the agenda on this
1284day and will be listed until it is marked done for the number of days
1285given here."
1286 :group 'org-agenda-daily/weekly
c8d0cf5c 1287 :type 'integer)
20908596 1288
93b62de8
CD
1289(defcustom org-agenda-log-mode-items '(closed clock)
1290 "List of items that should be shown in agenda log mode.
1291This list may contain the following symbols:
1292
1293 closed Show entries that have been closed on that day.
1294 clock Show entries that have received clocked time on that day.
c8d0cf5c
CD
1295 state Show all logged state changes.
1296Note that instead of changing this variable, you can also press `C-u l' in
1297the agenda to display all available LOG items temporarily."
93b62de8
CD
1298 :group 'org-agenda-daily/weekly
1299 :type '(set :greedy t (const closed) (const clock) (const state)))
1300
3ab2c837
BG
1301(defcustom org-agenda-clock-consistency-checks
1302 '(:max-duration "10:00" :min-duration 0 :max-gap "0:05"
1303 :gap-ok-around ("4:00")
1304 :default-face ((:background "DarkRed") (:foreground "white"))
1305 :overlap-face nil :gap-face nil :no-end-time-face nil
1306 :long-face nil :short-face nil)
1307 "This is a property list, with the following keys:
1308
1309:max-duration Mark clocking chunks that are longer than this time.
1310 This is a time string like \"HH:MM\", or the number
1311 of minutes as an integer.
1312
1313:min-duration Mark clocking chunks that are shorter that this.
1314 This is a time string like \"HH:MM\", or the number
1315 of minutes as an integer.
1316
1317:max-gap Mark gaps between clocking chunks that are longer than
1318 this duration. A number of minutes, or a string
1319 like \"HH:MM\".
1320
1321:gap-ok-around List of times during the day which are usually not working
1322 times. When a gap is detected, but the gap contains any
1323 of these times, the gap is *not* reported. For example,
1324 if this is (\"4:00\" \"13:00\") then gaps that contain
1325 4:00 in the morning (i.e. the night) and 13:00
1326 (i.e. a typical lunch time) do not cause a warning.
1327 You should have at least one time during the night in this
1328 list, or otherwise the first task each morning will trigger
1329 a warning because it follows a long gap.
1330
1331Furthermore, the following properties can be used to define faces for
1332issue display.
1333
1334:default-face the default face, if the specific face is undefined
1335:overlap-face face for overlapping clocks
1336:gap-face face for gaps between clocks
1337:no-end-time-face face for incomplete clocks
1338:long-face face for clock intervals that are too long
1339:short-face face for clock intervals that are too short"
1340 :group 'org-agenda-daily/weekly
1341 :group 'org-clock
372d7b21 1342 :version "24.1"
3ab2c837
BG
1343 :type 'plist)
1344
c8d0cf5c 1345(defcustom org-agenda-log-mode-add-notes t
ed21c5c8 1346 "Non-nil means add first line of notes to log entries in agenda views.
c8d0cf5c
CD
1347If a log item like a state change or a clock entry is associated with
1348notes, the first line of these notes will be added to the entry in the
1349agenda display."
1350 :group 'org-agenda-daily/weekly
1351 :type 'boolean)
1352
1353(defcustom org-agenda-start-with-log-mode nil
8223b1d2
BG
1354 "The initial value of log-mode in a newly created agenda window.
1355See `org-agenda-log-mode' and `org-agenda-log-mode-items' for further
1356explanations on the possible values."
c8d0cf5c
CD
1357 :group 'org-agenda-startup
1358 :group 'org-agenda-daily/weekly
8223b1d2 1359 :type '(choice (const :tag "Don't show log items" nil)
3c8b09ca
BG
1360 (const :tag "Show only log items" only)
1361 (const :tag "Show all possible log items" clockcheck)
8223b1d2 1362 (repeat :tag "Choose among possible values for `org-agenda-log-mode-items'"
3c8b09ca
BG
1363 (choice (const :tag "Show closed log items" closed)
1364 (const :tag "Show clocked log items" clock)
1365 (const :tag "Show all logged state changes" state)))))
c8d0cf5c 1366
20908596
CD
1367(defcustom org-agenda-start-with-clockreport-mode nil
1368 "The initial value of clockreport-mode in a newly created agenda window."
1369 :group 'org-agenda-startup
1370 :group 'org-agenda-daily/weekly
1371 :type 'boolean)
1372
1373(defcustom org-agenda-clockreport-parameter-plist '(:link t :maxlevel 2)
1374 "Property list with parameters for the clocktable in clockreport mode.
1375This is the display mode that shows a clock table in the daily/weekly
1376agenda, the properties for this dynamic block can be set here.
1377The usual clocktable parameters are allowed here, but you cannot set
1378the properties :name, :tstart, :tend, :block, and :scope - these will
1379be overwritten to make sure the content accurately reflects the
1380current display in the agenda."
1381 :group 'org-agenda-daily/weekly
1382 :type 'plist)
1383
ed21c5c8
CD
1384(defcustom org-agenda-search-view-always-boolean nil
1385 "Non-nil means the search string is interpreted as individual parts.
1386
1387The search string for search view can either be interpreted as a phrase,
1388or as a list of snippets that define a boolean search for a number of
1389strings.
1390
1391When this is non-nil, the string will be split on whitespace, and each
1392snippet will be searched individually, and all must match in order to
1393select an entry. A snippet is then a single string of non-white
1394characters, or a string in double quotes, or a regexp in {} braces.
86fbb8ca 1395If a snippet is preceded by \"-\", the snippet must *not* match.
ed21c5c8
CD
1396\"+\" is syntactic sugar for positive selection. Each snippet may
1397be found as a full word or a partial word, but see the variable
1398`org-agenda-search-view-force-full-words'.
1399
1400When this is nil, search will look for the entire search phrase as one,
1401with each space character matching any amount of whitespace, including
1402line breaks.
1403
1404Even when this is nil, you can still switch to Boolean search dynamically
86fbb8ca 1405by preceding the first snippet with \"+\" or \"-\". If the first snippet
ed21c5c8
CD
1406is a regexp marked with braces like \"{abc}\", this will also switch to
1407boolean search."
1408 :group 'org-agenda-search-view
372d7b21 1409 :version "24.1"
ed21c5c8
CD
1410 :type 'boolean)
1411
271672fa
BG
1412(org-defvaralias 'org-agenda-search-view-search-words-only
1413 'org-agenda-search-view-always-boolean)
ed21c5c8
CD
1414
1415(defcustom org-agenda-search-view-force-full-words nil
86fbb8ca 1416 "Non-nil means, search words must be matches as complete words.
ed21c5c8 1417When nil, they may also match part of a word."
8bfe682a 1418 :group 'org-agenda-search-view
372d7b21 1419 :version "24.1"
8bfe682a 1420 :type 'boolean)
20908596 1421
73d3db82 1422(defcustom org-agenda-search-view-max-outline-level 0
271672fa
BG
1423 "Maximum outline level to display in search view.
1424E.g. when this is set to 1, the search view will only
73d3db82
BG
1425show headlines of level 1. When set to 0, the default
1426value, don't limit agenda view by outline level."
271672fa
BG
1427 :group 'org-agenda-search-view
1428 :version "24.4"
73d3db82 1429 :package-version '(Org . "8.3")
271672fa
BG
1430 :type 'integer)
1431
20908596
CD
1432(defgroup org-agenda-time-grid nil
1433 "Options concerning the time grid in the Org-mode Agenda."
1434 :tag "Org Agenda Time Grid"
1435 :group 'org-agenda)
1436
c8d0cf5c 1437(defcustom org-agenda-search-headline-for-time t
ed21c5c8 1438 "Non-nil means search headline for a time-of-day.
c8d0cf5c
CD
1439If the headline contains a time-of-day in one format or another, it will
1440be used to sort the entry into the time sequence of items for a day.
1441Some people have time stamps in the headline that refer to the creation
1442time or so, and then this produces an unwanted side effect. If this is
1443the case for your, use this variable to turn off searching the headline
1444for a time."
1445 :group 'org-agenda-time-grid
1446 :type 'boolean)
1447
20908596 1448(defcustom org-agenda-use-time-grid t
ed21c5c8 1449 "Non-nil means show a time grid in the agenda schedule.
20908596
CD
1450A time grid is a set of lines for specific times (like every two hours between
14518:00 and 20:00). The items scheduled for a day at specific times are
1452sorted in between these lines.
1453For details about when the grid will be shown, and what it will look like, see
1454the variable `org-agenda-time-grid'."
1455 :group 'org-agenda-time-grid
1456 :type 'boolean)
1457
1458(defcustom org-agenda-time-grid
1459 '((daily today require-timed)
1460 "----------------"
1461 (800 1000 1200 1400 1600 1800 2000))
1462
1463 "The settings for time grid for agenda display.
1464This is a list of three items. The first item is again a list. It contains
1465symbols specifying conditions when the grid should be displayed:
1466
1467 daily if the agenda shows a single day
1468 weekly if the agenda shows an entire week
1469 today show grid on current date, independent of daily/weekly display
1470 require-timed show grid only if at least one item has a time specification
1471
b349f79f 1472The second item is a string which will be placed behind the grid time.
20908596
CD
1473
1474The third item is a list of integers, indicating the times that should have
1475a grid line."
1476 :group 'org-agenda-time-grid
1477 :type
1478 '(list
1479 (set :greedy t :tag "Grid Display Options"
1480 (const :tag "Show grid in single day agenda display" daily)
1481 (const :tag "Show grid in weekly agenda display" weekly)
1482 (const :tag "Always show grid for today" today)
1483 (const :tag "Show grid only if any timed entries are present"
1484 require-timed)
1485 (const :tag "Skip grid times already present in an entry"
1486 remove-match))
1487 (string :tag "Grid String")
1488 (repeat :tag "Grid Times" (integer :tag "Time"))))
1489
3ab2c837
BG
1490(defcustom org-agenda-show-current-time-in-grid t
1491 "Non-nil means show the current time in the time grid."
1492 :group 'org-agenda-time-grid
372d7b21 1493 :version "24.1"
3ab2c837
BG
1494 :type 'boolean)
1495
1496(defcustom org-agenda-current-time-string
1497 "now - - - - - - - - - - - - - - - - - - - - - - - - -"
1498 "The string for the current time marker in the agenda."
1499 :group 'org-agenda-time-grid
372d7b21 1500 :version "24.1"
3ab2c837
BG
1501 :type 'string)
1502
20908596
CD
1503(defgroup org-agenda-sorting nil
1504 "Options concerning sorting in the Org-mode Agenda."
1505 :tag "Org Agenda Sorting"
1506 :group 'org-agenda)
1507
1508(defcustom org-agenda-sorting-strategy
8bfe682a
CD
1509 '((agenda habit-down time-up priority-down category-keep)
1510 (todo priority-down category-keep)
1511 (tags priority-down category-keep)
20908596
CD
1512 (search category-keep))
1513 "Sorting structure for the agenda items of a single day.
1514This is a list of symbols which will be used in sequence to determine
1515if an entry should be listed before another entry. The following
1516symbols are recognized:
1517
c8d0cf5c
CD
1518time-up Put entries with time-of-day indications first, early first
1519time-down Put entries with time-of-day indications first, late first
271672fa
BG
1520timestamp-up Sort by any timestamp, early first
1521timestamp-down Sort by any timestamp, late first
1522scheduled-up Sort by scheduled timestamp, early first
1523scheduled-down Sort by scheduled timestamp, late first
1524deadline-up Sort by deadline timestamp, early first
1525deadline-down Sort by deadline timestamp, late first
1526ts-up Sort by active timestamp, early first
1527ts-down Sort by active timestamp, late first
1528tsia-up Sort by inactive timestamp, early first
1529tsia-down Sort by inactive timestamp, late first
c8d0cf5c
CD
1530category-keep Keep the default order of categories, corresponding to the
1531 sequence in `org-agenda-files'.
1532category-up Sort alphabetically by category, A-Z.
1533category-down Sort alphabetically by category, Z-A.
1534tag-up Sort alphabetically by last tag, A-Z.
1535tag-down Sort alphabetically by last tag, Z-A.
1536priority-up Sort numerically by priority, high priority last.
1537priority-down Sort numerically by priority, high priority first.
1538todo-state-up Sort by todo state, tasks that are done last.
1539todo-state-down Sort by todo state, tasks that are done first.
1540effort-up Sort numerically by estimated effort, high effort last.
1541effort-down Sort numerically by estimated effort, high effort first.
1542user-defined-up Sort according to `org-agenda-cmp-user-defined', high last.
1543user-defined-down Sort according to `org-agenda-cmp-user-defined', high first.
8bfe682a
CD
1544habit-up Put entries that are habits first
1545habit-down Put entries that are habits last
86fbb8ca
CD
1546alpha-up Sort headlines alphabetically
1547alpha-down Sort headlines alphabetically, reversed
20908596
CD
1548
1549The different possibilities will be tried in sequence, and testing stops
1550if one comparison returns a \"not-equal\". For example, the default
1551 '(time-up category-keep priority-down)
1552means: Pull out all entries having a specified time of day and sort them,
1553in order to make a time schedule for the current day the first thing in the
1554agenda listing for the day. Of the entries without a time indication, keep
1555the grouped in categories, don't sort the categories, but keep them in
1556the sequence given in `org-agenda-files'. Within each category sort by
1557priority.
1558
1559Leaving out `category-keep' would mean that items will be sorted across
1560categories by priority.
1561
1562Instead of a single list, this can also be a set of list for specific
1563contents, with a context symbol in the car of the list, any of
8bfe682a 1564`agenda', `todo', `tags', `search' for the corresponding agenda views.
c8d0cf5c
CD
1565
1566Custom commands can bind this variable in the options section."
20908596
CD
1567 :group 'org-agenda-sorting
1568 :type `(choice
1569 (repeat :tag "General" ,org-sorting-choice)
1570 (list :tag "Individually"
1571 (cons (const :tag "Strategy for Weekly/Daily agenda" agenda)
1572 (repeat ,org-sorting-choice))
1573 (cons (const :tag "Strategy for TODO lists" todo)
1574 (repeat ,org-sorting-choice))
1575 (cons (const :tag "Strategy for Tags matches" tags)
8bfe682a
CD
1576 (repeat ,org-sorting-choice))
1577 (cons (const :tag "Strategy for search matches" search)
20908596
CD
1578 (repeat ,org-sorting-choice)))))
1579
c8d0cf5c
CD
1580(defcustom org-agenda-cmp-user-defined nil
1581 "A function to define the comparison `user-defined'.
1582This function must receive two arguments, agenda entry a and b.
1583If a>b, return +1. If a<b, return -1. If they are equal as seen by
1584the user comparison, return nil.
1585When this is defined, you can make `user-defined-up' and `user-defined-down'
1586part of an agenda sorting strategy."
1587 :group 'org-agenda-sorting
1588 :type 'symbol)
1589
20908596 1590(defcustom org-sort-agenda-notime-is-late t
ed21c5c8 1591 "Non-nil means items without time are considered late.
20908596
CD
1592This is only relevant for sorting. When t, items which have no explicit
1593time like 15:30 will be considered as 99:01, i.e. later than any items which
1594do have a time. When nil, the default time is before 0:00. You can use this
1595option to decide if the schedule for today should come before or after timeless
1596agenda entries."
1597 :group 'org-agenda-sorting
1598 :type 'boolean)
1599
1600(defcustom org-sort-agenda-noeffort-is-high t
ed21c5c8 1601 "Non-nil means items without effort estimate are sorted as high effort.
c8d0cf5c
CD
1602This also applies when filtering an agenda view with respect to the
1603< or > effort operator. Then, tasks with no effort defined will be treated
1604as tasks with high effort.
20908596
CD
1605When nil, such items are sorted as 0 minutes effort."
1606 :group 'org-agenda-sorting
1607 :type 'boolean)
1608
1609(defgroup org-agenda-line-format nil
1610 "Options concerning the entry prefix in the Org-mode agenda display."
1611 :tag "Org Agenda Line Format"
1612 :group 'org-agenda)
1613
1614(defcustom org-agenda-prefix-format
acedf35c 1615 '((agenda . " %i %-12:c%?-12t% s")
20908596 1616 (timeline . " % s")
acedf35c
CD
1617 (todo . " %i %-12:c")
1618 (tags . " %i %-12:c")
1619 (search . " %i %-12:c"))
20908596 1620 "Format specifications for the prefix of items in the agenda views.
fe3c5669
PE
1621An alist with five entries, each for the different agenda types. The
1622keys of the sublists are `agenda', `timeline', `todo', `search' and `tags'.
3ab2c837
BG
1623The values are format strings.
1624
20908596
CD
1625This format works similar to a printf format, with the following meaning:
1626
fe3c5669 1627 %c the category of the item, \"Diary\" for entries from the diary,
3ab2c837 1628 or as given by the CATEGORY keyword or derived from the file name
e66ba1df 1629 %e the effort required by the item
271672fa 1630 %l the level of the item (insert X space(s) if item is of level X)
3ab2c837
BG
1631 %i the icon category of the item, see `org-agenda-category-icon-alist'
1632 %T the last tag of the item (ignore inherited tags, which come first)
1633 %t the HH:MM time-of-day specification if one applies to the entry
20908596 1634 %s Scheduling/Deadline information, a short string
271672fa 1635 %b show breadcrumbs, i.e., the names of the higher levels
3ab2c837
BG
1636 %(expression) Eval EXPRESSION and replace the control string
1637 by the result
20908596
CD
1638
1639All specifiers work basically like the standard `%s' of printf, but may
271672fa 1640contain two additional characters: a question mark just after the `%'
3ab2c837 1641and a whitespace/punctuation character just before the final letter.
20908596
CD
1642
1643If the first character after `%' is a question mark, the entire field
fe3c5669
PE
1644will only be included if the corresponding value applies to the current
1645entry. This is useful for fields which should have fixed width when
1646present, but zero width when absent. For example, \"%?-12t\" will
1647result in a 12 character time field if a time of the day is specified,
3ab2c837 1648but will completely disappear in entries which do not contain a time.
20908596 1649
271672fa
BG
1650If there is punctuation or whitespace character just before the
1651final format letter, this character will be appended to the field
1652value if the value is not empty. For example, the format
1653\"%-12:c\" leads to \"Diary: \" if the category is \"Diary\". If
1654the category is empty, no additional colon is inserted.
20908596 1655
fe3c5669 1656The default value for the agenda sublist is \" %-12:c%?-12t% s\",
3ab2c837
BG
1657which means:
1658
20908596 1659- Indent the line with two space characters
3ab2c837 1660- Give the category a 12 chars wide field, padded with whitespace on
20908596
CD
1661 the right (because of `-'). Append a colon if there is a category
1662 (because of `:').
1663- If there is a time-of-day, put it into a 12 chars wide field. If no
1664 time, don't put in an empty field, just skip it (because of '?').
3ab2c837 1665- Finally, put the scheduling information.
20908596
CD
1666
1667See also the variables `org-agenda-remove-times-when-in-prefix' and
c8d0cf5c
CD
1668`org-agenda-remove-tags'.
1669
1670Custom commands can set this variable in the options section."
20908596
CD
1671 :type '(choice
1672 (string :tag "General format")
1673 (list :greedy t :tag "View dependent"
1674 (cons (const agenda) (string :tag "Format"))
1675 (cons (const timeline) (string :tag "Format"))
1676 (cons (const todo) (string :tag "Format"))
1677 (cons (const tags) (string :tag "Format"))
1678 (cons (const search) (string :tag "Format"))))
1679 :group 'org-agenda-line-format)
1680
1681(defvar org-prefix-format-compiled nil
8223b1d2
BG
1682 "The compiled prefix format and associated variables.
1683This is a list where first element is a list of variable bindings, and second
1684element is the compiled format expression. See the variable
1685`org-agenda-prefix-format'.")
20908596
CD
1686
1687(defcustom org-agenda-todo-keyword-format "%-1s"
1688 "Format for the TODO keyword in agenda lines.
1689Set this to something like \"%-12s\" if you want all TODO keywords
1690to occupy a fixed space in the agenda display."
1691 :group 'org-agenda-line-format
1692 :type 'string)
1693
8223b1d2
BG
1694(defcustom org-agenda-diary-sexp-prefix nil
1695 "A regexp that matches part of a diary sexp entry
1696which should be treated as scheduling/deadline information in
1697`org-agenda'.
1698
1699For example, you can use this to extract the `diary-remind-message' from
1700`diary-remind' entries."
1701 :group 'org-agenda-line-format
1702 :type '(choice (const :tag "None" nil) (regexp :tag "Regexp")))
1703
ce4fdcb9
CD
1704(defcustom org-agenda-timerange-leaders '("" "(%d/%d): ")
1705 "Text preceding timerange entries in the agenda view.
1706This is a list with two strings. The first applies when the range
1707is entirely on one day. The second applies if the range spans several days.
1708The strings may have two \"%d\" format specifiers which will be filled
1709with the sequence number of the days, and the total number of days in the
1710range, respectively."
1711 :group 'org-agenda-line-format
1712 :type '(list
1713 (string :tag "Deadline today ")
1714 (choice :tag "Deadline relative"
1715 (string :tag "Format string")
1716 (function))))
1717
20908596 1718(defcustom org-agenda-scheduled-leaders '("Scheduled: " "Sched.%2dx: ")
86fbb8ca 1719 "Text preceding scheduled items in the agenda view.
20908596
CD
1720This is a list with two strings. The first applies when the item is
1721scheduled on the current day. The second applies when it has been scheduled
b349f79f
CD
1722previously, it may contain a %d indicating that this is the nth time that
1723this item is scheduled, due to automatic rescheduling of unfinished items
1724for the following day. So this number is one larger than the number of days
1725that passed since this item was scheduled first."
20908596 1726 :group 'org-agenda-line-format
271672fa
BG
1727 :version "24.4"
1728 :package-version '(Org . "8.0")
20908596
CD
1729 :type '(list
1730 (string :tag "Scheduled today ")
1731 (string :tag "Scheduled previously")))
1732
ed21c5c8 1733(defcustom org-agenda-inactive-leader "["
86fbb8ca 1734 "Text preceding item pulled into the agenda by inactive time stamps.
ed21c5c8
CD
1735These entries are added to the agenda when pressing \"[\"."
1736 :group 'org-agenda-line-format
372d7b21 1737 :version "24.1"
271672fa 1738 :type 'string)
ed21c5c8 1739
271672fa 1740(defcustom org-agenda-deadline-leaders '("Deadline: " "In %3d d.: " "%2d d. ago: ")
86fbb8ca 1741 "Text preceding deadline items in the agenda view.
271672fa
BG
1742This is a list with three strings. The first applies when the item has its
1743deadline on the current day. The second applies when the deadline is in the
1744future, the third one when it is in the past. The strings may contain %d
1745to capture the number of days."
20908596 1746 :group 'org-agenda-line-format
271672fa
BG
1747 :version "24.4"
1748 :package-version '(Org . "8.0")
20908596 1749 :type '(list
73d3db82
BG
1750 (string :tag "Deadline today ")
1751 (string :tag "Deadline in the future ")
1752 (string :tag "Deadline in the past ")))
20908596
CD
1753
1754(defcustom org-agenda-remove-times-when-in-prefix t
ed21c5c8 1755 "Non-nil means remove duplicate time specifications in agenda items.
20908596
CD
1756When the format `org-agenda-prefix-format' contains a `%t' specifier, a
1757time-of-day specification in a headline or diary entry is extracted and
1758placed into the prefix. If this option is non-nil, the original specification
1759\(a timestamp or -range, or just a plain time(range) specification like
176011:30-4pm) will be removed for agenda display. This makes the agenda less
1761cluttered.
1762The option can be t or nil. It may also be the symbol `beg', indicating
86fbb8ca 1763that the time should only be removed when it is located at the beginning of
20908596
CD
1764the headline/diary entry."
1765 :group 'org-agenda-line-format
1766 :type '(choice
1767 (const :tag "Always" t)
1768 (const :tag "Never" nil)
1769 (const :tag "When at beginning of entry" beg)))
1770
86fbb8ca
CD
1771(defcustom org-agenda-remove-timeranges-from-blocks nil
1772 "Non-nil means remove time ranges specifications in agenda
1773items that span on several days."
1774 :group 'org-agenda-line-format
372d7b21 1775 :version "24.1"
86fbb8ca 1776 :type 'boolean)
20908596
CD
1777
1778(defcustom org-agenda-default-appointment-duration nil
1779 "Default duration for appointments that only have a starting time.
1780When nil, no duration is specified in such cases.
1781When non-nil, this must be the number of minutes, e.g. 60 for one hour."
1782 :group 'org-agenda-line-format
1783 :type '(choice
1784 (integer :tag "Minutes")
1785 (const :tag "No default duration")))
1786
ff4be292 1787(defcustom org-agenda-show-inherited-tags t
a89c8ef0
BG
1788 "Non-nil means show inherited tags in each agenda line.
1789
1790When this option is set to 'always, it take precedences over
1791`org-agenda-use-tag-inheritance' and inherited tags are shown
1792in every agenda.
1793
1794When this option is set to t (the default), inherited tags are
1795shown when they are available, i.e. when the value of
1796`org-agenda-use-tag-inheritance' has been taken into account.
1797
1798This can be set to a list of agenda types in which the agenda
1799must display the inherited tags. Available types are 'todo,
1800'agenda, 'search and 'timeline.
1801
1802When set to nil, never show inherited tags in agenda lines."
ff4be292 1803 :group 'org-agenda-line-format
a89c8ef0
BG
1804 :group 'org-agenda
1805 :version "24.3"
1806 :type '(choice
1807 (const :tag "Show inherited tags when available" t)
3c8b09ca 1808 (const :tag "Always show inherited tags" always)
a89c8ef0
BG
1809 (repeat :tag "Show inherited tags only in selected agenda types"
1810 (symbol :tag "Agenda type"))))
20908596 1811
c7cf0ebc
BG
1812(defcustom org-agenda-use-tag-inheritance '(todo search timeline agenda)
1813 "List of agenda view types where to use tag inheritance.
1814
1815In tags/tags-todo/tags-tree agenda views, tag inheritance is
1816controlled by `org-use-tag-inheritance'. In other agenda types,
a89c8ef0
BG
1817`org-use-tag-inheritance' is not used for the selection of the
1818agenda entries. Still, you may want the agenda to be aware of
1819the inherited tags anyway, e.g. for later tag filtering.
c7cf0ebc 1820
a89c8ef0 1821Allowed value are 'todo, 'search, 'timeline and 'agenda.
c7cf0ebc 1822
a89c8ef0
BG
1823This variable has no effect if `org-agenda-show-inherited-tags'
1824is set to 'always. In that case, the agenda is aware of those
1825tags.
1826
1827The default value sets tags in every agenda type. Setting this
1828option to nil will speed up non-tags agenda view a lot."
c7cf0ebc 1829 :group 'org-agenda
a89c8ef0
BG
1830 :version "24.3"
1831 :type '(choice
1832 (const :tag "Use tag inheritance in all agenda types" t)
1833 (repeat :tag "Use tag inheritance in selected agenda types"
1834 (symbol :tag "Agenda type"))))
c7cf0ebc 1835
5dec9555
CD
1836(defcustom org-agenda-hide-tags-regexp nil
1837 "Regular expression used to filter away specific tags in agenda views.
1838This means that these tags will be present, but not be shown in the agenda
86fbb8ca 1839line. Secondary filtering will still work on the hidden tags.
afe98dfa 1840Nil means don't hide any tags."
5dec9555
CD
1841 :group 'org-agenda-line-format
1842 :type '(choice
1843 (const :tag "Hide none" nil)
1844 (string :tag "Regexp ")))
1845
20908596 1846(defcustom org-agenda-remove-tags nil
ed21c5c8 1847 "Non-nil means remove the tags from the headline copy in the agenda.
20908596
CD
1848When this is the symbol `prefix', only remove tags when
1849`org-agenda-prefix-format' contains a `%T' specifier."
1850 :group 'org-agenda-line-format
1851 :type '(choice
1852 (const :tag "Always" t)
1853 (const :tag "Never" nil)
1854 (const :tag "When prefix format contains %T" prefix)))
1855
271672fa
BG
1856(org-defvaralias 'org-agenda-remove-tags-when-in-prefix
1857 'org-agenda-remove-tags)
20908596 1858
5ace2fe5 1859(defcustom org-agenda-tags-column (if (featurep 'xemacs) -79 -80)
20908596
CD
1860 "Shift tags in agenda items to this column.
1861If this number is positive, it specifies the column. If it is negative,
1862it means that the tags should be flushright to that column. For example,
1863-80 works well for a normal 80 character screen."
1864 :group 'org-agenda-line-format
1865 :type 'integer)
1866
271672fa 1867(org-defvaralias 'org-agenda-align-tags-to-column 'org-agenda-tags-column)
20908596 1868
c8d0cf5c 1869(defcustom org-agenda-fontify-priorities 'cookies
ed21c5c8 1870 "Non-nil means highlight low and high priorities in agenda.
20908596 1871When t, the highest priority entries are bold, lowest priority italic.
86fbb8ca 1872However, settings in `org-priority-faces' will overrule these faces.
c8d0cf5c
CD
1873When this variable is the symbol `cookies', only fontify the
1874cookies, not the entire task.
621f83e4
CD
1875This may also be an association list of priority faces, whose
1876keys are the character values of `org-highest-priority',
1877`org-default-priority', and `org-lowest-priority' (the default values
ed21c5c8
CD
1878are ?A, ?B, and ?C, respectively). The face may be a named face, a
1879color as a string, or a list like `(:background \"Red\")'.
1880If it is a color, the variable `org-faces-easy-properties'
1881determines if it is a foreground or a background color."
20908596
CD
1882 :group 'org-agenda-line-format
1883 :type '(choice
1884 (const :tag "Never" nil)
1885 (const :tag "Defaults" t)
c8d0cf5c 1886 (const :tag "Cookies only" cookies)
20908596
CD
1887 (repeat :tag "Specify"
1888 (list (character :tag "Priority" :value ?A)
ed21c5c8
CD
1889 (choice :tag "Face "
1890 (string :tag "Color")
1891 (sexp :tag "Face"))))))
20908596 1892
acedf35c
CD
1893(defcustom org-agenda-day-face-function nil
1894 "Function called to determine what face should be used to display a day.
8223b1d2 1895The only argument passed to that function is the day. It should
acedf35c
CD
1896returns a face, or nil if does not want to specify a face and let
1897the normal rules apply."
1898 :group 'org-agenda-line-format
372d7b21 1899 :version "24.1"
271672fa 1900 :type '(choice (const nil) (function)))
acedf35c
CD
1901
1902(defcustom org-agenda-category-icon-alist nil
1903 "Alist of category icon to be displayed in agenda views.
1904
1905Each entry should have the following format:
1906
1907 (CATEGORY-REGEXP FILE-OR-DATA TYPE DATA-P PROPS)
1908
1909Where CATEGORY-REGEXP is a regexp matching the categories where
1910the icon should be displayed.
1911FILE-OR-DATA either a file path or a string containing image data.
1912
27e428e7 1913The other fields can be omitted safely if not needed:
acedf35c
CD
1914TYPE indicates the image type.
1915DATA-P is a boolean indicating whether the FILE-OR-DATA string is
1916image data.
1917PROPS are additional image attributes to assign to the image,
1918like, e.g. `:ascent center'.
1919
1920 (\"Org\" \"/path/to/icon.png\" nil nil :ascent center)
1921
1922If you want to set the display properties yourself, just put a
1923list as second element:
1924
1925 (CATEGORY-REGEXP (MY PROPERTY LIST))
1926
1927For example, to display a 16px horizontal space for Emacs
1928category, you can use:
1929
1930 (\"Emacs\" '(space . (:width (16))))"
1931 :group 'org-agenda-line-format
372d7b21 1932 :version "24.1"
acedf35c
CD
1933 :type '(alist :key-type (string :tag "Regexp matching category")
1934 :value-type (choice (list :tag "Icon"
1935 (string :tag "File or data")
1936 (symbol :tag "Type")
1937 (boolean :tag "Data?")
1938 (repeat :tag "Extra image properties" :inline t symbol))
1939 (list :tag "Display properties" sexp))))
1940
20908596
CD
1941(defgroup org-agenda-column-view nil
1942 "Options concerning column view in the agenda."
1943 :tag "Org Agenda Column View"
1944 :group 'org-agenda)
1945
1946(defcustom org-agenda-columns-show-summaries t
ed21c5c8 1947 "Non-nil means show summaries for columns displayed in the agenda view."
20908596
CD
1948 :group 'org-agenda-column-view
1949 :type 'boolean)
1950
1951(defcustom org-agenda-columns-compute-summary-properties t
ed21c5c8 1952 "Non-nil means recompute all summary properties before column view.
20908596
CD
1953When column view in the agenda is listing properties that have a summary
1954operator, it can go to all relevant buffers and recompute the summaries
1955there. This can mean overhead for the agenda column view, but is necessary
1956to have thing up to date.
1957As a special case, a CLOCKSUM property also makes sure that the clock
1958computations are current."
1959 :group 'org-agenda-column-view
1960 :type 'boolean)
1961
1962(defcustom org-agenda-columns-add-appointments-to-effort-sum nil
ed21c5c8 1963 "Non-nil means the duration of an appointment will add to day effort.
20908596
CD
1964The property to which appointment durations will be added is the one given
1965in the option `org-effort-property'. If an appointment does not have
1966an end time, `org-agenda-default-appointment-duration' will be used. If that
1967is not set, an appointment without end time will not contribute to the time
1968estimate."
1969 :group 'org-agenda-column-view
1970 :type 'boolean)
1971
8bfe682a
CD
1972(defcustom org-agenda-auto-exclude-function nil
1973 "A function called with a tag to decide if it is filtered on '/ RET'.
1974The sole argument to the function, which is called once for each
1975possible tag, is a string giving the name of the tag. The
1976function should return either nil if the tag should be included
ed21c5c8
CD
1977as normal, or \"-<TAG>\" to exclude the tag.
1978Note that for the purpose of tag filtering, only the lower-case version of
1979all tags will be considered, so that this function will only ever see
1980the lower-case version of all tags."
8bfe682a 1981 :group 'org-agenda
271672fa 1982 :type '(choice (const nil) (function)))
8bfe682a 1983
3ab2c837
BG
1984(defcustom org-agenda-bulk-custom-functions nil
1985 "Alist of characters and custom functions for bulk actions.
1986For example, this value makes those two functions available:
1987
1988 '((?R set-category)
1989 (?C bulk-cut))
1990
1991With selected entries in an agenda buffer, `B R' will call
fe3c5669 1992the custom function `set-category' on the selected entries.
3ab2c837
BG
1993Note that functions in this alist don't need to be quoted."
1994 :type 'alist
372d7b21 1995 :version "24.1"
3ab2c837
BG
1996 :group 'org-agenda)
1997
afe98dfa
CD
1998(defmacro org-agenda-with-point-at-orig-entry (string &rest body)
1999 "Execute BODY with point at location given by `org-hd-marker' property.
2000If STRING is non-nil, the text property will be fetched from position 0
2001in that string. If STRING is nil, it will be fetched from the beginning
2002of the current line."
e66ba1df
BG
2003 (org-with-gensyms (marker)
2004 `(let ((,marker (get-text-property (if string 0 (point-at-bol))
2005 'org-hd-marker ,string)))
2006 (with-current-buffer (marker-buffer ,marker)
2007 (save-excursion
2008 (goto-char ,marker)
2009 ,@body)))))
2010(def-edebug-spec org-agenda-with-point-at-orig-entry (form body))
afe98dfa 2011
20908596
CD
2012(defun org-add-agenda-custom-command (entry)
2013 "Replace or add a command in `org-agenda-custom-commands'.
2014This is mostly for hacking and trying a new command - once the command
2015works you probably want to add it to `org-agenda-custom-commands' for good."
2016 (let ((ass (assoc (car entry) org-agenda-custom-commands)))
2017 (if ass
2018 (setcdr ass (cdr entry))
2019 (push entry org-agenda-custom-commands))))
2020
8223b1d2 2021;;; Define the org-agenda-mode
20908596
CD
2022
2023(defvar org-agenda-mode-map (make-sparse-keymap)
2024 "Keymap for `org-agenda-mode'.")
271672fa 2025(org-defvaralias 'org-agenda-keymap 'org-agenda-mode-map)
20908596
CD
2026
2027(defvar org-agenda-menu) ; defined later in this file.
8223b1d2 2028(defvar org-agenda-restrict nil) ; defined later in this file.
20908596 2029(defvar org-agenda-follow-mode nil)
54a0dee5 2030(defvar org-agenda-entry-text-mode nil)
20908596
CD
2031(defvar org-agenda-clockreport-mode nil)
2032(defvar org-agenda-show-log nil)
2033(defvar org-agenda-redo-command nil)
2034(defvar org-agenda-query-string nil)
0bd48b37 2035(defvar org-agenda-mode-hook nil
8223b1d2
BG
2036 "Hook run after `org-agenda-mode' is turned on.
2037The buffer is still writable when this hook is called.")
20908596
CD
2038(defvar org-agenda-type nil)
2039(defvar org-agenda-force-single-file nil)
8223b1d2
BG
2040(defvar org-agenda-bulk-marked-entries nil
2041 "List of markers that refer to marked entries in the agenda.")
2042
2043;;; Multiple agenda buffers support
2044
2045(defcustom org-agenda-sticky nil
2046 "Non-nil means agenda q key will bury agenda buffers.
2047Agenda commands will then show existing buffer instead of generating new ones.
2048When nil, `q' will kill the single agenda buffer."
2049 :group 'org-agenda
2050 :version "24.3"
2051 :type 'boolean)
2052
bdebdb64 2053\f
8223b1d2
BG
2054;;;###autoload
2055(defun org-toggle-sticky-agenda (&optional arg)
2056 "Toggle `org-agenda-sticky'."
2057 (interactive "P")
2058 (let ((new-value (if arg
2059 (> (prefix-numeric-value arg) 0)
2060 (not org-agenda-sticky))))
2061 (if (equal new-value org-agenda-sticky)
2062 (and (org-called-interactively-p 'interactive)
2063 (message "Sticky agenda was already %s"
2064 (if org-agenda-sticky "enabled" "disabled")))
2065 (setq org-agenda-sticky new-value)
2066 (org-agenda-kill-all-agenda-buffers)
2067 (and (org-called-interactively-p 'interactive)
2068 (message "Sticky agenda was %s"
2069 (if org-agenda-sticky "enabled" "disabled"))))))
2070
2071(defvar org-agenda-buffer nil
2072 "Agenda buffer currently being generated.")
2073
2074(defvar org-agenda-last-prefix-arg nil)
2075(defvar org-agenda-this-buffer-name nil)
2076(defvar org-agenda-doing-sticky-redo nil)
2077(defvar org-agenda-this-buffer-is-sticky nil)
2078
2079(defconst org-agenda-local-vars
2080 '(org-agenda-this-buffer-name
2081 org-agenda-undo-list
2082 org-agenda-pending-undo-list
2083 org-agenda-follow-mode
2084 org-agenda-entry-text-mode
2085 org-agenda-clockreport-mode
2086 org-agenda-show-log
2087 org-agenda-redo-command
2088 org-agenda-query-string
2089 org-agenda-type
2090 org-agenda-bulk-marked-entries
2091 org-agenda-undo-has-started-in
2092 org-agenda-info
8223b1d2
BG
2093 org-agenda-pre-window-conf
2094 org-agenda-columns-active
271672fa 2095 org-agenda-tag-filter-overlays
8223b1d2 2096 org-agenda-tag-filter
271672fa 2097 org-agenda-cat-filter-overlays
8223b1d2 2098 org-agenda-category-filter
271672fa
BG
2099 org-agenda-re-filter-overlays
2100 org-agenda-regexp-filter
8223b1d2
BG
2101 org-agenda-markers
2102 org-agenda-last-search-view-search-was-boolean
2103 org-agenda-filtered-by-category
2104 org-agenda-filter-form
8223b1d2
BG
2105 org-agenda-cycle-counter
2106 org-agenda-last-prefix-arg)
2107 "Variables that must be local in agenda buffers to allow multiple buffers.")
20908596
CD
2108
2109(defun org-agenda-mode ()
2110 "Mode for time-sorted view on action items in Org-mode files.
2111
2112The following commands are available:
2113
2114\\{org-agenda-mode-map}"
2115 (interactive)
8223b1d2
BG
2116 (cond (org-agenda-doing-sticky-redo
2117 ;; Refreshing sticky agenda-buffer
2118 ;;
2119 ;; Preserve the value of `org-agenda-local-vars' variables,
2120 ;; while letting `kill-all-local-variables' kill the rest
2121 (let ((save (buffer-local-variables)))
2122 (kill-all-local-variables)
2123 (mapc 'make-local-variable org-agenda-local-vars)
2124 (dolist (elem save)
2125 (let ((var (car elem))
2126 (val (cdr elem)))
2127 (when (and val
2128 (member var org-agenda-local-vars))
2129 (set var val)))))
2130 (set (make-local-variable 'org-agenda-this-buffer-is-sticky) t))
2131 (org-agenda-sticky
2132 ;; Creating a sticky Agenda buffer for the first time
2133 (kill-all-local-variables)
2134 (mapc 'make-local-variable org-agenda-local-vars)
2135 (set (make-local-variable 'org-agenda-this-buffer-is-sticky) t))
2136 (t
2137 ;; Creating a non-sticky agenda buffer
2138 (kill-all-local-variables)
2139 (set (make-local-variable 'org-agenda-this-buffer-is-sticky) nil)))
20908596 2140 (setq org-agenda-undo-list nil
c8d0cf5c
CD
2141 org-agenda-pending-undo-list nil
2142 org-agenda-bulk-marked-entries nil)
20908596
CD
2143 (setq major-mode 'org-agenda-mode)
2144 ;; Keep global-font-lock-mode from turning on font-lock-mode
2145 (org-set-local 'font-lock-global-modes (list 'not major-mode))
2146 (setq mode-name "Org-Agenda")
30cb51f1 2147 (setq indent-tabs-mode nil)
20908596
CD
2148 (use-local-map org-agenda-mode-map)
2149 (easy-menu-add org-agenda-menu)
2150 (if org-startup-truncated (setq truncate-lines t))
54a0dee5 2151 (org-set-local 'line-move-visual nil)
8223b1d2 2152 (org-add-hook 'post-command-hook 'org-agenda-update-agenda-type nil 'local)
20908596
CD
2153 (org-add-hook 'pre-command-hook 'org-unhighlight nil 'local)
2154 ;; Make sure properties are removed when copying text
271672fa
BG
2155 (org-add-hook 'filter-buffer-substring-functions
2156 (lambda (fun start end delete)
2157 (substring-no-properties (funcall fun start end delete)))
2158 nil t)
20908596
CD
2159 (unless org-agenda-keep-modes
2160 (setq org-agenda-follow-mode org-agenda-start-with-follow-mode
54a0dee5 2161 org-agenda-entry-text-mode org-agenda-start-with-entry-text-mode
20908596 2162 org-agenda-clockreport-mode org-agenda-start-with-clockreport-mode
c8d0cf5c
CD
2163 org-agenda-show-log org-agenda-start-with-log-mode))
2164
20908596
CD
2165 (easy-menu-change
2166 '("Agenda") "Agenda Files"
2167 (append
2168 (list
2169 (vector
2170 (if (get 'org-agenda-files 'org-restrict)
2171 "Restricted to single file"
2172 "Edit File List")
2173 '(org-edit-agenda-file-list)
2174 (not (get 'org-agenda-files 'org-restrict)))
2175 "--")
2176 (mapcar 'org-file-menu-entry (org-agenda-files))))
2177 (org-agenda-set-mode-name)
2178 (apply
2179 (if (fboundp 'run-mode-hooks) 'run-mode-hooks 'run-hooks)
2180 (list 'org-agenda-mode-hook)))
2181
2182(substitute-key-definition 'undo 'org-agenda-undo
2183 org-agenda-mode-map global-map)
2184(org-defkey org-agenda-mode-map "\C-i" 'org-agenda-goto)
2185(org-defkey org-agenda-mode-map [(tab)] 'org-agenda-goto)
2186(org-defkey org-agenda-mode-map "\C-m" 'org-agenda-switch-to)
2187(org-defkey org-agenda-mode-map "\C-k" 'org-agenda-kill)
c8d0cf5c 2188(org-defkey org-agenda-mode-map "\C-c\C-w" 'org-agenda-refile)
271672fa
BG
2189(org-defkey org-agenda-mode-map [(meta down)] 'org-agenda-drag-line-forward)
2190(org-defkey org-agenda-mode-map [(meta up)] 'org-agenda-drag-line-backward)
c8d0cf5c 2191(org-defkey org-agenda-mode-map "m" 'org-agenda-bulk-mark)
271672fa 2192(org-defkey org-agenda-mode-map "\M-m" 'org-agenda-bulk-toggle)
8223b1d2 2193(org-defkey org-agenda-mode-map "*" 'org-agenda-bulk-mark-all)
271672fa 2194(org-defkey org-agenda-mode-map "\M-*" 'org-agenda-bulk-toggle-all)
c7cf0ebc 2195(org-defkey org-agenda-mode-map "#" 'org-agenda-dim-blocked-tasks)
3ab2c837 2196(org-defkey org-agenda-mode-map "%" 'org-agenda-bulk-mark-regexp)
c8d0cf5c 2197(org-defkey org-agenda-mode-map "u" 'org-agenda-bulk-unmark)
8223b1d2 2198(org-defkey org-agenda-mode-map "U" 'org-agenda-bulk-unmark-all)
c8d0cf5c 2199(org-defkey org-agenda-mode-map "B" 'org-agenda-bulk-action)
8223b1d2
BG
2200(org-defkey org-agenda-mode-map "k" 'org-agenda-capture)
2201(org-defkey org-agenda-mode-map "A" 'org-agenda-append-agenda)
c8d0cf5c 2202(org-defkey org-agenda-mode-map "\C-c\C-x!" 'org-reload)
8bfe682a
CD
2203(org-defkey org-agenda-mode-map "\C-c\C-x\C-a" 'org-agenda-archive-default)
2204(org-defkey org-agenda-mode-map "\C-c\C-xa" 'org-agenda-toggle-archive-tag)
2205(org-defkey org-agenda-mode-map "\C-c\C-xA" 'org-agenda-archive-to-archive-sibling)
54a0dee5 2206(org-defkey org-agenda-mode-map "\C-c\C-x\C-s" 'org-agenda-archive)
8bfe682a 2207(org-defkey org-agenda-mode-map "\C-c$" 'org-agenda-archive)
20908596 2208(org-defkey org-agenda-mode-map "$" 'org-agenda-archive)
20908596 2209(org-defkey org-agenda-mode-map "\C-c\C-o" 'org-agenda-open-link)
8bfe682a
CD
2210(org-defkey org-agenda-mode-map " " 'org-agenda-show-and-scroll-up)
2211(org-defkey org-agenda-mode-map [backspace] 'org-agenda-show-scroll-down)
2212(org-defkey org-agenda-mode-map "\d" 'org-agenda-show-scroll-down)
20908596
CD
2213(org-defkey org-agenda-mode-map [(control shift right)] 'org-agenda-todo-nextset)
2214(org-defkey org-agenda-mode-map [(control shift left)] 'org-agenda-todo-previousset)
2215(org-defkey org-agenda-mode-map "\C-c\C-xb" 'org-agenda-tree-to-indirect-buffer)
20908596
CD
2216(org-defkey org-agenda-mode-map "o" 'delete-other-windows)
2217(org-defkey org-agenda-mode-map "L" 'org-agenda-recenter)
54a0dee5 2218(org-defkey org-agenda-mode-map "\C-c\C-t" 'org-agenda-todo)
20908596 2219(org-defkey org-agenda-mode-map "t" 'org-agenda-todo)
8bfe682a 2220(org-defkey org-agenda-mode-map "a" 'org-agenda-archive-default-with-confirmation)
20908596 2221(org-defkey org-agenda-mode-map ":" 'org-agenda-set-tags)
71d35b24 2222(org-defkey org-agenda-mode-map "\C-c\C-q" 'org-agenda-set-tags)
20908596
CD
2223(org-defkey org-agenda-mode-map "." 'org-agenda-goto-today)
2224(org-defkey org-agenda-mode-map "j" 'org-agenda-goto-date)
2225(org-defkey org-agenda-mode-map "d" 'org-agenda-day-view)
2226(org-defkey org-agenda-mode-map "w" 'org-agenda-week-view)
20908596
CD
2227(org-defkey org-agenda-mode-map "y" 'org-agenda-year-view)
2228(org-defkey org-agenda-mode-map "\C-c\C-z" 'org-agenda-add-note)
2229(org-defkey org-agenda-mode-map "z" 'org-agenda-add-note)
c8d0cf5c
CD
2230(org-defkey org-agenda-mode-map [(shift right)] 'org-agenda-do-date-later)
2231(org-defkey org-agenda-mode-map [(shift left)] 'org-agenda-do-date-earlier)
2232(org-defkey org-agenda-mode-map [?\C-c ?\C-x (right)] 'org-agenda-do-date-later)
2233(org-defkey org-agenda-mode-map [?\C-c ?\C-x (left)] 'org-agenda-do-date-earlier)
20908596
CD
2234
2235(org-defkey org-agenda-mode-map ">" 'org-agenda-date-prompt)
2236(org-defkey org-agenda-mode-map "\C-c\C-s" 'org-agenda-schedule)
2237(org-defkey org-agenda-mode-map "\C-c\C-d" 'org-agenda-deadline)
2238(let ((l '(1 2 3 4 5 6 7 8 9 0)))
2239 (while l (org-defkey org-agenda-mode-map
8223b1d2 2240 (int-to-string (pop l)) 'digit-argument)))
20908596 2241
54a0dee5 2242(org-defkey org-agenda-mode-map "F" 'org-agenda-follow-mode)
20908596 2243(org-defkey org-agenda-mode-map "R" 'org-agenda-clockreport-mode)
54a0dee5 2244(org-defkey org-agenda-mode-map "E" 'org-agenda-entry-text-mode)
20908596 2245(org-defkey org-agenda-mode-map "l" 'org-agenda-log-mode)
c8d0cf5c 2246(org-defkey org-agenda-mode-map "v" 'org-agenda-view-mode-dispatch)
20908596 2247(org-defkey org-agenda-mode-map "D" 'org-agenda-toggle-diary)
ed21c5c8 2248(org-defkey org-agenda-mode-map "!" 'org-agenda-toggle-deadlines)
20908596
CD
2249(org-defkey org-agenda-mode-map "G" 'org-agenda-toggle-time-grid)
2250(org-defkey org-agenda-mode-map "r" 'org-agenda-redo)
8223b1d2 2251(org-defkey org-agenda-mode-map "g" (lambda () (interactive) (org-agenda-redo t)))
54a0dee5
CD
2252(org-defkey org-agenda-mode-map "e" 'org-agenda-set-effort)
2253(org-defkey org-agenda-mode-map "\C-c\C-xe" 'org-agenda-set-effort)
2254(org-defkey org-agenda-mode-map "\C-c\C-x\C-e"
2255 'org-clock-modify-effort-estimate)
2256(org-defkey org-agenda-mode-map "\C-c\C-xp" 'org-agenda-set-property)
20908596 2257(org-defkey org-agenda-mode-map "q" 'org-agenda-quit)
8223b1d2 2258(org-defkey org-agenda-mode-map "Q" 'org-agenda-Quit)
20908596 2259(org-defkey org-agenda-mode-map "x" 'org-agenda-exit)
e66ba1df 2260(org-defkey org-agenda-mode-map "\C-x\C-w" 'org-agenda-write)
20908596 2261(org-defkey org-agenda-mode-map "\C-x\C-s" 'org-save-all-org-buffers)
c8d0cf5c 2262(org-defkey org-agenda-mode-map "s" 'org-save-all-org-buffers)
20908596 2263(org-defkey org-agenda-mode-map "T" 'org-agenda-show-tags)
8bfe682a
CD
2264(org-defkey org-agenda-mode-map "n" 'org-agenda-next-line)
2265(org-defkey org-agenda-mode-map "p" 'org-agenda-previous-line)
8223b1d2
BG
2266(org-defkey org-agenda-mode-map "N" 'org-agenda-next-item)
2267(org-defkey org-agenda-mode-map "P" 'org-agenda-previous-item)
8bfe682a
CD
2268(substitute-key-definition 'next-line 'org-agenda-next-line
2269 org-agenda-mode-map global-map)
2270(substitute-key-definition 'previous-line 'org-agenda-previous-line
2271 org-agenda-mode-map global-map)
621f83e4 2272(org-defkey org-agenda-mode-map "\C-c\C-a" 'org-attach)
20908596
CD
2273(org-defkey org-agenda-mode-map "\C-c\C-n" 'org-agenda-next-date-line)
2274(org-defkey org-agenda-mode-map "\C-c\C-p" 'org-agenda-previous-date-line)
20908596 2275(org-defkey org-agenda-mode-map "\C-c," 'org-agenda-priority)
8223b1d2 2276(org-defkey org-agenda-mode-map "," 'org-agenda-priority)
20908596
CD
2277(org-defkey org-agenda-mode-map "i" 'org-agenda-diary-entry)
2278(org-defkey org-agenda-mode-map "c" 'org-agenda-goto-calendar)
2279(org-defkey org-agenda-mode-map "C" 'org-agenda-convert-date)
2280(org-defkey org-agenda-mode-map "M" 'org-agenda-phases-of-moon)
2281(org-defkey org-agenda-mode-map "S" 'org-agenda-sunrise-sunset)
2282(org-defkey org-agenda-mode-map "h" 'org-agenda-holidays)
2283(org-defkey org-agenda-mode-map "H" 'org-agenda-holidays)
2284(org-defkey org-agenda-mode-map "\C-c\C-x\C-i" 'org-agenda-clock-in)
2285(org-defkey org-agenda-mode-map "I" 'org-agenda-clock-in)
2286(org-defkey org-agenda-mode-map "\C-c\C-x\C-o" 'org-agenda-clock-out)
2287(org-defkey org-agenda-mode-map "O" 'org-agenda-clock-out)
2288(org-defkey org-agenda-mode-map "\C-c\C-x\C-x" 'org-agenda-clock-cancel)
2289(org-defkey org-agenda-mode-map "X" 'org-agenda-clock-cancel)
2290(org-defkey org-agenda-mode-map "\C-c\C-x\C-j" 'org-clock-goto)
afe98dfa 2291(org-defkey org-agenda-mode-map "J" 'org-agenda-clock-goto)
20908596
CD
2292(org-defkey org-agenda-mode-map "+" 'org-agenda-priority-up)
2293(org-defkey org-agenda-mode-map "-" 'org-agenda-priority-down)
2294(org-defkey org-agenda-mode-map [(shift up)] 'org-agenda-priority-up)
2295(org-defkey org-agenda-mode-map [(shift down)] 'org-agenda-priority-down)
2296(org-defkey org-agenda-mode-map [?\C-c ?\C-x (up)] 'org-agenda-priority-up)
2297(org-defkey org-agenda-mode-map [?\C-c ?\C-x (down)] 'org-agenda-priority-down)
54a0dee5
CD
2298(org-defkey org-agenda-mode-map "f" 'org-agenda-later)
2299(org-defkey org-agenda-mode-map "b" 'org-agenda-earlier)
20908596 2300(org-defkey org-agenda-mode-map "\C-c\C-x\C-c" 'org-agenda-columns)
c8d0cf5c 2301(org-defkey org-agenda-mode-map "\C-c\C-x>" 'org-agenda-remove-restriction-lock)
20908596
CD
2302
2303(org-defkey org-agenda-mode-map "[" 'org-agenda-manipulate-query-add)
2304(org-defkey org-agenda-mode-map "]" 'org-agenda-manipulate-query-subtract)
2305(org-defkey org-agenda-mode-map "{" 'org-agenda-manipulate-query-add-re)
2306(org-defkey org-agenda-mode-map "}" 'org-agenda-manipulate-query-subtract-re)
621f83e4 2307(org-defkey org-agenda-mode-map "/" 'org-agenda-filter-by-tag)
271672fa
BG
2308(org-defkey org-agenda-mode-map "=" 'org-agenda-filter-by-regexp)
2309(org-defkey org-agenda-mode-map "|" 'org-agenda-filter-remove-all)
71d35b24 2310(org-defkey org-agenda-mode-map "\\" 'org-agenda-filter-by-tag-refine)
271672fa 2311(org-defkey org-agenda-mode-map "~" 'org-agenda-limit-interactively)
e66ba1df 2312(org-defkey org-agenda-mode-map "<" 'org-agenda-filter-by-category)
271672fa 2313(org-defkey org-agenda-mode-map "^" 'org-agenda-filter-by-top-headline)
c8d0cf5c 2314(org-defkey org-agenda-mode-map ";" 'org-timer-set-timer)
8d642074
CD
2315(define-key org-agenda-mode-map "?" 'org-agenda-show-the-flagging-note)
2316(org-defkey org-agenda-mode-map "\C-c\C-x\C-mg" 'org-mobile-pull)
2317(org-defkey org-agenda-mode-map "\C-c\C-x\C-mp" 'org-mobile-push)
20908596 2318
86fbb8ca
CD
2319(org-defkey org-agenda-mode-map [mouse-2] 'org-agenda-goto-mouse)
2320(org-defkey org-agenda-mode-map [mouse-3] 'org-agenda-show-mouse)
20908596 2321(when org-agenda-mouse-1-follows-link
8bfe682a 2322 (org-defkey org-agenda-mode-map [follow-link] 'mouse-face))
20908596
CD
2323(easy-menu-define org-agenda-menu org-agenda-mode-map "Agenda menu"
2324 '("Agenda"
2325 ("Agenda Files")
2326 "--"
8d642074
CD
2327 ("Agenda Dates"
2328 ["Goto Today" org-agenda-goto-today (org-agenda-check-type nil 'agenda 'timeline)]
2329 ["Next Dates" org-agenda-later (org-agenda-check-type nil 'agenda)]
2330 ["Previous Dates" org-agenda-earlier (org-agenda-check-type nil 'agenda)]
2331 ["Jump to date" org-agenda-goto-date (org-agenda-check-type nil 'agenda)])
2332 "--"
2333 ("View"
2334 ["Day View" org-agenda-day-view
2335 :active (org-agenda-check-type nil 'agenda)
acedf35c 2336 :style radio :selected (eq org-agenda-current-span 'day)
8d642074
CD
2337 :keys "v d (or just d)"]
2338 ["Week View" org-agenda-week-view
2339 :active (org-agenda-check-type nil 'agenda)
acedf35c 2340 :style radio :selected (eq org-agenda-current-span 'week)
271672fa
BG
2341 :keys "v w"]
2342 ["Fortnight View" org-agenda-fortnight-view
2343 :active (org-agenda-check-type nil 'agenda)
2344 :style radio :selected (eq org-agenda-current-span 'fortnight)
2345 :keys "v f"]
8d642074
CD
2346 ["Month View" org-agenda-month-view
2347 :active (org-agenda-check-type nil 'agenda)
acedf35c 2348 :style radio :selected (eq org-agenda-current-span 'month)
8d642074
CD
2349 :keys "v m"]
2350 ["Year View" org-agenda-year-view
2351 :active (org-agenda-check-type nil 'agenda)
acedf35c 2352 :style radio :selected (eq org-agenda-current-span 'year)
8d642074
CD
2353 :keys "v y"]
2354 "--"
2355 ["Include Diary" org-agenda-toggle-diary
2356 :style toggle :selected org-agenda-include-diary
2357 :active (org-agenda-check-type nil 'agenda)]
ed21c5c8
CD
2358 ["Include Deadlines" org-agenda-toggle-deadlines
2359 :style toggle :selected org-agenda-include-deadlines
2360 :active (org-agenda-check-type nil 'agenda)]
8d642074
CD
2361 ["Use Time Grid" org-agenda-toggle-time-grid
2362 :style toggle :selected org-agenda-use-time-grid
2363 :active (org-agenda-check-type nil 'agenda)]
2364 "--"
2365 ["Show clock report" org-agenda-clockreport-mode
2366 :style toggle :selected org-agenda-clockreport-mode
2367 :active (org-agenda-check-type nil 'agenda)]
2368 ["Show some entry text" org-agenda-entry-text-mode
2369 :style toggle :selected org-agenda-entry-text-mode
2370 :active t]
8223b1d2 2371 "--"
8d642074
CD
2372 ["Show Logbook entries" org-agenda-log-mode
2373 :style toggle :selected org-agenda-show-log
2374 :active (org-agenda-check-type nil 'agenda 'timeline)
2375 :keys "v l (or just l)"]
2376 ["Include archived trees" org-agenda-archives-mode
2377 :style toggle :selected org-agenda-archives-mode :active t
2378 :keys "v a"]
2379 ["Include archive files" (org-agenda-archives-mode t)
2380 :style toggle :selected (eq org-agenda-archives-mode t) :active t
2381 :keys "v A"]
2382 "--"
2383 ["Remove Restriction" org-agenda-remove-restriction-lock org-agenda-restrict])
e66ba1df 2384 ["Write view to file" org-agenda-write t]
8d642074
CD
2385 ["Rebuild buffer" org-agenda-redo t]
2386 ["Save all Org-mode Buffers" org-save-all-org-buffers t]
2387 "--"
2388 ["Show original entry" org-agenda-show t]
20908596
CD
2389 ["Go To (other window)" org-agenda-goto t]
2390 ["Go To (this window)" org-agenda-switch-to t]
8223b1d2 2391 ["Capture with cursor date" org-agenda-capture t]
20908596
CD
2392 ["Follow Mode" org-agenda-follow-mode
2393 :style toggle :selected org-agenda-follow-mode :active t]
8223b1d2 2394 ;; ["Tree to indirect frame" org-agenda-tree-to-indirect-buffer t]
20908596 2395 "--"
8d642074
CD
2396 ("TODO"
2397 ["Cycle TODO" org-agenda-todo t]
2398 ["Next TODO set" org-agenda-todo-nextset t]
2399 ["Previous TODO set" org-agenda-todo-previousset t]
2400 ["Add note" org-agenda-add-note t])
2401 ("Archive/Refile/Delete"
8bfe682a
CD
2402 ["Archive default" org-agenda-archive-default t]
2403 ["Archive default" org-agenda-archive-default-with-confirmation t]
20908596
CD
2404 ["Toggle ARCHIVE tag" org-agenda-toggle-archive-tag t]
2405 ["Move to archive sibling" org-agenda-archive-to-archive-sibling t]
c8d0cf5c 2406 ["Archive subtree" org-agenda-archive t]
8d642074
CD
2407 "--"
2408 ["Refile" org-agenda-refile t]
2409 "--"
2410 ["Delete subtree" org-agenda-kill t])
c8d0cf5c 2411 ("Bulk action"
8d642074 2412 ["Mark entry" org-agenda-bulk-mark t]
8223b1d2 2413 ["Mark all" org-agenda-bulk-mark-all t]
8d642074 2414 ["Unmark entry" org-agenda-bulk-unmark t]
271672fa
BG
2415 ["Unmark all" org-agenda-bulk-unmark-all :active t :keys "U"]
2416 ["Toggle mark" org-agenda-bulk-toggle t]
2417 ["Toggle all" org-agenda-bulk-toggle-all t]
2418 ["Mark regexp" org-agenda-bulk-mark-regexp t])
8223b1d2 2419 ["Act on all marked" org-agenda-bulk-action t]
c8d0cf5c 2420 "--"
20908596
CD
2421 ("Tags and Properties"
2422 ["Show all Tags" org-agenda-show-tags t]
2423 ["Set Tags current line" org-agenda-set-tags (not (org-region-active-p))]
2424 ["Change tag in region" org-agenda-set-tags (org-region-active-p)]
2425 "--"
2426 ["Column View" org-columns t])
8d642074 2427 ("Deadline/Schedule"
20908596
CD
2428 ["Schedule" org-agenda-schedule t]
2429 ["Set Deadline" org-agenda-deadline t]
2430 "--"
2431 ["Change Date +1 day" org-agenda-date-later (org-agenda-check-type nil 'agenda 'timeline)]
2432 ["Change Date -1 day" org-agenda-date-earlier (org-agenda-check-type nil 'agenda 'timeline)]
c8d0cf5c
CD
2433 ["Change Time +1 hour" org-agenda-do-date-later :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u S-right"]
2434 ["Change Time -1 hour" org-agenda-do-date-earlier :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u S-left"]
2435 ["Change Time + min" org-agenda-date-later :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u C-u S-right"]
2436 ["Change Time - min" org-agenda-date-earlier :active (org-agenda-check-type nil 'agenda 'timeline) :keys "C-u C-u S-left"]
20908596 2437 ["Change Date to ..." org-agenda-date-prompt (org-agenda-check-type nil 'agenda 'timeline)])
54a0dee5 2438 ("Clock and Effort"
20908596
CD
2439 ["Clock in" org-agenda-clock-in t]
2440 ["Clock out" org-agenda-clock-out t]
2441 ["Clock cancel" org-agenda-clock-cancel t]
54a0dee5
CD
2442 ["Goto running clock" org-clock-goto t]
2443 "--"
2444 ["Set Effort" org-agenda-set-effort t]
2445 ["Change clocked effort" org-clock-modify-effort-estimate
2446 (org-clock-is-active)])
20908596
CD
2447 ("Priority"
2448 ["Set Priority" org-agenda-priority t]
2449 ["Increase Priority" org-agenda-priority-up t]
2450 ["Decrease Priority" org-agenda-priority-down t]
8223b1d2 2451 ["Show Priority" org-show-priority t])
20908596
CD
2452 ("Calendar/Diary"
2453 ["New Diary Entry" org-agenda-diary-entry (org-agenda-check-type nil 'agenda 'timeline)]
2454 ["Goto Calendar" org-agenda-goto-calendar (org-agenda-check-type nil 'agenda 'timeline)]
2455 ["Phases of the Moon" org-agenda-phases-of-moon (org-agenda-check-type nil 'agenda 'timeline)]
2456 ["Sunrise/Sunset" org-agenda-sunrise-sunset (org-agenda-check-type nil 'agenda 'timeline)]
2457 ["Holidays" org-agenda-holidays (org-agenda-check-type nil 'agenda 'timeline)]
2458 ["Convert" org-agenda-convert-date (org-agenda-check-type nil 'agenda 'timeline)]
2459 "--"
271672fa 2460 ["Create iCalendar File" org-icalendar-combine-agenda-files t])
20908596 2461 "--"
8d642074 2462 ["Undo Remote Editing" org-agenda-undo org-agenda-undo-list]
2c3ad40d 2463 "--"
8d642074
CD
2464 ("MobileOrg"
2465 ["Push Files and Views" org-mobile-push t]
2466 ["Get Captured and Flagged" org-mobile-pull t]
2467 ["Find FLAGGED Tasks" (org-agenda nil "?") :active t :keys "C-c a ?"]
2468 ["Show note / unflag" org-agenda-show-the-flagging-note t]
c8d0cf5c 2469 "--"
8d642074 2470 ["Setup" (progn (require 'org-mobile) (customize-group 'org-mobile)) t])
20908596
CD
2471 "--"
2472 ["Quit" org-agenda-quit t]
2473 ["Exit and Release Buffers" org-agenda-exit t]
2474 ))
2475
2476;;; Agenda undo
2477
2478(defvar org-agenda-allow-remote-undo t
ed21c5c8 2479 "Non-nil means allow remote undo from the agenda buffer.")
20908596
CD
2480(defvar org-agenda-undo-has-started-in nil
2481 "Buffers that have already seen `undo-start' in the current undo sequence.")
20908596 2482
20908596
CD
2483(defun org-agenda-undo ()
2484 "Undo a remote editing step in the agenda.
2485This undoes changes both in the agenda buffer and in the remote buffer
2486that have been changed along."
2487 (interactive)
2488 (or org-agenda-allow-remote-undo
271672fa 2489 (user-error "Check the variable `org-agenda-allow-remote-undo' to activate remote undo"))
20908596
CD
2490 (if (not (eq this-command last-command))
2491 (setq org-agenda-undo-has-started-in nil
2492 org-agenda-pending-undo-list org-agenda-undo-list))
2493 (if (not org-agenda-pending-undo-list)
271672fa 2494 (user-error "No further undo information"))
20908596
CD
2495 (let* ((entry (pop org-agenda-pending-undo-list))
2496 buf line cmd rembuf)
2497 (setq cmd (pop entry) line (pop entry))
2498 (setq rembuf (nth 2 entry))
2499 (org-with-remote-undo rembuf
2500 (while (bufferp (setq buf (pop entry)))
2501 (if (pop entry)
2502 (with-current-buffer buf
2503 (let ((last-undo-buffer buf)
2504 (inhibit-read-only t))
2505 (unless (memq buf org-agenda-undo-has-started-in)
2506 (push buf org-agenda-undo-has-started-in)
2507 (make-local-variable 'pending-undo-list)
2508 (undo-start))
2509 (while (and pending-undo-list
2510 (listp pending-undo-list)
2511 (not (car pending-undo-list)))
2512 (pop pending-undo-list))
2513 (undo-more 1))))))
54a0dee5 2514 (org-goto-line line)
20908596
CD
2515 (message "`%s' undone (buffer %s)" cmd (buffer-name rembuf))))
2516
2517(defun org-verify-change-for-undo (l1 l2)
2518 "Verify that a real change occurred between the undo lists L1 and L2."
2519 (while (and l1 (listp l1) (null (car l1))) (pop l1))
2520 (while (and l2 (listp l2) (null (car l2))) (pop l2))
2521 (not (eq l1 l2)))
2522
2523;;; Agenda dispatch
2524
20908596
CD
2525(defvar org-agenda-restrict-begin (make-marker))
2526(defvar org-agenda-restrict-end (make-marker))
2527(defvar org-agenda-last-dispatch-buffer nil)
2528(defvar org-agenda-overriding-restriction nil)
2529
8223b1d2
BG
2530(defcustom org-agenda-custom-commands-contexts nil
2531 "Alist of custom agenda keys and contextual rules.
2532
2533For example, if you have a custom agenda command \"p\" and you
2534want this command to be accessible only from plain text files,
2535use this:
2536
a89c8ef0 2537 '((\"p\" ((in-file . \"\\.txt\"))))
8223b1d2
BG
2538
2539Here are the available contexts definitions:
2540
2541 in-file: command displayed only in matching files
2542 in-mode: command displayed only in matching modes
2543 not-in-file: command not displayed in matching files
2544 not-in-mode: command not displayed in matching modes
271672fa
BG
2545 in-buffer: command displayed only in matching buffers
2546not-in-buffer: command not displayed in matching buffers
8223b1d2
BG
2547 [function]: a custom function taking no argument
2548
2549If you define several checks, the agenda command will be
2550accessible if there is at least one valid check.
2551
2552You can also bind a key to another agenda custom command
2553depending on contextual rules.
2554
a89c8ef0 2555 '((\"p\" \"q\" ((in-file . \"\\.txt\"))))
8223b1d2
BG
2556
2557Here it means: in .txt files, use \"p\" as the key for the
2558agenda command otherwise associated with \"q\". (The command
2559originally associated with \"q\" is not displayed to avoid
2560duplicates.)"
2561 :version "24.3"
2562 :group 'org-agenda-custom-commands
2563 :type '(repeat (list :tag "Rule"
2564 (string :tag " Agenda key")
2565 (string :tag "Replace by command")
2566 (repeat :tag "Available when"
2567 (choice
2568 (cons :tag "Condition"
2569 (choice
2570 (const :tag "In file" in-file)
2571 (const :tag "Not in file" not-in-file)
271672fa
BG
2572 (const :tag "In buffer" in-buffer)
2573 (const :tag "Not in buffer" not-in-buffer)
8223b1d2
BG
2574 (const :tag "In mode" in-mode)
2575 (const :tag "Not in mode" not-in-mode))
2576 (regexp))
2577 (function :tag "Custom function"))))))
2578
271672fa
BG
2579(defcustom org-agenda-max-entries nil
2580 "Maximum number of entries to display in an agenda.
2581This can be nil (no limit) or an integer or an alist of agenda
2582types with an associated number of entries to display in this
2583type."
2584 :version "24.4"
2585 :package-version '(Org . "8.0")
2586 :group 'org-agenda-custom-commands
2587 :type '(choice (symbol :tag "No limit" nil)
2588 (integer :tag "Max number of entries")
2589 (repeat
2590 (cons (choice :tag "Agenda type"
2591 (const agenda)
2592 (const todo)
2593 (const tags)
2594 (const search)
2595 (const timeline))
2596 (integer :tag "Max number of entries")))))
2597
2598(defcustom org-agenda-max-todos nil
2599 "Maximum number of TODOs to display in an agenda.
2600This can be nil (no limit) or an integer or an alist of agenda
2601types with an associated number of entries to display in this
2602type."
2603 :version "24.4"
2604 :package-version '(Org . "8.0")
2605 :group 'org-agenda-custom-commands
2606 :type '(choice (symbol :tag "No limit" nil)
2607 (integer :tag "Max number of entries")
2608 (repeat
2609 (cons (choice :tag "Agenda type"
2610 (const agenda)
2611 (const todo)
2612 (const tags)
2613 (const search)
2614 (const timeline))
2615 (integer :tag "Max number of entries")))))
2616
2617(defcustom org-agenda-max-tags nil
2618 "Maximum number of tagged entries to display in an agenda.
2619This can be nil (no limit) or an integer or an alist of agenda
2620types with an associated number of entries to display in this
2621type."
2622 :version "24.4"
2623 :package-version '(Org . "8.0")
2624 :group 'org-agenda-custom-commands
2625 :type '(choice (symbol :tag "No limit" nil)
2626 (integer :tag "Max number of entries")
2627 (repeat
2628 (cons (choice :tag "Agenda type"
2629 (const agenda)
2630 (const todo)
2631 (const tags)
2632 (const search)
2633 (const timeline))
2634 (integer :tag "Max number of entries")))))
2635
2636(defcustom org-agenda-max-effort nil
2637 "Maximum cumulated effort duration for the agenda.
2638This can be nil (no limit) or a number of minutes (as an integer)
2639or an alist of agenda types with an associated number of minutes
2640to limit entries to in this type."
2641 :version "24.4"
2642 :package-version '(Org . "8.0")
2643 :group 'org-agenda-custom-commands
2644 :type '(choice (symbol :tag "No limit" nil)
2645 (integer :tag "Max number of entries")
2646 (repeat
2647 (cons (choice :tag "Agenda type"
2648 (const agenda)
2649 (const todo)
2650 (const tags)
2651 (const search)
2652 (const timeline))
2653 (integer :tag "Max number of entries")))))
2654
8223b1d2
BG
2655(defvar org-keys nil)
2656(defvar org-match nil)
20908596 2657;;;###autoload
8223b1d2 2658(defun org-agenda (&optional arg org-keys restriction)
20908596
CD
2659 "Dispatch agenda commands to collect entries to the agenda buffer.
2660Prompts for a command to execute. Any prefix arg will be passed
2661on to the selected command. The default selections are:
2662
2663a Call `org-agenda-list' to display the agenda for current day or week.
2664t Call `org-todo-list' to display the global todo list.
2665T Call `org-todo-list' to display the global todo list, select only
2666 entries with a specific TODO keyword (the user gets a prompt).
2667m Call `org-tags-view' to display headlines with tags matching
2668 a condition (the user is prompted for the condition).
2669M Like `m', but select only TODO entries, no ordinary headlines.
2670L Create a timeline for the current buffer.
2671e Export views to associated files.
c8d0cf5c 2672s Search entries for keywords.
8223b1d2 2673S Search entries for keywords, only with TODO keywords.
8bfe682a 2674/ Multi occur across all agenda files and also files listed
c8d0cf5c
CD
2675 in `org-agenda-text-search-extra-files'.
2676< Restrict agenda commands to buffer, subtree, or region.
2677 Press several times to get the desired effect.
2678> Remove a previous restriction.
2679# List \"stuck\" projects.
2680! Configure what \"stuck\" means.
2681C Configure custom agenda commands.
20908596
CD
2682
2683More commands can be added by configuring the variable
2684`org-agenda-custom-commands'. In particular, specific tags and TODO keyword
2685searches can be pre-defined in this way.
2686
2687If the current buffer is in Org-mode and visiting a file, you can also
2688first press `<' once to indicate that the agenda should be temporarily
2689\(until the next use of \\[org-agenda]) restricted to the current file.
2690Pressing `<' twice means to restrict to the current subtree or region
2691\(if active)."
2692 (interactive "P")
2693 (catch 'exit
2694 (let* ((prefix-descriptions nil)
8223b1d2 2695 (org-agenda-buffer-name org-agenda-buffer-name)
54a0dee5
CD
2696 (org-agenda-window-setup (if (equal (buffer-name)
2697 org-agenda-buffer-name)
2698 'current-window
2699 org-agenda-window-setup))
20908596
CD
2700 (org-agenda-custom-commands-orig org-agenda-custom-commands)
2701 (org-agenda-custom-commands
2702 ;; normalize different versions
2703 (delq nil
2704 (mapcar
2705 (lambda (x)
2706 (cond ((stringp (cdr x))
2707 (push x prefix-descriptions)
2708 nil)
2709 ((stringp (nth 1 x)) x)
2710 ((not (nth 1 x)) (cons (car x) (cons "" (cddr x))))
2711 (t (cons (car x) (cons "" (cdr x))))))
2712 org-agenda-custom-commands)))
8223b1d2
BG
2713 (org-agenda-custom-commands
2714 (org-contextualize-keys
2715 org-agenda-custom-commands org-agenda-custom-commands-contexts))
20908596
CD
2716 (buf (current-buffer))
2717 (bfn (buffer-file-name (buffer-base-buffer)))
8223b1d2 2718 entry key type org-match lprops ans)
8d642074 2719 ;; Turn off restriction unless there is an overriding one,
20908596 2720 (unless org-agenda-overriding-restriction
8bfe682a 2721 (unless (org-bound-and-true-p org-agenda-keep-restricted-file-list)
8d642074
CD
2722 ;; There is a request to keep the file list in place
2723 (put 'org-agenda-files 'org-restrict nil))
20908596
CD
2724 (setq org-agenda-restrict nil)
2725 (move-marker org-agenda-restrict-begin nil)
2726 (move-marker org-agenda-restrict-end nil))
2727 ;; Delete old local properties
2728 (put 'org-agenda-redo-command 'org-lprops nil)
3ab2c837
BG
2729 ;; Delete previously set last-arguments
2730 (put 'org-agenda-redo-command 'last-args nil)
20908596
CD
2731 ;; Remember where this call originated
2732 (setq org-agenda-last-dispatch-buffer (current-buffer))
8223b1d2 2733 (unless org-keys
20908596 2734 (setq ans (org-agenda-get-restriction-and-command prefix-descriptions)
8223b1d2 2735 org-keys (car ans)
20908596 2736 restriction (cdr ans)))
8223b1d2
BG
2737 ;; If we have sticky agenda buffers, set a name for the buffer,
2738 ;; depending on the invoking keys. The user may still set this
2739 ;; as a command option, which will overwrite what we do here.
2740 (if org-agenda-sticky
2741 (setq org-agenda-buffer-name
2742 (format "*Org Agenda(%s)*" org-keys)))
8bfe682a 2743 ;; Establish the restriction, if any
20908596
CD
2744 (when (and (not org-agenda-overriding-restriction) restriction)
2745 (put 'org-agenda-files 'org-restrict (list bfn))
2746 (cond
2747 ((eq restriction 'region)
271672fa 2748 (setq org-agenda-restrict (current-buffer))
20908596
CD
2749 (move-marker org-agenda-restrict-begin (region-beginning))
2750 (move-marker org-agenda-restrict-end (region-end)))
2751 ((eq restriction 'subtree)
2752 (save-excursion
271672fa 2753 (setq org-agenda-restrict (current-buffer))
20908596
CD
2754 (org-back-to-heading t)
2755 (move-marker org-agenda-restrict-begin (point))
2756 (move-marker org-agenda-restrict-end
2757 (progn (org-end-of-subtree t)))))))
2758
20908596
CD
2759 ;; For example the todo list should not need it (but does...)
2760 (cond
8223b1d2 2761 ((setq entry (assoc org-keys org-agenda-custom-commands))
20908596
CD
2762 (if (or (symbolp (nth 2 entry)) (functionp (nth 2 entry)))
2763 (progn
8223b1d2 2764 (setq type (nth 2 entry) org-match (eval (nth 3 entry))
8bfe682a 2765 lprops (nth 4 entry))
8223b1d2
BG
2766 (if org-agenda-sticky
2767 (setq org-agenda-buffer-name
2768 (or (and (stringp org-match) (format "*Org Agenda(%s:%s)*" org-keys org-match))
2769 (format "*Org Agenda(%s)*" org-keys))))
20908596
CD
2770 (put 'org-agenda-redo-command 'org-lprops lprops)
2771 (cond
2772 ((eq type 'agenda)
2773 (org-let lprops '(org-agenda-list current-prefix-arg)))
271672fa
BG
2774 ((eq type 'agenda*)
2775 (org-let lprops '(org-agenda-list current-prefix-arg nil nil t)))
20908596
CD
2776 ((eq type 'alltodo)
2777 (org-let lprops '(org-todo-list current-prefix-arg)))
2778 ((eq type 'search)
8223b1d2 2779 (org-let lprops '(org-search-view current-prefix-arg org-match nil)))
20908596
CD
2780 ((eq type 'stuck)
2781 (org-let lprops '(org-agenda-list-stuck-projects
2782 current-prefix-arg)))
2783 ((eq type 'tags)
8223b1d2 2784 (org-let lprops '(org-tags-view current-prefix-arg org-match)))
20908596 2785 ((eq type 'tags-todo)
8223b1d2 2786 (org-let lprops '(org-tags-view '(4) org-match)))
20908596 2787 ((eq type 'todo)
8223b1d2 2788 (org-let lprops '(org-todo-list org-match)))
20908596
CD
2789 ((eq type 'tags-tree)
2790 (org-check-for-org-mode)
8223b1d2 2791 (org-let lprops '(org-match-sparse-tree current-prefix-arg org-match)))
20908596
CD
2792 ((eq type 'todo-tree)
2793 (org-check-for-org-mode)
2794 (org-let lprops
3ab2c837 2795 '(org-occur (concat "^" org-outline-regexp "[ \t]*"
8223b1d2 2796 (regexp-quote org-match) "\\>"))))
20908596
CD
2797 ((eq type 'occur-tree)
2798 (org-check-for-org-mode)
8223b1d2 2799 (org-let lprops '(org-occur org-match)))
20908596 2800 ((functionp type)
8223b1d2 2801 (org-let lprops '(funcall type org-match)))
20908596 2802 ((fboundp type)
8223b1d2 2803 (org-let lprops '(funcall type org-match)))
271672fa 2804 (t (user-error "Invalid custom agenda command type %s" type))))
3ab2c837 2805 (org-agenda-run-series (nth 1 entry) (cddr entry))))
8223b1d2 2806 ((equal org-keys "C")
20908596
CD
2807 (setq org-agenda-custom-commands org-agenda-custom-commands-orig)
2808 (customize-variable 'org-agenda-custom-commands))
8223b1d2
BG
2809 ((equal org-keys "a") (call-interactively 'org-agenda-list))
2810 ((equal org-keys "s") (call-interactively 'org-search-view))
2811 ((equal org-keys "S") (org-call-with-arg 'org-search-view (or arg '(4))))
2812 ((equal org-keys "t") (call-interactively 'org-todo-list))
2813 ((equal org-keys "T") (org-call-with-arg 'org-todo-list (or arg '(4))))
2814 ((equal org-keys "m") (call-interactively 'org-tags-view))
2815 ((equal org-keys "M") (org-call-with-arg 'org-tags-view (or arg '(4))))
2816 ((equal org-keys "e") (call-interactively 'org-store-agenda-views))
2817 ((equal org-keys "?") (org-tags-view nil "+FLAGGED")
8d642074
CD
2818 (org-add-hook
2819 'post-command-hook
2820 (lambda ()
2821 (unless (current-message)
2822 (let* ((m (org-agenda-get-any-marker))
2823 (note (and m (org-entry-get m "THEFLAGGINGNOTE"))))
2824 (when note
2825 (message (concat
2826 "FLAGGING-NOTE ([?] for more info): "
2827 (org-add-props
2828 (replace-regexp-in-string
2829 "\\\\n" "//"
2830 (copy-sequence note))
2831 nil 'face 'org-warning)))))))
2832 t t))
8223b1d2
BG
2833 ((equal org-keys "L")
2834 (unless (derived-mode-p 'org-mode)
271672fa 2835 (user-error "This is not an Org-mode file"))
20908596
CD
2836 (unless restriction
2837 (put 'org-agenda-files 'org-restrict (list bfn))
2838 (org-call-with-arg 'org-timeline arg)))
8223b1d2
BG
2839 ((equal org-keys "#") (call-interactively 'org-agenda-list-stuck-projects))
2840 ((equal org-keys "/") (call-interactively 'org-occur-in-agenda-files))
2841 ((equal org-keys "!") (customize-variable 'org-stuck-projects))
271672fa 2842 (t (user-error "Invalid agenda key"))))))
20908596 2843
666ffc7e
SM
2844(defvar org-agenda-multi)
2845
3ab2c837
BG
2846(defun org-agenda-append-agenda ()
2847 "Append another agenda view to the current one.
2848This function allows interactive building of block agendas.
2849Agenda views are separated by `org-agenda-block-separator'."
2850 (interactive)
8223b1d2 2851 (unless (derived-mode-p 'org-agenda-mode)
271672fa 2852 (user-error "Can only append from within agenda buffer"))
3ab2c837
BG
2853 (let ((org-agenda-multi t))
2854 (org-agenda)
8223b1d2
BG
2855 (widen)
2856 (org-agenda-finalize)
271672fa 2857 (setq buffer-read-only t)
8223b1d2 2858 (org-agenda-fit-window-to-buffer)))
3ab2c837 2859
20908596 2860(defun org-agenda-normalize-custom-commands (cmds)
271672fa 2861 "Normalize custom commands CMDS."
20908596
CD
2862 (delq nil
2863 (mapcar
2864 (lambda (x)
2865 (cond ((stringp (cdr x)) nil)
2866 ((stringp (nth 1 x)) x)
2867 ((not (nth 1 x)) (cons (car x) (cons "" (cddr x))))
2868 (t (cons (car x) (cons "" (cdr x))))))
2869 cmds)))
2870
2871(defun org-agenda-get-restriction-and-command (prefix-descriptions)
2872 "The user interface for selecting an agenda command."
2873 (catch 'exit
2874 (let* ((bfn (buffer-file-name (buffer-base-buffer)))
8223b1d2 2875 (restrict-ok (and bfn (derived-mode-p 'org-mode)))
20908596
CD
2876 (region-p (org-region-active-p))
2877 (custom org-agenda-custom-commands)
2878 (selstring "")
2879 restriction second-time
afe98dfa
CD
2880 c entry key type match prefixes rmheader header-end custom1 desc
2881 line lines left right n n1)
20908596
CD
2882 (save-window-excursion
2883 (delete-other-windows)
2884 (org-switch-to-buffer-other-window " *Agenda Commands*")
2885 (erase-buffer)
2886 (insert (eval-when-compile
2887 (let ((header
8223b1d2 2888 "Press key for an agenda command: < Buffer, subtree/region restriction
20908596
CD
2889-------------------------------- > Remove restriction
2890a Agenda for current week or day e Export agenda views
2891t List of all TODO entries T Entries with special TODO kwd
621f83e4 2892m Match a TAGS/PROP/TODO query M Like m, but only TODO entries
8223b1d2 2893s Search for keywords S Like s, but only TODO entries
20908596 2894L Timeline for current buffer # List stuck projects (!=configure)
8223b1d2
BG
2895/ Multi-occur C Configure custom agenda commands
2896? Find :FLAGGED: entries * Toggle sticky agenda views
20908596
CD
2897")
2898 (start 0))
2899 (while (string-match
2900 "\\(^\\| \\|(\\)\\(\\S-\\)\\( \\|=\\)"
2901 header start)
2902 (setq start (match-end 0))
2903 (add-text-properties (match-beginning 2) (match-end 2)
2904 '(face bold) header))
2905 header)))
c7cf0ebc 2906 (setq header-end (point-marker))
20908596
CD
2907 (while t
2908 (setq custom1 custom)
2909 (when (eq rmheader t)
54a0dee5 2910 (org-goto-line 1)
20908596
CD
2911 (re-search-forward ":" nil t)
2912 (delete-region (match-end 0) (point-at-eol))
2913 (forward-char 1)
2914 (looking-at "-+")
2915 (delete-region (match-end 0) (point-at-eol))
2916 (move-marker header-end (match-end 0)))
2917 (goto-char header-end)
2918 (delete-region (point) (point-max))
afe98dfa
CD
2919
2920 ;; Produce all the lines that describe custom commands and prefixes
2921 (setq lines nil)
20908596
CD
2922 (while (setq entry (pop custom1))
2923 (setq key (car entry) desc (nth 1 entry)
54a0dee5
CD
2924 type (nth 2 entry)
2925 match (nth 3 entry))
20908596
CD
2926 (if (> (length key) 1)
2927 (add-to-list 'prefixes (string-to-char key))
afe98dfa
CD
2928 (setq line
2929 (format
2930 "%-4s%-14s"
2931 (org-add-props (copy-sequence key)
2932 '(face bold))
2933 (cond
2934 ((string-match "\\S-" desc) desc)
2935 ((eq type 'agenda) "Agenda for current week or day")
271672fa 2936 ((eq type 'agenda*) "Appointments for current week or day")
afe98dfa
CD
2937 ((eq type 'alltodo) "List of all TODO entries")
2938 ((eq type 'search) "Word search")
2939 ((eq type 'stuck) "List of stuck projects")
2940 ((eq type 'todo) "TODO keyword")
2941 ((eq type 'tags) "Tags query")
2942 ((eq type 'tags-todo) "Tags (TODO)")
2943 ((eq type 'tags-tree) "Tags tree")
2944 ((eq type 'todo-tree) "TODO kwd tree")
2945 ((eq type 'occur-tree) "Occur tree")
2946 ((functionp type) (if (symbolp type)
2947 (symbol-name type)
2948 "Lambda expression"))
2949 (t "???"))))
2950 (if org-agenda-menu-show-matcher
2951 (setq line
2952 (concat line ": "
2953 (cond
2954 ((stringp match)
2955 (setq match (copy-sequence match))
2956 (org-add-props match nil 'face 'org-warning))
8223b1d2
BG
2957 ((listp type)
2958 (format "set of %d commands" (length type))))))
afe98dfa
CD
2959 (if (org-string-nw-p match)
2960 (add-text-properties
2961 0 (length line) (list 'help-echo
8223b1d2 2962 (concat "Matcher: " match)) line)))
afe98dfa
CD
2963 (push line lines)))
2964 (setq lines (nreverse lines))
20908596
CD
2965 (when prefixes
2966 (mapc (lambda (x)
afe98dfa
CD
2967 (push
2968 (format "%s %s"
20908596 2969 (org-add-props (char-to-string x)
afe98dfa
CD
2970 nil 'face 'bold)
2971 (or (cdr (assoc (concat selstring
2972 (char-to-string x))
20908596 2973 prefix-descriptions))
afe98dfa
CD
2974 "Prefix key"))
2975 lines))
20908596 2976 prefixes))
afe98dfa
CD
2977
2978 ;; Check if we should display in two columns
8223b1d2 2979 (if org-agenda-menu-two-columns
afe98dfa
CD
2980 (progn
2981 (setq n (length lines)
2982 n1 (+ (/ n 2) (mod n 2))
2983 right (nthcdr n1 lines)
2984 left (copy-sequence lines))
2985 (setcdr (nthcdr (1- n1) left) nil))
2986 (setq left lines right nil))
2987 (while left
2988 (insert "\n" (pop left))
2989 (when right
2990 (if (< (current-column) 40)
2991 (move-to-column 40 t)
2992 (insert " "))
2993 (insert (pop right))))
2994
2995 ;; Make the window the right size
20908596 2996 (goto-char (point-min))
93b62de8
CD
2997 (if second-time
2998 (if (not (pos-visible-in-window-p (point-max)))
2999 (org-fit-window-to-buffer))
3000 (setq second-time t)
3001 (org-fit-window-to-buffer))
afe98dfa
CD
3002
3003 ;; Ask for selection
20908596
CD
3004 (message "Press key for agenda command%s:"
3005 (if (or restrict-ok org-agenda-overriding-restriction)
3006 (if org-agenda-overriding-restriction
3007 " (restriction lock active)"
3008 (if restriction
3009 (format " (restricted to %s)" restriction)
3010 " (unrestricted)"))
3011 ""))
3012 (setq c (read-char-exclusive))
3013 (message "")
3014 (cond
3015 ((assoc (char-to-string c) custom)
3016 (setq selstring (concat selstring (char-to-string c)))
3017 (throw 'exit (cons selstring restriction)))
3018 ((memq c prefixes)
3019 (setq selstring (concat selstring (char-to-string c))
3020 prefixes nil
3021 rmheader (or rmheader t)
3022 custom (delq nil (mapcar
3023 (lambda (x)
3024 (if (or (= (length (car x)) 1)
3025 (/= (string-to-char (car x)) c))
3026 nil
3027 (cons (substring (car x) 1) (cdr x))))
3028 custom))))
8223b1d2
BG
3029 ((eq c ?*)
3030 (call-interactively 'org-toggle-sticky-agenda)
3031 (sit-for 2))
20908596
CD
3032 ((and (not restrict-ok) (memq c '(?1 ?0 ?<)))
3033 (message "Restriction is only possible in Org-mode buffers")
3034 (ding) (sit-for 1))
3035 ((eq c ?1)
3036 (org-agenda-remove-restriction-lock 'noupdate)
3037 (setq restriction 'buffer))
3038 ((eq c ?0)
3039 (org-agenda-remove-restriction-lock 'noupdate)
3040 (setq restriction (if region-p 'region 'subtree)))
3041 ((eq c ?<)
3042 (org-agenda-remove-restriction-lock 'noupdate)
3043 (setq restriction
3044 (cond
3045 ((eq restriction 'buffer)
3046 (if region-p 'region 'subtree))
3047 ((memq restriction '(subtree region))
3048 nil)
3049 (t 'buffer))))
3050 ((eq c ?>)
3051 (org-agenda-remove-restriction-lock 'noupdate)
3052 (setq restriction nil))
8223b1d2 3053 ((and (equal selstring "") (memq c '(?s ?S ?a ?t ?m ?L ?C ?e ?T ?M ?# ?! ?/ ??)))
20908596
CD
3054 (throw 'exit (cons (setq selstring (char-to-string c)) restriction)))
3055 ((and (> (length selstring) 0) (eq c ?\d))
3056 (delete-window)
3057 (org-agenda-get-restriction-and-command prefix-descriptions))
3058
3059 ((equal c ?q) (error "Abort"))
271672fa 3060 (t (user-error "Invalid key %c" c))))))))
20908596 3061
8223b1d2
BG
3062(defun org-agenda-fit-window-to-buffer ()
3063 "Fit the window to the buffer size."
3064 (and (memq org-agenda-window-setup '(reorganize-frame))
3065 (fboundp 'fit-window-to-buffer)
3066 (org-fit-window-to-buffer
3067 nil
3068 (floor (* (frame-height) (cdr org-agenda-window-frame-fractions)))
3069 (floor (* (frame-height) (car org-agenda-window-frame-fractions))))))
3070
3071(defvar org-cmd nil)
3072(defvar org-agenda-overriding-cmd nil)
3073(defvar org-agenda-overriding-arguments nil)
3074(defvar org-agenda-overriding-cmd-arguments nil)
3ab2c837 3075(defun org-agenda-run-series (name series)
271672fa 3076 "Run agenda NAME as a SERIES of agenda commands."
8223b1d2
BG
3077 (org-let (nth 1 series) '(org-agenda-prepare name))
3078 ;; We need to reset agenda markers here, because when constructing a
3079 ;; block agenda, the individual blocks do not do that.
3080 (org-agenda-reset-markers)
20908596 3081 (let* ((org-agenda-multi t)
3ab2c837 3082 (redo (list 'org-agenda-run-series name (list 'quote series)))
20908596
CD
3083 (cmds (car series))
3084 (gprops (nth 1 series))
3085 match ;; The byte compiler incorrectly complains about this. Keep it!
8223b1d2
BG
3086 org-cmd type lprops)
3087 (while (setq org-cmd (pop cmds))
3088 (setq type (car org-cmd)
3089 match (eval (nth 1 org-cmd))
3090 lprops (nth 2 org-cmd))
3091 (let ((org-agenda-overriding-arguments
3092 (if (eq org-agenda-overriding-cmd org-cmd)
3093 (or org-agenda-overriding-arguments
3094 org-agenda-overriding-cmd-arguments))))
3095 (cond
3096 ((eq type 'agenda)
3097 (org-let2 gprops lprops
3098 '(call-interactively 'org-agenda-list)))
271672fa
BG
3099 ((eq type 'agenda*)
3100 (org-let2 gprops lprops
3101 '(funcall 'org-agenda-list nil nil t)))
8223b1d2
BG
3102 ((eq type 'alltodo)
3103 (org-let2 gprops lprops
3104 '(call-interactively 'org-todo-list)))
3105 ((eq type 'search)
3106 (org-let2 gprops lprops
3107 '(org-search-view current-prefix-arg match nil)))
3108 ((eq type 'stuck)
3109 (org-let2 gprops lprops
3110 '(call-interactively 'org-agenda-list-stuck-projects)))
3111 ((eq type 'tags)
3112 (org-let2 gprops lprops
3113 '(org-tags-view current-prefix-arg match)))
3114 ((eq type 'tags-todo)
3115 (org-let2 gprops lprops
3116 '(org-tags-view '(4) match)))
3117 ((eq type 'todo)
3118 (org-let2 gprops lprops
3119 '(org-todo-list match)))
3120 ((fboundp type)
3121 (org-let2 gprops lprops
3122 '(funcall type match)))
3123 (t (error "Invalid type in command series")))))
20908596 3124 (widen)
8223b1d2
BG
3125 (let ((inhibit-read-only t))
3126 (add-text-properties (point-min) (point-max)
735135f9 3127 `(org-series t org-series-redo-cmd ,redo)))
20908596
CD
3128 (setq org-agenda-redo-command redo)
3129 (goto-char (point-min)))
8223b1d2
BG
3130 (org-agenda-fit-window-to-buffer)
3131 (org-let (nth 1 series) '(org-agenda-finalize)))
20908596
CD
3132
3133;;;###autoload
3134(defmacro org-batch-agenda (cmd-key &rest parameters)
3135 "Run an agenda command in batch mode and send the result to STDOUT.
3136If CMD-KEY is a string of length 1, it is used as a key in
3137`org-agenda-custom-commands' and triggers this command. If it is a
3138longer string it is used as a tags/todo match string.
86fbb8ca 3139Parameters are alternating variable names and values that will be bound
20908596 3140before running the agenda command."
e66ba1df 3141 (org-eval-in-environment (org-make-parameter-alist parameters)
271672fa
BG
3142 (let (org-agenda-sticky)
3143 (if (> (length cmd-key) 2)
3144 (org-tags-view nil cmd-key)
3145 (org-agenda nil cmd-key))))
e66ba1df
BG
3146 (set-buffer org-agenda-buffer-name)
3147 (princ (buffer-string)))
bdebdb64 3148
20908596
CD
3149(defvar org-agenda-info nil)
3150
3151;;;###autoload
3152(defmacro org-batch-agenda-csv (cmd-key &rest parameters)
3153 "Run an agenda command in batch mode and send the result to STDOUT.
3154If CMD-KEY is a string of length 1, it is used as a key in
3155`org-agenda-custom-commands' and triggers this command. If it is a
3156longer string it is used as a tags/todo match string.
86fbb8ca 3157Parameters are alternating variable names and values that will be bound
20908596
CD
3158before running the agenda command.
3159
3160The output gives a line for each selected agenda item. Each
3161item is a list of comma-separated values, like this:
3162
3163category,head,type,todo,tags,date,time,extra,priority-l,priority-n
3164
3165category The category of the item
3166head The headline, without TODO kwd, TAGS and PRIORITY
3167type The type of the agenda entry, can be
3168 todo selected in TODO match
3169 tagsmatch selected in tags match
3170 diary imported from diary
3171 deadline a deadline on given date
3172 scheduled scheduled on given date
3173 timestamp entry has timestamp on given date
3174 closed entry was closed on given date
3175 upcoming-deadline warning about deadline
3176 past-scheduled forwarded scheduled item
3177 block entry has date block including g. date
3178todo The todo keyword, if any
3179tags All tags including inherited ones, separated by colons
3180date The relevant date, like 2007-2-14
3181time The time, like 15:00-16:50
3182extra Sting with extra planning info
3183priority-l The priority letter if any was given
3184priority-n The computed numerical priority
3185agenda-day The day in the agenda where this is listed"
e66ba1df
BG
3186 (org-eval-in-environment (append '((org-agenda-remove-tags t))
3187 (org-make-parameter-alist parameters))
20908596 3188 (if (> (length cmd-key) 2)
e66ba1df
BG
3189 (org-tags-view nil cmd-key)
3190 (org-agenda nil cmd-key)))
3191 (set-buffer org-agenda-buffer-name)
3192 (let* ((lines (org-split-string (buffer-string) "\n"))
3193 line)
3194 (while (setq line (pop lines))
3195 (catch 'next
3196 (if (not (get-text-property 0 'org-category line)) (throw 'next nil))
3197 (setq org-agenda-info
3198 (org-fix-agenda-info (text-properties-at 0 line)))
3199 (princ
3200 (mapconcat 'org-agenda-export-csv-mapper
3201 '(org-category txt type todo tags date time extra
3202 priority-letter priority agenda-day)
3203 ","))
3204 (princ "\n")))))
bdebdb64 3205
20908596 3206(defun org-fix-agenda-info (props)
86fbb8ca
CD
3207 "Make sure all properties on an agenda item have a canonical form.
3208This ensures the export commands can easily use it."
20908596
CD
3209 (let (tmp re)
3210 (when (setq tmp (plist-get props 'tags))
3211 (setq props (plist-put props 'tags (mapconcat 'identity tmp ":"))))
3212 (when (setq tmp (plist-get props 'date))
3213 (if (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
3214 (let ((calendar-date-display-form '(year "-" month "-" day)))
3215 '((format "%4d, %9s %2s, %4s" dayname monthname day year))
3216
3217 (setq tmp (calendar-date-string tmp)))
3218 (setq props (plist-put props 'date tmp)))
3219 (when (setq tmp (plist-get props 'day))
3220 (if (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
3221 (let ((calendar-date-display-form '(year "-" month "-" day)))
3222 (setq tmp (calendar-date-string tmp)))
3223 (setq props (plist-put props 'day tmp))
3224 (setq props (plist-put props 'agenda-day tmp)))
3225 (when (setq tmp (plist-get props 'txt))
3226 (when (string-match "\\[#\\([A-Z0-9]\\)\\] ?" tmp)
3227 (plist-put props 'priority-letter (match-string 1 tmp))
3228 (setq tmp (replace-match "" t t tmp)))
3229 (when (and (setq re (plist-get props 'org-todo-regexp))
3230 (setq re (concat "\\`\\.*" re " ?"))
3231 (string-match re tmp))
3232 (plist-put props 'todo (match-string 1 tmp))
3233 (setq tmp (replace-match "" t t tmp)))
3234 (plist-put props 'txt tmp)))
3235 props)
3236
3237(defun org-agenda-export-csv-mapper (prop)
3238 (let ((res (plist-get org-agenda-info prop)))
3239 (setq res
3240 (cond
3241 ((not res) "")
3242 ((stringp res) res)
3243 (t (prin1-to-string res))))
3244 (while (string-match "," res)
3245 (setq res (replace-match ";" t t res)))
3246 (org-trim res)))
3247
20908596
CD
3248;;;###autoload
3249(defun org-store-agenda-views (&rest parameters)
271672fa 3250 "Store agenda views."
20908596
CD
3251 (interactive)
3252 (eval (list 'org-batch-store-agenda-views)))
3253
20908596
CD
3254;;;###autoload
3255(defmacro org-batch-store-agenda-views (&rest parameters)
3256 "Run all custom agenda commands that have a file argument."
3257 (let ((cmds (org-agenda-normalize-custom-commands org-agenda-custom-commands))
3258 (pop-up-frames nil)
3259 (dir default-directory)
e66ba1df 3260 (pars (org-make-parameter-alist parameters))
8223b1d2 3261 cmd thiscmdkey thiscmdcmd match files opts cmd-or-set bufname)
20908596
CD
3262 (save-window-excursion
3263 (while cmds
3264 (setq cmd (pop cmds)
3265 thiscmdkey (car cmd)
8223b1d2
BG
3266 thiscmdcmd (cdr cmd)
3267 match (nth 2 thiscmdcmd)
3268 bufname (if org-agenda-sticky
3269 (or (and (stringp match)
3270 (format "*Org Agenda(%s:%s)*" thiscmdkey match))
3271 (format "*Org Agenda(%s)*" thiscmdkey))
3272 org-agenda-buffer-name)
2c3ad40d
CD
3273 cmd-or-set (nth 2 cmd)
3274 opts (nth (if (listp cmd-or-set) 3 4) cmd)
3275 files (nth (if (listp cmd-or-set) 4 5) cmd))
20908596
CD
3276 (if (stringp files) (setq files (list files)))
3277 (when files
e66ba1df
BG
3278 (org-eval-in-environment (append org-agenda-exporter-settings
3279 opts pars)
3280 (org-agenda nil thiscmdkey))
8223b1d2 3281 (set-buffer bufname)
20908596 3282 (while files
e66ba1df
BG
3283 (org-eval-in-environment (append org-agenda-exporter-settings
3284 opts pars)
8223b1d2
BG
3285 (org-agenda-write (expand-file-name (pop files) dir) nil t bufname)))
3286 (and (get-buffer bufname)
3287 (kill-buffer bufname)))))))
bdebdb64 3288
8223b1d2
BG
3289(defvar org-agenda-current-span nil
3290 "The current span used in the agenda view.") ; local variable in the agenda buffer
8d642074
CD
3291(defun org-agenda-mark-header-line (pos)
3292 "Mark the line at POS as an agenda structure header."
3293 (save-excursion
3294 (goto-char pos)
3295 (put-text-property (point-at-bol) (point-at-eol)
3296 'org-agenda-structural-header t)
3297 (when org-agenda-title-append
3298 (put-text-property (point-at-bol) (point-at-eol)
3299 'org-agenda-title-append org-agenda-title-append))))
3300
8223b1d2 3301(defvar org-mobile-creating-agendas) ; defined in org-mobile.el
e66ba1df 3302(defvar org-agenda-write-buffer-name "Agenda View")
8223b1d2 3303(defun org-agenda-write (file &optional open nosettings agenda-bufname)
20908596
CD
3304 "Write the current buffer (an agenda view) as a file.
3305Depending on the extension of the file name, plain text (.txt),
271672fa 3306HTML (.html or .htm), PDF (.pdf) or Postscript (.ps) is produced.
e66ba1df 3307If the extension is .ics, run icalendar export over all files used
20908596
CD
3308to construct the agenda and limit the export to entries listed in the
3309agenda now.
271672fa
BG
3310If the extension is .org, collect all subtrees corresponding to the
3311agenda entries and add them in an .org file.
8bfe682a 3312With prefix argument OPEN, open the new file immediately.
20908596
CD
3313If NOSETTINGS is given, do not scope the settings of
3314`org-agenda-exporter-settings' into the export commands. This is used when
3315the settings have already been scoped and we do not wish to overrule other,
8223b1d2
BG
3316higher priority settings.
3317If AGENDA-BUFFER-NAME, use this as the buffer name for the agenda to write."
c8d0cf5c 3318 (interactive "FWrite agenda to file: \nP")
271672fa
BG
3319 (if (or (not (file-writable-p file))
3320 (and (file-exists-p file)
3321 (if (org-called-interactively-p 'any)
3322 (not (y-or-n-p (format "Overwrite existing file %s? " file))))))
3323 (user-error "Cannot write agenda to file %s" file))
20908596 3324 (org-let (if nosettings nil org-agenda-exporter-settings)
afe98dfa 3325 '(save-excursion
20908596 3326 (save-window-excursion
93b62de8 3327 (org-agenda-mark-filtered-text)
271672fa 3328 (let ((bs (copy-sequence (buffer-string))) beg content)
93b62de8
CD
3329 (org-agenda-unmark-filtered-text)
3330 (with-temp-buffer
e66ba1df 3331 (rename-buffer org-agenda-write-buffer-name t)
afe98dfa 3332 (set-buffer-modified-p nil)
20908596 3333 (insert bs)
93b62de8
CD
3334 (org-agenda-remove-marked-text 'org-filtered)
3335 (while (setq beg (text-property-any (point-min) (point-max)
3336 'org-filtered t))
3337 (delete-region
3338 beg (or (next-single-property-change beg 'org-filtered)
3339 (point-max))))
c8d0cf5c 3340 (run-hooks 'org-agenda-before-write-hook)
93b62de8 3341 (cond
8bfe682a
CD
3342 ((org-bound-and-true-p org-mobile-creating-agendas)
3343 (org-mobile-write-agenda-for-mobile file))
271672fa
BG
3344 ((string-match "\\.org\\'" file)
3345 (let (content p m message-log-max)
3346 (goto-char (point-min))
3347 (while (setq p (next-single-property-change (point) 'org-hd-marker nil))
3348 (goto-char p)
3349 (setq m (get-text-property (point) 'org-hd-marker))
3350 (when m
3351 (push (save-excursion
3352 (set-buffer (marker-buffer m))
3353 (goto-char m)
3354 (org-copy-subtree 1 nil t t)
3355 org-subtree-clip)
3356 content)))
3357 (find-file file)
3358 (erase-buffer)
3359 (mapcar (lambda (s) (org-paste-subtree 1 s)) (reverse content))
3360 (write-file file)
3361 (kill-buffer (current-buffer))
3362 (message "Org file written to %s" file)))
93b62de8 3363 ((string-match "\\.html?\\'" file)
afe98dfa 3364 (require 'htmlize)
93b62de8 3365 (set-buffer (htmlize-buffer (current-buffer)))
8223b1d2 3366 (when org-agenda-export-html-style
93b62de8
CD
3367 ;; replace <style> section with org-agenda-export-html-style
3368 (goto-char (point-min))
3369 (kill-region (- (search-forward "<style") 6)
3370 (search-forward "</style>"))
3371 (insert org-agenda-export-html-style))
3372 (write-file file)
3373 (kill-buffer (current-buffer))
3374 (message "HTML written to %s" file))
3375 ((string-match "\\.ps\\'" file)
c8d0cf5c 3376 (require 'ps-print)
afe98dfa 3377 (ps-print-buffer-with-faces file)
e66ba1df 3378 (message "Postscript written to %s" file))
c8d0cf5c
CD
3379 ((string-match "\\.pdf\\'" file)
3380 (require 'ps-print)
afe98dfa
CD
3381 (ps-print-buffer-with-faces
3382 (concat (file-name-sans-extension file) ".ps"))
c8d0cf5c
CD
3383 (call-process "ps2pdf" nil nil nil
3384 (expand-file-name
3385 (concat (file-name-sans-extension file) ".ps"))
3386 (expand-file-name file))
afe98dfa 3387 (delete-file (concat (file-name-sans-extension file) ".ps"))
c8d0cf5c 3388 (message "PDF written to %s" file))
93b62de8 3389 ((string-match "\\.ics\\'" file)
271672fa
BG
3390 (require 'ox-icalendar)
3391 (org-icalendar-export-current-agenda (expand-file-name file)))
93b62de8
CD
3392 (t
3393 (let ((bs (buffer-string)))
3394 (find-file file)
3395 (erase-buffer)
3396 (insert bs)
3397 (save-buffer 0)
3398 (kill-buffer (current-buffer))
3399 (message "Plain text written to %s" file))))))))
8223b1d2 3400 (set-buffer (or agenda-bufname
c7cf0ebc 3401 (and (org-called-interactively-p 'any) (buffer-name))
8223b1d2 3402 org-agenda-buffer-name)))
c8d0cf5c
CD
3403 (when open (org-open-file file)))
3404
e66ba1df
BG
3405(defvar org-agenda-tag-filter-overlays nil)
3406(defvar org-agenda-cat-filter-overlays nil)
271672fa 3407(defvar org-agenda-re-filter-overlays nil)
93b62de8
CD
3408
3409(defun org-agenda-mark-filtered-text ()
3410 "Mark all text hidden by filtering with a text property."
3411 (let ((inhibit-read-only t))
3412 (mapc
3413 (lambda (o)
86fbb8ca 3414 (when (equal (overlay-buffer o) (current-buffer))
93b62de8 3415 (put-text-property
86fbb8ca 3416 (overlay-start o) (overlay-end o)
93b62de8 3417 'org-filtered t)))
e66ba1df 3418 (append org-agenda-tag-filter-overlays
271672fa
BG
3419 org-agenda-cat-filter-overlays
3420 org-agenda-re-filter-overlays))))
93b62de8
CD
3421
3422(defun org-agenda-unmark-filtered-text ()
3423 "Remove the filtering text property."
3424 (let ((inhibit-read-only t))
3425 (remove-text-properties (point-min) (point-max) '(org-filtered t))))
3426
3427(defun org-agenda-remove-marked-text (property &optional value)
3428 "Delete all text marked with VALUE of PROPERTY.
3429VALUE defaults to t."
3430 (let (beg)
3431 (setq value (or value t))
3432 (while (setq beg (text-property-any (point-min) (point-max)
3433 property value))
3434 (delete-region
3435 beg (or (next-single-property-change beg 'org-filtered)
3436 (point-max))))))
20908596 3437
c8d0cf5c
CD
3438(defun org-agenda-add-entry-text ()
3439 "Add entry text to agenda lines.
3440This will add a maximum of `org-agenda-add-entry-text-maxlines' lines of the
3441entry text following headings shown in the agenda.
3442Drawers will be excluded, also the line with scheduling/deadline info."
8bfe682a
CD
3443 (when (and (> org-agenda-add-entry-text-maxlines 0)
3444 (not (org-bound-and-true-p org-mobile-creating-agendas)))
54a0dee5 3445 (let (m txt)
c8d0cf5c
CD
3446 (goto-char (point-min))
3447 (while (not (eobp))
8d642074 3448 (if (not (setq m (org-get-at-bol 'org-hd-marker)))
c8d0cf5c 3449 (beginning-of-line 2)
54a0dee5 3450 (setq txt (org-agenda-get-some-entry-text
8d642074 3451 m org-agenda-add-entry-text-maxlines " > "))
c8d0cf5c 3452 (end-of-line 1)
afe98dfa
CD
3453 (if (string-match "\\S-" txt)
3454 (insert "\n" txt)
3455 (or (eobp) (forward-char 1))))))))
c8d0cf5c 3456
8d642074
CD
3457(defun org-agenda-get-some-entry-text (marker n-lines &optional indent
3458 &rest keep)
54a0dee5 3459 "Extract entry text from MARKER, at most N-LINES lines.
8d642074
CD
3460This will ignore drawers etc, just get the text.
3461If INDENT is given, prefix every line with this string. If KEEP is
8bfe682a 3462given, it is a list of symbols, defining stuff that should not be
8d642074 3463removed from the entry content. Currently only `planning' is allowed here."
54a0dee5
CD
3464 (let (txt drawer-re kwd-time-re ind)
3465 (save-excursion
3466 (with-current-buffer (marker-buffer marker)
8223b1d2 3467 (if (not (derived-mode-p 'org-mode))
54a0dee5
CD
3468 (setq txt "")
3469 (save-excursion
3470 (save-restriction
3471 (widen)
3472 (goto-char marker)
8d642074 3473 (end-of-line 1)
54a0dee5 3474 (setq txt (buffer-substring
8d642074 3475 (min (1+ (point)) (point-max))
54a0dee5
CD
3476 (progn (outline-next-heading) (point)))
3477 drawer-re org-drawer-regexp
3478 kwd-time-re (concat "^[ \t]*" org-keyword-time-regexp
3479 ".*\n?"))
3480 (with-temp-buffer
3481 (insert txt)
3482 (when org-agenda-add-entry-text-descriptive-links
3483 (goto-char (point-min))
3484 (while (org-activate-bracket-links (point-max))
3485 (add-text-properties (match-beginning 0) (match-end 0)
3486 '(face org-link))))
3487 (goto-char (point-min))
3488 (while (re-search-forward org-bracket-link-regexp (point-max) t)
3489 (set-text-properties (match-beginning 0) (match-end 0)
3490 nil))
3491 (goto-char (point-min))
3492 (while (re-search-forward drawer-re nil t)
3493 (delete-region
3494 (match-beginning 0)
3495 (progn (re-search-forward
3496 "^[ \t]*:END:.*\n?" nil 'move)
3497 (point))))
8d642074
CD
3498 (unless (member 'planning keep)
3499 (goto-char (point-min))
3500 (while (re-search-forward kwd-time-re nil t)
3501 (replace-match "")))
54a0dee5 3502 (goto-char (point-min))
8d642074
CD
3503 (when org-agenda-entry-text-exclude-regexps
3504 (let ((re-list org-agenda-entry-text-exclude-regexps) re)
3505 (while (setq re (pop re-list))
3506 (goto-char (point-min))
3507 (while (re-search-forward re nil t)
3508 (replace-match "")))))
3509 (goto-char (point-max))
3510 (skip-chars-backward " \t\n")
3511 (if (looking-at "[ \t\n]+\\'") (replace-match ""))
3512
3513 ;; find and remove min common indentation
54a0dee5
CD
3514 (goto-char (point-min))
3515 (untabify (point-min) (point-max))
3516 (setq ind (org-get-indentation))
3517 (while (not (eobp))
3518 (unless (looking-at "[ \t]*$")
3519 (setq ind (min ind (org-get-indentation))))
3520 (beginning-of-line 2))
3521 (goto-char (point-min))
3522 (while (not (eobp))
3523 (unless (looking-at "[ \t]*$")
3524 (move-to-column ind)
3525 (delete-region (point-at-bol) (point)))
3526 (beginning-of-line 2))
8d642074
CD
3527
3528 (run-hooks 'org-agenda-entry-text-cleanup-hook)
3529
54a0dee5 3530 (goto-char (point-min))
8d642074
CD
3531 (when indent
3532 (while (and (not (eobp)) (re-search-forward "^" nil t))
3533 (replace-match indent t t)))
54a0dee5
CD
3534 (goto-char (point-min))
3535 (while (looking-at "[ \t]*\n") (replace-match ""))
3536 (goto-char (point-max))
3537 (when (> (org-current-line)
3538 n-lines)
3539 (org-goto-line (1+ n-lines))
3540 (backward-char 1))
3541 (setq txt (buffer-substring (point-min) (point)))))))))
3542 txt))
3543
20908596 3544(defun org-check-for-org-mode ()
e66ba1df 3545 "Make sure current buffer is in org-mode. Error if not."
8223b1d2 3546 (or (derived-mode-p 'org-mode)
f924a367 3547 (error "Cannot execute org-mode agenda command on buffer in %s"
20908596
CD
3548 major-mode)))
3549
20908596
CD
3550;;; Agenda prepare and finalize
3551
33306645 3552(defvar org-agenda-multi nil) ; dynamically scoped
8223b1d2 3553(defvar org-agenda-pre-window-conf nil)
20908596
CD
3554(defvar org-agenda-columns-active nil)
3555(defvar org-agenda-name nil)
e66ba1df
BG
3556(defvar org-agenda-tag-filter nil)
3557(defvar org-agenda-category-filter nil)
271672fa
BG
3558(defvar org-agenda-regexp-filter nil)
3559(defvar org-agenda-top-headline-filter nil)
e66ba1df
BG
3560(defvar org-agenda-tag-filter-while-redo nil)
3561(defvar org-agenda-tag-filter-preset nil
c8d0cf5c 3562 "A preset of the tags filter used for secondary agenda filtering.
86fbb8ca 3563This must be a list of strings, each string must be a single tag preceded
c8d0cf5c
CD
3564by \"+\" or \"-\".
3565This variable should not be set directly, but agenda custom commands can
afe98dfa
CD
3566bind it in the options section. The preset filter is a global property of
3567the entire agenda view. In a block agenda, it will not work reliably to
3568define a filter for one of the individual blocks. You need to set it in
3569the global options and expect it to be applied to the entire view.")
c8d0cf5c 3570
e66ba1df 3571(defvar org-agenda-category-filter-preset nil
27e428e7 3572 "A preset of the category filter used for secondary agenda filtering.
e66ba1df
BG
3573This must be a list of strings, each string must be a single category
3574preceded by \"+\" or \"-\".
3575This variable should not be set directly, but agenda custom commands can
3576bind it in the options section. The preset filter is a global property of
3577the entire agenda view. In a block agenda, it will not work reliably to
3578define a filter for one of the individual blocks. You need to set it in
3579the global options and expect it to be applied to the entire view.")
3580
271672fa
BG
3581(defvar org-agenda-regexp-filter-preset nil
3582 "A preset of the regexp filter used for secondary agenda filtering.
30cb51f1 3583This must be a list of strings, each string must be a single regexp
271672fa
BG
3584preceded by \"+\" or \"-\".
3585This variable should not be set directly, but agenda custom commands can
3586bind it in the options section. The preset filter is a global property of
3587the entire agenda view. In a block agenda, it will not work reliably to
3588define a filter for one of the individual blocks. You need to set it in
3589the global options and expect it to be applied to the entire view.")
8223b1d2
BG
3590
3591(defun org-agenda-use-sticky-p ()
3592 "Return non-nil if an agenda buffer named
3593`org-agenda-buffer-name' exists and should be shown instead of
3594generating a new one."
3595 (and
3596 ;; turned off by user
3597 org-agenda-sticky
3598 ;; For multi-agenda buffer already exists
3599 (not org-agenda-multi)
3600 ;; buffer found
3601 (get-buffer org-agenda-buffer-name)
3602 ;; C-u parameter is same as last call
3603 (with-current-buffer (get-buffer org-agenda-buffer-name)
3604 (and
3605 (equal current-prefix-arg
3606 org-agenda-last-prefix-arg)
3607 ;; In case user turned stickiness on, while having existing
3608 ;; Agenda buffer active, don't reuse that buffer, because it
3609 ;; does not have org variables local
3610 org-agenda-this-buffer-is-sticky))))
3611
3612(defun org-agenda-prepare-window (abuf)
3613 "Setup agenda buffer in the window."
3614 (let* ((awin (get-buffer-window abuf))
3615 wconf)
3616 (cond
3617 ((equal (current-buffer) abuf) nil)
3618 (awin (select-window awin))
3619 ((not (setq wconf (current-window-configuration))))
3620 ((equal org-agenda-window-setup 'current-window)
3621 (org-pop-to-buffer-same-window abuf))
3622 ((equal org-agenda-window-setup 'other-window)
3623 (org-switch-to-buffer-other-window abuf))
3624 ((equal org-agenda-window-setup 'other-frame)
3625 (switch-to-buffer-other-frame abuf))
3626 ((equal org-agenda-window-setup 'reorganize-frame)
3627 (delete-other-windows)
3628 (org-switch-to-buffer-other-window abuf)))
3629 ;; additional test in case agenda is invoked from within agenda
3630 ;; buffer via elisp link
3631 (unless (equal (current-buffer) abuf)
3632 (org-pop-to-buffer-same-window abuf))
3633 (setq org-agenda-pre-window-conf
3634 (or org-agenda-pre-window-conf wconf))))
3635
3636(defun org-agenda-prepare (&optional name)
3637 (if (org-agenda-use-sticky-p)
20908596 3638 (progn
8223b1d2
BG
3639 ;; Popup existing buffer
3640 (org-agenda-prepare-window (get-buffer org-agenda-buffer-name))
3641 (message "Sticky Agenda buffer, use `r' to refresh")
3642 (or org-agenda-multi (org-agenda-fit-window-to-buffer))
3643 (throw 'exit "Sticky Agenda buffer, use `r' to refresh"))
3644 (setq org-todo-keywords-for-agenda nil)
3645 (setq org-drawers-for-agenda nil)
3646 (unless org-agenda-persistent-filter
3647 (setq org-agenda-tag-filter nil
271672fa
BG
3648 org-agenda-category-filter nil
3649 org-agenda-regexp-filter nil))
8223b1d2
BG
3650 (put 'org-agenda-tag-filter :preset-filter
3651 org-agenda-tag-filter-preset)
3652 (put 'org-agenda-category-filter :preset-filter
3653 org-agenda-category-filter-preset)
271672fa
BG
3654 (put 'org-agenda-regexp-filter :preset-filter
3655 org-agenda-regexp-filter-preset)
8223b1d2
BG
3656 (if org-agenda-multi
3657 (progn
3658 (setq buffer-read-only nil)
3659 (goto-char (point-max))
3660 (unless (or (bobp) org-agenda-compact-blocks
3661 (not org-agenda-block-separator))
3662 (insert "\n"
3663 (if (stringp org-agenda-block-separator)
3664 org-agenda-block-separator
3665 (make-string (window-width) org-agenda-block-separator))
3666 "\n"))
3667 (narrow-to-region (point) (point-max)))
3668 (setq org-done-keywords-for-agenda nil)
3669
3670 ;; Setting any org variables that are in org-agenda-local-vars
3671 ;; list need to be done after the prepare call
3672 (org-agenda-prepare-window (get-buffer-create org-agenda-buffer-name))
3673 (setq buffer-read-only nil)
3674 (org-agenda-reset-markers)
3675 (let ((inhibit-read-only t)) (erase-buffer))
3676 (org-agenda-mode)
3677 (setq org-agenda-buffer (current-buffer))
3678 (setq org-agenda-contributing-files nil)
3679 (setq org-agenda-columns-active nil)
3680 (org-agenda-prepare-buffers (org-agenda-files nil 'ifmode))
3681 (setq org-todo-keywords-for-agenda
3682 (org-uniquify org-todo-keywords-for-agenda))
3683 (setq org-done-keywords-for-agenda
3684 (org-uniquify org-done-keywords-for-agenda))
3685 (setq org-drawers-for-agenda (org-uniquify org-drawers-for-agenda))
3686 (setq org-agenda-last-prefix-arg current-prefix-arg)
3687 (setq org-agenda-this-buffer-name org-agenda-buffer-name)
3688 (and name (not org-agenda-name)
3689 (org-set-local 'org-agenda-name name)))
3690 (setq buffer-read-only nil)))
3691
3692(defvar org-agenda-overriding-columns-format) ; From org-colview.el
3693(defun org-agenda-finalize ()
20908596
CD
3694 "Finishing touch for the agenda buffer, called just before displaying it."
3695 (unless org-agenda-multi
3696 (save-excursion
3697 (let ((inhibit-read-only t))
3698 (goto-char (point-min))
c7cf0ebc
BG
3699 (save-excursion
3700 (while (org-activate-bracket-links (point-max))
3701 (add-text-properties (match-beginning 0) (match-end 0)
3702 '(face org-link))))
3703 (save-excursion
3704 (while (org-activate-plain-links (point-max))
3705 (add-text-properties (match-beginning 0) (match-end 0)
3706 '(face org-link))))
3707 (unless (eq org-agenda-remove-tags t)
3708 (org-agenda-align-tags))
20908596 3709 (unless org-agenda-with-colors
2e3c2398
BG
3710 (remove-text-properties (point-min) (point-max) '(face nil)))
3711 (if (and (boundp 'org-agenda-overriding-columns-format)
3712 org-agenda-overriding-columns-format)
3713 (org-set-local 'org-agenda-overriding-columns-format
3714 org-agenda-overriding-columns-format))
3715 (if (and (boundp 'org-agenda-view-columns-initially)
3716 org-agenda-view-columns-initially)
3717 (org-agenda-columns))
3718 (when org-agenda-fontify-priorities
3719 (org-agenda-fontify-priorities))
3720 (when (and org-agenda-dim-blocked-tasks org-blocker-hook)
3721 (org-agenda-dim-blocked-tasks))
30cb51f1 3722 (org-agenda-mark-clocking-task)
2e3c2398
BG
3723 (when org-agenda-entry-text-mode
3724 (org-agenda-entry-text-hide)
3725 (org-agenda-entry-text-show))
3726 (if (and (functionp 'org-habit-insert-consistency-graphs)
3727 (save-excursion (next-single-property-change (point-min) 'org-habit-p)))
3728 (org-habit-insert-consistency-graphs))
3729 (setq org-agenda-type (org-get-at-bol 'org-agenda-type))
a89c8ef0
BG
3730 (unless (or (eq org-agenda-show-inherited-tags 'always)
3731 (and (listp org-agenda-show-inherited-tags)
3732 (memq org-agenda-type org-agenda-show-inherited-tags))
3733 (and (eq org-agenda-show-inherited-tags t)
3734 (or (eq org-agenda-use-tag-inheritance t)
3735 (and (listp org-agenda-use-tag-inheritance)
3736 (not (memq org-agenda-type
3737 org-agenda-use-tag-inheritance))))))
2e3c2398
BG
3738 (let (mrk)
3739 (save-excursion
3740 (goto-char (point-min))
3741 (while (equal (forward-line) 0)
3742 (when (setq mrk (or (get-text-property (point) 'org-hd-marker)
3743 (get-text-property (point) 'org-hd-marker)))
3744 (put-text-property (point-at-bol) (point-at-eol)
3745 'tags (org-with-point-at mrk
3746 (delete-dups
3747 (mapcar 'downcase (org-get-tags-at))))))))))
3748 (run-hooks 'org-agenda-finalize-hook)
30cb51f1 3749 (when org-agenda-tag-filter
2e3c2398 3750 (org-agenda-filter-apply org-agenda-tag-filter 'tag))
30cb51f1
BG
3751 (when (get 'org-agenda-tag-filter :preset-filter)
3752 (org-agenda-filter-apply
3753 (get 'org-agenda-tag-filter :preset-filter) 'tag))
3754 (when org-agenda-category-filter
2e3c2398 3755 (org-agenda-filter-apply org-agenda-category-filter 'category))
30cb51f1
BG
3756 (when (get 'org-agenda-category-filter :preset-filter)
3757 (org-agenda-filter-apply
3758 (get 'org-agenda-category-filter :preset-filter) 'category))
3759 (when org-agenda-regexp-filter
271672fa 3760 (org-agenda-filter-apply org-agenda-regexp-filter 'regexp))
30cb51f1
BG
3761 (when (get 'org-agenda-regexp-filter :preset-filter)
3762 (org-agenda-filter-apply
3763 (get 'org-agenda-regexp-filter :preset-filter) 'regexp))
2e3c2398 3764 (org-add-hook 'kill-buffer-hook 'org-agenda-reset-markers 'append 'local)))))
20908596 3765
54a0dee5
CD
3766(defun org-agenda-mark-clocking-task ()
3767 "Mark the current clock entry in the agenda if it is present."
30cb51f1
BG
3768 ;; We need to widen when `org-agenda-finalize' is called from
3769 ;; `org-agenda-change-all-lines' (e.g. in `org-agenda-clock-in')
3770 (when org-clock-current-task
3771 (save-restriction
3772 (widen)
3773 (org-agenda-unmark-clocking-task)
3774 (when (marker-buffer org-clock-hd-marker)
3775 (save-excursion
3776 (goto-char (point-min))
3777 (let (s ov)
3778 (while (setq s (next-single-property-change (point) 'org-hd-marker))
3779 (goto-char s)
3780 (when (equal (org-get-at-bol 'org-hd-marker)
3781 org-clock-hd-marker)
3782 (setq ov (make-overlay (point-at-bol) (1+ (point-at-eol))))
3783 (overlay-put ov 'type 'org-agenda-clocking)
3784 (overlay-put ov 'face 'org-agenda-clocking)
3785 (overlay-put ov 'help-echo
3786 "The clock is running in this item")))))))))
54a0dee5 3787
271672fa
BG
3788(defun org-agenda-unmark-clocking-task ()
3789 "Unmark the current clocking task."
3790 (mapc (lambda (o)
3791 (if (eq (overlay-get o 'type) 'org-agenda-clocking)
3792 (delete-overlay o)))
3793 (overlays-in (point-min) (point-max))))
3794
c8d0cf5c 3795(defun org-agenda-fontify-priorities ()
20908596
CD
3796 "Make highest priority lines bold, and lowest italic."
3797 (interactive)
86fbb8ca
CD
3798 (mapc (lambda (o) (if (eq (overlay-get o 'org-type) 'org-priority)
3799 (delete-overlay o)))
3800 (overlays-in (point-min) (point-max)))
20908596 3801 (save-excursion
271672fa 3802 (let (b e p ov h l)
20908596
CD
3803 (goto-char (point-min))
3804 (while (re-search-forward "\\[#\\(.\\)\\]" nil t)
3805 (setq h (or (get-char-property (point) 'org-highest-priority)
3806 org-highest-priority)
3807 l (or (get-char-property (point) 'org-lowest-priority)
3808 org-lowest-priority)
3809 p (string-to-char (match-string 1))
c8d0cf5c
CD
3810 b (match-beginning 0)
3811 e (if (eq org-agenda-fontify-priorities 'cookies)
3812 (match-end 0)
3813 (point-at-eol))
86fbb8ca
CD
3814 ov (make-overlay b e))
3815 (overlay-put
20908596 3816 ov 'face
271672fa
BG
3817 (cons (cond ((org-face-from-face-or-color
3818 'priority nil
3819 (cdr (assoc p org-priority-faces))))
3820 ((and (listp org-agenda-fontify-priorities)
3821 (org-face-from-face-or-color
3822 'priority nil
3823 (cdr (assoc p org-agenda-fontify-priorities)))))
3824 ((equal p l) 'italic)
3825 ((equal p h) 'bold))
3826 'org-priority))
86fbb8ca 3827 (overlay-put ov 'org-type 'org-priority)))))
20908596 3828
666ffc7e
SM
3829(defvar org-depend-tag-blocked)
3830
c7cf0ebc 3831(defun org-agenda-dim-blocked-tasks (&optional invisible)
271672fa
BG
3832 "Dim currently blocked TODO's in the agenda display.
3833When INVISIBLE is non-nil, hide currently blocked TODO instead of
3834dimming them."
c7cf0ebc 3835 (interactive "P")
271672fa
BG
3836 (when (org-called-interactively-p 'interactive)
3837 (message "Dim or hide blocked tasks..."))
86fbb8ca
CD
3838 (mapc (lambda (o) (if (eq (overlay-get o 'org-type) 'org-blocked-todo)
3839 (delete-overlay o)))
3840 (overlays-in (point-min) (point-max)))
d6685abc
CD
3841 (save-excursion
3842 (let ((inhibit-read-only t)
72d06d81 3843 (org-depend-tag-blocked nil)
c7cf0ebc
BG
3844 (invis (or (not (null invisible))
3845 (eq org-agenda-dim-blocked-tasks 'invisible)))
c8d0cf5c
CD
3846 org-blocked-by-checkboxes
3847 invis1 b e p ov h l)
d6685abc
CD
3848 (goto-char (point-min))
3849 (while (let ((pos (next-single-property-change (point) 'todo-state)))
3850 (and pos (goto-char (1+ pos))))
c8d0cf5c 3851 (setq org-blocked-by-checkboxes nil invis1 invis)
8d642074 3852 (let ((marker (org-get-at-bol 'org-hd-marker)))
d6685abc 3853 (when (and marker
e66ba1df
BG
3854 (with-current-buffer (marker-buffer marker)
3855 (save-excursion (goto-char marker)
3856 (org-entry-blocked-p))))
c8d0cf5c 3857 (if org-blocked-by-checkboxes (setq invis1 nil))
53e31a31
CD
3858 (setq b (if invis1
3859 (max (point-min) (1- (point-at-bol)))
3860 (point-at-bol))
d6685abc 3861 e (point-at-eol)
86fbb8ca 3862 ov (make-overlay b e))
c8d0cf5c 3863 (if invis1
30cb51f1
BG
3864 (progn (overlay-put ov 'invisible t)
3865 (overlay-put ov 'intangible t))
86fbb8ca 3866 (overlay-put ov 'face 'org-agenda-dimmed-todo-face))
c7cf0ebc 3867 (overlay-put ov 'org-type 'org-blocked-todo))))))
30cb51f1
BG
3868 (when (org-called-interactively-p 'interactive)
3869 (message "Dim or hide blocked tasks...done")))
20908596
CD
3870
3871(defvar org-agenda-skip-function nil
3872 "Function to be called at each match during agenda construction.
3873If this function returns nil, the current match should not be skipped.
3874Otherwise, the function must return a position from where the search
3875should be continued.
3876This may also be a Lisp form, it will be evaluated.
3877Never set this variable using `setq' or so, because then it will apply
3ab2c837
BG
3878to all future agenda commands. If you do want a global skipping condition,
3879use the option `org-agenda-skip-function-global' instead.
3880The correct usage for `org-agenda-skip-function' is to bind it with
3881`let' to scope it dynamically into the agenda-constructing command.
3882A good way to set it is through options in `org-agenda-custom-commands'.")
20908596
CD
3883
3884(defun org-agenda-skip ()
3885 "Throw to `:skip' in places that should be skipped.
3886Also moves point to the end of the skipped region, so that search can
3887continue from there."
3ab2c837 3888 (let ((p (point-at-bol)) to)
d3517077
BG
3889 (when (or
3890 (save-excursion (goto-char p) (looking-at comment-start-skip))
3891 (and org-agenda-skip-archived-trees (not org-agenda-archives-mode)
3892 (get-text-property p :org-archived)
3893 (org-end-of-subtree t))
3894 (and org-agenda-skip-comment-trees
3895 (get-text-property p :org-comment)
3896 (org-end-of-subtree t))
3897 (and (setq to (or (org-agenda-skip-eval org-agenda-skip-function-global)
3898 (org-agenda-skip-eval org-agenda-skip-function)))
3899 (goto-char to))
3900 (org-in-src-block-p t))
20908596
CD
3901 (throw :skip t))))
3902
3ab2c837 3903(defun org-agenda-skip-eval (form)
271672fa 3904 "If FORM is a function or a list, call (or eval) it and return the result.
3ab2c837
BG
3905`save-excursion' and `save-match-data' are wrapped around the call, so point
3906and match data are returned to the previous state no matter what these
3907functions do."
3908 (let (fp)
3909 (and form
3910 (or (setq fp (functionp form))
3911 (consp form))
3912 (save-excursion
3913 (save-match-data
3914 (if fp
3915 (funcall form)
3916 (eval form)))))))
3917
20908596
CD
3918(defvar org-agenda-markers nil
3919 "List of all currently active markers created by `org-agenda'.")
54a0dee5 3920(defvar org-agenda-last-marker-time (org-float-time)
20908596
CD
3921 "Creation time of the last agenda marker.")
3922
3923(defun org-agenda-new-marker (&optional pos)
3924 "Return a new agenda marker.
3925Org-mode keeps a list of these markers and resets them when they are
3926no longer in use."
3927 (let ((m (copy-marker (or pos (point)))))
54a0dee5 3928 (setq org-agenda-last-marker-time (org-float-time))
8223b1d2
BG
3929 (if org-agenda-buffer
3930 (with-current-buffer org-agenda-buffer
3931 (push m org-agenda-markers))
3932 (push m org-agenda-markers))
20908596
CD
3933 m))
3934
3935(defun org-agenda-reset-markers ()
3936 "Reset markers created by `org-agenda'."
3937 (while org-agenda-markers
3938 (move-marker (pop org-agenda-markers) nil)))
3939
b349f79f 3940(defun org-agenda-save-markers-for-cut-and-paste (beg end)
8223b1d2
BG
3941 "Save relative positions of markers in region.
3942This check for agenda markers in all agenda buffers currently active."
3943 (dolist (buf (buffer-list))
3944 (with-current-buffer buf
3945 (when (eq major-mode 'org-agenda-mode)
3946 (mapc (lambda (m) (org-check-and-save-marker m beg end))
3947 org-agenda-markers)))))
b349f79f 3948
54a0dee5
CD
3949;;; Entry text mode
3950
3951(defun org-agenda-entry-text-show-here ()
8bfe682a 3952 "Add some text from the entry as context to the current line."
54a0dee5 3953 (let (m txt o)
8d642074 3954 (setq m (org-get-at-bol 'org-hd-marker))
54a0dee5
CD
3955 (unless (marker-buffer m)
3956 (error "No marker points to an entry here"))
3957 (setq txt (concat "\n" (org-no-properties
3958 (org-agenda-get-some-entry-text
271672fa
BG
3959 m org-agenda-entry-text-maxlines
3960 org-agenda-entry-text-leaders))))
54a0dee5 3961 (when (string-match "\\S-" txt)
86fbb8ca
CD
3962 (setq o (make-overlay (point-at-bol) (point-at-eol)))
3963 (overlay-put o 'evaporate t)
3964 (overlay-put o 'org-overlay-type 'agenda-entry-content)
3965 (overlay-put o 'after-string txt))))
54a0dee5
CD
3966
3967(defun org-agenda-entry-text-show ()
3968 "Add entry context for all agenda lines."
3969 (interactive)
3970 (save-excursion
3971 (goto-char (point-max))
3972 (beginning-of-line 1)
3973 (while (not (bobp))
8d642074 3974 (when (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
3975 (org-agenda-entry-text-show-here))
3976 (beginning-of-line 0))))
3977
3978(defun org-agenda-entry-text-hide ()
3979 "Remove any shown entry context."
3980 (delq nil
3981 (mapcar (lambda (o)
86fbb8ca 3982 (if (eq (overlay-get o 'org-overlay-type)
54a0dee5 3983 'agenda-entry-content)
86fbb8ca
CD
3984 (progn (delete-overlay o) t)))
3985 (overlays-in (point-min) (point-max)))))
54a0dee5 3986
acedf35c
CD
3987(defun org-agenda-get-day-face (date)
3988 "Return the face DATE should be displayed with."
3989 (or (and (functionp org-agenda-day-face-function)
3990 (funcall org-agenda-day-face-function date))
3991 (cond ((org-agenda-todayp date)
3992 'org-agenda-date-today)
3993 ((member (calendar-day-of-week date) org-agenda-weekend-days)
3994 'org-agenda-date-weekend)
3995 (t 'org-agenda-date))))
3996
20908596
CD
3997;;; Agenda timeline
3998
3999(defvar org-agenda-only-exact-dates nil) ; dynamically scoped
666ffc7e 4000(defvar org-agenda-show-log-scoped) ;; dynamically scope in `org-timeline' or `org-agenda-list'
20908596 4001
e66ba1df 4002(defun org-timeline (&optional dotodo)
20908596
CD
4003 "Show a time-sorted view of the entries in the current org file.
4004Only entries with a time stamp of today or later will be listed. With
4005\\[universal-argument] prefix, all unfinished TODO items will also be shown,
4006under the current date.
4007If the buffer contains an active region, only check the region for
4008dates."
4009 (interactive "P")
20908596 4010 (let* ((dopast t)
8223b1d2 4011 (org-agenda-show-log-scoped org-agenda-show-log)
271672fa 4012 (org-agenda-show-log org-agenda-show-log-scoped)
afe98dfa
CD
4013 (entry (buffer-file-name (or (buffer-base-buffer (current-buffer))
4014 (current-buffer))))
20908596
CD
4015 (date (calendar-current-date))
4016 (beg (if (org-region-active-p) (region-beginning) (point-min)))
4017 (end (if (org-region-active-p) (region-end) (point-max)))
8223b1d2
BG
4018 (day-numbers (org-get-all-dates
4019 beg end 'no-ranges
4020 t org-agenda-show-log-scoped ; always include today
4021 org-timeline-show-empty-dates))
20908596
CD
4022 (org-deadline-warning-days 0)
4023 (org-agenda-only-exact-dates t)
acedf35c 4024 (today (org-today))
20908596
CD
4025 (past t)
4026 args
acedf35c 4027 s e rtn d emptyp)
20908596 4028 (setq org-agenda-redo-command
271672fa
BG
4029 (list 'let
4030 (list (list 'org-agenda-show-log 'org-agenda-show-log))
4031 (list 'org-switch-to-buffer-other-window (current-buffer))
4032 (list 'org-timeline (list 'quote dotodo))))
4033 (put 'org-agenda-redo-command 'org-lprops nil)
20908596
CD
4034 (if (not dopast)
4035 ;; Remove past dates from the list of dates.
4036 (setq day-numbers (delq nil (mapcar (lambda(x)
4037 (if (>= x today) x nil))
4038 day-numbers))))
8223b1d2
BG
4039 (org-agenda-prepare (concat "Timeline " (file-name-nondirectory entry)))
4040 (org-compile-prefix-format 'timeline)
4041 (org-set-sorting-strategy 'timeline)
4042 (if org-agenda-show-log-scoped (push :closed args))
20908596
CD
4043 (push :timestamp args)
4044 (push :deadline args)
4045 (push :scheduled args)
4046 (push :sexp args)
4047 (if dotodo (push :todo args))
8d642074
CD
4048 (insert "Timeline of file " entry "\n")
4049 (add-text-properties (point-min) (point)
4050 (list 'face 'org-agenda-structure))
4051 (org-agenda-mark-header-line (point-min))
20908596
CD
4052 (while (setq d (pop day-numbers))
4053 (if (and (listp d) (eq (car d) :omitted))
4054 (progn
4055 (setq s (point))
4056 (insert (format "\n[... %d empty days omitted]\n\n" (cdr d)))
4057 (put-text-property s (1- (point)) 'face 'org-agenda-structure))
4058 (if (listp d) (setq d (car d) emptyp t) (setq emptyp nil))
4059 (if (and (>= d today)
4060 dopast
4061 past)
4062 (progn
4063 (setq past nil)
4064 (insert (make-string 79 ?-) "\n")))
acedf35c 4065 (setq date (calendar-gregorian-from-absolute d))
20908596
CD
4066 (setq s (point))
4067 (setq rtn (and (not emptyp)
4068 (apply 'org-agenda-get-day-entries entry
4069 date args)))
4070 (if (or rtn (equal d today) org-timeline-show-empty-dates)
4071 (progn
4072 (insert
4073 (if (stringp org-agenda-format-date)
4074 (format-time-string org-agenda-format-date
4075 (org-time-from-absolute date))
4076 (funcall org-agenda-format-date date))
4077 "\n")
4078 (put-text-property s (1- (point)) 'face
acedf35c 4079 (org-agenda-get-day-face date))
20908596 4080 (put-text-property s (1- (point)) 'org-date-line t)
8d642074 4081 (put-text-property s (1- (point)) 'org-agenda-date-header t)
20908596
CD
4082 (if (equal d today)
4083 (put-text-property s (1- (point)) 'org-today t))
271672fa 4084 (and rtn (insert (org-agenda-finalize-entries rtn 'timeline) "\n"))
20908596 4085 (put-text-property s (1- (point)) 'day d)))))
20908596
CD
4086 (goto-char (or (text-property-any (point-min) (point-max) 'org-today t)
4087 (point-min)))
271672fa
BG
4088 (add-text-properties
4089 (point-min) (point-max)
4090 `(org-agenda-type timeline org-redo-cmd ,org-agenda-redo-command))
8223b1d2 4091 (org-agenda-finalize)
20908596
CD
4092 (setq buffer-read-only t)))
4093
4094(defun org-get-all-dates (beg end &optional no-ranges force-today inactive empty pre-re)
4095 "Return a list of all relevant day numbers from BEG to END buffer positions.
4096If NO-RANGES is non-nil, include only the start and end dates of a range,
4097not every single day in the range. If FORCE-TODAY is non-nil, make
4098sure that TODAY is included in the list. If INACTIVE is non-nil, also
4099inactive time stamps (those in square brackets) are included.
4100When EMPTY is non-nil, also include days without any entries."
4101 (let ((re (concat
4102 (if pre-re pre-re "")
4103 (if inactive org-ts-regexp-both org-ts-regexp)))
8223b1d2 4104 dates dates1 date day day1 day2 ts1 ts2 pos)
20908596 4105 (if force-today
acedf35c 4106 (setq dates (list (org-today))))
20908596
CD
4107 (save-excursion
4108 (goto-char beg)
4109 (while (re-search-forward re end t)
4110 (setq day (time-to-days (org-time-string-to-time
e66ba1df
BG
4111 (substring (match-string 1) 0 10)
4112 (current-buffer) (match-beginning 0))))
20908596
CD
4113 (or (memq day dates) (push day dates)))
4114 (unless no-ranges
4115 (goto-char beg)
4116 (while (re-search-forward org-tr-regexp end t)
e66ba1df 4117 (setq pos (match-beginning 0))
20908596
CD
4118 (setq ts1 (substring (match-string 1) 0 10)
4119 ts2 (substring (match-string 2) 0 10)
e66ba1df
BG
4120 day1 (time-to-days (org-time-string-to-time
4121 ts1 (current-buffer) pos))
4122 day2 (time-to-days (org-time-string-to-time
4123 ts2 (current-buffer) pos)))
20908596
CD
4124 (while (< (setq day1 (1+ day1)) day2)
4125 (or (memq day1 dates) (push day1 dates)))))
4126 (setq dates (sort dates '<))
4127 (when empty
4128 (while (setq day (pop dates))
4129 (setq day2 (car dates))
4130 (push day dates1)
4131 (when (and day2 empty)
4132 (if (or (eq empty t)
4133 (and (numberp empty) (<= (- day2 day) empty)))
4134 (while (< (setq day (1+ day)) day2)
4135 (push (list day) dates1))
4136 (push (cons :omitted (- day2 day)) dates1))))
4137 (setq dates (nreverse dates1)))
4138 dates)))
4139
4140;;; Agenda Daily/Weekly
4141
c8d0cf5c 4142(defvar org-agenda-start-day nil ; dynamically scoped parameter
8223b1d2 4143 "Start day for the agenda view.
271672fa
BG
4144Custom commands can set this variable in the options section.
4145This is usually a string like \"2007-11-01\", \"+2d\" or any other
4146input allowed when reading a date through the Org calendar.
4147See the docstring of `org-read-date' for details.")
20908596 4148(defvar org-starting-day nil) ; local variable in the agenda buffer
e66ba1df 4149(defvar org-arg-loc nil) ; local variable
20908596 4150
8223b1d2 4151(defvar org-agenda-buffer-tmp-name nil)
20908596 4152;;;###autoload
271672fa 4153(defun org-agenda-list (&optional arg start-day span with-hour)
20908596
CD
4154 "Produce a daily/weekly view from all files in variable `org-agenda-files'.
4155The view will be for the current day or week, but from the overview buffer
4156you will be able to go to other days/weeks.
4157
20908596 4158With a numeric prefix argument in an interactive call, the agenda will
e66ba1df 4159span ARG days. Lisp programs should instead specify SPAN to change
acedf35c 4160the number of days. SPAN defaults to `org-agenda-span'.
20908596
CD
4161
4162START-DAY defaults to TODAY, or to the most recent match for the weekday
271672fa
BG
4163given in `org-agenda-start-on-weekday'.
4164
4165When WITH-HOUR is non-nil, only include scheduled and deadline
4166items if they have an hour specification like [h]h:mm."
20908596 4167 (interactive "P")
20908596 4168 (if org-agenda-overriding-arguments
e66ba1df 4169 (setq arg (car org-agenda-overriding-arguments)
20908596 4170 start-day (nth 1 org-agenda-overriding-arguments)
acedf35c 4171 span (nth 2 org-agenda-overriding-arguments)))
8223b1d2
BG
4172 (if (and (integerp arg) (> arg 0))
4173 (setq span arg arg nil))
4174 (catch 'exit
4175 (setq org-agenda-buffer-name
4176 (or org-agenda-buffer-tmp-name
4177 (if org-agenda-sticky
4178 (cond ((and org-keys (stringp org-match))
4179 (format "*Org Agenda(%s:%s)*" org-keys org-match))
4180 (org-keys
4181 (format "*Org Agenda(%s)*" org-keys))
4182 (t "*Org Agenda(a)*")))
4183 org-agenda-buffer-name))
4184 (org-agenda-prepare "Day/Week")
4185 (setq start-day (or start-day org-agenda-start-day))
4186 (if (stringp start-day)
4187 ;; Convert to an absolute day number
4188 (setq start-day (time-to-days (org-read-date nil t start-day))))
4189 (org-compile-prefix-format 'agenda)
4190 (org-set-sorting-strategy 'agenda)
4191 (let* ((span (org-agenda-ndays-to-span
4192 (or span org-agenda-ndays org-agenda-span)))
4193 (today (org-today))
4194 (sd (or start-day today))
4195 (ndays (org-agenda-span-to-ndays span sd))
4196 (org-agenda-start-on-weekday
271672fa 4197 (if (or (eq ndays 7) (eq ndays 14))
8223b1d2
BG
4198 org-agenda-start-on-weekday))
4199 (thefiles (org-agenda-files nil 'ifmode))
4200 (files thefiles)
4201 (start (if (or (null org-agenda-start-on-weekday)
4202 (< ndays 7))
4203 sd
4204 (let* ((nt (calendar-day-of-week
4205 (calendar-gregorian-from-absolute sd)))
4206 (n1 org-agenda-start-on-weekday)
4207 (d (- nt n1)))
4208 (- sd (+ (if (< d 0) 7 0) d)))))
4209 (day-numbers (list start))
4210 (day-cnt 0)
4211 (inhibit-redisplay (not debug-on-error))
4212 (org-agenda-show-log-scoped org-agenda-show-log)
4213 s e rtn rtnall file date d start-pos end-pos todayp
4214 clocktable-start clocktable-end filter)
4215 (setq org-agenda-redo-command
271672fa 4216 (list 'org-agenda-list (list 'quote arg) start-day (list 'quote span) with-hour))
8223b1d2
BG
4217 (dotimes (n (1- ndays))
4218 (push (1+ (car day-numbers)) day-numbers))
4219 (setq day-numbers (nreverse day-numbers))
4220 (setq clocktable-start (car day-numbers)
4221 clocktable-end (1+ (or (org-last day-numbers) 0)))
4222 (org-set-local 'org-starting-day (car day-numbers))
4223 (org-set-local 'org-arg-loc arg)
4224 (org-set-local 'org-agenda-current-span (org-agenda-ndays-to-span span))
4225 (unless org-agenda-compact-blocks
4226 (let* ((d1 (car day-numbers))
4227 (d2 (org-last day-numbers))
4228 (w1 (org-days-to-iso-week d1))
4229 (w2 (org-days-to-iso-week d2)))
4230 (setq s (point))
4231 (if org-agenda-overriding-header
4232 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
4233 nil 'face 'org-agenda-structure) "\n")
4234 (insert (org-agenda-span-name span)
4235 "-agenda"
4236 (if (< (- d2 d1) 350)
4237 (if (= w1 w2)
4238 (format " (W%02d)" w1)
4239 (format " (W%02d-W%02d)" w1 w2))
4240 "")
4241 ":\n")))
4242 (add-text-properties s (1- (point)) (list 'face 'org-agenda-structure
4243 'org-date-line t))
4244 (org-agenda-mark-header-line s))
4245 (while (setq d (pop day-numbers))
4246 (setq date (calendar-gregorian-from-absolute d)
4247 s (point))
4248 (if (or (setq todayp (= d today))
4249 (and (not start-pos) (= d sd)))
4250 (setq start-pos (point))
4251 (if (and start-pos (not end-pos))
4252 (setq end-pos (point))))
4253 (setq files thefiles
4254 rtnall nil)
4255 (while (setq file (pop files))
4256 (catch 'nextfile
4257 (org-check-agenda-file file)
4258 (let ((org-agenda-entry-types org-agenda-entry-types))
271672fa
BG
4259 ;; Starred types override non-starred equivalents
4260 (when (member :deadline* org-agenda-entry-types)
8223b1d2
BG
4261 (setq org-agenda-entry-types
4262 (delq :deadline org-agenda-entry-types)))
271672fa
BG
4263 (when (member :scheduled* org-agenda-entry-types)
4264 (setq org-agenda-entry-types
4265 (delq :scheduled org-agenda-entry-types)))
4266 ;; Honor with-hour
4267 (when with-hour
4268 (when (member :deadline org-agenda-entry-types)
4269 (setq org-agenda-entry-types
4270 (delq :deadline org-agenda-entry-types))
4271 (push :deadline* org-agenda-entry-types))
4272 (when (member :scheduled org-agenda-entry-types)
4273 (setq org-agenda-entry-types
4274 (delq :scheduled org-agenda-entry-types))
4275 (push :scheduled* org-agenda-entry-types)))
4276 (unless org-agenda-include-deadlines
4277 (setq org-agenda-entry-types
4278 (delq :deadline* (delq :deadline org-agenda-entry-types))))
8223b1d2
BG
4279 (cond
4280 ((memq org-agenda-show-log-scoped '(only clockcheck))
4281 (setq rtn (org-agenda-get-day-entries
4282 file date :closed)))
4283 (org-agenda-show-log-scoped
4284 (setq rtn (apply 'org-agenda-get-day-entries
4285 file date
4286 (append '(:closed) org-agenda-entry-types))))
4287 (t
4288 (setq rtn (apply 'org-agenda-get-day-entries
4289 file date
4290 org-agenda-entry-types)))))
4291 (setq rtnall (append rtnall rtn)))) ;; all entries
4292 (if org-agenda-include-diary
4293 (let ((org-agenda-search-headline-for-time t))
4294 (require 'diary-lib)
4295 (setq rtn (org-get-entries-from-diary date))
4296 (setq rtnall (append rtnall rtn))))
4297 (if (or rtnall org-agenda-show-all-dates)
4298 (progn
4299 (setq day-cnt (1+ day-cnt))
4300 (insert
4301 (if (stringp org-agenda-format-date)
4302 (format-time-string org-agenda-format-date
4303 (org-time-from-absolute date))
4304 (funcall org-agenda-format-date date))
4305 "\n")
4306 (put-text-property s (1- (point)) 'face
4307 (org-agenda-get-day-face date))
4308 (put-text-property s (1- (point)) 'org-date-line t)
4309 (put-text-property s (1- (point)) 'org-agenda-date-header t)
4310 (put-text-property s (1- (point)) 'org-day-cnt day-cnt)
4311 (when todayp
4312 (put-text-property s (1- (point)) 'org-today t))
4313 (setq rtnall
4314 (org-agenda-add-time-grid-maybe rtnall ndays todayp))
4315 (if rtnall (insert ;; all entries
271672fa 4316 (org-agenda-finalize-entries rtnall 'agenda)
8223b1d2
BG
4317 "\n"))
4318 (put-text-property s (1- (point)) 'day d)
4319 (put-text-property s (1- (point)) 'org-day-cnt day-cnt))))
4320 (when (and org-agenda-clockreport-mode clocktable-start)
4321 (let ((org-agenda-files (org-agenda-files nil 'ifmode))
4322 ;; the above line is to ensure the restricted range!
4323 (p (copy-sequence org-agenda-clockreport-parameter-plist))
4324 tbl)
4325 (setq p (org-plist-delete p :block))
4326 (setq p (plist-put p :tstart clocktable-start))
4327 (setq p (plist-put p :tend clocktable-end))
4328 (setq p (plist-put p :scope 'agenda))
4329 (when (and (eq org-agenda-clockreport-mode 'with-filter)
4330 (setq filter (or org-agenda-tag-filter-while-redo
4331 (get 'org-agenda-tag-filter :preset-filter))))
4332 (setq p (plist-put p :tags (mapconcat (lambda (x)
4333 (if (string-match "[<>=]" x)
4334 ""
4335 x))
4336 filter ""))))
bdebdb64 4337 (setq tbl (apply 'org-clock-get-clocktable p))
8223b1d2
BG
4338 (insert tbl)))
4339 (goto-char (point-min))
4340 (or org-agenda-multi (org-agenda-fit-window-to-buffer))
4341 (unless (and (pos-visible-in-window-p (point-min))
4342 (pos-visible-in-window-p (point-max)))
4343 (goto-char (1- (point-max)))
4344 (recenter -1)
4345 (if (not (pos-visible-in-window-p (or start-pos 1)))
4346 (progn
4347 (goto-char (or start-pos 1))
4348 (recenter 1))))
4349 (goto-char (or start-pos 1))
4350 (add-text-properties (point-min) (point-max)
4351 `(org-agenda-type agenda
4352 org-last-args (,arg ,start-day ,span)
4353 org-redo-cmd ,org-agenda-redo-command
735135f9 4354 org-series-cmd ,org-cmd))
8223b1d2
BG
4355 (if (eq org-agenda-show-log-scoped 'clockcheck)
4356 (org-agenda-show-clocking-issues))
4357 (org-agenda-finalize)
4358 (setq buffer-read-only t)
4359 (message ""))))
20908596
CD
4360
4361(defun org-agenda-ndays-to-span (n)
acedf35c
CD
4362 "Return a span symbol for a span of N days, or N if none matches."
4363 (cond ((symbolp n) n)
4364 ((= n 1) 'day)
4365 ((= n 7) 'week)
271672fa 4366 ((= n 14) 'fortnight)
acedf35c
CD
4367 (t n)))
4368
8223b1d2 4369(defun org-agenda-span-to-ndays (span &optional start-day)
271672fa
BG
4370 "Return ndays from SPAN, possibly starting at START-DAY.
4371START-DAY is an absolute time value."
acedf35c
CD
4372 (cond ((numberp span) span)
4373 ((eq span 'day) 1)
4374 ((eq span 'week) 7)
271672fa 4375 ((eq span 'fortnight) 14)
acedf35c
CD
4376 ((eq span 'month)
4377 (let ((date (calendar-gregorian-from-absolute start-day)))
4378 (calendar-last-day-of-month (car date) (caddr date))))
4379 ((eq span 'year)
4380 (let ((date (calendar-gregorian-from-absolute start-day)))
4381 (if (calendar-leap-year-p (caddr date)) 366 365)))))
4382
4383(defun org-agenda-span-name (span)
4384 "Return a SPAN name."
4385 (if (null span)
4386 ""
4387 (if (symbolp span)
4388 (capitalize (symbol-name span))
4389 (format "%d days" span))))
20908596
CD
4390
4391;;; Agenda word search
4392
4393(defvar org-agenda-search-history nil)
20908596
CD
4394
4395(defvar org-search-syntax-table nil
e66ba1df
BG
4396 "Special syntax table for org-mode search.
4397In this table, we have single quotes not as word constituents, to
4398that when \"+Ameli\" is searched as a work, it will also match \"Ameli's\"")
20908596 4399
8223b1d2 4400(defvar org-mode-syntax-table) ; From org.el
20908596
CD
4401(defun org-search-syntax-table ()
4402 (unless org-search-syntax-table
4403 (setq org-search-syntax-table (copy-syntax-table org-mode-syntax-table))
4404 (modify-syntax-entry ?' "." org-search-syntax-table)
4405 (modify-syntax-entry ?` "." org-search-syntax-table))
4406 org-search-syntax-table)
4407
ed21c5c8
CD
4408(defvar org-agenda-last-search-view-search-was-boolean nil)
4409
20908596
CD
4410;;;###autoload
4411(defun org-search-view (&optional todo-only string edit-at)
ed21c5c8 4412 "Show all entries that contain a phrase or words or regular expressions.
20908596
CD
4413
4414With optional prefix argument TODO-ONLY, only consider entries that are
4415TODO entries. The argument STRING can be used to pass a default search
4416string into this function. If EDIT-AT is non-nil, it means that the
4417user should get a chance to edit this string, with cursor at position
4418EDIT-AT.
4419
ed21c5c8
CD
4420The search string can be viewed either as a phrase that should be found as
4421is, or it can be broken into a number of snippets, each of which must match
4422in a Boolean way to select an entry. The default depends on the variable
4423`org-agenda-search-view-always-boolean'.
4424Even if this is turned off (the default) you can always switch to
86fbb8ca 4425Boolean search dynamically by preceding the first word with \"+\" or \"-\".
ed21c5c8
CD
4426
4427The default is a direct search of the whole phrase, where each space in
4428the search string can expand to an arbitrary amount of whitespace,
4429including newlines.
4430
4431If using a Boolean search, the search string is split on whitespace and
4432each snippet is searched separately, with logical AND to select an entry.
4433Words prefixed with a minus must *not* occur in the entry. Words without
4434a prefix or prefixed with a plus must occur in the entry. Matching is
4435case-insensitive. Words are enclosed by word delimiters (i.e. they must
4436match whole words, not parts of a word) if
4437`org-agenda-search-view-force-full-words' is set (default is nil).
4438
4439Boolean search snippets enclosed by curly braces are interpreted as
86fbb8ca 4440regular expressions that must or (when preceded with \"-\") must not
ed21c5c8 4441match in the entry. Snippets enclosed into double quotes will be taken
86fbb8ca 4442as a whole, to include whitespace.
ed21c5c8
CD
4443
4444- If the search string starts with an asterisk, search only in headlines.
4445- If (possibly after the leading star) the search string starts with an
4446 exclamation mark, this also means to look at TODO entries only, an effect
4447 that can also be achieved with a prefix argument.
4448- If (possibly after star and exclamation mark) the search string starts
4449 with a colon, this will mean that the (non-regexp) snippets of the
4450 Boolean search must match as full words.
20908596
CD
4451
4452This command searches the agenda files, and in addition the files listed
4453in `org-agenda-text-search-extra-files'."
4454 (interactive "P")
8223b1d2
BG
4455 (if org-agenda-overriding-arguments
4456 (setq todo-only (car org-agenda-overriding-arguments)
4457 string (nth 1 org-agenda-overriding-arguments)
4458 edit-at (nth 2 org-agenda-overriding-arguments)))
20908596 4459 (let* ((props (list 'face nil
c8d0cf5c 4460 'done-face 'org-agenda-done
20908596
CD
4461 'org-not-done-regexp org-not-done-regexp
4462 'org-todo-regexp org-todo-regexp
b349f79f 4463 'org-complex-heading-regexp org-complex-heading-regexp
20908596 4464 'mouse-face 'highlight
20908596 4465 'help-echo (format "mouse-2 or RET jump to location")))
ed21c5c8 4466 (full-words org-agenda-search-view-force-full-words)
86fbb8ca 4467 (org-agenda-text-search-extra-files org-agenda-text-search-extra-files)
a89c8ef0 4468 regexp rtn rtnall files file pos inherited-tags
271672fa 4469 marker category category-pos level tags c neg re boolean
20908596
CD
4470 ee txt beg end words regexps+ regexps- hdl-only buffer beg1 str)
4471 (unless (and (not edit-at)
4472 (stringp string)
4473 (string-match "\\S-" string))
ed21c5c8
CD
4474 (setq string (read-string
4475 (if org-agenda-search-view-always-boolean
4476 "[+-]Word/{Regexp} ...: "
8223b1d2 4477 "Phrase or [+-]Word/{Regexp} ...: ")
ed21c5c8
CD
4478 (cond
4479 ((integerp edit-at) (cons string edit-at))
4480 (edit-at string))
4481 'org-agenda-search-history)))
8223b1d2
BG
4482 (catch 'exit
4483 (if org-agenda-sticky
4484 (setq org-agenda-buffer-name
4485 (if (stringp string)
4486 (format "*Org Agenda(%s:%s)*"
4487 (or org-keys (or (and todo-only "S") "s")) string)
4488 (format "*Org Agenda(%s)*" (or (and todo-only "S") "s")))))
4489 (org-agenda-prepare "SEARCH")
4490 (org-compile-prefix-format 'search)
4491 (org-set-sorting-strategy 'search)
4492 (setq org-agenda-redo-command
4493 (list 'org-search-view (if todo-only t nil)
4494 (list 'if 'current-prefix-arg nil string)))
4495 (setq org-agenda-query-string string)
4496 (if (equal (string-to-char string) ?*)
4497 (setq hdl-only t
4498 words (substring string 1))
4499 (setq words string))
4500 (when (equal (string-to-char words) ?!)
4501 (setq todo-only t
4502 words (substring words 1)))
4503 (when (equal (string-to-char words) ?:)
4504 (setq full-words t
4505 words (substring words 1)))
4506 (if (or org-agenda-search-view-always-boolean
4507 (member (string-to-char words) '(?- ?+ ?\{)))
4508 (setq boolean t))
4509 (setq words (org-split-string words))
4510 (let (www w)
ed21c5c8 4511 (while (setq w (pop words))
8223b1d2
BG
4512 (while (and (string-match "\\\\\\'" w) words)
4513 (setq w (concat (substring w 0 -1) " " (pop words))))
4514 (push w www))
4515 (setq words (nreverse www) www nil)
4516 (while (setq w (pop words))
4517 (when (and (string-match "\\`[-+]?{" w)
4518 (not (string-match "}\\'" w)))
4519 (while (and words (not (string-match "}\\'" (car words))))
4520 (setq w (concat w " " (pop words))))
4521 (setq w (concat w " " (pop words))))
4522 (push w www))
4523 (setq words (nreverse www)))
4524 (setq org-agenda-last-search-view-search-was-boolean boolean)
4525 (when boolean
4526 (let (wds w)
4527 (while (setq w (pop words))
4528 (if (or (equal (substring w 0 1) "\"")
4529 (and (> (length w) 1)
4530 (member (substring w 0 1) '("+" "-"))
4531 (equal (substring w 1 2) "\"")))
4532 (while (and words (not (equal (substring w -1) "\"")))
4533 (setq w (concat w " " (pop words)))))
4534 (and (string-match "\\`\\([-+]?\\)\"" w)
4535 (setq w (replace-match "\\1" nil nil w)))
4536 (and (equal (substring w -1) "\"") (setq w (substring w 0 -1)))
4537 (push w wds))
4538 (setq words (nreverse wds))))
4539 (if boolean
4540 (mapc (lambda (w)
4541 (setq c (string-to-char w))
4542 (if (equal c ?-)
4543 (setq neg t w (substring w 1))
4544 (if (equal c ?+)
4545 (setq neg nil w (substring w 1))
4546 (setq neg nil)))
4547 (if (string-match "\\`{.*}\\'" w)
4548 (setq re (substring w 1 -1))
4549 (if full-words
4550 (setq re (concat "\\<" (regexp-quote (downcase w)) "\\>"))
4551 (setq re (regexp-quote (downcase w)))))
4552 (if neg (push re regexps-) (push re regexps+)))
4553 words)
4554 (push (mapconcat (lambda (w) (regexp-quote w)) words "\\s-+")
4555 regexps+))
4556 (setq regexps+ (sort regexps+ (lambda (a b) (> (length a) (length b)))))
4557 (if (not regexps+)
4558 (setq regexp org-outline-regexp-bol)
4559 (setq regexp (pop regexps+))
4560 (if hdl-only (setq regexp (concat org-outline-regexp-bol ".*?"
4561 regexp))))
4562 (setq files (org-agenda-files nil 'ifmode))
4563 (when (eq (car org-agenda-text-search-extra-files) 'agenda-archives)
4564 (pop org-agenda-text-search-extra-files)
4565 (setq files (org-add-archive-files files)))
4566 (setq files (append files org-agenda-text-search-extra-files)
4567 rtnall nil)
4568 (while (setq file (pop files))
4569 (setq ee nil)
4570 (catch 'nextfile
4571 (org-check-agenda-file file)
4572 (setq buffer (if (file-exists-p file)
4573 (org-get-agenda-file-buffer file)
4574 (error "No such file %s" file)))
4575 (if (not buffer)
4576 ;; If file does not exist, make sure an error message is sent
4577 (setq rtn (list (format "ORG-AGENDA-ERROR: No such org-file %s"
4578 file))))
4579 (with-current-buffer buffer
4580 (with-syntax-table (org-search-syntax-table)
4581 (unless (derived-mode-p 'org-mode)
4582 (error "Agenda file %s is not in `org-mode'" file))
4583 (let ((case-fold-search t))
4584 (save-excursion
4585 (save-restriction
271672fa 4586 (if (eq buffer org-agenda-restrict)
8223b1d2
BG
4587 (narrow-to-region org-agenda-restrict-begin
4588 org-agenda-restrict-end)
4589 (widen))
4590 (goto-char (point-min))
4591 (unless (or (org-at-heading-p)
4592 (outline-next-heading))
4593 (throw 'nextfile t))
4594 (goto-char (max (point-min) (1- (point))))
4595 (while (re-search-forward regexp nil t)
4596 (org-back-to-heading t)
73d3db82 4597 (while (and (not (zerop org-agenda-search-view-max-outline-level))
271672fa
BG
4598 (> (org-reduced-level (org-outline-level))
4599 org-agenda-search-view-max-outline-level)
4600 (forward-line -1)
4601 (outline-back-to-heading t)))
8223b1d2
BG
4602 (skip-chars-forward "* ")
4603 (setq beg (point-at-bol)
4604 beg1 (point)
271672fa
BG
4605 end (progn
4606 (outline-next-heading)
73d3db82 4607 (while (and (not (zerop org-agenda-search-view-max-outline-level))
271672fa
BG
4608 (> (org-reduced-level (org-outline-level))
4609 org-agenda-search-view-max-outline-level)
4610 (forward-line 1)
4611 (outline-next-heading)))
4612 (point)))
4613
8223b1d2
BG
4614 (catch :skip
4615 (goto-char beg)
4616 (org-agenda-skip)
4617 (setq str (buffer-substring-no-properties
4618 (point-at-bol)
4619 (if hdl-only (point-at-eol) end)))
4620 (mapc (lambda (wr) (when (string-match wr str)
4621 (goto-char (1- end))
4622 (throw :skip t)))
4623 regexps-)
4624 (mapc (lambda (wr) (unless (string-match wr str)
4625 (goto-char (1- end))
4626 (throw :skip t)))
4627 (if todo-only
4628 (cons (concat "^\*+[ \t]+" org-not-done-regexp)
4629 regexps+)
4630 regexps+))
4631 (goto-char beg)
4632 (setq marker (org-agenda-new-marker (point))
4633 category (org-get-category)
271672fa 4634 level (make-string (org-reduced-level (org-outline-level)) ? )
8223b1d2 4635 category-pos (get-text-property (point) 'org-category-position)
a89c8ef0
BG
4636 inherited-tags
4637 (or (eq org-agenda-show-inherited-tags 'always)
d3517077
BG
4638 (and (listp org-agenda-show-inherited-tags)
4639 (memq 'todo org-agenda-show-inherited-tags))
a89c8ef0
BG
4640 (and (eq org-agenda-show-inherited-tags t)
4641 (or (eq org-agenda-use-tag-inheritance t)
4642 (memq 'todo org-agenda-use-tag-inheritance))))
4643 tags (org-get-tags-at nil (not inherited-tags))
8223b1d2
BG
4644 txt (org-agenda-format-item
4645 ""
4646 (buffer-substring-no-properties
4647 beg1 (point-at-eol))
271672fa 4648 level category tags t))
8223b1d2
BG
4649 (org-add-props txt props
4650 'org-marker marker 'org-hd-marker marker
4651 'org-todo-regexp org-todo-regexp
271672fa 4652 'level level
8223b1d2
BG
4653 'org-complex-heading-regexp org-complex-heading-regexp
4654 'priority 1000 'org-category category
4655 'org-category-position category-pos
4656 'type "search")
4657 (push txt ee)
4658 (goto-char (1- end))))))))))
4659 (setq rtn (nreverse ee))
4660 (setq rtnall (append rtnall rtn)))
4661 (if org-agenda-overriding-header
4662 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
4663 nil 'face 'org-agenda-structure) "\n")
4664 (insert "Search words: ")
4665 (add-text-properties (point-min) (1- (point))
4666 (list 'face 'org-agenda-structure))
4667 (setq pos (point))
4668 (insert string "\n")
4669 (add-text-properties pos (1- (point)) (list 'face 'org-warning))
4670 (setq pos (point))
4671 (unless org-agenda-multi
4672 (insert "Press `[', `]' to add/sub word, `{', `}' to add/sub regexp, `C-u r' to edit\n")
4673 (add-text-properties pos (1- (point))
4674 (list 'face 'org-agenda-structure))))
4675 (org-agenda-mark-header-line (point-min))
4676 (when rtnall
271672fa 4677 (insert (org-agenda-finalize-entries rtnall 'search) "\n"))
8223b1d2
BG
4678 (goto-char (point-min))
4679 (or org-agenda-multi (org-agenda-fit-window-to-buffer))
4680 (add-text-properties (point-min) (point-max)
4681 `(org-agenda-type search
4682 org-last-args (,todo-only ,string ,edit-at)
4683 org-redo-cmd ,org-agenda-redo-command
735135f9 4684 org-series-cmd ,org-cmd))
8223b1d2
BG
4685 (org-agenda-finalize)
4686 (setq buffer-read-only t))))
20908596
CD
4687
4688;;; Agenda TODO list
4689
271672fa
BG
4690(defun org-agenda-propertize-selected-todo-keywords (keywords)
4691 "Use `org-todo-keyword-faces' for the selected todo KEYWORDS."
4692 (concat
4693 (if (or (equal keywords "ALL") (not keywords))
4694 (propertize "ALL" 'face 'warning)
4695 (mapconcat
4696 (lambda (kw)
4697 (propertize kw 'face (org-get-todo-face kw)))
4698 (org-split-string keywords "|")
4699 "|"))
4700 "\n"))
4701
20908596
CD
4702(defvar org-select-this-todo-keyword nil)
4703(defvar org-last-arg nil)
4704
4705;;;###autoload
8223b1d2 4706(defun org-todo-list (&optional arg)
86fbb8ca 4707 "Show all (not done) TODO entries from all agenda file in a single list.
20908596
CD
4708The prefix arg can be used to select a specific TODO keyword and limit
4709the list to these. When using \\[universal-argument], you will be prompted
4710for a keyword. A numeric prefix directly selects the Nth keyword in
4711`org-todo-keywords-1'."
4712 (interactive "P")
8223b1d2
BG
4713 (if org-agenda-overriding-arguments
4714 (setq arg org-agenda-overriding-arguments))
ed21c5c8 4715 (if (and (stringp arg) (not (string-match "\\S-" arg))) (setq arg nil))
acedf35c 4716 (let* ((today (org-today))
20908596
CD
4717 (date (calendar-gregorian-from-absolute today))
4718 (kwds org-todo-keywords-for-agenda)
4719 (completion-ignore-case t)
4720 (org-select-this-todo-keyword
4721 (if (stringp arg) arg
4722 (and arg (integerp arg) (> arg 0)
4723 (nth (1- arg) kwds))))
4724 rtn rtnall files file pos)
4725 (when (equal arg '(4))
4726 (setq org-select-this-todo-keyword
54a0dee5 4727 (org-icompleting-read "Keyword (or KWD1|K2D2|...): "
8223b1d2 4728 (mapcar 'list kwds) nil nil)))
20908596 4729 (and (equal 0 arg) (setq org-select-this-todo-keyword nil))
8223b1d2
BG
4730 (catch 'exit
4731 (if org-agenda-sticky
4732 (setq org-agenda-buffer-name
4733 (if (stringp org-select-this-todo-keyword)
4734 (format "*Org Agenda(%s:%s)*" (or org-keys "t")
4735 org-select-this-todo-keyword)
4736 (format "*Org Agenda(%s)*" (or org-keys "t")))))
4737 (org-agenda-prepare "TODO")
4738 (org-compile-prefix-format 'todo)
4739 (org-set-sorting-strategy 'todo)
4740 (setq org-agenda-redo-command
4741 `(org-todo-list (or (and (numberp current-prefix-arg)
4742 current-prefix-arg)
4743 ,org-select-this-todo-keyword
4744 current-prefix-arg ,arg)))
4745 (setq files (org-agenda-files nil 'ifmode)
4746 rtnall nil)
4747 (while (setq file (pop files))
4748 (catch 'nextfile
4749 (org-check-agenda-file file)
4750 (setq rtn (org-agenda-get-day-entries file date :todo))
4751 (setq rtnall (append rtnall rtn))))
4752 (if org-agenda-overriding-header
4753 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
4754 nil 'face 'org-agenda-structure) "\n")
4755 (insert "Global list of TODO items of type: ")
4756 (add-text-properties (point-min) (1- (point))
4757 (list 'face 'org-agenda-structure
4758 'short-heading
4759 (concat "ToDo: "
4760 (or org-select-this-todo-keyword "ALL"))))
4761 (org-agenda-mark-header-line (point-min))
271672fa
BG
4762 (insert (org-agenda-propertize-selected-todo-keywords
4763 org-select-this-todo-keyword))
8223b1d2
BG
4764 (setq pos (point))
4765 (unless org-agenda-multi
4766 (insert "Available with `N r': (0)[ALL]")
4767 (let ((n 0) s)
4768 (mapc (lambda (x)
4769 (setq s (format "(%d)%s" (setq n (1+ n)) x))
4770 (if (> (+ (current-column) (string-width s) 1) (frame-width))
4771 (insert "\n "))
4772 (insert " " s))
4773 kwds))
4774 (insert "\n"))
4775 (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure)))
8d642074 4776 (org-agenda-mark-header-line (point-min))
8223b1d2 4777 (when rtnall
271672fa 4778 (insert (org-agenda-finalize-entries rtnall 'todo) "\n"))
8223b1d2
BG
4779 (goto-char (point-min))
4780 (or org-agenda-multi (org-agenda-fit-window-to-buffer))
4781 (add-text-properties (point-min) (point-max)
4782 `(org-agenda-type todo
4783 org-last-args ,arg
4784 org-redo-cmd ,org-agenda-redo-command
735135f9 4785 org-series-cmd ,org-cmd))
8223b1d2
BG
4786 (org-agenda-finalize)
4787 (setq buffer-read-only t))))
20908596
CD
4788
4789;;; Agenda tags match
4790
4791;;;###autoload
4792(defun org-tags-view (&optional todo-only match)
4793 "Show all headlines for all `org-agenda-files' matching a TAGS criterion.
4794The prefix arg TODO-ONLY limits the search to TODO entries."
4795 (interactive "P")
8223b1d2
BG
4796 (if org-agenda-overriding-arguments
4797 (setq todo-only (car org-agenda-overriding-arguments)
4798 match (nth 1 org-agenda-overriding-arguments)))
20908596 4799 (let* ((org-tags-match-list-sublevels
c8d0cf5c 4800 org-tags-match-list-sublevels)
20908596
CD
4801 (completion-ignore-case t)
4802 rtn rtnall files file pos matcher
4803 buffer)
ed21c5c8
CD
4804 (when (and (stringp match) (not (string-match "\\S-" match)))
4805 (setq match nil))
8223b1d2
BG
4806 (catch 'exit
4807 (if org-agenda-sticky
4808 (setq org-agenda-buffer-name
4809 (if (stringp match)
4810 (format "*Org Agenda(%s:%s)*"
4811 (or org-keys (or (and todo-only "M") "m")) match)
4812 (format "*Org Agenda(%s)*" (or (and todo-only "M") "m")))))
271672fa
BG
4813 ;; Prepare agendas (and `org-tag-alist-for-agenda') before
4814 ;; expanding tags within `org-make-tags-matcher'
8223b1d2 4815 (org-agenda-prepare (concat "TAGS " match))
271672fa
BG
4816 (setq matcher (org-make-tags-matcher match)
4817 match (car matcher) matcher (cdr matcher))
8223b1d2
BG
4818 (org-compile-prefix-format 'tags)
4819 (org-set-sorting-strategy 'tags)
4820 (setq org-agenda-query-string match)
4821 (setq org-agenda-redo-command
4822 (list 'org-tags-view `(quote ,todo-only)
4823 (list 'if 'current-prefix-arg nil `(quote ,org-agenda-query-string))))
4824 (setq files (org-agenda-files nil 'ifmode)
4825 rtnall nil)
4826 (while (setq file (pop files))
4827 (catch 'nextfile
4828 (org-check-agenda-file file)
4829 (setq buffer (if (file-exists-p file)
4830 (org-get-agenda-file-buffer file)
4831 (error "No such file %s" file)))
4832 (if (not buffer)
4833 ;; If file does not exist, error message to agenda
4834 (setq rtn (list
4835 (format "ORG-AGENDA-ERROR: No such org-file %s" file))
4836 rtnall (append rtnall rtn))
4837 (with-current-buffer buffer
4838 (unless (derived-mode-p 'org-mode)
4839 (error "Agenda file %s is not in `org-mode'" file))
4840 (save-excursion
4841 (save-restriction
271672fa 4842 (if (eq buffer org-agenda-restrict)
8223b1d2
BG
4843 (narrow-to-region org-agenda-restrict-begin
4844 org-agenda-restrict-end)
4845 (widen))
4846 (setq rtn (org-scan-tags 'agenda matcher todo-only))
4847 (setq rtnall (append rtnall rtn))))))))
4848 (if org-agenda-overriding-header
4849 (insert (org-add-props (copy-sequence org-agenda-overriding-header)
4850 nil 'face 'org-agenda-structure) "\n")
4851 (insert "Headlines with TAGS match: ")
4852 (add-text-properties (point-min) (1- (point))
4853 (list 'face 'org-agenda-structure
4854 'short-heading
4855 (concat "Match: " match)))
4856 (setq pos (point))
4857 (insert match "\n")
4858 (add-text-properties pos (1- (point)) (list 'face 'org-warning))
4859 (setq pos (point))
4860 (unless org-agenda-multi
4861 (insert "Press `C-u r' to search again with new search string\n"))
4862 (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure)))
4863 (org-agenda-mark-header-line (point-min))
4864 (when rtnall
271672fa 4865 (insert (org-agenda-finalize-entries rtnall 'tags) "\n"))
8223b1d2
BG
4866 (goto-char (point-min))
4867 (or org-agenda-multi (org-agenda-fit-window-to-buffer))
4868 (add-text-properties (point-min) (point-max)
4869 `(org-agenda-type tags
4870 org-last-args (,todo-only ,match)
4871 org-redo-cmd ,org-agenda-redo-command
735135f9 4872 org-series-cmd ,org-cmd))
8223b1d2
BG
4873 (org-agenda-finalize)
4874 (setq buffer-read-only t))))
20908596
CD
4875
4876;;; Agenda Finding stuck projects
4877
4878(defvar org-agenda-skip-regexp nil
4879 "Regular expression used in skipping subtrees for the agenda.
4880This is basically a temporary global variable that can be set and then
4881used by user-defined selections using `org-agenda-skip-function'.")
4882
4883(defvar org-agenda-overriding-header nil
3ab2c837 4884 "When set during agenda, todo and tags searches it replaces the header.
c8d0cf5c
CD
4885This variable should not be set directly, but custom commands can bind it
4886in the options section.")
4887
4888(defun org-agenda-skip-entry-when-regexp-matches ()
86fbb8ca 4889 "Check if the current entry contains match for `org-agenda-skip-regexp'.
c8d0cf5c
CD
4890If yes, it returns the end position of this entry, causing agenda commands
4891to skip the entry but continuing the search in the subtree. This is a
4892function that can be put into `org-agenda-skip-function' for the duration
4893of a command."
4894 (let ((end (save-excursion (org-end-of-subtree t)))
4895 skip)
4896 (save-excursion
4897 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
4898 (and skip end)))
20908596
CD
4899
4900(defun org-agenda-skip-subtree-when-regexp-matches ()
86fbb8ca 4901 "Check if the current subtree contains match for `org-agenda-skip-regexp'.
20908596
CD
4902If yes, it returns the end position of this tree, causing agenda commands
4903to skip this subtree. This is a function that can be put into
4904`org-agenda-skip-function' for the duration of a command."
4905 (let ((end (save-excursion (org-end-of-subtree t)))
4906 skip)
4907 (save-excursion
4908 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
4909 (and skip end)))
4910
c8d0cf5c 4911(defun org-agenda-skip-entry-when-regexp-matches-in-subtree ()
86fbb8ca 4912 "Check if the current subtree contains match for `org-agenda-skip-regexp'.
c8d0cf5c
CD
4913If yes, it returns the end position of the current entry (NOT the tree),
4914causing agenda commands to skip the entry but continuing the search in
4915the subtree. This is a function that can be put into
4916`org-agenda-skip-function' for the duration of a command. An important
4917use of this function is for the stuck project list."
4918 (let ((end (save-excursion (org-end-of-subtree t)))
4919 (entry-end (save-excursion (outline-next-heading) (1- (point))))
4920 skip)
4921 (save-excursion
4922 (setq skip (re-search-forward org-agenda-skip-regexp end t)))
4923 (and skip entry-end)))
4924
20908596
CD
4925(defun org-agenda-skip-entry-if (&rest conditions)
4926 "Skip entry if any of CONDITIONS is true.
4927See `org-agenda-skip-if' for details."
4928 (org-agenda-skip-if nil conditions))
4929
4930(defun org-agenda-skip-subtree-if (&rest conditions)
30cb51f1 4931 "Skip subtree if any of CONDITIONS is true.
20908596
CD
4932See `org-agenda-skip-if' for details."
4933 (org-agenda-skip-if t conditions))
4934
4935(defun org-agenda-skip-if (subtree conditions)
4936 "Checks current entity for CONDITIONS.
4937If SUBTREE is non-nil, the entire subtree is checked. Otherwise, only
153ae947 4938the entry (i.e. the text before the next heading) is checked.
20908596
CD
4939
4940CONDITIONS is a list of symbols, boolean OR is used to combine the results
4941from different tests. Valid conditions are:
4942
4943scheduled Check if there is a scheduled cookie
4944notscheduled Check if there is no scheduled cookie
4945deadline Check if there is a deadline
4946notdeadline Check if there is no deadline
c8d0cf5c
CD
4947timestamp Check if there is a timestamp (also deadline or scheduled)
4948nottimestamp Check if there is no timestamp (also deadline or scheduled)
20908596
CD
4949regexp Check if regexp matches
4950notregexp Check if regexp does not match.
ed21c5c8
CD
4951todo Check if TODO keyword matches
4952nottodo Check if TODO keyword does not match
20908596
CD
4953
4954The regexp is taken from the conditions list, it must come right after
4955the `regexp' or `notregexp' element.
4956
ed21c5c8
CD
4957`todo' and `nottodo' accept as an argument a list of todo
4958keywords, which may include \"*\" to match any todo keyword.
4959
4960 (org-agenda-skip-entry-if 'todo '(\"TODO\" \"WAITING\"))
4961
4962would skip all entries with \"TODO\" or \"WAITING\" keywords.
4963
153ae947 4964Instead of a list, a keyword class may be given. For example:
ed21c5c8
CD
4965
4966 (org-agenda-skip-entry-if 'nottodo 'done)
4967
4968would skip entries that haven't been marked with any of \"DONE\"
153ae947 4969keywords. Possible classes are: `todo', `done', `any'.
ed21c5c8 4970
20908596
CD
4971If any of these conditions is met, this function returns the end point of
4972the entity, causing the search to continue from there. This is a function
4973that can be put into `org-agenda-skip-function' for the duration of a command."
4974 (let (beg end m)
4975 (org-back-to-heading t)
4976 (setq beg (point)
4977 end (if subtree
4978 (progn (org-end-of-subtree t) (point))
4979 (progn (outline-next-heading) (1- (point)))))
4980 (goto-char beg)
4981 (and
4982 (or
4983 (and (memq 'scheduled conditions)
4984 (re-search-forward org-scheduled-time-regexp end t))
4985 (and (memq 'notscheduled conditions)
4986 (not (re-search-forward org-scheduled-time-regexp end t)))
4987 (and (memq 'deadline conditions)
4988 (re-search-forward org-deadline-time-regexp end t))
4989 (and (memq 'notdeadline conditions)
4990 (not (re-search-forward org-deadline-time-regexp end t)))
c8d0cf5c
CD
4991 (and (memq 'timestamp conditions)
4992 (re-search-forward org-ts-regexp end t))
4993 (and (memq 'nottimestamp conditions)
4994 (not (re-search-forward org-ts-regexp end t)))
20908596
CD
4995 (and (setq m (memq 'regexp conditions))
4996 (stringp (nth 1 m))
4997 (re-search-forward (nth 1 m) end t))
4998 (and (setq m (memq 'notregexp conditions))
4999 (stringp (nth 1 m))
ed21c5c8
CD
5000 (not (re-search-forward (nth 1 m) end t)))
5001 (and (or
153ae947 5002 (setq m (memq 'nottodo conditions))
8223b1d2
BG
5003 (setq m (memq 'todo-unblocked conditions))
5004 (setq m (memq 'nottodo-unblocked conditions))
153ae947 5005 (setq m (memq 'todo conditions)))
ed21c5c8 5006 (org-agenda-skip-if-todo m end)))
20908596
CD
5007 end)))
5008
ed21c5c8
CD
5009(defun org-agenda-skip-if-todo (args end)
5010 "Helper function for `org-agenda-skip-if', do not use it directly.
8223b1d2
BG
5011ARGS is a list with first element either `todo', `nottodo',
5012`todo-unblocked' or `nottodo-unblocked'. The remainder is either
5013a list of TODO keywords, or a state symbol `todo' or `done' or
5014`any'."
ed21c5c8
CD
5015 (let ((kw (car args))
5016 (arg (cadr args))
5017 todo-wds todo-re)
5018 (setq todo-wds
5019 (org-uniquify
5020 (cond
5021 ((listp arg) ;; list of keywords
5022 (if (member "*" arg)
5023 (mapcar 'substring-no-properties org-todo-keywords-1)
5024 arg))
5025 ((symbolp arg) ;; keyword class name
5026 (cond
5027 ((eq arg 'todo)
5028 (org-delete-all org-done-keywords
5029 (mapcar 'substring-no-properties
5030 org-todo-keywords-1)))
5031 ((eq arg 'done) org-done-keywords)
5032 ((eq arg 'any)
5033 (mapcar 'substring-no-properties org-todo-keywords-1)))))))
5034 (setq todo-re
5035 (concat "^\\*+[ \t]+\\<\\("
5036 (mapconcat 'identity todo-wds "\\|")
5037 "\\)\\>"))
8223b1d2
BG
5038 (cond
5039 ((eq kw 'todo) (re-search-forward todo-re end t))
5040 ((eq kw 'nottodo) (not (re-search-forward todo-re end t)))
5041 ((eq kw 'todo-unblocked)
5042 (catch 'unblocked
5043 (while (re-search-forward todo-re end t)
5044 (or (org-entry-blocked-p) (throw 'unblocked t)))
5045 nil))
5046 ((eq kw 'nottodo-unblocked)
5047 (catch 'unblocked
5048 (while (re-search-forward todo-re end t)
5049 (or (org-entry-blocked-p) (throw 'unblocked nil)))
5050 t))
5051 )))
ed21c5c8 5052
20908596
CD
5053;;;###autoload
5054(defun org-agenda-list-stuck-projects (&rest ignore)
5055 "Create agenda view for projects that are stuck.
5056Stuck projects are project that have no next actions. For the definitions
5057of what a project is and how to check if it stuck, customize the variable
afe98dfa 5058`org-stuck-projects'."
20908596 5059 (interactive)
c8d0cf5c
CD
5060 (let* ((org-agenda-skip-function
5061 'org-agenda-skip-entry-when-regexp-matches-in-subtree)
20908596 5062 ;; We could have used org-agenda-skip-if here.
c8d0cf5c
CD
5063 (org-agenda-overriding-header
5064 (or org-agenda-overriding-header "List of stuck projects: "))
20908596
CD
5065 (matcher (nth 0 org-stuck-projects))
5066 (todo (nth 1 org-stuck-projects))
5067 (todo-wds (if (member "*" todo)
5068 (progn
8223b1d2 5069 (org-agenda-prepare-buffers (org-agenda-files
2c3ad40d 5070 nil 'ifmode))
20908596
CD
5071 (org-delete-all
5072 org-done-keywords-for-agenda
5073 (copy-sequence org-todo-keywords-for-agenda)))
5074 todo))
5075 (todo-re (concat "^\\*+[ \t]+\\("
5076 (mapconcat 'identity todo-wds "\\|")
5077 "\\)\\>"))
5078 (tags (nth 2 org-stuck-projects))
5079 (tags-re (if (member "*" tags)
e66ba1df
BG
5080 (concat org-outline-regexp-bol
5081 (org-re ".*:[[:alnum:]_@#%]+:[ \t]*$"))
c8d0cf5c 5082 (if tags
3ab2c837
BG
5083 (concat org-outline-regexp-bol
5084 ".*:\\("
c8d0cf5c 5085 (mapconcat 'identity tags "\\|")
afe98dfa 5086 (org-re "\\):[[:alnum:]_@#%:]*[ \t]*$")))))
20908596
CD
5087 (gen-re (nth 3 org-stuck-projects))
5088 (re-list
5089 (delq nil
5090 (list
5091 (if todo todo-re)
5092 (if tags tags-re)
5093 (and gen-re (stringp gen-re) (string-match "\\S-" gen-re)
5094 gen-re)))))
5095 (setq org-agenda-skip-regexp
5096 (if re-list
5097 (mapconcat 'identity re-list "\\|")
5098 (error "No information how to identify unstuck projects")))
5099 (org-tags-view nil matcher)
30cb51f1 5100 (setq org-agenda-buffer-name (buffer-name))
20908596
CD
5101 (with-current-buffer org-agenda-buffer-name
5102 (setq org-agenda-redo-command
8223b1d2 5103 `(org-agenda-list-stuck-projects ,current-prefix-arg)))))
20908596
CD
5104
5105;;; Diary integration
5106
5107(defvar org-disable-agenda-to-diary nil) ;Dynamically-scoped param.
8223b1d2 5108(defvar diary-list-entries-hook)
3ab2c837 5109(defvar diary-time-regexp)
20908596
CD
5110(defun org-get-entries-from-diary (date)
5111 "Get the (Emacs Calendar) diary entries for DATE."
5112 (require 'diary-lib)
5113 (let* ((diary-fancy-buffer "*temporary-fancy-diary-buffer*")
20908596 5114 (diary-display-hook '(fancy-diary-display))
ca8ef0dc 5115 (diary-display-function 'fancy-diary-display)
20908596 5116 (pop-up-frames nil)
8223b1d2
BG
5117 (diary-list-entries-hook
5118 (cons 'org-diary-default-entry diary-list-entries-hook))
a89c8ef0 5119 (diary-file-name-prefix nil) ; turn this feature off
20908596
CD
5120 (diary-modify-entry-list-string-function 'org-modify-diary-entry-string)
5121 entries
5122 (org-disable-agenda-to-diary t))
5123 (save-excursion
5124 (save-window-excursion
5125 (funcall (if (fboundp 'diary-list-entries)
5126 'diary-list-entries 'list-diary-entries)
5127 date 1)))
5128 (if (not (get-buffer diary-fancy-buffer))
5129 (setq entries nil)
5130 (with-current-buffer diary-fancy-buffer
5131 (setq buffer-read-only nil)
5132 (if (zerop (buffer-size))
5133 ;; No entries
5134 (setq entries nil)
5135 ;; Omit the date and other unnecessary stuff
5136 (org-agenda-cleanup-fancy-diary)
5137 ;; Add prefix to each line and extend the text properties
5138 (if (zerop (buffer-size))
5139 (setq entries nil)
3ab2c837
BG
5140 (setq entries (buffer-substring (point-min) (- (point-max) 1)))
5141 (setq entries
5142 (with-temp-buffer
5143 (insert entries) (goto-char (point-min))
5144 (while (re-search-forward "\n[ \t]+\\(.+\\)$" nil t)
5145 (unless (save-match-data (string-match diary-time-regexp (match-string 1)))
5146 (replace-match (concat "; " (match-string 1)))))
5147 (buffer-string)))))
20908596
CD
5148 (set-buffer-modified-p nil)
5149 (kill-buffer diary-fancy-buffer)))
5150 (when entries
5151 (setq entries (org-split-string entries "\n"))
5152 (setq entries
5153 (mapcar
5154 (lambda (x)
271672fa 5155 (setq x (org-agenda-format-item "" x nil "Diary" nil 'time))
20908596
CD
5156 ;; Extend the text properties to the beginning of the line
5157 (org-add-props x (text-properties-at (1- (length x)) x)
ed21c5c8 5158 'type "diary" 'date date 'face 'org-agenda-diary))
20908596
CD
5159 entries)))))
5160
c8d0cf5c
CD
5161(defvar org-agenda-cleanup-fancy-diary-hook nil
5162 "Hook run when the fancy diary buffer is cleaned up.")
5163
20908596
CD
5164(defun org-agenda-cleanup-fancy-diary ()
5165 "Remove unwanted stuff in buffer created by `fancy-diary-display'.
5166This gets rid of the date, the underline under the date, and
5167the dummy entry installed by `org-mode' to ensure non-empty diary for each
5168date. It also removes lines that contain only whitespace."
5169 (goto-char (point-min))
5170 (if (looking-at ".*?:[ \t]*")
5171 (progn
5172 (replace-match "")
5173 (re-search-forward "\n=+$" nil t)
5174 (replace-match "")
5175 (while (re-search-backward "^ +\n?" nil t) (replace-match "")))
5176 (re-search-forward "\n=+$" nil t)
5177 (delete-region (point-min) (min (point-max) (1+ (match-end 0)))))
5178 (goto-char (point-min))
5179 (while (re-search-forward "^ +\n" nil t)
5180 (replace-match ""))
5181 (goto-char (point-min))
5182 (if (re-search-forward "^Org-mode dummy\n?" nil t)
c8d0cf5c
CD
5183 (replace-match ""))
5184 (run-hooks 'org-agenda-cleanup-fancy-diary-hook))
20908596
CD
5185
5186;; Make sure entries from the diary have the right text properties.
5187(eval-after-load "diary-lib"
5188 '(if (boundp 'diary-modify-entry-list-string-function)
5189 ;; We can rely on the hook, nothing to do
5190 nil
33306645 5191 ;; Hook not available, must use advice to make this work
20908596
CD
5192 (defadvice add-to-diary-list (before org-mark-diary-entry activate)
5193 "Make the position visible."
5194 (if (and org-disable-agenda-to-diary ;; called from org-agenda
5195 (stringp string)
5196 buffer-file-name)
5197 (setq string (org-modify-diary-entry-string string))))))
5198
5199(defun org-modify-diary-entry-string (string)
e66ba1df 5200 "Add text properties to string, allowing org-mode to act on it."
20908596
CD
5201 (org-add-props string nil
5202 'mouse-face 'highlight
20908596
CD
5203 'help-echo (if buffer-file-name
5204 (format "mouse-2 or RET jump to diary file %s"
5205 (abbreviate-file-name buffer-file-name))
5206 "")
5207 'org-agenda-diary-link t
5208 'org-marker (org-agenda-new-marker (point-at-bol))))
5209
5210(defun org-diary-default-entry ()
5211 "Add a dummy entry to the diary.
5212Needed to avoid empty dates which mess up holiday display."
5213 ;; Catch the error if dealing with the new add-to-diary-alist
5214 (when org-disable-agenda-to-diary
5215 (condition-case nil
5216 (org-add-to-diary-list original-date "Org-mode dummy" "")
5217 (error
5218 (org-add-to-diary-list original-date "Org-mode dummy" "" nil)))))
5219
5220(defun org-add-to-diary-list (&rest args)
5221 (if (fboundp 'diary-add-to-list)
5222 (apply 'diary-add-to-list args)
5223 (apply 'add-to-diary-list args)))
5224
ed21c5c8
CD
5225(defvar org-diary-last-run-time nil)
5226
20908596
CD
5227;;;###autoload
5228(defun org-diary (&rest args)
8223b1d2 5229 "Return diary information from org files.
20908596
CD
5230This function can be used in a \"sexp\" diary entry in the Emacs calendar.
5231It accesses org files and extracts information from those files to be
5232listed in the diary. The function accepts arguments specifying what
ed21c5c8
CD
5233items should be listed. For a list of arguments allowed here, see the
5234variable `org-agenda-entry-types'.
20908596
CD
5235
5236The call in the diary file should look like this:
5237
5238 &%%(org-diary) ~/path/to/some/orgfile.org
5239
5240Use a separate line for each org file to check. Or, if you omit the file name,
5241all files listed in `org-agenda-files' will be checked automatically:
5242
5243 &%%(org-diary)
5244
271672fa
BG
5245If you don't give any arguments (as in the example above), the default value
5246of `org-agenda-entry-types' is used: (:deadline :scheduled :timestamp :sexp).
20908596
CD
5247So the example above may also be written as
5248
5249 &%%(org-diary :deadline :timestamp :sexp :scheduled)
5250
5251The function expects the lisp variables `entry' and `date' to be provided
5252by the caller, because this is how the calendar works. Don't use this
5253function from a program - use `org-agenda-get-day-entries' instead."
54a0dee5 5254 (when (> (- (org-float-time)
20908596
CD
5255 org-agenda-last-marker-time)
5256 5)
8223b1d2
BG
5257 ;; I am not sure if this works with sticky agendas, because the marker
5258 ;; list is then no longer a global variable.
20908596
CD
5259 (org-agenda-reset-markers))
5260 (org-compile-prefix-format 'agenda)
5261 (org-set-sorting-strategy 'agenda)
271672fa 5262 (setq args (or args org-agenda-entry-types))
23f6720e
BG
5263 (let* ((files (if (and entry (stringp entry) (string-match "\\S-" entry))
5264 (list entry)
20908596 5265 (org-agenda-files t)))
ed21c5c8 5266 (time (org-float-time))
20908596 5267 file rtn results)
ed21c5c8
CD
5268 (when (or (not org-diary-last-run-time)
5269 (> (- time
5270 org-diary-last-run-time)
5271 3))
8223b1d2 5272 (org-agenda-prepare-buffers files))
ed21c5c8 5273 (setq org-diary-last-run-time time)
20908596
CD
5274 ;; If this is called during org-agenda, don't return any entries to
5275 ;; the calendar. Org Agenda will list these entries itself.
5276 (if org-disable-agenda-to-diary (setq files nil))
5277 (while (setq file (pop files))
5278 (setq rtn (apply 'org-agenda-get-day-entries file date args))
5279 (setq results (append results rtn)))
271672fa
BG
5280 (when results
5281 (setq results
5282 (mapcar (lambda (i) (replace-regexp-in-string
5283 org-bracket-link-regexp "\\3" i)) results))
5284 (concat (org-agenda-finalize-entries results) "\n"))))
20908596
CD
5285
5286;;; Agenda entry finders
5287
5288(defun org-agenda-get-day-entries (file date &rest args)
5289 "Does the work for `org-diary' and `org-agenda'.
5290FILE is the path to a file to be checked for entries. DATE is date like
5291the one returned by `calendar-current-date'. ARGS are symbols indicating
5292which kind of entries should be extracted. For details about these, see
5293the documentation of `org-diary'."
271672fa 5294 (setq args (or args org-agenda-entry-types))
20908596
CD
5295 (let* ((org-startup-folded nil)
5296 (org-startup-align-all-tables nil)
5297 (buffer (if (file-exists-p file)
5298 (org-get-agenda-file-buffer file)
5299 (error "No such file %s" file)))
54a0dee5 5300 arg results rtn deadline-results)
20908596
CD
5301 (if (not buffer)
5302 ;; If file does not exist, make sure an error message ends up in diary
5303 (list (format "ORG-AGENDA-ERROR: No such org-file %s" file))
5304 (with-current-buffer buffer
8223b1d2 5305 (unless (derived-mode-p 'org-mode)
20908596 5306 (error "Agenda file %s is not in `org-mode'" file))
8223b1d2 5307 (setq org-agenda-buffer (or org-agenda-buffer buffer))
20908596
CD
5308 (let ((case-fold-search nil))
5309 (save-excursion
5310 (save-restriction
271672fa 5311 (if (eq buffer org-agenda-restrict)
20908596
CD
5312 (narrow-to-region org-agenda-restrict-begin
5313 org-agenda-restrict-end)
5314 (widen))
5315 ;; The way we repeatedly append to `results' makes it O(n^2) :-(
5316 (while (setq arg (pop args))
5317 (cond
5318 ((and (eq arg :todo)
3ab2c837
BG
5319 (equal date (calendar-gregorian-from-absolute
5320 (org-today))))
20908596
CD
5321 (setq rtn (org-agenda-get-todos))
5322 (setq results (append results rtn)))
5323 ((eq arg :timestamp)
5324 (setq rtn (org-agenda-get-blocks))
5325 (setq results (append results rtn))
8223b1d2 5326 (setq rtn (org-agenda-get-timestamps deadline-results))
20908596
CD
5327 (setq results (append results rtn)))
5328 ((eq arg :sexp)
5329 (setq rtn (org-agenda-get-sexps))
5330 (setq results (append results rtn)))
5331 ((eq arg :scheduled)
54a0dee5 5332 (setq rtn (org-agenda-get-scheduled deadline-results))
20908596 5333 (setq results (append results rtn)))
271672fa
BG
5334 ((eq arg :scheduled*)
5335 (setq rtn (org-agenda-get-scheduled deadline-results t))
5336 (setq results (append results rtn)))
20908596 5337 ((eq arg :closed)
93b62de8 5338 (setq rtn (org-agenda-get-progress))
20908596
CD
5339 (setq results (append results rtn)))
5340 ((eq arg :deadline)
5341 (setq rtn (org-agenda-get-deadlines))
54a0dee5 5342 (setq deadline-results (copy-sequence rtn))
271672fa
BG
5343 (setq results (append results rtn)))
5344 ((eq arg :deadline*)
5345 (setq rtn (org-agenda-get-deadlines t))
5346 (setq deadline-results (copy-sequence rtn))
20908596
CD
5347 (setq results (append results rtn))))))))
5348 results))))
5349
271672fa
BG
5350(defsubst org-em (x y list)
5351 "Is X or Y a member of LIST?"
5352 (or (memq x list) (memq y list)))
5353
e66ba1df 5354(defvar org-heading-keyword-regexp-format) ; defined in org.el
271672fa
BG
5355(defvar org-agenda-sorting-strategy-selected nil)
5356
20908596
CD
5357(defun org-agenda-get-todos ()
5358 "Return the TODO information for agenda display."
5359 (let* ((props (list 'face nil
c8d0cf5c 5360 'done-face 'org-agenda-done
20908596
CD
5361 'org-not-done-regexp org-not-done-regexp
5362 'org-todo-regexp org-todo-regexp
b349f79f 5363 'org-complex-heading-regexp org-complex-heading-regexp
20908596 5364 'mouse-face 'highlight
20908596
CD
5365 'help-echo
5366 (format "mouse-2 or RET jump to org file %s"
5367 (abbreviate-file-name buffer-file-name))))
e66ba1df
BG
5368 (regexp (format org-heading-keyword-regexp-format
5369 (cond
5370 ((and org-select-this-todo-keyword
5371 (equal org-select-this-todo-keyword "*"))
5372 org-todo-regexp)
5373 (org-select-this-todo-keyword
5374 (concat "\\("
5375 (mapconcat 'identity
5376 (org-split-string
5377 org-select-this-todo-keyword
5378 "|")
5379 "\\|") "\\)"))
5380 (t org-not-done-regexp))))
271672fa
BG
5381 marker priority category category-pos level tags todo-state ts-date ts-date-type
5382 ee txt beg end inherited-tags todo-state-end-pos)
20908596
CD
5383 (goto-char (point-min))
5384 (while (re-search-forward regexp nil t)
5385 (catch :skip
5386 (save-match-data
5387 (beginning-of-line)
3ab2c837 5388 (org-agenda-skip)
d6685abc 5389 (setq beg (point) end (save-excursion (outline-next-heading) (point)))
271672fa
BG
5390 (unless (and (setq todo-state (org-get-todo-state))
5391 (setq todo-state-end-pos (match-end 2)))
5392 (goto-char end)
5393 (throw :skip nil))
0bd48b37 5394 (when (org-agenda-check-for-timestamp-as-reason-to-ignore-todo-item end)
20908596
CD
5395 (goto-char (1+ beg))
5396 (or org-agenda-todo-list-sublevels (org-end-of-subtree 'invisible))
5397 (throw :skip nil)))
e66ba1df 5398 (goto-char (match-beginning 2))
20908596
CD
5399 (setq marker (org-agenda-new-marker (match-beginning 0))
5400 category (org-get-category)
271672fa
BG
5401 ts-date (let (ts)
5402 (save-match-data
5403 (cond ((org-em 'scheduled-up 'scheduled-down
5404 org-agenda-sorting-strategy-selected)
5405 (setq ts (org-entry-get (point) "SCHEDULED")
5406 ts-date-type " scheduled"))
5407 ((org-em 'deadline-up 'deadline-down
5408 org-agenda-sorting-strategy-selected)
5409 (setq ts (org-entry-get (point) "DEADLINE")
5410 ts-date-type " deadline"))
5411 ((org-em 'ts-up 'ts-down
5412 org-agenda-sorting-strategy-selected)
5413 (setq ts (org-entry-get (point) "TIMESTAMP")
5414 ts-date-type " timestamp"))
5415 ((org-em 'tsia-up 'tsia-down
5416 org-agenda-sorting-strategy-selected)
5417 (setq ts (org-entry-get (point) "TIMESTAMP_IA")
5418 ts-date-type " timestamp_ia"))
5419 ((org-em 'timestamp-up 'timestamp-down
5420 org-agenda-sorting-strategy-selected)
5421 (setq ts (or (org-entry-get (point) "SCHEDULED")
5422 (org-entry-get (point) "DEADLINE")
5423 (org-entry-get (point) "TIMESTAMP")
5424 (org-entry-get (point) "TIMESTAMP_IA"))
5425 ts-date-type ""))
5426 (t (setq ts-date-type "")))
5427 (when ts (ignore-errors (org-time-string-to-absolute ts)))))
8223b1d2 5428 category-pos (get-text-property (point) 'org-category-position)
e66ba1df
BG
5429 txt (org-trim
5430 (buffer-substring (match-beginning 2) (match-end 0)))
a89c8ef0
BG
5431 inherited-tags
5432 (or (eq org-agenda-show-inherited-tags 'always)
5433 (and (listp org-agenda-show-inherited-tags)
5434 (memq 'todo org-agenda-show-inherited-tags))
5435 (and (eq org-agenda-show-inherited-tags t)
5436 (or (eq org-agenda-use-tag-inheritance t)
5437 (memq 'todo org-agenda-use-tag-inheritance))))
5438 tags (org-get-tags-at nil (not inherited-tags))
271672fa
BG
5439 level (make-string (org-reduced-level (org-outline-level)) ? )
5440 txt (org-agenda-format-item "" txt level category tags t)
5441 priority (1+ (org-get-priority txt)))
20908596
CD
5442 (org-add-props txt props
5443 'org-marker marker 'org-hd-marker marker
5444 'priority priority 'org-category category
271672fa
BG
5445 'level level
5446 'ts-date ts-date
8223b1d2 5447 'org-category-position category-pos
271672fa 5448 'type (concat "todo" ts-date-type) 'todo-state todo-state)
20908596
CD
5449 (push txt ee)
5450 (if org-agenda-todo-list-sublevels
271672fa 5451 (goto-char todo-state-end-pos)
20908596
CD
5452 (org-end-of-subtree 'invisible))))
5453 (nreverse ee)))
5454
3ab2c837 5455(defun org-agenda-todo-custom-ignore-p (time n)
8223b1d2 5456 "Check whether timestamp is farther away than n number of days.
3ab2c837
BG
5457This function is invoked if `org-agenda-todo-ignore-deadlines',
5458`org-agenda-todo-ignore-scheduled' or
5459`org-agenda-todo-ignore-timestamp' is set to an integer."
271672fa
BG
5460 (let ((days (org-time-stamp-to-now
5461 time org-agenda-todo-ignore-time-comparison-use-seconds)))
3ab2c837
BG
5462 (if (>= n 0)
5463 (>= days n)
5464 (<= days n))))
5465
73d3db82 5466;;;###autoload
ed21c5c8 5467(defun org-agenda-check-for-timestamp-as-reason-to-ignore-todo-item
30cb51f1 5468 (&optional end)
ed21c5c8 5469 "Do we have a reason to ignore this TODO entry because it has a time stamp?"
0bd48b37
CD
5470 (when (or org-agenda-todo-ignore-with-date
5471 org-agenda-todo-ignore-scheduled
acedf35c
CD
5472 org-agenda-todo-ignore-deadlines
5473 org-agenda-todo-ignore-timestamp)
0bd48b37
CD
5474 (setq end (or end (save-excursion (outline-next-heading) (point))))
5475 (save-excursion
5476 (or (and org-agenda-todo-ignore-with-date
5477 (re-search-forward org-ts-regexp end t))
5478 (and org-agenda-todo-ignore-scheduled
ed21c5c8
CD
5479 (re-search-forward org-scheduled-time-regexp end t)
5480 (cond
5481 ((eq org-agenda-todo-ignore-scheduled 'future)
271672fa
BG
5482 (> (org-time-stamp-to-now
5483 (match-string 1) org-agenda-todo-ignore-time-comparison-use-seconds) 0))
ed21c5c8 5484 ((eq org-agenda-todo-ignore-scheduled 'past)
271672fa
BG
5485 (<= (org-time-stamp-to-now
5486 (match-string 1) org-agenda-todo-ignore-time-comparison-use-seconds) 0))
3ab2c837
BG
5487 ((numberp org-agenda-todo-ignore-scheduled)
5488 (org-agenda-todo-custom-ignore-p
5489 (match-string 1) org-agenda-todo-ignore-scheduled))
ed21c5c8 5490 (t)))
0bd48b37
CD
5491 (and org-agenda-todo-ignore-deadlines
5492 (re-search-forward org-deadline-time-regexp end t)
ed21c5c8
CD
5493 (cond
5494 ((memq org-agenda-todo-ignore-deadlines '(t all)) t)
5495 ((eq org-agenda-todo-ignore-deadlines 'far)
5496 (not (org-deadline-close (match-string 1))))
5497 ((eq org-agenda-todo-ignore-deadlines 'future)
271672fa
BG
5498 (> (org-time-stamp-to-now
5499 (match-string 1) org-agenda-todo-ignore-time-comparison-use-seconds) 0))
ed21c5c8 5500 ((eq org-agenda-todo-ignore-deadlines 'past)
271672fa
BG
5501 (<= (org-time-stamp-to-now
5502 (match-string 1) org-agenda-todo-ignore-time-comparison-use-seconds) 0))
3ab2c837
BG
5503 ((numberp org-agenda-todo-ignore-deadlines)
5504 (org-agenda-todo-custom-ignore-p
5505 (match-string 1) org-agenda-todo-ignore-deadlines))
acedf35c
CD
5506 (t (org-deadline-close (match-string 1)))))
5507 (and org-agenda-todo-ignore-timestamp
5508 (let ((buffer (current-buffer))
5509 (regexp
5510 (concat
5511 org-scheduled-time-regexp "\\|" org-deadline-time-regexp))
5512 (start (point)))
5513 ;; Copy current buffer into a temporary one
5514 (with-temp-buffer
5515 (insert-buffer-substring buffer start end)
5516 (goto-char (point-min))
5517 ;; Delete SCHEDULED and DEADLINE items
5518 (while (re-search-forward regexp end t)
5519 (delete-region (match-beginning 0) (match-end 0)))
5520 (goto-char (point-min))
5521 ;; No search for timestamp left
5522 (when (re-search-forward org-ts-regexp nil t)
5523 (cond
5524 ((eq org-agenda-todo-ignore-timestamp 'future)
271672fa
BG
5525 (> (org-time-stamp-to-now
5526 (match-string 1) org-agenda-todo-ignore-time-comparison-use-seconds) 0))
acedf35c 5527 ((eq org-agenda-todo-ignore-timestamp 'past)
271672fa
BG
5528 (<= (org-time-stamp-to-now
5529 (match-string 1) org-agenda-todo-ignore-time-comparison-use-seconds) 0))
3ab2c837
BG
5530 ((numberp org-agenda-todo-ignore-timestamp)
5531 (org-agenda-todo-custom-ignore-p
5532 (match-string 1) org-agenda-todo-ignore-timestamp))
acedf35c 5533 (t))))))))))
0bd48b37 5534
8223b1d2 5535(defun org-agenda-get-timestamps (&optional deadline-results)
20908596 5536 "Return the date stamp information for agenda display."
e66ba1df 5537 (let* ((props (list 'face 'org-agenda-calendar-event
20908596
CD
5538 'org-not-done-regexp org-not-done-regexp
5539 'org-todo-regexp org-todo-regexp
b349f79f 5540 'org-complex-heading-regexp org-complex-heading-regexp
20908596 5541 'mouse-face 'highlight
20908596
CD
5542 'help-echo
5543 (format "mouse-2 or RET jump to org file %s"
5544 (abbreviate-file-name buffer-file-name))))
5545 (d1 (calendar-absolute-from-gregorian date))
8223b1d2
BG
5546 mm
5547 (deadline-position-alist
5548 (mapcar (lambda (a) (and (setq mm (get-text-property
5549 0 'org-hd-marker a))
5550 (cons (marker-position mm) a)))
5551 deadline-results))
5552 (remove-re org-ts-regexp)
20908596
CD
5553 (regexp
5554 (concat
5555 (if org-agenda-include-inactive-timestamps "[[<]" "<")
5556 (regexp-quote
5557 (substring
5558 (format-time-string
5559 (car org-time-stamp-formats)
5560 (apply 'encode-time ; DATE bound by calendar
5561 (list 0 0 0 (nth 1 date) (car date) (nth 2 date))))
5562 1 11))
8223b1d2 5563 "\\|\\(<[0-9]+-[0-9]+-[0-9]+[^>\n]+?\\+[0-9]+[hdwmy]>\\)"
20908596
CD
5564 "\\|\\(<%%\\(([^>\n]+)\\)>\\)"))
5565 marker hdmarker deadlinep scheduledp clockp closedp inactivep
271672fa 5566 donep tmp priority category category-pos level ee txt timestr tags
a89c8ef0 5567 b0 b3 e3 head todo-state end-of-match show-all warntime habitp
271672fa 5568 inherited-tags ts-date)
20908596 5569 (goto-char (point-min))
c8d0cf5c 5570 (while (setq end-of-match (re-search-forward regexp nil t))
20908596 5571 (setq b0 (match-beginning 0)
3ab2c837
BG
5572 b3 (match-beginning 3) e3 (match-end 3)
5573 todo-state (save-match-data (ignore-errors (org-get-todo-state)))
bdebdb64 5574 habitp (and (functionp 'org-is-habit-p) (save-match-data (org-is-habit-p)))
3ab2c837
BG
5575 show-all (or (eq org-agenda-repeating-timestamp-show-all t)
5576 (member todo-state
5577 org-agenda-repeating-timestamp-show-all)))
20908596
CD
5578 (catch :skip
5579 (and (org-at-date-range-p) (throw :skip nil))
5580 (org-agenda-skip)
5581 (if (and (match-end 1)
5582 (not (= d1 (org-time-string-to-absolute
e66ba1df
BG
5583 (match-string 1) d1 nil show-all
5584 (current-buffer) b0))))
20908596
CD
5585 (throw :skip nil))
5586 (if (and e3
5587 (not (org-diary-sexp-entry (buffer-substring b3 e3) "" date)))
5588 (throw :skip nil))
c8d0cf5c 5589 (setq tmp (buffer-substring (max (point-min)
20908596
CD
5590 (- b0 org-ds-keyword-length))
5591 b0)
5592 timestr (if b3 "" (buffer-substring b0 (point-at-eol)))
5593 inactivep (= (char-after b0) ?\[)
5594 deadlinep (string-match org-deadline-regexp tmp)
5595 scheduledp (string-match org-scheduled-regexp tmp)
5596 closedp (and org-agenda-include-inactive-timestamps
5597 (string-match org-closed-string tmp))
5598 clockp (and org-agenda-include-inactive-timestamps
5599 (or (string-match org-clock-string tmp)
5600 (string-match "]-+\\'" tmp)))
c7cf0ebc 5601 warntime (get-text-property (point) 'org-appt-warntime)
621f83e4 5602 donep (member todo-state org-done-keywords))
c8d0cf5c
CD
5603 (if (or scheduledp deadlinep closedp clockp
5604 (and donep org-agenda-skip-timestamp-if-done))
20908596
CD
5605 (throw :skip t))
5606 (if (string-match ">" timestr)
5607 ;; substring should only run to end of time stamp
5608 (setq timestr (substring timestr 0 (match-end 0))))
c8d0cf5c 5609 (setq marker (org-agenda-new-marker b0)
e66ba1df 5610 category (org-get-category b0)
8223b1d2 5611 category-pos (get-text-property b0 'org-category-position))
20908596 5612 (save-excursion
3ab2c837 5613 (if (not (re-search-backward org-outline-regexp-bol nil t))
d3517077 5614 (throw :skip nil)
c8d0cf5c 5615 (goto-char (match-beginning 0))
8223b1d2
BG
5616 (if (and (eq t org-agenda-skip-timestamp-if-deadline-is-shown)
5617 (assoc (point) deadline-position-alist))
5618 (throw :skip nil))
c8d0cf5c 5619 (setq hdmarker (org-agenda-new-marker)
a89c8ef0
BG
5620 inherited-tags
5621 (or (eq org-agenda-show-inherited-tags 'always)
5622 (and (listp org-agenda-show-inherited-tags)
5623 (memq 'agenda org-agenda-show-inherited-tags))
5624 (and (eq org-agenda-show-inherited-tags t)
5625 (or (eq org-agenda-use-tag-inheritance t)
5626 (memq 'agenda org-agenda-use-tag-inheritance))))
271672fa
BG
5627 tags (org-get-tags-at nil (not inherited-tags))
5628 level (make-string (org-reduced-level (org-outline-level)) ? ))
c8d0cf5c 5629 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
3ab2c837 5630 (setq head (or (match-string 1) ""))
e66ba1df 5631 (setq txt (org-agenda-format-item
ed21c5c8 5632 (if inactivep org-agenda-inactive-leader nil)
271672fa 5633 head level category tags timestr
bdebdb64 5634 remove-re habitp)))
20908596 5635 (setq priority (org-get-priority txt))
271672fa
BG
5636 (org-add-props txt props 'priority priority
5637 'org-marker marker 'org-hd-marker hdmarker
20908596 5638 'org-category category 'date date
271672fa
BG
5639 'level level
5640 'ts-date
5641 (ignore-errors (org-time-string-to-absolute timestr))
8223b1d2 5642 'org-category-position category-pos
621f83e4 5643 'todo-state todo-state
8223b1d2 5644 'warntime warntime
20908596
CD
5645 'type "timestamp")
5646 (push txt ee))
c8d0cf5c
CD
5647 (if org-agenda-skip-additional-timestamps-same-entry
5648 (outline-next-heading)
5649 (goto-char end-of-match))))
20908596
CD
5650 (nreverse ee)))
5651
5652(defun org-agenda-get-sexps ()
5653 "Return the sexp information for agenda display."
5654 (require 'diary-lib)
e66ba1df
BG
5655 (let* ((props (list 'face 'org-agenda-calendar-sexp
5656 'mouse-face 'highlight
20908596
CD
5657 'help-echo
5658 (format "mouse-2 or RET jump to org file %s"
5659 (abbreviate-file-name buffer-file-name))))
5660 (regexp "^&?%%(")
271672fa 5661 marker category extra category-pos level ee txt tags entry
a89c8ef0 5662 result beg b sexp sexp-entry todo-state warntime inherited-tags)
20908596
CD
5663 (goto-char (point-min))
5664 (while (re-search-forward regexp nil t)
5665 (catch :skip
5666 (org-agenda-skip)
5667 (setq beg (match-beginning 0))
5668 (goto-char (1- (match-end 0)))
5669 (setq b (point))
5670 (forward-sexp 1)
5671 (setq sexp (buffer-substring b (point)))
5672 (setq sexp-entry (if (looking-at "[ \t]*\\(\\S-.*\\)")
5673 (org-trim (match-string 1))
5674 ""))
5675 (setq result (org-diary-sexp-entry sexp sexp-entry date))
5676 (when result
5677 (setq marker (org-agenda-new-marker beg)
271672fa 5678 level (make-string (org-reduced-level (org-outline-level)) ? )
c8d0cf5c 5679 category (org-get-category beg)
8223b1d2 5680 category-pos (get-text-property beg 'org-category-position)
a89c8ef0
BG
5681 inherited-tags
5682 (or (eq org-agenda-show-inherited-tags 'always)
5683 (and (listp org-agenda-show-inherited-tags)
5684 (memq 'agenda org-agenda-show-inherited-tags))
5685 (and (eq org-agenda-show-inherited-tags t)
5686 (or (eq org-agenda-use-tag-inheritance t)
5687 (memq 'agenda org-agenda-use-tag-inheritance))))
5688 tags (org-get-tags-at nil (not inherited-tags))
8223b1d2 5689 todo-state (org-get-todo-state)
c7cf0ebc 5690 warntime (get-text-property (point) 'org-appt-warntime)
bdebdb64 5691 extra nil)
20908596 5692
afe98dfa
CD
5693 (dolist (r (if (stringp result)
5694 (list result)
5695 result)) ;; we expect a list here
8223b1d2
BG
5696 (when (and org-agenda-diary-sexp-prefix
5697 (string-match org-agenda-diary-sexp-prefix r))
5698 (setq extra (match-string 0 r)
5699 r (replace-match "" nil nil r)))
afe98dfa
CD
5700 (if (string-match "\\S-" r)
5701 (setq txt r)
5702 (setq txt "SEXP entry returned empty string"))
271672fa
BG
5703 (setq txt (org-agenda-format-item extra txt level category tags 'time))
5704 (org-add-props txt props 'org-marker marker
30cb51f1
BG
5705 'org-category category 'date date 'todo-state todo-state
5706 'org-category-position category-pos 'tags tags
5707 'level level
5708 'type "sexp" 'warntime warntime)
afe98dfa 5709 (push txt ee)))))
20908596
CD
5710 (nreverse ee)))
5711
3ab2c837
BG
5712;; Calendar sanity: define some functions that are independent of
5713;; `calendar-date-style'.
5714;; Normally I would like to use ISO format when calling the diary functions,
5715;; but to make sure we still have Emacs 22 compatibility we bind
5716;; also `european-calendar-style' and use european format
5717(defun org-anniversary (year month day &optional mark)
5718 "Like `diary-anniversary', but with fixed (ISO) order of arguments."
5719 (org-no-warnings
5720 (let ((calendar-date-style 'european) (european-calendar-style t))
5721 (diary-anniversary day month year mark))))
5722(defun org-cyclic (N year month day &optional mark)
5723 "Like `diary-cyclic', but with fixed (ISO) order of arguments."
5724 (org-no-warnings
5725 (let ((calendar-date-style 'european) (european-calendar-style t))
5726 (diary-cyclic N day month year mark))))
5727(defun org-block (Y1 M1 D1 Y2 M2 D2 &optional mark)
5728 "Like `diary-block', but with fixed (ISO) order of arguments."
5729 (org-no-warnings
5730 (let ((calendar-date-style 'european) (european-calendar-style t))
5731 (diary-block D1 M1 Y1 D2 M2 Y2 mark))))
5732(defun org-date (year month day &optional mark)
5733 "Like `diary-date', but with fixed (ISO) order of arguments."
5734 (org-no-warnings
5735 (let ((calendar-date-style 'european) (european-calendar-style t))
5736 (diary-date day month year mark))))
3ab2c837
BG
5737
5738;; Define the` org-class' function
5739(defun org-class (y1 m1 d1 y2 m2 d2 dayname &rest skip-weeks)
ed21c5c8 5740 "Entry applies if date is between dates on DAYNAME, but skips SKIP-WEEKS.
e66ba1df
BG
5741DAYNAME is a number between 0 (Sunday) and 6 (Saturday).
5742SKIP-WEEKS is any number of ISO weeks in the block period for which the
5743item should be skipped. If any of the SKIP-WEEKS arguments is the symbol
5744`holidays', then any date that is known by the Emacs calendar to be a
271672fa
BG
5745holiday will also be skipped. If SKIP-WEEKS arguments are holiday strings,
5746then those holidays will be skipped."
3ab2c837
BG
5747 (let* ((date1 (calendar-absolute-from-gregorian (list m1 d1 y1)))
5748 (date2 (calendar-absolute-from-gregorian (list m2 d2 y2)))
271672fa
BG
5749 (d (calendar-absolute-from-gregorian date))
5750 (h (when skip-weeks (calendar-check-holidays date))))
ed21c5c8
CD
5751 (and
5752 (<= date1 d)
5753 (<= d date2)
5754 (= (calendar-day-of-week date) dayname)
5755 (or (not skip-weeks)
5756 (progn
5757 (require 'cal-iso)
5758 (not (member (car (calendar-iso-from-absolute d)) skip-weeks))))
271672fa
BG
5759 (not (or (and h (memq 'holidays skip-weeks))
5760 (delq nil (mapcar (lambda(g) (member g skip-weeks)) h))))
23f6720e 5761 entry)))
ed21c5c8 5762
3ab2c837
BG
5763(defun org-diary-class (m1 d1 y1 m2 d2 y2 dayname &rest skip-weeks)
5764 "Like `org-class', but honor `calendar-date-style'.
5765The order of the first 2 times 3 arguments depends on the variable
5766`calendar-date-style' or, if that is not defined, on `european-calendar-style'.
5767So for American calendars, give this as MONTH DAY YEAR, for European as
5768DAY MONTH YEAR, and for ISO as YEAR MONTH DAY.
5769DAYNAME is a number between 0 (Sunday) and 6 (Saturday). SKIP-WEEKS
5770is any number of ISO weeks in the block period for which the item should
5771be skipped.
5772
5773This function is here only for backward compatibility and it is deprecated,
5774please use `org-class' instead."
5775 (let* ((date1 (org-order-calendar-date-args m1 d1 y1))
5776 (date2 (org-order-calendar-date-args m2 d2 y2)))
5777 (org-class
5778 (nth 2 date1) (car date1) (nth 1 date1)
5779 (nth 2 date2) (car date2) (nth 1 date2)
5780 dayname skip-weeks)))
e66ba1df 5781(make-obsolete 'org-diary-class 'org-class "")
3ab2c837 5782
d60b1ba1 5783(defalias 'org-get-closed 'org-agenda-get-progress)
93b62de8 5784(defun org-agenda-get-progress ()
20908596
CD
5785 "Return the logged TODO entries for agenda display."
5786 (let* ((props (list 'mouse-face 'highlight
5787 'org-not-done-regexp org-not-done-regexp
5788 'org-todo-regexp org-todo-regexp
b349f79f 5789 'org-complex-heading-regexp org-complex-heading-regexp
20908596
CD
5790 'help-echo
5791 (format "mouse-2 or RET jump to org file %s"
5792 (abbreviate-file-name buffer-file-name))))
8223b1d2
BG
5793 (items (if (consp org-agenda-show-log-scoped)
5794 org-agenda-show-log-scoped
5795 (if (eq org-agenda-show-log-scoped 'clockcheck)
3ab2c837
BG
5796 '(clock)
5797 org-agenda-log-mode-items)))
ff4be292 5798 (parts
93b62de8
CD
5799 (delq nil
5800 (list
5801 (if (memq 'closed items) (concat "\\<" org-closed-string))
5802 (if (memq 'clock items) (concat "\\<" org-clock-string))
c8d0cf5c 5803 (if (memq 'state items) "- State \"\\([a-zA-Z0-9]+\\)\".*?"))))
93b62de8
CD
5804 (parts-re (if parts (mapconcat 'identity parts "\\|")
5805 (error "`org-agenda-log-mode-items' is empty")))
20908596 5806 (regexp (concat
93b62de8
CD
5807 "\\(" parts-re "\\)"
5808 " *\\["
20908596
CD
5809 (regexp-quote
5810 (substring
5811 (format-time-string
5812 (car org-time-stamp-formats)
5813 (apply 'encode-time ; DATE bound by calendar
5814 (list 0 0 0 (nth 1 date) (car date) (nth 2 date))))
5815 1 11))))
c8d0cf5c 5816 (org-agenda-search-headline-for-time nil)
271672fa 5817 marker hdmarker priority category category-pos level tags closedp
a89c8ef0 5818 statep clockp state ee txt extra timestr rest clocked inherited-tags)
20908596
CD
5819 (goto-char (point-min))
5820 (while (re-search-forward regexp nil t)
5821 (catch :skip
5822 (org-agenda-skip)
5823 (setq marker (org-agenda-new-marker (match-beginning 0))
5824 closedp (equal (match-string 1) org-closed-string)
93b62de8 5825 statep (equal (string-to-char (match-string 1)) ?-)
c8d0cf5c 5826 clockp (not (or closedp statep))
93b62de8 5827 state (and statep (match-string 2))
20908596 5828 category (org-get-category (match-beginning 0))
8223b1d2 5829 category-pos (get-text-property (match-beginning 0) 'org-category-position)
e66ba1df 5830 timestr (buffer-substring (match-beginning 0) (point-at-eol)))
b349f79f
CD
5831 (when (string-match "\\]" timestr)
5832 ;; substring should only run to end of time stamp
5833 (setq rest (substring timestr (match-end 0))
5834 timestr (substring timestr 0 (match-end 0)))
93b62de8 5835 (if (and (not closedp) (not statep)
e66ba1df
BG
5836 (string-match "\\([0-9]\\{1,2\\}:[0-9]\\{2\\}\\)\\].*?\\([0-9]\\{1,2\\}:[0-9]\\{2\\}\\)"
5837 rest))
621f83e4
CD
5838 (progn (setq timestr (concat (substring timestr 0 -1)
5839 "-" (match-string 1 rest) "]"))
5840 (setq clocked (match-string 2 rest)))
5841 (setq clocked "-")))
20908596 5842 (save-excursion
3ab2c837
BG
5843 (setq extra
5844 (cond
5845 ((not org-agenda-log-mode-add-notes) nil)
5846 (statep
5847 (and (looking-at ".*\\\\\n[ \t]*\\([^-\n \t].*?\\)[ \t]*$")
5848 (match-string 1)))
5849 (clockp
5850 (and (looking-at ".*\n[ \t]*-[ \t]+\\([^-\n \t].*?\\)[ \t]*$")
5851 (match-string 1)))))
5852 (if (not (re-search-backward org-outline-regexp-bol nil t))
d3517077 5853 (throw :skip nil)
c8d0cf5c
CD
5854 (goto-char (match-beginning 0))
5855 (setq hdmarker (org-agenda-new-marker)
a89c8ef0
BG
5856 inherited-tags
5857 (or (eq org-agenda-show-inherited-tags 'always)
5858 (and (listp org-agenda-show-inherited-tags)
5859 (memq 'todo org-agenda-show-inherited-tags))
5860 (and (eq org-agenda-show-inherited-tags t)
5861 (or (eq org-agenda-use-tag-inheritance t)
5862 (memq 'todo org-agenda-use-tag-inheritance))))
271672fa
BG
5863 tags (org-get-tags-at nil (not inherited-tags))
5864 level (make-string (org-reduced-level (org-outline-level)) ? ))
c8d0cf5c
CD
5865 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
5866 (setq txt (match-string 1))
5867 (when extra
5868 (if (string-match "\\([ \t]+\\)\\(:[^ \n\t]*?:\\)[ \t]*$" txt)
5869 (setq txt (concat (substring txt 0 (match-beginning 1))
5870 " - " extra " " (match-string 2 txt)))
5871 (setq txt (concat txt " - " extra))))
e66ba1df 5872 (setq txt (org-agenda-format-item
c8d0cf5c
CD
5873 (cond
5874 (closedp "Closed: ")
8223b1d2
BG
5875 (statep (concat "State: (" state ")"))
5876 (t (concat "Clocked: (" clocked ")")))
271672fa 5877 txt level category tags timestr)))
20908596
CD
5878 (setq priority 100000)
5879 (org-add-props txt props
c8d0cf5c 5880 'org-marker marker 'org-hd-marker hdmarker 'face 'org-agenda-done
20908596 5881 'priority priority 'org-category category
8223b1d2 5882 'org-category-position category-pos
271672fa 5883 'level level
20908596 5884 'type "closed" 'date date
c8d0cf5c 5885 'undone-face 'org-warning 'done-face 'org-agenda-done)
20908596
CD
5886 (push txt ee))
5887 (goto-char (point-at-eol))))
5888 (nreverse ee)))
5889
3ab2c837
BG
5890(defun org-agenda-show-clocking-issues ()
5891 "Add overlays, showing issues with clocking.
5892See also the user option `org-agenda-clock-consistency-checks'."
5893 (interactive)
271672fa
BG
5894 (let* ((org-time-clocksum-use-effort-durations nil)
5895 (pl org-agenda-clock-consistency-checks)
3ab2c837
BG
5896 (re (concat "^[ \t]*"
5897 org-clock-string
5898 "[ \t]+"
5899 "\\(\\[.*?\\]\\)" ; group 1 is first stamp
5900 "\\(-\\{1,3\\}\\(\\[.*?\\]\\)\\)?")) ; group 3 is second
5901 (tlstart 0.)
5902 (tlend 0.)
fe3c5669 5903 (maxtime (org-hh:mm-string-to-minutes
3ab2c837 5904 (or (plist-get pl :max-duration) "24:00")))
fe3c5669 5905 (mintime (org-hh:mm-string-to-minutes
3ab2c837
BG
5906 (or (plist-get pl :min-duration) 0)))
5907 (maxgap (org-hh:mm-string-to-minutes
5908 ;; default 30:00 means never complain
5909 (or (plist-get pl :max-gap) "30:00")))
5910 (gapok (mapcar 'org-hh:mm-string-to-minutes
5911 (plist-get pl :gap-ok-around)))
5912 (def-face (or (plist-get pl :default-face)
5913 '((:background "DarkRed") (:foreground "white"))))
5914 issue face m te ts dt ov)
5915 (goto-char (point-min))
5916 (while (re-search-forward " Clocked: +(-\\|\\([0-9]+:[0-9]+\\))" nil t)
5917 (setq issue nil face def-face)
5918 (catch 'next
5919 (setq m (org-get-at-bol 'org-marker)
5920 te nil ts nil)
5921 (unless (and m (markerp m))
5922 (setq issue "No valid clock line") (throw 'next t))
5923 (org-with-point-at m
5924 (save-excursion
5925 (goto-char (point-at-bol))
5926 (unless (looking-at re)
5927 (error "No valid Clock line")
5928 (throw 'next t))
5929 (unless (match-end 3)
5930 (setq issue "No end time"
5931 face (or (plist-get pl :no-end-time-face) face))
5932 (throw 'next t))
5933 (setq ts (match-string 1)
5934 te (match-string 3)
5935 ts (org-float-time
5936 (apply 'encode-time (org-parse-time-string ts)))
5937 te (org-float-time
5938 (apply 'encode-time (org-parse-time-string te)))
5939 dt (- te ts))))
5940 (cond
5941 ((> dt (* 60 maxtime))
5942 ;; a very long clocking chunk
5943 (setq issue (format "Clocking interval is very long: %s"
271672fa 5944 (org-minutes-to-clocksum-string
3ab2c837
BG
5945 (floor (/ (float dt) 60.))))
5946 face (or (plist-get pl :long-face) face)))
5947 ((< dt (* 60 mintime))
5948 ;; a very short clocking chunk
5949 (setq issue (format "Clocking interval is very short: %s"
271672fa 5950 (org-minutes-to-clocksum-string
3ab2c837
BG
5951 (floor (/ (float dt) 60.))))
5952 face (or (plist-get pl :short-face) face)))
5953 ((and (> tlend 0) (< ts tlend))
5954 ;; Two clock entries are overlapping
5955 (setq issue (format "Clocking overlap: %d minutes"
5956 (/ (- tlend ts) 60))
5957 face (or (plist-get pl :overlap-face) face)))
5958 ((and (> tlend 0) (> ts (+ tlend (* 60 maxgap))))
e66ba1df 5959 ;; There is a gap, lets see if we need to report it
3ab2c837
BG
5960 (unless (org-agenda-check-clock-gap tlend ts gapok)
5961 (setq issue (format "Clocking gap: %d minutes"
8223b1d2 5962 (/ (- ts tlend) 60))
3ab2c837
BG
5963 face (or (plist-get pl :gap-face) face))))
5964 (t nil)))
5965 (setq tlend (or te tlend) tlstart (or ts tlstart))
5966 (when issue
5967 ;; OK, there was some issue, add an overlay to show the issue
5968 (setq ov (make-overlay (point-at-bol) (point-at-eol)))
5969 (overlay-put ov 'before-string
5970 (concat
5971 (org-add-props
5972 (format "%-43s" (concat " " issue))
5973 nil
5974 'face face)
5975 "\n"))
5976 (overlay-put ov 'evaporate t)))))
5977
5978(defun org-agenda-check-clock-gap (t1 t2 ok-list)
5979 "Check if gap T1 -> T2 contains one of the OK-LIST time-of-day values."
5980 (catch 'exit
5981 (unless ok-list
5982 ;; there are no OK times for gaps...
5983 (throw 'exit nil))
5984 (if (> (- (/ t2 36000) (/ t1 36000)) 24)
5985 ;; This is more than 24 hours, so it is OK.
5986 ;; because we have at least one OK time, that must be in the
5987 ;; 24 hour interval.
5988 (throw 'exit t))
5989 ;; We have a shorter gap.
5990 ;; Now we have to get the minute of the day when these times are
5991 (let* ((t1dec (decode-time (seconds-to-time t1)))
5992 (t2dec (decode-time (seconds-to-time t2)))
5993 ;; compute the minute on the day
5994 (min1 (+ (nth 1 t1dec) (* 60 (nth 2 t1dec))))
5995 (min2 (+ (nth 1 t2dec) (* 60 (nth 2 t2dec)))))
5996 (when (< min2 min1)
5997 ;; if min2 is smaller than min1, this means it is on the next day.
5998 ;; Wrap it to after midnight.
5999 (setq min2 (+ min2 1440)))
6000 ;; Now check if any of the OK times is in the gap
6001 (mapc (lambda (x)
6002 ;; Wrap the time to after midnight if necessary
6003 (if (< x min1) (setq x (+ x 1440)))
6004 ;; Check if in interval
6005 (and (<= min1 x) (>= min2 x) (throw 'exit t)))
6006 ok-list)
6007 ;; Nope, this gap is not OK
6008 nil)))
6009
271672fa
BG
6010(defun org-agenda-get-deadlines (&optional with-hour)
6011 "Return the deadline information for agenda display.
6012When WITH-HOUR is non-nil, only return deadlines with an hour
6013specification like [h]h:mm."
20908596
CD
6014 (let* ((props (list 'mouse-face 'highlight
6015 'org-not-done-regexp org-not-done-regexp
6016 'org-todo-regexp org-todo-regexp
b349f79f 6017 'org-complex-heading-regexp org-complex-heading-regexp
20908596
CD
6018 'help-echo
6019 (format "mouse-2 or RET jump to org file %s"
6020 (abbreviate-file-name buffer-file-name))))
271672fa
BG
6021 (regexp (if with-hour
6022 org-deadline-time-hour-regexp
6023 org-deadline-time-regexp))
621f83e4 6024 (todayp (org-agenda-todayp date)) ; DATE bound by calendar
271672fa
BG
6025 (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar
6026 (dl0 (car org-agenda-deadline-leaders))
6027 (dl1 (nth 1 org-agenda-deadline-leaders))
6028 (dl2 (or (nth 2 org-agenda-deadline-leaders) dl1))
6029 d2 diff dfrac wdays pos pos1 category category-pos level
e66ba1df 6030 tags suppress-prewarning ee txt head face s todo-state
271672fa 6031 show-all upcomingp donep timestr warntime inherited-tags ts-date)
20908596
CD
6032 (goto-char (point-min))
6033 (while (re-search-forward regexp nil t)
6034 (catch :skip
6035 (org-agenda-skip)
6036 (setq s (match-string 1)
c8d0cf5c 6037 txt nil
20908596 6038 pos (1- (match-beginning 1))
3ab2c837
BG
6039 todo-state (save-match-data (org-get-todo-state))
6040 show-all (or (eq org-agenda-repeating-timestamp-show-all t)
6041 (member todo-state
8223b1d2 6042 org-agenda-repeating-timestamp-show-all))
20908596 6043 d2 (org-time-string-to-absolute
271672fa
BG
6044 s d1 'past show-all (current-buffer) pos)
6045 diff (- d2 d1))
6046 (setq suppress-prewarning
6047 (let ((ds (and org-agenda-skip-deadline-prewarning-if-scheduled
6048 (let ((item (buffer-substring (point-at-bol)
6049 (point-at-eol))))
6050 (save-match-data
6051 (and (string-match
6052 org-scheduled-time-regexp item)
6053 (match-string 1 item)))))))
6054 (cond
6055 ((not ds) nil)
6056 ;; The current item has a scheduled date (in ds), so
6057 ;; evaluate its prewarning lead time.
6058 ((integerp org-agenda-skip-deadline-prewarning-if-scheduled)
6059 ;; Use global prewarning-restart lead time.
6060 org-agenda-skip-deadline-prewarning-if-scheduled)
6061 ((eq org-agenda-skip-deadline-prewarning-if-scheduled
6062 'pre-scheduled)
6063 ;; Set prewarning to no earlier than scheduled.
6064 (min (- d2 (org-time-string-to-absolute
6065 ds d1 'past show-all (current-buffer) pos))
6066 org-deadline-warning-days))
6067 ;; Set prewarning to deadline.
6068 (t 0))))
6069 (setq wdays (if suppress-prewarning
ed21c5c8
CD
6070 (let ((org-deadline-warning-days suppress-prewarning))
6071 (org-get-wdays s))
6072 (org-get-wdays s))
e66ba1df 6073 dfrac (- 1 (/ (* 1.0 diff) (max wdays 1)))
20908596
CD
6074 upcomingp (and todayp (> diff 0)))
6075 ;; When to show a deadline in the calendar:
6076 ;; If the expiration is within wdays warning time.
6077 ;; Past-due deadlines are only shown on the current date
8bfe682a
CD
6078 (if (and (or (and (<= diff wdays)
6079 (and todayp (not org-agenda-only-exact-dates)))
6080 (= diff 0)))
20908596 6081 (save-excursion
3ab2c837 6082 ;; (setq todo-state (org-get-todo-state))
c8d0cf5c
CD
6083 (setq donep (member todo-state org-done-keywords))
6084 (if (and donep
6085 (or org-agenda-skip-deadline-if-done
6086 (not (= diff 0))))
6087 (setq txt nil)
e66ba1df 6088 (setq category (org-get-category)
c7cf0ebc 6089 warntime (get-text-property (point) 'org-appt-warntime)
8223b1d2 6090 category-pos (get-text-property (point) 'org-category-position))
c8d0cf5c 6091 (if (not (re-search-backward "^\\*+[ \t]+" nil t))
d3517077 6092 (throw :skip nil)
c8d0cf5c
CD
6093 (goto-char (match-end 0))
6094 (setq pos1 (match-beginning 0))
271672fa 6095 (setq level (make-string (org-reduced-level (org-outline-level)) ? ))
d3517077
BG
6096 (setq inherited-tags
6097 (or (eq org-agenda-show-inherited-tags 'always)
6098 (and (listp org-agenda-show-inherited-tags)
6099 (memq 'agenda org-agenda-show-inherited-tags))
6100 (and (eq org-agenda-show-inherited-tags t)
6101 (or (eq org-agenda-use-tag-inheritance t)
6102 (memq 'agenda org-agenda-use-tag-inheritance))))
6103 tags (org-get-tags-at pos1 (not inherited-tags)))
6104 (setq head (buffer-substring
c8d0cf5c
CD
6105 (point)
6106 (progn (skip-chars-forward "^\r\n")
6107 (point))))
6108 (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
6109 (setq timestr
6110 (concat (substring s (match-beginning 1)) " "))
6111 (setq timestr 'time))
e66ba1df 6112 (setq txt (org-agenda-format-item
271672fa
BG
6113 (cond ((= diff 0) dl0)
6114 ((> diff 0)
6115 (if (functionp dl1)
6116 (funcall dl1 diff date)
6117 (format dl1 diff)))
6118 (t
6119 (if (functionp dl2)
6120 (funcall dl2 diff date)
6121 (format dl2 (if (string= dl2 dl1)
6122 diff (abs diff))))))
6123 head level category tags
c8d0cf5c 6124 (if (not (= diff 0)) nil timestr)))))
20908596 6125 (when txt
e66ba1df 6126 (setq face (org-agenda-deadline-face dfrac))
20908596
CD
6127 (org-add-props txt props
6128 'org-marker (org-agenda-new-marker pos)
8223b1d2 6129 'warntime warntime
271672fa
BG
6130 'level level
6131 'ts-date d2
20908596
CD
6132 'org-hd-marker (org-agenda-new-marker pos1)
6133 'priority (+ (- diff)
6134 (org-get-priority txt))
6135 'org-category category
8223b1d2 6136 'org-category-position category-pos
621f83e4 6137 'todo-state todo-state
20908596
CD
6138 'type (if upcomingp "upcoming-deadline" "deadline")
6139 'date (if upcomingp date d2)
c8d0cf5c
CD
6140 'face (if donep 'org-agenda-done face)
6141 'undone-face face 'done-face 'org-agenda-done)
20908596
CD
6142 (push txt ee))))))
6143 (nreverse ee)))
6144
e66ba1df 6145(defun org-agenda-deadline-face (fraction)
20908596
CD
6146 "Return the face to displaying a deadline item.
6147FRACTION is what fraction of the head-warning time has passed."
20908596
CD
6148 (let ((faces org-agenda-deadline-faces) f)
6149 (catch 'exit
6150 (while (setq f (pop faces))
6151 (if (>= fraction (car f)) (throw 'exit (cdr f)))))))
6152
271672fa
BG
6153(defun org-agenda-get-scheduled (&optional deadline-results with-hour)
6154 "Return the scheduled information for agenda display.
6155When WITH-HOUR is non-nil, only return scheduled items with
6156an hour specification like [h]h:mm."
20908596
CD
6157 (let* ((props (list 'org-not-done-regexp org-not-done-regexp
6158 'org-todo-regexp org-todo-regexp
b349f79f 6159 'org-complex-heading-regexp org-complex-heading-regexp
c8d0cf5c 6160 'done-face 'org-agenda-done
20908596 6161 'mouse-face 'highlight
20908596
CD
6162 'help-echo
6163 (format "mouse-2 or RET jump to org file %s"
6164 (abbreviate-file-name buffer-file-name))))
271672fa
BG
6165 (regexp (if with-hour
6166 org-scheduled-time-hour-regexp
6167 org-scheduled-time-regexp))
621f83e4 6168 (todayp (org-agenda-todayp date)) ; DATE bound by calendar
20908596 6169 (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar
54a0dee5
CD
6170 mm
6171 (deadline-position-alist
6172 (mapcar (lambda (a) (and (setq mm (get-text-property
8223b1d2
BG
6173 0 'org-hd-marker a))
6174 (cons (marker-position mm) a)))
54a0dee5 6175 deadline-results))
271672fa 6176 d2 diff pos pos1 category category-pos level tags donep
8223b1d2 6177 ee txt head pastschedp todo-state face timestr s habitp show-all
271672fa
BG
6178 did-habit-check-p warntime inherited-tags ts-date suppress-delay
6179 ddays)
20908596
CD
6180 (goto-char (point-min))
6181 (while (re-search-forward regexp nil t)
6182 (catch :skip
6183 (org-agenda-skip)
6184 (setq s (match-string 1)
c8d0cf5c 6185 txt nil
20908596 6186 pos (1- (match-beginning 1))
3ab2c837
BG
6187 todo-state (save-match-data (org-get-todo-state))
6188 show-all (or (eq org-agenda-repeating-timestamp-show-all t)
6189 (member todo-state
6190 org-agenda-repeating-timestamp-show-all))
20908596 6191 d2 (org-time-string-to-absolute
271672fa 6192 s d1 'past show-all (current-buffer) pos)
8223b1d2 6193 diff (- d2 d1)
c7cf0ebc 6194 warntime (get-text-property (point) 'org-appt-warntime))
20908596 6195 (setq pastschedp (and todayp (< diff 0)))
8223b1d2 6196 (setq did-habit-check-p nil)
271672fa
BG
6197 (setq suppress-delay
6198 (let ((ds (and org-agenda-skip-scheduled-delay-if-deadline
6199 (let ((item (buffer-substring (point-at-bol) (point-at-eol))))
6200 (save-match-data
6201 (and (string-match
6202 org-deadline-time-regexp item)
6203 (match-string 1 item)))))))
6204 (cond
6205 ((not ds) nil)
6206 ;; The current item has a deadline date (in ds), so
6207 ;; evaluate its delay time.
6208 ((integerp org-agenda-skip-scheduled-delay-if-deadline)
6209 ;; Use global delay time.
6210 (- org-agenda-skip-scheduled-delay-if-deadline))
6211 ((eq org-agenda-skip-scheduled-delay-if-deadline
6212 'post-deadline)
6213 ;; Set delay to no later than deadline.
6214 (min (- d2 (org-time-string-to-absolute
6215 ds d1 'past show-all (current-buffer) pos))
6216 org-scheduled-delay-days))
6217 (t 0))))
6218 (setq ddays (if suppress-delay
6219 (let ((org-scheduled-delay-days suppress-delay))
6220 (org-get-wdays s t t))
6221 (org-get-wdays s t)))
6222 ;; Use a delay of 0 when there is a repeater and the delay is
6223 ;; of the form --3d
6224 (when (and (save-match-data (string-match "--[0-9]+[hdwmy]" s))
6225 (< (org-time-string-to-absolute s)
6226 (org-time-string-to-absolute
6227 s d2 'past nil (current-buffer) pos)))
6228 (setq ddays 0))
20908596
CD
6229 ;; When to show a scheduled item in the calendar:
6230 ;; If it is on or past the date.
271672fa
BG
6231 (when (or (and (> ddays 0) (= diff (- ddays)))
6232 (and (zerop ddays) (= diff 0))
6233 (and (< (+ diff ddays) 0)
8bfe682a
CD
6234 (< (abs diff) org-scheduled-past-days)
6235 (and todayp (not org-agenda-only-exact-dates)))
8223b1d2
BG
6236 ;; org-is-habit-p uses org-entry-get, which is expansive
6237 ;; so we go extra mile to only call it once
6238 (and todayp
6239 (boundp 'org-habit-show-all-today)
6240 org-habit-show-all-today
6241 (setq did-habit-check-p t)
6242 (setq habitp (and (functionp 'org-is-habit-p)
6243 (org-is-habit-p)))))
8bfe682a 6244 (save-excursion
8bfe682a 6245 (setq donep (member todo-state org-done-keywords))
8bfe682a 6246 (if (and donep
3ab2c837
BG
6247 (or org-agenda-skip-scheduled-if-done
6248 (not (= diff 0))
6249 (and (functionp 'org-is-habit-p)
6250 (org-is-habit-p))))
8bfe682a 6251 (setq txt nil)
8223b1d2
BG
6252 (setq habitp (if did-habit-check-p habitp
6253 (and (functionp 'org-is-habit-p)
6254 (org-is-habit-p))))
e66ba1df 6255 (setq category (org-get-category)
8223b1d2 6256 category-pos (get-text-property (point) 'org-category-position))
271672fa
BG
6257 (if (and (eq org-agenda-skip-scheduled-if-deadline-is-shown
6258 'repeated-after-deadline)
30cb51f1 6259 (org-get-deadline-time (point))
271672fa
BG
6260 (<= 0 (- d2 (time-to-days (org-get-deadline-time (point))))))
6261 (throw :skip nil))
8bfe682a 6262 (if (not (re-search-backward "^\\*+[ \t]+" nil t))
d3517077 6263 (throw :skip nil)
8bfe682a
CD
6264 (goto-char (match-end 0))
6265 (setq pos1 (match-beginning 0))
6266 (if habitp
6267 (if (or (not org-habit-show-habits)
6268 (and (not todayp)
8223b1d2 6269 (boundp 'org-habit-show-habits-only-for-today)
8bfe682a
CD
6270 org-habit-show-habits-only-for-today))
6271 (throw :skip nil))
54a0dee5
CD
6272 (if (and
6273 (or (eq t org-agenda-skip-scheduled-if-deadline-is-shown)
271672fa 6274 (and (eq org-agenda-skip-scheduled-if-deadline-is-shown 'not-today)
54a0dee5
CD
6275 pastschedp))
6276 (setq mm (assoc pos1 deadline-position-alist)))
8bfe682a 6277 (throw :skip nil)))
a89c8ef0
BG
6278 (setq inherited-tags
6279 (or (eq org-agenda-show-inherited-tags 'always)
6280 (and (listp org-agenda-show-inherited-tags)
6281 (memq 'agenda org-agenda-show-inherited-tags))
6282 (and (eq org-agenda-show-inherited-tags t)
6283 (or (eq org-agenda-use-tag-inheritance t)
6284 (memq 'agenda org-agenda-use-tag-inheritance))))
271672fa 6285
a89c8ef0 6286 tags (org-get-tags-at nil (not inherited-tags)))
271672fa 6287 (setq level (make-string (org-reduced-level (org-outline-level)) ? ))
d3517077 6288 (setq head (buffer-substring
8bfe682a
CD
6289 (point)
6290 (progn (skip-chars-forward "^\r\n") (point))))
6291 (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s)
6292 (setq timestr
6293 (concat (substring s (match-beginning 1)) " "))
6294 (setq timestr 'time))
e66ba1df 6295 (setq txt (org-agenda-format-item
8bfe682a
CD
6296 (if (= diff 0)
6297 (car org-agenda-scheduled-leaders)
6298 (format (nth 1 org-agenda-scheduled-leaders)
6299 (- 1 diff)))
271672fa 6300 head level category tags
8bfe682a 6301 (if (not (= diff 0)) nil timestr)
3ab2c837 6302 nil habitp))))
8bfe682a
CD
6303 (when txt
6304 (setq face
6305 (cond
6306 ((and (not habitp) pastschedp)
6307 'org-scheduled-previously)
6308 (todayp 'org-scheduled-today)
6309 (t 'org-scheduled))
6310 habitp (and habitp (org-habit-parse-todo)))
6311 (org-add-props txt props
6312 'undone-face face
6313 'face (if donep 'org-agenda-done face)
6314 'org-marker (org-agenda-new-marker pos)
6315 'org-hd-marker (org-agenda-new-marker pos1)
6316 'type (if pastschedp "past-scheduled" "scheduled")
6317 'date (if pastschedp d2 date)
271672fa 6318 'ts-date d2
8223b1d2 6319 'warntime warntime
271672fa 6320 'level level
8bfe682a
CD
6321 'priority (if habitp
6322 (org-habit-get-priority habitp)
6323 (+ 94 (- 5 diff) (org-get-priority txt)))
6324 'org-category category
8223b1d2 6325 'category-position category-pos
8bfe682a
CD
6326 'org-habit-p habitp
6327 'todo-state todo-state)
6328 (push txt ee))))))
20908596
CD
6329 (nreverse ee)))
6330
6331(defun org-agenda-get-blocks ()
6332 "Return the date-range information for agenda display."
6333 (let* ((props (list 'face nil
6334 'org-not-done-regexp org-not-done-regexp
6335 'org-todo-regexp org-todo-regexp
b349f79f 6336 'org-complex-heading-regexp org-complex-heading-regexp
20908596 6337 'mouse-face 'highlight
20908596
CD
6338 'help-echo
6339 (format "mouse-2 or RET jump to org file %s"
6340 (abbreviate-file-name buffer-file-name))))
6341 (regexp org-tr-regexp)
6342 (d0 (calendar-absolute-from-gregorian date))
8223b1d2 6343 marker hdmarker ee txt d1 d2 s1 s2 category category-pos
271672fa 6344 level todo-state tags pos head donep inherited-tags)
20908596
CD
6345 (goto-char (point-min))
6346 (while (re-search-forward regexp nil t)
6347 (catch :skip
6348 (org-agenda-skip)
6349 (setq pos (point))
3ab2c837
BG
6350 (let ((start-time (match-string 1))
6351 (end-time (match-string 2)))
6352 (setq s1 (match-string 1)
6353 s2 (match-string 2)
e66ba1df
BG
6354 d1 (time-to-days (org-time-string-to-time s1 (current-buffer) pos))
6355 d2 (time-to-days (org-time-string-to-time s2 (current-buffer) pos)))
3ab2c837
BG
6356 (if (and (> (- d0 d1) -1) (> (- d2 d0) -1))
6357 ;; Only allow days between the limits, because the normal
6358 ;; date stamps will catch the limits.
6359 (save-excursion
6360 (setq todo-state (org-get-todo-state))
6361 (setq donep (member todo-state org-done-keywords))
6362 (if (and donep org-agenda-skip-timestamp-if-done)
6363 (throw :skip t))
6364 (setq marker (org-agenda-new-marker (point)))
e66ba1df 6365 (setq category (org-get-category)
8223b1d2 6366 category-pos (get-text-property (point) 'org-category-position))
3ab2c837 6367 (if (not (re-search-backward org-outline-regexp-bol nil t))
d3517077 6368 (throw :skip nil)
3ab2c837 6369 (goto-char (match-beginning 0))
a89c8ef0
BG
6370 (setq hdmarker (org-agenda-new-marker (point))
6371 inherited-tags
6372 (or (eq org-agenda-show-inherited-tags 'always)
6373 (and (listp org-agenda-show-inherited-tags)
6374 (memq 'agenda org-agenda-show-inherited-tags))
6375 (and (eq org-agenda-show-inherited-tags t)
6376 (or (eq org-agenda-use-tag-inheritance t)
6377 (memq 'agenda org-agenda-use-tag-inheritance))))
271672fa 6378
a89c8ef0 6379 tags (org-get-tags-at nil (not inherited-tags)))
271672fa 6380 (setq level (make-string (org-reduced-level (org-outline-level)) ? ))
3ab2c837
BG
6381 (looking-at "\\*+[ \t]+\\([^\r\n]+\\)")
6382 (setq head (match-string 1))
6383 (let ((remove-re
6384 (if org-agenda-remove-timeranges-from-blocks
6385 (concat
6386 "<" (regexp-quote s1) ".*?>"
6387 "--"
6388 "<" (regexp-quote s2) ".*?>")
6389 nil)))
e66ba1df 6390 (setq txt (org-agenda-format-item
3ab2c837
BG
6391 (format
6392 (nth (if (= d1 d2) 0 1)
6393 org-agenda-timerange-leaders)
6394 (1+ (- d0 d1)) (1+ (- d2 d1)))
271672fa 6395 head level category tags
e66ba1df
BG
6396 (cond ((and (= d1 d0) (= d2 d0))
6397 (concat "<" start-time ">--<" end-time ">"))
6398 ((= d1 d0)
3ab2c837
BG
6399 (concat "<" start-time ">"))
6400 ((= d2 d0)
8223b1d2 6401 (concat "<" end-time ">")))
bdebdb64 6402 remove-re))))
3ab2c837
BG
6403 (org-add-props txt props
6404 'org-marker marker 'org-hd-marker hdmarker
6405 'type "block" 'date date
271672fa 6406 'level level
3ab2c837 6407 'todo-state todo-state
e66ba1df 6408 'priority (org-get-priority txt) 'org-category category
8223b1d2 6409 'org-category-position category-pos)
3ab2c837 6410 (push txt ee))))
20908596
CD
6411 (goto-char pos)))
6412 ;; Sort the entries by expiration date.
6413 (nreverse ee)))
6414
6415;;; Agenda presentation and sorting
6416
6417(defvar org-prefix-has-time nil
6418 "A flag, set by `org-compile-prefix-format'.
6419The flag is set if the currently compiled format contains a `%t'.")
6420(defvar org-prefix-has-tag nil
6421 "A flag, set by `org-compile-prefix-format'.
6422The flag is set if the currently compiled format contains a `%T'.")
6423(defvar org-prefix-has-effort nil
6424 "A flag, set by `org-compile-prefix-format'.
6425The flag is set if the currently compiled format contains a `%e'.")
271672fa
BG
6426(defvar org-prefix-has-breadcrumbs nil
6427 "A flag, set by `org-compile-prefix-format'.
6428The flag is set if the currently compiled format contains a `%b'.")
8d642074 6429(defvar org-prefix-category-length nil
86fbb8ca 6430 "Used by `org-compile-prefix-format' to remember the category field width.")
8bfe682a 6431(defvar org-prefix-category-max-length nil
86fbb8ca 6432 "Used by `org-compile-prefix-format' to remember the category field width.")
20908596 6433
acedf35c
CD
6434(defun org-agenda-get-category-icon (category)
6435 "Return an image for CATEGORY according to `org-agenda-category-icon-alist'."
6436 (dolist (entry org-agenda-category-icon-alist)
6437 (when (org-string-match-p (car entry) category)
6438 (if (listp (cadr entry))
6439 (return (cadr entry))
8223b1d2 6440 (return (apply 'create-image (cdr entry)))))))
acedf35c 6441
271672fa 6442(defun org-agenda-format-item (extra txt &optional level category tags dotime
3ab2c837 6443 remove-re habitp)
20908596 6444 "Format TXT to be inserted into the agenda buffer.
271672fa
BG
6445In particular, add the prefix and corresponding text properties.
6446
6447EXTRA must be a string to replace the `%s' specifier in the prefix format.
6448LEVEL may be a string to replace the `%l' specifier.
6449CATEGORY (a string, a symbol or nil) may be used to overrule the default
20908596 6450category taken from local variable or file name. It will replace the `%c'
271672fa
BG
6451specifier in the format.
6452DOTIME, when non-nil, indicates that a time-of-day should be extracted from
6453TXT for sorting of this entry, and for the `%t' specifier in the format.
6454When DOTIME is a string, this string is searched for a time before TXT is.
6455TAGS can be the tags of the headline.
20908596 6456Any match of REMOVE-RE will be removed from TXT."
8223b1d2 6457 ;; We keep the org-prefix-* variable values along with a compiled
271672fa 6458 ;; formatter, so that multiple agendas existing at the same time do
8223b1d2
BG
6459 ;; not step on each other toes.
6460 ;;
6461 ;; It was inconvenient to make these variables buffer local in
6462 ;; Agenda buffers, because this function expects to be called with
6463 ;; the buffer where item comes from being current, and not agenda
6464 ;; buffer
6465 (let* ((bindings (car org-prefix-format-compiled))
6466 (formatter (cadr org-prefix-format-compiled)))
6467 (loop for (var value) in bindings
6468 do (set var value))
6469 (save-match-data
6470 ;; Diary entries sometimes have extra whitespace at the beginning
271672fa 6471 (setq txt (org-trim txt))
8223b1d2
BG
6472
6473 ;; Fix the tags part in txt
6474 (setq txt (org-agenda-fix-displayed-tags
6475 txt tags
6476 org-agenda-show-inherited-tags
6477 org-agenda-hide-tags-regexp))
271672fa 6478
8223b1d2
BG
6479 (let* ((category (or category
6480 (if (stringp org-category)
6481 org-category
6482 (and org-category (symbol-name org-category)))
6483 (if buffer-file-name
6484 (file-name-sans-extension
6485 (file-name-nondirectory buffer-file-name))
6486 "")))
6487 (category-icon (org-agenda-get-category-icon category))
6488 (category-icon (if category-icon
6489 (propertize " " 'display category-icon)
6490 ""))
6491 ;; time, tag, effort are needed for the eval of the prefix format
6492 (tag (if tags (nth (1- (length tags)) tags) ""))
6493 time effort neffort
6494 (ts (if dotime (concat
6495 (if (stringp dotime) dotime "")
6496 (and org-agenda-search-headline-for-time txt))))
6497 (time-of-day (and dotime (org-get-time-of-day ts)))
6498 stamp plain s0 s1 s2 rtn srp l
271672fa 6499 duration thecategory breadcrumbs)
8223b1d2
BG
6500 (and (derived-mode-p 'org-mode) buffer-file-name
6501 (add-to-list 'org-agenda-contributing-files buffer-file-name))
6502 (when (and dotime time-of-day)
6503 ;; Extract starting and ending time and move them to prefix
6504 (when (or (setq stamp (string-match org-stamp-time-of-day-regexp ts))
6505 (setq plain (string-match org-plain-time-of-day-regexp ts)))
6506 (setq s0 (match-string 0 ts)
6507 srp (and stamp (match-end 3))
6508 s1 (match-string (if plain 1 2) ts)
6509 s2 (match-string (if plain 8 (if srp 4 6)) ts))
6510
6511 ;; If the times are in TXT (not in DOTIMES), and the prefix will list
6512 ;; them, we might want to remove them there to avoid duplication.
6513 ;; The user can turn this off with a variable.
6514 (if (and org-prefix-has-time
6515 org-agenda-remove-times-when-in-prefix (or stamp plain)
6516 (string-match (concat (regexp-quote s0) " *") txt)
6517 (not (equal ?\] (string-to-char (substring txt (match-end 0)))))
6518 (if (eq org-agenda-remove-times-when-in-prefix 'beg)
6519 (= (match-beginning 0) 0)
6520 t))
6521 (setq txt (replace-match "" nil nil txt))))
6522 ;; Normalize the time(s) to 24 hour
6523 (if s1 (setq s1 (org-get-time-of-day s1 'string t)))
6524 (if s2 (setq s2 (org-get-time-of-day s2 'string t)))
6525
6526 ;; Try to set s2 if s1 and `org-agenda-default-appointment-duration' are set
271672fa
BG
6527 (let (org-time-clocksum-use-effort-durations)
6528 (when (and s1 (not s2) org-agenda-default-appointment-duration)
6529 (setq s2
6530 (org-minutes-to-clocksum-string
6531 (+ (org-hh:mm-string-to-minutes s1)
6532 org-agenda-default-appointment-duration)))))
8223b1d2
BG
6533
6534 ;; Compute the duration
6535 (when s2
6536 (setq duration (- (org-hh:mm-string-to-minutes s2)
6537 (org-hh:mm-string-to-minutes s1)))))
6538
6539 (when (string-match (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@#%:]+:\\)[ \t]*$")
6540 txt)
6541 ;; Tags are in the string
6542 (if (or (eq org-agenda-remove-tags t)
6543 (and org-agenda-remove-tags
6544 org-prefix-has-tag))
6545 (setq txt (replace-match "" t t txt))
6546 (setq txt (replace-match
6547 (concat (make-string (max (- 50 (length txt)) 1) ?\ )
6548 (match-string 2 txt))
6549 t t txt))))
6550 (when (derived-mode-p 'org-mode)
271672fa
BG
6551 (setq effort (ignore-errors (get-text-property 0 'org-effort txt))))
6552
6553 ;; org-agenda-add-time-grid-maybe calls us with *Agenda* as
6554 ;; current buffer, so move this check outside of above
6555 (if effort
8223b1d2 6556 (setq neffort (org-duration-string-to-minutes effort)
271672fa
BG
6557 effort (setq effort (concat "[" effort "]")))
6558 ;; prevent erroring out with %e format when there is no effort
6559 (setq effort ""))
8223b1d2
BG
6560
6561 (when remove-re
6562 (while (string-match remove-re txt)
6563 (setq txt (replace-match "" t t txt))))
6564
6565 ;; Set org-heading property on `txt' to mark the start of the
6566 ;; heading.
6567 (add-text-properties 0 (length txt) '(org-heading t) txt)
6568
6569 ;; Prepare the variables needed in the eval of the compiled format
271672fa
BG
6570 (if org-prefix-has-breadcrumbs
6571 (setq breadcrumbs (org-with-point-at (org-get-at-bol 'org-marker)
6572 (let ((s (org-display-outline-path nil nil "->" t)))
6573 (if (eq "" s) "" (concat s "->"))))))
8223b1d2
BG
6574 (setq time (cond (s2 (concat
6575 (org-agenda-time-of-day-to-ampm-maybe s1)
6576 "-" (org-agenda-time-of-day-to-ampm-maybe s2)
6577 (if org-agenda-timegrid-use-ampm " ")))
6578 (s1 (concat
6579 (org-agenda-time-of-day-to-ampm-maybe s1)
6580 (if org-agenda-timegrid-use-ampm
6581 "........ "
6582 "......")))
6583 (t ""))
6584 extra (or (and (not habitp) extra) "")
6585 category (if (symbolp category) (symbol-name category) category)
271672fa
BG
6586 thecategory (copy-sequence category)
6587 level (or level ""))
8223b1d2
BG
6588 (if (string-match org-bracket-link-regexp category)
6589 (progn
6590 (setq l (if (match-end 3)
6591 (- (match-end 3) (match-beginning 3))
6592 (- (match-end 1) (match-beginning 1))))
6593 (when (< l (or org-prefix-category-length 0))
6594 (setq category (copy-sequence category))
6595 (org-add-props category nil
6596 'extra-space (make-string
6597 (- org-prefix-category-length l 1) ?\ ))))
6598 (if (and org-prefix-category-max-length
6599 (>= (length category) org-prefix-category-max-length))
6600 (setq category (substring category 0 (1- org-prefix-category-max-length)))))
6601 ;; Evaluate the compiled format
6602 (setq rtn (concat (eval formatter) txt))
6603
6604 ;; And finally add the text properties
6605 (remove-text-properties 0 (length rtn) '(line-prefix t wrap-prefix t) rtn)
6606 (org-add-props rtn nil
6607 'org-category (if thecategory (downcase thecategory) category)
6608 'tags (mapcar 'org-downcase-keep-props tags)
6609 'org-highest-priority org-highest-priority
6610 'org-lowest-priority org-lowest-priority
6611 'time-of-day time-of-day
6612 'duration duration
6613 'effort effort
6614 'effort-minutes neffort
271672fa 6615 'breadcrumbs breadcrumbs
8223b1d2 6616 'txt txt
271672fa 6617 'level level
8223b1d2
BG
6618 'time time
6619 'extra extra
6620 'format org-prefix-format-compiled
6621 'dotime dotime)))))
20908596 6622
5dec9555
CD
6623(defun org-agenda-fix-displayed-tags (txt tags add-inherited hide-re)
6624 "Remove tags string from TXT, and add a modified list of tags.
6625The modified list may contain inherited tags, and tags matched by
6626`org-agenda-hide-tags-regexp' will be removed."
6627 (when (or add-inherited hide-re)
afe98dfa 6628 (if (string-match (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@#%:]+:\\)[ \t]*$") txt)
5dec9555 6629 (setq txt (substring txt 0 (match-beginning 0))))
ed21c5c8
CD
6630 (setq tags
6631 (delq nil
6632 (mapcar (lambda (tg)
6633 (if (or (and hide-re (string-match hide-re tg))
6634 (and (not add-inherited)
6635 (get-text-property 0 'inherited tg)))
6636 nil
6637 tg))
6638 tags)))
5dec9555 6639 (when tags
5dec9555
CD
6640 (let ((have-i (get-text-property 0 'inherited (car tags)))
6641 i)
6642 (setq txt (concat txt " :"
6643 (mapconcat
6644 (lambda (x)
6645 (setq i (get-text-property 0 'inherited x))
6646 (if (and have-i (not i))
6647 (progn
6648 (setq have-i nil)
6649 (concat ":" x))
6650 x))
6651 tags ":")
6652 (if have-i "::" ":"))))))
8223b1d2 6653 txt)
ff4be292
CD
6654
6655(defun org-downcase-keep-props (s)
6656 (let ((props (text-properties-at 0 s)))
6657 (setq s (downcase s))
6658 (add-text-properties 0 (length s) props s)
6659 s))
6660
20908596 6661(defvar org-agenda-sorting-strategy) ;; because the def is in a let form
20908596
CD
6662
6663(defun org-agenda-add-time-grid-maybe (list ndays todayp)
271672fa
BG
6664 "Add a time-grid for agenda items which need it.
6665
6666LIST is the list of agenda items formatted by `org-agenda-list'.
6667NDAYS is the span of the current agenda view.
6668TODAYP is `t' when the current agenda view is on today."
20908596
CD
6669 (catch 'exit
6670 (cond ((not org-agenda-use-time-grid) (throw 'exit list))
6671 ((and todayp (member 'today (car org-agenda-time-grid))))
6672 ((and (= ndays 1) (member 'daily (car org-agenda-time-grid))))
6673 ((member 'weekly (car org-agenda-time-grid)))
6674 (t (throw 'exit list)))
6675 (let* ((have (delq nil (mapcar
6676 (lambda (x) (get-text-property 1 'time-of-day x))
6677 list)))
6678 (string (nth 1 org-agenda-time-grid))
6679 (gridtimes (nth 2 org-agenda-time-grid))
6680 (req (car org-agenda-time-grid))
6681 (remove (member 'remove-match req))
6682 new time)
6683 (if (and (member 'require-timed req) (not have))
6684 ;; don't show empty grid
6685 (throw 'exit list))
6686 (while (setq time (pop gridtimes))
6687 (unless (and remove (member time have))
afe98dfa 6688 (setq time (replace-regexp-in-string " " "0" (format "%04s" time)))
e66ba1df 6689 (push (org-agenda-format-item
271672fa 6690 nil string nil "" nil
20908596
CD
6691 (concat (substring time 0 -2) ":" (substring time -2)))
6692 new)
6693 (put-text-property
afe98dfa 6694 2 (length (car new)) 'face 'org-time-grid (car new))))
3ab2c837 6695 (when (and todayp org-agenda-show-current-time-in-grid)
e66ba1df 6696 (push (org-agenda-format-item
271672fa 6697 nil org-agenda-current-time-string nil "" nil
3ab2c837
BG
6698 (format-time-string "%H:%M "))
6699 new)
6700 (put-text-property
6701 2 (length (car new)) 'face 'org-agenda-current-time (car new)))
6702
20908596
CD
6703 (if (member 'time-up org-agenda-sorting-strategy-selected)
6704 (append new list)
6705 (append list new)))))
6706
6707(defun org-compile-prefix-format (key)
6708 "Compile the prefix format into a Lisp form that can be evaluated.
8223b1d2
BG
6709The resulting form and associated variable bindings is returned
6710and stored in the variable `org-prefix-format-compiled'."
271672fa
BG
6711 (setq org-prefix-has-time nil
6712 org-prefix-has-tag nil
e66ba1df 6713 org-prefix-category-length nil
271672fa
BG
6714 org-prefix-has-effort nil
6715 org-prefix-has-breadcrumbs nil)
20908596
CD
6716 (let ((s (cond
6717 ((stringp org-agenda-prefix-format)
6718 org-agenda-prefix-format)
6719 ((assq key org-agenda-prefix-format)
6720 (cdr (assq key org-agenda-prefix-format)))
6721 (t " %-12:c%?-12t% s")))
6722 (start 0)
6723 varform vars var e c f opt)
271672fa 6724 (while (string-match "%\\(\\?\\)?\\([-+]?[0-9.]*\\)\\([ .;,:!?=|/<>]?\\)\\([cltseib]\\|(.+)\\)"
20908596 6725 s start)
3ab2c837 6726 (setq var (or (cdr (assoc (match-string 4 s)
271672fa
BG
6727 '(("c" . category) ("t" . time) ("l" . level) ("s" . extra)
6728 ("i" . category-icon) ("T" . tag) ("e" . effort) ("b" . breadcrumbs))))
3ab2c837 6729 'eval)
20908596
CD
6730 c (or (match-string 3 s) "")
6731 opt (match-beginning 1)
6732 start (1+ (match-beginning 0)))
6733 (if (equal var 'time) (setq org-prefix-has-time t))
6734 (if (equal var 'tag) (setq org-prefix-has-tag t))
6735 (if (equal var 'effort) (setq org-prefix-has-effort t))
271672fa 6736 (if (equal var 'breadcrumbs) (setq org-prefix-has-breadcrumbs t))
20908596 6737 (setq f (concat "%" (match-string 2 s) "s"))
8bfe682a
CD
6738 (when (equal var 'category)
6739 (setq org-prefix-category-length
6740 (floor (abs (string-to-number (match-string 2 s)))))
6741 (setq org-prefix-category-max-length
6742 (let ((x (match-string 2 s)))
6743 (save-match-data
6744 (if (string-match "\\.[0-9]+" x)
6745 (string-to-number (substring (match-string 0 x) 1)))))))
3ab2c837
BG
6746 (if (eq var 'eval)
6747 (setq varform `(format ,f (org-eval ,(read (match-string 4 s)))))
6748 (if opt
6749 (setq varform
6750 `(if (equal "" ,var)
6751 ""
6752 (format ,f (if (equal "" ,var) "" (concat ,var ,c)))))
6753 (setq varform `(format ,f (if (equal ,var "") "" (concat ,var ,c (get-text-property 0 'extra-space ,var)))))))
20908596
CD
6754 (setq s (replace-match "%s" t nil s))
6755 (push varform vars))
6756 (setq vars (nreverse vars))
8223b1d2
BG
6757 (with-current-buffer (or org-agenda-buffer (current-buffer))
6758 (setq org-prefix-format-compiled
6759 (list
6760 `((org-prefix-has-time ,org-prefix-has-time)
6761 (org-prefix-has-tag ,org-prefix-has-tag)
6762 (org-prefix-category-length ,org-prefix-category-length)
271672fa
BG
6763 (org-prefix-has-effort ,org-prefix-has-effort)
6764 (org-prefix-has-breadcrumbs ,org-prefix-has-breadcrumbs))
8223b1d2 6765 `(format ,s ,@vars))))))
20908596
CD
6766
6767(defun org-set-sorting-strategy (key)
6768 (if (symbolp (car org-agenda-sorting-strategy))
6769 ;; the old format
6770 (setq org-agenda-sorting-strategy-selected org-agenda-sorting-strategy)
6771 (setq org-agenda-sorting-strategy-selected
6772 (or (cdr (assq key org-agenda-sorting-strategy))
6773 (cdr (assq 'agenda org-agenda-sorting-strategy))
6774 '(time-up category-keep priority-down)))))
6775
6776(defun org-get-time-of-day (s &optional string mod24)
6777 "Check string S for a time of day.
6778If found, return it as a military time number between 0 and 2400.
6779If not found, return nil.
6780The optional STRING argument forces conversion into a 5 character wide string
6781HH:MM."
6782 (save-match-data
6783 (when
6784 (or (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)\\([AaPp][Mm]\\)?\\> *" s)
6785 (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?\\([AaPp][Mm]\\)\\> *" s))
8223b1d2
BG
6786 (let* ((h (string-to-number (match-string 1 s)))
6787 (m (if (match-end 3) (string-to-number (match-string 3 s)) 0))
6788 (ampm (if (match-end 4) (downcase (match-string 4 s))))
6789 (am-p (equal ampm "am"))
6790 (h1 (cond ((not ampm) h)
6791 ((= h 12) (if am-p 0 12))
6792 (t (+ h (if am-p 0 12)))))
6793 (h2 (if (and string mod24 (not (and (= m 0) (= h1 24))))
6794 (mod h1 24) h1))
6795 (t0 (+ (* 100 h2) m))
6796 (t1 (concat (if (>= h1 24) "+" " ")
6797 (if (and org-agenda-time-leading-zero
6798 (< t0 1000)) "0" "")
6799 (if (< t0 100) "0" "")
6800 (if (< t0 10) "0" "")
6801 (int-to-string t0))))
6802 (if string (concat (substring t1 -4 -2) ":" (substring t1 -2)) t0)))))
20908596 6803
afe98dfa
CD
6804(defvar org-agenda-before-sorting-filter-function nil
6805 "Function to be applied to agenda items prior to sorting.
6806Prior to sorting also means just before they are inserted into the agenda.
6807
6808To aid sorting, you may revisit the original entries and add more text
6809properties which will later be used by the sorting functions.
6810
6811The function should take a string argument, an agenda line.
6812It has access to the text properties in that line, which contain among
6813other things, the property `org-hd-marker' that points to the entry
6814where the line comes from. Note that not all lines going into the agenda
6815have this property, only most.
6816
6817The function should return the modified string. It is probably best
6818to ONLY change text properties.
6819
6820You can also use this function as a filter, by returning nil for lines
6821you don't want to have in the agenda at all. For this application, you
6822could bind the variable in the options section of a custom command.")
6823
271672fa
BG
6824(defun org-agenda-finalize-entries (list &optional type)
6825 "Sort, limit and concatenate the LIST of agenda items.
6826The optional argument TYPE tells the agenda type."
6827 (let ((max-effort (cond ((listp org-agenda-max-effort)
6828 (cdr (assoc type org-agenda-max-effort)))
6829 (t org-agenda-max-effort)))
6830 (max-todo (cond ((listp org-agenda-max-todos)
6831 (cdr (assoc type org-agenda-max-todos)))
6832 (t org-agenda-max-todos)))
6833 (max-tags (cond ((listp org-agenda-max-tags)
6834 (cdr (assoc type org-agenda-max-tags)))
6835 (t org-agenda-max-tags)))
6836 (max-entries (cond ((listp org-agenda-max-entries)
6837 (cdr (assoc type org-agenda-max-entries)))
6838 (t org-agenda-max-entries))) l)
afe98dfa 6839 (when org-agenda-before-sorting-filter-function
271672fa
BG
6840 (setq list
6841 (delq nil
6842 (mapcar
6843 org-agenda-before-sorting-filter-function list))))
6844 (setq list (mapcar 'org-agenda-highlight-todo list)
6845 list (mapcar 'identity (sort list 'org-entries-lessp)))
6846 (when max-effort
6847 (setq list (org-agenda-limit-entries
6848 list 'effort-minutes max-effort 'identity)))
6849 (when max-todo
6850 (setq list (org-agenda-limit-entries list 'todo-state max-todo)))
6851 (when max-tags
6852 (setq list (org-agenda-limit-entries list 'tags max-tags)))
6853 (when max-entries
6854 (setq list (org-agenda-limit-entries list 'org-hd-marker max-entries)))
6855 (mapconcat 'identity list "\n")))
6856
6857(defun org-agenda-limit-entries (list prop limit &optional fn)
6858 "Limit the number of agenda entries."
6859 (let ((include (and limit (< limit 0))))
6860 (if limit
6861 (let ((fun (or fn (lambda (p) (if p 1))))
6862 (lim 0))
6863 (delq nil
6864 (mapcar
6865 (lambda (e)
6866 (let ((pval (funcall fun (get-text-property 1 prop e))))
6867 (if pval (setq lim (+ lim pval)))
6868 (cond ((and pval (<= lim (abs limit))) e)
6869 ((and include (not pval)) e))))
6870 list)))
6871 list)))
6872
6873(defun org-agenda-limit-interactively ()
6874 "In agenda, interactively limit entries to various maximums."
6875 (interactive)
6876 (let* ((max (read-char "Number of [e]ntries [t]odos [T]ags [E]ffort? "))
6877 (num (string-to-number (read-from-minibuffer "How many? "))))
6878 (cond ((equal max ?e)
6879 (let ((org-agenda-max-entries num)) (org-agenda-redo)))
6880 ((equal max ?t)
6881 (let ((org-agenda-max-todos num)) (org-agenda-redo)))
6882 ((equal max ?T)
6883 (let ((org-agenda-max-tags num)) (org-agenda-redo)))
6884 ((equal max ?E)
6885 (let ((org-agenda-max-effort num)) (org-agenda-redo)))))
6886 (org-agenda-fit-window-to-buffer))
20908596
CD
6887
6888(defun org-agenda-highlight-todo (x)
621f83e4 6889 (let ((org-done-keywords org-done-keywords-for-agenda)
ed21c5c8 6890 (case-fold-search nil)
e66ba1df 6891 re)
20908596
CD
6892 (if (eq x 'line)
6893 (save-excursion
6894 (beginning-of-line 1)
8d642074 6895 (setq re (org-get-at-bol 'org-todo-regexp))
3ab2c837 6896 (goto-char (or (text-property-any (point-at-bol) (point-at-eol) 'org-heading t) (point)))
621f83e4 6897 (when (looking-at (concat "[ \t]*\\.*\\(" re "\\) +"))
c8d0cf5c 6898 (add-text-properties (match-beginning 0) (match-end 1)
621f83e4 6899 (list 'face (org-get-todo-face 1)))
20908596
CD
6900 (let ((s (buffer-substring (match-beginning 1) (match-end 1))))
6901 (delete-region (match-beginning 1) (1- (match-end 0)))
6902 (goto-char (match-beginning 1))
6903 (insert (format org-agenda-todo-keyword-format s)))))
3ab2c837
BG
6904 (let ((pl (text-property-any 0 (length x) 'org-heading t x)))
6905 (setq re (get-text-property 0 'org-todo-regexp x))
6906 (when (and re
153ae947
BG
6907 ;; Test `pl' because if there's no heading content,
6908 ;; there's no point matching to highlight. Note
6909 ;; that if we didn't test `pl' first, and there
6910 ;; happened to be no keyword from `org-todo-regexp'
6911 ;; on this heading line, then the `equal' comparison
6912 ;; afterwards would spuriously succeed in the case
6913 ;; where `pl' is nil -- causing an args-out-of-range
6914 ;; error when we try to add text properties to text
6915 ;; that isn't there.
6916 pl
3ab2c837 6917 (equal (string-match (concat "\\(\\.*\\)" re "\\( +\\)")
153ae947 6918 x pl) pl))
3ab2c837
BG
6919 (add-text-properties
6920 (or (match-end 1) (match-end 0)) (match-end 0)
6921 (list 'face (org-get-todo-face (match-string 2 x)))
e66ba1df 6922 x)
3ab2c837
BG
6923 (when (match-end 1)
6924 (setq x (concat (substring x 0 (match-end 1))
6925 (format org-agenda-todo-keyword-format
6926 (match-string 2 x))
e66ba1df
BG
6927 (org-add-props " " (text-properties-at 0 x))
6928 (substring x (match-end 3)))))))
20908596
CD
6929 x)))
6930
6931(defsubst org-cmp-priority (a b)
6932 "Compare the priorities of string A and B."
6933 (let ((pa (or (get-text-property 1 'priority a) 0))
6934 (pb (or (get-text-property 1 'priority b) 0)))
6935 (cond ((> pa pb) +1)
8223b1d2 6936 ((< pa pb) -1))))
20908596
CD
6937
6938(defsubst org-cmp-effort (a b)
e66ba1df 6939 "Compare the effort values of string A and B."
20908596
CD
6940 (let* ((def (if org-sort-agenda-noeffort-is-high 32767 -1))
6941 (ea (or (get-text-property 1 'effort-minutes a) def))
6942 (eb (or (get-text-property 1 'effort-minutes b) def)))
6943 (cond ((> ea eb) +1)
8223b1d2 6944 ((< ea eb) -1))))
20908596
CD
6945
6946(defsubst org-cmp-category (a b)
6947 "Compare the string values of categories of strings A and B."
6948 (let ((ca (or (get-text-property 1 'org-category a) ""))
6949 (cb (or (get-text-property 1 'org-category b) "")))
6950 (cond ((string-lessp ca cb) -1)
8223b1d2 6951 ((string-lessp cb ca) +1))))
20908596 6952
621f83e4
CD
6953(defsubst org-cmp-todo-state (a b)
6954 "Compare the todo states of strings A and B."
c8d0cf5c
CD
6955 (let* ((ma (or (get-text-property 1 'org-marker a)
6956 (get-text-property 1 'org-hd-marker a)))
6957 (mb (or (get-text-property 1 'org-marker b)
6958 (get-text-property 1 'org-hd-marker b)))
6959 (fa (and ma (marker-buffer ma)))
6960 (fb (and mb (marker-buffer mb)))
6961 (todo-kwds
6962 (or (and fa (with-current-buffer fa org-todo-keywords-1))
6963 (and fb (with-current-buffer fb org-todo-keywords-1))))
6964 (ta (or (get-text-property 1 'todo-state a) ""))
621f83e4 6965 (tb (or (get-text-property 1 'todo-state b) ""))
c8d0cf5c
CD
6966 (la (- (length (member ta todo-kwds))))
6967 (lb (- (length (member tb todo-kwds))))
ff4be292 6968 (donepa (member ta org-done-keywords-for-agenda))
621f83e4
CD
6969 (donepb (member tb org-done-keywords-for-agenda)))
6970 (cond ((and donepa (not donepb)) -1)
6971 ((and (not donepa) donepb) +1)
6972 ((< la lb) -1)
8223b1d2 6973 ((< lb la) +1))))
621f83e4 6974
86fbb8ca
CD
6975(defsubst org-cmp-alpha (a b)
6976 "Compare the headlines, alphabetically."
3ab2c837
BG
6977 (let* ((pla (text-property-any 0 (length a) 'org-heading t a))
6978 (plb (text-property-any 0 (length b) 'org-heading t b))
86fbb8ca
CD
6979 (ta (and pla (substring a pla)))
6980 (tb (and plb (substring b plb))))
6981 (when pla
6982 (if (string-match (concat "\\`[ \t]*" (or (get-text-property 0 'org-todo-regexp a) "")
6983 "\\([ \t]*\\[[a-zA-Z0-9]\\]\\)? *") ta)
6984 (setq ta (substring ta (match-end 0))))
6985 (setq ta (downcase ta)))
6986 (when plb
6987 (if (string-match (concat "\\`[ \t]*" (or (get-text-property 0 'org-todo-regexp b) "")
6988 "\\([ \t]*\\[[a-zA-Z0-9]\\]\\)? *") tb)
6989 (setq tb (substring tb (match-end 0))))
6990 (setq tb (downcase tb)))
6991 (cond ((not ta) +1)
6992 ((not tb) -1)
6993 ((string-lessp ta tb) -1)
8223b1d2 6994 ((string-lessp tb ta) +1))))
86fbb8ca 6995
20908596 6996(defsubst org-cmp-tag (a b)
71d35b24 6997 "Compare the string values of the first tags of A and B."
20908596
CD
6998 (let ((ta (car (last (get-text-property 1 'tags a))))
6999 (tb (car (last (get-text-property 1 'tags b)))))
7000 (cond ((not ta) +1)
7001 ((not tb) -1)
7002 ((string-lessp ta tb) -1)
8223b1d2 7003 ((string-lessp tb ta) +1))))
20908596
CD
7004
7005(defsubst org-cmp-time (a b)
7006 "Compare the time-of-day values of strings A and B."
7007 (let* ((def (if org-sort-agenda-notime-is-late 9901 -1))
7008 (ta (or (get-text-property 1 'time-of-day a) def))
7009 (tb (or (get-text-property 1 'time-of-day b) def)))
7010 (cond ((< ta tb) -1)
8223b1d2 7011 ((< tb ta) +1))))
20908596 7012
271672fa
BG
7013(defsubst org-cmp-ts (a b &optional type)
7014 "Compare the timestamps values of entries A and B.
7015When TYPE is \"scheduled\", \"deadline\", \"timestamp\" or
7016\"timestamp_ia\", compare within each of these type. When TYPE
7017is the empty string, compare all timestamps without respect of
7018their type."
3c8b09ca 7019 (let* ((def (if org-sort-agenda-notime-is-late most-positive-fixnum -1))
271672fa
BG
7020 (ta (or (and (string-match type (or (get-text-property 1 'type a) ""))
7021 (get-text-property 1 'ts-date a)) def))
7022 (tb (or (and (string-match type (or (get-text-property 1 'type b) ""))
7023 (get-text-property 1 'ts-date b)) def)))
7024 (cond ((< ta tb) -1)
7025 ((< tb ta) +1))))
7026
8bfe682a
CD
7027(defsubst org-cmp-habit-p (a b)
7028 "Compare the todo states of strings A and B."
7029 (let ((ha (get-text-property 1 'org-habit-p a))
7030 (hb (get-text-property 1 'org-habit-p b)))
7031 (cond ((and ha (not hb)) -1)
8223b1d2 7032 ((and (not ha) hb) +1))))
8bfe682a 7033
20908596
CD
7034(defun org-entries-lessp (a b)
7035 "Predicate for sorting agenda entries."
7036 ;; The following variables will be used when the form is evaluated.
7037 ;; So even though the compiler complains, keep them.
86fbb8ca 7038 (let* ((ss org-agenda-sorting-strategy-selected)
271672fa
BG
7039 (timestamp-up (and (org-em 'timestamp-up 'timestamp-down ss)
7040 (org-cmp-ts a b "")))
7041 (timestamp-down (if timestamp-up (- timestamp-up) nil))
7042 (scheduled-up (and (org-em 'scheduled-up 'scheduled-down ss)
7043 (org-cmp-ts a b "scheduled")))
7044 (scheduled-down (if scheduled-up (- scheduled-up) nil))
7045 (deadline-up (and (org-em 'deadline-up 'deadline-down ss)
7046 (org-cmp-ts a b "deadline")))
7047 (deadline-down (if deadline-up (- deadline-up) nil))
7048 (tsia-up (and (org-em 'tsia-up 'tsia-down ss)
7049 (org-cmp-ts a b "iatimestamp_ia")))
7050 (tsia-down (if tsia-up (- tsia-up) nil))
7051 (ts-up (and (org-em 'ts-up 'ts-down ss)
7052 (org-cmp-ts a b "timestamp")))
7053 (ts-down (if ts-up (- ts-up) nil))
86fbb8ca
CD
7054 (time-up (and (org-em 'time-up 'time-down ss)
7055 (org-cmp-time a b)))
7056 (time-down (if time-up (- time-up) nil))
7057 (priority-up (and (org-em 'priority-up 'priority-down ss)
7058 (org-cmp-priority a b)))
7059 (priority-down (if priority-up (- priority-up) nil))
7060 (effort-up (and (org-em 'effort-up 'effort-down ss)
7061 (org-cmp-effort a b)))
7062 (effort-down (if effort-up (- effort-up) nil))
7063 (category-up (and (or (org-em 'category-up 'category-down ss)
7064 (memq 'category-keep ss))
7065 (org-cmp-category a b)))
7066 (category-down (if category-up (- category-up) nil))
7067 (category-keep (if category-up +1 nil))
7068 (tag-up (and (org-em 'tag-up 'tag-down ss)
7069 (org-cmp-tag a b)))
7070 (tag-down (if tag-up (- tag-up) nil))
7071 (todo-state-up (and (org-em 'todo-state-up 'todo-state-down ss)
7072 (org-cmp-todo-state a b)))
c8d0cf5c 7073 (todo-state-down (if todo-state-up (- todo-state-up) nil))
86fbb8ca
CD
7074 (habit-up (and (org-em 'habit-up 'habit-down ss)
7075 (org-cmp-habit-p a b)))
7076 (habit-down (if habit-up (- habit-up) nil))
7077 (alpha-up (and (org-em 'alpha-up 'alpha-down ss)
7078 (org-cmp-alpha a b)))
7079 (alpha-down (if alpha-up (- alpha-up) nil))
afe98dfa 7080 (need-user-cmp (org-em 'user-defined-up 'user-defined-down ss))
c8d0cf5c 7081 user-defined-up user-defined-down)
afe98dfa 7082 (if (and need-user-cmp org-agenda-cmp-user-defined
c8d0cf5c
CD
7083 (functionp org-agenda-cmp-user-defined))
7084 (setq user-defined-up
7085 (funcall org-agenda-cmp-user-defined a b)
7086 user-defined-down (if user-defined-up (- user-defined-up) nil)))
20908596
CD
7087 (cdr (assoc
7088 (eval (cons 'or org-agenda-sorting-strategy-selected))
7089 '((-1 . t) (1 . nil) (nil . nil))))))
7090
7091;;; Agenda restriction lock
7092
86fbb8ca 7093(defvar org-agenda-restriction-lock-overlay (make-overlay 1 1)
8bfe682a 7094 "Overlay to mark the headline to which agenda commands are restricted.")
86fbb8ca
CD
7095(overlay-put org-agenda-restriction-lock-overlay
7096 'face 'org-agenda-restriction-lock)
7097(overlay-put org-agenda-restriction-lock-overlay
7098 'help-echo "Agendas are currently limited to this subtree.")
20908596
CD
7099(org-detach-overlay org-agenda-restriction-lock-overlay)
7100
c71bf861 7101;;;###autoload
20908596
CD
7102(defun org-agenda-set-restriction-lock (&optional type)
7103 "Set restriction lock for agenda, to current subtree or file.
7104Restriction will be the file if TYPE is `file', or if type is the
7105universal prefix '(4), or if the cursor is before the first headline
7106in the file. Otherwise, restriction will be to the current subtree."
7107 (interactive "P")
7108 (and (equal type '(4)) (setq type 'file))
7109 (setq type (cond
7110 (type type)
7111 ((org-at-heading-p) 'subtree)
7112 ((condition-case nil (org-back-to-heading t) (error nil))
7113 'subtree)
7114 (t 'file)))
7115 (if (eq type 'subtree)
7116 (progn
271672fa 7117 (setq org-agenda-restrict (current-buffer))
20908596
CD
7118 (setq org-agenda-overriding-restriction 'subtree)
7119 (put 'org-agenda-files 'org-restrict
7120 (list (buffer-file-name (buffer-base-buffer))))
7121 (org-back-to-heading t)
271672fa
BG
7122 (move-overlay org-agenda-restriction-lock-overlay
7123 (point)
7124 (if org-agenda-restriction-lock-highlight-subtree
7125 (save-excursion (org-end-of-subtree t t) (point))
7126 (point-at-eol)))
20908596
CD
7127 (move-marker org-agenda-restrict-begin (point))
7128 (move-marker org-agenda-restrict-end
271672fa 7129 (save-excursion (org-end-of-subtree t t)))
20908596
CD
7130 (message "Locking agenda restriction to subtree"))
7131 (put 'org-agenda-files 'org-restrict
7132 (list (buffer-file-name (buffer-base-buffer))))
7133 (setq org-agenda-restrict nil)
7134 (setq org-agenda-overriding-restriction 'file)
7135 (move-marker org-agenda-restrict-begin nil)
7136 (move-marker org-agenda-restrict-end nil)
7137 (message "Locking agenda restriction to file"))
7138 (setq current-prefix-arg nil)
7139 (org-agenda-maybe-redo))
7140
7141(defun org-agenda-remove-restriction-lock (&optional noupdate)
7142 "Remove the agenda restriction lock."
7143 (interactive "P")
7144 (org-detach-overlay org-agenda-restriction-lock-overlay)
7145 (org-detach-overlay org-speedbar-restriction-lock-overlay)
7146 (setq org-agenda-overriding-restriction nil)
7147 (setq org-agenda-restrict nil)
7148 (put 'org-agenda-files 'org-restrict nil)
7149 (move-marker org-agenda-restrict-begin nil)
7150 (move-marker org-agenda-restrict-end nil)
7151 (setq current-prefix-arg nil)
7152 (message "Agenda restriction lock removed")
7153 (or noupdate (org-agenda-maybe-redo)))
7154
7155(defun org-agenda-maybe-redo ()
7156 "If there is any window showing the agenda view, update it."
7157 (let ((w (get-buffer-window org-agenda-buffer-name t))
7158 (w0 (selected-window)))
7159 (when w
7160 (select-window w)
7161 (org-agenda-redo)
7162 (select-window w0)
7163 (if org-agenda-overriding-restriction
7164 (message "Agenda view shifted to new %s restriction"
7165 org-agenda-overriding-restriction)
7166 (message "Agenda restriction lock removed")))))
7167
7168;;; Agenda commands
7169
7170(defun org-agenda-check-type (error &rest types)
7171 "Check if agenda buffer is of allowed type.
c7cf0ebc
BG
7172If ERROR is non-nil, throw an error, otherwise just return nil.
7173Allowed types are 'agenda 'timeline 'todo 'tags 'search."
8223b1d2
BG
7174 (if (not org-agenda-type)
7175 (error "No Org agenda currently displayed")
7176 (if (memq org-agenda-type types)
7177 t
7178 (if error
7179 (error "Not allowed in %s-type agenda buffers" org-agenda-type)
7180 nil))))
7181
271672fa
BG
7182(defun org-agenda-Quit ()
7183 "Exit the agenda and kill buffers loaded by `org-agenda'.
7184Also restore the window configuration."
20908596
CD
7185 (interactive)
7186 (if org-agenda-columns-active
7187 (org-columns-quit)
7188 (let ((buf (current-buffer)))
8d642074
CD
7189 (if (eq org-agenda-window-setup 'other-frame)
7190 (progn
8d642074 7191 (org-agenda-reset-markers)
8223b1d2 7192 (kill-buffer buf)
8d642074
CD
7193 (org-columns-remove-overlays)
7194 (setq org-agenda-archives-mode nil)
7195 (delete-frame))
7196 (and (not (eq org-agenda-window-setup 'current-window))
7197 (not (one-window-p))
7198 (delete-window))
8d642074 7199 (org-agenda-reset-markers)
8223b1d2 7200 (kill-buffer buf)
8d642074
CD
7201 (org-columns-remove-overlays)
7202 (setq org-agenda-archives-mode nil)))
271672fa 7203 (setq org-agenda-buffer nil)
20908596
CD
7204 ;; Maybe restore the pre-agenda window configuration.
7205 (and org-agenda-restore-windows-after-quit
7206 (not (eq org-agenda-window-setup 'other-frame))
8223b1d2
BG
7207 org-agenda-pre-window-conf
7208 (set-window-configuration org-agenda-pre-window-conf)
7209 (setq org-agenda-pre-window-conf nil))))
7210
7211(defun org-agenda-quit ()
271672fa
BG
7212 "Exit the agenda and restore the window configuration.
7213When `org-agenda-sticky' is non-nil, only bury the agenda."
8223b1d2
BG
7214 (interactive)
7215 (if (and (eq org-indirect-buffer-display 'other-window)
7216 org-last-indirect-buffer)
d3517077
BG
7217 (let ((org-last-indirect-window
7218 (get-buffer-window org-last-indirect-buffer)))
7219 (if org-last-indirect-window
7220 (delete-window org-last-indirect-window))))
8223b1d2
BG
7221 (if org-agenda-columns-active
7222 (org-columns-quit)
7223 (if org-agenda-sticky
7224 (let ((buf (current-buffer)))
7225 (if (eq org-agenda-window-setup 'other-frame)
7226 (progn
7227 (delete-frame))
7228 (and (not (eq org-agenda-window-setup 'current-window))
7229 (not (one-window-p))
7230 (delete-window)))
7231 (with-current-buffer buf
7232 (bury-buffer)
7233 ;; Maybe restore the pre-agenda window configuration.
7234 (and org-agenda-restore-windows-after-quit
7235 (not (eq org-agenda-window-setup 'other-frame))
7236 org-agenda-pre-window-conf
7237 (set-window-configuration org-agenda-pre-window-conf)
7238 (setq org-agenda-pre-window-conf nil))))
7239 (org-agenda-Quit))))
20908596
CD
7240
7241(defun org-agenda-exit ()
271672fa
BG
7242 "Exit the agenda and restore the window configuration.
7243Also kill Org-mode buffers loaded by `org-agenda'. Org-mode
7244buffers visited directly by the user will not be touched."
20908596
CD
7245 (interactive)
7246 (org-release-buffers org-agenda-new-buffers)
7247 (setq org-agenda-new-buffers nil)
8223b1d2
BG
7248 (org-agenda-Quit))
7249
7250(defun org-agenda-kill-all-agenda-buffers ()
735135f9 7251 "Kill all buffers in `org-agenda-mode'.
271672fa
BG
7252This is used when toggling sticky agendas.
7253You can also explicitly invoke it with `C-c a C-k'."
8223b1d2
BG
7254 (interactive)
7255 (let (blist)
7256 (dolist (buf (buffer-list))
7257 (when (with-current-buffer buf (eq major-mode 'org-agenda-mode))
7258 (push buf blist)))
7259 (mapc 'kill-buffer blist)))
20908596
CD
7260
7261(defun org-agenda-execute (arg)
86fbb8ca
CD
7262 "Execute another agenda command, keeping same window.
7263So this is just a shortcut for \\<global-map>`\\[org-agenda]', available
7264in the agenda."
20908596
CD
7265 (interactive "P")
7266 (let ((org-agenda-window-setup 'current-window))
7267 (org-agenda arg)))
7268
8223b1d2
BG
7269(defun org-agenda-redo (&optional all)
7270 "Rebuild possibly ALL agenda view(s) in the current buffer."
7271 (interactive "P")
7272 (let* ((p (or (and (looking-at "\\'") (1- (point))) (point)))
7273 (cpa (unless (eq all t) current-prefix-arg))
7274 (org-agenda-doing-sticky-redo org-agenda-sticky)
7275 (org-agenda-sticky nil)
7276 (org-agenda-buffer-name (or org-agenda-this-buffer-name
7277 org-agenda-buffer-name))
7278 (org-agenda-keep-modes t)
e66ba1df
BG
7279 (tag-filter org-agenda-tag-filter)
7280 (tag-preset (get 'org-agenda-tag-filter :preset-filter))
271672fa 7281 (top-hl-filter org-agenda-top-headline-filter)
e66ba1df
BG
7282 (cat-filter org-agenda-category-filter)
7283 (cat-preset (get 'org-agenda-category-filter :preset-filter))
271672fa
BG
7284 (re-filter org-agenda-regexp-filter)
7285 (re-preset (get 'org-agenda-regexp-filter :preset-filter))
e66ba1df 7286 (org-agenda-tag-filter-while-redo (or tag-filter tag-preset))
20908596
CD
7287 (cols org-agenda-columns-active)
7288 (line (org-current-line))
7289 (window-line (- line (org-current-line (window-start))))
8223b1d2
BG
7290 (lprops (get 'org-agenda-redo-command 'org-lprops))
7291 (redo-cmd (get-text-property p 'org-redo-cmd))
7292 (last-args (get-text-property p 'org-last-args))
735135f9 7293 (org-agenda-overriding-cmd (get-text-property p 'org-series-cmd))
8223b1d2
BG
7294 (org-agenda-overriding-cmd-arguments
7295 (unless (eq all t)
7296 (cond ((listp last-args)
7297 (cons (or cpa (car last-args)) (cdr last-args)))
7298 ((stringp last-args)
7299 last-args))))
735135f9 7300 (series-redo-cmd (get-text-property p 'org-series-redo-cmd)))
e66ba1df
BG
7301 (put 'org-agenda-tag-filter :preset-filter nil)
7302 (put 'org-agenda-category-filter :preset-filter nil)
271672fa 7303 (put 'org-agenda-regexp-filter :preset-filter nil)
20908596
CD
7304 (and cols (org-columns-quit))
7305 (message "Rebuilding agenda buffer...")
735135f9
PE
7306 (if series-redo-cmd
7307 (eval series-redo-cmd)
271672fa 7308 (org-let lprops redo-cmd))
20908596 7309 (setq org-agenda-undo-list nil
271672fa
BG
7310 org-agenda-pending-undo-list nil
7311 org-agenda-tag-filter tag-filter
7312 org-agenda-category-filter cat-filter
7313 org-agenda-regexp-filter re-filter
7314 org-agenda-top-headline-filter top-hl-filter)
20908596 7315 (message "Rebuilding agenda buffer...done")
e66ba1df
BG
7316 (put 'org-agenda-tag-filter :preset-filter tag-preset)
7317 (put 'org-agenda-category-filter :preset-filter cat-preset)
271672fa 7318 (put 'org-agenda-regexp-filter :preset-filter re-preset)
e66ba1df
BG
7319 (and (or tag-filter tag-preset) (org-agenda-filter-apply tag-filter 'tag))
7320 (and (or cat-filter cat-preset) (org-agenda-filter-apply cat-filter 'category))
271672fa
BG
7321 (and (or re-filter re-preset) (org-agenda-filter-apply re-filter 'regexp))
7322 (and top-hl-filter (org-agenda-filter-top-headline-apply top-hl-filter))
3ab2c837 7323 (and cols (org-called-interactively-p 'any) (org-agenda-columns))
54a0dee5 7324 (org-goto-line line)
20908596
CD
7325 (recenter window-line)))
7326
621f83e4 7327(defvar org-global-tags-completion-table nil)
71d35b24 7328(defvar org-agenda-filter-form nil)
153ae947 7329(defvar org-agenda-filtered-by-category nil)
e66ba1df
BG
7330
7331(defun org-agenda-filter-by-category (strip)
7332 "Keep only those lines in the agenda buffer that have a specific category.
7333The category is that of the current line."
7334 (interactive "P")
8223b1d2
BG
7335 (if (and org-agenda-filtered-by-category
7336 org-agenda-category-filter)
e66ba1df
BG
7337 (org-agenda-filter-show-all-cat)
7338 (let ((cat (org-no-properties (get-text-property (point) 'org-category))))
271672fa
BG
7339 (cond
7340 ((and cat strip)
7341 (org-agenda-filter-apply
7342 (push (concat "-" cat) org-agenda-category-filter) 'category))
7343 ((and cat)
7344 (org-agenda-filter-apply
7345 (setq org-agenda-category-filter
7346 (list (concat "+" cat))) 'category))
7347 ((error "No category at point"))))))
7348
7349(defun org-find-top-headline (&optional pos)
7350 "Find the topmost parent headline and return it."
8223b1d2
BG
7351 (save-excursion
7352 (with-current-buffer (if pos (marker-buffer pos) (current-buffer))
7353 (if pos (goto-char pos))
7354 ;; Skip up to the topmost parent
7355 (while (ignore-errors (outline-up-heading 1) t))
7356 (ignore-errors
7357 (nth 4 (org-heading-components))))))
7358
271672fa
BG
7359(defvar org-agenda-filtered-by-top-headline nil)
7360(defun org-agenda-filter-by-top-headline (strip)
7361 "Keep only those lines that are descendants from the same top headline.
7362The top headline is that of the current line."
8223b1d2 7363 (interactive "P")
271672fa 7364 (if org-agenda-filtered-by-top-headline
8223b1d2 7365 (progn
271672fa
BG
7366 (setq org-agenda-filtered-by-top-headline nil
7367 org-agenda-top-headline-filter nil)
8223b1d2 7368 (org-agenda-filter-show-all-cat))
271672fa
BG
7369 (let ((cat (org-find-top-headline (org-get-at-bol 'org-hd-marker))))
7370 (if cat (org-agenda-filter-top-headline-apply cat strip)
8223b1d2
BG
7371 (error "No top-level category at point")))))
7372
271672fa
BG
7373(defvar org-agenda-regexp-filter nil)
7374(defun org-agenda-filter-by-regexp (strip)
7375 "Filter agenda entries by a regular expression.
7376Regexp filters are cumulative.
7377With no prefix argument, keep entries matching the regexp.
7378With one prefix argument, filter out entries matching the regexp.
7379With two prefix arguments, remove the regexp filters."
7380 (interactive "P")
7381 (if (not (equal strip '(16)))
7382 (let ((flt (concat (if (equal strip '(4)) "-" "+")
7383 (read-from-minibuffer
7384 (if (equal strip '(4))
7385 "Filter out entries matching regexp: "
30cb51f1 7386 "Narrow to entries matching regexp: ")))))
271672fa
BG
7387 (push flt org-agenda-regexp-filter)
7388 (org-agenda-filter-apply org-agenda-regexp-filter 'regexp))
7389 (org-agenda-filter-show-all-re)
7390 (message "Regexp filter removed")))
7391
7392(defun org-agenda-filter-remove-all ()
7393 "Remove all filters from the current agenda buffer."
7394 (interactive)
7395 (when org-agenda-tag-filter
7396 (org-agenda-filter-show-all-tag))
7397 (when org-agenda-category-filter
7398 (org-agenda-filter-show-all-cat))
7399 (when org-agenda-regexp-filter
7400 (org-agenda-filter-show-all-re)))
7401
71d35b24 7402(defun org-agenda-filter-by-tag (strip &optional char narrow)
621f83e4
CD
7403 "Keep only those lines in the agenda buffer that have a specific tag.
7404The tag is selected with its fast selection letter, as configured.
71d35b24
CD
7405With prefix argument STRIP, remove all lines that do have the tag.
7406A lisp caller can specify CHAR. NARROW means that the new tag should be
7407used to narrow the search - the interactive user can also press `-' or `+'
7408to switch to narrowing."
621f83e4 7409 (interactive "P")
71d35b24 7410 (let* ((alist org-tag-alist-for-agenda)
8bfe682a
CD
7411 (tag-chars (mapconcat
7412 (lambda (x) (if (and (not (symbolp (car x)))
7413 (cdr x))
7414 (char-to-string (cdr x))
7415 ""))
7416 alist ""))
7417 (efforts (org-split-string
7418 (or (cdr (assoc (concat org-effort-property "_ALL")
7419 org-global-properties))
3ab2c837
BG
7420 "0 0:10 0:30 1:00 2:00 3:00 4:00 5:00 6:00 7:00 8:00"
7421 "")))
8bfe682a
CD
7422 (effort-op org-agenda-filter-effort-default-operator)
7423 (effort-prompt "")
7424 (inhibit-read-only t)
e66ba1df 7425 (current org-agenda-tag-filter)
3ab2c837 7426 maybe-refresh a n tag)
71d35b24 7427 (unless char
ff4be292 7428 (message
8bfe682a
CD
7429 "%s by tag [%s ], [TAB], %s[/]:off, [+-]:narrow, [>=<?]:effort: "
7430 (if narrow "Narrow" "Filter") tag-chars
7431 (if org-agenda-auto-exclude-function "[RET], " ""))
e66ba1df 7432 (setq char (read-char-exclusive)))
71d35b24
CD
7433 (when (member char '(?+ ?-))
7434 ;; Narrowing down
7435 (cond ((equal char ?-) (setq strip t narrow t))
7436 ((equal char ?+) (setq strip nil narrow t)))
ff4be292 7437 (message
71d35b24 7438 "Narrow by tag [%s ], [TAB], [/]:off, [>=<]:effort: " tag-chars)
e66ba1df 7439 (setq char (read-char-exclusive)))
c8d0cf5c 7440 (when (member char '(?< ?> ?= ??))
71d35b24
CD
7441 ;; An effort operator
7442 (setq effort-op (char-to-string char))
71d35b24 7443 (setq alist nil) ; to make sure it will be interpreted as effort.
c8d0cf5c
CD
7444 (unless (equal char ??)
7445 (loop for i from 0 to 9 do
7446 (setq effort-prompt
7447 (concat
7448 effort-prompt " ["
7449 (if (= i 9) "0" (int-to-string (1+ i)))
7450 "]" (nth i efforts))))
7451 (message "Effort%s: %s " effort-op effort-prompt)
e66ba1df 7452 (setq char (read-char-exclusive))
c8d0cf5c 7453 (when (or (< char ?0) (> char ?9))
8223b1d2 7454 (error "Need 1-9,0 to select effort"))))
71d35b24
CD
7455 (when (equal char ?\t)
7456 (unless (local-variable-p 'org-global-tags-completion-table (current-buffer))
7457 (org-set-local 'org-global-tags-completion-table
7458 (org-global-tags-completion-table)))
7459 (let ((completion-ignore-case t))
54a0dee5 7460 (setq tag (org-icompleting-read
71d35b24
CD
7461 "Tag: " org-global-tags-completion-table))))
7462 (cond
8bfe682a 7463 ((equal char ?\r)
e66ba1df 7464 (org-agenda-filter-show-all-tag)
8bfe682a 7465 (when org-agenda-auto-exclude-function
271672fa 7466 (setq org-agenda-tag-filter nil)
ed21c5c8
CD
7467 (dolist (tag (org-agenda-get-represented-tags))
7468 (let ((modifier (funcall org-agenda-auto-exclude-function tag)))
8bfe682a 7469 (if modifier
e66ba1df
BG
7470 (push modifier org-agenda-tag-filter))))
7471 (if (not (null org-agenda-tag-filter))
7472 (org-agenda-filter-apply org-agenda-tag-filter 'tag)))
3ab2c837 7473 (setq maybe-refresh t))
c8d0cf5c 7474 ((equal char ?/)
e66ba1df
BG
7475 (org-agenda-filter-show-all-tag)
7476 (when (get 'org-agenda-tag-filter :preset-filter)
7477 (org-agenda-filter-apply org-agenda-tag-filter 'tag))
7478 (setq maybe-refresh t))
7479 ((equal char ?. )
7480 (setq org-agenda-tag-filter
7481 (mapcar (lambda(tag) (concat "+" tag))
7482 (org-get-at-bol 'tags)))
7483 (org-agenda-filter-apply org-agenda-tag-filter 'tag)
3ab2c837 7484 (setq maybe-refresh t))
71d35b24
CD
7485 ((or (equal char ?\ )
7486 (setq a (rassoc char alist))
7487 (and (>= char ?0) (<= char ?9)
7488 (setq n (if (= char ?0) 9 (- char ?0 1))
7489 tag (concat effort-op (nth n efforts))
7490 a (cons tag nil)))
c8d0cf5c
CD
7491 (and (= char ??)
7492 (setq tag "?eff")
7493 a (cons tag nil))
71d35b24 7494 (and tag (setq a (cons tag nil))))
e66ba1df 7495 (org-agenda-filter-show-all-tag)
71d35b24 7496 (setq tag (car a))
e66ba1df 7497 (setq org-agenda-tag-filter
71d35b24
CD
7498 (cons (concat (if strip "-" "+") tag)
7499 (if narrow current nil)))
e66ba1df 7500 (org-agenda-filter-apply org-agenda-tag-filter 'tag)
3ab2c837
BG
7501 (setq maybe-refresh t))
7502 (t (error "Invalid tag selection character %c" char)))
58e9b49a
BG
7503 (when (and maybe-refresh
7504 (eq org-agenda-clockreport-mode 'with-filter))
3ab2c837 7505 (org-agenda-redo))))
71d35b24 7506
ed21c5c8
CD
7507(defun org-agenda-get-represented-tags ()
7508 "Get a list of all tags currently represented in the agenda."
7509 (let (p tags)
7510 (save-excursion
7511 (goto-char (point-min))
7512 (while (setq p (next-single-property-change (point) 'tags))
7513 (goto-char p)
7514 (mapc (lambda (x) (add-to-list 'tags x))
7515 (get-text-property (point) 'tags))))
7516 tags))
7517
71d35b24 7518(defun org-agenda-filter-by-tag-refine (strip &optional char)
e66ba1df 7519 "Refine the current filter. See `org-agenda-filter-by-tag'."
71d35b24
CD
7520 (interactive "P")
7521 (org-agenda-filter-by-tag strip char 'refine))
7522
271672fa 7523(defun org-agenda-filter-make-matcher (filter type)
e66ba1df 7524 "Create the form that tests a line for agenda filter."
71d35b24 7525 (let (f f1)
271672fa
BG
7526 (cond
7527 ;; Tag filter
7528 ((eq type 'tag)
7529 (setq filter
7530 (delete-dups
7531 (append (get 'org-agenda-tag-filter :preset-filter)
7532 filter)))
7533 (dolist (x filter)
7534 (let ((nfilter (org-agenda-filter-expand-tags filter)) nf nf1
7535 (ffunc
7536 (lambda (nf0 nf01 fltr notgroup op)
7537 (dolist (x fltr)
7538 (if (member x '("-" "+"))
7539 (setq nf01 (if (equal x "-") 'tags '(not tags)))
7540 (if (string-match "[<=>?]" x)
7541 (setq nf01 (org-agenda-filter-effort-form x))
7542 (setq nf01 (list 'member (downcase (substring x 1))
7543 'tags)))
7544 (when (equal (string-to-char x) ?-)
7545 (setq nf01 (list 'not nf01))
7546 (when (not notgroup) (setq op 'and))))
7547 (push nf01 nf0))
7548 (if notgroup
7549 (push (cons 'and nf0) f)
7550 (push (cons (or op 'or) nf0) f)))))
7551 (cond ((equal filter '("+"))
7552 (setq f (list (list 'not 'tags))))
7553 ((equal nfilter filter)
7554 (funcall ffunc f1 f filter t nil))
7555 (t (funcall ffunc nf1 nf nfilter nil nil))))))
7556 ;; Category filter
7557 ((eq type 'category)
7558 (setq filter
7559 (delete-dups
7560 (append (get 'org-agenda-category-filter :preset-filter)
7561 filter)))
7562 (dolist (x filter)
7563 (if (equal "-" (substring x 0 1))
7564 (setq f1 (list 'not (list 'equal (substring x 1) 'cat)))
7565 (setq f1 (list 'equal (substring x 1) 'cat)))
7566 (push f1 f)))
7567 ;; Regexp filter
7568 ((eq type 'regexp)
7569 (setq filter
7570 (delete-dups
7571 (append (get 'org-agenda-regexp-filter :preset-filter)
7572 filter)))
7573 (dolist (x filter)
7574 (if (equal "-" (substring x 0 1))
7575 (setq f1 (list 'not (list 'string-match (substring x 1) 'txt)))
7576 (setq f1 (list 'string-match (substring x 1) 'txt)))
7577 (push f1 f))))
71d35b24
CD
7578 (cons 'and (nreverse f))))
7579
7580(defun org-agenda-filter-effort-form (e)
7581 "Return the form to compare the effort of the current line with what E says.
86fbb8ca 7582E looks like \"+<2:25\"."
71d35b24
CD
7583 (let (op)
7584 (setq e (substring e 1))
7585 (setq op (string-to-char e) e (substring e 1))
c8d0cf5c
CD
7586 (setq op (cond ((equal op ?<) '<=)
7587 ((equal op ?>) '>=)
7588 ((equal op ??) op)
7589 (t '=)))
71d35b24 7590 (list 'org-agenda-compare-effort (list 'quote op)
3ab2c837 7591 (org-duration-string-to-minutes e))))
71d35b24
CD
7592
7593(defun org-agenda-compare-effort (op value)
7594 "Compare the effort of the current line with VALUE, using OP.
7595If the line does not have an effort defined, return nil."
8d642074 7596 (let ((eff (org-get-at-bol 'effort-minutes)))
c8d0cf5c
CD
7597 (if (equal op ??)
7598 (not eff)
7599 (funcall op (or eff (if org-sort-agenda-noeffort-is-high 32767 0))
7600 value))))
71d35b24 7601
271672fa
BG
7602(defun org-agenda-filter-expand-tags (filter &optional no-operator)
7603 "Expand group tags in FILTER for the agenda.
7604When NO-OPERATOR is non-nil, do not add the + operator to returned tags."
7605 (if org-group-tags
7606 (let ((case-fold-search t) rtn)
7607 (mapc
7608 (lambda (f)
7609 (let (f0 dir)
7610 (if (string-match "^\\([+-]\\)\\(.+\\)" f)
7611 (setq dir (match-string 1 f) f0 (match-string 2 f))
7612 (setq dir (if no-operator "" "+") f0 f))
7613 (setq rtn (append (mapcar (lambda(f1) (concat dir f1))
7614 (org-tags-expand f0 t t))
7615 rtn))))
7616 filter)
7617 (reverse rtn))
7618 filter))
7619
e66ba1df 7620(defun org-agenda-filter-apply (filter type)
71d35b24 7621 "Set FILTER as the new agenda filter and apply it."
271672fa
BG
7622 ;; Deactivate `org-agenda-entry-text-mode' when filtering
7623 (if org-agenda-entry-text-mode (org-agenda-entry-text-mode))
7624 (let (tags cat txt)
7625 (setq org-agenda-filter-form
7626 (org-agenda-filter-make-matcher filter type))
801a68c8
BG
7627 (if (and (eq type 'category)
7628 (not (equal (substring (car filter) 0 1) "-")))
7629 ;; Only set `org-agenda-filtered-by-category' to t
7630 ;; when a unique category is used as the filter
7631 (setq org-agenda-filtered-by-category t))
71d35b24
CD
7632 (org-agenda-set-mode-name)
7633 (save-excursion
7634 (goto-char (point-min))
7635 (while (not (eobp))
8d642074 7636 (if (org-get-at-bol 'org-marker)
71d35b24 7637 (progn
271672fa
BG
7638 (setq tags ; used in eval
7639 (apply 'append
7640 (mapcar (lambda (f)
7641 (org-agenda-filter-expand-tags (list f) t))
7642 (org-get-at-bol 'tags)))
7643 cat (get-text-property (point) 'org-category)
7644 txt (get-text-property (point) 'txt))
71d35b24 7645 (if (not (eval org-agenda-filter-form))
e66ba1df 7646 (org-agenda-filter-hide-line type))
71d35b24 7647 (beginning-of-line 2))
afe98dfa
CD
7648 (beginning-of-line 2))))
7649 (if (get-char-property (point) 'invisible)
801a68c8 7650 (ignore-errors (org-agenda-previous-line)))))
621f83e4 7651
271672fa
BG
7652(defun org-agenda-filter-top-headline-apply (hl &optional negative)
7653 "Filter by top headline HL."
8223b1d2
BG
7654 (org-agenda-set-mode-name)
7655 (save-excursion
7656 (goto-char (point-min))
7657 (while (not (eobp))
7658 (let* ((pos (org-get-at-bol 'org-hd-marker))
271672fa
BG
7659 (tophl (and pos (org-find-top-headline pos))))
7660 (if (and tophl (funcall (if negative 'identity 'not)
30cb51f1 7661 (string= hl tophl)))
8223b1d2
BG
7662 (org-agenda-filter-hide-line 'category)))
7663 (beginning-of-line 2)))
7664 (if (get-char-property (point) 'invisible)
7665 (org-agenda-previous-line))
271672fa
BG
7666 (setq org-agenda-top-headline-filter hl
7667 org-agenda-filtered-by-top-headline t))
8223b1d2 7668
e66ba1df 7669(defun org-agenda-filter-hide-line (type)
271672fa 7670 "Hide lines with TYPE in the agenda buffer."
30cb51f1
BG
7671 (let* ((b (max (point-min) (1- (point-at-bol))))
7672 (e (point-at-eol))
7673 (ov (make-overlay b e)))
86fbb8ca 7674 (overlay-put ov 'invisible t)
30cb51f1 7675 (overlay-put ov 'intangible t)
e66ba1df 7676 (overlay-put ov 'type type)
271672fa
BG
7677 (cond ((eq type 'tag) (push ov org-agenda-tag-filter-overlays))
7678 ((eq type 'category) (push ov org-agenda-cat-filter-overlays))
7679 ((eq type 'regexp) (push ov org-agenda-re-filter-overlays)))))
621f83e4 7680
71d35b24
CD
7681(defun org-agenda-fix-tags-filter-overlays-at (&optional pos)
7682 (setq pos (or pos (point)))
7683 (save-excursion
86fbb8ca
CD
7684 (dolist (ov (overlays-at pos))
7685 (when (and (overlay-get ov 'invisible)
e66ba1df 7686 (eq (overlay-get ov 'type) 'tag))
71d35b24 7687 (goto-char pos)
86fbb8ca
CD
7688 (if (< (overlay-start ov) (point-at-eol))
7689 (move-overlay ov (point-at-eol)
8223b1d2 7690 (overlay-end ov)))))))
71d35b24 7691
e66ba1df 7692(defun org-agenda-filter-show-all-tag nil
271672fa 7693 "Remove tag filter overlays from the agenda buffer."
e66ba1df
BG
7694 (mapc 'delete-overlay org-agenda-tag-filter-overlays)
7695 (setq org-agenda-tag-filter-overlays nil
7696 org-agenda-tag-filter nil
7697 org-agenda-filter-form nil)
7698 (org-agenda-set-mode-name))
7699
271672fa
BG
7700(defun org-agenda-filter-show-all-re nil
7701 "Remove regexp filter overlays from the agenda buffer."
7702 (mapc 'delete-overlay org-agenda-re-filter-overlays)
7703 (setq org-agenda-re-filter-overlays nil
7704 org-agenda-regexp-filter nil
7705 org-agenda-filter-form nil)
7706 (org-agenda-set-mode-name))
7707
e66ba1df 7708(defun org-agenda-filter-show-all-cat nil
271672fa 7709 "Remove category filter overlays from the agenda buffer."
e66ba1df
BG
7710 (mapc 'delete-overlay org-agenda-cat-filter-overlays)
7711 (setq org-agenda-cat-filter-overlays nil
7712 org-agenda-filtered-by-category nil
7713 org-agenda-category-filter nil
7714 org-agenda-filter-form nil)
71d35b24 7715 (org-agenda-set-mode-name))
621f83e4 7716
20908596
CD
7717(defun org-agenda-manipulate-query-add ()
7718 "Manipulate the query by adding a search term with positive selection.
ed21c5c8 7719Positive selection means the term must be matched for selection of an entry."
20908596
CD
7720 (interactive)
7721 (org-agenda-manipulate-query ?\[))
7722(defun org-agenda-manipulate-query-subtract ()
7723 "Manipulate the query by adding a search term with negative selection.
ed21c5c8 7724Negative selection means term must not be matched for selection of an entry."
20908596
CD
7725 (interactive)
7726 (org-agenda-manipulate-query ?\]))
7727(defun org-agenda-manipulate-query-add-re ()
7728 "Manipulate the query by adding a search regexp with positive selection.
ed21c5c8 7729Positive selection means the regexp must match for selection of an entry."
20908596
CD
7730 (interactive)
7731 (org-agenda-manipulate-query ?\{))
7732(defun org-agenda-manipulate-query-subtract-re ()
7733 "Manipulate the query by adding a search regexp with negative selection.
ed21c5c8 7734Negative selection means regexp must not match for selection of an entry."
20908596
CD
7735 (interactive)
7736 (org-agenda-manipulate-query ?\}))
7737(defun org-agenda-manipulate-query (char)
7738 (cond
7739 ((memq org-agenda-type '(timeline agenda))
54a0dee5
CD
7740 (let ((org-agenda-include-inactive-timestamps t))
7741 (org-agenda-redo))
7742 (message "Display now includes inactive timestamps as well"))
20908596
CD
7743 ((eq org-agenda-type 'search)
7744 (org-add-to-string
7745 'org-agenda-query-string
ed21c5c8
CD
7746 (if org-agenda-last-search-view-search-was-boolean
7747 (cdr (assoc char '((?\[ . " +") (?\] . " -")
7748 (?\{ . " +{}") (?\} . " -{}"))))
7749 " "))
20908596
CD
7750 (setq org-agenda-redo-command
7751 (list 'org-search-view
8223b1d2
BG
7752 (car (get-text-property (min (1- (point-max)) (point))
7753 'org-last-args))
20908596
CD
7754 org-agenda-query-string
7755 (+ (length org-agenda-query-string)
7756 (if (member char '(?\{ ?\})) 0 1))))
7757 (set-register org-agenda-query-register org-agenda-query-string)
8223b1d2
BG
7758 (let ((org-agenda-overriding-arguments
7759 (cdr org-agenda-redo-command)))
7760 (org-agenda-redo)))
20908596
CD
7761 (t (error "Cannot manipulate query for %s-type agenda buffers"
7762 org-agenda-type))))
7763
7764(defun org-add-to-string (var string)
7765 (set var (concat (symbol-value var) string)))
7766
8223b1d2 7767(defun org-agenda-goto-date (span)
20908596 7768 "Jump to DATE in agenda."
8223b1d2
BG
7769 (interactive "P")
7770 (let* ((org-read-date-prefer-future
7771 (eval org-agenda-jump-prefer-future))
7772 (date (org-read-date))
271672fa 7773 (day (time-to-days (org-time-string-to-time date)))
8223b1d2
BG
7774 (org-agenda-sticky-orig org-agenda-sticky)
7775 (org-agenda-buffer-tmp-name (buffer-name))
7776 (args (get-text-property (min (1- (point-max)) (point)) 'org-last-args))
7777 (0-arg (or current-prefix-arg (car args)))
7778 (2-arg (nth 2 args))
271672fa 7779 (with-hour-p (nth 4 org-agenda-redo-command))
8223b1d2 7780 (newcmd (list 'org-agenda-list 0-arg date
271672fa
BG
7781 (org-agenda-span-to-ndays
7782 2-arg (org-time-string-to-absolute date))
7783 with-hour-p))
8223b1d2
BG
7784 (newargs (cdr newcmd))
7785 (inhibit-read-only t)
7786 org-agenda-sticky)
7787 (if (not (org-agenda-check-type t 'agenda))
271672fa 7788 (error "Not available in non-agenda views")
8223b1d2
BG
7789 (add-text-properties (point-min) (point-max)
7790 `(org-redo-cmd ,newcmd org-last-args ,newargs))
7791 (org-agenda-redo)
271672fa
BG
7792 (goto-char (point-min))
7793 (while (not (or (= (or (get-text-property (point) 'day) 0) day)
7794 (save-excursion (move-beginning-of-line 2) (eobp))))
7795 (move-beginning-of-line 2))
7796 (setq org-agenda-sticky org-agenda-sticky-orig
7797 org-agenda-this-buffer-is-sticky org-agenda-sticky))))
20908596
CD
7798
7799(defun org-agenda-goto-today ()
7800 "Go to today."
7801 (interactive)
7802 (org-agenda-check-type t 'timeline 'agenda)
8223b1d2
BG
7803 (let* ((args (get-text-property (min (1- (point-max)) (point)) 'org-last-args))
7804 (curspan (nth 2 args))
7805 (tdpos (text-property-any (point-min) (point-max) 'org-today t)))
20908596
CD
7806 (cond
7807 (tdpos (goto-char tdpos))
7808 ((eq org-agenda-type 'agenda)
acedf35c 7809 (let* ((sd (org-agenda-compute-starting-span
8223b1d2
BG
7810 (org-today) (or curspan org-agenda-ndays org-agenda-span)))
7811 (org-agenda-overriding-arguments args))
acedf35c 7812 (setf (nth 1 org-agenda-overriding-arguments) sd)
20908596
CD
7813 (org-agenda-redo)
7814 (org-agenda-find-same-or-today-or-agenda)))
7815 (t (error "Cannot find today")))))
7816
7817(defun org-agenda-find-same-or-today-or-agenda (&optional cnt)
7818 (goto-char
7819 (or (and cnt (text-property-any (point-min) (point-max) 'org-day-cnt cnt))
7820 (text-property-any (point-min) (point-max) 'org-today t)
7821 (text-property-any (point-min) (point-max) 'org-agenda-type 'agenda)
735135f9 7822 (and (get-text-property (min (1- (point-max)) (point)) 'org-series)
8223b1d2 7823 (org-agenda-goto-block-beginning))
20908596
CD
7824 (point-min))))
7825
8223b1d2
BG
7826(defun org-agenda-goto-block-beginning ()
7827 "Go the agenda block beginning."
7828 (interactive)
7829 (if (not (derived-mode-p 'org-agenda-mode))
7830 (error "Cannot execute this command outside of org-agenda-mode buffers")
7831 (let (dest)
7832 (save-excursion
7833 (unless (looking-at "\\'")
7834 (forward-char))
7835 (let* ((prop 'org-agenda-structural-header)
7836 (p (previous-single-property-change (point) prop))
7837 (n (next-single-property-change (or (and (looking-at "\\`") 1)
7838 (1- (point))) prop)))
7839 (setq dest (cond ((eq n (point-at-eol)) (1- n)) (p (1- p))))))
7840 (if (not dest)
7841 (error "Cannot find the beginning of the blog")
7842 (goto-char dest)
7843 (move-beginning-of-line 1)))))
7844
20908596 7845(defun org-agenda-later (arg)
bdebdb64 7846 "Go forward in time by the current span.
20908596
CD
7847With prefix ARG, go forward that many times the current span."
7848 (interactive "p")
7849 (org-agenda-check-type t 'agenda)
8223b1d2
BG
7850 (let* ((args (get-text-property (min (1- (point-max)) (point)) 'org-last-args))
7851 (span (or (nth 2 args) org-agenda-current-span))
7852 (sd (or (nth 1 args) (org-get-at-bol 'day) org-starting-day))
20908596 7853 (greg (calendar-gregorian-from-absolute sd))
8d642074 7854 (cnt (org-get-at-bol 'org-day-cnt))
acedf35c 7855 greg2)
20908596 7856 (cond
8223b1d2 7857 ((numberp span)
bdebdb64 7858 (setq sd (+ (* span arg) sd)))
20908596 7859 ((eq span 'day)
acedf35c 7860 (setq sd (+ arg sd)))
20908596 7861 ((eq span 'week)
acedf35c 7862 (setq sd (+ (* 7 arg) sd)))
271672fa
BG
7863 ((eq span 'fortnight)
7864 (setq sd (+ (* 14 arg) sd)))
20908596
CD
7865 ((eq span 'month)
7866 (setq greg2 (list (+ (car greg) arg) (nth 1 greg) (nth 2 greg))
7867 sd (calendar-absolute-from-gregorian greg2))
acedf35c 7868 (setcar greg2 (1+ (car greg2))))
20908596
CD
7869 ((eq span 'year)
7870 (setq greg2 (list (car greg) (nth 1 greg) (+ arg (nth 2 greg)))
7871 sd (calendar-absolute-from-gregorian greg2))
acedf35c
CD
7872 (setcar (nthcdr 2 greg2) (1+ (nth 2 greg2))))
7873 (t
7874 (setq sd (+ (* span arg) sd))))
8223b1d2
BG
7875 (let ((org-agenda-overriding-cmd
7876 ;; `cmd' may have been set by `org-agenda-run-series' which
7877 ;; uses `org-agenda-overriding-cmd' to decide whether
7878 ;; overriding is allowed for `cmd'
735135f9 7879 (get-text-property (min (1- (point-max)) (point)) 'org-series-cmd))
8223b1d2
BG
7880 (org-agenda-overriding-arguments
7881 (list (car args) sd span)))
20908596
CD
7882 (org-agenda-redo)
7883 (org-agenda-find-same-or-today-or-agenda cnt))))
7884
7885(defun org-agenda-earlier (arg)
7886 "Go backward in time by the current span.
7887With prefix ARG, go backward that many times the current span."
7888 (interactive "p")
7889 (org-agenda-later (- arg)))
7890
c8d0cf5c
CD
7891(defun org-agenda-view-mode-dispatch ()
7892 "Call one of the view mode commands."
7893 (interactive)
271672fa 7894 (message "View: [d]ay [w]eek for[t]night [m]onth [y]ear [SPC]reset [q]uit/abort
8223b1d2
BG
7895 time[G]rid [[]inactive [f]ollow [l]og [L]og-all [c]lockcheck
7896 [a]rch-trees [A]rch-files clock[R]eport include[D]iary [E]ntryText")
c8d0cf5c
CD
7897 (let ((a (read-char-exclusive)))
7898 (case a
3ab2c837 7899 (?\ (call-interactively 'org-agenda-reset-view))
c8d0cf5c
CD
7900 (?d (call-interactively 'org-agenda-day-view))
7901 (?w (call-interactively 'org-agenda-week-view))
271672fa 7902 (?t (call-interactively 'org-agenda-fortnight-view))
c8d0cf5c
CD
7903 (?m (call-interactively 'org-agenda-month-view))
7904 (?y (call-interactively 'org-agenda-year-view))
7905 (?l (call-interactively 'org-agenda-log-mode))
ed21c5c8 7906 (?L (org-agenda-log-mode '(4)))
3ab2c837 7907 (?c (org-agenda-log-mode 'clockcheck))
54a0dee5 7908 ((?F ?f) (call-interactively 'org-agenda-follow-mode))
c8d0cf5c
CD
7909 (?a (call-interactively 'org-agenda-archives-mode))
7910 (?A (org-agenda-archives-mode 'files))
54a0dee5
CD
7911 ((?R ?r) (call-interactively 'org-agenda-clockreport-mode))
7912 ((?E ?e) (call-interactively 'org-agenda-entry-text-mode))
c8d0cf5c
CD
7913 (?G (call-interactively 'org-agenda-toggle-time-grid))
7914 (?D (call-interactively 'org-agenda-toggle-diary))
ed21c5c8 7915 (?\! (call-interactively 'org-agenda-toggle-deadlines))
54a0dee5
CD
7916 (?\[ (let ((org-agenda-include-inactive-timestamps t))
7917 (org-agenda-check-type t 'timeline 'agenda)
7918 (org-agenda-redo))
7919 (message "Display now includes inactive timestamps as well"))
c8d0cf5c
CD
7920 (?q (message "Abort"))
7921 (otherwise (error "Invalid key" )))))
7922
3ab2c837
BG
7923(defun org-agenda-reset-view ()
7924 "Switch to default view for agenda."
7925 (interactive)
7926 (org-agenda-change-time-span (or org-agenda-ndays org-agenda-span)))
271672fa 7927(defun org-agenda-day-view (&optional day-of-month)
20908596 7928 "Switch to daily view for agenda.
271672fa 7929With argument DAY-OF-MONTH, switch to that day of the month."
20908596 7930 (interactive "P")
271672fa 7931 (org-agenda-change-time-span 'day day-of-month))
20908596
CD
7932(defun org-agenda-week-view (&optional iso-week)
7933 "Switch to daily view for agenda.
7934With argument ISO-WEEK, switch to the corresponding ISO week.
7935If ISO-WEEK has more then 2 digits, only the last two encode the
7936week. Any digits before this encode a year. So 200712 means
7937week 12 of year 2007. Years in the range 1938-2037 can also be
7938written as 2-digit years."
7939 (interactive "P")
20908596 7940 (org-agenda-change-time-span 'week iso-week))
271672fa
BG
7941(defun org-agenda-fortnight-view (&optional iso-week)
7942 "Switch to daily view for agenda.
7943With argument ISO-WEEK, switch to the corresponding ISO week.
7944If ISO-WEEK has more then 2 digits, only the last two encode the
7945week. Any digits before this encode a year. So 200712 means
7946week 12 of year 2007. Years in the range 1938-2037 can also be
7947written as 2-digit years."
7948 (interactive "P")
7949 (org-agenda-change-time-span 'fortnight iso-week))
20908596 7950(defun org-agenda-month-view (&optional month)
b349f79f 7951 "Switch to monthly view for agenda.
20908596
CD
7952With argument MONTH, switch to that month."
7953 (interactive "P")
7954 (org-agenda-change-time-span 'month month))
7955(defun org-agenda-year-view (&optional year)
b349f79f 7956 "Switch to yearly view for agenda.
20908596
CD
7957With argument YEAR, switch to that year.
7958If MONTH has more then 2 digits, only the last two encode the
7959month. Any digits before this encode a year. So 200712 means
7960December year 2007. Years in the range 1938-2037 can also be
7961written as 2-digit years."
7962 (interactive "P")
7963 (when year
7964 (setq year (org-small-year-to-year year)))
7965 (if (y-or-n-p "Are you sure you want to compute the agenda for an entire year? ")
7966 (org-agenda-change-time-span 'year year)
7967 (error "Abort")))
7968
7969(defun org-agenda-change-time-span (span &optional n)
7970 "Change the agenda view to SPAN.
271672fa 7971SPAN may be `day', `week', `fortnight', `month', `year'."
20908596 7972 (org-agenda-check-type t 'agenda)
8223b1d2
BG
7973 (let* ((args (get-text-property (min (1- (point-max)) (point)) 'org-last-args))
7974 (curspan (nth 2 args)))
7975 (if (and (not n) (equal curspan span))
7976 (error "Viewing span is already \"%s\"" span))
7977 (let* ((sd (or (org-get-at-bol 'day)
7978 (nth 1 args)
7979 org-starting-day))
7980 (sd (org-agenda-compute-starting-span sd span n))
7981 (org-agenda-overriding-cmd
735135f9 7982 (get-text-property (min (1- (point-max)) (point)) 'org-series-cmd))
8223b1d2
BG
7983 (org-agenda-overriding-arguments
7984 (list (car args) sd span)))
7985 (org-agenda-redo)
7986 (org-agenda-find-same-or-today-or-agenda))
7987 (org-agenda-set-mode-name)
7988 (message "Switched to %s view" span)))
20908596 7989
acedf35c
CD
7990(defun org-agenda-compute-starting-span (sd span &optional n)
7991 "Compute starting date for agenda.
271672fa 7992SPAN may be `day', `week', `fortnight', `month', `year'. The return value
20908596
CD
7993is a cons cell with the starting date and the number of days,
7994so that the date SD will be in that range."
7995 (let* ((greg (calendar-gregorian-from-absolute sd))
7996 (dg (nth 1 greg))
7997 (mg (car greg))
acedf35c 7998 (yg (nth 2 greg)))
20908596
CD
7999 (cond
8000 ((eq span 'day)
8001 (when n
8002 (setq sd (+ (calendar-absolute-from-gregorian
8003 (list mg 1 yg))
acedf35c 8004 n -1))))
271672fa 8005 ((or (eq span 'week) (eq span 'fortnight))
20908596
CD
8006 (let* ((nt (calendar-day-of-week
8007 (calendar-gregorian-from-absolute sd)))
8008 (d (if org-agenda-start-on-weekday
8009 (- nt org-agenda-start-on-weekday)
acedf35c
CD
8010 0))
8011 y1)
20908596
CD
8012 (setq sd (- sd (+ (if (< d 0) 7 0) d)))
8013 (when n
8014 (require 'cal-iso)
20908596
CD
8015 (when (> n 99)
8016 (setq y1 (org-small-year-to-year (/ n 100))
8017 n (mod n 100)))
8018 (setq sd
8019 (calendar-absolute-from-iso
8020 (list n 1
acedf35c 8021 (or y1 (nth 2 (calendar-iso-from-absolute sd)))))))))
20908596 8022 ((eq span 'month)
acedf35c
CD
8023 (let (y1)
8024 (when (and n (> n 99))
8025 (setq y1 (org-small-year-to-year (/ n 100))
8026 n (mod n 100)))
8027 (setq sd (calendar-absolute-from-gregorian
8028 (list (or n mg) 1 (or y1 yg))))))
20908596
CD
8029 ((eq span 'year)
8030 (setq sd (calendar-absolute-from-gregorian
acedf35c
CD
8031 (list 1 1 (or n yg))))))
8032 sd))
20908596
CD
8033
8034(defun org-agenda-next-date-line (&optional arg)
8035 "Jump to the next line indicating a date in agenda buffer."
8036 (interactive "p")
8037 (org-agenda-check-type t 'agenda 'timeline)
8038 (beginning-of-line 1)
8039 ;; This does not work if user makes date format that starts with a blank
8040 (if (looking-at "^\\S-") (forward-char 1))
8041 (if (not (re-search-forward "^\\S-" nil t arg))
8042 (progn
8043 (backward-char 1)
8044 (error "No next date after this line in this buffer")))
8045 (goto-char (match-beginning 0)))
8046
8047(defun org-agenda-previous-date-line (&optional arg)
8048 "Jump to the previous line indicating a date in agenda buffer."
8049 (interactive "p")
8050 (org-agenda-check-type t 'agenda 'timeline)
8051 (beginning-of-line 1)
8052 (if (not (re-search-backward "^\\S-" nil t arg))
8053 (error "No previous date before this line in this buffer")))
8054
8055;; Initialize the highlight
86fbb8ca
CD
8056(defvar org-hl (make-overlay 1 1))
8057(overlay-put org-hl 'face 'highlight)
20908596
CD
8058
8059(defun org-highlight (begin end &optional buffer)
8060 "Highlight a region with overlay."
86fbb8ca 8061 (move-overlay org-hl begin end (or buffer (current-buffer))))
20908596
CD
8062
8063(defun org-unhighlight ()
8064 "Detach overlay INDEX."
86fbb8ca 8065 (org-detach-overlay org-hl))
20908596 8066
20908596
CD
8067(defun org-unhighlight-once ()
8068 "Remove the highlight from its position, and this function from the hook."
8069 (remove-hook 'pre-command-hook 'org-unhighlight-once)
8070 (org-unhighlight))
8071
8223b1d2 8072(defvar org-agenda-pre-follow-window-conf nil)
20908596
CD
8073(defun org-agenda-follow-mode ()
8074 "Toggle follow mode in an agenda buffer."
8075 (interactive)
8223b1d2
BG
8076 (unless org-agenda-follow-mode
8077 (setq org-agenda-pre-follow-window-conf
8078 (current-window-configuration)))
20908596 8079 (setq org-agenda-follow-mode (not org-agenda-follow-mode))
8223b1d2
BG
8080 (unless org-agenda-follow-mode
8081 (set-window-configuration org-agenda-pre-follow-window-conf))
20908596 8082 (org-agenda-set-mode-name)
e66ba1df 8083 (org-agenda-do-context-action)
20908596
CD
8084 (message "Follow mode is %s"
8085 (if org-agenda-follow-mode "on" "off")))
8086
54a0dee5
CD
8087(defun org-agenda-entry-text-mode (&optional arg)
8088 "Toggle entry text mode in an agenda buffer."
8089 (interactive "P")
271672fa
BG
8090 (if (or org-agenda-tag-filter
8091 org-agenda-category-filter
8092 org-agenda-regexp-filter
8093 org-agenda-top-headline-filter)
8094 (user-error "Can't show entry text in filtered views")
8095 (setq org-agenda-entry-text-mode (or (integerp arg)
8096 (not org-agenda-entry-text-mode)))
8097 (org-agenda-entry-text-hide)
8098 (and org-agenda-entry-text-mode
8099 (let ((org-agenda-entry-text-maxlines
8100 (if (integerp arg) arg org-agenda-entry-text-maxlines)))
8101 (org-agenda-entry-text-show)))
8102 (org-agenda-set-mode-name)
8103 (message "Entry text mode is %s%s"
8104 (if org-agenda-entry-text-mode "on" "off")
8105 (if (not org-agenda-entry-text-mode) ""
8106 (format " (maximum number of lines is %d)"
8107 (if (integerp arg) arg org-agenda-entry-text-maxlines))))))
54a0dee5 8108
acedf35c
CD
8109(defun org-agenda-clockreport-mode (&optional with-filter)
8110 "Toggle clocktable mode in an agenda buffer.
8111With prefix arg WITH-FILTER, make the clocktable respect the current
8112agenda filter."
8113 (interactive "P")
20908596 8114 (org-agenda-check-type t 'agenda)
acedf35c
CD
8115 (if with-filter
8116 (setq org-agenda-clockreport-mode 'with-filter)
8117 (setq org-agenda-clockreport-mode (not org-agenda-clockreport-mode)))
20908596
CD
8118 (org-agenda-set-mode-name)
8119 (org-agenda-redo)
8120 (message "Clocktable mode is %s"
8121 (if org-agenda-clockreport-mode "on" "off")))
8122
93b62de8
CD
8123(defun org-agenda-log-mode (&optional special)
8124 "Toggle log mode in an agenda buffer.
8125With argument SPECIAL, show all possible log items, not only the ones
8126configured in `org-agenda-log-mode-items'.
8127With a double `C-u' prefix arg, show *only* log items, nothing else."
8128 (interactive "P")
20908596 8129 (org-agenda-check-type t 'agenda 'timeline)
93b62de8 8130 (setq org-agenda-show-log
3ab2c837
BG
8131 (cond
8132 ((equal special '(16)) 'only)
8133 ((eq special 'clockcheck)
8134 (if (eq org-agenda-show-log 'clockcheck)
8135 nil 'clockcheck))
8136 (special '(closed clock state))
8137 (t (not org-agenda-show-log))))
20908596
CD
8138 (org-agenda-set-mode-name)
8139 (org-agenda-redo)
8140 (message "Log mode is %s"
8141 (if org-agenda-show-log "on" "off")))
8142
2c3ad40d 8143(defun org-agenda-archives-mode (&optional with-files)
c8d0cf5c
CD
8144 "Toggle inclusion of items in trees marked with :ARCHIVE:.
8145When called with a prefix argument, include all archive files as well."
2c3ad40d
CD
8146 (interactive "P")
8147 (setq org-agenda-archives-mode
8148 (if with-files t (if org-agenda-archives-mode nil 'trees)))
8149 (org-agenda-set-mode-name)
8150 (org-agenda-redo)
8151 (message
8152 "%s"
8153 (cond
8154 ((eq org-agenda-archives-mode nil)
8155 "No archives are included")
8156 ((eq org-agenda-archives-mode 'trees)
8157 (format "Trees with :%s: tag are included" org-archive-tag))
8158 ((eq org-agenda-archives-mode t)
8159 (format "Trees with :%s: tag and all active archive files are included"
8160 org-archive-tag)))))
8161
20908596
CD
8162(defun org-agenda-toggle-diary ()
8163 "Toggle diary inclusion in an agenda buffer."
8164 (interactive)
8165 (org-agenda-check-type t 'agenda)
8166 (setq org-agenda-include-diary (not org-agenda-include-diary))
8167 (org-agenda-redo)
8168 (org-agenda-set-mode-name)
8169 (message "Diary inclusion turned %s"
8170 (if org-agenda-include-diary "on" "off")))
8171
ed21c5c8 8172(defun org-agenda-toggle-deadlines ()
acedf35c 8173 "Toggle inclusion of entries with a deadline in an agenda buffer."
ed21c5c8
CD
8174 (interactive)
8175 (org-agenda-check-type t 'agenda)
8176 (setq org-agenda-include-deadlines (not org-agenda-include-deadlines))
8177 (org-agenda-redo)
8178 (org-agenda-set-mode-name)
8179 (message "Deadlines inclusion turned %s"
8180 (if org-agenda-include-deadlines "on" "off")))
8181
20908596
CD
8182(defun org-agenda-toggle-time-grid ()
8183 "Toggle time grid in an agenda buffer."
8184 (interactive)
8185 (org-agenda-check-type t 'agenda)
8186 (setq org-agenda-use-time-grid (not org-agenda-use-time-grid))
8187 (org-agenda-redo)
8188 (org-agenda-set-mode-name)
8189 (message "Time-grid turned %s"
8190 (if org-agenda-use-time-grid "on" "off")))
8191
8192(defun org-agenda-set-mode-name ()
8193 "Set the mode name to indicate all the small mode settings."
8194 (setq mode-name
acedf35c
CD
8195 (list "Org-Agenda"
8196 (if (get 'org-agenda-files 'org-restrict) " []" "")
8197 " "
8198 '(:eval (org-agenda-span-name org-agenda-current-span))
8199 (if org-agenda-follow-mode " Follow" "")
8200 (if org-agenda-entry-text-mode " ETxt" "")
8201 (if org-agenda-include-diary " Diary" "")
8202 (if org-agenda-include-deadlines " Ddl" "")
8203 (if org-agenda-use-time-grid " Grid" "")
8204 (if (and (boundp 'org-habit-show-habits)
8205 org-habit-show-habits) " Habit" "")
3ab2c837
BG
8206 (cond
8207 ((consp org-agenda-show-log) " LogAll")
8208 ((eq org-agenda-show-log 'clockcheck) " ClkCk")
8209 (org-agenda-show-log " Log")
8210 (t ""))
271672fa
BG
8211 (if (or org-agenda-category-filter
8212 (get 'org-agenda-category-filter :preset-filter))
e66ba1df
BG
8213 '(:eval (org-propertize
8214 (concat " <"
8215 (mapconcat
8216 'identity
8217 (append
8218 (get 'org-agenda-category-filter :preset-filter)
8219 org-agenda-category-filter)
8220 "")
8221 ">")
8222 'face 'org-agenda-filter-category
271672fa
BG
8223 'help-echo "Category used in filtering")) "")
8224 (if (or org-agenda-tag-filter
8225 (get 'org-agenda-tag-filter :preset-filter))
e66ba1df
BG
8226 '(:eval (org-propertize
8227 (concat " {"
8228 (mapconcat
8229 'identity
8230 (append
8231 (get 'org-agenda-tag-filter :preset-filter)
8232 org-agenda-tag-filter)
8233 "")
8234 "}")
8235 'face 'org-agenda-filter-tags
271672fa
BG
8236 'help-echo "Tags used in filtering")) "")
8237 (if (or org-agenda-regexp-filter
8238 (get 'org-agenda-regexp-filter :preset-filter))
8239 '(:eval (org-propertize
8240 (concat " ["
8241 (mapconcat
8242 'identity
8243 (append
8244 (get 'org-agenda-regexp-filter :preset-filter)
8245 org-agenda-regexp-filter)
8246 "")
8247 "]")
8248 'face 'org-agenda-filter-regexp
8249 'help-echo "Regexp used in filtering")) "")
acedf35c
CD
8250 (if org-agenda-archives-mode
8251 (if (eq org-agenda-archives-mode t)
8252 " Archives"
8253 (format " :%s:" org-archive-tag))
8254 "")
8255 (if org-agenda-clockreport-mode
8256 (if (eq org-agenda-clockreport-mode 'with-filter)
8257 " Clock{}" " Clock")
8258 "")))
20908596
CD
8259 (force-mode-line-update))
8260
a89c8ef0 8261(define-obsolete-function-alias
8223b1d2
BG
8262 'org-agenda-post-command-hook 'org-agenda-update-agenda-type "24.3")
8263
8264(defun org-agenda-update-agenda-type ()
8265 "Update the agenda type after each command."
b349f79f
CD
8266 (setq org-agenda-type
8267 (or (get-text-property (point) 'org-agenda-type)
8223b1d2 8268 (get-text-property (max (point-min) (1- (point))) 'org-agenda-type))))
8bfe682a
CD
8269
8270(defun org-agenda-next-line ()
86fbb8ca 8271 "Move cursor to the next line, and show if follow mode is active."
8bfe682a
CD
8272 (interactive)
8273 (call-interactively 'next-line)
1bcdebed
CD
8274 (org-agenda-do-context-action))
8275
8bfe682a
CD
8276(defun org-agenda-previous-line ()
8277 "Move cursor to the previous line, and show if follow-mode is active."
8bfe682a
CD
8278 (interactive)
8279 (call-interactively 'previous-line)
1bcdebed
CD
8280 (org-agenda-do-context-action))
8281
8223b1d2
BG
8282(defun org-agenda-next-item (n)
8283 "Move cursor to next agenda item."
8284 (interactive "p")
8285 (let ((col (current-column)))
8286 (dotimes (c n)
8287 (when (next-single-property-change (point-at-eol) 'org-marker)
8288 (move-end-of-line 1)
8289 (goto-char (next-single-property-change (point) 'org-marker))))
8290 (org-move-to-column col))
8291 (org-agenda-do-context-action))
8292
8293(defun org-agenda-previous-item (n)
8294 "Move cursor to next agenda item."
8295 (interactive "p")
8296 (dotimes (c n)
8297 (let ((col (current-column))
8298 (goto (save-excursion
8299 (move-end-of-line 0)
8300 (previous-single-property-change (point) 'org-marker))))
8301 (if goto (goto-char goto))
8302 (org-move-to-column col)))
8303 (org-agenda-do-context-action))
8304
1bcdebed 8305(defun org-agenda-do-context-action ()
86fbb8ca 8306 "Show outline path and, maybe, follow mode window."
1bcdebed 8307 (let ((m (org-get-at-bol 'org-marker)))
e66ba1df
BG
8308 (when (and (markerp m) (marker-buffer m))
8309 (and org-agenda-follow-mode
8310 (if org-agenda-follow-indirect
8223b1d2 8311 (org-agenda-tree-to-indirect-buffer nil)
e66ba1df
BG
8312 (org-agenda-show)))
8313 (and org-agenda-show-outline-path
8314 (org-with-point-at m (org-display-outline-path t))))))
20908596 8315
20908596
CD
8316(defun org-agenda-show-tags ()
8317 "Show the tags applicable to the current item."
8318 (interactive)
8d642074 8319 (let* ((tags (org-get-at-bol 'tags)))
20908596
CD
8320 (if tags
8321 (message "Tags are :%s:"
8322 (org-no-properties (mapconcat 'identity tags ":")))
8323 (message "No tags associated with this line"))))
8324
8325(defun org-agenda-goto (&optional highlight)
8326 "Go to the Org-mode file which contains the item at point."
8327 (interactive)
8d642074 8328 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
8329 (org-agenda-error)))
8330 (buffer (marker-buffer marker))
8331 (pos (marker-position marker)))
8332 (switch-to-buffer-other-window buffer)
8333 (widen)
86fbb8ca 8334 (push-mark)
20908596 8335 (goto-char pos)
8223b1d2 8336 (when (derived-mode-p 'org-mode)
20908596
CD
8337 (org-show-context 'agenda)
8338 (save-excursion
8339 (and (outline-next-heading)
3ab2c837
BG
8340 (org-flag-heading nil)))) ; show the next heading
8341 (when (outline-invisible-p)
8342 (show-entry)) ; display invisible text
20908596
CD
8343 (recenter (/ (window-height) 2))
8344 (run-hooks 'org-agenda-after-show-hook)
8345 (and highlight (org-highlight (point-at-bol) (point-at-eol)))))
8346
8347(defvar org-agenda-after-show-hook nil
8348 "Normal hook run after an item has been shown from the agenda.
8349Point is in the buffer where the item originated.")
8350
8351(defun org-agenda-kill ()
8352 "Kill the entry or subtree belonging to the current agenda entry."
8353 (interactive)
8354 (or (eq major-mode 'org-agenda-mode) (error "Not in agenda"))
8223b1d2
BG
8355 (let* ((bufname-orig (buffer-name))
8356 (marker (or (org-get-at-bol 'org-marker)
20908596
CD
8357 (org-agenda-error)))
8358 (buffer (marker-buffer marker))
8359 (pos (marker-position marker))
8d642074 8360 (type (org-get-at-bol 'type))
20908596
CD
8361 dbeg dend (n 0) conf)
8362 (org-with-remote-undo buffer
8223b1d2
BG
8363 (with-current-buffer buffer
8364 (save-excursion
8365 (goto-char pos)
8366 (if (and (derived-mode-p 'org-mode) (not (member type '("sexp"))))
8367 (setq dbeg (progn (org-back-to-heading t) (point))
8368 dend (org-end-of-subtree t t))
8369 (setq dbeg (point-at-bol)
8370 dend (min (point-max) (1+ (point-at-eol)))))
8371 (goto-char dbeg)
8372 (while (re-search-forward "^[ \t]*\\S-" dend t) (setq n (1+ n)))))
8373 (setq conf (or (eq t org-agenda-confirm-kill)
8374 (and (numberp org-agenda-confirm-kill)
8375 (> n org-agenda-confirm-kill))))
8376 (and conf
8377 (not (y-or-n-p
8378 (format "Delete entry with %d lines in buffer \"%s\"? "
8379 n (buffer-name buffer))))
8380 (error "Abort"))
8381 (let ((org-agenda-buffer-name bufname-orig))
8382 (org-remove-subtree-entries-from-agenda buffer dbeg dend))
8383 (with-current-buffer buffer (delete-region dbeg dend))
8384 (message "Agenda item and source killed"))))
8385
8386(defvar org-archive-default-command) ; defined in org-archive.el
8bfe682a
CD
8387(defun org-agenda-archive-default ()
8388 "Archive the entry or subtree belonging to the current agenda entry."
8389 (interactive)
8390 (require 'org-archive)
8391 (org-agenda-archive-with org-archive-default-command))
8392
8393(defun org-agenda-archive-default-with-confirmation ()
8394 "Archive the entry or subtree belonging to the current agenda entry."
8395 (interactive)
8396 (require 'org-archive)
8397 (org-agenda-archive-with org-archive-default-command 'confirm))
8398
20908596
CD
8399(defun org-agenda-archive ()
8400 "Archive the entry or subtree belonging to the current agenda entry."
8401 (interactive)
8bfe682a 8402 (org-agenda-archive-with 'org-archive-subtree))
20908596
CD
8403
8404(defun org-agenda-archive-to-archive-sibling ()
8bfe682a
CD
8405 "Move the entry to the archive sibling."
8406 (interactive)
8407 (org-agenda-archive-with 'org-archive-to-archive-sibling))
8408
8409(defun org-agenda-archive-with (cmd &optional confirm)
20908596
CD
8410 "Move the entry to the archive sibling."
8411 (interactive)
8412 (or (eq major-mode 'org-agenda-mode) (error "Not in agenda"))
8223b1d2
BG
8413 (let* ((bufname-orig (buffer-name))
8414 (marker (or (org-get-at-bol 'org-marker)
20908596
CD
8415 (org-agenda-error)))
8416 (buffer (marker-buffer marker))
8417 (pos (marker-position marker)))
8418 (org-with-remote-undo buffer
8419 (with-current-buffer buffer
8223b1d2 8420 (if (derived-mode-p 'org-mode)
8bfe682a
CD
8421 (if (and confirm
8422 (not (y-or-n-p "Archive this subtree or entry? ")))
8423 (error "Abort")
271672fa 8424 (save-window-excursion
8bfe682a 8425 (goto-char pos)
8223b1d2
BG
8426 (let ((org-agenda-buffer-name bufname-orig))
8427 (org-remove-subtree-entries-from-agenda))
8bfe682a
CD
8428 (org-back-to-heading t)
8429 (funcall cmd)))
20908596
CD
8430 (error "Archiving works only in Org-mode files"))))))
8431
8432(defun org-remove-subtree-entries-from-agenda (&optional buf beg end)
8433 "Remove all lines in the agenda that correspond to a given subtree.
8434The subtree is the one in buffer BUF, starting at BEG and ending at END.
8435If this information is not given, the function uses the tree at point."
8436 (let ((buf (or buf (current-buffer))) m p)
8437 (save-excursion
8438 (unless (and beg end)
8439 (org-back-to-heading t)
8440 (setq beg (point))
8441 (org-end-of-subtree t)
8442 (setq end (point)))
8443 (set-buffer (get-buffer org-agenda-buffer-name))
8444 (save-excursion
8445 (goto-char (point-max))
8446 (beginning-of-line 1)
8447 (while (not (bobp))
8d642074 8448 (when (and (setq m (org-get-at-bol 'org-marker))
20908596
CD
8449 (equal buf (marker-buffer m))
8450 (setq p (marker-position m))
8451 (>= p beg)
c8d0cf5c 8452 (< p end))
20908596
CD
8453 (let ((inhibit-read-only t))
8454 (delete-region (point-at-bol) (1+ (point-at-eol)))))
8455 (beginning-of-line 0))))))
8456
86fbb8ca 8457(defun org-agenda-refile (&optional goto rfloc no-update)
271672fa
BG
8458 "Refile the item at point.
8459
8460When GOTO is 0 or '(64), clear the refile cache.
8461When GOTO is '(16), go to the location of the last refiled item.
8462RFLOC can be a refile location obtained in a different way.
8463When NO-UPDATE is non-nil, don't redo the agenda buffer."
54a0dee5 8464 (interactive "P")
271672fa
BG
8465 (cond
8466 ((member goto '(0 (64)))
8467 (org-refile-cache-clear))
8468 ((equal goto '(16))
8469 (org-refile-goto-last-stored))
8470 (t
8223b1d2
BG
8471 (let* ((buffer-orig (buffer-name))
8472 (marker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
8473 (org-agenda-error)))
8474 (buffer (marker-buffer marker))
8475 (pos (marker-position marker))
8476 (rfloc (or rfloc
8477 (org-refile-get-location
3ab2c837 8478 (if goto "Goto" "Refile to") buffer
54a0dee5
CD
8479 org-refile-allow-creating-parent-nodes))))
8480 (with-current-buffer buffer
8481 (save-excursion
8482 (save-restriction
8483 (widen)
8484 (goto-char marker)
8223b1d2
BG
8485 (let ((org-agenda-buffer-name buffer-orig))
8486 (org-remove-subtree-entries-from-agenda))
86fbb8ca 8487 (org-refile goto buffer rfloc)))))
271672fa 8488 (unless no-update (org-agenda-redo)))))
54a0dee5
CD
8489
8490(defun org-agenda-open-link (&optional arg)
c7cf0ebc
BG
8491 "Open the link(s) in the current entry, if any.
8492This looks for a link in the displayed line in the agenda.
8493It also looks at the text of the entry itself."
c8d0cf5c 8494 (interactive "P")
8d642074
CD
8495 (let* ((marker (or (org-get-at-bol 'org-hd-marker)
8496 (org-get-at-bol 'org-marker)))
8497 (buffer (and marker (marker-buffer marker)))
d3517077 8498 (prefix (buffer-substring (point-at-bol) (point-at-eol)))
30cb51f1
BG
8499 (lkall (and buffer (org-offer-links-in-entry
8500 buffer marker arg prefix)))
d3517077
BG
8501 (lk0 (car lkall))
8502 (lk (if (stringp lk0) (list lk0) lk0))
c7cf0ebc
BG
8503 (lkend (cdr lkall))
8504 trg)
8bfe682a 8505 (cond
d3517077
BG
8506 ((and buffer lk)
8507 (mapcar (lambda(l)
8508 (with-current-buffer buffer
8509 (setq trg (and (string-match org-bracket-link-regexp l)
8510 (match-string 1 l)))
8511 (if (or (not trg) (string-match org-any-link-re trg))
8512 (save-excursion
8513 (save-restriction
8514 (widen)
8515 (goto-char marker)
8516 (when (search-forward l nil lkend)
8517 (goto-char (match-beginning 0))
8518 (org-open-at-point))))
8519 ;; This is an internal link, widen the buffer
8520 (switch-to-buffer-other-window buffer)
8521 (widen)
8522 (goto-char marker)
8523 (when (search-forward l nil lkend)
8524 (goto-char (match-beginning 0))
8525 (org-open-at-point)))))
8526 lk))
8bfe682a
CD
8527 ((or (org-in-regexp (concat "\\(" org-bracket-link-regexp "\\)"))
8528 (save-excursion
8529 (beginning-of-line 1)
8530 (looking-at (concat ".*?\\(" org-bracket-link-regexp "\\)"))))
8531 (org-open-link-from-string (match-string 1)))
c7cf0ebc 8532 (t (message "No link to open here")))))
20908596
CD
8533
8534(defun org-agenda-copy-local-variable (var)
8535 "Get a variable from a referenced buffer and install it here."
8d642074 8536 (let ((m (org-get-at-bol 'org-marker)))
20908596
CD
8537 (when (and m (buffer-live-p (marker-buffer m)))
8538 (org-set-local var (with-current-buffer (marker-buffer m)
8539 (symbol-value var))))))
8540
8541(defun org-agenda-switch-to (&optional delete-other-windows)
8542 "Go to the Org-mode file which contains the item at point."
8543 (interactive)
8bfe682a
CD
8544 (if (and org-return-follows-link
8545 (not (org-get-at-bol 'org-marker))
8546 (org-in-regexp org-bracket-link-regexp))
8547 (org-open-link-from-string (match-string 0))
8548 (let* ((marker (or (org-get-at-bol 'org-marker)
8549 (org-agenda-error)))
8550 (buffer (marker-buffer marker))
8551 (pos (marker-position marker)))
e66ba1df 8552 (org-pop-to-buffer-same-window buffer)
8bfe682a
CD
8553 (and delete-other-windows (delete-other-windows))
8554 (widen)
8555 (goto-char pos)
8223b1d2 8556 (when (derived-mode-p 'org-mode)
8bfe682a
CD
8557 (org-show-context 'agenda)
8558 (save-excursion
8559 (and (outline-next-heading)
3ab2c837
BG
8560 (org-flag-heading nil))) ; show the next heading
8561 (when (outline-invisible-p)
8223b1d2
BG
8562 (show-entry)) ; display invisible text
8563 (run-hooks 'org-agenda-after-show-hook)))))
20908596
CD
8564
8565(defun org-agenda-goto-mouse (ev)
8566 "Go to the Org-mode file which contains the item at the mouse click."
8567 (interactive "e")
8568 (mouse-set-point ev)
8569 (org-agenda-goto))
8570
fdf730ed
CD
8571(defun org-agenda-show (&optional full-entry)
8572 "Display the Org-mode file which contains the item at point.
8573With prefix argument FULL-ENTRY, make the entire entry visible
8574if it was hidden in the outline."
8575 (interactive "P")
20908596 8576 (let ((win (selected-window)))
fdf730ed
CD
8577 (if full-entry
8578 (let ((org-show-entry-below t))
8579 (org-agenda-goto t))
8580 (org-agenda-goto t))
20908596
CD
8581 (select-window win)))
8582
8bfe682a 8583(defvar org-agenda-show-window nil)
8223b1d2 8584(defun org-agenda-show-and-scroll-up (&optional arg)
8bfe682a 8585 "Display the Org-mode file which contains the item at point.
8223b1d2
BG
8586When called repeatedly, scroll the window that is displaying the buffer.
8587With a \\[universal-argument] prefix, use `org-show-entry' instead of
8588`show-subtree' to display the item, so that drawers and logbooks stay
8589folded."
8590 (interactive "P")
8bfe682a
CD
8591 (let ((win (selected-window)))
8592 (if (and (window-live-p org-agenda-show-window)
8593 (eq this-command last-command))
8594 (progn
8595 (select-window org-agenda-show-window)
8596 (ignore-errors (scroll-up)))
8597 (org-agenda-goto t)
8223b1d2 8598 (if arg (org-show-entry) (show-subtree))
8bfe682a
CD
8599 (setq org-agenda-show-window (selected-window)))
8600 (select-window win)))
8601
8602(defun org-agenda-show-scroll-down ()
8603 "Scroll down the window showing the agenda."
8604 (interactive)
8605 (let ((win (selected-window)))
8606 (when (window-live-p org-agenda-show-window)
8607 (select-window org-agenda-show-window)
8608 (ignore-errors (scroll-down))
8609 (select-window win))))
8610
c8d0cf5c
CD
8611(defun org-agenda-show-1 (&optional more)
8612 "Display the Org-mode file which contains the item at point.
8bfe682a 8613The prefix arg selects the amount of information to display:
c8d0cf5c
CD
8614
86150 hide the subtree
86161 just show the entry according to defaults.
54a0dee5
CD
86172 show the children view
86183 show the subtree view
c8d0cf5c
CD
86194 show the entire subtree and any LOGBOOK drawers
86205 show the entire subtree and any drawers
8621With prefix argument FULL-ENTRY, make the entire entry visible
8622if it was hidden in the outline."
8623 (interactive "p")
8624 (let ((win (selected-window)))
8625 (org-agenda-goto t)
8626 (org-recenter-heading 1)
8627 (cond
8628 ((= more 0)
8629 (hide-subtree)
54a0dee5
CD
8630 (save-excursion
8631 (org-back-to-heading)
8632 (run-hook-with-args 'org-cycle-hook 'folded))
8633 (message "Remote: FOLDED"))
3ab2c837 8634 ((and (org-called-interactively-p 'any) (= more 1))
c8d0cf5c
CD
8635 (message "Remote: show with default settings"))
8636 ((= more 2)
8637 (show-entry)
54a0dee5 8638 (show-children)
c8d0cf5c
CD
8639 (save-excursion
8640 (org-back-to-heading)
54a0dee5
CD
8641 (run-hook-with-args 'org-cycle-hook 'children))
8642 (message "Remote: CHILDREN"))
c8d0cf5c
CD
8643 ((= more 3)
8644 (show-subtree)
8645 (save-excursion
8646 (org-back-to-heading)
54a0dee5
CD
8647 (run-hook-with-args 'org-cycle-hook 'subtree))
8648 (message "Remote: SUBTREE"))
c8d0cf5c
CD
8649 ((= more 4)
8650 (let* ((org-drawers (delete "LOGBOOK" (copy-sequence org-drawers)))
8651 (org-drawer-regexp
8652 (concat "^[ \t]*:\\("
8653 (mapconcat 'regexp-quote org-drawers "\\|")
8654 "\\):[ \t]*$")))
8655 (show-subtree)
8656 (save-excursion
8657 (org-back-to-heading)
8658 (org-cycle-hide-drawers 'subtree)))
54a0dee5 8659 (message "Remote: SUBTREE AND LOGBOOK"))
c8d0cf5c
CD
8660 ((> more 4)
8661 (show-subtree)
54a0dee5 8662 (message "Remote: SUBTREE AND ALL DRAWERS")))
c8d0cf5c
CD
8663 (select-window win)))
8664
8665(defun org-recenter-heading (n)
8666 (save-excursion
8667 (org-back-to-heading)
8668 (recenter n)))
8669
8670(defvar org-agenda-cycle-counter nil)
54a0dee5 8671(defun org-agenda-cycle-show (&optional n)
c8d0cf5c
CD
8672 "Show the current entry in another window, with default settings.
8673Default settings are taken from `org-show-hierarchy-above' and siblings.
54a0dee5 8674When use repeatedly in immediate succession, the remote entry will cycle
c8d0cf5c
CD
8675through visibility
8676
54a0dee5
CD
8677children -> subtree -> folded
8678
8679When called with a numeric prefix arg, that arg will be passed through to
8680`org-agenda-show-1'. For the interpretation of that argument, see the
8681docstring of `org-agenda-show-1'."
8682 (interactive "P")
8683 (if (integerp n)
8684 (setq org-agenda-cycle-counter n)
8685 (if (not (eq last-command this-command))
8686 (setq org-agenda-cycle-counter 1)
8687 (if (equal org-agenda-cycle-counter 0)
8688 (setq org-agenda-cycle-counter 2)
8689 (setq org-agenda-cycle-counter (1+ org-agenda-cycle-counter))
8690 (if (> org-agenda-cycle-counter 3)
8691 (setq org-agenda-cycle-counter 0)))))
c8d0cf5c
CD
8692 (org-agenda-show-1 org-agenda-cycle-counter))
8693
20908596
CD
8694(defun org-agenda-recenter (arg)
8695 "Display the Org-mode file which contains the item at point and recenter."
8696 (interactive "P")
8697 (let ((win (selected-window)))
8698 (org-agenda-goto t)
8699 (recenter arg)
8700 (select-window win)))
8701
8702(defun org-agenda-show-mouse (ev)
8703 "Display the Org-mode file which contains the item at the mouse click."
8704 (interactive "e")
8705 (mouse-set-point ev)
8706 (org-agenda-show))
8707
8708(defun org-agenda-check-no-diary ()
8709 "Check if the entry is a diary link and abort if yes."
8d642074 8710 (if (org-get-at-bol 'org-agenda-diary-link)
20908596
CD
8711 (org-agenda-error)))
8712
8713(defun org-agenda-error ()
8714 (error "Command not allowed in this line"))
8715
8223b1d2 8716(defun org-agenda-tree-to-indirect-buffer (arg)
20908596 8717 "Show the subtree corresponding to the current entry in an indirect buffer.
8223b1d2
BG
8718This calls the command `org-tree-to-indirect-buffer' from the original buffer.
8719
8720With a numerical prefix ARG, go up to this level and then take that tree.
8721With a negative numeric ARG, go up by this number of levels.
86fbb8ca
CD
8722With a \\[universal-argument] prefix, make a separate frame for this tree (i.e. don't
8723use the dedicated frame)."
8223b1d2
BG
8724 (interactive "P")
8725 (if current-prefix-arg
8726 (org-agenda-do-tree-to-indirect-buffer arg)
8727 (let ((agenda-buffer (buffer-name))
8728 (agenda-window (selected-window))
153ae947
BG
8729 (indirect-window
8730 (and org-last-indirect-buffer
8731 (get-buffer-window org-last-indirect-buffer))))
8223b1d2
BG
8732 (save-window-excursion (org-agenda-do-tree-to-indirect-buffer arg))
8733 (unless (or (eq org-indirect-buffer-display 'new-frame)
8734 (eq org-indirect-buffer-display 'dedicated-frame))
8735 (unwind-protect
8736 (unless (and indirect-window (window-live-p indirect-window))
8737 (setq indirect-window (split-window agenda-window)))
8738 (and indirect-window (select-window indirect-window))
8739 (switch-to-buffer org-last-indirect-buffer :norecord)
8740 (fit-window-to-buffer indirect-window)))
8741 (select-window (get-buffer-window agenda-buffer)))))
8742
8743(defun org-agenda-do-tree-to-indirect-buffer (arg)
e66ba1df 8744 "Same as `org-agenda-tree-to-indirect-buffer' without saving window."
20908596 8745 (org-agenda-check-no-diary)
8d642074 8746 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
8747 (org-agenda-error)))
8748 (buffer (marker-buffer marker))
8749 (pos (marker-position marker)))
8750 (with-current-buffer buffer
8751 (save-excursion
8752 (goto-char pos)
8223b1d2 8753 (funcall 'org-tree-to-indirect-buffer arg)))))
20908596
CD
8754
8755(defvar org-last-heading-marker (make-marker)
8756 "Marker pointing to the headline that last changed its TODO state
8757by a remote command from the agenda.")
8758
8759(defun org-agenda-todo-nextset ()
8760 "Switch TODO entry to next sequence."
8761 (interactive)
8762 (org-agenda-todo 'nextset))
8763
8764(defun org-agenda-todo-previousset ()
8765 "Switch TODO entry to previous sequence."
8766 (interactive)
8767 (org-agenda-todo 'previousset))
8768
8769(defun org-agenda-todo (&optional arg)
8770 "Cycle TODO state of line at point, also in Org-mode file.
8771This changes the line at point, all other lines in the agenda referring to
8772the same tree node, and the headline of the tree node in the Org-mode file."
8773 (interactive "P")
8774 (org-agenda-check-no-diary)
8775 (let* ((col (current-column))
8d642074 8776 (marker (or (org-get-at-bol 'org-marker)
20908596
CD
8777 (org-agenda-error)))
8778 (buffer (marker-buffer marker))
8779 (pos (marker-position marker))
8d642074 8780 (hdmarker (org-get-at-bol 'org-hd-marker))
acedf35c 8781 (todayp (org-agenda-todayp (org-get-at-bol 'day)))
20908596 8782 (inhibit-read-only t)
93b62de8 8783 org-agenda-headline-snapshot-before-repeat newhead just-one)
20908596
CD
8784 (org-with-remote-undo buffer
8785 (with-current-buffer buffer
8786 (widen)
8787 (goto-char pos)
8788 (org-show-context 'agenda)
8789 (save-excursion
8790 (and (outline-next-heading)
8791 (org-flag-heading nil))) ; show the next heading
a2a2e7fb
CD
8792 (let ((current-prefix-arg arg))
8793 (call-interactively 'org-todo))
20908596
CD
8794 (and (bolp) (forward-char 1))
8795 (setq newhead (org-get-heading))
93b62de8
CD
8796 (when (and (org-bound-and-true-p
8797 org-agenda-headline-snapshot-before-repeat)
8798 (not (equal org-agenda-headline-snapshot-before-repeat
8799 newhead))
8800 todayp)
8801 (setq newhead org-agenda-headline-snapshot-before-repeat
8802 just-one t))
20908596
CD
8803 (save-excursion
8804 (org-back-to-heading)
8805 (move-marker org-last-heading-marker (point))))
8806 (beginning-of-line 1)
30cb51f1 8807 (save-window-excursion
93b62de8 8808 (org-agenda-change-all-lines newhead hdmarker 'fixface just-one))
30cb51f1
BG
8809 (when (org-bound-and-true-p org-clock-out-when-done)
8810 (string-match (concat "^" (regexp-opt org-done-keywords-for-agenda))
8811 newhead)
8812 (org-agenda-unmark-clocking-task))
20908596
CD
8813 (org-move-to-column col))))
8814
8815(defun org-agenda-add-note (&optional arg)
8816 "Add a time-stamped note to the entry at point."
8817 (interactive "P")
8818 (org-agenda-check-no-diary)
8d642074 8819 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
8820 (org-agenda-error)))
8821 (buffer (marker-buffer marker))
8822 (pos (marker-position marker))
8d642074 8823 (hdmarker (org-get-at-bol 'org-hd-marker))
20908596
CD
8824 (inhibit-read-only t))
8825 (with-current-buffer buffer
8826 (widen)
8827 (goto-char pos)
8828 (org-show-context 'agenda)
8829 (save-excursion
8830 (and (outline-next-heading)
8831 (org-flag-heading nil))) ; show the next heading
8832 (org-add-note))))
8833
db55f368 8834(defun org-agenda-change-all-lines (newhead hdmarker
4ed008de 8835 &optional fixface just-this)
20908596
CD
8836 "Change all lines in the agenda buffer which match HDMARKER.
8837The new content of the line will be NEWHEAD (as modified by
e66ba1df 8838`org-agenda-format-item'). HDMARKER is checked with
20908596 8839`equal' against all `org-hd-marker' text properties in the file.
33306645 8840If FIXFACE is non-nil, the face of each item is modified according to
db55f368
CD
8841the new TODO state.
8842If JUST-THIS is non-nil, change just the current line, not all.
33306645 8843If FORCE-TAGS is non nil, the car of it returns the new tags."
20908596 8844 (let* ((inhibit-read-only t)
93b62de8 8845 (line (org-current-line))
8223b1d2 8846 (org-agenda-buffer (current-buffer))
fdf730ed 8847 (thetags (with-current-buffer (marker-buffer hdmarker)
4ed008de
CD
8848 (save-excursion (save-restriction (widen)
8849 (goto-char hdmarker)
fdf730ed 8850 (org-get-tags-at)))))
271672fa 8851 props m pl undone-face done-face finish new dotime level cat tags)
20908596
CD
8852 (save-excursion
8853 (goto-char (point-max))
8854 (beginning-of-line 1)
8855 (while (not finish)
8856 (setq finish (bobp))
8d642074 8857 (when (and (setq m (org-get-at-bol 'org-hd-marker))
93b62de8 8858 (or (not just-this) (= (org-current-line) line))
20908596
CD
8859 (equal m hdmarker))
8860 (setq props (text-properties-at (point))
8d642074
CD
8861 dotime (org-get-at-bol 'dotime)
8862 cat (org-get-at-bol 'org-category)
271672fa 8863 level (org-get-at-bol 'level)
4ed008de 8864 tags thetags
3ab2c837
BG
8865 new
8866 (let ((org-prefix-format-compiled
8223b1d2
BG
8867 (or (get-text-property (min (1- (point-max)) (point)) 'format)
8868 org-prefix-format-compiled))
8869 (extra (org-get-at-bol 'extra)))
3ab2c837
BG
8870 (with-current-buffer (marker-buffer hdmarker)
8871 (save-excursion
8872 (save-restriction
8873 (widen)
271672fa 8874 (org-agenda-format-item extra newhead level cat tags dotime)))))
3ab2c837 8875 pl (text-property-any (point-at-bol) (point-at-eol) 'org-heading t)
8d642074
CD
8876 undone-face (org-get-at-bol 'undone-face)
8877 done-face (org-get-at-bol 'done-face))
3ab2c837 8878 (beginning-of-line 1)
20908596
CD
8879 (cond
8880 ((equal new "")
20908596
CD
8881 (and (looking-at ".*\n?") (replace-match "")))
8882 ((looking-at ".*")
8883 (replace-match new t t)
8884 (beginning-of-line 1)
8885 (add-text-properties (point-at-bol) (point-at-eol) props)
8886 (when fixface
8887 (add-text-properties
8888 (point-at-bol) (point-at-eol)
8889 (list 'face
8890 (if org-last-todo-state-is-todo
8891 undone-face done-face))))
8892 (org-agenda-highlight-todo 'line)
8893 (beginning-of-line 1))
8223b1d2
BG
8894 (t (error "Line update did not work")))
8895 (save-restriction
8896 (narrow-to-region (point-at-bol) (point-at-eol))
8897 (org-agenda-finalize)))
8898 (beginning-of-line 0)))))
20908596
CD
8899
8900(defun org-agenda-align-tags (&optional line)
8901 "Align all tags in agenda items to `org-agenda-tags-column'."
8902 (let ((inhibit-read-only t) l c)
8903 (save-excursion
8904 (goto-char (if line (point-at-bol) (point-min)))
afe98dfa 8905 (while (re-search-forward (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@#%:]+:\\)[ \t]*$")
20908596
CD
8906 (if line (point-at-eol) nil) t)
8907 (add-text-properties
8908 (match-beginning 2) (match-end 2)
30ab4580
GM
8909 (list 'face (delq nil (let ((prop (get-text-property
8910 (match-beginning 2) 'face)))
8911 (or (listp prop) (setq prop (list prop)))
8912 (if (memq 'org-tag prop)
8913 prop
8914 (cons 'org-tag prop))))))
20908596
CD
8915 (setq l (- (match-end 2) (match-beginning 2))
8916 c (if (< org-agenda-tags-column 0)
8917 (- (abs org-agenda-tags-column) l)
8918 org-agenda-tags-column))
8919 (delete-region (match-beginning 1) (match-end 1))
8920 (goto-char (match-beginning 1))
8921 (insert (org-add-props
8922 (make-string (max 1 (- c (current-column))) ?\ )
ed21c5c8
CD
8923 (plist-put (copy-sequence (text-properties-at (point)))
8924 'face nil))))
ff4be292
CD
8925 (goto-char (point-min))
8926 (org-font-lock-add-tag-faces (point-max)))))
20908596
CD
8927
8928(defun org-agenda-priority-up ()
8929 "Increase the priority of line at point, also in Org-mode file."
8930 (interactive)
8931 (org-agenda-priority 'up))
8932
8933(defun org-agenda-priority-down ()
8934 "Decrease the priority of line at point, also in Org-mode file."
8935 (interactive)
8936 (org-agenda-priority 'down))
8937
c7cf0ebc 8938(defun org-agenda-priority (&optional force-direction)
20908596
CD
8939 "Set the priority of line at point, also in Org-mode file.
8940This changes the line at point, all other lines in the agenda referring to
c7cf0ebc
BG
8941the same tree node, and the headline of the tree node in the Org-mode file.
8942Called with a universal prefix arg, show the priority instead of setting it."
8223b1d2 8943 (interactive "P")
c7cf0ebc
BG
8944 (if (equal force-direction '(4))
8945 (org-show-priority)
8946 (unless org-enable-priority-commands
8947 (error "Priority commands are disabled"))
8948 (org-agenda-check-no-diary)
30cb51f1
BG
8949 (let* ((col (current-column))
8950 (marker (or (org-get-at-bol 'org-marker)
c7cf0ebc
BG
8951 (org-agenda-error)))
8952 (hdmarker (org-get-at-bol 'org-hd-marker))
8953 (buffer (marker-buffer hdmarker))
8954 (pos (marker-position hdmarker))
8955 (inhibit-read-only t)
8956 newhead)
8957 (org-with-remote-undo buffer
8958 (with-current-buffer buffer
8959 (widen)
8960 (goto-char pos)
8961 (org-show-context 'agenda)
8962 (save-excursion
8963 (and (outline-next-heading)
8964 (org-flag-heading nil))) ; show the next heading
8965 (funcall 'org-priority force-direction)
8966 (end-of-line 1)
8967 (setq newhead (org-get-heading)))
8968 (org-agenda-change-all-lines newhead hdmarker)
30cb51f1 8969 (org-move-to-column col)))))
20908596
CD
8970
8971;; FIXME: should fix the tags property of the agenda line.
c8d0cf5c 8972(defun org-agenda-set-tags (&optional tag onoff)
20908596
CD
8973 "Set tags for the current headline."
8974 (interactive)
8975 (org-agenda-check-no-diary)
3ab2c837 8976 (if (and (org-region-active-p) (org-called-interactively-p 'any))
20908596 8977 (call-interactively 'org-change-tag-in-region)
8d642074 8978 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
20908596
CD
8979 (org-agenda-error)))
8980 (buffer (marker-buffer hdmarker))
8981 (pos (marker-position hdmarker))
8982 (inhibit-read-only t)
4ed008de 8983 newhead)
20908596
CD
8984 (org-with-remote-undo buffer
8985 (with-current-buffer buffer
8986 (widen)
8987 (goto-char pos)
8988 (save-excursion
8989 (org-show-context 'agenda))
8990 (save-excursion
8991 (and (outline-next-heading)
8992 (org-flag-heading nil))) ; show the next heading
8993 (goto-char pos)
c8d0cf5c
CD
8994 (if tag
8995 (org-toggle-tag tag onoff)
8996 (call-interactively 'org-set-tags))
20908596
CD
8997 (end-of-line 1)
8998 (setq newhead (org-get-heading)))
4ed008de 8999 (org-agenda-change-all-lines newhead hdmarker)
20908596
CD
9000 (beginning-of-line 1)))))
9001
54a0dee5
CD
9002(defun org-agenda-set-property ()
9003 "Set a property for the current headline."
9004 (interactive)
9005 (org-agenda-check-no-diary)
8d642074 9006 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
9007 (org-agenda-error)))
9008 (buffer (marker-buffer hdmarker))
9009 (pos (marker-position hdmarker))
9010 (inhibit-read-only t)
9011 newhead)
9012 (org-with-remote-undo buffer
9013 (with-current-buffer buffer
9014 (widen)
9015 (goto-char pos)
9016 (save-excursion
9017 (org-show-context 'agenda))
9018 (save-excursion
9019 (and (outline-next-heading)
9020 (org-flag-heading nil))) ; show the next heading
9021 (goto-char pos)
9022 (call-interactively 'org-set-property)))))
9023
9024(defun org-agenda-set-effort ()
9025 "Set the effort property for the current headline."
9026 (interactive)
9027 (org-agenda-check-no-diary)
8d642074 9028 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
54a0dee5
CD
9029 (org-agenda-error)))
9030 (buffer (marker-buffer hdmarker))
9031 (pos (marker-position hdmarker))
9032 (inhibit-read-only t)
9033 newhead)
9034 (org-with-remote-undo buffer
9035 (with-current-buffer buffer
9036 (widen)
9037 (goto-char pos)
9038 (save-excursion
9039 (org-show-context 'agenda))
9040 (save-excursion
9041 (and (outline-next-heading)
3ab2c837 9042 (org-flag-heading nil))) ; show the next heading
54a0dee5
CD
9043 (goto-char pos)
9044 (call-interactively 'org-set-effort)
3ab2c837
BG
9045 (end-of-line 1)
9046 (setq newhead (org-get-heading)))
9047 (org-agenda-change-all-lines newhead hdmarker))))
54a0dee5 9048
20908596
CD
9049(defun org-agenda-toggle-archive-tag ()
9050 "Toggle the archive tag for the current entry."
9051 (interactive)
9052 (org-agenda-check-no-diary)
8d642074 9053 (let* ((hdmarker (or (org-get-at-bol 'org-hd-marker)
20908596
CD
9054 (org-agenda-error)))
9055 (buffer (marker-buffer hdmarker))
9056 (pos (marker-position hdmarker))
9057 (inhibit-read-only t)
9058 newhead)
9059 (org-with-remote-undo buffer
9060 (with-current-buffer buffer
9061 (widen)
9062 (goto-char pos)
9063 (org-show-context 'agenda)
9064 (save-excursion
9065 (and (outline-next-heading)
9066 (org-flag-heading nil))) ; show the next heading
9067 (call-interactively 'org-toggle-archive-tag)
9068 (end-of-line 1)
9069 (setq newhead (org-get-heading)))
9070 (org-agenda-change-all-lines newhead hdmarker)
9071 (beginning-of-line 1))))
9072
c8d0cf5c
CD
9073(defun org-agenda-do-date-later (arg)
9074 (interactive "P")
9075 (cond
9076 ((or (equal arg '(16))
9077 (memq last-command
9078 '(org-agenda-date-later-minutes org-agenda-date-earlier-minutes)))
9079 (setq this-command 'org-agenda-date-later-minutes)
9080 (org-agenda-date-later-minutes 1))
9081 ((or (equal arg '(4))
9082 (memq last-command
9083 '(org-agenda-date-later-hours org-agenda-date-earlier-hours)))
9084 (setq this-command 'org-agenda-date-later-hours)
9085 (org-agenda-date-later-hours 1))
9086 (t
9087 (org-agenda-date-later (prefix-numeric-value arg)))))
9088
9089(defun org-agenda-do-date-earlier (arg)
9090 (interactive "P")
9091 (cond
9092 ((or (equal arg '(16))
9093 (memq last-command
9094 '(org-agenda-date-later-minutes org-agenda-date-earlier-minutes)))
9095 (setq this-command 'org-agenda-date-earlier-minutes)
9096 (org-agenda-date-earlier-minutes 1))
9097 ((or (equal arg '(4))
9098 (memq last-command
9099 '(org-agenda-date-later-hours org-agenda-date-earlier-hours)))
9100 (setq this-command 'org-agenda-date-earlier-hours)
9101 (org-agenda-date-earlier-hours 1))
9102 (t
9103 (org-agenda-date-earlier (prefix-numeric-value arg)))))
9104
20908596 9105(defun org-agenda-date-later (arg &optional what)
3ab2c837 9106 "Change the date of this item to ARG day(s) later."
20908596
CD
9107 (interactive "p")
9108 (org-agenda-check-type t 'agenda 'timeline)
9109 (org-agenda-check-no-diary)
8d642074 9110 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
9111 (org-agenda-error)))
9112 (buffer (marker-buffer marker))
e66ba1df
BG
9113 (pos (marker-position marker))
9114 cdate today)
20908596 9115 (org-with-remote-undo buffer
e66ba1df
BG
9116 (with-current-buffer buffer
9117 (widen)
9118 (goto-char pos)
9119 (if (not (org-at-timestamp-p))
9120 (error "Cannot find time stamp"))
9121 (when (and org-agenda-move-date-from-past-immediately-to-today
9122 (equal arg 1)
9123 (or (not what) (eq what 'day))
9124 (not (save-match-data (org-at-date-range-p))))
9125 (setq cdate (org-parse-time-string (match-string 0) 'nodefault)
9126 cdate (calendar-absolute-from-gregorian
9127 (list (nth 4 cdate) (nth 3 cdate) (nth 5 cdate)))
9128 today (org-today))
9129 (if (> today cdate)
9130 ;; immediately shift to today
9131 (setq arg (- today cdate))))
9132 (org-timestamp-change arg (or what 'day))
9133 (when (and (org-at-date-range-p)
9134 (re-search-backward org-tr-regexp-both (point-at-bol)))
9135 (let ((end org-last-changed-timestamp))
9136 (org-timestamp-change arg (or what 'day))
9137 (setq org-last-changed-timestamp
9138 (concat org-last-changed-timestamp "--" end)))))
9139 (org-agenda-show-new-time marker org-last-changed-timestamp))
20908596
CD
9140 (message "Time stamp changed to %s" org-last-changed-timestamp)))
9141
9142(defun org-agenda-date-earlier (arg &optional what)
3ab2c837 9143 "Change the date of this item to ARG day(s) earlier."
20908596
CD
9144 (interactive "p")
9145 (org-agenda-date-later (- arg) what))
9146
c8d0cf5c
CD
9147(defun org-agenda-date-later-minutes (arg)
9148 "Change the time of this item, in units of `org-time-stamp-rounding-minutes'."
9149 (interactive "p")
9150 (setq arg (* arg (cadr org-time-stamp-rounding-minutes)))
9151 (org-agenda-date-later arg 'minute))
9152
9153(defun org-agenda-date-earlier-minutes (arg)
9154 "Change the time of this item, in units of `org-time-stamp-rounding-minutes'."
9155 (interactive "p")
9156 (setq arg (* arg (cadr org-time-stamp-rounding-minutes)))
9157 (org-agenda-date-earlier arg 'minute))
9158
9159(defun org-agenda-date-later-hours (arg)
9160 "Change the time of this item, in hour steps."
9161 (interactive "p")
9162 (org-agenda-date-later arg 'hour))
9163
9164(defun org-agenda-date-earlier-hours (arg)
9165 "Change the time of this item, in hour steps."
9166 (interactive "p")
9167 (org-agenda-date-earlier arg 'hour))
9168
20908596
CD
9169(defun org-agenda-show-new-time (marker stamp &optional prefix)
9170 "Show new date stamp via text properties."
9171 ;; We use text properties to make this undoable
8a28a5b8
BG
9172 (let ((inhibit-read-only t))
9173 (setq stamp (concat prefix " => " stamp " "))
20908596
CD
9174 (save-excursion
9175 (goto-char (point-max))
9176 (while (not (bobp))
8d642074 9177 (when (equal marker (org-get-at-bol 'org-marker))
30cb51f1
BG
9178 (remove-text-properties (point-at-bol) (point-at-eol) '(display))
9179 (org-move-to-column (- (window-width) (length stamp)) t)
9180
71d35b24 9181 (org-agenda-fix-tags-filter-overlays-at (point))
20908596
CD
9182 (if (featurep 'xemacs)
9183 ;; Use `duplicable' property to trigger undo recording
9184 (let ((ex (make-extent nil nil))
9185 (gl (make-glyph stamp)))
9186 (set-glyph-face gl 'secondary-selection)
9187 (set-extent-properties
9188 ex (list 'invisible t 'end-glyph gl 'duplicable t))
9189 (insert-extent ex (1- (point)) (point-at-eol)))
9190 (add-text-properties
30cb51f1 9191 (1- (point)) (point-at-eol)
20908596
CD
9192 (list 'display (org-add-props stamp nil
9193 'face 'secondary-selection))))
9194 (beginning-of-line 1))
9195 (beginning-of-line 0)))))
9196
9197(defun org-agenda-date-prompt (arg)
9198 "Change the date of this item. Date is prompted for, with default today.
9199The prefix ARG is passed to the `org-time-stamp' command and can therefore
9200be used to request time specification in the time stamp."
9201 (interactive "P")
9202 (org-agenda-check-type t 'agenda 'timeline)
9203 (org-agenda-check-no-diary)
8d642074 9204 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
9205 (org-agenda-error)))
9206 (buffer (marker-buffer marker))
9207 (pos (marker-position marker)))
9208 (org-with-remote-undo buffer
9209 (with-current-buffer buffer
9210 (widen)
9211 (goto-char pos)
ed21c5c8 9212 (if (not (org-at-timestamp-p t))
20908596 9213 (error "Cannot find time stamp"))
ed21c5c8 9214 (org-time-stamp arg (equal (char-after (match-beginning 0)) ?\[)))
8d642074
CD
9215 (org-agenda-show-new-time marker org-last-changed-timestamp))
9216 (message "Time stamp changed to %s" org-last-changed-timestamp)))
20908596 9217
3ab2c837 9218(defun org-agenda-schedule (arg &optional time)
ed21c5c8 9219 "Schedule the item at point.
3ab2c837 9220ARG is passed through to `org-schedule'."
20908596
CD
9221 (interactive "P")
9222 (org-agenda-check-type t 'agenda 'timeline 'todo 'tags 'search)
9223 (org-agenda-check-no-diary)
8d642074 9224 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
9225 (org-agenda-error)))
9226 (type (marker-insertion-type marker))
9227 (buffer (marker-buffer marker))
9228 (pos (marker-position marker))
9229 (org-insert-labeled-timestamps-at-point nil)
9230 ts)
20908596
CD
9231 (set-marker-insertion-type marker t)
9232 (org-with-remote-undo buffer
9233 (with-current-buffer buffer
9234 (widen)
9235 (goto-char pos)
3ab2c837 9236 (setq ts (org-schedule arg time)))
8a28a5b8 9237 (org-agenda-show-new-time marker ts " S"))
63aa0982 9238 (message "%s" ts)))
20908596 9239
3ab2c837 9240(defun org-agenda-deadline (arg &optional time)
ed21c5c8 9241 "Schedule the item at point.
3ab2c837 9242ARG is passed through to `org-deadline'."
20908596
CD
9243 (interactive "P")
9244 (org-agenda-check-type t 'agenda 'timeline 'todo 'tags 'search)
9245 (org-agenda-check-no-diary)
8d642074 9246 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596
CD
9247 (org-agenda-error)))
9248 (buffer (marker-buffer marker))
9249 (pos (marker-position marker))
9250 (org-insert-labeled-timestamps-at-point nil)
9251 ts)
9252 (org-with-remote-undo buffer
9253 (with-current-buffer buffer
9254 (widen)
9255 (goto-char pos)
3ab2c837 9256 (setq ts (org-deadline arg time)))
8a28a5b8 9257 (org-agenda-show-new-time marker ts " D"))
63aa0982 9258 (message "%s" ts)))
ff4be292 9259
20908596
CD
9260(defun org-agenda-clock-in (&optional arg)
9261 "Start the clock on the currently selected item."
9262 (interactive "P")
9263 (org-agenda-check-no-diary)
9264 (if (equal arg '(4))
9265 (org-clock-in arg)
8d642074 9266 (let* ((marker (or (org-get-at-bol 'org-marker)
20908596 9267 (org-agenda-error)))
271672fa 9268 (hdmarker (or (org-get-at-bol 'org-hd-marker) marker))
b349f79f 9269 (pos (marker-position marker))
271672fa 9270 (col (current-column))
b349f79f 9271 newhead)
20908596
CD
9272 (org-with-remote-undo (marker-buffer marker)
9273 (with-current-buffer (marker-buffer marker)
9274 (widen)
9275 (goto-char pos)
b349f79f
CD
9276 (org-show-context 'agenda)
9277 (org-show-entry)
9278 (org-cycle-hide-drawers 'children)
9279 (org-clock-in arg)
9280 (setq newhead (org-get-heading)))
271672fa
BG
9281 (org-agenda-change-all-lines newhead hdmarker))
9282 (org-move-to-column col))))
20908596 9283
afe98dfa 9284(defun org-agenda-clock-out ()
20908596 9285 "Stop the currently running clock."
afe98dfa 9286 (interactive)
20908596
CD
9287 (unless (marker-buffer org-clock-marker)
9288 (error "No running clock"))
271672fa 9289 (let ((marker (make-marker)) (col (current-column)) newhead)
c8d0cf5c
CD
9290 (org-with-remote-undo (marker-buffer org-clock-marker)
9291 (with-current-buffer (marker-buffer org-clock-marker)
9292 (save-excursion
9293 (save-restriction
9294 (widen)
9295 (goto-char org-clock-marker)
9296 (org-back-to-heading t)
9297 (move-marker marker (point))
9298 (org-clock-out)
9299 (setq newhead (org-get-heading))))))
9300 (org-agenda-change-all-lines newhead marker)
271672fa
BG
9301 (move-marker marker nil)
9302 (org-move-to-column col)
9303 (org-agenda-unmark-clocking-task)))
20908596
CD
9304
9305(defun org-agenda-clock-cancel (&optional arg)
9306 "Cancel the currently running clock."
9307 (interactive "P")
9308 (unless (marker-buffer org-clock-marker)
271672fa 9309 (user-error "No running clock"))
20908596
CD
9310 (org-with-remote-undo (marker-buffer org-clock-marker)
9311 (org-clock-cancel)))
9312
afe98dfa
CD
9313(defun org-agenda-clock-goto ()
9314 "Jump to the currently clocked in task within the agenda.
9315If the currently clocked in task is not listed in the agenda
9316buffer, display it in another window."
9317 (interactive)
9318 (let (pos)
9319 (mapc (lambda (o)
9320 (if (eq (overlay-get o 'type) 'org-agenda-clocking)
9321 (setq pos (overlay-start o))))
9322 (overlays-in (point-min) (point-max)))
9323 (cond (pos (goto-char pos))
9324 ;; If the currently clocked entry is not in the agenda
9325 ;; buffer, we visit it in another window:
9326 (org-clock-current-task
9327 (org-switch-to-buffer-other-window (org-clock-goto)))
9328 (t (message "No running clock, use `C-c C-x C-j' to jump to the most recent one")))))
9329
8bfe682a
CD
9330(defun org-agenda-diary-entry-in-org-file ()
9331 "Make a diary entry in the file `org-agenda-diary-file'."
5dec9555 9332 (let (d1 d2 char (text "") dp1 dp2)
8bfe682a
CD
9333 (if (equal (buffer-name) "*Calendar*")
9334 (setq d1 (calendar-cursor-to-date t)
9335 d2 (car calendar-mark-ring))
5dec9555 9336 (setq dp1 (get-text-property (point-at-bol) 'day))
271672fa 9337 (unless dp1 (user-error "No date defined in current line"))
5dec9555
CD
9338 (setq d1 (calendar-gregorian-from-absolute dp1)
9339 d2 (and (ignore-errors (mark))
9340 (save-excursion
9341 (goto-char (mark))
9342 (setq dp2 (get-text-property (point-at-bol) 'day)))
9343 (calendar-gregorian-from-absolute dp2))))
8bfe682a
CD
9344 (message "Diary entry: [d]ay [a]nniversary [b]lock [j]ump to date tree")
9345 (setq char (read-char-exclusive))
9346 (cond
9347 ((equal char ?d)
9348 (setq text (read-string "Day entry: "))
5dec9555
CD
9349 (org-agenda-add-entry-to-org-agenda-diary-file 'day text d1)
9350 (and (equal (buffer-name) org-agenda-buffer-name) (org-agenda-redo)))
8bfe682a
CD
9351 ((equal char ?a)
9352 (setq d1 (list (car d1) (nth 1 d1)
9353 (read-number (format "Reference year [%d]: " (nth 2 d1))
9354 (nth 2 d1))))
9355 (setq text (read-string "Anniversary (use %d to show years): "))
5dec9555
CD
9356 (org-agenda-add-entry-to-org-agenda-diary-file 'anniversary text d1)
9357 (and (equal (buffer-name) org-agenda-buffer-name) (org-agenda-redo)))
8bfe682a
CD
9358 ((equal char ?b)
9359 (setq text (read-string "Block entry: "))
9360 (unless (and d1 d2 (not (equal d1 d2)))
271672fa 9361 (user-error "No block of days selected"))
5dec9555
CD
9362 (org-agenda-add-entry-to-org-agenda-diary-file 'block text d1 d2)
9363 (and (equal (buffer-name) org-agenda-buffer-name) (org-agenda-redo)))
8bfe682a
CD
9364 ((equal char ?j)
9365 (org-switch-to-buffer-other-window
9366 (find-file-noselect org-agenda-diary-file))
ed21c5c8 9367 (require 'org-datetree)
8bfe682a
CD
9368 (org-datetree-find-date-create d1)
9369 (org-reveal t))
271672fa 9370 (t (user-error "Invalid selection character `%c'" char)))))
8bfe682a 9371
5dec9555
CD
9372(defcustom org-agenda-insert-diary-strategy 'date-tree
9373 "Where in `org-agenda-diary-file' should new entries be added?
9374Valid values:
9375
9376date-tree in the date tree, as child of the date
9377top-level as top-level entries at the end of the file."
9378 :group 'org-agenda
9379 :type '(choice
9380 (const :tag "in a date tree" date-tree)
9381 (const :tag "as top level at end of file" top-level)))
9382
ed21c5c8
CD
9383(defcustom org-agenda-insert-diary-extract-time nil
9384 "Non-nil means extract any time specification from the diary entry."
9385 :group 'org-agenda
372d7b21 9386 :version "24.1"
ed21c5c8
CD
9387 :type 'boolean)
9388
8223b1d2
BG
9389(defcustom org-agenda-bulk-mark-char ">"
9390 "A single-character string to be used as the bulk mark."
9391 :group 'org-agenda
9392 :version "24.1"
9393 :type 'string)
9394
8bfe682a
CD
9395(defun org-agenda-add-entry-to-org-agenda-diary-file (type text &optional d1 d2)
9396 "Add a diary entry with TYPE to `org-agenda-diary-file'.
9397If TEXT is not empty, it will become the headline of the new entry, and
9398the resulting entry will not be shown. When TEXT is empty, switch to
9399`org-agenda-diary-file' and let the user finish the entry there."
9400 (let ((cw (current-window-configuration)))
9401 (org-switch-to-buffer-other-window
9402 (find-file-noselect org-agenda-diary-file))
9403 (widen)
9404 (goto-char (point-min))
9405 (cond
9406 ((eq type 'anniversary)
9407 (or (re-search-forward "^*[ \t]+Anniversaries" nil t)
8223b1d2
BG
9408 (progn
9409 (or (org-at-heading-p t)
9410 (progn
9411 (outline-next-heading)
9412 (insert "* Anniversaries\n\n")
9413 (beginning-of-line -1)))))
8bfe682a
CD
9414 (outline-next-heading)
9415 (org-back-over-empty-lines)
9416 (backward-char 1)
9417 (insert "\n")
3ab2c837
BG
9418 (insert (format "%%%%(org-anniversary %d %2d %2d) %s"
9419 (nth 2 d1) (car d1) (nth 1 d1) text)))
8bfe682a 9420 ((eq type 'day)
ed21c5c8
CD
9421 (let ((org-prefix-has-time t)
9422 (org-agenda-time-leading-zero t)
9423 fmt time time2)
9424 (if org-agenda-insert-diary-extract-time
e66ba1df 9425 ;; Use org-agenda-format-item to parse text for a time-range and
ed21c5c8
CD
9426 ;; remove it. FIXME: This is a hack, we should refactor
9427 ;; that function to make time extraction available separately
271672fa 9428 (setq fmt (org-agenda-format-item nil text nil nil nil t)
ed21c5c8
CD
9429 time (get-text-property 0 'time fmt)
9430 time2 (if (> (length time) 0)
9431 ;; split-string removes trailing ...... if
9432 ;; no end time given. First space
9433 ;; separates time from date.
9434 (concat " " (car (split-string time "\\.")))
9435 nil)
9436 text (get-text-property 0 'txt fmt)))
9437 (if (eq org-agenda-insert-diary-strategy 'top-level)
9438 (org-agenda-insert-diary-as-top-level text)
9439 (require 'org-datetree)
9440 (org-datetree-find-date-create d1)
9441 (org-agenda-insert-diary-make-new-entry text))
9442 (org-insert-time-stamp (org-time-from-absolute
9443 (calendar-absolute-from-gregorian d1))
9444 nil nil nil nil time2))
8bfe682a
CD
9445 (end-of-line 0))
9446 ((eq type 'block)
9447 (if (> (calendar-absolute-from-gregorian d1)
9448 (calendar-absolute-from-gregorian d2))
9449 (setq d1 (prog1 d2 (setq d2 d1))))
5dec9555
CD
9450 (if (eq org-agenda-insert-diary-strategy 'top-level)
9451 (org-agenda-insert-diary-as-top-level text)
9452 (require 'org-datetree)
9453 (org-datetree-find-date-create d1)
9454 (org-agenda-insert-diary-make-new-entry text))
8bfe682a
CD
9455 (org-insert-time-stamp (org-time-from-absolute
9456 (calendar-absolute-from-gregorian d1)))
9457 (insert "--")
9458 (org-insert-time-stamp (org-time-from-absolute
9459 (calendar-absolute-from-gregorian d2)))
9460 (end-of-line 0)))
9461 (if (string-match "\\S-" text)
9462 (progn
9463 (set-window-configuration cw)
9464 (message "%s entry added to %s"
9465 (capitalize (symbol-name type))
9466 (abbreviate-file-name org-agenda-diary-file)))
9467 (org-reveal t)
9468 (message "Please finish entry here"))))
9469
5dec9555
CD
9470(defun org-agenda-insert-diary-as-top-level (text)
9471 "Make new entry as a top-level entry at the end of the file.
9472Add TEXT as headline, and position the cursor in the second line so that
9473a timestamp can be added there."
9474 (widen)
9475 (goto-char (point-max))
9476 (or (bolp) (insert "\n"))
9477 (insert "* " text "\n")
9478 (if org-adapt-indentation (org-indent-to-column 2)))
9479
8bfe682a
CD
9480(defun org-agenda-insert-diary-make-new-entry (text)
9481 "Make new entry as last child of current entry.
9482Add TEXT as headline, and position the cursor in the second line so that
9483a timestamp can be added there."
9484 (let ((org-show-following-heading t)
9485 (org-show-siblings t)
9486 (org-show-hierarchy-above t)
9487 (org-show-entry-below t)
9488 col)
9489 (outline-next-heading)
9490 (org-back-over-empty-lines)
9491 (or (looking-at "[ \t]*$")
9492 (progn (insert "\n") (backward-char 1)))
ed21c5c8 9493 (org-insert-heading nil t)
8bfe682a
CD
9494 (org-do-demote)
9495 (setq col (current-column))
9496 (insert text "\n")
9497 (if org-adapt-indentation (org-indent-to-column col))
9498 (let ((org-show-following-heading t)
9499 (org-show-siblings t)
9500 (org-show-hierarchy-above t)
9501 (org-show-entry-below t))
9502 (org-show-context))))
9503
20908596
CD
9504(defun org-agenda-diary-entry ()
9505 "Make a diary entry, like the `i' command from the calendar.
8bfe682a
CD
9506All the standard commands work: block, weekly etc.
9507When `org-agenda-diary-file' points to a file,
9508`org-agenda-diary-entry-in-org-file' is called instead to create
9509entries in that Org-mode file."
20908596 9510 (interactive)
8bfe682a
CD
9511 (if (not (eq org-agenda-diary-file 'diary-file))
9512 (org-agenda-diary-entry-in-org-file)
9513 (require 'diary-lib)
9514 (let* ((char (progn
9515 (message "Diary entry: [d]ay [w]eekly [m]onthly [y]early [a]nniversary [b]lock [c]yclic")
9516 (read-char-exclusive)))
9517 (cmd (cdr (assoc char
9518 '((?d . insert-diary-entry)
9519 (?w . insert-weekly-diary-entry)
9520 (?m . insert-monthly-diary-entry)
9521 (?y . insert-yearly-diary-entry)
9522 (?a . insert-anniversary-diary-entry)
9523 (?b . insert-block-diary-entry)
9524 (?c . insert-cyclic-diary-entry)))))
9525 (oldf (symbol-function 'calendar-cursor-to-date))
9526 ;; (buf (get-file-buffer (substitute-in-file-name diary-file)))
9527 (point (point))
9528 (mark (or (mark t) (point))))
9529 (unless cmd
271672fa 9530 (user-error "No command associated with <%c>" char))
8bfe682a
CD
9531 (unless (and (get-text-property point 'day)
9532 (or (not (equal ?b char))
9533 (get-text-property mark 'day)))
271672fa 9534 (user-error "Don't know which date to use for diary entry"))
8bfe682a
CD
9535 ;; We implement this by hacking the `calendar-cursor-to-date' function
9536 ;; and the `calendar-mark-ring' variable. Saves a lot of code.
9537 (let ((calendar-mark-ring
9538 (list (calendar-gregorian-from-absolute
9539 (or (get-text-property mark 'day)
9540 (get-text-property point 'day))))))
9541 (unwind-protect
9542 (progn
9543 (fset 'calendar-cursor-to-date
9544 (lambda (&optional error dummy)
9545 (calendar-gregorian-from-absolute
9546 (get-text-property point 'day))))
20908596 9547 (call-interactively cmd))
8bfe682a 9548 (fset 'calendar-cursor-to-date oldf))))))
20908596 9549
20908596 9550(defun org-agenda-execute-calendar-command (cmd)
8223b1d2 9551 "Execute a calendar command from the agenda with date from cursor."
20908596
CD
9552 (org-agenda-check-type t 'agenda 'timeline)
9553 (require 'diary-lib)
8223b1d2 9554 (unless (get-text-property (min (1- (point-max)) (point)) 'day)
271672fa 9555 (user-error "Don't know which date to use for the calendar command"))
20908596
CD
9556 (let* ((oldf (symbol-function 'calendar-cursor-to-date))
9557 (point (point))
9558 (date (calendar-gregorian-from-absolute
9559 (get-text-property point 'day)))
9560 ;; the following 2 vars are needed in the calendar
9561 (displayed-month (car date))
9562 (displayed-year (nth 2 date)))
8223b1d2
BG
9563 (unwind-protect
9564 (progn
9565 (fset 'calendar-cursor-to-date
9566 (lambda (&optional error dummy)
9567 (calendar-gregorian-from-absolute
9568 (get-text-property point 'day))))
9569 (call-interactively cmd))
9570 (fset 'calendar-cursor-to-date oldf))))
20908596
CD
9571
9572(defun org-agenda-phases-of-moon ()
9573 "Display the phases of the moon for the 3 months around the cursor date."
9574 (interactive)
9575 (org-agenda-execute-calendar-command 'calendar-phases-of-moon))
9576
9577(defun org-agenda-holidays ()
9578 "Display the holidays for the 3 months around the cursor date."
9579 (interactive)
9580 (org-agenda-execute-calendar-command 'list-calendar-holidays))
9581
8223b1d2
BG
9582(defvar calendar-longitude) ; defined in calendar.el
9583(defvar calendar-latitude) ; defined in calendar.el
9584(defvar calendar-location-name) ; defined in calendar.el
20908596
CD
9585
9586(defun org-agenda-sunrise-sunset (arg)
9587 "Display sunrise and sunset for the cursor date.
9588Latitude and longitude can be specified with the variables
9589`calendar-latitude' and `calendar-longitude'. When called with prefix
9590argument, latitude and longitude will be prompted for."
9591 (interactive "P")
9592 (require 'solar)
9593 (let ((calendar-longitude (if arg nil calendar-longitude))
9594 (calendar-latitude (if arg nil calendar-latitude))
9595 (calendar-location-name
9596 (if arg "the given coordinates" calendar-location-name)))
9597 (org-agenda-execute-calendar-command 'calendar-sunrise-sunset)))
9598
9599(defun org-agenda-goto-calendar ()
9600 "Open the Emacs calendar with the date at the cursor."
9601 (interactive)
9602 (org-agenda-check-type t 'agenda 'timeline)
8223b1d2 9603 (let* ((day (or (get-text-property (min (1- (point-max)) (point)) 'day)
271672fa 9604 (user-error "Don't know which date to open in calendar")))
20908596
CD
9605 (date (calendar-gregorian-from-absolute day))
9606 (calendar-move-hook nil)
9607 (calendar-view-holidays-initially-flag nil)
3820f429 9608 (calendar-view-diary-initially-flag nil))
20908596
CD
9609 (calendar)
9610 (calendar-goto-date date)))
9611
9612;;;###autoload
9613(defun org-calendar-goto-agenda ()
9614 "Compute the Org-mode agenda for the calendar date displayed at the cursor.
9615This is a command that has to be installed in `calendar-mode-map'."
9616 (interactive)
9617 (org-agenda-list nil (calendar-absolute-from-gregorian
9618 (calendar-cursor-to-date))
9619 nil))
9620
9621(defun org-agenda-convert-date ()
9622 (interactive)
9623 (org-agenda-check-type t 'agenda 'timeline)
8223b1d2 9624 (let ((day (get-text-property (min (1- (point-max)) (point)) 'day))
20908596
CD
9625 date s)
9626 (unless day
271672fa 9627 (user-error "Don't know which date to convert"))
20908596
CD
9628 (setq date (calendar-gregorian-from-absolute day))
9629 (setq s (concat
9630 "Gregorian: " (calendar-date-string date) "\n"
9631 "ISO: " (calendar-iso-date-string date) "\n"
9632 "Day of Yr: " (calendar-day-of-year-string date) "\n"
9633 "Julian: " (calendar-julian-date-string date) "\n"
9634 "Astron. JD: " (calendar-astro-date-string date)
9635 " (Julian date number at noon UTC)\n"
9636 "Hebrew: " (calendar-hebrew-date-string date) " (until sunset)\n"
9637 "Islamic: " (calendar-islamic-date-string date) " (until sunset)\n"
9638 "French: " (calendar-french-date-string date) "\n"
9639 "Baha'i: " (calendar-bahai-date-string date) " (until sunset)\n"
9640 "Mayan: " (calendar-mayan-date-string date) "\n"
9641 "Coptic: " (calendar-coptic-date-string date) "\n"
9642 "Ethiopic: " (calendar-ethiopic-date-string date) "\n"
9643 "Persian: " (calendar-persian-date-string date) "\n"
9644 "Chinese: " (calendar-chinese-date-string date) "\n"))
9645 (with-output-to-temp-buffer "*Dates*"
9646 (princ s))
93b62de8 9647 (org-fit-window-to-buffer (get-buffer-window "*Dates*"))))
20908596 9648
c8d0cf5c
CD
9649;;; Bulk commands
9650
54a0dee5
CD
9651(defun org-agenda-bulk-marked-p ()
9652 (eq (get-char-property (point-at-bol) 'type)
9653 'org-marked-entry-overlay))
9654
acedf35c 9655(defun org-agenda-bulk-mark (&optional arg)
c8d0cf5c 9656 "Mark the entry at point for future bulk action."
acedf35c 9657 (interactive "p")
2f885dca 9658 (dotimes (i (or arg 1))
acedf35c
CD
9659 (unless (org-get-at-bol 'org-agenda-diary-link)
9660 (let* ((m (org-get-at-bol 'org-hd-marker))
9661 ov)
9662 (unless (org-agenda-bulk-marked-p)
271672fa 9663 (unless m (user-error "Nothing to mark at point"))
acedf35c
CD
9664 (push m org-agenda-bulk-marked-entries)
9665 (setq ov (make-overlay (point-at-bol) (+ 2 (point-at-bol))))
8223b1d2 9666 (org-overlay-display ov (concat org-agenda-bulk-mark-char " ")
acedf35c
CD
9667 (org-get-todo-face "TODO")
9668 'evaporate)
9669 (overlay-put ov 'type 'org-marked-entry-overlay))
271672fa
BG
9670 (end-of-line 1)
9671 (or (ignore-errors
9672 (goto-char (next-single-property-change (point) 'txt)))
9673 (beginning-of-line 2))
acedf35c
CD
9674 (while (and (get-char-property (point) 'invisible) (not (eobp)))
9675 (beginning-of-line 2))
9676 (message "%d entries marked for bulk action"
9677 (length org-agenda-bulk-marked-entries))))))
c8d0cf5c 9678
8223b1d2
BG
9679(defun org-agenda-bulk-mark-all ()
9680 "Mark all entries for future agenda bulk action."
9681 (interactive)
9682 (org-agenda-bulk-mark-regexp "."))
9683
3ab2c837 9684(defun org-agenda-bulk-mark-regexp (regexp)
8223b1d2 9685 "Mark entries matching REGEXP for future agenda bulk action."
3ab2c837 9686 (interactive "sMark entries matching regexp: ")
271672fa 9687 (let ((entries-marked 0) txt-at-point)
3ab2c837
BG
9688 (save-excursion
9689 (goto-char (point-min))
9690 (goto-char (next-single-property-change (point) 'txt))
271672fa
BG
9691 (while (and (re-search-forward regexp nil t)
9692 (setq txt-at-point (get-text-property (point) 'txt)))
9693 (when (string-match regexp txt-at-point)
8c8b834f 9694 (setq entries-marked (1+ entries-marked))
3ab2c837
BG
9695 (call-interactively 'org-agenda-bulk-mark))))
9696 (if (not entries-marked)
9697 (message "No entry matching this regexp."))))
9698
8223b1d2 9699(defun org-agenda-bulk-unmark (&optional arg)
c8d0cf5c 9700 "Unmark the entry at point for future bulk action."
8223b1d2
BG
9701 (interactive "P")
9702 (if arg
9703 (org-agenda-bulk-unmark-all)
9704 (cond ((org-agenda-bulk-marked-p)
9705 (org-agenda-bulk-remove-overlays
9706 (point-at-bol) (+ 2 (point-at-bol)))
9707 (setq org-agenda-bulk-marked-entries
9708 (delete (org-get-at-bol 'org-hd-marker)
9709 org-agenda-bulk-marked-entries))
271672fa
BG
9710 (end-of-line 1)
9711 (or (ignore-errors
9712 (goto-char (next-single-property-change (point) 'txt)))
9713 (beginning-of-line 2))
8223b1d2
BG
9714 (while (and (get-char-property (point) 'invisible) (not (eobp)))
9715 (beginning-of-line 2))
9716 (message "%d entries left marked for bulk action"
9717 (length org-agenda-bulk-marked-entries)))
9718 (t (message "No entry to unmark here")))))
c8d0cf5c 9719
271672fa
BG
9720(defun org-agenda-bulk-toggle-all ()
9721 "Toggle all marks for bulk action."
9722 (interactive)
9723 (save-excursion
9724 (goto-char (point-min))
9725 (while (ignore-errors
9726 (goto-char (next-single-property-change (point) 'txt)))
9727 (org-agenda-bulk-toggle))))
9728
54a0dee5 9729(defun org-agenda-bulk-toggle ()
271672fa 9730 "Toggle the mark at point for bulk action."
8223b1d2
BG
9731 (interactive)
9732 (if (org-agenda-bulk-marked-p)
9733 (org-agenda-bulk-unmark)
9734 (org-agenda-bulk-mark)))
c8d0cf5c
CD
9735
9736(defun org-agenda-bulk-remove-overlays (&optional beg end)
9737 "Remove the mark overlays between BEG and END in the agenda buffer.
9738BEG and END default to the buffer limits.
9739
9740This only removes the overlays, it does not remove the markers
9741from the list in `org-agenda-bulk-marked-entries'."
9742 (interactive)
9743 (mapc (lambda (ov)
86fbb8ca
CD
9744 (and (eq (overlay-get ov 'type) 'org-marked-entry-overlay)
9745 (delete-overlay ov)))
9746 (overlays-in (or beg (point-min)) (or end (point-max)))))
c8d0cf5c 9747
8223b1d2 9748(defun org-agenda-bulk-unmark-all ()
c8d0cf5c 9749 "Remove all marks in the agenda buffer.
8223b1d2 9750This will remove the markers and the overlays."
c8d0cf5c 9751 (interactive)
8223b1d2
BG
9752 (if (null org-agenda-bulk-marked-entries)
9753 (message "No entry to unmark")
9754 (mapc (lambda (m) (move-marker m nil)) org-agenda-bulk-marked-entries)
9755 (setq org-agenda-bulk-marked-entries nil)
9756 (org-agenda-bulk-remove-overlays (point-min) (point-max))))
9757
9758(defcustom org-agenda-persistent-marks nil
9759 "Non-nil means marked items will stay marked after a bulk action.
9760You can toggle this interactively by typing `p' when prompted for a
9761bulk action."
9762 :group 'org-agenda
9763 :version "24.1"
9764 :type 'boolean)
c8d0cf5c 9765
ed21c5c8
CD
9766(defun org-agenda-bulk-action (&optional arg)
9767 "Execute an remote-editing action on all marked entries.
9768The prefix arg is passed through to the command if possible."
9769 (interactive "P")
3ab2c837 9770 ;; Make sure we have markers, and only valid ones
271672fa 9771 (unless org-agenda-bulk-marked-entries (user-error "No entries are marked"))
3ab2c837
BG
9772 (mapc
9773 (lambda (m)
9774 (unless (and (markerp m)
9775 (marker-buffer m)
9776 (buffer-live-p (marker-buffer m))
9777 (marker-position m))
271672fa 9778 (user-error "Marker %s for bulk command is invalid" m)))
3ab2c837
BG
9779 org-agenda-bulk-marked-entries)
9780
9781 ;; Prompt for the bulk command
8223b1d2
BG
9782 (let* ((msg (if org-agenda-persistent-marks "Bulk (persistent): " "Bulk: ")))
9783 (message (concat msg "[$]arch [A]rch->sib [t]odo [+/-]tag [s]chd [d]eadline [r]efile "
9784 "[S]catter [f]unction "
9785 (when org-agenda-bulk-custom-functions
9786 (concat " Custom: ["
9787 (mapconcat (lambda(f) (char-to-string (car f)))
9788 org-agenda-bulk-custom-functions "")
9789 "]"))))
9790 (catch 'exit
9791 (let* ((action (read-char-exclusive))
9792 (org-log-refile (if org-log-refile 'time nil))
9793 (entries (reverse org-agenda-bulk-marked-entries))
9794 (org-overriding-default-time
9795 (if (get-text-property (point) 'org-agenda-date-header)
9796 (org-get-cursor-date)))
9797 redo-at-end
9798 cmd rfloc state e tag pos (cnt 0) (cntskip 0))
9799 (cond
9800 ((equal action ?p)
9801 (let ((org-agenda-persistent-marks
9802 (not org-agenda-persistent-marks)))
9803 (org-agenda-bulk-action)
9804 (throw 'exit nil)))
9805
9806 ((equal action ?$)
9807 (setq cmd '(org-agenda-archive)))
9808
9809 ((equal action ?A)
9810 (setq cmd '(org-agenda-archive-to-archive-sibling)))
9811
9812 ((member action '(?r ?w))
9813 (setq rfloc (org-refile-get-location
9814 "Refile to"
9815 (marker-buffer (car entries))
9816 org-refile-allow-creating-parent-nodes))
9817 (if (nth 3 rfloc)
9818 (setcar (nthcdr 3 rfloc)
9819 (move-marker (make-marker) (nth 3 rfloc)
9820 (or (get-file-buffer (nth 1 rfloc))
9821 (find-buffer-visiting (nth 1 rfloc))
9822 (error "This should not happen")))))
9823
9824 (setq cmd (list 'org-agenda-refile nil (list 'quote rfloc) t)
9825 redo-at-end t))
9826
9827 ((equal action ?t)
9828 (setq state (org-icompleting-read
9829 "Todo state: "
9830 (with-current-buffer (marker-buffer (car entries))
9831 (mapcar 'list org-todo-keywords-1))))
9832 (setq cmd `(let ((org-inhibit-blocking t)
9833 (org-inhibit-logging 'note))
9834 (org-agenda-todo ,state))))
9835
9836 ((memq action '(?- ?+))
9837 (setq tag (org-icompleting-read
9838 (format "Tag to %s: " (if (eq action ?+) "add" "remove"))
9839 (with-current-buffer (marker-buffer (car entries))
9840 (delq nil
9841 (mapcar (lambda (x)
9842 (if (stringp (car x)) x)) org-tag-alist)))))
9843 (setq cmd `(org-agenda-set-tags ,tag ,(if (eq action ?+) ''on ''off))))
9844
9845 ((memq action '(?s ?d))
9846 (let* ((time
9847 (unless arg
9848 (org-read-date
9849 nil nil nil
9850 (if (eq action ?s) "(Re)Schedule to" "(Re)Set Deadline to")
9851 org-overriding-default-time)))
9852 (c1 (if (eq action ?s) 'org-agenda-schedule 'org-agenda-deadline)))
9853 (setq cmd `(eval '(,c1 arg ,time)))))
9854
9855 ((equal action ?S)
9856 (if (not (org-agenda-check-type nil 'agenda 'timeline 'todo))
271672fa 9857 (user-error "Can't scatter tasks in \"%s\" agenda view" org-agenda-type)
8223b1d2
BG
9858 (let ((days (read-number
9859 (format "Scatter tasks across how many %sdays: "
9860 (if arg "week" "")) 7)))
9861 (setq cmd
9862 `(let ((distance (1+ (random ,days))))
9863 (if arg
9864 (let ((dist distance)
9865 (day-of-week
9866 (calendar-day-of-week
9867 (calendar-gregorian-from-absolute (org-today)))))
9868 (dotimes (i (1+ dist))
9869 (while (member day-of-week org-agenda-weekend-days)
9870 (incf distance)
9871 (incf day-of-week)
9872 (if (= day-of-week 7)
9873 (setq day-of-week 0)))
9874 (incf day-of-week)
9875 (if (= day-of-week 7)
9876 (setq day-of-week 0)))))
9877 ;; silently fail when try to replan a sexp entry
9878 (condition-case nil
9879 (let* ((date (calendar-gregorian-from-absolute
9880 (+ (org-today) distance)))
9881 (time (encode-time 0 0 0 (nth 1 date) (nth 0 date)
9882 (nth 2 date))))
9883 (org-agenda-schedule nil time))
9884 (error nil)))))))
9885
9886 ((assoc action org-agenda-bulk-custom-functions)
9887 (setq cmd (list (cadr (assoc action org-agenda-bulk-custom-functions)))
9888 redo-at-end t))
9889
9890 ((equal action ?f)
9891 (setq cmd (list (intern
9892 (org-icompleting-read "Function: "
9893 obarray 'fboundp t nil nil)))))
9894
271672fa 9895 (t (user-error "Invalid bulk action")))
8223b1d2
BG
9896
9897 ;; Sort the markers, to make sure that parents are handled before children
9898 (setq entries (sort entries
9899 (lambda (a b)
9900 (cond
9901 ((equal (marker-buffer a) (marker-buffer b))
9902 (< (marker-position a) (marker-position b)))
9903 (t
9904 (string< (buffer-name (marker-buffer a))
9905 (buffer-name (marker-buffer b))))))))
9906
9907 ;; Now loop over all markers and apply cmd
9908 (while (setq e (pop entries))
9909 (setq pos (text-property-any (point-min) (point-max) 'org-hd-marker e))
9910 (if (not pos)
9911 (progn (message "Skipping removed entry at %s" e)
9912 (setq cntskip (1+ cntskip)))
9913 (goto-char pos)
9914 (let (org-loop-over-headlines-in-active-region)
9915 (eval cmd))
9916 (setq cnt (1+ cnt))))
9917 (when redo-at-end (org-agenda-redo))
9918 (unless org-agenda-persistent-marks
9919 (org-agenda-bulk-unmark-all))
9920 (message "Acted on %d entries%s%s"
9921 cnt
9922 (if (= cntskip 0)
9923 ""
9924 (format ", skipped %d (disappeared before their turn)"
9925 cntskip))
9926 (if (not org-agenda-persistent-marks)
9927 "" " (kept marked)"))))))
9928
271672fa
BG
9929(defun org-agenda-capture (&optional with-time)
9930 "Call `org-capture' with the date at point.
9931With a `C-1' prefix, use the HH:MM value at point (if any) or the
9932current HH:MM time."
9933 (interactive "P")
8223b1d2 9934 (if (not (eq major-mode 'org-agenda-mode))
271672fa 9935 (user-error "You cannot do this outside of agenda buffers")
8223b1d2 9936 (let ((org-overriding-default-time
271672fa 9937 (org-get-cursor-date (equal with-time 1))))
8223b1d2 9938 (call-interactively 'org-capture))))
8d642074 9939
271672fa
BG
9940;;; Dragging agenda lines forward/backward
9941
30cb51f1
BG
9942(defun org-agenda-reapply-filters ()
9943 "Re-apply all agenda filters."
9944 (mapcar
9945 (lambda(f) (when (car f) (org-agenda-filter-apply (car f) (cadr f))))
9946 `((,org-agenda-tag-filter tag)
9947 (,org-agenda-category-filter category)
9948 (,org-agenda-regexp-filter regexp)
9949 (,(get 'org-agenda-tag-filter :preset-filter) tag)
9950 (,(get 'org-agenda-category-filter :preset-filter) category)
9951 (,(get 'org-agenda-regexp-filter :preset-filter) regexp))))
9952
9953(defun org-agenda-drag-line-forward (arg &optional backward)
9954 "Drag an agenda line forward by ARG lines.
9955When the optional argument `backward' is non-nil, move backward."
271672fa 9956 (interactive "p")
30cb51f1 9957 (let ((inhibit-read-only t) lst line)
271672fa
BG
9958 (if (or (not (get-text-property (point) 'txt))
9959 (save-excursion
9960 (dotimes (n arg)
30cb51f1 9961 (move-beginning-of-line (if backward 0 2))
271672fa
BG
9962 (push (not (get-text-property (point) 'txt)) lst))
9963 (delq nil lst)))
9964 (message "Cannot move line forward")
30cb51f1
BG
9965 (let ((end (save-excursion (move-beginning-of-line 2) (point))))
9966 (move-beginning-of-line 1)
9967 (setq line (buffer-substring (point) end))
9968 (delete-region (point) end)
9969 (move-beginning-of-line (funcall (if backward '1- '1+) arg))
9970 (insert line)
9971 (org-agenda-reapply-filters)
9972 (org-agenda-mark-clocking-task)
9973 (move-beginning-of-line 0)))))
271672fa
BG
9974
9975(defun org-agenda-drag-line-backward (arg)
9976 "Drag an agenda line backward by ARG lines."
9977 (interactive "p")
30cb51f1 9978 (org-agenda-drag-line-forward arg t))
271672fa 9979
8d642074
CD
9980;;; Flagging notes
9981
9982(defun org-agenda-show-the-flagging-note ()
9983 "Display the flagging note in the other window.
9984When called a second time in direct sequence, offer to remove the FLAGGING
9985tag and (if present) the flagging note."
9986 (interactive)
9987 (let ((hdmarker (org-get-at-bol 'org-hd-marker))
9988 (win (selected-window))
9989 note heading newhead)
9990 (unless hdmarker
271672fa 9991 (user-error "No linked entry at point"))
8d642074
CD
9992 (if (and (eq this-command last-command)
9993 (y-or-n-p "Unflag and remove any flagging note? "))
9994 (progn
9995 (org-agenda-remove-flag hdmarker)
9996 (let ((win (get-buffer-window "*Flagging Note*")))
9997 (and win (delete-window win)))
27e428e7 9998 (message "Entry unflagged"))
8d642074
CD
9999 (setq note (org-entry-get hdmarker "THEFLAGGINGNOTE"))
10000 (unless note
271672fa 10001 (user-error "No flagging note"))
8d642074
CD
10002 (org-kill-new note)
10003 (org-switch-to-buffer-other-window "*Flagging Note*")
10004 (erase-buffer)
10005 (insert note)
10006 (goto-char (point-min))
10007 (while (re-search-forward "\\\\n" nil t)
10008 (replace-match "\n" t t))
10009 (goto-char (point-min))
10010 (select-window win)
10011 (message "Flagging note pushed to kill ring. Press [?] again to remove tag and note"))))
10012
10013(defun org-agenda-remove-flag (marker)
8bfe682a 10014 "Remove the FLAGGED tag and any flagging note in the entry."
8d642074
CD
10015 (let (newhead)
10016 (org-with-point-at marker
10017 (org-toggle-tag "FLAGGED" 'off)
10018 (org-entry-delete nil "THEFLAGGINGNOTE")
10019 (setq newhead (org-get-heading)))
10020 (org-agenda-change-all-lines newhead marker)
27e428e7 10021 (message "Entry unflagged")))
8d642074
CD
10022
10023(defun org-agenda-get-any-marker (&optional pos)
10024 (or (get-text-property (or pos (point-at-bol)) 'org-hd-marker)
10025 (get-text-property (or pos (point-at-bol)) 'org-marker)))
c8d0cf5c 10026
20908596
CD
10027;;; Appointment reminders
10028
8223b1d2 10029(defvar appt-time-msg-list) ; defined in appt.el
20908596
CD
10030
10031;;;###autoload
e66ba1df 10032(defun org-agenda-to-appt (&optional refresh filter &rest args)
20908596
CD
10033 "Activate appointments found in `org-agenda-files'.
10034With a \\[universal-argument] prefix, refresh the list of
33306645 10035appointments.
20908596
CD
10036
10037If FILTER is t, interactively prompt the user for a regular
10038expression, and filter out entries that don't match it.
10039
10040If FILTER is a string, use this string as a regular expression
10041for filtering entries out.
10042
e66ba1df
BG
10043If FILTER is a function, filter out entries against which
10044calling the function returns nil. This function takes one
10045argument: an entry from `org-agenda-get-day-entries'.
10046
20908596
CD
10047FILTER can also be an alist with the car of each cell being
10048either 'headline or 'category. For example:
10049
10050 '((headline \"IMPORTANT\")
10051 (category \"Work\"))
10052
10053will only add headlines containing IMPORTANT or headlines
e66ba1df
BG
10054belonging to the \"Work\" category.
10055
10056ARGS are symbols indicating what kind of entries to consider.
271672fa
BG
10057By default `org-agenda-to-appt' will use :deadline*, :scheduled*
10058\(i.e., deadlines and scheduled items with a hh:mm specification)
e66ba1df 10059and :timestamp entries. See the docstring of `org-diary' for
8223b1d2
BG
10060details and examples.
10061
8a28a5b8 10062If an entry has a APPT_WARNTIME property, its value will be used
8223b1d2 10063to override `appt-message-warning-time'."
20908596 10064 (interactive "P")
20908596
CD
10065 (if refresh (setq appt-time-msg-list nil))
10066 (if (eq filter t)
10067 (setq filter (read-from-minibuffer "Regexp filter: ")))
10068 (let* ((cnt 0) ; count added events
271672fa 10069 (scope (or args '(:deadline* :scheduled* :timestamp)))
20908596
CD
10070 (org-agenda-new-buffers nil)
10071 (org-deadline-warning-days 0)
acedf35c
CD
10072 ;; Do not use `org-today' here because appt only takes
10073 ;; time and without date as argument, so it may pass wrong
10074 ;; information otherwise
20908596
CD
10075 (today (org-date-to-gregorian
10076 (time-to-days (current-time))))
c8d0cf5c 10077 (org-agenda-restrict nil)
8223b1d2
BG
10078 (files (org-agenda-files 'unrestricted)) entries file
10079 (org-agenda-buffer nil))
20908596 10080 ;; Get all entries which may contain an appt
8223b1d2 10081 (org-agenda-prepare-buffers files)
20908596
CD
10082 (while (setq file (pop files))
10083 (setq entries
e66ba1df
BG
10084 (delq nil
10085 (append entries
10086 (apply 'org-agenda-get-day-entries
10087 file today scope)))))
20908596
CD
10088 ;; Map thru entries and find if we should filter them out
10089 (mapc
10090 (lambda(x)
271672fa
BG
10091 (let* ((evt (org-trim
10092 (replace-regexp-in-string
10093 org-bracket-link-regexp "\\3"
10094 (or (get-text-property 1 'txt x) ""))))
20908596
CD
10095 (cat (get-text-property 1 'org-category x))
10096 (tod (get-text-property 1 'time-of-day x))
10097 (ok (or (null filter)
10098 (and (stringp filter) (string-match filter evt))
e66ba1df 10099 (and (functionp filter) (funcall filter x))
20908596 10100 (and (listp filter)
e66ba1df
BG
10101 (let ((cat-filter (cadr (assoc 'category filter)))
10102 (evt-filter (cadr (assoc 'headline filter))))
10103 (or (and (stringp cat-filter)
10104 (string-match cat-filter cat))
10105 (and (stringp evt-filter)
8223b1d2
BG
10106 (string-match evt-filter evt)))))))
10107 (wrn (get-text-property 1 'warntime x)))
20908596
CD
10108 ;; FIXME: Shall we remove text-properties for the appt text?
10109 ;; (setq evt (set-text-properties 0 (length evt) nil evt))
10110 (when (and ok tod)
621f83e4 10111 (setq tod (concat "00" (number-to-string tod))
20908596 10112 tod (when (string-match
621f83e4 10113 "\\([0-9]\\{1,2\\}\\)\\([0-9]\\{2\\}\\)\\'" tod)
20908596
CD
10114 (concat (match-string 1 tod) ":"
10115 (match-string 2 tod))))
8223b1d2
BG
10116 (if (version< emacs-version "23.3")
10117 (appt-add tod evt)
10118 (appt-add tod evt wrn))
20908596
CD
10119 (setq cnt (1+ cnt))))) entries)
10120 (org-release-buffers org-agenda-new-buffers)
10121 (if (eq cnt 0)
10122 (message "No event to add")
10123 (message "Added %d event%s for today" cnt (if (> cnt 1) "s" "")))))
10124
621f83e4
CD
10125(defun org-agenda-todayp (date)
10126 "Does DATE mean today, when considering `org-extend-today-until'?"
acedf35c
CD
10127 (let ((today (org-today))
10128 (date (if (and date (listp date)) (calendar-absolute-from-gregorian date)
10129 date)))
10130 (eq date today)))
621f83e4 10131
e66ba1df 10132(defun org-agenda-todo-yesterday (&optional arg)
8223b1d2 10133 "Like `org-agenda-todo' but the time of change will be 23:59 of yesterday."
e66ba1df
BG
10134 (interactive "P")
10135 (let* ((hour (third (decode-time
10136 (org-current-time))))
10137 (org-extend-today-until (1+ hour)))
10138 (org-agenda-todo arg)))
5b409b39 10139
e66ba1df 10140(provide 'org-agenda)
b349f79f 10141
20908596 10142;;; org-agenda.el ends here