@narumitw/pi-btw 0.55.1 → 0.55.3
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/dist/index.ts +143 -46
- package/dist/index.ts.map +3 -3
- package/package.json +6 -6
- package/src/fullscreen-ui.ts +136 -22
package/dist/index.ts
CHANGED
|
@@ -481,6 +481,9 @@ import {
|
|
|
481
481
|
copyToClipboard as copyToHostClipboard
|
|
482
482
|
} from "@earendil-works/pi-coding-agent";
|
|
483
483
|
import {
|
|
484
|
+
isKeyRelease,
|
|
485
|
+
Key as Key2,
|
|
486
|
+
matchesKey as matchesKey2,
|
|
484
487
|
TuiAltScreen,
|
|
485
488
|
truncateToWidth as truncateToWidth2
|
|
486
489
|
} from "@earendil-works/pi-tui";
|
|
@@ -509,23 +512,31 @@ async function runBtwFullscreen(ctx, run, dependencies = {}) {
|
|
|
509
512
|
));
|
|
510
513
|
let liveEditorText = ctx.ui.getEditorText();
|
|
511
514
|
let restoreEditor = false;
|
|
515
|
+
let host;
|
|
512
516
|
const outcome = await ctx.ui.custom(
|
|
513
|
-
(parent, theme, keybindings, done) =>
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
517
|
+
(parent, theme, keybindings, done) => {
|
|
518
|
+
host = new BtwFullscreenHost(
|
|
519
|
+
parent,
|
|
520
|
+
theme,
|
|
521
|
+
keybindings,
|
|
522
|
+
ctx,
|
|
523
|
+
run,
|
|
524
|
+
(value) => {
|
|
525
|
+
try {
|
|
526
|
+
liveEditorText = ctx.ui.getEditorText();
|
|
527
|
+
restoreEditor = true;
|
|
528
|
+
} catch {
|
|
529
|
+
}
|
|
530
|
+
done(value);
|
|
531
|
+
},
|
|
532
|
+
createTui
|
|
533
|
+
);
|
|
534
|
+
return host;
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
overlay: true,
|
|
538
|
+
onHandle: (handle) => host?.setParentOverlay(handle)
|
|
539
|
+
}
|
|
529
540
|
);
|
|
530
541
|
if (restoreEditor) {
|
|
531
542
|
try {
|
|
@@ -536,9 +547,52 @@ async function runBtwFullscreen(ctx, run, dependencies = {}) {
|
|
|
536
547
|
if (outcome.kind === "failed") throw outcome.error;
|
|
537
548
|
return outcome.value;
|
|
538
549
|
}
|
|
550
|
+
var btwInputListeners = /* @__PURE__ */ new WeakMap();
|
|
551
|
+
function dispatchBtwInput(listeners, data) {
|
|
552
|
+
let current = data;
|
|
553
|
+
for (const group of [listeners.beforeViewport, listeners.regular]) {
|
|
554
|
+
for (const listener of group) {
|
|
555
|
+
const result = listener(current);
|
|
556
|
+
if (result?.consume) return result;
|
|
557
|
+
if (result?.data !== void 0) current = result.data;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
return current === data ? void 0 : { data: current };
|
|
561
|
+
}
|
|
562
|
+
var BtwTuiAltScreen = class extends TuiAltScreen {
|
|
563
|
+
addInputListener(listener) {
|
|
564
|
+
let listeners = btwInputListeners.get(this);
|
|
565
|
+
if (!listeners) {
|
|
566
|
+
const registeredListeners = {
|
|
567
|
+
beforeViewport: /* @__PURE__ */ new Set(),
|
|
568
|
+
regular: /* @__PURE__ */ new Set()
|
|
569
|
+
};
|
|
570
|
+
btwInputListeners.set(this, registeredListeners);
|
|
571
|
+
super.addInputListener((data) => dispatchBtwInput(registeredListeners, data));
|
|
572
|
+
listeners = registeredListeners;
|
|
573
|
+
}
|
|
574
|
+
listeners.regular.add(listener);
|
|
575
|
+
return () => listeners.regular.delete(listener);
|
|
576
|
+
}
|
|
577
|
+
addInputListenerBeforeViewport(listener) {
|
|
578
|
+
const listeners = btwInputListeners.get(this);
|
|
579
|
+
if (!listeners) return super.addInputListener(listener);
|
|
580
|
+
listeners.beforeViewport.add(listener);
|
|
581
|
+
return () => listeners.beforeViewport.delete(listener);
|
|
582
|
+
}
|
|
583
|
+
removeInputListener(listener) {
|
|
584
|
+
const listeners = btwInputListeners.get(this);
|
|
585
|
+
if (!listeners) {
|
|
586
|
+
super.removeInputListener(listener);
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
listeners.beforeViewport.delete(listener);
|
|
590
|
+
listeners.regular.delete(listener);
|
|
591
|
+
}
|
|
592
|
+
};
|
|
539
593
|
function createBtwFullscreenTui(parent, theme, openUrl, copyToClipboard2) {
|
|
540
594
|
const styleSearchMatch = (text) => theme.bg("searchMatchBg", theme.fg("searchMatchText", text));
|
|
541
|
-
return new
|
|
595
|
+
return new BtwTuiAltScreen(parent.terminal, parent.getShowHardwareCursor(), void 0, {
|
|
542
596
|
mouse: true,
|
|
543
597
|
searchMatchStyle: (text) => theme.underline(styleSearchMatch(text)),
|
|
544
598
|
searchCurrentMatchStyle: (text) => theme.bold(theme.inverse(styleSearchMatch(text))),
|
|
@@ -577,10 +631,21 @@ var BtwFullscreenHost = class {
|
|
|
577
631
|
done;
|
|
578
632
|
createTui;
|
|
579
633
|
fullscreen;
|
|
634
|
+
parentOverlay;
|
|
580
635
|
cancelActiveCustom;
|
|
636
|
+
hardCancelActiveCustom;
|
|
637
|
+
removeHardCancelListener;
|
|
581
638
|
started = false;
|
|
582
639
|
disposed = false;
|
|
583
640
|
finished = false;
|
|
641
|
+
parentStopped = false;
|
|
642
|
+
parentRestarted = false;
|
|
643
|
+
fullscreenCreated = false;
|
|
644
|
+
fullscreenStopped = false;
|
|
645
|
+
cleanupError;
|
|
646
|
+
setParentOverlay(overlay) {
|
|
647
|
+
this.parentOverlay = overlay;
|
|
648
|
+
}
|
|
584
649
|
render(width) {
|
|
585
650
|
return [truncateToWidth2(this.theme.fg("muted", "Opening btw side thread\u2026"), width)];
|
|
586
651
|
}
|
|
@@ -595,44 +660,64 @@ var BtwFullscreenHost = class {
|
|
|
595
660
|
if (this.started || this.finished) return;
|
|
596
661
|
this.started = true;
|
|
597
662
|
let outcome;
|
|
598
|
-
let parentStopped = false;
|
|
599
|
-
let fullscreenCreated = false;
|
|
600
663
|
try {
|
|
601
664
|
if (this.disposed) throw new FullscreenUiDisposedError();
|
|
602
665
|
this.parent.stop({ preserveScreen: true });
|
|
603
|
-
parentStopped = true;
|
|
666
|
+
this.parentStopped = true;
|
|
604
667
|
if (this.disposed) throw new FullscreenUiDisposedError();
|
|
605
668
|
this.fullscreen = this.createTui(this.parent, this.theme);
|
|
606
|
-
fullscreenCreated = true;
|
|
669
|
+
this.fullscreenCreated = true;
|
|
607
670
|
this.fullscreen.start();
|
|
671
|
+
const addHardCancelListener = this.fullscreen.addInputListenerBeforeViewport?.bind(this.fullscreen) ?? this.fullscreen.addInputListener.bind(this.fullscreen);
|
|
672
|
+
this.removeHardCancelListener = addHardCancelListener((data) => {
|
|
673
|
+
if (isKeyRelease(data) || !matchesKey2(data, Key2.ctrl("c"))) return void 0;
|
|
674
|
+
try {
|
|
675
|
+
this.hardCancelActiveCustom?.();
|
|
676
|
+
} finally {
|
|
677
|
+
this.restoreParent();
|
|
678
|
+
}
|
|
679
|
+
return { consume: true };
|
|
680
|
+
});
|
|
608
681
|
outcome = { kind: "completed", value: await this.run(this.createContext()) };
|
|
609
682
|
} catch (error) {
|
|
610
683
|
outcome = { kind: "failed", error };
|
|
611
684
|
}
|
|
612
|
-
let cleanupError;
|
|
613
685
|
try {
|
|
614
686
|
this.cancelActiveCustom?.();
|
|
615
687
|
} catch (error) {
|
|
616
|
-
cleanupError
|
|
688
|
+
this.cleanupError ??= error;
|
|
617
689
|
}
|
|
618
|
-
|
|
690
|
+
this.restoreParent();
|
|
691
|
+
if (this.cleanupError !== void 0) outcome = { kind: "failed", error: this.cleanupError };
|
|
692
|
+
this.finished = true;
|
|
693
|
+
this.done(outcome);
|
|
694
|
+
}
|
|
695
|
+
restoreParent() {
|
|
696
|
+
this.removeHardCancelListener?.();
|
|
697
|
+
this.removeHardCancelListener = void 0;
|
|
698
|
+
if (this.fullscreenCreated && !this.fullscreenStopped) {
|
|
699
|
+
this.fullscreenStopped = true;
|
|
619
700
|
try {
|
|
620
701
|
this.fullscreen?.stop({ preserveScreen: true });
|
|
621
702
|
} catch (error) {
|
|
622
|
-
cleanupError ??= error;
|
|
703
|
+
this.cleanupError ??= error;
|
|
623
704
|
}
|
|
624
705
|
}
|
|
625
|
-
if (parentStopped)
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
706
|
+
if (!this.parentStopped || this.parentRestarted) return;
|
|
707
|
+
const parentOverlay = this.parentOverlay;
|
|
708
|
+
this.parentOverlay = void 0;
|
|
709
|
+
try {
|
|
710
|
+
parentOverlay?.setHidden(true);
|
|
711
|
+
} catch (error) {
|
|
712
|
+
this.cleanupError ??= error;
|
|
713
|
+
}
|
|
714
|
+
try {
|
|
715
|
+
this.parent.start();
|
|
716
|
+
this.parentRestarted = true;
|
|
717
|
+
this.parent.renderNow(false);
|
|
718
|
+
} catch (error) {
|
|
719
|
+
this.cleanupError ??= error;
|
|
632
720
|
}
|
|
633
|
-
if (cleanupError !== void 0) outcome = { kind: "failed", error: cleanupError };
|
|
634
|
-
this.finished = true;
|
|
635
|
-
this.done(outcome);
|
|
636
721
|
}
|
|
637
722
|
createContext() {
|
|
638
723
|
const ui = new Proxy(this.ctx.ui, {
|
|
@@ -706,6 +791,7 @@ var BtwFullscreenHost = class {
|
|
|
706
791
|
if (promiseSettled || !hasPendingValue) return;
|
|
707
792
|
promiseSettled = true;
|
|
708
793
|
this.cancelActiveCustom = void 0;
|
|
794
|
+
this.hardCancelActiveCustom = void 0;
|
|
709
795
|
if (!factorySettled) {
|
|
710
796
|
resolve(pendingValue);
|
|
711
797
|
return;
|
|
@@ -729,6 +815,7 @@ var BtwFullscreenHost = class {
|
|
|
729
815
|
closed = true;
|
|
730
816
|
promiseSettled = true;
|
|
731
817
|
this.cancelActiveCustom = void 0;
|
|
818
|
+
this.hardCancelActiveCustom = void 0;
|
|
732
819
|
try {
|
|
733
820
|
unmount();
|
|
734
821
|
reject(error);
|
|
@@ -741,6 +828,16 @@ var BtwFullscreenHost = class {
|
|
|
741
828
|
disposeComponent();
|
|
742
829
|
if (!promiseSettled) fail(new FullscreenUiDisposedError());
|
|
743
830
|
};
|
|
831
|
+
this.hardCancelActiveCustom = () => {
|
|
832
|
+
if (promiseSettled) return;
|
|
833
|
+
try {
|
|
834
|
+
component?.handleInput?.("");
|
|
835
|
+
} catch (error) {
|
|
836
|
+
fail(error);
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
this.cancelActiveCustom?.();
|
|
840
|
+
};
|
|
744
841
|
let created;
|
|
745
842
|
try {
|
|
746
843
|
created = factory(fullscreen, this.theme, this.keybindings, close);
|
|
@@ -789,7 +886,7 @@ import {
|
|
|
789
886
|
copyToClipboard,
|
|
790
887
|
TreeSelectorComponent
|
|
791
888
|
} from "@earendil-works/pi-coding-agent";
|
|
792
|
-
import { Key as
|
|
889
|
+
import { Key as Key3, matchesKey as matchesKey3 } from "@earendil-works/pi-tui";
|
|
793
890
|
|
|
794
891
|
// src/settings.ts
|
|
795
892
|
import { randomUUID } from "node:crypto";
|
|
@@ -1386,7 +1483,7 @@ var MainThreadTreePickerComponent = class {
|
|
|
1386
1483
|
return this.selector.render(width);
|
|
1387
1484
|
}
|
|
1388
1485
|
handleInput(data) {
|
|
1389
|
-
if (
|
|
1486
|
+
if (matchesKey3(data, Key3.ctrl("c"))) {
|
|
1390
1487
|
this.onClose();
|
|
1391
1488
|
return;
|
|
1392
1489
|
}
|
|
@@ -1678,10 +1775,10 @@ import {
|
|
|
1678
1775
|
import {
|
|
1679
1776
|
CURSOR_MARKER,
|
|
1680
1777
|
Editor,
|
|
1681
|
-
Key as
|
|
1778
|
+
Key as Key4,
|
|
1682
1779
|
Loader,
|
|
1683
1780
|
Markdown,
|
|
1684
|
-
matchesKey as
|
|
1781
|
+
matchesKey as matchesKey4,
|
|
1685
1782
|
ScrollView,
|
|
1686
1783
|
truncateToWidth as truncateToWidth3,
|
|
1687
1784
|
VStack,
|
|
@@ -1794,12 +1891,12 @@ var BtwTranscriptPager = class {
|
|
|
1794
1891
|
}
|
|
1795
1892
|
handleInput(data) {
|
|
1796
1893
|
if (this.finished) return;
|
|
1797
|
-
if (
|
|
1894
|
+
if (matchesKey4(data, Key4.ctrl("c"))) {
|
|
1798
1895
|
this.finished = true;
|
|
1799
1896
|
this.onAction({ kind: "close" });
|
|
1800
1897
|
return;
|
|
1801
1898
|
}
|
|
1802
|
-
if (this.canBringToMain &&
|
|
1899
|
+
if (this.canBringToMain && matchesKey4(data, Key4.ctrl("r"))) {
|
|
1803
1900
|
this.finished = true;
|
|
1804
1901
|
this.onAction({ kind: "bringToMain", questionDraft: this.editor.getExpandedText() });
|
|
1805
1902
|
return;
|
|
@@ -1816,12 +1913,12 @@ var BtwTranscriptPager = class {
|
|
|
1816
1913
|
}
|
|
1817
1914
|
return;
|
|
1818
1915
|
}
|
|
1819
|
-
if (
|
|
1916
|
+
if (matchesKey4(data, Key4.pageUp)) {
|
|
1820
1917
|
this.scrollView.scrollBy(-Math.max(1, this.scrollView.viewportHeight));
|
|
1821
1918
|
this.tui.requestRender();
|
|
1822
1919
|
return;
|
|
1823
1920
|
}
|
|
1824
|
-
if (
|
|
1921
|
+
if (matchesKey4(data, Key4.pageDown)) {
|
|
1825
1922
|
this.scrollView.scrollBy(Math.max(1, this.scrollView.viewportHeight));
|
|
1826
1923
|
this.tui.requestRender();
|
|
1827
1924
|
return;
|
|
@@ -2018,7 +2115,7 @@ var BtwAnsweringView = class {
|
|
|
2018
2115
|
}
|
|
2019
2116
|
handleInput(data) {
|
|
2020
2117
|
if (this.finished) return;
|
|
2021
|
-
if (
|
|
2118
|
+
if (matchesKey4(data, Key4.ctrl("c"))) {
|
|
2022
2119
|
this.finished = true;
|
|
2023
2120
|
this.loader.stop();
|
|
2024
2121
|
this.controller.abort();
|
|
@@ -2037,12 +2134,12 @@ var BtwAnsweringView = class {
|
|
|
2037
2134
|
}
|
|
2038
2135
|
return;
|
|
2039
2136
|
}
|
|
2040
|
-
if (
|
|
2137
|
+
if (matchesKey4(data, Key4.pageUp)) {
|
|
2041
2138
|
this.scrollView.scrollBy(-Math.max(1, this.scrollView.viewportHeight));
|
|
2042
2139
|
this.tui.requestRender();
|
|
2043
2140
|
return;
|
|
2044
2141
|
}
|
|
2045
|
-
if (
|
|
2142
|
+
if (matchesKey4(data, Key4.pageDown)) {
|
|
2046
2143
|
this.scrollView.scrollBy(Math.max(1, this.scrollView.viewportHeight));
|
|
2047
2144
|
this.tui.requestRender();
|
|
2048
2145
|
return;
|