From 4743d43dd8e448b6c440b1e4988bcd353de60cc7 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Sun, 17 Apr 2016 20:42:08 +0200 Subject: [PATCH] Properly handle `org-tag-persistent-alist' * lisp/org.el (org-current-tag-alist): New variable. (org-set-tags): (org-global-tags-completion-table): (org-agenda-prepare-buffers): Use new variable. (org-set-regexps-and-options): Use new variable. Handle STARTUP early so that "#+STARTUP: noptag" is taken into consideration. * lisp/org-agenda.el (org-agenda-bulk-action): Use new variable. * lisp/org-mobile.el (org-mobile-create-index-file): `org-tag-alist' is no longer buffer-local. * testing/lisp/test-org.el (test-org/set-regexps-and-options): Add tests. --- lisp/org-agenda.el | 13 +++---- lisp/org-mobile.el | 2 +- lisp/org.el | 56 ++++++++++++++++------------- testing/lisp/test-org.el | 77 +++++++++++++++++++++++++++++----------- 4 files changed, 95 insertions(+), 53 deletions(-) diff --git a/lisp/org-agenda.el b/lisp/org-agenda.el index 3ed380360..9557d4961 100644 --- a/lisp/org-agenda.el +++ b/lisp/org-agenda.el @@ -86,10 +86,11 @@ (declare-function org-add-archive-files "org-archive" (files)) (declare-function org-capture "org-capture" (&optional goto keys)) -(defvar calendar-mode-map) ; defined in calendar.el -(defvar org-clock-current-task nil) ; defined in org-clock.el -(defvar org-mobile-force-id-on-agenda-items) ; defined in org-mobile.el -(defvar org-habit-show-habits) ; defined in org-habit.el +(defvar calendar-mode-map) +(defvar org-clock-current-task) +(defvar org-current-tag-alist) +(defvar org-mobile-force-id-on-agenda-items) +(defvar org-habit-show-habits) (defvar org-habit-show-habits-only-for-today) (defvar org-habit-show-all-today) @@ -9930,8 +9931,8 @@ The prefix arg is passed through to the command if possible." (format "Tag to %s: " (if (eq action ?+) "add" "remove")) (with-current-buffer (marker-buffer (car entries)) (delq nil - (mapcar (lambda (x) - (if (stringp (car x)) x)) org-tag-alist))))) + (mapcar (lambda (x) (and (stringp (car x)) x)) + org-current-tag-alist))))) (setq cmd `(org-agenda-set-tags ,tag ,(if (eq action ?+) ''on ''off)))) ((memq action '(?s ?d)) diff --git a/lisp/org-mobile.el b/lisp/org-mobile.el index 9ceecc9de..f07b6ff7b 100644 --- a/lisp/org-mobile.el +++ b/lisp/org-mobile.el @@ -422,7 +422,7 @@ agenda view showing the flagged items." (let ((files-alist (sort (copy-sequence org-mobile-files-alist) (lambda (a b) (string< (cdr a) (cdr b))))) (def-todo (default-value 'org-todo-keywords)) - (def-tags (default-value 'org-tag-alist)) + (def-tags org-tag-alist) (target-file (expand-file-name org-mobile-index-file org-mobile-directory)) file link-name todo-kwds done-kwds tags entry kwds dwds twds) diff --git a/lisp/org.el b/lisp/org.el index 66ac7f65d..55700ecaf 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -2581,6 +2581,10 @@ taken from the (otherwise obsolete) variable `org-todo-interpretation'." "Alist of all groups tags from all current agenda files.") (defvar-local org-tag-groups-alist nil) (defvar org-agenda-contributing-files nil) +(defvar-local org-current-tag-alist nil + "Alist of all tag groups in current buffer. +This variable takes into consideration `org-tag-alist', +`org-tag-persistent-alist' and TAGS keywords in the buffer.") (defvar-local org-not-done-keywords nil) (defvar-local org-done-keywords nil) (defvar-local org-todo-heads nil) @@ -4901,13 +4905,28 @@ related expressions." '("ARCHIVE" "CATEGORY" "COLUMNS" "CONSTANTS" "LINK" "OPTIONS" "PRIORITIES" "PROPERTY" "SEQ_TODO" "STARTUP" "TODO" "TYP_TODO"))))))) + ;; Startup options. Get this early since it does change + ;; behavior for other options (e.g., tags). + (let ((startup (cdr (assq 'startup alist)))) + (dolist (option startup) + (let ((entry (assoc-string option org-startup-options t))) + (when entry + (let ((var (nth 1 entry)) + (val (nth 2 entry))) + (if (not (nth 3 entry)) (set (make-local-variable var) val) + (unless (listp (symbol-value var)) + (set (make-local-variable var) nil)) + (add-to-list var val))))))) (setq-local org-file-tags (mapcar #'org-add-prop-inherited (cdr (assq 'filetags alist)))) - (setq-local org-tag-alist - (let ((tags (cdr (assq 'tags alist)))) - (if tags (org-tag-string-to-alist tags) org-tag-alist))) - (setq-local org-tag-groups-alist (org-tag-alist-to-groups org-tag-alist)) + (setq org-current-tag-alist + (append org-tag-persistent-alist + (let ((tags (cdr (assq 'tags alist)))) + (if tags (org-tag-string-to-alist tags) + org-tag-alist)))) + (setq org-tag-groups-alist + (org-tag-alist-to-groups org-current-tag-alist)) (unless tags-only ;; File properties. (setq-local org-file-properties (cdr (assq 'property alist))) @@ -4939,17 +4958,6 @@ related expressions." (let ((scripts (assq 'scripts alist))) (when scripts (setq-local org-use-sub-superscripts (cdr scripts)))) - ;; Startup options. - (let ((startup (cdr (assq 'startup alist)))) - (dolist (option startup) - (let ((entry (assoc-string option org-startup-options t))) - (when entry - (let ((var (nth 1 entry)) - (val (nth 2 entry))) - (if (not (nth 3 entry)) (set (make-local-variable var) val) - (unless (listp (symbol-value var)) - (set (make-local-variable var) nil)) - (add-to-list var val))))))) ;; TODO keywords. (setq-local org-todo-kwd-alist nil) (setq-local org-todo-key-alist nil) @@ -14364,16 +14372,15 @@ instead of the agenda files." (save-excursion (org-uniquify (delq nil - (apply 'append + (apply #'append (mapcar (lambda (file) (set-buffer (find-file-noselect file)) - (append (org-get-buffer-tags) - (mapcar (lambda (x) (if (stringp (car-safe x)) - (list (car-safe x)) nil)) - org-tag-alist))) - (if (and files (car files)) - files + (mapcar (lambda (x) + (and (stringp (car-safe x)) + (list (car-safe x)))) + (or org-current-tag-alist (org-get-buffer-tags)))) + (if (car-safe files) files (org-agenda-files)))))))) (defun org-make-tags-matcher (match) @@ -14937,7 +14944,7 @@ When JUST-ALIGN is non-nil, only align tags." org-last-tags-completion-table (append org-tag-persistent-alist - (or org-tag-alist (org-get-buffer-tags)) + (or org-current-tag-alist (org-get-buffer-tags)) (and org-complete-tags-always-offer-all-agenda-tags (org-global-tags-completion-table @@ -18717,8 +18724,7 @@ When a buffer is unmodified, it is just killed. When modified, it is saved (setq org-tag-alist-for-agenda (org-uniquify (append org-tag-alist-for-agenda - org-tag-alist - org-tag-persistent-alist))) + org-current-tag-alist))) ;; Merge current file's tag groups into global ;; `org-tag-groups-alist-for-agenda'. (when org-group-tags diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index 197839df5..60df97d89 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -1656,41 +1656,76 @@ SCHEDULED: <2014-03-04 tue.>" (ert-deftest test-org/set-regexps-and-options () "Test `org-set-regexps-and-options' specifications." ;; TAGS keyword. + (should + (equal '(("A")) + (let ((org-tag-alist '(("A"))) + (org-tag-persistent-alist nil)) + (org-test-with-temp-text "" + (org-mode-restart) + org-current-tag-alist)))) + (should + (equal '(("B")) + (let ((org-tag-alist '(("A"))) + (org-tag-persistent-alist nil)) + (org-test-with-temp-text "#+TAGS: B" + (org-mode-restart) + org-current-tag-alist)))) + (should + (equal '(("C") ("B")) + (let ((org-tag-alist '(("A"))) + (org-tag-persistent-alist '(("C")))) + (org-test-with-temp-text "#+TAGS: B" + (org-mode-restart) + org-current-tag-alist)))) + (should + (equal '(("B")) + (let ((org-tag-alist '(("A"))) + (org-tag-persistent-alist '(("C")))) + (org-test-with-temp-text "#+STARTUP: noptag\n#+TAGS: B" + (org-mode-restart) + org-current-tag-alist)))) (should (equal '(("A" . ?a) ("B") ("C")) - (org-test-with-temp-text "#+TAGS: A(a) B C" - (org-mode-restart) - org-tag-alist))) + (let ((org-tag-persistant-alist nil)) + (org-test-with-temp-text "#+TAGS: A(a) B C" + (org-mode-restart) + org-current-tag-alist)))) (should (equal '(("A") (:newline) ("B")) - (org-test-with-temp-text "#+TAGS: A\n#+TAGS: B" - (org-mode-restart) - org-tag-alist))) + (let ((org-tag-persistent-alist nil)) + (org-test-with-temp-text "#+TAGS: A\n#+TAGS: B" + (org-mode-restart) + org-current-tag-alist)))) (should (equal '((:startgroup) ("A") ("B") (:endgroup) ("C")) - (org-test-with-temp-text "#+TAGS: { A B } C" - (org-mode-restart) - org-tag-alist))) + (let ((org-tag-persistent-alist nil)) + (org-test-with-temp-text "#+TAGS: { A B } C" + (org-mode-restart) + org-current-tag-alist)))) (should (equal '((:startgroup) ("A") (:grouptags) ("B") ("C") (:endgroup)) - (org-test-with-temp-text "#+TAGS: { A : B C }" - (org-mode-restart) - org-tag-alist))) + (let ((org-tag-persistent-alist nil)) + (org-test-with-temp-text "#+TAGS: { A : B C }" + (org-mode-restart) + org-current-tag-alist)))) (should (equal '(("A" "B" "C")) - (org-test-with-temp-text "#+TAGS: { A : B C }" - (org-mode-restart) - org-tag-groups-alist))) + (let ((org-tag-persistent-alist nil)) + (org-test-with-temp-text "#+TAGS: { A : B C }" + (org-mode-restart) + org-tag-groups-alist)))) (should (equal '((:startgrouptag) ("A") (:grouptags) ("B") ("C") (:endgrouptag)) - (org-test-with-temp-text "#+TAGS: [ A : B C ]" - (org-mode-restart) - org-tag-alist))) + (let ((org-tag-persistent-alist nil)) + (org-test-with-temp-text "#+TAGS: [ A : B C ]" + (org-mode-restart) + org-current-tag-alist)))) (should (equal '(("A" "B" "C")) - (org-test-with-temp-text "#+TAGS: [ A : B C ]" - (org-mode-restart) - org-tag-groups-alist))) + (let ((org-tag-persistent-alist nil)) + (org-test-with-temp-text "#+TAGS: [ A : B C ]" + (org-mode-restart) + org-tag-groups-alist)))) ;; FILETAGS keyword. (should (equal '("A" "B" "C")