|
@@ -7468,8 +7468,8 @@ With a prefix argument, do so in all agenda buffers."
|
|
|
(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."
|
|
|
+With a `\\[universal-argument]' prefix argument, exclude the lines of that category.
|
|
|
+When there is already a category filter in place, this command removes the filter."
|
|
|
(interactive "P")
|
|
|
(if (and org-agenda-filtered-by-category
|
|
|
org-agenda-category-filter)
|
|
@@ -7499,7 +7499,8 @@ search from."
|
|
|
(defvar org-agenda-filtered-by-top-headline nil)
|
|
|
(defun org-agenda-filter-by-top-headline (strip)
|
|
|
"Keep only those lines that are descendants from the same top headline.
|
|
|
-The top headline is that of the current line."
|
|
|
+The top headline is that of the current line. With prefix arg STRIP, hide
|
|
|
+all lines of the category at point."
|
|
|
(interactive "P")
|
|
|
(if org-agenda-filtered-by-top-headline
|
|
|
(progn
|
|
@@ -7511,77 +7512,85 @@ The top headline is that of the current line."
|
|
|
(error "No top-level headline at point")))))
|
|
|
|
|
|
(defvar org-agenda-regexp-filter nil)
|
|
|
-(defun org-agenda-filter-by-regexp (strip)
|
|
|
- "Filter agenda entries by regular expressions.
|
|
|
-
|
|
|
-With one prefix argument, filter out entries matching the regexp.
|
|
|
-If there is already a regexp filter, remove it unless called with
|
|
|
-two prefix arguments."
|
|
|
+(defun org-agenda-filter-by-regexp (strip-or-accumulate)
|
|
|
+ "Filter agenda entries by a regular expressions.
|
|
|
+You will be prompted for the regular expresssion, and the agenda
|
|
|
+view will only show entires that are matched by that expression.
|
|
|
+
|
|
|
+With one `\\[universal-argument]' prefix argument, hide entries matching the regexp.
|
|
|
+When there is already a regexp filter active, this command removed the
|
|
|
+filter. However, with two `\\[universal-argument]' prefix arguments, add a new condition to
|
|
|
+an already existing regexp filter."
|
|
|
(interactive "P")
|
|
|
- (cond
|
|
|
- ((and org-agenda-regexp-filter (not (equal strip '(16))))
|
|
|
- (org-agenda-filter-show-all-re)
|
|
|
- (message "Regexp filter removed"))
|
|
|
- (t (let ((flt (concat (if (equal strip '(4)) "-" "+")
|
|
|
- (read-from-minibuffer
|
|
|
- (if (equal strip '(4))
|
|
|
- "Filter out entries matching regexp: "
|
|
|
- "Narrow to entries matching regexp: ")))))
|
|
|
- (push flt org-agenda-regexp-filter)
|
|
|
- (org-agenda-filter-apply org-agenda-regexp-filter 'regexp)))))
|
|
|
-
|
|
|
+ (let* ((strip (equal strip-or-accumulate '(4)))
|
|
|
+ (accumulate (equal strip-or-accumulate '(16))))
|
|
|
+ (cond
|
|
|
+ ((and org-agenda-regexp-filter (not accumulate))
|
|
|
+ (org-agenda-filter-show-all-re)
|
|
|
+ (message "Regexp filter removed"))
|
|
|
+ (t (let ((flt (concat (if strip "-" "+")
|
|
|
+ (read-from-minibuffer
|
|
|
+ (if strip
|
|
|
+ "Hide entries matching regexp: "
|
|
|
+ "Narrow to entries matching regexp: ")))))
|
|
|
+ (push flt org-agenda-regexp-filter)
|
|
|
+ (org-agenda-filter-apply org-agenda-regexp-filter 'regexp))))))
|
|
|
+
|
|
|
(defvar org-agenda-effort-filter nil)
|
|
|
-(defun org-agenda-filter-by-effort (strip)
|
|
|
+(defun org-agenda-filter-by-effort (strip-or-accumulate)
|
|
|
"Filter agenda entries by effort.
|
|
|
-With no prefix argument, keep entries matching the effort condition.
|
|
|
-With one prefix argument, filter out entries matching the condition.
|
|
|
-With two prefix arguments, remove the effort filters."
|
|
|
+With no `\\[universal-argument]' prefix argument, keep entries matching the effort condition.
|
|
|
+With one `\\[universal-argument]' prefix argument, filter out entries matching the condition.
|
|
|
+With two `\\[universal-argument]' prefix arguments, add a second condition to the existing filter.
|
|
|
+This last option is in practice not very useful, but it is available for
|
|
|
+consistency with the other filter commands."
|
|
|
(interactive "P")
|
|
|
- (cond
|
|
|
- ((member strip '(nil 4))
|
|
|
- (let* ((efforts (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")))
|
|
|
- ;; XXX: the following handles only up to 10 different
|
|
|
- ;; effort values.
|
|
|
- (allowed-keys (if (null efforts) nil
|
|
|
- (mapcar (lambda (n) (mod n 10)) ;turn 10 into 0
|
|
|
- (number-sequence 1 (length efforts)))))
|
|
|
- (op nil))
|
|
|
- (while (not (memq op '(?< ?> ?= ?_)))
|
|
|
- (setq op (read-char-exclusive "Effort operator? (> = or <) or press `_' again to remove filter")))
|
|
|
- ;; Select appropriate duration. Ignore non-digit characters.
|
|
|
- (if (eq op ?_)
|
|
|
- (progn
|
|
|
- (org-agenda-filter-show-all-effort)
|
|
|
- (message "Effort filter removed"))
|
|
|
- (let ((prompt
|
|
|
- (apply #'format
|
|
|
- (concat "Effort %c "
|
|
|
- (mapconcat (lambda (s) (concat "[%d]" s))
|
|
|
- efforts
|
|
|
- " "))
|
|
|
- op allowed-keys))
|
|
|
- (eff -1))
|
|
|
- (while (not (memq eff allowed-keys))
|
|
|
- (message prompt)
|
|
|
- (setq eff (- (read-char-exclusive) 48)))
|
|
|
- (setq org-agenda-effort-filter
|
|
|
- (list (concat (if strip "-" "+")
|
|
|
- (char-to-string op)
|
|
|
- ;; Numbering is 1 2 3 ... 9 0, but we want
|
|
|
- ;; 0 1 2 ... 8 9.
|
|
|
- (nth (mod (1- eff) 10) efforts)))))
|
|
|
- (org-agenda-filter-apply org-agenda-effort-filter 'effort))))
|
|
|
- (t (org-agenda-filter-show-all-effort)
|
|
|
- (message "Effort filter removed"))))
|
|
|
-
|
|
|
-
|
|
|
-(defun org-agenda-filter (&optional keep)
|
|
|
+ (let* ((efforts (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")))
|
|
|
+ ;; XXX: the following handles only up to 10 different
|
|
|
+ ;; effort values.
|
|
|
+ (allowed-keys (if (null efforts) nil
|
|
|
+ (mapcar (lambda (n) (mod n 10)) ;turn 10 into 0
|
|
|
+ (number-sequence 1 (length efforts)))))
|
|
|
+ (keep (equal strip-or-accumulate '(16)))
|
|
|
+ (negative (equal strip-or-accumulate '(4)))
|
|
|
+ (current org-agenda-effort-filter)
|
|
|
+ (op nil))
|
|
|
+ (while (not (memq op '(?< ?> ?= ?_)))
|
|
|
+ (setq op (read-char-exclusive
|
|
|
+ "Effort operator? (> = or <) or press `_' again to remove filter")))
|
|
|
+ ;; Select appropriate duration. Ignore non-digit characters.
|
|
|
+ (if (eq op ?_)
|
|
|
+ (progn
|
|
|
+ (org-agenda-filter-show-all-effort)
|
|
|
+ (message "Effort filter removed"))
|
|
|
+ (let ((prompt
|
|
|
+ (apply #'format
|
|
|
+ (concat "Effort %c "
|
|
|
+ (mapconcat (lambda (s) (concat "[%d]" s))
|
|
|
+ efforts
|
|
|
+ " "))
|
|
|
+ op allowed-keys))
|
|
|
+ (eff -1))
|
|
|
+ (while (not (memq eff allowed-keys))
|
|
|
+ (message prompt)
|
|
|
+ (setq eff (- (read-char-exclusive) 48)))
|
|
|
+ (org-agenda-filter-show-all-effort)
|
|
|
+ (setq org-agenda-effort-filter
|
|
|
+ (append
|
|
|
+ (list (concat (if negative "-" "+")
|
|
|
+ (char-to-string op)
|
|
|
+ ;; Numbering is 1 2 3 ... 9 0, but we want
|
|
|
+ ;; 0 1 2 ... 8 9.
|
|
|
+ (nth (mod (1- eff) 10) efforts)))
|
|
|
+ (if keep current nil)))
|
|
|
+ (org-agenda-filter-apply org-agenda-effort-filter 'effort)))))
|
|
|
+
|
|
|
+
|
|
|
+(defun org-agenda-filter (&optional strip-or-accumulate)
|
|
|
"Prompt for a general filter string and apply it to the agenda.
|
|
|
-The new filter replaces all existing elements. When called with a
|
|
|
-prefix arg KEEP, add the new elements to the existing filter.
|
|
|
|
|
|
The string may contain filter elements like
|
|
|
|
|
@@ -7604,14 +7613,17 @@ values is offered. Since the syntax for categories and tags is identical
|
|
|
there should be no overlap between categoroes and tags. If there is, tags
|
|
|
get priority.
|
|
|
|
|
|
-Instead of using the prefix argument to add to the current filter
|
|
|
-set, you can also add an additional leading `+' to filter string,
|
|
|
-like `+-John'.
|
|
|
+A single `\\[universal-argument]' prefix arg STRIP-OR-ACCUMULATE will negate the
|
|
|
+entire filter, which can be useful in connection with the prompt history.
|
|
|
|
|
|
-With a double prefix argument, execute the computed filtering defined in
|
|
|
+A double `\\[universal-argument] \\[universal-argument]' prefix arg will add the new filter elements to the
|
|
|
+existing ones. A shortcut for this is to add an additional `+' at the
|
|
|
+beginning of the string, like `+-John'.
|
|
|
+
|
|
|
+With a triple prefix argument, execute the computed filtering defined in
|
|
|
the variable `org-agenda-auto-exclude-function'."
|
|
|
(interactive "P")
|
|
|
- (if (equal keep '(16))
|
|
|
+ (if (equal strip-or-accumulate '(64))
|
|
|
;; Execute the auto-exclude action
|
|
|
(if (not org-agenda-auto-exclude-function)
|
|
|
(user-error "`org-agenda-auto-exclude-function' is undefined")
|
|
@@ -7626,11 +7638,15 @@ the variable `org-agenda-auto-exclude-function'."
|
|
|
;; Prompt for a filter and act
|
|
|
(let* ((tag-list (org-agenda-get-represented-tags))
|
|
|
(category-list (org-agenda-get-represented-categories))
|
|
|
- (f-string (completing-read "Filter [+cat-tag<0:10-/regexp/]: "
|
|
|
- 'org-agenda-filter-completion-function))
|
|
|
+ (negate (equal strip-or-accumulate '(4)))
|
|
|
+ (f-string (completing-read
|
|
|
+ (concat
|
|
|
+ (if negate "Negative filter" "Filter")
|
|
|
+ " [+cat-tag<0:10-/regexp/]: ")
|
|
|
+ 'org-agenda-filter-completion-function))
|
|
|
(keep (or (if (string-match "^+[-+]" f-string)
|
|
|
(progn (setq f-string (substring f-string 1)) t))
|
|
|
- keep))
|
|
|
+ (equal strip-or-accumulate '(16))))
|
|
|
(fc (if keep org-agenda-category-filter))
|
|
|
(ft (if keep org-agenda-tag-filter))
|
|
|
(fe (if keep org-agenda-effort-filter))
|
|
@@ -7638,6 +7654,8 @@ the variable `org-agenda-auto-exclude-function'."
|
|
|
pm s)
|
|
|
(while (string-match "^[ \t]*\\([-+]\\)?\\(\\([^-+<>=/ \t]+\\)\\|\\([<>=][0-9:]+\\)\\|\\(/\\([^/]+\\)/?\\)\\)" f-string)
|
|
|
(setq pm (if (match-beginning 1) (match-string 1 f-string) "+"))
|
|
|
+ (when negate
|
|
|
+ (setq pm (if (equal pm "+") "-" "+")))
|
|
|
(cond
|
|
|
((match-beginning 3)
|
|
|
;; category or tag
|
|
@@ -7648,7 +7666,7 @@ the variable `org-agenda-auto-exclude-function'."
|
|
|
((member s category-list)
|
|
|
(add-to-list 'fc (concat pm s) 'append 'equal))
|
|
|
(t (message
|
|
|
- "`%s%s' filter ignored tag/category is not represented"
|
|
|
+ "`%s%s' filter ignored because tag/category is not represented"
|
|
|
pm s))))
|
|
|
((match-beginning 4)
|
|
|
;; effort
|
|
@@ -7718,14 +7736,17 @@ which see."
|
|
|
(org-agenda-filter-show-all-effort))
|
|
|
(org-agenda-finalize))
|
|
|
|
|
|
-(defun org-agenda-filter-by-tag (arg &optional char exclude)
|
|
|
+(defun org-agenda-filter-by-tag (strip-or-accumulate &optional char exclude)
|
|
|
"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 a `\\[universal-argument]' prefix, exclude the agenda search.
|
|
|
+With a `\\[universal-argument]' prefix, apply the filter negatively, stripping all matches.
|
|
|
+
|
|
|
+With a `\\[universal-argument] \\[universal-argument]' prefix, add the new tag to the existing filter
|
|
|
+instead of replacing it.
|
|
|
|
|
|
-With a `\\[universal-argument] \\[universal-argument]' prefix, filter the literal tag, \
|
|
|
+With a `\\[universal-argument] \\[universal-argument] \\[universal-argument]' prefix, filter the literal tag, \
|
|
|
i.e. don't
|
|
|
filter on all its group members.
|
|
|
|
|
@@ -7746,8 +7767,9 @@ also press `-' or `+' to switch between filtering and excluding."
|
|
|
org-tag-alist-for-agenda ""))
|
|
|
(valid-char-list (append '(?\t ?\r ?\\ ?. ?\s ?q)
|
|
|
(string-to-list tag-chars)))
|
|
|
- (exclude (or exclude (equal arg '(4))))
|
|
|
- (expand (not (equal arg '(16))))
|
|
|
+ (exclude (or exclude (equal strip-or-accumulate '(4))))
|
|
|
+ (accumulate (equal strip-or-accumulate '(16)))
|
|
|
+ (expand (not (equal strip-or-accumulate '(64))))
|
|
|
(inhibit-read-only t)
|
|
|
(current org-agenda-tag-filter)
|
|
|
a n tag)
|
|
@@ -7764,7 +7786,7 @@ also press `-' or `+' to switch between filtering and excluding."
|
|
|
(cond ((eq char ?-) (setq exclude t))
|
|
|
((eq char ?+) (setq exclude nil)))))
|
|
|
(when (eq char ?\t)
|
|
|
- (unless (local-variable-p 'org-global-tags-completion-table (current-buffer))
|
|
|
+ (unless (local-variable-p 'org-global-tags-completion-table)
|
|
|
(setq-local org-global-tags-completion-table
|
|
|
(org-global-tags-completion-table)))
|
|
|
(let ((completion-ignore-case t))
|
|
@@ -7798,7 +7820,7 @@ also press `-' or `+' to switch between filtering and excluding."
|
|
|
(setq tag (car a))
|
|
|
(setq org-agenda-tag-filter
|
|
|
(cons (concat (if exclude "-" "+") tag)
|
|
|
- current))
|
|
|
+ (if accumulate current nil)))
|
|
|
(org-agenda-filter-apply org-agenda-tag-filter 'tag expand))
|
|
|
(t (error "Invalid tag selection character %c" char)))))
|
|
|
|
|
@@ -7890,7 +7912,7 @@ function to set the right switches in the returned form."
|
|
|
(dolist (x tags (cons (if (eq op ?-) 'and 'or) form))
|
|
|
(let* ((tag (substring x 1))
|
|
|
(f (cond
|
|
|
- ((string= "" tag) '(not tags))
|
|
|
+ ((string= "" tag) 'tags)
|
|
|
((and (string-match-p "\\`{" tag) (string-match-p "}\\'" tag))
|
|
|
;; TAG is a regexp.
|
|
|
(list 'org-match-any-p (substring tag 1 -1) 'tags))
|
|
@@ -7945,7 +7967,8 @@ tags in the FILTER if any of the tags in FILTER are grouptags."
|
|
|
;; Deactivate `org-agenda-entry-text-mode' when filtering
|
|
|
(when org-agenda-entry-text-mode (org-agenda-entry-text-mode))
|
|
|
(let (tags cat txt)
|
|
|
- (setq org-agenda-filter-form (org-agenda-filter-make-matcher filter type expand))
|
|
|
+ (setq org-agenda-filter-form (org-agenda-filter-make-matcher
|
|
|
+ filter type expand))
|
|
|
;; Only set `org-agenda-filtered-by-category' to t when a unique
|
|
|
;; category is used as the filter:
|
|
|
(setq org-agenda-filtered-by-category
|
|
@@ -7998,7 +8021,8 @@ tags in the FILTER if any of the tags in FILTER are grouptags."
|
|
|
(save-excursion
|
|
|
(goto-char (point-min))
|
|
|
(let ((inhibit-read-only t) pos)
|
|
|
- (while (setq pos (text-property-any (point) (point-max) 'org-filter-type type))
|
|
|
+ (while (setq pos (text-property-any (point) (point-max)
|
|
|
+ 'org-filter-type type))
|
|
|
(goto-char pos)
|
|
|
(remove-text-properties
|
|
|
(point) (next-single-property-change (point) 'org-filter-type)
|