alphapapa / org-ql

A searching tool for Org-mode, including custom query languages, commands, saved searches and agenda-like views, etc.
GNU General Public License v3.0
1.35k stars 104 forks source link

Calling `org-ql-sparse-tree` programmatically #362

Closed ivanperez-keera closed 11 months ago

ivanperez-keera commented 11 months ago

I'm trying to attach certain org-ql sparse tree queries to menu entries in emacs. I know I can call custom functions (I've checked that that works).

I've associated the following function to a menu entry:

(defun interactive-week4-tree()
(interactive)
(org-ql-sparse-tree "(tags \"week4\")")
)

When I call the matching menu entry, I see at the bottom of my file the message 0 matches. However, when I execute M-x org-ql-sparse-tree and type (tags "week4") when prompted for a query, several headlines come up.

What am I missing? Should I be passing additional arguments to org-ql-sparse-tree, or invoking it in a different way?

Thanks!

ivanperez-keera commented 11 months ago

I run into the same issue if I try to run (org-ql-sparse-tree "(tags \"week4\")") with M-:

ivanperez-keera commented 11 months ago

I think this is unrelated to org-ql-sparse-tree. Basic searches with constants like (org-ql-sparse-tree "true") work just fine. It's probably just an issue with escaping the double quotes. I'm just lisp-illiterate :(

alphapapa commented 11 months ago

Hi Ivan,

I'm not sure if this will help, but try passing the query as a sexp rather than a string, i.e.

(org-ql-sparse-tree '(tags "week4"))
ivanperez-keera commented 11 months ago

Thanks! So that works. However, I'm composing this query using many sub-strings, so ultimately I want to do something like: (org-ql-sparse-tree query-string).

To turn the string into an s-exp, I've tried:

(org-ql-sparse-tree (read-from-string "(tags \"week4\")"))

But that doesn't work. I could potentially use the non-sexp query syntax, but is it possible to nest ors and ands with that?

alphapapa commented 11 months ago

Hm, well, as you can see here (though I realize your familiarity with Elisp is limited):

https://github.com/alphapapa/org-ql/blob/eb5377320fcfd38354d6e9e3e655969ae3c0e052/org-ql-search.el#L114-L118

When the string starts with an open paren or a quotation mark, it's passed through read, which turns it into a sexp. So unless I'm missing something, there shouldn't even be a problem with what you were doing first.

Anyway, if you want to use the sexp-based query syntax, I'd recommend not composing the query from string parts but from sexps. It's not hard; see the Elisp manual section on backquoting and splicing. If you're familiar with Python (as a Haskeller, you probably are), it's like using the * and ** unpacking operators to unpack one list into another.

I could potentially use the non-sexp query syntax, but is it possible to nest ors and ands with that?

Not yet, but that is planned. There's a PR about it too.

ivanperez-keera commented 11 months ago

Thanks for the very quick reply.

I am almost there. I was able to compose everything without strings, except for adding the date for the :to argument of a scheduled predicate.

This is the smallest reproducible example:

(defun interactive-demo (last-date)
 (interactive (list
                 (org-read-date "" 'totime nil nil (current-time) "")))

 (progn
   (setq last-day (format-time-string "%Y-%m-%d" last-date))
   (setq day (concat "\"" last-day "\""))
   (message day) ;; Just for debugging
   (org-ql-sparse-tree '(scheduled :to day))
 )
)

If I replace day with "2023-07-30" (that is, if I hardcode that string in my lisp function), then I get a short list with only items scheduled until today. If I use day or last-day in the call to org-ql-sparse-tree, then I see items scheduled for 2024 (past the end of the range).

I tried it with let too, just in case that made a difference.

ivanperez-keera commented 11 months ago

I'm guessing this has something to do with the expression being quoted. Sorry for asking such elementary questions. I'm sure this is novice level for a lisper.

alphapapa commented 11 months ago

This is why you need to read the Elisp manual sections 10.3 and 10.4. :)

Try this:

(defun ipk/org-sparse-tree-scheduled-to-date (date)
  "Show a sparse tree with items scheduled to DATE.
DATE is a Lisp timestamp.  Interactively, prompt for DATE."
  (interactive (list (org-read-date "" 'totime nil nil (current-time) "")))
  (org-ql-sparse-tree `(scheduled :to ,(format-time-string "%Y-%m-%d" date))))

By the way, for debugging, this is an ideal case for using Edebug. See the manual for details, but to start, press C-u C-M-x on the defun form, then call the command, and use SPC/n, etc. to move through the forms to see how it evaluates at each step.

ivanperez-keera commented 11 months ago

Thanks! Reading those sections did help :)