Hello,
I am new to Lisp and SLIME and am using Peter Seibel's Lispbox 0.7 on Windows XP Home to explore the language.
I wanted to add an automatic code indentation feature as described at http://ssinghi.kreeti.com/Xemacs%20&%20Lisp%20For%20Dummies.html, so I changed my .emacs file to contain the following:
;; shortcut for saving (global-set-key "\M-s" 'save-buffer)
;; indenting (defun my-set-newline-and-indent() (local-set-key [return] 'newline-and-indent))
(add-hook 'c++-mode-hook 'my-set-newline-and-indent) (add-hook 'lisp-mode-hook 'my-set-newline-and-indent) (add-hook 'Lisp-mode-hook 'my-set-newline-and-indent)
Then I removed the "--no-init-file" option from C:\lispbox-0.7\lispbox.bat.
After starting Lispbox, and verifying that the indentation feature was working as I expected, I opened a buffer of code from Chapter 2 of Practical Common Lisp and compiled it with a "C-c C-k". The REPL echoed that everything had compiled without errors. But when I attempted to type any further commands at the ">" prompt, the REPL did not respond with an evaluation.
Peter Seibel directed me to this list for help. He said that it was possible that the "return is bound by SLIME in the REPL to slime-repl-return which presumably is responsible for packaging up the expression and sending it to Lisp to be evaluated, etc. The slime- repl-mode-map inherits some bindings from lisp-mode so it may be that by setting this key in lisp-mode you are overriding the binding SLIME uses."
Would any of the SLIME developers have an idea on why this is the case? Thanks for any pointers.
Sincerely,
Kelvin Wu
The SLIME REPL must have some way of knowing that the input is finished. Simply inserting a newline does not inform it of this; instead, as Seibel suggested, there is a command `slime-repl-return' that does send the input if it is finished, and which RET is usually bound to in the REPL. `slime-repl-return' also, incidentally, if the input is incomplete, automatically indents, so you don't need to do anything special to get that behaviour.
The way you're setting up key bindings is a little weird. Locally set key bindings will shadow any others, I believe, and since the SLIME REPL uses a mode that runs lisp-mode-hook you're defining a key binding that will always shadow `slime-repl-return'.
A better way to do this is to make the key bindings in the key maps used by the various modes. I think the C++ mode uses `c++-mode-map', and all Lisp modes use `lisp-mode-shared-map'. This code will set up these key maps with the binding you want, without shadowing any bindings that the SLIME REPL wants:
(define-key lisp-mode-shared-map (kbd "RET") 'newline-and-indent)
(eval-after-load 'cpp ; This will wait until the C++ mode is ; loaded, and `c++-mode-map' defined, ; before running the code. '(define-key c++-mode-map (kbd "RET") 'newline-and-indent))
+ "Taylor R. Campbell" campbell@mumble.net:
| The way you're setting up key bindings is a little weird.
I must disagree. Users aren't supposed to know the name of modes' keymaps: The recommended method of making your own bindings for a given mode is precisely to use local-set-key in a mode hook.
| Locally set key bindings will shadow any others, I believe, and | since the SLIME REPL uses a mode that runs lisp-mode-hook you're | defining a key binding that will always shadow `slime-repl-return'.
Is the problem here that slime-mode-map is the current local keymap when slime-repl-mode runs lisp-mode-hook? If lisp-mode-map were the local keymap at that point instead, then local-set-key would modify lisp-mode-map. Later, it is safe to make slime-repl-mode-map the local map. It will then shadow lisp-mode-map, and nobody is surprised (too much).
I don't have the time to read the code carefully right now, so I haven't managed to discover how slime-repl-mode ends up running lisp-mode-hook (if that is what you are saying). If I did, I might be able to suggest a solution.
- Harald
Date: Tue, 18 Apr 2006 20:00:50 +0200 (CEST) From: Harald Hanche-Olsen hanche@math.ntnu.no
I must disagree. Users aren't supposed to know the name of modes' keymaps: The recommended method of making your own bindings for a given mode is precisely to use local-set-key in a mode hook.
Indeed? I've always just used the modes' key maps. Is this explained in any part of the Emacs or elisp manuals? In the Info node `Major Mode Conventions', the elisp manual says that the key map should be stored permanently in a global variable named `MODENAME-mode-map', so it seems to me that this is meant for users to exploit.
Is the problem here that slime-mode-map is the current local keymap when slime-repl-mode runs lisp-mode-hook? If lisp-mode-map were the local keymap at that point instead, then local-set-key would modify lisp-mode-map. Later, it is safe to make slime-repl-mode-map the local map. It will then shadow lisp-mode-map, and nobody is surprised (too much).
Hmmm. Actually, I can't reproduce the behaviour observed by Kelvin Wu, though I'm using GNU Emacs, not XEmacs. I wonder what C-h c RET says when in the SLIME REPL.
+ "Taylor R. Campbell" campbell@mumble.net:
| Date: Tue, 18 Apr 2006 20:00:50 +0200 (CEST) | From: Harald Hanche-Olsen hanche@math.ntnu.no | | I must disagree. Users aren't supposed to know the name of modes' | keymaps: The recommended method of making your own bindings for a | given mode is precisely to use local-set-key in a mode hook. | | Indeed? I've always just used the modes' key maps. Is this explained | in any part of the Emacs or elisp manuals?
Er, no. I am not sure where I have picked this up from, but evidently not from the info files, I can see that now. I must have been told this in some newsgroup or other. And repeatedly, for I am sure have heard it more than once. But at least, I think it's safe to say this is not uncommon practice, so it pays to make sure you don't break stuff for people who do this.
| Hmmm. Actually, I can't reproduce the behaviour observed by Kelvin | Wu, though I'm using GNU Emacs, not XEmacs. I wonder what C-h c RET | says when in the SLIME REPL.
I could repeat it. But guess what: RET is bound to slime-repl-return initially, after you start slime. But when you start typing some input, THAT is when lisp-mode-hook gets called, and afterwards, RET is bound to newline-and-indent. More precisely, type M-( + space, then slime displays the arglist for +, and the key gets rebound.
I tried adding a function to lisp-mode-hook that calls (error), and it didn't trigger until I started typing. It seems to be slime-fontify-string that is the culprit here. But that makes no sense either: It creates a temporary buffer for the purpose of fontifying some lisp, but that is running pure lisp-mode, so should be the hook will twiddle the wrong keymap.
I just can't figure out what is going on, and it's not for lack of trying: I added a function to lisp-mode-hook that checks whether (current-local-map) is equal to lisp-mode-map and records the answer, and it is always yes. But still, Kelvin Wu's hook rebinds return in lisp-mode-map. Argh.
- Harald
Harald Hanche-Olsen hanche@math.ntnu.no writes:
I just can't figure out what is going on
There seems to be a lot of confusion. The problem is <return> vs <RET> (C-m) (and keymap inheritance). If you change the original code to use (kbd "RET") everything should work.
The <return> function key is mapped into RET if otherwise unbound. lisp-mode-map is the parent map of slime-repl-mode-map. slime-repl-mode-map binds RET, but has no binding of its own for <return>, so any binding for <return> in lisp-mode-map is visible. Better leave <return> alone.