1
0
mirror of https://git.savannah.gnu.org/git/emacs/org-mode.git synced 2024-12-28 10:56:57 +00:00

Implement context filtering for agenda commands and capture templates.

* org.el (org-contextualize-agenda-or-capture)
(org-rule-validate): New functions, implement context
filtering for agenda commands and capture templates.

* org-agenda.el (org-agenda-custom-commands-contexts): New
option.
(org-agenda): Use it.

* org-capture.el (org-capture-templates-contexts): New option.
(org-capture-select-template): Use it.

* org.texi (Templates in contexts): Document the new option
`org-capture-templates-contexts'.
(Storing searches): Document the new option
`org-agenda-custom-commands-contexts'.

This idea comes from Sylvain Rousseau, who implemented a similar
feature with org-context.el: https://github.com/thisirs/org-context

This implementation is a bit simpler and more general.  Simpler
because it relies on existing templates, no need to define other
contextual ones.  More general because contexts can be defined
wrt files and modes.

Thanks *very much* to Sylvain for paving the way -- certainly a
great addition to Org.
This commit is contained in:
Bastien Guerry 2012-08-23 11:08:47 +02:00
parent 6dedecf806
commit d378c7b41b
4 changed files with 131 additions and 7 deletions

View File

@ -1,4 +1,3 @@
\input texinfo
@c %**start of header
@setfilename ../../info/org
@ -494,6 +493,7 @@ Capture templates
* Template elements:: What is needed for a complete template entry
* Template expansion:: Filling in information about time and context
* Templates in contexts:: Only show a template in a specific context
Archiving
@ -6631,6 +6631,7 @@ like this:
@menu
* Template elements:: What is needed for a complete template entry
* Template expansion:: Filling in information about time and context
* Templates in contexts:: Only show a template in a specific context
@end menu
@node Template elements, Template expansion, Capture templates, Capture templates
@ -6774,7 +6775,7 @@ buffer again after capture is completed.
@end table
@end table
@node Template expansion, , Template elements, Capture templates
@node Template expansion, Templates in contexts, Template elements, Capture templates
@subsubsection Template expansion
In the template itself, special @kbd{%}-escapes@footnote{If you need one of
@ -6852,6 +6853,20 @@ To place the cursor after template expansion use:
%? @r{After completing the template, position cursor here.}
@end smallexample
@node Templates in contexts, , Template expansion, Capture templates
@subsubsection Templates in contexts
@vindex org-capture-templates-contexts
To control whether a capture template should be accessible from a specific
context, you can customize @var{org-capture-templates-contexts}. Let's say
for example that you have a capture template @code{"p"} for storing Gnus
emails containing patches. Then you would configure this option like this:
@example
(setq org-capture-templates-contexts '(("p" (in-mode . "message-mode"))))
@end example
See the docstring of the variable for more information.
@node Attachments, RSS Feeds, Capture, Capture - Refile - Archive
@section Attachments
@ -8590,11 +8605,12 @@ buffer, or a sparse tree (the latter covering of course only the current
buffer).
@kindex C-c a C
@vindex org-agenda-custom-commands
Custom commands are configured in the variable
@code{org-agenda-custom-commands}. You can customize this variable, for
example by pressing @kbd{C-c a C}. You can also directly set it with
Emacs Lisp in @file{.emacs}. The following example contains all valid
search types:
example by pressing @kbd{C-c a C}. You can also directly set it with Emacs
Lisp in @file{.emacs}. The following example contains all valid search
types:
@lisp
@group
@ -8754,6 +8770,18 @@ this interface, the @emph{values} are just Lisp expressions. So if the
value is a string, you need to add the double-quotes around the value
yourself.
@vindex org-agenda-custom-commands-contexts
To control whether an agenda command should be accessible from a specific
context, you can customize @var{org-agenda-custom-commands-contexts}. Let's
say for example that you have an agenda commands @code{"o"} displaying a view
that you only need when reading emails. Then you would configure this option
like this:
@example
(setq org-agenda-custom-commands-contexts '(("o" (in-mode . "message-mode"))))
@end example
See the docstring of the variable for more information.
@node Exporting Agenda Views, Agenda column view, Custom agenda views, Agenda Views
@section Exporting Agenda Views
@ -16819,7 +16847,6 @@ work on a tty.
@item
@i{Piotr Zielinski} wrote @file{org-mouse.el}, proposed agenda blocks
and contributed various ideas and code snippets.
@item
@end itemize

View File

@ -2334,6 +2334,37 @@ that have been changed along."
(defvar org-agenda-last-dispatch-buffer nil)
(defvar org-agenda-overriding-restriction nil)
(defcustom org-agenda-custom-commands-contexts nil
"Alist of custom agenda commands and valid contexts.
For example, if you have a custom agenda command \"p\" and you
want this command to be accessible only from plain text files,
use this:
'((\"p\" (in-file . \"\\.txt\")))
Here are the available checks:
in-file: command displayed only in matching files
in-mode: command displayed only in matching modes
not-in-file: command not displayed in matching files
not-in-mode: command not displayed in matching modes
If you define several checks, the agenda command will be
accessible if there is at least one valid check."
;; :version "24.3"
:group 'org-agenda-custom-commands
:type '(repeat (cons :tag "Rule"
(string :tag "Agenda key")
(repeat :tag "Available when"
(cons :tag "Condition"
(choice
(const :tag "In file" in-file)
(const :tag "Not in file" not-in-file)
(const :tag "In mode" in-mode)
(const :tag "Not in mode" not-in-mode))
(regexp))))))
;;;###autoload
(defun org-agenda (&optional arg keys restriction)
"Dispatch agenda commands to collect entries to the agenda buffer.
@ -2389,6 +2420,9 @@ Pressing `<' twice means to restrict to the current subtree or region
((not (nth 1 x)) (cons (car x) (cons "" (cddr x))))
(t (cons (car x) (cons "" (cdr x))))))
org-agenda-custom-commands)))
(org-agenda-custom-commands
(org-contextualize-agenda-or-capture
org-agenda-custom-commands org-agenda-custom-commands-contexts))
(buf (current-buffer))
(bfn (buffer-file-name (buffer-base-buffer)))
entry key type match lprops ans)

View File

@ -438,6 +438,37 @@ for a capture buffer.")
(entry (org-capture-select-template keys)))
(org-capture)))
(defcustom org-capture-templates-contexts nil
"Bind capture keys with rules on where to display them.
For example, if you have a capture template \"c\" and you want
this template to be accessible only from message-mode buffers,
use this:
'((\"c\" (in-mode . \"message-mode\")))
Here are the available checks:
in-file: template displayed only in matching files
in-mode: template displayed only in matching modes
not-in-file: template not displayed in matching files
not-in-mode: template not displayed in matching modes
If you define several checks, the capture template will be
accessible if there is at least one valid check."
;; :version "24.3"
:group 'org-capture
:type '(repeat (cons :tag "Rule"
(string :tag "Capture key")
(repeat :tag "Available when"
(cons :tag "Condition"
(choice
(const :tag "In file" in-file)
(const :tag "Not in file" not-in-file)
(const :tag "In mode" in-mode)
(const :tag "Not in mode" not-in-mode))
(regexp))))))
;;;###autoload
(defun org-capture (&optional goto keys)
"Capture something.
@ -1282,7 +1313,8 @@ Use PREFIX as a prefix for the name of the indirect buffer."
"Select a capture template.
Lisp programs can force the template by setting KEYS to a string."
(let ((org-capture-templates
(or org-capture-templates
(or (org-contextualize-agenda-or-capture
org-capture-templates org-capture-templates-contexts)
'(("t" "Task" entry (file+headline "" "Tasks")
"* TODO %?\n %u\n %a")))))
(if keys

View File

@ -8619,6 +8619,37 @@ to execute outside of tables."
keys)
'('orgstruct-error))))))))
(defun org-contextualize-agenda-or-capture (alist contexts)
"Return a subset of elements in ALIST depending on CONTEXTS.
ALIST can be either `org-agenda-custom-commands' or
`org-capture-templates'."
(let ((a alist) c r)
(while (setq c (pop a))
(when (or (not (assoc (car c) contexts))
(and (assoc (car c) contexts)
(org-rule-validate
(cdr (assoc (car c) contexts)))))
(push c r)))
;; Return the limited ALIST
r))
(defun org-rule-validate (rules)
"Check if one of RULES is valid in this buffer."
(let (r res)
(while (setq r (pop rules))
(when (or (and (eq (car r) 'in-file)
(buffer-file-name)
(string-match (cdr r) (buffer-file-name)))
(and (eq (car r) 'in-mode)
(string-match (cdr r) (symbol-name major-mode)))
(when (and (eq (car r) 'not-in-file)
(buffer-file-name))
(not (string-match (cdr r) (buffer-file-name))))
(when (eq (car r) 'not-in-mode)
(not (string-match (cdr r) (symbol-name major-mode)))))
(push r res)))
(delq nil res)))
(defun org-context-p (&rest contexts)
"Check if local context is any of CONTEXTS.
Possible values in the list of contexts are `table', `headline', and `item'."