Browse Source

General operators for property searches.

We have now numerical comparisons, and we can do < and > for strings.
Carsten Dominik 17 years ago
parent
commit
d38aab0443
5 changed files with 98 additions and 92 deletions
  1. 5 0
      ChangeLog
  2. 13 10
      Makefile
  3. 43 70
      doc/org.texi
  4. 1 1
      lisp/org-table.el
  5. 36 11
      lisp/org.el

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+2008-04-23  Carsten Dominik  <dominik@science.uva.nl>
+
+	* lisp/org.el (org-op-to-function, org<>, org-string<=)
+	(org-string>=, org-string<>): New functions.
+
 2008-04-21  Carsten Dominik  <dominik@science.uva.nl>
 2008-04-21  Carsten Dominik  <dominik@science.uva.nl>
 
 
 	* lisp/org-remember.el (org-get-x-clipboard): Protect the call to
 	* lisp/org-remember.el (org-get-x-clipboard): Protect the call to

+ 13 - 10
Makefile

@@ -61,31 +61,33 @@ CP = cp -p
 
 
 # The following variables need to be defined by the maintainer
 # The following variables need to be defined by the maintainer
 LISPF      = 	org.el			\
 LISPF      = 	org.el			\
+		org-agenda.el		\
 	     	org-archive.el		\
 	     	org-archive.el		\
+		org-bbdb.el		\
+		org-bibtex.el		\
+	     	org-clock.el		\
 	     	org-colview.el		\
 	     	org-colview.el		\
 	     	org-colview-xemacs.el	\
 	     	org-colview-xemacs.el	\
 	     	org-compat.el		\
 	     	org-compat.el		\
-	     	org-macs.el		\
-	     	org-clock.el		\
-		org-table.el		\
 		org-exp.el		\
 		org-exp.el		\
-		org-faces.el		\
-		org-remember.el		\
-		org-agenda.el		\
-		org-publish.el		\
-		org-mouse.el		\
 		org-export-latex.el	\
 		org-export-latex.el	\
-		org-bbdb.el		\
-		org-bibtex.el		\
+		org-faces.el		\
 		org-gnus.el		\
 		org-gnus.el		\
 		org-info.el		\
 		org-info.el		\
 		org-infojs.el		\
 		org-infojs.el		\
 		org-irc.el		\
 		org-irc.el		\
 		org-mac-message.el	\
 		org-mac-message.el	\
+	     	org-macs.el		\
+		org-mew.el              \
 		org-mhe.el		\
 		org-mhe.el		\
+		org-mouse.el		\
+		org-publish.el		\
+		org-remember.el		\
 		org-rmail.el		\
 		org-rmail.el		\
+		org-table.el		\
 		org-vm.el		\
 		org-vm.el		\
 		org-wl.el
 		org-wl.el
+
 LISPFILES0 = $(LISPF:%=lisp/%)
 LISPFILES0 = $(LISPF:%=lisp/%)
 LISPFILES  = $(LISPFILES0) lisp/org-install.el
 LISPFILES  = $(LISPFILES0) lisp/org-install.el
 ELCFILES0  = $(LISPFILES0:.el=.elc)
 ELCFILES0  = $(LISPFILES0:.el=.elc)
@@ -279,6 +281,7 @@ lisp/org-bbdb.elc:         lisp/org.elc
 lisp/org-bibtex.elc:       lisp/org.elc
 lisp/org-bibtex.elc:       lisp/org.elc
 lisp/org-clock.elc:        lisp/org.elc
 lisp/org-clock.elc:        lisp/org.elc
 lisp/org-colview.elc:      lisp/org.elc
 lisp/org-colview.elc:      lisp/org.elc
+lisp/org-colview-xemacs.elc:      lisp/org.elc
 lisp/org-compat.elc:
 lisp/org-compat.elc:
 lisp/org-exp.elc:          lisp/org.elc lisp/org-agenda.elc
 lisp/org-exp.elc:          lisp/org.elc lisp/org-agenda.elc
 lisp/org-export-latex.elc: lisp/org.elc lisp/org-exp.elc
 lisp/org-export-latex.elc: lisp/org.elc lisp/org-exp.elc

+ 43 - 70
doc/org.texi

