Function `org-link-search' does exact headline search

* lisp/org.el (org-link-search): Change headline search such that it
always does an exact search, ignoring spaces.

* testing/lisp/test-org.el (test-org/fuzzy-links): Test exact headline
match with spaces and cookies.

* doc/org.texi (External links): Cleanup footnote about the
`org-link-search-must-match-exact-headline' option for text searches
and add a footnote about the effect of the same option for heading
searches.

* doc/ORG-NEWS: Document changes.
This commit is contained in:
Alan Schmitt 2014-12-12 08:26:05 +01:00 committed by Nicolas Goaziou
parent a9a9af030d
commit 6d691e2aa8
4 changed files with 68 additions and 27 deletions

View File

@ -3561,10 +3561,14 @@ file:projects.org::some words @r{text search in Org file}@footnote{
The actual behavior of the search will depend on the value of
the option @code{org-link-search-must-match-exact-headline}. If its value
is @code{nil}, then a fuzzy text search will be done. If it is t, then only the
exact headline will be matched. If the value is @code{'query-to-create},
then an exact headline will be searched; if it is not found, then the user
will be queried to create it.}
file:projects.org::*task title @r{heading search in Org file}
exact headline will be matched, ignoring spaces and cookies. If the value is
@code{query-to-create}, then an exact headline will be searched; if it is not
found, then the user will be queried to create it.}
file:projects.org::*task title @r{heading search in Org
file}@footnote{ Headline searches always match the exact headline, ignoring
spaces and cookies. If the headline is not found and the value of the option
@code{org-link-search-must-match-exact-headline} is @code{query-to-create},
then the user will be queried to create it.}
file+sys:/path/to/file @r{open via OS, like double-click}
file+emacs:/path/to/file @r{force opening by Emacs}
docview:papers/last.pdf::NNN @r{open in doc-view mode at page}

View File

@ -218,6 +218,11 @@ The build system has been enhanced to allow test selection with a
regular expression by defining =BTEST_RE= during the test invocation.
This is especially useful during bisection to find just when a
particular test failure was introduced.
*** Exact heading search for external links ignore spaces and cookies
Exact heading search for links now ignore spaces and cookies. This is
the case for links of the form ~file:projects.org::*task title~, as
well as links of the form ~file:projects.org::some words~
when ~org-link-search-must-match-exact-headline~ is not nil.
* Version 8.2
** Incompatible changes

View File

