问题
The function (org-heading-components)
and (org-element-property)
produce integers for the number of stars and also for the priority. I'd like to store the entire headline as a variable and then use re-search-forward
(or a similar function) to go back to that heading, but I foresee the problem that will occur when it cannot find an integer. I need to store the whole heading as a variable, because I often have todo entries with duplicate titles but the other components are diferent.
For example, the following todo:
** Active [#A] Ask the geniuses on stackoverflow how to do this. :lawlist:
when evaluated with (org-heading-components)
looks like this:
(2 2 "Active" 65 "Ask the geniuses on stackoverflow how to do this." ":lawlist:")
So, when storing that as a variable and later using re-search-forward
there will be problems because 2 2
is not the same as **
, and 65
is not the same as [#A]
.
(defun lawlist ()
(interactive)
(let* (
(beg (point))
(complete-heading (org-heading-components) ))
* * *
(goto-char (point-min))
(re-search-forward complete-heading nil t) ))
回答1:
There's a brilliant part of org that might suit you: org-id-copy
and
org-id-goto
. It works with precision across buffers and sessions:
org-id-copy
produces a string. You can feed that string to
org-id-goto
which will take you to that heading. Even if you've
closed the original buffer. Even if you've restarted Emacs.
回答2:
You should be able to convert the output as follows:
- The first # is the current level (# of stars)
- The second number is the reduced headline level, applicable if
org-odd-levels-only
is set, but this is not regarding output. - Todo keyword
- Priority character (65 is ASCII code for A)
- Headline text
- Tags or nil
The following will return the headline string as shown in the buffer. It will not work with re-search-forward
but will work with search-forward
(It does not escape any characters).
(defun zin/search-test ()
(interactive)
(let ((head (org-element-interpret-data (org-element-at-point))))
(message "%s" (format "%s" (car (split-string head "\n"))))))
This does not set it to any variable, you'll have to wrap it in an appropriate function that will set your desired variable. Then use (search-forward <var> nil t)
to match it, without it erroring out if it cannot find it.
回答3:
EDIT (December 15, 2013): Updated solution based upon the variable org-heading-regexp
(defined within org.el
) and a modification thereof to include (if it exists) a second line containing a deadline - i.e., lawlist-org-heading-regexp
. The revision also includes a nifty function regexp-quote
that was just taught to me by @Drew over on superuser: https://superuser.com/questions/688781/how-to-highlight-string-and-unhighlight-string-in-buffer-make-overlay?noredirect=1#comment874515_688781 (buffer-substring-no-properties beg end)
is used to set the string as a variable.
EDIT (December 17, 2013): Added isearch-highlight
and isearch-dehighlight
, and commented out highlight-regexp
and unhighlight-regexp
. When moving the point around with more complex functions, highlight-regexp
does not reliably highlight the entire string -- this may be because the screen has not refreshed, or it may also be caused by other factors -- e.g., hl-line-mode, etc.) -- placing various sit-for 0
did not fix the issue with highlight-regexp
-- isearch-highlight
works better.
EDIT (January 6, 2014): See also this related thread for a complete regexp to match any element of the entire todo from stars through to the end of the notes: https://stackoverflow.com/a/20960301/2112489
(require 'org)
(defvar lawlist-org-heading-regexp
"^\\(\\*+\\)\\(?: +\\(.*?\\)\\)?[ \t]*\\(\n.*DEADLINE.*$\\)"
"Match headline, plus second line with a deadline.")
(defun example ()
(interactive)
(switch-to-buffer (get-buffer-create "foo"))
(org-mode)
(insert "* Example\n\n")
(insert "** Active [#A] This is an active todo. :lawlist:\n")
(insert " DEADLINE: <2013-12-15 Sun 08:00> SCHEDULED: <2013-12-15 Sun>\n\n")
(insert "** Next-Action [#B] This is an inactive todo. :lawlist:\n")
(insert " DEADLINE: <2013-12-16 Mon 08:00> SCHEDULED: <2013-12-16 Mon>")
(goto-char (point-min))
(sit-for 2)
(re-search-forward (regexp-quote "** Active [#A] "))
(sit-for 2)
(let ((init-pos (point)))
(org-back-to-heading t)
(let* (
lawlist-item-whole
lawlist-item-partial
(beg (point)))
(if (and
(looking-at org-heading-regexp)
(and (looking-at lawlist-org-heading-regexp) (match-string 3)))
(re-search-forward lawlist-org-heading-regexp nil t)
(re-search-forward org-heading-regexp nil t))
(let ((end (point)))
(setq lawlist-item-whole (buffer-substring-no-properties beg end))
(setq lawlist-item-partial (buffer-substring-no-properties beg init-pos))
(re-search-backward (regexp-quote lawlist-item-whole) nil t)
;; (highlight-regexp (regexp-quote lawlist-item-whole))
(isearch-highlight beg end)
(sit-for 2)
;; (unhighlight-regexp (regexp-quote lawlist-item-whole))
(isearch-dehighlight)
(re-search-forward (regexp-quote lawlist-item-partial) nil t)
(sit-for 2)
(kill-buffer "foo")))))
EDIT (October 27, 2013): Prior solution that is being preserved temporarily as a historical part of the evolution process towards a final answer. However, it is no longer a preferred method.
(defun lawlist-org-heading-components ()
(org-back-to-heading t)
(if (let (case-fold-search) (looking-at org-complex-heading-regexp))
(concat
(cond
((equal (org-match-string-no-properties 1) "**")
"^[*][*]")
((equal (org-match-string-no-properties 1) "*")
"^[*]"))
(cond
((and (match-end 2) (aref (match-string 2) 1))
(concat " " (org-match-string-no-properties 2))))
(cond
((and (match-end 3) (aref (match-string 3) 2))
(concat " \\" (org-match-string-no-properties 3))))
(cond
((and (match-end 4) (aref (match-string 4) 3))
(concat " " (org-match-string-no-properties 4))))
(cond
((and (match-end 5) (aref (match-string 5) 4))
(concat " " (org-match-string-no-properties 5)))))))
来源:https://stackoverflow.com/questions/19620273/how-to-search-for-a-complete-org-headline-that-was-saved-as-a-variable