|
1 |
| -;; Copyright (c) 2013-2022 by Greg Hendershott. |
| 1 | +;; Copyright (c) 2013-2025 by Greg Hendershott. |
2 | 2 | ;; SPDX-License-Identifier: GPL-3.0-or-later.
|
3 | 3 |
|
4 | 4 | #lang racket/base
|
5 | 5 |
|
| 6 | +;; This module acts as a "shim" or "launcher" for command-server.rkt. |
| 7 | +;; |
| 8 | +;; We dynamic-require command-server.rkt within an exn handler for |
| 9 | +;; missing modules, to provide a better error UX when people are using |
| 10 | +;; Minimal Racket; see issue #744. Any such error is written to stdout |
| 11 | +;; as a "notification" for the Emacs front end, which can display it |
| 12 | +;; in a dedicated buffer. Not only is this better than error text |
| 13 | +;; flashing by in the echo bar and hiding in the *Messages* buffer, |
| 14 | +;; our dedicated can supply a browse-url button to our docs section |
| 15 | +;; about Minimal Racket. |
| 16 | +;; |
| 17 | +;; Note that the exn handler is active only during the dynamic extent |
| 18 | +;; of the dynamic-require to extract the command-server-loop function. |
| 19 | +;; Subsequently we call that function without any such handler in |
| 20 | +;; effect. |
| 21 | +;; |
| 22 | +;; Use the same notification mechanism for other back end startup |
| 23 | +;; failures, such as when they need a newer version of Racket. |
| 24 | + |
| 25 | +;; Limit imports to those supplied by Minimal Racket! |
6 | 26 | (require racket/match
|
7 |
| - racket/port |
| 27 | + (only-in racket/port open-output-nowhere) |
| 28 | + racket/runtime-path |
8 | 29 | (only-in racket/string string-trim)
|
9 | 30 | (only-in racket/system system/exit-code)
|
10 | 31 | version/utils
|
11 |
| - "command-server.rkt" |
12 | 32 | (only-in "image.rkt" set-use-svg?!))
|
13 | 33 |
|
| 34 | +;; Write a "notification" for the Emacs front end and exit. |
| 35 | +(define (notify/exit kind data) |
| 36 | + (writeln `(startup-error ,kind ,data)) |
| 37 | + (flush-output) |
| 38 | + (exit 13)) |
| 39 | + |
14 | 40 | (define (assert-racket-version minimum-version)
|
15 | 41 | (define actual-version (version))
|
16 | 42 | (unless (version<=? minimum-version actual-version)
|
17 |
| - (error '|Racket Mode back end| "Need Racket ~a or newer but ~a is ~a" |
18 |
| - minimum-version |
19 |
| - (find-executable-path (find-system-path 'exec-file)) |
20 |
| - actual-version))) |
| 43 | + (notify/exit |
| 44 | + 'other |
| 45 | + (format "Racket Mode needs Racket ~a or newer but ~a is ~a." |
| 46 | + minimum-version |
| 47 | + (find-executable-path (find-system-path 'exec-file)) |
| 48 | + actual-version)) |
| 49 | + (flush-output) |
| 50 | + (exit 14))) |
21 | 51 |
|
22 | 52 | (define (macos-sequoia-or-newer?)
|
23 | 53 | (and (eq? 'macosx (system-type 'os))
|
|
40 | 70 | [(vector "--use-svg" ) (set-use-svg?! #t)]
|
41 | 71 | [(vector "--do-not-use-svg") (set-use-svg?! #f)]
|
42 | 72 | [v
|
43 |
| - (error '|Racket Mode back end| |
44 |
| - "Bad command-line arguments:\n~s\n" v)]) |
| 73 | + (notify/exit |
| 74 | + 'other |
| 75 | + (format "Bad command-line arguments:\n~s\n" v))]) |
| 76 | + |
| 77 | + (define-runtime-path command-server.rkt "command-server.rkt") |
| 78 | + (define command-server-loop |
| 79 | + (with-handlers ([exn:fail:syntax:missing-module? |
| 80 | + (λ (e) |
| 81 | + (notify/exit |
| 82 | + 'missing-module |
| 83 | + (format "~a" (exn:fail:syntax:missing-module-path e))))]) |
| 84 | + (dynamic-require command-server.rkt 'command-server-loop))) |
45 | 85 |
|
46 | 86 | ;; Save original current-{input output}-port to give to
|
47 |
| - ;; command-server-loop for command I/O. |
| 87 | + ;; command-server-loop for command I/O ... |
48 | 88 | (let ([stdin (current-input-port)]
|
49 | 89 | [stdout (current-output-port)])
|
50 |
| - ;; Set no-ops so e.g. rando print can't bork the command I/O. |
| 90 | + ;; ... and set no-ops so rando print can't bork the command I/O. |
51 | 91 | (parameterize ([current-input-port (open-input-bytes #"")]
|
52 | 92 | [current-output-port (open-output-nowhere)])
|
53 | 93 | (command-server-loop stdin stdout))))
|
0 commit comments