Skip to content

Commit 2522488

Browse files
Redesign REPL I/O and add racket-hash-lang-mode
This commit is a squash of nearly 250 commits from the long-running branch, `hash-lang`. Major themes: 1. Change REPL I/O. We no longer use a TCP connection to do I/O for each REPL. Instead use commands (input) and notifications (output). Furthermore send various kinds of output as distinct notifications. 2. Support use of hash-lang colors, indent, navigation when editing and in REPL. Add racket-hash-lang-mode, an alternative to racket-mode for editing source files, which uses coloring, indent and navigation supplied by a lang. Any number of racket-mode or racket-hash-lang-mode buffers may take turns using the same racket-repl-mode. The last-run edit buffer's settings are used in the REPL. Needs Racket 6.12+ for interval-map-ref/bounds. Use syntax-color/color-textoid when available (with new-enough versions of Racket and/or syntax-color-lib) but not required. 3. racket-xp-mode: Do "semantic" highlighting of binding sites. Intended for use by racket-hash-lang-mode to get more than just lexer colors. --- Fixes greghendershott#482. Fixes greghendershott#619. Fixes greghendershott#642. Fixes greghendershott#663. Fixes greghendershott#667. Fixes greghendershott#671. Fixes greghendershott#672. Fixes greghendershott#673. Closes greghendershott#64. Closes greghendershott#633. Closes PR greghendershott#661.
1 parent b516232 commit 2522488

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+5712
-1777
lines changed

.github/workflows/test.yml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ jobs:
1313
emacs_version:
1414
- '25.1' # our minimum supported version
1515
- '26.3'
16-
- '28.1' # most recent release
16+
- '29.1' # most recent release
1717
racket_version:
18-
- '6.9' # our minimum supported version
18+
- '6.12' # our minimum supported version
1919
- 'stable' # most recent release
2020
# Also include bleeding edge snapshots of both Emacs and
2121
# Racket. Note that "allow_failure: true" doesn't seem to
@@ -46,18 +46,20 @@ jobs:
4646
run: make show-versions
4747
- name: Install Emacs Packages
4848
run: make deps
49-
- name: Compile Elisp
49+
- name: Compile Emacs Lisp
5050
run: make compile
51-
- name: Run Tests
52-
run: make test
51+
- name: Run Emacs Lisp Tests
52+
run: make test-elisp
53+
- name: Run Racket Tests
54+
run: xvfb-run make test-racket
5355

5456
windows:
5557
runs-on: windows-latest
5658
strategy:
5759
fail-fast: false
5860
matrix:
5961
emacs_version:
60-
- '28.1' # most recent release
62+
- '29.1' # most recent release
6163
racket_version:
6264
- 'stable' # most recent release
6365
name: Windows Emacs ${{ matrix.emacs_version }} and Racket ${{ matrix.racket_version }}
@@ -78,6 +80,7 @@ jobs:
7880
run: make deps
7981
- name: Compile Elisp
8082
run: make compile
81-
- name: Run Tests
82-
run: make test
83-
83+
- name: Run Emacs Lisp Tests
84+
run: make test-elisp
85+
- name: Run Racket Tests
86+
run: make test-racket

Makefile

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,19 @@ help:
77
# default on PATH. e.g. `EMACS=/path/to/emacs make`.
88
EMACS ?= emacs
99
RACKET ?= racket
10+
# Allow another locations for Emacs packages.
11+
EMACS_PACKAGES ?= ~/.emacs.d/elpa
1012

1113
show-versions:
1214
@echo `which $(RACKET)`
1315
@$(RACKET) --version
1416
@echo `which $(EMACS)`
1517
@$(EMACS) --version
1618

17-
batch-emacs := $(EMACS) --batch -Q -L . --eval '(package-initialize)'
19+
batch-emacs := \
20+
$(EMACS) --batch -Q -L . \
21+
--eval '(setq package-user-dir "$(EMACS_PACKAGES)")' \
22+
--eval '(package-initialize)'
1823

1924
byte-compile := \
2025
$(batch-emacs) \
@@ -61,10 +66,16 @@ test-elisp:
6166
--eval '(setq racket-program "$(RACKET)")' \
6267
-f ert-run-tests-batch-and-exit
6368

