The client drops -dev- from its names, and starts the buffer you are in
`-dev-` was in every Emacs symbol this client owns and meant nothing to anyone typing one: the daemon is `flan dev` at a shell, but from inside Emacs there is no other kind of connection to distinguish it from. `M-x flan-dev` is now `M-x flan`, `flan-dev-quit` is `flan-quit`, the private prefix `flan-dev--` is `flan--`, and every defcustom follows — ninety-odd symbols, with the two files renamed to emacs/flan.el and emacs/test-flan.el so the file names say the same thing as the symbols in them. No aliases. Renaming a defcustom breaks a config that names it and there is no way around that; the repo has no precedent for softening one, and an alias left behind is what keeps a rename from finishing. MANUAL.md says the old names are gone and how to fix a config, which is the whole of the migration path. Three strings are not symbols and keep their spelling: `.flan-dev.sock`, which bin/main.ml writes and which a renamed variable searching for a renamed file would simply never find; and the two buffer names `*flan-dev*` and ` *flan-dev*`, which name the `flan dev` subcommand's own output rather than anything in elisp. `flan dev` with a space is the CLI and is untouched everywhere. The entry point also stops asking a question it already has the answer to. From a buffer visiting a .flan file it starts that file; from anywhere else it reads one from the minibuffer as before; `C-u` reads one either way, which is how you start a second program without leaving the first. The current buffer is still the only source of the default — the bug where a previous project won over the buffer you were in was fixed by removing `flan--file` from that position, and nothing here puts it back. Four checks on the `interactive' form, evaluated on its own rather than by calling the command, because calling it would build and launch a program and the question is only which file the form arrives at and whether it had to ask. A fifth asserts that nothing answers to the old names. test/test_emacs.ml loads the test file by path and test/test_session.ml names the client file in a comment, so the rename reaches those two lines; nothing else outside emacs/ and the docs moved. Verified by byte-compiling every file clean and by `dune test` and `@page`.
This commit is contained in:
parent
233bb780b0
commit
d9404bb34a
4
FIX.org
4
FIX.org
@ -1,5 +1,5 @@
|
|||||||
* Stuff I've found
|
* Stuff I've found
|
||||||
** Why do I need to call flan-dev to open another window?
|
** Why do I need to call flan to open another window?
|
||||||
let: flan: the program exited; restart flan dev
|
let: flan: the program exited; restart flan dev
|
||||||
** I can't eval a toplevel defvar, need to eval-defun (C-c C-c)
|
** I can't eval a toplevel defvar, need to eval-defun (C-c C-c)
|
||||||
For Flan’s intended live-program workflow, C-x C-e on any complete top-level form should do the natural thing:
|
For Flan’s intended live-program workflow, C-x C-e on any complete top-level form should do the natural thing:
|
||||||
@ -40,7 +40,7 @@ Globals are NOT reset between runs. That is the CL/Clojure semantics asked for:
|
|||||||
the process never died, so a second (main) sees what the first one left.
|
the process never died, so a second (main) sees what the first one left.
|
||||||
|
|
||||||
** 2. C-x C-e on a top-level form — QUEUED behind 1
|
** 2. C-x C-e on a top-level form — QUEUED behind 1
|
||||||
Same file as 1 (emacs/flan-dev.el), so it waits rather than merging by hand.
|
Same file as 1 (emacs/flan.el), so it waits rather than merging by hand.
|
||||||
No design questions; the note specifies it.
|
No design questions; the note specifies it.
|
||||||
|
|
||||||
** 3. Runtime-loaded owning globals — DISPATCHED
|
** 3. Runtime-loaded owning globals — DISPATCHED
|
||||||
|
|||||||
12
NEXT.md
12
NEXT.md
@ -801,9 +801,9 @@ tip themselves. A lane that did not notice would produce plausible work against
|
|||||||
|
|
||||||
### ~~From `HANDOFF-f2.md` — `pause` marking, the Emacs half~~
|
### ~~From `HANDOFF-f2.md` — `pause` marking, the Emacs half~~
|
||||||
|
|
||||||
**Built.** All seven items landed: the `eval_expr` pause path, `flan-dev--eval` sending the position,
|
**Built.** All seven items landed: the `eval_expr` pause path, `flan--eval` sending the position,
|
||||||
`flan-eval-defun` taking `C-u`, the overlay and its face, `test/programs/dev-pause.flan`, the `test_dev.ml` block and
|
`flan-eval-defun` taking `C-u`, the overlay and its face, `test/programs/dev-pause.flan`, the `test_dev.ml` block and
|
||||||
the `emacs/test-flan-dev.el` one. `HANDOFF-f2.md` is deleted; the reasoning is in `docs/BUILT.md`, "A breakpoint is a
|
the `emacs/test-flan.el` one. `HANDOFF-f2.md` is deleted; the reasoning is in `docs/BUILT.md`, "A breakpoint is a
|
||||||
function call, and the editor only says where".
|
function call, and the editor only says where".
|
||||||
|
|
||||||
### ~~From `HANDOFF-f1.md`~~ — the socket flake is fixed, and everything that followed it is done
|
### ~~From `HANDOFF-f1.md`~~ — the socket flake is fixed, and everything that followed it is done
|
||||||
@ -884,7 +884,7 @@ putting the old `?` back in `flan-watch-ghost-call-regexp` and watching exactly
|
|||||||
**Closed.** The dead `n=0` branch in `watch_render_num` is deleted and the reader stays epoch-blind on purpose: a
|
**Closed.** The dead `n=0` branch in `watch_render_num` is deleted and the reader stays epoch-blind on purpose: a
|
||||||
stopped program does not sample, so an epoch-aware reader would blank the watch for the whole of a break loop, which
|
stopped program does not sample, so an epoch-aware reader would blank the watch for the whole of a break loop, which
|
||||||
is exactly when the numbers are being read. What was actually wrong was in the editor — `flan-watch--tick` sent
|
is exactly when the numbers are being read. What was actually wrong was in the editor — `flan-watch--tick` sent
|
||||||
`:reset t` five times a second at a program that could not answer it — and it is now guarded on `flan-dev--stopped`,
|
`:reset t` five times a second at a program that could not answer it — and it is now guarded on `flan--stopped`,
|
||||||
with the read still going out every tick. `emacs/test-flan-watch.el` pins both halves. `HANDOFF-f3.md` is deleted;
|
with the read still going out every tick. `emacs/test-flan-watch.el` pins both halves. `HANDOFF-f3.md` is deleted;
|
||||||
the reasoning is in `docs/BUILT.md`, "A hot loop keeps five numbers, and the window is the editor's".
|
the reasoning is in `docs/BUILT.md`, "A hot loop keeps five numbers, and the window is the editor's".
|
||||||
|
|
||||||
@ -1440,7 +1440,7 @@ reader ✅ → parse ✅ → load ✅ → check ✅ → emit ✅ → clang ✅
|
|||||||
| `lib/shim.ml` | **`declare-c` -> the generated C that flattens a struct crossing** |
|
| `lib/shim.ml` | **`declare-c` -> the generated C that flattens a struct crossing** |
|
||||||
| `vendor/raylib/` | **the raylib package: `raylib.flan` and `link`, and no C at all** |
|
| `vendor/raylib/` | **the raylib package: `raylib.flan` and `link`, and no C at all** |
|
||||||
| `vendor/agent/` | **the dev agent: one verb table, a loader thread, install at a frame boundary** |
|
| `vendor/agent/` | **the dev agent: one verb table, a loader thread, install at a frame boundary** |
|
||||||
| `emacs/` | **`flan-mode.el`, `flan-dev.el`, `flan-repl.el`: the editor half of the dev loop** |
|
| `emacs/` | **`flan-mode.el`, `flan.el`, `flan-repl.el`: the editor half of the dev loop** |
|
||||||
| `bin/main.ml` | `flan read \| parse \| check \| emit \| shim \| build \| run \| reload \| dev` |
|
| `bin/main.ml` | `flan read \| parse \| check \| emit \| shim \| build \| run \| reload \| dev` |
|
||||||
| `test/test_flan.ml` | reader, parser and checker |
|
| `test/test_flan.ml` | reader, parser and checker |
|
||||||
| `test/test_acceptance.ml` | expression/result pairs + whole programs + the traps |
|
| `test/test_acceptance.ml` | expression/result pairs + whole programs + the traps |
|
||||||
@ -1564,7 +1564,7 @@ way, and such a frame is now refused by name. Kept separate from the slot finger
|
|||||||
reads a frame whose locals are fine and whose global attribution is not.
|
reads a frame whose locals are fine and whose global attribution is not.
|
||||||
|
|
||||||
**The break buffer opens by itself when the program stops.** Today a condition stops the program and the buffer appears
|
**The break buffer opens by itself when the program stops.** Today a condition stops the program and the buffer appears
|
||||||
only when `C-c C-b` is typed. `flan-dev--absorb` already inspects every reply for `:stopped` and a poll covers the case
|
only when `C-c C-b` is typed. `flan--absorb` already inspects every reply for `:stopped` and a poll covers the case
|
||||||
where no reply is pending, so the client already knows the moment it happens and already moves the mode line from it —
|
where no reply is pending, so the client already knows the moment it happens and already moves the mode line from it —
|
||||||
this is a hook at a point that exists, not new plumbing.
|
this is a hook at a point that exists, not new plumbing.
|
||||||
|
|
||||||
@ -1840,7 +1840,7 @@ wrote Flan in the old spelling and their files want the same pass at merge:
|
|||||||
```
|
```
|
||||||
python3 tools/unit-return.py .
|
python3 tools/unit-return.py .
|
||||||
python3 tools/unit-return.py --in-strings test/test_flan.ml test/test_acceptance.ml \
|
python3 tools/unit-return.py --in-strings test/test_flan.ml test/test_acceptance.ml \
|
||||||
test/test_session.ml emacs/test-flan-dev.el emacs/test-flan-mode.el
|
test/test_session.ml emacs/test-flan.el emacs/test-flan-mode.el
|
||||||
python3 tools/unit-return.py --raw-ml lib/prelude.ml
|
python3 tools/unit-return.py --raw-ml lib/prelude.ml
|
||||||
python3 tools/unit-return.py --in-html web/index.html
|
python3 tools/unit-return.py --in-html web/index.html
|
||||||
```
|
```
|
||||||
|
|||||||
@ -89,7 +89,7 @@ To set up the mode:
|
|||||||
(require 'flan-mode)
|
(require 'flan-mode)
|
||||||
```
|
```
|
||||||
|
|
||||||
Then use `M-x flan-dev` to start and attach, or `C-c C-z` to attach to a
|
Then use `M-x flan` to start and attach, or `C-c C-z` to attach to a
|
||||||
session started in a terminal. The editor workflow is documented in
|
session started in a terminal. The editor workflow is documented in
|
||||||
[emacs/MANUAL.md](emacs/MANUAL.md).
|
[emacs/MANUAL.md](emacs/MANUAL.md).
|
||||||
|
|
||||||
|
|||||||
@ -1367,7 +1367,7 @@ the merged entry point uses to flush and park.
|
|||||||
|
|
||||||
The park used to be `for (;;) pause()`, and that was a dead end with the process still standing: you ran a program, it
|
The park used to be `for (;;) pause()`, and that was a dead end with the process still standing: you ran a program, it
|
||||||
opened a window, you closed the window, `main` returned, and the only way to get another window was
|
opened a window, you closed the window, `main` returned, and the only way to get another window was
|
||||||
`flan-dev-restart-program` — a new build, a new session, every global gone. Common Lisp and Clojure do not have that
|
`flan-restart-program` — a new build, a new session, every global gone. Common Lisp and Clojure do not have that
|
||||||
problem because the image outlives `main` and you call it again. The process here already outlived `main`; nothing
|
problem because the image outlives `main` and you call it again. The process here already outlived `main`; nothing
|
||||||
could wake it.
|
could wake it.
|
||||||
|
|
||||||
@ -1530,7 +1530,7 @@ s-expressions, so sexp motion, paren matching, `beginning-of-defun` and indentat
|
|||||||
Flan's own bracket syntax (`[` and `{` are brackets, not symbol characters — every binding list and every type is
|
Flan's own bracket syntax (`[` and `{` are brackets, not symbol characters — every binding list and every type is
|
||||||
written with them), the characters a Flan name may contain (`-`, `?`, `/`, `.`), and its keywords.
|
written with them), the characters a Flan name may contain (`-`, `?`, `/`, `.`), and its keywords.
|
||||||
|
|
||||||
`emacs/flan-dev.el` is the client. There is no parser in it, which is the point of the protocol choice: `prin1` writes a
|
`emacs/flan.el` is the client. There is no parser in it, which is the point of the protocol choice: `prin1` writes a
|
||||||
request and `read` reads a reply.
|
request and `read` reads a reply.
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
@ -1843,7 +1843,7 @@ errors — and that is a reply the client is already reading. Finding out a seco
|
|||||||
out *after* the echo area had said the evaluation was fine.
|
out *after* the echo area had said the evaluation was fine.
|
||||||
- **And a timer asks anyway**, once a second, with `describe` — the cheap op, which is also how the output pipe is
|
- **And a timer asks anyway**, once a second, with `describe` — the cheap op, which is also how the output pipe is
|
||||||
drained. A program that stops in a frame of its own game loop produces no reply at all, and folding state into replies
|
drained. A program that stops in a frame of its own game loop produces no reply at all, and folding state into replies
|
||||||
that never come says nothing. The timer never *reconnects*: `flan-dev--request` reopens a socket a restarted daemon left
|
that never come says nothing. The timer never *reconnects*: `flan--request` reopens a socket a restarted daemon left
|
||||||
behind, which is right for something a person did and wrong for a background poll, because it would quietly erase the
|
behind, which is right for something a person did and wrong for a background poll, because it would quietly erase the
|
||||||
`lost` state that exists to be seen. It also skips while another request is in flight — `accept-process-output` runs
|
`lost` state that exists to be seen. It also skips while another request is in flight — `accept-process-output` runs
|
||||||
timers, so a poll firing inside a read would eat the reply that read was waiting for.
|
timers, so a poll firing inside a read would eat the reply that read was waiting for.
|
||||||
@ -4358,7 +4358,7 @@ old spelling and their files want the same pass at merge:
|
|||||||
```
|
```
|
||||||
python3 tools/unit-return.py .
|
python3 tools/unit-return.py .
|
||||||
python3 tools/unit-return.py --in-strings test/test_flan.ml test/test_acceptance.ml \
|
python3 tools/unit-return.py --in-strings test/test_flan.ml test/test_acceptance.ml \
|
||||||
test/test_session.ml emacs/test-flan-dev.el emacs/test-flan-mode.el
|
test/test_session.ml emacs/test-flan.el emacs/test-flan-mode.el
|
||||||
python3 tools/unit-return.py --raw-ml lib/prelude.ml
|
python3 tools/unit-return.py --raw-ml lib/prelude.ml
|
||||||
python3 tools/unit-return.py --in-html web/index.html
|
python3 tools/unit-return.py --in-html web/index.html
|
||||||
```
|
```
|
||||||
@ -5143,7 +5143,7 @@ which is the honest answer to a question asked of a table that is never still.
|
|||||||
**"At exit" is not a hook, and the honest reason is that a game is killed.** A program stopped by a signal runs no
|
**"At exit" is not a hook, and the honest reason is that a game is killed.** A program stopped by a signal runs no
|
||||||
`atexit` handler, no destructor, nothing — so no code written inside the program could report anything about the run
|
`atexit` handler, no destructor, nothing — so no code written inside the program could report anything about the run
|
||||||
that matters most. The authoritative reader is therefore `(:op "leaks")`, which reads the same table over the agent
|
that matters most. The authoritative reader is therefore `(:op "leaks")`, which reads the same table over the agent
|
||||||
socket and can be asked at any moment, including the one before the kill. `flan-dev.el` does not ask on teardown
|
socket and can be asked at any moment, including the one before the kill. `flan.el` does not ask on teardown
|
||||||
either: that would put a request on a path that runs every time the editor closes, for an answer nobody asked for.
|
either: that would put a request on a path that runs every time the editor closes, for an answer nobody asked for.
|
||||||
|
|
||||||
The hook exists for the other program — the one that returns from `main` — and it is two decisions:
|
The hook exists for the other program — the one that returns from `main` — and it is two decisions:
|
||||||
@ -5201,7 +5201,7 @@ name in the table came from one of these call sites by construction — and the
|
|||||||
|
|
||||||
**One reply, two pictures.** Ghost text does not poll. It is painted from `flan-watch--absorb`, the same function
|
**One reply, two pictures.** Ghost text does not poll. It is painted from `flan-watch--absorb`, the same function
|
||||||
that paints the buffer, from the same reply, so the two cannot disagree and there is no second `:op "watch"` in
|
that paints the buffer, from the same reply, so the two cannot disagree and there is no second `:op "watch"` in
|
||||||
flight — the one-request invariant `flan-dev-settle-hook` exists to keep. What had to change is that the **watch
|
flight — the one-request invariant `flan-settle-hook` exists to keep. What had to change is that the **watch
|
||||||
buffer used to be the subscription**: killing it cancelled the timer and disarmed the table. That was right while it
|
buffer used to be the subscription**: killing it cancelled the timer and disarmed the table. That was right while it
|
||||||
was the only consumer and wrong the moment it was not, so arming and the timer now hang off
|
was the only consumer and wrong the moment it was not, so arming and the timer now hang off
|
||||||
`flan-watch--consumers`, and only the last consumer out turns the lights off.
|
`flan-watch--consumers`, and only the last consumer out turns the lights off.
|
||||||
@ -5309,7 +5309,7 @@ sample. It is the wrong trade, because **a stopped program does not sample**. An
|
|||||||
watch for as long as the program sat in a break loop, and reading the numbers from the moment you stopped is the
|
watch for as long as the program sat in a break loop, and reading the numbers from the moment you stopped is the
|
||||||
entire point of stopping. The lazy clear gives exactly the right answer there. What was actually wrong was narrower
|
entire point of stopping. The lazy clear gives exactly the right answer there. What was actually wrong was narrower
|
||||||
and lives in the editor: `flan-watch--tick` was sending `:reset t` five times a second at a program that could not
|
and lives in the editor: `flan-watch--tick` was sending `:reset t` five times a second at a program that could not
|
||||||
answer it. So the reset is now guarded on `flan-dev--stopped` — the read still goes out every tick, only the reset
|
answer it. So the reset is now guarded on `flan--stopped` — the read still goes out every tick, only the reset
|
||||||
field drops — and the runtime is untouched. That keeps the policy where the rest of this section already put it:
|
field drops — and the runtime is untouched. That keeps the policy where the rest of this section already put it:
|
||||||
"since you last looked" is the editor's idea, not the table's. `watch_render_num`'s unreachable `n=0` arm is deleted
|
"since you last looked" is the editor's idea, not the table's. `watch_render_num`'s unreachable `n=0` arm is deleted
|
||||||
rather than commented, since the only way to reach it is the epoch check that was just rejected, and dead code is an
|
rather than commented, since the only way to reach it is the epoch check that was just rejected, and dead code is an
|
||||||
@ -5370,7 +5370,7 @@ the session would have been a second source of truth that drifts the first time
|
|||||||
touching it, and clearing would have had to be written rather than falling out.
|
touching it, and clearing would have had to be written rather than falling out.
|
||||||
|
|
||||||
**`C-u C-x C-e` is a flag, not a position.** `flan-eval-last-sexp` sends a raw `buffer-substring` with no line
|
**`C-u C-x C-e` is a flag, not a position.** `flan-eval-last-sexp` sends a raw `buffer-substring` with no line
|
||||||
padding — unlike `flan-dev--text`, which pads a snippet back onto its own line — so buffer coordinates do not survive
|
padding — unlike `flan--text`, which pads a snippet back onto its own line — so buffer coordinates do not survive
|
||||||
that path. They are also not needed: the expression sent *is* the target, so `:pause t` says everything there is to
|
that path. They are also not needed: the expression sent *is* the target, so `:pause t` says everything there is to
|
||||||
say, and `Session.eval_expr` wraps the parsed expression before `Check.expression`. It does not stick and cannot: a
|
say, and `Session.eval_expr` wraps the parsed expression before `Check.expression`. It does not stick and cannot: a
|
||||||
thunk is built and thrown away, so there is no declaration for the mark to live in.
|
thunk is built and thrown away, so there is no declaration for the mark to live in.
|
||||||
@ -5392,16 +5392,16 @@ reports because a nested break overwrites `condition_name` and restores it on th
|
|||||||
`status` verb). A program already parked on a `Pause` is the one case this cannot tell apart, and nothing could: both
|
`status` verb). A program already parked on a `Pause` is the one case this cannot tell apart, and nothing could: both
|
||||||
answers are "stopped at a pause".
|
answers are "stopped at a pause".
|
||||||
|
|
||||||
**The editor's column is a byte offset.** `flan-dev--wire-position` is the inverse of `flan-dev--position` and has to
|
**The editor's column is a byte offset.** `flan--wire-position` is the inverse of `flan--position` and has to
|
||||||
count bytes for the same reason: the reader walks the source a byte at a time, so `current-column` would be short by
|
count bytes for the same reason: the reader walks the source a byte at a time, so `current-column` would be short by
|
||||||
one per extra byte in every non-ASCII character earlier on the line and the daemon would find nothing where it was
|
one per extra byte in every non-ASCII character earlier on the line and the daemon would find nothing where it was
|
||||||
pointed. The *line* is the buffer's own, which works because `flan-dev--text` pads the snippet with leading newlines.
|
pointed. The *line* is the buffer's own, which works because `flan--text` pads the snippet with leading newlines.
|
||||||
|
|
||||||
**One key, three targets.** `flan-eval-defun` takes `C-u` for the innermost form point is inside — `backward-up-list`,
|
**One key, three targets.** `flan-eval-defun` takes `C-u` for the innermost form point is inside — `backward-up-list`,
|
||||||
falling back to the defun when point is not nested — and `C-u C-u` for the top-level form itself. With `C-u C-x C-e`
|
falling back to the defun when point is not nested — and `C-u C-u` for the top-level form itself. With `C-u C-x C-e`
|
||||||
that is all three of §9's targets and no new binding; `flan-mode.el` did not change.
|
that is all three of §9's targets and no new binding; `flan-mode.el` did not change.
|
||||||
|
|
||||||
**The overlay is an annotation, not feedback.** `flan-dev-pause-face` is drawn over the marked form and deliberately
|
**The overlay is an annotation, not feedback.** `flan-pause-face` is drawn over the marked form and deliberately
|
||||||
does *not* copy the error overlays' lifetime. An error overlay is about the command that just failed and the next
|
does *not* copy the error overlays' lifetime. An error overlay is about the command that just failed and the next
|
||||||
keystroke takes it down; a pause mark is about the running program, and it has to survive `pre-command-hook` or the
|
keystroke takes it down; a pause mark is about the running program, and it has to survive `pre-command-hook` or the
|
||||||
buffer stops showing a breakpoint that is still there. What clears it is what clears the mark itself: an accepted
|
buffer stops showing a breakpoint that is still there. What clears it is what clears the mark itself: an accepted
|
||||||
@ -5722,11 +5722,11 @@ The region is `C-x C-e`'s, plus one case it has no need of: the form *at* point
|
|||||||
delimiter. A macro call is a form you put point on, and `backward-sexp` from an open paren takes the previous
|
delimiter. A macro call is a form you put point on, and `backward-sexp` from an open paren takes the previous
|
||||||
sibling, which is never what was meant.
|
sibling, which is never what was meant.
|
||||||
|
|
||||||
The text is padded onto its own line **and its own column**, which `flan-dev--text` does not do and says why it
|
The text is padded onto its own line **and its own column**, which `flan--text` does not do and says why it
|
||||||
does not: a top-level form starts at column 1, so the columns already agreed. A macro call does not — it is
|
does not: a top-level form starts at column 1, so the columns already agreed. A macro call does not — it is
|
||||||
written well inside a `defn` — and the refusal this path can get carries a column measured from the start of the
|
written well inside a `defn` — and the refusal this path can get carries a column measured from the start of the
|
||||||
snippet, so an unpadded send would draw "did not settle" at the start of the line. Leading newlines and leading
|
snippet, so an unpadded send would draw "did not settle" at the start of the line. Leading newlines and leading
|
||||||
spaces are both whitespace the reader skips. `test-flan-dev.el` checks the arithmetic the only way that proves it:
|
spaces are both whitespace the reader skips. `test-flan.el` checks the arithmetic the only way that proves it:
|
||||||
it evaluates a spinning `defmacro` into a live session, asks for the fixpoint of a call to it from a known buffer
|
it evaluates a spinning `defmacro` into a live session, asks for the fixpoint of a call to it from a known buffer
|
||||||
position, and requires the error overlay to start at exactly that position.
|
position, and requires the error overlay to start at exactly that position.
|
||||||
|
|
||||||
|
|||||||
@ -316,9 +316,9 @@ cursor at `(+ 1| 1)` the program stops at that `(+ ...)`.
|
|||||||
`continue` resumes at the call.
|
`continue` resumes at the call.
|
||||||
- **`flan-eval-defun`** takes the top-level form's bounds and sends the text; **`flan-eval-last-sexp`** sends the sexp
|
- **`flan-eval-defun`** takes the top-level form's bounds and sends the text; **`flan-eval-last-sexp`** sends the sexp
|
||||||
before point. Both hand a *string* to the daemon, which is the hook — the buffer never has to be modified.
|
before point. Both hand a *string* to the daemon, which is the hook — the buffer never has to be modified.
|
||||||
- **`flan-dev--enclosing-head`** (`flan-dev.el:1009`) already walks out to the enclosing form to find its head, for
|
- **`flan--enclosing-head`** (`flan.el:1009`) already walks out to the enclosing form to find its head, for
|
||||||
eldoc. The third target's hard part is already written.
|
eldoc. The third target's hard part is already written.
|
||||||
- `current-prefix-arg` is already read in one place (`flan-dev.el:1429`), so the `C-u` convention has precedent.
|
- `current-prefix-arg` is already read in one place (`flan.el:1429`), so the `C-u` convention has precedent.
|
||||||
|
|
||||||
**So the work is a source-to-source rewrite in Emacs before sending:** find the target form's bounds, send the
|
**So the work is a source-to-source rewrite in Emacs before sending:** find the target form's bounds, send the
|
||||||
top-level form with that span replaced by `(do (pause) <span>)`. Nothing on the compiler side changes.
|
top-level form with that span replaced by `(do (pause) <span>)`. Nothing on the compiler side changes.
|
||||||
|
|||||||
@ -52,7 +52,7 @@ one borrows its memory model from.
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `farolero` | 2023-05-05 | Common Lisp conditions and restarts, portably — a smaller read than SBCL's for *semantics*. |
|
| `farolero` | 2023-05-05 | Common Lisp conditions and restarts, portably — a smaller read than SBCL's for *semantics*. |
|
||||||
| `lem` | 2025-08-29 | An editor written in CL. Its own REPL and process model. |
|
| `lem` | 2025-08-29 | An editor written in CL. Its own REPL and process model. |
|
||||||
| `cider` | 2026-09-10 | The Clojure editor protocol this repo's `flan-dev.el` is shaped after. |
|
| `cider` | 2026-09-10 | The Clojure editor protocol this repo's `flan.el` is shaped after. |
|
||||||
| `emacs` | 2026-04-18 | Overlays, faces, `pre-command-hook` — the C and Lisp behind the editor half. |
|
| `emacs` | 2026-04-18 | Overlays, faces, `pre-command-hook` — the C and Lisp behind the editor half. |
|
||||||
| `fennel-ls` | 2026-05-06 | A Lisp language server. |
|
| `fennel-ls` | 2026-05-06 | A Lisp language server. |
|
||||||
| `Carp` | 2026-08-24 | A statically typed Lisp with no GC. **The closest thing to this language's premise.** |
|
| `Carp` | 2026-08-24 | A statically typed Lisp with no GC. **The closest thing to this language's premise.** |
|
||||||
|
|||||||
@ -172,7 +172,7 @@ The containers, strings/UTF-8, sequences, random, and printing layers are decent
|
|||||||
- **No `-Wall -Wextra` on the runtime's C compile** (`lib/build.ml:827`, `:1069`).
|
- **No `-Wall -Wextra` on the runtime's C compile** (`lib/build.ml:827`, `:1069`).
|
||||||
- **Package visibility** — everything in a package is public except `main`
|
- **Package visibility** — everything in a package is public except `main`
|
||||||
(`lib/load.ml:25-31`); `rl/get-color-raw` is the recorded symptom.
|
(`lib/load.ml:25-31`); `rl/get-color-raw` is the recorded symptom.
|
||||||
- **Emacs client**: 30s hard deadline with no retry on long builds (`flan-dev.el:155-170`);
|
- **Emacs client**: 30s hard deadline with no retry on long builds (`flan.el:155-170`);
|
||||||
`accept-process-output` loops can freeze Emacs up to 60s on a hung daemon (`:521`,
|
`accept-process-output` loops can freeze Emacs up to 60s on a hung daemon (`:521`,
|
||||||
`:576-600`); no package headers, so not installable off MELPA or by path alone.
|
`:576-600`); no package headers, so not installable off MELPA or by path alone.
|
||||||
- **No CI** — README states it openly and records two silent-failure incidents. `@checks`
|
- **No CI** — README states it openly and records two silent-failure incidents. `@checks`
|
||||||
|
|||||||
@ -49,10 +49,10 @@ reaches it through `declare-function`, so everything else installs and works
|
|||||||
without it.
|
without it.
|
||||||
|
|
||||||
You also need the `flan` binary on your `PATH`. If it is somewhere else, set
|
You also need the `flan` binary on your `PATH`. If it is somewhere else, set
|
||||||
`flan-dev-command`.
|
`flan-command`.
|
||||||
|
|
||||||
Two settings worth knowing about before you need them. `flan-dev-start-timeout`
|
Two settings worth knowing about before you need them. `flan-start-timeout`
|
||||||
(60s) bounds the wait for a daemon to come up, and `flan-dev-reply-timeout`
|
(60s) bounds the wait for a daemon to come up, and `flan-reply-timeout`
|
||||||
(30s) bounds one request once it has. The second is the one a long first
|
(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
|
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
|
daemon's own build log is, so you can see whether it is still working before
|
||||||
@ -64,9 +64,15 @@ you raise it.
|
|||||||
|
|
||||||
Two ways in, and they are different.
|
Two ways in, and they are different.
|
||||||
|
|
||||||
**`M-x flan-dev`** starts the program for you. It runs `flan dev` on a file,
|
**`M-x flan`** starts the program for you. It runs `flan dev` on a file,
|
||||||
waits for it to come up, and connects. This is the normal way.
|
waits for it to come up, and connects. This is the normal way.
|
||||||
|
|
||||||
|
From a buffer already visiting a `.flan` file it starts *that* file and asks
|
||||||
|
nothing — the buffer has answered the question. From anywhere else it reads the
|
||||||
|
file from the minibuffer, and `C-u M-x flan` reads it even from a `.flan`
|
||||||
|
buffer, which is how you start some other program without leaving the one you
|
||||||
|
are looking at.
|
||||||
|
|
||||||
**`C-c C-z`** (`flan-connect`) attaches to a program that is *already* running —
|
**`C-c C-z`** (`flan-connect`) attaches to a program that is *already* running —
|
||||||
one you started in a terminal, say. It looks for a `.flan-dev.sock` file in the
|
one you started in a terminal, say. It looks for a `.flan-dev.sock` file in the
|
||||||
current directory and upward, so from anywhere in the project it finds the one
|
current directory and upward, so from anywhere in the project it finds the one
|
||||||
@ -79,7 +85,7 @@ it found:
|
|||||||
flan dev: connected to ~/Development/flan/.flan-dev.sock (47 functions, 2 globals)
|
flan dev: connected to ~/Development/flan/.flan-dev.sock (47 functions, 2 globals)
|
||||||
```
|
```
|
||||||
|
|
||||||
**`C-c C-q`** disconnects without stopping the program. **`M-x flan-dev-quit`**
|
**`C-c C-q`** disconnects without stopping the program. **`M-x flan-quit`**
|
||||||
stops the program too — but only one this Emacs started. A daemon you launched
|
stops the program too — but only one this Emacs started. A daemon you launched
|
||||||
in a terminal is not Emacs' to kill, and it will say so rather than do something
|
in a terminal is not Emacs' to kill, and it will say so rather than do something
|
||||||
surprising.
|
surprising.
|
||||||
@ -703,7 +709,7 @@ next time that buffer's evaluation is accepted — so it disappears when you fix
|
|||||||
the thing rather than when you dismiss it.
|
the thing rather than when you dismiss it.
|
||||||
|
|
||||||
**"No .flan-dev.sock found above this buffer"** — nothing is running, or you are
|
**"No .flan-dev.sock found above this buffer"** — nothing is running, or you are
|
||||||
outside the project. Start one with `M-x flan-dev`.
|
outside the project. Start one with `M-x flan`.
|
||||||
|
|
||||||
**The modeline says nothing about a program** — you are not connected. `C-c C-z`.
|
**The modeline says nothing about a program** — you are not connected. `C-c C-z`.
|
||||||
|
|
||||||
@ -744,7 +750,7 @@ Use `C-c C-g` if you need frames.
|
|||||||
| `C-c C-x` | rebuild, relaunch, reconnect |
|
| `C-c C-x` | rebuild, relaunch, reconnect |
|
||||||
| `M-.` / `M-,` | where a name is written / back |
|
| `M-.` / `M-,` | where a name is written / back |
|
||||||
|
|
||||||
Commands with no key: `M-x flan-dev` (start a program), `M-x flan-dev-quit`
|
Commands with no key: `M-x flan` (start a program), `M-x flan-quit`
|
||||||
(stop it), `M-x flan-watch` (the watch buffer), `M-x flan-watch-stop`,
|
(stop it), `M-x flan-watch` (the watch buffer), `M-x flan-watch-stop`,
|
||||||
`M-x flan-watch-ghost-mode` (the same values inline),
|
`M-x flan-watch-ghost-mode` (the same values inline),
|
||||||
`M-x flan-inspect-address` (what is at an address), `M-x flan-macroexpand-all`
|
`M-x flan-inspect-address` (what is at an address), `M-x flan-macroexpand-all`
|
||||||
@ -757,14 +763,14 @@ Commands with no key: `M-x flan-dev` (start a program), `M-x flan-dev-quit`
|
|||||||
|
|
||||||
| Variable | Default | What it is |
|
| Variable | Default | What it is |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `flan-dev-command` | `"flan"` | the compiler binary |
|
| `flan-command` | `"flan"` | the compiler binary |
|
||||||
| `flan-dev-socket-name` | `".flan-dev.sock"` | what `C-c C-z` searches for |
|
| `flan-socket-name` | `".flan-dev.sock"` | what `C-c C-z` searches for |
|
||||||
| `flan-dev-echo-result` | `t` | print `C-x C-e`'s value in the echo area |
|
| `flan-echo-result` | `t` | print `C-x C-e`'s value in the echo area |
|
||||||
| `flan-dev-names-shown` | `4` | how many names to list before summarising |
|
| `flan-names-shown` | `4` | how many names to list before summarising |
|
||||||
| `flan-dev-output-buffer` | `"*flan-output*"` | where the program's output goes |
|
| `flan-output-buffer` | `"*flan-output*"` | where the program's output goes |
|
||||||
| `flan-dev-poll-interval` | `1.0` | seconds between checks for whether it stopped |
|
| `flan-poll-interval` | `1.0` | seconds between checks for whether it stopped |
|
||||||
| `flan-dev-daemon-buffer` | `"*flan-dev*"` | the daemon's own log |
|
| `flan-daemon-buffer` | `"*flan-dev*"` | the daemon's own log |
|
||||||
| `flan-dev-start-timeout` | `60` | seconds to wait for a program to come up |
|
| `flan-start-timeout` | `60` | seconds to wait for a program to come up |
|
||||||
| `flan-lower-buffer` | `"*flan-lowering*"` | where `C-c C-l` writes |
|
| `flan-lower-buffer` | `"*flan-lowering*"` | where `C-c C-l` writes |
|
||||||
| `flan-lower-program` | `"flan"` | the compiler `C-c C-l` shells out to |
|
| `flan-lower-program` | `"flan"` | the compiler `C-c C-l` shells out to |
|
||||||
| `flan-lower-flags` | `nil` | flags for `flan emit` — `("--dev")` for the dev lowerings |
|
| `flan-lower-flags` | `nil` | flags for `flan emit` — `("--dev")` for the dev lowerings |
|
||||||
@ -773,6 +779,12 @@ Commands with no key: `M-x flan-dev` (start a program), `M-x flan-dev-quit`
|
|||||||
| `flan-watch-interval` | `0.2` | seconds between repaints — not the watch rate |
|
| `flan-watch-interval` | `0.2` | seconds between repaints — not the watch rate |
|
||||||
| `flan-watch-ghost-call-regexp` | `"watch\(?:-[[:alnum:]]+\)?"` | the head of a call ghost text anchors on |
|
| `flan-watch-ghost-call-regexp` | `"watch\(?:-[[:alnum:]]+\)?"` | the head of a call ghost text anchors on |
|
||||||
|
|
||||||
|
Every one of these used to be spelled `flan-dev-…`, and so did the commands:
|
||||||
|
`M-x flan-dev` is now `M-x flan`, `flan-dev-quit` is `flan-quit`, and so on
|
||||||
|
through the file. Nothing answers to the old names — there are no aliases —
|
||||||
|
so a `setq` or a keybinding in your config that names one will break, and the
|
||||||
|
fix is to delete `-dev` from it.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## The files
|
## The files
|
||||||
@ -780,7 +792,7 @@ Commands with no key: `M-x flan-dev` (start a program), `M-x flan-dev-quit`
|
|||||||
| File | What it is |
|
| File | What it is |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `flan-mode.el` | the major mode: syntax, indentation, imenu, the keymap |
|
| `flan-mode.el` | the major mode: syntax, indentation, imenu, the keymap |
|
||||||
| `flan-dev.el` | the client — the socket, evaluation, xref, eldoc, completion |
|
| `flan.el` | the client — the socket, evaluation, xref, eldoc, completion |
|
||||||
| `flan-repl.el` | the `*flan-repl*` buffer |
|
| `flan-repl.el` | the `*flan-repl*` buffer |
|
||||||
| `flan-watch.el` | watched values: the program pushes, this paints them in a buffer and inline |
|
| `flan-watch.el` | watched values: the program pushes, this paints them in a buffer and inline |
|
||||||
| `flan-cnr.el` | the conditions-and-restarts buffer |
|
| `flan-cnr.el` | the conditions-and-restarts buffer |
|
||||||
|
|||||||
@ -64,7 +64,7 @@
|
|||||||
(require 'seq)
|
(require 'seq)
|
||||||
(require 'subr-x)
|
(require 'subr-x)
|
||||||
|
|
||||||
(declare-function flan-dev--request "flan-dev" (form))
|
(declare-function flan--request "flan" (form))
|
||||||
(declare-function flan-inspect "flan-inspect" (expr))
|
(declare-function flan-inspect "flan-inspect" (expr))
|
||||||
(declare-function flan-inspect-slot "flan-inspect" (frame slot name))
|
(declare-function flan-inspect-slot "flan-inspect" (frame slot name))
|
||||||
|
|
||||||
@ -77,10 +77,10 @@
|
|||||||
"Where the break buffer draws."
|
"Where the break buffer draws."
|
||||||
:type 'string)
|
:type 'string)
|
||||||
|
|
||||||
(defvar flan-cnr-request-function #'flan-dev--request
|
(defvar flan-cnr-request-function #'flan--request
|
||||||
"How this buffer reaches the daemon.
|
"How this buffer reaches the daemon.
|
||||||
One plist in, the reply plist out. A variable so the renderers can be driven
|
One plist in, the reply plist out. A variable so the renderers can be driven
|
||||||
from fixtures, and so `flan-dev.el' is named in one place.")
|
from fixtures, and so `flan.el' is named in one place.")
|
||||||
|
|
||||||
;;; What is not available, and why
|
;;; What is not available, and why
|
||||||
|
|
||||||
@ -441,7 +441,7 @@ puts the likely culprit on top."
|
|||||||
;; while the program is stopped, and re-asking on every fold would put a
|
;; while the program is stopped, and re-asking on every fold would put a
|
||||||
;; round trip behind a keystroke that looks like pure redrawing.
|
;; round trip behind a keystroke that looks like pure redrawing.
|
||||||
;; Only when there is something to ask. The fixture tests render this
|
;; Only when there is something to ask. The fixture tests render this
|
||||||
;; buffer from a literal state with no socket behind it and no `flan-dev'
|
;; buffer from a literal state with no socket behind it and no `flan'
|
||||||
;; loaded, and folding a frame must stay a display operation there — the
|
;; loaded, and folding a frame must stay a display operation there — the
|
||||||
;; renderer already draws a reason for a frame whose locals are nil, which
|
;; renderer already draws a reason for a frame whose locals are nil, which
|
||||||
;; is the same degradation every other section of this buffer uses.
|
;; is the same degradation every other section of this buffer uses.
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
;; to is not an Emacs package and cannot be listed here either -- emacs/MANUAL.md
|
;; to is not an Emacs package and cannot be listed here either -- emacs/MANUAL.md
|
||||||
;; says what has to be on PATH.
|
;; says what has to be on PATH.
|
||||||
|
|
||||||
;; The other half of the dev loop. flan-dev.el is about a program that keeps
|
;; The other half of the dev loop. flan.el is about a program that keeps
|
||||||
;; running while you change it; this is about stopping one and reading it.
|
;; running while you change it; this is about stopping one and reading it.
|
||||||
;;
|
;;
|
||||||
;; There is no DAP implementation here and there should not be. `flan build
|
;; There is no DAP implementation here and there should not be. `flan build
|
||||||
@ -65,7 +65,7 @@
|
|||||||
|
|
||||||
(defcustom flan-dape-command "flan"
|
(defcustom flan-dape-command "flan"
|
||||||
"The flan executable used to build a program for debugging.
|
"The flan executable used to build a program for debugging.
|
||||||
Its own option rather than flan-dev.el's `flan-dev-command', because this
|
Its own option rather than flan.el's `flan-command', because this
|
||||||
file is meant to load without that one: editing Flan, debugging Flan and
|
file is meant to load without that one: editing Flan, debugging Flan and
|
||||||
attaching to a running Flan are three independent things to want."
|
attaching to a running Flan are three independent things to want."
|
||||||
:type 'string)
|
:type 'string)
|
||||||
@ -182,7 +182,7 @@ common case is one command rather than a config prompt."
|
|||||||
|
|
||||||
;;; --dev and --debug are different builds
|
;;; --dev and --debug are different builds
|
||||||
;;
|
;;
|
||||||
;; `flan dev' — what flan-dev.el connects to — builds with --dev: every
|
;; `flan dev' — what flan.el connects to — builds with --dev: every
|
||||||
;; cross-function call goes through a cell so a redefinition can be installed,
|
;; cross-function call goes through a cell so a redefinition can be installed,
|
||||||
;; and -rdynamic exports those cells. `flan build --debug' is a different
|
;; and -rdynamic exports those cells. `flan build --debug' is a different
|
||||||
;; axis: -O0, DWARF, and no cells unless --dev is also passed.
|
;; axis: -O0, DWARF, and no cells unless --dev is also passed.
|
||||||
|
|||||||
@ -99,7 +99,7 @@
|
|||||||
(require 'seq)
|
(require 'seq)
|
||||||
(require 'subr-x)
|
(require 'subr-x)
|
||||||
|
|
||||||
(declare-function flan-dev--request "flan-dev" (form))
|
(declare-function flan--request "flan" (form))
|
||||||
|
|
||||||
(defgroup flan-inspect nil
|
(defgroup flan-inspect nil
|
||||||
"Navigating values in a running Flan program."
|
"Navigating values in a running Flan program."
|
||||||
@ -110,12 +110,12 @@
|
|||||||
"Where the inspector draws."
|
"Where the inspector draws."
|
||||||
:type 'string)
|
:type 'string)
|
||||||
|
|
||||||
(defvar flan-inspect-request-function #'flan-dev--request
|
(defvar flan-inspect-request-function #'flan--request
|
||||||
"How the inspector reaches the program.
|
"How the inspector reaches the program.
|
||||||
Called with one plist — a request — and returning the reply plist. It is a
|
Called with one plist — a request — and returning the reply plist. It is a
|
||||||
variable rather than a direct call so that a test can hand the renderers a
|
variable rather than a direct call so that a test can hand the renderers a
|
||||||
reply without a daemon behind them, and so that this file names
|
reply without a daemon behind them, and so that this file names
|
||||||
`flan-dev.el' in exactly one place.")
|
`flan.el' in exactly one place.")
|
||||||
|
|
||||||
;;; Reading what the renderer wrote
|
;;; Reading what the renderer wrote
|
||||||
|
|
||||||
|
|||||||
@ -62,7 +62,7 @@
|
|||||||
(require 'subr-x)
|
(require 'subr-x)
|
||||||
(require 'seq)
|
(require 'seq)
|
||||||
(require 'outline)
|
(require 'outline)
|
||||||
(require 'flan-dev)
|
(require 'flan)
|
||||||
|
|
||||||
(defgroup flan-lower nil
|
(defgroup flan-lower nil
|
||||||
"Every lowering of one Flan function, side by side."
|
"Every lowering of one Flan function, side by side."
|
||||||
@ -616,7 +616,7 @@ was being read open."
|
|||||||
(completing-read
|
(completing-read
|
||||||
"Lowerings of: "
|
"Lowerings of: "
|
||||||
(mapcar #'car (seq-filter (lambda (d) (equal (nth 1 d) "fn"))
|
(mapcar #'car (seq-filter (lambda (d) (equal (nth 1 d) "fn"))
|
||||||
flan-dev--defs))
|
flan--defs))
|
||||||
nil nil nil nil
|
nil nil nil nil
|
||||||
(and (fboundp 'flan-current-defun-name)
|
(and (fboundp 'flan-current-defun-name)
|
||||||
(flan-current-defun-name))))
|
(flan-current-defun-name))))
|
||||||
|
|||||||
@ -71,31 +71,31 @@
|
|||||||
|
|
||||||
;; The keymap binds them, but do not load the client merely to edit a file.
|
;; The keymap binds them, but do not load the client merely to edit a file.
|
||||||
;; These must be real autoloads, not just `declare-function`s: otherwise a
|
;; These must be real autoloads, not just `declare-function`s: otherwise a
|
||||||
;; user who has loaded only flan-mode cannot invoke M-x flan-dev at all.
|
;; user who has loaded only flan-mode cannot invoke M-x flan at all.
|
||||||
(autoload 'flan-eval-defun "flan-dev" nil t)
|
(autoload 'flan-eval-defun "flan" nil t)
|
||||||
(autoload 'flan-eval-buffer "flan-dev" nil t)
|
(autoload 'flan-eval-buffer "flan" nil t)
|
||||||
(autoload 'flan-eval-last-sexp "flan-dev" nil t)
|
(autoload 'flan-eval-last-sexp "flan" nil t)
|
||||||
(autoload 'flan-connect "flan-dev" nil t)
|
(autoload 'flan-connect "flan" nil t)
|
||||||
(autoload 'flan-disconnect "flan-dev" nil t)
|
(autoload 'flan-disconnect "flan" nil t)
|
||||||
(autoload 'flan-describe "flan-dev" nil t)
|
(autoload 'flan-describe "flan" nil t)
|
||||||
(autoload 'flan-show-output "flan-dev" nil t)
|
(autoload 'flan-show-output "flan" nil t)
|
||||||
(autoload 'flan-repl "flan-repl" nil t)
|
(autoload 'flan-repl "flan-repl" nil t)
|
||||||
(autoload 'flan-break "flan-dev" nil t)
|
(autoload 'flan-break "flan" nil t)
|
||||||
;; The two CIDER-shaped buffers. They reach the daemon through an indirection
|
;; The two CIDER-shaped buffers. They reach the daemon through an indirection
|
||||||
;; of their own so that fixtures can drive them, so autoloading is all the
|
;; of their own so that fixtures can drive them, so autoloading is all the
|
||||||
;; wiring they need.
|
;; wiring they need.
|
||||||
(autoload 'flan-inspect "flan-inspect" nil t)
|
(autoload 'flan-inspect "flan-inspect" nil t)
|
||||||
(autoload 'flan-cnr-show "flan-cnr" nil t)
|
(autoload 'flan-cnr-show "flan-cnr" nil t)
|
||||||
(autoload 'flan-doc "flan-dev" nil t)
|
(autoload 'flan-doc "flan" nil t)
|
||||||
(autoload 'flan-dev "flan-dev" nil t)
|
(autoload 'flan "flan" nil t)
|
||||||
(autoload 'flan-dev-quit "flan-dev" nil t)
|
(autoload 'flan-quit "flan" nil t)
|
||||||
(autoload 'flan-dev-restart-program "flan-dev" nil t)
|
(autoload 'flan-restart-program "flan" nil t)
|
||||||
;; And the cheap counterpart, which needs an autoload for the reason above and
|
;; And the cheap counterpart, which needs an autoload for the reason above and
|
||||||
;; more than most: it is the command someone reaches for the moment a window
|
;; more than most: it is the command someone reaches for the moment a window
|
||||||
;; closes, which can be the first thing they ever ask the client to do.
|
;; closes, which can be the first thing they ever ask the client to do.
|
||||||
(autoload 'flan-rerun "flan-dev" nil t)
|
(autoload 'flan-rerun "flan" nil t)
|
||||||
;; Bound below, like the rest, and it was the one missing an autoload.
|
;; Bound below, like the rest, and it was the one missing an autoload.
|
||||||
(autoload 'flan-disassemble "flan-dev" nil t)
|
(autoload 'flan-disassemble "flan" nil t)
|
||||||
;; The other question about the same function, and the reason it is a second
|
;; The other question about the same function, and the reason it is a second
|
||||||
;; command rather than a fifth argument to the first: `flan-disassemble' asks
|
;; command rather than a fifth argument to the first: `flan-disassemble' asks
|
||||||
;; the running program, and this compiles the file.
|
;; the running program, and this compiles the file.
|
||||||
@ -103,8 +103,8 @@
|
|||||||
;; C-c C-m and the half of it that is findable by name rather than by a
|
;; C-c C-m and the half of it that is findable by name rather than by a
|
||||||
;; modifier. Real autoloads for the reason stated above: a `declare-function'
|
;; modifier. Real autoloads for the reason stated above: a `declare-function'
|
||||||
;; would leave M-x with nothing to load.
|
;; would leave M-x with nothing to load.
|
||||||
(autoload 'flan-macroexpand "flan-dev" nil t)
|
(autoload 'flan-macroexpand "flan" nil t)
|
||||||
(autoload 'flan-macroexpand-all "flan-dev" nil t)
|
(autoload 'flan-macroexpand-all "flan" nil t)
|
||||||
|
|
||||||
(defgroup flan nil
|
(defgroup flan nil
|
||||||
"Editing and evaluating Flan."
|
"Editing and evaluating Flan."
|
||||||
@ -196,7 +196,7 @@ line is off screen."
|
|||||||
|
|
||||||
(defvar flan-mode-map
|
(defvar flan-mode-map
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
;; Autoloaded from flan-dev.el, so the client loads on first use.
|
;; Autoloaded from flan.el, so the client loads on first use.
|
||||||
(define-key map (kbd "C-c C-c") #'flan-eval-defun)
|
(define-key map (kbd "C-c C-c") #'flan-eval-defun)
|
||||||
(define-key map (kbd "C-c C-k") #'flan-eval-buffer)
|
(define-key map (kbd "C-c C-k") #'flan-eval-buffer)
|
||||||
(define-key map (kbd "C-x C-e") #'flan-eval-last-sexp)
|
(define-key map (kbd "C-x C-e") #'flan-eval-last-sexp)
|
||||||
@ -236,7 +236,7 @@ line is off screen."
|
|||||||
;; a full expansion is stamped with the outermost name only.
|
;; a full expansion is stamped with the outermost name only.
|
||||||
(define-key map (kbd "C-c C-m") #'flan-macroexpand)
|
(define-key map (kbd "C-c C-m") #'flan-macroexpand)
|
||||||
;; The way out when a reload is refused: rebuild, relaunch, reconnect.
|
;; The way out when a reload is refused: rebuild, relaunch, reconnect.
|
||||||
(define-key map (kbd "C-c C-x") #'flan-dev-restart-program)
|
(define-key map (kbd "C-c C-x") #'flan-restart-program)
|
||||||
;; And beside it the cheap one, which is the same question — "run this
|
;; And beside it the cheap one, which is the same question — "run this
|
||||||
;; program" — asked of a process that is already there: `main' again, with
|
;; program" — asked of a process that is already there: `main' again, with
|
||||||
;; the globals as the finished run left them. The pairing is `C-c C-b'
|
;; the globals as the finished run left them. The pairing is `C-c C-b'
|
||||||
|
|||||||
@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
(require 'comint)
|
(require 'comint)
|
||||||
(require 'flan-mode)
|
(require 'flan-mode)
|
||||||
(require 'flan-dev)
|
(require 'flan)
|
||||||
|
|
||||||
(defcustom flan-repl-buffer "*flan-repl*"
|
(defcustom flan-repl-buffer "*flan-repl*"
|
||||||
"Name of the Flan REPL buffer."
|
"Name of the Flan REPL buffer."
|
||||||
@ -78,7 +78,7 @@
|
|||||||
;; The prompt gets completion, eldoc and M-. for the same names a buffer
|
;; The prompt gets completion, eldoc and M-. for the same names a buffer
|
||||||
;; does, and against the same program: they read the client's cache, which
|
;; does, and against the same program: they read the client's cache, which
|
||||||
;; is program-scoped, which is exactly what a prompt is.
|
;; is program-scoped, which is exactly what a prompt is.
|
||||||
(flan-dev-setup)
|
(flan-setup)
|
||||||
(setq-local font-lock-defaults '(flan-font-lock-keywords)))
|
(setq-local font-lock-defaults '(flan-font-lock-keywords)))
|
||||||
|
|
||||||
(defun flan-repl--complete-p (text)
|
(defun flan-repl--complete-p (text)
|
||||||
@ -105,7 +105,7 @@ should open a line, not send something the reader will reject."
|
|||||||
((string-empty-p code) (flan-repl--output ""))
|
((string-empty-p code) (flan-repl--output ""))
|
||||||
(t
|
(t
|
||||||
(let ((reply (condition-case err
|
(let ((reply (condition-case err
|
||||||
(flan-dev--request
|
(flan--request
|
||||||
(list :op "eval-expr" :code code :file "<repl>"))
|
(list :op "eval-expr" :code code :file "<repl>"))
|
||||||
(error (list :status "error"
|
(error (list :status "error"
|
||||||
:message (error-message-string err))))))
|
:message (error-message-string err))))))
|
||||||
@ -133,7 +133,7 @@ should open a line, not send something the reader will reject."
|
|||||||
"Open a prompt on the program `flan dev' is running.
|
"Open a prompt on the program `flan dev' is running.
|
||||||
Connects first if it has to."
|
Connects first if it has to."
|
||||||
(interactive)
|
(interactive)
|
||||||
(unless (and flan-dev--connection (process-live-p flan-dev--connection))
|
(unless (and flan--connection (process-live-p flan--connection))
|
||||||
(call-interactively #'flan-connect))
|
(call-interactively #'flan-connect))
|
||||||
(let ((buf (get-buffer-create flan-repl-buffer)))
|
(let ((buf (get-buffer-create flan-repl-buffer)))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
|
|||||||
@ -78,7 +78,7 @@
|
|||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
(require 'flan-dev)
|
(require 'flan)
|
||||||
(require 'subr-x)
|
(require 'subr-x)
|
||||||
|
|
||||||
(defgroup flan-watch nil
|
(defgroup flan-watch nil
|
||||||
@ -191,7 +191,7 @@ was the only consumer and wrong the moment it was not.")
|
|||||||
;; WHEN IT UPDATES. On the same timer, from the same reply. The two pictures
|
;; WHEN IT UPDATES. On the same timer, from the same reply. The two pictures
|
||||||
;; therefore cannot disagree — they are one table read, painted twice — and
|
;; therefore cannot disagree — they are one table read, painted twice — and
|
||||||
;; there is no second `:op "watch"' in flight, which is the invariant
|
;; there is no second `:op "watch"' in flight, which is the invariant
|
||||||
;; `flan-dev-settle-hook' exists to keep. As with the buffer, the timer decides
|
;; `flan-settle-hook' exists to keep. As with the buffer, the timer decides
|
||||||
;; how often the picture is repainted and not how fresh it is: the program
|
;; how often the picture is repainted and not how fresh it is: the program
|
||||||
;; writes every frame regardless.
|
;; writes every frame regardless.
|
||||||
;;
|
;;
|
||||||
@ -312,7 +312,7 @@ Guarded on the row's length so a short name cannot be claimed by accident."
|
|||||||
(defun flan-watch--ghost-paint (rows overflow)
|
(defun flan-watch--ghost-paint (rows overflow)
|
||||||
"Place inline overlays for ROWS. OVERFLOW means some name found no slot."
|
"Place inline overlays for ROWS. OVERFLOW means some name found no slot."
|
||||||
(flan-watch--ghost-clear)
|
(flan-watch--ghost-clear)
|
||||||
(let ((stale (and flan-dev--stopped t)))
|
(let ((stale (and flan--stopped t)))
|
||||||
(dolist (buf (flan-watch--ghost-buffers))
|
(dolist (buf (flan-watch--ghost-buffers))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(let* ((sites (flan-watch--ghost-sites))
|
(let* ((sites (flan-watch--ghost-sites))
|
||||||
@ -365,24 +365,24 @@ Guarded on the row's length so a short name cannot be claimed by accident."
|
|||||||
(defun flan-watch--settle ()
|
(defun flan-watch--settle ()
|
||||||
"Collect an outstanding watch reply, blocking if it has not arrived.
|
"Collect an outstanding watch reply, blocking if it has not arrived.
|
||||||
|
|
||||||
Hung on `flan-dev-settle-hook', so an ordinary request never reads the watch
|
Hung on `flan-settle-hook', so an ordinary request never reads the watch
|
||||||
timer's reply as its own. Blocking here is fine and blocking in the tick is
|
timer's reply as its own. Blocking here is fine and blocking in the tick is
|
||||||
not: this runs inside something a person asked for, which already waits, and
|
not: this runs inside something a person asked for, which already waits, and
|
||||||
what it waits for is a table read with nothing compiled behind it."
|
what it waits for is a table read with nothing compiled behind it."
|
||||||
(when flan-watch--pending
|
(when flan-watch--pending
|
||||||
(setq flan-watch--pending nil)
|
(setq flan-watch--pending nil)
|
||||||
(when-let* ((proc flan-dev--connection))
|
(when-let* ((proc flan--connection))
|
||||||
(when (process-live-p proc)
|
(when (process-live-p proc)
|
||||||
(ignore-errors (flan-watch--absorb (flan-dev--read-reply proc)))))))
|
(ignore-errors (flan-watch--absorb (flan--read-reply proc)))))))
|
||||||
|
|
||||||
(defun flan-watch--tick ()
|
(defun flan-watch--tick ()
|
||||||
"Collect the last reply if it has come, then ask again. Never blocks.
|
"Collect the last reply if it has come, then ask again. Never blocks.
|
||||||
|
|
||||||
Deliberately not `flan-dev--request', which waits for its answer: a
|
Deliberately not `flan--request', which waits for its answer: a
|
||||||
synchronous call on a 0.2s timer stalls Emacs's UI every tick, and a timer is
|
synchronous call on a 0.2s timer stalls Emacs's UI every tick, and a timer is
|
||||||
the one caller that must not. So this takes whatever has already arrived and
|
the one caller that must not. So this takes whatever has already arrived and
|
||||||
sends the next question, leaving at most one request in flight — the invariant
|
sends the next question, leaving at most one request in flight — the invariant
|
||||||
`flan-dev-settle-hook' exists to keep."
|
`flan-settle-hook' exists to keep."
|
||||||
(cond
|
(cond
|
||||||
;; Killing the buffer cancels the buffer's half of the subscription, and
|
;; Killing the buffer cancels the buffer's half of the subscription, and
|
||||||
;; only that. When it was the only consumer this stops the timer and
|
;; only that. When it was the only consumer this stops the timer and
|
||||||
@ -392,23 +392,23 @@ sends the next question, leaving at most one request in flight — the invariant
|
|||||||
((and (memq 'buffer flan-watch--consumers)
|
((and (memq 'buffer flan-watch--consumers)
|
||||||
(not (get-buffer flan-watch-buffer)))
|
(not (get-buffer flan-watch-buffer)))
|
||||||
(flan-watch--drop 'buffer))
|
(flan-watch--drop 'buffer))
|
||||||
((not (process-live-p flan-dev--connection))
|
((not (process-live-p flan--connection))
|
||||||
(flan-watch--paint "error:\nnot connected to a running program\n")
|
(flan-watch--paint "error:\nnot connected to a running program\n")
|
||||||
(flan-watch-stop))
|
(flan-watch-stop))
|
||||||
;; Something else owns the connection this instant — an evaluation is
|
;; Something else owns the connection this instant — an evaluation is
|
||||||
;; mid-flight. Skipping is right: its `flan-dev-settle-hook' has already
|
;; mid-flight. Skipping is right: its `flan-settle-hook' has already
|
||||||
;; taken any reply of ours, and the next tick is 0.2s away.
|
;; taken any reply of ours, and the next tick is 0.2s away.
|
||||||
(flan-dev--busy nil)
|
(flan--busy nil)
|
||||||
(t
|
(t
|
||||||
(when flan-watch--pending
|
(when flan-watch--pending
|
||||||
;; Taken off the connection either way. `flan-dev--extract-reply'
|
;; Taken off the connection either way. `flan--extract-reply'
|
||||||
;; deletes a frame before it reads it, so a payload that will not read
|
;; deletes a frame before it reads it, so a payload that will not read
|
||||||
;; has still been consumed — and a pending flag left standing after it
|
;; has still been consumed — and a pending flag left standing after it
|
||||||
;; would wait for ever for a reply that is no longer in the buffer,
|
;; would wait for ever for a reply that is no longer in the buffer,
|
||||||
;; which stops the timer sending anything again. One bad reply costs
|
;; which stops the timer sending anything again. One bad reply costs
|
||||||
;; one tick, not the session.
|
;; one tick, not the session.
|
||||||
(when-let* ((reply (condition-case nil
|
(when-let* ((reply (condition-case nil
|
||||||
(flan-dev--take-reply flan-dev--connection)
|
(flan--take-reply flan--connection)
|
||||||
(error (setq flan-watch--pending nil) nil))))
|
(error (setq flan-watch--pending nil) nil))))
|
||||||
(setq flan-watch--pending nil)
|
(setq flan-watch--pending nil)
|
||||||
(flan-watch--absorb reply)))
|
(flan-watch--absorb reply)))
|
||||||
@ -432,11 +432,11 @@ sends the next question, leaving at most one request in flight — the invariant
|
|||||||
;; would ask for a new window five times a second that nothing can
|
;; would ask for a new window five times a second that nothing can
|
||||||
;; fill. The guard lives here rather than in the runtime because
|
;; fill. The guard lives here rather than in the runtime because
|
||||||
;; "since you last looked" is the editor's policy, not the table's.
|
;; "since you last looked" is the editor's policy, not the table's.
|
||||||
;; `flan-dev--stopped' is the one place that state is tracked, and
|
;; `flan--stopped' is the one place that state is tracked, and
|
||||||
;; `flan-dev.el''s background poll keeps it current whether or not
|
;; `flan.el''s background poll keeps it current whether or not
|
||||||
;; anyone is evaluating.
|
;; anyone is evaluating.
|
||||||
(progn (flan-dev--send flan-dev--connection
|
(progn (flan--send flan--connection
|
||||||
(if flan-dev--stopped
|
(if flan--stopped
|
||||||
'(:op "watch")
|
'(:op "watch")
|
||||||
'(:op "watch" :reset t)))
|
'(:op "watch" :reset t)))
|
||||||
(setq flan-watch--pending t))
|
(setq flan-watch--pending t))
|
||||||
@ -456,14 +456,14 @@ writer, so it has to be told somebody is looking — and while nobody is, nothin
|
|||||||
writes the table at all, which is what makes a watch call in a program nobody is
|
writes the table at all, which is what makes a watch call in a program nobody is
|
||||||
debugging a load and a not-taken branch. It is sent once for the first
|
debugging a load and a not-taken branch. It is sent once for the first
|
||||||
consumer: two of them looking at one table is still one table."
|
consumer: two of them looking at one table is still one table."
|
||||||
(flan-dev--live-connection)
|
(flan--live-connection)
|
||||||
(unless flan-watch--consumers
|
(unless flan-watch--consumers
|
||||||
(let ((r (flan-dev--request '(:op "watch-enable" :on t))))
|
(let ((r (flan--request '(:op "watch-enable" :on t))))
|
||||||
(unless (equal (plist-get r :status) "ok")
|
(unless (equal (plist-get r :status) "ok")
|
||||||
(user-error "flan: %s" (or (plist-get r :message) "watch refused")))))
|
(user-error "flan: %s" (or (plist-get r :message) "watch refused")))))
|
||||||
(unless (memq consumer flan-watch--consumers)
|
(unless (memq consumer flan-watch--consumers)
|
||||||
(push consumer flan-watch--consumers))
|
(push consumer flan-watch--consumers))
|
||||||
(add-hook 'flan-dev-settle-hook #'flan-watch--settle)
|
(add-hook 'flan-settle-hook #'flan-watch--settle)
|
||||||
(when flan-watch--timer (cancel-timer flan-watch--timer))
|
(when flan-watch--timer (cancel-timer flan-watch--timer))
|
||||||
(setq flan-watch--timer
|
(setq flan-watch--timer
|
||||||
(run-with-timer 0 flan-watch-interval #'flan-watch--tick)))
|
(run-with-timer 0 flan-watch-interval #'flan-watch--tick)))
|
||||||
@ -520,16 +520,16 @@ Tears down both consumers. `flan-watch--drop' is the way to stop one of them."
|
|||||||
(setq flan-watch--timer nil))
|
(setq flan-watch--timer nil))
|
||||||
;; Settle before disarming, or the disarm request reads the tick's reply.
|
;; Settle before disarming, or the disarm request reads the tick's reply.
|
||||||
(flan-watch--settle)
|
(flan-watch--settle)
|
||||||
(remove-hook 'flan-dev-settle-hook #'flan-watch--settle)
|
(remove-hook 'flan-settle-hook #'flan-watch--settle)
|
||||||
;; Only on a connection that is already live, and this is the important half.
|
;; Only on a connection that is already live, and this is the important half.
|
||||||
;; `flan-dev--request' *reconnects* — which is right for something a person
|
;; `flan--request' *reconnects* — which is right for something a person
|
||||||
;; did and wrong here, because this is also called from the tick, and the
|
;; did and wrong here, because this is also called from the tick, and the
|
||||||
;; reason the tick calls it is that the connection has gone. Reconnecting
|
;; reason the tick calls it is that the connection has gone. Reconnecting
|
||||||
;; from a timer would quietly erase the `lost' state that exists to be seen,
|
;; from a timer would quietly erase the `lost' state that exists to be seen,
|
||||||
;; which `flan-dev.el' already forbids for its own poll timer. And there is
|
;; which `flan.el' already forbids for its own poll timer. And there is
|
||||||
;; nothing to disarm anyway: the table went with the program.
|
;; nothing to disarm anyway: the table went with the program.
|
||||||
(when (process-live-p flan-dev--connection)
|
(when (process-live-p flan--connection)
|
||||||
(ignore-errors (flan-dev--request '(:op "watch-enable" :on nil)))))
|
(ignore-errors (flan--request '(:op "watch-enable" :on nil)))))
|
||||||
|
|
||||||
;;; What ghost text still cannot show
|
;;; What ghost text still cannot show
|
||||||
|
|
||||||
@ -554,7 +554,7 @@ Tears down both consumers. `flan-watch--drop' is the way to stop one of them."
|
|||||||
;; - The module in the running program can be older than the buffer. A site
|
;; - The module in the running program can be older than the buffer. A site
|
||||||
;; you have typed but not yet installed with `C-c C-c' has no row, and one
|
;; you have typed but not yet installed with `C-c C-c' has no row, and one
|
||||||
;; you deleted but not yet installed still writes. Deliberately unreported:
|
;; you deleted but not yet installed still writes. Deliberately unreported:
|
||||||
;; the stale-caller machinery in `flan-dev.el' already tracks what needs
|
;; the stale-caller machinery in `flan.el' already tracks what needs
|
||||||
;; re-evaluating, and a second opinion about it here would be a worse one.
|
;; re-evaluating, and a second opinion about it here would be a worse one.
|
||||||
;;
|
;;
|
||||||
;; Still genuinely blocked on the checker, and unchanged by any of this: a
|
;; Still genuinely blocked on the checker, and unchanged by any of this: a
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -18,9 +18,9 @@
|
|||||||
|
|
||||||
(require 'flan-inspect)
|
(require 'flan-inspect)
|
||||||
(require 'flan-cnr)
|
(require 'flan-cnr)
|
||||||
;; For `flan-dev--auto-break', which is a decision about globals and windows
|
;; For `flan--auto-break', which is a decision about globals and windows
|
||||||
;; and needs neither a daemon nor a socket to be asked.
|
;; and needs neither a daemon nor a socket to be asked.
|
||||||
(require 'flan-dev)
|
(require 'flan)
|
||||||
|
|
||||||
(defvar test-flan--failures 0)
|
(defvar test-flan--failures 0)
|
||||||
(defvar test-flan--ran 0)
|
(defvar test-flan--ran 0)
|
||||||
@ -275,14 +275,14 @@
|
|||||||
(message "\nthe registry listings")
|
(message "\nthe registry listings")
|
||||||
|
|
||||||
(let* ((sent nil)
|
(let* ((sent nil)
|
||||||
(flan-dev--request-stub
|
(flan--request-stub
|
||||||
(lambda (form)
|
(lambda (form)
|
||||||
(setq sent form)
|
(setq sent form)
|
||||||
'(:status "ok"
|
'(:status "ok"
|
||||||
:types (("Enemy" 2 64) ("i32" 1 16))
|
:types (("Enemy" 2 64) ("i32" 1 16))
|
||||||
:blocks 3 :bytes 80 :overflow nil
|
:blocks 3 :bytes 80 :overflow nil
|
||||||
:note "every block the registry recorded"))))
|
:note "every block the registry recorded"))))
|
||||||
(cl-letf (((symbol-function 'flan-dev--request) flan-dev--request-stub)
|
(cl-letf (((symbol-function 'flan--request) flan--request-stub)
|
||||||
((symbol-function 'display-buffer) #'ignore))
|
((symbol-function 'display-buffer) #'ignore))
|
||||||
(let ((flan-allocations-buffer " *test-allocations*"))
|
(let ((flan-allocations-buffer " *test-allocations*"))
|
||||||
(flan-allocations)
|
(flan-allocations)
|
||||||
@ -301,7 +301,7 @@
|
|||||||
;; An overflowed table has blocks in the program that are in nobody's row, so
|
;; An overflowed table has blocks in the program that are in nobody's row, so
|
||||||
;; every number under it is a floor. Said before the numbers, because a reader
|
;; every number under it is a floor. Said before the numbers, because a reader
|
||||||
;; who missed it would quote them as counts.
|
;; who missed it would quote them as counts.
|
||||||
(cl-letf (((symbol-function 'flan-dev--request)
|
(cl-letf (((symbol-function 'flan--request)
|
||||||
(lambda (_) '(:status "ok" :types (("Enemy" 1 32)) :blocks 1 :bytes 32
|
(lambda (_) '(:status "ok" :types (("Enemy" 1 32)) :blocks 1 :bytes 32
|
||||||
:overflow t)))
|
:overflow t)))
|
||||||
((symbol-function 'display-buffer) #'ignore))
|
((symbol-function 'display-buffer) #'ignore))
|
||||||
@ -315,7 +315,7 @@
|
|||||||
;; And a release build, which records nothing and says so. The refusal comes
|
;; And a release build, which records nothing and says so. The refusal comes
|
||||||
;; back as an ordinary error status and reaches the person, rather than an
|
;; back as an ordinary error status and reaches the person, rather than an
|
||||||
;; empty listing that reads like a program holding nothing.
|
;; empty listing that reads like a program holding nothing.
|
||||||
(cl-letf (((symbol-function 'flan-dev--request)
|
(cl-letf (((symbol-function 'flan--request)
|
||||||
(lambda (_) '(:status "error"
|
(lambda (_) '(:status "error"
|
||||||
:message "the allocation registry is off; this is not a dev build")))
|
:message "the allocation registry is off; this is not a dev build")))
|
||||||
((symbol-function 'display-buffer) #'ignore))
|
((symbol-function 'display-buffer) #'ignore))
|
||||||
@ -1044,7 +1044,7 @@ unwind would send the next one to a daemon that is not there."
|
|||||||
|
|
||||||
;;; Opening the break buffer by itself
|
;;; Opening the break buffer by itself
|
||||||
|
|
||||||
;; `flan-dev--auto-break' is a decision — given the state the client is in,
|
;; `flan--auto-break' is a decision — given the state the client is in,
|
||||||
;; does the break buffer appear — so it is asked here with the state bound
|
;; does the break buffer appear — so it is asked here with the state bound
|
||||||
;; rather than by stopping a real program. Every guard in it exists because
|
;; rather than by stopping a real program. Every guard in it exists because
|
||||||
;; the answer is no in some state a person is actually in.
|
;; the answer is no in some state a person is actually in.
|
||||||
@ -1052,7 +1052,7 @@ unwind would send the next one to a daemon that is not there."
|
|||||||
(message "\nthe break buffer opening itself")
|
(message "\nthe break buffer opening itself")
|
||||||
|
|
||||||
(defun test-flan--auto-break (&rest bindings)
|
(defun test-flan--auto-break (&rest bindings)
|
||||||
"Non-nil if `flan-dev--auto-break' would show the buffer.
|
"Non-nil if `flan--auto-break' would show the buffer.
|
||||||
BINDINGS is a plist of extra state; the defaults are a live connection and a
|
BINDINGS is a plist of extra state; the defaults are a live connection and a
|
||||||
stopped program, which is the case where it should fire."
|
stopped program, which is the case where it should fire."
|
||||||
(let ((shown nil))
|
(let ((shown nil))
|
||||||
@ -1063,16 +1063,16 @@ stopped program, which is the case where it should fire."
|
|||||||
((symbol-function 'process-live-p)
|
((symbol-function 'process-live-p)
|
||||||
(lambda (_) (if (plist-member bindings :live)
|
(lambda (_) (if (plist-member bindings :live)
|
||||||
(plist-get bindings :live) t))))
|
(plist-get bindings :live) t))))
|
||||||
(let ((flan-dev--stopped
|
(let ((flan--stopped
|
||||||
(if (plist-member bindings :stopped)
|
(if (plist-member bindings :stopped)
|
||||||
(plist-get bindings :stopped) "Missing"))
|
(plist-get bindings :stopped) "Missing"))
|
||||||
(flan-dev-break-on-stop
|
(flan-break-on-stop
|
||||||
(if (plist-member bindings :setting)
|
(if (plist-member bindings :setting)
|
||||||
(plist-get bindings :setting) 'display))
|
(plist-get bindings :setting) 'display))
|
||||||
(flan-dev--busy (plist-get bindings :busy))
|
(flan--busy (plist-get bindings :busy))
|
||||||
(executing-kbd-macro (plist-get bindings :macro))
|
(executing-kbd-macro (plist-get bindings :macro))
|
||||||
(flan-dev--connection 'stub))
|
(flan--connection 'stub))
|
||||||
(flan-dev--auto-break)))
|
(flan--auto-break)))
|
||||||
shown))
|
shown))
|
||||||
|
|
||||||
(test-flan--check "a stopped program opens it"
|
(test-flan--check "a stopped program opens it"
|
||||||
@ -1081,7 +1081,7 @@ stopped program, which is the case where it should fire."
|
|||||||
(not (test-flan--auto-break :stopped nil)))
|
(not (test-flan--auto-break :stopped nil)))
|
||||||
(test-flan--check "nor does a connection that has gone"
|
(test-flan--check "nor does a connection that has gone"
|
||||||
(not (test-flan--auto-break :live nil)))
|
(not (test-flan--auto-break :live nil)))
|
||||||
;; The reason it is deferred at all: `flan-dev--absorb' notices the stop in the
|
;; The reason it is deferred at all: `flan--absorb' notices the stop in the
|
||||||
;; middle of reading a reply, and three more requests down the same socket
|
;; middle of reading a reply, and three more requests down the same socket
|
||||||
;; would interleave two conversations.
|
;; would interleave two conversations.
|
||||||
(test-flan--check "nor while a request is still in flight"
|
(test-flan--check "nor while a request is still in flight"
|
||||||
@ -1118,7 +1118,7 @@ stopped program, which is the case where it should fire."
|
|||||||
;;; The macroexpansion buffer
|
;;; The macroexpansion buffer
|
||||||
|
|
||||||
;; The same kind of thing again: a reply in, a buffer out. What the live test
|
;; The same kind of thing again: a reply in, a buffer out. What the live test
|
||||||
;; in test-flan-dev.el cannot easily reach is the shape where *nothing*
|
;; in test-flan.el cannot easily reach is the shape where *nothing*
|
||||||
;; expanded — a head that is not a macro, and a macro whose answer is its own
|
;; expanded — a head that is not a macro, and a macro whose answer is its own
|
||||||
;; call — because both have to be arranged in a program. Here they are a
|
;; call — because both have to be arranged in a program. Here they are a
|
||||||
;; plist.
|
;; plist.
|
||||||
|
|||||||
@ -141,7 +141,7 @@ what bounds its cost; a `with-temp-buffer' would be scanned by nothing."
|
|||||||
"(watch-i64 \"ticks\" ticks)\n"
|
"(watch-i64 \"ticks\" ticks)\n"
|
||||||
"(watch-i64 \"gone\" g)\n")))
|
"(watch-i64 \"gone\" g)\n")))
|
||||||
(flan-watch--consumers '(ghost))
|
(flan-watch--consumers '(ghost))
|
||||||
(flan-dev--stopped nil))
|
(flan--stopped nil))
|
||||||
(flan-watch--ghost-paint '(("ticks" . "42")) nil)
|
(flan-watch--ghost-paint '(("ticks" . "42")) nil)
|
||||||
(test-flan--check
|
(test-flan--check
|
||||||
"a site whose name is in the table gets an overlay, and one that is not does not"
|
"a site whose name is in the table gets an overlay, and one that is not does not"
|
||||||
@ -163,14 +163,14 @@ what bounds its cost; a `with-temp-buffer' would be scanned by nothing."
|
|||||||
(equal (nth 2 (test-flan-watch--strings))
|
(equal (nth 2 (test-flan-watch--strings))
|
||||||
" => no slot: the table is full"))
|
" => no slot: the table is full"))
|
||||||
|
|
||||||
(setq flan-dev--stopped "BoundsError")
|
(setq flan--stopped "BoundsError")
|
||||||
(flan-watch--ghost-paint '(("ticks" . "42")) nil)
|
(flan-watch--ghost-paint '(("ticks" . "42")) nil)
|
||||||
(test-flan--check
|
(test-flan--check
|
||||||
"stopping the program marks every overlay, not the buffer's modeline only"
|
"stopping the program marks every overlay, not the buffer's modeline only"
|
||||||
(equal (test-flan-watch--strings)
|
(equal (test-flan-watch--strings)
|
||||||
'(" => 42 one slot, 2 sites last frame"
|
'(" => 42 one slot, 2 sites last frame"
|
||||||
" => 42 one slot, 2 sites last frame")))
|
" => 42 one slot, 2 sites last frame")))
|
||||||
(setq flan-dev--stopped nil)
|
(setq flan--stopped nil)
|
||||||
|
|
||||||
;; The whole answer to invalidating an overlay whose line moved: no overlay
|
;; The whole answer to invalidating an overlay whose line moved: no overlay
|
||||||
;; outlives a repaint, so there is nothing to invalidate.
|
;; outlives a repaint, so there is nothing to invalidate.
|
||||||
@ -219,24 +219,24 @@ what bounds its cost; a `with-temp-buffer' would be scanned by nothing."
|
|||||||
;; paused it. So the tick must drop `:reset' while stopped and keep reading.
|
;; paused it. So the tick must drop `:reset' while stopped and keep reading.
|
||||||
;;
|
;;
|
||||||
;; Asserted at the level the rest of this file works at: no daemon, no socket.
|
;; Asserted at the level the rest of this file works at: no daemon, no socket.
|
||||||
;; The tick is a function from `flan-dev--stopped' to the form it puts on the
|
;; The tick is a function from `flan--stopped' to the form it puts on the
|
||||||
;; wire, and that is the whole claim, so `flan-dev--send' and `process-live-p'
|
;; wire, and that is the whole claim, so `flan--send' and `process-live-p'
|
||||||
;; are stubs. What this cannot reach is the daemon actually honouring the
|
;; are stubs. What this cannot reach is the daemon actually honouring the
|
||||||
;; absent field; `test/test_dev.ml' drives a real program for that.
|
;; absent field; `test/test_dev.ml' drives a real program for that.
|
||||||
|
|
||||||
(defun test-flan-watch--tick-form (stopped)
|
(defun test-flan-watch--tick-form (stopped)
|
||||||
"The form `flan-watch--tick' sends with the program STOPPED or not."
|
"The form `flan-watch--tick' sends with the program STOPPED or not."
|
||||||
(let ((sent nil)
|
(let ((sent nil)
|
||||||
(flan-dev--stopped stopped)
|
(flan--stopped stopped)
|
||||||
(flan-dev--connection 'a-process)
|
(flan--connection 'a-process)
|
||||||
(flan-dev--busy nil)
|
(flan--busy nil)
|
||||||
(flan-watch--pending nil)
|
(flan-watch--pending nil)
|
||||||
;; Not `buffer': that consumer checks for a live watch buffer first and
|
;; Not `buffer': that consumer checks for a live watch buffer first and
|
||||||
;; would drop the subscription instead of ticking.
|
;; would drop the subscription instead of ticking.
|
||||||
(flan-watch--consumers '(ghost)))
|
(flan-watch--consumers '(ghost)))
|
||||||
(cl-letf (((symbol-function 'process-live-p) (lambda (_) t))
|
(cl-letf (((symbol-function 'process-live-p) (lambda (_) t))
|
||||||
((symbol-function 'flan-dev--take-reply) (lambda (_) nil))
|
((symbol-function 'flan--take-reply) (lambda (_) nil))
|
||||||
((symbol-function 'flan-dev--send)
|
((symbol-function 'flan--send)
|
||||||
(lambda (_proc form) (setq sent form))))
|
(lambda (_proc form) (setq sent form))))
|
||||||
(flan-watch--tick)
|
(flan-watch--tick)
|
||||||
(list sent flan-watch--pending))))
|
(list sent flan-watch--pending))))
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -112,7 +112,7 @@ let () =
|
|||||||
let code =
|
let code =
|
||||||
Sys.command
|
Sys.command
|
||||||
(Printf.sprintf
|
(Printf.sprintf
|
||||||
"emacs -Q --batch -L ../../../emacs -l ../../../emacs/test-flan-dev.el \
|
"emacs -Q --batch -L ../../../emacs -l ../../../emacs/test-flan.el \
|
||||||
-- %s %s %s %s 2>&1"
|
-- %s %s %s %s 2>&1"
|
||||||
(Filename.quote sock) (Filename.quote buf) (Filename.quote flan_abs)
|
(Filename.quote sock) (Filename.quote buf) (Filename.quote flan_abs)
|
||||||
(Filename.quote program))
|
(Filename.quote program))
|
||||||
|
|||||||
@ -290,7 +290,7 @@ let () =
|
|||||||
let t, _ = Session.create ~file:"../sand.flan" () in
|
let t, _ = Session.create ~file:"../sand.flan" () in
|
||||||
let src = In_channel.with_open_bin "../sand.flan" In_channel.input_all in
|
let src = In_channel.with_open_bin "../sand.flan" In_channel.input_all in
|
||||||
(* [~origin] is the buffer's own path and both editor paths send it
|
(* [~origin] is the buffer's own path and both editor paths send it
|
||||||
(flan-dev.el's `:file (or buffer-file-name "<buffer>")`). Omitting it here
|
(flan.el's `:file (or buffer-file-name "<buffer>")`). Omitting it here
|
||||||
was testing a request the editor never sends. It used to matter to this
|
was testing a request the editor never sends. It used to matter to this
|
||||||
case for a second reason — sand.flan embedded brush.png, and an embedded
|
case for a second reason — sand.flan embedded brush.png, and an embedded
|
||||||
path resolves relative to the file the form is written in, so the default
|
path resolves relative to the file the form is written in, so the default
|
||||||
|
|||||||
@ -1731,7 +1731,7 @@ retains three, permanently and correctly.</p>
|
|||||||
<code>lisp-mode</code>'s syntax table, so sexp motion, paren matching and indentation are
|
<code>lisp-mode</code>'s syntax table, so sexp motion, paren matching and indentation are
|
||||||
already right. It adds Flan's brackets — <code>[</code> and <code>{</code> are brackets,
|
already right. It adds Flan's brackets — <code>[</code> and <code>{</code> are brackets,
|
||||||
not symbol characters, since every binding list and every type is written with them — and
|
not symbol characters, since every binding list and every type is written with them — and
|
||||||
the characters a Flan name may contain. <code>emacs/flan-dev.el</code> is the client;
|
the characters a Flan name may contain. <code>emacs/flan.el</code> is the client;
|
||||||
there is no parser in it.</p>
|
there is no parser in it.</p>
|
||||||
|
|
||||||
<h3>Setting up</h3>
|
<h3>Setting up</h3>
|
||||||
@ -1745,15 +1745,15 @@ the client, the REPL, the inspector and the conditions buffer all load on first
|
|||||||
|
|
||||||
<p><code>flan-dape.el</code> is separate on purpose, so <code>flan-mode</code> works
|
<p><code>flan-dape.el</code> is separate on purpose, so <code>flan-mode</code> works
|
||||||
without dape installed. You also need <code>flan</code> on your <code>PATH</code>, or
|
without dape installed. You also need <code>flan</code> on your <code>PATH</code>, or
|
||||||
<code>flan-dev-command</code> pointed at it.</p>
|
<code>flan-command</code> pointed at it.</p>
|
||||||
|
|
||||||
<h3>Starting a program</h3>
|
<h3>Starting a program</h3>
|
||||||
|
|
||||||
<p><code>M-x flan-dev</code> runs <code>flan dev</code> on a file, waits for it to come up
|
<p><code>M-x flan</code> runs <code>flan dev</code> on a file, waits for it to come up
|
||||||
and connects. <kbd>C-c C-z</kbd> attaches to one that is already running, looking for
|
and connects. <kbd>C-c C-z</kbd> attaches to one that is already running, looking for
|
||||||
<code>.flan-dev.sock</code> upward from the buffer, so from anywhere in the project it
|
<code>.flan-dev.sock</code> upward from the buffer, so from anywhere in the project it
|
||||||
finds the one program you have going. <kbd>C-c C-q</kbd> disconnects and leaves it
|
finds the one program you have going. <kbd>C-c C-q</kbd> disconnects and leaves it
|
||||||
running; <code>M-x flan-dev-quit</code> stops it, but only one this Emacs started — a
|
running; <code>M-x flan-quit</code> stops it, but only one this Emacs started — a
|
||||||
daemon you launched in a terminal is not Emacs' to kill, and it says so rather than doing
|
daemon you launched in a terminal is not Emacs' to kill, and it says so rather than doing
|
||||||
something surprising.</p>
|
something surprising.</p>
|
||||||
|
|
||||||
@ -1782,8 +1782,8 @@ something surprising.</p>
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>Some commands have no key. <code>M-x flan-dev</code> starts a program and
|
<p>Some commands have no key. <code>M-x flan</code> starts a program and
|
||||||
<code>M-x flan-dev-quit</code> stops it. <code>M-x flan-watch</code> opens the watch
|
<code>M-x flan-quit</code> stops it. <code>M-x flan-watch</code> opens the watch
|
||||||
buffer, which shows values <em>while the program runs</em> rather than while it is
|
buffer, which shows values <em>while the program runs</em> rather than while it is
|
||||||
stopped, and <code>M-x flan-watch-ghost-mode</code> shows the same values inline at the
|
stopped, and <code>M-x flan-watch-ghost-mode</code> shows the same values inline at the
|
||||||
call that wrote each one. <code>M-x flan-inspect-address</code> roots an inspection at a
|
call that wrote each one. <code>M-x flan-inspect-address</code> roots an inspection at a
|
||||||
@ -1879,13 +1879,13 @@ answers with the outer binding.</p>
|
|||||||
<div class="scroll">
|
<div class="scroll">
|
||||||
<table>
|
<table>
|
||||||
<tr><th>Setting</th><th>Default</th><th>What it is</th></tr>
|
<tr><th>Setting</th><th>Default</th><th>What it is</th></tr>
|
||||||
<tr><td><code>flan-dev-command</code></td><td><code>"flan"</code></td><td>the compiler binary</td></tr>
|
<tr><td><code>flan-command</code></td><td><code>"flan"</code></td><td>the compiler binary</td></tr>
|
||||||
<tr><td><code>flan-dev-socket-name</code></td><td><code>".flan-dev.sock"</code></td><td>what <kbd>C-c C-z</kbd> searches for</td></tr>
|
<tr><td><code>flan-socket-name</code></td><td><code>".flan-dev.sock"</code></td><td>what <kbd>C-c C-z</kbd> searches for</td></tr>
|
||||||
<tr><td><code>flan-dev-echo-result</code></td><td><code>t</code></td><td>print <kbd>C-x C-e</kbd>'s value in the echo area</td></tr>
|
<tr><td><code>flan-echo-result</code></td><td><code>t</code></td><td>print <kbd>C-x C-e</kbd>'s value in the echo area</td></tr>
|
||||||
<tr><td><code>flan-dev-names-shown</code></td><td><code>4</code></td><td>how many names to list before counting them</td></tr>
|
<tr><td><code>flan-names-shown</code></td><td><code>4</code></td><td>how many names to list before counting them</td></tr>
|
||||||
<tr><td><code>flan-dev-output-buffer</code></td><td><code>"*flan-output*"</code></td><td>where the program's output goes</td></tr>
|
<tr><td><code>flan-output-buffer</code></td><td><code>"*flan-output*"</code></td><td>where the program's output goes</td></tr>
|
||||||
<tr><td><code>flan-dev-poll-interval</code></td><td><code>1.0</code></td><td>seconds between checks for whether it stopped</td></tr>
|
<tr><td><code>flan-poll-interval</code></td><td><code>1.0</code></td><td>seconds between checks for whether it stopped</td></tr>
|
||||||
<tr><td><code>flan-dev-start-timeout</code></td><td><code>60</code></td><td>seconds to wait for a program to come up</td></tr>
|
<tr><td><code>flan-start-timeout</code></td><td><code>60</code></td><td>seconds to wait for a program to come up</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user