1
1
; ;; racket-repl.el -*- lexical-binding : t ; -*-
2
2
3
- ; ; Copyright (c) 2013-2018 by Greg Hendershott.
3
+ ; ; Copyright (c) 2013-2019 by Greg Hendershott.
4
4
; ; Portions Copyright (C) 1985-1986, 1999-2013 Free Software Foundation, Inc.
5
5
; ; Image portions Copyright (C) 2012 Jose Antonio Ortega Ruiz.
6
6
@@ -258,15 +258,9 @@ used. See the latter for more information."
258
258
(when display
259
259
(display-buffer (current-buffer )))
260
260
(message " Starting %s to run %s ... " racket-program run.rkt)
261
- ; ; Ensure command server connection closed when racket process dies.
262
- (set-process-sentinel proc
263
- (lambda (_proc event )
264
- (with-racket-repl-buffer
265
- (insert (concat " Process Racket REPL " event)))
266
- (racket--cmd-disconnect)))
267
261
(set-process-coding-system proc 'utf-8 'utf-8 ) ; for e.g. λ
268
262
(racket-repl-mode)))))
269
- (unless (racket--cmd-connected -or-connecting-p)
263
+ (unless (racket--cmd-open -or-connecting-p)
270
264
(racket--cmd-connect-start)))
271
265
272
266
(defun racket--version ()
@@ -292,10 +286,15 @@ used. See the latter for more information."
292
286
; ;; Connection to command process
293
287
294
288
(defvar racket--cmd-proc nil
295
- " Process when connection to the command server is established." )
296
- (defvar racket--cmd-buf nil
297
- " Process buffer when connection to the command server is established." )
298
- (defvar racket--cmd-connecting-p nil )
289
+ " Process for talking to the command server.
290
+ Use `racket--cmd-open-p' to check if it is non-nil and in an
291
+ 'open state." )
292
+
293
+ (defvar racket--cmd-connecting-p nil
294
+ " True while a series of connection attempts is underway.
295
+ See `racket--cmd-connect-start' and`racket--cmd-connect-finish' .
296
+ Used to guard against starting more than one series of connection
297
+ attempts at once." )
299
298
300
299
(defvar racket--cmd-nonce->callback (make-hash-table :test 'eq )
301
300
" A hash from nonce to callback function." )
@@ -305,76 +304,90 @@ used. See the latter for more information."
305
304
(defvar racket--cmd-connect-attempts 15 )
306
305
(defvar racket--cmd-connect-timeout 15 )
307
306
308
- (defun racket--cmd-connected-or-connecting-p ()
309
- (and (or racket--cmd-proc racket--cmd-connecting-p) t ))
310
-
311
- (defun racket--cmd-connect-start (&optional attempt )
312
- " Start to connect to the Racket command process.
313
-
314
- If already connected, disconnects first.
315
-
316
- The command server may might not be ready to accept connections,
317
- because Racket itself and our backend are still starting up.
318
- After calling this, call `racket--cmd-connect-finish' to
319
- wait for the connection to be established."
307
+ (defun racket--cmd-open-p ()
308
+ (and racket--cmd-proc
309
+ (eq 'open (process-status racket--cmd-proc))))
310
+
311
+ (defun racket--cmd-open-or-connecting-p ()
312
+ (or (racket--cmd-open-p)
313
+ racket--cmd-connecting-p))
314
+
315
+ (defun racket--cmd-connect-start ()
316
+ " Start a series of attempts to connect to the Racket command process.
317
+
318
+ The command server might not be ready to accept connections,
319
+ because Racket itself and our backend are still starting up. We
320
+ don't want to block Emacs while waiting. Instead: Call this to
321
+ start a series of connection attempts that will \" happen in the
322
+ background\" at intervals using `run-with-timer' . After this
323
+ returns, then later when eventually something really must wait
324
+ for the connection, to issue a command, call
325
+ `racket--cmd-connect-finish' "
320
326
(unless (featurep 'make-network-process '(:nowait t ))
321
327
(error " racket-mode needs Emacs to support the :nowait feature " ))
322
- (let ((attempt (or attempt 1 )))
323
- (when (= attempt 1 )
324
- (racket--cmd-disconnect)
325
- (setq racket--cmd-connecting-p t ))
326
- (make-network-process
327
- :name " racket-command"
328
- :host " 127.0.0.1"
329
- :service racket-command-port
330
- :nowait t
331
- :sentinel
332
- (lambda (proc event )
333
- ; ;(message "sentinel process %S event %S attempt %s" proc event attempt)
334
- (cond
335
- ((string-match-p " ^open" event)
336
- (setq racket--cmd-proc proc)
337
- (setq racket--cmd-buf (generate-new-buffer
338
- (concat " " (process-name proc))))
339
- (buffer-disable-undo racket--cmd-buf)
340
- (set-process-filter proc #'racket--cmd-process-filter )
341
- (process-send-string proc (concat racket--cmd-auth " \n " ))
342
- (message " Connected to %s process on port %s after %s attempt(s) "
343
- proc racket-command-port attempt))
344
- ((string-match-p " ^failed" event)
345
- (delete-process proc)
346
- (when (<= attempt racket--cmd-connect-attempts)
347
- (run-at-time 1.0 nil
348
- #'racket--cmd-connect-start
349
- (1+ attempt))))
350
- (t (racket--cmd-disconnect)))))))
328
+ (when (racket--cmd-open-p)
329
+ (error " racket--cmd-proc already open " ))
330
+ (when racket--cmd-connecting-p
331
+ (error " already in a series attempts to connect to racket command process " ))
332
+ (setq racket--cmd-connecting-p t )
333
+ (racket--cmd-connect-attempt 1 ))
334
+
335
+ (defun racket--cmd-connect-attempt (attempt )
336
+ " Only for use by `racket--cmd-connect-start' ."
337
+ (setq
338
+ racket--cmd-proc
339
+ (make-network-process
340
+ :name " racket-command"
341
+ :host " 127.0.0.1"
342
+ :service racket-command-port
343
+ :nowait t
344
+ :sentinel
345
+ (lambda (proc event )
346
+ ; ;(message "sentinel got (%S %S) [attempt %s]" proc event attempt)
347
+ (cond ((string-match-p " ^open" event)
348
+ (let ((buf (generate-new-buffer (concat " *" (process-name proc) " *" ))))
349
+ (set-process-buffer proc buf)
350
+ (buffer-disable-undo buf))
351
+ (set-process-filter proc #'racket--cmd-process-filter )
352
+ (process-send-string proc (concat racket--cmd-auth " \n " ))
353
+ (setq racket--cmd-connecting-p nil )
354
+ (message " Connected to %s process on port %s after %s attempt(s) "
355
+ proc racket-command-port attempt))
356
+
357
+ ((string-match-p " ^failed" event)
358
+ (delete-process proc) ; we'll get called with "deleted" event, below
359
+ (if (<= attempt racket--cmd-connect-attempts)
360
+ (run-at-time 1.0 nil
361
+ #'racket--cmd-connect-attempt
362
+ (1+ attempt))
363
+ (setq racket--cmd-connecting-p nil )))
364
+
365
+ ((or (string-match-p " ^deleted" event)
366
+ (string-match-p " ^connection broken by remote peer" event))
367
+ (clrhash racket--cmd-nonce->callback))
368
+
369
+ (t (message " sentinel surprised by (%S %S ) [attempt %s ] " proc event attempt)))))))
351
370
352
371
(defun racket--cmd-connect-finish ()
372
+ " Call this to wait for the series of connection attempts to complete."
373
+ ; ; Important: Every flow path must set `racket--cmd-connecting-p'
374
+ ; ; back to nil. For example: 1. Do so before calling `error' . 2. Use
375
+ ; ; `inhibit-quit' to handle the user getting tired of waiting and
376
+ ; ; pressing C-g.
353
377
(with-timeout (racket--cmd-connect-timeout
354
378
(setq racket--cmd-connecting-p nil )
355
379
(error " Could not connect to racket-command process on port %s "
356
380
racket-command-port))
357
- (while (not racket--cmd-proc)
358
- (message " Still trying to connect to racket-command process on port %s ... "
359
- racket-command-port)
360
- (sit-for 0.2 ))
361
- (setq racket--cmd-connecting-p nil )))
362
-
363
- (defun racket--cmd-disconnect ()
364
- " Disconnect from the Racket command process."
365
- (setq racket--cmd-connecting-p nil )
366
- (when racket--cmd-proc
367
- ; ; Sentinel calls us for "deleted" event, which we ourselves will
368
- ; ; trigger with the `delete-process' below. So set
369
- ; ; racket--cmd-proc nil before calling `delete-process' .
370
- (let ((proc (prog1 racket--cmd-proc (setq racket--cmd-proc nil )))
371
- (buf (prog1 racket--cmd-buf (setq racket--cmd-buf nil ))))
372
- (delete-process proc)
373
- (kill-buffer buf)
374
- (clrhash racket--cmd-nonce->callback))))
375
-
376
- (defun racket--cmd-process-filter (_proc string )
377
- (let ((buffer racket--cmd-buf))
381
+ (let ((inhibit-quit t ))
382
+ (while (and (not quit-flag)
383
+ (not (racket--cmd-open-p)))
384
+ (message " Still trying to connect to racket-command process on port %s ... "
385
+ racket-command-port)
386
+ (sit-for 0.2 ))
387
+ (setq racket--cmd-connecting-p nil ))))
388
+
389
+ (defun racket--cmd-process-filter (proc string )
390
+ (let ((buffer (process-buffer proc)))
378
391
(when (buffer-live-p buffer)
379
392
(with-current-buffer buffer
380
393
(goto-char (point-max ))
@@ -425,6 +438,8 @@ form."
425
438
(when (and callback
426
439
(not (equal callback #'ignore )))
427
440
(puthash racket--cmd-nonce callback racket--cmd-nonce->callback))
441
+ (unless (racket--cmd-open-p)
442
+ (error " racket command process not open " ))
428
443
(process-send-string racket--cmd-proc
429
444
(format " %S \n " (cons racket--cmd-nonce
430
445
command-sexpr))))
0 commit comments