@@ -3654,23 +3654,30 @@ CLOCKSUM     @r{The sum of CLOCK intervals in the subtree.  @code{org-clock-sum}
 @cindex properties, searching
 @cindex properties, searching
 @cindex searching, of properties
 @cindex searching, of properties
 
 
-To create sparse trees and special lists with selection based on
-properties, the same commands are used as for tag searches (@pxref{Tag
-searches}), and the same logic applies.  For example, a search string
+To create sparse trees and special lists with selection based on properties,
+the same commands are used as for tag searches (@pxref{Tag searches}), and
+the same logic applies.  For example, here is a search string:
 
 
 @example
 @example
-+work-boss+PRIORITY="A"+Coffee="unlimited"+Effort=""+With=@{Sarah\|Denny@}
++work-boss+PRIORITY="A"+Coffee="unlimited"+Effort<2+With=@{Sarah\|Denny@}
 @end example
 @end example
 
 
 @noindent
 @noindent
-finds entries tagged @samp{:work:} but not @samp{:boss:}, which
-also have a priority value @samp{A}, a @samp{:Coffee:} property with the
-value @samp{unlimited}, an @samp{Effort} property that is undefined or
-empty, and a @samp{:With:} property that is matched by
-the regular expression @samp{Sarah\|Denny}.
-
-You can configure Org mode to use property inheritance during a search,
-see @ref{Property inheritance} for details.
+If the comparison value is a plain number, a numerical comparison is done,
+and the allowed operators are @samp{<}, @samp{=}, @samp{>}, @samp{<=},
+@samp{>=}, and @samp{<>}.  If the comparison value is enclosed in double
+quotes, a string comparison is done, and the same operators are allowed.  If
+the comparison value is enclosed in curly braces, a regexp match is
+performed.  So the search string in the example finds entries tagged
+@samp{:work:} but not @samp{:boss:}, which also have a priority value
+@samp{A}, a @samp{:Coffee:} property with the value @samp{unlimited}, an
+@samp{Effort} property that is numerically smaller than 2, and a
+@samp{:With:} property that is matched by the regular expression
+@samp{Sarah\|Denny}.
+
+You can configure Org mode to use property inheritance during a search, but
+beware that this can slow down searches considerably.  See @ref{Property
+inheritance} for details.
 
 
 There is also a special command for creating sparse trees based on a
 There is also a special command for creating sparse trees based on a
 single property:
 single property:
@@ -4241,11 +4248,12 @@ M-S-@key{right}/@key{left}   @r{One month forward/backward.}
 @key{RET}           @r{Choose date in calendar.}
 @key{RET}           @r{Choose date in calendar.}
 @end example
 @end example
 
 
-The actions of the date/time prompt may seem complex, but I assure you
-they will grow on you.  To help you understand what is going on, the
-current interpretation of your input will be displayed live in the
-minibuffer@footnote{If you find this distracting, turn the display of
-with @code{org-read-date-display-live}.}.
+The actions of the date/time prompt may seem complex, but I assure you they
+will grow on you, and you will start getting annoyed by pretty much any other
+way of entering a date/time out there.  To help you understand what is going
+on, the current interpretation of your input will be displayed live in the
+minibuffer@footnote{If you find this distracting, turn the display of with
+@code{org-read-date-display-live}.}.
 
 
 @node Custom time format,  , The date/time prompt, Creating timestamps
 @node Custom time format,  , The date/time prompt, Creating timestamps
 @subsection Custom time format
 @subsection Custom time format
@@ -4883,7 +4891,7 @@ for details.
 @item C-u C-c C-w
 @item C-u C-c C-w
 Use the refile interface to jump to a heading.
 Use the refile interface to jump to a heading.
 @kindex C-u C-u C-c C-w
 @kindex C-u C-u C-c C-w
-@item C- C-u C-c C-w
+@item C-u C-u C-c C-w
 Jump to the location where @code{org-refile} last moved a tree to.
 Jump to the location where @code{org-refile} last moved a tree to.
 @end table
 @end table
 
 
@@ -6469,7 +6477,7 @@ environments and math templates.  Inside Org mode, you can make use of
 some of the features of CDLaTeX mode.  You need to install
 some of the features of CDLaTeX mode.  You need to install
 @file{cdlatex.el} and @file{texmathp.el} (the latter comes also with
 @file{cdlatex.el} and @file{texmathp.el} (the latter comes also with
 AUCTeX) from @url{http://www.astro.uva.nl/~dominik/Tools/cdlatex}.
 AUCTeX) from @url{http://www.astro.uva.nl/~dominik/Tools/cdlatex}.
-Don't turn CDLaTeX mode itself under Org mode, but use the light
+Don't use CDLaTeX mode itself under Org mode, but use the light
 version @code{org-cdlatex-mode} that comes as part of Org mode.  Turn it
 version @code{org-cdlatex-mode} that comes as part of Org mode.  Turn it
 on for the current buffer with @code{M-x org-cdlatex-mode}, or for all
 on for the current buffer with @code{M-x org-cdlatex-mode}, or for all
 Org files with
 Org files with
@@ -6829,16 +6837,15 @@ view:    @r{Initial view when website is first shown.  Possible values are}
          showall   @r{Folding interface, all headlines and text visible.}
          showall   @r{Folding interface, all headlines and text visible.}
 sdepth:  @r{Maximum headline level that will still become an independent}
 sdepth:  @r{Maximum headline level that will still become an independent}
          @r{section for info and folding modes.  The default is taken from}
          @r{section for info and folding modes.  The default is taken from}
-         @r{@code{org-headline-levels} (= the @code{H} @code{#+OPTIONS} switch).}
+         @r{@code{org-headline-levels} (= the @code{H} switch in @code{#+OPTIONS}).}
          @r{If this is smaller than in @code{org-headline-levels}, each}
          @r{If this is smaller than in @code{org-headline-levels}, each}
          @r{info/folding section can still contain children headlines.}
          @r{info/folding section can still contain children headlines.}
-         @r{Default is @code{org-headline-levels} (= the @code{H} @code{#+OPTIONS} switch).}
 toc:     @r{Should the table of content @emph{initially} be visible?}
 toc:     @r{Should the table of content @emph{initially} be visible?}
          @r{Even when @code{nil}, you can always get to the toc with @kbd{i}.}
          @r{Even when @code{nil}, you can always get to the toc with @kbd{i}.}
 tdepth:  @r{The depth of the table of contents.  The defaults are taken from}
 tdepth:  @r{The depth of the table of contents.  The defaults are taken from}
          @r{the variables @code{org-headline-levels} and @code{org-export-with-toc}.}
          @r{the variables @code{org-headline-levels} and @code{org-export-with-toc}.}
 ltoc:    @r{Should there be short contents (children) in each section?}
 ltoc:    @r{Should there be short contents (children) in each section?}
-mouse:   @r{Headings are highlighted when the mouse is over themq.  Should be}
+mouse:   @r{Headings are highlighted when the mouse is over them.  Should be}
          @r{@samp{underline} (default) or a background color like @samp{#cccccc}.}
          @r{@samp{underline} (default) or a background color like @samp{#cccccc}.}
 buttons: @r{Should view-toggle buttons be everywhere?  When @code{nil} (the}
 buttons: @r{Should view-toggle buttons be everywhere?  When @code{nil} (the}
          @r{default), only one such button will be present.}
          @r{default), only one such button will be present.}
@@ -8247,51 +8254,11 @@ Org.
 @section Third-party extensions for Org
 @section Third-party extensions for Org
 @cindex extension, third-party
 @cindex extension, third-party
 
 
-The following extensions for Org have been written by other people:
-
-@table @asis
-@cindex @file{org-publish.el}
-@item @file{org-publish.el} by David O'Toole
-This package provides facilities for publishing related sets of Org
-files together with linked files like images as web pages.  It is
-highly configurable and can be used for other publishing purposes as
-well.  As of Org version 4.30, @file{org-publish.el} is part of the
-Org distribution.  It is not yet part of Emacs, however, a delay
-caused by the preparations for the 22.1 release.  In the mean time,
-@file{org-publish.el} can be downloaded from David's site:
-@url{http://dto.freeshell.org/e/org-publish.el}.
-@cindex @file{org-mouse.el}
-@item @file{org-mouse.el} by Piotr Zielinski
-This package implements extended mouse functionality for Org.  It
-allows you to cycle visibility and to edit the document structure with
-the mouse.  Best of all, it provides a context-sensitive menu on
-@key{mouse-3} that changes depending on the context of a mouse-click.
-As of Org version 4.53, @file{org-mouse.el} is part of the
-Org distribution.  It is not yet part of Emacs, however, a delay
-caused by the preparations for the 22.1 release.  In the mean time,
-@file{org-mouse.el} can be downloaded from Piotr's site:
-@url{http://www.cl.cam.ac.uk/~pz215/files/org-mouse.el}.
-@cindex @file{org-blog.el}
-@item @file{org-blog.el} by David O'Toole
-A blogging plug-in for @file{org-publish.el}.@*
-@url{http://dto.freeshell.org/notebook/OrgMode.html}.
-@cindex @file{blorg.el}
-@item @file{blorg.el} by Bastien Guerry
-Publish Org files as
-blogs. @url{http://www.cognition.ens.fr/~guerry/blorg.html}.
-@cindex @file{org2rem.el}
-@item @file{org2rem.el} by Bastien Guerry
-Translates Org files into something readable by
-Remind. @url{http://www.cognition.ens.fr/~guerry/u/org2rem.el}.
-@item @file{org-toc.el} by Bastien Guerry
-Produces a simple table of contents of an Org file, for easy
-navigation. @url{http://www.cognition.ens.fr/~guerry/u/org-registry.el}.
-@item @file{org-registry.el} by Bastien Guerry
-Find which Org-file link to a certain document.
-@url{http://www.cognition.ens.fr/~guerry/u/org2rem.el}.
-@end table
-
-@page
+There are lots of extensions that have been written by other people.  Most of
+them have either been integrated into Org by now, or they can be found in the
+Org distribution, in the @file{contrib} directory.  The list has gotten too
+long to cover in any detail here, but there is a seaparate manual for these
+extensions.
 
 
 @node Adding hyperlink types, Tables in arbitrary syntax, Extensions, Extensions and Hacking
 @node Adding hyperlink types, Tables in arbitrary syntax, Extensions, Extensions and Hacking
 @section Adding hyperlink types
 @section Adding hyperlink types
@@ -8774,7 +8741,8 @@ The corresponding block writer function could look like this:
 If you want to make sure that all dynamic blocks are always up-to-date,
 If you want to make sure that all dynamic blocks are always up-to-date,
 you could add the function @code{org-update-all-dblocks} to a hook, for
 you could add the function @code{org-update-all-dblocks} to a hook, for
 example @code{before-save-hook}.  @code{org-update-all-dblocks} is
 example @code{before-save-hook}.  @code{org-update-all-dblocks} is
-written in a way that is does nothing in buffers that are not in Org.
+written in a way that is does nothing in buffers that are not in
+@code{org-mode}.
 
 
 @node Special agenda views, Using the property API, Dynamic blocks, Extensions and Hacking
 @node Special agenda views, Using the property API, Dynamic blocks, Extensions and Hacking
 @section Special agenda views
 @section Special agenda views
@@ -8820,6 +8788,12 @@ like this:
 Note that this also binds @code{org-agenda-overriding-header} to get a
 Note that this also binds @code{org-agenda-overriding-header} to get a
 meaningful header in the agenda view.
 meaningful header in the agenda view.
 
 
+A general way to create custom searches is to base them on a search for
+entries with a certain level limit.  If you want to study all entries with
+your custom search function, simply do a search for @samp{LEVEL>0}, and then
+use @code{org-agenda-skip-function} to select the entries you really want to
+have.
+
 You may also put a Lisp form into @code{org-agenda-skip-function}.  In
 You may also put a Lisp form into @code{org-agenda-skip-function}.  In
 particular, you may use the functions @code{org-agenda-skip-entry-if}
 particular, you may use the functions @code{org-agenda-skip-entry-if}
 and @code{org-agenda-skip-subtree-if} in this form, for example:
 and @code{org-agenda-skip-subtree-if} in this form, for example:
@@ -8852,7 +8826,6 @@ like this, even without defining a special function:
     (org-agenda-overriding-header "Projects waiting for something: "))))
     (org-agenda-overriding-header "Projects waiting for something: "))))
 @end lisp
 @end lisp
 
 
-
 @node Using the property API,  , Special agenda views, Extensions and Hacking
 @node Using the property API,  , Special agenda views, Extensions and Hacking
 @section Using the property API
 @section Using the property API
 @cindex API, for properties
 @cindex API, for properties
@@ -8936,7 +8909,7 @@ incorporate project planning functionality directly into a notes file.
 
 
 A special thanks goes to @i{Bastien Guerry} who has not only writen a large
 A special thanks goes to @i{Bastien Guerry} who has not only writen a large
 number of extensions to Org (most of them integrated into the core by now),
 number of extensions to Org (most of them integrated into the core by now),
-but has also helep the development and maintenance of Org so much that e
+but has also helped the development and maintenance of Org so much that he
 should be considered co-author of this package.
 should be considered co-author of this package.
 
 
 Since the first release, literally thousands of emails to me or on
 Since the first release, literally thousands of emails to me or on

+ 1 - 1
lisp/org-table.el

@@ -1767,7 +1767,7 @@ When NAMED is non-nil, look for a named equation."
       (when (looking-at "\\([ \t]*\n\\)*#\\+TBLFM: *\\(.*\\)")
       (when (looking-at "\\([ \t]*\n\\)*#\\+TBLFM: *\\(.*\\)")
 	(setq strings (org-split-string (match-string 2) " *:: *"))
 	(setq strings (org-split-string (match-string 2) " *:: *"))
 	(while (setq string (pop strings))
 	(while (setq string (pop strings))
-	  (when (string-match "\\(@[0-9]+\\$[0-9]+\\|\\$\\([a-zA-Z0-9]+\\)\\) *= *\\(.*[^ \t]\\)" string)
+	  (when (string-match "\\`\\(@[0-9]+\\$[0-9]+\\|\\$\\([a-zA-Z0-9]+\\)\\) *= *\\(.*[^ \t]\\)" string)
 	    (setq scol (if (match-end 2)
 	    (setq scol (if (match-end 2)
 			   (match-string 2 string)
 			   (match-string 2 string)
 			 (match-string 1 string))
 			 (match-string 1 string))

+ 36 - 11
lisp/org.el

@@ -8764,10 +8764,11 @@ also TODO lines."
 
 
   ;; Parse the string and create a lisp form
   ;; Parse the string and create a lisp form
   (let ((match0 match)
   (let ((match0 match)
-	(re (org-re "^&?\\([-+:]\\)?\\({[^}]+}\\|LEVEL=\\([0-9]+\\)\\|\\([[:alnum:]_]+\\)=\\({[^}]+}\\|\"[^\"]*\"\\)\\|[[:alnum:]_@]+\\)"))
+	(re (org-re "^&?\\([-+:]\\)?\\({[^}]+}\\|LEVEL\\([<=>]\\{1,2\\}\\)\\([0-9]+\\)\\|\\([[:alnum:]_]+\\)\\([<>=]\\{1,2\\}\\)\\({[^}]+}\\|\"[^\"]*\"\\|-?[.0-9]+\\(?:[eE][-+]?[0-9]+\\)?\\)\\|[[:alnum:]_@]+\\)"))
 	minus tag mm
 	minus tag mm
 	tagsmatch todomatch tagsmatcher todomatcher kwd matcher
 	tagsmatch todomatch tagsmatcher todomatcher kwd matcher
-	orterms term orlist re-p level-p prop-p pn pv cat-p gv)
+	orterms term orlist re-p str-p level-p level-op 
+	prop-p pn pv po cat-p gv)
     (if (string-match "/+" match)
     (if (string-match "/+" match)
 	;; match contains also a todo-matching request
 	;; match contains also a todo-matching request
 	(progn
 	(progn
@@ -8792,24 +8793,32 @@ also TODO lines."
 			   (equal (match-string 1 term) "-"))
 			   (equal (match-string 1 term) "-"))
 		tag (match-string 2 term)
 		tag (match-string 2 term)
 		re-p (equal (string-to-char tag) ?{)
 		re-p (equal (string-to-char tag) ?{)
-		level-p (match-end 3)
-		prop-p (match-end 4)
+		level-p (match-end 4)
+		prop-p (match-end 5)
 		mm (cond
 		mm (cond
 		    (re-p `(org-match-any-p ,(substring tag 1 -1) tags-list))
 		    (re-p `(org-match-any-p ,(substring tag 1 -1) tags-list))
-		    (level-p `(= level ,(string-to-number
-					 (match-string 3 term))))
+		    (level-p
+		     (setq level-op (org-op-to-function (match-string 3 term)))
+		     `(,level-op level ,(string-to-number
+					 (match-string 4 term))))
 		    (prop-p
 		    (prop-p
-		     (setq pn (match-string 4 term)
-			   pv (match-string 5 term)
+		     (setq pn (match-string 5 term)
+			   po (match-string 6 term)
+			   pv (match-string 7 term)
 			   cat-p (equal pn "CATEGORY")
 			   cat-p (equal pn "CATEGORY")
 			   re-p (equal (string-to-char pv) ?{)
 			   re-p (equal (string-to-char pv) ?{)
-			   pv (substring pv 1 -1))
+			   str-p (equal (string-to-char pv) ?\")
+			   pv (if (or re-p str-p) (substring pv 1 -1) pv))
+		     (setq po (org-op-to-function po str-p))
 		     (if (equal pn "CATEGORY")
 		     (if (equal pn "CATEGORY")
 			 (setq gv '(get-text-property (point) 'org-category))
 			 (setq gv '(get-text-property (point) 'org-category))
 		       (setq gv `(org-cached-entry-get nil ,pn)))
 		       (setq gv `(org-cached-entry-get nil ,pn)))
 		     (if re-p
 		     (if re-p
 			 `(string-match ,pv (or ,gv ""))
 			 `(string-match ,pv (or ,gv ""))
-		       `(equal ,pv (or ,gv ""))))
+		       (if str-p
+			   `(,po (or ,gv "") ,pv)
+			 `(,po (string-to-number (or ,gv ""))
+			       ,(string-to-number pv) ))))
 		    (t `(member ,(downcase tag) tags-list)))
 		    (t `(member ,(downcase tag) tags-list)))
 		mm (if minus (list 'not mm) mm)
 		mm (if minus (list 'not mm) mm)
 		term (substring term (match-end 0)))
 		term (substring term (match-end 0)))
@@ -8822,7 +8831,7 @@ also TODO lines."
       (setq tagsmatcher (if (> (length orlist) 1) (cons 'or orlist) (car orlist)))
       (setq tagsmatcher (if (> (length orlist) 1) (cons 'or orlist) (car orlist)))
       (setq tagsmatcher
       (setq tagsmatcher
 	    (list 'progn '(setq org-cached-props nil) tagsmatcher)))
 	    (list 'progn '(setq org-cached-props nil) tagsmatcher)))
-
+    (debug)
     ;; Make the todo matcher
     ;; Make the todo matcher
     (if (or (not todomatch) (not (string-match "\\S-" todomatch)))
     (if (or (not todomatch) (not (string-match "\\S-" todomatch)))
 	(setq todomatcher t)
 	(setq todomatcher t)
@@ -8853,6 +8862,22 @@ also TODO lines."
 		    tagsmatcher))
 		    tagsmatcher))
     (cons match0 matcher)))
     (cons match0 matcher)))
 
 
+(defun org-op-to-function (op &optional stringp)
+  (setq op
+	(cond
+	 ((equal  op   "<"       ) '(<     string<      ))
+	 ((equal  op   ">"       ) '(>     string>      ))
+	 ((member op '("<=" "=<")) '(<=    org-string<= ))
+	 ((member op '(">=" "=>")) '(>=    org-string>= ))
+	 ((member op '("="  "==")) '(=     string=      ))
+	 ((member op '("<>" "!=")) '(org<> org-string<> ))))
+  (nth (if stringp 1 0) op))
+
+(defun org<> (a b) (not (= a b)))
+(defun org-string<= (a b) (or (string= a b) (string< a b)))
+(defun org-string>= (a b) (or (string= a b) (string> a b)))
+(defun org-string<> (a b) (not (string= a b)))
+
 (defun org-match-any-p (re list)
 (defun org-match-any-p (re list)
   "Does re match any element of list?"
   "Does re match any element of list?"
   (setq list (mapcar (lambda (x) (string-match re x)) list))
   (setq list (mapcar (lambda (x) (string-match re x)) list))