Illusory stillness

mumble mumble techblog

Get Emacs Set Up for Racket

I want to get back to doing problems out of SICP, but I want to use a more familiar editor.

Racket suggests Geiser and Quack. I already have Geiser installed from sopme package archive when I aborted an earlier attempt (and Geiser is supposed to, independently, include a version of Quack, or something?)

When I go to edit a .rkt file, I end up in Scheme-mode, defined in scheme.el. Is this Geiser? No — Geiser is the bit that interacts with the REPL, and it’s not enabled.

1
(add-hook 'scheme-mode-hook 'geiser-mode)

Wait, the indicator for Geiser mode is that it says “Racket/A” in the modeline._Geiser is a minor-mode.

So how do I start a Racket interpreter? M-x run-geiser. It asks me whether I want Racket or Guile. Despite what the manual claims, I can’t make that a default. I can make it the only option by saying there is no Guile to worry about.:

1
(setq geiser-active-implementations '(racket))

There appears to be no notion of “use a default but allow you to select from options with a C-u prefix” which would strike me as a more Emacsy way of doing it. ಠ_ಠ (And it also turns out you can do M-x run-racket.)

Now, the REPL appears with this error:

1
2
3
4
5
6
7
8
9
10
11
12
Welcome to Racket v6.0.1.
/Users/peter/.emacs.d/elpa/geiser-0.5/scheme/racket/geiser/user.rkt:17:9: collection not found
  for module path: mzlib/thread
  collection: "mzlib"
  in collection directories:
   /Users/peter/Library/Racket/6.0.1/collects
   /usr/local/Cellar/plt-racket/6.0.1/share/racket/collects
   /Users/peter/.emacs.d/elpa/geiser-0.5/scheme/racket/
  context...:
   show-collection-err
   standard-module-name-resolver
   standard-module-name-resolver

The first problem this points to is that it’s running Racket out of Homebrew, not the mroe complete one I downloaded from the Racket website.

It looks like one is expected to add /Applications/Racket/{bin,man}, etc to one’s path(s). I did that in the form of a Homeshick module:

1
2
3
4
5
$ homeshick generate plt-racket
$ homeshick cd plt-racket
$ mkdir home/.bashrc_includes
$ echo 'export PATH=/Applications/Racket\ v6.1/bin:$PATH' > home/.bashrc_includes/racket.sh
$ homeshick link plt-racket

Alternately, I think I could have done$ raco pkg install compatibility-lib to fix the error in Homebrew’s Racket.

Finally, I’ll install racket-mode from ELPA.

How do I use this thing?

NowI need to learn the things that I already knew for other Emacs-based REPLS.

  • How do I load a whole file into the Racket interpreter? C-c C-b?
    • (Gohd, how do I make keybindings for all the different flavors of Comint more consistent?)
  • How do I interactively send forms to the Racket interpreter? C-x C-e, same as Emacs lisp.
  • How do I switch between more than one instance of Racket interpreter? Uhhhhhh…..
  • “Switching between modules” seems important somehow. You do it with C-c C-m and C-c C-a in editing buffers.
  • C-c C-z for “jump to REPL”, C-c C-a for jump to REPL and switch module.

What about #lang directive?

Pressing C-c C-b in one of my SICP problem sets got me:

Error: retort-syntax

UNKNOWN::862: read: #lang not enabled in the current context
  context...:
   /Applications/Racket v6.1/collects/racket/private/misc.rkt:87:7
racket@>

Expression evaluated was:

#lang planet neil/sicp

This means actually I should use C-c C-a. I knew modules sounded important! Note that this does’t auto-save before loading, so I often give a C-x C-s C-c C-a sequence. I cut that out by making it autosave:

1
2
3
4
5
6
7
8
9
10
11
(define geiser-buffer-p ()
  "true if current buffer is a Geiser buffer"
  geiser-mode)
;
(defun geiser-repl-save-some-buffers-and-enter-module ()
  (interactive)
  (save-some-buffers t 'geiser-buffer-p)
  (geiser-mode-switch-to-repl-and-enter))
;
(define-key geiser-mode-map (kbd "C-c C-a")
  'geiser-repl-save-some-buffers-and-enter-module)

Now how do I get autocompletion?

Something happens when I press Tab, so far so good.

And what about documentation!

Autodoc is enabled and it’s like eldoc. C-c C-d d for jump to documentation for symbol at point C-c C-d i finds it in the Racket manual in your web browser. C-c C-d m lists the bindings in a module.

Cool, this is looking like it will work.

And what about linting / flychecking?

I turn on flycheck mode? Haven’t seen it do anything yet. Ah, there it goes. I want to make it more obtrusive (its error highlights are single characters often.)

Also, as I edit code I’m getting this annoyingly big message in the minibuffer:

1
2
3
4
5
6
Checker racket returned non-zero exit code 1, but no errors from output: r5rs:body: no expression in body
  in: (r5rs:body (define (new-record data) attach-tag data) (define (get-record name) (new-record data)) (define (get-salary record) (quote salary)))
  context...:
   /Applications/Racket v6.1/share/pkgs/r5rs-lib/r5rs/main.rkt:335:2

Checker definition probably flawed.

In other words, one kind of syntax error (no expression on body) is not getting interpreted as an “error”.

Actually this particular syntax error (at least when writing code in the #lang planet neil/sicp module) is annoying because it won’t point you to the line on which error occurs despite it being mostly syntax. Usually turns out to be an ‘if’ with no clauses, a duplicated paren, or something.

Additionally, the red underline that flycheck puts is misplaced and tiny (it is frequently on an open paren, when it should really be on all of the first sexp inside that paren).

How about autocomplete in the REPL for symbols defined in my module? How about eldoc for my own definitions?

This should be possible, right? I’m getting “end of file during parsing” errors. I don’t get it. But DrRacket was not autocompleting symbols defined in buffer either.

Autocomplete in REPL does seem to work once I can successfully load the module.

However, there appear to be situations in which the link between Geiser and Racket freezes up.

What does “compile” do?

As far as I can tell, C-c C-k on one of my SICP problemsets pops up a “compile” buffer with the following contents:

1
2
3
4
5
6
Compiling /Users/peter/sicp/chap2.4.rkt ...

Error: retort-syntax

(mcons (mcons 'result (mcons "#<void>" '())) (mcons (mcons 'output "") '()))
racket@chap2.4.rkt>

“Retort-syntax”? WTH?

Navigating errors.

<backtab> and navigates errors in the buffer. <tab> also indents or autocompletes symbols. But <tab> from an empty prompt doesn’t DWIM “go to previous error, then preceding prompt, then next error” from an empty prompt, which it should (then I could just tab to the most likely link I want to take, then <return> to follow it, two keystrokes.)

The error links were not always working, and were ugly, so I spent some time fixing them.

This led to error links not actually navigating to the error when I pressed <return>, so I added this to restore that behavior:

1
2
3
4
5
6
7
(defun geiser-repl--follow-error-or-maybe-send ()
  (interactive)
  (if (get-text-property (point) 'compilation-message)
      (compile-goto-error)
      (geiser-repl--maybe-send)))
(define-key geiser-repl-mode-map (kbd "<return>")
  'geiser-repl--follow-error-or-maybe-send)

Set the output syntax

The “write” output syntax puts “mcons” everywhere. In DrRacket, one can choose the “write” output style to elide the difference between mutable and immutable output cells. How does that work from the REPL? (Answered in Stack Overflow question. How to do this automatically, haven’t worked out yet.)

Improve error display

To what extent can Racket error output be customized? Sometimes it elides path names with “...” which is annoying. Other times it elides path names for good.

Weird issues

Occasionally in the Geiser REPL I will be unable to use C-a to go to back to the prompt, if point is at the end of buffer. What gives?