diff --git a/emacs/MANUAL.md b/emacs/MANUAL.md index a33c335..d1a7e04 100644 --- a/emacs/MANUAL.md +++ b/emacs/MANUAL.md @@ -30,9 +30,34 @@ works without dape installed, and `C-c C-g` only exists once you load it. (require 'flan-dape) ; only if you have dape ``` +Or install it as a package, which gets you autoloads and byte-compiled files +without a `load-path` line. `package-install-file` names the package after the +directory, so the directory has to be called `flan-mode` — symlink it once and +point Emacs at the link: + +```sh +ln -s ~/Development/flan/emacs ~/.emacs.d/flan-mode +``` + +``` +M-x package-install-file RET ~/.emacs.d/flan-mode/ RET +``` + +Every file carries `Version:` and `Package-Requires: ((emacs "29.1"))`, which is +what package.el reads. dape is deliberately not in that list: `flan-dape.el` +reaches it through `declare-function`, so everything else installs and works +without it. + You also need the `flan` binary on your `PATH`. If it is somewhere else, set `flan-dev-command`. +Two settings worth knowing about before you need them. `flan-dev-start-timeout` +(60s) bounds the wait for a daemon to come up, and `flan-dev-reply-timeout` +(30s) bounds one request once it has. The second is the one a long first +compile can exhaust: the message says so and names `*flan-dev*`, where the +daemon's own build log is, so you can see whether it is still working before +you raise it. + --- ## Starting a program diff --git a/emacs/flan-cnr.el b/emacs/flan-cnr.el index 73e645f..b8fe4ec 100644 --- a/emacs/flan-cnr.el +++ b/emacs/flan-cnr.el @@ -1,5 +1,24 @@ ;;; flan-cnr.el --- What a stopped program is offering -*- lexical-binding: t; -*- +;; Author: Joseph Ferano +;; Version: 0.1.0 +;; Package-Requires: ((emacs "29.1")) +;; Keywords: languages, lisp, tools + +;; The headers above are what make this directory installable. M-x +;; package-install-file on it reads them, and a file with no Version: is not a +;; package as far as package.el is concerned -- until now the client was +;; reachable only by adding it to load-path by hand, which is a thing to +;; explain to every person who wants to try it. +;; +;; 29.1 is the floor because it is the oldest Emacs any of this has been run +;; against, not because some function here is known to need it. dape, which +;; flan-dape drives, asks for 29.1 as well and is a soft dependency: it is +;; reached through declare-function, so the rest of the client loads and works +;; without it and it is deliberately not listed above. The compiler this talks +;; to is not an Emacs package and cannot be listed here either -- emacs/MANUAL.md +;; says what has to be on PATH. + ;; `C-c C-b' is a `completing-read' over restart names. That is the whole UI ;; for the one moment the dev loop exists to make survivable, and it is thin in ;; a way that is worth being specific about: it shows the names and nothing diff --git a/emacs/flan-dape.el b/emacs/flan-dape.el index 9ab2b31..8371604 100644 --- a/emacs/flan-dape.el +++ b/emacs/flan-dape.el @@ -1,5 +1,24 @@ ;;; flan-dape.el --- Debug a Flan program with dape and lldb-dap -*- lexical-binding: t; -*- +;; Author: Joseph Ferano +;; Version: 0.1.0 +;; Package-Requires: ((emacs "29.1")) +;; Keywords: languages, lisp, tools + +;; The headers above are what make this directory installable. M-x +;; package-install-file on it reads them, and a file with no Version: is not a +;; package as far as package.el is concerned -- until now the client was +;; reachable only by adding it to load-path by hand, which is a thing to +;; explain to every person who wants to try it. +;; +;; 29.1 is the floor because it is the oldest Emacs any of this has been run +;; against, not because some function here is known to need it. dape, which +;; flan-dape drives, asks for 29.1 as well and is a soft dependency: it is +;; reached through declare-function, so the rest of the client loads and works +;; without it and it is deliberately not listed above. The compiler this talks +;; to is not an Emacs package and cannot be listed here either -- emacs/MANUAL.md +;; says what has to be on PATH. + ;; The other half of the dev loop. flan-dev.el is about a program that keeps ;; running while you change it; this is about stopping one and reading it. ;; diff --git a/emacs/flan-dev.el b/emacs/flan-dev.el index bbee9e7..1586a26 100644 --- a/emacs/flan-dev.el +++ b/emacs/flan-dev.el @@ -1,5 +1,24 @@ ;;; flan-dev.el --- Talk to a running Flan program -*- lexical-binding: t; -*- +;; Author: Joseph Ferano +;; Version: 0.1.0 +;; Package-Requires: ((emacs "29.1")) +;; Keywords: languages, lisp, tools + +;; The headers above are what make this directory installable. M-x +;; package-install-file on it reads them, and a file with no Version: is not a +;; package as far as package.el is concerned -- until now the client was +;; reachable only by adding it to load-path by hand, which is a thing to +;; explain to every person who wants to try it. +;; +;; 29.1 is the floor because it is the oldest Emacs any of this has been run +;; against, not because some function here is known to need it. dape, which +;; flan-dape drives, asks for 29.1 as well and is a soft dependency: it is +;; reached through declare-function, so the rest of the client loads and works +;; without it and it is deliberately not listed above. The compiler this talks +;; to is not an Emacs package and cannot be listed here either -- emacs/MANUAL.md +;; says what has to be on PATH. + ;; The editor half of Flan's dev loop. `flan dev program.flan' compiles the ;; program, launches it, and listens on .flan-dev.sock beside the source; this ;; connects to that socket and sends it forms. M-x flan-dev starts that @@ -77,6 +96,29 @@ that quietly did nothing, which is why it is on." "Buffer the running program's own output is appended to." :type 'string) +(defcustom flan-dev-daemon-buffer "*flan-dev*" + "Buffer the daemon's own output goes to. +This is where a build that failed says so: the daemon compiles the program +before it binds its socket, so a program that does not compile produces no +socket at all and this buffer is the only account of why. It is also where a +build that is merely slow can be watched, which is what the reply timeout +below points at." + :type 'string) + +(defcustom flan-dev-reply-timeout 30 + "Seconds to wait for one reply from the daemon before giving up. + +This bounds a single request, not a session. Thirty seconds is generous +for an evaluation and tight for a first compile of a large program on a +cold object cache, which is the one case that legitimately runs long — so +it is a setting rather than a constant. + +Giving up here never resends. If the daemon took the request and died +before replying the evaluation may well already have happened, and sending +it again would install a body twice or run a side-effecting expression +twice; reconnecting happens before a send and never after one." + :type 'number) + (defvar flan-dev--connection nil "The open connection, or nil.") @@ -149,7 +191,7 @@ Point is in the process buffer, and the frame is known to be complete." (defun flan-dev--read-reply (proc) "Block until PROC sends one complete framed message, and read it." (with-current-buffer (process-buffer proc) - (let ((deadline (+ (float-time) 30))) + (let ((deadline (+ (float-time) flan-dev-reply-timeout))) ;; The header first: digits up to a newline. (while (and (not (save-excursion (goto-char (point-min)) (re-search-forward "\\`\\([0-9]+\\)\n" nil t))) @@ -161,9 +203,17 @@ Point is in the process buffer, and the frame is known to be complete." ;; before replying, the evaluation may well have happened — sending it ;; again would install it twice, or run a side-effecting expression ;; twice. Reconnecting happens before a send, never after one. + ;; What a person does next, not just what failed. A live daemon that + ;; has not answered is nearly always still working — a first compile + ;; of a large program on a cold object cache is the case that runs + ;; long — and the daemon's own log says which step it is on, so the + ;; message names the buffer to look in and the setting to raise + ;; rather than leaving both to be discovered. (if (process-live-p proc) - (error "flan dev: no reply in 30s from %s" - (abbreviate-file-name (or flan-dev--socket "the daemon"))) + (error "flan dev: no reply in %ss from %s; the daemon may still be building — see %s for its log, and raise `flan-dev-reply-timeout' if this build is simply long" + flan-dev-reply-timeout + (abbreviate-file-name (or flan-dev--socket "the daemon")) + flan-dev-daemon-buffer) (error "flan dev: the daemon on %s closed the connection; not resent, because it may already have run" (abbreviate-file-name (or flan-dev--socket "?"))))) @@ -511,12 +561,10 @@ With no argument, look for `flan-dev-socket-name' up from this buffer." A name is looked up on `exec-path'; a path is used as given." :type 'string) -(defcustom flan-dev-daemon-buffer "*flan-dev*" - "Buffer the daemon's own output goes to. -This is where a build that failed says so: the daemon compiles the program -before it binds its socket, so a program that does not compile produces no -socket at all and this buffer is the only account of why." - :type 'string) +;; `flan-dev-daemon-buffer' belongs to this section and is declared with the +;; other buffer names at the top of the file instead, because the reply reader +;; -- which runs long before any of this -- names it in the message it gives +;; when a request times out, and the byte-compiler reads a file in order. (defcustom flan-dev-start-timeout 60 "Seconds to wait for a daemon started from Emacs to accept a connection. diff --git a/emacs/flan-inspect.el b/emacs/flan-inspect.el index c77d2e1..9e065bd 100644 --- a/emacs/flan-inspect.el +++ b/emacs/flan-inspect.el @@ -1,5 +1,24 @@ ;;; flan-inspect.el --- Navigate a running program's values -*- lexical-binding: t; -*- +;; Author: Joseph Ferano +;; Version: 0.1.0 +;; Package-Requires: ((emacs "29.1")) +;; Keywords: languages, lisp, tools + +;; The headers above are what make this directory installable. M-x +;; package-install-file on it reads them, and a file with no Version: is not a +;; package as far as package.el is concerned -- until now the client was +;; reachable only by adding it to load-path by hand, which is a thing to +;; explain to every person who wants to try it. +;; +;; 29.1 is the floor because it is the oldest Emacs any of this has been run +;; against, not because some function here is known to need it. dape, which +;; flan-dape drives, asks for 29.1 as well and is a soft dependency: it is +;; reached through declare-function, so the rest of the client loads and works +;; without it and it is deliberately not listed above. The compiler this talks +;; to is not an Emacs package and cannot be listed here either -- emacs/MANUAL.md +;; says what has to be on PATH. + ;; `C-x C-e' renders a value once and puts it in the echo area. This is the ;; interactive version of the same walk: the fields laid out one per line, RET ;; to go into one, `l' to come back, `g' to read it again. CIDER's inspector, diff --git a/emacs/flan-lower.el b/emacs/flan-lower.el index cd20c29..e289302 100644 --- a/emacs/flan-lower.el +++ b/emacs/flan-lower.el @@ -1,5 +1,24 @@ ;;; flan-lower.el --- Every lowering of one function, in one buffer -*- lexical-binding: t; -*- +;; Author: Joseph Ferano +;; Version: 0.1.0 +;; Package-Requires: ((emacs "29.1")) +;; Keywords: languages, lisp, tools + +;; The headers above are what make this directory installable. M-x +;; package-install-file on it reads them, and a file with no Version: is not a +;; package as far as package.el is concerned -- until now the client was +;; reachable only by adding it to load-path by hand, which is a thing to +;; explain to every person who wants to try it. +;; +;; 29.1 is the floor because it is the oldest Emacs any of this has been run +;; against, not because some function here is known to need it. dape, which +;; flan-dape drives, asks for 29.1 as well and is a soft dependency: it is +;; reached through declare-function, so the rest of the client loads and works +;; without it and it is deliberately not listed above. The compiler this talks +;; to is not an Emacs package and cannot be listed here either -- emacs/MANUAL.md +;; says what has to be on PATH. + ;; `spike/x86/dump.sh' prints four lowerings of one function side by side -- ;; the LLVM IR the frontend emits, what `llc' makes of it at -O0 and at -O2, ;; and what the hand-written x86 backend emits. Reading one against another is diff --git a/emacs/flan-mode.el b/emacs/flan-mode.el index 491c1ff..8309bd0 100644 --- a/emacs/flan-mode.el +++ b/emacs/flan-mode.el @@ -1,5 +1,24 @@ ;;; flan-mode.el --- Major mode for Flan -*- lexical-binding: t; -*- +;; Author: Joseph Ferano +;; Version: 0.1.0 +;; Package-Requires: ((emacs "29.1")) +;; Keywords: languages, lisp, tools + +;; The headers above are what make this directory installable. M-x +;; package-install-file on it reads them, and a file with no Version: is not a +;; package as far as package.el is concerned -- until now the client was +;; reachable only by adding it to load-path by hand, which is a thing to +;; explain to every person who wants to try it. +;; +;; 29.1 is the floor because it is the oldest Emacs any of this has been run +;; against, not because some function here is known to need it. dape, which +;; flan-dape drives, asks for 29.1 as well and is a soft dependency: it is +;; reached through declare-function, so the rest of the client loads and works +;; without it and it is deliberately not listed above. The compiler this talks +;; to is not an Emacs package and cannot be listed here either -- emacs/MANUAL.md +;; says what has to be on PATH. + ;; Derived from `prog-mode', borrowing `lisp-mode''s machinery for the parts ;; that are simply s-expressions: sexp motion, paren matching and ;; `beginning-of-defun' already do the right thing. diff --git a/emacs/flan-repl.el b/emacs/flan-repl.el index f66256a..762dd79 100644 --- a/emacs/flan-repl.el +++ b/emacs/flan-repl.el @@ -1,5 +1,24 @@ ;;; flan-repl.el --- A prompt for a running Flan program -*- lexical-binding: t; -*- +;; Author: Joseph Ferano +;; Version: 0.1.0 +;; Package-Requires: ((emacs "29.1")) +;; Keywords: languages, lisp, tools + +;; The headers above are what make this directory installable. M-x +;; package-install-file on it reads them, and a file with no Version: is not a +;; package as far as package.el is concerned -- until now the client was +;; reachable only by adding it to load-path by hand, which is a thing to +;; explain to every person who wants to try it. +;; +;; 29.1 is the floor because it is the oldest Emacs any of this has been run +;; against, not because some function here is known to need it. dape, which +;; flan-dape drives, asks for 29.1 as well and is a soft dependency: it is +;; reached through declare-function, so the rest of the client loads and works +;; without it and it is deliberately not listed above. The compiler this talks +;; to is not an Emacs package and cannot be listed here either -- emacs/MANUAL.md +;; says what has to be on PATH. + ;; A buffer to type expressions at, sent to the program `flan dev' is running ;; and answered with the value they had *there*. It adds no protocol and no ;; compiler support: every line goes through the same `eval-expr' request that diff --git a/emacs/flan-watch.el b/emacs/flan-watch.el index da26578..f0f6e0f 100644 --- a/emacs/flan-watch.el +++ b/emacs/flan-watch.el @@ -1,5 +1,24 @@ ;;; flan-watch.el --- Watched values, in a pinned buffer or inline -*- lexical-binding: t; -*- +;; Author: Joseph Ferano +;; Version: 0.1.0 +;; Package-Requires: ((emacs "29.1")) +;; Keywords: languages, lisp, tools + +;; The headers above are what make this directory installable. M-x +;; package-install-file on it reads them, and a file with no Version: is not a +;; package as far as package.el is concerned -- until now the client was +;; reachable only by adding it to load-path by hand, which is a thing to +;; explain to every person who wants to try it. +;; +;; 29.1 is the floor because it is the oldest Emacs any of this has been run +;; against, not because some function here is known to need it. dape, which +;; flan-dape drives, asks for 29.1 as well and is a soft dependency: it is +;; reached through declare-function, so the rest of the client loads and works +;; without it and it is deliberately not listed above. The compiler this talks +;; to is not an Emacs package and cannot be listed here either -- emacs/MANUAL.md +;; says what has to be on PATH. + ;; A HUD for a running Flan program: a buffer that always shows the current ;; frame's values and nothing else. Ported from the author's Clojure ;; `clj-watch', with one thing kept and one thing inverted.