Merge branch 'make-new-filter-interface-the-default'

This commit is contained in:
Carsten Dominik 2019-09-03 15:50:34 +02:00
commit 9962df2b48
2 changed files with 177 additions and 131 deletions

View File

@ -9030,13 +9030,24 @@ the estimated effort of an entry (see [[*Effort Estimates]]).
:DESCRIPTION: Dynamically narrow the agenda. :DESCRIPTION: Dynamically narrow the agenda.
:END: :END:
#+vindex: org-agenda-category-filter-preset
#+vindex: org-agenda-tag-filter-preset
#+vindex: org-agenda-effort-filter-preset
#+vindex: org-agenda-regexp-filter-preset
Agenda built-in or customized commands are statically defined. Agenda Agenda built-in or customized commands are statically defined. Agenda
filters and limits provide two ways of dynamically narrowing down the filters and limits provide two ways of narrowing down the list of
list of agenda entries: /filters/ and /limits/. Filters only act on agenda entries.
the display of the items, while limits take effect before the list of
agenda entries is built. Filters are more often used interactively, Filters only change the visibility of items, are very fast and are
while limits are mostly useful when defined as local variables within mostly used interactively[fn:96]. You can switch quickly between
custom agenda commands. different filters without having to recreate the agenda. If creating
the agenda seems slow, one solution would be to create a view that
contains everything you might want to work on for a while, and then
use filtering to drill down.
Limits on the other hand take effect before the agenda buffer is
populated, so they are mostly useful when defined as local variables
within custom agenda commands.
**** Filtering in the agenda **** Filtering in the agenda
:PROPERTIES: :PROPERTIES:
@ -9050,64 +9061,34 @@ custom agenda commands.
#+cindex: effort filtering, in agenda #+cindex: effort filtering, in agenda
#+cindex: query editing, in agenda #+cindex: query editing, in agenda
- {{{kbd(/)}}} (~org-agenda-filter-by-tag~) :: The general filtering command that gives access to the full
functionality is ~org-agenda-filter~, bound to {{{kbd(/)}}}. But
before we introduce it, we first describe commands for individual
filter types.
- {{{kbd(\)}}} (~org-agenda-filter-by-tag~) ::
#+findex: org-agenda-filter-by-tag #+findex: org-agenda-filter-by-tag
#+vindex: org-agenda-tag-filter-preset Filter the agenda view with respect to a tag. You are prompted for
Filter the agenda view with respect to a tag and/or effort a tag selection letter; {{{kbd(SPC)}}} means any tag at all.
estimates. The difference between this and a custom agenda command Pressing {{{kbd(TAB)}}} at that prompt offers completion to select a
is that filtering is very fast, so that you can switch quickly tag, including any tags that do not have a selection character. The
between different filters without having to recreate the command then hides all entries that do not contain or inherit this
agenda.[fn:96] tag. Call the command repeatedly to add several tags to the
filter. When called with prefix argument, remove the entries that
/do/ have the tag. Pressing {{{kbd(+)}}} or {{{kbd(-)}}} at the
prompt also switches between filtering for and against the next tag.
{{{kbd(\)}}} at the prompt turns off the filter and shows any hidden
entries.
You are prompted for a tag selection letter; {{{kbd(SPC)}}} means
any tag at all. Pressing {{{kbd(TAB)}}} at that prompt offers
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 argument,
remove the entries that /do/ have the tag. A second {{{kbd(/)}}} at
the prompt turns off the filter and shows any hidden entries.
Pressing {{{kbd(+)}}} or {{{kbd(-)}}} switches between filtering and
excluding the next tag.
#+vindex: org-agenda-auto-exclude-function
Org also supports automatic, context-aware tag filtering. If the
variable ~org-agenda-auto-exclude-function~ is set to a user-defined
function, that function can decide which tags should be excluded
from the agenda automatically. Once this is set, the {{{kbd(/)}}}
command then accepts {{{kbd(RET)}}} as a sub-option key and runs the
auto exclusion logic. For example, let's say you use a =Net= tag to
identify tasks which need network access, an =Errand= tag for
errands in town, and a =Call= tag for making phone calls. You could
auto-exclude these tags based on the availability of the Internet,
and outside of business hours, with something like this:
#+begin_src emacs-lisp
(defun org-my-auto-exclude-function (tag)
(and (cond
((string= tag "Net")
(/= 0 (call-process "/sbin/ping" nil nil nil
"-c1" "-q" "-t1" "mail.gnu.org")))
((or (string= tag "Errand") (string= tag "Call"))
(let ((hour (nth 2 (decode-time))))
(or (< hour 8) (> hour 21)))))
(concat "-" tag)))
(setq org-agenda-auto-exclude-function 'org-my-auto-exclude-function)
#+end_src
- {{{kbd(<)}}} (~org-agenda-filter-by-category~) :: - {{{kbd(<)}}} (~org-agenda-filter-by-category~) ::
#+findex: org-agenda-filter-by-category #+findex: org-agenda-filter-by-category
Filter the current agenda view with respect to the category of the Filter by category of the line at point, and show only entries with
item at point. Pressing {{{kbd(<)}}} another time removes this this category. Pressing {{{kbd(<)}}} again removes this filter.
filter. When called with a prefix argument exclude the category of When called with a prefix argument exclude the category of the item
the item at point from the agenda. at point from the agenda.
#+vindex: org-agenda-category-filter-preset
You can add a filter preset in custom agenda commands through the
option ~org-agenda-category-filter-preset~. See [[*Setting options
for custom commands]].
- {{{kbd(=)}}} (~org-agenda-filter-by-regexp~) :: - {{{kbd(=)}}} (~org-agenda-filter-by-regexp~) ::
@ -9117,12 +9098,7 @@ custom agenda commands.
called with a prefix argument, it filters /out/ entries matching the called with a prefix argument, it filters /out/ entries matching the
regexp. Called in a regexp-filtered agenda view, remove the filter, regexp. Called in a regexp-filtered agenda view, remove the filter,
unless there are two universal prefix arguments, in which case unless there are two universal prefix arguments, in which case
filters are cumulated. filters are accumulated.
#+vindex: org-agenda-regexp-filter-preset
You can add a filter preset in custom agenda commands through the
option ~org-agenda-regexp-filter-preset~. See [[*Setting options
for custom commands]].
- {{{kbd(_)}}} (~org-agenda-filter-by-effort~) :: - {{{kbd(_)}}} (~org-agenda-filter-by-effort~) ::
@ -9149,21 +9125,23 @@ custom agenda commands.
condition. With two universal prefix arguments, it clears effort condition. With two universal prefix arguments, it clears effort
filters, which can be accumulated. filters, which can be accumulated.
#+vindex: org-agenda-effort-filter-preset - {{{kbd(^)}}} (~org-agenda-filter-by-top-headline~) ::
You can add a filter preset in custom agenda commands through the
option ~org-agenda-effort-filter-preset~. See [[*Setting options for
custom commands]].
- {{{kbd(\)}}} (~org-agenda-filter~) :: #+findex: org-agenda-filter-by-top-headline
Filter the current agenda view and only display items that fall
under the same top-level headline as the current entry. So this
simulated the effect of restricting the agenda creation to this
tree.
- {{{kbd(/)}}} (~org-agenda-filter~) ::
#+findex: org-agenda-filter #+findex: org-agenda-filter
This is an alternative interface to all four filter methods This a the unified interface to four of the five filter methods
described above. At the prompt, one would specify different filter described above. At the prompt, specify different filter elements
elements in a single string, with full completion support. For in a single string, with full completion support. For example,
example,
#+begin_example #+begin_example
+work-John<0:10-/plot/ +work-John+<0:10-/plot/
#+end_example #+end_example
selects entries with category `work' and effort estimates below 10 selects entries with category `work' and effort estimates below 10
@ -9174,20 +9152,47 @@ custom agenda commands.
(tags will take priority). If you reply to the prompt with the (tags will take priority). If you reply to the prompt with the
empty string, all filtering is removed. If a filter is specified, empty string, all filtering is removed. If a filter is specified,
it replaces all current filters. But if you call the command with a it replaces all current filters. But if you call the command with a
prefix argument, or if you add an additional `+' (e.g. `+-John') to prefix argument, or if you add an additional `+' (e.g. `++work') to
the front of the string, the new filter elements are added to the the front of the string, the new filter elements are added to the
active ones. active ones.
- {{{kbd(^)}}} (~org-agenda-filter-by-top-headline~) ::
#+findex: org-agenda-filter-by-top-headline
Filter the current agenda view and only display items that fall
under the same top-level headline as the current entry.
- {{{kbd(|)}}} (~org-agenda-filter-remove-all~) :: - {{{kbd(|)}}} (~org-agenda-filter-remove-all~) ::
Remove all filters in the current agenda view. Remove all filters in the current agenda view.
**** Computed exclusion filtering
:PROPERTIES:
:UNNUMBERED: notoc
:END:
#+vindex: org-agenda-auto-exclude-function
If the variable ~org-agenda-auto-exclude-function~ is set to a
user-defined function, that function can select tags that should be
excluded from the agenda when requested. The function will be called
with lower-case versions of all tags. For example, let's say you use
a =Net= tag to identify tasks which need network access, an =Errand=
tag for errands in town, and a =Call= tag for making phone calls. You
could auto-exclude these tags based on the availability of the
Internet, and outside of business hours, with something like this:
#+begin_src emacs-lisp
(defun org-my-auto-exclude-fn (tag)
(and (cond
((string= tag "net")
(/= 0 (call-process "/sbin/ping" nil nil nil
"-c1" "-q" "-t1" "mail.gnu.org")))
((or (member tag '("errand" "call")))
(let ((hr (nth 2 (decode-time))))
(or (< hr 8) (> hr 21)))))
(concat "-" tag)))
(setq org-agenda-auto-exclude-function 'org-my-auto-exclude-fn)
#+end_src
You can apply this self-adapting filter by using a double prefix
argument to ~org-agenda-filter~, i.e. press {{{kbd(C-u C-u /)}}}, or
by pressing {{{kbd(RET)}}} in ~org-agenda-filter-by-tag~.
**** Setting limits for the agenda **** Setting limits for the agenda
:PROPERTIES: :PROPERTIES:
:UNNUMBERED: notoc :UNNUMBERED: notoc
@ -21407,12 +21412,15 @@ to ISO and therefore independent of the value of
[fn:95] You can, however, disable this by setting [fn:95] You can, however, disable this by setting
~org-agenda-search-headline-for-time~ variable to a ~nil~ value. ~org-agenda-search-headline-for-time~ variable to a ~nil~ value.
[fn:96] Custom commands can preset a filter by binding the variable [fn:96] Custom agenda commands can preset a filter by binding one of
~org-agenda-tag-filter-preset~ as an option. This filter is then the variables ~org-agenda-tag-filter-preset~,
applied to the view and persists as a basic filter through refreshes ~org-agenda-category-filter-preset~, ~org-agenda-effort-filter-preset~
and more secondary filtering. The filter is a global property of the or ~org-agenda-regexp-filter-preset~ as an option. This filter is
entire agenda view---in a block agenda, you should only set this in then applied to the view and persists as a basic filter through
the global options section, not in the section of an individual block. refreshes and more secondary filtering. The filter is a global
property of the entire agenda view---in a block agenda, you should
only set this in the global options section, not in the section of an
individual block.
[fn:97] Only tags filtering is respected here, effort filtering is [fn:97] Only tags filtering is respected here, effort filtering is
ignored. ignored.

View File

@ -2399,10 +2399,10 @@ The following commands are available:
(org-defkey org-agenda-mode-map "]" 'org-agenda-manipulate-query-subtract) (org-defkey org-agenda-mode-map "]" 'org-agenda-manipulate-query-subtract)
(org-defkey org-agenda-mode-map "{" 'org-agenda-manipulate-query-add-re) (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-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)
(org-defkey org-agenda-mode-map "_" 'org-agenda-filter-by-effort) (org-defkey org-agenda-mode-map "_" 'org-agenda-filter-by-effort)
(org-defkey org-agenda-mode-map "=" 'org-agenda-filter-by-regexp) (org-defkey org-agenda-mode-map "=" 'org-agenda-filter-by-regexp)
(org-defkey org-agenda-mode-map "\\" 'org-agenda-filter) (org-defkey org-agenda-mode-map "/" 'org-agenda-filter)
(org-defkey org-agenda-mode-map "|" 'org-agenda-filter-remove-all) (org-defkey org-agenda-mode-map "|" 'org-agenda-filter-remove-all)
(org-defkey org-agenda-mode-map "~" 'org-agenda-limit-interactively) (org-defkey org-agenda-mode-map "~" 'org-agenda-limit-interactively)
(org-defkey org-agenda-mode-map "<" 'org-agenda-filter-by-category) (org-defkey org-agenda-mode-map "<" 'org-agenda-filter-by-category)
@ -7464,6 +7464,25 @@ With a prefix argument, do so in all agenda buffers."
"Return the category of the agenda line." "Return the category of the agenda line."
(org-get-at-bol 'org-category)) (org-get-at-bol 'org-category))
(defun org-agenda-filter-by-category (strip)
"Filter lines in the agenda buffer that have a specific category.
The category is that of the current line.
Without prefix argument, keep only the lines of that category.
With a prefix argument, exclude the lines of that category."
(interactive "P")
(if (and org-agenda-filtered-by-category
org-agenda-category-filter)
(org-agenda-filter-show-all-cat)
(let ((cat (org-no-properties (org-get-at-eol 'org-category 1))))
(cond
((and cat strip)
(org-agenda-filter-apply
(push (concat "-" cat) org-agenda-category-filter) 'category))
(cat
(org-agenda-filter-apply
(setq org-agenda-category-filter
(list (concat "+" cat))) 'category))
(t (error "No category at point"))))))
(defun org-agenda-filter-by-category (strip) (defun org-agenda-filter-by-category (strip)
"Filter lines in the agenda buffer that have a specific category. "Filter lines in the agenda buffer that have a specific category.
@ -7613,48 +7632,67 @@ get priority.
Instead of using the prefix argument to add to the current filter Instead of using the prefix argument to add to the current filter
set, you can also add an additional leading `+' to filter string, set, you can also add an additional leading `+' to filter string,
like `+-John'." like `+-John'.
With a double prefix argument, execute the computed filtering defined in
the variable `org-agenda-auto-exclude-function'."
(interactive "P") (interactive "P")
(let* ((tag-list (org-agenda-get-represented-tags)) (if (equal keep '(16))
(category-list (org-agenda-get-represented-categories)) ;; Execute the auto-exclude action
(f-string (completing-read "Filter [+cat-tag<0:10-/regexp/]: " 'org-agenda-filter-completion-function)) (if (not org-agenda-auto-exclude-function)
(keep (or (if (string-match "^+[-+]" f-string) (user-error "`org-agenda-auto-exclude-function' is undefined")
(progn (setq f-string (substring f-string 1)) t)) (org-agenda-filter-show-all-tag)
keep)) (setq org-agenda-tag-filter nil)
(fc (if keep org-agenda-category-filter)) (dolist (tag (org-agenda-get-represented-tags))
(ft (if keep org-agenda-tag-filter)) (let ((modifier (funcall org-agenda-auto-exclude-function tag)))
(fe (if keep org-agenda-effort-filter)) (when modifier
(fr (if keep org-agenda-regexp-filter)) (push modifier org-agenda-tag-filter))))
log s) (unless (null org-agenda-tag-filter)
(while (string-match "^[ \t]*\\([-+]\\)?\\(\\([^-+<>=/ \t]+\\)\\|\\([<>=][0-9:]+\\)\\|\\(/\\([^/]+\\)/?\\)\\)" (org-agenda-filter-apply org-agenda-tag-filter 'tag expand)))
f-string) ;; Prompt for a filter and act
(setq log (if (match-beginning 1) (match-string 1 f-string) "+")) (let* ((tag-list (org-agenda-get-represented-tags))
(cond (category-list (org-agenda-get-represented-categories))
((match-beginning 3) (f-string (completing-read "Filter [+cat-tag<0:10-/regexp/]: "
;; category or tag 'org-agenda-filter-completion-function))
(setq s (match-string 3 f-string)) (keep (or (if (string-match "^+[-+]" f-string)
(cond ((member s tag-list) (progn (setq f-string (substring f-string 1)) t))
(add-to-list 'ft (concat log s) 'append 'equal)) keep))
((member s category-list) (fc (if keep org-agenda-category-filter))
(add-to-list 'fc (concat log s) 'append 'equal)) (ft (if keep org-agenda-tag-filter))
(t (message "`%s%s' filter ignored because it is not represented as tag or category" log s)))) (fe (if keep org-agenda-effort-filter))
((match-beginning 4) (fr (if keep org-agenda-regexp-filter))
;; effort pm s)
(add-to-list 'fe (concat log (match-string 4 f-string)) 'append 'equal)) (while (string-match "^[ \t]*\\([-+]\\)?\\(\\([^-+<>=/ \t]+\\)\\|\\([<>=][0-9:]+\\)\\|\\(/\\([^/]+\\)/?\\)\\)" f-string)
((match-beginning 5) (setq pm (if (match-beginning 1) (match-string 1 f-string) "+"))
;; regexp (cond
(add-to-list 'fr (concat log (match-string 6 f-string)) 'append 'equal))) ((match-beginning 3)
(setq f-string (substring f-string (match-end 0)))) ;; category or tag
(org-agenda-filter-remove-all) (setq s (match-string 3 f-string))
(and fc (org-agenda-filter-apply (cond
(setq org-agenda-category-filter fc) 'category)) ((member s tag-list)
(and ft (org-agenda-filter-apply (add-to-list 'ft (concat pm s) 'append 'equal))
(setq org-agenda-tag-filter ft) 'tag)) ((member s category-list)
(and fe (org-agenda-filter-apply (add-to-list 'fc (concat pm s) 'append 'equal))
(setq org-agenda-effort-filter fe) 'effort)) (t (message
(and fr (org-agenda-filter-apply "`%s%s' filter ignored tag/category is not represented"
(setq org-agenda-regexp-filter fr) 'regexp)) pm s))))
)) ((match-beginning 4)
;; effort
(add-to-list 'fe (concat pm (match-string 4 f-string)) t 'equal))
((match-beginning 5)
;; regexp
(add-to-list 'fr (concat pm (match-string 6 f-string)) t 'equal)))
(setq f-string (substring f-string (match-end 0))))
(org-agenda-filter-remove-all)
(and fc (org-agenda-filter-apply
(setq org-agenda-category-filter fc) 'category))
(and ft (org-agenda-filter-apply
(setq org-agenda-tag-filter ft) 'tag))
(and fe (org-agenda-filter-apply
(setq org-agenda-effort-filter fe) 'effort))
(and fr (org-agenda-filter-apply
(setq org-agenda-regexp-filter fr) 'regexp))
)))
(defun org-agenda-filter-completion-function (string _predicate &optional flag) (defun org-agenda-filter-completion-function (string _predicate &optional flag)
"Complete a complex filter string "Complete a complex filter string
@ -7732,7 +7770,7 @@ also press `-' or `+' to switch between filtering and excluding."
(char-to-string (cdr x))) (char-to-string (cdr x)))
"")) ""))
org-tag-alist-for-agenda "")) org-tag-alist-for-agenda ""))
(valid-char-list (append '(?\t ?\r ?/ ?. ?\s ?q) (valid-char-list (append '(?\t ?\r ?\\ ?. ?\s ?q)
(string-to-list tag-chars))) (string-to-list tag-chars)))
(exclude (or exclude (equal arg '(4)))) (exclude (or exclude (equal arg '(4))))
(expand (not (equal arg '(16)))) (expand (not (equal arg '(16))))