| Commit message (Collapse) | Author |
|
The bumpy one, again. Every `.py` outside `vendor/` plus the three `contrib/`
scripts that are Python with no extension: 60 files, 6,714 lines rewritten, no
behaviour changed. Nothing here is worth reading -- the next commit adds it to
`.git-blame-ignore-revs` so `git blame` walks past it.
It is a bigger reformat than the C was, 60% of the lines against 17%, and for a
reason worth writing down rather than tuning away: ruff and black break a call that
does not fit onto one argument per line, where this code aligned the continuation
under the opening paren. The test suite is thousands of `check("some prose", cond,
detail)` calls, so nearly every one of them changed shape and the suite grew 3,308
lines. Line length was the one lever that moved it -- 120 columns would have been a
40% reformat and no growth at all -- and it was left at 88, because picking an
unusual width to dodge a one-time diff is paying forever to avoid paying once.
Import sorting came with it. Two files had `import os, pty, uuid, select, struct,
sys, termios, time, fcntl, signal` on one line and now have ten.
Verified after, not before, because a formatter that alters behaviour would be
worse than none:
- `make retest`, 1801 checks green -- and this reformats the suite that does the
checking, including `harness.py`, which every one of those files imports.
- `make test-live`, the tty tests the fast suite skips. They matter here more than
usual: `live_input.py` and `live_m0.py` are two of the files whose comma-imports
were split, and nothing in the fast suite would have noticed if that broke them.
- All 60 files still compile, `make fmt` twice in a row changes nothing the second
time, and `ruff check --select I` has nothing left to say.
|
|
A config that half-applied said nothing. An unknown shader, a binding
that does not parse, an include that is not there: the file loaded, that
line did not, and the session announced "config reloaded" as though
nothing had happened. Every one of those messages was already being
produced -- config_load has filled `err` on a successful load since it
was written -- and then dropped on the floor by every caller, because a
non-zero return meant "fine".
So the complaint from the last load is kept, and the front end says it
where it would have said "config reloaded". Once at startup too: a config
that loaded with a complaint still started the session, and the stderr
line goes where nobody attached can read it. The `reload` control verb
answers `{"ok":true,"warning":"..."}` -- ok, because the file did apply,
with the reason attached for a script that cares.
Two things fell out of writing the test for it.
An include's complaint was reported by nobody when the file in the middle
was fine. apply_includes only looked at the return value, so a theme that
loaded while *its* include was missing swallowed the message: the child
returned true, and true meant there was nothing to say. The complaint now
travels up whether or not the include itself loaded.
And a complaint now carries the name of the file it happened in, exactly
once -- added by the file that produced it, never by the files that
included it, because prefixing at every level builds a chain that
truncates before the part that matters. So:
t.kdl: unknown shader: bloom
keys.kdl: line 2: unknown action fly
b.kdl: includes nested too deep (a cycle?)
cannot open /home/you/.config/sl0ppty/themes/nope.kdl
which is enough to know which file to open, in a message that fits in a
toast.
|
|
include "themes/amber.kdl"
include "keys/vim.kdl" "shaders/crt.kdl"
which is how you switch a theme by editing one line rather than pasting
one in. Nothing about it is theme-specific: an include is another config
file applied here, so the same line composes keys, shader chains, states
or geometry, and contrib/themes stops being a directory you copy out of.
A relative path is relative to *the file doing the including*, never to
the directory the session was started from -- a config is a thing on disk
that refers to its neighbours, and where you were standing is not part of
what it means. A leading `~` is a home directory, an absolute path is
itself, and an included file may include others.
What you include is the base: the file with the `include` line in it wins
wherever they disagree, and a later include wins over an earlier one.
That holds wherever the line sits, because the loader reads a document by
asking it for the keys it knows rather than walking it top to bottom --
so "here" is not a position it could honour, and "the file you are
editing wins" is the rule worth having anyway. It is what makes a theme
something you can put two lines on top of.
A depth limit rather than a set of files already seen, because the two
failures it has to stop are the same failure: a config that includes
itself and a config eleven files deep are both a mistake, and the message
says which one you have. A file that will not load is skipped and the
rest of the config still applies (D9) -- losing your keybindings over a
mistyped theme name would be the worse answer.
The loader was already shaped for this: `config_load` applied one parsed
root onto a config_t, so it becomes a recursive `load_into` that applies
its includes first and then itself. Errors from an include get their own
buffer, so a broken theme cannot overwrite a message the file that
included it has already produced.
tests/test_include.py covers the two rules that carry the weight -- the
outer file winning either way round, and a nested include resolving
against the file that wrote it -- plus multiple files on one line, `~`, a
binding from an included file, a missing file, a cycle, switching theme
through a reload, and every file in contrib/themes applying as an
include, checked against each file's own frame_focus so it cannot pass by
looking default.
Not yet: an included file is not watched, so editing the theme itself
does not reload the session. Editing the include line does.
|