[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [O] Mutually-exclusive Org tags still inherit each other
From: |
Tina Russell |
Subject: |
Re: [O] Mutually-exclusive Org tags still inherit each other |
Date: |
Fri, 1 Mar 2019 13:47:44 -0800 |
Well, I think it’s unreasonable to ask users to reinforce manually and
continuously something they’ve already specified in their settings.
Besides, my example was intentionally trivial—imagine managing a large
tree and having to remember which tags are mutually exclusive to what,
all the time.
But, no matter! I have created a patch! It works great, even for edge
cases like when an entry has two tags that are set as mutually
exclusive to each other.
First, we have two new functions: one which returns the tags currently
defined as mutually exclusive, and one which checks for tags that
conflict with the given tag (with the help of the cl-loop “if” clause
and cl-set-difference).
(defun org-get-exclusive-tags (&optional alist)
"Return a list of mutually exclusive tags occuring in ALIST.
ALIST defaults to `org-current-tag-alist'. The result is a list
of lists of strings, where each string represents a tag, and each
list of strings represents a group of mutually exclusive tags."
;; Most of this code was culled from `org-fast-tag-selection'
(let ((alist (or alist org-current-tag-alist))
groups ingroup intaggroup tag)
(dolist (e alist groups)
(cond
((eq (car e) :startgroup)
(push '() groups) (setq ingroup t))
((eq (car e) :endgroup)
(setq ingroup nil))
((eq (car e) :startgrouptag)
(setq intaggroup t))
((eq (car e) :endgrouptag)
(setq intaggroup nil))
((equal e '(:newline))) ; do nothing
((equal e '(:grouptags))) ; do nothing
(t
(setq tag (copy-sequence (car e)))
(when ingroup (push tag (car groups))))))))
(defun org-get-conflicting-tags (tags &optional alist)
"For list TAGS, return tags which would conflict according to ALIST.
ALIST defaults to `org-current-tag-alist'. For more information
on mutually exclusive tags, see Info node `(org)Tag Hierarchy'."
(let* ((alist (or alist org-current-tag-alist))
(groups (org-get-exclusive-tags alist)))
(cl-loop for group in groups
if (cl-some (lambda (x) (member x group)) tags)
append (cl-set-difference group tags :test 'equal))))
Then, we redefine org-get-tags slightly to remove conflicting tags
from the list of inherited tags.
(defun org-get-tags (&optional pos local)
;; "the usual docstring, skipped here for email brevity"
(if (and org-trust-scanner-tags
(or (not pos) (eq pos (point)))
(not local))
org-scanner-tags
(org-with-point-at (or pos (point))
(unless (org-before-first-heading-p)
(org-back-to-heading t)
(let ((ltags (org--get-local-tags)) itags)
(if (or local (not org-use-tag-inheritance)) ltags
(let* ((conflicting-tags (org-get-conflicting-tags ltags))
(ct-predicate (lambda (x) (member x conflicting-tags))))
(while (org-up-heading-safe)
(nconc conflicting-tags
(org-get-conflicting-tags itags
org-current-tag-alist))
(setq itags (append (mapcar #'org-add-prop-inherited
(cl-remove-if ct-predicate
(org--get-local-tags)))
itags)))
(setq itags (append
(cl-remove-if ct-predicate org-file-tags)
itags)))
(delete-dups
(append (org-remove-uninherited-tags itags) ltags))))))))
If everything looks good, I’ll figure out how to submit it as a proper
Git patch (right now it’s just “code that’s been sitting in my config
for weeks”), and do the copyright-assignment thing so we can get it
merged. I hope you like it!
—Tina
On Sat, Feb 9, 2019 at 10:03 AM Nicolas Goaziou <address@hidden> wrote:
>
> Hello,
>
> Tina Russell <address@hidden> writes:
>
> > So, according to the Org documentation: “You can also group together tags
> > that are mutually exclusive by using braces … Selecting a tag in a group of
> > mutually exclusive tags will turn off any other tags from that group.
> >
> > But, if I do this…
> >
> > #+TAGS: { place(c) container(c) object(o) }
> >
> > * Room :place:
> > ** Box :container:
> > *** Toy :object:
> >
> > …and then use (org-get-tags) on “Toy,” it reports that it has the tags
> > “place”, “container”, and “object”, even though these tags are all defined
> > to be mutually exclusive! This is a problem,
>
> Not really. `org-get-tags' is a low-level function, i.e., it has no
> knowledge about tag groups or mutually exclusive tags.
>
> > since turning off tag
> > inheritance (for a document or for specific tags) seems to be an
> > all-or-nothing affair. That means if I wanted to do this:
> >
> > * Room :place:
> > ** Bookcase
> > ** Dresser
> > ** Desk
> > ** Nightstand
> > ** Closet
> > *** Box :container:
> > **** Toy :object:
> >
> > …and then search for all headings with the tag “place,” either (with tag
> > inheritance) everything, including “Box” and “Toy,” will be returned, or
> > (without tag inheritance) only “Room” would be returned. (I could put a tag
> > on every heading where I want it inherited, but that would both defeat the
> > purpose of inheritance and make it difficult to manage large trees.)
>
> You don't need to use mutually exclusive tags for this example. You
> could search for "place-container", assuming tag inheritance.
>
> Regards,
>
> --
> Nicolas Goaziou
- Re: [O] Mutually-exclusive Org tags still inherit each other,
Tina Russell <=