all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* patch for thingatpt.el
@ 2007-07-15 21:08 Drew Adams
  2007-07-16  6:54 ` Drew Adams
  2007-07-16 15:12 ` Stefan Monnier
  0 siblings, 2 replies; 16+ messages in thread
From: Drew Adams @ 2007-07-15 21:08 UTC (permalink / raw)
  To: Emacs-Devel

Below is a patch for thingatpt.el that provides additional functionality and
new thing and form functions. In particular: (1) it lets you supply a
syntax-table argument to most functions, to affect the definition of what a
word etc. is, and (2) it provides functions to return things near point, not
just precisely at point.

FYI - I mentioned some of these enhancements in thread "find-tag-default" on
2005-05-29. RMS raised the question of the definition of "near", to which my
answer at that time was that the calling code is best placed to define what
it means by "near", to fit its needs, and that it could do this by narrowing
the region around point to what it considers an appropriate distance for
"near" to be.

However, I've since added two user options, `near-point-x-distance', and
`near-point-y-distance', that control nearness. Calling code can bind these
variables to override this user preference locally, if appropriate. By
default, "near" means within 50 characters left and right of point and
within 5 lines before and after point.

These are the main changes this patch provides:

1. Adds functions to retrieve things near point.
2. Adds user options to control nearness.
3. Adds functions to return non-nil symbols and symbol names.
4. `symbol-at-point': New optional arg NON-NIL.
5. Adds optional SYNTAX-TABLE argument to most functions.
6. Adds missing doc strings.

As an example, I use `non-nil-symbol-name-nearest-point' to provide a
default symbol name for functions `grep', `find-dired', `make-face',
`Info-goto-emacs-command-node', `name-last-kbd-macro', `insert-kbd-macro',
`enable-command', `disable-command', `query-replace', `read-variable',
`cancel-function-timers', and more.

Here is a change-log entry for the patch:

------------8<------- log entry --------------------

2007-07-15  Drew Adams  <drew.adams@oracle.com>

      * thingatpt.el: Added functions for things near point.

        (near-point-x-distance, near-point-y-distance): New options.

        (bounds-of-form-at-point, bounds-of-form-nearest-point,
         bounds-of-symbol-at-point, bounds-of-symbol-nearest-point,
         bounds-of-thing-at-point-1, bounds-of-thing-nearest-point,
         form-at-point-with-bounds, form-nearest-point,
         form-nearest-point-with-bounds, forward-char-same-line,
         list-nearest-point, non-nil-symbol-name-at-point,
         non-nil-symbol-name-nearest-point,
         non-nil-symbol-nearest-point, number-nearest-point,
         sentence-nearest-point, sexp-nearest-point,
         symbol-at-point-with-bounds, symbol-name-at-point,
         symbol-name-nearest-point, symbol-nearest-point,
         symbol-nearest-point-with-bounds, thing-at-point-with-bounds,
         thing/form-nearest-point-with-bounds, thing-nearest-point,
         thing-nearest-point-with-bounds, word-nearest-point):
         New functions.

        (bounds-of-thing-at-point, form-at-point, list-at-point,
         number-at-point, sentence-at-point, sexp-at-point,
         thing-at-point, word-at-point): New arg SYNTAX-TABLE.

        (symbol-at-point): New arg NON-NIL.

        (beginning-of-thing, beginning-of-sexp, end-of-thing,
         end-of-sexp, form-at-point, forward-same-syntax,
         forward-symbol, forward-whitespace, in-string-p,
         list-at-point, number-at-point, sentence-at-point,
         sexp-at-point, symbol-at-point,
         thing-at-point-bounds-of-url-at-point, word-at-point):
         Added doc string.

------------8<-------- thingatpt.el diff -------------------

*** thingatpt-CVS-2007-07-14.el	Sat Jul 14 08:40:06 2007
--- thingatpt-CVS-patched-2007-07-15.el	Sun Jul 15 13:47:18 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,95 ----

  (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 &optional syntax-table)
    "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 file `thingatpt.el' for how to define a symbol as a valid THING.

! SYNTAX-TABLE is a syntax table to use.

! The value returned is a cons cell (START . END) giving the start and
! end positions of the textual entity that was found."
!   (if syntax-table
!       (let ((buffer-syntax (syntax-table)))
!         (unwind-protect
!             (progn
!               (set-syntax-table syntax-table)
!               (bounds-of-thing-at-point-1 thing))
!           (set-syntax-table buffer-syntax)))
!     (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,147 ****
  	(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))))
--- 136,284 ----
  	(error nil)))))

  ;;;###autoload
