Function: org-link-search
org-link-search is a byte-compiled function defined in ol.el.gz.
Signature
(org-link-search S &optional AVOID-POS STEALTH NEW-HEADING-CONTAINER)
Documentation
Search for a search string S in the accessible part of the buffer.
If S starts with "#", it triggers a custom ID search.
If S is enclosed within parenthesis, it initiates a coderef search.
If S is surrounded by forward slashes, it is interpreted as
a regular expression. In Org mode files, this will create an
org-occur sparse tree. In ordinary files, occur will be used
to list matches. If the current buffer is in dired-mode, grep
will be used to search in all files.
When AVOID-POS is given, ignore matches near that position.
When optional argument STEALTH is non-nil, do not modify
visibility around point, thus ignoring org-show-context-detail
variable.
When optional argument NEW-HEADING-CONTAINER is an element, any
new heading that is created (see
org-link-search-must-match-exact-headline) will be added as a
subheading of NEW-HEADING-CONTAINER. Otherwise, new headings are
created at level 1 at the end of the accessible part of the
buffer.
Search is case-insensitive and ignores white spaces. Return type
of matched result, which is either dedicated or fuzzy. Search
respects buffer narrowing.
Source Code
;; Defined in /usr/src/emacs/lisp/org/ol.el.gz
(defun org-link-search (s &optional avoid-pos stealth new-heading-container)
"Search for a search string S in the accessible part of the buffer.
If S starts with \"#\", it triggers a custom ID search.
If S is enclosed within parenthesis, it initiates a coderef
search.
If S is surrounded by forward slashes, it is interpreted as
a regular expression. In Org mode files, this will create an
`org-occur' sparse tree. In ordinary files, `occur' will be used
to list matches. If the current buffer is in `dired-mode', grep
will be used to search in all files.
When AVOID-POS is given, ignore matches near that position.
When optional argument STEALTH is non-nil, do not modify
visibility around point, thus ignoring `org-show-context-detail'
variable.
When optional argument NEW-HEADING-CONTAINER is an element, any
new heading that is created (see
`org-link-search-must-match-exact-headline') will be added as a
subheading of NEW-HEADING-CONTAINER. Otherwise, new headings are
created at level 1 at the end of the accessible part of the
buffer.
Search is case-insensitive and ignores white spaces. Return type
of matched result, which is either `dedicated' or `fuzzy'. Search
respects buffer narrowing."
(unless (org-string-nw-p s) (error "Invalid search string \"%s\"" s))
(let* ((case-fold-search t)
(origin (point))
(normalized (replace-regexp-in-string "\n[ \t]*" " " s))
(starred (eq (string-to-char normalized) ?*))
(words (split-string (if starred (substring s 1) s)))
(s-multi-re (mapconcat #'regexp-quote words "\\(?:[ \t\n]+\\)"))
(s-single-re (mapconcat #'regexp-quote words "[ \t]+"))
type)
(cond
;; Check if there are any special search functions.
((run-hook-with-args-until-success 'org-execute-file-search-functions s))
((eq (string-to-char s) ?#)
;; Look for a custom ID S if S starts with "#".
(let* ((id (substring normalized 1))
(match (org-find-property "CUSTOM_ID" id)))
(if match (progn (goto-char match) (setf type 'dedicated))
(error "No match for custom ID: %s" id))))
((string-match "\\`(\\(.*\\))\\'" normalized)
;; Look for coderef targets if S is enclosed within parenthesis.
(let ((coderef (match-string-no-properties 1 normalized))
(re (substring s-single-re 1 -1)))
(goto-char (point-min))
(catch :coderef-match
(while (re-search-forward re nil t)
(let ((element (org-element-at-point)))
(when (and (org-element-type-p element '(example-block src-block))
(org-match-line
(concat ".*?" (org-src-coderef-regexp
(org-src-coderef-format element)
coderef))))
(setq type 'dedicated)
(goto-char (match-beginning 2))
(throw :coderef-match nil))))
(goto-char origin)
(error "No match for coderef: %s" coderef))))
((string-match "\\`/\\(.*\\)/\\'" normalized)
;; Look for a regular expression.
(funcall (if (derived-mode-p 'org-mode) #'org-occur #'org-do-occur)
(match-string 1 s)))
;; From here, we handle fuzzy links.
;;
;; Look for targets, only if not in a headline search.
((and (not starred)
(let ((target (format "<<%s>>" s-multi-re)))
(catch :target-match
(goto-char (point-min))
(while (re-search-forward target nil t)
(backward-char)
(let ((context (org-element-context)))
(when (org-element-type-p context 'target)
(setq type 'dedicated)
(goto-char (org-element-begin context))
(throw :target-match t))))
nil))))
;; Look for elements named after S, only if not in a headline
;; search.
((and (not starred)
(let ((name (format "^[ \t]*#\\+NAME: +%s[ \t]*$" s-single-re)))
(catch :name-match
(goto-char (point-min))
(while (re-search-forward name nil t)
(let* ((element (org-element-at-point))
(name (org-element-property :name element)))
(when (and name (equal (mapcar #'upcase words) (mapcar #'upcase (split-string name))))
(setq type 'dedicated)
(forward-line 0)
(throw :name-match t))))
nil))))
;; Regular text search. Prefer headlines in Org mode buffers.
;; Ignore COMMENT keyword, TODO keywords, priority cookies,
;; statistics cookies and tags.
((and (derived-mode-p 'org-mode)
(let ((title-re
(format "%s.*\\(?:%s[ \t]\\)?.*%s"
org-outline-regexp-bol
org-comment-string
(mapconcat #'regexp-quote words ".+"))))
(goto-char (point-min))
(catch :found
(while (re-search-forward title-re nil t)
(when (equal (mapcar #'upcase words)
(mapcar #'upcase
(split-string
(org-link--normalize-string
(org-get-heading t t t t)))))
(throw :found t)))
nil)))
(forward-line 0)
(setq type 'dedicated))
;; Offer to create non-existent headline depending on
;; `org-link-search-must-match-exact-headline'.
((and (derived-mode-p 'org-mode)
(eq org-link-search-must-match-exact-headline 'query-to-create)
(yes-or-no-p "No match - create this as a new heading? "))
(let* ((container-ok (and new-heading-container
(org-element-type-p new-heading-container '(headline))))
(new-heading-position (if container-ok
(- (org-element-end new-heading-container) 1)
(point-max)))
(new-heading-level (if container-ok
(+ 1 (org-element-property :level new-heading-container))
1)))
;; Need to widen when target is outside accessible portion of
;; buffer, since the we want the user to end up there.
(unless (and (<= (point-min) new-heading-position)
(>= (point-max) new-heading-position))
(widen))
(goto-char new-heading-position)
(unless (bolp) (newline))
(org-insert-heading nil t new-heading-level)
(insert (if starred (substring s 1) s) "\n")
(forward-line -1)))
;; Only headlines are looked after. No need to process
;; further: throw an error.
((and (derived-mode-p 'org-mode)
(or starred org-link-search-must-match-exact-headline))
(goto-char origin)
(error "No match for fuzzy expression: %s" normalized))
;; Regular text search.
((catch :fuzzy-match
(goto-char (point-min))
(while (re-search-forward s-multi-re nil t)
;; Skip match if it contains AVOID-POS or it is included in
;; a link with a description but outside the description.
(unless (or (and avoid-pos
(<= (match-beginning 0) avoid-pos)
(> (match-end 0) avoid-pos))
(and (save-match-data
(org-in-regexp org-link-bracket-re))
(match-beginning 3)
(or (> (match-beginning 3) (point))
(<= (match-end 3) (point)))
(org-element-lineage
(save-match-data (org-element-context))
'link t)))
(goto-char (match-beginning 0))
(setq type 'fuzzy)
(throw :fuzzy-match t)))
nil))
;; All failed. Throw an error.
(t (goto-char origin)
(error "No match for fuzzy expression: %s" normalized)))
;; Disclose surroundings of match, if appropriate.
(when (and (derived-mode-p 'org-mode) (not stealth))
(org-fold-show-context 'link-search))
type))