@ -11007,8 +11007,7 @@ visibility around point, thus ignoring
org-emphasis-alist)
"\\|") "\\)"))
(pos (point))
(pre nil) (post nil)
words re0 re1 re2 re3 re4_ re4 re5 re2a re2a_ reall)
words re0 re2 re4_ re4 re5 re2a re2a_ reall)
(cond
;; First check if there are any special search functions
((run-hook-with-args-until-success 'org-execute-file-search-functions s))
@ -11062,14 +11061,34 @@ visibility around point, thus ignoring
((derived-mode-p 'org-mode)
(org-occur (match-string 1 s)))
(t (org-do-occur (match-string 1 s)))))
((and (derived-mode-p 'org-mode) org-link-search-must-match-exact-headline)
(and (equal (string-to-char s) ?*) (setq s (substring s 1)))
((and (derived-mode-p 'org-mode)
(or (and (equal (string-to-char s) ?*) (setq s (substring s 1)))
org-link-search-must-match-exact-headline))
;; Headline search.
(goto-char (point-min))
(cond
((let (case-fold-search)
(re-search-forward (format org-complex-heading-regexp-format
(regexp-quote s))
nil t))
(re-search-forward
(let* ((wspace "[ \t]")
(wspaceopt (concat wspace "*"))
(cookie (concat "\\(?:"
wspaceopt
"\\[[0-9]*\\(?:%\\|/[0-9]*\\)\\]"
wspaceopt
"\\)"))
(sep (concat "\\(?:" wspace "+\\|" cookie "+\\)")))
(concat
org-outline-regexp-bol
"\\(?:" org-todo-regexp "[ \t]+\\)?"
"\\(?:\\[#.\\][ \t]+\\)?"
sep "*"
(mapconcat #'identity
(org-split-string (regexp-quote s))
(concat sep "+"))
sep "*"
(org-re "\\(?:[ \t]+:[[:alnum:]_@#%%:]+:\\)?")
"[ \t]*$"))
nil t))
;; OK, found a match
(setq type 'dedicated)
(goto-char (match-beginning 0)))
@ -11085,11 +11104,6 @@ visibility around point, thus ignoring
(error "No match"))))
(t
;; A normal search string
(when (equal (string-to-char s) ?*)
;; Anchor on headlines, post may include tags.
(setq pre "^\\*+[ \t]+\\(?:\\sw+\\)?[ \t]*"
post (org-re "[ \t]*\\(?:[ \t]+:[[:alnum:]_@#%:+]:[ \t]*\\)?$")
s (substring s 1)))
(remove-text-properties
0 (length s)
'(face nil mouse-face nil keymap nil fontified nil) s)
@ -11106,15 +11120,9 @@ visibility around point, thus ignoring
"[^a-zA-Z_\r\n]+") "\\)[^a-zA-Z_]")
re4 (concat "[^a-zA-Z_]" re4_)
re1 (concat pre re2 post)
re3 (concat pre (if pre re4_ re4) post)
re5 (concat pre ".*" re4)
re2 (concat pre re2)
re2a (concat pre (if pre re2a_ re2a))
re4 (concat pre (if pre re4_ re4))
reall (concat "\\(" re0 "\\)\\|\\(" re1 "\\)\\|\\(" re2
"\\)\\|\\(" re3 "\\)\\|\\(" re4 "\\)\\|\\("
re5 "\\)"))
re5 (concat ".*" re4)
reall (concat "\\(" re0 "\\)\\|\\(" re2 "\\)\\|\\(" re4
"\\)\\|\\(" re5 "\\)"))
(cond
((eq type 'org-occur) (org-occur reall))
((eq type 'occur) (org-do-occur (downcase reall) 'cleanup))
@ -11122,10 +11130,8 @@ visibility around point, thus ignoring
(setq type 'fuzzy)
(if (or (and (org-search-not-self 1 re0 nil t)
(setq type 'dedicated))
(org-search-not-self 1 re1 nil t)
(org-search-not-self 1 re2 nil t)
(org-search-not-self 1 re2a nil t)
(org-search-not-self 1 re3 nil t)
(org-search-not-self 1 re4 nil t)
(org-search-not-self 1 re5 nil t))
(goto-char (match-beginning 1))

View File

@ -1331,6 +1331,32 @@
(goto-line 3)
(org-open-at-point)
(looking-at "\\* Test")))
;; With a leading star in link, enforce exact heading match, even
;; with `org-link-search-must-match-exact-headline' set to nil.
(should-error
(org-test-with-temp-text "* Test 1\nFoo Bar\n<point>[[*Test]]"
(let ((org-link-search-must-match-exact-headline nil))
(org-open-at-point))))
;; Heading match should not care about spaces, cookies, todo
;; keywords, priorities, and tags.
(should
(let ((first-line
"** TODO [#A] [/] Test [1/2] [33%] 1 \t 2 [%] :work:urgent: "))
(org-test-with-temp-text
(concat first-line "\nFoo Bar\n<point>[[*Test 1 2]]")
(let ((org-link-search-must-match-exact-headline nil)
(org-todo-regexp "TODO"))
(org-open-at-point))
(looking-at (regexp-quote first-line)))))
;; Heading match should still be exact.
(should-error
(let ((first-line
"** TODO [#A] [/] Test [1/2] [33%] 1 \t 2 [%] :work:urgent: "))
(org-test-with-temp-text
(concat first-line "\nFoo Bar\n<point>[[*Test 1]]")
(let ((org-link-search-must-match-exact-headline nil)
(org-todo-regexp "TODO"))
(org-open-at-point)))))
;; Correctly un-hexify fuzzy links.
(should
(org-test-with-temp-text "* With space\n[[*With%20space][With space]]"