Some changes are not a reload, and saying so is the feature
A struct whose layout moved cannot be installed into a program built with the old one, and the daemon says so. There is no smaller answer than a rebuild: a session's layouts and global types describe a process only if that session compiled it, so the program and everything in its memory go too. That is the cost, and it is why this is its own command and not something C-c C-c falls back to. Emacs owns the daemon now, so this is stop-and-start rather than a new op. The old one is waited out first: it unlinks the socket as it leaves and would otherwise take its successor's with it. Also: quitting a daemon that would not close now says its program may have outlived it, because killing the daemon skips the cleanup that signals the child — and C-c C-v rather than C-c C-h for the doc buffer, which was shadowing the way anyone discovers what is under C-c.
This commit is contained in:
parent
76f84071df
commit
aee8a032b1
@ -345,6 +345,11 @@ socket at all and this buffer is the only account of why."
|
||||
It builds the program first, which for a cold project is most of this."
|
||||
:type 'number)
|
||||
|
||||
(defvar flan-dev--file nil
|
||||
"The program the daemon this Emacs started was started on, or nil.
|
||||
Kept so that it can be started again on the same program and the same
|
||||
socket, which is what `flan-dev-restart-program' is.")
|
||||
|
||||
(defvar flan-dev--daemon nil
|
||||
"The `flan dev' process this Emacs started, or nil.
|
||||
A daemon started in a terminal is not here, and `flan-connect' still works
|
||||
@ -432,6 +437,7 @@ which is the one thing a dev loop exists to avoid doing by accident."
|
||||
(file-name-directory file)))))
|
||||
(unless (file-exists-p file)
|
||||
(user-error "flan dev: no such file: %s" file))
|
||||
(setq flan-dev--file file)
|
||||
(setq flan-dev--daemon (flan-dev--start-daemon file socket))
|
||||
(flan-dev--connect-when-ready socket flan-dev--daemon)
|
||||
;; Connected by now, so the rest is what `flan-connect' does after opening:
|
||||
@ -474,11 +480,44 @@ socket; the process is killed only if it does not take it."
|
||||
(while (and (process-live-p proc) (< (float-time) deadline))
|
||||
(accept-process-output proc 0.05)))
|
||||
(when (process-live-p proc)
|
||||
(delete-process proc)))
|
||||
;; Killed rather than asked, so its own cleanup never runs — and that
|
||||
;; cleanup is what signals the program. The program is therefore
|
||||
;; probably still running, reparented, holding its agent socket, and
|
||||
;; saying "stopped" here would be the one place in this client where
|
||||
;; a success message meant "probably".
|
||||
(delete-process proc)
|
||||
(setq flan-dev--daemon nil)
|
||||
(force-mode-line-update t)
|
||||
(user-error
|
||||
"flan dev: the daemon would not close and was killed; its program may still be running")))
|
||||
(setq flan-dev--daemon nil)
|
||||
(force-mode-line-update t)
|
||||
(message "flan dev: stopped")))
|
||||
|
||||
;;;###autoload
|
||||
(defun flan-dev-restart-program ()
|
||||
"Stop the program this Emacs started and start it again from source.
|
||||
|
||||
For a change the running program cannot take: a struct whose layout moved, a
|
||||
function whose signature changed, anything the daemon refuses by telling you
|
||||
to restart. There is no smaller version of this. A session's struct layouts
|
||||
and global types describe the memory of a process only if that session
|
||||
compiled it, so a new layout means a new build, which means a new process and
|
||||
the session that made it — and the program's state goes with it, which is the
|
||||
whole cost and the reason this is a separate command rather than something
|
||||
`C-c C-c' falls back to.
|
||||
|
||||
The old daemon is waited for before the new one starts, because it unlinks
|
||||
the socket on its way out and would otherwise unlink the one its successor
|
||||
had just bound."
|
||||
(interactive)
|
||||
(unless (process-live-p flan-dev--daemon)
|
||||
(user-error "flan dev: no daemon started from Emacs to restart"))
|
||||
(let ((file flan-dev--file)
|
||||
(socket flan-dev--socket))
|
||||
(flan-dev-quit) ; returns only once it is really gone
|
||||
(flan-dev file socket)))
|
||||
|
||||
;;; The modeline
|
||||
|
||||
;; Whether there is a program on the other end is the one thing worth a
|
||||
|
||||
@ -121,8 +121,10 @@ line is off screen."
|
||||
(define-key map (kbd "C-c C-b") #'flan-break)
|
||||
;; Help on the name at point. C-c C-d is taken by `flan-describe', which
|
||||
;; is about the session rather than about a name, and renaming a key that
|
||||
;; is already documented costs more than it is worth.
|
||||
(define-key map (kbd "C-c C-h") #'flan-doc)
|
||||
;; is already documented costs more than it is worth. Not C-c C-h either:
|
||||
;; C-h after a prefix is how anyone finds out what is under C-c, and a
|
||||
;; binding there takes that away.
|
||||
(define-key map (kbd "C-c C-v") #'flan-doc)
|
||||
map)
|
||||
"Keymap for `flan-mode'.")
|
||||
|
||||
|
||||
@ -537,6 +537,25 @@ is written instead — the real `message' call the real command makes."
|
||||
(and raised (string-match-p "already running" raised))))
|
||||
;; The daemon owns the program's lifetime, so quitting has to actually end
|
||||
;; the process — not just drop the socket and leave it running.
|
||||
;; Restarting the program: for a change the running one cannot take — a
|
||||
;; struct whose layout moved — where the answer is a new build, a new
|
||||
;; process and the session that compiled it. Proved by what it throws
|
||||
;; away: a name installed into the old program is not in the new one.
|
||||
(flan-dev--eval "(defn only-in-the-old-program [] i64 1)" "form")
|
||||
(test-flan--check "a name installed into the running program is there"
|
||||
(assoc "only-in-the-old-program" flan-dev--defs))
|
||||
(let ((old flan-dev--daemon))
|
||||
(flan-dev-restart-program)
|
||||
(test-flan--check "restarting gives a different daemon, connected"
|
||||
(and (not (process-live-p old))
|
||||
(process-live-p flan-dev--daemon)
|
||||
(not (eq old flan-dev--daemon))
|
||||
(eq (flan-dev-state) 'live))))
|
||||
(test-flan--check "and a program built from source, without the addition"
|
||||
(and (assoc "step" flan-dev--defs)
|
||||
(null (assoc "only-in-the-old-program"
|
||||
flan-dev--defs))))
|
||||
|
||||
(let ((proc flan-dev--daemon))
|
||||
(flan-dev-quit)
|
||||
;; The process, not the variable: forgetting a daemon is not stopping
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user