Subject: bug#64739: (forward-thing 'number) doesn't work with decimal numbers

From: Joseph Turner <[email-masked]>
Date: Sun, 23 Jul 2023 12:03:50 -0700

Eli Zaretskii <[email-masked]> writes:

>> From: Joseph Turner <[email-masked]>
>> Cc: Roland Winkler <[email-masked]>, [email-masked]
>> Date: Sat, 22 Jul 2023 20:36:16 -0700
>>
>> > By "its own function" I meant that we implement it in Emacs, not that
>> > you implement it in your personal customizations.
>>
>> I see that the definition of number-at-point includes two magic regexps,
>> one matching hex numbers and another matching decimal numbers. Would it
>> make sense to move those regexps into defconsts, and then create a new
>> function forward-number which uses those new constants?
>
> That's probably one idea, yes.  (But note that those regexps don't
> support numbers like "1.0e2".)

I agree that the regexp solution is not ideal.

> Another idea is to define a special-purpose syntax table and use that
> with forward-word.

Did you have something like this in mind?

(defvar number-syntax-table
  (let ((st (make-syntax-table)))
    (modify-syntax-entry ?. "w " st)
    ;; ?- and ?+ could indicate the sign at the beginning of a number or
    ;; they could indicate the sign of an exponent like 1.5e-6
    (modify-syntax-entry ?- "w " st)
    (modify-syntax-entry ?+ "w " st)
    ;; ?# acts as a prefix for integers in bases other than 10.
    (modify-syntax-entry ?# "w " st)
    st)
  "Syntax table used to detect word boundaries for numbers.")

(defun forward-number (&optional n)
  (interactive)
  (with-syntax-table number-syntax-table
    (forward-word-strictly n)))

(defun backward-number (&optional n)
  (interactive)
  (with-syntax-table number-syntax-table
    (forward-word-strictly n)))

;; We don't need the following two lines, since forward-thing uses
;; intern-soft to get these function names anyway.

(put 'number 'forward-op 'forward-number)
(put 'number 'beginning-op 'backward-number)

What would we use for end-op? Is it necessary?

Also I notice that the current implementation of number-at-point fails
to recognize the following as a single number:

-1.5e+6

Could we do something like:

(defun number-at-point (&optional no-properties)
  (with-syntax-table number-syntax-table
    (word-at-point no-properties)))

(put 'number 'thing-at-point 'number-at-point)

I'd appreciate feedback on the syntax table above. It incorrectly
recognizes some non-number strings as numbers:

a-a+a-
#abc#abc

> Yet another idea is to use 'read', since the Lisp reader already knows
> how to read numbers.

Sounds interesting! I'm not sure how to approach a solution like that.
How would you let the Lisp reader know where to start and stop reading?

Joseph