[lice @ dont load the .asd file]
[lice.git] / lisp-mode.lisp
blob41856ddf0d8559bc1f06b26566f17e94b3582b18
1 ;;; This is a cheap, pigeon lisp mode. One Day, it'll be replaced with
2 ;;; something amazing.
4 (in-package "LICE")
6 (defcustom *defun-prompt-regexp* nil
7 "*If non-nil, a regexp to ignore before a defun.
8 This is only necessary if the opening paren or brace is not in column 0.
9 See function `beginning-of-defun'."
10 :type '(choice (const nil)
11 regexp)
12 :group 'lisp)
14 (defvar *emacs-lisp-mode-syntax-table*
15 (let ((table (make-syntax-table)))
16 (loop for i from (char-code #\0) to (char-code #\9) do
17 (modify-syntax-entry (code-char i) :symbol-constituent :table table))
18 (loop for i from (char-code #\A) to (char-code #\Z) do
19 (modify-syntax-entry (code-char i) :symbol-constituent :table table))
21 (loop for i from (char-code #\a) to (char-code #\z) do
22 (modify-syntax-entry (code-char i) :symbol-constituent :table table))
24 (loop for c in '(#\{ #\| #\} #\~ #| 127 |#) do
25 (modify-syntax-entry c :symbol-constituent :table table))
27 (modify-syntax-entry #\Space :whitespace :table table)
28 (modify-syntax-entry #\Tab :whitespace :table table)
29 ;; XXX what is \f ? (modify-syntax-entry ?\f :whitespace :table table)
30 (modify-syntax-entry #\Newline :end-comment :table table)
31 ;; This is probably obsolete since nowadays such features use overlays.
32 ;; ;; Give CR the same syntax as newline, for selective-display.
33 ;; (modify-syntax-entry ?\^m "> " :table table)
34 (modify-syntax-entry #\; :comment :table table)
35 (modify-syntax-entry #\` :quote :table table)
36 (modify-syntax-entry #\' :quote :table table)
37 (modify-syntax-entry #\, :quote :table table)
38 (modify-syntax-entry #\@ :quote :table table)
39 ;; Used to be singlequote; changed for flonums.
40 (modify-syntax-entry #\. :symbol-constituent :table table)
41 (modify-syntax-entry #\# :quote :table table)
42 (modify-syntax-entry #\" :string :table table)
43 (modify-syntax-entry #\\ :escape :table table)
44 (modify-syntax-entry #\( :open :extra #\) :table table)
45 (modify-syntax-entry #\) :close :extra #\( :table table)
46 (modify-syntax-entry #\[ :open :extra #\] :table table)
47 (modify-syntax-entry #\] :close :extra #\[ :table table)
48 table))
50 (defvar *lisp-mode-syntax-table*
51 (let ((table (copy-syntax-table *emacs-lisp-mode-syntax-table*)))
52 (modify-syntax-entry #\[ :symbol-constituent :table table)
53 (modify-syntax-entry #\] :symbol-constituent :table table)
54 (modify-syntax-entry #\# :quote :flags '(:comment-start-first :comment-end-second :comment-style) :table table)
55 (modify-syntax-entry #\| :string :flags '(:comment-start-second :comment-end-first :comment-style :comment-nested) :table table)
56 table))
58 (defvar *lisp-interaction-mode*
59 (make-instance 'major-mode
60 :name "Lisp Interaction"
61 :map (let ((m (make-sparse-keymap)))
62 (define-key m (kbd "C-j") 'eval-print-last-sexp)
63 (define-key m (make-key :char #\Tab) 'lisp-indent-line)
64 (define-key m (kbd "C-i") 'lisp-indent-line)
65 (define-key m (kbd "C-M-q") 'indent-sexp)
66 (define-key m (kbd "C-M-x") 'eval-defun)
68 :syntax-table *lisp-mode-syntax-table*)
69 "Lisp mode.")
71 (defvar *lisp-mode*
72 (make-instance 'major-mode
73 :name "Lisp"
74 :map (let ((m (make-sparse-keymap)))
75 (define-key m (make-key :char #\Tab) 'lisp-indent-line)
76 (define-key m (kbd "C-i") 'lisp-indent-line)
77 (define-key m (kbd "C-M-q") 'indent-sexp)
78 (define-key m (kbd "C-M-x") 'eval-defun)
80 :syntax-table *lisp-mode-syntax-table*))
82 (defcommand lisp-mode ()
83 "Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp.
84 Commands:
85 Delete converts tabs to spaces as it moves back.
86 Blank lines separate paragraphs. Semicolons start comments.
87 \\{lisp-mode-map}
88 Note that `run-lisp' may be used either to start an inferior Lisp job
89 or to switch back to an existing one.
91 Entry to this mode calls the value of `lisp-mode-hook'
92 if that value is non-nil."
93 (set-major-mode '*lisp-mode*))
95 (defun buffer-end (arg)
96 "Return the \"far end\" position of the buffer, in direction ARG.
97 If ARG is positive, that's the end of the buffer.
98 Otherwise, that's the beginning of the buffer."
99 (if (> arg 0) (point-max) (point-min)))
101 (defvar *end-of-defun-function* nil
102 "If non-nil, function for function `end-of-defun' to call.
103 This is used to find the end of the defun instead of using the normal
104 recipe (see `end-of-defun'). Major modes can define this if the
105 normal method is not appropriate.")
107 (defcommand end-of-defun ((&optional arg)
108 :prefix)
109 "Move forward to next end of defun.
110 With argument, do it that many times.
111 Negative argument -N means move back to Nth preceding end of defun.
113 An end of a defun occurs right after the close-parenthesis that
114 matches the open-parenthesis that starts a defun; see function
115 `beginning-of-defun'.
117 If variable `*end-of-defun-function*' is non-nil, its value
118 is called as a function to find the defun's end."
119 (or (not (eq *this-command* 'end-of-defun))
120 (eq *last-command* 'end-of-defun)
121 ;;XXX (and transient-mark-mode mark-active)
122 (push-mark))
123 (if (or (null arg) (= arg 0)) (setq arg 1))
124 (if *end-of-defun-function*
125 (if (> arg 0)
126 (dotimes (i arg)
127 (funcall *end-of-defun-function*))
128 ;; Better not call beginning-of-defun-function
129 ;; directly, in case it's not defined.
130 (beginning-of-defun (- arg)))
131 (let ((first t))
132 (while (and (> arg 0) (< (point) (point-max)))
133 (let ((pos (point)))
134 (while (progn
135 (if (and first
136 (progn
137 (end-of-line 1)
138 (beginning-of-defun-raw 1)))
140 (progn
141 (or (bobp) (forward-char -1))
142 (beginning-of-defun-raw -1)))
143 (setq first nil)
144 (forward-list 1)
145 (skip-whitespace-forward)
146 (if (looking-at ";|\\n") ; XXX: used to be comment starter \\s<
147 (forward-line 1))
148 (<= (point) pos))
149 (message "point: ~d ~d" (point) pos)))
150 (setq arg (1- arg)))
151 (while (< arg 0)
152 (let ((pos (point)))
153 (beginning-of-defun-raw 1)
154 (forward-sexp 1)
155 (forward-line 1)
156 (if (>= (point) pos)
157 (if (beginning-of-defun-raw 2)
158 (progn
159 (forward-list 1)
160 (skip-whitespace-forward)
161 (if (looking-at ";|\\n") ; XXX: used to be comment starter \\s<
162 (forward-line 1)))
163 (goto-char (point-min)))))
164 (setq arg (1+ arg))))))
166 (defvar *forward-sexp-function* nil
167 "If non-nil, `forward-sexp' delegates to this function.
168 Should take the same arguments and behave similarly to `forward-sexp'.")
170 (defcommand forward-sexp ((&optional (arg 1))
171 :prefix)
172 "Move forward across one balanced expression (sexp).
173 With ARG, do it that many times. Negative arg -N means
174 move backward across N balanced expressions."
175 (if *forward-sexp-function*
176 (funcall *forward-sexp-function* arg)
177 (progn
178 (goto-char (or (scan-sexps (point) arg) (buffer-end arg)))
179 (if (< arg 0) (backward-prefix-chars)))))
181 (defcommand backward-sexp ((&optional (arg 1))
182 :prefix)
183 "Move backward across one balanced expression (sexp).
184 With ARG, do it that many times. Negative arg -N means
185 move forward across N balanced expressions."
186 (forward-sexp (- arg)))
188 (defcommand forward-list ((&optional arg)
189 :prefix)
190 "Move forward across one balanced group of parentheses.
191 With ARG, do it that many times.
192 Negative arg -N means move backward across N groups of parentheses."
193 (or arg (setq arg 1))
194 (goto-char (or (scan-lists (point) arg 0) (buffer-end arg))))
196 (defcommand backward-list ((&optional arg)
197 :prefix)
198 "Move backward across one balanced group of parentheses.
199 With ARG, do it that many times.
200 Negative arg -N means move forward across N groups of parentheses."
201 (or arg (setq arg 1))
202 (forward-list (- arg)))
204 (defcommand eval-last-sexp ()
205 (let ((start (point))
206 end)
207 ;; some nice'n'gross point handling
208 (backward-sexp)
209 (setf end (point))
210 (goto-char start)
211 (handler-case (eval-echo (buffer-substring-no-properties start end))
212 (error (c) (message "Eval error: ~a" c)))))
214 (defcommand eval-print-last-sexp ()
215 (let ((start (point))
216 end)
217 ;; some nice'n'gross point handling
218 (backward-sexp)
219 (setf end (point))
220 (goto-char start)
221 (handler-case (eval-print (buffer-substring-no-properties start end))
222 (error (c) (message "Eval error: ~a" c)))))
224 (defcommand lisp-interaction-mode ()
225 (set-major-mode '*lisp-interaction-mode*))
227 (defvar *lisp-indent-offset* nil
228 "If non-nil, indent second line of expressions that many more columns.")
230 (defvar *lisp-indent-function* 'common-lisp-indent-function)
232 (defcommand lisp-indent-line ((&optional whole-exp)
233 :raw-prefix)
234 "Indent current line as Lisp code.
235 With argument, indent any additional lines of the same expression
236 rigidly along with this one."
237 (let ((indent (calculate-lisp-indent)) shift-amt end
238 (pos (- (point-max) (point)))
239 (beg (progn (beginning-of-line) (point))))
240 (skip-whitespace-forward)
241 (if (or (null indent) (looking-at ";;;")) ; XXX: used to be comment starter \\s<
242 ;; Don't alter indentation of a ;;; comment line
243 ;; or a line that starts in a string.
244 (goto-char (- (point-max) pos))
245 (progn
246 (if (and (looking-at ";") (not (looking-at ";;"))) ; XXX: used to be comment starter \\s<
247 ;; Single-semicolon comment lines should be indented
248 ;; as comment lines, not as code.
249 (progn (indent-for-comment) (forward-char -1))
250 (progn
251 (if (listp indent) (setq indent (car indent)))
252 (setq shift-amt (- indent (current-column)))
253 (if (zerop shift-amt)
255 (progn
256 (delete-region beg (point))
257 (indent-to indent)))))
258 ;; If initial point was within line's indentation,
259 ;; position after the indentation. Else stay at same point in text.
260 (if (> (- (point-max) pos) (point))
261 (goto-char (- (point-max) pos)))
262 ;; If desired, shift remaining lines of expression the same amount.
263 (and whole-exp (not (zerop shift-amt))
264 (save-excursion
265 (goto-char beg)
266 (message "this111")
267 (forward-sexp 1)
268 (message "done 11")
269 (setq end (point))
270 (goto-char beg)
271 (forward-line 1)
272 (setq beg (point))
273 (> end beg))
274 (indent-code-rigidly beg end shift-amt))))))
276 (defvar *calculate-lisp-indent-last-sexp*)
278 (defun calculate-lisp-indent (&optional parse-start)
279 "Return appropriate indentation for current line as Lisp code.
280 In usual case returns an integer: the column to indent to.
281 If the value is nil, that means don't change the indentation
282 because the line starts inside a string.
284 The value can also be a list of the form (COLUMN CONTAINING-SEXP-START).
285 This means that following lines at the same level of indentation
286 should not necessarily be indented the same as this line.
287 Then COLUMN is the column to indent to, and CONTAINING-SEXP-START
288 is the buffer position of the start of the containing expression."
289 (save-excursion
290 (beginning-of-line)
291 (let ((indent-point (point))
292 state paren-depth
293 ;; setting this to a number inhibits calling hook
294 (desired-indent nil)
295 (retry t)
296 *calculate-lisp-indent-last-sexp* containing-sexp)
297 (if parse-start
298 (goto-char parse-start)
299 (beginning-of-defun))
300 ;; Find outermost containing sexp
301 (while (< (point) indent-point)
302 (message "flitz ~d" indent-point (point))
303 (setq state (parse-partial-sexp (point) indent-point :target-depth 0)))
304 ;; Find innermost containing sexp
305 (while (and retry
306 state
307 (> (setq paren-depth (parse-state-depth state)) 0))
308 (setq retry nil)
309 (setq *calculate-lisp-indent-last-sexp* (parse-state-this-level-start state))
310 (message "gaah ~d" *calculate-lisp-indent-last-sexp*)
311 (setq containing-sexp (parse-state-prev-level-start state))
312 ;; Position following last unclosed open.
313 (goto-char (1+ containing-sexp))
314 ;; Is there a complete sexp since then?
315 (if (and *calculate-lisp-indent-last-sexp*
316 (> *calculate-lisp-indent-last-sexp* (point)))
317 ;; Yes, but is there a containing sexp after that?
318 (let ((peek (parse-partial-sexp *calculate-lisp-indent-last-sexp*
319 indent-point :target-depth 0)))
320 (if (setq retry (parse-state-prev-level-start peek)) (setq state peek)))))
321 (message "retry ~a" retry)
322 (if retry
324 ;; Innermost containing sexp found
325 (progn
326 (goto-char (1+ containing-sexp))
327 (if (not *calculate-lisp-indent-last-sexp*)
328 ;; indent-point immediately follows open paren.
329 ;; Don't call hook.
330 (setq desired-indent (current-column))
331 (progn
332 ;; Find the start of first element of containing sexp.
333 (parse-partial-sexp (point) *calculate-lisp-indent-last-sexp* :target-depth 0 :stop-before t)
334 (cond ((looking-at "\\(") ; XXX used to be open \\s(
335 ;; First element of containing sexp is a list.
336 ;; Indent under that list.
338 ((> (save-excursion (forward-line 1) (point))
339 *calculate-lisp-indent-last-sexp*)
341 ;; This is the first line to start within the containing sexp.
342 ;; It's almost certainly a function call.
343 (if (= (point) *calculate-lisp-indent-last-sexp*)
344 ;; Containing sexp has nothing before this line
345 ;; except the first element. Indent under that element.
347 ;; Skip the first element, find start of second (the first
348 ;; argument of the function call) and indent under.
349 (progn (forward-sexp 1)
350 (parse-partial-sexp (point)
351 *calculate-lisp-indent-last-sexp*
352 :target-depth 0 :stop-before t)))
353 (backward-prefix-chars))
355 ;; Indent beneath first sexp on same line as
356 ;; `*calculate-lisp-indent-last-sexp*'. Again, it's
357 ;; almost certainly a function call.
358 (goto-char *calculate-lisp-indent-last-sexp*)
359 (beginning-of-line)
360 (parse-partial-sexp (point) *calculate-lisp-indent-last-sexp*
361 :target-depth 0 :stop-before t)
362 (backward-prefix-chars)))))))
363 ;; Point is at the point to indent under unless we are inside a string.
364 ;; Call indentation hook except when overridden by *lisp-indent-offset*
365 ;; or if the desired indentation has already been computed.
366 (let ((normal-indent (current-column)))
367 (cond ((parse-state-in-string state)
368 ;; Inside a string, don't change indentation.
369 nil)
370 ((and (integerp *lisp-indent-offset*) containing-sexp)
371 ;; Indent by constant offset
372 (goto-char containing-sexp)
373 (+ (current-column) *lisp-indent-offset*))
374 (desired-indent)
375 ((and (boundp '*lisp-indent-function*)
376 *lisp-indent-function*
377 (not retry))
378 (or (funcall *lisp-indent-function* indent-point state)
379 normal-indent))
381 normal-indent))))))
383 (defvar *beginning-of-defun-function* nil
384 "If non-nil, function for `beginning-of-defun-raw' to call.
385 This is used to find the beginning of the defun instead of using the
386 normal recipe (see `beginning-of-defun'). Major modes can define this
387 if defining `*defun-prompt-regexp*' is not sufficient to handle the mode's
388 needs.
390 The function (of no args) should go to the line on which the current
391 defun starts, and return non-nil, or should return nil if it can't
392 find the beginning.")
394 (defcommand beginning-of-defun-raw ((&optional (arg 1))
395 :prefix)
396 "Move point to the character that starts a defun.
397 This is identical to function `beginning-of-defun', except that point
398 does not move to the beginning of the line when `*defun-prompt-regexp*'
399 is non-nil.
401 If variable `*beginning-of-defun-function*' is non-nil, its value
402 is called as a function to find the defun's beginning."
403 (if *beginning-of-defun-function*
404 (if (> arg 0)
405 (dotimes (i arg)
406 (funcall *beginning-of-defun-function*))
407 ;; Better not call *end-of-defun-function* directly, in case
408 ;; it's not defined.
409 (end-of-defun (- arg)))
410 (progn
411 (when (and (< arg 0)
412 (not (eobp)))
413 (forward-char 1))
414 (with-match-data
415 (and (if *defun-prompt-regexp*
416 (re-search-backward (concat (if *open-paren-in-column-0-is-defun-start*
417 "^\\(|" "")
418 "(?:" *defun-prompt-regexp* ")\\(")
419 :error 'move :count (or arg 1))
420 (search-backward (format nil "~%(") ;; FIXME: doesn't match beginning of buffer
421 :error 'move :count (or arg 1))) ;; used to be ^\\(
422 (progn (goto-char (1- (match-end 0))) t))))))
424 (defcommand beginning-of-defun ((&optional (arg 1))
425 :prefix)
426 "Move backward to the beginning of a defun.
427 With ARG, do it that many times. Negative arg -N
428 means move forward to Nth following beginning of defun.
429 Returns t unless search stops due to beginning or end of buffer.
431 Normally a defun starts when there is a char with open-parenthesis
432 syntax at the beginning of a line. If `*defun-prompt-regexp*' is
433 non-nil, then a string which matches that regexp may precede the
434 open-parenthesis, and point ends up at the beginning of the line.
436 If variable `*beginning-of-defun-function*' is non-nil, its value
437 is called as a function to find the defun's beginning."
438 (or (not (eq *this-command* 'beginning-of-defun))
439 (eq *last-command* 'beginning-of-defun)
440 ;;XXX (and transient-mark-mode mark-active)
441 (push-mark))
442 (and (beginning-of-defun-raw arg)
443 (progn (beginning-of-line) t)))
445 (defcommand indent-code-rigidly ((start end arg &optional nochange-regexp)
446 :region-beginning :region-end :prefix)
447 "Indent all lines of code, starting in the region, sideways by ARG columns.
448 Does not affect lines starting inside comments or strings, assuming that
449 the start of the region is not inside them.
451 Called from a program, takes args START, END, COLUMNS and NOCHANGE-REGEXP.
452 The last is a regexp which, if matched at the beginning of a line,
453 means don't indent that line."
454 (let (state)
455 (save-excursion
456 (goto-char end)
457 (setq end (point-marker))
458 (goto-char start)
459 (or (bolp)
460 (setq state (parse-partial-sexp (point)
461 (progn
462 (forward-line 1) (point))
463 :old-state state)))
464 (while (< (point) end)
465 (or (car (nthcdr 3 state))
466 (and nochange-regexp
467 (looking-at nochange-regexp))
468 ;; If line does not start in string, indent it
469 (let ((indent (current-indentation)))
470 (delete-region (point) (progn (skip-whitespace-forward) (point)))
471 (or (eolp)
472 (indent-to (max 0 (+ indent arg)) 0))))
473 (setq state (parse-partial-sexp (point)
474 (progn
475 (forward-line 1) (point))
476 :old-state state))))))
479 (defcommand indent-sexp ((&optional endpos))
480 "Indent each line of the list starting just after point.
481 If optional arg ENDPOS is given, indent each line, stopping when
482 ENDPOS is encountered."
483 (let ((indent-stack (list nil))
484 (next-depth 0)
485 ;; If ENDPOS is non-nil, use nil as STARTING-POINT
486 ;; so that calculate-lisp-indent will find the beginning of
487 ;; the defun we are in.
488 ;; If ENDPOS is nil, it is safe not to scan before point
489 ;; since every line we indent is more deeply nested than point is.
490 (starting-point (if endpos nil (point)))
491 (last-point (point))
492 last-depth bol outer-loop-done inner-loop-done state this-indent)
493 (or endpos
494 ;; Get error now if we don't have a complete sexp after point.
495 (save-excursion (forward-sexp 1)))
496 (save-excursion
497 (setq outer-loop-done nil)
498 (while (if endpos (< (point) (ensure-number endpos))
499 (not outer-loop-done))
500 (setq last-depth next-depth
501 inner-loop-done nil)
502 ;; Parse this line so we can learn the state
503 ;; to indent the next line.
504 ;; This inner loop goes through only once
505 ;; unless a line ends inside a string.
506 (while (and (not inner-loop-done)
507 (not (setq outer-loop-done (eobp))))
508 (setq state (parse-partial-sexp (point) (progn (end-of-line) (point))
509 :old-state state))
510 (setq next-depth (parse-state-depth state))
511 ;; If the line contains a comment other than the sort
512 ;; that is indented like code,
513 ;; indent it now with indent-for-comment.
514 ;; Comments indented like code are right already.
515 ;; In any case clear the in-comment flag in the state
516 ;; because parse-partial-sexp never sees the newlines.
517 (if (parse-state-in-comment state) ;;(car (nthcdr 4 state))
518 (progn (indent-for-comment)
519 (end-of-line)
520 (setf (parse-state-in-comment state) nil))) ;;(setcar (nthcdr 4 state) nil)))
521 ;; If this line ends inside a string,
522 ;; go straight to next line, remaining within the inner loop,
523 ;; and turn off the \-flag.
524 (if (parse-state-in-string state) ;;(car (nthcdr 3 state))
525 (progn
526 (forward-line 1)
527 (setf (parse-state-in-string state) nil));;(setf (car (nthcdr 5 state)) nil))
528 (setq inner-loop-done t)))
529 (and endpos
530 (<= next-depth 0)
531 (progn
532 (setq indent-stack (nconc indent-stack
533 (make-list (- next-depth) :initial-element nil))
534 last-depth (- last-depth next-depth)
535 next-depth 0)))
536 (or outer-loop-done endpos
537 (setq outer-loop-done (<= next-depth 0)))
538 (if outer-loop-done
539 (forward-line 1)
540 (progn
541 (while (> last-depth next-depth)
542 (setq indent-stack (cdr indent-stack)
543 last-depth (1- last-depth)))
544 (while (< last-depth next-depth)
545 (setq indent-stack (cons nil indent-stack)
546 last-depth (1+ last-depth)))
547 ;; Now go to the next line and indent it according
548 ;; to what we learned from parsing the previous one.
549 (forward-line 1)
550 (setq bol (point))
551 (skip-whitespace-forward)
552 ;; But not if the line is blank, or just a comment
553 ;; (except for double-semi comments; indent them as usual).
554 (if (or (eobp) (looking-at "\\w|\\n")) ;; FIXME: used to be "\\s<|\\n"
556 (progn
557 (if (and (car indent-stack)
558 (>= (car indent-stack) 0))
559 (setq this-indent (car indent-stack))
560 (let ((val (calculate-lisp-indent
561 (if (car indent-stack) (- (car indent-stack))
562 starting-point))))
563 (if (null val)
564 (setq this-indent val)
565 (if (integerp val)
566 (setf (car indent-stack)
567 (setq this-indent val))
568 (progn
569 (setf (car indent-stack) (- (car (cdr val))))
570 (setq this-indent (car val)))))))
571 (if (and this-indent (/= (current-column) this-indent))
572 (progn (delete-region bol (point))
573 (indent-to this-indent)))))))
574 (or outer-loop-done
575 (setq outer-loop-done (= (point) last-point))
576 (setq last-point (point)))))))
578 (defun lisp-indent-region (start end)
579 "Indent every line whose first char is between START and END inclusive."
580 (save-excursion
581 (let ((endmark (copy-marker end)))
582 (goto-char start)
583 (and (bolp) (not (eolp))
584 (lisp-indent-line))
585 (indent-sexp endmark)
586 (set-marker endmark nil))))
588 (defun eval-defun-1 (form)
589 "Treat some expressions specially.
590 Reset the `defvar' and `defcustom' variables to the initial value.
591 Reinitialize the face according to the `defface' specification."
592 ;; The code in edebug-defun should be consistent with this, but not
593 ;; the same, since this gets a macroexpended form.
594 (cond ((not (listp form))
595 form)
596 ((and (eq (car form) 'defvar)
597 (cdr-safe (cdr-safe form))
598 (boundp (cadr form)))
599 ;; Force variable to be re-set.
600 `(progn (defvar ,(nth 1 form) nil ,@(nthcdr 3 form))
601 (setf ,(nth 1 form) ,(nth 2 form)))) ;; used to be setq-default
602 ;; `defcustom' is now macroexpanded to
603 ;; `custom-declare-variable' with a quoted value arg.
604 ((and (eq (car form) 'custom-declare-variable)
605 (boundp (eval (nth 1 form)))) ;; used to be default-boundp
606 ;; Force variable to be bound.
607 ;; XXX: we can't handle defcustom
608 ;;(set-default (eval (nth 1 form)) (eval (nth 1 (nth 2 form))))
609 form)
610 ;; `defface' is macroexpanded to `custom-declare-face'.
611 ((eq (car form) 'custom-declare-face)
612 ;; Reset the face.
613 ;; XXX: what do we do with this?
614 ;; (setq face-new-frame-defaults
615 ;; (assq-delete-all (eval (nth 1 form)) face-new-frame-defaults))
616 ;; (put (eval (nth 1 form)) 'face-defface-spec nil)
617 ;; ;; Setting `customized-face' to the new spec after calling
618 ;; ;; the form, but preserving the old saved spec in `saved-face',
619 ;; ;; imitates the situation when the new face spec is set
620 ;; ;; temporarily for the current session in the customize
621 ;; ;; buffer, thus allowing `face-user-default-spec' to use the
622 ;; ;; new customized spec instead of the saved spec.
623 ;; ;; Resetting `saved-face' temporarily to nil is needed to let
624 ;; ;; `defface' change the spec, regardless of a saved spec.
625 ;; (prog1 `(prog1 ,form
626 ;; (put ,(nth 1 form) 'saved-face
627 ;; ',(get (eval (nth 1 form)) 'saved-face))
628 ;; (put ,(nth 1 form) 'customized-face
629 ;; ,(nth 2 form)))
630 ;; (put (eval (nth 1 form)) 'saved-face nil))
632 ((eq (car form) 'progn)
633 (cons 'progn (mapcar 'eval-defun-1 (cdr form))))
634 (t form)))
636 (defcommand eval-defun-2 ()
637 "Evaluate defun that point is in or before.
638 The value is displayed in the minibuffer.
639 If the current defun is actually a call to `defvar',
640 then reset the variable using the initial value expression
641 even if the variable already has some other value.
642 \(Normally `defvar' does not change the variable's value
643 if it already has a value.\)
645 With argument, insert value in current buffer after the defun.
646 Return the result of evaluation."
647 (let* ((*debug-on-error* *eval-expression-debug-on-error*)
648 (*print-length* *eval-expression-print-length*)
649 (*print-level* *eval-expression-print-level*)
650 ;; FIXME: accum the eval/compiler output and i guess do
651 ;; something with it, cept in this case we don't.
652 (*debug-io* (make-string-output-stream))
653 (*standard-output* *debug-io*)
654 (*error-output* *debug-io*))
655 (save-excursion
656 ;; FIXME: In gnu emacs eval-region handles recording which file defines
657 ;; a function or variable. How do we do that in CL?
659 (let ( ;;XXX (standard-output t)
660 beg end form)
661 ;; Read the form from the buffer, and record where it ends.
662 (save-excursion
663 (end-of-defun)
664 (beginning-of-defun)
665 (setq beg (point))
666 (setq form (read-from-buffer))
667 (setq end (point)))
668 ;; Alter the form if necessary. FIXME: we don't macroexpand
669 ;; but really we want to macroexpand down to defvar (and
670 ;; friends) which could be several layers of expansion
671 ;; down. We don't want to go all the way since defvar is
672 ;; itself a macro.
673 (setq form (eval-defun-1 form ;; (macroexpand form)
675 (eval form)))))
677 (defcommand eval-defun ((edebug-it)
678 :prefix)
679 "Evaluate the top-level form containing point, or after point.
681 If the current defun is actually a call to `defvar' or `defcustom',
682 evaluating it this way resets the variable using its initial value
683 expression even if the variable already has some other value.
684 \(Normally `defvar' and `defcustom' do not alter the value if there
685 already is one.)
687 If `eval-expression-debug-on-error' is non-nil, which is the default,
688 this command arranges for all errors to enter the debugger.
690 With a prefix argument, instrument the code for Edebug.
692 If acting on a `defun' for FUNCTION, and the function was
693 instrumented, `Edebug: FUNCTION' is printed in the minibuffer. If not
694 instrumented, just FUNCTION is printed.
696 If not acting on a `defun', the result of evaluation is displayed in
697 the minibuffer. This display is controlled by the variables
698 `eval-expression-print-length' and `eval-expression-print-level',
699 which see."
700 ;; FIXME: edebug?
701 (declare (ignore edebug-it))
702 (cond ;; (edebug-it
703 ;; (require 'edebug)
704 ;; (eval-defun (not edebug-all-defs)))
706 (if (null *eval-expression-debug-on-error*)
707 (eval-defun-2)
708 (let ((old-value (gensym "t")) new-value value)
709 (let ((*debug-on-error* old-value))
710 (setq value (eval-defun-2))
711 (setq new-value *debug-on-error*))
712 (unless (eq old-value new-value)
713 (setq *debug-on-error* new-value))
714 value)))))
717 (provide :lice-0.1/lisp-mode)