Skip to content

Commit 529dc07

Browse files
committed
Detect operators and binding operators at point for xref
This will be used for `xref-find-references` (`M-?`), although that command currently ignores the string and only uses the location. If an identifier both succeeds and precedes point, prefer the former. For instance, in `a+b` with the cursor on `+`, use `+` as the idenfier; with the cursor on `b`, use `b`.
1 parent de3f6bc commit 529dc07

File tree

1 file changed

+63
-1
lines changed

1 file changed

+63
-1
lines changed

emacs/merlin-xref.el

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,70 @@
4949
(cl-defmethod xref-backend-identifier-completion-table ((_backend (eql merlin-xref)))
5050
nil)
5151

52+
(defconst merlin-xref--operator-regexp
53+
(eval-when-compile
54+
(let* ((core-operator-char
55+
`(or "$" "&" "*" "+" "-" "/" "=" ">" "@" "^" "|"))
56+
(operator-char `(or "~" "!" "?" ,core-operator-char "%" "<" ":" "."))
57+
(prefix-symbol `(or (seq "!" (* ,operator-char))
58+
(seq (or "?" "~") (+ ,operator-char))))
59+
(infix-symbol `(or (seq (or ,core-operator-char "%" "<")
60+
(* ,operator-char))
61+
(seq "#" (+ ,operator-char))))
62+
(infix-op `(or ,infix-symbol
63+
":="
64+
;; Already handled as part of `infix-symbol':
65+
;; "*" "+" "-" "-." "=" "!=" "<" ">" "||" "&" "&&"
66+
;; Treated as normal symbols:
67+
;; "or" "mod" "land" "lor" "lxor" "lsl" "lsr" "asr"
68+
))
69+
(operator-name `(or ,prefix-symbol ,infix-op)))
70+
(rx-to-string operator-name t))))
71+
72+
(defconst merlin-xref--binding-operator-regexp
73+
(eval-when-compile
74+
(let* ((core-operator-char
75+
`(or "$" "&" "*" "+" "-" "/" "=" ">" "@" "^" "|"))
76+
(dot-operator-char
77+
`(or "!" "?" ,core-operator-char "%" ":"))
78+
(binding-suffix
79+
`(seq (or ,core-operator-char "<") (* ,dot-operator-char)))
80+
(binding-operator
81+
`(seq symbol-start (or "let" "and") ,binding-suffix)))
82+
(rx-to-string binding-operator t))))
83+
84+
(defconst merlin-xref--identifier-regexp
85+
(rx symbol-start (in "A-Za-z_") (* (in "A-Za-z0-9_'"))))
86+
5287
(cl-defmethod xref-backend-identifier-at-point ((_backend (eql merlin-xref)))
53-
(let ((symbol (thing-at-point 'symbol)))
88+
(let ((symbol
89+
(and
90+
(or
91+
;; Starting at point:
92+
;; - binding operator
93+
(looking-at merlin-xref--binding-operator-regexp)
94+
;; - ordinary name
95+
(looking-at merlin-xref--identifier-regexp)
96+
;; - operator
97+
(looking-at merlin-xref--operator-regexp)
98+
;; Starting before point:
99+
(let ((pt (point)))
100+
(and (or
101+
;; - binding operator
102+
(save-excursion
103+
(skip-chars-backward "letand$&*+/=<>@^|!?%:-")
104+
(looking-at merlin-xref--binding-operator-regexp))
105+
;; - ordinary name
106+
(save-excursion
107+
(skip-chars-backward "A-Za-z0-9_'")
108+
(looking-at merlin-xref--identifier-regexp))
109+
;; - operator
110+
(save-excursion
111+
(skip-chars-backward "$&*+/=<>@^|!?%:.~#-")
112+
(looking-at merlin-xref--operator-regexp)))
113+
114+
(<= pt (match-end 0)))))
115+
(match-string 0))))
54116
;; Return a string with the buffer position in a property, in case
55117
;; point changes before the string is used by one of the methods above.
56118
(and symbol (propertize symbol 'merlin-xref-point (point)))))

0 commit comments

Comments
 (0)