Merge branch 'filtering'

Conflicts:
	lisp/ChangeLog
This commit is contained in:
Carsten Dominik 2008-10-20 23:32:22 +02:00
commit a086743480
4 changed files with 233 additions and 52 deletions

View File

@ -17,6 +17,52 @@
:END:
** Details
*** Enhancements to secondary agenda filtering
**** You can now refining the current filter by an additional criterion
When filtering an existing agenda view with =/=, you can
now narrow down the existing selection by an additional
condition. Do do this, use =\= instead of =/= to add the
aditional criterion. You can also press =+= or =-= after
=/= to add a positive or negative condition. A condition
can be a TAG, or an effort estimate limit, see below.
**** It is now possible to filter for effort estimates
This means to filter the agenda for the value of the Effort
property. For this you should best set up global allowed
values for effort estimates, with
#+begin_src emacs-lisp
(setq org-global-properties
'(("Effort_ALL" . "0 0:10 0:30 1:00 2:00 3:00 4:00")))
#+end_src
You may then select effort limits with single keys in the
filter. It works like this: After =/= or =\=, first select
the operater which you want to use to compare effort
estimates:
: < Select entries with effort smaller than or equal to the limit
: > Select entries with effort larger than or equal to the limit
: = Select entries with effort equal to the limit
After that, you can press a single digit number which is
used as an index to the allowed effort estimates.
If you do not use digits to fast-select tags, you can even
skip the operator, which will then default to
`org-agenda-filter-effort-default-operator', which is by
default =<=.
Thanks to Manish for the great idea to include fast effort
filtering into the agenda filtering process.
**** The mode line will show the active filter
For example, if there is a filter in place that does select
for HOME tags, against EMAILtags, and for tasks with an
estimated effort smaller than 30 minutes, the mode-line with
show =+HOME-EMAIL+<0:30=
*** Setting tags has now its own binding, =C-c C-q=

View File

@ -4863,10 +4863,10 @@ you want to clock your time). For a specific buffer you can use
@end example
@noindent
or you can set up these values globally by customizing the variables
@code{org-global-properties} and @code{org-columns-default-format}. In
particular if you want to use this setup also in the agenda, a global setup
may be advised.
or, even better, you can set up these values globally by customizing the
variables @code{org-global-properties} and @code{org-columns-default-format}.
In particular if you want to use this setup also in the agenda, a global
setup may be advised.
The way to assign estimates to individual items is then to switch to column
mode, and to use @kbd{S-@key{right}} and @kbd{S-@key{left}} to change the
@ -4882,6 +4882,10 @@ option @code{org-agenda-columns-add-appointments-to-effort-sum}. The
appointments on a day that take place over a specified time interval will
then also be added to the load estimate of the day.
Effort estimates can be used in secondary agenda filtering that is triggered
with the @kbd{/} key in the agenda (@pxref{Agenda commands}). If you have
these estimates defined consistently, two or three key presses will narrow
down the list to stuff that fits into an available time slot.
@node Capture, Agenda Views, Dates and Times, Top
@chapter Capture
@ -5835,9 +5839,7 @@ sequence in which they are found in the agenda files.
Sorting can be customized using the variable
@code{org-agenda-sorting-strategy}, and may also include criteria based on
the estimated effort of an entry.
@c FIXME: link!!!!!!!!
the estimated effort of an entry (@pxref{Effort estimates}).
@node Agenda commands, Custom agenda views, Presentation and sorting, Agenda Views
@section Commands in the agenda buffer
@ -5994,17 +5996,48 @@ that entry would be in the original buffer (taken from a property, from a
@code{org-columns-default-format}), will be used in the agenda.
@tsubheading{Secondary filtering and query editing}
@cindex filtering, by tag and effort, in agenda
@cindex tag filtering, in agenda
@cindex effort filtering, in agenda
@cindex query editing, in agenda
@kindex /
@item /
Filter the current agenda view with respect to a tag. You will be prompted
for a tag selection letter. Pressing @key{TAB} at that prompt will offer use
completion to select a tag (including any tags that do not have a selection
character). The command then hides all entries that do not contain or
inherit this tag. When called with prefix arg, remove the entries that
@emph{do} have the tag. A second @kbd{/} at the prompt will unhide any
hidden entries.
Filter the current agenda view with respect to a tag and/or effort estimates.
The difference between this and a custom agenda commands is that filtering is
very fast, so that you can switch quickly between different filters without
having to recreate the agenda.
You will be prompted for a tag selection letter. Pressing @key{TAB} at that
prompt will offer use completion to select a tag (including any tags that do
not have a selection character). The command then hides all entries that do
not contain or inherit this tag. When called with prefix arg, remove the
entries that @emph{do} have the tag. A second @kbd{/} at the prompt will
turn off the filter and unhide any hidden entries. If the first key you
press is either @kbd{+} or @kbd{-}, the previous filter will be narrowed by
requiring or forbidding the selected additional tag. Instead of pressing
@kbd{+} or {-}, you can also use the @kbd{\} command.
In order to filter for effort estimates, you should set-up allowed
efforts globally, for example
@lisp
(setq org-global-properties
'(("Effort_ALL". "0 0:10 0:30 1:00 2:00 3:00 4:00")))
@end lisp
You can then filter for an effort by first typing an operator, one of @kbd{<},
@kbd{>}, and @kbd{=}, and then the one-digit index of an effort estimate in
your array of allowed values, where @kbd{0} means the 10th value. The filter
will then restrict to entries with effort smaller-or-equal, equal, or
larger-or-equal than the selected value. If the digits 0-9 are not used as
fast access keys to tags, you can also simply press the index digit directly
without an operator. In this case, @kbd{<} will be assumed.
@kindex \
@item \
Narrow the current agenda filter by an additional condition. When called with
prefix arg, remove the entries that @emph{do} have the tag, or that do match
the effort criterion. You can achieve the same effect by pressing @kbd{+} or
@kbd{-} as the first key after the @kbd{/} command.
@kindex [
@kindex ]

View File

@ -5,6 +5,9 @@
(org-add-log-note): Mask prefix argument when immediately storing
the note.
* org-agenda.el (org-agenda-filter-effort-default-operator): New
option.
2008-10-19 James TD Smith <ahktenzero@mohorovi.cc>
* org.el (org-add-log-setup): Bugfix; code to find insertion point
@ -13,6 +16,12 @@
2008-10-18 Carsten Dominik <dominik@science.uva.nl>
* org-agenda.el (org-agenda-filter-tags,org-agenda-filter-form):
New variables.
(org-prepare-agenda): Reset the filter tags.
(org-agenda-filter-by-tag, org-agenda-filter-by-tag-show-all):
Show filter tags in mode line.
* org-table.el (orgtbl-to-html): Bind `html-table-tag' for the
formatter.

View File

@ -387,6 +387,14 @@ or `C-c a #' to produce the list."
(repeat :tag "Projects are *not* stuck if they have an entry with TAG being any of" (string))
(regexp :tag "Projects are *not* stuck if this regexp matches\ninside the subtree")))
(defcustom org-agenda-filter-effort-default-operator "<"
"The default operator for effort estimate filtering.
If you select an effort estimate limit with first pressing an operator,
this one will be used."
:group 'org-agenda-custom-commands
:type '(choice (const :tag "less or equal" "<")
(const :tag "greater or equal"">")
(const :tag "equal" "=")))
(defgroup org-agenda-skip nil
"Options concerning skipping parts of agenda files."
@ -1169,6 +1177,7 @@ The following commands are available:
(org-defkey org-agenda-mode-map "{" 'org-agenda-manipulate-query-add-re)
(org-defkey org-agenda-mode-map "}" 'org-agenda-manipulate-query-subtract-re)
(org-defkey org-agenda-mode-map "/" 'org-agenda-filter-by-tag)
(org-defkey org-agenda-mode-map "\\" 'org-agenda-filter-by-tag-refine)
(defvar org-agenda-keymap (copy-keymap org-agenda-mode-map)
"Local keymap for agenda entries from Org-mode.")
@ -1958,6 +1967,7 @@ higher priority settings."
(defun org-prepare-agenda (&optional name)
(setq org-todo-keywords-for-agenda nil)
(setq org-done-keywords-for-agenda nil)
(setq org-agenda-filter-tags nil)
(if org-agenda-multi
(progn
(setq buffer-read-only nil)
@ -4117,48 +4127,125 @@ When this is the global TODO list, a prefix argument will be interpreted."
(goto-line line)
(recenter window-line)))
(defvar org-global-tags-completion-table nil)
(defun org-agenda-filter-by-tag (strip &optional char)
(defvar org-agenda-filter-tags nil)
(defvar org-agenda-filter-form nil)
(defun org-agenda-filter-by-tag (strip &optional char narrow)
"Keep only those lines in the agenda buffer that have a specific tag.
The tag is selected with its fast selection letter, as configured.
With prefix argument STRIP, remove all lines that do have the tag."
With prefix argument STRIP, remove all lines that do have the tag.
A lisp caller can specify CHAR. NARROW means that the new tag should be
used to narrow the search - the interactive user can also press `-' or `+'
to switch to narrowing."
(interactive "P")
(let (char a tag tags (inhibit-read-only t))
(message "Select tag [%s] or no tag [ ], [TAB] to complete, [/] to restore: "
(mapconcat
(lambda (x) (if (cdr x) (char-to-string (cdr x)) ""))
org-tag-alist-for-agenda ""))
(let* ((alist org-tag-alist-for-agenda)
(tag-chars (mapconcat
(lambda (x) (if (cdr x) (char-to-string (cdr x)) ""))
alist ""))
(efforts (org-split-string
(or (cdr (assoc (concat org-effort-property "_ALL")
org-global-properties))
"0 0:10 0:30 1:00 2:00 3:00 4:00 5:00 6:00 7:00 8:00" "")))
(effort-op org-agenda-filter-effort-default-operator)
(effort-prompt "")
(inhibit-read-only t)
(current org-agenda-filter-tags)
char a tag tags)
(unless char
(message
"%s by tag [%s ], [TAB], [/]:off, [+-]:narrow, [>=<]:effort: "
(if narrow "Narrow" "Filter") tag-chars)
(setq char (read-char)))
(when (member char '(?+ ?-))
;; Narrowing down
(cond ((equal char ?-) (setq strip t narrow t))
((equal char ?+) (setq strip nil narrow t)))
(message
"Narrow by tag [%s ], [TAB], [/]:off, [>=<]:effort: " tag-chars)
(setq char (read-char)))
(when (member char '(?< ?> ?=))
;; An effort operator
(setq effort-op (char-to-string char))
(loop for i from 0 to 9 do
(setq effort-prompt
(concat
effort-prompt " ["
(if (= i 9) "0" (int-to-string (1+ i)))
"]" (nth i efforts))))
(setq alist nil) ; to make sure it will be interpreted as effort.
(message "Effort%s: %s " effort-op effort-prompt)
(setq char (read-char))
(when (equal char ?\t)
(unless (local-variable-p 'org-global-tags-completion-table (current-buffer))
(org-set-local 'org-global-tags-completion-table
(org-global-tags-completion-table)))
(let ((completion-ignore-case t))
(setq tag (completing-read
"Tag: " org-global-tags-completion-table))))
(cond
((equal char ?/) (org-agenda-filter-by-tag-show-all))
((or (equal char ?\ )
(setq a (rassoc char org-tag-alist-for-agenda))
(and tag (setq a (cons tag nil))))
(org-agenda-filter-by-tag-show-all)
(setq tag (car a))
(save-excursion
(goto-char (point-min))
(while (not (eobp))
(if (get-text-property (point) 'org-marker)
(progn
(setq tags (get-text-property (point) 'tags))
(if (not tag)
(if (or (and strip (not tags))
(and (not strip) tags))
(org-agenda-filter-by-tag-hide-line))
(if (or (and (member tag tags) strip)
(and (not (member tag tags)) (not strip)))
(org-agenda-filter-by-tag-hide-line)))
(beginning-of-line 2))
(beginning-of-line 2)))))
(t (error "Invalid tag selection character %c" char)))))
(when (or (< char ?0) (> char ?9))
(error "Need 1-9,0 to select effort" )))
(when (equal char ?\t)
(unless (local-variable-p 'org-global-tags-completion-table (current-buffer))
(org-set-local 'org-global-tags-completion-table
(org-global-tags-completion-table)))
(let ((completion-ignore-case t))
(setq tag (completing-read
"Tag: " org-global-tags-completion-table))))
(cond
((equal char ?/) (org-agenda-filter-by-tag-show-all))
((or (equal char ?\ )
(setq a (rassoc char alist))
(and (>= char ?0) (<= char ?9)
(setq n (if (= char ?0) 9 (- char ?0 1))
tag (concat effort-op (nth n efforts))
a (cons tag nil)))
(and tag (setq a (cons tag nil))))
(org-agenda-filter-by-tag-show-all)
(setq tag (car a))
(setq org-agenda-filter-tags
(cons (concat (if strip "-" "+") tag)
(if narrow current nil)))
(setq org-agenda-filter-form (org-agenda-filter-make-matcher))
(org-agenda-set-mode-name)
(save-excursion
(goto-char (point-min))
(while (not (eobp))
(if (get-text-property (point) 'org-marker)
(progn
(setq tags (get-text-property (point) 'tags))
(if (not (eval org-agenda-filter-form))
(org-agenda-filter-by-tag-hide-line))
(beginning-of-line 2))
(beginning-of-line 2)))))
(t (error "Invalid tag selection character %c" char)))))
(defun org-agenda-filter-by-tag-refine (strip &optional char)
"Refine the current filter. See `org-agenda-filter-by-tag."
(interactive "P")
(org-agenda-filter-by-tag strip char 'refine))
(defun org-agenda-filter-make-matcher ()
(let (f f1)
(dolist (x org-agenda-filter-tags)
(if (member x '("-" "+"))
(setq f1 '(not tags))
(if (string-match "[<=>]" x)
(setq f1 (org-agenda-filter-effort-form x))
(setq f1 (list 'member (substring x 1) 'tags)))
(if (equal (string-to-char x) ?-)
(setq f1 (list 'not f1))))
(push f1 f))
(cons 'and (nreverse f))))
(defun org-agenda-filter-effort-form (e)
"Return the form to compare the effort of the current line with what E says.
E looks line \"+<2:25\"."
(let (op)
(setq e (substring e 1))
(setq op (string-to-char e) e (substring e 1))
(setq op (if (equal op ?<) '<= (if (equal op ?>) '>= '=)))
(list 'org-agenda-compare-effort (list 'quote op)
(org-hh:mm-string-to-minutes e))))
(defun org-agenda-compare-effort (op value)
(let ((eff (get-text-property 'effort-minutes)))
(if (not eff)
nil ; we don't have an effort defined
(funcall op eff value))))
(defvar org-agenda-filter-overlays nil)
@ -4183,7 +4270,10 @@ With prefix argument STRIP, remove all lines that do have the tag."
(defun org-agenda-filter-by-tag-show-all ()
(mapc 'org-delete-overlay org-agenda-filter-overlays)
(setq org-agenda-filter-overlays nil))
(setq org-agenda-filter-overlays nil)
(setq org-agenda-filter-tags nil)
(setq org-agenda-filter-form nil)
(org-agenda-set-mode-name))
(defun org-agenda-manipulate-query-add ()
"Manipulate the query by adding a search term with positive selection.
@ -4522,6 +4612,9 @@ so that the date SD will be in that range."
(if org-agenda-include-diary " Diary" "")
(if org-agenda-use-time-grid " Grid" "")
(if org-agenda-show-log " Log" "")
(if org-agenda-filter-tags
(concat " {" (mapconcat 'identity org-agenda-filter-tags "") "}")
"")
(if org-agenda-archives-mode
(if (eq org-agenda-archives-mode t)
" Archives"