@neosh/api 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/generated/ApiCall.ts +21 -0
- package/src/generated/TabInfo.ts +16 -0
- package/src/generated/UiEvent.ts +18 -1
- package/src/generated/UpdateStatus.ts +21 -1
- package/src/index.ts +73 -7
package/package.json
CHANGED
package/src/generated/ApiCall.ts
CHANGED
|
@@ -141,7 +141,18 @@ export type ApiCall =
|
|
|
141
141
|
* work somewhere is not, for the same reason `SessionNew { activate: false }` exists.
|
|
142
142
|
*/
|
|
143
143
|
activate: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Which strip to open it on. See [`TabInfo::group`].
|
|
146
|
+
*
|
|
147
|
+
* `None` inherits the tab you are on, which is what a new tab almost always wants: opened
|
|
148
|
+
* while reading a conversation, it is that conversation's. Saying one is for a caller
|
|
149
|
+
* putting a tab somewhere *else* — and a group nothing is currently showing is a tab that
|
|
150
|
+
* is made and is off the bar, which is a legitimate thing to want and a surprising thing
|
|
151
|
+
* to do by accident.
|
|
152
|
+
*/
|
|
153
|
+
group?: string | null;
|
|
144
154
|
}
|
|
155
|
+
| { "call": "tab_group"; tab: TabId; group: string | null }
|
|
145
156
|
| { "call": "tab_close"; tab: TabId }
|
|
146
157
|
| { "call": "tab_select"; tab: TabId }
|
|
147
158
|
| { "call": "tab_step"; view?: ViewId | null; delta: number }
|
|
@@ -639,6 +650,16 @@ export type ApiCall =
|
|
|
639
650
|
* Ask the network again rather than answering from the last check.
|
|
640
651
|
*/
|
|
641
652
|
force: boolean;
|
|
653
|
+
/**
|
|
654
|
+
* Answer from what this machine already knows, and never reach the network.
|
|
655
|
+
*
|
|
656
|
+
* The two are not opposites and are never both set: `local` is checked first and wins.
|
|
657
|
+
* It exists because half of an update status is not about a registry at all —
|
|
658
|
+
* [`UpdateStatus::restart_pending`] is a `stat` of one file — and a caller that wants
|
|
659
|
+
* only that half should not be the reason a workspace makes an HTTP request. Which is
|
|
660
|
+
* what a panel polling for "has something replaced my binary" would otherwise be.
|
|
661
|
+
*/
|
|
662
|
+
local: boolean;
|
|
642
663
|
}
|
|
643
664
|
| { "call": "update_apply" }
|
|
644
665
|
| {
|
package/src/generated/TabInfo.ts
CHANGED
|
@@ -24,4 +24,20 @@ export type TabInfo = {
|
|
|
24
24
|
* rather than in whichever pane happens to be first.
|
|
25
25
|
*/
|
|
26
26
|
active_pane: PaneId;
|
|
27
|
+
/**
|
|
28
|
+
* Which strip this tab is on — the conversation it belongs to.
|
|
29
|
+
*
|
|
30
|
+
* **A tab belongs to a conversation, and the bar shows one conversation's tabs.** A shell
|
|
31
|
+
* opened while reading one is *that* conversation's shell: it was started in its directory,
|
|
32
|
+
* about its work, and a bar that goes on showing it after you have switched is a bar about
|
|
33
|
+
* the terminal rather than about what you are doing. The tabs of the conversations you are
|
|
34
|
+
* not in are not closed, and nothing in them stops — they are off the strip until you go
|
|
35
|
+
* back, which is what makes leaving a build running and returning to it work.
|
|
36
|
+
*
|
|
37
|
+
* Opaque here and in the editor, which only ever asks whether two of them are equal: the host
|
|
38
|
+
* fills it with a [`crate::SessionId`], and a plugin that grouped its tabs by project would be
|
|
39
|
+
* using it exactly as intended. `None` is a group of its own — where a tab nobody has filed
|
|
40
|
+
* sits, and what every tab was before this existed.
|
|
41
|
+
*/
|
|
42
|
+
group?: string | null;
|
|
27
43
|
};
|
package/src/generated/UiEvent.ts
CHANGED
|
@@ -81,4 +81,21 @@ export type UiEvent =
|
|
|
81
81
|
}
|
|
82
82
|
| { "type": "clipboard"; text: string }
|
|
83
83
|
| { "type": "flush" }
|
|
84
|
-
| {
|
|
84
|
+
| {
|
|
85
|
+
"type": "shutdown";
|
|
86
|
+
/**
|
|
87
|
+
* Whether it is coming straight back, and this terminal should follow it.
|
|
88
|
+
*
|
|
89
|
+
* `neosh stop` and a restart are the same shutdown — conversations flushed, plugins torn
|
|
90
|
+
* down — and they differ entirely in what the *terminal* should do next. Stopping is
|
|
91
|
+
* somebody finishing; a restart is the second half of an update, and a terminal that
|
|
92
|
+
* exits to the shell there has turned "finish updating" into "and now type `neosh`
|
|
93
|
+
* again", which is the step nobody knows is owed. It cannot be worked out at the far end
|
|
94
|
+
* either: from a closed socket, a workspace that stopped and a workspace that is
|
|
95
|
+
* restarting look identical.
|
|
96
|
+
*
|
|
97
|
+
* `#[serde(default)]` so an older terminal reads it as an ordinary stop, which is the
|
|
98
|
+
* behaviour it already has.
|
|
99
|
+
*/
|
|
100
|
+
restarting: boolean;
|
|
101
|
+
};
|
|
@@ -33,7 +33,27 @@ export type UpdateStatus = {
|
|
|
33
33
|
*/
|
|
34
34
|
error?: string | null;
|
|
35
35
|
/**
|
|
36
|
-
* Whether
|
|
36
|
+
* Whether the binary on disk is not the one this process is running.
|
|
37
|
+
*
|
|
38
|
+
* Not "whether neosh downloaded something": most installs are updated by somebody else's
|
|
39
|
+
* package manager, in another terminal, and the workspace goes on executing the inode it
|
|
40
|
+
* started with — which is the whole failure this field exists to name. `brew upgrade neosh`
|
|
41
|
+
* finishes, says so, and leaves a workspace running the old code with nothing on screen to
|
|
42
|
+
* say why the thing you just installed is not there. So this is a `stat` of the running
|
|
43
|
+
* executable against the stamp taken at startup, and it is true for a self-update, a
|
|
44
|
+
* `brew upgrade`, an `npm install -g` and a re-run of `install.sh` alike.
|
|
45
|
+
*
|
|
46
|
+
* Never set when there is no binary left to restart onto: a promise of a restart that cannot
|
|
47
|
+
* come back is worse than saying nothing.
|
|
37
48
|
*/
|
|
38
49
|
restart_pending: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* What is waiting on disk, when it could be read.
|
|
52
|
+
*
|
|
53
|
+
* Asked of the binary itself (`neosh --version`) rather than assumed to be
|
|
54
|
+
* [`latest`](UpdateStatus::latest): somebody who ran `brew upgrade` got whatever Homebrew had,
|
|
55
|
+
* which is not always the newest release, and a row naming the wrong number is a row that
|
|
56
|
+
* teaches you not to read it. `None` means *something* changed and it would not say what.
|
|
57
|
+
*/
|
|
58
|
+
restart_version?: string | null;
|
|
39
59
|
};
|
package/src/index.ts
CHANGED
|
@@ -662,21 +662,63 @@ export interface PaneApi {
|
|
|
662
662
|
equalize(view?: ViewId): Promise<void>;
|
|
663
663
|
}
|
|
664
664
|
|
|
665
|
-
/**
|
|
665
|
+
/**
|
|
666
|
+
* The tabs of one terminal. Each is a title, a tree of panes, and the conversation it belongs to.
|
|
667
|
+
*
|
|
668
|
+
* **A tab belongs to a conversation, and the bar shows one conversation's tabs** — that is
|
|
669
|
+
* {@link TabInfo.group}, and it is why a shell opened while reading one conversation is not still
|
|
670
|
+
* on the bar after you have switched to another. The tabs of the conversations you are not in are
|
|
671
|
+
* not closed and nothing in them stops; they are off the strip until you go back.
|
|
672
|
+
*
|
|
673
|
+
* Which splits these calls in two. {@link TabApi.list} answers with *every* tab of a terminal,
|
|
674
|
+
* whatever bar it is on, because "what is open here" is a real question — and {@link TabApi.step},
|
|
675
|
+
* {@link TabApi.move} and the numbers on the strip all count the tabs of one conversation, because
|
|
676
|
+
* a key about where you are looking must not change what you are working on.
|
|
677
|
+
*/
|
|
666
678
|
export interface TabApi {
|
|
667
|
-
/**
|
|
679
|
+
/**
|
|
680
|
+
* Every tab of a terminal, its panes, and which one is on screen.
|
|
681
|
+
*
|
|
682
|
+
* All of them, including the ones on other conversations' bars: filter by {@link TabInfo.group}
|
|
683
|
+
* for what is drawn, which is the tabs sharing the active tab's group.
|
|
684
|
+
*/
|
|
668
685
|
list(view?: ViewId): Promise<{ tabs: TabInfo[]; active: TabId }>;
|
|
669
686
|
/**
|
|
670
687
|
* Open a tab with one empty pane. `activate` goes to it — `false` is for putting work somewhere
|
|
671
688
|
* without moving the screen out from under whoever is reading it.
|
|
689
|
+
*
|
|
690
|
+
* On the bar you are looking at unless `group` says otherwise: a tab opened while reading a
|
|
691
|
+
* conversation is that conversation's, which is what a new tab almost always wants.
|
|
692
|
+
*/
|
|
693
|
+
create(opts?: {
|
|
694
|
+
title?: string;
|
|
695
|
+
activate?: boolean;
|
|
696
|
+
view?: ViewId;
|
|
697
|
+
group?: string;
|
|
698
|
+
}): Promise<TabId>;
|
|
699
|
+
/**
|
|
700
|
+
* Move a tab to another conversation's bar, or to nobody's with `null`. See
|
|
701
|
+
* {@link TabInfo.group}.
|
|
702
|
+
*
|
|
703
|
+
* It keeps its panes, its windows and anything running in them — this says which bar it is on
|
|
704
|
+
* and nothing else, so moving the tab you are *in* changes which other tabs are beside it.
|
|
672
705
|
*/
|
|
673
|
-
|
|
674
|
-
/** Close a tab and every pane in it. Rejects on a
|
|
706
|
+
group(tab: TabId, group: string | null): Promise<void>;
|
|
707
|
+
/** Close a tab and every pane in it. Rejects on a conversation's last tab. */
|
|
675
708
|
close(tab: TabId): Promise<void>;
|
|
676
709
|
select(tab: TabId): Promise<void>;
|
|
677
|
-
/**
|
|
710
|
+
/**
|
|
711
|
+
* Go `delta` tabs along, wrapping — a tab bar is a list you can see all of. Along *this
|
|
712
|
+
* conversation's* tabs: stepping into another one's would be a key that changes what you are
|
|
713
|
+
* working on.
|
|
714
|
+
*/
|
|
678
715
|
step(delta: number, view?: ViewId): Promise<void>;
|
|
679
|
-
/**
|
|
716
|
+
/**
|
|
717
|
+
* Move a tab along the bar, clamped at the ends. This is a drag; a drag that teleports is a bug.
|
|
718
|
+
*
|
|
719
|
+
* `to` counts the tabs on the bar, which is the number printed on the strip — the tabs of other
|
|
720
|
+
* conversations sit between these and are not places a drag can land.
|
|
721
|
+
*/
|
|
680
722
|
move(tab: TabId, to: number): Promise<void>;
|
|
681
723
|
/** Name a tab, or pass `null` to give it back its derived name. */
|
|
682
724
|
rename(tab: TabId, title: string | null): Promise<void>;
|
|
@@ -1791,6 +1833,17 @@ export interface UpdateApi {
|
|
|
1791
1833
|
* {@link UpdateStatus.error} when it is there.
|
|
1792
1834
|
*/
|
|
1793
1835
|
check(force?: boolean): Promise<UpdateStatus>;
|
|
1836
|
+
/**
|
|
1837
|
+
* The same answer, from this machine alone, never touching the network.
|
|
1838
|
+
*
|
|
1839
|
+
* Which is enough for the half that matters most often. {@link UpdateStatus.restart_pending} is a
|
|
1840
|
+
* `stat` of one file — *is the binary on disk the binary this workspace is running* — and it goes
|
|
1841
|
+
* true when somebody runs `brew upgrade neosh` in another terminal, which is how most installs
|
|
1842
|
+
* are actually updated and the moment nothing used to say anything. Cheap enough to poll on a
|
|
1843
|
+
* tick; {@link check} is not, and a panel that used it for this would be a workspace making an
|
|
1844
|
+
* HTTP request every thirty seconds.
|
|
1845
|
+
*/
|
|
1846
|
+
local(): Promise<UpdateStatus>;
|
|
1794
1847
|
/**
|
|
1795
1848
|
* Update, by whichever route this install takes.
|
|
1796
1849
|
*
|
|
@@ -2425,7 +2478,16 @@ function build(
|
|
|
2425
2478
|
},
|
|
2426
2479
|
update: {
|
|
2427
2480
|
async check(force) {
|
|
2428
|
-
return expect(
|
|
2481
|
+
return expect(
|
|
2482
|
+
await c({ call: "update_check", force: force ?? false, local: false }),
|
|
2483
|
+
"update",
|
|
2484
|
+
).update;
|
|
2485
|
+
},
|
|
2486
|
+
async local() {
|
|
2487
|
+
return expect(
|
|
2488
|
+
await c({ call: "update_check", force: false, local: true }),
|
|
2489
|
+
"update",
|
|
2490
|
+
).update;
|
|
2429
2491
|
},
|
|
2430
2492
|
async apply() {
|
|
2431
2493
|
return expect(await c({ call: "update_apply" }), "update_applied").outcome;
|
|
@@ -2648,10 +2710,14 @@ function build(
|
|
|
2648
2710
|
view: opts?.view,
|
|
2649
2711
|
title: opts?.title,
|
|
2650
2712
|
activate: opts?.activate ?? true,
|
|
2713
|
+
group: opts?.group,
|
|
2651
2714
|
}),
|
|
2652
2715
|
"tab",
|
|
2653
2716
|
).tab;
|
|
2654
2717
|
},
|
|
2718
|
+
async group(tab, group) {
|
|
2719
|
+
await c({ call: "tab_group", tab, group });
|
|
2720
|
+
},
|
|
2655
2721
|
async close(tab) {
|
|
2656
2722
|
await c({ call: "tab_close", tab });
|
|
2657
2723
|
},
|