aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard M. Stallman1997-07-04 19:59:49 +0000
committerRichard M. Stallman1997-07-04 19:59:49 +0000
commitd9cc804bf8f440fa73f49abe7977518554126601 (patch)
treef36cddd67c874dfec9f1c4d5cbec67379a9ece82
parent766e15c6b5dd54cc46aec2453eb00b4d0cc9e962 (diff)
downloademacs-d9cc804bf8f440fa73f49abe7977518554126601.tar.gz
emacs-d9cc804bf8f440fa73f49abe7977518554126601.zip
(thing-at-point): Use `thing-at-point' property, if any.
(bounds-of-thing-at-point): Use `bounds-of-thing-at-point' property. (thing-at-point-bounds-of-url-at-point): New function. (thing-at-point-looking-at): New function, adapted from old browse-url-looking-at. (thing-at-point-url-at-point): New function, adapted from browse-url-url-at-point. (thing-at-point-url-chars): Variable deleted. (thing-at-point-url-path-regexp, thing-at-point-short-url-regexp, thing-at-point-url-regexp, thing-at-point-markedup-url-regexp): New variables. (url): `beginning-op' property function changed to use `thing-at-point-bounds-of-url-at-point'. `end-op' property no longer set -- functionality no longer supported for the more sophisticated treatment of URLs so `forward-thing' no longer works in this case.
-rw-r--r--lisp/thingatpt.el211
1 files changed, 155 insertions, 56 deletions
diff --git a/lisp/thingatpt.el b/lisp/thingatpt.el
index 436f2ff3589..4ea50c5dd23 100644
--- a/lisp/thingatpt.el
+++ b/lisp/thingatpt.el
@@ -1,6 +1,6 @@
1;;; thingatpt.el --- Get the `thing' at point 1;;; thingatpt.el --- Get the `thing' at point
2 2
3;; Copyright (C) 1991,92,93,94,95,1996 Free Software Foundation, Inc. 3;; Copyright (C) 1991,92,93,94,95,96,1997 Free Software Foundation, Inc.
4 4
5;; Author: Mike Williams <mikew@gopher.dosli.govt.nz> 5;; Author: Mike Williams <mikew@gopher.dosli.govt.nz>
6;; Keywords: extensions, matching, mouse 6;; Keywords: extensions, matching, mouse
@@ -72,54 +72,56 @@ a symbol as a valid THING.
72 72
73The value is a cons cell (START . END) giving the start and end positions 73The value is a cons cell (START . END) giving the start and end positions
74of the textual entity that was found." 74of the textual entity that was found."
75 (let ((orig (point))) 75 (if (get thing 'bounds-of-thing-at-point)
76 (condition-case nil 76 (funcall (get thing 'bounds-of-thing-at-point))
77 (save-excursion 77 (let ((orig (point)))
78 ;; Try moving forward, then back. 78 (condition-case nil
79 (let ((end (progn 79 (save-excursion
80 (funcall 80 ;; Try moving forward, then back.
81 (or (get thing 'end-op) 81 (let ((end (progn
82 (function (lambda () (forward-thing thing 1)))))
83 (point)))
84 (beg (progn
85 (funcall
86 (or (get thing 'beginning-op)
87 (function (lambda () (forward-thing thing -1)))))
88 (point))))
89 (if (not (and beg (> beg orig)))
90 ;; If that brings us all the way back to ORIG,
91 ;; it worked. But END may not be the real end.
92 ;; So find the real end that corresponds to BEG.
93 (let ((real-end
94 (progn
95 (funcall 82 (funcall
96 (or (get thing 'end-op) 83 (or (get thing 'end-op)
97 (function (lambda () (forward-thing thing 1))))) 84 (function (lambda () (forward-thing thing 1)))))
85 (point)))
86 (beg (progn
87 (funcall
88 (or (get thing 'beginning-op)
89 (function (lambda () (forward-thing thing -1)))))
98 (point)))) 90 (point))))
99 (if (and beg real-end (<= beg orig) (<= orig real-end)) 91 (if (not (and beg (> beg orig)))
100 (cons beg real-end))) 92 ;; If that brings us all the way back to ORIG,
101 (goto-char orig) 93 ;; it worked. But END may not be the real end.
102 ;; Try a second time, moving backward first and then forward, 94 ;; So find the real end that corresponds to BEG.
103 ;; so that we can find a thing that ends at ORIG. 95 (let ((real-end
104 (let ((beg (progn 96 (progn
105 (funcall
106 (or (get thing 'beginning-op)
107 (function (lambda () (forward-thing thing -1)))))
108 (point)))
109 (end (progn
110 (funcall 97 (funcall
111 (or (get thing 'end-op) 98 (or (get thing 'end-op)
112 (function (lambda () (forward-thing thing 1))))) 99 (function (lambda () (forward-thing thing 1)))))
113 (point))) 100 (point))))
114 (real-beg 101 (if (and beg real-end (<= beg orig) (<= orig real-end))
115 (progn 102 (cons beg real-end)))
116 (funcall 103 (goto-char orig)
117 (or (get thing 'beginning-op) 104 ;; Try a second time, moving backward first and then forward,
118 (function (lambda () (forward-thing thing -1))))) 105 ;; so that we can find a thing that ends at ORIG.
119 (point)))) 106 (let ((beg (progn
120 (if (and real-beg end (<= real-beg orig) (<= orig end)) 107 (funcall
121 (cons real-beg end)))))) 108 (or (get thing 'beginning-op)
122 (error nil)))) 109 (function (lambda () (forward-thing thing -1)))))
110 (point)))
111 (end (progn
112 (funcall
113 (or (get thing 'end-op)
114 (function (lambda () (forward-thing thing 1)))))
115 (point)))
116 (real-beg
117 (progn
118 (funcall
119 (or (get thing 'beginning-op)
120 (function (lambda () (forward-thing thing -1)))))
121 (point))))
122 (if (and real-beg end (<= real-beg orig) (<= orig end))
123 (cons real-beg end))))))
124 (error nil)))))
123 125
124;;;###autoload 126;;;###autoload
125(defun thing-at-point (thing) 127(defun thing-at-point (thing)
@@ -130,9 +132,11 @@ Possibilities include `symbol', `list', `sexp', `defun', `filename', `url',
130 132
131See the file `thingatpt.el' for documentation on how to define 133See the file `thingatpt.el' for documentation on how to define
132a symbol as a valid THING." 134a symbol as a valid THING."
133 (let ((bounds (bounds-of-thing-at-point thing))) 135 (if (get thing 'thing-at-point)
134 (if bounds 136 (funcall (get thing 'thing-at-point))
135 (buffer-substring (car bounds) (cdr bounds))))) 137 (let ((bounds (bounds-of-thing-at-point thing)))
138 (if bounds
139 (buffer-substring (car bounds) (cdr bounds))))))
136 140
137;; Go to beginning/end 141;; Go to beginning/end
138 142
@@ -197,19 +201,114 @@ a symbol as a valid THING."
197(put 'filename 'beginning-op 201(put 'filename 'beginning-op
198 '(lambda () (skip-chars-backward thing-at-point-file-name-chars))) 202 '(lambda () (skip-chars-backward thing-at-point-file-name-chars)))
199 203
200(defvar thing-at-point-url-chars "~/A-Za-z0-9---_@$%&=.," 204(defvar thing-at-point-url-path-regexp
201 "Characters allowable in a URL.") 205 "[^]\t\n \"'()<>[^`{}]*[^]\t\n \"'()<>[^`{}.,;]+"
202 206 "A regular expression probably matching the host, path or e-mail part of a URL.")
203(put 'url 'end-op 207
204 '(lambda () (skip-chars-forward (concat ":" thing-at-point-url-chars)) 208(defvar thing-at-point-short-url-regexp
205 (skip-chars-backward ".,:"))) 209 (concat "[-A-Za-z0-9.]+" thing-at-point-url-path-regexp)
210 "A regular expression probably matching a URL without an access scheme.
211Hostname matching is stricter in this case than for
212``thing-at-point-url-regexp''.")
213
214(defvar thing-at-point-url-regexp
215 (concat
216 "\\(https?://\\|ftp://\\|gopher://\\|telnet://\\|wais://\\|file:/\\|s?news:\\|mailto:\\)"
217 thing-at-point-url-path-regexp)
218 "A regular expression probably matching a complete URL.")
219
220(defvar thing-at-point-markedup-url-regexp
221 "<URL:[^>]+>"
222 "A regular expression matching a URL marked up per RFC1738.
223This may contain whitespace (including newlines) .")
224
225(put 'url 'bounds-of-thing-at-point 'thing-at-point-bounds-of-url-at-point)
226(defun thing-at-point-bounds-of-url-at-point ()
227 (let ((url "") short strip)
228 (if (or (setq strip (thing-at-point-looking-at
229 thing-at-point-markedup-url-regexp))
230 (thing-at-point-looking-at thing-at-point-url-regexp)
231 ;; Access scheme omitted?
232 (setq short (thing-at-point-looking-at
233 thing-at-point-short-url-regexp)))
234 (let ((beginning (match-beginning 0))
235 (end (match-end 0)))
236 (cond (strip
237 (setq beginning (+ beginning 5))
238 (setq end (- end 1))))
239 (cons beginning end)))))
240
241(put 'url 'thing-at-point 'thing-at-point-url-at-point)
242(defun thing-at-point-url-at-point ()
243 "Return the URL around or before point.
244Search backwards for the start of a URL ending at or after
245point. If no URL found, return nil. The access scheme, `http://'
246will be prepended if absent."
247 (let ((url "") short strip)
248 (if (or (setq strip (thing-at-point-looking-at
249 thing-at-point-markedup-url-regexp))
250 (thing-at-point-looking-at thing-at-point-url-regexp)
251 ;; Access scheme omitted?
252 (setq short (thing-at-point-looking-at
253 thing-at-point-short-url-regexp)))
254 (progn
255 (setq url (buffer-substring-no-properties (match-beginning 0)
256 (match-end 0)))
257 (and strip (setq url (substring url 5 -1))) ; Drop "<URL:" & ">"
258 ;; strip whitespace
259 (while (string-match "\\s +\\|\n+" url)
260 (setq url (replace-match "" t t url)))
261 (and short (setq url (concat (if (string-match "@" url)
262 "mailto:" "http://") url)))
263 (if (string-equal "" url)
264 nil
265 url)))))
266
267;; The normal thingatpt mechanism doesn't work for complex regexps.
268;; This should work for almost any regexp wherever we are in the
269;; match. To do a perfect job for any arbitrary regexp would mean
270;; testing every position before point. Regexp searches won't find
271;; matches that straddle the start position so we search forwards once
272;; and then back repeatedly and then back up a char at a time.
273
274(defun thing-at-point-looking-at (regexp)
275 "Return non-nil if point is in or just after a match for REGEXP.
276Set the match data from the earliest such match ending at or after
277point."
278 (save-excursion
279 (let ((old-point (point)) match)
280 (and (looking-at regexp)
281 (>= (match-end 0) old-point)
282 (setq match (point)))
283 ;; Search back repeatedly from end of next match.
284 ;; This may fail if next match ends before this match does.
285 (re-search-forward regexp nil 'limit)
286 (while (and (re-search-backward regexp nil t)
287 (or (> (match-beginning 0) old-point)
288 (and (looking-at regexp) ; Extend match-end past search start
289 (>= (match-end 0) old-point)
290 (setq match (point))))))
291 (if (not match) nil
292 (goto-char match)
293 ;; Back up a char at a time in case search skipped
294 ;; intermediate match straddling search start pos.
295 (while (and (not (bobp))
296 (progn (backward-char 1) (looking-at regexp))
297 (>= (match-end 0) old-point)
298 (setq match (point))))
299 (goto-char match)
300 (looking-at regexp)))))
301
302;; Can't do it sensibly?
303;(put 'url 'end-op
304; '(lambda () (skip-chars-forward (concat ":" thing-at-point-url-chars))
305; (skip-chars-backward ".,:")))
206(put 'url 'beginning-op 306(put 'url 'beginning-op
207 '(lambda () 307 '(lambda ()
208 (skip-chars-backward thing-at-point-url-chars) 308 (let ((bounds (thing-at-point-bounds-of-url-at-point)))
209 (or (= (preceding-char) ?:) 309 (if bounds
210 (error "No URL here")) 310 (goto-char (car bounds))
211 (forward-char -1) 311 (error "No URL here")))))
212 (skip-chars-backward "a-zA-Z")))
213 312
214;; Whitespace 313;; Whitespace
215 314