scheme interaction mode
[bpt/emacs.git] / lisp / progmodes / scheme.el
CommitLineData
d5031a2a 1;;; scheme.el --- Scheme (and DSSSL) editing mode -*- lexical-binding: t; -*-
c88ab9ce 2
ba318903 3;; Copyright (C) 1986-1988, 1997-1998, 2001-2014 Free Software
ab422c4d 4;; Foundation, Inc.
3a801d0c 5
4228277d 6;; Author: Bill Rozas <jinx@martigny.ai.mit.edu>
d575e99d 7;; Adapted-by: Dave Love <d.love@dl.ac.uk>
d7b4d18f 8;; Keywords: languages, lisp
e5167999 9
ac5b21ac
RS
10;; This file is part of GNU Emacs.
11
b1fc2b50 12;; GNU Emacs is free software: you can redistribute it and/or modify
ac5b21ac 13;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
ac5b21ac
RS
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
b1fc2b50 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
ac5b21ac 24
e5167999 25;;; Commentary:
ac5b21ac 26
1367ff3a
RS
27;; The major mode for editing Scheme-type Lisp code, very similar to
28;; the Lisp mode documented in the Emacs manual. `dsssl-mode' is a
29;; variant of scheme-mode for editing DSSSL specifications for SGML
30;; documents. [As of Apr 1997, some pointers for DSSSL may be found,
31;; for instance, at <URL:http://www.sil.org/sgml/related.html#dsssl>.]
32;; All these Lisp-ish modes vary basically in details of the language
33;; syntax they highlight/indent/index, but dsssl-mode uses "^;;;" as
64ef5f39 34;; the page-delimiter since ^L isn't normally a valid SGML character.
1367ff3a
RS
35;;
36;; For interacting with a Scheme interpreter See also `run-scheme' in
37;; the `cmuscheme' package and also the implementation-specific
38;; `xscheme' package.
ac5b21ac 39
2b20743d
DL
40;; Here's a recipe to generate a TAGS file for DSSSL, by the way:
41;; etags --lang=scheme --regex='/[ \t]*(\(mode\|element\)[ \t
42;; ]+\([^ \t(
43;; ]+\)/\2/' --regex='/[ \t]*(element[ \t
44;; ]*([^)]+[ \t
45;; ]+\([^)]+\)[ \t
46;; ]*)/\1/' --regex='/(declare[^ \t
47;; ]*[ \t
48;; ]+\([^ \t
49;; ]+\)/\1/' "$@"
50
e5167999 51;;; Code:
ac5b21ac 52\f
1367ff3a
RS
53(require 'lisp-mode)
54
9fce950d
SM
55(defvar scheme-mode-syntax-table
56 (let ((st (make-syntax-table))
57 (i 0))
f13f86fb
CY
58 ;; Symbol constituents
59 ;; We used to treat chars 128-256 as symbol-constituent, but they
60 ;; should be valid word constituents (Bug#8843). Note that valid
61 ;; identifier characters are Scheme-implementation dependent.
62 (while (< i ?0)
c676c4e5
TTN
63 (modify-syntax-entry i "_ " st)
64 (setq i (1+ i)))
f13f86fb
CY
65 (setq i (1+ ?9))
66 (while (< i ?A)
67 (modify-syntax-entry i "_ " st)
c676c4e5 68 (setq i (1+ i)))
f13f86fb
CY
69 (setq i (1+ ?Z))
70 (while (< i ?a)
71 (modify-syntax-entry i "_ " st)
c676c4e5 72 (setq i (1+ i)))
f13f86fb
CY
73 (setq i (1+ ?z))
74 (while (< i 128)
75 (modify-syntax-entry i "_ " st)
c676c4e5
TTN
76 (setq i (1+ i)))
77
78 ;; Whitespace
79 (modify-syntax-entry ?\t " " st)
80 (modify-syntax-entry ?\n "> " st)
81 (modify-syntax-entry ?\f " " st)
82 (modify-syntax-entry ?\r " " st)
347a0b69 83 (modify-syntax-entry ?\s " " st)
c676c4e5
TTN
84
85 ;; These characters are delimiters but otherwise undefined.
86 ;; Brackets and braces balance for editing convenience.
87 (modify-syntax-entry ?\[ "(] " st)
88 (modify-syntax-entry ?\] ")[ " st)
89 (modify-syntax-entry ?{ "(} " st)
90 (modify-syntax-entry ?} "){ " st)
f17ae68f
SM
91 (modify-syntax-entry ?\| "\" 23bn" st)
92 ;; Guile allows #! ... !# comments.
93 ;; But SRFI-22 defines the comment as #!...\n instead.
94 ;; Also Guile says that the !# should be on a line of its own.
95 ;; It's too difficult to get it right, for too little benefit.
96 ;; (modify-syntax-entry ?! "_ 2" st)
c676c4e5
TTN
97
98 ;; Other atom delimiters
99 (modify-syntax-entry ?\( "() " st)
100 (modify-syntax-entry ?\) ")( " st)
21c3ef84 101 ;; It's used for single-line comments as well as for #;(...) sexp-comments.
0a5cfeee 102 (modify-syntax-entry ?\; "<" st)
21c3ef84 103 (modify-syntax-entry ?\" "\" " st)
0a08535e
RS
104 (modify-syntax-entry ?' "' " st)
105 (modify-syntax-entry ?` "' " st)
c676c4e5
TTN
106
107 ;; Special characters
0a08535e
RS
108 (modify-syntax-entry ?, "' " st)
109 (modify-syntax-entry ?@ "' " st)
c5683ceb 110 (modify-syntax-entry ?# "' 14" st)
c676c4e5 111 (modify-syntax-entry ?\\ "\\ " st)
9fce950d 112 st))
ac5b21ac 113\f
d17f0db5 114(defvar scheme-mode-abbrev-table nil)
ac5b21ac
RS
115(define-abbrev-table 'scheme-mode-abbrev-table ())
116
1367ff3a 117(defvar scheme-imenu-generic-expression
d17f0db5 118 '((nil
d575e99d 119 "^(define\\(\\|-\\(generic\\(\\|-procedure\\)\\|method\\)\\)*\\s-+(?\\(\\sw+\\)" 4)
d17f0db5 120 ("Types"
d575e99d 121 "^(define-class\\s-+(?\\(\\sw+\\)" 1)
93a7d76f 122 ("Macros"
d575e99d 123 "^(\\(defmacro\\|define-macro\\|define-syntax\\)\\s-+(?\\(\\sw+\\)" 2))
1367ff3a
RS
124 "Imenu generic expression for Scheme mode. See `imenu-generic-expression'.")
125
ac5b21ac
RS
126(defun scheme-mode-variables ()
127 (set-syntax-table scheme-mode-syntax-table)
128 (setq local-abbrev-table scheme-mode-abbrev-table)
ba03d0d9
CY
129 (setq-local paragraph-start (concat "$\\|" page-delimiter))
130 (setq-local paragraph-separate paragraph-start)
131 (setq-local paragraph-ignore-fill-prefix t)
132 (setq-local fill-paragraph-function 'lisp-fill-paragraph)
1367ff3a
RS
133 ;; Adaptive fill mode gets in the way of auto-fill,
134 ;; and should make no difference for explicit fill
135 ;; because lisp-fill-paragraph should do the job.
ba03d0d9
CY
136 (setq-local adaptive-fill-mode nil)
137 (setq-local indent-line-function 'lisp-indent-line)
138 (setq-local parse-sexp-ignore-comments t)
139 (setq-local outline-regexp ";;; \\|(....")
140 (setq-local add-log-current-defun-function #'lisp-current-defun-name)
141 (setq-local comment-start ";")
142 (setq-local comment-add 1)
4f8aeb84
DG
143 (setq-local comment-start-skip ";+[ \t]*")
144 (setq-local comment-use-syntax t)
ba03d0d9
CY
145 (setq-local comment-column 40)
146 (setq-local parse-sexp-ignore-comments t)
147 (setq-local lisp-indent-function 'scheme-indent-function)
1367ff3a 148 (setq mode-line-process '("" scheme-mode-line-process))
ba03d0d9 149 (setq-local imenu-case-fold-search t)
0a5cfeee
SM
150 (setq-local imenu-generic-expression scheme-imenu-generic-expression)
151 (setq-local imenu-syntax-alist '(("+-*/.<>=?!$%_&~^:" . "w")))
152 (setq-local syntax-propertize-function #'scheme-syntax-propertize)
ba03d0d9
CY
153 (setq font-lock-defaults
154 '((scheme-font-lock-keywords
155 scheme-font-lock-keywords-1 scheme-font-lock-keywords-2)
156 nil t (("+-*/.<>=!?$%_&~^:" . "w") (?#. "w 14"))
157 beginning-of-defun
0a5cfeee 158 (font-lock-mark-block-function . mark-defun)))
ba03d0d9 159 (setq-local lisp-doc-string-elt-property 'scheme-doc-string-elt))
ac5b21ac
RS
160
161(defvar scheme-mode-line-process "")
162
150bbae7
SM
163(defvar scheme-mode-map
164 (let ((smap (make-sparse-keymap))
165 (map (make-sparse-keymap "Scheme")))
166 (set-keymap-parent smap lisp-mode-shared-map)
167 (define-key smap [menu-bar scheme] (cons "Scheme" map))
ece8c34d
DL
168 (define-key map [run-scheme] '("Run Inferior Scheme" . run-scheme))
169 (define-key map [uncomment-region]
170 '("Uncomment Out Region" . (lambda (beg end)
171 (interactive "r")
172 (comment-region beg end '(4)))))
173 (define-key map [comment-region] '("Comment Out Region" . comment-region))
174 (define-key map [indent-region] '("Indent Region" . indent-region))
175 (define-key map [indent-line] '("Indent Line" . lisp-indent-line))
176 (put 'comment-region 'menu-enable 'mark-active)
177 (put 'uncomment-region 'menu-enable 'mark-active)
150bbae7
SM
178 (put 'indent-region 'menu-enable 'mark-active)
179 smap)
180 "Keymap for Scheme mode.
181All commands in `lisp-mode-shared-map' are inherited by this map.")
1367ff3a
RS
182
183;; Used by cmuscheme
ac5b21ac 184(defun scheme-mode-commands (map)
48879301 185 ;;(define-key map "\t" 'indent-for-tab-command) ; default
ac5b21ac 186 (define-key map "\177" 'backward-delete-char-untabify)
48879301 187 (define-key map "\e\C-q" 'indent-sexp))
ac5b21ac 188\f
e2ab0aa6 189;;;###autoload
175069ef 190(define-derived-mode scheme-mode prog-mode "Scheme"
ac5b21ac 191 "Major mode for editing Scheme code.
d17f0db5 192Editing commands are similar to those of `lisp-mode'.
ac5b21ac
RS
193
194In addition, if an inferior Scheme process is running, some additional
195commands will be defined, for evaluating expressions and controlling
196the interpreter, and the state of the process will be displayed in the
37269466 197mode line of all Scheme buffers. The names of commands that interact
1b9a1e9d
DL
198with the Scheme process start with \"xscheme-\" if you use the MIT
199Scheme-specific `xscheme' package; for more information see the
200documentation for `xscheme-interaction-mode'. Use \\[run-scheme] to
201start an inferior Scheme using the more general `cmuscheme' package.
ac5b21ac
RS
202
203Commands:
204Delete converts tabs to spaces as it moves back.
205Blank lines separate paragraphs. Semicolons start comments.
ae1f1ce1 206\\{scheme-mode-map}"
175069ef 207 (scheme-mode-variables))
ac5b21ac 208
48879301 209(defgroup scheme nil
347a0b69 210 "Editing Scheme code."
8ec3bce0 211 :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
48879301
RS
212 :group 'lisp)
213
214(defcustom scheme-mit-dialect t
ac5b21ac 215 "If non-nil, scheme mode is specialized for MIT Scheme.
48879301
RS
216Set this to nil if you normally use another dialect."
217 :type 'boolean
218 :group 'scheme)
1367ff3a 219
48879301 220(defcustom dsssl-sgml-declaration
1367ff3a
RS
221 "<!DOCTYPE style-sheet PUBLIC \"-//James Clark//DTD DSSSL Style Sheet//EN\">
222"
fb7ada5f 223 "An SGML declaration for the DSSSL file.
2b20743d 224If it is defined as a string this will be inserted into an empty buffer
d17f0db5 225which is in `dsssl-mode'. It is typically James Clark's style-sheet
48879301 226doctype, as required for Jade."
d17f0db5 227 :type '(choice (string :tag "Specified string")
2b20743d
DL
228 (const :tag "None" :value nil))
229 :group 'scheme)
230
231(defcustom scheme-mode-hook nil
d17f0db5 232 "Normal hook run when entering `scheme-mode'.
2b20743d
DL
233See `run-hooks'."
234 :type 'hook
235 :group 'scheme)
236
237(defcustom dsssl-mode-hook nil
d17f0db5 238 "Normal hook run when entering `dsssl-mode'.
2b20743d
DL
239See `run-hooks'."
240 :type 'hook
48879301 241 :group 'scheme)
1367ff3a 242
f7a6110d
DL
243;; This is shared by cmuscheme and xscheme.
244(defcustom scheme-program-name "scheme"
fb7ada5f 245 "Program invoked by the `run-scheme' command."
f7a6110d
DL
246 :type 'string
247 :group 'scheme)
248
1367ff3a
RS
249(defvar dsssl-imenu-generic-expression
250 ;; Perhaps this should also look for the style-sheet DTD tags. I'm
251 ;; not sure it's the best way to organize it; perhaps one type
252 ;; should be at the first level, though you don't see this anyhow if
253 ;; it gets split up.
d17f0db5 254 '(("Defines"
d575e99d 255 "^(define\\s-+(?\\(\\sw+\\)" 1)
93a7d76f 256 ("Modes"
d575e99d 257 "^\\s-*(mode\\s-+\\(\\(\\sw\\|\\s-\\)+\\)" 1)
93a7d76f 258 ("Elements"
1367ff3a 259 ;; (element foo ...) or (element (foo bar ...) ...)
26d05e22 260 ;; Fixme: Perhaps it should do `root'.
d575e99d 261 "^\\s-*(element\\s-+(?\\(\\(\\sw\\|\\s-\\)+\\))?" 1)
d17f0db5 262 ("Declarations"
d575e99d 263 "^(declare\\(-\\sw+\\)+\\>\\s-+\\(\\sw+\\)" 2))
1367ff3a
RS
264 "Imenu generic expression for DSSSL mode. See `imenu-generic-expression'.")
265
22dcd0d1
DL
266(defconst scheme-font-lock-keywords-1
267 (eval-when-compile
268 (list
269 ;;
270 ;; Declarations. Hannes Haug <hannes.haug@student.uni-tuebingen.de> says
271 ;; this works for SOS, STklos, SCOOPS, Meroon and Tiny CLOS.
405ff5ea 272 (list (concat "(\\(define\\*?\\("
22dcd0d1 273 ;; Function names.
405ff5ea 274 "\\(\\|-public\\|-method\\|-generic\\(-procedure\\)?\\)\\|"
22dcd0d1 275 ;; Macro names, as variable names. A bit dubious, this.
1b9a1e9d 276 "\\(-syntax\\|-macro\\)\\|"
22dcd0d1
DL
277 ;; Class names.
278 "-class"
405ff5ea
RS
279 ;; Guile modules.
280 "\\|-module"
22dcd0d1
DL
281 "\\)\\)\\>"
282 ;; Any whitespace and declared object.
5e4ab4e4
TTN
283 ;; The "(*" is for curried definitions, e.g.,
284 ;; (define ((sum a) b) (+ a b))
285 "[ \t]*(*"
22dcd0d1
DL
286 "\\(\\sw+\\)?")
287 '(1 font-lock-keyword-face)
288 '(6 (cond ((match-beginning 3) font-lock-function-name-face)
289 ((match-beginning 5) font-lock-variable-name-face)
290 (t font-lock-type-face))
291 nil t))
292 ))
293 "Subdued expressions to highlight in Scheme modes.")
294
295(defconst scheme-font-lock-keywords-2
296 (append scheme-font-lock-keywords-1
297 (eval-when-compile
298 (list
299 ;;
300 ;; Control structures.
301 (cons
302 (concat
303 "(" (regexp-opt
304 '("begin" "call-with-current-continuation" "call/cc"
305 "call-with-input-file" "call-with-output-file" "case" "cond"
67ed8fcd 306 "do" "else" "for-each" "if" "lambda" "λ"
22dcd0d1 307 "let" "let*" "let-syntax" "letrec" "letrec-syntax"
12e5e86e
SH
308 ;; R6RS library subforms.
309 "export" "import"
12cf1a12
TTN
310 ;; SRFI 11 usage comes up often enough.
311 "let-values" "let*-values"
22dcd0d1 312 ;; Hannes Haug <hannes.haug@student.uni-tuebingen.de> wants:
c1bfdd54 313 "and" "or" "delay" "force"
22dcd0d1
DL
314 ;; Stefan Monnier <stefan.monnier@epfl.ch> says don't bother:
315 ;;"quasiquote" "quote" "unquote" "unquote-splicing"
316 "map" "syntax" "syntax-rules") t)
317 "\\>") 1)
318 ;;
22071507
TTN
319 ;; It wouldn't be Scheme w/o named-let.
320 '("(let\\s-+\\(\\sw+\\)"
321 (1 font-lock-function-name-face))
322 ;;
22dcd0d1
DL
323 ;; David Fox <fox@graphics.cs.nyu.edu> for SOS/STklos class specifiers.
324 '("\\<<\\sw+>\\>" . font-lock-type-face)
325 ;;
cb049c41
TTN
326 ;; Scheme `:' and `#:' keywords as builtins.
327 '("\\<#?:\\sw+\\>" . font-lock-builtin-face)
12e5e86e
SH
328 ;; R6RS library declarations.
329 '("(\\(\\<library\\>\\)\\s-*(?\\(\\sw+\\)?"
330 (1 font-lock-keyword-face)
331 (2 font-lock-type-face))
22dcd0d1
DL
332 )))
333 "Gaudy expressions to highlight in Scheme modes.")
334
335(defvar scheme-font-lock-keywords scheme-font-lock-keywords-1
336 "Default expressions to highlight in Scheme modes.")
337
21c3ef84
SM
338(defconst scheme-sexp-comment-syntax-table
339 (let ((st (make-syntax-table scheme-mode-syntax-table)))
340 (modify-syntax-entry ?\; "." st)
341 (modify-syntax-entry ?\n " " st)
342 (modify-syntax-entry ?# "'" st)
343 st))
344
345(put 'lambda 'scheme-doc-string-elt 2)
346;; Docstring's pos in a `define' depends on whether it's a var or fun def.
347(put 'define 'scheme-doc-string-elt
348 (lambda ()
349 ;; The function is called with point right after "define".
350 (forward-comment (point-max))
351 (if (eq (char-after) ?\() 2 0)))
352
0a5cfeee
SM
353(defun scheme-syntax-propertize (beg end)
354 (goto-char beg)
355 (scheme-syntax-propertize-sexp-comment (point) end)
356 (funcall
357 (syntax-propertize-rules
358 ("\\(#\\);" (1 (prog1 "< cn"
359 (scheme-syntax-propertize-sexp-comment (point) end)))))
360 (point) end))
361
362(defun scheme-syntax-propertize-sexp-comment (_ end)
363 (let ((state (syntax-ppss)))
364 (when (eq 2 (nth 7 state))
365 ;; It's a sexp-comment. Tell parse-partial-sexp where it ends.
366 (condition-case nil
367 (progn
368 (goto-char (+ 2 (nth 8 state)))
369 ;; FIXME: this doesn't handle the case where the sexp
370 ;; itself contains a #; comment.
371 (forward-sexp 1)
372 (put-text-property (1- (point)) (point)
373 'syntax-table (string-to-syntax "> cn")))
374 (scan-error (goto-char end))))))
f17ae68f 375
1367ff3a 376;;;###autoload
150bbae7 377(define-derived-mode dsssl-mode scheme-mode "DSSSL"
1367ff3a 378 "Major mode for editing DSSSL code.
d17f0db5 379Editing commands are similar to those of `lisp-mode'.
1367ff3a
RS
380
381Commands:
382Delete converts tabs to spaces as it moves back.
383Blank lines separate paragraphs. Semicolons start comments.
384\\{scheme-mode-map}
22dcd0d1
DL
385Entering this mode runs the hooks `scheme-mode-hook' and then
386`dsssl-mode-hook' and inserts the value of `dsssl-sgml-declaration' if
387that variable's value is a string."
ba03d0d9 388 (setq-local page-delimiter "^;;;") ; ^L not valid SGML char
1367ff3a 389 ;; Insert a suitable SGML declaration into an empty buffer.
150bbae7 390 ;; FIXME: This should use `auto-insert-alist' instead.
1367ff3a 391 (and (zerop (buffer-size))
26d05e22 392 (stringp dsssl-sgml-declaration)
1367ff3a
RS
393 (not buffer-read-only)
394 (insert dsssl-sgml-declaration))
22dcd0d1
DL
395 (setq font-lock-defaults '(dsssl-font-lock-keywords
396 nil t (("+-*/.<>=?$%_&~^:" . "w"))
397 beginning-of-defun
398 (font-lock-mark-block-function . mark-defun)))
ba03d0d9
CY
399 (setq-local add-log-current-defun-function #'lisp-current-defun-name)
400 (setq-local imenu-case-fold-search nil)
c0b08eb0 401 (setq imenu-generic-expression dsssl-imenu-generic-expression)
ba03d0d9 402 (setq-local imenu-syntax-alist '(("+-*/.<>=?$%_&~^:" . "w"))))
1367ff3a
RS
403
404;; Extra syntax for DSSSL. This isn't separated from Scheme, but
405;; shouldn't cause much trouble in scheme-mode.
406(put 'element 'scheme-indent-function 1)
407(put 'mode 'scheme-indent-function 1)
408(put 'with-mode 'scheme-indent-function 1)
2f5029f3 409(put 'make 'scheme-indent-function 1)
26d05e22
RS
410(put 'style 'scheme-indent-function 1)
411(put 'root 'scheme-indent-function 1)
67ed8fcd 412(put 'λ 'scheme-indent-function 1)
1367ff3a
RS
413
414(defvar dsssl-font-lock-keywords
26d05e22
RS
415 (eval-when-compile
416 (list
417 ;; Similar to Scheme
418 (list "(\\(define\\(-\\w+\\)?\\)\\>[ ]*\\\((?\\)\\(\\sw+\\)\\>"
419 '(1 font-lock-keyword-face)
420 '(4 font-lock-function-name-face))
421 (cons
422 (concat "(\\("
423 ;; (make-regexp '("case" "cond" "else" "if" "lambda"
424 ;; "let" "let*" "letrec" "and" "or" "map" "with-mode"))
425 "and\\|c\\(ase\\|ond\\)\\|else\\|if\\|"
426 "l\\(ambda\\|et\\(\\|*\\|rec\\)\\)\\|map\\|or\\|with-mode"
427 "\\)\\>")
428 1)
429 ;; DSSSL syntax
430 '("(\\(element\\|mode\\|declare-\\w+\\)\\>[ ]*\\(\\sw+\\)"
431 (1 font-lock-keyword-face)
432 (2 font-lock-type-face))
433 '("(\\(element\\)\\>[ ]*(\\(\\S)+\\))"
434 (1 font-lock-keyword-face)
435 (2 font-lock-type-face))
883212ce 436 '("\\<\\sw+:\\>" . font-lock-constant-face) ; trailing `:' c.f. scheme
26d05e22
RS
437 ;; SGML markup (from sgml-mode) :
438 '("<\\([!?][-a-z0-9]+\\)" 1 font-lock-keyword-face)
439 '("<\\(/?[-a-z0-9]+\\)" 1 font-lock-function-name-face)))
1367ff3a
RS
440 "Default expressions to highlight in DSSSL mode.")
441
ac5b21ac 442\f
1367ff3a
RS
443(defvar calculate-lisp-indent-last-sexp)
444
b7556719
GM
445
446;; FIXME this duplicates almost all of lisp-indent-function.
447;; Extract common code to a subroutine.
ac5b21ac 448(defun scheme-indent-function (indent-point state)
b7556719
GM
449 "Scheme mode function for the value of the variable `lisp-indent-function'.
450This behaves like the function `lisp-indent-function', except that:
451
452i) it checks for a non-nil value of the property `scheme-indent-function'
dd4b63a6 453\(or the deprecated `scheme-indent-hook'), rather than `lisp-indent-function'.
b7556719 454
b026d240 455ii) if that property specifies a function, it is called with three
b7556719
GM
456arguments (not two), the third argument being the default (i.e., current)
457indentation."
ac5b21ac 458 (let ((normal-indent (current-column)))
1367ff3a
RS
459 (goto-char (1+ (elt state 1)))
460 (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
461 (if (and (elt state 2)
462 (not (looking-at "\\sw\\|\\s_")))
4696802b 463 ;; car of form doesn't seem to be a symbol
1367ff3a
RS
464 (progn
465 (if (not (> (save-excursion (forward-line 1) (point))
466 calculate-lisp-indent-last-sexp))
467 (progn (goto-char calculate-lisp-indent-last-sexp)
468 (beginning-of-line)
469 (parse-partial-sexp (point)
470 calculate-lisp-indent-last-sexp 0 t)))
471 ;; Indent under the list or under the first sexp on the same
472 ;; line as calculate-lisp-indent-last-sexp. Note that first
473 ;; thing on that line has to be complete sexp since we are
474 ;; inside the innermost containing sexp.
475 (backward-prefix-chars)
476 (current-column))
477 (let ((function (buffer-substring (point)
478 (progn (forward-sexp 1) (point))))
479 method)
480 (setq method (or (get (intern-soft function) 'scheme-indent-function)
481 (get (intern-soft function) 'scheme-indent-hook)))
482 (cond ((or (eq method 'defun)
483 (and (null method)
484 (> (length function) 3)
485 (string-match "\\`def" function)))
486 (lisp-indent-defform state indent-point))
487 ((integerp method)
488 (lisp-indent-specform method state
489 indent-point normal-indent))
490 (method
61185f42 491 (funcall method state indent-point normal-indent)))))))
1367ff3a 492
ac5b21ac
RS
493\f
494;;; Let is different in Scheme
495
d5031a2a
LL
496;; (defun scheme-would-be-symbol (string)
497;; (not (string-equal (substring string 0 1) "(")))
ac5b21ac 498
d5031a2a
LL
499;; (defun scheme-next-sexp-as-string ()
500;; ;; Assumes that it is protected by a save-excursion
501;; (forward-sexp 1)
502;; (let ((the-end (point)))
503;; (backward-sexp 1)
504;; (buffer-substring (point) the-end)))
ac5b21ac
RS
505
506;; This is correct but too slow.
507;; The one below works almost always.
508;;(defun scheme-let-indent (state indent-point)
d5031a2a 509;; (if (scheme-would-be-symbol (scheme-next-sexp-as-string))
ac5b21ac
RS
510;; (scheme-indent-specform 2 state indent-point)
511;; (scheme-indent-specform 1 state indent-point)))
512
61185f42 513(defun scheme-let-indent (state indent-point normal-indent)
ac5b21ac 514 (skip-chars-forward " \t")
61361a07 515 (if (looking-at "[-a-zA-Z0-9+*/?!@$%^&_:~]")
61185f42
KH
516 (lisp-indent-specform 2 state indent-point normal-indent)
517 (lisp-indent-specform 1 state indent-point normal-indent)))
ac5b21ac
RS
518
519;; (put 'begin 'scheme-indent-function 0), say, causes begin to be indented
520;; like defun if the first form is placed on the next line, otherwise
521;; it is indented like any other form (i.e. forms line up under first).
522
523(put 'begin 'scheme-indent-function 0)
524(put 'case 'scheme-indent-function 1)
525(put 'delay 'scheme-indent-function 0)
526(put 'do 'scheme-indent-function 2)
527(put 'lambda 'scheme-indent-function 1)
528(put 'let 'scheme-indent-function 'scheme-let-indent)
529(put 'let* 'scheme-indent-function 1)
530(put 'letrec 'scheme-indent-function 1)
12cf1a12
TTN
531(put 'let-values 'scheme-indent-function 1) ; SRFI 11
532(put 'let*-values 'scheme-indent-function 1) ; SRFI 11
2b20743d
DL
533(put 'sequence 'scheme-indent-function 0) ; SICP, not r4rs
534(put 'let-syntax 'scheme-indent-function 1)
535(put 'letrec-syntax 'scheme-indent-function 1)
536(put 'syntax-rules 'scheme-indent-function 1)
0ec2c350 537(put 'syntax-case 'scheme-indent-function 2) ; not r5rs
12e5e86e 538(put 'library 'scheme-indent-function 1) ; R6RS
ac5b21ac
RS
539
540(put 'call-with-input-file 'scheme-indent-function 1)
541(put 'with-input-from-file 'scheme-indent-function 1)
542(put 'with-input-from-port 'scheme-indent-function 1)
543(put 'call-with-output-file 'scheme-indent-function 1)
544(put 'with-output-to-file 'scheme-indent-function 1)
545(put 'with-output-to-port 'scheme-indent-function 1)
2b20743d
DL
546(put 'call-with-values 'scheme-indent-function 1) ; r5rs?
547(put 'dynamic-wind 'scheme-indent-function 3) ; r5rs?
ac5b21ac
RS
548\f
549;;;; MIT Scheme specific indentation.
550
551(if scheme-mit-dialect
552 (progn
553 (put 'fluid-let 'scheme-indent-function 1)
554 (put 'in-package 'scheme-indent-function 1)
ac5b21ac
RS
555 (put 'local-declare 'scheme-indent-function 1)
556 (put 'macro 'scheme-indent-function 1)
557 (put 'make-environment 'scheme-indent-function 0)
558 (put 'named-lambda 'scheme-indent-function 1)
559 (put 'using-syntax 'scheme-indent-function 1)
560
561 (put 'with-input-from-string 'scheme-indent-function 1)
562 (put 'with-output-to-string 'scheme-indent-function 0)
563 (put 'with-values 'scheme-indent-function 1)
564
565 (put 'syntax-table-define 'scheme-indent-function 2)
566 (put 'list-transform-positive 'scheme-indent-function 1)
567 (put 'list-transform-negative 'scheme-indent-function 1)
568 (put 'list-search-positive 'scheme-indent-function 1)
569 (put 'list-search-negative 'scheme-indent-function 1)
570
571 (put 'access-components 'scheme-indent-function 1)
572 (put 'assignment-components 'scheme-indent-function 1)
573 (put 'combination-components 'scheme-indent-function 1)
574 (put 'comment-components 'scheme-indent-function 1)
575 (put 'conditional-components 'scheme-indent-function 1)
576 (put 'disjunction-components 'scheme-indent-function 1)
577 (put 'declaration-components 'scheme-indent-function 1)
578 (put 'definition-components 'scheme-indent-function 1)
579 (put 'delay-components 'scheme-indent-function 1)
580 (put 'in-package-components 'scheme-indent-function 1)
581 (put 'lambda-components 'scheme-indent-function 1)
582 (put 'lambda-components* 'scheme-indent-function 1)
583 (put 'lambda-components** 'scheme-indent-function 1)
584 (put 'open-block-components 'scheme-indent-function 1)
585 (put 'pathname-components 'scheme-indent-function 1)
586 (put 'procedure-components 'scheme-indent-function 1)
587 (put 'sequence-components 'scheme-indent-function 1)
588 (put 'unassigned\?-components 'scheme-indent-function 1)
589 (put 'unbound\?-components 'scheme-indent-function 1)
590 (put 'variable-components 'scheme-indent-function 1)))
32a9496d
RT
591\f
592;; Scheme Interaction Mode
593
594(defun scheme-eval-defun ()
595 (interactive)
596 (let ((debug-on-error eval-expression-debug-on-error)
597 (print-length eval-expression-print-length)
598 (print-level eval-expression-print-level))
599 (let* ((value (eval-scheme (thing-at-point 'defun t)))
600 (str (eval-expression-print-format value)))
601 (prin1 value t)
602 (if str (princ str))
603 value)))
604
605(defun scheme-eval-print-last-sexp (arg)
606 (interactive "P")
607 (setq arg (or arg t))
608 (let ((standard-output (current-buffer)))
609 (terpri)
610 (let ((standard-output (if arg (current-buffer) t))
611 (form (buffer-substring-no-properties
612 (save-excursion (backward-sexp) (point))
613 (point))))
614 (eval-last-sexp-print-value (eval-scheme form) arg))
615 (terpri)))
616
617(defvar scheme-interaction-mode-map
618 (let ((map (make-sparse-keymap))
619 (menu-map (make-sparse-keymap "Scheme-Interaction")))
620 (set-keymap-parent map lisp-mode-shared-map)
621 (define-key map "\e\C-x" 'scheme-eval-defun)
622 (define-key map "\n" 'scheme-eval-print-last-sexp)
623 (bindings--define-key map [menu-bar scheme-interaction]
624 (cons "Scheme-Interaction" menu-map))
625 (bindings--define-key menu-map [eval-defun]
626 '(menu-item "Evaluate Defun" scheme-eval-defun
627 :help "Evaluate the top-level form containing point, or after point"))
628 (bindings--define-key menu-map [print-last-sexp]
629 '(menu-item "Evaluate and Print" scheme-eval-print-last-sexp
630 :help "Evaluate sexp before point; print value into current buffer"))
631 (bindings--define-key menu-map [indent-sexp]
632 '(menu-item "Indent" indent-sexp
633 :help "Indent each line of the list starting just after point"))
634 map)
635 "Keymap for Scheme Interaction mode.
636All commands in `lisp-mode-shared-map' are inherited by this map.")
637
638(define-derived-mode scheme-interaction-mode scheme-mode "Scheme Interaction"
639 "Major mode for typing and evaluating Scheme forms.
640Like Scheme mode except that \\[scheme-eval-print-last-sexp] evals the
641Scheme expression before point, and prints its value into the
642buffer, advancing point. Note that printing is controlled by
643`eval-expression-print-length' and `eval-expression-print-level'.
644
645Commands:
646Delete converts tabs to spaces as it moves back.
647Paragraphs are separated only by blank lines.
648Semicolons start comments.
649
650\\{scheme-interaction-mode-map}"
651 :abbrev-table nil)
49116ac0
JB
652
653(provide 'scheme)
c88ab9ce
ER
654
655;;; scheme.el ends here