From mboxrd@z Thu Jan 1 00:00:00 1970 From: Nicolas Goaziou Subject: Re: [RFC] [PATCH] Changes to Tag groups - allow nesting and regexps Date: Tue, 24 Feb 2015 17:43:06 +0100 Message-ID: <87a90345wl.fsf@nicolasgoaziou.fr> References: <874mr7pcju.fsf@nicolasgoaziou.fr> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:45558) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YQIYd-0005fa-QT for emacs-orgmode@gnu.org; Tue, 24 Feb 2015 11:42:05 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YQIYX-0005H3-Iz for emacs-orgmode@gnu.org; Tue, 24 Feb 2015 11:42:03 -0500 Received: from relay4-d.mail.gandi.net ([2001:4b98:c:538::196]:39856) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YQIYX-0005Gs-9v for emacs-orgmode@gnu.org; Tue, 24 Feb 2015 11:41:57 -0500 In-Reply-To: ("Gustav \=\?utf-8\?Q\?Wikstr\=C3\=B6m\=22's\?\= message of "Thu, 19 Feb 2015 21:00:27 +0100") List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: Gustav =?utf-8?Q?Wikstr=C3=B6m?= Cc: Org Mode List Gustav Wikstr=C3=B6m writes: > Hi again! The FSA-assignment is now complete. New patches are attached > and comments below. OK. I updated list of contributors accordingly. > The reason for the use of [ ] is because { } already has another purpose > - it is used to make the tags within { } exclusive. > > this example > > ,---- > | #+TAGS: { group : include1 include2 } > `---- > > will only allow one of the tags on any specific headline. [ ] solves > this. Note that grouptags doesn't care if { } or [ ] is used. The only > difference is the exclusiveness. I.e both > > ,---- > | #+TAGS: [ group : include1 include2 ] > | #+TAGS: { group : include1 include2 } > `---- > > will work. With some limitations on the second example due to the way { > } works since before. OK, but is it really needed? What is the point of having two tags of the same group (or, if we consider nested group tags, the same set of siblings) at the same time? > Subject: [PATCH 1/3] org: Grouptags not unique and can contain regexp > > * lisp/org.el (org--setup-process-tags): > (org-fast-tag-selection): > > Grouptags had to previously be defined with { }. This syntax is > already used for exclusive tags and Grouptags need their own, > non-exclusive syntax. This behaviour is achieved with [ ] > instead. Note: { } can still be used also for Grouptags but then > only one of the given tags can be used on the headline at the same > time. Example: You need to separate sentences with two spaces. Also, commit messages need to be formatted this way * lisp/org.el (function): Small description. (other function): Small description. Long explanations. > - (org-re "\\`\\([[:alnum:]_@#%]+\\)\\(?:(\\(.\\))\\)?\\'") e) > + (org-re (concat "\\`\\([[:alnum:]_@#%]+" > + "\\|{.+}\\)" ; regular expression ^^^ I think it should be non-greedy above. > + (taggroups (or org-tag-groups-alist-for-agenda org-tag-groups-alis= t)) > + (taggroups (if downcased (mapcar (lambda(tg) (mapcar 'downcase tg)= ) taggroups) taggroups)) Nitpick: "(lambda (tg) ... #'downcase ...)" Also it should be wrapped at 80 characters. > + (taggroups-keys (mapcar 'car taggroups)) Nitpick: (mapcar #'car taggroups) > + (return-match (if downcased (downcase match) match)) > + (count 0) > + regexps-in-match tags-in-group regexp-in-group regexp-in-group-esc= aped) > ;; @ and _ are allowed as word-components in tags > (modify-syntax-entry ?@ "w" stable) > (modify-syntax-entry ?_ "w" stable) > - (while (and tml > + ;; Temporarily replace regexp-expressions in the match-expression Nitpick: missing full stop. > + (while (string-match "{.+?}" return-match) > + (setq count (1+ count)) Nitpick: (incf count) > + (setq regexps-in-match (cons (match-string 0 return-match) regexps-in= -match)) Nitpick: (push (match-string 0 return-match) regexps-in-match) > + (setq return-match (replace-match (concat "<" (number-to-string count= ) ">") t nil return-match))) Nitpick: (format "<%d>" count) > + ; Filter tag-regexps from tags > + (setq regexp-in-group-escaped (delq nil (mapcar (lambda (x) > + (if (stringp x) > + (and (string-prefix-p "{" x) > + (string-suffix-p "}" x) > + x) > + x)) tags-in-group)) We cannot use `string-prefix-p' and `string-suffix-p' due to backward compatibility. The former will be fine in Org 8.4 (it was introduced in Emacs 24.1), but the latter comes from Emacs 24.4. You can use (equal (substring x ... ...) ...) instead. Be careful about line width, too. > + tags-in-group (delq nil (mapcar (lambda (x) > + (if (stringp x) > + (and (not (string-prefix-p "{" x)) > + (not (string-suffix-p "}" x)) > + x) > + x)) tags-in-group))) Ditto. > + ; If single-as-list, do no more in the while-loop... > + (if (not single-as-list) > + (progn > + (if regexp-in-group > + (setq regexp-in-group (concat "\\|" (mapconcat 'identity regexp-in-gr= oup "\\|")))) > + (setq tags-in-group (concat dir "{\\<" (regexp-opt tags-in-group) = regexp-in-group "\\>}")) > + (if (stringp tags-in-group) (org-add-props tags-in-group '(groupta= g t))) Nitpick: (when (stringp tags-in-group) ...) > + (setq return-match (replace-match tags-in-group t t return-match))) > + (setq tags-in-group (append regexp-in-group-escaped tags-in-group)))) > + (setq taggroups-keys (delete tag taggroups-keys)))) I think you can refactor this part into a `cond'. (cond (single-as-list (setq taggroups-keys (delete tag taggroups-keys))) (regexp-in-group (setq regexp-in-group ...)) (t (setq tags-in-group ....) (when (stringp tags-in-group) ...) (setq return match ...)) > + ;; Add the regular expressions back into the match-expression again See above. > + (while regexps-in-match > + (setq return-match (replace-regexp-in-string (concat "<" (number-to-s= tring count) ">") See above. > + ((equal (car e) :startgrouptags) `eq' instead of `equal'. > + (setq intaggroup t) > + (when (not (=3D cnt 0)) (unless (zerop cnt) ...) or (unless (=3D cnt 0) ...) > + ((equal (car e) :endgrouptags) See above. > (when (not (=3D cnt 0)) Ditto. > + (if (and (=3D cnt 0) (not ingroup) (not intaggroup)) (insert " ")) `when' instead of `if'. > + (if (or ingroup intaggroup) (insert " ")) Ditto. > Subject: [PATCH 2/3] org-agenda: Filtering in the agenda on grouptags [...] > + (while (not (member char (append '(?\t ?\r ?/ ?. ?\ ?q) > + (string-to-list tag-chars)))) Nitpick: `memq' instead of `member'. > + (cond ((equal char ?-) (setq exclude t)) > + ((equal char ?+) (setq exclude nil))))) Nitpick: `eq' instead of `equal'. > + ((equal char ?q)) ;If q, abort (even if there is a q-key for a tag.= ..) Ditto. > -(defun org-agenda-filter-make-matcher (filter type) > +(defun org-agenda-filter-make-matcher (filter type &optional expand) > "Create the form that tests a line for agenda filter." You need to explain arguments (data type, purpose) in the docstring. > + ;(if expand (setq filter (org-agenda-filter-expand-tags filter))) This line should be removed. > + (let ((op (string-to-char x))) > + (if expand (setq x (org-agenda-filter-expand-tags (list x) t)) > + (setq x (list x))) > + (setq f1 (org-agenda-filter-make-matcher-tag-exp x op)) > + (push f1 f)))) Is it useful to bind OP since you use it only once anyway? > +(defun org-agenda-filter-make-matcher-tag-exp (tags op) Missing docstring. > + (let (f f1) ;f =3D return expression. f1 =3D working-area > + (dolist (x tags) > + (let* ((tag (substring x 1)) > + (isregexp (and (string-prefix-p "{" tag) > + (string-suffix-p "}" tag))) See above. > + regexp) > + (cond > + (isregexp > + (setq regexp (substring tag 1 -1)) > + (setq f1 (list 'string-match regexp '(apply 'concat tags)))) Spurious space. > + (t > + (setq f1 (list 'member (downcase tag) 'tags)))) > + (when (equal op ?-) `eq' > + ; any of the expressions can match if op =3D + > + ; all must match if the operator is -. All o You need two semi-colons here. > + (if (equal op ?-) `eq' > +(defun org-agenda-filter-apply (filter type &optional expand) > "Set FILTER as the new agenda filter and apply it." See above. > Subject: [PATCH 3/3] org: Nesting grouptags > > * lisp/org.el (org-tags-expand): Nesting grouptags. Allowing subtags > to be defined as groups themselves. > > : #+TAGS: [ Group : SubOne(1) SubTwo ] > : #+TAGS: [ SubOne : SubOne1 SubOne2 ] > : #+TAGS: [ SubTwo : SubTwo1 SubTwo2 ] > > Should be seen as a tree of tags: > - Group > - SubOne > - SubOne1 > - SubOne2 > - SubTwo > - SubTwo1 > - SubTwo2 > > Searching for "Group" should return all tags defined above. > --- > lisp/org.el | 25 +++++++++++++++++++++++-- > 1 file changed, 23 insertions(+), 2 deletions(-) > > diff --git a/lisp/org.el b/lisp/org.el > index 6bb8edf..5c80238 100755 > --- a/lisp/org.el > +++ b/lisp/org.el > @@ -14543,7 +14543,7 @@ See also `org-scan-tags'. > matcher))) > (cons match0 matcher))) >=20=20 > -(defun org-tags-expand (match &optional single-as-list downcased) > +(defun org-tags-expand (match &optional single-as-list downcased tags-al= ready-expanded) > "Expand group tags in MATCH. See above. > + (when (and (not (get-text-property 0 'grouptag (match-string 2 retu= rn-match))) > + (not (member tag work-already-expanded))) Nitpick: (unless (or (get-text-property ...) (member tag ...))) > + (setq work-already-expanded (append (list tag) work-already-expan= ded)) (push tag work-already-expanded) > + ; Recursively expand each tag in the group, if the tag hasn't > + ; already been expanded See above. Missing full stop, too. > + ;; Redo the regexp-match because the recursive calls seems to mess= it up... You can also use `save-match-data' and restore it later. Thanks for your work. Regards,