! (defun thing-at-point-with-bounds (thing &optional syntax-table)
!   "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'.
! SYNTAX-TABLE is a syntax table to use."
!   (let ((bounds (bounds-of-thing-at-point thing syntax-table)))
!     (and bounds (cons (buffer-substring (car bounds) (cdr bounds))
bounds))))
!
! ;;;###autoload
! (defun thing-at-point (thing &optional syntax-table)
!   "Return the THING at point, or nil if there is none.
  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 file `thingatpt.el' for how to define a symbol as a valid THING.

! SYNTAX-TABLE is a syntax table to use."
    (if (get thing 'thing-at-point)
        (funcall (get thing 'thing-at-point))
!     (let ((bounds (bounds-of-thing-at-point thing syntax-table)))
!       (and bounds (buffer-substring (car bounds) (cdr bounds))))))
!
! ;;;###autoload
! (defun thing-nearest-point-with-bounds (thing &optional syntax-table)
!   "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).
! SYNTAX-TABLE is a syntax table to use."
!   (thing/form-nearest-point-with-bounds
!    #'thing-at-point-with-bounds thing nil syntax-table))
!
! (defun thing/form-nearest-point-with-bounds (fn thing pred syntax-table)
!   "Thing or form nearest point, with bounds.
! FN is a function returning a thing or form at point, with bounds.
! Other args are as for `thing-nearest-point-with-bounds'."
!   (let ((f-or-t+bds (if pred
!                         (funcall fn thing pred syntax-table)
!                       (funcall fn thing syntax-table)))
!         (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 syntax-table)
!                              (funcall fn thing syntax-table))
!                 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
syntax-table)
!                                                 (funcall fn thing
syntax-table)))))
!               (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
syntax-table)
!                                      (funcall fn thing syntax-table)))))
!               (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 &optional syntax-table)
!   "Return (START . END) with START and END of  type THING.
! Return nil if no such THING is found.  See `thing-nearest-point'.
! SYNTAX-TABLE is a syntax table to use."
!   (let ((thing+bds (thing-nearest-point-with-bounds thing syntax-table)))
!     (and thing+bds (cdr thing+bds))))
!
! ;;;###autoload
! (defun thing-nearest-point (thing &optional syntax-table)
!   "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.
!
! A related function:
!   `thing-at-point' returns the THING under the cursor, or nil if none.
!
! SYNTAX-TABLE is a syntax table to use."
!   (let ((thing+bds (thing-nearest-point-with-bounds thing syntax-table)))
!     (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))))
***************
*** 159,170 ****
--- 296,309 ----
  ;;  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)))
***************
*** 174,179 ****
--- 313,319 ----
  (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)))
