From mboxrd@z Thu Jan 1 00:00:00 1970 From: Christopher League Subject: RFC: interactive tag query adjustment Date: Sat, 8 Dec 2007 09:00:01 -0500 Message-ID: Mime-Version: 1.0 (Apple Message framework v915) Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit Return-path: Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1J10E0-0003Ny-5N for emacs-orgmode@gnu.org; Sat, 08 Dec 2007 09:00:12 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1J10Dw-0003LG-JP for emacs-orgmode@gnu.org; Sat, 08 Dec 2007 09:00:10 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1J10Dv-0003Kj-Eb for emacs-orgmode@gnu.org; Sat, 08 Dec 2007 09:00:07 -0500 Received: from contrapunctus.net ([207.210.219.173]) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1J10Du-000235-Tf for emacs-orgmode@gnu.org; Sat, 08 Dec 2007 09:00:07 -0500 Received: from sagan.home.lan (ool-182cbf56.dyn.optonline.net [24.44.191.86]) by contrapunctus.net (Postfix) with ESMTP id AF609842A for ; Sat, 8 Dec 2007 09:00:01 -0500 (EST) List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: emacs-orgmode@gnu.org Hi, I've been using org-mode for about a year, and recently updated to the latest release. I was happy to discover the enhanced tag query features ("phone|email/NEXT|SOMEDAY", etc) and started rethinking my configuration a little. I'd like to have an interface for interactive query adjustment. For example, in a tags match (C-c a m, org-tags-view), I could begin with the query "phone/NEXT" and type the keys "/h" to quickly turn it into "phone+home/NEXT" and then ";s" to get "phone+home/NEXT|SOMEDAY", then "=[" to clear all the tags to "/NEXT|SOMEDAY", and so on. Then, one more keystroke to save the current query into org-agenda-custom- commands would be icing on the cake. I'm new to the mailing list, so maybe some functionality like this was discussed before. Closest I found was a thread begun by John W in October, wherein "interactive" and "query" were mentioned together a few times... http://thread.gmane.org/gmane.emacs.orgmode/3628 but I don't think it's the same idea. Below is a first crack at this kind of functionality. It's very rough.. I've hacked elisp before, but I'm new to the org.el code. Load this after org, then "C-c a m", enter any match query, then try some of the commands with your tag shortcut keys. It assumes you have some settings in org-tag-alist. Currently, todo shortcut keys may not work because org-todo-key-alist is still nil; it's not clear to me how this should get initialized from agenda-mode. Let me know what you think! Thanks Carsten and community for all the hard work and great ideas surrounding org-mode! Chris ;; Currently, it seems the query string is kept only as part of the ;; org-agenda-redo-command, which is a Lisp form. A distinct global ;; would be cleaner, but that entails modifications to org-mode." ;; org-agenda-redo-command: (org-tags-view 'nil (if current-prefix-arg nil "")) ;; The "" will contain the current query string (defun cl-agenda-twiddle-query () (cl-agenda-twiddle-iter org-agenda-redo-command)) (defun cl-agenda-twiddle-iter (sexp) "Find query string in SEXP and replace it." (if (consp sexp) (if (and (stringp (car sexp)) (null (cdr sexp))) (setcar sexp (cl-agenda-apply-changes (car sexp))) (cl-agenda-twiddle-iter (car sexp)) (cl-agenda-twiddle-iter (cdr sexp))))) (defun cl-agenda-apply-changes (str) (cl-agenda-apply-iter cl-agenda-op str cl-agenda-args)) (defun cl-agenda-apply-iter (op str args) (if (null args) str (funcall op (cl-agenda-apply-iter op str (cdr args)) (caar args) (cdar args)))) (defun cl-agenda-tag-clear (query kind str) (if (string-match (concat "[-\\+&|]?\\b" (regexp-quote str) "\\b") query) (replace-match "" t t query) query)) (defun cl-agenda-tag-set (query kind str) (let* ((q (cl-agenda-tag-clear query kind str)) (r (string-match "\\([^/]*\\)/?\\(.*\\)" q)) (q1 (match-string 1 q)) (q2 (match-string 2 q))) (cond ((eq kind 'tag) (concat q1 cl-agenda-sep str "/" q2)) ((equal cl-agenda-sep "+") (concat q1 "/+" str)) (t (concat q1 "/" q2 cl-agenda-sep str))))) ;;; ALMOST THERE: IT'S JUST THAT org-todo-key-alist IS NIL. (defun cl-agenda-all (kind alist) (cond ((null alist) nil) ((stringp (caar alist)) (cons (cons kind (caar alist)) (cl-agenda-all kind (cdr alist)))) (t (cl-agenda-all kind (cdr alist))))) (defun cl-agenda-interp-key (k) (let ((v1 (rassoc k org-tag-alist)) (v2 (rassoc k org-todo-key-alist))) (cond ((eq k ? ) (append (cl-agenda-all 'tag org-tag-alist) (cl-agenda-all 'todo org-todo-key-alist))) ((eq k ?[) (cl-agenda-all 'tag org-tag-alist)) ((eq k ?]) (cl-agenda-all 'todo org-todo-key-alist)) (v1 (list (cons 'tag (car v1)))) (v2 (list (cons 'todo (car v2)))) (t nil)))) (defun cl-agenda-tag-cmd (op sep) (let ((cl-agenda-op op) (cl-agenda-sep sep) (cl-agenda-args (cl-agenda-interp-key (read-char)))) (cl-agenda-twiddle-query)) (org-agenda-redo)) (defun cl-agenda-tag-clear-cmd () (interactive) (cl-agenda-tag-cmd 'cl-agenda-tag-clear "")) (defun cl-agenda-tag-and-cmd () (interactive) (cl-agenda-tag-cmd 'cl-agenda-tag-set "+")) (defun cl-agenda-tag-or-cmd () (interactive) (cl-agenda-tag-cmd 'cl-agenda-tag-set "|")) (defun cl-agenda-tag-not-cmd () (interactive) (cl-agenda-tag-cmd 'cl-agenda-tag-set "-")) (org-defkey org-agenda-mode-map "=" 'cl-agenda-tag-clear-cmd) (org-defkey org-agenda-mode-map "/" 'cl-agenda-tag-and-cmd) (org-defkey org-agenda-mode-map ";" 'cl-agenda-tag-or-cmd) (org-defkey org-agenda-mode-map "\\" 'cl-agenda-tag-not-cmd)