Commit | Line | Data |
---|---|---|
bbcc4d97 | 1 | ;;; lisp.el --- Lisp editing commands for Emacs -*- lexical-binding:t -*- |
6594deb0 | 2 | |
ba318903 | 3 | ;; Copyright (C) 1985-1986, 1994, 2000-2014 Free Software Foundation, |
ab422c4d | 4 | ;; Inc. |
9750e079 | 5 | |
34dc21db | 6 | ;; Maintainer: emacs-devel@gnu.org |
e9571d2a | 7 | ;; Keywords: lisp, languages |
bd78fa1d | 8 | ;; Package: emacs |
e5167999 | 9 | |
b73b9811 | 10 | ;; This file is part of GNU Emacs. |
11 | ||
d6cba7ae | 12 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
b73b9811 | 13 | ;; it under the terms of the GNU General Public License as published by |
d6cba7ae GM |
14 | ;; the Free Software Foundation, either version 3 of the License, or |
15 | ;; (at your option) any later version. | |
b73b9811 | 16 | |
17 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | ;; GNU General Public License for more details. | |
21 | ||
22 | ;; You should have received a copy of the GNU General Public License | |
d6cba7ae | 23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
b73b9811 | 24 | |
e41b2db1 ER |
25 | ;;; Commentary: |
26 | ||
e50c4203 DL |
27 | ;; Lisp editing commands to go with Lisp major mode. More-or-less |
28 | ;; applicable in other modes too. | |
e41b2db1 | 29 | |
e5167999 | 30 | ;;; Code: |
b73b9811 | 31 | |
7fe78b07 | 32 | ;; Note that this variable is used by non-lisp modes too. |
30e19aee | 33 | (defcustom defun-prompt-regexp nil |
cb711556 | 34 | "If non-nil, a regexp to ignore before a defun. |
7fe78b07 | 35 | This is only necessary if the opening paren or brace is not in column 0. |
a64dc1a4 | 36 | See function `beginning-of-defun'." |
ba6b3a2a RS |
37 | :type '(choice (const nil) |
38 | regexp) | |
30e19aee | 39 | :group 'lisp) |
24ff5498 | 40 | (make-variable-buffer-local 'defun-prompt-regexp) |
b73b9811 | 41 | |
30e19aee | 42 | (defcustom parens-require-spaces t |
becc6788 CY |
43 | "If non-nil, add whitespace as needed when inserting parentheses. |
44 | This affects `insert-parentheses' and `insert-pair'." | |
30e19aee RS |
45 | :type 'boolean |
46 | :group 'lisp) | |
44a53673 | 47 | |
11ae6c5d | 48 | (defvar forward-sexp-function nil |
dd8791e9 SM |
49 | ;; FIXME: |
50 | ;; - for some uses, we may want a "sexp-only" version, which only | |
51 | ;; jumps over a well-formed sexp, rather than some dwimish thing | |
52 | ;; like jumping from an "else" back up to its "if". | |
53 | ;; - for up-list, we could use the "sexp-only" behavior as well | |
54 | ;; to treat the dwimish halfsexp as a form of "up-list" step. | |
11ae6c5d SM |
55 | "If non-nil, `forward-sexp' delegates to this function. |
56 | Should take the same arguments and behave similarly to `forward-sexp'.") | |
57 | ||
b73b9811 | 58 | (defun forward-sexp (&optional arg) |
59 | "Move forward across one balanced expression (sexp). | |
3f63a9f7 DC |
60 | With ARG, do it that many times. Negative arg -N means move |
61 | backward across N balanced expressions. This command assumes | |
62 | point is not in a string or comment. Calls | |
63 | `forward-sexp-function' to do the work, if that is non-nil. If | |
64 | unable to move over a sexp, signal `scan-error' with three | |
65 | arguments: a message, the start of the obstacle (usually a | |
66 | parenthesis or list marker of some kind), and end of the | |
67 | obstacle." | |
61eee794 | 68 | (interactive "^p") |
b73b9811 | 69 | (or arg (setq arg 1)) |
11ae6c5d SM |
70 | (if forward-sexp-function |
71 | (funcall forward-sexp-function arg) | |
72 | (goto-char (or (scan-sexps (point) arg) (buffer-end arg))) | |
73 | (if (< arg 0) (backward-prefix-chars)))) | |
b73b9811 | 74 | |
75 | (defun backward-sexp (&optional arg) | |
76 | "Move backward across one balanced expression (sexp). | |
c6eeec65 | 77 | With ARG, do it that many times. Negative arg -N means |
8fc2ac41 | 78 | move forward across N balanced expressions. |
ba947bc4 GM |
79 | This command assumes point is not in a string or comment. |
80 | Uses `forward-sexp' to do the work." | |
61eee794 | 81 | (interactive "^p") |
b73b9811 | 82 | (or arg (setq arg 1)) |
83 | (forward-sexp (- arg))) | |
84 | ||
afb62fdd | 85 | (defun mark-sexp (&optional arg allow-extend) |
b73b9811 | 86 | "Set mark ARG sexps from point. |
e3f99b91 | 87 | The place mark goes is the same place \\[forward-sexp] would |
f07493e7 | 88 | move to with the same argument. |
afb62fdd | 89 | Interactively, if this command is repeated |
a64dc1a4 | 90 | or (in Transient Mark mode) if the mark is active, |
8fc2ac41 AM |
91 | it marks the next ARG sexps after the ones already marked. |
92 | This command assumes point is not in a string or comment." | |
afb62fdd RS |
93 | (interactive "P\np") |
94 | (cond ((and allow-extend | |
95 | (or (and (eq last-command this-command) (mark t)) | |
96 | (and transient-mark-mode mark-active))) | |
3610d3c9 | 97 | (setq arg (if arg (prefix-numeric-value arg) |
967e1a52 | 98 | (if (< (mark) (point)) -1 1))) |
cad113ae KG |
99 | (set-mark |
100 | (save-excursion | |
967e1a52 JL |
101 | (goto-char (mark)) |
102 | (forward-sexp arg) | |
103 | (point)))) | |
cad113ae KG |
104 | (t |
105 | (push-mark | |
106 | (save-excursion | |
3610d3c9 | 107 | (forward-sexp (prefix-numeric-value arg)) |
cad113ae KG |
108 | (point)) |
109 | nil t)))) | |
b73b9811 | 110 | |
111 | (defun forward-list (&optional arg) | |
112 | "Move forward across one balanced group of parentheses. | |
3bd1d8a8 LI |
113 | This command will also work on other parentheses-like expressions |
114 | defined by the current language mode. | |
c6eeec65 | 115 | With ARG, do it that many times. |
8fc2ac41 AM |
116 | Negative arg -N means move backward across N groups of parentheses. |
117 | This command assumes point is not in a string or comment." | |
61eee794 | 118 | (interactive "^p") |
b73b9811 | 119 | (or arg (setq arg 1)) |
120 | (goto-char (or (scan-lists (point) arg 0) (buffer-end arg)))) | |
121 | ||
122 | (defun backward-list (&optional arg) | |
123 | "Move backward across one balanced group of parentheses. | |
3bd1d8a8 LI |
124 | This command will also work on other parentheses-like expressions |
125 | defined by the current language mode. | |
c6eeec65 | 126 | With ARG, do it that many times. |
8fc2ac41 AM |
127 | Negative arg -N means move forward across N groups of parentheses. |
128 | This command assumes point is not in a string or comment." | |
61eee794 | 129 | (interactive "^p") |
b73b9811 | 130 | (or arg (setq arg 1)) |
131 | (forward-list (- arg))) | |
132 | ||
e50c4203 | 133 | (defun down-list (&optional arg) |
b73b9811 | 134 | "Move forward down one level of parentheses. |
3bd1d8a8 LI |
135 | This command will also work on other parentheses-like expressions |
136 | defined by the current language mode. | |
c6eeec65 | 137 | With ARG, do this that many times. |
8fc2ac41 AM |
138 | A negative argument means move backward but still go down a level. |
139 | This command assumes point is not in a string or comment." | |
61eee794 | 140 | (interactive "^p") |
e50c4203 | 141 | (or arg (setq arg 1)) |
b73b9811 | 142 | (let ((inc (if (> arg 0) 1 -1))) |
143 | (while (/= arg 0) | |
144 | (goto-char (or (scan-lists (point) inc -1) (buffer-end arg))) | |
145 | (setq arg (- arg inc))))) | |
146 | ||
3f63a9f7 | 147 | (defun backward-up-list (&optional arg escape-strings no-syntax-crossing) |
b73b9811 | 148 | "Move backward out of one level of parentheses. |
3bd1d8a8 | 149 | This command will also work on other parentheses-like expressions |
3f63a9f7 DC |
150 | defined by the current language mode. With ARG, do this that |
151 | many times. A negative argument means move forward but still to | |
152 | a less deep spot. If ESCAPE-STRINGS is non-nil (as it is | |
153 | interactively), move out of enclosing strings as well. If | |
154 | NO-SYNTAX-CROSSING is non-nil (as it is interactively), prefer to | |
155 | break out of any enclosing string instead of moving to the start | |
156 | of a list broken across multiple strings. On error, location of | |
157 | point is unspecified." | |
158 | (interactive "^p\nd\nd") | |
159 | (up-list (- (or arg 1)) escape-strings no-syntax-crossing)) | |
b73b9811 | 160 | |
3f63a9f7 | 161 | (defun up-list (&optional arg escape-strings no-syntax-crossing) |
b73b9811 | 162 | "Move forward out of one level of parentheses. |
3bd1d8a8 | 163 | This command will also work on other parentheses-like expressions |
3f63a9f7 DC |
164 | defined by the current language mode. With ARG, do this that |
165 | many times. A negative argument means move backward but still to | |
166 | a less deep spot. If ESCAPE-STRINGS is non-nil (as it is | |
167 | interactively), move out of enclosing strings as well. If | |
168 | NO-SYNTAX-CROSSING is non-nil (as it is interactively), prefer to | |
169 | break out of any enclosing string instead of moving to the start | |
170 | of a list broken across multiple strings. On error, location of | |
171 | point is unspecified." | |
172 | (interactive "^p\nd\nd") | |
e50c4203 | 173 | (or arg (setq arg 1)) |
984edd22 | 174 | (let ((inc (if (> arg 0) 1 -1)) |
3f63a9f7 | 175 | (pos nil)) |
b73b9811 | 176 | (while (/= arg 0) |
3f63a9f7 DC |
177 | (condition-case err |
178 | (save-restriction | |
179 | ;; If we've been asked not to cross string boundaries | |
180 | ;; and we're inside a string, narrow to that string so | |
181 | ;; that scan-lists doesn't find a match in a different | |
182 | ;; string. | |
183 | (when no-syntax-crossing | |
184 | (let* ((syntax (syntax-ppss)) | |
185 | (string-comment-start (nth 8 syntax))) | |
186 | (when string-comment-start | |
187 | (save-excursion | |
188 | (goto-char string-comment-start) | |
189 | (narrow-to-region | |
190 | (point) | |
191 | (if (nth 3 syntax) ; in string | |
192 | (condition-case nil | |
193 | (progn (forward-sexp) (point)) | |
194 | (scan-error (point-max))) | |
195 | (forward-comment 1) | |
196 | (point))))))) | |
197 | (if (null forward-sexp-function) | |
198 | (goto-char (or (scan-lists (point) inc 1) | |
199 | (buffer-end arg))) | |
200 | (condition-case err | |
201 | (while (progn (setq pos (point)) | |
202 | (forward-sexp inc) | |
203 | (/= (point) pos))) | |
204 | (scan-error (goto-char (nth (if (> arg 0) 3 2) err)))) | |
205 | (if (= (point) pos) | |
206 | (signal 'scan-error | |
207 | (list "Unbalanced parentheses" (point) (point)))))) | |
208 | (scan-error | |
209 | (let ((syntax nil)) | |
210 | (or | |
211 | ;; If we bumped up against the end of a list, see whether | |
212 | ;; we're inside a string: if so, just go to the beginning | |
213 | ;; or end of that string. | |
214 | (and escape-strings | |
215 | (or syntax (setf syntax (syntax-ppss))) | |
216 | (nth 3 syntax) | |
217 | (goto-char (nth 8 syntax)) | |
218 | (progn (when (> inc 0) | |
219 | (forward-sexp)) | |
220 | t)) | |
221 | ;; If we narrowed to a comment above and failed to escape | |
222 | ;; it, the error might be our fault, not an indication | |
223 | ;; that we're out of syntax. Try again from beginning or | |
224 | ;; end of the comment. | |
225 | (and no-syntax-crossing | |
226 | (or syntax (setf syntax (syntax-ppss))) | |
227 | (nth 4 syntax) | |
228 | (goto-char (nth 8 syntax)) | |
229 | (or (< inc 0) | |
230 | (forward-comment 1)) | |
231 | (setf arg (+ arg inc))) | |
232 | (signal (car err) (cdr err)))))) | |
b73b9811 | 233 | (setq arg (- arg inc))))) |
234 | ||
e50c4203 | 235 | (defun kill-sexp (&optional arg) |
dd60a465 RS |
236 | "Kill the sexp (balanced expression) following point. |
237 | With ARG, kill that many sexps after point. | |
8fc2ac41 AM |
238 | Negative arg -N means kill N sexps before point. |
239 | This command assumes point is not in a string or comment." | |
b73b9811 | 240 | (interactive "p") |
241 | (let ((opoint (point))) | |
e50c4203 | 242 | (forward-sexp (or arg 1)) |
b73b9811 | 243 | (kill-region opoint (point)))) |
244 | ||
e50c4203 | 245 | (defun backward-kill-sexp (&optional arg) |
dd60a465 RS |
246 | "Kill the sexp (balanced expression) preceding point. |
247 | With ARG, kill that many sexps before point. | |
8fc2ac41 AM |
248 | Negative arg -N means kill N sexps after point. |
249 | This command assumes point is not in a string or comment." | |
b73b9811 | 250 | (interactive "p") |
e50c4203 | 251 | (kill-sexp (- (or arg 1)))) |
de6d64b2 EZ |
252 | |
253 | ;; After Zmacs: | |
254 | (defun kill-backward-up-list (&optional arg) | |
255 | "Kill the form containing the current sexp, leaving the sexp itself. | |
256 | A prefix argument ARG causes the relevant number of surrounding | |
8fc2ac41 AM |
257 | forms to be removed. |
258 | This command assumes point is not in a string or comment." | |
de6d64b2 EZ |
259 | (interactive "*p") |
260 | (let ((current-sexp (thing-at-point 'sexp))) | |
261 | (if current-sexp | |
262 | (save-excursion | |
263 | (backward-up-list arg) | |
264 | (kill-sexp) | |
265 | (insert current-sexp)) | |
266 | (error "Not at a sexp")))) | |
b73b9811 | 267 | \f |
ab22ee53 | 268 | (defvar beginning-of-defun-function nil |
c6eeec65 DL |
269 | "If non-nil, function for `beginning-of-defun-raw' to call. |
270 | This is used to find the beginning of the defun instead of using the | |
ab22ee53 RS |
271 | normal recipe (see `beginning-of-defun'). Major modes can define this |
272 | if defining `defun-prompt-regexp' is not sufficient to handle the mode's | |
273 | needs. | |
c6eeec65 | 274 | |
50bfa18a SM |
275 | The function takes the same argument as `beginning-of-defun' and should |
276 | behave similarly, returning non-nil if it found the beginning of a defun. | |
277 | Ideally it should move to a point right before an open-paren which encloses | |
278 | the body of the defun.") | |
c6eeec65 | 279 | |
b73b9811 | 280 | (defun beginning-of-defun (&optional arg) |
281 | "Move backward to the beginning of a defun. | |
6957495d CY |
282 | With ARG, do it that many times. Negative ARG means move forward |
283 | to the ARGth following beginning of defun. | |
284 | ||
285 | If search is successful, return t; point ends up at the beginning | |
286 | of the line where the search succeeded. Otherwise, return nil. | |
287 | ||
288 | When `open-paren-in-column-0-is-defun-start' is non-nil, a defun | |
289 | is assumed to start where there is a char with open-parenthesis | |
290 | syntax at the beginning of a line. If `defun-prompt-regexp' is | |
291 | non-nil, then a string which matches that regexp may also precede | |
292 | the open-parenthesis. If `defun-prompt-regexp' and | |
293 | `open-paren-in-column-0-is-defun-start' are both nil, this | |
294 | function instead finds an open-paren at the outermost level. | |
295 | ||
296 | If the variable `beginning-of-defun-function' is non-nil, its | |
297 | value is called as a function, with argument ARG, to find the | |
298 | defun's beginning. | |
299 | ||
300 | Regardless of the values of `defun-prompt-regexp' and | |
301 | `beginning-of-defun-function', point always moves to the | |
302 | beginning of the line whenever the search is successful." | |
61eee794 | 303 | (interactive "^p") |
90c08845 | 304 | (or (not (eq this-command 'beginning-of-defun)) |
967e1a52 JL |
305 | (eq last-command 'beginning-of-defun) |
306 | (and transient-mark-mode mark-active) | |
307 | (push-mark)) | |
afa995e1 KH |
308 | (and (beginning-of-defun-raw arg) |
309 | (progn (beginning-of-line) t))) | |
310 | ||
311 | (defun beginning-of-defun-raw (&optional arg) | |
312 | "Move point to the character that starts a defun. | |
c6eeec65 DL |
313 | This is identical to function `beginning-of-defun', except that point |
314 | does not move to the beginning of the line when `defun-prompt-regexp' | |
315 | is non-nil. | |
316 | ||
ab22ee53 RS |
317 | If variable `beginning-of-defun-function' is non-nil, its value |
318 | is called as a function to find the defun's beginning." | |
61eee794 | 319 | (interactive "^p") ; change this to "P", maybe, if we ever come to pass ARG |
4df5698c CY |
320 | ; to beginning-of-defun-function. |
321 | (unless arg (setq arg 1)) | |
6cb54822 AM |
322 | (cond |
323 | (beginning-of-defun-function | |
50bfa18a SM |
324 | (condition-case nil |
325 | (funcall beginning-of-defun-function arg) | |
326 | ;; We used to define beginning-of-defun-function as taking no argument | |
327 | ;; but that makes it impossible to implement correct forward motion: | |
328 | ;; we used to use end-of-defun for that, but it's not supposed to do | |
329 | ;; the same thing (it moves to the end of a defun not to the beginning | |
330 | ;; of the next). | |
331 | ;; In case the beginning-of-defun-function uses the old calling | |
332 | ;; convention, fallback on the old implementation. | |
333 | (wrong-number-of-arguments | |
334 | (if (> arg 0) | |
bbcc4d97 | 335 | (dotimes (_ arg) |
50bfa18a | 336 | (funcall beginning-of-defun-function)) |
bbcc4d97 | 337 | (dotimes (_ (- arg)) |
8e911f6f | 338 | (funcall end-of-defun-function)))))) |
6cb54822 AM |
339 | |
340 | ((or defun-prompt-regexp open-paren-in-column-0-is-defun-start) | |
341 | (and (< arg 0) (not (eobp)) (forward-char 1)) | |
c6eeec65 | 342 | (and (re-search-backward (if defun-prompt-regexp |
418d645c GM |
343 | (concat (if open-paren-in-column-0-is-defun-start |
344 | "^\\s(\\|" "") | |
b5ed9def | 345 | "\\(?:" defun-prompt-regexp "\\)\\s(") |
c6eeec65 | 346 | "^\\s(") |
6cb54822 | 347 | nil 'move arg) |
4114bc49 SM |
348 | (progn (goto-char (1- (match-end 0))) |
349 | t))) | |
6cb54822 | 350 | |
4df5698c CY |
351 | ;; If open-paren-in-column-0-is-defun-start and defun-prompt-regexp |
352 | ;; are both nil, column 0 has no significance - so scan forward | |
353 | ;; from BOB to see how nested point is, then carry on from there. | |
354 | ;; | |
355 | ;; It is generally not a good idea to land up here, because the | |
356 | ;; call to scan-lists below can be extremely slow. This is because | |
357 | ;; back_comment in syntax.c may have to scan from bob to find the | |
358 | ;; beginning of each comment. Fixing this is not trivial -- cyd. | |
359 | ||
360 | ((eq arg 0)) | |
6cb54822 | 361 | (t |
4df5698c CY |
362 | (let ((floor (point-min)) |
363 | (ceiling (point-max)) | |
364 | (arg-+ve (> arg 0))) | |
6cb54822 AM |
365 | (save-restriction |
366 | (widen) | |
4df5698c CY |
367 | (let ((ppss (let (syntax-begin-function |
368 | font-lock-beginning-of-syntax-function) | |
369 | (syntax-ppss))) | |
370 | ;; position of least enclosing paren, or nil. | |
371 | encl-pos) | |
372 | ;; Back out of any comment/string, so that encl-pos will always | |
373 | ;; become nil if we're at top-level. | |
374 | (when (nth 8 ppss) | |
375 | (goto-char (nth 8 ppss)) | |
376 | (setq ppss (syntax-ppss))) ; should be fast, due to cache. | |
377 | (setq encl-pos (syntax-ppss-toplevel-pos ppss)) | |
378 | (if encl-pos (goto-char encl-pos)) | |
379 | ||
380 | (and encl-pos arg-+ve (setq arg (1- arg))) | |
381 | (and (not encl-pos) (not arg-+ve) (not (looking-at "\\s(")) | |
382 | (setq arg (1+ arg))) | |
383 | ||
384 | (condition-case nil ; to catch crazy parens. | |
385 | (progn | |
386 | (goto-char (scan-lists (point) (- arg) 0)) | |
387 | (if arg-+ve | |
388 | (if (>= (point) floor) | |
389 | t | |
390 | (goto-char floor) | |
391 | nil) | |
392 | ;; forward to next (, or trigger the c-c | |
393 | (goto-char (1- (scan-lists (point) 1 -1))) | |
394 | (if (<= (point) ceiling) | |
395 | t | |
396 | (goto-char ceiling) | |
397 | nil))) | |
398 | (error | |
399 | (goto-char (if arg-+ve floor ceiling)) | |
400 | nil)))))))) | |
c6eeec65 | 401 | |
7bbab3e0 SM |
402 | (defvar end-of-defun-function |
403 | (lambda () (forward-sexp 1)) | |
61e21607 | 404 | "Function for `end-of-defun' to call. |
6d3e4d22 | 405 | This is used to find the end of the defun at point. |
61e21607 | 406 | It is called with no argument, right after calling `beginning-of-defun-raw'. |
6d3e4d22 SM |
407 | So the function can assume that point is at the beginning of the defun body. |
408 | It should move point to the first position after the defun.") | |
b73b9811 | 409 | |
410 | (defun buffer-end (arg) | |
a64dc1a4 | 411 | "Return the \"far end\" position of the buffer, in direction ARG. |
03deb635 RS |
412 | If ARG is positive, that's the end of the buffer. |
413 | Otherwise, that's the beginning of the buffer." | |
b73b9811 | 414 | (if (> arg 0) (point-max) (point-min))) |
415 | ||
416 | (defun end-of-defun (&optional arg) | |
a64dc1a4 LT |
417 | "Move forward to next end of defun. |
418 | With argument, do it that many times. | |
b73b9811 | 419 | Negative argument -N means move back to Nth preceding end of defun. |
420 | ||
c6eeec65 DL |
421 | An end of a defun occurs right after the close-parenthesis that |
422 | matches the open-parenthesis that starts a defun; see function | |
ab22ee53 RS |
423 | `beginning-of-defun'. |
424 | ||
425 | If variable `end-of-defun-function' is non-nil, its value | |
426 | is called as a function to find the defun's end." | |
61eee794 | 427 | (interactive "^p") |
90c08845 | 428 | (or (not (eq this-command 'end-of-defun)) |
967e1a52 JL |
429 | (eq last-command 'end-of-defun) |
430 | (and transient-mark-mode mark-active) | |
431 | (push-mark)) | |
44b254cc | 432 | (if (or (null arg) (= arg 0)) (setq arg 1)) |
f9f34ece | 433 | (let ((pos (point)) |
7b952d61 SM |
434 | (beg (progn (end-of-line 1) (beginning-of-defun-raw 1) (point))) |
435 | (skip (lambda () | |
436 | ;; When comparing point against pos, we want to consider that if | |
437 | ;; point was right after the end of the function, it's still | |
438 | ;; considered as "in that function". | |
439 | ;; E.g. `eval-defun' from right after the last close-paren. | |
440 | (unless (bolp) | |
441 | (skip-chars-forward " \t") | |
442 | (if (looking-at "\\s<\\|\n") | |
443 | (forward-line 1)))))) | |
f9f34ece | 444 | (funcall end-of-defun-function) |
7b952d61 | 445 | (funcall skip) |
f9f34ece SM |
446 | (cond |
447 | ((> arg 0) | |
448 | ;; Moving forward. | |
449 | (if (> (point) pos) | |
450 | ;; We already moved forward by one because we started from | |
451 | ;; within a function. | |
452 | (setq arg (1- arg)) | |
453 | ;; We started from after the end of the previous function. | |
454 | (goto-char pos)) | |
455 | (unless (zerop arg) | |
456 | (beginning-of-defun-raw (- arg)) | |
457 | (funcall end-of-defun-function))) | |
458 | ((< arg 0) | |
459 | ;; Moving backward. | |
460 | (if (< (point) pos) | |
461 | ;; We already moved backward because we started from between | |
462 | ;; two functions. | |
463 | (setq arg (1+ arg)) | |
464 | ;; We started from inside a function. | |
465 | (goto-char beg)) | |
466 | (unless (zerop arg) | |
467 | (beginning-of-defun-raw (- arg)) | |
7b952d61 | 468 | (setq beg (point)) |
f9f34ece | 469 | (funcall end-of-defun-function)))) |
7b952d61 SM |
470 | (funcall skip) |
471 | (while (and (< arg 0) (>= (point) pos)) | |
472 | ;; We intended to move backward, but this ended up not doing so: | |
473 | ;; Try harder! | |
474 | (goto-char beg) | |
475 | (beginning-of-defun-raw (- arg)) | |
476 | (if (>= (point) beg) | |
477 | (setq arg 0) | |
478 | (setq beg (point)) | |
479 | (funcall end-of-defun-function) | |
480 | (funcall skip))))) | |
b73b9811 | 481 | |
afb62fdd | 482 | (defun mark-defun (&optional allow-extend) |
b73b9811 | 483 | "Put mark at end of this defun, point at beginning. |
cad113ae | 484 | The defun marked is the one that contains point or follows point. |
afb62fdd RS |
485 | |
486 | Interactively, if this command is repeated | |
a64dc1a4 | 487 | or (in Transient Mark mode) if the mark is active, |
afb62fdd RS |
488 | it marks the next defun after the ones already marked." |
489 | (interactive "p") | |
490 | (cond ((and allow-extend | |
491 | (or (and (eq last-command this-command) (mark t)) | |
492 | (and transient-mark-mode mark-active))) | |
be0d25b6 KG |
493 | (set-mark |
494 | (save-excursion | |
495 | (goto-char (mark)) | |
496 | (end-of-defun) | |
497 | (point)))) | |
498 | (t | |
d3d6bc9b RS |
499 | (let ((opoint (point)) |
500 | beg end) | |
501 | (push-mark opoint) | |
502 | ;; Try first in this order for the sake of languages with nested | |
503 | ;; functions where several can end at the same place as with | |
504 | ;; the offside rule, e.g. Python. | |
505 | (beginning-of-defun) | |
506 | (setq beg (point)) | |
507 | (end-of-defun) | |
508 | (setq end (point)) | |
509 | (while (looking-at "^\n") | |
510 | (forward-line 1)) | |
511 | (if (> (point) opoint) | |
512 | (progn | |
513 | ;; We got the right defun. | |
514 | (push-mark beg nil t) | |
515 | (goto-char end) | |
516 | (exchange-point-and-mark)) | |
517 | ;; beginning-of-defun moved back one defun | |
518 | ;; so we got the wrong one. | |
519 | (goto-char opoint) | |
520 | (end-of-defun) | |
521 | (push-mark (point) nil t) | |
522 | (beginning-of-defun)) | |
523 | (re-search-backward "^\n" (- (point) 1) t))))) | |
b73b9811 | 524 | |
bbcc4d97 | 525 | (defun narrow-to-defun (&optional _arg) |
3f7e952d | 526 | "Make text outside current defun invisible. |
c6eeec65 DL |
527 | The defun visible is the one that contains point or follows point. |
528 | Optional ARG is ignored." | |
3f7e952d RS |
529 | (interactive) |
530 | (save-excursion | |
531 | (widen) | |
d3d6bc9b RS |
532 | (let ((opoint (point)) |
533 | beg end) | |
534 | ;; Try first in this order for the sake of languages with nested | |
535 | ;; functions where several can end at the same place as with | |
536 | ;; the offside rule, e.g. Python. | |
050cc68b LB |
537 | |
538 | ;; Finding the start of the function is a bit problematic since | |
539 | ;; `beginning-of-defun' when we are on the first character of | |
540 | ;; the function might go to the previous function. | |
541 | ;; | |
542 | ;; Therefore we first move one character forward and then call | |
543 | ;; `beginning-of-defun'. However now we must check that we did | |
544 | ;; not move into the next function. | |
545 | (let ((here (point))) | |
546 | (unless (eolp) | |
547 | (forward-char)) | |
548 | (beginning-of-defun) | |
549 | (when (< (point) here) | |
550 | (goto-char here) | |
551 | (beginning-of-defun))) | |
d3d6bc9b | 552 | (setq beg (point)) |
750e563f | 553 | (end-of-defun) |
d3d6bc9b RS |
554 | (setq end (point)) |
555 | (while (looking-at "^\n") | |
556 | (forward-line 1)) | |
557 | (unless (> (point) opoint) | |
558 | ;; beginning-of-defun moved back one defun | |
559 | ;; so we got the wrong one. | |
560 | (goto-char opoint) | |
561 | (end-of-defun) | |
562 | (setq end (point)) | |
563 | (beginning-of-defun) | |
564 | (setq beg (point))) | |
565 | (goto-char end) | |
566 | (re-search-backward "^\n" (- (point) 1) t) | |
567 | (narrow-to-region beg end)))) | |
3f7e952d | 568 | |
d97c8198 JL |
569 | (defvar insert-pair-alist |
570 | '((?\( ?\)) (?\[ ?\]) (?\{ ?\}) (?\< ?\>) (?\" ?\") (?\' ?\') (?\` ?\')) | |
571 | "Alist of paired characters inserted by `insert-pair'. | |
572 | Each element looks like (OPEN-CHAR CLOSE-CHAR) or (COMMAND-CHAR | |
573 | OPEN-CHAR CLOSE-CHAR). The characters OPEN-CHAR and CLOSE-CHAR | |
574 | of the pair whose key is equal to the last input character with | |
575 | or without modifiers, are inserted by `insert-pair'.") | |
576 | ||
577 | (defun insert-pair (&optional arg open close) | |
5891bf24 JL |
578 | "Enclose following ARG sexps in a pair of OPEN and CLOSE characters. |
579 | Leave point after the first character. | |
e3ac26cb | 580 | A negative ARG encloses the preceding ARG sexps instead. |
5891bf24 JL |
581 | No argument is equivalent to zero: just insert characters |
582 | and leave point between. | |
d5bfe076 | 583 | If `parens-require-spaces' is non-nil, this command also inserts a space |
5891bf24 | 584 | before and after, depending on the surrounding characters. |
d97c8198 JL |
585 | If region is active, insert enclosing characters at region boundaries. |
586 | ||
587 | If arguments OPEN and CLOSE are nil, the character pair is found | |
588 | from the variable `insert-pair-alist' according to the last input | |
589 | character with or without modifiers. If no character pair is | |
590 | found in the variable `insert-pair-alist', then the last input | |
8fc2ac41 AM |
591 | character is inserted ARG times. |
592 | ||
593 | This command assumes point is not in a string or comment." | |
b73b9811 | 594 | (interactive "P") |
d97c8198 | 595 | (if (not (and open close)) |
61a846fb | 596 | (let ((pair (or (assq last-command-event insert-pair-alist) |
d97c8198 JL |
597 | (assq (event-basic-type last-command-event) |
598 | insert-pair-alist)))) | |
599 | (if pair | |
600 | (if (nth 2 pair) | |
601 | (setq open (nth 1 pair) close (nth 2 pair)) | |
602 | (setq open (nth 0 pair) close (nth 1 pair)))))) | |
603 | (if (and open close) | |
604 | (if (and transient-mark-mode mark-active) | |
605 | (progn | |
606 | (save-excursion (goto-char (region-end)) (insert close)) | |
607 | (save-excursion (goto-char (region-beginning)) (insert open))) | |
608 | (if arg (setq arg (prefix-numeric-value arg)) | |
609 | (setq arg 0)) | |
610 | (cond ((> arg 0) (skip-chars-forward " \t")) | |
611 | ((< arg 0) (forward-sexp arg) (setq arg (- arg)))) | |
612 | (and parens-require-spaces | |
613 | (not (bobp)) | |
614 | (memq (char-syntax (preceding-char)) (list ?w ?_ (char-syntax close))) | |
615 | (insert " ")) | |
616 | (insert open) | |
617 | (save-excursion | |
618 | (or (eq arg 0) (forward-sexp arg)) | |
619 | (insert close) | |
620 | (and parens-require-spaces | |
621 | (not (eobp)) | |
622 | (memq (char-syntax (following-char)) (list ?w ?_ (char-syntax open))) | |
623 | (insert " ")))) | |
624 | (insert-char (event-basic-type last-command-event) | |
625 | (prefix-numeric-value arg)))) | |
626 | ||
627 | (defun insert-parentheses (&optional arg) | |
a64dc1a4 LT |
628 | "Enclose following ARG sexps in parentheses. |
629 | Leave point after open-paren. | |
5891bf24 JL |
630 | A negative ARG encloses the preceding ARG sexps instead. |
631 | No argument is equivalent to zero: just insert `()' and leave point between. | |
632 | If `parens-require-spaces' is non-nil, this command also inserts a space | |
633 | before and after, depending on the surrounding characters. | |
8fc2ac41 AM |
634 | If region is active, insert enclosing characters at region boundaries. |
635 | ||
636 | This command assumes point is not in a string or comment." | |
5891bf24 JL |
637 | (interactive "P") |
638 | (insert-pair arg ?\( ?\))) | |
b73b9811 | 639 | |
d97c8198 JL |
640 | (defun delete-pair () |
641 | "Delete a pair of characters enclosing the sexp that follows point." | |
642 | (interactive) | |
643 | (save-excursion (forward-sexp 1) (delete-char -1)) | |
644 | (delete-char 1)) | |
645 | ||
646 | (defun raise-sexp (&optional arg) | |
647 | "Raise ARG sexps higher up the tree." | |
648 | (interactive "p") | |
649 | (let ((s (if (and transient-mark-mode mark-active) | |
650 | (buffer-substring (region-beginning) (region-end)) | |
651 | (buffer-substring | |
652 | (point) | |
653 | (save-excursion (forward-sexp arg) (point)))))) | |
654 | (backward-up-list 1) | |
655 | (delete-region (point) (save-excursion (forward-sexp 1) (point))) | |
656 | (save-excursion (insert s)))) | |
657 | ||
b73b9811 | 658 | (defun move-past-close-and-reindent () |
659 | "Move past next `)', delete indentation before it, then indent after it." | |
660 | (interactive) | |
661 | (up-list 1) | |
662 | (forward-char -1) | |
663 | (while (save-excursion ; this is my contribution | |
664 | (let ((before-paren (point))) | |
665 | (back-to-indentation) | |
adce3b5f RS |
666 | (and (= (point) before-paren) |
667 | (progn | |
668 | ;; Move to end of previous line. | |
669 | (beginning-of-line) | |
670 | (forward-char -1) | |
671 | ;; Verify it doesn't end within a string or comment. | |
672 | (let ((end (point)) | |
673 | state) | |
674 | (beginning-of-line) | |
675 | ;; Get state at start of line. | |
c6eeec65 | 676 | (setq state (list 0 nil nil |
adce3b5f RS |
677 | (null (calculate-lisp-indent)) |
678 | nil nil nil nil | |
679 | nil)) | |
680 | ;; Parse state across the line to get state at end. | |
681 | (setq state (parse-partial-sexp (point) end nil nil | |
682 | state)) | |
683 | ;; Check not in string or comment. | |
684 | (and (not (elt state 3)) (not (elt state 4)))))))) | |
b73b9811 | 685 | (delete-indentation)) |
686 | (forward-char 1) | |
687 | (newline-and-indent)) | |
c6eeec65 DL |
688 | |
689 | (defun check-parens () ; lame name? | |
690 | "Check for unbalanced parentheses in the current buffer. | |
691 | More accurately, check the narrowed part of the buffer for unbalanced | |
692 | expressions (\"sexps\") in general. This is done according to the | |
693 | current syntax table and will find unbalanced brackets or quotes as | |
7bc10886 | 694 | appropriate. (See Info node `(emacs)Parentheses'.) If imbalance is |
8ad8cfa5 | 695 | found, an error is signaled and point is left at the first unbalanced |
7bc10886 | 696 | character." |
c6eeec65 DL |
697 | (interactive) |
698 | (condition-case data | |
699 | ;; Buffer can't have more than (point-max) sexps. | |
700 | (scan-sexps (point-min) (point-max)) | |
701 | (scan-error (goto-char (nth 2 data)) | |
702 | ;; Could print (nth 1 data), which is either | |
703 | ;; "Containing expression ends prematurely" or | |
704 | ;; "Unbalanced parentheses", but those may not be so | |
705 | ;; accurate/helpful, e.g. quotes may actually be | |
706 | ;; mismatched. | |
dd8791e9 | 707 | (user-error "Unmatched bracket or quote")))) |
b73b9811 | 708 | \f |
61e21607 | 709 | (defun field-complete (table &optional predicate) |
dd8791e9 | 710 | (declare (obsolete completion-in-region "24.4")) |
73ebf88f SM |
711 | (let ((minibuffer-completion-table table) |
712 | (minibuffer-completion-predicate predicate) | |
713 | ;; This made sense for lisp-complete-symbol, but for | |
714 | ;; field-complete, this is out of place. --Stef | |
715 | ;; (completion-annotate-function | |
716 | ;; (unless (eq predicate 'fboundp) | |
717 | ;; (lambda (str) | |
718 | ;; (if (fboundp (intern-soft str)) " <f>")))) | |
719 | ) | |
720 | (call-interactively 'minibuffer-complete))) | |
61e21607 | 721 | |
e50c4203 | 722 | (defun lisp-complete-symbol (&optional predicate) |
2eb9adab RS |
723 | "Perform completion on Lisp symbol preceding point. |
724 | Compare that symbol against the known Lisp symbols. | |
1fa1cb1b RS |
725 | If no characters can be completed, display a list of possible completions. |
726 | Repeating the command at that point scrolls the list. | |
2eb9adab | 727 | |
e50c4203 DL |
728 | When called from a program, optional arg PREDICATE is a predicate |
729 | determining which symbols are considered, e.g. `commandp'. | |
730 | If PREDICATE is nil, the context determines which symbols are | |
731 | considered. If the symbol starts just after an open-parenthesis, only | |
732 | symbols with function definitions are considered. Otherwise, all | |
733 | symbols with function definitions, values or properties are | |
734 | considered." | |
dd8791e9 | 735 | (declare (obsolete completion-at-point "24.4")) |
b73b9811 | 736 | (interactive) |
51ef56c4 SM |
737 | (let* ((data (lisp-completion-at-point predicate)) |
738 | (plist (nthcdr 3 data))) | |
ccaa4765 SM |
739 | (if (null data) |
740 | (minibuffer-message "Nothing to complete") | |
2403c841 SM |
741 | (let ((completion-extra-properties plist)) |
742 | (completion-in-region (nth 0 data) (nth 1 data) (nth 2 data) | |
ccaa4765 | 743 | (plist-get plist :predicate)))))) |
0ca12598 | 744 | |
bbcc4d97 SM |
745 | (defun lisp--local-variables-1 (vars sexp) |
746 | "Return the vars locally bound around the witness, or nil if not found." | |
747 | (let (res) | |
748 | (while | |
749 | (unless | |
750 | (setq res | |
751 | (pcase sexp | |
752 | (`(,(or `let `let*) ,bindings) | |
753 | (let ((vars vars)) | |
754 | (when (eq 'let* (car sexp)) | |
755 | (dolist (binding (cdr (reverse bindings))) | |
756 | (push (or (car-safe binding) binding) vars))) | |
757 | (lisp--local-variables-1 | |
758 | vars (car (cdr-safe (car (last bindings))))))) | |
759 | (`(,(or `let `let*) ,bindings . ,body) | |
760 | (let ((vars vars)) | |
761 | (dolist (binding bindings) | |
762 | (push (or (car-safe binding) binding) vars)) | |
763 | (lisp--local-variables-1 vars (car (last body))))) | |
764 | (`(lambda ,_) (setq sexp nil)) | |
765 | (`(lambda ,args . ,body) | |
766 | (lisp--local-variables-1 | |
767 | (append args vars) (car (last body)))) | |
768 | (`(condition-case ,_ ,e) (lisp--local-variables-1 vars e)) | |
769 | (`(condition-case ,v ,_ . ,catches) | |
770 | (lisp--local-variables-1 | |
771 | (cons v vars) (cdr (car (last catches))))) | |
772 | (`(,_ . ,_) | |
773 | (lisp--local-variables-1 vars (car (last sexp)))) | |
774 | (`lisp--witness--lisp (or vars '(nil))) | |
775 | (_ nil))) | |
776 | (setq sexp (ignore-errors (butlast sexp))))) | |
777 | res)) | |
778 | ||
779 | (defun lisp--local-variables () | |
780 | "Return a list of locally let-bound variables at point." | |
781 | (save-excursion | |
782 | (skip-syntax-backward "w_") | |
783 | (let* ((ppss (syntax-ppss)) | |
784 | (txt (buffer-substring-no-properties (or (car (nth 9 ppss)) (point)) | |
785 | (or (nth 8 ppss) (point)))) | |
786 | (closer ())) | |
787 | (dolist (p (nth 9 ppss)) | |
788 | (push (cdr (syntax-after p)) closer)) | |
789 | (setq closer (apply #'string closer)) | |
b2388336 DG |
790 | (let* ((sexp (condition-case nil |
791 | (car (read-from-string | |
792 | (concat txt "lisp--witness--lisp" closer))) | |
793 | (end-of-file nil))) | |
bbcc4d97 SM |
794 | (macroexpand-advice (lambda (expander form &rest args) |
795 | (condition-case nil | |
796 | (apply expander form args) | |
797 | (error form)))) | |
798 | (sexp | |
799 | (unwind-protect | |
800 | (progn | |
801 | (advice-add 'macroexpand :around macroexpand-advice) | |
802 | (macroexpand-all sexp)) | |
803 | (advice-remove 'macroexpand macroexpand-advice))) | |
804 | (vars (lisp--local-variables-1 nil sexp))) | |
805 | (delq nil | |
806 | (mapcar (lambda (var) | |
807 | (and (symbolp var) | |
808 | (not (string-match (symbol-name var) "\\`[&_]")) | |
809 | ;; Eliminate uninterned vars. | |
810 | (intern-soft var) | |
811 | var)) | |
812 | vars)))))) | |
813 | ||
814 | (defvar lisp--local-variables-completion-table | |
815 | ;; Use `defvar' rather than `defconst' since defconst would purecopy this | |
816 | ;; value, which would doubly fail: it would fail because purecopy can't | |
817 | ;; handle the recursive bytecode object, and it would fail because it would | |
818 | ;; move `lastpos' and `lastvars' to pure space where they'd be immutable! | |
819 | (let ((lastpos nil) (lastvars nil)) | |
820 | (letrec ((hookfun (lambda () | |
821 | (setq lastpos nil) | |
822 | (remove-hook 'post-command-hook hookfun)))) | |
823 | (completion-table-dynamic | |
824 | (lambda (_string) | |
825 | (save-excursion | |
826 | (skip-syntax-backward "_w") | |
827 | (let ((newpos (cons (point) (current-buffer)))) | |
828 | (unless (equal lastpos newpos) | |
829 | (add-hook 'post-command-hook hookfun) | |
830 | (setq lastpos newpos) | |
831 | (setq lastvars | |
832 | (mapcar #'symbol-name (lisp--local-variables)))))) | |
833 | lastvars))))) | |
834 | ||
2da4c3ab SM |
835 | ;; FIXME: Support for Company brings in features which straddle eldoc. |
836 | ;; We should consolidate this, so that major modes can provide all that | |
837 | ;; data all at once: | |
838 | ;; - a function to extract "the reference at point" (may be more complex | |
839 | ;; than a mere string, to distinguish various namespaces). | |
840 | ;; - a function to jump to such a reference. | |
841 | ;; - a function to show the signature/interface of such a reference. | |
842 | ;; - a function to build a help-buffer about that reference. | |
843 | ;; FIXME: Those functions should also be used by the normal completion code in | |
844 | ;; the *Completions* buffer. | |
845 | ||
846 | (defun lisp--company-doc-buffer (str) | |
847 | (let ((symbol (intern-soft str))) | |
848 | ;; FIXME: we really don't want to "display-buffer and then undo it". | |
849 | (save-window-excursion | |
850 | ;; Make sure we don't display it in another frame, otherwise | |
851 | ;; save-window-excursion won't be able to undo it. | |
852 | (let ((display-buffer-overriding-action | |
853 | '(nil . ((inhibit-switch-frame . t))))) | |
854 | (ignore-errors | |
855 | (cond | |
856 | ((fboundp symbol) (describe-function symbol)) | |
857 | ((boundp symbol) (describe-variable symbol)) | |
858 | ((featurep symbol) (describe-package symbol)) | |
859 | ((facep symbol) (describe-face symbol)) | |
860 | (t (signal 'user-error nil))) | |
861 | (help-buffer)))))) | |
862 | ||
863 | (defun lisp--company-doc-string (str) | |
864 | (let* ((symbol (intern-soft str)) | |
865 | (doc (if (fboundp symbol) | |
866 | (documentation symbol t) | |
867 | (documentation-property symbol 'variable-documentation t)))) | |
868 | (and (stringp doc) | |
869 | (string-match ".*$" doc) | |
870 | (match-string 0 doc)))) | |
871 | ||
872 | (declare-function find-library-name "find-func" (library)) | |
873 | ||
874 | (defun lisp--company-location (str) | |
875 | (let ((sym (intern-soft str))) | |
876 | (cond | |
877 | ((fboundp sym) (find-definition-noselect sym nil)) | |
878 | ((boundp sym) (find-definition-noselect sym 'defvar)) | |
879 | ((featurep sym) | |
880 | (require 'find-func) | |
881 | (cons (find-file-noselect (find-library-name | |
882 | (symbol-name sym))) | |
883 | 0)) | |
884 | ((facep sym) (find-definition-noselect sym 'defface))))) | |
885 | ||
bbcc4d97 | 886 | (defun lisp-completion-at-point (&optional _predicate) |
0ca12598 | 887 | "Function used for `completion-at-point-functions' in `emacs-lisp-mode'." |
4c528197 | 888 | (with-syntax-table emacs-lisp-mode-syntax-table |
4c14013d JB |
889 | (let* ((pos (point)) |
890 | (beg (condition-case nil | |
891 | (save-excursion | |
892 | (backward-sexp 1) | |
893 | (skip-syntax-forward "'") | |
894 | (point)) | |
895 | (scan-error pos))) | |
4c14013d JB |
896 | (end |
897 | (unless (or (eq beg (point-max)) | |
29127376 SM |
898 | (member (char-syntax (char-after beg)) |
899 | '(?\s ?\" ?\( ?\)))) | |
4c14013d JB |
900 | (condition-case nil |
901 | (save-excursion | |
902 | (goto-char beg) | |
903 | (forward-sexp 1) | |
904 | (when (>= (point) pos) | |
905 | (point))) | |
dd8791e9 SM |
906 | (scan-error pos)))) |
907 | (funpos (eq (char-before beg) ?\()) ;t if in function position. | |
908 | (table-etc | |
909 | (if (not funpos) | |
910 | ;; FIXME: We could look at the first element of the list and | |
911 | ;; use it to provide a more specific completion table in some | |
912 | ;; cases. E.g. filter out keywords that are not understood by | |
913 | ;; the macro/function being called. | |
a333e4d2 | 914 | (list nil (completion-table-merge |
bbcc4d97 | 915 | lisp--local-variables-completion-table |
29127376 SM |
916 | (apply-partially #'completion-table-with-predicate |
917 | obarray | |
918 | ;; Don't include all symbols | |
919 | ;; (bug#16646). | |
920 | (lambda (sym) | |
921 | (or (boundp sym) | |
922 | (fboundp sym) | |
923 | (symbol-plist sym))) | |
924 | 'strict)) | |
dd8791e9 | 925 | :annotation-function |
2da4c3ab SM |
926 | (lambda (str) (if (fboundp (intern-soft str)) " <f>")) |
927 | :company-doc-buffer #'lisp--company-doc-buffer | |
928 | :company-docsig #'lisp--company-doc-string | |
929 | :company-location #'lisp--company-location) | |
dd8791e9 SM |
930 | ;; Looks like a funcall position. Let's double check. |
931 | (save-excursion | |
932 | (goto-char (1- beg)) | |
933 | (let ((parent | |
934 | (condition-case nil | |
935 | (progn (up-list -1) (forward-char 1) | |
936 | (let ((c (char-after))) | |
937 | (if (eq c ?\() ?\( | |
938 | (if (memq (char-syntax c) '(?w ?_)) | |
939 | (read (current-buffer)))))) | |
940 | (error nil)))) | |
941 | (pcase parent | |
942 | ;; FIXME: Rather than hardcode special cases here, | |
943 | ;; we should use something like a symbol-property. | |
944 | (`declare | |
945 | (list t (mapcar (lambda (x) (symbol-name (car x))) | |
2da4c3ab SM |
946 | (delete-dups |
947 | ;; FIXME: We should include some | |
948 | ;; docstring with each entry. | |
949 | (append | |
950 | macro-declarations-alist | |
951 | defun-declarations-alist))))) | |
c9023370 SM |
952 | ((and (or `condition-case `condition-case-unless-debug) |
953 | (guard (save-excursion | |
954 | (ignore-errors | |
955 | (forward-sexp 2) | |
956 | (< (point) beg))))) | |
dd8791e9 SM |
957 | (list t obarray |
958 | :predicate (lambda (sym) (get sym 'error-conditions)))) | |
e333fb10 SM |
959 | ((and ?\( |
960 | (guard (save-excursion | |
961 | (goto-char (1- beg)) | |
962 | (up-list -1) | |
963 | (forward-symbol -1) | |
964 | (looking-at "\\_<let\\*?\\_>")))) | |
965 | (list t obarray | |
966 | :predicate #'boundp | |
967 | :company-doc-buffer #'lisp--company-doc-buffer | |
968 | :company-docsig #'lisp--company-doc-string | |
969 | :company-location #'lisp--company-location)) | |
2da4c3ab SM |
970 | (_ (list nil obarray |
971 | :predicate #'fboundp | |
972 | :company-doc-buffer #'lisp--company-doc-buffer | |
973 | :company-docsig #'lisp--company-doc-string | |
974 | :company-location #'lisp--company-location | |
975 | )))))))) | |
4c14013d | 976 | (when end |
dd8791e9 SM |
977 | (let ((tail (if (null (car table-etc)) |
978 | (cdr table-etc) | |
979 | (cons | |
df76dacb | 980 | (if (memq (char-syntax (or (char-after end) ?\s)) |
dd8791e9 SM |
981 | '(?\s ?>)) |
982 | (cadr table-etc) | |
983 | (apply-partially 'completion-table-with-terminator | |
984 | " " (cadr table-etc))) | |
985 | (cddr table-etc))))) | |
986 | `(,beg ,end ,@tail)))))) | |
6594deb0 ER |
987 | |
988 | ;;; lisp.el ends here |