aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-17 14:22:38 +0200
committeruser <user@clank>2026-08-17 14:22:38 +0200
commitec91ccffe631ae34b111bf6161fd0e3c487f684c (patch)
tree4a9fdbb720d9bf03edd5f538d1d87afd2bf51bfb /src
parentsl0ppty: clang-format, and a hook that runs it on what you staged (diff)
downloadslosh-ec91ccffe631ae34b111bf6161fd0e3c487f684c.tar.gz
slosh-ec91ccffe631ae34b111bf6161fd0e3c487f684c.tar.xz
slosh-ec91ccffe631ae34b111bf6161fd0e3c487f684c.zip
sl0ppty: clang-format the tree
The bumpy one. `make fmt` over every `.c` and `.h` outside `vendor/`: 32 files, 1,843 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. Two thirds of it is alignment the formatter now owns: trailing comments in a struct, continuation lines under a signature. The rest is the hand-packed tables opening up to one entry per line -- `ACTIONS`, `NAMED_KEYS`, `ACTION_HELP`. That is a real loss of density and a real gain in diffs: adding an action was a reflow of the block and is now one line. Anything worth keeping packed can be fenced with `// clang-format off`; nothing was, on the grounds that a table is the thing a formatter is for. **One change is not formatting.** `src/config.h` had three trailing comments glued onto one field: uint16_t hover_delay_ms; /* how long the pointer must rest to arm a guide */ /* how long an announcement stays up */ /* rows per wheel notch */ -- `toast_ms`'s and `scroll_lines`' comments, landed on their neighbour by an earlier edit, documenting the wrong things ever since. It is in this commit because it is what caught it: clang-format could not settle on that line, wrapping it one way and then re-indenting the wrap on a second pass, so `make fmt` was not idempotent. The comments are back where they belong and it is. Verified after the reformat, not before: `make clean && make all` is warning-free, `make retest` is 1801 checks green, and `make fmt` twice in a row changes nothing the second time. A formatter that alters behaviour would be worse than none, so the gate was the whole suite rather than a reading of the diff.
Diffstat (limited to 'src')
-rw-r--r--src/app.c1103
-rw-r--r--src/app.h21
-rw-r--r--src/client.c26
-rw-r--r--src/cmd.c53
-rw-r--r--src/config.c464
-rw-r--r--src/config.h18
-rw-r--r--src/expr.c370
-rw-r--r--src/graphics.c6
-rw-r--r--src/graphics.h22
-rw-r--r--src/input.c326
-rw-r--r--src/input.h26
-rw-r--r--src/json.c26
-rw-r--r--src/json.h2
-rw-r--r--src/jsonval.c102
-rw-r--r--src/jsonval.h7
-rw-r--r--src/kdl.c17
-rw-r--r--src/kdl.h3
-rw-r--r--src/main.c57
-rw-r--r--src/osc5577.c76
-rw-r--r--src/pane.c85
-rw-r--r--src/project.c6
-rw-r--r--src/proto.c6
-rw-r--r--src/pty.c5
-rw-r--r--src/screen.c46
-rw-r--r--src/server.c122
-rw-r--r--src/shader.c41
-rw-r--r--src/shader_abi.h28
-rw-r--r--src/sl0ppty.h4
28 files changed, 1752 insertions, 1316 deletions
diff --git a/src/app.c b/src/app.c
index 7fa6b9e..ac676d0 100644
--- a/src/app.c
+++ b/src/app.c
@@ -213,10 +213,10 @@ struct node {
* meet there. Recomputed every frame with the layout it describes. */
typedef struct {
rect_t r;
- uint32_t h_id[2]; /* row boundaries meeting here: these move vertically */
+ uint32_t h_id[2]; /* row boundaries meeting here: these move vertically */
size_t h_edge[2];
size_t nh;
- uint32_t v_id[2]; /* column boundaries: these move horizontally */
+ uint32_t v_id[2]; /* column boundaries: these move horizontally */
size_t v_edge[2];
size_t nv;
} corner_t;
@@ -266,17 +266,17 @@ struct app {
DRAG_BORDER,
DRAG_TAB,
} kind;
- uint32_t src; /* pane being dragged, or the split being resized */
- uint32_t target; /* pane under the pointer, for the drop highlight */
+ uint32_t src; /* pane being dragged, or the split being resized */
+ uint32_t target; /* pane under the pointer, for the drop highlight */
/* ...or the tab under it, when a pane is dragged over the strip: the same
* gesture with a different kind of destination. Never both -- the pointer is
* over one thing, and two highlights would be two promises. */
uint32_t tab_target;
bool new_tab_target; /* the strip's `+`: a tab of its own */
- size_t edge; /* which boundary of that split */
- uint16_t x, y; /* where the pointer was at the last event */
- bool moved; /* a press that never moves is a click */
- char side; /* border press: 'l' 'r' 't' 'b' */
+ size_t edge; /* which boundary of that split */
+ uint16_t x, y; /* where the pointer was at the last event */
+ bool moved; /* a press that never moves is a click */
+ char side; /* border press: 'l' 'r' 't' 'b' */
/* A corner drag carries the boundaries it is moving, not an index into
* the corner list: that list is rebuilt from the layout every frame, and
* the layout is the thing being changed. Halfway through a drag the
@@ -324,12 +324,7 @@ struct app {
* rather than two that would drift apart, for the same reason the rename
* editor is. Only one can be open, which is what makes sharing the query
* and the selection honest rather than a saving. */
- enum {
- PICK_NONE = 0,
- PICK_FINDER,
- PICK_PALETTE,
- PICK_WORKSPACES
- } picker;
+ enum { PICK_NONE = 0, PICK_FINDER, PICK_PALETTE, PICK_WORKSPACES } picker;
/* What the project picker is listing: scanned once when it opens, because
* draw_picker asks for its rows every frame and a readdir per repaint is a
* filesystem walk at 120Hz. Once per opening is when the answer has to be
@@ -479,8 +474,9 @@ static void on_pane_shader(app_t *a, pane_t *p, const char *payload) {
return;
}
if (!chrome && !content) {
- snprintf(reply, sizeof reply,
- "\033]5577;1;shader-reply;error;where must be content or chrome\033\\");
+ snprintf(
+ reply, sizeof reply,
+ "\033]5577;1;shader-reply;error;where must be content or chrome\033\\");
pane_write(p, reply, strlen(reply));
return;
}
@@ -488,12 +484,12 @@ static void on_pane_shader(app_t *a, pane_t *p, const char *payload) {
char err[192] = {0};
const char *text = semi ? semi + 1 : "";
size_t nchrome = 0, ncontent = 0;
- bool ok = app_set_pane_shaders(a, b.found->id, chrome, text, &nchrome, &ncontent,
- err, sizeof err);
+ bool ok = app_set_pane_shaders(a, b.found->id, chrome, text, &nchrome,
+ &ncontent, err, sizeof err);
if (ok)
snprintf(reply, sizeof reply,
- "\033]5577;1;shader-reply;ok;%zu chrome, %zu content\033\\", nchrome,
- ncontent);
+ "\033]5577;1;shader-reply;ok;%zu chrome, %zu content\033\\",
+ nchrome, ncontent);
else
snprintf(reply, sizeof reply, "\033]5577;1;shader-reply;error;%s\033\\",
err[0] ? err : "refused");
@@ -514,8 +510,8 @@ static void on_pane_shader_load(app_t *a, pane_t *p, const char *payload) {
err, sizeof err);
if (ok)
snprintf(reply, sizeof reply,
- "\033]5577;1;shader-reply;ok;%zu chrome, %zu content\033\\", nchrome,
- ncontent);
+ "\033]5577;1;shader-reply;ok;%zu chrome, %zu content\033\\",
+ nchrome, ncontent);
else
snprintf(reply, sizeof reply, "\033]5577;1;shader-reply;error;%s\033\\",
err[0] ? err : "refused");
@@ -575,7 +571,8 @@ static void toasts_expire(app_t *a) {
int app_next_deadline_ms(app_t *a) {
int64_t soonest = -1;
for (size_t i = 0; i < a->ntoasts; i++)
- if (soonest < 0 || a->toasts[i].until < soonest) soonest = a->toasts[i].until;
+ if (soonest < 0 || a->toasts[i].until < soonest)
+ soonest = a->toasts[i].until;
if (a->ptr_valid && a->painted) {
int64_t due = a->ptr_still_since + CFG.hover_delay_ms;
@@ -635,14 +632,15 @@ static const char *hint_for(app_t *a, const char *action) {
if (strncmp(action, "scrollbottom:", 13) == 0) return "back to the bottom";
if (strncmp(action, "panetitle:", 10) == 0)
return "double-click to rename \u00b7 drag to move";
- if (strncmp(action, "title:", 6) == 0) return "drag to move \u00b7 click to split up";
+ if (strncmp(action, "title:", 6) == 0)
+ return "drag to move \u00b7 click to split up";
if (strncmp(action, "border:", 7) == 0) {
const char *side = strrchr(action, ':');
switch (side && side[1] ? side[1] : 0) {
- case 'l': return "click to split left";
- case 'r': return "click to split right";
- case 't': return "click to split up";
- default: return "click to split down";
+ case 'l': return "click to split left";
+ case 'r': return "click to split right";
+ case 't': return "click to split up";
+ default: return "click to split down";
}
}
if (strncmp(action, "edge:", 5) == 0) return "drag to resize";
@@ -681,7 +679,8 @@ static void draw_min_bar(app_t *a, screen_t *s) {
uint16_t right = (uint16_t)(bar.x + bar.w);
/* A legend, so a row of bare names is not a mystery. */
- x = (uint16_t)(x + screen_text(s, x, bar.y, CFG.min_mark, MINBAR, NO_COLOR, 0));
+ x = (uint16_t)(x +
+ screen_text(s, x, bar.y, CFG.min_mark, MINBAR, NO_COLOR, 0));
x = (uint16_t)(x + 1);
for (size_t i = 0; i < nmin && x < right; i++) {
@@ -806,9 +805,11 @@ static void draw_status_line(app_t *a, screen_t *s) {
const char *pt = pane_title(f->pane);
const char *pp = f->purpose[0] ? f->purpose : NULL;
if (pp)
- n += (size_t)snprintf(line + n, sizeof line - n, "%s%s", n ? " \u00b7 " : "", pp);
+ n += (size_t)snprintf(line + n, sizeof line - n, "%s%s",
+ n ? " \u00b7 " : "", pp);
else if (pt && *pt)
- n += (size_t)snprintf(line + n, sizeof line - n, "%s%s", n ? " \u00b7 " : "", pt);
+ n += (size_t)snprintf(line + n, sizeof line - n, "%s%s",
+ n ? " \u00b7 " : "", pt);
}
if (n > (size_t)(right - x)) line[right - x] = 0;
if (n) screen_text(s, x, y, line, STATUS_C, NO_COLOR, 0);
@@ -898,7 +899,10 @@ static void on_pane_notify(pane_t *p, const char *title, const char *body,
if (title && *title && body && *body)
snprintf(msg, sizeof msg, "%s: %s", title, body);
else
- snprintf(msg, sizeof msg, "%s", (title && *title) ? title : body ? body : "");
+ snprintf(msg, sizeof msg, "%s",
+ (title && *title) ? title
+ : body ? body
+ : "");
app_toast((app_t *)ud, msg);
}
@@ -1343,8 +1347,8 @@ static void layout_node(node_t *n, rect_t r, layout_ctx_t *ctx) {
return;
}
- uint16_t gap = n->dir == SPLIT_COLS ? (uint16_t)(CFG.gap * CFG.gap_aspect)
- : CFG.gap;
+ uint16_t gap =
+ n->dir == SPLIT_COLS ? (uint16_t)(CFG.gap * CFG.gap_aspect) : CFG.gap;
uint16_t total = n->dir == SPLIT_COLS ? r.w : r.h;
/* Does every child clear the floor? If not, this node collapses — a local
@@ -1589,8 +1593,10 @@ static void place_beside(app_t *a, tab_t *t, node_t *leaf, node_t *node,
sp->kids[before ? 1 : 0] = leaf;
sp->kids[before ? 0 : 1] = node;
sp->parent = leaf->parent;
- if (leaf->parent) replace_child(leaf->parent, leaf, sp);
- else t->root = sp;
+ if (leaf->parent)
+ replace_child(leaf->parent, leaf, sp);
+ else
+ t->root = sp;
leaf->parent = sp;
node->parent = sp;
}
@@ -1698,7 +1704,7 @@ static void split_focus_ui(app_t *a, split_dir_t dir) {
static split_dir_t preferred_dir(const node_t *leaf) {
uint16_t aspect = CFG.gap_aspect ? CFG.gap_aspect : 1;
return (uint32_t)leaf->rect.w >= (uint32_t)leaf->rect.h * aspect ? SPLIT_COLS
- : SPLIT_ROWS;
+ : SPLIT_ROWS;
}
/* Split whichever way there is room for, preferring the longer side.
@@ -1714,8 +1720,10 @@ static void split_focus_auto(app_t *a) {
split_dir_t want = preferred_dir(n);
split_dir_t other = want == SPLIT_COLS ? SPLIT_ROWS : SPLIT_COLS;
split_dir_t dir;
- if (split_fits(n, want)) dir = want;
- else if (split_fits(n, other)) dir = other;
+ if (split_fits(n, want))
+ dir = want;
+ else if (split_fits(n, other))
+ dir = other;
else {
app_toast(a, "no room to split");
return;
@@ -1762,8 +1770,10 @@ static void close_leaf(app_t *a, node_t *leaf) {
node_t *survivor = p->kids[0];
if (p->nkids == 1) { /* a split with one child is just that child */
survivor->parent = p->parent;
- if (p->parent) replace_child(p->parent, p, survivor);
- else t->root = survivor;
+ if (p->parent)
+ replace_child(p->parent, p, survivor);
+ else
+ t->root = survivor;
free(p->kids);
free(p);
}
@@ -1785,9 +1795,9 @@ static bool keep_corpse(const pane_t *p) {
* having had one. */
if (pane_ephemeral(p)) return false;
switch (CFG.keep_dead) {
- case KEEP_DEAD_ALL: return true;
- case KEEP_DEAD_NONE: return false;
- default: return pane_label(p)[0] != 0;
+ case KEEP_DEAD_ALL: return true;
+ case KEEP_DEAD_NONE: return false;
+ default: return pane_label(p)[0] != 0;
}
}
@@ -1853,8 +1863,10 @@ bool app_close_tab(app_t *a, uint32_t id) {
for (size_t i = 0; i < a->ntabs; i++) {
if (a->tabs[i].id != id) continue;
tab_remove(a, i);
- if (a->ntabs == 0) a->quit = true;
- else layout(a);
+ if (a->ntabs == 0)
+ a->quit = true;
+ else
+ layout(a);
return true;
}
return false;
@@ -1936,9 +1948,12 @@ static void move_tab(app_t *a, size_t from, size_t to) {
memmove(&a->tabs[to + 1], &a->tabs[to], (from - to) * sizeof *a->tabs);
a->tabs[to] = moved;
- if (a->cur == from) a->cur = to;
- else if (a->cur > from && a->cur <= to) a->cur--;
- else if (a->cur >= to && a->cur < from) a->cur++;
+ if (a->cur == from)
+ a->cur = to;
+ else if (a->cur > from && a->cur <= to)
+ a->cur--;
+ else if (a->cur >= to && a->cur < from)
+ a->cur++;
}
bool app_move_tab(app_t *a, uint32_t id, size_t index) {
@@ -2089,8 +2104,10 @@ static bool detach_leaf(app_t *a, node_t *leaf, size_t *from, bool *emptied) {
node_t *survivor = p->kids[0];
if (p->nkids == 1) { /* a split with one child is just that child */
survivor->parent = p->parent;
- if (p->parent) replace_child(p->parent, p, survivor);
- else t->root = survivor;
+ if (p->parent)
+ replace_child(p->parent, p, survivor);
+ else
+ t->root = survivor;
free(p->kids);
free(p);
}
@@ -2108,7 +2125,8 @@ static bool detach_leaf(app_t *a, node_t *leaf, size_t *from, bool *emptied) {
* or the pane is already in that tab. The tab you are looking at does not change;
* whether a caller follows the pane is a question about intent, and this is the
* mechanism. */
-bool app_move_pane_to_tab(app_t *a, uint32_t pane_id, uint32_t tab_id, bool rows) {
+bool app_move_pane_to_tab(app_t *a, uint32_t pane_id, uint32_t tab_id,
+ bool rows) {
node_t *leaf = pane_id ? pane_by_id(a, pane_id) : cur(a)->focus;
if (!leaf || leaf->kind != NODE_LEAF) return false;
tab_t *dest = tab_by_id(a, tab_id);
@@ -2147,7 +2165,8 @@ bool app_move_pane_to_tab(app_t *a, uint32_t pane_id, uint32_t tab_id, bool rows
* Worth having as its own call rather than "move to a tab you make first": a pane
* that is the only thing in its tab would otherwise have its tab removed from under
* the new one, and the order in which those two happen is exactly the bug. */
-uint32_t app_move_pane_to_new_tab(app_t *a, uint32_t pane_id, const char *name) {
+uint32_t app_move_pane_to_new_tab(app_t *a, uint32_t pane_id,
+ const char *name) {
node_t *leaf = pane_id ? pane_by_id(a, pane_id) : cur(a)->focus;
if (!leaf || leaf->kind != NODE_LEAF) return 0;
size_t src_ti = tab_of(a, leaf);
@@ -2226,7 +2245,8 @@ bool app_edit_config(app_t *a) {
}
}
- const char *editor = CFG.editor && *CFG.editor ? CFG.editor : getenv("EDITOR");
+ const char *editor =
+ CFG.editor && *CFG.editor ? CFG.editor : getenv("EDITOR");
/* vi is the one editor a POSIX system is required to have. Better a wrong
* guess you can see and change than a pane that opens empty. */
if (!editor || !*editor) editor = "vi";
@@ -2250,8 +2270,8 @@ bool app_edit_config(app_t *a) {
bool app_rerun_pane(app_t *a, uint32_t id) {
node_t *n = id ? pane_by_id(a, id) : (a->ntabs ? cur(a)->focus : NULL);
if (!n) return false;
- bool ok = pane_suspended(n->pane) ? pane_start(n->pane)
- : pane_restart(n->pane);
+ bool ok =
+ pane_suspended(n->pane) ? pane_start(n->pane) : pane_restart(n->pane);
if (!ok) {
app_toast(a, "cannot run it again");
return false;
@@ -2299,8 +2319,8 @@ static node_t *build_pane(app_t *a, const kdl_node_t *node, const char *cwd,
* resolving it twice would re-root a path against itself. */
char cwdbuf[1024];
const char *own = kdl_prop(node, "cwd", NULL);
- const char *node_cwd = own ? path_resolve(own, base, cwdbuf, sizeof cwdbuf)
- : cwd;
+ const char *node_cwd =
+ own ? path_resolve(own, base, cwdbuf, sizeof cwdbuf) : cwd;
/* a split: children, in order, in one direction */
size_t kids = 0;
@@ -2355,8 +2375,7 @@ static node_t *build_pane(app_t *a, const kdl_node_t *node, const char *cwd,
}
node_t *leaf = leaf_new_ex(a, command ? argv : default_argv(a), node_cwd,
- suspended,
- command ? command : "");
+ suspended, command ? command : "");
if (!leaf) return NULL;
leaf->weight = (int)kdl_prop_int(node, "weight", WEIGHT_UNIT);
if (leaf->weight < WEIGHT_MIN) leaf->weight = WEIGHT_UNIT;
@@ -2395,8 +2414,10 @@ bool app_apply_layout(app_t *a, const kdl_node_t *root, bool replace,
* are its root's -- including `cwd`, which build_pane reads off the body
* for itself. `base` as the inherited value is what makes a layout with no
* `cwd` anywhere in it start in the directory it was checked into. */
- kdl_node_t body = {.name = (char *)"pane", .kids = t->kids,
- .nkids = t->nkids, .props = t->props,
+ kdl_node_t body = {.name = (char *)"pane",
+ .kids = t->kids,
+ .nkids = t->nkids,
+ .props = t->props,
.nprops = t->nprops};
node_t *tree = build_pane(a, &body, base, base);
if (!tree) tree = leaf_new(a);
@@ -2425,7 +2446,8 @@ bool app_apply_layout(app_t *a, const kdl_node_t *root, bool replace,
if (n && n->name && config_is_setting(n->name)) {
if (err)
snprintf(err, errcap,
- "this is a config, not a layout: `%s` is a setting", n->name);
+ "this is a config, not a layout: `%s` is a setting",
+ n->name);
return false;
}
}
@@ -2482,8 +2504,8 @@ bool app_apply_layout_file(app_t *a, const char *path, bool replace, char *err,
const char *file = path_expand(path, pathbuf, sizeof pathbuf);
kdl_node_t *root = kdl_parse_file(file, err, errcap);
if (!root) return false;
- bool ok = app_apply_layout(a, root, replace,
- path_dir(file, dirbuf, sizeof dirbuf), err, errcap);
+ bool ok = app_apply_layout(
+ a, root, replace, path_dir(file, dirbuf, sizeof dirbuf), err, errcap);
kdl_free(root);
return ok;
}
@@ -2503,9 +2525,8 @@ bool app_apply_layout_file(app_t *a, const char *path, bool replace, char *err,
*/
/* Read by build_pane, on a `pane` node or on a tab acting as its own root. */
-static const char *const PANE_PROPS[] = {"split", "weight", "cwd",
- "command", "focus", "purpose",
- "suspended"};
+static const char *const PANE_PROPS[] = {
+ "split", "weight", "cwd", "command", "focus", "purpose", "suspended"};
/* Read by app_apply_layout off the tab itself. */
static const char *const TAB_PROPS[] = {"name", "active"};
@@ -2609,7 +2630,8 @@ size_t layout_check(const kdl_node_t *root, const char *file,
const kdl_node_t *n = root->kids[i];
if (!n || !n->name) continue;
if (lay && n == lay) continue;
- if (strcmp(n->name, "tab") == 0) continue; /* a bare list of tabs is legal */
+ if (strcmp(n->name, "tab") == 0)
+ continue; /* a bare list of tabs is legal */
if (config_is_setting(n->name)) {
lc_say(&c, n->line, "this is a config, not a layout: `%s` is a setting",
n->name);
@@ -2623,7 +2645,8 @@ size_t layout_check(const kdl_node_t *root, const char *file,
const kdl_node_t *n = lay->kids[i];
if (!n || !n->name) continue;
if (strcmp(n->name, "tab") != 0) {
- if (lay != root) lc_say(&c, n->line, "a layout holds tabs, not `%s`", n->name);
+ if (lay != root)
+ lc_say(&c, n->line, "a layout holds tabs, not `%s`", n->name);
continue;
}
tabs++;
@@ -2827,7 +2850,7 @@ size_t app_workspace_close(app_t *a, const char *slug) {
* out of asking the same question the picker asks rather than being a rule of
* its own. */
static bool tab_project(app_t *a, const tab_t *t, const char *path,
- project_t *out) {
+ project_t *out) {
int depth = 2;
const char *const *roots = workspace_roots(&depth);
if (path && *path) return project_find(roots, depth, path, out);
@@ -2844,8 +2867,8 @@ static bool tab_project(app_t *a, const tab_t *t, const char *path,
if (!t->focus) return false;
char cwdbuf[4096];
- return project_find(roots, depth, live_cwd(t->focus->pane, cwdbuf, sizeof cwdbuf),
- out);
+ return project_find(roots, depth,
+ live_cwd(t->focus->pane, cwdbuf, sizeof cwdbuf), out);
}
bool app_workspace_save(app_t *a, uint32_t tab, const char *path, int suspend,
@@ -2870,10 +2893,11 @@ bool app_workspace_save(app_t *a, uint32_t tab, const char *path, int suspend,
* the wrong tab was focused, so it is said rather than obeyed. */
if (strncmp(t->purpose, "project:", 8) == 0 &&
strcmp(t->purpose, p.slug) != 0) {
- snprintf(err, errcap,
- "this tab is another project's workspace (%s): save it from its own"
- " tab, or pass that tab's id",
- t->purpose);
+ snprintf(
+ err, errcap,
+ "this tab is another project's workspace (%s): save it from its own"
+ " tab, or pass that tab's id",
+ t->purpose);
return false;
}
snprintf(out->path, sizeof out->path, "%s/%s", p.path, PROJECT_LAYOUT_FILE);
@@ -2884,8 +2908,8 @@ bool app_workspace_save(app_t *a, uint32_t tab, const char *path, int suspend,
return false;
}
- dump_layout_t o = {.tab = t->id, .base = p.path, .suspend = suspend,
- .for_project = true};
+ dump_layout_t o = {
+ .tab = t->id, .base = p.path, .suspend = suspend, .for_project = true};
char *kdl = app_dump_layout(a, &o);
if (!kdl || !o.tabs) {
free(kdl);
@@ -2950,8 +2974,8 @@ static void transfer_weight(node_t *from, node_t *to, int amount) {
node_t *sp = from->parent;
if (sp && sp->nkids >= 2) {
uint16_t floor_ = sp->dir == SPLIT_COLS ? MIN_PANE_COLS : MIN_PANE_ROWS;
- uint16_t gap = sp->dir == SPLIT_COLS ? (uint16_t)(CFG.gap * CFG.gap_aspect)
- : CFG.gap;
+ uint16_t gap =
+ sp->dir == SPLIT_COLS ? (uint16_t)(CFG.gap * CFG.gap_aspect) : CFG.gap;
uint16_t span = sp->dir == SPLIT_COLS ? sp->rect.w : sp->rect.h;
uint16_t gaps = (uint16_t)(gap * (sp->nkids - 1));
uint16_t avail = span > gaps ? (uint16_t)(span - gaps) : span;
@@ -2989,11 +3013,15 @@ static void resize_focus(app_t *a, int dx, int dy) {
int dir = dx ? dx : dy;
if (i + 1 < p->nkids) {
- if (dir > 0) transfer_weight(p->kids[i + 1], n, WEIGHT_STEP);
- else transfer_weight(n, p->kids[i + 1], WEIGHT_STEP);
+ if (dir > 0)
+ transfer_weight(p->kids[i + 1], n, WEIGHT_STEP);
+ else
+ transfer_weight(n, p->kids[i + 1], WEIGHT_STEP);
} else if (i > 0) {
- if (dir > 0) transfer_weight(n, p->kids[i - 1], WEIGHT_STEP);
- else transfer_weight(p->kids[i - 1], n, WEIGHT_STEP);
+ if (dir > 0)
+ transfer_weight(n, p->kids[i - 1], WEIGHT_STEP);
+ else
+ transfer_weight(p->kids[i - 1], n, WEIGHT_STEP);
}
layout(a);
}
@@ -3166,7 +3194,8 @@ static void dir_cb(node_t *n, void *ud) {
if (n == d->from) return;
/* centres, in a coordinate space where a row counts double so that
* "nearest" means the same thing horizontally and vertically */
- long fx = d->from->rect.x * 2 + d->from->rect.w, fy = d->from->rect.y * 2 + d->from->rect.h;
+ long fx = d->from->rect.x * 2 + d->from->rect.w,
+ fy = d->from->rect.y * 2 + d->from->rect.h;
long nx = n->rect.x * 2 + n->rect.w, ny = n->rect.y * 2 + n->rect.h;
long along = d->dx ? (nx - fx) * d->dx : (ny - fy) * d->dy;
if (along <= 0) return; /* not in that direction */
@@ -3267,9 +3296,9 @@ static void draw_pane_status(app_t *a, screen_t *s, node_t *leaf, color_t fg,
char label[80];
snprintf(label, sizeof label, "[%s]", row[i].label);
bool hot = ptr_on(a, x, y, w, 1);
- uint16_t drawn = screen_text(s, x, y, label, focused || hot ? BTN_FG : fg,
- focused || hot ? BTN_BG : BTN_BG_IDLE,
- hot ? ATTR_BOLD : 0);
+ uint16_t drawn =
+ screen_text(s, x, y, label, focused || hot ? BTN_FG : fg,
+ focused || hot ? BTN_BG : BTN_BG_IDLE, hot ? ATTR_BOLD : 0);
hit_add(&s->hits, x, y, drawn, 1, row[i].action);
}
@@ -3502,7 +3531,8 @@ static void draw_frame(app_t *a, screen_t *s, node_t *leaf) {
uint16_t iw = (uint16_t)(nd + 4); /* space, arrow, space, digits, space */
if (iw + 2 < avail) {
uint16_t ix = (uint16_t)((has_btn ? btn_x : x1) - iw);
- uint16_t drawn = screen_text(s, ix, r.y, ind, SCROLL_FG, SCROLL_BG, ATTR_BOLD);
+ uint16_t drawn =
+ screen_text(s, ix, r.y, ind, SCROLL_FG, SCROLL_BG, ATTR_BOLD);
char action[48];
snprintf(action, sizeof action, "scrollbottom:%u", leaf->id);
hit_add(&s->hits, ix, r.y, drawn, 1, action);
@@ -3519,10 +3549,10 @@ static void draw_frame(app_t *a, screen_t *s, node_t *leaf) {
/* The purpose editor says which label it is: typed into the same cell as a
* rename, an unlabelled caret would leave you guessing which one you are
* changing -- and the two are edited from keys one shift apart. */
- int len = tagging
- ? snprintf(buf, sizeof buf, " purpose %s\u2588 ", a->rename_buf)
- : naming ? snprintf(buf, sizeof buf, " %s\u2588 ", a->rename_buf)
- : snprintf(buf, sizeof buf, " %s ", title);
+ int len =
+ tagging ? snprintf(buf, sizeof buf, " purpose %s\u2588 ", a->rename_buf)
+ : naming ? snprintf(buf, sizeof buf, " %s\u2588 ", a->rename_buf)
+ : snprintf(buf, sizeof buf, " %s ", title);
/* snprintf reports what it *would* have written; clamp to what it did, or
* the scroll below would move bytes that are not there. */
if (len < 0) len = 0;
@@ -3552,11 +3582,10 @@ static void draw_frame(app_t *a, screen_t *s, node_t *leaf) {
/* An editor announces itself: the name sits in the button colours while it
* is being typed, so a half-finished rename can never be mistaken for what
* the pane is actually called. */
- uint16_t drawn =
- screen_text(s, tx, r.y, buf,
- editing ? RENAME_FG : (focused ? TITLE_FOCUS : TITLE_IDLE),
- editing ? RENAME_BG : NO_COLOR,
- editing || focused ? ATTR_BOLD : 0);
+ uint16_t drawn = screen_text(
+ s, tx, r.y, buf,
+ editing ? RENAME_FG : (focused ? TITLE_FOCUS : TITLE_IDLE),
+ editing ? RENAME_BG : NO_COLOR, editing || focused ? ATTR_BOLD : 0);
/* The title names the pane; it is not an edge. It carves its own cells out
* of the top row's handle so that resting there arms no split guide and
@@ -3620,7 +3649,8 @@ static void draw_collapsed(app_t *a, screen_t *s, node_t *n) {
} else if (pane_scrolled(leaf->pane)) {
uint32_t above = 0, total = 0;
pane_scroll_pos(leaf->pane, &above, &total);
- snprintf(words, sizeof words, "\u25b2 %u", total > above ? total - above : 0);
+ snprintf(words, sizeof words, "\u25b2 %u",
+ total > above ? total - above : 0);
status = words;
}
char line[256];
@@ -3724,9 +3754,9 @@ bool app_load_pane_shaders(app_t *a, uint32_t pane_id, const char *path,
inband_chain_t con = {0}, chr = {0};
expr_prog_t *exprs[SHADE_MAX * 2];
size_t nexprs = 0;
- size_t got = config_parse_chain_file(path, CFG.frame_focus, con.sh, &con.n,
- chr.sh, &chr.n, exprs, &nexprs, err,
- errcap);
+ size_t got =
+ config_parse_chain_file(path, CFG.frame_focus, con.sh, &con.n, chr.sh,
+ &chr.n, exprs, &nexprs, err, errcap);
if (!got) {
for (size_t i = 0; i < nexprs; i++) expr_free(exprs[i]);
if (err && errcap && !err[0]) snprintf(err, errcap, "nothing in it to run");
@@ -4024,17 +4054,20 @@ static void draw_corners(app_t *a, screen_t *s) {
bool active = a->drag.kind == DRAG_EDGE && (a->drag.c_nh || a->drag.c_nv) &&
a->drag.c_nh && c->nh && a->drag.c_h[0] == c->h_id[0] &&
- a->drag.c_hedge[0] == c->h_edge[0] && a->drag.c_v[0] == c->v_id[0];
+ a->drag.c_hedge[0] == c->h_edge[0] &&
+ a->drag.c_v[0] == c->v_id[0];
/* (C) The mark appears the moment the pointer is on it, before the dwell
* that arms the two boundaries. A crossing is two cells wide and gives no
* other sign it is anything: something has to say it is there, and the
* ghost costs nothing if you were only passing through. */
- bool over = a->drag.kind == DRAG_NONE && ptr_on(a, c->r.x, c->r.y, c->r.w, c->r.h);
+ bool over =
+ a->drag.kind == DRAG_NONE && ptr_on(a, c->r.x, c->r.y, c->r.w, c->r.h);
if (!active && !over) continue;
bool armed = active || now_ms_() - a->ptr_still_since >= CFG.hover_delay_ms;
for (uint16_t x = c->r.x; x < c->r.x + c->r.w; x++)
- screen_text(s, x, c->r.y, armed ? (active ? "\u256c" : "\u253c") : "\u253c",
- RESIZE_C, NO_COLOR, active ? ATTR_BOLD : 0);
+ screen_text(s, x, c->r.y,
+ armed ? (active ? "\u256c" : "\u253c") : "\u253c", RESIZE_C,
+ NO_COLOR, active ? ATTR_BOLD : 0);
}
}
@@ -4071,7 +4104,8 @@ static void draw_cb(node_t *n, void *ud) {
w = n->content.w;
if (w > 1) {
line[w - 1] = 0;
- line[w - 2] = 0xe2; /* fall back to a plain dot rather than a cut UTF-8 */
+ line[w - 2] =
+ 0xe2; /* fall back to a plain dot rather than a cut UTF-8 */
line[w - 2] = '.';
} else {
line[w] = 0;
@@ -4120,8 +4154,8 @@ static void draw_tab_strip(app_t *a, screen_t *s) {
/* Right side first, so a long tab list can never eat the indicators — the
* same budgeting rule as the split button and the OSC buttons. */
- uint16_t right = (uint16_t)(s->cols > CFG.status_pad ? s->cols - CFG.status_pad
- : s->cols);
+ uint16_t right =
+ (uint16_t)(s->cols > CFG.status_pad ? s->cols - CFG.status_pad : s->cols);
char info[64];
size_t np = app_pane_count(a);
snprintf(info, sizeof info, "%zu pane%s", np, np == 1 ? "" : "s");
@@ -4152,16 +4186,17 @@ static void draw_tab_strip(app_t *a, screen_t *s) {
/* A pane that rang in a tab you are not looking at is invisible without
* this, and that is the case the whole indicator exists for. */
bool rang = CFG.bell_indicator && tab_has_bell(t);
- if (nm[0]) snprintf(label, sizeof label, " %zu:%s ", i + 1, nm);
- else snprintf(label, sizeof label, " %zu ", i + 1);
+ if (nm[0])
+ snprintf(label, sizeof label, " %zu:%s ", i + 1, nm);
+ else
+ snprintf(label, sizeof label, " %zu ", i + 1);
/* Renaming: the tab's own cell becomes the editor, in the editor's
* colours, so a half-typed name can never be mistaken for the tab's real
* one. The caret is part of the label, so the width below — and therefore
* the hit — is the width of what is actually drawn. */
bool editing = a->renaming == RENAME_TAB && a->rename_id == t->id;
- if (editing)
- snprintf(label, sizeof label, " %s\u2588 ", a->rename_buf);
+ if (editing) snprintf(label, sizeof label, " %s\u2588 ", a->rename_buf);
bool active = i == a->cur;
uint16_t attrs = active ? ATTR_BOLD : 0;
@@ -4170,12 +4205,11 @@ static void draw_tab_strip(app_t *a, screen_t *s) {
* hover colour if that width turns out to be under the pointer — which
* costs a repaint of a few cells and guarantees the lit cells are the
* registered ones. */
- uint16_t w = screen_text(s, x, y, label,
- editing ? RENAME_FG
- : (active ? TAB_ACTIVE_FG : TAB_IDLE),
- editing ? RENAME_BG
- : (active ? TAB_ACTIVE_BG : NO_COLOR),
- editing ? ATTR_BOLD : attrs);
+ uint16_t w =
+ screen_text(s, x, y, label,
+ editing ? RENAME_FG : (active ? TAB_ACTIVE_FG : TAB_IDLE),
+ editing ? RENAME_BG : (active ? TAB_ACTIVE_BG : NO_COLOR),
+ editing ? ATTR_BOLD : attrs);
/* Hovering keeps the active tab's fill — it is still the tab you are in —
* so its feedback lands on the text instead. An inactive tab has no fill
* to keep, and brightens. */
@@ -4321,8 +4355,10 @@ static void find_corners(app_t *a) {
if (g[j].sp->dir != SPLIT_COLS) continue;
rect_t v = g[j].r;
- bool touch_y = v.y <= (uint16_t)(h.y + h.h) && h.y <= (uint16_t)(v.y + v.h);
- bool touch_x = h.x <= (uint16_t)(v.x + v.w) && v.x <= (uint16_t)(h.x + h.w);
+ bool touch_y =
+ v.y <= (uint16_t)(h.y + h.h) && h.y <= (uint16_t)(v.y + v.h);
+ bool touch_x =
+ h.x <= (uint16_t)(v.x + v.w) && v.x <= (uint16_t)(h.x + h.w);
if (!touch_y || !touch_x) continue;
rect_t cr = {v.x, h.y, v.w, h.h};
@@ -4395,15 +4431,18 @@ static void draw_resize_hint(app_t *a, screen_t *s, node_t *split, size_t idx,
int ci = -1;
if (a->drag.kind == DRAG_EDGE && (a->drag.c_nv || a->drag.c_nh)) {
for (size_t k = 0; k < a->drag.c_nh; k++)
- if (a->drag.c_h[k] == split->id && a->drag.c_hedge[k] == idx) active = true;
+ if (a->drag.c_h[k] == split->id && a->drag.c_hedge[k] == idx)
+ active = true;
for (size_t k = 0; k < a->drag.c_nv; k++)
- if (a->drag.c_v[k] == split->id && a->drag.c_vedge[k] == idx) active = true;
+ if (a->drag.c_v[k] == split->id && a->drag.c_vedge[k] == idx)
+ active = true;
} else if (a->drag.kind == DRAG_NONE) {
ci = corner_at(a, a->ptr_x, a->ptr_y);
}
if (ci >= 0 && (size_t)ci < a->ncorners &&
corner_uses(&a->corners[ci], split->id, idx)) {
- if (false) active = true;
+ if (false)
+ active = true;
else if (now_ms_() - a->ptr_still_since >= CFG.hover_delay_ms) {
uint16_t attrs0 = 0;
if (split->dir == SPLIT_COLS) {
@@ -4506,8 +4545,8 @@ static bool ci_contains(const char *hay, const char *needle) {
size_t nl = strlen(needle);
for (const char *p = hay; *p; p++) {
size_t i = 0;
- while (i < nl && p[i] && tolower((unsigned char)p[i]) ==
- tolower((unsigned char)needle[i]))
+ while (i < nl && p[i] &&
+ tolower((unsigned char)p[i]) == tolower((unsigned char)needle[i]))
i++;
if (i == nl) return true;
}
@@ -4549,9 +4588,8 @@ typedef struct {
} help_row_t;
static size_t help_rows(help_row_t *out, size_t cap) {
- static const char *const GROUPS[] = {"panes", "focus", "size",
- "tabs", "projects", "scroll",
- "session"};
+ static const char *const GROUPS[] = {"panes", "focus", "size", "tabs",
+ "projects", "scroll", "session"};
size_t n = 0;
for (size_t g = 0; g < sizeof GROUPS / sizeof *GROUPS && n < cap; g++) {
bool titled = false;
@@ -4571,7 +4609,8 @@ static size_t help_rows(help_row_t *out, size_t cap) {
* thing to learn. */
bool tabish = act == ACT_SELECT_TAB_1 && bound >= ACT_SELECT_TAB_1;
if (bound != (action_t)act && !tabish) continue;
- if (tabish && bound != ACT_SELECT_TAB_1 && bound != ACT_SELECT_TAB_1 + 8)
+ if (tabish && bound != ACT_SELECT_TAB_1 &&
+ bound != ACT_SELECT_TAB_1 + 8)
continue; /* first and last, shown as a range */
char one[24];
@@ -4662,8 +4701,10 @@ static rect_t modal_frame(app_t *a, screen_t *s, uint16_t w, uint16_t h,
for (uint16_t xx = x; xx < x + w; xx++)
screen_text(s, xx, yy, " ", NO_COLOR, MODAL_BG, 0);
- const char *tl = CFG.rounded ? "\u256d" : "\u250c", *tr = CFG.rounded ? "\u256e" : "\u2510";
- const char *bl = CFG.rounded ? "\u2570" : "\u2514", *br = CFG.rounded ? "\u256f" : "\u2518";
+ const char *tl = CFG.rounded ? "\u256d" : "\u250c",
+ *tr = CFG.rounded ? "\u256e" : "\u2510";
+ const char *bl = CFG.rounded ? "\u2570" : "\u2514",
+ *br = CFG.rounded ? "\u256f" : "\u2518";
screen_text(s, x, y, tl, MODAL_BORDER, MODAL_BG, 0);
screen_text(s, x1, y, tr, MODAL_BORDER, MODAL_BG, 0);
screen_text(s, x, y1, bl, MODAL_BORDER, MODAL_BG, 0);
@@ -4738,8 +4779,11 @@ static void draw_help(app_t *a, screen_t *s) {
if (two) {
size_t half = (n + 1) / 2;
split = half;
- while (split < n && rows[split].group) split++; /* to the next heading */
- if (split >= n) { split = half; while (split > 1 && rows[split].group) split--; }
+ while (split < n && rows[split].group) split++; /* to the next heading */
+ if (split >= n) {
+ split = half;
+ while (split > 1 && rows[split].group) split--;
+ }
/* Land on the heading itself, not on the blank row above it: a column
* that starts with a blank line looks like a mistake. */
if (split < n && !rows[split].group && !rows[split].label) split++;
@@ -4782,8 +4826,9 @@ static void draw_help(app_t *a, screen_t *s) {
if (row >= shown && rows[i].label) hidden++;
}
- rect_t in = modal_frame(a, s, (uint16_t)(body + 6), (uint16_t)(shown + 6 + (hidden ? 1 : 0)),
- "keys", "closehelp");
+ rect_t in = modal_frame(a, s, (uint16_t)(body + 6),
+ (uint16_t)(shown + 6 + (hidden ? 1 : 0)), "keys",
+ "closehelp");
uint16_t x1 = (uint16_t)(in.x + in.w); /* the right border */
/* Everything here is prefix-then-key, and saying so once beats repeating
@@ -4847,8 +4892,8 @@ typedef struct {
char left[24];
char mid[80];
char right[80];
- bool here; /* mark this row: the pane you are already in */
- char action[48]; /* what a click on it does */
+ bool here; /* mark this row: the pane you are already in */
+ char action[48]; /* what a click on it does */
} pick_row_t;
/* A band of background, for a row that is selected or under the pointer. The
@@ -4980,8 +5025,8 @@ static size_t workspace_rows(app_t *a, pick_row_t *out, size_t max) {
const char *root_end = p->path + keep;
const char *root_start = root_end;
while (root_start > p->path && root_start[-1] != '/') root_start--;
- snprintf(r->left, sizeof r->left, "%.*s",
- (int)(root_end - root_start), root_start);
+ snprintf(r->left, sizeof r->left, "%.*s", (int)(root_end - root_start),
+ root_start);
snprintf(r->mid, sizeof r->mid, "%s", p->name);
/* What it is, or what it already is: an open workspace says how many panes
* it has, and a project with no layout says so, which reads as the
@@ -5026,8 +5071,9 @@ static void draw_picker(app_t *a, screen_t *s) {
bool palette = a->picker == PICK_PALETTE;
bool projects = a->picker == PICK_WORKSPACES;
const char *title = palette ? "commands" : projects ? "projects" : "find";
- const char *close = palette ? "closepalette"
- : projects ? "closeprojects" : "closefind";
+ const char *close = palette ? "closepalette"
+ : projects ? "closeprojects"
+ : "closefind";
/* The window of results on screen. Kept around the selection rather than
* anchored at the top, so arrowing past the bottom scrolls instead of
@@ -5059,8 +5105,9 @@ static void draw_picker(app_t *a, screen_t *s) {
if (!n) {
/* An empty box says the picker is broken; this says the query is. */
- const char *none = palette ? "no command matches that"
- : (a->query[0] ? "no pane matches that" : "no panes");
+ const char *none =
+ palette ? "no command matches that"
+ : (a->query[0] ? "no pane matches that" : "no panes");
help_text(s, (uint16_t)(in.x + 2), ly, none, (uint16_t)(in.w - 2), HINT_C,
MODAL_BG, 0);
return;
@@ -5112,15 +5159,17 @@ static void draw_picker(app_t *a, screen_t *s) {
/* What is off the top and bottom of the window. Without this a list that
* scrolls looks like a list that ends. */
if (first)
- screen_text(s, (uint16_t)(in.x + in.w - 1), ly, "\u2191", HINT_C, MODAL_BG, 0);
+ screen_text(s, (uint16_t)(in.x + in.w - 1), ly, "\u2191", HINT_C, MODAL_BG,
+ 0);
if (first + shown < n)
- screen_text(s, (uint16_t)(in.x + in.w - 1),
- (uint16_t)(ly + shown - 1), "\u2193", HINT_C, MODAL_BG, 0);
+ screen_text(s, (uint16_t)(in.x + in.w - 1), (uint16_t)(ly + shown - 1),
+ "\u2193", HINT_C, MODAL_BG, 0);
/* The count belongs where the eye already goes for "how much is there", and
* it is the answer to "is my query too narrow, or is there nothing?". */
char foot[64];
- snprintf(foot, sizeof foot, " %zu of %zu \u00b7 \u2191\u2193 enter ", a->sel + 1, n);
+ snprintf(foot, sizeof foot, " %zu of %zu \u00b7 \u2191\u2193 enter ",
+ a->sel + 1, n);
if (in.w > cells(foot))
screen_text(s, (uint16_t)(in.x + (in.w - cells(foot)) / 2),
(uint16_t)(in.y + in.h), foot, HINT_C, MODAL_BG, 0);
@@ -5153,8 +5202,10 @@ static bool push_pane_a_tab(app_t *a, bool forward) {
for (size_t i = 0; i < a->ntabs; i++)
if (a->tabs[i].id == tid) at = i;
char msg[128];
- if (name[0]) snprintf(msg, sizeof msg, "moved to tab %zu (%s)", at + 1, name);
- else snprintf(msg, sizeof msg, "moved to tab %zu", at + 1);
+ if (name[0])
+ snprintf(msg, sizeof msg, "moved to tab %zu (%s)", at + 1, name);
+ else
+ snprintf(msg, sizeof msg, "moved to tab %zu", at + 1);
app_toast(a, msg);
return true;
}
@@ -5176,7 +5227,8 @@ static void drop_pane_on_strip(app_t *a) {
uint32_t tid = a->drag.tab_target;
char name[64] = {0};
for (size_t i = 0; i < a->ntabs; i++)
- if (a->tabs[i].id == tid) snprintf(name, sizeof name, "%s", a->tabs[i].name);
+ if (a->tabs[i].id == tid)
+ snprintf(name, sizeof name, "%s", a->tabs[i].name);
if (!app_move_pane_to_tab(a, src, tid, false)) {
/* The one refusal a drag can reach: the tab it is already in. */
@@ -5187,8 +5239,10 @@ static void drop_pane_on_strip(app_t *a) {
for (size_t i = 0; i < a->ntabs; i++)
if (a->tabs[i].id == tid) at = i;
char msg[128];
- if (name[0]) snprintf(msg, sizeof msg, "moved to tab %zu (%s)", at + 1, name);
- else snprintf(msg, sizeof msg, "moved to tab %zu", at + 1);
+ if (name[0])
+ snprintf(msg, sizeof msg, "moved to tab %zu (%s)", at + 1, name);
+ else
+ snprintf(msg, sizeof msg, "moved to tab %zu", at + 1);
app_toast(a, msg);
}
@@ -5230,7 +5284,7 @@ static void picker_move(app_t *a, int d) {
}
int64_t sel = (int64_t)a->sel + d;
int64_t last = (int64_t)n - 1;
- if (sel < 0) sel = d == -1 ? last : 0; /* a page up stops at the top */
+ if (sel < 0) sel = d == -1 ? last : 0; /* a page up stops at the top */
if (sel > last) sel = d == 1 ? 0 : last;
a->sel = (size_t)sel;
}
@@ -5266,57 +5320,42 @@ static bool picker_key(app_t *a, const input_event_t *ev) {
}
switch (ev->key) {
- case GHOSTTY_KEY_ESCAPE:
- a->picker = PICK_NONE;
- return true;
- case GHOSTTY_KEY_ENTER: {
- pick_row_t rows[128];
- size_t n = picker_rows(a, rows, 128);
- /* The row's own action, the one a click on it would run: a picker that
+ case GHOSTTY_KEY_ESCAPE: a->picker = PICK_NONE; return true;
+ case GHOSTTY_KEY_ENTER: {
+ pick_row_t rows[128];
+ size_t n = picker_rows(a, rows, 128);
+ /* The row's own action, the one a click on it would run: a picker that
* chose by keyboard down one path and by mouse down another would be
* two pickers wearing one box. */
- char action[48] = "";
- if (a->sel < n) snprintf(action, sizeof action, "%s", rows[a->sel].action);
- a->picker = PICK_NONE;
- if (*action) picker_accept(a, action);
- return true;
- }
- case GHOSTTY_KEY_TAB:
- picker_move(a, shift ? -1 : 1);
- return true;
- case GHOSTTY_KEY_ARROW_DOWN:
- picker_move(a, 1);
- return true;
- case GHOSTTY_KEY_ARROW_UP:
- picker_move(a, -1);
- return true;
- case GHOSTTY_KEY_PAGE_DOWN:
- picker_move(a, FINDER_ROWS);
- return true;
- case GHOSTTY_KEY_PAGE_UP:
- picker_move(a, -FINDER_ROWS);
- return true;
- case GHOSTTY_KEY_HOME:
- a->sel = 0;
- return true;
- case GHOSTTY_KEY_END: {
- size_t n = picker_count(a);
- a->sel = n ? n - 1 : 0;
- return true;
- }
- case GHOSTTY_KEY_BACKSPACE: {
- /* A character, not a byte: the query can hold whatever a pane's title
+ char action[48] = "";
+ if (a->sel < n) snprintf(action, sizeof action, "%s", rows[a->sel].action);
+ a->picker = PICK_NONE;
+ if (*action) picker_accept(a, action);
+ return true;
+ }
+ case GHOSTTY_KEY_TAB: picker_move(a, shift ? -1 : 1); return true;
+ case GHOSTTY_KEY_ARROW_DOWN: picker_move(a, 1); return true;
+ case GHOSTTY_KEY_ARROW_UP: picker_move(a, -1); return true;
+ case GHOSTTY_KEY_PAGE_DOWN: picker_move(a, FINDER_ROWS); return true;
+ case GHOSTTY_KEY_PAGE_UP: picker_move(a, -FINDER_ROWS); return true;
+ case GHOSTTY_KEY_HOME: a->sel = 0; return true;
+ case GHOSTTY_KEY_END: {
+ size_t n = picker_count(a);
+ a->sel = n ? n - 1 : 0;
+ return true;
+ }
+ case GHOSTTY_KEY_BACKSPACE: {
+ /* A character, not a byte: the query can hold whatever a pane's title
* did, and half a UTF-8 sequence is not a search. (The rename editor
* learned this first; this one was still eating bytes.) */
- size_t l = strlen(a->query);
- while (l && ((unsigned char)a->query[l - 1] & 0xC0) == 0x80) l--;
- if (l) l--;
- a->query[l] = 0;
- a->sel = 0;
- return true;
- }
- default:
- break;
+ size_t l = strlen(a->query);
+ while (l && ((unsigned char)a->query[l - 1] & 0xC0) == 0x80) l--;
+ if (l) l--;
+ a->query[l] = 0;
+ a->sel = 0;
+ return true;
+ }
+ default: break;
}
if (!ctrl && ev->text_len && (unsigned char)ev->text[0] >= 0x20) {
size_t l = strlen(a->query);
@@ -5419,23 +5458,18 @@ static bool rename_key(app_t *a, const input_event_t *ev) {
if (ev->kind != EV_KEY || ev->action == KEY_RELEASE) return true;
switch (ev->key) {
- case GHOSTTY_KEY_ESCAPE:
- rename_end(a, false);
- return true;
- case GHOSTTY_KEY_ENTER:
- rename_end(a, true);
- return true;
- case GHOSTTY_KEY_BACKSPACE: {
- /* A character, not a byte: a title is whatever the program could set,
+ case GHOSTTY_KEY_ESCAPE: rename_end(a, false); return true;
+ case GHOSTTY_KEY_ENTER: rename_end(a, true); return true;
+ case GHOSTTY_KEY_BACKSPACE: {
+ /* A character, not a byte: a title is whatever the program could set,
* and half a UTF-8 sequence is not a name. */
- size_t l = strlen(a->rename_buf);
- while (l && ((unsigned char)a->rename_buf[l - 1] & 0xC0) == 0x80) l--;
- if (l) l--;
- a->rename_buf[l] = 0;
- return true;
- }
- default:
- break;
+ size_t l = strlen(a->rename_buf);
+ while (l && ((unsigned char)a->rename_buf[l - 1] & 0xC0) == 0x80) l--;
+ if (l) l--;
+ a->rename_buf[l] = 0;
+ return true;
+ }
+ default: break;
}
if (ev->text_len && (unsigned char)ev->text[0] >= 0x20) {
size_t l = strlen(a->rename_buf);
@@ -5477,7 +5511,7 @@ void app_compose(app_t *a, screen_t *s) {
if (a->picker || a->help) draw_scrim(a, s);
if (a->picker) draw_picker(a, s);
if (a->help) draw_help(a, s);
- draw_toasts(a, s); /* and above even that: it is transient */
+ draw_toasts(a, s); /* and above even that: it is transient */
}
/* ---- kitty graphics ------------------------------------------------------ */
@@ -5534,34 +5568,36 @@ static void gfx_from_pane(pane_t *p, const pane_gfx_t *g, void *ud) {
}
if (!cols || !rows) return;
- gfx_place(c->a->gfx, &(gfx_req_t){
- .pane = leaf->id,
- .src_id = g->image_id,
- .gen = g->generation,
- .place_id = g->place_id,
- .col = (uint16_t)(leaf->content.x + g->col),
- .row = (uint16_t)(leaf->content.y + g->row),
- .cols = cols,
- .rows = rows,
- /* Carried through untouched: the pane's own clipping already dealt with
+ gfx_place(
+ c->a->gfx,
+ &(gfx_req_t){
+ .pane = leaf->id,
+ .src_id = g->image_id,
+ .gen = g->generation,
+ .place_id = g->place_id,
+ .col = (uint16_t)(leaf->content.x + g->col),
+ .row = (uint16_t)(leaf->content.y + g->row),
+ .cols = cols,
+ .rows = rows,
+ /* Carried through untouched: the pane's own clipping already dealt with
* it, and the offset is relative to the first cell either way. */
- .x_off = g->x_off,
- .y_off = g->y_off,
- /* Clipped the same way the cell counts were, and zero when the program
+ .x_off = g->x_off,
+ .y_off = g->y_off,
+ /* Clipped the same way the cell counts were, and zero when the program
* never asked to scale. */
- .scale_cols = g->req_cols ? cols : 0,
- .scale_rows = g->req_rows ? rows : 0,
- .sx = g->sx,
- .sy = g->sy,
- .sw = sw,
- .sh = sh,
- .px_w = g->src_w,
- .px_h = g->src_h,
- .format = g->format,
- .compression = g->compression,
- .data = g->data,
- .data_len = g->data_len,
- });
+ .scale_cols = g->req_cols ? cols : 0,
+ .scale_rows = g->req_rows ? rows : 0,
+ .sx = g->sx,
+ .sy = g->sy,
+ .sw = sw,
+ .sh = sh,
+ .px_w = g->src_w,
+ .px_h = g->src_h,
+ .format = g->format,
+ .compression = g->compression,
+ .data = g->data,
+ .data_len = g->data_len,
+ });
}
static void gfx_leaf_cb(node_t *n, void *ud) {
@@ -5644,9 +5680,10 @@ static void drag_edge(app_t *a, node_t *sp, size_t i, int cells) {
int amount = (int)((long)labs(cells) * total / (span ? span : 1));
if (amount <= 0) amount = 1;
-
- if (cells > 0) transfer_weight(sp->kids[i + 1], sp->kids[i], amount);
- else transfer_weight(sp->kids[i], sp->kids[i + 1], amount);
+ if (cells > 0)
+ transfer_weight(sp->kids[i + 1], sp->kids[i], amount);
+ else
+ transfer_weight(sp->kids[i], sp->kids[i + 1], amount);
layout(a);
}
@@ -5834,7 +5871,8 @@ static void do_action(app_t *a, const char *action, const input_event_t *ev) {
/* A press always focuses; a hover only when it is allowed to. The event
* is forwarded either way, so a pane that tracks the mouse still sees the
* pointer cross it whether or not focus moved. */
- if (ev->maction != MOUSE_MOTION || hover_focus_allowed(a)) cur(a)->focus = n;
+ if (ev->maction != MOUSE_MOTION || hover_focus_allowed(a))
+ cur(a)->focus = n;
/* translate to pane-local coordinates before forwarding */
input_event_t local = *ev;
local.mx = (uint16_t)(ev->mx - n->content.x);
@@ -5915,147 +5953,149 @@ static bool run_action(app_t *a, action_t act) {
return true;
}
switch (act) {
- case ACT_SPLIT: split_focus_auto(a); return true;
- case ACT_SPLIT_COLS: split_focus_ui(a, SPLIT_COLS); return true;
- case ACT_SPLIT_ROWS: split_focus_ui(a, SPLIT_ROWS); return true;
- case ACT_ZOOM: app_toggle_zoom(a, 0); return true;
- case ACT_MINIMIZE:
- if (!app_minimize(a, 0)) app_toast(a, "nothing else to show");
- return true;
- case ACT_CLOSE_PANE:
- if (cur(a)->focus) close_leaf(a, cur(a)->focus);
- return true;
- case ACT_SET_PURPOSE:
- /* Nothing to tag in an empty tab, and a purpose belongs to a pane rather
+ case ACT_SPLIT: split_focus_auto(a); return true;
+ case ACT_SPLIT_COLS: split_focus_ui(a, SPLIT_COLS); return true;
+ case ACT_SPLIT_ROWS: split_focus_ui(a, SPLIT_ROWS); return true;
+ case ACT_ZOOM: app_toggle_zoom(a, 0); return true;
+ case ACT_MINIMIZE:
+ if (!app_minimize(a, 0)) app_toast(a, "nothing else to show");
+ return true;
+ case ACT_CLOSE_PANE:
+ if (cur(a)->focus) close_leaf(a, cur(a)->focus);
+ return true;
+ case ACT_SET_PURPOSE:
+ /* Nothing to tag in an empty tab, and a purpose belongs to a pane rather
* than to the space one would occupy. */
- if (cur(a)->focus) purpose_begin(a, cur(a)->focus->id);
- return true;
- case ACT_RERUN:
- /* The keyboard's half of a dead pane's [re-run] button. Refused on a
+ if (cur(a)->focus) purpose_begin(a, cur(a)->focus->id);
+ return true;
+ case ACT_RERUN:
+ /* The keyboard's half of a dead pane's [re-run] button. Refused on a
* live pane rather than restarting it: "run it again" would mean
* killing something that is still working, which is not what anybody
* pressing it is asking for. */
- if (cur(a)->focus && pane_alive(cur(a)->focus->pane) &&
- !pane_suspended(cur(a)->focus->pane))
- app_toast(a, "still running");
- else
- app_rerun_pane(a, 0);
- return true;
- case ACT_FOCUS_LEFT: focus_dir(a, -1, 0); return true;
- case ACT_FOCUS_RIGHT: focus_dir(a, 1, 0); return true;
- case ACT_FOCUS_UP: focus_dir(a, 0, -1); return true;
- case ACT_FOCUS_DOWN: focus_dir(a, 0, 1); return true;
- case ACT_FOCUS_NEXT: focus_next(a); return true;
- case ACT_NEW_TAB: app_new_tab(a, ""); return true;
- case ACT_CLOSE_TAB: {
- /* The last tab is refused rather than obeyed. `app_close_tab` ends the
+ if (cur(a)->focus && pane_alive(cur(a)->focus->pane) &&
+ !pane_suspended(cur(a)->focus->pane))
+ app_toast(a, "still running");
+ else
+ app_rerun_pane(a, 0);
+ return true;
+ case ACT_FOCUS_LEFT: focus_dir(a, -1, 0); return true;
+ case ACT_FOCUS_RIGHT: focus_dir(a, 1, 0); return true;
+ case ACT_FOCUS_UP: focus_dir(a, 0, -1); return true;
+ case ACT_FOCUS_DOWN: focus_dir(a, 0, 1); return true;
+ case ACT_FOCUS_NEXT: focus_next(a); return true;
+ case ACT_NEW_TAB: app_new_tab(a, ""); return true;
+ case ACT_CLOSE_TAB: {
+ /* The last tab is refused rather than obeyed. `app_close_tab` ends the
* session when nothing is left, which is right for a *request* -- a script
* asking to close the only tab means it -- and a trap for a key: one that
* closes a tab four times and ends your session the fifth is a key you
* cannot press without counting first. `quit` is how you mean that, and it
* is one letter away. */
- if (a->ntabs < 2) {
- app_toast(a, "last tab: quit the session instead");
- return true;
- }
- /* Said out loud with the count, because everything in it goes with it and
- * the panes it kills are the ones you were not looking at. */
- size_t n = count_leaves(cur(a)->root);
- char said[64];
- snprintf(said, sizeof said, "closed tab \u00b7 %zu pane%s", n,
- n == 1 ? "" : "s");
- if (app_close_tab(a, cur(a)->id)) app_toast(a, said);
+ if (a->ntabs < 2) {
+ app_toast(a, "last tab: quit the session instead");
return true;
}
- case ACT_NEXT_TAB: app_cycle_tab(a, 1); return true;
- case ACT_PREV_TAB: app_cycle_tab(a, -1); return true;
- case ACT_RESIZE_LEFT: resize_focus(a, -1, 0); return true;
- case ACT_RESIZE_RIGHT: resize_focus(a, 1, 0); return true;
- case ACT_RESIZE_UP: resize_focus(a, 0, -1); return true;
- case ACT_RESIZE_DOWN: resize_focus(a, 0, 1); return true;
- case ACT_CLEAR_SHADERS:
- /* Says which of the two happened. "Nothing to undo" and "undone" look
+ /* Said out loud with the count, because everything in it goes with it and
+ * the panes it kills are the ones you were not looking at. */
+ size_t n = count_leaves(cur(a)->root);
+ char said[64];
+ snprintf(said, sizeof said, "closed tab \u00b7 %zu pane%s", n,
+ n == 1 ? "" : "s");
+ if (app_close_tab(a, cur(a)->id)) app_toast(a, said);
+ return true;
+ }
+ case ACT_NEXT_TAB: app_cycle_tab(a, 1); return true;
+ case ACT_PREV_TAB: app_cycle_tab(a, -1); return true;
+ case ACT_RESIZE_LEFT: resize_focus(a, -1, 0); return true;
+ case ACT_RESIZE_RIGHT: resize_focus(a, 1, 0); return true;
+ case ACT_RESIZE_UP: resize_focus(a, 0, -1); return true;
+ case ACT_RESIZE_DOWN: resize_focus(a, 0, 1); return true;
+ case ACT_CLEAR_SHADERS:
+ /* Says which of the two happened. "Nothing to undo" and "undone" look
* identical on a pane that was never painted, and a key that might have
* done nothing is a key you press again. */
- app_toast(a, app_clear_pane_shaders(a, 0) ? "shaders cleared"
- : "no shaders on this pane");
- return true;
- case ACT_PANE_TO_NEXT_TAB:
- case ACT_PANE_TO_PREV_TAB:
- return push_pane_a_tab(a, act == ACT_PANE_TO_NEXT_TAB);
- case ACT_PANE_TO_NEW_TAB: {
- uint32_t made = app_move_pane_to_new_tab(a, 0, "");
- app_toast(a, made ? "into a tab of its own"
- : "it is the only pane in this tab");
- return true;
- }
- case ACT_EQUALIZE:
- if (!app_equalize_splits(a)) app_toast(a, "nothing to even out");
- return true;
- case ACT_ROTATE_LAYOUT: rotate_layout_ui(a); return true;
- case ACT_SCROLL_UP: pane_scroll(cur(a)->focus->pane, -CFG.scroll_lines); return true;
- case ACT_SCROLL_DOWN: pane_scroll(cur(a)->focus->pane, CFG.scroll_lines); return true;
- case ACT_SCROLL_PAGE_UP:
- pane_scroll(cur(a)->focus->pane, -(int)cur(a)->focus->content.h);
- return true;
- case ACT_SCROLL_PAGE_DOWN:
- pane_scroll(cur(a)->focus->pane, (int)cur(a)->focus->content.h);
- return true;
- case ACT_SCROLL_TOP: pane_scroll_edge(cur(a)->focus->pane, true); return true;
- case ACT_SCROLL_BOTTOM: pane_scroll_edge(cur(a)->focus->pane, false); return true;
- case ACT_FINDER:
- case ACT_PALETTE:
- a->picker = act == ACT_PALETTE ? PICK_PALETTE : PICK_FINDER;
- a->query[0] = 0;
- a->sel = 0;
- return true;
- case ACT_WORKSPACES: {
- /* Scanned here, once, and kept only while the picker is up: draw_picker
+ app_toast(a, app_clear_pane_shaders(a, 0) ? "shaders cleared"
+ : "no shaders on this pane");
+ return true;
+ case ACT_PANE_TO_NEXT_TAB:
+ case ACT_PANE_TO_PREV_TAB:
+ return push_pane_a_tab(a, act == ACT_PANE_TO_NEXT_TAB);
+ case ACT_PANE_TO_NEW_TAB: {
+ uint32_t made = app_move_pane_to_new_tab(a, 0, "");
+ app_toast(a, made ? "into a tab of its own"
+ : "it is the only pane in this tab");
+ return true;
+ }
+ case ACT_EQUALIZE:
+ if (!app_equalize_splits(a)) app_toast(a, "nothing to even out");
+ return true;
+ case ACT_ROTATE_LAYOUT: rotate_layout_ui(a); return true;
+ case ACT_SCROLL_UP:
+ pane_scroll(cur(a)->focus->pane, -CFG.scroll_lines);
+ return true;
+ case ACT_SCROLL_DOWN:
+ pane_scroll(cur(a)->focus->pane, CFG.scroll_lines);
+ return true;
+ case ACT_SCROLL_PAGE_UP:
+ pane_scroll(cur(a)->focus->pane, -(int)cur(a)->focus->content.h);
+ return true;
+ case ACT_SCROLL_PAGE_DOWN:
+ pane_scroll(cur(a)->focus->pane, (int)cur(a)->focus->content.h);
+ return true;
+ case ACT_SCROLL_TOP: pane_scroll_edge(cur(a)->focus->pane, true); return true;
+ case ACT_SCROLL_BOTTOM:
+ pane_scroll_edge(cur(a)->focus->pane, false);
+ return true;
+ case ACT_FINDER:
+ case ACT_PALETTE:
+ a->picker = act == ACT_PALETTE ? PICK_PALETTE : PICK_FINDER;
+ a->query[0] = 0;
+ a->sel = 0;
+ return true;
+ case ACT_WORKSPACES: {
+ /* Scanned here, once, and kept only while the picker is up: draw_picker
* asks for its rows every frame. Opening is also exactly when the list
* has to be right, which is why nothing older than this keystroke is
* ever shown. */
- if (!app_project_roots_set()) {
- app_toast(a, "no project roots: set project_roots in your config");
- return true;
- }
- free(a->projects);
- a->projects = calloc(PROJECTS_MAX, sizeof *a->projects);
- a->nprojects = a->projects ? app_projects(a->projects, PROJECTS_MAX) : 0;
- if (!a->nprojects) {
- app_toast(a, "no projects under your project_roots");
- return true;
- }
- a->picker = PICK_WORKSPACES;
- a->query[0] = 0;
- a->sel = 0;
+ if (!app_project_roots_set()) {
+ app_toast(a, "no project roots: set project_roots in your config");
return true;
}
- case ACT_SAVE_WORKSPACE: {
- app_workspace_save_t w;
- char err[256] = {0};
- /* `commands` rather than as-is: the pane running this morning's dev server
- * should be in the file asleep, not started on every open. */
- if (!app_workspace_save(a, 0, NULL, DUMP_SUSPEND_COMMANDS, true, &w, err,
- sizeof err)) {
- app_toast(a, err[0] ? err : "cannot save that");
- return true;
- }
- char said[96];
- snprintf(said, sizeof said, "%s %s \u00b7 %zu pane%s, %zu suspended",
- w.replaced ? "replaced" : "wrote", PROJECT_LAYOUT_FILE, w.panes,
- w.panes == 1 ? "" : "s", w.suspended);
- app_toast(a, said);
+ free(a->projects);
+ a->projects = calloc(PROJECTS_MAX, sizeof *a->projects);
+ a->nprojects = a->projects ? app_projects(a->projects, PROJECTS_MAX) : 0;
+ if (!a->nprojects) {
+ app_toast(a, "no projects under your project_roots");
return true;
}
- case ACT_EDIT_CONFIG:
- app_edit_config(a);
- return true;
- case ACT_HELP:
- a->help = !a->help;
+ a->picker = PICK_WORKSPACES;
+ a->query[0] = 0;
+ a->sel = 0;
+ return true;
+ }
+ case ACT_SAVE_WORKSPACE: {
+ app_workspace_save_t w;
+ char err[256] = {0};
+ /* `commands` rather than as-is: the pane running this morning's dev server
+ * should be in the file asleep, not started on every open. */
+ if (!app_workspace_save(a, 0, NULL, DUMP_SUSPEND_COMMANDS, true, &w, err,
+ sizeof err)) {
+ app_toast(a, err[0] ? err : "cannot save that");
return true;
- case ACT_DETACH: a->detach = true; return true;
- case ACT_QUIT: a->quit = true; return true;
- default: return false;
+ }
+ char said[96];
+ snprintf(said, sizeof said, "%s %s \u00b7 %zu pane%s, %zu suspended",
+ w.replaced ? "replaced" : "wrote", PROJECT_LAYOUT_FILE, w.panes,
+ w.panes == 1 ? "" : "s", w.suspended);
+ app_toast(a, said);
+ return true;
+ }
+ case ACT_EDIT_CONFIG: app_edit_config(a); return true;
+ case ACT_HELP: a->help = !a->help; return true;
+ case ACT_DETACH: a->detach = true; return true;
+ case ACT_QUIT: a->quit = true; return true;
+ default: return false;
}
}
@@ -6105,7 +6145,8 @@ void app_event(app_t *a, const input_event_t *ev) {
if (a->prefix) {
a->prefix = false;
/* prefix twice sends the prefix itself, whatever it is bound to */
- if (is_prefix || config_lookup(&CFG, ev->key, mods) == ACT_LITERAL_PREFIX) {
+ if (is_prefix ||
+ config_lookup(&CFG, ev->key, mods) == ACT_LITERAL_PREFIX) {
input_event_t literal = *ev;
literal.key = CFG.prefix_key;
literal.mods = CFG.prefix_mods;
@@ -6136,199 +6177,197 @@ void app_event(app_t *a, const input_event_t *ev) {
}
switch (ev->kind) {
- case EV_KEY:
- /* the first keystroke starts a suspended pane, and is not forwarded */
- if (pane_suspended(cur(a)->focus->pane)) {
- pane_start(cur(a)->focus->pane);
- break;
- }
- pane_send_key(cur(a)->focus->pane, ev);
+ case EV_KEY:
+ /* the first keystroke starts a suspended pane, and is not forwarded */
+ if (pane_suspended(cur(a)->focus->pane)) {
+ pane_start(cur(a)->focus->pane);
break;
- case EV_MOUSE: {
- /* Mouse routing is a hit-list lookup, never a re-derivation of geometry:
+ }
+ pane_send_key(cur(a)->focus->pane, ev);
+ break;
+ case EV_MOUSE: {
+ /* Mouse routing is a hit-list lookup, never a re-derivation of geometry:
* the list was filled by the pass that painted what the user clicked. */
- if (!a->painted) break;
- const char *action = hit_test(&a->painted->hits, ev->mx, ev->my);
+ if (!a->painted) break;
+ const char *action = hit_test(&a->painted->hits, ev->mx, ev->my);
- /* Clicking away keeps the name, the way leaving a field commits it.
+ /* Clicking away keeps the name, the way leaving a field commits it.
* Clicking the thing's own label again does not, so a stray second
* double-click lands in the editor instead of closing it. */
- if (a->renaming && ev->maction == MOUSE_PRESS) {
- char own[48];
- snprintf(own, sizeof own,
- a->renaming == RENAME_PANE ? "panetitle:%u" : "tab:%u",
- a->rename_id);
- if (!action || strcmp(action, own) != 0) rename_end(a, true);
- }
+ if (a->renaming && ev->maction == MOUSE_PRESS) {
+ char own[48];
+ snprintf(own, sizeof own,
+ a->renaming == RENAME_PANE ? "panetitle:%u" : "tab:%u",
+ a->rename_id);
+ if (!action || strcmp(action, own) != 0) rename_end(a, true);
+ }
- if (!a->ptr_valid || ev->mx != a->ptr_x || ev->my != a->ptr_y)
- a->ptr_still_since = now_ms_();
- a->ptr_x = ev->mx;
- a->ptr_y = ev->my;
- a->ptr_valid = true;
+ if (!a->ptr_valid || ev->mx != a->ptr_x || ev->my != a->ptr_y)
+ a->ptr_still_since = now_ms_();
+ a->ptr_x = ev->mx;
+ a->ptr_y = ev->my;
+ a->ptr_valid = true;
- if (a->drag.kind != DRAG_NONE) {
- if (ev->maction == MOUSE_MOTION) {
- a->drag.moved = true;
- if (a->drag.kind == DRAG_SELECT) {
- node_t *n = pane_by_id(a, a->drag.src);
- if (n)
- pane_select_extend(n->pane, (uint16_t)(ev->mx - n->content.x),
- (uint16_t)(ev->my - n->content.y));
- } else if (a->drag.kind == DRAG_EDGE &&
- (a->drag.c_nv || a->drag.c_nh)) {
- /* One axis to each: the row boundary takes the vertical movement
+ if (a->drag.kind != DRAG_NONE) {
+ if (ev->maction == MOUSE_MOTION) {
+ a->drag.moved = true;
+ if (a->drag.kind == DRAG_SELECT) {
+ node_t *n = pane_by_id(a, a->drag.src);
+ if (n)
+ pane_select_extend(n->pane, (uint16_t)(ev->mx - n->content.x),
+ (uint16_t)(ev->my - n->content.y));
+ } else if (a->drag.kind == DRAG_EDGE &&
+ (a->drag.c_nv || a->drag.c_nh)) {
+ /* One axis to each: the row boundary takes the vertical movement
* and the column boundaries the horizontal, so the corner follows
* the pointer in both at once. The column boundaries above and
* below get the same delta, which is what keeps them one line. */
- int dx = (int)ev->mx - (int)a->drag.x;
- int dy = (int)ev->my - (int)a->drag.y;
- for (size_t i = 0; i < a->drag.c_nh; i++)
- drag_edge(a, split_by_id(a, a->drag.c_h[i]), a->drag.c_hedge[i],
- dy);
- for (size_t i = 0; i < a->drag.c_nv; i++)
- drag_edge(a, split_by_id(a, a->drag.c_v[i]), a->drag.c_vedge[i],
- dx);
- } else if (a->drag.kind == DRAG_EDGE) {
- node_t *sp = split_by_id(a, a->drag.src);
- int cells = sp && sp->dir == SPLIT_COLS
- ? (int)ev->mx - (int)a->drag.x
- : (int)ev->my - (int)a->drag.y;
- drag_edge(a, sp, a->drag.edge, cells);
- } else if (a->drag.kind == DRAG_TAB) {
- /* Reordered as you drag, rather than dropped at the end: the
+ int dx = (int)ev->mx - (int)a->drag.x;
+ int dy = (int)ev->my - (int)a->drag.y;
+ for (size_t i = 0; i < a->drag.c_nh; i++)
+ drag_edge(a, split_by_id(a, a->drag.c_h[i]), a->drag.c_hedge[i],
+ dy);
+ for (size_t i = 0; i < a->drag.c_nv; i++)
+ drag_edge(a, split_by_id(a, a->drag.c_v[i]), a->drag.c_vedge[i],
+ dx);
+ } else if (a->drag.kind == DRAG_EDGE) {
+ node_t *sp = split_by_id(a, a->drag.src);
+ int cells = sp && sp->dir == SPLIT_COLS
+ ? (int)ev->mx - (int)a->drag.x
+ : (int)ev->my - (int)a->drag.y;
+ drag_edge(a, sp, a->drag.edge, cells);
+ } else if (a->drag.kind == DRAG_TAB) {
+ /* Reordered as you drag, rather than dropped at the end: the
* strip is the only thing that could show an insertion point, and
* a strip that already shows the result needs no such invention.
* Off the strip entirely, nothing moves — dragging away is not a
* cancel, it is simply not a move. */
- size_t from = tab_index(a, a->drag.src);
- if (from != (size_t)-1 && action) {
- size_t to = (size_t)-1;
- if (strncmp(action, "tab:", 4) == 0)
- to = tab_index(a, (uint32_t)strtoul(action + 4, NULL, 10));
- else if (strcmp(action, "newtab") == 0)
- to = a->ntabs - 1; /* past the last tab means last */
- if (to != (size_t)-1) move_tab(a, from, to);
- }
- } else if (a->drag.kind == DRAG_TITLE && action &&
- strncmp(action, "tab:", 4) == 0) {
- /* Over the strip: this pane is going to that tab. */
- a->drag.tab_target = (uint32_t)strtoul(action + 4, NULL, 10);
- a->drag.new_tab_target = false;
- a->drag.target = 0;
- } else if (a->drag.kind == DRAG_TITLE && action &&
- strcmp(action, "newtab") == 0) {
- /* The button that makes a tab, used as somewhere to put one pane. */
- a->drag.new_tab_target = true;
- a->drag.tab_target = 0;
- a->drag.target = 0;
- } else if (action && strncmp(action, "title:", 6) == 0) {
- a->drag.target = (uint32_t)strtoul(action + 6, NULL, 10);
- a->drag.tab_target = 0;
- a->drag.new_tab_target = false;
- } else if (action && strncmp(action, "panetitle:", 10) == 0) {
- /* Dropping onto a pane's name is dropping onto that pane. */
- a->drag.target = (uint32_t)strtoul(action + 10, NULL, 10);
- a->drag.tab_target = 0;
- a->drag.new_tab_target = false;
- } else if (action && strncmp(action, "pane:", 5) == 0) {
- a->drag.target = (uint32_t)strtoul(action + 5, NULL, 10);
- a->drag.tab_target = 0;
- a->drag.new_tab_target = false;
+ size_t from = tab_index(a, a->drag.src);
+ if (from != (size_t)-1 && action) {
+ size_t to = (size_t)-1;
+ if (strncmp(action, "tab:", 4) == 0)
+ to = tab_index(a, (uint32_t)strtoul(action + 4, NULL, 10));
+ else if (strcmp(action, "newtab") == 0)
+ to = a->ntabs - 1; /* past the last tab means last */
+ if (to != (size_t)-1) move_tab(a, from, to);
}
- a->drag.x = ev->mx;
- a->drag.y = ev->my;
- } else if (ev->maction == MOUSE_RELEASE) {
- /* A press that never moved is a click, and a click on an edge
+ } else if (a->drag.kind == DRAG_TITLE && action &&
+ strncmp(action, "tab:", 4) == 0) {
+ /* Over the strip: this pane is going to that tab. */
+ a->drag.tab_target = (uint32_t)strtoul(action + 4, NULL, 10);
+ a->drag.new_tab_target = false;
+ a->drag.target = 0;
+ } else if (a->drag.kind == DRAG_TITLE && action &&
+ strcmp(action, "newtab") == 0) {
+ /* The button that makes a tab, used as somewhere to put one pane. */
+ a->drag.new_tab_target = true;
+ a->drag.tab_target = 0;
+ a->drag.target = 0;
+ } else if (action && strncmp(action, "title:", 6) == 0) {
+ a->drag.target = (uint32_t)strtoul(action + 6, NULL, 10);
+ a->drag.tab_target = 0;
+ a->drag.new_tab_target = false;
+ } else if (action && strncmp(action, "panetitle:", 10) == 0) {
+ /* Dropping onto a pane's name is dropping onto that pane. */
+ a->drag.target = (uint32_t)strtoul(action + 10, NULL, 10);
+ a->drag.tab_target = 0;
+ a->drag.new_tab_target = false;
+ } else if (action && strncmp(action, "pane:", 5) == 0) {
+ a->drag.target = (uint32_t)strtoul(action + 5, NULL, 10);
+ a->drag.tab_target = 0;
+ a->drag.new_tab_target = false;
+ }
+ a->drag.x = ev->mx;
+ a->drag.y = ev->my;
+ } else if (ev->maction == MOUSE_RELEASE) {
+ /* A press that never moved is a click, and a click on an edge
* splits toward it. */
- if (!a->drag.moved && a->drag.side &&
- (a->drag.kind == DRAG_BORDER || a->drag.kind == DRAG_TITLE)) {
- node_t *n = pane_by_id(a, a->drag.src);
- if (n) {
- char side = a->drag.side;
- bool before = side == 'l' || side == 't';
- split_dir_t dir = side_dir(side);
- /* The guide already declined to offer this, so the click that
+ if (!a->drag.moved && a->drag.side &&
+ (a->drag.kind == DRAG_BORDER || a->drag.kind == DRAG_TITLE)) {
+ node_t *n = pane_by_id(a, a->drag.src);
+ if (n) {
+ char side = a->drag.side;
+ bool before = side == 'l' || side == 't';
+ split_dir_t dir = side_dir(side);
+ /* The guide already declined to offer this, so the click that
* the guide would have explained must decline too — otherwise
* the border silently does something it just said it would not. */
- if (!split_fits(n, dir)) {
- app_toast(a, dir == SPLIT_COLS ? "no room to split across"
- : "no room to split down");
- } else {
- split_node(a, n, dir, before);
- app_toast(a, side == 'l' ? "split left"
- : side == 'r' ? "split right"
- : side == 't' ? "split up"
- : "split down");
- }
+ if (!split_fits(n, dir)) {
+ app_toast(a, dir == SPLIT_COLS ? "no room to split across"
+ : "no room to split down");
+ } else {
+ split_node(a, n, dir, before);
+ app_toast(a, side == 'l' ? "split left"
+ : side == 'r' ? "split right"
+ : side == 't' ? "split up"
+ : "split down");
}
- a->drag.kind = DRAG_NONE;
- a->drag.src = a->drag.target = 0;
- break;
}
- if (a->drag.kind == DRAG_SELECT) {
- /* Releasing copies, which is the whole point: no menu, no chord,
+ a->drag.kind = DRAG_NONE;
+ a->drag.src = a->drag.target = 0;
+ break;
+ }
+ if (a->drag.kind == DRAG_SELECT) {
+ /* Releasing copies, which is the whole point: no menu, no chord,
* the selection *is* the copy. */
- node_t *n = pane_by_id(a, a->drag.src);
- if (n) {
- set_clipboard(a, pane_selection_text(n->pane));
- pane_select_done(n->pane);
- }
+ node_t *n = pane_by_id(a, a->drag.src);
+ if (n) {
+ set_clipboard(a, pane_selection_text(n->pane));
+ pane_select_done(n->pane);
}
- if (a->drag.kind == DRAG_TITLE &&
- (a->drag.tab_target || a->drag.new_tab_target)) {
- /* Dropped on the strip: the pane changes tab rather than places. */
- drop_pane_on_strip(a);
- } else if (a->drag.kind == DRAG_TITLE &&
- a->drag.target != a->drag.src) {
- swap_panes(a, a->drag.src, a->drag.target);
- }
- a->drag.kind = DRAG_NONE;
- a->drag.src = a->drag.target = a->drag.tab_target = 0;
- a->drag.new_tab_target = false;
}
- break; /* a drag owns the mouse until the button comes up */
+ if (a->drag.kind == DRAG_TITLE &&
+ (a->drag.tab_target || a->drag.new_tab_target)) {
+ /* Dropped on the strip: the pane changes tab rather than places. */
+ drop_pane_on_strip(a);
+ } else if (a->drag.kind == DRAG_TITLE &&
+ a->drag.target != a->drag.src) {
+ swap_panes(a, a->drag.src, a->drag.target);
+ }
+ a->drag.kind = DRAG_NONE;
+ a->drag.src = a->drag.target = a->drag.tab_target = 0;
+ a->drag.new_tab_target = false;
}
+ break; /* a drag owns the mouse until the button comes up */
+ }
- /* Any press dismisses the cheatsheet, wherever it lands -- including on
+ /* Any press dismisses the cheatsheet, wherever it lands -- including on
* its own close button, which is there because a modal without a way
* out that you can *see* is a modal people hunt for the way out of. */
- if (a->help) {
- if (ev->maction == MOUSE_PRESS) a->help = false;
- break;
- }
+ if (a->help) {
+ if (ev->maction == MOUSE_PRESS) a->help = false;
+ break;
+ }
- /* The finder owns the pointer as well as the keyboard. A press on one
+ /* The finder owns the pointer as well as the keyboard. A press on one
* of its rows chooses; a press anywhere else dismisses it and does
* nothing further -- clicking past a modal must not also land on the
* layout behind it, which is how you end up focusing a pane you were
* trying to click *away* from. Motion still falls through, so rows
* light up under the pointer. */
- if (a->picker && ev->maction != MOUSE_MOTION) {
- bool own = action && (strncmp(action, "find:", 5) == 0 ||
- strncmp(action, "run:", 4) == 0 ||
- strncmp(action, "open:", 5) == 0 ||
- strcmp(action, "closefind") == 0 ||
- strcmp(action, "closepalette") == 0 ||
- strcmp(action, "closeprojects") == 0);
- if (!own) {
- if (ev->maction == MOUSE_PRESS) a->picker = PICK_NONE;
- break;
- }
+ if (a->picker && ev->maction != MOUSE_MOTION) {
+ bool own = action && (strncmp(action, "find:", 5) == 0 ||
+ strncmp(action, "run:", 4) == 0 ||
+ strncmp(action, "open:", 5) == 0 ||
+ strcmp(action, "closefind") == 0 ||
+ strcmp(action, "closepalette") == 0 ||
+ strcmp(action, "closeprojects") == 0);
+ if (!own) {
+ if (ev->maction == MOUSE_PRESS) a->picker = PICK_NONE;
+ break;
}
-
- if (action) do_action(a, action, ev);
- break;
}
- case EV_PASTE:
- pane_send_paste(cur(a)->focus->pane, ev->paste, ev->paste_len);
- break;
- default:
- break;
+
+ if (action) do_action(a, action, ev);
+ break;
+ }
+ case EV_PASTE:
+ pane_send_paste(cur(a)->focus->pane, ev->paste, ev->paste_len);
+ break;
+ default: break;
}
}
-
/* ---- dumping a session back out as a layout ------------------------------
*
* The inverse of apply-layout, and the thing that makes a restart survivable:
@@ -6371,8 +6410,10 @@ static void sb_quoted(strbuf_t *b, const char *key, const char *val) {
if (!val || !*val) return;
sb_add(b, " %s=\"", key);
for (const char *p = val; *p; p++) {
- if (*p == '"' || *p == '\\') sb_add(b, "\\%c", *p);
- else if ((unsigned char)*p >= 0x20) sb_add(b, "%c", *p);
+ if (*p == '"' || *p == '\\')
+ sb_add(b, "\\%c", *p);
+ else if ((unsigned char)*p >= 0x20)
+ sb_add(b, "%c", *p);
}
sb_add(b, "\"");
}
@@ -6438,10 +6479,10 @@ static const char *dump_command(const node_t *n, char *buf, size_t cap) {
* `suspended=true` under this policy would start a dev server on every open. */
static bool dump_suspended(const char *command, const node_t *n, int policy) {
switch (policy) {
- case DUMP_SUSPEND_NONE: return false;
- case DUMP_SUSPEND_ALL: return true;
- case DUMP_SUSPEND_COMMANDS: return command && *command;
- default: return pane_suspended(n->pane);
+ case DUMP_SUSPEND_NONE: return false;
+ case DUMP_SUSPEND_ALL: return true;
+ case DUMP_SUSPEND_COMMANDS: return command && *command;
+ default: return pane_suspended(n->pane);
}
}
diff --git a/src/app.h b/src/app.h
index f8025ba..3c5e357 100644
--- a/src/app.h
+++ b/src/app.h
@@ -147,12 +147,12 @@ size_t app_projects(project_t *out, size_t max);
uint32_t app_workspace_tab(app_t *a, const char *slug);
typedef struct {
- uint32_t tab; /* the tab to land in */
- char purpose[64]; /* the workspace's identity */
- char path[512]; /* the project on disk */
- size_t tabs; /* tabs it adopted */
- size_t honoured; /* tabs whose own declared purpose was left alone */
- bool created; /* false when it was already open and was focused */
+ uint32_t tab; /* the tab to land in */
+ char purpose[64]; /* the workspace's identity */
+ char path[512]; /* the project on disk */
+ size_t tabs; /* tabs it adopted */
+ size_t honoured; /* tabs whose own declared purpose was left alone */
+ bool created; /* false when it was already open and was focused */
} app_workspace_open_t;
/* Open a project's layout as a workspace, or focus the one already open --
@@ -167,10 +167,10 @@ bool app_workspace_open(app_t *a, const char *name, bool suspended,
size_t app_workspace_close(app_t *a, const char *slug);
typedef struct {
- char path[512]; /* the file written */
- char purpose[64]; /* the workspace the tab now carries */
+ char path[512]; /* the file written */
+ char purpose[64]; /* the workspace the tab now carries */
size_t panes, suspended;
- bool replaced; /* there was a layout there before */
+ bool replaced; /* there was a layout there before */
} app_workspace_save_t;
/* Write one tab out as a project's layout: the same dump `dump-layout` answers
@@ -205,7 +205,8 @@ bool app_minimize(app_t *a, uint32_t id);
* A move drops what the old tab thought about the pane: a zoom naming it, and its
* minimised flag. Carried across, the first would zoom a pane that has left and the
* second would file the arrival in a strip nobody asked for. */
-bool app_move_pane_to_tab(app_t *a, uint32_t pane_id, uint32_t tab_id, bool rows);
+bool app_move_pane_to_tab(app_t *a, uint32_t pane_id, uint32_t tab_id,
+ bool rows);
/* The same, into a tab of its own; returns that tab's id, or 0 -- including for a
* pane that is already alone in its tab, which has nowhere to go. */
diff --git a/src/client.c b/src/client.c
index 2c22af9..b1155b8 100644
--- a/src/client.c
+++ b/src/client.c
@@ -16,14 +16,14 @@
#include "proto.h"
-#define TERM_ENTER \
- "\x1b[?1049h\x1b[0m\x1b[2J" \
- "\x1b[?1002h\x1b[?1003h\x1b[?1006h" \
- "\x1b[?1004h" \
- "\x1b[?2004h" \
+#define TERM_ENTER \
+ "\x1b[?1049h\x1b[0m\x1b[2J" \
+ "\x1b[?1002h\x1b[?1003h\x1b[?1006h" \
+ "\x1b[?1004h" \
+ "\x1b[?2004h" \
"\x1b[>1u"
-#define TERM_LEAVE \
- "\x1b[<u\x1b[?2004l\x1b[?1004l\x1b[?1006l\x1b[?1003l\x1b[?1002l" \
+#define TERM_LEAVE \
+ "\x1b[<u\x1b[?2004l\x1b[?1004l\x1b[?1006l\x1b[?1003l\x1b[?1002l" \
"\x1b[?25h\x1b[0m\x1b[?1049l"
static volatile sig_atomic_t g_winch = 0, g_quit = 0;
@@ -31,8 +31,10 @@ static struct termios g_saved;
static bool g_saved_ok = false;
static void on_sig(int s) {
- if (s == SIGWINCH) g_winch = 1;
- else g_quit = 1;
+ if (s == SIGWINCH)
+ g_winch = 1;
+ else
+ g_quit = 1;
}
static void restore(void) {
@@ -160,8 +162,10 @@ int client_run(int fd) {
restore();
g_saved_ok = false;
- if (exit_reason == EXIT_DETACHED) fprintf(stderr, "[detached]\n");
- else if (exit_reason == EXIT_REPLACED) fprintf(stderr, "[replaced by another client]\n");
+ if (exit_reason == EXIT_DETACHED)
+ fprintf(stderr, "[detached]\n");
+ else if (exit_reason == EXIT_REPLACED)
+ fprintf(stderr, "[replaced by another client]\n");
return 0;
}
diff --git a/src/cmd.c b/src/cmd.c
index 58e22e9..eb3a09d 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -21,21 +21,21 @@ size_t cmd_unescape(const char *in, uint8_t *out, size_t cap) {
}
p++;
switch (*p) {
- case 'e': out[n++] = 0x1b; break;
- case 'n': out[n++] = '\n'; break;
- case 'r': out[n++] = '\r'; break;
- case 't': out[n++] = '\t'; break;
- case '0': out[n++] = 0; break;
- case '\\': out[n++] = '\\'; break;
- case 'x': {
- int hi = 0, lo = 0;
- sscanf(p + 1, "%1x%1x", &hi, &lo);
- out[n++] = (uint8_t)(hi * 16 + lo);
- p += 2;
- break;
- }
- case 0: return n;
- default: out[n++] = (uint8_t)*p; break;
+ case 'e': out[n++] = 0x1b; break;
+ case 'n': out[n++] = '\n'; break;
+ case 'r': out[n++] = '\r'; break;
+ case 't': out[n++] = '\t'; break;
+ case '0': out[n++] = 0; break;
+ case '\\': out[n++] = '\\'; break;
+ case 'x': {
+ int hi = 0, lo = 0;
+ sscanf(p + 1, "%1x%1x", &hi, &lo);
+ out[n++] = (uint8_t)(hi * 16 + lo);
+ p += 2;
+ break;
+ }
+ case 0: return n;
+ default: out[n++] = (uint8_t)*p; break;
}
}
return n;
@@ -195,7 +195,8 @@ static char *cmd_json(app_t *a, screen_t *s, input_parser_t *in,
uint32_t tid = (uint32_t)jv_geti(req, "tab", 0);
bool rows = strcmp(jv_gets(req, "dir", "cols"), "rows") == 0;
if (!tid) {
- uint32_t made = app_move_pane_to_new_tab(a, pid, jv_gets(req, "name", ""));
+ uint32_t made =
+ app_move_pane_to_new_tab(a, pid, jv_gets(req, "name", ""));
if (!made) return jerr("cannot move it to a tab of its own");
return jok_int("tab", (long long)made);
}
@@ -238,8 +239,8 @@ static char *cmd_json(app_t *a, screen_t *s, input_parser_t *in,
uint32_t id = (uint32_t)jv_geti(req, "id", 0);
const char *name = jv_gets(req, "name", "");
bool pane = strcmp(target, "pane") == 0;
- bool ok = pane ? app_set_pane_name(a, id, name)
- : app_set_tab_name(a, id, name);
+ bool ok =
+ pane ? app_set_pane_name(a, id, name) : app_set_tab_name(a, id, name);
return ok ? jok_int(NULL, 0) : jerr(pane ? "no such pane" : "no such tab");
}
if (strcmp(cmd, "set-purpose") == 0) {
@@ -257,7 +258,8 @@ static char *cmd_json(app_t *a, screen_t *s, input_parser_t *in,
if (strcmp(cmd, "dump-layout") == 0) {
dump_layout_t o = {.tab = (uint32_t)jv_geti(req, "tab", 0),
.base = jv_gets(req, "relative_to", NULL)};
- o.suspend = suspend_policy(jv_gets(req, "suspend", NULL), DUMP_SUSPEND_ASIS);
+ o.suspend =
+ suspend_policy(jv_gets(req, "suspend", NULL), DUMP_SUSPEND_ASIS);
if (o.suspend < 0) return jerr("suspend is as-is, none, commands or all");
char *kdl = app_dump_layout(a, &o);
if (o.tab && !o.tabs) {
@@ -280,9 +282,9 @@ static char *cmd_json(app_t *a, screen_t *s, input_parser_t *in,
const char *text = jv_gets(req, "kdl", NULL);
bool replace = jv_getb(req, "replace", false);
char err[256] = {0};
- bool ok = text ? app_apply_layout_text(a, text, replace, err, sizeof err)
- : path ? app_apply_layout_file(a, path, replace, err, sizeof err)
- : false;
+ bool ok = text ? app_apply_layout_text(a, text, replace, err, sizeof err)
+ : path ? app_apply_layout_file(a, path, replace, err, sizeof err)
+ : false;
if (!ok) return jerr(err[0] ? err : "need a path or kdl");
app_resize(a, s->cols, s->rows);
s->force_full = true;
@@ -368,8 +370,8 @@ static char *cmd_json(app_t *a, screen_t *s, input_parser_t *in,
return jok_int("closed", (long long)n);
}
if (strcmp(cmd, "save-workspace") == 0) {
- int suspend = suspend_policy(jv_gets(req, "suspend", NULL),
- DUMP_SUSPEND_COMMANDS);
+ int suspend =
+ suspend_policy(jv_gets(req, "suspend", NULL), DUMP_SUSPEND_COMMANDS);
if (suspend < 0) return jerr("suspend is as-is, none, commands or all");
app_workspace_save_t w;
char err[256] = {0};
@@ -523,7 +525,8 @@ char *cmd_exec(app_t *a, screen_t *s, input_parser_t *in, const char *line,
return app_tabs_json(a);
}
if (strcmp(verb, "dump-layout") == 0) {
- app_compose(a, s); /* the layout is a function of the frame: compose first */
+ app_compose(a,
+ s); /* the layout is a function of the frame: compose first */
return app_dump_layout(a, NULL);
}
/* The bare forms the harness and a person at a shell use. Same functions, so
diff --git a/src/config.c b/src/config.c
index 556f7f8..4958883 100644
--- a/src/config.c
+++ b/src/config.c
@@ -16,32 +16,44 @@ static const struct {
action_t action;
} ACTIONS[] = {
{"split", ACT_SPLIT},
- {"split-cols", ACT_SPLIT_COLS}, {"split-rows", ACT_SPLIT_ROWS},
- {"close-pane", ACT_CLOSE_PANE}, {"rerun", ACT_RERUN},
+ {"split-cols", ACT_SPLIT_COLS},
+ {"split-rows", ACT_SPLIT_ROWS},
+ {"close-pane", ACT_CLOSE_PANE},
+ {"rerun", ACT_RERUN},
{"zoom", ACT_ZOOM},
- {"minimize", ACT_MINIMIZE}, {"set-purpose", ACT_SET_PURPOSE},
+ {"minimize", ACT_MINIMIZE},
+ {"set-purpose", ACT_SET_PURPOSE},
{"focus-left", ACT_FOCUS_LEFT},
- {"focus-right", ACT_FOCUS_RIGHT}, {"focus-up", ACT_FOCUS_UP},
- {"focus-down", ACT_FOCUS_DOWN}, {"focus-next", ACT_FOCUS_NEXT},
- {"resize-left", ACT_RESIZE_LEFT}, {"resize-right", ACT_RESIZE_RIGHT},
- {"resize-up", ACT_RESIZE_UP}, {"resize-down", ACT_RESIZE_DOWN},
+ {"focus-right", ACT_FOCUS_RIGHT},
+ {"focus-up", ACT_FOCUS_UP},
+ {"focus-down", ACT_FOCUS_DOWN},
+ {"focus-next", ACT_FOCUS_NEXT},
+ {"resize-left", ACT_RESIZE_LEFT},
+ {"resize-right", ACT_RESIZE_RIGHT},
+ {"resize-up", ACT_RESIZE_UP},
+ {"resize-down", ACT_RESIZE_DOWN},
{"equalize", ACT_EQUALIZE},
{"clear-shaders", ACT_CLEAR_SHADERS},
{"pane-to-next-tab", ACT_PANE_TO_NEXT_TAB},
{"pane-to-prev-tab", ACT_PANE_TO_PREV_TAB},
{"pane-to-new-tab", ACT_PANE_TO_NEW_TAB},
{"rotate-layout", ACT_ROTATE_LAYOUT},
- {"scroll-up", ACT_SCROLL_UP}, {"scroll-down", ACT_SCROLL_DOWN},
+ {"scroll-up", ACT_SCROLL_UP},
+ {"scroll-down", ACT_SCROLL_DOWN},
{"scroll-page-up", ACT_SCROLL_PAGE_UP},
{"scroll-page-down", ACT_SCROLL_PAGE_DOWN},
- {"scroll-top", ACT_SCROLL_TOP}, {"scroll-bottom", ACT_SCROLL_BOTTOM},
- {"new-tab", ACT_NEW_TAB}, {"next-tab", ACT_NEXT_TAB},
+ {"scroll-top", ACT_SCROLL_TOP},
+ {"scroll-bottom", ACT_SCROLL_BOTTOM},
+ {"new-tab", ACT_NEW_TAB},
+ {"next-tab", ACT_NEXT_TAB},
{"close-tab", ACT_CLOSE_TAB},
- {"prev-tab", ACT_PREV_TAB}, {"finder", ACT_FINDER},
+ {"prev-tab", ACT_PREV_TAB},
+ {"finder", ACT_FINDER},
{"palette", ACT_PALETTE},
{"workspaces", ACT_WORKSPACES},
{"save-workspace", ACT_SAVE_WORKSPACE},
- {"detach", ACT_DETACH}, {"quit", ACT_QUIT},
+ {"detach", ACT_DETACH},
+ {"quit", ACT_QUIT},
{"literal-prefix", ACT_LITERAL_PREFIX},
{"help", ACT_HELP},
{"edit-config", ACT_EDIT_CONFIG},
@@ -51,16 +63,26 @@ static const struct {
const char *name;
int key;
} NAMED_KEYS[] = {
- {"left", GHOSTTY_KEY_ARROW_LEFT}, {"right", GHOSTTY_KEY_ARROW_RIGHT},
- {"up", GHOSTTY_KEY_ARROW_UP}, {"down", GHOSTTY_KEY_ARROW_DOWN},
- {"enter", GHOSTTY_KEY_ENTER}, {"tab", GHOSTTY_KEY_TAB},
- {"escape", GHOSTTY_KEY_ESCAPE}, {"space", GHOSTTY_KEY_SPACE},
- {"backspace", GHOSTTY_KEY_BACKSPACE}, {"home", GHOSTTY_KEY_HOME},
- {"end", GHOSTTY_KEY_END}, {"pageup", GHOSTTY_KEY_PAGE_UP},
- {"pagedown", GHOSTTY_KEY_PAGE_DOWN},{"delete", GHOSTTY_KEY_DELETE},
- {"insert", GHOSTTY_KEY_INSERT}, {"backslash", GHOSTTY_KEY_BACKSLASH},
- {"minus", GHOSTTY_KEY_MINUS}, {"slash", GHOSTTY_KEY_SLASH},
- {"comma", GHOSTTY_KEY_COMMA}, {"period", GHOSTTY_KEY_PERIOD},
+ {"left", GHOSTTY_KEY_ARROW_LEFT},
+ {"right", GHOSTTY_KEY_ARROW_RIGHT},
+ {"up", GHOSTTY_KEY_ARROW_UP},
+ {"down", GHOSTTY_KEY_ARROW_DOWN},
+ {"enter", GHOSTTY_KEY_ENTER},
+ {"tab", GHOSTTY_KEY_TAB},
+ {"escape", GHOSTTY_KEY_ESCAPE},
+ {"space", GHOSTTY_KEY_SPACE},
+ {"backspace", GHOSTTY_KEY_BACKSPACE},
+ {"home", GHOSTTY_KEY_HOME},
+ {"end", GHOSTTY_KEY_END},
+ {"pageup", GHOSTTY_KEY_PAGE_UP},
+ {"pagedown", GHOSTTY_KEY_PAGE_DOWN},
+ {"delete", GHOSTTY_KEY_DELETE},
+ {"insert", GHOSTTY_KEY_INSERT},
+ {"backslash", GHOSTTY_KEY_BACKSLASH},
+ {"minus", GHOSTTY_KEY_MINUS},
+ {"slash", GHOSTTY_KEY_SLASH},
+ {"comma", GHOSTTY_KEY_COMMA},
+ {"period", GHOSTTY_KEY_PERIOD},
};
/* A character to a key, and whether typing it needs shift.
@@ -79,37 +101,37 @@ static int key_from_char(char c, bool *shifted) {
}
if (c >= '0' && c <= '9') return GHOSTTY_KEY_DIGIT_0 + (c - '0');
switch (c) {
- case '\\': return GHOSTTY_KEY_BACKSLASH;
- case '-': return GHOSTTY_KEY_MINUS;
- case '=': return GHOSTTY_KEY_EQUAL;
- case '[': return GHOSTTY_KEY_BRACKET_LEFT;
- case ']': return GHOSTTY_KEY_BRACKET_RIGHT;
- case ';': return GHOSTTY_KEY_SEMICOLON;
- case '\'': return GHOSTTY_KEY_QUOTE;
- case ',': return GHOSTTY_KEY_COMMA;
- case '.': return GHOSTTY_KEY_PERIOD;
- case '/': return GHOSTTY_KEY_SLASH;
- case '`': return GHOSTTY_KEY_BACKQUOTE;
- case ' ': return GHOSTTY_KEY_SPACE;
- default: break;
+ case '\\': return GHOSTTY_KEY_BACKSLASH;
+ case '-': return GHOSTTY_KEY_MINUS;
+ case '=': return GHOSTTY_KEY_EQUAL;
+ case '[': return GHOSTTY_KEY_BRACKET_LEFT;
+ case ']': return GHOSTTY_KEY_BRACKET_RIGHT;
+ case ';': return GHOSTTY_KEY_SEMICOLON;
+ case '\'': return GHOSTTY_KEY_QUOTE;
+ case ',': return GHOSTTY_KEY_COMMA;
+ case '.': return GHOSTTY_KEY_PERIOD;
+ case '/': return GHOSTTY_KEY_SLASH;
+ case '`': return GHOSTTY_KEY_BACKQUOTE;
+ case ' ': return GHOSTTY_KEY_SPACE;
+ default: break;
}
/* The shifted half of the same keys, which config.kdl has always said were
* writable and the parser has always refused: `bind "?" "help"` is in the
* file it ships and in every config `--dump-config` has ever written. */
if (shifted) *shifted = true;
switch (c) {
- case '|': return GHOSTTY_KEY_BACKSLASH;
- case '_': return GHOSTTY_KEY_MINUS;
- case '+': return GHOSTTY_KEY_EQUAL;
- case '{': return GHOSTTY_KEY_BRACKET_LEFT;
- case '}': return GHOSTTY_KEY_BRACKET_RIGHT;
- case ':': return GHOSTTY_KEY_SEMICOLON;
- case '"': return GHOSTTY_KEY_QUOTE;
- case '<': return GHOSTTY_KEY_COMMA;
- case '>': return GHOSTTY_KEY_PERIOD;
- case '?': return GHOSTTY_KEY_SLASH;
- case '~': return GHOSTTY_KEY_BACKQUOTE;
- default: break;
+ case '|': return GHOSTTY_KEY_BACKSLASH;
+ case '_': return GHOSTTY_KEY_MINUS;
+ case '+': return GHOSTTY_KEY_EQUAL;
+ case '{': return GHOSTTY_KEY_BRACKET_LEFT;
+ case '}': return GHOSTTY_KEY_BRACKET_RIGHT;
+ case ':': return GHOSTTY_KEY_SEMICOLON;
+ case '"': return GHOSTTY_KEY_QUOTE;
+ case '<': return GHOSTTY_KEY_COMMA;
+ case '>': return GHOSTTY_KEY_PERIOD;
+ case '?': return GHOSTTY_KEY_SLASH;
+ case '~': return GHOSTTY_KEY_BACKQUOTE;
+ default: break;
}
if (shifted) *shifted = false;
return GHOSTTY_KEY_UNIDENTIFIED;
@@ -120,8 +142,10 @@ static const struct {
const char *glyph;
int key;
} ARROW_GLYPHS[] = {
- {"\u2190", GHOSTTY_KEY_ARROW_LEFT}, {"\u2192", GHOSTTY_KEY_ARROW_RIGHT},
- {"\u2191", GHOSTTY_KEY_ARROW_UP}, {"\u2193", GHOSTTY_KEY_ARROW_DOWN},
+ {"\u2190", GHOSTTY_KEY_ARROW_LEFT},
+ {"\u2192", GHOSTTY_KEY_ARROW_RIGHT},
+ {"\u2191", GHOSTTY_KEY_ARROW_UP},
+ {"\u2193", GHOSTTY_KEY_ARROW_DOWN},
};
/* `implied` comes back true when the shift in `out_mods` came from the character
@@ -136,17 +160,33 @@ static bool parse_chord_ex(const char *text, int *out_key, uint16_t *out_mods,
const char *p = text;
if (implied) *implied = false;
for (;;) {
- if (strncmp(p, "ctrl+", 5) == 0) { mods |= MOD_CTRL; p += 5; }
- else if (strncmp(p, "alt+", 4) == 0) { mods |= MOD_ALT; p += 4; }
- else if (strncmp(p, "shift+", 6) == 0) { mods |= MOD_SHIFT; p += 6; }
- else if (strncmp(p, "super+", 6) == 0) { mods |= MOD_SUPER; p += 6; }
+ if (strncmp(p, "ctrl+", 5) == 0) {
+ mods |= MOD_CTRL;
+ p += 5;
+ } else if (strncmp(p, "alt+", 4) == 0) {
+ mods |= MOD_ALT;
+ p += 4;
+ } else if (strncmp(p, "shift+", 6) == 0) {
+ mods |= MOD_SHIFT;
+ p += 6;
+ } else if (strncmp(p, "super+", 6) == 0) {
+ mods |= MOD_SUPER;
+ p += 6;
+ }
/* The cheatsheet's own shorthand. It prints `C-a`, `M-x`, `S-tab`, and the
* whole claim of that sheet is that what it shows is what you would write
* -- which was false for every chord it printed with a modifier. */
- else if (strncmp(p, "C-", 2) == 0) { mods |= MOD_CTRL; p += 2; }
- else if (strncmp(p, "M-", 2) == 0) { mods |= MOD_ALT; p += 2; }
- else if (strncmp(p, "S-", 2) == 0) { mods |= MOD_SHIFT; p += 2; }
- else break;
+ else if (strncmp(p, "C-", 2) == 0) {
+ mods |= MOD_CTRL;
+ p += 2;
+ } else if (strncmp(p, "M-", 2) == 0) {
+ mods |= MOD_ALT;
+ p += 2;
+ } else if (strncmp(p, "S-", 2) == 0) {
+ mods |= MOD_SHIFT;
+ p += 2;
+ } else
+ break;
}
if (!*p) return false;
@@ -218,7 +258,8 @@ static void complain(config_t *c, char *err, size_t errcap, int line,
const char *file = c && c->loading ? c->loading : NULL;
const char *base = file ? strrchr(file, '/') : NULL;
if (file && line > 0)
- snprintf(full, sizeof full, "%s:%d: %s", base ? base + 1 : file, line, text);
+ snprintf(full, sizeof full, "%s:%d: %s", base ? base + 1 : file, line,
+ text);
else if (file)
snprintf(full, sizeof full, "%s: %s", base ? base + 1 : file, text);
else
@@ -236,8 +277,8 @@ size_t config_messages(const config_t *c, const char **out, size_t max) {
}
static const char *const PSTATE_NAMES[PSTATE_COUNT] = {
- "dragging", "drop_hover", "drop_target", "dead", "suspended",
- "bell", "scrolled", "unfocused",
+ "dragging", "drop_hover", "drop_target", "dead",
+ "suspended", "bell", "scrolled", "unfocused",
};
const char *pane_state_name(pane_state_t s) {
@@ -257,8 +298,8 @@ const char *pane_state_name(pane_state_t s) {
* rather than run at some guessed strength. */
static bool parse_shader_entry(const kdl_node_t *k, color_t default_color,
bool default_chrome, bool *on_chrome,
- shader_t *out,
- expr_prog_t **expr, char *why, size_t whycap) {
+ shader_t *out, expr_prog_t **expr, char *why,
+ size_t whycap) {
*expr = NULL;
/* Every parameter a shader takes is a property, so a bare argument is not a
@@ -267,7 +308,8 @@ static bool parse_shader_entry(const kdl_node_t *k, color_t default_color,
* spare word, and answering "ok" to that is how you spend ten minutes
* wondering why the second one does nothing. */
if (k->nargs) {
- snprintf(why, whycap, "unexpected argument for %s: %s (separate entries with `;`)",
+ snprintf(why, whycap,
+ "unexpected argument for %s: %s (separate entries with `;`)",
k->name, kdl_arg(k, 0, ""));
return false;
}
@@ -276,7 +318,8 @@ static bool parse_shader_entry(const kdl_node_t *k, color_t default_color,
* one we know, for the same reason a bad `amount` is: the entry says what it
* wants and we cannot do it, and running it over the contents because "chrom"
* was a typo would be a surprise nobody asked for. */
- const char *where = kdl_prop(k, "where", default_chrome ? "chrome" : "content");
+ const char *where =
+ kdl_prop(k, "where", default_chrome ? "chrome" : "content");
*on_chrome = strcmp(where, "chrome") == 0;
if (!*on_chrome && strcmp(where, "content") != 0) {
snprintf(why, whycap, "bad where for %s: %s (content or chrome)", k->name,
@@ -290,8 +333,10 @@ static bool parse_shader_entry(const kdl_node_t *k, color_t default_color,
* rectangle. Refused the same way a bad `where` is, and for the same reason. */
const char *chan = kdl_prop(k, "channel", "both");
uint8_t channels = SHADE_BOTH;
- if (strcmp(chan, "fg") == 0) channels = SHADE_FG;
- else if (strcmp(chan, "bg") == 0) channels = SHADE_BG;
+ if (strcmp(chan, "fg") == 0)
+ channels = SHADE_FG;
+ else if (strcmp(chan, "bg") == 0)
+ channels = SHADE_BG;
else if (strcmp(chan, "both") != 0) {
snprintf(why, whycap, "bad channel for %s: %s (fg, bg or both)", k->name,
chan);
@@ -350,7 +395,8 @@ static bool parse_shader_entry(const kdl_node_t *k, color_t default_color,
/* A bad colour is worth saying and not worth dropping the pass over: the
* shader runs at the default colour, which is visible, rather than not at
* all, which is not. */
- if (bad_colour) snprintf(why, whycap, "bad colour for shader %s: %s", k->name, cs);
+ if (bad_colour)
+ snprintf(why, whycap, "bad colour for shader %s: %s", k->name, cs);
return true;
}
@@ -404,9 +450,10 @@ static void parse_shader_list(config_t *c, const kdl_node_t *node,
* for their rect are dropped, and the first refusal lands in `err`. */
static size_t route_entries(const kdl_node_t *const *kids, size_t nkids,
color_t default_color, bool default_chrome,
- shader_t *content, size_t *ncontent, shader_t *chrome,
- size_t *nchrome, expr_prog_t **exprs, size_t *nexprs,
- char *err, size_t errcap) {
+ shader_t *content, size_t *ncontent,
+ shader_t *chrome, size_t *nchrome,
+ expr_prog_t **exprs, size_t *nexprs, char *err,
+ size_t errcap) {
size_t total = 0;
for (size_t i = 0; i < nkids; i++) {
const kdl_node_t *k = kids[i];
@@ -443,9 +490,9 @@ static size_t route_entries(const kdl_node_t *const *kids, size_t nkids,
* parser, so what you prototype is what you can paste and the other way round. */
size_t config_parse_chain_doc(const char *text, color_t default_color,
bool default_chrome, shader_t *content,
- size_t *ncontent, shader_t *chrome, size_t *nchrome,
- expr_prog_t **exprs, size_t *nexprs, char *err,
- size_t errcap) {
+ size_t *ncontent, shader_t *chrome,
+ size_t *nchrome, expr_prog_t **exprs,
+ size_t *nexprs, char *err, size_t errcap) {
*ncontent = 0;
*nchrome = 0;
*nexprs = 0;
@@ -455,7 +502,8 @@ size_t config_parse_chain_doc(const char *text, color_t default_color,
char perr[192] = {0};
kdl_node_t *root = kdl_parse(text, perr, sizeof perr);
if (!root) {
- if (err && errcap) snprintf(err, errcap, "%s", perr[0] ? perr : "bad chain");
+ if (err && errcap)
+ snprintf(err, errcap, "%s", perr[0] ? perr : "bad chain");
return 0;
}
@@ -467,13 +515,13 @@ size_t config_parse_chain_doc(const char *text, color_t default_color,
const kdl_node_t *k = root->kids[i];
if (k && k->name && strcmp(k->name, "shaders") == 0) block = k;
}
- const kdl_node_t *const *kids =
- block ? (const kdl_node_t *const *)block->kids
- : (const kdl_node_t *const *)root->kids;
+ const kdl_node_t *const *kids = block ? (const kdl_node_t *const *)block->kids
+ : (const kdl_node_t *const *)root->kids;
size_t nkids = block ? block->nkids : root->nkids;
- size_t n = route_entries(kids, nkids, default_color, default_chrome, content,
- ncontent, chrome, nchrome, exprs, nexprs, err, errcap);
+ size_t n =
+ route_entries(kids, nkids, default_color, default_chrome, content,
+ ncontent, chrome, nchrome, exprs, nexprs, err, errcap);
kdl_free(root);
return n;
}
@@ -492,8 +540,8 @@ size_t config_parse_chain_doc(const char *text, color_t default_color,
size_t config_parse_chain_file(const char *path, color_t default_color,
shader_t *content, size_t *ncontent,
shader_t *chrome, size_t *nchrome,
- expr_prog_t **exprs, size_t *nexprs,
- char *err, size_t errcap) {
+ expr_prog_t **exprs, size_t *nexprs, char *err,
+ size_t errcap) {
*ncontent = 0;
*nchrome = 0;
*nexprs = 0;
@@ -595,8 +643,7 @@ static const struct {
{"toast_bg", offsetof(config_t, toast_bg)},
};
-#define THEME_COLOR(c, i) \
- ((color_t *)((char *)(c) + THEME_COLORS[i].off))
+#define THEME_COLOR(c, i) ((color_t *)((char *)(c) + THEME_COLORS[i].off))
static void bind_add(config_t *c, int key, uint16_t mods, action_t action,
bool direct) {
@@ -672,10 +719,11 @@ void config_defaults(config_t *c) {
*
* Single width, and not emoji: many terminals draw those two columns wide
* while chrome here is booked as one. */
- snprintf(c->zoom_mark, sizeof c->zoom_mark, "\u25a1"); /* □ fill the tab */
- snprintf(c->zoom_on_mark, sizeof c->zoom_on_mark, "\u25a0"); /* ■ ...and back */
- snprintf(c->close_mark, sizeof c->close_mark, "\u2715"); /* ✕ close */
- snprintf(c->min_mark, sizeof c->min_mark, "\u25ac"); /* ▬ into the strip */
+ snprintf(c->zoom_mark, sizeof c->zoom_mark, "\u25a1"); /* □ fill the tab */
+ snprintf(c->zoom_on_mark, sizeof c->zoom_on_mark,
+ "\u25a0"); /* ■ ...and back */
+ snprintf(c->close_mark, sizeof c->close_mark, "\u2715"); /* ✕ close */
+ snprintf(c->min_mark, sizeof c->min_mark, "\u25ac"); /* ▬ into the strip */
snprintf(c->newtab_mark, sizeof c->newtab_mark, "+");
c->bell_indicator = true;
snprintf(c->bell_mark, sizeof c->bell_mark, "\u2022");
@@ -936,8 +984,8 @@ void config_defaults(config_t *c) {
bind_add(c, GHOSTTY_KEY_D, 0, ACT_DETACH, false);
bind_add(c, GHOSTTY_KEY_Q, 0, ACT_QUIT, false);
for (int i = 0; i < 9; i++)
- bind_add(c, GHOSTTY_KEY_DIGIT_1 + i, 0,
- (action_t)(ACT_SELECT_TAB_1 + i), false);
+ bind_add(c, GHOSTTY_KEY_DIGIT_1 + i, 0, (action_t)(ACT_SELECT_TAB_1 + i),
+ false);
}
void config_free(config_t *c) {
@@ -953,7 +1001,6 @@ void config_free(config_t *c) {
memset(c, 0, sizeof *c);
}
-
/* ---- naming things, for the cheatsheet ---------------------------------- */
/* Phrases rather than the config's names: `split-cols` is what you write,
@@ -1063,10 +1110,14 @@ void config_chord_name(int key, uint16_t mods, char *out, size_t cap) {
int key;
const char *plain, *shifted;
} PUNCT[] = {
- {GHOSTTY_KEY_SLASH, "/", "?"}, {GHOSTTY_KEY_BACKSLASH, "\\", "|"},
- {GHOSTTY_KEY_MINUS, "-", "_"}, {GHOSTTY_KEY_EQUAL, "=", "+"},
- {GHOSTTY_KEY_COMMA, ",", "<"}, {GHOSTTY_KEY_PERIOD, ".", ">"},
- {GHOSTTY_KEY_SEMICOLON, ";", ":"}, {GHOSTTY_KEY_QUOTE, "'", "\""},
+ {GHOSTTY_KEY_SLASH, "/", "?"},
+ {GHOSTTY_KEY_BACKSLASH, "\\", "|"},
+ {GHOSTTY_KEY_MINUS, "-", "_"},
+ {GHOSTTY_KEY_EQUAL, "=", "+"},
+ {GHOSTTY_KEY_COMMA, ",", "<"},
+ {GHOSTTY_KEY_PERIOD, ".", ">"},
+ {GHOSTTY_KEY_SEMICOLON, ";", ":"},
+ {GHOSTTY_KEY_QUOTE, "'", "\""},
{GHOSTTY_KEY_BRACKET_LEFT, "[", "{"},
{GHOSTTY_KEY_BRACKET_RIGHT, "]", "}"},
{GHOSTTY_KEY_BACKQUOTE, "`", "~"},
@@ -1077,8 +1128,10 @@ void config_chord_name(int key, uint16_t mods, char *out, size_t cap) {
int key;
const char *glyph;
} ARROWS[] = {
- {GHOSTTY_KEY_ARROW_LEFT, "\u2190"}, {GHOSTTY_KEY_ARROW_RIGHT, "\u2192"},
- {GHOSTTY_KEY_ARROW_UP, "\u2191"}, {GHOSTTY_KEY_ARROW_DOWN, "\u2193"},
+ {GHOSTTY_KEY_ARROW_LEFT, "\u2190"},
+ {GHOSTTY_KEY_ARROW_RIGHT, "\u2192"},
+ {GHOSTTY_KEY_ARROW_UP, "\u2191"},
+ {GHOSTTY_KEY_ARROW_DOWN, "\u2193"},
};
for (size_t i = 0; i < sizeof PUNCT / sizeof *PUNCT; i++)
@@ -1089,7 +1142,8 @@ void config_chord_name(int key, uint16_t mods, char *out, size_t cap) {
if (shifted) mods &= (uint16_t)~MOD_SHIFT; /* spent on the glyph */
}
for (size_t i = 0; i < sizeof ARROWS / sizeof *ARROWS; i++)
- if (ARROWS[i].key == key) snprintf(base, sizeof base, "%s", ARROWS[i].glyph);
+ if (ARROWS[i].key == key)
+ snprintf(base, sizeof base, "%s", ARROWS[i].glyph);
if (!base[0])
for (size_t i = 0; i < sizeof NAMED_KEYS / sizeof *NAMED_KEYS; i++)
@@ -1108,14 +1162,14 @@ void config_chord_name(int key, uint16_t mods, char *out, size_t cap) {
}
}
if (!base[0] && key >= GHOSTTY_KEY_DIGIT_0 && key <= GHOSTTY_KEY_DIGIT_9)
- snprintf(base, sizeof base, "%c", (char)('0' + (key - GHOSTTY_KEY_DIGIT_0)));
+ snprintf(base, sizeof base, "%c",
+ (char)('0' + (key - GHOSTTY_KEY_DIGIT_0)));
if (!base[0]) snprintf(base, sizeof base, "?");
snprintf(out, cap, "%s%s%s%s", mods & MOD_CTRL ? "C-" : "",
mods & MOD_ALT ? "M-" : "", mods & MOD_SHIFT ? "S-" : "", base);
}
-
/* ---- rendering a config back out ----------------------------------------
*
* Every knob with its default, as a file you could have written -- the name
@@ -1167,8 +1221,10 @@ static const char *yesno(bool v) { return v ? "true" : "false"; }
static void cb_qval(cfgbuf_t *b, const char *val) {
cb_add(b, "\"");
for (const char *q = val; q && *q; q++) {
- if (*q == '"' || *q == '\\') cb_add(b, "\\%c", *q);
- else cb_add(b, "%c", *q);
+ if (*q == '"' || *q == '\\')
+ cb_add(b, "\\%c", *q);
+ else
+ cb_add(b, "%c", *q);
}
cb_add(b, "\"");
}
@@ -1196,10 +1252,14 @@ static void cb_qstr(cfgbuf_t *b, const char *key, const char *val,
static void cb_chord(cfgbuf_t *b, int key, uint16_t mods) {
char chord[32] = {0};
size_t n = 0;
- if (mods & MOD_CTRL) n += (size_t)snprintf(chord + n, sizeof chord - n, "ctrl+");
- if (mods & MOD_ALT) n += (size_t)snprintf(chord + n, sizeof chord - n, "alt+");
- if (mods & MOD_SHIFT) n += (size_t)snprintf(chord + n, sizeof chord - n, "shift+");
- if (mods & MOD_SUPER) n += (size_t)snprintf(chord + n, sizeof chord - n, "super+");
+ if (mods & MOD_CTRL)
+ n += (size_t)snprintf(chord + n, sizeof chord - n, "ctrl+");
+ if (mods & MOD_ALT)
+ n += (size_t)snprintf(chord + n, sizeof chord - n, "alt+");
+ if (mods & MOD_SHIFT)
+ n += (size_t)snprintf(chord + n, sizeof chord - n, "shift+");
+ if (mods & MOD_SUPER)
+ n += (size_t)snprintf(chord + n, sizeof chord - n, "super+");
const char *name = NULL;
for (size_t i = 0; i < sizeof NAMED_KEYS / sizeof *NAMED_KEYS; i++)
@@ -1208,16 +1268,20 @@ static void cb_chord(cfgbuf_t *b, int key, uint16_t mods) {
if (name) {
snprintf(chord + n, sizeof chord - n, "%s", name);
} else if (key >= GHOSTTY_KEY_A && key <= GHOSTTY_KEY_Z) {
- snprintf(chord + n, sizeof chord - n, "%c", (char)('a' + (key - GHOSTTY_KEY_A)));
+ snprintf(chord + n, sizeof chord - n, "%c",
+ (char)('a' + (key - GHOSTTY_KEY_A)));
} else if (key >= GHOSTTY_KEY_DIGIT_0 && key <= GHOSTTY_KEY_DIGIT_9) {
snprintf(chord + n, sizeof chord - n, "%c",
(char)('0' + (key - GHOSTTY_KEY_DIGIT_0)));
} else {
/* The punctuation the parser knows, by the character you press. */
- static const struct { int key; char ch; } PUNCT[] = {
- {GHOSTTY_KEY_EQUAL, '='}, {GHOSTTY_KEY_BRACKET_LEFT, '['},
+ static const struct {
+ int key;
+ char ch;
+ } PUNCT[] = {
+ {GHOSTTY_KEY_EQUAL, '='}, {GHOSTTY_KEY_BRACKET_LEFT, '['},
{GHOSTTY_KEY_BRACKET_RIGHT, ']'}, {GHOSTTY_KEY_SEMICOLON, ';'},
- {GHOSTTY_KEY_QUOTE, '\''}, {GHOSTTY_KEY_BACKQUOTE, '`'},
+ {GHOSTTY_KEY_QUOTE, '\''}, {GHOSTTY_KEY_BACKQUOTE, '`'},
};
char ch = 0;
for (size_t i = 0; i < sizeof PUNCT / sizeof *PUNCT; i++)
@@ -1249,8 +1313,10 @@ static void cb_chain(cfgbuf_t *b, const char *indent, const shader_t *sh,
sh[i].color.b);
if (sh[i].param) cb_add(b, " at=%u", sh[i].param);
if (chrome) cb_add(b, " where=\"chrome\"");
- if (sh[i].channels == SHADE_FG) cb_add(b, " channel=\"fg\"");
- else if (sh[i].channels == SHADE_BG) cb_add(b, " channel=\"bg\"");
+ if (sh[i].channels == SHADE_FG)
+ cb_add(b, " channel=\"fg\"");
+ else if (sh[i].channels == SHADE_BG)
+ cb_add(b, " channel=\"bg\"");
cb_add(b, "\n");
}
}
@@ -1265,12 +1331,14 @@ char *config_render(const config_t *c) {
cb_add(&b, "// anything you do not want to pin; what is missing is a\n");
cb_add(&b, "// default, and defaults are allowed to improve.\n");
cb_add(&b, "//\n");
- cb_add(&b, "// The commented reference -- what each setting is for, and why\n");
+ cb_add(&b,
+ "// The commented reference -- what each setting is for, and why\n");
cb_add(&b, "// it exists -- is config/config.kdl in the source tree.\n\n");
cb_add(&b, "// ---- geometry ----\n");
cb_add(&b, "gap %u\n", c->gap);
- cb_add(&b, "gap_aspect %u // columns per row, so a gap looks square\n",
+ cb_add(&b,
+ "gap_aspect %u // columns per row, so a gap looks square\n",
c->gap_aspect);
/* The shortest form that means what is in force, because `padding 0` reads
* better than `padding 0 0 0 0` and round-trips to the same four numbers. */
@@ -1284,12 +1352,14 @@ char *config_render(const config_t *c) {
c->pad_right, c->pad_bottom, c->pad_left);
cb_add(&b, "rounded %s\n", yesno(c->rounded));
cb_add(&b, "title_align \"%s\"\n",
- c->title_align == ALIGN_LEFT ? "left"
- : c->title_align == ALIGN_RIGHT ? "right" : "center");
+ c->title_align == ALIGN_LEFT ? "left"
+ : c->title_align == ALIGN_RIGHT ? "right"
+ : "center");
cb_add(&b, "title_inset %u\n", c->title_inset);
cb_add(&b, "min_pane cols=%u rows=%u // below this a pane collapses\n",
c->min_pane_cols, c->min_pane_rows);
- cb_add(&b, "min_split cols=%u rows=%u // below this a split is not offered\n",
+ cb_add(&b,
+ "min_split cols=%u rows=%u // below this a split is not offered\n",
c->min_split_cols, c->min_split_rows);
cb_add(&b, "\n// ---- what is on screen ----\n");
@@ -1298,9 +1368,11 @@ char *config_render(const config_t *c) {
cb_add(&b, "status_line %s // the line along the bottom\n",
yesno(c->status_line));
cb_add(&b, "status_pad %u\n", c->status_pad);
- cb_add(&b, "hints %s // what the pointer is on, in the middle\n",
+ cb_add(&b,
+ "hints %s // what the pointer is on, in the middle\n",
yesno(c->hints));
- cb_add(&b, "version_banner %s // ...and which build this is, when idle\n",
+ cb_add(&b,
+ "version_banner %s // ...and which build this is, when idle\n",
yesno(c->version_banner));
cb_add(&b, "pane_buttons %s // the marks in a frame's top-right\n",
yesno(c->pane_buttons));
@@ -1316,10 +1388,13 @@ char *config_render(const config_t *c) {
cb_add(&b, "focus_follows_mouse %s\n", yesno(c->focus_follows_mouse));
cb_add(&b, "in_band_shaders %s\n", yesno(c->in_band_shaders));
cb_add(&b, "scroll_lines %u\n", c->scroll_lines);
- cb_add(&b, "scrollback %zu // lines of history per pane; 0 for none\n",
+ cb_add(&b,
+ "scrollback %zu // lines of history per pane; 0 for none\n",
c->scrollback);
- cb_add(&b, "scrollback_bytes %zu // the ceiling that count runs into; 0 for none\n",
- c->scrollback_bytes);
+ cb_add(
+ &b,
+ "scrollback_bytes %zu // the ceiling that count runs into; 0 for none\n",
+ c->scrollback_bytes);
cb_add(&b, "toast_ms %u\n", c->toast_ms);
cb_add(&b, "hover_delay_ms %u\n", c->hover_delay_ms);
cb_add(&b, "double_click_ms %u\n", c->double_click_ms);
@@ -1329,17 +1404,26 @@ char *config_render(const config_t *c) {
c->anim_ms);
cb_add(&b, "modal_scrim %u // how far a modal pushes the rest back\n",
c->modal_scrim);
- cb_add(&b, "dim_unfocused %u // ...and how far the panes you are not in\n",
+ cb_add(&b,
+ "dim_unfocused %u // ...and how far the panes you are not in\n",
c->dim_unfocused);
- cb_add(&b, "keep_dead \"%s\" // which dead panes stay: commands, all, none\n",
- c->keep_dead == KEEP_DEAD_ALL ? "all"
- : c->keep_dead == KEEP_DEAD_NONE ? "none" : "commands");
- if (c->shell) cb_qstr(&b, "shell", c->shell, NULL);
- else cb_add(&b, "// shell \"/bin/zsh\" // unset: $SHELL\n");
- if (c->editor) cb_qstr(&b, "editor", c->editor, NULL);
- else cb_add(&b, "// editor \"nvim\" // unset: $EDITOR, then vi\n");
- if (c->shader_dir) cb_qstr(&b, "shader_dir", c->shader_dir, NULL);
- else cb_add(&b, "// shader_dir \"~/.config/sl0ppty/shaders\"\n");
+ cb_add(&b,
+ "keep_dead \"%s\" // which dead panes stay: commands, all, none\n",
+ c->keep_dead == KEEP_DEAD_ALL ? "all"
+ : c->keep_dead == KEEP_DEAD_NONE ? "none"
+ : "commands");
+ if (c->shell)
+ cb_qstr(&b, "shell", c->shell, NULL);
+ else
+ cb_add(&b, "// shell \"/bin/zsh\" // unset: $SHELL\n");
+ if (c->editor)
+ cb_qstr(&b, "editor", c->editor, NULL);
+ else
+ cb_add(&b, "// editor \"nvim\" // unset: $EDITOR, then vi\n");
+ if (c->shader_dir)
+ cb_qstr(&b, "shader_dir", c->shader_dir, NULL);
+ else
+ cb_add(&b, "// shader_dir \"~/.config/sl0ppty/shaders\"\n");
if (c->nproject_roots) {
cb_add(&b, "project_roots");
for (size_t i = 0; i < c->nproject_roots; i++) {
@@ -1351,8 +1435,10 @@ char *config_render(const config_t *c) {
cb_add(&b, "// project_roots \"~/dev\" \"~/work\" depth=%d\n",
c->project_depth);
}
- if (c->project_layout) cb_qstr(&b, "project_layout", c->project_layout, NULL);
- else cb_add(&b, "// project_layout \"~/.config/sl0ppty/project.layout.kdl\"\n");
+ if (c->project_layout)
+ cb_qstr(&b, "project_layout", c->project_layout, NULL);
+ else
+ cb_add(&b, "// project_layout \"~/.config/sl0ppty/project.layout.kdl\"\n");
cb_add(&b, "\n// ---- colour ----\ntheme {\n");
for (size_t i = 0; i < sizeof THEME_COLORS / sizeof *THEME_COLORS; i++)
@@ -1363,19 +1449,23 @@ char *config_render(const config_t *c) {
* none", where nothing at all says "we forgot to tell you". Chrome passes
* live in the same blocks, marked, because that is how they are written. */
cb_add(&b, "\n// ---- colour passes over every pane ----\n");
- cb_add(&b, "// (contrib/shaders has thirty-odd to paste; contrib/shadertoy.html\n");
- cb_add(&b, "// previews them. where=\"chrome\" runs a pass over the frame\n");
+ cb_add(
+ &b,
+ "// (contrib/shaders has thirty-odd to paste; contrib/shadertoy.html\n");
+ cb_add(&b,
+ "// previews them. where=\"chrome\" runs a pass over the frame\n");
cb_add(&b, "// instead of the contents)\nshaders {\n");
cb_chain(&b, " ", c->shaders, c->nshaders, false);
cb_chain(&b, " ", c->chrome_shaders, c->nchrome_shaders, true);
cb_add(&b, "}\n");
- cb_add(&b, "\n// ---- what a pane looks like in a given state ----\nstates {\n");
+ cb_add(&b,
+ "\n// ---- what a pane looks like in a given state ----\nstates {\n");
for (int st = 0; st < PSTATE_COUNT; st++) {
cb_add(&b, " %s {\n", pane_state_name((pane_state_t)st));
cb_chain(&b, " ", c->state_shaders[st], c->state_n[st], false);
- cb_chain(&b, " ", c->chrome_state_shaders[st],
- c->chrome_state_n[st], true);
+ cb_chain(&b, " ", c->chrome_state_shaders[st], c->chrome_state_n[st],
+ true);
cb_add(&b, " }\n");
}
cb_add(&b, "}\n");
@@ -1468,7 +1558,8 @@ const char *config_default_path(void) {
return path;
}
const char *xdg = getenv("XDG_CONFIG_HOME");
- if (xdg && *xdg) snprintf(path, sizeof path, "%s/sl0ppty/config.kdl", xdg);
+ if (xdg && *xdg)
+ snprintf(path, sizeof path, "%s/sl0ppty/config.kdl", xdg);
else {
const char *home = getenv("HOME");
snprintf(path, sizeof path, "%s/.config/sl0ppty/config.kdl",
@@ -1558,8 +1649,9 @@ static void complain_unknown_top(config_t *c, const kdl_node_t *root, char *err,
if (!n || !n->name) continue;
if (config_is_setting(n->name)) continue;
if (strcmp(n->name, "layout") == 0)
- complain(c, err, errcap, n->line,
- "this is a layout, not a config: `sl0ppty --layout` reads those");
+ complain(
+ c, err, errcap, n->line,
+ "this is a layout, not a config: `sl0ppty --layout` reads those");
else
complain(c, err, errcap, n->line, "unknown setting: %s", n->name);
}
@@ -1583,8 +1675,10 @@ static void include_path(const char *base_file, const char *ref, char *out,
char dir[512];
snprintf(dir, sizeof dir, "%s", base_file);
char *slash = strrchr(dir, '/');
- if (slash) *slash = 0;
- else snprintf(dir, sizeof dir, ".");
+ if (slash)
+ *slash = 0;
+ else
+ snprintf(dir, sizeof dir, ".");
snprintf(out, cap, "%s/%s", dir, r);
}
@@ -1604,8 +1698,9 @@ static void include_path(const char *base_file, const char *ref, char *out,
* applied while *its* include did not still has something to say, and the first
* version only looked at the return value — so a bad file two levels down was
* reported by nobody, because the file in the middle had parsed fine. */
-static void apply_includes(config_t *c, const kdl_node_t *root, const char *path,
- int depth, char *err, size_t errcap) {
+static void apply_includes(config_t *c, const kdl_node_t *root,
+ const char *path, int depth, char *err,
+ size_t errcap) {
for (size_t i = 0; i < root->nkids; i++) {
const kdl_node_t *n = root->kids[i];
if (!n || !n->name || strcmp(n->name, "include") != 0) continue;
@@ -1623,7 +1718,8 @@ static void apply_includes(config_t *c, const kdl_node_t *root, const char *path
snprintf(ierr, sizeof ierr, "cannot include it");
/* Already carries its own file and line: it was produced by the file
* that has the problem, not by this one. */
- if (ierr[0] && err && errcap && !err[0]) snprintf(err, errcap, "%s", ierr);
+ if (ierr[0] && err && errcap && !err[0])
+ snprintf(err, errcap, "%s", ierr);
}
}
}
@@ -1705,7 +1801,8 @@ static bool load_into(config_t *c, const char *path, int depth, char *err,
size_t n = pn->nargs < 4 ? pn->nargs : 4;
for (size_t i = 0; i < n; i++) v[i] = kdl_arg_int(pn, i, 0);
if (pn->nargs == 1) {
- c->pad_top = c->pad_right = c->pad_bottom = c->pad_left = (uint16_t)v[0];
+ c->pad_top = c->pad_right = c->pad_bottom = c->pad_left =
+ (uint16_t)v[0];
} else if (pn->nargs == 2) {
c->pad_top = c->pad_bottom = (uint16_t)v[0];
c->pad_right = c->pad_left = (uint16_t)v[1];
@@ -1717,7 +1814,8 @@ static bool load_into(config_t *c, const char *path, int depth, char *err,
} else {
complain(c, err, errcap, pn->line,
"padding takes 1, 2 or 4 values (all, vertical horizontal, or "
- "top right bottom left), not %zu", pn->nargs);
+ "top right bottom left), not %zu",
+ pn->nargs);
}
}
}
@@ -1727,16 +1825,19 @@ static bool load_into(config_t *c, const char *path, int depth, char *err,
kdl_arg_bool(kdl_child(root, "status_line"), 0, c->status_line);
c->status_pad =
(uint16_t)kdl_arg_int(kdl_child(root, "status_pad"), 0, c->status_pad);
- c->focus_follows_mouse = kdl_arg_bool(kdl_child(root, "focus_follows_mouse"), 0,
- c->focus_follows_mouse);
- c->in_band_shaders = kdl_arg_bool(kdl_child(root, "in_band_shaders"), 0,
- c->in_band_shaders);
+ c->focus_follows_mouse = kdl_arg_bool(kdl_child(root, "focus_follows_mouse"),
+ 0, c->focus_follows_mouse);
+ c->in_band_shaders =
+ kdl_arg_bool(kdl_child(root, "in_band_shaders"), 0, c->in_band_shaders);
const char *align = kdl_arg(kdl_child(root, "title_align"), 0, NULL);
if (align) {
- if (strcmp(align, "left") == 0) c->title_align = ALIGN_LEFT;
- else if (strcmp(align, "right") == 0) c->title_align = ALIGN_RIGHT;
- else c->title_align = ALIGN_CENTER;
+ if (strcmp(align, "left") == 0)
+ c->title_align = ALIGN_LEFT;
+ else if (strcmp(align, "right") == 0)
+ c->title_align = ALIGN_RIGHT;
+ else
+ c->title_align = ALIGN_CENTER;
}
c->title_inset =
@@ -1763,10 +1864,12 @@ static bool load_into(config_t *c, const char *path, int depth, char *err,
* behaviour. */
const char *kd = kdl_arg(kdl_child(root, "keep_dead"), 0, NULL);
if (kd) {
- if (!strcmp(kd, "all") || !strcmp(kd, "true")) c->keep_dead = KEEP_DEAD_ALL;
+ if (!strcmp(kd, "all") || !strcmp(kd, "true"))
+ c->keep_dead = KEEP_DEAD_ALL;
else if (!strcmp(kd, "none") || !strcmp(kd, "false"))
c->keep_dead = KEEP_DEAD_NONE;
- else if (!strcmp(kd, "commands")) c->keep_dead = KEEP_DEAD_COMMANDS;
+ else if (!strcmp(kd, "commands"))
+ c->keep_dead = KEEP_DEAD_COMMANDS;
else
complain(c, err, errcap, kdl_child(root, "keep_dead")->line,
"keep_dead: %s (want commands, all or none)", kd);
@@ -1783,10 +1886,8 @@ static bool load_into(config_t *c, const char *path, int depth, char *err,
const kdl_node_t *mins = kdl_child(root, "min_split");
if (mins) {
- c->min_split_cols =
- (uint16_t)kdl_prop_int(mins, "cols", c->min_split_cols);
- c->min_split_rows =
- (uint16_t)kdl_prop_int(mins, "rows", c->min_split_rows);
+ c->min_split_cols = (uint16_t)kdl_prop_int(mins, "cols", c->min_split_cols);
+ c->min_split_rows = (uint16_t)kdl_prop_int(mins, "rows", c->min_split_rows);
}
const kdl_node_t *minp = kdl_child(root, "min_pane");
@@ -1794,8 +1895,8 @@ static bool load_into(config_t *c, const char *path, int depth, char *err,
c->min_pane_cols = (uint16_t)kdl_prop_int(minp, "cols", c->min_pane_cols);
c->min_pane_rows = (uint16_t)kdl_prop_int(minp, "rows", c->min_pane_rows);
}
- c->scroll_lines =
- (uint16_t)kdl_arg_int(kdl_child(root, "scroll_lines"), 0, c->scroll_lines);
+ c->scroll_lines = (uint16_t)kdl_arg_int(kdl_child(root, "scroll_lines"), 0,
+ c->scroll_lines);
/* Read as a `long` so a negative is *refused* rather than wrapping into a
* limit of eighteen quintillion lines, which is how "unlimited" gets into a
* program by accident. There is no unlimited on purpose: with 64 panes it is a
@@ -1803,33 +1904,35 @@ static bool load_into(config_t *c, const char *path, int depth, char *err,
const kdl_node_t *sbn = kdl_child(root, "scrollback");
if (sbn) {
long v = kdl_arg_int(sbn, 0, (long)c->scrollback);
- if (v < 0) complain(c, err, errcap, sbn->line,
- "scrollback is a number of lines, 0 for none, not %ld", v);
- else c->scrollback = (size_t)v;
+ if (v < 0)
+ complain(c, err, errcap, sbn->line,
+ "scrollback is a number of lines, 0 for none, not %ld", v);
+ else
+ c->scrollback = (size_t)v;
}
const kdl_node_t *sbb = kdl_child(root, "scrollback_bytes");
if (sbb) {
long v = kdl_arg_int(sbb, 0, (long)c->scrollback_bytes);
- if (v < 0) complain(c, err, errcap, sbb->line,
- "scrollback_bytes is a byte ceiling, 0 for none, not %ld",
- v);
- else c->scrollback_bytes = (size_t)v;
+ if (v < 0)
+ complain(c, err, errcap, sbb->line,
+ "scrollback_bytes is a byte ceiling, 0 for none, not %ld", v);
+ else
+ c->scrollback_bytes = (size_t)v;
}
- c->toast_ms = (uint16_t)kdl_arg_int(kdl_child(root, "toast_ms"), 0, c->toast_ms);
- c->hover_delay_ms = (uint16_t)kdl_arg_int(kdl_child(root, "hover_delay_ms"), 0,
- c->hover_delay_ms);
+ c->toast_ms =
+ (uint16_t)kdl_arg_int(kdl_child(root, "toast_ms"), 0, c->toast_ms);
+ c->hover_delay_ms = (uint16_t)kdl_arg_int(kdl_child(root, "hover_delay_ms"),
+ 0, c->hover_delay_ms);
c->double_click_ms = (uint16_t)kdl_arg_int(kdl_child(root, "double_click_ms"),
0, c->double_click_ms);
const char *ws = kdl_arg(kdl_child(root, "word_separators"), 0, NULL);
if (ws) snprintf(c->word_separators, sizeof c->word_separators, "%s", ws);
- c->anim_ms =
- (uint16_t)kdl_arg_int(kdl_child(root, "anim_ms"), 0, c->anim_ms);
+ c->anim_ms = (uint16_t)kdl_arg_int(kdl_child(root, "anim_ms"), 0, c->anim_ms);
{
long v = kdl_arg_int(kdl_child(root, "modal_scrim"), 0, c->modal_scrim);
c->modal_scrim = (uint8_t)(v < 0 ? 0 : v > 255 ? 255 : v);
}
-
const char *sh = kdl_arg(kdl_child(root, "shell"), 0, NULL);
if (sh) {
free(c->shell);
@@ -1859,8 +1962,10 @@ static bool load_into(config_t *c, const char *path, int depth, char *err,
} else {
snprintf(dir, sizeof dir, "%s", path);
char *slash = strrchr(dir, '/');
- if (slash) slash[1] = 0;
- else dir[0] = 0;
+ if (slash)
+ slash[1] = 0;
+ else
+ dir[0] = 0;
snprintf(dir + strlen(dir), sizeof dir - strlen(dir), "shaders");
}
char lerr[256] = {0};
@@ -1883,7 +1988,8 @@ static bool load_into(config_t *c, const char *path, int depth, char *err,
for (size_t i = 0; i < proots->nargs; i++) {
if (c->nproject_roots >= PROJECT_ROOTS_MAX) {
complain(c, err, errcap, proots->line,
- "project_roots takes at most %d directories", PROJECT_ROOTS_MAX);
+ "project_roots takes at most %d directories",
+ PROJECT_ROOTS_MAX);
break;
}
c->project_roots[c->nproject_roots++] = strdup(proots->args[i]);
diff --git a/src/config.h b/src/config.h
index 00ea5cc..6609ea3 100644
--- a/src/config.h
+++ b/src/config.h
@@ -32,7 +32,7 @@ typedef enum {
* and then exited is a pane that exited. It ends when you look at the pane,
* which is what answering a bell is. */
PSTATE_BELL,
- PSTATE_SCROLLED, /* looking at scrollback rather than the present */
+ PSTATE_SCROLLED, /* looking at scrollback rather than the present */
PSTATE_UNFOCUSED,
PSTATE_COUNT,
} pane_state_t;
@@ -183,7 +183,7 @@ typedef struct {
* number and a different question. Never used below min_pane: refusing to
* offer something the layout would collapse anyway is the floor. */
uint16_t min_split_cols, min_split_rows;
- uint16_t scroll_lines;
+ uint16_t scroll_lines; /* rows per wheel notch */
/* How much history a pane keeps. `scrollback` is the number people mean --
* lines -- and `scrollback_bytes` is the ceiling that keeps one very wide,
* heavily styled pane from spending the machine to honour it: lib-vt applies
@@ -194,8 +194,8 @@ typedef struct {
* and a silently wrapped limit is worse than a refused one. */
size_t scrollback;
size_t scrollback_bytes;
- uint16_t toast_ms;
- uint16_t hover_delay_ms; /* how long the pointer must rest to arm a guide */ /* how long an announcement stays up */ /* rows per wheel notch */
+ uint16_t toast_ms; /* how long an announcement stays up */
+ uint16_t hover_delay_ms; /* how long the pointer must rest to arm a guide */
uint16_t double_click_ms; /* how close two clicks must be to be a double */
/* What a double-click's word stops at, listed as *separators* rather than as
* word characters: anything unlisted belongs to a word, so text nobody
@@ -446,9 +446,9 @@ size_t config_files(const config_t *c, const char **out, size_t max);
* many entries were understood, writing the first refusal to `err`. */
size_t config_parse_chain_doc(const char *text, color_t default_color,
bool default_chrome, shader_t *content,
- size_t *ncontent, shader_t *chrome, size_t *nchrome,
- expr_prog_t **exprs, size_t *nexprs, char *err,
- size_t errcap);
+ size_t *ncontent, shader_t *chrome,
+ size_t *nchrome, expr_prog_t **exprs,
+ size_t *nexprs, char *err, size_t errcap);
/* The same, from a file: a `shaders { }` block as `contrib/chrome` and
* `contrib/shaders` ship them, read with the parser that already knows this
@@ -460,8 +460,8 @@ size_t config_parse_chain_doc(const char *text, color_t default_color,
size_t config_parse_chain_file(const char *path, color_t default_color,
shader_t *content, size_t *ncontent,
shader_t *chrome, size_t *nchrome,
- expr_prog_t **exprs, size_t *nexprs,
- char *err, size_t errcap);
+ expr_prog_t **exprs, size_t *nexprs, char *err,
+ size_t errcap);
/* Whether a name is one of the config's own settings. For the layout loader, which
* shares this syntax and needs to tell a config apart from a session file -- one
diff --git a/src/expr.c b/src/expr.c
index 501ac03..0df4a97 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -11,21 +11,54 @@
enum {
OP_PUSH, /* imm */
OP_VAR, /* imm = which */
- OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_NEG,
- OP_LT, OP_GT, OP_LE, OP_GE, OP_EQ, OP_NE,
- OP_AND, OP_OR, OP_NOT,
+ OP_ADD,
+ OP_SUB,
+ OP_MUL,
+ OP_DIV,
+ OP_MOD,
+ OP_NEG,
+ OP_LT,
+ OP_GT,
+ OP_LE,
+ OP_GE,
+ OP_EQ,
+ OP_NE,
+ OP_AND,
+ OP_OR,
+ OP_NOT,
/* On the 32-bit value, with JavaScript's semantics to the letter: the shift
* count is masked to five bits and `>>` keeps the sign. Not a free choice --
* contrib/shadertoy.html reimplements this language in JS and a test compares
* the two, so `x << 33` has to mean the same thing in both. */
- OP_BAND, OP_BXOR, OP_BOR, OP_BNOT, OP_SHL, OP_SHR,
- OP_MIN, OP_MAX, OP_ABS, OP_CLAMP, OP_DIST, OP_SIN, OP_COS,
+ OP_BAND,
+ OP_BXOR,
+ OP_BOR,
+ OP_BNOT,
+ OP_SHL,
+ OP_SHR,
+ OP_MIN,
+ OP_MAX,
+ OP_ABS,
+ OP_CLAMP,
+ OP_DIST,
+ OP_SIN,
+ OP_COS,
OP_SELECT, /* cond a b -> a or b, both already evaluated */
};
/* Variable slots, in the order the names table lists them. */
-enum { V_X, V_Y, V_COLS, V_ROWS, V_CURX, V_CURY, V_CURSOR, V_FOCUSED, V_T,
- V_SINCE };
+enum {
+ V_X,
+ V_Y,
+ V_COLS,
+ V_ROWS,
+ V_CURX,
+ V_CURY,
+ V_CURSOR,
+ V_FOCUSED,
+ V_T,
+ V_SINCE
+};
/* Angles are counted in degrees here (see `isin`), and pi is not a number in an
* angle language -- it is a half turn. So `PI` is 180 and `TAU` is 360, and a
@@ -190,7 +223,8 @@ static void parse_primary(parser_t *ps, expr_prog_t *pr) {
if ((*ps->p >= 'a' && *ps->p <= 'z') || (*ps->p >= 'A' && *ps->p <= 'Z') ||
*ps->p == '_') {
const char *s = ps->p;
- while ((*ps->p >= 'a' && *ps->p <= 'z') || (*ps->p >= 'A' && *ps->p <= 'Z') ||
+ while ((*ps->p >= 'a' && *ps->p <= 'z') ||
+ (*ps->p >= 'A' && *ps->p <= 'Z') ||
(*ps->p >= '0' && *ps->p <= '9') || *ps->p == '_')
ps->p++;
size_t len = (size_t)(ps->p - s);
@@ -210,9 +244,9 @@ static void parse_primary(parser_t *ps, expr_prog_t *pr) {
int args;
uint8_t op;
} FNS[] = {
- {"min", 2, OP_MIN}, {"max", 2, OP_MAX}, {"abs", 1, OP_ABS},
- {"clamp", 3, OP_CLAMP}, {"dist", 4, OP_DIST},
- {"sin", 1, OP_SIN}, {"cos", 1, OP_COS},
+ {"min", 2, OP_MIN}, {"max", 2, OP_MAX}, {"abs", 1, OP_ABS},
+ {"clamp", 3, OP_CLAMP}, {"dist", 4, OP_DIST}, {"sin", 1, OP_SIN},
+ {"cos", 1, OP_COS},
};
for (size_t i = 0; i < sizeof FNS / sizeof *FNS; i++) {
if (strcmp(FNS[i].name, name) != 0) continue;
@@ -265,10 +299,14 @@ static void parse_mul(parser_t *ps, expr_prog_t *pr) {
if (ps->failed) return;
skip_ws(ps);
uint8_t op;
- if (*ps->p == '*') op = OP_MUL;
- else if (*ps->p == '/') op = OP_DIV;
- else if (*ps->p == '%') op = OP_MOD;
- else return;
+ if (*ps->p == '*')
+ op = OP_MUL;
+ else if (*ps->p == '/')
+ op = OP_DIV;
+ else if (*ps->p == '%')
+ op = OP_MOD;
+ else
+ return;
ps->p++;
parse_primary(ps, pr);
emit(ps, pr, op, 0);
@@ -281,9 +319,12 @@ static void parse_add(parser_t *ps, expr_prog_t *pr) {
if (ps->failed) return;
skip_ws(ps);
uint8_t op;
- if (*ps->p == '+') op = OP_ADD;
- else if (*ps->p == '-') op = OP_SUB;
- else return;
+ if (*ps->p == '+')
+ op = OP_ADD;
+ else if (*ps->p == '-')
+ op = OP_SUB;
+ else
+ return;
ps->p++;
parse_mul(ps, pr);
emit(ps, pr, op, 0);
@@ -303,9 +344,12 @@ static void parse_shift(parser_t *ps, expr_prog_t *pr) {
if (ps->failed) return;
skip_ws(ps);
uint8_t op;
- if (eat(ps, "<<")) op = OP_SHL;
- else if (eat(ps, ">>")) op = OP_SHR;
- else return;
+ if (eat(ps, "<<"))
+ op = OP_SHL;
+ else if (eat(ps, ">>"))
+ op = OP_SHR;
+ else
+ return;
parse_add(ps, pr);
emit(ps, pr, op, 0);
}
@@ -356,13 +400,22 @@ static void parse_cmp(parser_t *ps, expr_prog_t *pr) {
uint8_t op;
/* Longest first: `<` would otherwise eat the `<` of `<=` and leave an `=`
* that parses as nothing. */
- if (eat(ps, "<=")) op = OP_LE;
- else if (eat(ps, ">=")) op = OP_GE;
- else if (eat(ps, "==")) op = OP_EQ;
- else if (eat(ps, "!=")) op = OP_NE;
- else if (*ps->p == '<') { ps->p++; op = OP_LT; }
- else if (*ps->p == '>') { ps->p++; op = OP_GT; }
- else return;
+ if (eat(ps, "<="))
+ op = OP_LE;
+ else if (eat(ps, ">="))
+ op = OP_GE;
+ else if (eat(ps, "=="))
+ op = OP_EQ;
+ else if (eat(ps, "!="))
+ op = OP_NE;
+ else if (*ps->p == '<') {
+ ps->p++;
+ op = OP_LT;
+ } else if (*ps->p == '>') {
+ ps->p++;
+ op = OP_GT;
+ } else
+ return;
parse_bor(ps, pr);
emit(ps, pr, op, 0);
}
@@ -404,7 +457,6 @@ static void parse_expr(parser_t *ps, expr_prog_t *pr) {
emit(ps, pr, OP_SELECT, 0);
}
-
/* ---- trigonometry, in the only arithmetic this language has ---------------
*
* `sin(d)` and `cos(d)` take **degrees** and answer -255..255. Degrees because
@@ -420,8 +472,8 @@ static void parse_expr(parser_t *ps, expr_prog_t *pr) {
* approximations of the same curve do.
*/
static const int16_t SIN_Q[91] = {
- 0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53,
- 57, 62, 66, 70, 75, 79, 83, 87, 91, 96, 100, 104, 108,
+ 0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53,
+ 57, 62, 66, 70, 75, 79, 83, 87, 91, 96, 100, 104, 108,
112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 153, 157,
160, 164, 167, 171, 174, 177, 180, 183, 186, 190, 192, 195, 198,
201, 204, 206, 209, 211, 214, 216, 219, 221, 223, 225, 227, 229,
@@ -444,15 +496,19 @@ static int vm_run(const expr_prog_t *pr, const expr_env_t *env) {
int32_t st[MAX_STACK];
int sp = 0;
const int32_t vars[] = {
- [V_X] = env->x, [V_Y] = env->y,
- [V_COLS] = env->cols, [V_ROWS] = env->rows,
- [V_CURX] = env->curx, [V_CURY] = env->cury,
- [V_CURSOR] = env->cursor, [V_FOCUSED] = env->focused,
+ [V_X] = env->x,
+ [V_Y] = env->y,
+ [V_COLS] = env->cols,
+ [V_ROWS] = env->rows,
+ [V_CURX] = env->curx,
+ [V_CURY] = env->cury,
+ [V_CURSOR] = env->cursor,
+ [V_FOCUSED] = env->focused,
[V_T] = (int32_t)(env->t & 0x7fffffff),
/* Clamped, not wrapped: a pane that has been unfocused for a month
* should read as "a long time", and a `since` that rolled over would
* make an effect restart for no reason anybody could see. */
- [V_SINCE] = (int32_t)(env->since < 0 ? 0
+ [V_SINCE] = (int32_t)(env->since < 0 ? 0
: env->since > 0x7fffffff ? 0x7fffffff
: env->since),
};
@@ -464,92 +520,160 @@ static int vm_run(const expr_prog_t *pr, const expr_env_t *env) {
* a predictable branch and turns that into a wrong colour, not a smash. */
if (sp >= MAX_STACK - 1) return 0;
switch (in->op) {
- case OP_PUSH: st[sp++] = in->imm; break;
- case OP_VAR: st[sp++] = vars[in->imm]; break;
- case OP_NEG: if (sp) st[sp - 1] = -st[sp - 1]; break;
- case OP_NOT: if (sp) st[sp - 1] = !st[sp - 1]; break;
- case OP_BNOT: if (sp) st[sp - 1] = (int32_t)~(uint32_t)st[sp - 1]; break;
- case OP_ABS: if (sp) st[sp - 1] = st[sp - 1] < 0 ? -st[sp - 1] : st[sp - 1]; break;
- case OP_SIN: if (sp) st[sp - 1] = isin(st[sp - 1]); break;
- case OP_COS: if (sp) st[sp - 1] = isin(st[sp - 1] + 90); break;
- default: {
- int need = in->op == OP_CLAMP ? 3 : in->op == OP_DIST ? 4
- : in->op == OP_SELECT ? 3 : 2;
- if (sp < need) return 0;
- int32_t b = st[sp - 1], a = st[sp - 2];
- switch (in->op) {
- case OP_ADD: st[sp - 2] = a + b; sp--; break;
- case OP_SUB: st[sp - 2] = a - b; sp--; break;
- case OP_MUL: st[sp - 2] = a * b; sp--; break;
- /* Defined rather than trapping: an expression that divides by zero
+ case OP_PUSH: st[sp++] = in->imm; break;
+ case OP_VAR: st[sp++] = vars[in->imm]; break;
+ case OP_NEG:
+ if (sp) st[sp - 1] = -st[sp - 1];
+ break;
+ case OP_NOT:
+ if (sp) st[sp - 1] = !st[sp - 1];
+ break;
+ case OP_BNOT:
+ if (sp) st[sp - 1] = (int32_t)~(uint32_t)st[sp - 1];
+ break;
+ case OP_ABS:
+ if (sp) st[sp - 1] = st[sp - 1] < 0 ? -st[sp - 1] : st[sp - 1];
+ break;
+ case OP_SIN:
+ if (sp) st[sp - 1] = isin(st[sp - 1]);
+ break;
+ case OP_COS:
+ if (sp) st[sp - 1] = isin(st[sp - 1] + 90);
+ break;
+ default: {
+ int need = in->op == OP_CLAMP ? 3
+ : in->op == OP_DIST ? 4
+ : in->op == OP_SELECT ? 3
+ : 2;
+ if (sp < need) return 0;
+ int32_t b = st[sp - 1], a = st[sp - 2];
+ switch (in->op) {
+ case OP_ADD:
+ st[sp - 2] = a + b;
+ sp--;
+ break;
+ case OP_SUB:
+ st[sp - 2] = a - b;
+ sp--;
+ break;
+ case OP_MUL:
+ st[sp - 2] = a * b;
+ sp--;
+ break;
+ /* Defined rather than trapping: an expression that divides by zero
* should look wrong, not take the session with it. */
- case OP_DIV: st[sp - 2] = b ? a / b : 0; sp--; break;
- case OP_MOD: st[sp - 2] = b ? a % b : 0; sp--; break;
- case OP_LT: st[sp - 2] = a < b; sp--; break;
- case OP_GT: st[sp - 2] = a > b; sp--; break;
- case OP_LE: st[sp - 2] = a <= b; sp--; break;
- case OP_GE: st[sp - 2] = a >= b; sp--; break;
- case OP_EQ: st[sp - 2] = a == b; sp--; break;
- case OP_NE: st[sp - 2] = a != b; sp--; break;
- case OP_AND: st[sp - 2] = a && b; sp--; break;
- case OP_BAND: st[sp - 2] = (int32_t)((uint32_t)a & (uint32_t)b); sp--; break;
- case OP_BXOR: st[sp - 2] = (int32_t)((uint32_t)a ^ (uint32_t)b); sp--; break;
- case OP_BOR: st[sp - 2] = (int32_t)((uint32_t)a | (uint32_t)b); sp--; break;
- /* Count masked to five bits, like JS, so a silly shift is defined
+ case OP_DIV:
+ st[sp - 2] = b ? a / b : 0;
+ sp--;
+ break;
+ case OP_MOD:
+ st[sp - 2] = b ? a % b : 0;
+ sp--;
+ break;
+ case OP_LT:
+ st[sp - 2] = a < b;
+ sp--;
+ break;
+ case OP_GT:
+ st[sp - 2] = a > b;
+ sp--;
+ break;
+ case OP_LE:
+ st[sp - 2] = a <= b;
+ sp--;
+ break;
+ case OP_GE:
+ st[sp - 2] = a >= b;
+ sp--;
+ break;
+ case OP_EQ:
+ st[sp - 2] = a == b;
+ sp--;
+ break;
+ case OP_NE:
+ st[sp - 2] = a != b;
+ sp--;
+ break;
+ case OP_AND:
+ st[sp - 2] = a && b;
+ sp--;
+ break;
+ case OP_BAND:
+ st[sp - 2] = (int32_t)((uint32_t)a & (uint32_t)b);
+ sp--;
+ break;
+ case OP_BXOR:
+ st[sp - 2] = (int32_t)((uint32_t)a ^ (uint32_t)b);
+ sp--;
+ break;
+ case OP_BOR:
+ st[sp - 2] = (int32_t)((uint32_t)a | (uint32_t)b);
+ sp--;
+ break;
+ /* Count masked to five bits, like JS, so a silly shift is defined
* rather than undefined. Shifted unsigned because moving a bit into
* the sign of a signed value is undefined in C and simply wraps in JS,
* which is what the preview will show. */
- case OP_SHL:
- st[sp - 2] = (int32_t)((uint32_t)a << (b & 31));
- sp--;
- break;
- /* Arithmetic: the sign is kept, so `-8 >> 1` is -4. Written out rather
+ case OP_SHL:
+ st[sp - 2] = (int32_t)((uint32_t)a << (b & 31));
+ sp--;
+ break;
+ /* Arithmetic: the sign is kept, so `-8 >> 1` is -4. Written out rather
* than left to the compiler, because a signed right shift is
* implementation-defined in C and this one has to match JS. */
- case OP_SHR: {
- unsigned k = (unsigned)(b & 31);
- uint32_t u = (uint32_t)a;
- st[sp - 2] = (int32_t)(a < 0 ? ~((~u) >> k) : u >> k);
- sp--;
- break;
- }
- case OP_OR: st[sp - 2] = a || b; sp--; break;
- case OP_MIN: st[sp - 2] = a < b ? a : b; sp--; break;
- case OP_MAX: st[sp - 2] = a > b ? a : b; sp--; break;
- case OP_CLAMP: {
- int32_t hi = st[sp - 1], lo = st[sp - 2], v = st[sp - 3];
- st[sp - 3] = v < lo ? lo : v > hi ? hi : v;
- sp -= 2;
- break;
- }
- case OP_SELECT: {
- int32_t f = st[sp - 1], t = st[sp - 2], c = st[sp - 3];
- st[sp - 3] = c ? t : f;
- sp -= 2;
- break;
- }
- case OP_DIST: {
- /* A cell is about twice as tall as it is wide, so a distance in
+ case OP_SHR: {
+ unsigned k = (unsigned)(b & 31);
+ uint32_t u = (uint32_t)a;
+ st[sp - 2] = (int32_t)(a < 0 ? ~((~u) >> k) : u >> k);
+ sp--;
+ break;
+ }
+ case OP_OR:
+ st[sp - 2] = a || b;
+ sp--;
+ break;
+ case OP_MIN:
+ st[sp - 2] = a < b ? a : b;
+ sp--;
+ break;
+ case OP_MAX:
+ st[sp - 2] = a > b ? a : b;
+ sp--;
+ break;
+ case OP_CLAMP: {
+ int32_t hi = st[sp - 1], lo = st[sp - 2], v = st[sp - 3];
+ st[sp - 3] = v < lo ? lo : v > hi ? hi : v;
+ sp -= 2;
+ break;
+ }
+ case OP_SELECT: {
+ int32_t f = st[sp - 1], t = st[sp - 2], c = st[sp - 3];
+ st[sp - 3] = c ? t : f;
+ sp -= 2;
+ break;
+ }
+ case OP_DIST: {
+ /* A cell is about twice as tall as it is wide, so a distance in
* cells counts a row double -- the same correction the layout's
* own centre-distance makes. Without it every "circle" here is an
* ellipse, which is the first thing anyone notices. */
- int32_t y2 = st[sp - 1], x2 = st[sp - 2], y1 = st[sp - 3],
- x1 = st[sp - 4];
- int32_t dx = x1 - x2, dy = (y1 - y2) * 2;
- int32_t d2 = dx * dx + dy * dy;
- /* Integer square root, so `dist` is a distance and not its
+ int32_t y2 = st[sp - 1], x2 = st[sp - 2], y1 = st[sp - 3],
+ x1 = st[sp - 4];
+ int32_t dx = x1 - x2, dy = (y1 - y2) * 2;
+ int32_t d2 = dx * dx + dy * dy;
+ /* Integer square root, so `dist` is a distance and not its
* square: expressions that scale linearly with it are what people
* write, and squaring is easy to ask for and hard to undo. */
- int32_t r = 0;
- while ((r + 1) * (r + 1) <= d2 && r < 4096) r++;
- st[sp - 4] = r;
- sp -= 3;
- break;
- }
- default: return 0;
- }
+ int32_t r = 0;
+ while ((r + 1) * (r + 1) <= d2 && r < 4096) r++;
+ st[sp - 4] = r;
+ sp -= 3;
break;
}
+ default: return 0;
+ }
+ break;
+ }
}
}
return sp ? st[sp - 1] : 0;
@@ -564,18 +688,18 @@ static bool stack_fits(const expr_prog_t *pr) {
int sp = 0, peak = 0;
for (size_t i = 0; i < pr->n; i++) {
switch (pr->code[i].op) {
- case OP_PUSH:
- case OP_VAR: sp++; break;
- case OP_NEG:
- case OP_NOT:
- case OP_BNOT:
- case OP_SIN:
- case OP_COS:
- case OP_ABS: break;
- case OP_CLAMP:
- case OP_SELECT: sp -= 2; break;
- case OP_DIST: sp -= 3; break;
- default: sp--; break;
+ case OP_PUSH:
+ case OP_VAR: sp++; break;
+ case OP_NEG:
+ case OP_NOT:
+ case OP_BNOT:
+ case OP_SIN:
+ case OP_COS:
+ case OP_ABS: break;
+ case OP_CLAMP:
+ case OP_SELECT: sp -= 2; break;
+ case OP_DIST: sp -= 3; break;
+ default: sp--; break;
}
if (sp > peak) peak = sp;
if (sp < 0) return false;
@@ -629,7 +753,9 @@ int expr_eval(const expr_prog_t *p, const expr_env_t *env) {
return vm_run(p, env);
}
-static uint8_t clamp8(int v) { return (uint8_t)(v < 0 ? 0 : v > 255 ? 255 : v); }
+static uint8_t clamp8(int v) {
+ return (uint8_t)(v < 0 ? 0 : v > 255 ? 255 : v);
+}
bool expr_amount_map(expr_prog_t *p, const expr_env_t *env, uint8_t **out) {
if (!p || !out) return false;
diff --git a/src/graphics.c b/src/graphics.c
index 8ee0177..26391fd 100644
--- a/src/graphics.c
+++ b/src/graphics.c
@@ -102,7 +102,8 @@ void gfx_begin(graphics_t *g) {
* of range for a char -- the compiler catches that one, but the same shape
* with a digit that stays in range ("\x1b1") compiles and emits one wrong
* byte. Escape then digit is always two strings. */
- out_str(g, "\x1b" "7"); /* DECSC */
+ out_str(g, "\x1b"
+ "7"); /* DECSC */
}
static gfx_image_t *img_find(graphics_t *g, uint32_t pane, uint32_t src_id) {
@@ -259,7 +260,8 @@ char *gfx_flush(graphics_t *g, size_t *out_len) {
g->len = 0;
if (g->out) g->out[0] = 0;
} else {
- out_str(g, "\x1b" "8"); /* DECRC */
+ out_str(g, "\x1b"
+ "8"); /* DECRC */
}
*out_len = g->len;
diff --git a/src/graphics.h b/src/graphics.h
index cc495ec..2967b2a 100644
--- a/src/graphics.h
+++ b/src/graphics.h
@@ -19,10 +19,10 @@ typedef struct graphics graphics_t;
/* One image, as this session knows it. */
typedef struct {
- uint32_t pane; /* which pane transmitted it */
- uint32_t src_id; /* the id the program chose, unique only within its pane */
- uint32_t out_id; /* the id we give the client, unique across the session */
- uint64_t gen; /* image generation, so a changed image is re-sent */
+ uint32_t pane; /* which pane transmitted it */
+ uint32_t src_id; /* the id the program chose, unique only within its pane */
+ uint32_t out_id; /* the id we give the client, unique across the session */
+ uint64_t gen; /* image generation, so a changed image is re-sent */
bool sent;
} gfx_image_t;
@@ -56,16 +56,16 @@ void gfx_begin(graphics_t *g);
* perfectly and shows up as a picture in slightly the wrong place — which is
* exactly the bug class this file is for. */
typedef struct {
- uint32_t pane; /* which pane it belongs to */
- uint32_t src_id; /* the id the program chose */
- uint64_t gen; /* image generation, so a changed image is re-sent */
+ uint32_t pane; /* which pane it belongs to */
+ uint32_t src_id; /* the id the program chose */
+ uint64_t gen; /* image generation, so a changed image is re-sent */
uint32_t place_id;
- uint16_t col, row; /* screen cells */
+ uint16_t col, row; /* screen cells */
uint16_t cols, rows; /* cells covered */
uint16_t scale_cols, scale_rows; /* cells to scale into, 0 for natural */
- uint32_t x_off, y_off; /* offset within the first cell, in pixels */
- uint32_t sx, sy, sw, sh; /* source rectangle, in image pixels */
- uint32_t px_w, px_h; /* the image's own size */
+ uint32_t x_off, y_off; /* offset within the first cell, in pixels */
+ uint32_t sx, sy, sw, sh; /* source rectangle, in image pixels */
+ uint32_t px_w, px_h; /* the image's own size */
int format, compression;
const uint8_t *data; /* NULL once the client has it */
size_t data_len;
diff --git a/src/input.c b/src/input.c
index 04dc0b5..47b4737 100644
--- a/src/input.c
+++ b/src/input.c
@@ -54,100 +54,113 @@ static int ascii_key(uint8_t c) {
if (c >= 'A' && c <= 'Z') return GHOSTTY_KEY_A + (c - 'A');
if (c >= '0' && c <= '9') return GHOSTTY_KEY_DIGIT_0 + (c - '0');
switch (c) {
- case ' ': return GHOSTTY_KEY_SPACE;
- case '`': case '~': return GHOSTTY_KEY_BACKQUOTE;
- case '-': case '_': return GHOSTTY_KEY_MINUS;
- case '=': case '+': return GHOSTTY_KEY_EQUAL;
- case '[': case '{': return GHOSTTY_KEY_BRACKET_LEFT;
- case ']': case '}': return GHOSTTY_KEY_BRACKET_RIGHT;
- case '\\': case '|': return GHOSTTY_KEY_BACKSLASH;
- case ';': case ':': return GHOSTTY_KEY_SEMICOLON;
- case '\'': case '"': return GHOSTTY_KEY_QUOTE;
- case ',': case '<': return GHOSTTY_KEY_COMMA;
- case '.': case '>': return GHOSTTY_KEY_PERIOD;
- case '/': case '?': return GHOSTTY_KEY_SLASH;
- case '!': return GHOSTTY_KEY_DIGIT_1;
- case '@': return GHOSTTY_KEY_DIGIT_2;
- case '#': return GHOSTTY_KEY_DIGIT_3;
- case '$': return GHOSTTY_KEY_DIGIT_4;
- case '%': return GHOSTTY_KEY_DIGIT_5;
- case '^': return GHOSTTY_KEY_DIGIT_6;
- case '&': return GHOSTTY_KEY_DIGIT_7;
- case '*': return GHOSTTY_KEY_DIGIT_8;
- case '(': return GHOSTTY_KEY_DIGIT_9;
- case ')': return GHOSTTY_KEY_DIGIT_0;
- default: return GHOSTTY_KEY_UNIDENTIFIED;
+ case ' ': return GHOSTTY_KEY_SPACE;
+ case '`':
+ case '~': return GHOSTTY_KEY_BACKQUOTE;
+ case '-':
+ case '_': return GHOSTTY_KEY_MINUS;
+ case '=':
+ case '+': return GHOSTTY_KEY_EQUAL;
+ case '[':
+ case '{': return GHOSTTY_KEY_BRACKET_LEFT;
+ case ']':
+ case '}': return GHOSTTY_KEY_BRACKET_RIGHT;
+ case '\\':
+ case '|': return GHOSTTY_KEY_BACKSLASH;
+ case ';':
+ case ':': return GHOSTTY_KEY_SEMICOLON;
+ case '\'':
+ case '"': return GHOSTTY_KEY_QUOTE;
+ case ',':
+ case '<': return GHOSTTY_KEY_COMMA;
+ case '.':
+ case '>': return GHOSTTY_KEY_PERIOD;
+ case '/':
+ case '?': return GHOSTTY_KEY_SLASH;
+ case '!': return GHOSTTY_KEY_DIGIT_1;
+ case '@': return GHOSTTY_KEY_DIGIT_2;
+ case '#': return GHOSTTY_KEY_DIGIT_3;
+ case '$': return GHOSTTY_KEY_DIGIT_4;
+ case '%': return GHOSTTY_KEY_DIGIT_5;
+ case '^': return GHOSTTY_KEY_DIGIT_6;
+ case '&': return GHOSTTY_KEY_DIGIT_7;
+ case '*': return GHOSTTY_KEY_DIGIT_8;
+ case '(': return GHOSTTY_KEY_DIGIT_9;
+ case ')': return GHOSTTY_KEY_DIGIT_0;
+ default: return GHOSTTY_KEY_UNIDENTIFIED;
}
}
/* CSI <n> ~ */
static int tilde_key(int n) {
switch (n) {
- case 1: case 7: return GHOSTTY_KEY_HOME;
- case 2: return GHOSTTY_KEY_INSERT;
- case 3: return GHOSTTY_KEY_DELETE;
- case 4: case 8: return GHOSTTY_KEY_END;
- case 5: return GHOSTTY_KEY_PAGE_UP;
- case 6: return GHOSTTY_KEY_PAGE_DOWN;
- case 11: return GHOSTTY_KEY_F1;
- case 12: return GHOSTTY_KEY_F2;
- case 13: return GHOSTTY_KEY_F3;
- case 14: return GHOSTTY_KEY_F4;
- case 15: return GHOSTTY_KEY_F5;
- case 17: return GHOSTTY_KEY_F6;
- case 18: return GHOSTTY_KEY_F7;
- case 19: return GHOSTTY_KEY_F8;
- case 20: return GHOSTTY_KEY_F9;
- case 21: return GHOSTTY_KEY_F10;
- case 23: return GHOSTTY_KEY_F11;
- case 24: return GHOSTTY_KEY_F12;
- default: return GHOSTTY_KEY_UNIDENTIFIED;
+ case 1:
+ case 7: return GHOSTTY_KEY_HOME;
+ case 2: return GHOSTTY_KEY_INSERT;
+ case 3: return GHOSTTY_KEY_DELETE;
+ case 4:
+ case 8: return GHOSTTY_KEY_END;
+ case 5: return GHOSTTY_KEY_PAGE_UP;
+ case 6: return GHOSTTY_KEY_PAGE_DOWN;
+ case 11: return GHOSTTY_KEY_F1;
+ case 12: return GHOSTTY_KEY_F2;
+ case 13: return GHOSTTY_KEY_F3;
+ case 14: return GHOSTTY_KEY_F4;
+ case 15: return GHOSTTY_KEY_F5;
+ case 17: return GHOSTTY_KEY_F6;
+ case 18: return GHOSTTY_KEY_F7;
+ case 19: return GHOSTTY_KEY_F8;
+ case 20: return GHOSTTY_KEY_F9;
+ case 21: return GHOSTTY_KEY_F10;
+ case 23: return GHOSTTY_KEY_F11;
+ case 24: return GHOSTTY_KEY_F12;
+ default: return GHOSTTY_KEY_UNIDENTIFIED;
}
}
/* final byte of a CSI/SS3 cursor-ish sequence */
static int final_key(uint8_t f) {
switch (f) {
- case 'A': return GHOSTTY_KEY_ARROW_UP;
- case 'B': return GHOSTTY_KEY_ARROW_DOWN;
- case 'C': return GHOSTTY_KEY_ARROW_RIGHT;
- case 'D': return GHOSTTY_KEY_ARROW_LEFT;
- case 'E': return GHOSTTY_KEY_NUMPAD_BEGIN;
- case 'H': return GHOSTTY_KEY_HOME;
- case 'F': return GHOSTTY_KEY_END;
- case 'P': return GHOSTTY_KEY_F1;
- case 'Q': return GHOSTTY_KEY_F2;
- case 'R': return GHOSTTY_KEY_F3;
- case 'S': return GHOSTTY_KEY_F4;
- default: return GHOSTTY_KEY_UNIDENTIFIED;
+ case 'A': return GHOSTTY_KEY_ARROW_UP;
+ case 'B': return GHOSTTY_KEY_ARROW_DOWN;
+ case 'C': return GHOSTTY_KEY_ARROW_RIGHT;
+ case 'D': return GHOSTTY_KEY_ARROW_LEFT;
+ case 'E': return GHOSTTY_KEY_NUMPAD_BEGIN;
+ case 'H': return GHOSTTY_KEY_HOME;
+ case 'F': return GHOSTTY_KEY_END;
+ case 'P': return GHOSTTY_KEY_F1;
+ case 'Q': return GHOSTTY_KEY_F2;
+ case 'R': return GHOSTTY_KEY_F3;
+ case 'S': return GHOSTTY_KEY_F4;
+ default: return GHOSTTY_KEY_UNIDENTIFIED;
}
}
/* kitty functional codepoints (CSI u form) */
static int kitty_key(uint32_t cp) {
switch (cp) {
- case 27: return GHOSTTY_KEY_ESCAPE;
- case 13: return GHOSTTY_KEY_ENTER;
- case 9: return GHOSTTY_KEY_TAB;
- case 127: return GHOSTTY_KEY_BACKSPACE;
- case 57358: return GHOSTTY_KEY_CAPS_LOCK;
- case 57359: return GHOSTTY_KEY_SCROLL_LOCK;
- case 57360: return GHOSTTY_KEY_NUM_LOCK;
- case 57361: return GHOSTTY_KEY_PRINT_SCREEN;
- case 57362: return GHOSTTY_KEY_PAUSE;
- case 57363: return GHOSTTY_KEY_CONTEXT_MENU;
- case 57441: return GHOSTTY_KEY_SHIFT_LEFT;
- case 57442: return GHOSTTY_KEY_CONTROL_LEFT;
- case 57443: return GHOSTTY_KEY_ALT_LEFT;
- case 57444: return GHOSTTY_KEY_META_LEFT;
- case 57447: return GHOSTTY_KEY_SHIFT_RIGHT;
- case 57448: return GHOSTTY_KEY_CONTROL_RIGHT;
- case 57449: return GHOSTTY_KEY_ALT_RIGHT;
- case 57450: return GHOSTTY_KEY_META_RIGHT;
- default:
- if (cp >= 57376 && cp <= 57398) return GHOSTTY_KEY_F13 + (int)(cp - 57376);
- if (cp < 128) return ascii_key((uint8_t)cp);
- return GHOSTTY_KEY_UNIDENTIFIED;
+ case 27: return GHOSTTY_KEY_ESCAPE;
+ case 13: return GHOSTTY_KEY_ENTER;
+ case 9: return GHOSTTY_KEY_TAB;
+ case 127: return GHOSTTY_KEY_BACKSPACE;
+ case 57358: return GHOSTTY_KEY_CAPS_LOCK;
+ case 57359: return GHOSTTY_KEY_SCROLL_LOCK;
+ case 57360: return GHOSTTY_KEY_NUM_LOCK;
+ case 57361: return GHOSTTY_KEY_PRINT_SCREEN;
+ case 57362: return GHOSTTY_KEY_PAUSE;
+ case 57363: return GHOSTTY_KEY_CONTEXT_MENU;
+ case 57441: return GHOSTTY_KEY_SHIFT_LEFT;
+ case 57442: return GHOSTTY_KEY_CONTROL_LEFT;
+ case 57443: return GHOSTTY_KEY_ALT_LEFT;
+ case 57444: return GHOSTTY_KEY_META_LEFT;
+ case 57447: return GHOSTTY_KEY_SHIFT_RIGHT;
+ case 57448: return GHOSTTY_KEY_CONTROL_RIGHT;
+ case 57449: return GHOSTTY_KEY_ALT_RIGHT;
+ case 57450: return GHOSTTY_KEY_META_RIGHT;
+ default:
+ if (cp >= 57376 && cp <= 57398) return GHOSTTY_KEY_F13 + (int)(cp - 57376);
+ if (cp < 128) return ascii_key((uint8_t)cp);
+ return GHOSTTY_KEY_UNIDENTIFIED;
}
}
@@ -215,9 +228,8 @@ static size_t parse_one(input_parser_t *p, input_cb_t cb, void *ud) {
static const char end[] = "\x1b[201~";
for (size_t i = 0; i + sizeof end - 1 <= n; i++) {
if (memcmp(b + i, end, sizeof end - 1) == 0) {
- input_event_t ev = {.kind = EV_PASTE,
- .paste = (const char *)b,
- .paste_len = i};
+ input_event_t ev = {
+ .kind = EV_PASTE, .paste = (const char *)b, .paste_len = i};
cb(&ev, ud);
p->in_paste = false;
return i + sizeof end - 1;
@@ -257,7 +269,10 @@ static size_t parse_one(input_parser_t *p, input_cb_t cb, void *ud) {
if (plen >= 1 && params[0] == '<' && (final == 'M' || final == 'm')) {
int f[3] = {0, 0, 0}, fi = 0;
for (size_t k = 1; k < plen && fi < 3; k++) {
- if (params[k] == ';') { fi++; continue; }
+ if (params[k] == ';') {
+ fi++;
+ continue;
+ }
if (params[k] >= '0' && params[k] <= '9')
f[fi] = f[fi] * 10 + (params[k] - '0');
}
@@ -271,14 +286,15 @@ static size_t parse_one(input_parser_t *p, input_cb_t cb, void *ud) {
bool motion = (btn & 32) != 0;
int base = btn & 0xc3; /* strip mods+motion, keep high wheel bits */
if (base >= 64 && base <= 67) {
- ev.button = (uint8_t)(MBTN_FOUR + (base - 64)); /* wheel up/down/l/r */
+ ev.button =
+ (uint8_t)(MBTN_FOUR + (base - 64)); /* wheel up/down/l/r */
ev.maction = MOUSE_PRESS;
} else {
switch (base & 3) {
- case 0: ev.button = MBTN_LEFT; break;
- case 1: ev.button = MBTN_MIDDLE; break;
- case 2: ev.button = MBTN_RIGHT; break;
- default: ev.button = MBTN_UNKNOWN; break; /* 3 = release/none */
+ case 0: ev.button = MBTN_LEFT; break;
+ case 1: ev.button = MBTN_MIDDLE; break;
+ case 2: ev.button = MBTN_RIGHT; break;
+ default: ev.button = MBTN_UNKNOWN; break; /* 3 = release/none */
}
ev.maction = motion ? MOUSE_MOTION
: (final == 'M' ? MOUSE_PRESS : MOUSE_RELEASE);
@@ -294,8 +310,10 @@ static size_t parse_one(input_parser_t *p, input_cb_t cb, void *ud) {
uint8_t ch = params[k];
if (ch >= '0' && ch <= '9') {
any = true;
- if (sub_i == 0) nums[ncount] = nums[ncount] * 10 + (ch - '0');
- else if (sub_i <= 2) subs[ncount][sub_i] = subs[ncount][sub_i] * 10 + (ch - '0');
+ if (sub_i == 0)
+ nums[ncount] = nums[ncount] * 10 + (ch - '0');
+ else if (sub_i <= 2)
+ subs[ncount][sub_i] = subs[ncount][sub_i] * 10 + (ch - '0');
} else if (ch == ':') {
if (sub_i < 2) sub_i++;
} else if (ch == ';') {
@@ -323,11 +341,13 @@ static size_t parse_one(input_parser_t *p, input_cb_t cb, void *ud) {
size_t tlen = 0;
/* associated text (3rd param) wins; else derive from the codepoint */
uint32_t out_cp = 0;
- if (ncount >= 3 && nums[2]) out_cp = (uint32_t)nums[2];
+ if (ncount >= 3 && nums[2])
+ out_cp = (uint32_t)nums[2];
else if (!(mods & (MOD_CTRL | MOD_SUPER)) && cp >= 32 && cp != 127)
out_cp = (mods & MOD_SHIFT) && shifted ? shifted : cp;
if (out_cp) {
- if (out_cp < 0x80) text[tlen++] = (char)out_cp;
+ if (out_cp < 0x80)
+ text[tlen++] = (char)out_cp;
else if (out_cp < 0x800) {
text[tlen++] = (char)(0xc0 | (out_cp >> 6));
text[tlen++] = (char)(0x80 | (out_cp & 0x3f));
@@ -393,20 +413,38 @@ static size_t parse_one(input_parser_t *p, input_cb_t cb, void *ud) {
}
/* --- C0 controls ----------------------------------------------------- */
- if (c == '\r') { emit_key(cb, ud, GHOSTTY_KEY_ENTER, 0, KEY_PRESS, "\r", 1, 13); return 1; }
- if (c == '\n') { emit_key(cb, ud, GHOSTTY_KEY_ENTER, 0, KEY_PRESS, "\r", 1, 13); return 1; }
- if (c == '\t') { emit_key(cb, ud, GHOSTTY_KEY_TAB, 0, KEY_PRESS, "\t", 1, 9); return 1; }
- if (c == 0x7f) { emit_key(cb, ud, GHOSTTY_KEY_BACKSPACE, 0, KEY_PRESS, NULL, 0, 127); return 1; }
- if (c == 0x08) { emit_key(cb, ud, GHOSTTY_KEY_BACKSPACE, 0, KEY_PRESS, NULL, 0, 8); return 1; }
- if (c == 0x00) { emit_key(cb, ud, GHOSTTY_KEY_SPACE, MOD_CTRL, KEY_PRESS, NULL, 0, ' '); return 1; }
+ if (c == '\r') {
+ emit_key(cb, ud, GHOSTTY_KEY_ENTER, 0, KEY_PRESS, "\r", 1, 13);
+ return 1;
+ }
+ if (c == '\n') {
+ emit_key(cb, ud, GHOSTTY_KEY_ENTER, 0, KEY_PRESS, "\r", 1, 13);
+ return 1;
+ }
+ if (c == '\t') {
+ emit_key(cb, ud, GHOSTTY_KEY_TAB, 0, KEY_PRESS, "\t", 1, 9);
+ return 1;
+ }
+ if (c == 0x7f) {
+ emit_key(cb, ud, GHOSTTY_KEY_BACKSPACE, 0, KEY_PRESS, NULL, 0, 127);
+ return 1;
+ }
+ if (c == 0x08) {
+ emit_key(cb, ud, GHOSTTY_KEY_BACKSPACE, 0, KEY_PRESS, NULL, 0, 8);
+ return 1;
+ }
+ if (c == 0x00) {
+ emit_key(cb, ud, GHOSTTY_KEY_SPACE, MOD_CTRL, KEY_PRESS, NULL, 0, ' ');
+ return 1;
+ }
if (c < 0x20) {
int key;
switch (c) {
- case 0x1c: key = GHOSTTY_KEY_BACKSLASH; break;
- case 0x1d: key = GHOSTTY_KEY_BRACKET_RIGHT; break;
- case 0x1e: key = GHOSTTY_KEY_DIGIT_6; break;
- case 0x1f: key = GHOSTTY_KEY_MINUS; break;
- default: key = GHOSTTY_KEY_A + (c - 1); break;
+ case 0x1c: key = GHOSTTY_KEY_BACKSLASH; break;
+ case 0x1d: key = GHOSTTY_KEY_BRACKET_RIGHT; break;
+ case 0x1e: key = GHOSTTY_KEY_DIGIT_6; break;
+ case 0x1f: key = GHOSTTY_KEY_MINUS; break;
+ default: key = GHOSTTY_KEY_A + (c - 1); break;
}
uint32_t unshifted = c < 0x1b ? (uint32_t)('a' + c - 1) : 0;
emit_key(cb, ud, key, MOD_CTRL, KEY_PRESS, NULL, 0, unshifted);
@@ -455,23 +493,23 @@ void input_timeout(input_parser_t *p, input_cb_t cb, void *ud) {
static const char *key_name(int key) {
switch (key) {
- case GHOSTTY_KEY_ARROW_UP: return "ARROW_UP";
- case GHOSTTY_KEY_ARROW_DOWN: return "ARROW_DOWN";
- case GHOSTTY_KEY_ARROW_LEFT: return "ARROW_LEFT";
- case GHOSTTY_KEY_ARROW_RIGHT: return "ARROW_RIGHT";
- case GHOSTTY_KEY_ENTER: return "ENTER";
- case GHOSTTY_KEY_TAB: return "TAB";
- case GHOSTTY_KEY_ESCAPE: return "ESCAPE";
- case GHOSTTY_KEY_BACKSPACE: return "BACKSPACE";
- case GHOSTTY_KEY_SPACE: return "SPACE";
- case GHOSTTY_KEY_HOME: return "HOME";
- case GHOSTTY_KEY_END: return "END";
- case GHOSTTY_KEY_INSERT: return "INSERT";
- case GHOSTTY_KEY_DELETE: return "DELETE";
- case GHOSTTY_KEY_PAGE_UP: return "PAGE_UP";
- case GHOSTTY_KEY_PAGE_DOWN: return "PAGE_DOWN";
- case GHOSTTY_KEY_UNIDENTIFIED: return "UNIDENTIFIED";
- default: break;
+ case GHOSTTY_KEY_ARROW_UP: return "ARROW_UP";
+ case GHOSTTY_KEY_ARROW_DOWN: return "ARROW_DOWN";
+ case GHOSTTY_KEY_ARROW_LEFT: return "ARROW_LEFT";
+ case GHOSTTY_KEY_ARROW_RIGHT: return "ARROW_RIGHT";
+ case GHOSTTY_KEY_ENTER: return "ENTER";
+ case GHOSTTY_KEY_TAB: return "TAB";
+ case GHOSTTY_KEY_ESCAPE: return "ESCAPE";
+ case GHOSTTY_KEY_BACKSPACE: return "BACKSPACE";
+ case GHOSTTY_KEY_SPACE: return "SPACE";
+ case GHOSTTY_KEY_HOME: return "HOME";
+ case GHOSTTY_KEY_END: return "END";
+ case GHOSTTY_KEY_INSERT: return "INSERT";
+ case GHOSTTY_KEY_DELETE: return "DELETE";
+ case GHOSTTY_KEY_PAGE_UP: return "PAGE_UP";
+ case GHOSTTY_KEY_PAGE_DOWN: return "PAGE_DOWN";
+ case GHOSTTY_KEY_UNIDENTIFIED: return "UNIDENTIFIED";
+ default: break;
}
if (key >= GHOSTTY_KEY_A && key <= GHOSTTY_KEY_Z) {
static char buf[2];
@@ -503,33 +541,33 @@ void input_event_describe(const input_event_t *ev, char *buf, size_t cap) {
if (ev->mods & MOD_SUPER) strcat(mods, "M");
switch (ev->kind) {
- case EV_KEY: {
- const char *act = ev->action == KEY_PRESS ? "press"
- : ev->action == KEY_RELEASE ? "release" : "repeat";
- char text[32] = "";
- if (ev->text_len) {
- snprintf(text, sizeof text, " text=%.*s", (int)ev->text_len, ev->text);
- }
- snprintf(buf, cap, "key %s mods=%s %s%s", key_name(ev->key),
- *mods ? mods : "-", act, text);
- break;
- }
- case EV_MOUSE: {
- const char *act = ev->maction == MOUSE_PRESS ? "press"
- : ev->maction == MOUSE_RELEASE ? "release" : "motion";
- snprintf(buf, cap, "mouse btn=%u %s at=%u,%u mods=%s", ev->button, act,
- ev->mx, ev->my, *mods ? mods : "-");
- break;
+ case EV_KEY: {
+ const char *act = ev->action == KEY_PRESS ? "press"
+ : ev->action == KEY_RELEASE ? "release"
+ : "repeat";
+ char text[32] = "";
+ if (ev->text_len) {
+ snprintf(text, sizeof text, " text=%.*s", (int)ev->text_len, ev->text);
}
- case EV_PASTE:
- snprintf(buf, cap, "paste len=%zu text=%.*s", ev->paste_len,
- (int)(ev->paste_len > 20 ? 20 : ev->paste_len), ev->paste);
- break;
- case EV_FOCUS:
- snprintf(buf, cap, "focus %s", ev->focused ? "in" : "out");
- break;
- default:
- snprintf(buf, cap, "none");
- break;
+ snprintf(buf, cap, "key %s mods=%s %s%s", key_name(ev->key),
+ *mods ? mods : "-", act, text);
+ break;
+ }
+ case EV_MOUSE: {
+ const char *act = ev->maction == MOUSE_PRESS ? "press"
+ : ev->maction == MOUSE_RELEASE ? "release"
+ : "motion";
+ snprintf(buf, cap, "mouse btn=%u %s at=%u,%u mods=%s", ev->button, act,
+ ev->mx, ev->my, *mods ? mods : "-");
+ break;
+ }
+ case EV_PASTE:
+ snprintf(buf, cap, "paste len=%zu text=%.*s", ev->paste_len,
+ (int)(ev->paste_len > 20 ? 20 : ev->paste_len), ev->paste);
+ break;
+ case EV_FOCUS:
+ snprintf(buf, cap, "focus %s", ev->focused ? "in" : "out");
+ break;
+ default: snprintf(buf, cap, "none"); break;
}
}
diff --git a/src/input.h b/src/input.h
index e2fd7fe..4329f78 100644
--- a/src/input.h
+++ b/src/input.h
@@ -29,23 +29,33 @@ enum { KEY_RELEASE = 0, KEY_PRESS = 1, KEY_REPEAT = 2 };
enum { MOUSE_PRESS = 0, MOUSE_RELEASE = 1, MOUSE_MOTION = 2 };
/* mirrors GhosttyMouseButton */
enum {
- MBTN_UNKNOWN = 0, MBTN_LEFT = 1, MBTN_RIGHT = 2, MBTN_MIDDLE = 3,
- MBTN_FOUR = 4, MBTN_FIVE = 5, MBTN_SIX = 6, MBTN_SEVEN = 7,
+ MBTN_UNKNOWN = 0,
+ MBTN_LEFT = 1,
+ MBTN_RIGHT = 2,
+ MBTN_MIDDLE = 3,
+ MBTN_FOUR = 4,
+ MBTN_FIVE = 5,
+ MBTN_SIX = 6,
+ MBTN_SEVEN = 7,
};
/* mirrors GHOSTTY_MODS_* */
enum {
- MOD_SHIFT = 1 << 0, MOD_CTRL = 1 << 1, MOD_ALT = 1 << 2, MOD_SUPER = 1 << 3,
- MOD_CAPS = 1 << 4, MOD_NUM = 1 << 5,
+ MOD_SHIFT = 1 << 0,
+ MOD_CTRL = 1 << 1,
+ MOD_ALT = 1 << 2,
+ MOD_SUPER = 1 << 3,
+ MOD_CAPS = 1 << 4,
+ MOD_NUM = 1 << 5,
};
typedef struct {
ev_kind_t kind;
/* EV_KEY */
- int key; /* GhosttyKey */
- uint16_t mods; /* MOD_* */
- uint8_t action; /* KEY_* */
- char text[16]; /* UTF-8 the key produced, if any */
+ int key; /* GhosttyKey */
+ uint16_t mods; /* MOD_* */
+ uint8_t action; /* KEY_* */
+ char text[16]; /* UTF-8 the key produced, if any */
uint8_t text_len;
uint32_t unshifted; /* unshifted codepoint, 0 if unknown */
diff --git a/src/json.c b/src/json.c
index efbe120..a8fb995 100644
--- a/src/json.c
+++ b/src/json.c
@@ -48,19 +48,19 @@ static void escaped(json_t *j, const char *s, size_t len) {
for (size_t i = 0; i < len; i++) {
unsigned char c = (unsigned char)s[i];
switch (c) {
- case '"': rawz(j, "\\\""); break;
- case '\\': rawz(j, "\\\\"); break;
- case '\n': rawz(j, "\\n"); break;
- case '\r': rawz(j, "\\r"); break;
- case '\t': rawz(j, "\\t"); break;
- default:
- if (c < 0x20) {
- char b[8];
- snprintf(b, sizeof b, "\\u%04x", c);
- rawz(j, b);
- } else {
- raw(j, (const char *)&c, 1); /* UTF-8 passes through */
- }
+ case '"': rawz(j, "\\\""); break;
+ case '\\': rawz(j, "\\\\"); break;
+ case '\n': rawz(j, "\\n"); break;
+ case '\r': rawz(j, "\\r"); break;
+ case '\t': rawz(j, "\\t"); break;
+ default:
+ if (c < 0x20) {
+ char b[8];
+ snprintf(b, sizeof b, "\\u%04x", c);
+ rawz(j, b);
+ } else {
+ raw(j, (const char *)&c, 1); /* UTF-8 passes through */
+ }
}
}
rawz(j, "\"");
diff --git a/src/json.h b/src/json.h
index 9e24811..f8365e4 100644
--- a/src/json.h
+++ b/src/json.h
@@ -15,7 +15,7 @@ typedef struct {
void json_init(json_t *j);
void json_free(json_t *j);
-void json_obj_open(json_t *j, const char *key); /* key may be NULL in arrays */
+void json_obj_open(json_t *j, const char *key); /* key may be NULL in arrays */
void json_obj_close(json_t *j);
void json_arr_open(json_t *j, const char *key);
void json_arr_close(json_t *j);
diff --git a/src/jsonval.c b/src/jsonval.c
index acc3334..bd718b1 100644
--- a/src/jsonval.c
+++ b/src/jsonval.c
@@ -12,7 +12,8 @@ typedef struct {
static jv_t *parse_value(P *s);
static void skip_ws(P *s) {
- while (*s->p == ' ' || *s->p == '\t' || *s->p == '\n' || *s->p == '\r') s->p++;
+ while (*s->p == ' ' || *s->p == '\t' || *s->p == '\n' || *s->p == '\r')
+ s->p++;
}
static jv_t *jv_new(jv_kind_t k) {
@@ -23,7 +24,8 @@ static jv_t *jv_new(jv_kind_t k) {
static void utf8_put(char **out, unsigned cp) {
char *o = *out;
- if (cp < 0x80) *o++ = (char)cp;
+ if (cp < 0x80)
+ *o++ = (char)cp;
else if (cp < 0x800) {
*o++ = (char)(0xc0 | (cp >> 6));
*o++ = (char)(0x80 | (cp & 0x3f));
@@ -45,9 +47,12 @@ static unsigned hex4(const char *p) {
for (int i = 0; i < 4; i++) {
char c = p[i];
v <<= 4;
- if (c >= '0' && c <= '9') v |= (unsigned)(c - '0');
- else if (c >= 'a' && c <= 'f') v |= (unsigned)(c - 'a' + 10);
- else if (c >= 'A' && c <= 'F') v |= (unsigned)(c - 'A' + 10);
+ if (c >= '0' && c <= '9')
+ v |= (unsigned)(c - '0');
+ else if (c >= 'a' && c <= 'f')
+ v |= (unsigned)(c - 'a' + 10);
+ else if (c >= 'A' && c <= 'F')
+ v |= (unsigned)(c - 'A' + 10);
}
return v;
}
@@ -66,29 +71,29 @@ static char *parse_string_raw(P *s, size_t *out_len) {
if (*s->p == '\\') {
s->p++;
switch (*s->p) {
- case 'n': *o++ = '\n'; break;
- case 't': *o++ = '\t'; break;
- case 'r': *o++ = '\r'; break;
- case 'b': *o++ = '\b'; break;
- case 'f': *o++ = '\f'; break;
- case '/': *o++ = '/'; break;
- case '"': *o++ = '"'; break;
- case '\\': *o++ = '\\'; break;
- case 'u': {
- unsigned cp = hex4(s->p + 1);
- s->p += 4;
- if (cp >= 0xd800 && cp < 0xdc00 && s->p[1] == '\\' && s->p[2] == 'u') {
- unsigned lo = hex4(s->p + 3);
- s->p += 6;
- cp = 0x10000 + ((cp - 0xd800) << 10) + (lo - 0xdc00);
- }
- utf8_put(&o, cp);
- break;
+ case 'n': *o++ = '\n'; break;
+ case 't': *o++ = '\t'; break;
+ case 'r': *o++ = '\r'; break;
+ case 'b': *o++ = '\b'; break;
+ case 'f': *o++ = '\f'; break;
+ case '/': *o++ = '/'; break;
+ case '"': *o++ = '"'; break;
+ case '\\': *o++ = '\\'; break;
+ case 'u': {
+ unsigned cp = hex4(s->p + 1);
+ s->p += 4;
+ if (cp >= 0xd800 && cp < 0xdc00 && s->p[1] == '\\' && s->p[2] == 'u') {
+ unsigned lo = hex4(s->p + 3);
+ s->p += 6;
+ cp = 0x10000 + ((cp - 0xd800) << 10) + (lo - 0xdc00);
}
- default:
- s->bad = true;
- free(buf);
- return NULL;
+ utf8_put(&o, cp);
+ break;
+ }
+ default:
+ s->bad = true;
+ free(buf);
+ return NULL;
}
s->p++;
} else {
@@ -121,20 +126,38 @@ static jv_t *parse_value(P *s) {
for (;;) {
skip_ws(s);
char *key = parse_string_raw(s, NULL);
- if (s->bad) { jv_free(v); return NULL; }
+ if (s->bad) {
+ jv_free(v);
+ return NULL;
+ }
skip_ws(s);
- if (*s->p != ':') { s->bad = true; free(key); jv_free(v); return NULL; }
+ if (*s->p != ':') {
+ s->bad = true;
+ free(key);
+ jv_free(v);
+ return NULL;
+ }
s->p++;
jv_t *val = parse_value(s);
- if (!val) { free(key); jv_free(v); return NULL; }
+ if (!val) {
+ free(key);
+ jv_free(v);
+ return NULL;
+ }
v->keys = realloc(v->keys, (v->len + 1) * sizeof *v->keys);
v->kids = realloc(v->kids, (v->len + 1) * sizeof *v->kids);
v->keys[v->len] = key;
v->kids[v->len] = val;
v->len++;
skip_ws(s);
- if (*s->p == ',') { s->p++; continue; }
- if (*s->p == '}') { s->p++; return v; }
+ if (*s->p == ',') {
+ s->p++;
+ continue;
+ }
+ if (*s->p == '}') {
+ s->p++;
+ return v;
+ }
s->bad = true;
jv_free(v);
return NULL;
@@ -151,12 +174,21 @@ static jv_t *parse_value(P *s) {
}
for (;;) {
jv_t *val = parse_value(s);
- if (!val) { jv_free(v); return NULL; }
+ if (!val) {
+ jv_free(v);
+ return NULL;
+ }
v->kids = realloc(v->kids, (v->len + 1) * sizeof *v->kids);
v->kids[v->len++] = val;
skip_ws(s);
- if (*s->p == ',') { s->p++; continue; }
- if (*s->p == ']') { s->p++; return v; }
+ if (*s->p == ',') {
+ s->p++;
+ continue;
+ }
+ if (*s->p == ']') {
+ s->p++;
+ return v;
+ }
s->bad = true;
jv_free(v);
return NULL;
diff --git a/src/jsonval.h b/src/jsonval.h
index 53f1fe1..9d0a5d2 100644
--- a/src/jsonval.h
+++ b/src/jsonval.h
@@ -8,7 +8,12 @@
#include <stddef.h>
typedef enum {
- JV_NULL, JV_BOOL, JV_NUM, JV_STR, JV_ARR, JV_OBJ,
+ JV_NULL,
+ JV_BOOL,
+ JV_NUM,
+ JV_STR,
+ JV_ARR,
+ JV_OBJ,
} jv_kind_t;
typedef struct jv jv_t;
diff --git a/src/kdl.c b/src/kdl.c
index 1ff4e79..13d624f 100644
--- a/src/kdl.c
+++ b/src/kdl.c
@@ -85,13 +85,13 @@ static char *parse_string(K *k) {
if (c == '\\') {
char e = *k->p++;
switch (e) {
- case 'n': c = '\n'; break;
- case 't': c = '\t'; break;
- case 'r': c = '\r'; break;
- case 'e': c = 0x1b; break;
- case '\\': c = '\\'; break;
- case '"': c = '"'; break;
- default: c = e; break;
+ case 'n': c = '\n'; break;
+ case 't': c = '\t'; break;
+ case 'r': c = '\r'; break;
+ case 'e': c = 0x1b; break;
+ case '\\': c = '\\'; break;
+ case '"': c = '"'; break;
+ default: c = e; break;
}
}
if (c == '\n') k->line++;
@@ -276,7 +276,8 @@ bool kdl_arg_bool(const kdl_node_t *n, size_t i, bool fallback) {
return fallback;
}
-const char *kdl_prop(const kdl_node_t *n, const char *key, const char *fallback) {
+const char *kdl_prop(const kdl_node_t *n, const char *key,
+ const char *fallback) {
if (!n) return fallback;
for (size_t i = n->nprops; i-- > 0;) /* last wins */
if (strcmp(n->props[i].key, key) == 0) return n->props[i].val;
diff --git a/src/kdl.h b/src/kdl.h
index 390b6b4..9a774c7 100644
--- a/src/kdl.h
+++ b/src/kdl.h
@@ -42,7 +42,8 @@ const kdl_node_t *kdl_child(const kdl_node_t *n, const char *name);
const char *kdl_arg(const kdl_node_t *n, size_t i, const char *fallback);
long kdl_arg_int(const kdl_node_t *n, size_t i, long fallback);
bool kdl_arg_bool(const kdl_node_t *n, size_t i, bool fallback);
-const char *kdl_prop(const kdl_node_t *n, const char *key, const char *fallback);
+const char *kdl_prop(const kdl_node_t *n, const char *key,
+ const char *fallback);
long kdl_prop_int(const kdl_node_t *n, const char *key, long fallback);
bool kdl_prop_bool(const kdl_node_t *n, const char *key, bool fallback);
diff --git a/src/main.c b/src/main.c
index e393699..766d290 100644
--- a/src/main.c
+++ b/src/main.c
@@ -46,7 +46,8 @@ static void term_size(uint16_t *cols, uint16_t *rows) {
* is a config whose "defaults would stand". */
static bool looks_like_layout(const char *path) {
char buf[1024];
- kdl_node_t *root = kdl_parse_file(path_expand(path, buf, sizeof buf), NULL, 0);
+ kdl_node_t *root =
+ kdl_parse_file(path_expand(path, buf, sizeof buf), NULL, 0);
if (!root) return strstr(path, ".layout.") != NULL;
bool layout = false;
for (size_t i = 0; i < root->nkids && !layout; i++) {
@@ -113,8 +114,7 @@ static int check_config(const char *path) {
char prefix[24];
config_chord_name(cfg.prefix_key, cfg.prefix_mods, prefix, sizeof prefix);
printf("%s: ok\n", file);
- for (size_t i = 0; i < nf; i++)
- printf(" read %s\n", files[i]);
+ for (size_t i = 0; i < nf; i++) printf(" read %s\n", files[i]);
printf(" prefix %s\n", prefix);
printf(" bindings %zu\n", cfg.nbinds);
}
@@ -149,22 +149,28 @@ int main(int argc, char **argv) {
for (int i = 1; i < argc; i++) {
const char *a = argv[i];
- if (strcmp(a, "--headless") == 0) headless = true;
- else if (strcmp(a, "--script") == 0) headless = script = true;
- else if (strcmp(a, "--server") == 0) server = true;
- else if (strcmp(a, "-s") == 0 && i + 1 < argc) name = argv[++i];
- else if (strcmp(a, "--layout") == 0 && i + 1 < argc) layout = argv[++i];
- else if (strcmp(a, "--no-reload") == 0) watch = false;
+ if (strcmp(a, "--headless") == 0)
+ headless = true;
+ else if (strcmp(a, "--script") == 0)
+ headless = script = true;
+ else if (strcmp(a, "--server") == 0)
+ server = true;
+ else if (strcmp(a, "-s") == 0 && i + 1 < argc)
+ name = argv[++i];
+ else if (strcmp(a, "--layout") == 0 && i + 1 < argc)
+ layout = argv[++i];
+ else if (strcmp(a, "--no-reload") == 0)
+ watch = false;
else if (strcmp(a, "--check") == 0) {
/* An optional path, so it lints a file you have not installed yet:
* `sl0ppty --check theme.kdl`. Without one it checks the config a session
* would actually read. A layout is checked as a layout: one flag, and the
* file decides which schema it is held to. */
- const char *path = (i + 1 < argc && argv[i + 1][0] != '-') ? argv[++i] : NULL;
+ const char *path =
+ (i + 1 < argc && argv[i + 1][0] != '-') ? argv[++i] : NULL;
return path && looks_like_layout(path) ? check_layout(path)
- : check_config(path);
- }
- else if (strcmp(a, "--dump-config") == 0) {
+ : check_config(path);
+ } else if (strcmp(a, "--dump-config") == 0) {
/* Every setting with its *default*, as a file you could have written:
* `sl0ppty --dump-config > ~/.config/sl0ppty/config.kdl` is a supported
* way to start one. Deliberately not the values a config in effect gives
@@ -174,23 +180,27 @@ int main(int argc, char **argv) {
fputs(text, stdout);
free(text);
return 0;
- }
- else if (strcmp(a, "--version") == 0) {
+ } else if (strcmp(a, "--version") == 0) {
/* The same string the status line shows, so "which build is this" has
* one answer whether you ask the binary or the session. */
printf("sl0ppty %s\n", SL0PPTY_VERSION);
return 0;
- }
- else if (strcmp(a, "ls") == 0) list = true;
- else if (strcmp(a, "cmd") == 0 && i + 1 < argc) cmd_line = argv[++i];
- else if (strcmp(a, "--cols") == 0 && i + 1 < argc) cols = (uint16_t)atoi(argv[++i]);
- else if (strcmp(a, "--rows") == 0 && i + 1 < argc) rows = (uint16_t)atoi(argv[++i]);
- else if (strcmp(a, "--idle-ms") == 0 && i + 1 < argc) idle_ms = atoi(argv[++i]);
+ } else if (strcmp(a, "ls") == 0)
+ list = true;
+ else if (strcmp(a, "cmd") == 0 && i + 1 < argc)
+ cmd_line = argv[++i];
+ else if (strcmp(a, "--cols") == 0 && i + 1 < argc)
+ cols = (uint16_t)atoi(argv[++i]);
+ else if (strcmp(a, "--rows") == 0 && i + 1 < argc)
+ rows = (uint16_t)atoi(argv[++i]);
+ else if (strcmp(a, "--idle-ms") == 0 && i + 1 < argc)
+ idle_ms = atoi(argv[++i]);
else if (strcmp(a, "-h") == 0 || strcmp(a, "--help") == 0) {
usage();
return 0;
} else if (strcmp(a, "--") == 0) {
- for (int j = i + 1; j < argc && cmd_n < 63; j++) cmd_argv[cmd_n++] = argv[j];
+ for (int j = i + 1; j < argc && cmd_n < 63; j++)
+ cmd_argv[cmd_n++] = argv[j];
break;
} else {
fprintf(stderr, "sl0ppty: unknown argument: %s\n", a);
@@ -227,7 +237,8 @@ int main(int argc, char **argv) {
return client_control(fd, cmd_line);
}
- if (headless) return run_headless(cmd_argv, cols, rows, idle_ms, script, layout);
+ if (headless)
+ return run_headless(cmd_argv, cols, rows, idle_ms, script, layout);
if (isatty(STDOUT_FILENO)) term_size(&cols, &rows);
if (server) return server_run(name, cmd_argv, cols, rows, layout, watch);
diff --git a/src/osc5577.c b/src/osc5577.c
index 35f23b4..dd2ec26 100644
--- a/src/osc5577.c
+++ b/src/osc5577.c
@@ -45,47 +45,47 @@ void osc_scan_feed(osc_scan_t *s, const uint8_t *data, size_t len,
for (size_t i = 0; i < len; i++) {
uint8_t c = data[i];
switch (s->state) {
- case OS_GROUND:
- if (c == 0x1b) s->state = OS_ESC;
- break;
+ case OS_GROUND:
+ if (c == 0x1b) s->state = OS_ESC;
+ break;
- case OS_ESC:
- if (c == ']') {
- s->state = OS_BODY;
- s->len = 0;
- s->overflow = false;
- } else {
- s->state = c == 0x1b ? OS_ESC : OS_GROUND;
- }
- break;
+ case OS_ESC:
+ if (c == ']') {
+ s->state = OS_BODY;
+ s->len = 0;
+ s->overflow = false;
+ } else {
+ s->state = c == 0x1b ? OS_ESC : OS_GROUND;
+ }
+ break;
- case OS_BODY:
- if (c == 0x07) { /* BEL terminator, as accepted for OSC 0/2 */
- if (!s->overflow) dispatch(s->buf, s->len, cb, ud);
- s->state = OS_GROUND;
- } else if (c == 0x1b) {
- s->state = OS_BODY_ESC;
- } else if (c < 0x20) {
- s->state = OS_GROUND; /* a control byte ends a malformed OSC */
- } else if (s->len < sizeof s->buf) {
- s->buf[s->len++] = (char)c;
- } else {
- s->overflow = true; /* keep scanning to the terminator, then drop */
- }
- break;
+ case OS_BODY:
+ if (c == 0x07) { /* BEL terminator, as accepted for OSC 0/2 */
+ if (!s->overflow) dispatch(s->buf, s->len, cb, ud);
+ s->state = OS_GROUND;
+ } else if (c == 0x1b) {
+ s->state = OS_BODY_ESC;
+ } else if (c < 0x20) {
+ s->state = OS_GROUND; /* a control byte ends a malformed OSC */
+ } else if (s->len < sizeof s->buf) {
+ s->buf[s->len++] = (char)c;
+ } else {
+ s->overflow = true; /* keep scanning to the terminator, then drop */
+ }
+ break;
- case OS_BODY_ESC:
- if (c == '\\') { /* ST */
- if (!s->overflow) dispatch(s->buf, s->len, cb, ud);
- s->state = OS_GROUND;
- } else if (c == ']') {
- s->state = OS_BODY; /* a new OSC started inside one: restart */
- s->len = 0;
- s->overflow = false;
- } else {
- s->state = OS_GROUND;
- }
- break;
+ case OS_BODY_ESC:
+ if (c == '\\') { /* ST */
+ if (!s->overflow) dispatch(s->buf, s->len, cb, ud);
+ s->state = OS_GROUND;
+ } else if (c == ']') {
+ s->state = OS_BODY; /* a new OSC started inside one: restart */
+ s->len = 0;
+ s->overflow = false;
+ } else {
+ s->state = OS_GROUND;
+ }
+ break;
}
}
}
diff --git a/src/pane.c b/src/pane.c
index 860806f..16734c7 100644
--- a/src/pane.c
+++ b/src/pane.c
@@ -233,9 +233,11 @@ static void on_notify(GhosttyTerminal t, void *ud,
if (!p->notify_cb || !n) return;
char title[96] = {0}, body[96] = {0};
if (n->title.len)
- snprintf(title, sizeof title, "%.*s", (int)n->title.len, (const char *)n->title.ptr);
+ snprintf(title, sizeof title, "%.*s", (int)n->title.len,
+ (const char *)n->title.ptr);
if (n->body.len)
- snprintf(body, sizeof body, "%.*s", (int)n->body.len, (const char *)n->body.ptr);
+ snprintf(body, sizeof body, "%.*s", (int)n->body.len,
+ (const char *)n->body.ptr);
p->notify_cb(p, title, body, p->notify_ud);
}
@@ -356,8 +358,8 @@ pane_t *pane_new(const char *const argv[], uint16_t cols, uint16_t rows,
* clusters too; under a terminal that does not, wide emoji may misalign. */
static const uint16_t default_on[] = {25, 2027};
for (size_t i = 0; i < sizeof default_on / sizeof *default_on; i++) {
- GhosttyTerminalModeConfig mc = {.mode = ghostty_mode_new(default_on[i], false),
- .value = true};
+ GhosttyTerminalModeConfig mc = {
+ .mode = ghostty_mode_new(default_on[i], false), .value = true};
ghostty_terminal_set(p->term, GHOSTTY_TERMINAL_OPT_MODE_DEFAULT, &mc);
}
@@ -691,8 +693,10 @@ void pane_send_mouse(pane_t *p, const input_event_t *ev) {
ghostty_mouse_event_set_position(p->mev, pos);
/* "no button held" is its own thing, not button zero: bare motion (hover)
* must be encoded as none, or a pane in any-event tracking sees nothing. */
- if (ev->button == MBTN_UNKNOWN) ghostty_mouse_event_clear_button(p->mev);
- else ghostty_mouse_event_set_button(p->mev, (GhosttyMouseButton)ev->button);
+ if (ev->button == MBTN_UNKNOWN)
+ ghostty_mouse_event_clear_button(p->mev);
+ else
+ ghostty_mouse_event_set_button(p->mev, (GhosttyMouseButton)ev->button);
ghostty_mouse_event_set_action(p->mev, (GhosttyMouseAction)ev->maction);
ghostty_mouse_event_set_mods(p->mev, (GhosttyMods)ev->mods);
@@ -737,7 +741,8 @@ size_t pane_graphics(pane_t *p, pane_gfx_fn cb, void *ud) {
if (ghostty_kitty_graphics_placement_iterator_new(NULL, &it) !=
GHOSTTY_SUCCESS)
return 0;
- if (ghostty_kitty_graphics_get(gfx, GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR,
+ if (ghostty_kitty_graphics_get(gfx,
+ GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR,
&it) != GHOSTTY_SUCCESS) {
ghostty_kitty_graphics_placement_iterator_free(it);
return 0;
@@ -838,10 +843,12 @@ size_t pane_graphics(pane_t *p, pane_gfx_fn cb, void *ud) {
const uint8_t *data = NULL;
size_t data_len = 0;
ghostty_kitty_graphics_image_get(img, GHOSTTY_KITTY_IMAGE_DATA_WIDTH, &w);
- ghostty_kitty_graphics_image_get(img, GHOSTTY_KITTY_IMAGE_DATA_HEIGHT, &h);
- ghostty_kitty_graphics_image_get(img, GHOSTTY_KITTY_IMAGE_DATA_FORMAT, &fmt);
- ghostty_kitty_graphics_image_get(img, GHOSTTY_KITTY_IMAGE_DATA_COMPRESSION,
- &comp);
+ ghostty_kitty_graphics_image_get(img, GHOSTTY_KITTY_IMAGE_DATA_HEIGHT,
+ &h);
+ ghostty_kitty_graphics_image_get(img, GHOSTTY_KITTY_IMAGE_DATA_FORMAT,
+ &fmt);
+ ghostty_kitty_graphics_image_get(
+ img, GHOSTTY_KITTY_IMAGE_DATA_COMPRESSION, &comp);
ghostty_kitty_graphics_image_get(img, GHOSTTY_KITTY_IMAGE_DATA_GENERATION,
&generation);
ghostty_kitty_graphics_image_get(img, GHOSTTY_KITTY_IMAGE_DATA_DATA_PTR,
@@ -872,7 +879,8 @@ size_t pane_graphics(pane_t *p, pane_gfx_fn cb, void *ud) {
* reports the per-row range for us to highlight.
*/
-static bool grid_ref_at(pane_t *p, uint16_t x, uint16_t y, GhosttyGridRef *out) {
+static bool grid_ref_at(pane_t *p, uint16_t x, uint16_t y,
+ GhosttyGridRef *out) {
GhosttyPoint pt = {.tag = GHOSTTY_POINT_TAG_VIEWPORT,
.value.coordinate = {.x = x, .y = y}};
return ghostty_terminal_grid_ref(p->term, pt, out) == GHOSTTY_SUCCESS;
@@ -935,7 +943,8 @@ static bool word_cell(const char *utf8, size_t len, const char *seps) {
* forward. Which is enough: the run containing `x` is bounded by the separator
* before it and the one after it, and both are met on that single pass. */
bool pane_select_word(pane_t *p, uint16_t x, uint16_t y, const char *seps) {
- if (!p || !p->term || !p->rstate || x >= p->cols || y >= p->rows_n) return false;
+ if (!p || !p->term || !p->rstate || x >= p->cols || y >= p->rows_n)
+ return false;
if (ghostty_render_state_update(p->rstate, p->term) != GHOSTTY_SUCCESS)
return false;
if (ghostty_render_state_get(p->rstate,
@@ -1012,7 +1021,8 @@ bool pane_select_word(pane_t *p, uint16_t x, uint16_t y, const char *seps) {
if (!done) return false;
GhosttyGridRef a, b;
- if (!grid_ref_at(p, left, y, &a) || !grid_ref_at(p, right, y, &b)) return false;
+ if (!grid_ref_at(p, left, y, &a) || !grid_ref_at(p, right, y, &b))
+ return false;
GhosttySelection sel = GHOSTTY_INIT_SIZED(GhosttySelection);
sel.start = a;
sel.end = b;
@@ -1045,8 +1055,8 @@ char *pane_selection_text(pane_t *p) {
opts.trim = true;
uint8_t *ptr = NULL;
size_t len = 0;
- if (ghostty_terminal_selection_format_alloc(p->term, NULL, opts, &ptr, &len) !=
- GHOSTTY_SUCCESS ||
+ if (ghostty_terminal_selection_format_alloc(p->term, NULL, opts, &ptr,
+ &len) != GHOSTTY_SUCCESS ||
!len)
return NULL;
char *out = malloc(len + 1);
@@ -1066,14 +1076,16 @@ void pane_scroll(pane_t *p, int delta) {
}
void pane_scroll_edge(pane_t *p, bool top) {
- GhosttyTerminalScrollViewport b = {
- .tag = top ? GHOSTTY_SCROLL_VIEWPORT_TOP : GHOSTTY_SCROLL_VIEWPORT_BOTTOM};
+ GhosttyTerminalScrollViewport b = {.tag =
+ top ? GHOSTTY_SCROLL_VIEWPORT_TOP
+ : GHOSTTY_SCROLL_VIEWPORT_BOTTOM};
ghostty_terminal_scroll_viewport(p->term, b);
p->dirty = true;
}
bool pane_scrolled(const pane_t *p) {
- bool active = true; /* "the viewport is on the active area", i.e. the bottom */
+ bool active =
+ true; /* "the viewport is on the active area", i.e. the bottom */
ghostty_terminal_get(p->term, GHOSTTY_TERMINAL_DATA_VIEWPORT_ACTIVE, &active);
return !active;
}
@@ -1135,16 +1147,19 @@ static color_t to_color(const GhosttyColorRgb *c, bool ok) {
void pane_compose(pane_t *p, screen_t *s, uint16_t x0, uint16_t y0,
bool focused) {
- if (ghostty_render_state_update(p->rstate, p->term) != GHOSTTY_SUCCESS) return;
+ if (ghostty_render_state_update(p->rstate, p->term) != GHOSTTY_SUCCESS)
+ return;
- if (ghostty_render_state_get(p->rstate, GHOSTTY_RENDER_STATE_DATA_ROW_ITERATOR,
+ if (ghostty_render_state_get(p->rstate,
+ GHOSTTY_RENDER_STATE_DATA_ROW_ITERATOR,
&p->rows) != GHOSTTY_SUCCESS)
return;
uint16_t y = 0;
while (ghostty_render_state_row_iterator_next(p->rows)) {
if (y >= p->rows_n) break;
- if (ghostty_render_state_row_get(p->rows, GHOSTTY_RENDER_STATE_ROW_DATA_CELLS,
+ if (ghostty_render_state_row_get(p->rows,
+ GHOSTTY_RENDER_STATE_ROW_DATA_CELLS,
&p->cells) != GHOSTTY_SUCCESS) {
y++;
continue;
@@ -1214,8 +1229,12 @@ void pane_compose(pane_t *p, screen_t *s, uint16_t x0, uint16_t y0,
size_t n = gb.len < sizeof dst->text ? gb.len : sizeof dst->text;
memset(dst->text, 0, sizeof dst->text);
- if (n) memcpy(dst->text, utf8, n);
- else { dst->text[0] = ' '; n = 1; }
+ if (n)
+ memcpy(dst->text, utf8, n);
+ else {
+ dst->text[0] = ' ';
+ n = 1;
+ }
dst->len = (uint8_t)n;
dst->width = wide == GHOSTTY_CELL_WIDE_WIDE ? 2 : 1;
/* Selected cells are inverted rather than recoloured, so a selection
@@ -1234,15 +1253,16 @@ void pane_compose(pane_t *p, screen_t *s, uint16_t x0, uint16_t y0,
if (focused) {
bool vis = false, has_pos = false;
uint16_t cxp = 0, cyp = 0;
- ghostty_render_state_get(p->rstate, GHOSTTY_RENDER_STATE_DATA_CURSOR_VISIBLE,
- &vis);
+ ghostty_render_state_get(p->rstate,
+ GHOSTTY_RENDER_STATE_DATA_CURSOR_VISIBLE, &vis);
ghostty_render_state_get(
- p->rstate, GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_HAS_VALUE, &has_pos);
+ p->rstate, GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_HAS_VALUE,
+ &has_pos);
if (vis && has_pos) {
- ghostty_render_state_get(p->rstate,
- GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_X, &cxp);
- ghostty_render_state_get(p->rstate,
- GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_Y, &cyp);
+ ghostty_render_state_get(
+ p->rstate, GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_X, &cxp);
+ ghostty_render_state_get(
+ p->rstate, GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_Y, &cyp);
s->cursor_visible = true;
s->cursor_x = (uint16_t)(x0 + cxp);
s->cursor_y = (uint16_t)(y0 + cyp);
@@ -1252,6 +1272,7 @@ void pane_compose(pane_t *p, screen_t *s, uint16_t x0, uint16_t y0,
}
GhosttyRenderStateDirty clean = GHOSTTY_RENDER_STATE_DIRTY_FALSE;
- ghostty_render_state_set(p->rstate, GHOSTTY_RENDER_STATE_OPTION_DIRTY, &clean);
+ ghostty_render_state_set(p->rstate, GHOSTTY_RENDER_STATE_OPTION_DIRTY,
+ &clean);
p->dirty = false;
}
diff --git a/src/project.c b/src/project.c
index 4e2ba2d..381d17f 100644
--- a/src/project.c
+++ b/src/project.c
@@ -70,12 +70,14 @@ static bool describe(const char *path, project_t *p) {
const char *resolved = realpath(path, real) ? real : path;
snprintf(p->path, sizeof p->path, "%s", resolved);
basename_of(p->path, p->name, sizeof p->name);
- if (!p->name[0] || p->name[0] == '.') return false; /* not `.`, `..`, dotdirs */
+ if (!p->name[0] || p->name[0] == '.')
+ return false; /* not `.`, `..`, dotdirs */
project_slug(p->path, p->name, p->slug, sizeof p->slug);
struct stat lst;
if (exists(p->path, PROJECT_LAYOUT_FILE, &lst)) {
- snprintf(p->layout, sizeof p->layout, "%s/%s", p->path, PROJECT_LAYOUT_FILE);
+ snprintf(p->layout, sizeof p->layout, "%s/%s", p->path,
+ PROJECT_LAYOUT_FILE);
p->mtime = (int64_t)lst.st_mtime;
return true;
}
diff --git a/src/proto.c b/src/proto.c
index f714b91..100791e 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -94,8 +94,10 @@ int msg_send(int fd, uint8_t type, const void *data, size_t len) {
static int session_dir(char *out, size_t cap) {
const char *run = getenv("XDG_RUNTIME_DIR");
- if (run && *run) snprintf(out, cap, "%s/sl0ppty", run);
- else snprintf(out, cap, "/tmp/sl0ppty-%u", (unsigned)getuid());
+ if (run && *run)
+ snprintf(out, cap, "%s/sl0ppty", run);
+ else
+ snprintf(out, cap, "/tmp/sl0ppty-%u", (unsigned)getuid());
if (mkdir(out, 0700) != 0 && errno != EEXIST) return -1;
return 0;
}
diff --git a/src/pty.c b/src/pty.c
index 59448df..73fb707 100644
--- a/src/pty.c
+++ b/src/pty.c
@@ -57,7 +57,10 @@ int pty_spawn(pty_t *p, const char *const argv[], uint16_t cols, uint16_t rows,
if (slave > STDERR_FILENO) close(slave);
close(master);
- if (cwd) { if (chdir(cwd) != 0) { /* keep going in the old cwd */ } }
+ if (cwd) {
+ if (chdir(cwd) != 0) { /* keep going in the old cwd */
+ }
+ }
/* We are opinionated about the outer terminal (D11), and we present the
* same contract inward. xterm-ghostty is what libghostty-vt implements. */
diff --git a/src/screen.c b/src/screen.c
index aa0faa3..4642634 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -135,16 +135,22 @@ static size_t decode_utf8(const char *txt, size_t len, uint32_t *cps,
if (l == 0 || i + l > len) break;
uint32_t cp;
switch (l) {
- case 1: cp = (unsigned char)txt[i]; break;
- case 2: cp = ((uint32_t)((unsigned char)txt[i] & 0x1f) << 6) |
- ((unsigned char)txt[i + 1] & 0x3f); break;
- case 3: cp = ((uint32_t)((unsigned char)txt[i] & 0x0f) << 12) |
- ((uint32_t)((unsigned char)txt[i + 1] & 0x3f) << 6) |
- ((unsigned char)txt[i + 2] & 0x3f); break;
- default: cp = ((uint32_t)((unsigned char)txt[i] & 0x07) << 18) |
- ((uint32_t)((unsigned char)txt[i + 1] & 0x3f) << 12) |
- ((uint32_t)((unsigned char)txt[i + 2] & 0x3f) << 6) |
- ((unsigned char)txt[i + 3] & 0x3f); break;
+ case 1: cp = (unsigned char)txt[i]; break;
+ case 2:
+ cp = ((uint32_t)((unsigned char)txt[i] & 0x1f) << 6) |
+ ((unsigned char)txt[i + 1] & 0x3f);
+ break;
+ case 3:
+ cp = ((uint32_t)((unsigned char)txt[i] & 0x0f) << 12) |
+ ((uint32_t)((unsigned char)txt[i + 1] & 0x3f) << 6) |
+ ((unsigned char)txt[i + 2] & 0x3f);
+ break;
+ default:
+ cp = ((uint32_t)((unsigned char)txt[i] & 0x07) << 18) |
+ ((uint32_t)((unsigned char)txt[i + 1] & 0x3f) << 12) |
+ ((uint32_t)((unsigned char)txt[i + 2] & 0x3f) << 6) |
+ ((unsigned char)txt[i + 3] & 0x3f);
+ break;
}
cps[n++] = cp;
i += l;
@@ -182,8 +188,8 @@ uint16_t screen_cells(const char *txt) {
size_t len = strlen(txt), at = 0;
while (at < len) {
size_t used = 0;
- size_t n = decode_utf8(txt + at, len - at, cps, sizeof cps / sizeof *cps,
- &used);
+ size_t n =
+ decode_utf8(txt + at, len - at, cps, sizeof cps / sizeof *cps, &used);
if (!n) break;
for (size_t i = 0; i < n;) {
uint8_t w = 1;
@@ -231,7 +237,6 @@ void screen_put_utf8(screen_t *s, uint16_t x, uint16_t y, const char *txt,
c->attrs = attrs;
}
-
uint16_t screen_text(screen_t *s, uint16_t x, uint16_t y, const char *txt,
color_t fg, color_t bg, uint16_t attrs) {
uint16_t n = 0;
@@ -276,7 +281,8 @@ static void emit_sgr(screen_t *s, const cell_t *c) {
}
static bool style_eq(const cell_t *a, const cell_t *b) {
- return a->attrs == b->attrs && color_eq(a->fg, b->fg) && color_eq(a->bg, b->bg);
+ return a->attrs == b->attrs && color_eq(a->fg, b->fg) &&
+ color_eq(a->bg, b->bg);
}
void screen_render(screen_t *s) {
@@ -319,8 +325,10 @@ void screen_render(screen_t *s) {
style = *c;
have_style = true;
}
- if (c->len) out_bytes(s, c->text, c->len);
- else out_str(s, " ");
+ if (c->len)
+ out_bytes(s, c->text, c->len);
+ else
+ out_str(s, " ");
*p = *c;
cx += c->width ? c->width : 1;
@@ -399,9 +407,9 @@ static void dump_style_runs(screen_t *s, json_t *j) {
uint16_t bit;
const char *name;
} names[] = {
- {ATTR_BOLD, "bold"}, {ATTR_DIM, "dim"},
- {ATTR_ITALIC, "italic"}, {ATTR_UNDERLINE, "underline"},
- {ATTR_BLINK, "blink"}, {ATTR_INVERSE, "inverse"},
+ {ATTR_BOLD, "bold"}, {ATTR_DIM, "dim"},
+ {ATTR_ITALIC, "italic"}, {ATTR_UNDERLINE, "underline"},
+ {ATTR_BLINK, "blink"}, {ATTR_INVERSE, "inverse"},
{ATTR_INVISIBLE, "invisible"}, {ATTR_STRIKE, "strike"},
};
for (size_t i = 0; i < sizeof names / sizeof *names; i++)
diff --git a/src/server.c b/src/server.c
index f728036..398d279 100644
--- a/src/server.c
+++ b/src/server.c
@@ -216,8 +216,8 @@ static void watch_config(watchset_t *w) {
* a mistyped path should not leave a directory behind. */
if (i == 0) path_mkdirs(dir);
- int wd = inotify_add_watch(w->fd, dir,
- IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE);
+ int wd =
+ inotify_add_watch(w->fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE);
if (wd >= 0) {
bool have = false;
for (size_t k = 0; k < w->nwds; k++)
@@ -260,8 +260,10 @@ static bool watch_hit(const watchset_t *w, const char *name) {
* and set rather than inherited so it names the binary that actually made this
* pane, not one that made some pane somewhere. */
void session_env(const char *name) {
- if (name) setenv("SL0PPTY_SESSION", name, 1);
- else unsetenv("SL0PPTY_SESSION");
+ if (name)
+ setenv("SL0PPTY_SESSION", name, 1);
+ else
+ unsetenv("SL0PPTY_SESSION");
char self[512];
ssize_t sn = readlink("/proc/self/exe", self, sizeof self - 1);
if (sn > 0) {
@@ -276,7 +278,8 @@ int server_run(const char *name, const char *const argv[], uint16_t cols,
if (session_socket_path(name, path, sizeof path) != 0) return 1;
int lfd = listen_socket(path);
if (lfd < 0) {
- fprintf(stderr, "sl0ppty: cannot listen on %s: %s\n", path, strerror(errno));
+ fprintf(stderr, "sl0ppty: cannot listen on %s: %s\n", path,
+ strerror(errno));
return 1;
}
@@ -415,66 +418,65 @@ int server_run(const char *name, const char *const argv[], uint16_t cols,
bool closed = false;
while (!closed && msg_reader_next(&s.conns[ci].reader, &m)) {
switch (m.type) {
- case MSG_HELLO:
- case MSG_RESIZE:
- if (m.type == MSG_HELLO && !s.conns[ci].display) {
- /* now it is a client: the previous display is displaced */
- for (size_t j = 0; j < s.nconns; j++)
- if (j != ci && s.conns[j].display) {
- conn_drop(&s, j, EXIT_REPLACED);
- if (j < ci) ci--; /* the array compacted under us */
- break;
- }
- s.conns[ci].display = true;
- }
- if (m.len >= 4 && s.conns[ci].display) {
- uint16_t c = (uint16_t)(m.data[0] << 8 | m.data[1]);
- uint16_t rr = (uint16_t)(m.data[2] << 8 | m.data[3]);
- if (c && rr) {
- screen_resize(&s.screen, c, rr);
- app_resize(s.app, c, rr);
+ case MSG_HELLO:
+ case MSG_RESIZE:
+ if (m.type == MSG_HELLO && !s.conns[ci].display) {
+ /* now it is a client: the previous display is displaced */
+ for (size_t j = 0; j < s.nconns; j++)
+ if (j != ci && s.conns[j].display) {
+ conn_drop(&s, j, EXIT_REPLACED);
+ if (j < ci) ci--; /* the array compacted under us */
+ break;
}
- /* The cell size arrived with it, from a client new enough to
+ s.conns[ci].display = true;
+ }
+ if (m.len >= 4 && s.conns[ci].display) {
+ uint16_t c = (uint16_t)(m.data[0] << 8 | m.data[1]);
+ uint16_t rr = (uint16_t)(m.data[2] << 8 | m.data[3]);
+ if (c && rr) {
+ screen_resize(&s.screen, c, rr);
+ app_resize(s.app, c, rr);
+ }
+ /* The cell size arrived with it, from a client new enough to
* send one and a terminal willing to say. Zero means neither,
* and app_set_cell_px leaves the default standing. */
- if (m.len >= 8) {
- uint16_t cw = (uint16_t)(m.data[4] << 8 | m.data[5]);
- uint16_t ch = (uint16_t)(m.data[6] << 8 | m.data[7]);
- app_set_cell_px(s.app, cw, ch);
- }
+ if (m.len >= 8) {
+ uint16_t cw = (uint16_t)(m.data[4] << 8 | m.data[5]);
+ uint16_t ch = (uint16_t)(m.data[6] << 8 | m.data[7]);
+ app_set_cell_px(s.app, cw, ch);
}
- s.screen.force_full = true; /* a fresh client knows nothing */
- app_graphics_reset(s.app); /* including any image we had sent */
- pending_paint = true;
- next_frame = now_ms();
- break;
- case MSG_INPUT:
- if (!s.conns[ci].display) break; /* only the client types */
- input_feed(s.in, m.data, m.len, srv_event, &s);
- esc_due = now_ms() + ESC_MS;
- pending_paint = true;
- break;
- case MSG_DETACH:
- conn_drop(&s, ci, EXIT_DETACHED);
- closed = true;
- break;
- case MSG_CMD: {
- /* The same vocabulary the headless driver speaks (cmd.c), so a
- * script written against one works against the other. */
- bool q = false;
- char *reply =
- cmd_exec(s.app, &s.screen, s.in, (const char *)m.data, &q);
- const char *body = reply ? reply : "{\"error\":\"unknown command\"}";
- msg_send(s.conns[ci].fd, MSG_REPLY, body, strlen(body));
- free(reply);
- if (q) g_stop = 1;
- s.screen.force_full = true; /* it may have changed the layout */
- pending_paint = true;
- next_frame = now_ms();
- break;
}
- default:
- break;
+ s.screen.force_full = true; /* a fresh client knows nothing */
+ app_graphics_reset(s.app); /* including any image we had sent */
+ pending_paint = true;
+ next_frame = now_ms();
+ break;
+ case MSG_INPUT:
+ if (!s.conns[ci].display) break; /* only the client types */
+ input_feed(s.in, m.data, m.len, srv_event, &s);
+ esc_due = now_ms() + ESC_MS;
+ pending_paint = true;
+ break;
+ case MSG_DETACH:
+ conn_drop(&s, ci, EXIT_DETACHED);
+ closed = true;
+ break;
+ case MSG_CMD: {
+ /* The same vocabulary the headless driver speaks (cmd.c), so a
+ * script written against one works against the other. */
+ bool q = false;
+ char *reply =
+ cmd_exec(s.app, &s.screen, s.in, (const char *)m.data, &q);
+ const char *body = reply ? reply : "{\"error\":\"unknown command\"}";
+ msg_send(s.conns[ci].fd, MSG_REPLY, body, strlen(body));
+ free(reply);
+ if (q) g_stop = 1;
+ s.screen.force_full = true; /* it may have changed the layout */
+ pending_paint = true;
+ next_frame = now_ms();
+ break;
+ }
+ default: break;
}
}
if (!closed) ci++;
diff --git a/src/shader.c b/src/shader.c
index 56a0a2b..6f24564 100644
--- a/src/shader.c
+++ b/src/shader.c
@@ -20,8 +20,8 @@ static uint8_t mix8(uint8_t from, uint8_t to, uint8_t amount) {
}
static color_t mix(color_t from, color_t to, uint8_t amount) {
- return (color_t){true, mix8(from.r, to.r, amount),
- mix8(from.g, to.g, amount), mix8(from.b, to.b, amount)};
+ return (color_t){true, mix8(from.r, to.r, amount), mix8(from.g, to.g, amount),
+ mix8(from.b, to.b, amount)};
}
/* Rec. 601 luma. The green weight is not a rounding error: the eye is far more
@@ -84,10 +84,22 @@ static void sh_vignette(const shader_t *sh, const shade_ctx_t *ctx, cell_t *c) {
static void sh_gradient(const shader_t *sh, const shade_ctx_t *ctx, cell_t *c) {
int span, pos;
switch (sh->param) {
- case 1: span = ctx->rows; pos = ctx->rows - 1 - ctx->y; break;
- case 2: span = ctx->cols; pos = ctx->x; break;
- case 3: span = ctx->cols; pos = ctx->cols - 1 - ctx->x; break;
- default: span = ctx->rows; pos = ctx->y; break;
+ case 1:
+ span = ctx->rows;
+ pos = ctx->rows - 1 - ctx->y;
+ break;
+ case 2:
+ span = ctx->cols;
+ pos = ctx->x;
+ break;
+ case 3:
+ span = ctx->cols;
+ pos = ctx->cols - 1 - ctx->x;
+ break;
+ default:
+ span = ctx->rows;
+ pos = ctx->y;
+ break;
}
if (span <= 1) return;
uint8_t a = (uint8_t)((int)sh->amount * pos / (span - 1));
@@ -126,8 +138,8 @@ static void sh_spotlight(const shader_t *sh, const shade_ctx_t *ctx,
if (!ctx->has_cursor) return;
int r = sh->param ? sh->param : 10;
int inner = r * r;
- int d = dist2((int)ctx->x - (int)ctx->cursor_x,
- (int)ctx->y - (int)ctx->cursor_y);
+ int d =
+ dist2((int)ctx->x - (int)ctx->cursor_x, (int)ctx->y - (int)ctx->cursor_y);
if (d <= inner) return;
int ramp = inner * 3;
int over = d - inner;
@@ -188,8 +200,11 @@ bool shader_make_p(shader_t *out, const char *kind, color_t color,
if (!d) return false;
/* channels left 0, which the pass reads as both: a shader made here has no
* opinion about that, and the config sets it when the config has one. */
- *out = (shader_t){.kind = d->name, .fn = d->fn, .color = color,
- .amount = amount, .param = param};
+ *out = (shader_t){.kind = d->name,
+ .fn = d->fn,
+ .color = color,
+ .amount = amount,
+ .param = param};
return true;
}
@@ -403,8 +418,10 @@ void shade_apply(screen_t *s, const shader_t *shaders, size_t n, rect_t r,
* reused for as long as nothing it reads has changed. One that does
* read the clock is evaluated per cell, per frame, which is what
* asking for animation costs. */
- if (expr_amount_map(sh->amount_expr, &env, &m)) map = m;
- else per_cell = true;
+ if (expr_amount_map(sh->amount_expr, &env, &m))
+ map = m;
+ else
+ per_cell = true;
}
}
diff --git a/src/shader_abi.h b/src/shader_abi.h
index 96b7069..5cfb560 100644
--- a/src/shader_abi.h
+++ b/src/shader_abi.h
@@ -110,7 +110,7 @@ struct shader {
const char *kind; /* registry name, NULL for an empty slot */
shade_fn fn;
expr_prog_t *amount_expr; /* NULL when `amount` is just a number */
- color_t color; /* the target colour, for shaders that have one */
+ color_t color; /* the target colour, for shaders that have one */
/* Strength, 0..255; 0 is identity, 255 is fully applied. A cell whose
* strength works out to 0 is skipped by the pass rather than handed to the
* shader, so a plugin is never called to do nothing -- and a cell the
@@ -158,19 +158,19 @@ typedef struct {
#define SL0PPTY_SHADER_PLUGIN_SYM "sl0ppty_shader_plugin"
/* Define the entry point. `defs` is a static array of shader_def_t. */
-#define SL0PPTY_SHADER_PLUGIN(bundle_name, defs) \
- const shader_plugin_t *sl0ppty_shader_plugin(void); \
- const shader_plugin_t *sl0ppty_shader_plugin(void) { \
- static const shader_plugin_t table = { \
- .abi = SL0PPTY_SHADER_ABI, \
- .cell_size = sizeof(cell_t), \
- .ctx_size = sizeof(shade_ctx_t), \
- .shader_size = sizeof(shader_t), \
- .name = (bundle_name), \
- .count = sizeof(defs) / sizeof((defs)[0]), \
- .shaders = (defs), \
- }; \
- return &table; \
+#define SL0PPTY_SHADER_PLUGIN(bundle_name, defs) \
+ const shader_plugin_t *sl0ppty_shader_plugin(void); \
+ const shader_plugin_t *sl0ppty_shader_plugin(void) { \
+ static const shader_plugin_t table = { \
+ .abi = SL0PPTY_SHADER_ABI, \
+ .cell_size = sizeof(cell_t), \
+ .ctx_size = sizeof(shade_ctx_t), \
+ .shader_size = sizeof(shader_t), \
+ .name = (bundle_name), \
+ .count = sizeof(defs) / sizeof((defs)[0]), \
+ .shaders = (defs), \
+ }; \
+ return &table; \
}
#endif /* SL0PPTY_SHADER_ABI_H */
diff --git a/src/sl0ppty.h b/src/sl0ppty.h
index 7e9e11d..09e373e 100644
--- a/src/sl0ppty.h
+++ b/src/sl0ppty.h
@@ -245,8 +245,8 @@ typedef struct {
* placement happens to cover changes by one as it slides across a cell
* boundary — so passing it on makes a moving image change size. */
uint16_t req_cols, req_rows;
- uint32_t px_w, px_h; /* rendered size */
- uint32_t src_w, src_h; /* the image's own size */
+ uint32_t px_w, px_h; /* rendered size */
+ uint32_t src_w, src_h; /* the image's own size */
/* The part of the image to draw, in pixels. Clipping has to move this:
* asking for fewer columns alone *scales* the image into them, it does not
* crop it. */