pi-tab-focus 1.0.0

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.
@@ -0,0 +1,101 @@
1
+ type ScrollIndicatorTui = {
2
+ mode: string;
3
+ scrollToEndIndicator?: () => string;
4
+ };
5
+
6
+ type BorderRenderer = (width: number, hiddenLineCount: number) => string;
7
+
8
+ type BorderRenderableEditor = object & {
9
+ renderTopBorder?: BorderRenderer;
10
+ renderBottomBorder?: BorderRenderer;
11
+ };
12
+
13
+ const TRANSCRIPT_BORDER_GLYPH = "·";
14
+ const SOLID_BORDER_GLYPH = "─";
15
+
16
+ function patchBorderRenderer(
17
+ editor: BorderRenderableEditor,
18
+ key: "renderTopBorder" | "renderBottomBorder",
19
+ isTranscriptFocused: () => boolean,
20
+ ): (() => void) | undefined {
21
+ const original = editor[key];
22
+ if (typeof original !== "function") return undefined;
23
+
24
+ const hadOwnProperty = Object.prototype.hasOwnProperty.call(editor, key);
25
+ const ownDescriptor = hadOwnProperty
26
+ ? Object.getOwnPropertyDescriptor(editor, key)
27
+ : undefined;
28
+
29
+ const wrapped: BorderRenderer = function(
30
+ this: BorderRenderableEditor,
31
+ width,
32
+ hiddenLineCount,
33
+ ) {
34
+ const rendered = original.call(this, width, hiddenLineCount);
35
+ return isTranscriptFocused()
36
+ ? rendered.replaceAll(SOLID_BORDER_GLYPH, TRANSCRIPT_BORDER_GLYPH)
37
+ : rendered;
38
+ };
39
+
40
+ try {
41
+ Object.defineProperty(editor, key, {
42
+ configurable: true,
43
+ writable: true,
44
+ value: wrapped,
45
+ });
46
+ } catch {
47
+ return undefined;
48
+ }
49
+
50
+ return () => {
51
+ // Avoid clobbering a later decorator that replaced this method after us.
52
+ if (editor[key] !== wrapped) return;
53
+
54
+ if (hadOwnProperty && ownDescriptor) {
55
+ Object.defineProperty(editor, key, ownDescriptor);
56
+ } else {
57
+ delete editor[key];
58
+ }
59
+ };
60
+ }
61
+
62
+ export function installTranscriptEditorBorderStyle(
63
+ editor: object,
64
+ isTranscriptFocused: () => boolean,
65
+ ): (() => void) | undefined {
66
+ const target = editor as BorderRenderableEditor;
67
+ const restorers = [
68
+ patchBorderRenderer(target, "renderTopBorder", isTranscriptFocused),
69
+ patchBorderRenderer(target, "renderBottomBorder", isTranscriptFocused),
70
+ ].filter((restore): restore is () => void => restore !== undefined);
71
+
72
+ if (restorers.length === 0) return undefined;
73
+
74
+ return () => {
75
+ for (let index = restorers.length - 1; index >= 0; index--) {
76
+ restorers[index]();
77
+ }
78
+ };
79
+ }
80
+
81
+ export function suppressDefaultScrollIndicator(
82
+ tui: ScrollIndicatorTui,
83
+ enabled: boolean,
84
+ ): (() => void) | undefined {
85
+ if (
86
+ !enabled ||
87
+ tui.mode !== "fullscreen" ||
88
+ !("scrollToEndIndicator" in tui)
89
+ ) {
90
+ return undefined;
91
+ }
92
+
93
+ const previous = tui.scrollToEndIndicator;
94
+ tui.scrollToEndIndicator = undefined;
95
+
96
+ return () => {
97
+ // Do not overwrite a later extension that installed its own indicator.
98
+ if (tui.scrollToEndIndicator !== undefined) return;
99
+ tui.scrollToEndIndicator = previous;
100
+ };
101
+ }