1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
/* The session: a layout tree of panes, focus, and the chrome around them.
*
* Both front ends (the interactive client and the headless driver) drive this
* same object, so there is exactly one implementation of what a key does. */
#ifndef SL0PPTY_APP_H
#define SL0PPTY_APP_H
#include "shader.h"
#include "sl0ppty.h"
typedef enum { SPLIT_COLS, SPLIT_ROWS } split_dir_t;
typedef struct node node_t;
typedef struct app app_t;
app_t *app_new(const char *const argv[], uint16_t cols, uint16_t rows);
void app_free(app_t *a);
void app_event(app_t *a, const input_event_t *ev);
/* Kitty graphics for this frame: the bytes the client's terminal needs, and
* the same thing as JSON for tests. Bytes are borrowed until the next call. */
const char *app_graphics(app_t *a, size_t *len);
void app_graphics_reset(app_t *a);
char *app_graphics_json(app_t *a);
/* Transient announcements, drawn bottom-right and expiring on their own. */
void app_toast(app_t *a, const char *text);
size_t app_toast_count(app_t *a);
/* Milliseconds until something needs repainting on its own — a toast expiring,
* a hover guide arming, or a shader whose amount reads the clock having run
* over the frame just composed — or -1 when nothing does. A property of that
* frame, so it is asked after composing one. */
int app_next_deadline_ms(app_t *a);
/* Text the session has copied, and the copy the client has not been told
* about yet (which the front end sends on as OSC 52). Caller frees the take. */
const char *app_clipboard(const app_t *a);
char *app_take_clipboard(app_t *a);
/* Re-read the config file. Keeps the working one if the new file is broken. */
bool app_reload_config(char *err, size_t errcap);
/* The files the config in force was read from: the one that was loaded and
* everything it included, existing or not. What the watcher watches. */
size_t app_config_files(const char **out, size_t max);
/* What the config in force complained about while loading, or "". A complaint is
* not a failure -- an include that is not there, a shader nobody has heard of --
* so the session is running either way; this is for saying so. */
const char *app_config_complaint(void);
void app_resize(app_t *a, uint16_t cols, uint16_t rows);
/* The attached client's cell size in pixels, passed on to every pane's pty and
* terminal. Images need it: a placement that does not say how many cells it
* covers is sized from the image's pixels and this. Ignored if either is 0,
* so a client that cannot find out leaves the default standing. */
void app_set_cell_px(app_t *a, uint16_t w, uint16_t h);
void app_cell_px(const app_t *a, uint16_t *w, uint16_t *h);
/* Pump every pane that has data. Returns true if anything changed. */
bool app_pump_fd(app_t *a, int fd);
/* Fill `out` with every live pane fd; returns the count. */
size_t app_fds(app_t *a, int *out, size_t max);
/* Close panes whose process exited, collapsing the tree — only under
* `keep_dead false`. By default a dead pane stays until it is dismissed, so
* this does nothing and the pane offers [re-run] and [close] in its frame. */
void app_reap(app_t *a);
void app_compose(app_t *a, screen_t *s);
/* Bytes straight into the focused pane's pty (the harness's `raw`). */
void app_write_focused(app_t *a, const void *buf, size_t len);
bool app_should_quit(const app_t *a);
/* C-a d asks the client to leave while the session keeps running. */
bool app_detach_requested(const app_t *a);
void app_clear_detach(app_t *a);
size_t app_pane_count(const app_t *a);
/* Tabs. A tab is a layout tree; panes in every tab keep running. */
uint32_t app_new_tab(app_t *a, const char *name);
bool app_select_tab(app_t *a, size_t index);
bool app_select_tab_id(app_t *a, uint32_t id);
void app_cycle_tab(app_t *a, int delta);
size_t app_tab_count(const app_t *a);
bool app_close_tab(app_t *a, uint32_t id);
bool app_set_tab_name(app_t *a, uint32_t id, const char *name);
/* Put a tab at a different position in the strip, 0-based. The strip is the
* order, so this is what dragging one does; you stay in the tab you were in. */
bool app_move_tab(app_t *a, uint32_t id, size_t index);
/* Purposes (D8). `declared` means "from a layout/control API": it outranks an
* in-band purpose and locks it, so a pane cannot relabel itself afterwards.
* Returns false when a locked purpose refuses an in-band change. */
bool app_set_pane_purpose(app_t *a, uint32_t id, const char *purpose,
bool declared);
bool app_set_tab_purpose(app_t *a, uint32_t id, const char *purpose,
bool declared);
/* Build tabs and panes from a KDL layout. `replace` drops what was there.
* Purposes a layout declares are locked (D8). */
bool app_apply_layout_text(app_t *a, const char *text, bool replace, char *err,
size_t errcap);
bool app_apply_layout_file(app_t *a, const char *path, bool replace, char *err,
size_t errcap);
/* What this session is called, for the status line. The server knows it
* because it opened the socket under that name. */
void app_set_session(app_t *a, const char *name);
/* Put a pane away into the strip along the bottom. 0 means the focused one.
* False if it would leave the tab with nothing on screen. Restoring is done by
* focusing it, which is what clicking its row does. */
bool app_minimize(app_t *a, uint32_t id);
/* Fill the tab with one pane, or put it back. 0 means the focused one. */
bool app_toggle_zoom(app_t *a, uint32_t id);
bool app_pane_zoomed(app_t *a, uint32_t id);
/* Give every visible pane in the current tab an even share of the rows and
* columns it competes for: each split's children weighted by how many visible
* panes are behind them, so "even" means the same thing at every depth. False
* when the tab is a single pane and there is nothing to divide. */
bool app_equalize_splits(app_t *a);
/* Address panes by id (the control API), not "the focused one". */
bool app_focus_pane(app_t *a, uint32_t id);
bool app_split_pane(app_t *a, uint32_t id, bool rows);
bool app_close_pane(app_t *a, uint32_t id);
/* Run a dead (or not-yet-started) pane's command again, in the same pane and
* on top of the same scrollback. 0 means the focused one. */
bool app_rerun_pane(app_t *a, uint32_t id);
/* Turn the current tab's layout a quarter turn clockwise: every split changes
* axis, and the children of a row split reverse, because the pane on top of a
* stack is the pane on the right once you turn it. Four turns are the identity.
* False when the tab is a single pane, which looks the same from every angle. */
bool app_rotate_layout(app_t *a);
/* Open the config file in $EDITOR, in a pane of its own, so the edit/save/
* watch loop happens without leaving the session. The pane is ephemeral. */
bool app_edit_config(app_t *a);
uint32_t app_focused_pane_id(app_t *a);
uint32_t app_current_tab_id(app_t *a);
/* Colour passes over a pane's contents (shader.h). Policy-only for now: these
* are called from inside the app, not reachable over the control API or from
* a program in a pane. False if the pane or the shader kind is unknown, or if
* the pane already has SHADE_MAX of them. */
bool app_shade_add(app_t *a, uint32_t pane_id, const char *kind, color_t color,
uint8_t amount);
void app_shade_clear(app_t *a, uint32_t pane_id);
size_t app_shade_count(app_t *a, uint32_t pane_id);
/* The session written back out as a layout file: tabs, splits, proportions,
* directories and commands. The inverse of app_apply_layout_text(), and what
* makes "quit, rebuild, come back to the same screen" possible. Caller frees.
*
* The shape is restorable; what is running inside a program is not, and this
* does not pretend otherwise. */
char *app_dump_layout(app_t *a);
/* State as JSON, for the control API and the harness. Caller frees. */
char *app_panes_json(app_t *a);
char *app_tabs_json(app_t *a);
#endif /* SL0PPTY_APP_H */
|