69+
# Files to test using `raco test -x`.
70+
test-x-rkt-files := $(wildcard ./racket/*.rkt) $(wildcard ./racket/commands/*.rkt)
71+
# Exclude hash-lang.rkt because it will fail to eval on older Rackets;
72+
# normally we only dynamic-require it. Furthermore its tests are in
73+
# ./test/racket/hash-lang-test.rkt.
74+
test-x-rkt-files := $(filter-out ./racket/hash-lang.rkt, $(test-x-rkt-files))
75+
6476
test-racket:
77+
$(RACKET) -l raco test -x $(test-x-rkt-files)
6578
$(RACKET) -l raco test ./test/racket/
66-
$(RACKET) -l raco test -x ./racket/*.rkt
67-
$(RACKET) -l raco test -x ./racket/commands/*.rkt
6879

6980
test-slow:
7081
$(RACKET) -l raco test --submodule slow-test ./racket/imports.rkt

README.org

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ A variety of Emacs major and minor modes for [[https://www.racket-lang.org/][Rac
99
check-syntax, debug, profile, logging, and more. The edit/run
1010
experience is similar to [[https://docs.racket-lang.org/drracket/][DrRacket]].
1111

12-
Compatible with *Emacs 25.1+* and *Racket 6.9+*.
12+
Compatible with *Emacs 25.1+* and *Racket 6.12+*.
1313

1414
** Documentation
1515

doc/arch-pict.rkt

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
(define pipe-color "blue")
1111
(define ssh-color "purple")
12-
(define tcp-color "brown")
1312

1413
(define host-color (make-color 0 0 0 0.0))
1514
(define front-end-color (make-color #xF0 #xF7 #xF0 1.0))
@@ -48,17 +47,14 @@
4847
(vl-append
4948
(text "Emacs front end" '(bold))
5049
(hc-append
51-
(text "Command requests/responses via ")
50+
(text "Command requests/responses and notifications via ")
5251
(colorize (text "pipe" '(bold)) pipe-color)
5352
(text " or ")
5453
(colorize (text "ssh" '(bold)) ssh-color)
55-
(text "."))
56-
(hc-append
57-
(text "REPL I/O via one ")
58-
(colorize (text "TCP" '(bold)) tcp-color)
59-
(text " connection per REPL buffer.")))))
54+
(text ".")))))
6055

6156
(define (backend path)
57+
(define i/o-color (if (regexp-match? #rx"^/[^:]+:" path) ssh-color pipe-color))
6258
(box
6359
#:inset 5
6460
#:color (light "black")
@@ -73,17 +69,17 @@
7369
10
7470
(colorize
7571
(box #:inset 5 (text "Commands"))
76-
(if (regexp-match? #rx"^/[^:]+:" path) ssh-color pipe-color))
72+
i/o-color)
7773
(vl-append
7874
4
7975
(colorize (box #:inset 2 (text "REPL 1"))
80-
tcp-color)
76+
i/o-color)
8177
(colorize (box #:inset 2 (text "REPL 2"))
82-
tcp-color)
78+
i/o-color)
8379
(colorize (box #:inset 2
8480
#:segment 2
8581
(text "REPL n" '(italic)))
86-
tcp-color))))))
82+
i/o-color))))))
8783

8884
(define (back-end-source-files)
8985
(box

doc/generate.el

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
(require 'racket-unicode-input-method)
2020
(require 'racket-smart-open)
2121
(require 'racket-repl-buffer-name)
22+
(require 'racket-hash-lang)
2223
(require 'seq)
2324

2425
(defun racket-generate-reference.org ()
@@ -51,6 +52,13 @@
5152
racket-align
5253
racket-unalign
5354
racket-complete-at-point
55+
"Hash Langs"
56+
racket-hash-lang-mode
57+
(racket-hash-lang-backward ,racket-hash-lang-mode-map)
58+
(racket-hash-lang-forward ,racket-hash-lang-mode-map)
59+
(racket-hash-lang-up ,racket-hash-lang-mode-map)
60+
(racket-hash-lang-down ,racket-hash-lang-mode-map)
61+
(racket-hash-lang-C-M-q-dwim ,racket-hash-lang-mode-map)
5462
"Explore"
5563
racket-xp-mode
5664
(racket-xp-describe ,racket-xp-mode-map)
@@ -180,7 +188,11 @@
180188
racket-browse-url-function
181189
racket-xp-after-change-refresh-delay
182190
racket-xp-highlight-unused-regexp
191+
racket-xp-binding-font-lock-face-modes
183192
racket-documentation-search-location
193+
"Hash lang variables"
194+
racket-hash-lang-token-face-alist
195+
racket-hash-lang-module-language-hook
184196
"REPL variables"
185197
racket-repl-buffer-name-function
186198
racket-submodules-to-run
@@ -241,6 +253,12 @@
241253
racket-xp-unused-face
242254
racket-xp-tail-target-face
243255
racket-xp-tail-position-face
256+
racket-xp-binding-lang-face
257+
racket-xp-binding-lang-use-face
258+
racket-xp-binding-import-face
259+
racket-xp-binding-import-use-face
260+
racket-xp-binding-local-face
261+
racket-xp-binding-local-use-face
244262
racket-logger-config-face
245263
racket-logger-topic-face
246264
racket-logger-fatal-face
@@ -251,7 +269,14 @@
251269
racket-doc-link-face
252270
racket-ext-link-face
253271
racket-doc-output-face
254-
racket-doc-litchar-face)
272+
racket-doc-litchar-face
273+
racket-repl-message
274+
racket-repl-prompt
275+
racket-repl-value
276+
racket-repl-error-message
277+
racket-repl-error-location
278+
racket-repl-stdout
279+
racket-repl-stderr)
255280
"Faces to include in the Reference.")
256281

257282
(defun racket-generate--faces ()

doc/racket-mode.org

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#+OPTIONS: ':t toc:t author:t email:t H:4
22

33
#+MACRO: kbd @@texinfo:@kbd{$1}@@ @@html:<kbd>$1</kbd>@@
4-
#+MACRO: img @@texinfo:@image{$1,,,$2. Command I/O via pipe (local) or ssh (remote). REPL I/O via one TCP connection per REPL buffer (local/remote). Each back end provides zero or more REPLs.,.svg}@@
4+
#+MACRO: img @@texinfo:@image{$1,,,$2. Command I/O via pipe (local) or ssh (remote). Each back end provides zero or more REPLs.,.svg}@@
55
#+MACRO: ref @@texinfo:@ref{$1}@@
66
#+MACRO: see @@texinfo:@xref{$1}@@
77

@@ -32,11 +32,13 @@ SPDX-License-Identifier: GPL-3.0-or-later
3232

3333
The [[https://www.racket-mode.com/][Racket Mode]] package consists of a variety of Emacs major and minor modes, including:
3434

35-
- ~racket-mode~: A major mode for editing ~.rkt~ files.
35+
- ~racket-mode~: A major mode to edit ~.rkt~ files. Generally assumes ~#lang racket~.
3636

37-
- {{{ref(racket-xp-mode)}}}: An optional minor mode that enhances ~racket-mode~ to explain and explore code.
37+
- {{{ref(racket-hash-lang-mode)}}}: An alternative to ~racket-mode~ using behavior specified by a ~#lang~ for colors, indent, expression navigation, etc. /Experimental/.
3838

39-
- ~racket-repl-mode~: A major mode for running programs providing a REPL.
39+
- {{{ref(racket-xp-mode)}}}: A minor mode to enhance either edit mode. Explain and explore code, similar to background check-syntax in Dr Racket.
40+
41+
- ~racket-repl-mode~: A major mode to run programs and use a REPL.
4042

4143
- Various other modes to support specific features:
4244
- {{{ref(racket-logger-mode)}}}
@@ -45,7 +47,7 @@ The [[https://www.racket-mode.com/][Racket Mode]] package consists of a variety
4547

4648
For code, issues, and pull requests, see the [[https://github.com/greghendershott/racket-mode][Git repo]].
4749

48-
To fund this work, see [[https://github.com/users/greghendershott/sponsorship][GitHub Sponsors]] or [[https://www.paypal.me/greghendershott][PayPal]].
50+
To sponsor this work, see [[https://github.com/users/greghendershott/sponsorship][GitHub Sponsors]] or [[https://www.paypal.me/greghendershott][PayPal]].
4951

5052
* Install, Update, and Uninstall
5153

@@ -163,6 +165,29 @@ On macOS, downloading Racket doesn't add its ~bin~ directory to your ~PATH~. Eve
163165

164166
You can ~setq~ this directly in your Emacs init file (=~/.emacs= or =~/.emacs.d/init.el=), or, use {{{kbd(M-x)}}} ~customize~, as you prefer.
165167

168+
** Which major mode to use
169+
170+
Racket is a programming language.
171+
172+
Racket is also a "language-oriented programming language". Most Racket source files contain a `#lang` line. The lang may be an s-expression lang like ~racket~, or an at-expression lang like ~scribble/manual~, or something completely different like ~datalog~ or ~rhombus~.
173+
174+
The Racket Mode package offers a choice of two major modes to use in buffers for viewing and editing source code. Each has pros and cons.
175+
176+
Whereas ~racket-mode~ is in the tradition of Emacs ~lisp-mode~ and ~scheme-mode~ and assumes s-expression langs, ~racket-hash-lang-mode~ takes the approach of DrRacket to work for all langs.
177+
178+
- ~racket-mode~ is the original, "classic" mode for ~#lang racket~ and related s-expression languages. It is implemented entirely in Emacs and does /not/ need Racket Mode's back end racket process running. Font-lock (coloring) uses rules for a fixed set of identifiers from ~racket~ lang and popular modules like ~racket/match~. Indentation uses rules for a fixed set of forms, and may be customized (see below).
179+
180+
- ~racket-hash-lang-mode~ uses font-lock (colors) and indentation determined by the lang; to get this information it /does/ need the Racket Mode's back end racket process running. Although basic editing should feel fast, you might notice some delay when indenting. You might see colors appear after a small delay (but it will not block editing). Speaking of colors, they will be "plainer" than ~racket-mode~ -- mostly just for different kinds of tokens like numbers, comments, strings, and keywords. This looks similar to DrRacket. However if you /also/ enable the minor mode ~racket-xp-mode~, it will eventually add more colors at definition and use sites, and vary the colors depending on whether the identifier is local, imported, or from the module language. So you may see the "syntax" highlighting appear fairly quickly from ~racket-hash-lang-mode~, and later see more "semantic" highlighting contributed by ~racket-xp-mode~. The end result will be about as rich, although not exactly the same, as ~racket-mode~.
181+
182+
You can use different major modes for different kinds of files:
183+
184+
- For editing ~.rkt~ files and s-expression langs, which mode to use is personal preference.
185+
186+
- For ~.scrbl~ and at-expression langs like ~scribble/manual~, ~racket-hash-lang-mode~ is probably better than ~racket-mode~. (Note there is also an unrelated ~scribble-mode~ package.)
187+
188+
- For non-s-expression langs like ~datalog~ or ~rhombus~ (~.rhm~), ~racket-hash-lang-mode~ is definitely better than ~racket-mode~. (Note there is also an unrelated ~rhombus-mode~ package.)
189+
190+
You can use ~auto-mode-alist~ to tell Emacs which major mode to use initially for certain file extensions. Also, in a buffer you can use ~M-x racket-mode~ and ~M-x racket-hash-lang-mode~ to switch between them.
166191
** Key bindings
167192

168193
To customize things like key bindings, you can use ~racket-mode-hook~ in your Emacs init file to modify ~racket-mode-map~. For example, although {{{kbd(C-c C-c)}}} is bound by default to the ~racket-run~ command, let's say you wanted {{{kbd(F5)}}} to be an additional binding:
@@ -171,13 +196,16 @@ To customize things like key bindings, you can use ~racket-mode-hook~ in your Em
171196
(add-hook 'racket-mode-hook
172197
(lambda ()
173198
(define-key racket-mode-map (kbd "<f5>") 'racket-run)))
174-
175199
#+END_SRC
176200

177201
Likewise for ~racket-repl-mode-hook~ and ~racket-repl-mode-map~.
178202

179203
** Font-lock (syntax highlighting)
180204

205+
#+BEGIN_QUOTE
206+
Note: The alternative major mode {{{ref(racket-hash-lang-mode)}}} disables all of the following behavior and uses colors determined by the #lang.
207+
#+END_QUOTE
208+
181209
Font-lock (as Emacs calls syntax highlighting) can be controlled using the variable ~font-lock-maximum-decoration~, which defaults to ~t~ (maximum). You can set it to a number, where ~0~ is the lowest level. You can even supply an association list to specify different values for different major modes.
182210

183211
Historically you might choose a lower level for speed. These days you might do so because you prefer a simpler appearance.
@@ -249,12 +277,20 @@ In any case, using the Emacs xref API allows for consistent command names, short
249277

250278
** Indent
251279

280+
#+BEGIN_QUOTE
281+
Note: The alternative major mode {{{ref(racket-hash-lang-mode)}}} disables all of the following behavior and uses indentation determined by the #lang.
282+
#+END_QUOTE
283+
252284
Indentation can be customized in a way similar to lisp-mode and scheme-mode: {{{ref(racket-indent-line)}}}.
253285

254286
(Indentation preserves your line breaks. If you want to use an auto-reformatter --- an expressive pretty printer that chooses line breaks while computing an optimal layout --- the Racket package [[https://docs.racket-lang.org/fmt/][fmt]] is supported by the Emacs package [[https://github.com/lassik/emacs-format-all-the-code][emacs-format-all-the-code]].)
255287

256288
** paredit
257289

290+
#+BEGIN_QUOTE
291+
Note: If you use {{{ref(racket-hash-lang-mode)}}}, you can use ~racket-hash-lang-mode-hook~ to enable/disable paredit based on the specific #lang.
292+
#+END_QUOTE
293+
258294
If you use [[https://melpa.org/#/paredit][paredit]], you might want to add keybindings to ~paredit-mode-map~:
259295

260296
- Bind the curly brace keys to ~paredit-open-curly~ and ~paredit-close-curly~.

0 commit comments

Comments
 (0)