Commit | Line | Data |
---|---|---|
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. | |
110 | When t, a confirmation is always needed. When a number N, confirmation is | |
111 | only 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 |
120 | This is done globally by leaving out lines like the agenda span |
121 | name 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. | |
127 | If this is a string, it will be used as the separator, with a newline added. | |
3ab2c837 BG |
128 | If it is a character, it will be repeated to fill the window width. |
129 | If nil the separator is disabled. In `org-agenda-custom-commands' this | |
130 | addresses 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 |
149 | This is a good place to set options for ps-print and for htmlize. |
150 | Note that the way this is implemented, the values will be evaluated | |
151 | before 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. |
164 | A 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. | |
171 | This 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 |
173 | When this is 0, nothing will happen. When it is greater than 0, it |
174 | specifies the maximum number of lines that will be added for each entry | |
54a0dee5 CD |
175 | that is listed in the agenda view. |
176 | ||
177 | Note that this variable is not used during display, only when exporting | |
86fbb8ca CD |
178 | the agenda. For agenda display, see the variables `org-agenda-entry-text-mode' |
179 | and `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 |
185 | This variable applies to the text added to the agenda when |
186 | `org-agenda-add-entry-text-maxlines' is larger than 0. | |
e66ba1df | 187 | When 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. |
193 | If this variable contains a string, it will replace the default <style> | |
194 | section as produced by `htmlize'. | |
195 | Since there are different ways of setting style information, this variable | |
196 | needs to contain the full HTML structure to provide a style, including the | |
197 | surrounding HTML tags. The style specifications should include definitions | |
198 | the 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 | ||
222 | or, if you want to keep the style in a file, | |
223 | ||
224 | <link rel=\"stylesheet\" type=\"text/css\" href=\"mystyles.css\"> | |
225 | ||
226 | As the value of this option simply gets inserted into the HTML <head> header, | |
8223b1d2 | 227 | you 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. | |
269 | This variable is a list of symbols that controls the types of | |
270 | items that appear in the daily/weekly agenda. Allowed symbols in this | |
271 | list 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 | ||
296 | By default, all four non-starred types are turned on. | |
297 | ||
298 | When :scheduled* or :deadline* are included, :schedule or :deadline | |
299 | will be ignored. | |
300 | ||
301 | Never set this variable globally using `setq', because then it | |
302 | will apply to all future agenda commands. Instead, bind it with | |
303 | `let' to scope it dynamically into the agenda-constructing | |
304 | command. A good way to set it is through options in | |
305 | `org-agenda-custom-commands'. For a more flexible (though | |
306 | somewhat less efficient) way of determining what is included in | |
307 | the 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. |
427 | This 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. |
434 | These commands will be offered on the splash screen displayed by the | |
435 | agenda dispatcher \\[org-agenda]. Each entry is a list like this: | |
436 | ||
437 | (key desc type match settings files) | |
438 | ||
439 | key The key (one or more characters as a string) to be associated | |
440 | with the command. | |
e66ba1df | 441 | desc A description of the command, when omitted or nil, a default |
20908596 CD |
442 | description is built using MATCH. |
443 | type 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. | |
453 | match 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. | |
459 | settings 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. | |
462 | files 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 | |
468 | You can also define a set of commands, to create a composite agenda buffer. | |
469 | In this case, an entry looks like this: | |
470 | ||
471 | (key desc (cmd1 cmd2 ...) general-settings-for-whole-set files) | |
472 | ||
473 | where | |
474 | ||
475 | desc A description string to be displayed in the dispatcher menu. | |
476 | cmd 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 | ||
487 | Each command can carry a list of options, and another set of options can be | |
488 | given for the whole set of commands. Individual command options take | |
489 | precedence over the general options. | |
490 | ||
491 | When using several characters as key to a command, the first characters | |
492 | are prefix commands. For the dispatcher to display useful information, you | |
493 | should 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 | 569 | The purpose of this is that if you construct a query string interactively, |
20908596 CD |
570 | you 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. | |
577 | This is a list of four items: | |
c8d0cf5c CD |
578 | 1. 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. |
581 | 2. 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. | |
585 | 3. 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 |
592 | 4. An arbitrary regular expression matching non-stuck projects. |
593 | ||
c8d0cf5c CD |
594 | If the project turns out to be not stuck, search continues also in the |
595 | subtree to see if any of the subtasks have project status. | |
596 | ||
597 | See also the variable `org-tags-match-list-sublevels' which applies | |
598 | to projects matched by this search as well. | |
599 | ||
20908596 CD |
600 | After defining this variable, you may use \\[org-agenda-list-stuck-projects] |
601 | or `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 | 611 | If you select an effort estimate limit without first pressing an operator, |
71d35b24 CD |
612 | this 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. | |
625 | If this function returns nil, the current match should not be skipped. | |
626 | If the function decided to skip an agenda match, is must return the | |
627 | buffer position from which the search should be continued. | |
628 | This may also be a Lisp form, which will be evaluated. | |
629 | ||
630 | This variable will be applied to every agenda match, including | |
631 | tags/property searches and TODO lists. So try to make the test function | |
632 | do its checking as efficiently as possible. To implement a skipping | |
633 | condition just for specific agenda commands, use the variable | |
634 | `org-agenda-skip-function' which can be set in the options section | |
635 | of 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 |
658 | If this is the symbol `trees', trees in the selected agenda scope |
659 | that are marked with the ARCHIVE tag will be included anyway. When this is | |
660 | t, also all archive files associated with the current selection of agenda | |
661 | files 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. | |
665 | Otherwise only highlight the headline. Highlighting the whole subtree is | |
666 | useful 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 | 672 | When 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 |
678 | When nil, the sublevels of a TODO entry are not checked, resulting in |
679 | potentially 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 |
686 | You can use this if you prefer to mark mere appointments with a TODO keyword, |
687 | but don't want them to show up in the TODO list. | |
688 | When this is set, it also covers deadlines and scheduled items, the settings | |
689 | of `org-agenda-todo-ignore-scheduled' and `org-agenda-todo-ignore-deadlines' | |
c8d0cf5c CD |
690 | will be ignored. |
691 | See 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. | |
698 | This applies when creating the global todo list. | |
699 | Valid values are: | |
700 | ||
701 | past Don't show entries for today or in the past. | |
702 | ||
703 | future 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 | ||
708 | all 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 |
712 | This variable can also have an integer as a value. If positive (N), |
713 | todos with a timestamp N or more days in the future will be ignored. If | |
3ab2c837 | 714 | negative (-N), todos with a timestamp N or more days in the past will be |
8223b1d2 BG |
715 | ignored. If 0, todos with a timestamp either today or in the future will |
716 | be ignored. For example, a value of -1 will exclude todos with a | |
3ab2c837 BG |
717 | timestamp in the past (yesterday or earlier), while a value of 7 will |
718 | exclude todos with a timestamp a week or more in the future. | |
719 | ||
acedf35c CD |
720 | See also `org-agenda-todo-ignore-with-date'. |
721 | See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want | |
722 | to 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. |
735 | This applies when creating the global todo list. | |
736 | Valid values are: | |
737 | ||
738 | past Don't show entries scheduled today or in the past. | |
739 | ||
740 | future 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 | ||
744 | all 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 | ||
748 | t Same as `all', for backward compatibility. | |
749 | ||
8223b1d2 | 750 | This variable can also have an integer as a value. See |
3ab2c837 BG |
751 | `org-agenda-todo-ignore-timestamp' for more details. |
752 | ||
c8d0cf5c | 753 | See also `org-agenda-todo-ignore-with-date'. |
ed21c5c8 CD |
754 | See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want |
755 | to 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 |
768 | There are different motivations for using different values, please think |
769 | carefully when configuring this variable. | |
770 | ||
86fbb8ca | 771 | This applies when creating the global todo list. |
ed21c5c8 CD |
772 | Valid values are: |
773 | ||
774 | near 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 | ||
778 | far 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 | ||
782 | past Don't show entries with a deadline timestamp for today or in the past. | |
783 | ||
784 | future Don't show entries with a deadline timestamp in the future, not even | |
785 | when they become `near' ones. Use it with caution. | |
786 | ||
787 | all Ignore all TODO entries that do have a deadline. | |
788 | ||
789 | t Same as `near', for backward compatibility. | |
790 | ||
8223b1d2 | 791 | This variable can also have an integer as a value. See |
3ab2c837 BG |
792 | `org-agenda-todo-ignore-timestamp' for more details. |
793 | ||
c8d0cf5c | 794 | See also `org-agenda-todo-ignore-with-date'. |
ed21c5c8 CD |
795 | See also the variable `org-agenda-tags-todo-honor-ignore-options' if you want |
796 | to 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 | ||
810 | See the docstring of various `org-agenda-todo-ignore-*' options. | |
811 | The default is to compare time stamps using days. An item is thus | |
812 | considered to be in the future if it is at least one day after today. | |
813 | Non-nil means to compare time stamps using seconds. An item is then | |
814 | considered 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 |
825 | The 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' |
830 | make the global TODO list skip entries that have time stamps of certain | |
831 | kinds. If this option is set, the same options will also apply for the | |
832 | tags-todo search, which is the general tags/property matcher | |
833 | restricted 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. | |
841 | This is relevant for the daily/weekly agenda, not for the TODO list. And | |
842 | it applies only to the actual date of the scheduling. Warnings about | |
843 | an item with a past scheduling dates are always turned off when the item | |
844 | is 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 | |
852 | In the agenda of today, an entry can show up multiple times | |
853 | because it is both scheduled and has a nearby deadline, and maybe | |
854 | a plain time stamp as well. | |
855 | ||
856 | When this variable is nil, the entry will be shown several times. | |
857 | ||
858 | When set to t, then only the deadline is shown and the fact that | |
859 | the entry is scheduled today or was scheduled previously is not | |
860 | shown. | |
861 | ||
862 | When set to the symbol `not-today', skip scheduled previously, | |
863 | but not scheduled today. | |
864 | ||
865 | When set to the symbol `repeated-after-deadline', skip scheduled | |
d1389828 | 866 | items 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. | |
877 | In the agenda of today, an entry can show up multiple times | |
878 | because it has both a plain timestamp and has a nearby deadline. | |
879 | When this variable is t, then only the deadline is shown and the | |
880 | fact that the entry has a timestamp for or including today is not | |
881 | shown. When this variable is nil, the entry will be shown | |
882 | several 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 |
892 | When nil, the deadline is still shown and should give you a happy feeling. |
893 | This is relevant for the daily/weekly agenda. And it applied only to the | |
33306645 | 894 | actually date of the deadline. Warnings about approaching and past-due |
20908596 CD |
895 | deadlines 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. | |
902 | This will apply on all days where a prewarning for the deadline would | |
903 | be shown, but not at the day when the entry is actually due. On that day, | |
904 | the deadline will be shown anyway. | |
271672fa BG |
905 | This variable may be set to nil, t, the symbol `pre-scheduled', |
906 | or a number which will then give the number of days before the actual | |
907 | deadline when the prewarnings should resume. The symbol `pre-scheduled' | |
908 | eliminates the deadline prewarning only prior to the scheduled date. | |
ed21c5c8 CD |
909 | This can be used in a workflow where the first showing of the deadline will |
910 | trigger you to schedule it, and then you don't want to be reminded of it | |
911 | because 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. | |
923 | This variable may be set to nil, t, the symbol `post-deadline', | |
924 | or a number which will then give the number of days after the actual | |
925 | scheduled date when the delay should expire. The symbol `post-deadline' | |
926 | eliminates 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. |
939 | When non-nil, after the search for timestamps has matched once in an | |
940 | entry, 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 |
952 | This causes some overhead during agenda construction, but if you |
953 | have turned on `org-enforce-todo-dependencies', | |
954 | `org-enforce-todo-checkbox-dependencies', or any other blocking | |
955 | mechanism, this will create useful feedback in the agenda. | |
956 | ||
8bfe682a | 957 | Instead of t, this variable can also have the value `invisible'. |
c8d0cf5c CD |
958 | Then blocked tasks will be invisible and only become visible when |
959 | they become unblocked. An exemption to this behavior is when a task is | |
960 | blocked because of unchecked checkboxes below it. Since checkboxes do | |
961 | not show up in the agenda views, making this task invisible you remove any | |
962 | trace from agenda views that there is something to do. Therefore, a task | |
963 | that is blocked because of checkboxes will never be made invisible, it | |
964 | will 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 |
975 | When nil, only the days which actually have entries are shown. |
976 | When t, all days between the first and the last date are shown. | |
977 | When an integer, show also empty dates, but if there is a gap of more than | |
978 | N 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 |
992 | When nil, the matcher string is not shown, but is put into the help-echo |
993 | property so than moving the mouse over the command shows it. | |
994 | Setting it to nil is good if matcher strings are very long and/or if | |
8223b1d2 | 995 | you 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. |
1004 | If you use this, you probably want to set `org-agenda-menu-show-matcher' | |
1005 | to 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. | |
1013 | The buffer is still writable when the hook is called. | |
1014 | ||
1015 | You can modify some of the buffer substrings but you should be | |
1016 | extra careful not to modify the text properties of the agenda | |
1017 | headlines 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 |
1023 | A longer mouse click will still set point. Does not work on XEmacs. |
1024 | Needs 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 | |
1035 | current 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 | |
1053 | Note that this variable only used during agenda display. Add add entry text | |
1054 | when 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. | |
1061 | The complete matches of all regular expressions in this list will be | |
1062 | removed 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. | |
1075 | This cleanup is done in a temporary buffer, so the function may inspect and | |
1076 | change the entire buffer. | |
1077 | Some default stuff like drawers and scheduling/deadline dates will already | |
1078 | have been removed when this is called, as will any matches for regular | |
1079 | expressions 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. |
1083 | Dynamically 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. | |
1092 | Possible values for this option are: | |
1093 | ||
1094 | current-window Show agenda in the current window, keeping all other windows. | |
20908596 CD |
1095 | other-window Use `switch-to-buffer-other-window' to display agenda. |
1096 | reorganize-frame Show only two windows on the current frame, the current | |
1097 | window and the agenda. | |
8d642074 CD |
1098 | other-frame Use `switch-to-buffer-other-frame' to display agenda. |
1099 | Also, when exiting the agenda, kill that frame. | |
20908596 CD |
1100 | See 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. | |
1110 | The value of the variable is a cons cell with two numbers between 0 and 1. | |
1111 | It 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 |
1117 | Before the window configuration is changed for displaying the agenda, |
1118 | the 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 | 1121 | option 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 | 1127 | Should be 1 or 7. |
acedf35c | 1128 | Obsolete, 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. | |
1137 | Can be day, week, month, year, or any number of days. | |
c8d0cf5c | 1138 | Custom 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 | 1149 | 0 denotes Sunday, 1 denotes Monday, etc. |
c8d0cf5c CD |
1150 | When nil, always start on the current day. |
1151 | Custom 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 |
1158 | When 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. | |
1164 | Used by the daily/weekly agenda and by the timeline. This should be | |
1165 | a format string understood by `format-time-string', or a function returning | |
1166 | the formatted date as a string. The function must take a single argument, | |
1167 | a 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 |
1175 | This 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. | |
1198 | For 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? | |
1234 | These days get the special face `org-agenda-date-weekend' in the agenda | |
1235 | and 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 |
1248 | When using S-right in the agenda to move a a date forward, and the date |
1249 | stamp currently points to the past, the first key press will move it | |
1250 | to today. WHen nil, just move one day forward even if the date stays | |
1251 | in 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. |
1258 | Custom 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. | |
1264 | Custom 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 |
1271 | When set to a list of strings, only show occurrences of repeating |
1272 | stamps for these TODO keywords. When nil, only one occurrence is | |
1273 | shown, 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 |
1283 | When an item is scheduled on a date, it shows up in the agenda on this |
1284 | day and will be listed until it is marked done for the number of days | |
1285 | given 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. | |
1291 | This 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. |
1296 | Note that instead of changing this variable, you can also press `C-u l' in | |
1297 | the 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 | ||
1331 | Furthermore, the following properties can be used to define faces for | |
1332 | issue 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 |
1347 | If a log item like a state change or a clock entry is associated with |
1348 | notes, the first line of these notes will be added to the entry in the | |
1349 | agenda 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. |
1355 | See `org-agenda-log-mode' and `org-agenda-log-mode-items' for further | |
1356 | explanations 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. | |
1375 | This is the display mode that shows a clock table in the daily/weekly | |
1376 | agenda, the properties for this dynamic block can be set here. | |
1377 | The usual clocktable parameters are allowed here, but you cannot set | |
1378 | the properties :name, :tstart, :tend, :block, and :scope - these will | |
1379 | be overwritten to make sure the content accurately reflects the | |
1380 | current 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 | ||
1387 | The search string for search view can either be interpreted as a phrase, | |
1388 | or as a list of snippets that define a boolean search for a number of | |
1389 | strings. | |
1390 | ||
1391 | When this is non-nil, the string will be split on whitespace, and each | |
1392 | snippet will be searched individually, and all must match in order to | |
1393 | select an entry. A snippet is then a single string of non-white | |
1394 | characters, or a string in double quotes, or a regexp in {} braces. | |
86fbb8ca | 1395 | If a snippet is preceded by \"-\", the snippet must *not* match. |
ed21c5c8 CD |
1396 | \"+\" is syntactic sugar for positive selection. Each snippet may |
1397 | be found as a full word or a partial word, but see the variable | |
1398 | `org-agenda-search-view-force-full-words'. | |
1399 | ||
1400 | When this is nil, search will look for the entire search phrase as one, | |
1401 | with each space character matching any amount of whitespace, including | |
1402 | line breaks. | |
1403 | ||
1404 | Even when this is nil, you can still switch to Boolean search dynamically | |
86fbb8ca | 1405 | by preceding the first snippet with \"+\" or \"-\". If the first snippet |
ed21c5c8 CD |
1406 | is a regexp marked with braces like \"{abc}\", this will also switch to |
1407 | boolean 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 | 1417 | When 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. |
1424 | E.g. when this is set to 1, the search view will only | |
73d3db82 BG |
1425 | show headlines of level 1. When set to 0, the default |
1426 | value, 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 |
1439 | If the headline contains a time-of-day in one format or another, it will |
1440 | be used to sort the entry into the time sequence of items for a day. | |
1441 | Some people have time stamps in the headline that refer to the creation | |
1442 | time or so, and then this produces an unwanted side effect. If this is | |
1443 | the case for your, use this variable to turn off searching the headline | |
1444 | for 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 |
1450 | A time grid is a set of lines for specific times (like every two hours between |
1451 | 8:00 and 20:00). The items scheduled for a day at specific times are | |
1452 | sorted in between these lines. | |
1453 | For details about when the grid will be shown, and what it will look like, see | |
1454 | the 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. | |
1464 | This is a list of three items. The first item is again a list. It contains | |
1465 | symbols 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 | 1472 | The second item is a string which will be placed behind the grid time. |
20908596 CD |
1473 | |
1474 | The third item is a list of integers, indicating the times that should have | |
1475 | a 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. | |
1514 | This is a list of symbols which will be used in sequence to determine | |
1515 | if an entry should be listed before another entry. The following | |
1516 | symbols are recognized: | |
1517 | ||
c8d0cf5c CD |
1518 | time-up Put entries with time-of-day indications first, early first |
1519 | time-down Put entries with time-of-day indications first, late first | |
271672fa BG |
1520 | timestamp-up Sort by any timestamp, early first |
1521 | timestamp-down Sort by any timestamp, late first | |
1522 | scheduled-up Sort by scheduled timestamp, early first | |
1523 | scheduled-down Sort by scheduled timestamp, late first | |
1524 | deadline-up Sort by deadline timestamp, early first | |
1525 | deadline-down Sort by deadline timestamp, late first | |
1526 | ts-up Sort by active timestamp, early first | |
1527 | ts-down Sort by active timestamp, late first | |
1528 | tsia-up Sort by inactive timestamp, early first | |
1529 | tsia-down Sort by inactive timestamp, late first | |
c8d0cf5c CD |
1530 | category-keep Keep the default order of categories, corresponding to the |
1531 | sequence in `org-agenda-files'. | |
1532 | category-up Sort alphabetically by category, A-Z. | |
1533 | category-down Sort alphabetically by category, Z-A. | |
1534 | tag-up Sort alphabetically by last tag, A-Z. | |
1535 | tag-down Sort alphabetically by last tag, Z-A. | |
1536 | priority-up Sort numerically by priority, high priority last. | |
1537 | priority-down Sort numerically by priority, high priority first. | |
1538 | todo-state-up Sort by todo state, tasks that are done last. | |
1539 | todo-state-down Sort by todo state, tasks that are done first. | |
1540 | effort-up Sort numerically by estimated effort, high effort last. | |
1541 | effort-down Sort numerically by estimated effort, high effort first. | |
1542 | user-defined-up Sort according to `org-agenda-cmp-user-defined', high last. | |
1543 | user-defined-down Sort according to `org-agenda-cmp-user-defined', high first. | |
8bfe682a CD |
1544 | habit-up Put entries that are habits first |
1545 | habit-down Put entries that are habits last | |
86fbb8ca CD |
1546 | alpha-up Sort headlines alphabetically |
1547 | alpha-down Sort headlines alphabetically, reversed | |
20908596 CD |
1548 | |
1549 | The different possibilities will be tried in sequence, and testing stops | |
1550 | if one comparison returns a \"not-equal\". For example, the default | |
1551 | '(time-up category-keep priority-down) | |
1552 | means: Pull out all entries having a specified time of day and sort them, | |
1553 | in order to make a time schedule for the current day the first thing in the | |
1554 | agenda listing for the day. Of the entries without a time indication, keep | |
1555 | the grouped in categories, don't sort the categories, but keep them in | |
1556 | the sequence given in `org-agenda-files'. Within each category sort by | |
1557 | priority. | |
1558 | ||
1559 | Leaving out `category-keep' would mean that items will be sorted across | |
1560 | categories by priority. | |
1561 | ||
1562 | Instead of a single list, this can also be a set of list for specific | |
1563 | contents, 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 | |
1566 | Custom 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'. | |
1582 | This function must receive two arguments, agenda entry a and b. | |
1583 | If a>b, return +1. If a<b, return -1. If they are equal as seen by | |
1584 | the user comparison, return nil. | |
1585 | When this is defined, you can make `user-defined-up' and `user-defined-down' | |
1586 | part 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 |
1592 | This is only relevant for sorting. When t, items which have no explicit |
1593 | time like 15:30 will be considered as 99:01, i.e. later than any items which | |
1594 | do have a time. When nil, the default time is before 0:00. You can use this | |
1595 | option to decide if the schedule for today should come before or after timeless | |
1596 | agenda 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 |
1602 | This also applies when filtering an agenda view with respect to the |
1603 | < or > effort operator. Then, tasks with no effort defined will be treated | |
1604 | as tasks with high effort. | |
20908596 CD |
1605 | When 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 |
1621 | An alist with five entries, each for the different agenda types. The |
1622 | keys of the sublists are `agenda', `timeline', `todo', `search' and `tags'. | |
3ab2c837 BG |
1623 | The values are format strings. |
1624 | ||
20908596 CD |
1625 | This 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 | |
1639 | All specifiers work basically like the standard `%s' of printf, but may | |
271672fa | 1640 | contain two additional characters: a question mark just after the `%' |
3ab2c837 | 1641 | and a whitespace/punctuation character just before the final letter. |
20908596 CD |
1642 | |
1643 | If the first character after `%' is a question mark, the entire field | |
fe3c5669 PE |
1644 | will only be included if the corresponding value applies to the current |
1645 | entry. This is useful for fields which should have fixed width when | |
1646 | present, but zero width when absent. For example, \"%?-12t\" will | |
1647 | result in a 12 character time field if a time of the day is specified, | |
3ab2c837 | 1648 | but will completely disappear in entries which do not contain a time. |
20908596 | 1649 | |
271672fa BG |
1650 | If there is punctuation or whitespace character just before the |
1651 | final format letter, this character will be appended to the field | |
1652 | value if the value is not empty. For example, the format | |
1653 | \"%-12:c\" leads to \"Diary: \" if the category is \"Diary\". If | |
1654 | the category is empty, no additional colon is inserted. | |
20908596 | 1655 | |
fe3c5669 | 1656 | The default value for the agenda sublist is \" %-12:c%?-12t% s\", |
3ab2c837 BG |
1657 | which 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 | |
1667 | See also the variables `org-agenda-remove-times-when-in-prefix' and | |
c8d0cf5c CD |
1668 | `org-agenda-remove-tags'. |
1669 | ||
1670 | Custom 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. |
1683 | This is a list where first element is a list of variable bindings, and second | |
1684 | element 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. | |
1689 | Set this to something like \"%-12s\" if you want all TODO keywords | |
1690 | to 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 | |
1696 | which should be treated as scheduling/deadline information in | |
1697 | `org-agenda'. | |
1698 | ||
1699 | For 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. | |
1706 | This is a list with two strings. The first applies when the range | |
1707 | is entirely on one day. The second applies if the range spans several days. | |
1708 | The strings may have two \"%d\" format specifiers which will be filled | |
1709 | with the sequence number of the days, and the total number of days in the | |
1710 | range, 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 |
1720 | This is a list with two strings. The first applies when the item is |
1721 | scheduled on the current day. The second applies when it has been scheduled | |
b349f79f CD |
1722 | previously, it may contain a %d indicating that this is the nth time that |
1723 | this item is scheduled, due to automatic rescheduling of unfinished items | |
1724 | for the following day. So this number is one larger than the number of days | |
1725 | that 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 |
1735 | These 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 |
1742 | This is a list with three strings. The first applies when the item has its |
1743 | deadline on the current day. The second applies when the deadline is in the | |
1744 | future, the third one when it is in the past. The strings may contain %d | |
1745 | to 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 |
1756 | When the format `org-agenda-prefix-format' contains a `%t' specifier, a |
1757 | time-of-day specification in a headline or diary entry is extracted and | |
1758 | placed 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 | |
1760 | 11:30-4pm) will be removed for agenda display. This makes the agenda less | |
1761 | cluttered. | |
1762 | The option can be t or nil. It may also be the symbol `beg', indicating | |
86fbb8ca | 1763 | that the time should only be removed when it is located at the beginning of |
20908596 CD |
1764 | the 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 | |
1773 | items 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. | |
1780 | When nil, no duration is specified in such cases. | |
1781 | When 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 | ||
1790 | When this option is set to 'always, it take precedences over | |
1791 | `org-agenda-use-tag-inheritance' and inherited tags are shown | |
1792 | in every agenda. | |
1793 | ||
1794 | When this option is set to t (the default), inherited tags are | |
1795 | shown when they are available, i.e. when the value of | |
1796 | `org-agenda-use-tag-inheritance' has been taken into account. | |
1797 | ||
1798 | This can be set to a list of agenda types in which the agenda | |
1799 | must display the inherited tags. Available types are 'todo, | |
1800 | 'agenda, 'search and 'timeline. | |
1801 | ||
1802 | When 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 | ||
1815 | In tags/tags-todo/tags-tree agenda views, tag inheritance is | |
1816 | controlled by `org-use-tag-inheritance'. In other agenda types, | |
a89c8ef0 BG |
1817 | `org-use-tag-inheritance' is not used for the selection of the |
1818 | agenda entries. Still, you may want the agenda to be aware of | |
1819 | the inherited tags anyway, e.g. for later tag filtering. | |
c7cf0ebc | 1820 | |
a89c8ef0 | 1821 | Allowed value are 'todo, 'search, 'timeline and 'agenda. |
c7cf0ebc | 1822 | |
a89c8ef0 BG |
1823 | This variable has no effect if `org-agenda-show-inherited-tags' |
1824 | is set to 'always. In that case, the agenda is aware of those | |
1825 | tags. | |
1826 | ||
1827 | The default value sets tags in every agenda type. Setting this | |
1828 | option 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. | |
1838 | This means that these tags will be present, but not be shown in the agenda | |
86fbb8ca | 1839 | line. Secondary filtering will still work on the hidden tags. |
afe98dfa | 1840 | Nil 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 |
1848 | When 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. |
1861 | If this number is positive, it specifies the column. If it is negative, | |
1862 | it 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 | 1871 | When t, the highest priority entries are bold, lowest priority italic. |
86fbb8ca | 1872 | However, settings in `org-priority-faces' will overrule these faces. |
c8d0cf5c CD |
1873 | When this variable is the symbol `cookies', only fontify the |
1874 | cookies, not the entire task. | |
621f83e4 CD |
1875 | This may also be an association list of priority faces, whose |
1876 | keys are the character values of `org-highest-priority', | |
1877 | `org-default-priority', and `org-lowest-priority' (the default values | |
ed21c5c8 CD |
1878 | are ?A, ?B, and ?C, respectively). The face may be a named face, a |
1879 | color as a string, or a list like `(:background \"Red\")'. | |
1880 | If it is a color, the variable `org-faces-easy-properties' | |
1881 | determines 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 | 1895 | The only argument passed to that function is the day. It should |
acedf35c CD |
1896 | returns a face, or nil if does not want to specify a face and let |
1897 | the 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 | ||
1905 | Each entry should have the following format: | |
1906 | ||
1907 | (CATEGORY-REGEXP FILE-OR-DATA TYPE DATA-P PROPS) | |
1908 | ||
1909 | Where CATEGORY-REGEXP is a regexp matching the categories where | |
1910 | the icon should be displayed. | |
1911 | FILE-OR-DATA either a file path or a string containing image data. | |
1912 | ||
27e428e7 | 1913 | The other fields can be omitted safely if not needed: |
acedf35c CD |
1914 | TYPE indicates the image type. |
1915 | DATA-P is a boolean indicating whether the FILE-OR-DATA string is | |
1916 | image data. | |
1917 | PROPS are additional image attributes to assign to the image, | |
1918 | like, e.g. `:ascent center'. | |
1919 | ||
1920 | (\"Org\" \"/path/to/icon.png\" nil nil :ascent center) | |
1921 | ||
1922 | If you want to set the display properties yourself, just put a | |
1923 | list as second element: | |
1924 | ||
1925 | (CATEGORY-REGEXP (MY PROPERTY LIST)) | |
1926 | ||
1927 | For example, to display a 16px horizontal space for Emacs | |
1928 | category, 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 |
1953 | When column view in the agenda is listing properties that have a summary |
1954 | operator, it can go to all relevant buffers and recompute the summaries | |
1955 | there. This can mean overhead for the agenda column view, but is necessary | |
1956 | to have thing up to date. | |
1957 | As a special case, a CLOCKSUM property also makes sure that the clock | |
1958 | computations 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 |
1964 | The property to which appointment durations will be added is the one given |
1965 | in the option `org-effort-property'. If an appointment does not have | |
1966 | an end time, `org-agenda-default-appointment-duration' will be used. If that | |
1967 | is not set, an appointment without end time will not contribute to the time | |
1968 | estimate." | |
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'. | |
1974 | The sole argument to the function, which is called once for each | |
1975 | possible tag, is a string giving the name of the tag. The | |
1976 | function should return either nil if the tag should be included | |
ed21c5c8 CD |
1977 | as normal, or \"-<TAG>\" to exclude the tag. |
1978 | Note that for the purpose of tag filtering, only the lower-case version of | |
1979 | all tags will be considered, so that this function will only ever see | |
1980 | the 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. | |
1986 | For example, this value makes those two functions available: | |
1987 | ||
1988 | '((?R set-category) | |
1989 | (?C bulk-cut)) | |
1990 | ||
1991 | With selected entries in an agenda buffer, `B R' will call | |
fe3c5669 | 1992 | the custom function `set-category' on the selected entries. |
3ab2c837 BG |
1993 | Note 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. | |
2000 | If STRING is non-nil, the text property will be fetched from position 0 | |
2001 | in that string. If STRING is nil, it will be fetched from the beginning | |
2002 | of 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'. | |
2014 | This is mostly for hacking and trying a new command - once the command | |
2015 | works 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. |
2037 | The 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. | |
2047 | Agenda commands will then show existing buffer instead of generating new ones. | |
2048 | When 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 | ||
2112 | The 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. | |
2485 | This undoes changes both in the agenda buffer and in the remote buffer | |
2486 | that 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 | ||
2533 | For example, if you have a custom agenda command \"p\" and you | |
2534 | want this command to be accessible only from plain text files, | |
2535 | use this: | |
2536 | ||
a89c8ef0 | 2537 | '((\"p\" ((in-file . \"\\.txt\")))) |
8223b1d2 BG |
2538 | |
2539 | Here 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 |
2546 | not-in-buffer: command not displayed in matching buffers | |
8223b1d2 BG |
2547 | [function]: a custom function taking no argument |
2548 | ||
2549 | If you define several checks, the agenda command will be | |
2550 | accessible if there is at least one valid check. | |
2551 | ||
2552 | You can also bind a key to another agenda custom command | |
2553 | depending on contextual rules. | |
2554 | ||
a89c8ef0 | 2555 | '((\"p\" \"q\" ((in-file . \"\\.txt\")))) |
8223b1d2 BG |
2556 | |
2557 | Here it means: in .txt files, use \"p\" as the key for the | |
2558 | agenda command otherwise associated with \"q\". (The command | |
2559 | originally associated with \"q\" is not displayed to avoid | |
2560 | duplicates.)" | |
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. | |
2581 | This can be nil (no limit) or an integer or an alist of agenda | |
2582 | types with an associated number of entries to display in this | |
2583 | type." | |
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. | |
2600 | This can be nil (no limit) or an integer or an alist of agenda | |
2601 | types with an associated number of entries to display in this | |
2602 | type." | |
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. | |
2619 | This can be nil (no limit) or an integer or an alist of agenda | |
2620 | types with an associated number of entries to display in this | |
2621 | type." | |
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. | |
2638 | This can be nil (no limit) or a number of minutes (as an integer) | |
2639 | or an alist of agenda types with an associated number of minutes | |
2640 | to 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. |
2660 | Prompts for a command to execute. Any prefix arg will be passed | |
2661 | on to the selected command. The default selections are: | |
2662 | ||
2663 | a Call `org-agenda-list' to display the agenda for current day or week. | |
2664 | t Call `org-todo-list' to display the global todo list. | |
2665 | T Call `org-todo-list' to display the global todo list, select only | |
2666 | entries with a specific TODO keyword (the user gets a prompt). | |
2667 | m Call `org-tags-view' to display headlines with tags matching | |
2668 | a condition (the user is prompted for the condition). | |
2669 | M Like `m', but select only TODO entries, no ordinary headlines. | |
2670 | L Create a timeline for the current buffer. | |
2671 | e Export views to associated files. | |
c8d0cf5c | 2672 | s Search entries for keywords. |
8223b1d2 | 2673 | S 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. | |
2681 | C Configure custom agenda commands. | |
20908596 CD |
2682 | |
2683 | More commands can be added by configuring the variable | |
2684 | `org-agenda-custom-commands'. In particular, specific tags and TODO keyword | |
2685 | searches can be pre-defined in this way. | |
2686 | ||
2687 | If the current buffer is in Org-mode and visiting a file, you can also | |
2688 | first press `<' once to indicate that the agenda should be temporarily | |
2689 | \(until the next use of \\[org-agenda]) restricted to the current file. | |
2690 | Pressing `<' 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. | |
2848 | This function allows interactive building of block agendas. | |
2849 | Agenda 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 |
2890 | a Agenda for current week or day e Export agenda views | |
2891 | t List of all TODO entries T Entries with special TODO kwd | |
621f83e4 | 2892 | m Match a TAGS/PROP/TODO query M Like m, but only TODO entries |
8223b1d2 | 2893 | s Search for keywords S Like s, but only TODO entries |
20908596 | 2894 | L 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. | |
3136 | If 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 | |
3138 | longer string it is used as a tags/todo match string. | |
86fbb8ca | 3139 | Parameters are alternating variable names and values that will be bound |
20908596 | 3140 | before 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. | |
3154 | If 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 | |
3156 | longer string it is used as a tags/todo match string. | |
86fbb8ca | 3157 | Parameters are alternating variable names and values that will be bound |
20908596 CD |
3158 | before running the agenda command. |
3159 | ||
3160 | The output gives a line for each selected agenda item. Each | |
3161 | item is a list of comma-separated values, like this: | |
3162 | ||
3163 | category,head,type,todo,tags,date,time,extra,priority-l,priority-n | |
3164 | ||
3165 | category The category of the item | |
3166 | head The headline, without TODO kwd, TAGS and PRIORITY | |
3167 | type 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 | |
3178 | todo The todo keyword, if any | |
3179 | tags All tags including inherited ones, separated by colons | |
3180 | date The relevant date, like 2007-2-14 | |
3181 | time The time, like 15:00-16:50 | |
3182 | extra Sting with extra planning info | |
3183 | priority-l The priority letter if any was given | |
3184 | priority-n The computed numerical priority | |
3185 | agenda-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. |
3208 | This 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. |
3305 | Depending on the extension of the file name, plain text (.txt), | |
271672fa | 3306 | HTML (.html or .htm), PDF (.pdf) or Postscript (.ps) is produced. |
e66ba1df | 3307 | If the extension is .ics, run icalendar export over all files used |
20908596 CD |
3308 | to construct the agenda and limit the export to entries listed in the |
3309 | agenda now. | |
271672fa BG |
3310 | If the extension is .org, collect all subtrees corresponding to the |
3311 | agenda entries and add them in an .org file. | |
8bfe682a | 3312 | With prefix argument OPEN, open the new file immediately. |
20908596 CD |
3313 | If NOSETTINGS is given, do not scope the settings of |
3314 | `org-agenda-exporter-settings' into the export commands. This is used when | |
3315 | the settings have already been scoped and we do not wish to overrule other, | |
8223b1d2 BG |
3316 | higher priority settings. |
3317 | If 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. | |
3429 | VALUE 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. | |
3440 | This will add a maximum of `org-agenda-add-entry-text-maxlines' lines of the | |
3441 | entry text following headings shown in the agenda. | |
3442 | Drawers 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 |
3460 | This will ignore drawers etc, just get the text. |
3461 | If INDENT is given, prefix every line with this string. If KEEP is | |
8bfe682a | 3462 | given, it is a list of symbols, defining stuff that should not be |
8d642074 | 3463 | removed 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 | 3563 | This must be a list of strings, each string must be a single tag preceded |
c8d0cf5c CD |
3564 | by \"+\" or \"-\". |
3565 | This variable should not be set directly, but agenda custom commands can | |
afe98dfa CD |
3566 | bind it in the options section. The preset filter is a global property of |
3567 | the entire agenda view. In a block agenda, it will not work reliably to | |
3568 | define a filter for one of the individual blocks. You need to set it in | |
3569 | the 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 |
3573 | This must be a list of strings, each string must be a single category |
3574 | preceded by \"+\" or \"-\". | |
3575 | This variable should not be set directly, but agenda custom commands can | |
3576 | bind it in the options section. The preset filter is a global property of | |
3577 | the entire agenda view. In a block agenda, it will not work reliably to | |
3578 | define a filter for one of the individual blocks. You need to set it in | |
3579 | the 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 | 3583 | This must be a list of strings, each string must be a single regexp |
271672fa BG |
3584 | preceded by \"+\" or \"-\". |
3585 | This variable should not be set directly, but agenda custom commands can | |
3586 | bind it in the options section. The preset filter is a global property of | |
3587 | the entire agenda view. In a block agenda, it will not work reliably to | |
3588 | define a filter for one of the individual blocks. You need to set it in | |
3589 | the 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 | |
3594 | generating 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. |
3833 | When INVISIBLE is non-nil, hide currently blocked TODO instead of | |
3834 | dimming 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. | |
3873 | If this function returns nil, the current match should not be skipped. | |
3874 | Otherwise, the function must return a position from where the search | |
3875 | should be continued. | |
3876 | This may also be a Lisp form, it will be evaluated. | |
3877 | Never set this variable using `setq' or so, because then it will apply | |
3ab2c837 BG |
3878 | to all future agenda commands. If you do want a global skipping condition, |
3879 | use the option `org-agenda-skip-function-global' instead. | |
3880 | The correct usage for `org-agenda-skip-function' is to bind it with | |
3881 | `let' to scope it dynamically into the agenda-constructing command. | |
3882 | A 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. | |
3886 | Also moves point to the end of the skipped region, so that search can | |
3887 | continue 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 |
3906 | and match data are returned to the previous state no matter what these | |
3907 | functions 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. | |
3925 | Org-mode keeps a list of these markers and resets them when they are | |
3926 | no 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. |
3942 | This 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. |
4004 | Only 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, | |
4006 | under the current date. | |
4007 | If the buffer contains an active region, only check the region for | |
4008 | dates." | |
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. | |
4096 | If NO-RANGES is non-nil, include only the start and end dates of a range, | |
4097 | not every single day in the range. If FORCE-TODAY is non-nil, make | |
4098 | sure that TODAY is included in the list. If INACTIVE is non-nil, also | |
4099 | inactive time stamps (those in square brackets) are included. | |
4100 | When 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 |
4144 | Custom commands can set this variable in the options section. |
4145 | This is usually a string like \"2007-11-01\", \"+2d\" or any other | |
4146 | input allowed when reading a date through the Org calendar. | |
4147 | See 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'. |
4155 | The view will be for the current day or week, but from the overview buffer | |
4156 | you will be able to go to other days/weeks. | |
4157 | ||
20908596 | 4158 | With a numeric prefix argument in an interactive call, the agenda will |
e66ba1df | 4159 | span ARG days. Lisp programs should instead specify SPAN to change |
acedf35c | 4160 | the number of days. SPAN defaults to `org-agenda-span'. |
20908596 CD |
4161 | |
4162 | START-DAY defaults to TODAY, or to the most recent match for the weekday | |
271672fa BG |
4163 | given in `org-agenda-start-on-weekday'. |
4164 | ||
4165 | When WITH-HOUR is non-nil, only include scheduled and deadline | |
4166 | items 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. |
4371 | START-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. |
4397 | In this table, we have single quotes not as word constituents, to | |
4398 | that 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 | |
4414 | With optional prefix argument TODO-ONLY, only consider entries that are | |
4415 | TODO entries. The argument STRING can be used to pass a default search | |
4416 | string into this function. If EDIT-AT is non-nil, it means that the | |
4417 | user should get a chance to edit this string, with cursor at position | |
4418 | EDIT-AT. | |
4419 | ||
ed21c5c8 CD |
4420 | The search string can be viewed either as a phrase that should be found as |
4421 | is, or it can be broken into a number of snippets, each of which must match | |
4422 | in a Boolean way to select an entry. The default depends on the variable | |
4423 | `org-agenda-search-view-always-boolean'. | |
4424 | Even if this is turned off (the default) you can always switch to | |
86fbb8ca | 4425 | Boolean search dynamically by preceding the first word with \"+\" or \"-\". |
ed21c5c8 CD |
4426 | |
4427 | The default is a direct search of the whole phrase, where each space in | |
4428 | the search string can expand to an arbitrary amount of whitespace, | |
4429 | including newlines. | |
4430 | ||
4431 | If using a Boolean search, the search string is split on whitespace and | |
4432 | each snippet is searched separately, with logical AND to select an entry. | |
4433 | Words prefixed with a minus must *not* occur in the entry. Words without | |
4434 | a prefix or prefixed with a plus must occur in the entry. Matching is | |
4435 | case-insensitive. Words are enclosed by word delimiters (i.e. they must | |
4436 | match whole words, not parts of a word) if | |
4437 | `org-agenda-search-view-force-full-words' is set (default is nil). | |
4438 | ||
4439 | Boolean search snippets enclosed by curly braces are interpreted as | |
86fbb8ca | 4440 | regular expressions that must or (when preceded with \"-\") must not |
ed21c5c8 | 4441 | match in the entry. Snippets enclosed into double quotes will be taken |
86fbb8ca | 4442 | as 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 | |
4452 | This command searches the agenda files, and in addition the files listed | |
4453 | in `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 |
4708 | The prefix arg can be used to select a specific TODO keyword and limit |
4709 | the list to these. When using \\[universal-argument], you will be prompted | |
4710 | for 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. | |
4794 | The 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. | |
4880 | This is basically a temporary global variable that can be set and then | |
4881 | used 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 |
4885 | This variable should not be set directly, but custom commands can bind it |
4886 | in 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 |
4890 | If yes, it returns the end position of this entry, causing agenda commands |
4891 | to skip the entry but continuing the search in the subtree. This is a | |
4892 | function that can be put into `org-agenda-skip-function' for the duration | |
4893 | of 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 |
4902 | If yes, it returns the end position of this tree, causing agenda commands |
4903 | to 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 |
4913 | If yes, it returns the end position of the current entry (NOT the tree), |
4914 | causing agenda commands to skip the entry but continuing the search in | |
4915 | the subtree. This is a function that can be put into | |
4916 | `org-agenda-skip-function' for the duration of a command. An important | |
4917 | use 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. | |
4927 | See `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 |
4932 | See `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. | |
4937 | If SUBTREE is non-nil, the entire subtree is checked. Otherwise, only | |
153ae947 | 4938 | the entry (i.e. the text before the next heading) is checked. |
20908596 CD |
4939 | |
4940 | CONDITIONS is a list of symbols, boolean OR is used to combine the results | |
4941 | from different tests. Valid conditions are: | |
4942 | ||
4943 | scheduled Check if there is a scheduled cookie | |
4944 | notscheduled Check if there is no scheduled cookie | |
4945 | deadline Check if there is a deadline | |
4946 | notdeadline Check if there is no deadline | |
c8d0cf5c CD |
4947 | timestamp Check if there is a timestamp (also deadline or scheduled) |
4948 | nottimestamp Check if there is no timestamp (also deadline or scheduled) | |
20908596 CD |
4949 | regexp Check if regexp matches |
4950 | notregexp Check if regexp does not match. | |
ed21c5c8 CD |
4951 | todo Check if TODO keyword matches |
4952 | nottodo Check if TODO keyword does not match | |
20908596 CD |
4953 | |
4954 | The regexp is taken from the conditions list, it must come right after | |
4955 | the `regexp' or `notregexp' element. | |
4956 | ||
ed21c5c8 CD |
4957 | `todo' and `nottodo' accept as an argument a list of todo |
4958 | keywords, which may include \"*\" to match any todo keyword. | |
4959 | ||
4960 | (org-agenda-skip-entry-if 'todo '(\"TODO\" \"WAITING\")) | |
4961 | ||
4962 | would skip all entries with \"TODO\" or \"WAITING\" keywords. | |
4963 | ||
153ae947 | 4964 | Instead of a list, a keyword class may be given. For example: |
ed21c5c8 CD |
4965 | |
4966 | (org-agenda-skip-entry-if 'nottodo 'done) | |
4967 | ||
4968 | would skip entries that haven't been marked with any of \"DONE\" | |
153ae947 | 4969 | keywords. Possible classes are: `todo', `done', `any'. |
ed21c5c8 | 4970 | |
20908596 CD |
4971 | If any of these conditions is met, this function returns the end point of |
4972 | the entity, causing the search to continue from there. This is a function | |
4973 | that 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 |
5011 | ARGS is a list with first element either `todo', `nottodo', |
5012 | `todo-unblocked' or `nottodo-unblocked'. The remainder is either | |
5013 | a 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. | |
5056 | Stuck projects are project that have no next actions. For the definitions | |
5057 | of 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'. | |
5166 | This gets rid of the date, the underline under the date, and | |
5167 | the dummy entry installed by `org-mode' to ensure non-empty diary for each | |
5168 | date. 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. | |
5212 | Needed 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 |
5230 | This function can be used in a \"sexp\" diary entry in the Emacs calendar. |
5231 | It accesses org files and extracts information from those files to be | |
5232 | listed in the diary. The function accepts arguments specifying what | |
ed21c5c8 CD |
5233 | items should be listed. For a list of arguments allowed here, see the |
5234 | variable `org-agenda-entry-types'. | |
20908596 CD |
5235 | |
5236 | The call in the diary file should look like this: | |
5237 | ||
5238 | &%%(org-diary) ~/path/to/some/orgfile.org | |
5239 | ||
5240 | Use a separate line for each org file to check. Or, if you omit the file name, | |
5241 | all files listed in `org-agenda-files' will be checked automatically: | |
5242 | ||
5243 | &%%(org-diary) | |
5244 | ||
271672fa BG |
5245 | If you don't give any arguments (as in the example above), the default value |
5246 | of `org-agenda-entry-types' is used: (:deadline :scheduled :timestamp :sexp). | |
20908596 CD |
5247 | So the example above may also be written as |
5248 | ||
5249 | &%%(org-diary :deadline :timestamp :sexp :scheduled) | |
5250 | ||
5251 | The function expects the lisp variables `entry' and `date' to be provided | |
5252 | by the caller, because this is how the calendar works. Don't use this | |
5253 | function 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'. | |
5290 | FILE is the path to a file to be checked for entries. DATE is date like | |
5291 | the one returned by `calendar-current-date'. ARGS are symbols indicating | |
5292 | which kind of entries should be extracted. For details about these, see | |
5293 | the 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 |
5457 | This 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 |
5741 | DAYNAME is a number between 0 (Sunday) and 6 (Saturday). |
5742 | SKIP-WEEKS is any number of ISO weeks in the block period for which the | |
5743 | item 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 |
5745 | holiday will also be skipped. If SKIP-WEEKS arguments are holiday strings, |
5746 | then 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'. | |
5765 | The 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'. | |
5767 | So for American calendars, give this as MONTH DAY YEAR, for European as | |
5768 | DAY MONTH YEAR, and for ISO as YEAR MONTH DAY. | |
5769 | DAYNAME is a number between 0 (Sunday) and 6 (Saturday). SKIP-WEEKS | |
5770 | is any number of ISO weeks in the block period for which the item should | |
5771 | be skipped. | |
5772 | ||
5773 | This function is here only for backward compatibility and it is deprecated, | |
5774 | please 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. | |
5892 | See 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. | |
6012 | When WITH-HOUR is non-nil, only return deadlines with an hour | |
6013 | specification 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. |
6147 | FRACTION 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. | |
6155 | When WITH-HOUR is non-nil, only return scheduled items with | |
6156 | an 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'. | |
6419 | The 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'. | |
6422 | The 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'. | |
6425 | The 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'. | |
6428 | The 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 |
6445 | In particular, add the prefix and corresponding text properties. |
6446 | ||
6447 | EXTRA must be a string to replace the `%s' specifier in the prefix format. | |
6448 | LEVEL may be a string to replace the `%l' specifier. | |
6449 | CATEGORY (a string, a symbol or nil) may be used to overrule the default | |
20908596 | 6450 | category taken from local variable or file name. It will replace the `%c' |
271672fa BG |
6451 | specifier in the format. |
6452 | DOTIME, when non-nil, indicates that a time-of-day should be extracted from | |
6453 | TXT for sorting of this entry, and for the `%t' specifier in the format. | |
6454 | When DOTIME is a string, this string is searched for a time before TXT is. | |
6455 | TAGS can be the tags of the headline. | |
20908596 | 6456 | Any 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. | |
6625 | The 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 | ||
6666 | LIST is the list of agenda items formatted by `org-agenda-list'. | |
6667 | NDAYS is the span of the current agenda view. | |
6668 | TODAYP 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 |
6709 | The resulting form and associated variable bindings is returned |
6710 | and 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. | |
6778 | If found, return it as a military time number between 0 and 2400. | |
6779 | If not found, return nil. | |
6780 | The optional STRING argument forces conversion into a 5 character wide string | |
6781 | HH: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. | |
6806 | Prior to sorting also means just before they are inserted into the agenda. | |
6807 | ||
6808 | To aid sorting, you may revisit the original entries and add more text | |
6809 | properties which will later be used by the sorting functions. | |
6810 | ||
6811 | The function should take a string argument, an agenda line. | |
6812 | It has access to the text properties in that line, which contain among | |
6813 | other things, the property `org-hd-marker' that points to the entry | |
6814 | where the line comes from. Note that not all lines going into the agenda | |
6815 | have this property, only most. | |
6816 | ||
6817 | The function should return the modified string. It is probably best | |
6818 | to ONLY change text properties. | |
6819 | ||
6820 | You can also use this function as a filter, by returning nil for lines | |
6821 | you don't want to have in the agenda at all. For this application, you | |
6822 | could 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. | |
6826 | The 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. | |
7015 | When TYPE is \"scheduled\", \"deadline\", \"timestamp\" or | |
7016 | \"timestamp_ia\", compare within each of these type. When TYPE | |
7017 | is the empty string, compare all timestamps without respect of | |
7018 | their 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. | |
7104 | Restriction will be the file if TYPE is `file', or if type is the | |
7105 | universal prefix '(4), or if the cursor is before the first headline | |
7106 | in 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 |
7172 | If ERROR is non-nil, throw an error, otherwise just return nil. |
7173 | Allowed 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'. | |
7184 | Also 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. |
7213 | When `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. |
7243 | Also kill Org-mode buffers loaded by `org-agenda'. Org-mode | |
7244 | buffers 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 |
7252 | This is used when toggling sticky agendas. |
7253 | You 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. |
7263 | So this is just a shortcut for \\<global-map>`\\[org-agenda]', available | |
7264 | in 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. | |
7333 | The 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. | |
7362 | The 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. | |
7376 | Regexp filters are cumulative. | |
7377 | With no prefix argument, keep entries matching the regexp. | |
7378 | With one prefix argument, filter out entries matching the regexp. | |
7379 | With 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. |
7404 | The tag is selected with its fast selection letter, as configured. | |
71d35b24 CD |
7405 | With prefix argument STRIP, remove all lines that do have the tag. |
7406 | A lisp caller can specify CHAR. NARROW means that the new tag should be | |
7407 | used to narrow the search - the interactive user can also press `-' or `+' | |
7408 | to 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 | 7582 | E 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. | |
7595 | If 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. | |
7604 | When 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 | 7719 | Positive 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 | 7724 | Negative 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 | 7729 | Positive 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 | 7734 | Negative 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 |
7847 | With 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. | |
7887 | With 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 | 7929 | With 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. | |
7934 | With argument ISO-WEEK, switch to the corresponding ISO week. | |
7935 | If ISO-WEEK has more then 2 digits, only the last two encode the | |
7936 | week. Any digits before this encode a year. So 200712 means | |
7937 | week 12 of year 2007. Years in the range 1938-2037 can also be | |
7938 | written 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. | |
7943 | With argument ISO-WEEK, switch to the corresponding ISO week. | |
7944 | If ISO-WEEK has more then 2 digits, only the last two encode the | |
7945 | week. Any digits before this encode a year. So 200712 means | |
7946 | week 12 of year 2007. Years in the range 1938-2037 can also be | |
7947 | written 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 |
7952 | With 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 |
7957 | With argument YEAR, switch to that year. |
7958 | If MONTH has more then 2 digits, only the last two encode the | |
7959 | month. Any digits before this encode a year. So 200712 means | |
7960 | December year 2007. Years in the range 1938-2037 can also be | |
7961 | written 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 | 7971 | SPAN 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 | 7992 | SPAN may be `day', `week', `fortnight', `month', `year'. The return value |
20908596 CD |
7993 | is a cons cell with the starting date and the number of days, |
7994 | so 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. | |
8111 | With prefix arg WITH-FILTER, make the clocktable respect the current | |
8112 | agenda 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. | |
8125 | With argument SPECIAL, show all possible log items, not only the ones | |
8126 | configured in `org-agenda-log-mode-items'. | |
8127 | With 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:. |
8145 | When 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. | |
8349 | Point 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. | |
8434 | The subtree is the one in buffer BUF, starting at BEG and ending at END. | |
8435 | If 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 | ||
8460 | When GOTO is 0 or '(64), clear the refile cache. | |
8461 | When GOTO is '(16), go to the location of the last refiled item. | |
8462 | RFLOC can be a refile location obtained in a different way. | |
8463 | When 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. |
8492 | This looks for a link in the displayed line in the agenda. | |
8493 | It 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. | |
8573 | With prefix argument FULL-ENTRY, make the entire entry visible | |
8574 | if 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 |
8586 | When called repeatedly, scroll the window that is displaying the buffer. |
8587 | With a \\[universal-argument] prefix, use `org-show-entry' instead of | |
8588 | `show-subtree' to display the item, so that drawers and logbooks stay | |
8589 | folded." | |
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 | 8613 | The prefix arg selects the amount of information to display: |
c8d0cf5c CD |
8614 | |
8615 | 0 hide the subtree | |
8616 | 1 just show the entry according to defaults. | |
54a0dee5 CD |
8617 | 2 show the children view |
8618 | 3 show the subtree view | |
c8d0cf5c CD |
8619 | 4 show the entire subtree and any LOGBOOK drawers |
8620 | 5 show the entire subtree and any drawers | |
8621 | With prefix argument FULL-ENTRY, make the entire entry visible | |
8622 | if 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. |
8673 | Default settings are taken from `org-show-hierarchy-above' and siblings. | |
54a0dee5 | 8674 | When use repeatedly in immediate succession, the remote entry will cycle |
c8d0cf5c CD |
8675 | through visibility |
8676 | ||
54a0dee5 CD |
8677 | children -> subtree -> folded |
8678 | ||
8679 | When 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 | |
8681 | docstring 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 |
8718 | This calls the command `org-tree-to-indirect-buffer' from the original buffer. |
8719 | ||
8720 | With a numerical prefix ARG, go up to this level and then take that tree. | |
8721 | With a negative numeric ARG, go up by this number of levels. | |
86fbb8ca CD |
8722 | With a \\[universal-argument] prefix, make a separate frame for this tree (i.e. don't |
8723 | use 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 | |
8757 | by 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. | |
8771 | This changes the line at point, all other lines in the agenda referring to | |
8772 | the 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. |
8837 | The 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 | 8840 | If FIXFACE is non-nil, the face of each item is modified according to |
db55f368 CD |
8841 | the new TODO state. |
8842 | If JUST-THIS is non-nil, change just the current line, not all. | |
33306645 | 8843 | If 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. |
8940 | This changes the line at point, all other lines in the agenda referring to | |
c7cf0ebc BG |
8941 | the same tree node, and the headline of the tree node in the Org-mode file. |
8942 | Called 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. | |
9199 | The prefix ARG is passed to the `org-time-stamp' command and can therefore | |
9200 | be 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 | 9220 | ARG 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 | 9242 | ARG 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. | |
9315 | If the currently clocked in task is not listed in the agenda | |
9316 | buffer, 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? | |
9374 | Valid values: | |
9375 | ||
9376 | date-tree in the date tree, as child of the date | |
9377 | top-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'. | |
9397 | If TEXT is not empty, it will become the headline of the new entry, and | |
9398 | the 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. | |
9472 | Add TEXT as headline, and position the cursor in the second line so that | |
9473 | a 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. | |
9482 | Add TEXT as headline, and position the cursor in the second line so that | |
9483 | a 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 |
9506 | All the standard commands work: block, weekly etc. |
9507 | When `org-agenda-diary-file' points to a file, | |
9508 | `org-agenda-diary-entry-in-org-file' is called instead to create | |
9509 | entries 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. | |
9588 | Latitude and longitude can be specified with the variables | |
9589 | `calendar-latitude' and `calendar-longitude'. When called with prefix | |
9590 | argument, 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. | |
9615 | This 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. | |
9738 | BEG and END default to the buffer limits. | |
9739 | ||
9740 | This only removes the overlays, it does not remove the markers | |
9741 | from 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 | 9750 | This 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. | |
9760 | You can toggle this interactively by typing `p' when prompted for a | |
9761 | bulk 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. | |
9768 | The 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. | |
9931 | With a `C-1' prefix, use the HH:MM value at point (if any) or the | |
9932 | current 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. | |
9955 | When 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. | |
9984 | When called a second time in direct sequence, offer to remove the FLAGGING | |
9985 | tag 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'. |
10034 | With a \\[universal-argument] prefix, refresh the list of | |
33306645 | 10035 | appointments. |
20908596 CD |
10036 | |
10037 | If FILTER is t, interactively prompt the user for a regular | |
10038 | expression, and filter out entries that don't match it. | |
10039 | ||
10040 | If FILTER is a string, use this string as a regular expression | |
10041 | for filtering entries out. | |
10042 | ||
e66ba1df BG |
10043 | If FILTER is a function, filter out entries against which |
10044 | calling the function returns nil. This function takes one | |
10045 | argument: an entry from `org-agenda-get-day-entries'. | |
10046 | ||
20908596 CD |
10047 | FILTER can also be an alist with the car of each cell being |
10048 | either 'headline or 'category. For example: | |
10049 | ||
10050 | '((headline \"IMPORTANT\") | |
10051 | (category \"Work\")) | |
10052 | ||
10053 | will only add headlines containing IMPORTANT or headlines | |
e66ba1df BG |
10054 | belonging to the \"Work\" category. |
10055 | ||
10056 | ARGS are symbols indicating what kind of entries to consider. | |
271672fa BG |
10057 | By default `org-agenda-to-appt' will use :deadline*, :scheduled* |
10058 | \(i.e., deadlines and scheduled items with a hh:mm specification) | |
e66ba1df | 10059 | and :timestamp entries. See the docstring of `org-diary' for |
8223b1d2 BG |
10060 | details and examples. |
10061 | ||
8a28a5b8 | 10062 | If an entry has a APPT_WARNTIME property, its value will be used |
8223b1d2 | 10063 | to 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 |