pi-zentui 0.2.2 → 0.2.5
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.
|
@@ -32,11 +32,13 @@ import { PolishedEditor, WrappedPolishedEditor } from "./ui";
|
|
|
32
32
|
import { installUserMessageStyle } from "./user-message";
|
|
33
33
|
|
|
34
34
|
const ZENTUI_EDITOR_FACTORY = Symbol.for("pi-zentui.editor-factory");
|
|
35
|
+
const ZENTUI_EDITOR_BASE_FACTORY = Symbol.for("pi-zentui.editor-base-factory");
|
|
35
36
|
|
|
36
37
|
type EditorFactory = NonNullable<Parameters<ExtensionContext["ui"]["setEditorComponent"]>[0]>;
|
|
37
38
|
|
|
38
39
|
type ZentuiEditorFactory = EditorFactory & {
|
|
39
40
|
[ZENTUI_EDITOR_FACTORY]?: true;
|
|
41
|
+
[ZENTUI_EDITOR_BASE_FACTORY]?: EditorFactory;
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
type ApplyUiResult = {
|
|
@@ -49,6 +51,15 @@ function isZentuiEditorFactory(factory: EditorFactory | undefined): boolean {
|
|
|
49
51
|
return Boolean((factory as ZentuiEditorFactory | undefined)?.[ZENTUI_EDITOR_FACTORY]);
|
|
50
52
|
}
|
|
51
53
|
|
|
54
|
+
function getZentuiEditorBaseFactory(factory: EditorFactory | undefined): EditorFactory | undefined {
|
|
55
|
+
return (factory as ZentuiEditorFactory | undefined)?.[ZENTUI_EDITOR_BASE_FACTORY];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isTuiContext(ctx: ExtensionContext): boolean {
|
|
59
|
+
const mode = (ctx as ExtensionContext & { mode?: string }).mode;
|
|
60
|
+
return ctx.hasUI && (mode === undefined || mode === "tui");
|
|
61
|
+
}
|
|
62
|
+
|
|
52
63
|
export default function (pi: ExtensionAPI) {
|
|
53
64
|
const state: FooterState = createInitialState(emptyGitStatus());
|
|
54
65
|
|
|
@@ -61,6 +72,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
61
72
|
let footerInstalled = false;
|
|
62
73
|
let editorInstalled = false;
|
|
63
74
|
let editorInstallMode: EditorInstallMode = "none";
|
|
75
|
+
let installedEditorFactory: EditorFactory | undefined;
|
|
64
76
|
let wrappedEditorFactory: EditorFactory | undefined;
|
|
65
77
|
let prototypePatchesInstalled = false;
|
|
66
78
|
|
|
@@ -148,24 +160,38 @@ export default function (pi: ExtensionAPI) {
|
|
|
148
160
|
getThinkingLevel,
|
|
149
161
|
)) as ZentuiEditorFactory;
|
|
150
162
|
factory[ZENTUI_EDITOR_FACTORY] = true;
|
|
163
|
+
factory[ZENTUI_EDITOR_BASE_FACTORY] = baseFactory;
|
|
151
164
|
return factory;
|
|
152
165
|
};
|
|
153
166
|
|
|
154
167
|
const installEditor = (ctx: ExtensionContext): boolean => {
|
|
155
168
|
const currentFactory = ctx.ui.getEditorComponent();
|
|
156
|
-
if (currentFactory &&
|
|
169
|
+
if (currentFactory && currentFactory === installedEditorFactory) {
|
|
157
170
|
editorInstalled = true;
|
|
158
171
|
return true;
|
|
159
172
|
}
|
|
160
173
|
|
|
161
174
|
installPrototypePatches();
|
|
162
|
-
|
|
175
|
+
const currentZentuiBaseFactory = getZentuiEditorBaseFactory(currentFactory);
|
|
176
|
+
if (currentFactory && isZentuiEditorFactory(currentFactory)) {
|
|
177
|
+
wrappedEditorFactory = currentZentuiBaseFactory;
|
|
178
|
+
const nextFactory = currentZentuiBaseFactory
|
|
179
|
+
? makeWrappedEditorFactory(ctx, currentZentuiBaseFactory)
|
|
180
|
+
: makeEditorFactory(ctx);
|
|
181
|
+
ctx.ui.setEditorComponent(nextFactory);
|
|
182
|
+
installedEditorFactory = nextFactory;
|
|
183
|
+
editorInstallMode = currentZentuiBaseFactory ? "wrapper" : "standalone";
|
|
184
|
+
} else if (currentFactory) {
|
|
163
185
|
wrappedEditorFactory = currentFactory;
|
|
164
|
-
|
|
186
|
+
const nextFactory = makeWrappedEditorFactory(ctx, currentFactory);
|
|
187
|
+
ctx.ui.setEditorComponent(nextFactory);
|
|
188
|
+
installedEditorFactory = nextFactory;
|
|
165
189
|
editorInstallMode = "wrapper";
|
|
166
190
|
} else {
|
|
167
191
|
wrappedEditorFactory = undefined;
|
|
168
|
-
|
|
192
|
+
const nextFactory = makeEditorFactory(ctx);
|
|
193
|
+
ctx.ui.setEditorComponent(nextFactory);
|
|
194
|
+
installedEditorFactory = nextFactory;
|
|
169
195
|
editorInstallMode = "standalone";
|
|
170
196
|
}
|
|
171
197
|
editorInstalled = true;
|
|
@@ -181,6 +207,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
181
207
|
editorInstallMode === "wrapper" && wrappedEditorFactory ? wrappedEditorFactory : undefined,
|
|
182
208
|
);
|
|
183
209
|
wrappedEditorFactory = undefined;
|
|
210
|
+
installedEditorFactory = undefined;
|
|
184
211
|
editorInstallMode = "none";
|
|
185
212
|
editorInstalled = false;
|
|
186
213
|
return true;
|
|
@@ -216,7 +243,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
216
243
|
|
|
217
244
|
const applyConfiguredUi = (ctx: ExtensionContext): ApplyUiResult => {
|
|
218
245
|
const result: ApplyUiResult = { editorBlocked: false };
|
|
219
|
-
if (!ctx
|
|
246
|
+
if (!isTuiContext(ctx)) return result;
|
|
220
247
|
activeTheme = ctx.ui.theme;
|
|
221
248
|
if (currentConfig.features.editor) {
|
|
222
249
|
const currentFactory = ctx.ui.getEditorComponent();
|
|
@@ -235,11 +262,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
235
262
|
};
|
|
236
263
|
|
|
237
264
|
const installUi = (ctx: ExtensionContext) => {
|
|
238
|
-
if (!ctx
|
|
265
|
+
if (!isTuiContext(ctx)) return;
|
|
239
266
|
activeTheme = ctx.ui.theme;
|
|
240
267
|
uninstallPrototypePatches();
|
|
241
268
|
footerInstalled = false;
|
|
242
269
|
editorInstalled = false;
|
|
270
|
+
installedEditorFactory = undefined;
|
|
243
271
|
ensureConfigExists();
|
|
244
272
|
currentConfig = loadConfig();
|
|
245
273
|
syncFooterState(ctx);
|
|
@@ -250,9 +278,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
250
278
|
|
|
251
279
|
const scheduleEditorReconciliation = (ctx: ExtensionContext) => {
|
|
252
280
|
setTimeout(() => {
|
|
253
|
-
if (!ctx
|
|
281
|
+
if (!isTuiContext(ctx) || !currentConfig.features.editor) return;
|
|
254
282
|
const currentFactory = ctx.ui.getEditorComponent();
|
|
255
|
-
if (currentFactory &&
|
|
283
|
+
if (currentFactory && currentFactory !== installedEditorFactory) {
|
|
256
284
|
applyConfiguredUi(ctx);
|
|
257
285
|
refresh();
|
|
258
286
|
}
|
|
@@ -264,18 +292,20 @@ export default function (pi: ExtensionAPI) {
|
|
|
264
292
|
stopProjectRefresh();
|
|
265
293
|
requestFooterRender = undefined;
|
|
266
294
|
getActiveExtensionStatuses = () => new Map();
|
|
267
|
-
if (ctx
|
|
295
|
+
if (ctx && isTuiContext(ctx)) {
|
|
268
296
|
ctx.ui.setFooter(undefined);
|
|
269
297
|
const currentFactory = ctx.ui.getEditorComponent();
|
|
270
298
|
if (!currentFactory || isZentuiEditorFactory(currentFactory)) {
|
|
271
299
|
ctx.ui.setEditorComponent(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
300
|
+
getZentuiEditorBaseFactory(currentFactory) ??
|
|
301
|
+
(editorInstallMode === "wrapper" && wrappedEditorFactory
|
|
302
|
+
? wrappedEditorFactory
|
|
303
|
+
: undefined),
|
|
275
304
|
);
|
|
276
305
|
}
|
|
277
306
|
}
|
|
278
307
|
wrappedEditorFactory = undefined;
|
|
308
|
+
installedEditorFactory = undefined;
|
|
279
309
|
editorInstallMode = "none";
|
|
280
310
|
footerInstalled = false;
|
|
281
311
|
editorInstalled = false;
|
|
@@ -305,7 +305,8 @@ export function registerZentuiSettingsCommand(pi: ExtensionAPI, deps: SettingsCo
|
|
|
305
305
|
return;
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
-
|
|
308
|
+
const mode = (ctx as typeof ctx & { mode?: string }).mode;
|
|
309
|
+
if (!ctx.hasUI || (mode !== undefined && mode !== "tui")) return;
|
|
309
310
|
|
|
310
311
|
await ctx.ui.custom<void>((tui, theme, _keybindings, done) => {
|
|
311
312
|
const settingsListTheme = deps.settingsListTheme ?? getSettingsListTheme();
|
package/extensions/zentui/ui.ts
CHANGED
|
@@ -132,6 +132,40 @@ function composeMetadataLine(left: string, right: string | undefined, width: num
|
|
|
132
132
|
return `${leftText}${gap}${right}`;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
function plainRenderedText(line: string): string {
|
|
136
|
+
return line
|
|
137
|
+
.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "")
|
|
138
|
+
.replace(/\x1b\][^\x07]*(?:\x07|\x1b\\)/g, "")
|
|
139
|
+
.replace(/\[[/?][^\]]+\]/g, "");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function isHorizontalBorder(line: string): boolean {
|
|
143
|
+
const plain = plainRenderedText(line).trim();
|
|
144
|
+
return plain.length > 0 && /^─+$/.test(plain);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function isRenderedModelMetaLine(line: string, modelMeta: EditorMeta): boolean {
|
|
148
|
+
const plain = plainRenderedText(line);
|
|
149
|
+
return plain.includes(modelMeta.modelLabel) && plain.includes(modelMeta.providerLabel);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function removeRenderedModelMetaLines(lines: string[], modelMeta: EditorMeta): string[] {
|
|
153
|
+
const result: string[] = [];
|
|
154
|
+
for (let index = 0; index < lines.length; index++) {
|
|
155
|
+
const line = lines[index] ?? "";
|
|
156
|
+
if (isRenderedModelMetaLine(line, modelMeta)) continue;
|
|
157
|
+
|
|
158
|
+
const plain = plainRenderedText(line).trim();
|
|
159
|
+
const previousWasMeta = index > 0 && isRenderedModelMetaLine(lines[index - 1] ?? "", modelMeta);
|
|
160
|
+
const nextIsMeta =
|
|
161
|
+
index < lines.length - 1 && isRenderedModelMetaLine(lines[index + 1] ?? "", modelMeta);
|
|
162
|
+
if (!plain && (previousWasMeta || nextIsMeta)) continue;
|
|
163
|
+
|
|
164
|
+
result.push(line);
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
|
|
135
169
|
function vimModeColor(mode: string): string {
|
|
136
170
|
switch (mode.toLowerCase()) {
|
|
137
171
|
case "insert":
|
|
@@ -195,10 +229,9 @@ function renderPolishedFrame({
|
|
|
195
229
|
autocompleteCount > 0 && autocompleteCount < baseRendered.length
|
|
196
230
|
? baseRendered.slice(-autocompleteCount)
|
|
197
231
|
: [];
|
|
198
|
-
|
|
199
232
|
if (editorFrame.length < 2) return clampRenderedLines(baseRendered, width);
|
|
200
233
|
|
|
201
|
-
const editorLines = editorFrame.slice(1, -1);
|
|
234
|
+
const editorLines = removeRenderedModelMetaLines(editorFrame.slice(1, -1), modelMeta);
|
|
202
235
|
const model = renderStyleForSourceOrFallback(
|
|
203
236
|
uiTheme,
|
|
204
237
|
colorSource,
|