***************
*** 240,245 ****
--- 380,386 ----

  (put 'url 'bounds-of-thing-at-point
'thing-at-point-bounds-of-url-at-point)
  (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
***************
*** 370,375 ****
--- 511,518 ----
  ;;  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)
***************
*** 387,392 ****
--- 530,537 ----
  ;;  Symbols

  (defun forward-symbol (arg)
+   "Move forward ARG symbols.
+ Move backward if ARG is negative."
    (interactive "p")
    (if (natnump arg)
        (re-search-forward "\\(\\sw\\|\\s_\\)+" nil 'move arg)
***************
*** 398,403 ****
--- 543,550 ----
  ;;  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
***************
*** 407,417 ****
      (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."
--- 554,559 ----
***************
*** 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
--- 568,856 ----
  	(error "Can't read whole string")
        (car read-data))))

!
! ;;; FORMS ----------------------------------------------------------
!
! ;;;###autoload
! (defun form-at-point-with-bounds (&optional thing pred syntax-table)
!   "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.
!
! Optional arguments:
!   THING is the kind of form desired (default: `sexp').
!   PRED is a predicate that THING must satisfy to qualify.
!   SYNTAX-TABLE is a syntax table to use."
!   (let* ((thing+bds (thing-at-point-with-bounds (or thing 'sexp)
!                                                 syntax-table))
!          (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 syntax-table)
!   "Return (START . END), with START and END of `form-at-point'.
!
! Optional arguments:
!   THING is the kind of form desired (default: `sexp').
!   PRED is a predicate that THING must satisfy to qualify.
!   SYNTAX-TABLE is a syntax table to use."
!   (let ((form+bds (form-at-point-with-bounds thing pred syntax-table)))
!     (and form+bds (cdr form+bds))))
!
! ;;;###autoload
! (defun form-at-point (&optional thing pred syntax-table)
!   "Return the form nearest to the cursor, if any, else return nil.
! The form is a Lisp entity, not necessarily a string.
!
! Optional arguments:
!   THING is the kind of form desired (default: `sexp').
!   PRED is a predicate that THING must satisfy to qualify.
!   SYNTAX-TABLE is a syntax table to use."
    (let ((sexp (condition-case nil
! 		  (read-from-whole-string (thing-at-point (or thing 'sexp)
syntax-table))
  		(error nil))))
      (if (or (not pred) (funcall pred sexp)) sexp)))

  ;;;###autoload
! (defun form-nearest-point-with-bounds (&optional thing pred syntax-table)
!   "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.
!
! Optional arguments:
!   THING is the kind of form desired (default: `sexp').
!   PRED is a predicate that THING must satisfy to qualify.
!   SYNTAX-TABLE is a syntax table to use."
!   (thing/form-nearest-point-with-bounds
!    #'form-at-point-with-bounds thing pred syntax-table))
!
! ;;;###autoload
! (defun bounds-of-form-nearest-point (&optional thing pred syntax-table)
!   "Return (START . END) with START and END of `form-nearest-point'.
! Return nil if no such form is found.
!
! Optional arguments:
!   THING is the kind of form desired (default: `sexp').
!   PRED is a predicate that THING must satisfy to qualify.
!   SYNTAX-TABLE is a syntax table to use."
!   (let ((form+bds (form-nearest-point-with-bounds thing pred
syntax-table)))
!     (and form+bds (cdr form+bds))))
!
! ;;;###autoload
! (defun form-nearest-point (&optional thing pred syntax-table)
!   "Return the form nearest to the cursor, if any, else return nil.
! \"Nearest\" to point is determined as for `thing-nearest-point'.
!
! Optional arguments:
!   THING is the kind of form desired (default: `sexp').
!   PRED is a predicate that THING must satisfy to qualify.
!   SYNTAX-TABLE is a syntax table to use."
!   (let ((form+bds (form-nearest-point-with-bounds thing pred
syntax-table)))
!     (and form+bds (car form+bds))))
!
!
! ;;; SYMBOLS ----------------------------------------------------------
!
! ;;;###autoload
! (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."
!   (form-at-point-with-bounds
!    'symbol (if non-nil (lambda (sym) (and sym (symbolp sym))) 'symbolp)
!    emacs-lisp-mode-syntax-table))
!
! ;;;###autoload
! (defun bounds-of-symbol-at-point (&optional non-nil)
!   "Return (START . END) with START and END of `symbol-at-point'.
! If optional arg NON-NIL is non-nil, then the nearest symbol other
!   than `nil' is sought."
!   (let ((symb+bds (symbol-at-point-with-bounds non-nil)))
!     (and symb+bds (cdr symb+bds))))
!
! ;;;###autoload
! (defun 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-nearest-point' returns the symbol nearest the cursor, or nil.
!   `symbol-name-nearest-point' returns the name of
!     `symbol-nearest-point' as a string, or \"\" if none.
!   `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."
!   ;; Needs to satisfy both: 1) symbol syntax, 2) be interned.
!   (form-at-point
!    'symbol (if non-nil (lambda (sym) (and sym (symbolp sym))) 'symbolp)
!    emacs-lisp-mode-syntax-table))
!
! ;;;###autoload
! (defun symbol-nearest-point-with-bounds (&optional non-nil)
!   "Return (SYMBOL START . END) with START and END of SYMBOL.
! SYMBOL is the `symbol-nearest-point' (which see).
! If optional arg NON-NIL is non-nil, then the nearest symbol other
!   than `nil' is sought.
! Return nil if no such Emacs Lisp symbol is found."
!   (form-nearest-point-with-bounds
!    'symbol (if non-nil (lambda (sym) (and sym (symbolp sym))) 'symbolp)
!    emacs-lisp-mode-syntax-table))
!
! ;;;###autoload
! (defun bounds-of-symbol-nearest-point (&optional non-nil)
!   "Return (START . END) with START and END of `symbol-nearest-point'.
! If optional arg NON-NIL is non-nil, then the nearest symbol other
!   than `nil' is sought."
!   (let ((symb+bds (symbol-nearest-point-with-bounds non-nil)))
!     (and symb+bds (cdr symb+bds))))
!
! ;;;###autoload
! (defun 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 symbol under the cursor, or nil if none.
!   `symbol-name-nearest-point' returns the name of `symbol-nearest-point'
!     as a string, or \"\" if none.
!   `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 non-nil)))
!     (and symb+bds (car symb+bds))))
!
! ;;;###autoload
! (defun non-nil-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 symbol under the cursor, or nil if none.
!   `symbol-name-nearest-point' returns the name of `symbol-nearest-point'
!     as a string, or \"\" if none.
!   `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 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 (symbol-at-point-with-bounds)))
!     (if symb+bds (symbol-name (car symb+bds)) "")))
!
  ;;;###autoload
! (defun non-nil-symbol-name-at-point ()
!   "String naming the Emacs Lisp symbol nearest point, or \"\" if none.
! Returns the name of the nearest symbol other than `nil'.
! \"Nearest\" to point is determined as for `thing-nearest-point'."
!   (let ((symb+bds (symbol-at-point-with-bounds t)))
!     (if symb+bds (symbol-name (car symb+bds)) "")))
!
! ;;;###autoload
! (defun 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 (symbol-nearest-point-with-bounds)))
!     (if symb+bds (symbol-name (car symb+bds)) "")))
!
! ;;;###autoload
! (defun non-nil-symbol-name-nearest-point ()
!   "String naming the Emacs Lisp symbol nearest point, or \"\" if none.
! Returns the name of the nearest symbol other than `nil'.
! \"Nearest\" to point is determined as for `thing-nearest-point'."
!   (let ((symb+bds (symbol-nearest-point-with-bounds t)))
!     (if symb+bds (symbol-name (car symb+bds)) "")))
!
! ;;;###autoload
! (defun word-at-point (&optional syntax-table)
!   "Return the word (a string) nearest to point, if any, else \"\".
! SYNTAX-TABLE is a syntax table to use."
!   (thing-at-point 'word syntax-table))
!
! ;;;###autoload
! (defun word-nearest-point (&optional syntax-table)
!   "Return the word (a string) nearest to point, if any, else \"\".
! \"Nearest\" to point is determined as for `thing-nearest-point'.
! SYNTAX-TABLE is a syntax table to use."
!   (thing-nearest-point 'word syntax-table))
!
! ;;;###autoload
! (defun sentence-at-point (&optional syntax-table)
!   "Return the sentence (a string) nearest to point, if any, else \"\".
! SYNTAX-TABLE is a syntax table to use."
!   (thing-at-point 'sentence syntax-table))
!
! ;;;###autoload
! (defun sentence-nearest-point (&optional syntax-table)
!   "Return the sentence (a string) nearest to point, if any, else \"\".
! \"Nearest\" to point is determined as for `thing-nearest-point'.
! SYNTAX-TABLE is a syntax table to use."
!   (thing-nearest-point 'sentence syntax-table))
!
! ;;;###autoload
! (defun sexp-at-point (&optional syntax-table)
!   "Return the sexp (a string) nearest to point, if any, else \"\"..
! SYNTAX-TABLE is a syntax table to use."
!   (form-at-point 'sexp syntax-table))
!
! ;;;###autoload
! (defun sexp-nearest-point (&optional syntax-table)
!   "Return the sexp (a string) nearest to point, if any, else \"\".
! \"Nearest\" to point is determined as for `thing-nearest-point'.
! SYNTAX-TABLE is a syntax table to use."
!   (form-nearest-point 'sexp syntax-table))
!
! ;;;###autoload
! (defun number-at-point (&optional syntax-table)
!   "Return the number at point, if any, else nil.
! SYNTAX-TABLE is a syntax table to use."
!   (form-at-point 'sexp 'numberp syntax-table))
!
! ;;;###autoload
! (defun number-nearest-point (&optional syntax-table)
!   "Return the number nearest to point, if any, else nil.
! \"Nearest\" to point is determined as for `thing-nearest-point'.
! SYNTAX-TABLE is a syntax table to use."
!   (form-nearest-point 'sexp 'numberp syntax-table))
!
! ;;;###autoload
! (defun list-at-point (&optional syntax-table)
!   "Return the list nearest to point, if any, else nil.
! SYNTAX-TABLE is a syntax table to use."
!   (form-at-point 'list 'listp syntax-table))
!
  ;;;###autoload
! (defun list-nearest-point (&optional syntax-table)
!   "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'.
! SYNTAX-TABLE is a syntax table to use."
!   (form-nearest-point 'list 'listp syntax-table))

  ;; arch-tag: bb65a163-dae2-4055-aedc-fe11f497f698
  ;;; thingatpt.el ends here

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: patch for thingatpt.el
  2007-07-15 21:08 patch for thingatpt.el Drew Adams
@ 2007-07-16  6:54 ` Drew Adams
  2007-07-16  7:12   ` Drew Adams
  2007-07-16 15:12 ` Stefan Monnier
  1 sibling, 1 reply; 16+ messages in thread
From: Drew Adams @ 2007-07-16  6:54 UTC (permalink / raw)
  To: Emacs-Devel

Here is a minor bug fix for thingatpt.el - add these lines:

(put 'defun 'beginning-op 'beginning-of-defun)
(put 'defun 'end-op 'end-of-defun)

Otherwise, these two doc strings that refer to thing type `defun' are
incorrect: `bounds-of-thing-at-point', `thing-at-point'. Without those two
lines, these functions always return nil for type `defun'.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: patch for thingatpt.el
  2007-07-16  6:54 ` Drew Adams
@ 2007-07-16  7:12   ` Drew Adams
  0 siblings, 0 replies; 16+ messages in thread
From: Drew Adams @ 2007-07-16  7:12 UTC (permalink / raw)
  To: Emacs-Devel

> Here is a minor bug fix for thingatpt.el - add these lines:
>
> (put 'defun 'beginning-op 'beginning-of-defun)
> (put 'defun 'end-op 'end-of-defun)
>
> Otherwise, these two doc strings that refer to thing type `defun' are
> incorrect: `bounds-of-thing-at-point', `thing-at-point'. Without those two
> lines, these functions always return nil for type `defun'.


Sorry for the noise, but this one is also needed:
(put 'defun 'forward-op 'end-of-defun)

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: patch for thingatpt.el
  2007-07-15 21:08 patch for thingatpt.el Drew Adams
  2007-07-16  6:54 ` Drew Adams
@ 2007-07-16 15:12 ` Stefan Monnier
  2007-07-16 16:55   ` Drew Adams
  1 sibling, 1 reply; 16+ messages in thread
From: Stefan Monnier @ 2007-07-16 15:12 UTC (permalink / raw)
  To: Drew Adams; +Cc: Emacs-Devel

> Below is a patch for thingatpt.el that provides additional functionality and
> new thing and form functions. In particular: (1) it lets you supply a
> syntax-table argument to most functions, to affect the definition of what a
> word etc. is, and (2) it provides functions to return things near point, not
> just precisely at point.

I believe that point 1 is misguided.  We have `with-syntax-table' for those
cases and it is quite sufficient AFAIK.


        Stefan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: patch for thingatpt.el
  2007-07-16 15:12 ` Stefan Monnier
@ 2007-07-16 16:55   ` Drew Adams
  2007-07-16 17:33     ` Stefan Monnier
  0 siblings, 1 reply; 16+ messages in thread
From: Drew Adams @ 2007-07-16 16:55 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Emacs-Devel

> > Below is a patch for thingatpt.el that provides additional
> > functionality and new thing and form functions. In particular:
> > (1) it lets you supply a syntax-table argument to most functions,
> > to affect the definition of what a word etc. is, and (2) it
> > provides functions to return things near point, not
> > just precisely at point.
>
> I believe that point 1 is misguided.  We have `with-syntax-table'
> for those cases and it is quite sufficient AFAIK.

Right, and it's a much better approach too. Sorry about that. My enhancement
predated `with-syntax-table', and I wasn't aware of it.

Here is an updated change log and patch, which also incorporates the `defun'
bug fix I sent after the previous patch.

---------8<------------------

2007-07-16  Drew Adams  <drew.adams@oracle.com>

      * thingatpt.el: Functions for things near point.  Treat defuns.

        (near-point-x-distance, near-point-y-distance): New options.

        (bounds-of-form-at-point, bounds-of-form-nearest-point,
         bounds-of-symbol-at-point, bounds-of-symbol-nearest-point,
         bounds-of-thing-at-point-1, bounds-of-thing-nearest-point,
         form-at-point-with-bounds, form-nearest-point,
         form-nearest-point-with-bounds, forward-char-same-line,
         list-nearest-point, non-nil-symbol-name-at-point,
         non-nil-symbol-name-nearest-point,
         non-nil-symbol-nearest-point, number-nearest-point,
         sentence-nearest-point, sexp-nearest-point,
         symbol-at-point-with-bounds, symbol-name-at-point,
         symbol-name-nearest-point, symbol-nearest-point,
         symbol-nearest-point-with-bounds, thing-at-point-with-bounds,
         thing/form-nearest-point-with-bounds, thing-nearest-point,
         thing-nearest-point-with-bounds, word-nearest-point):
         New functions.

        (symbol-at-point): New arg NON-NIL.

        (beginning-of-thing, beginning-of-sexp, end-of-thing,
         end-of-sexp, form-at-point, forward-same-syntax,
         forward-symbol, forward-whitespace, in-string-p,
         list-at-point, number-at-point, sentence-at-point,
         sexp-at-point, symbol-at-point,
         thing-at-point-bounds-of-url-at-point, word-at-point):
         Added doc string.

        Defined treatment of defuns (in doc strings, but undefined).

---------8<------------------

*** thingatpt-CVS-2007-07-14.el	Sat Jul 14 08:40:06 2007
--- thingatpt-CVS-patched-2007-07-16.el	Mon Jul 16 09:45:58 2007
***************
*** 49,66 ****

  (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)
--- 49,71 ----

  (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)
***************
*** 68,79 ****
  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)))
--- 73,85 ----
  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 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)
--- 126,325 ----
  	(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 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 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
--- 352,359 ----
    "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))
--- 368,381 ----
              (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 ****
--- 403,409 ----
  	  (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)))
--- 439,444 ----
***************
*** 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)))
--- 463,468 ----
***************
*** 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)))
--- 470,475 ----
***************
*** 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)
--- 478,486 ----
                (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."
--- 490,522 ----
  	      (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."
    (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
--- 531,788 ----
  	(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-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))))
!
! ;;;###autoload
! (defun bounds-of-symbol-at-point (&optional non-nil)
!   "Return (START . END) with START and END of `symbol-at-point'.
! If optional arg NON-NIL is non-nil, then the nearest symbol other
!   than `nil' is sought."
!   (let ((symb+bds (symbol-at-point-with-bounds non-nil)))
!     (and symb+bds (cdr symb+bds))))
!
! ;;;###autoload
! (defun 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-nearest-point' returns the symbol nearest the cursor, or nil.
!   `symbol-name-nearest-point' returns the name of
!     `symbol-nearest-point' as a string, or \"\" if none.
!   `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 symbol-nearest-point-with-bounds (&optional non-nil)
!   "Return (SYMBOL START . END) with START and END of SYMBOL.
! SYMBOL is the `symbol-nearest-point' (which see).
! If optional arg NON-NIL is non-nil, then the nearest symbol other
!   than `nil' is sought.
! Return nil if no such Emacs Lisp symbol is found."
!   (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-symbol-nearest-point (&optional non-nil)
!   "Return (START . END) with START and END of `symbol-nearest-point'.
! If optional arg NON-NIL is non-nil, then the nearest symbol other
!   than `nil' is sought."
!   (let ((symb+bds (symbol-nearest-point-with-bounds non-nil)))
!     (and symb+bds (cdr symb+bds))))
!
! ;;;###autoload
! (defun 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 symbol under the cursor, or nil if none.
!   `symbol-name-nearest-point' returns the name of `symbol-nearest-point'
!     as a string, or \"\" if none.
!   `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 non-nil)))
!     (and symb+bds (car symb+bds))))
!
! ;;;###autoload
! (defun non-nil-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 symbol under the cursor, or nil if none.
!   `symbol-name-nearest-point' returns the name of `symbol-nearest-point'
!     as a string, or \"\" if none.
!   `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 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 (symbol-at-point-with-bounds)))
!     (if symb+bds (symbol-name (car symb+bds)) "")))
!
  ;;;###autoload
! (defun non-nil-symbol-name-at-point ()
!   "String naming the Emacs Lisp symbol nearest point, or \"\" if none.
! Returns the name of the nearest symbol other than `nil'.
! \"Nearest\" to point is determined as for `thing-nearest-point'."
!   (let ((symb+bds (symbol-at-point-with-bounds t)))
!     (if symb+bds (symbol-name (car symb+bds)) "")))
!
  ;;;###autoload
! (defun 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 (symbol-nearest-point-with-bounds)))
!     (if symb+bds (symbol-name (car symb+bds)) "")))
!
! ;;;###autoload
! (defun non-nil-symbol-name-nearest-point ()
!   "String naming the Emacs Lisp symbol nearest point, or \"\" if none.
! Returns the name of the nearest symbol other than `nil'.
! \"Nearest\" to point is determined as for `thing-nearest-point'."
!   (let ((symb+bds (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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: patch for thingatpt.el
  2007-07-16 16:55   ` Drew Adams
@ 2007-07-16 17:33     ` Stefan Monnier
  2007-07-16 21:01       ` Drew Adams
  0 siblings, 1 reply; 16+ messages in thread
From: Stefan Monnier @ 2007-07-16 17:33 UTC (permalink / raw)
  To: Drew Adams; +Cc: Emacs-Devel

>>>>> "Drew" == Drew Adams <drew.adams@oracle.com> writes:

>> > Below is a patch for thingatpt.el that provides additional
>> > functionality and new thing and form functions. In particular:
>> > (1) it lets you supply a syntax-table argument to most functions,
>> > to affect the definition of what a word etc. is, and (2) it
>> > provides functions to return things near point, not
>> > just precisely at point.
>> 
>> I believe that point 1 is misguided.  We have `with-syntax-table'
>> for those cases and it is quite sufficient AFAIK.

> Right, and it's a much better approach too. Sorry about that. My enhancement
> predated `with-syntax-table', and I wasn't aware of it.

> 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').


        Stefan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: patch for thingatpt.el
  2007-07-16 17:33     ` Stefan Monnier
@ 2007-07-16 21:01       ` Drew Adams
  2007-07-26 15:06         ` Drew Adams
  0 siblings, 1 reply; 16+ messages in thread
From: Drew Adams @ 2007-07-16 21:01 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Emacs-Devel

> > 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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: patch for thingatpt.el
  2007-07-16 21:01       ` Drew Adams
@ 2007-07-26 15:06         ` Drew Adams
  2008-06-06 16:28           ` Drew Adams
  0 siblings, 1 reply; 16+ messages in thread
From: Drew Adams @ 2007-07-26 15:06 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Emacs-Devel

Resending patch. What is the status of this?

> From: Drew Adams Sent: Monday, July 16, 2007 2:01 PM
>
> > > 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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: patch for thingatpt.el
  2007-07-26 15:06         ` Drew Adams
@ 2008-06-06 16:28           ` Drew Adams
  2008-06-06 19:29             ` Stefan Monnier
  0 siblings, 1 reply; 16+ messages in thread
From: Drew Adams @ 2008-06-06 16:28 UTC (permalink / raw)
  To: 'Stefan Monnier'; +Cc: 'Emacs-Devel'

Resending. There was no reply. 

> From: Drew Adams Sent: Thursday, July 26, 2007 8:07 AM
> Resending patch. What is the status of this?





^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: patch for thingatpt.el
  2008-06-06 16:28           ` Drew Adams
@ 2008-06-06 19:29             ` Stefan Monnier
  2008-06-06 20:29               ` Drew Adams
  0 siblings, 1 reply; 16+ messages in thread
From: Stefan Monnier @ 2008-06-06 19:29 UTC (permalink / raw)
  To: Drew Adams; +Cc: 'Emacs-Devel'

> Resending. There was no reply. 
>> From: Drew Adams Sent: Thursday, July 26, 2007 8:07 AM
>> Resending patch. What is the status of this?

Well, here's a reply, then.


        Stefan "who has no idea what this is about"




^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: patch for thingatpt.el
  2008-06-06 19:29             ` Stefan Monnier
@ 2008-06-06 20:29               ` Drew Adams
  2008-06-07 12:19                 ` Andreas Röhler
  0 siblings, 1 reply; 16+ messages in thread
From: Drew Adams @ 2008-06-06 20:29 UTC (permalink / raw)
  To: 'Stefan Monnier'; +Cc: 'Emacs-Devel'

> > Resending. There was no reply. 
> >> From: Drew Adams Sent: Thursday, July 26, 2007 8:07 AM
> >> Resending patch. What is the status of this?
> 
> Well, here's a reply, then.
>         Stefan "who has no idea what this is about"

Very witty.

For those who don't want to look in the archives:

----------8<----------------
> From: Drew Adams Sent: Monday, July 16, 2007 2:01 PM
>
> > > 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





^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: patch for thingatpt.el
  2008-06-06 20:29               ` Drew Adams
@ 2008-06-07 12:19                 ` Andreas Röhler
  2008-06-07 21:06                   ` Drew Adams
  0 siblings, 1 reply; 16+ messages in thread
From: Andreas Röhler @ 2008-06-07 12:19 UTC (permalink / raw)
  To: emacs-devel; +Cc: Stefan Monnier, Drew Adams

Am Freitag, 6. Juni 2008 schrieb Drew Adams:
> form-nearest-point

Hi Drew,

just for curiosity: could you tell in which
circumstances you use something like "nearest point"?

Saw that implemented already in your code, so
you will know the reason.

Simply can't imagine, in the case being nearby some
form, why not use forward-word or backward-word,
resp. skip-chars-... that kind of simple things?

Thanks

Andreas Röhler






^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: patch for thingatpt.el
  2008-06-07 12:19                 ` Andreas Röhler
@ 2008-06-07 21:06                   ` Drew Adams
  2008-06-08  3:17                     ` Stefan Monnier
  2008-06-08  7:18                     ` Andreas Röhler
  0 siblings, 2 replies; 16+ messages in thread
From: Drew Adams @ 2008-06-07 21:06 UTC (permalink / raw)
  To: 'Andreas Röhler', emacs-devel; +Cc: 'Stefan Monnier'

> just for curiosity: could you tell in which
> circumstances you use something like "nearest point"?
> 
> Saw that implemented already in your code, so
> you will know the reason.

I use `*-nearest-point' functions typically to pick up a default value for use
in completion by a command. I use `symbol-nearest-point' and
`symbol-name-nearest-point' more often than other `*-nearest-point' functions.

Places where I use `*-nearest-point':

grep, make-face, find-dired, where-is, describe-function, describe-command,
describe-variable, describe-option, descibe-option-of-type,
Info-goto-emacs-command-node, name-last-kbd-macro, insert-kbd-macro,
enable-command, disable-command, query-replace, query-replace-regexp,
query-replace-regexp-eval, replace-string, replace-regexp, keep-lines,
flush-lines, how-many, occur, multi-occur, multi-occur-in-matching-buffers,
read-variable, read-any-variable, synonyms, synonyms-no-read,
synonyms-definition, synonyms-definition-no-read, synonyms-definition-mouse,
thing-region, cycle-thing-region, cancel-function-timers 

(For those of the above that are standard functions, I have my own version that
uses `*-nearest-point'.)

And in Icicles, you can use `M-.' in the minibuffer to yank different kinds of
thing from at or near point to the minibuffer. I use `*-nearest-point' there
also.

> Simply can't imagine, in the case being nearby some
> form, why not use forward-word or backward-word,
> resp. skip-chars-... that kind of simple things?

Do you mean as a user or as part of the definition of some command? If the
former, then why should a user need to fiddle with the exact cursor position,
just to be able to pick up a default value? If you mean the latter, then that's
just what `*-nearest-point' does.

See the recent bug with subject "describe-* and M-x should see past quote mark"
as an example. Stefan presumably (I haven't checked) fixed this by maneuvering
around a quote mark at point, to get to the symbol. That kind of maneuvering is
unnecessary as a one-off fix if you just use `*-nearest-point'.

That's the kind of thing that `*-nearest-point' is designed for. Quote marks,
parens, spaces, etc. are some of the stuff that might be under the cursor when
it is near a name that could serve as a good default value.







^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: patch for thingatpt.el
  2008-06-07 21:06                   ` Drew Adams
@ 2008-06-08  3:17                     ` Stefan Monnier
  2008-06-08  7:18                     ` Andreas Röhler
  1 sibling, 0 replies; 16+ messages in thread
From: Stefan Monnier @ 2008-06-08  3:17 UTC (permalink / raw)
  To: Drew Adams; +Cc: 'Andreas Röhler', emacs-devel

> See the recent bug with subject "describe-* and M-x should see past
> quote mark" as an example.  Stefan presumably (I haven't checked)
> fixed this by maneuvering around a quote mark at point, to get to the
> symbol. That kind of maneuvering is unnecessary as a one-off fix if
> you just use `*-nearest-point'.

Actually, that's a bad example: the code already did the right thing,
but some part of it was not run with the proper syntax-table.


        Stefan





^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: patch for thingatpt.el
  2008-06-07 21:06                   ` Drew Adams
  2008-06-08  3:17                     ` Stefan Monnier
@ 2008-06-08  7:18                     ` Andreas Röhler
  2008-06-08  7:49                       ` Drew Adams
  1 sibling, 1 reply; 16+ messages in thread
From: Andreas Röhler @ 2008-06-08  7:18 UTC (permalink / raw)
  To: emacs-devel; +Cc: Stefan Monnier, Drew Adams

Am Samstag, 7. Juni 2008 schrieb Drew Adams:
> > just for curiosity: could you tell in which
> > circumstances you use something like "nearest point"?
> > 
> > Saw that implemented already in your code, so
> > you will know the reason.
> 
> I use `*-nearest-point' functions typically to pick up a default value for 
use
> in completion by a command. I use `symbol-nearest-point' and
> `symbol-name-nearest-point' more often than other `*-nearest-point' 
functions.
> 
> Places where I use `*-nearest-point':
> 
> grep, make-face, find-dired, where-is, describe-function, describe-command,
> describe-variable, describe-option, descibe-option-of-type,
> Info-goto-emacs-command-node, name-last-kbd-macro, insert-kbd-macro,
> enable-command, disable-command, query-replace, query-replace-regexp,
> query-replace-regexp-eval, replace-string, replace-regexp, keep-lines,
> flush-lines, how-many, occur, multi-occur, multi-occur-in-matching-buffers,
> read-variable, read-any-variable, synonyms, synonyms-no-read,
> synonyms-definition, synonyms-definition-no-read, synonyms-definition-mouse,
> thing-region, cycle-thing-region, cancel-function-timers 
> 
> (For those of the above that are standard functions, I have my own version 
that
> uses `*-nearest-point'.)
> 
> And in Icicles, you can use `M-.' in the minibuffer to yank different kinds 
of
> thing from at or near point to the minibuffer. I use `*-nearest-point' there
> also.
> 
> > Simply can't imagine, in the case being nearby some
> > form, why not use forward-word or backward-word,
> > resp. skip-chars-... that kind of simple things?
> 
> Do you mean as a user or as part of the definition of some command? If the
> former, then why should a user need to fiddle with the exact cursor 
position,
> just to be able to pick up a default value? If you mean the latter, then 
that's
> just what `*-nearest-point' does.
> 
> See the recent bug with subject "describe-* and M-x should see past quote 
mark"
> as an example. Stefan presumably (I haven't checked) fixed this by 
maneuvering
> around a quote mark at point, to get to the symbol. That kind of maneuvering 
is
> unnecessary as a one-off fix if you just use `*-nearest-point'.
> 
> That's the kind of thing that `*-nearest-point' is designed for. Quote 
marks,
> parens, spaces, etc. are some of the stuff that might be under the cursor 
when
> it is near a name that could serve as a good default value.
> 
> 

Thanks a lot.

I assume, if already at thing, thing-nearest- will
also DTRT, so one key/command will be enough then.

Please let me raise still two other points at the
occasion:

All thing-at-point forms might be very useful for
immediate copying (and some more operations) IMO. 
What about to make them callable interactivly?

Return-value of `symbol-at-point' is not consistent
with other forms.

`symbol-at-point' interns symbol-name under
point--as you told me kindly months ago--while 
all other form deliver a portion of the
buffer, a substring.

My suggestion is: let `symbol-at-point' behave as the
rest. Then write (intern (symbol-at-point)) if the 
interned symbol is needed.

That change will break some code now, but is more
straightforward and looks promising on the long run.

It enables the set-up of a range of functions relying
 on thing-at-point. Otherwise you must always deal 
separatly with symbol-at... 



Andreas Röhler







^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: patch for thingatpt.el
  2008-06-08  7:18                     ` Andreas Röhler
@ 2008-06-08  7:49                       ` Drew Adams
  0 siblings, 0 replies; 16+ messages in thread
From: Drew Adams @ 2008-06-08  7:49 UTC (permalink / raw)
  To: 'Andreas Röhler', emacs-devel; +Cc: 'Stefan Monnier'

> I assume, if already at thing, thing-nearest- will
> also DTRT, so one key/command will be enough then.
> 
> Please let me raise still two other points at the
> occasion:
> 
> All thing-at-point forms might be very useful for
> immediate copying (and some more operations) IMO. 
> What about to make them callable interactivly?
> 
> Return-value of `symbol-at-point' is not consistent
> with other forms.
> 
> `symbol-at-point' interns symbol-name under
> point--as you told me kindly months ago--while 
> all other form deliver a portion of the
> buffer, a substring.
> 
> My suggestion is: let `symbol-at-point' behave as the
> rest. Then write (intern (symbol-at-point)) if the 
> interned symbol is needed.
> 
> That change will break some code now, but is more
> straightforward and looks promising on the long run.
> 
> It enables the set-up of a range of functions relying
> on thing-at-point. Otherwise you must always deal 
> separatly with symbol-at... 

Please start another thread for all of that. This thread is about a specific
patch. Additional proposals for different changes to thingatpt.el can be
discussed separately (preferably after this patch is applied).

Wrt the return value of `symbol-at-point', see the previous discussion, which I
referenced earlier. What you are after is called `symbol-name-at-point' in my
patch. A symbol is a symbol; a symbol name is a string.





^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2008-06-08  7:49 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-07-15 21:08 patch for thingatpt.el Drew Adams
2007-07-16  6:54 ` Drew Adams
2007-07-16  7:12   ` Drew Adams
2007-07-16 15:12 ` Stefan Monnier
2007-07-16 16:55   ` Drew Adams
2007-07-16 17:33     ` Stefan Monnier
2007-07-16 21:01       ` Drew Adams
2007-07-26 15:06         ` Drew Adams
2008-06-06 16:28           ` Drew Adams
2008-06-06 19:29             ` Stefan Monnier
2008-06-06 20:29               ` Drew Adams
2008-06-07 12:19                 ` Andreas Röhler
2008-06-07 21:06                   ` Drew Adams
2008-06-08  3:17                     ` Stefan Monnier
2008-06-08  7:18                     ` Andreas Röhler
2008-06-08  7:49                       ` Drew Adams

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.