From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: "Drew Adams" Newsgroups: gmane.emacs.devel Subject: RE: patch for thingatpt.el Date: Mon, 16 Jul 2007 14:01:21 -0700 Message-ID: References: NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Trace: sea.gmane.org 1184619812 2489 80.91.229.12 (16 Jul 2007 21:03:32 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Mon, 16 Jul 2007 21:03:32 +0000 (UTC) Cc: Emacs-Devel To: "Stefan Monnier" Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Jul 16 23:03:28 2007 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1IAXj3-0004rv-KE for ged-emacs-devel@m.gmane.org; Mon, 16 Jul 2007 23:03:27 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1IAXj2-0002Rl-OT for ged-emacs-devel@m.gmane.org; Mon, 16 Jul 2007 17:03:24 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1IAXiT-0002Dr-K1 for emacs-devel@gnu.org; Mon, 16 Jul 2007 17:02:49 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1IAXiS-0002D7-8Q for emacs-devel@gnu.org; Mon, 16 Jul 2007 17:02:49 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1IAXiS-0002D2-53 for emacs-devel@gnu.org; Mon, 16 Jul 2007 17:02:48 -0400 Original-Received: from rgminet01.oracle.com ([148.87.113.118]) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1IAXiR-0006j3-6T for emacs-devel@gnu.org; Mon, 16 Jul 2007 17:02:47 -0400 Original-Received: from agmgw2.us.oracle.com (agmgw2.us.oracle.com [152.68.180.213]) by rgminet01.oracle.com (Switch-3.2.4/Switch-3.1.6) with ESMTP id l6GL2dQG010282; Mon, 16 Jul 2007 15:02:40 -0600 Original-Received: from acsmt350.oracle.com (acsmt350.oracle.com [141.146.40.150]) by agmgw2.us.oracle.com (Switch-3.2.0/Switch-3.2.0) with ESMTP id l6GCjQdP018663; Mon, 16 Jul 2007 15:02:38 -0600 Original-Received: from dhcp-4op11-4op12-west-130-35-178-179.us.oracle.com by acsmt350.oracle.com with ESMTP id 3044247571184619686; Mon, 16 Jul 2007 14:01:26 -0700 X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook IMO, Build 9.0.6604 (9.0.2911.0) In-Reply-To: Importance: Normal X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3138 X-Brightmail-Tracker: AAAAAQAAAAI= X-Brightmail-Tracker: AAAAAQAAAAI= X-Whitelist: TRUE X-Whitelist: TRUE X-detected-kernel: Linux 2.4-2.6 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:74923 Archived-At: > > Here is an updated change log and patch, which also > > incorporates the `defun' bug fix I sent after the previous patch. > > > ! (defun symbol-at-point-with-bounds (&optional non-nil) > > ! "Return (SYMBOL START . END) with START and END of SYMBOL. > > ! Return nil if no such Emacs Lisp symbol is found. > > ! SYMBOL is the `symbol-at-point' (which see). > > ! If optional arg NON-NIL is non-nil, then the nearest symbol other > > ! than `nil' is sought." > > ! (with-syntax-table emacs-lisp-mode-syntax-table > > ! (form-at-point-with-bounds > > ! 'symbol (if non-nil (lambda (sym) (and sym (symbolp sym))) > > ! 'symbolp)))) > > This is wrong. The name is clearly generic, whereas the > docstring then goes on to say it's only specific to Emacs Lisp symbols. > I think the name is right and the docstring (and code) are wrong. > > Check "recent" changes to symbol-at-point where I've fixed a > similar problem (basically you shouldn't call `read'). I'm not sure which recent changes you mean. I see an entry for 2006-07-04 that mentions allowing symbol characters such as `(' and `''. Please elaborate, if you meant some other change. I think you're saying that you look at "symbol" here as referring to symbol syntax, whatever the language, whereas I interpreted it as meaning a symbol object in Emacs Lisp - that is, something that satisfies `symbolp'. AFAIK, my interpretation was the traditional one for the meaning and behavior of `symbol-at-point'. IIUC, `symbol-at-point' was intended to retrieve Emacs-Lisp symbols, for use as default values in Emacs help functions, for instance. You apparently changed the interpretation and behavior last year; before that, `symbol-at-point' returned an Emacs-Lisp symbol or nil if there was none at point. I wouldn't call such a change in meaning a bug fix, but that's your call. Emacs uses "symbol" in different ways, depending on the context. For example, we have function `complete-symbol', which respects the current symbol syntax, and we have function `lisp-complete-symbol', which uses Lisp syntax and the names of objects that satisfy `symbolp'. Some of the function names that contain "symbol" refer to symbols whose names respect Emacs-Lisp syntax; others refer to symbols whose names respect the current symbol syntax. I'm not sure if we have a convention, but `symbol' vs `lisp-symbol' seems OK. (`complete-lisp-symbol' would be better than `lisp-complete symbol', BTW.) Below is a new patch. I've renamed the symbol and symbol-name functions that I introduced, from `*symbol*' to `*lisp-symbol*'. I've restored your definition of `symbol-at-point' (and added a doc string). FWIW - I was wondering whether all of the current uses of `symbol-at-point' in fact expect the current syntax table to define what constitutes a symbol, or if, on the contrary, some of them might expect a symbol that respects Emacs-Lisp syntax. When I grepped, I was surprised to see that `symbol-at-point' is hardly used. In my own code, I like to provide default values for user input, and I tend to let users use completion for inputting, so I use a function that returns a Lisp symbol (or its name) fairly often. In all such cases in my code, the appropriate value is a name that respects Emacs-Lisp symbol syntax - regardless of the current mode and syntax table. My guess is that if Emacs were to do similarly, using more symbol-name default values, then most of the need for a symbol or symbol name at or near point would be for an Emacs-Lisp symbol. In any case, with the new names we should have sufficient flexibility for whatever is needed. ---------8<------------------------ *** thingatpt-CVS-2007-07-14.el Sat Jul 14 08:40:06 2007 --- thingatpt-CVS-patched-2007-07-16b.el Mon Jul 16 13:03:44 2007 *************** *** 49,79 **** (provide 'thingatpt) ! ;; Basic movement ! ;;;###autoload ! (defun forward-thing (thing &optional n) ! "Move forward to the end of the Nth next THING." ! (let ((forward-op (or (get thing 'forward-op) ! (intern-soft (format "forward-%s" thing))))) ! (if (functionp forward-op) ! (funcall forward-op (or n 1)) ! (error "Can't determine how to move over a %s" thing)))) ! ;; General routines ;;;###autoload (defun bounds-of-thing-at-point (thing) "Determine the start and end buffer locations for the THING at point. ! THING is a symbol which specifies the kind of syntactic entity you want. ! Possibilities include `symbol', `list', `sexp', `defun', `filename', `url', ! `email', `word', `sentence', `whitespace', `line', `page' and others. ! ! See the file `thingatpt.el' for documentation on how to define ! a symbol as a valid THING. ! The value is a cons cell (START . END) giving the start and end positions ! of the textual entity that was found." (if (get thing 'bounds-of-thing-at-point) (funcall (get thing 'bounds-of-thing-at-point)) (let ((orig (point))) --- 49,86 ---- (provide 'thingatpt) ! ;;; Options ! (defcustom near-point-x-distance 50 ! "Maximum number of characters from point to search, left and right. ! Used by functions that provide default text for minibuffer input. ! Some functions might ignore or override this setting temporarily." ! :type 'integer :group 'minibuffer) ! ! (defcustom near-point-y-distance 5 ! "Maximum number of lines from point to search, up and down. ! To constrain search to the same line as point, set this to zero. ! Used by functions that provide default text for minibuffer input. ! Some functions might ignore or override this setting temporarily." ! :type 'integer :group 'minibuffer) ! ! ;;; THINGS ----------------------------------------------- ;;;###autoload (defun bounds-of-thing-at-point (thing) "Determine the start and end buffer locations for the THING at point. ! THING is an Emacs-Lisp symbol that specifies the kind of syntactic ! entity you want. Possibilities include `symbol', `list', `sexp', ! `defun', `filename', `url', `email', `word', `sentence', `whitespace', ! `line', `page' and others. See file `thingatpt.el' for how to define ! a symbol as a valid THING. The value returned is a cons cell (START ! . END) giving the start and end positions of the textual entity that ! was found." ! (bounds-of-thing-at-point-1 thing)) ! (defun bounds-of-thing-at-point-1 (thing) ! "Helper function for `bounds-of-thing-at-point'." (if (get thing 'bounds-of-thing-at-point) (funcall (get thing 'bounds-of-thing-at-point)) (let ((orig (point))) *************** *** 120,211 **** (error nil))))) ;;;###autoload ! (defun thing-at-point (thing) ! "Return the THING at point. ! THING is a symbol which specifies the kind of syntactic entity you want. ! Possibilities include `symbol', `list', `sexp', `defun', `filename', `url', ! `email', `word', `sentence', `whitespace', `line', `page' and others. ! See the file `thingatpt.el' for documentation on how to define a symbol as a valid THING." (if (get thing 'thing-at-point) (funcall (get thing 'thing-at-point)) (let ((bounds (bounds-of-thing-at-point thing))) ! (if bounds ! (buffer-substring (car bounds) (cdr bounds)))))) ;; Go to beginning/end (defun beginning-of-thing (thing) (let ((bounds (bounds-of-thing-at-point thing))) (or bounds (error "No %s here" thing)) (goto-char (car bounds)))) (defun end-of-thing (thing) (let ((bounds (bounds-of-thing-at-point thing))) (or bounds (error "No %s here" thing)) (goto-char (cdr bounds)))) ;; Special cases ! ;; Lines ;; bolp will be false when you click on the last line in the buffer ;; and it has no final newline. ! ! (put 'line 'beginning-op ! (lambda () (if (bolp) (forward-line -1) (beginning-of-line)))) ;; Sexps - (defun in-string-p () (let ((orig (point))) (save-excursion (beginning-of-defun) (nth 3 (parse-partial-sexp (point) orig))))) (defun end-of-sexp () (let ((char-syntax (char-syntax (char-after (point))))) (if (or (eq char-syntax ?\)) (and (eq char-syntax ?\") (in-string-p))) (forward-char 1) (forward-sexp 1)))) - (put 'sexp 'end-op 'end-of-sexp) (defun beginning-of-sexp () (let ((char-syntax (char-syntax (char-before (point))))) (if (or (eq char-syntax ?\() (and (eq char-syntax ?\") (in-string-p))) (forward-char -1) (forward-sexp -1)))) - (put 'sexp 'beginning-op 'beginning-of-sexp) ;; Lists - (put 'list 'end-op (lambda () (up-list 1))) (put 'list 'beginning-op 'backward-sexp) ;; Filenames and URLs www.com/foo%32bar - (defvar thing-at-point-file-name-chars "-~/[:alnum:]_.${}#%,:" "Characters allowable in filenames.") ! ! (put 'filename 'end-op ! (lambda () ! (re-search-forward (concat "\\=[" thing-at-point-file-name-chars "]*") nil t))) ! (put 'filename 'beginning-op ! (lambda () ! (if (re-search-backward (concat "[^" thing-at-point-file-name-chars "]") nil t) (forward-char) (goto-char (point-min))))) (defvar thing-at-point-url-path-regexp "[^]\t\n \"'()<>[^`{}]*[^]\t\n \"'()<>[^`{}.,;]+" ! "A regular expression probably matching the host and filename or e-mail part of a URL.") (defvar thing-at-point-short-url-regexp (concat "[-A-Za-z0-9.]+" thing-at-point-url-path-regexp) --- 127,327 ---- (error nil))))) ;;;###autoload ! (defun thing-at-point-with-bounds (thing) ! "Return (THING START . END) with START and END of THING. ! Return nil if no THING is found. ! THING is the `thing-at-point' (which see). ! START and END are the car and cdr of the `bounds-of-thing-at-point'." ! (let ((bounds (bounds-of-thing-at-point thing))) ! (and bounds (cons (buffer-substring (car bounds) (cdr bounds)) bounds)))) ! ;;;###autoload ! (defun thing-at-point (thing) ! "Return the THING at point, or nil if there is none. ! THING is an Emacs-Lisp symbol that specifies the kind of syntactic ! entity you want. Possibilities include `symbol', `list', `sexp', ! `defun', `filename', `url', `email', `word', `sentence', `whitespace', ! `line', `page' and others. See file `thingatpt.el' for how to define a symbol as a valid THING." (if (get thing 'thing-at-point) (funcall (get thing 'thing-at-point)) (let ((bounds (bounds-of-thing-at-point thing))) ! (and bounds (buffer-substring (car bounds) (cdr bounds)))))) ! ! ;;;###autoload ! (defun thing-nearest-point-with-bounds (thing) ! "Return (THING START . END) with START and END of THING. ! Return nil if no THING is found. ! THING is the `thing-nearest-point' (which see)." ! (thing/form-nearest-point-with-bounds #'thing-at-point-with-bounds thing)) ! ! (defun thing/form-nearest-point-with-bounds (fn thing &optional pred) ! "Thing or form nearest point, with bounds. ! FN is a function returning a thing or form at point, with bounds. ! If PRED is non-nil, then FN is called with THING and PRED as ! arguments. Otherwise, it is called with THING as argument. ! THING is the `thing-nearest-point' (which see). ! PRED is an optional predicate that THING must satisfy to qualify." ! (let ((f-or-t+bds (if pred (funcall fn thing pred) (funcall fn thing))) ! (ind1 0) (ind2 0) (bobp (bobp)) (updown 1) ! (eobp (eobp)) (bolp (bolp)) (eolp (eolp)) ! (max-x (abs near-point-x-distance)) ! (max-y (abs near-point-y-distance))) ! ;; IND2: Loop over lines (alternately up and down). ! (while (and (<= ind2 max-y) (not f-or-t+bds) (not (and bobp eobp))) ! (setq updown (- updown)) ; Switch directions up/down (1/-1). ! (save-excursion ! (condition-case () ! (previous-line (* updown ind2)) ; 0, 1, -1, 2, -2, ... ! (beginning-of-buffer (setq bobp t)) ! (end-of-buffer (setq eobp t)) ! (error nil)) ! ;; Don't try to go beyond buffer limit. ! (unless (or (and bobp (natnump updown)) (and eobp (< updown 0))) ! (setq f-or-t+bds (if pred (funcall fn thing pred) (funcall fn thing)) ! bolp (bolp) eolp (eolp) ind1 0) ! (save-excursion ! ;; IND1: Loop over chars in same line (alternately left and right), ! ;; until either found thing/form or both line limits reached. ! (while (and (not (and bolp eolp)) ! (<= ind1 max-x) ! (not f-or-t+bds)) ! (unless bolp (save-excursion ; Left. ! (setq bolp (forward-char-same-line (- ind1)) ! f-or-t+bds ! (if pred (funcall fn thing pred) (funcall fn thing))))) ! (unless (or f-or-t+bds eolp) ; Right. ! (save-excursion ! (setq eolp (forward-char-same-line ind1) ! f-or-t+bds (if pred (funcall fn thing pred) (funcall fn thing))))) ! (setq ind1 (1+ ind1))) ! (setq bobp (bobp) eobp (eobp))))) ! ;; Increase search line distance every second time (once up, once down). ! (when (or (< updown 0) (zerop ind2)) (setq ind2 (1+ ind2)))) ; 0,1,1,2,2... ! f-or-t+bds)) ! ! (defun forward-char-same-line (&optional arg) ! "Move forward a max of ARG chars on the same line, or backward if ARG < 0. ! Return the signed number of chars moved if /= ARG, else return nil." ! (interactive "p") ! (let* ((start (point)) ! (fwd-p (natnump arg)) ! (max (save-excursion ! (if fwd-p (end-of-line) (beginning-of-line)) ! (- (point) start)))) ! (forward-char (if fwd-p (min max arg) (max max arg))) ! (and (< (abs max) (abs arg)) max))) ! ! ;;;###autoload ! (defun bounds-of-thing-nearest-point (thing) ! "Return (START . END) with START and END of type THING. ! Return nil if no such THING is found. See `thing-nearest-point'." ! (let ((thing+bds (thing-nearest-point-with-bounds thing))) ! (and thing+bds (cdr thing+bds)))) ! ! ;;;###autoload ! (defun thing-nearest-point (thing) ! "Return the THING nearest to the cursor, if any, else return nil. ! \"Nearest\" to point is determined as follows: ! The nearest THING on the same line is returned, if there is any. ! Between two THINGs equidistant from point on the same line, the ! leftmost is considered nearer. ! Otherwise, neighboring lines are tried in sequence: ! previous, next, 2nd previous, 2nd next, 3rd previous, 3rd next, etc. ! This means that between two THINGs equidistant from point in ! lines above and below it, the THING in the line above point ! (previous Nth) is considered nearer to it. ! Related function `thing-at-point' returns the THING under the cursor, ! or nil if none." ! (let ((thing+bds (thing-nearest-point-with-bounds thing))) ! (and thing+bds (car thing+bds)))) ! ! ! ;;; FORWARD, BEGINNING, END OPERATIONS ------------------------------ ! ! ;;;###autoload ! (defun forward-thing (thing &optional n) ! "Move forward to the end of the Nth next THING." ! (let ((forward-op (or (get thing 'forward-op) ! (intern-soft (format "forward-%s" thing))))) ! (if (functionp forward-op) ! (funcall forward-op (or n 1)) ! (error "Can't determine how to move over a %s" thing)))) ;; Go to beginning/end (defun beginning-of-thing (thing) + "Go to the beginning of THING." (let ((bounds (bounds-of-thing-at-point thing))) (or bounds (error "No %s here" thing)) (goto-char (car bounds)))) (defun end-of-thing (thing) + "Go to the end of THING." (let ((bounds (bounds-of-thing-at-point thing))) (or bounds (error "No %s here" thing)) (goto-char (cdr bounds)))) ;; Special cases ! ;; Defuns ! (put 'defun 'beginning-op 'beginning-of-defun) ! (put 'defun 'end-op 'end-of-defun) ! (put 'defun 'forward-op 'end-of-defun) + ;; Lines ;; bolp will be false when you click on the last line in the buffer ;; and it has no final newline. ! (put 'line 'beginning-op (lambda () ! (if (bolp) (forward-line -1) (beginning-of-line)))) ;; Sexps (defun in-string-p () + "True if point is inside a string." (let ((orig (point))) (save-excursion (beginning-of-defun) (nth 3 (parse-partial-sexp (point) orig))))) (defun end-of-sexp () + "Go to the end of the sexp at point." (let ((char-syntax (char-syntax (char-after (point))))) (if (or (eq char-syntax ?\)) (and (eq char-syntax ?\") (in-string-p))) (forward-char 1) (forward-sexp 1)))) (put 'sexp 'end-op 'end-of-sexp) (defun beginning-of-sexp () + "Go to the beginning of the sexp at point." (let ((char-syntax (char-syntax (char-before (point))))) (if (or (eq char-syntax ?\() (and (eq char-syntax ?\") (in-string-p))) (forward-char -1) (forward-sexp -1)))) (put 'sexp 'beginning-op 'beginning-of-sexp) ;; Lists (put 'list 'end-op (lambda () (up-list 1))) (put 'list 'beginning-op 'backward-sexp) ;; Filenames and URLs www.com/foo%32bar (defvar thing-at-point-file-name-chars "-~/[:alnum:]_.${}#%,:" "Characters allowable in filenames.") ! (put 'filename 'end-op (lambda () ! (re-search-forward ! (concat "\\=[" thing-at-point-file-name-chars "]*") nil t))) ! (put 'filename 'beginning-op (lambda () ! (if (re-search-backward ! (concat "[^" thing-at-point-file-name-chars "]") nil t) (forward-char) (goto-char (point-min))))) (defvar thing-at-point-url-path-regexp "[^]\t\n \"'()<>[^`{}]*[^]\t\n \"'()<>[^`{}.,;]+" ! "A regexp probably matching the host and filename or e-mail part of a URL.") (defvar thing-at-point-short-url-regexp (concat "[-A-Za-z0-9.]+" thing-at-point-url-path-regexp) *************** *** 238,245 **** "A regular expression matching a URL marked up per RFC1738. This may contain whitespace (including newlines) .") - (put 'url 'bounds-of-thing-at-point 'thing-at-point-bounds-of-url-at-point) (defun thing-at-point-bounds-of-url-at-point () (let ((strip (thing-at-point-looking-at thing-at-point-markedup-url-regexp))) ;; (url "") short (if (or strip --- 354,361 ---- "A regular expression matching a URL marked up per RFC1738. This may contain whitespace (including newlines) .") (defun thing-at-point-bounds-of-url-at-point () + "Return the bounds of the URL around or before point." (let ((strip (thing-at-point-looking-at thing-at-point-markedup-url-regexp))) ;; (url "") short (if (or strip *************** *** 254,269 **** (setq beginning (+ beginning 5)) (setq end (- end 1))) (cons beginning end))))) - (put 'url 'thing-at-point 'thing-at-point-url-at-point) (defun thing-at-point-url-at-point () "Return the URL around or before point. - Search backwards for the start of a URL ending at or after point. If no URL found, return nil. The access scheme will be prepended if absent: \"mailto:\" if the string contains \"@\", \"ftp://\" if it starts with \"ftp\" and not \"ftp:/\", or \"http://\" by default." - (let ((url "") short strip) (if (or (setq strip (thing-at-point-looking-at thing-at-point-markedup-url-regexp)) --- 370,383 ---- (setq beginning (+ beginning 5)) (setq end (- end 1))) (cons beginning end))))) + (put 'url 'bounds-of-thing-at-point 'thing-at-point-bounds-of-url-at-point) (defun thing-at-point-url-at-point () "Return the URL around or before point. Search backwards for the start of a URL ending at or after point. If no URL found, return nil. The access scheme will be prepended if absent: \"mailto:\" if the string contains \"@\", \"ftp://\" if it starts with \"ftp\" and not \"ftp:/\", or \"http://\" by default." (let ((url "") short strip) (if (or (setq strip (thing-at-point-looking-at thing-at-point-markedup-url-regexp)) *************** *** 291,296 **** --- 405,411 ---- (if (string-equal "" url) nil url))))) + (put 'url 'thing-at-point 'thing-at-point-url-at-point) ;; The normal thingatpt mechanism doesn't work for complex regexps. ;; This should work for almost any regexp wherever we are in the *************** *** 326,332 **** (setq match (point)))) (goto-char match) (looking-at regexp))))) - (put 'url 'end-op (lambda () (let ((bounds (thing-at-point-bounds-of-url-at-point))) --- 441,446 ---- *************** *** 351,357 **** ;; not sure they're actually needed, and URL seems to skip them too. ;; Note that (end-of-thing 'email) and (beginning-of-thing 'email) ;; work automagically, though. - (put 'email 'bounds-of-thing-at-point (lambda () (let ((thing (thing-at-point-looking-at thing-at-point-email-regexp))) --- 465,470 ---- *************** *** 359,365 **** (let ((beginning (match-beginning 0)) (end (match-end 0))) (cons beginning end)))))) - (put 'email 'thing-at-point (lambda () (let ((boundary-pair (bounds-of-thing-at-point 'email))) --- 472,477 ---- *************** *** 368,375 **** (car boundary-pair) (cdr boundary-pair)))))) ;; Whitespace - (defun forward-whitespace (arg) (interactive "p") (if (natnump arg) (re-search-forward "[ \t]+\\|\n" nil 'move arg) --- 480,488 ---- (car boundary-pair) (cdr boundary-pair)))))) ;; Whitespace (defun forward-whitespace (arg) + "Move forward over ARG groups of TAB or SPC characters or ARG lines. + Move backward if ARG is negative." (interactive "p") (if (natnump arg) (re-search-forward "[ \t]+\\|\n" nil 'move arg) *************** *** 379,417 **** (skip-chars-backward " \t"))) (setq arg (1+ arg))))) ! ;; Buffer ! (put 'buffer 'end-op (lambda () (goto-char (point-max)))) (put 'buffer 'beginning-op (lambda () (goto-char (point-min)))) ;; Symbols - (defun forward-symbol (arg) (interactive "p") (if (natnump arg) (re-search-forward "\\(\\sw\\|\\s_\\)+" nil 'move arg) (while (< arg 0) ! (if (re-search-backward "\\(\\sw\\|\\s_\\)+" nil 'move) (skip-syntax-backward "w_")) (setq arg (1+ arg))))) ;; Syntax blocks - (defun forward-same-syntax (&optional arg) (interactive "p") (while (< arg 0) ! (skip-syntax-backward ! (char-to-string (char-syntax (char-after (1- (point)))))) (setq arg (1+ arg))) (while (> arg 0) (skip-syntax-forward (char-to-string (char-syntax (char-after (point))))) (setq arg (1- arg)))) - ;; Aliases - - (defun word-at-point () (thing-at-point 'word)) - (defun sentence-at-point () (thing-at-point 'sentence)) - (defun read-from-whole-string (str) "Read a Lisp expression from STR. Signal an error if the entire string was not used." --- 492,527 ---- (skip-chars-backward " \t"))) (setq arg (1+ arg))))) ! ;; Buffers (put 'buffer 'end-op (lambda () (goto-char (point-max)))) (put 'buffer 'beginning-op (lambda () (goto-char (point-min)))) ;; Symbols (defun forward-symbol (arg) + "Move forward ARG symbols. Move backward if ARG is negative. + \"Symbol\" here means any group of symbol characters. The current + syntax table is used to determine which characters are symbol + characters." (interactive "p") (if (natnump arg) (re-search-forward "\\(\\sw\\|\\s_\\)+" nil 'move arg) (while (< arg 0) ! (when (re-search-backward "\\(\\sw\\|\\s_\\)+" nil 'move) (skip-syntax-backward "w_")) (setq arg (1+ arg))))) ;; Syntax blocks (defun forward-same-syntax (&optional arg) + "Move forward over ARG groups of characters with the same syntax. + Move backward if ARG is negative." (interactive "p") (while (< arg 0) ! (skip-syntax-backward (char-to-string (char-syntax (char-after (1- (point)))))) (setq arg (1+ arg))) (while (> arg 0) (skip-syntax-forward (char-to-string (char-syntax (char-after (point))))) (setq arg (1- arg)))) (defun read-from-whole-string (str) "Read a Lisp expression from STR. Signal an error if the entire string was not used." *************** *** 426,447 **** (error "Can't read whole string") (car read-data)))) (defun form-at-point (&optional thing pred) (let ((sexp (condition-case nil (read-from-whole-string (thing-at-point (or thing 'sexp))) (error nil)))) (if (or (not pred) (funcall pred sexp)) sexp))) ;;;###autoload ! (defun sexp-at-point () (form-at-point 'sexp)) ;;;###autoload (defun symbol-at-point () ! (let ((thing (thing-at-point 'symbol))) ! (if thing (intern thing)))) ;;;###autoload ! (defun number-at-point () (form-at-point 'sexp 'numberp)) ;;;###autoload ! (defun list-at-point () (form-at-point 'list 'listp)) ;; arch-tag: bb65a163-dae2-4055-aedc-fe11f497f698 ;;; thingatpt.el ends here --- 536,813 ---- (error "Can't read whole string") (car read-data)))) + + ;;; FORMS ---------------------------------------------------------- + + ;;;###autoload + (defun form-at-point-with-bounds (&optional thing pred) + "Return (FORM START . END), START and END the char positions of FORM. + FORM is the `form-at-point'. Return nil if no form is found. + THING is the kind of form desired (default: `sexp'). + PRED is a predicate that THING must satisfy to qualify." + (let* ((thing+bds (thing-at-point-with-bounds (or thing 'sexp))) + (sexp (and thing+bds + (condition-case nil + (read-from-whole-string (car thing+bds)) + (error nil))))) ; E.g. tries to read `.'. + (and (or sexp (and thing+bds (string= "nil" (car thing+bds)))) ; Could be `nil'. + (or (not pred) (funcall pred sexp)) + (cons sexp (cdr thing+bds))))) + + ;;;###autoload + (defun bounds-of-form-at-point (&optional thing pred) + "Return (START . END), with START and END of `form-at-point'. + THING is the kind of form desired (default: `sexp'). + PRED is a predicate that THING must satisfy to qualify." + (let ((form+bds (form-at-point-with-bounds thing pred))) + (and form+bds (cdr form+bds)))) + + ;;;###autoload (defun form-at-point (&optional thing pred) + "Return the form nearest to the cursor, if any, else return nil. + The form is a Lisp entity, not necessarily a string. + THING is the kind of form desired (default: `sexp'). + PRED is a predicate that THING must satisfy to qualify." (let ((sexp (condition-case nil (read-from-whole-string (thing-at-point (or thing 'sexp))) (error nil)))) (if (or (not pred) (funcall pred sexp)) sexp))) ;;;###autoload ! (defun form-nearest-point-with-bounds (&optional thing pred) ! "Return (FORM START . END), START and END the char positions of FORM. ! FORM is the `form-nearest-point'. ! Return nil if no such form is found. ! THING is the kind of form desired (default: `sexp'). ! PRED is a predicate that THING must satisfy to qualify." ! (thing/form-nearest-point-with-bounds #'form-at-point-with-bounds thing pred)) ! ! ;;;###autoload ! (defun bounds-of-form-nearest-point (&optional thing pred) ! "Return (START . END) with START and END of `form-nearest-point'. ! Return nil if no such form is found. ! THING is the kind of form desired (default: `sexp'). ! PRED is a predicate that THING must satisfy to qualify." ! (let ((form+bds (form-nearest-point-with-bounds thing pred))) ! (and form+bds (cdr form+bds)))) ! ! ;;;###autoload ! (defun form-nearest-point (&optional thing pred) ! "Return the form nearest to the cursor, if any, else return nil. ! \"Nearest\" to point is determined as for `thing-nearest-point'. ! THING is the kind of form desired (default: `sexp'). ! PRED is a predicate that THING must satisfy to qualify." ! (let ((form+bds (form-nearest-point-with-bounds thing pred))) ! (and form+bds (car form+bds)))) ! ! ! ;;; SYMBOLS ---------------------------------------------------------- ! ;;;###autoload (defun symbol-at-point () ! "Return the symbol under the cursor, or nil if none. ! \"Symbol\" here means any Emacs-Lisp symbol whose name has symbol ! characters. The current syntax table is used to determine which ! characters are symbol characters." ! (let ((thing (thing-at-point 'symbol))) (if thing (intern thing)))) ! ! ;;;###autoload ! (defun lisp-symbol-at-point-with-bounds (&optional non-nil) ! "Return (SYMBOL START . END) with START and END of SYMBOL. ! Return nil if no such Emacs-Lisp symbol is found. ! SYMBOL is the `lisp-symbol-at-point' (which see). ! If optional arg NON-NIL is non-nil, then the nearest symbol other ! than `nil' is sought." ! (with-syntax-table emacs-lisp-mode-syntax-table ! (form-at-point-with-bounds ! 'symbol (if non-nil (lambda (sym) (and sym (symbolp sym))) 'symbolp)))) ! ! ;;;###autoload ! (defun bounds-of-lisp-symbol-at-point (&optional non-nil) ! "Return (START . END) with START and END of `lisp-symbol-at-point'. ! If optional arg NON-NIL is non-nil, then the nearest Emacs-Lisp symbol ! other than `nil' is sought." ! (let ((symb+bds (lisp-symbol-at-point-with-bounds non-nil))) ! (and symb+bds (cdr symb+bds)))) ! ! ;;;###autoload ! (defun lisp-symbol-at-point (&optional non-nil) ! "Return the Emacs-Lisp symbol under the cursor, or nil if none. ! If optional arg NON-NIL is non-nil, then the nearest symbol other ! than `nil' is sought. ! Some related functions: ! `symbol-at-point' returns the Emacs-Lisp symbol at point whose name ! is composed of symbol characters, where such characters are ! determined by the current syntax table. ! `lisp-symbol-nearest-point' returns the Emacs-Lisp symbol nearest ! the cursor, or nil if none. ! `lisp-symbol-name-nearest-point' returns the name of ! `lisp-symbol-nearest-point' as a string, or \"\" if none. ! `lisp-symbol-name-before-point' returns the string naming the symbol ! at or before the cursor (even if it is on a previous line) or \"\" ! if none. ! `word-before-point' returns the word (a string) at or before cursor. ! Note that these last three functions return strings, not symbols." ! (with-syntax-table emacs-lisp-mode-syntax-table ! (form-at-point ! 'symbol (if non-nil (lambda (sym) (and sym (symbolp sym))) 'symbolp)))) ! ! ;;;###autoload ! (defun lisp-symbol-nearest-point-with-bounds (&optional non-nil) ! "Return (SYMBOL START . END) with START and END of SYMBOL. ! Return nil if no such Emacs-Lisp symbol is found. ! SYMBOL is the `lisp-symbol-nearest-point' (which see). ! If optional arg NON-NIL is non-nil, then the nearest Emacs-Lisp symbol ! other than `nil' is sought." ! (with-syntax-table emacs-lisp-mode-syntax-table ! (form-nearest-point-with-bounds ! 'symbol (if non-nil (lambda (sym) (and sym (symbolp sym))) 'symbolp)))) ! ! ;;;###autoload ! (defun bounds-of-lisp-symbol-nearest-point (&optional non-nil) ! "Return (START . END) with START and END of `lisp-symbol-nearest-point'. ! If optional arg NON-NIL is non-nil, then the nearest symbol other ! than `nil' is sought." ! (let ((symb+bds (lisp-symbol-nearest-point-with-bounds non-nil))) ! (and symb+bds (cdr symb+bds)))) ! ! ;;;###autoload ! (defun lisp-symbol-nearest-point (&optional non-nil) ! "Return the Emacs-Lisp symbol nearest the cursor, or nil if none. ! \"Nearest\" to point is determined as for `thing-nearest-point'. ! If optional arg NON-NIL is non-nil, then the nearest symbol other ! than `nil' is sought. ! Some related functions: ! `symbol-at-point' returns the Emacs-Lisp symbol at point whose name ! is composed of symbol characters, where such characters are ! determined by the current syntax table. ! `lisp-symbol-at-point' returns the Emacs-Lisp symbol under the ! cursor, or nil if none. ! `lisp-symbol-name-nearest-point' returns the name of ! `lisp-symbol-nearest-point' as a string, or \"\" if none. ! `lisp-symbol-name-before-point' returns the string naming the symbol ! at or before the cursor (even if it is on a previous line) or \"\" ! if none. ! `word-at-point' returns the word at point, or nil if none. ! `word-nearest-point' returns the word nearest point, or \"\" if none. ! `word-before-point' returns the word at or before the cursor as a string. ! Note that these last three functions return strings, not symbols." ! (let ((symb+bds (lisp-symbol-nearest-point-with-bounds non-nil))) ! (and symb+bds (car symb+bds)))) ! ;;;###autoload ! (defun non-nil-lisp-symbol-nearest-point () ! "Return the Emacs-Lisp symbol other than `nil' nearest the cursor. ! Return nil if none is found. ! \"Nearest\" to point is determined as for `thing-nearest-point'. ! Some related functions: ! `symbol-at-point' returns the Emacs-Lisp symbol at point whose name ! is composed of symbol characters, where such characters are ! determined by the current syntax table. ! `lisp-symbol-at-point' returns the Emacs-Lisp symbol under the ! cursor, or nil if none. ! `lisp-symbol-name-nearest-point' returns the name of ! `lisp-symbol-nearest-point' as a string, or \"\" if none. ! `lisp-symbol-name-before-point' returns the string naming the symbol ! at or before the cursor (even if it is on a previous line) or \"\" ! if none. ! `word-at-point' returns the word at point, or nil if none. ! `word-nearest-point' returns the word nearest point, or \"\" if none. ! `word-before-point' returns the word at or before the cursor as a string. ! Note that these last three functions return strings, not symbols." ! (let ((symb+bds (symbol-nearest-point-with-bounds t))) ! (and symb+bds (car symb+bds)))) ! ! ! ;;; SYMBOL NAMES, WORDS, SENTENCES, SEXPS, NUMBERS, LISTS, etc. ---------- ! ! ;;;###autoload ! (defun lisp-symbol-name-at-point () ! "String naming the Emacs-Lisp symbol at point, or \"\" if none." ! ;; We do it this way to be able to pick symbol `nil' (name "nil"). ! (let ((symb+bds (lisp-symbol-at-point-with-bounds))) ! (if symb+bds (symbol-name (car symb+bds)) ""))) ! ! ;;;###autoload ! (defun non-nil-lisp-symbol-name-at-point () ! "String naming the Emacs-Lisp symbol nearest point, or \"\" if none. ! Returns the name of the nearest Emacs-Lisp symbol other than `nil'. ! \"Nearest\" to point is determined as for `thing-nearest-point'." ! (let ((symb+bds (lisp-symbol-at-point-with-bounds t))) ! (if symb+bds (symbol-name (car symb+bds)) ""))) ! ! ;;;###autoload ! (defun lisp-symbol-name-nearest-point () ! "String naming the Emacs-Lisp symbol nearest point, or \"\" if none. ! \"Nearest\" to point is determined as for `thing-nearest-point'." ! ;; We do it this way to be able to pick symbol `nil' (name "nil"). ! (let ((symb+bds (lisp-symbol-nearest-point-with-bounds))) ! (if symb+bds (symbol-name (car symb+bds)) ""))) ! ! ;;;###autoload ! (defun non-nil-lisp-symbol-name-nearest-point () ! "String naming the Emacs-Lisp symbol nearest point, or \"\" if none. ! Returns the name of the nearest Emacs-Lispsymbol other than `nil'. ! \"Nearest\" to point is determined as for `thing-nearest-point'." ! (let ((symb+bds (lisp-symbol-nearest-point-with-bounds t))) ! (if symb+bds (symbol-name (car symb+bds)) ""))) ! ! ;;;###autoload ! (defun word-at-point () ! "Return the word (a string) nearest to point, if any, else \"\"." ! (thing-at-point 'word)) ! ! ;;;###autoload ! (defun word-nearest-point () ! "Return the word (a string) nearest to point, if any, else \"\". ! \"Nearest\" to point is determined as for `thing-nearest-point'." ! (thing-nearest-point 'word)) ! ! ;;;###autoload ! (defun sentence-at-point () ! "Return the sentence (a string) nearest to point, if any, else \"\"." ! (thing-at-point 'sentence)) ! ! ;;;###autoload ! (defun sentence-nearest-point () ! "Return the sentence (a string) nearest to point, if any, else \"\". ! \"Nearest\" to point is determined as for `thing-nearest-point'." ! (thing-nearest-point 'sentence)) ! ! ;;;###autoload ! (defun sexp-at-point () ! "Return the sexp (a string) nearest to point, if any, else \"\"." ! (form-at-point 'sexp)) ! ! ;;;###autoload ! (defun sexp-nearest-point () ! "Return the sexp (a string) nearest to point, if any, else \"\". ! \"Nearest\" to point is determined as for `thing-nearest-point'." ! (form-nearest-point 'sexp)) ! ! ;;;###autoload ! (defun number-at-point () ! "Return the number at point, if any, else nil." ! (form-at-point 'sexp 'numberp)) ! ! ;;;###autoload ! (defun number-nearest-point () ! "Return the number nearest to point, if any, else nil. ! \"Nearest\" to point is determined as for `thing-nearest-point'." ! (form-nearest-point 'sexp 'numberp)) ! ! ;;;###autoload ! (defun list-at-point () ! "Return the list nearest to point, if any, else nil." ! (form-at-point 'list 'listp)) ! ;;;###autoload ! (defun list-nearest-point () ! "Return the list nearest to point, if any, else nil. ! This does not distinguish between finding no list and finding ! the empty list. \"Nearest\" to point is determined as for ! `thing-nearest-point'." ! (form-nearest-point 'list 'listp)) ;; arch-tag: bb65a163-dae2-4055-aedc-fe11f497f698 ;;; thingatpt.el ends here