There doesn't seem to be any indentation in the default inferior scheme. At least, when I do M-x run-scheme the resulting repl doesn't indent my code at all.

How can I change this? Preferably without anything like geiser or other wrappers.


I think the issue is that RET is probably mapped to comint-send-input, which doesn't do any indentation.

What I do is map C-j to newline-and-indent and leave RET mapped to comint-send-input. So I press C-j to enter a newline, and indent the new line, or RET to actually send the form for evaluation. (Actually I map C-j to paredit-newline, but newline-and-indent should work if you're not using Paredit).

Of course, you could reverse those and use RET for newline-and-indent with C-j for comint-send-input.

As an example of mapping one of these keys, this will map C-j to newline-and-indent:

(with-eval-after-load 'cmuscheme
  (define-key inferior-scheme-mode-map (kbd "C-j") #'newline-and-indent))

(cmuscheme is, for historical reasons, the name of the package that implements inferior-scheme-mode, i.e. the Scheme REPL.)


Here's something that seems to work, though I haven't tested it extensively:

(defun comint-send-input-indent ()
  (unless (save-excursion (forward-char -1)
                          (eq (field-at-pos (point)) 'output))

(with-eval-after-load 'cmuscheme
  (define-key inferior-scheme-mode-map (kbd "RET") #'comint-send-input-indent))

The idea is to call comint-send-input, then check if point (the cursor) is immediately before the prompt. If it's not (because comint-send-input just entered a newline), call indent-for-tab-command, which indents the line appropriately.

Another edit:

On second thought, I think this definition probably makes more sense:

(defun comint-send-input-indent ()
  (let ((parens (or (car (syntax-ppss)) 0)))
    (if (zerop parens)

See C-h f syntax-ppss RET (and, better, C-h f parse-partial-sexp RET) for more information. The short version is that they can tell us how deep the paren nesting is at point, so we can use that to decide whether to newline-and-indent or comint-send-input.

| improve this answer | |
  • I could imagine a way to write a single command Doing The Right Thing™. Basically, the difference between a form that can be sent to the subprocess and a form that requires indentation of the rest is that the former is complete (read: balanced) while the latter is not. – wasamasa Mar 4 '16 at 10:31
  • Sorry but I'm really new to emacs. How can I map these keys? – Lara Mar 4 '16 at 16:14
  • @Darklightus, my bad, I've edited the answer to include an example. If you want to remap RET instead, just replace "C-j" with "RET" – jbm Mar 4 '16 at 18:05
  • @wasamasa, that indeed seems like it should be possible. In fact, in the Emacs 25 pretest I'm using (I didn't try other versions) comint-send-input already enters a newline (rather than sending the input), but doesn't indent the new line, if the form is incomplete. However, after a quick read of the source it's not clear to me how that works. Hm, I'll have to look at it more later. – jbm Mar 4 '16 at 18:10
  • If RET does comint-send-input by default, but I just want indentation in addition to that, couldn't I do both newline-and-indent and comint-send-input? Then instead of using two keys I could use just one. How would I do that? I'd use begin in other lisps but that doesn't seem to do anything (other than breaking emacs) Apart from that the solution works fine by the way. – Lara Mar 4 '16 at 18:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.