From 4f7cb263f37d85e041b9d1b8b6493f30e4d77368 Mon Sep 17 00:00:00 2001 From: Carsten Dominik Date: Fri, 29 Feb 2008 14:49:06 +0100 Subject: [PATCH] Implementing search view. --- ChangeLog | 11 +++++ ORGWEBPAGE/Changes.org | 13 ++++-- org.el | 119 +++++++++++++++++++++++++++++++++++++++++-------- org.texi | 32 +++++++++++-- 4 files changed, 149 insertions(+), 26 deletions(-) diff --git a/ChangeLog b/ChangeLog index 10f2e75da..1c6054ad8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-02-29 Carsten Dominik + + * org.el (org-agenda-text-search-extra-files): Renamed from + `org-agenda-multi-occur-extra-files'. + (org-agenda-manipulate-query-add) + (org-agenda-manipulate-query-subtract) + (org-agenda-manipulate-query-add-regexp) + (org-agenda-manipulate-query-subtract-regexp) + (org-agenda-manipulate-query): New functions. + (org-agenda-query-register): New option. + 2008-02-28 Carsten Dominik * org.el (org-auto-repeat-maybe): Make sure that the repeat stuff diff --git a/ORGWEBPAGE/Changes.org b/ORGWEBPAGE/Changes.org index c9d34af99..388cde8ba 100644 --- a/ORGWEBPAGE/Changes.org +++ b/ORGWEBPAGE/Changes.org @@ -15,8 +15,9 @@ `C-c a s' now invokes a special agenda view that can be used to search notes by keyword and regular expressions. The - search knows the boundaries of an entry, and it can use - simple Boolean logic. For example, the search string + search knows the boundaries of an entry, can use simple + Boolean logic and is reasonably fast. For example, the + search string : +computer +wifi -ethernet -{8\.11[bg]} @@ -29,12 +30,16 @@ otherwise it will look at the headine and the text below it, up to the next (possibly sub-) heading. - If find it very useful to define a custom command to do such + The command searches all agenda files, and in addition the + files listed in `org-agenda-text-search-extra-files'. + + I find it very useful to define a custom command to do such a search only in a limited number of files (my notes files), like this: : ("N" "Search notes" search "" - : ((org-agenda-files '("~/org/notes.org" "~/org/computer.org")))) + : ((org-agenda-files '("~/org/notes.org" "~/org/computer.org")) + : (org-agenda-text-search-extra-files nil))) *** Many new extensions available in the CONTRIB directory diff --git a/org.el b/org.el index 0feb6428e..88849e4c4 100644 --- a/org.el +++ b/org.el @@ -2262,12 +2262,21 @@ Nil means to remove them, after a query, from the list." :group 'org-agenda :type 'boolean) -(defcustom org-agenda-multi-occur-extra-files nil - "List of extra files to be searched by `org-occur-in-agenda-files'. -The files in `org-agenda-files' are always searched." +(defcustom org-agenda-text-search-extra-files nil + "List of extra files to be searched by text search commands. +These files will be search in addition to the agenda files bu the +commands `org-search-view' (`C-c a s') and `org-occur-in-agenda-files'. +Note that these files will only be searched for text search commands, +not for the other agenda views like todo lists, tag earches or the weekly +agenda. This variable is intended to list notes and possibly archive files +that should also be searched by these two commands." :group 'org-agenda :type '(repeat file)) +(if (fboundp 'defvaralias) + (defvaralias 'org-agenda-multi-occur-extra-files + 'org-agenda-text-search-extra-files)) + (defcustom org-agenda-confirm-kill 1 "When set, remote killing from the agenda buffer needs confirmation. When t, a confirmation is always needed. When a number N, confirmation is @@ -2492,6 +2501,13 @@ should provide a description for the prefix, like (string :tag "Access Key(s)") (string :tag "Description "))))) +(defcustom org-agenda-query-register ?o + "The register holding the current query string. +The prupose of this is that if you construct a query string interactively, +you can then use it to define a custom command." + :group 'org-agenda-custom-commands + :type 'character) + (defcustom org-stuck-projects '("+LEVEL=2/-DONE" ("TODO" "NEXT" "NEXTACTION") nil "") "How to identify stuck projects. @@ -19329,6 +19345,7 @@ FIXME: describe the elements." (defvar org-agenda-follow-mode nil) (defvar org-agenda-show-log nil) (defvar org-agenda-redo-command nil) +(defvar org-agenda-query-string nil) (defvar org-agenda-mode-hook nil) (defvar org-agenda-type nil) (defvar org-agenda-force-single-file nil) @@ -19465,6 +19482,11 @@ The following commands are available: (org-defkey org-agenda-mode-map [(left)] 'org-agenda-earlier) (org-defkey org-agenda-mode-map "\C-c\C-x\C-c" 'org-agenda-columns) +(org-defkey org-agenda-mode-map "[" 'org-agenda-manipulate-query-add) +(org-defkey org-agenda-mode-map "]" 'org-agenda-manipulate-query-subtract) +(org-defkey org-agenda-mode-map "{" 'org-agenda-manipulate-query-add-re) +(org-defkey org-agenda-mode-map "}" 'org-agenda-manipulate-query-subtract-re) + (defvar org-agenda-keymap (copy-keymap org-agenda-mode-map) "Local keymap for agenda entries from Org-mode.") @@ -20878,7 +20900,10 @@ Words without a prefix or prefixed with a plus must occur in the entry. Matching is case-insensitive and the words are enclosed by word delimiters. Words enclosed by curly braces are interpreted as regular expressions -that must or must not match in the entry." +that must or must not match in the entry. + +This command searches the agenda files, and in addition the files listed +in `org-agenda-text-search-extra-files'." (interactive "P") (org-compile-prefix-format 'search) (org-set-sorting-strategy 'search) @@ -20890,18 +20915,20 @@ that must or must not match in the entry." 'mouse-face 'highlight 'keymap org-agenda-keymap 'help-echo (format "mouse-2 or RET jump to location"))) - ;; FIXME: get rid of the \n at some point but watch out - (regexp (concat "^" org-outline-regexp)) - rtn rtnall files file pos - marker priority category tags + regexp rtn rtnall files file pos + marker priority category tags c neg re ee txt beg end words regexps+ regexps- hdl-only buffer beg1 str) - (unless (and (stringp string) + (unless (and (not arg) + (stringp string) (string-match "\\S-" string)) - (setq string (read-string "Word Search: " nil + (setq string (read-string "[+-]Word/{Regexp} ...: " + (cond + ((integerp arg) (cons string arg)) + (arg string)) 'org-agenda-search-history))) - (setq org-agenda-redo-command (list 'org-search-view 'current-prefix-arg string)) + (setq org-agenda-query-string string) (if (equal (string-to-char string) ?*) (setq hdl-only t @@ -20920,7 +20947,13 @@ that must or must not match in the entry." (setq re (concat "\\<" (regexp-quote (downcase w)) "\\>"))) (if neg (push re regexps-) (push re regexps+))) words) - (setq files (org-agenda-files) + (setq regexps+ (sort regexps+ (lambda (a b) (> (length a) (length b))))) + (if (not regexps+) + (setq regexp (concat "^" org-outline-regexp)) + (setq regexp (pop regexps+)) + (if hdl-only (setq regexp (concat "^" org-outline-regexp ".*?" + regexp)))) + (setq files (append (org-agenda-files) org-agenda-text-search-extra-files) rtnall nil) (while (setq file (pop files)) (setq ee nil) @@ -20944,11 +20977,17 @@ that must or must not match in the entry." org-agenda-restrict-end) (widen)) (goto-char (point-min)) + (unless (or (org-on-heading-p) + (outline-next-heading)) + (throw 'nextfile t)) + (goto-char (max (point-min) (1- (point)))) (while (re-search-forward regexp nil t) + (org-back-to-heading t) + (skip-chars-forward "* ") + (setq beg (point-at-bol) + beg1 (point) + end (progn (outline-next-heading) (point))) (catch :skip - (setq beg (point-at-bol) - beg1 (match-end 0) - end (progn (outline-next-heading) (point))) (goto-char beg) (org-agenda-skip) (setq str (buffer-substring-no-properties @@ -20977,7 +21016,7 @@ that must or must not match in the entry." 'type "search") (push txt ee) (goto-char (1- end))))))))) - (setq rtn ee) + (setq rtn (nreverse ee)) (setq rtnall (append rtnall rtn))) (if org-agenda-overriding-header (insert (org-add-props (copy-sequence org-agenda-overriding-header) @@ -20988,7 +21027,11 @@ that must or must not match in the entry." (setq pos (point)) (insert string "\n") (add-text-properties pos (1- (point)) (list 'face 'org-warning)) - (setq pos (point))) + (setq pos (point)) + (unless org-agenda-multi + (insert "Press `[', `]' to add/sub word, `{', `}' to add/sub regexp, `C-u r' to edit\n") + (add-text-properties pos (1- (point)) + (list 'face 'org-agenda-structure)))) (when rtnall (insert (org-finalize-agenda-entries rtnall) "\n")) (goto-char (point-min)) @@ -22440,6 +22483,46 @@ When this is the global TODO list, a prefix argument will be interpreted." (goto-line line) (recenter window-line))) +(defun org-agenda-manipulate-query-add () + "Manipulate the query by adding a search term with positive selection. +Positive selection means, the term must be matched for selection of an entry." + (interactive) + (org-agenda-manipulate-query ?\[)) +(defun org-agenda-manipulate-query-subtract () + "Manipulate the query by adding a search term with negative selection. +Negative selection means, term must not be matched for selection of an entry." + (interactive) + (org-agenda-manipulate-query ?\])) +(defun org-agenda-manipulate-query-add-re () + "Manipulate the query by adding a search regexp with positive selection. +Positive selection means, the regexp must match for selection of an entry." + (interactive) + (org-agenda-manipulate-query ?\{)) +(defun org-agenda-manipulate-query-subtract-re () + "Manipulate the query by adding a search regexp with negative selection. +Negative selection means, regexp must not match for selection of an entry." + (interactive) + (org-agenda-manipulate-query ?\})) +(defun org-agenda-manipulate-query (char) + (cond + ((eq org-agenda-type 'search) + (org-add-to-string + 'org-agenda-query-string + (cdr (assoc char '((?\[ . " +") (?\] . " -") + (?\{ . " +{}") (?\} . " -{}"))))) + (setq org-agenda-redo-command + (list 'org-search-view + (+ (length org-agenda-query-string) + (if (member char '(?\{ ?\})) 0 1)) + org-agenda-query-string)) + (set-register org-agenda-query-register org-agenda-query-string) + (org-agenda-redo)) + (t (error "Canot manipulate query for %s-type agenda buffers" + org-agenda-type)))) + +(defun org-add-to-string (var string) + (set var (concat (symbol-value var) string))) + (defun org-agenda-goto-date (date) "Jump to DATE in agenda." (interactive (list (org-read-date))) @@ -27776,7 +27859,7 @@ really on, so that the block visually is on the match." (interactive "sOrg-files matching: \np") (let* ((files (org-agenda-files)) (tnames (mapcar 'file-truename files)) - (extra org-agenda-multi-occur-extra-files) + (extra org-agenda-text-search-extra-files) f) (while (setq f (pop extra)) (unless (member (file-truename f) tnames) diff --git a/org.texi b/org.texi index bdc519126..02929bc87 100644 --- a/org.texi +++ b/org.texi @@ -5127,12 +5127,15 @@ string +computer +wifi -ethernet -@{8\.11[bg]@} @end example -Will search for note entries that contain the keywords @code{computer} +@noindent +will search for note entries that contain the keywords @code{computer} and @code{wifi}, but not the keyword @code{ethernet}, and which are also not matched by the regular expression @code{8\.11[bg]}, meaning to exclude both 8.11b and 8.11g. -@end table +Note that in addition to the agenda files, this command will also search +the files listed in @code{org-agenda-text-search-extra-files}. +@end table @node Stuck projects, , Timeline, Built-in agenda views @subsection Stuck projects @@ -5426,6 +5429,23 @@ Display the previous dates. @item . Goto today. +@tsubheading{Query editing} +@cindex query editing, in agenda + +@kindex [ +@kindex ] +@kindex @{ +@kindex @} +@item [ ] @{ @} +In the @i{search view} (@pxref{Keyword search}), these keys add new +search words (@kbd{[} and @kbd{]}) or new regular expressions (@kbd{@{} +and @kbd{@}}) to the query string. The opening bracket/brace will add a +positive search term prefixed by @samp{+}, indicating that this search +term @i{must} occur/match in the entry. Closing bracket/brace add a +negative search term which @i{must not} occur/match in the entry for it +to be selected. + + @tsubheading{Remote editing} @cindex remote editing, from agenda @@ -5744,7 +5764,10 @@ right spot in @code{org-agenda-custom-commands}. For example: (org-agenda-prefix-format " Mixed: "))) ("U" tags-tree "+boss-urgent" ((org-show-following-heading nil) - (org-show-hierarchy-above nil))))) + (org-show-hierarchy-above nil))) + ("N" search "" + ((org-agenda-files '("~org/notes.org")) + (org-agenda-text-search-extra-files nil))))) @end group @end lisp @@ -5754,7 +5777,8 @@ priority, and the prefix format is modified to just say @samp{ Mixed: } instead of giving the category of the entry. The sparse tags tree of @kbd{C-c a U} will now turn out ultra-compact, because neither the headline hierarchy above the match, nor the headline following the match -will be shown. +will be shown. The command @kbd{C-c a N} will do a text search limited +to only a single file. For command sets creating a block agenda, @code{org-agenda-custom-commands} has two separate spots for setting -- 2.11.4.GIT