@danypops/papyrus 0.28.1 → 0.28.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.
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
CURSOR_MARKER,
|
|
19
19
|
decodeKittyPrintable,
|
|
20
20
|
Editor,
|
|
21
|
+
type EditorComponent,
|
|
21
22
|
type EditorTheme,
|
|
22
23
|
fuzzyFilter,
|
|
23
24
|
Key,
|
|
@@ -51,7 +52,7 @@ function safeMarkdownTheme(): MarkdownTheme | undefined {
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
export type AskDisplayMode = "overlay" | "inline";
|
|
55
|
+
export type AskDisplayMode = "overlay" | "inline" | "editor";
|
|
55
56
|
|
|
56
57
|
export interface AskQuestionParams {
|
|
57
58
|
question: string;
|
|
@@ -1142,7 +1143,7 @@ async function askQuestionUnguarded(ctx: ExtensionContext, params: AskQuestionPa
|
|
|
1142
1143
|
const allowFreeform = params.allowFreeform ?? true;
|
|
1143
1144
|
const allowComment = params.allowComment ?? parseBooleanPreference(process.env["PAPYRUS_DISCUSS_ALLOW_COMMENT"]) ?? false;
|
|
1144
1145
|
const envMode = process.env["PAPYRUS_DISCUSS_DISPLAY_MODE"]?.trim().toLowerCase();
|
|
1145
|
-
const envDisplayMode: AskDisplayMode | undefined = envMode === "overlay" || envMode === "inline" ? envMode : undefined;
|
|
1146
|
+
const envDisplayMode: AskDisplayMode | undefined = envMode === "overlay" || envMode === "inline" || envMode === "editor" ? envMode : undefined;
|
|
1146
1147
|
const displayMode: AskDisplayMode = params.displayMode ?? envDisplayMode ?? "overlay";
|
|
1147
1148
|
const normalizedContext = params.context?.trim() || undefined;
|
|
1148
1149
|
|
|
@@ -1155,6 +1156,63 @@ async function askQuestionUnguarded(ctx: ExtensionContext, params: AskQuestionPa
|
|
|
1155
1156
|
}
|
|
1156
1157
|
}
|
|
1157
1158
|
|
|
1159
|
+
/**
|
|
1160
|
+
* Hosts an AskComponent in place of the real input editor (ctx.ui.setEditorComponent), the same
|
|
1161
|
+
* mechanism Pi's own slash-command menu ecosystem uses to render attached to the prompt rather
|
|
1162
|
+
* than as a floating overlay. getText() always returns the human's real in-progress draft,
|
|
1163
|
+
* captured once before swapping in -- setEditorComponent's own swap logic reads getText() off
|
|
1164
|
+
* the OUTGOING editor to carry a draft forward when restoring the previous one afterward; if
|
|
1165
|
+
* this returned anything else, restoring would silently overwrite a real draft with an empty
|
|
1166
|
+
* string. Implements EditorComponent directly rather than extending CustomEditor: CustomEditor's
|
|
1167
|
+
* duck-typed actionHandlers Map would otherwise get every app-level action (model switching,
|
|
1168
|
+
* clear, suspend) copied onto it by Pi's own editor-swap code, none of which this host uses or
|
|
1169
|
+
* forwards -- avoiding the inheritance sidesteps that dead weight entirely.
|
|
1170
|
+
*/
|
|
1171
|
+
class DiscussEditorHost implements EditorComponent {
|
|
1172
|
+
constructor(
|
|
1173
|
+
private readonly ask: AskComponent,
|
|
1174
|
+
private readonly preservedText: string,
|
|
1175
|
+
) {}
|
|
1176
|
+
getText(): string { return this.preservedText; }
|
|
1177
|
+
setText(_text: string): void {}
|
|
1178
|
+
render(width: number): string[] { return this.ask.render(width); }
|
|
1179
|
+
handleInput(data: string): void { this.ask.handleInput(data); }
|
|
1180
|
+
invalidate(): void { this.ask.invalidate(); }
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
async function askViaEditorSwap(
|
|
1184
|
+
ctx: ExtensionContext,
|
|
1185
|
+
params: AskQuestionParams,
|
|
1186
|
+
options: AskOption[],
|
|
1187
|
+
allowMultiple: boolean,
|
|
1188
|
+
allowFreeform: boolean,
|
|
1189
|
+
allowComment: boolean,
|
|
1190
|
+
normalizedContext: string | undefined,
|
|
1191
|
+
shortcuts: ResolvedAskShortcuts,
|
|
1192
|
+
): Promise<AskResponse | null> {
|
|
1193
|
+
const previousFactory = ctx.ui.getEditorComponent();
|
|
1194
|
+
const preservedText = ctx.ui.getEditorText();
|
|
1195
|
+
// setEditorComponent's factory only receives an EditorTheme (borderColor + selectList) --
|
|
1196
|
+
// nowhere near AskComponent's actual dependency on the full Theme surface (.fg(), .bold(),
|
|
1197
|
+
// etc). ctx.ui.theme is the real, rich Theme; captured here rather than from the factory.
|
|
1198
|
+
const theme = ctx.ui.theme;
|
|
1199
|
+
return new Promise<AskResponse | null>((resolve) => {
|
|
1200
|
+
let settled = false;
|
|
1201
|
+
const finish = (result: AskResponse | null) => {
|
|
1202
|
+
if (settled) return;
|
|
1203
|
+
settled = true;
|
|
1204
|
+
ctx.ui.setEditorComponent(previousFactory);
|
|
1205
|
+
resolve(result);
|
|
1206
|
+
};
|
|
1207
|
+
if (params.signal) params.signal.addEventListener("abort", () => finish(null), { once: true });
|
|
1208
|
+
if (params.timeout && params.timeout > 0) setTimeout(() => finish(null), params.timeout);
|
|
1209
|
+
ctx.ui.setEditorComponent((tui: TUI, _editorTheme: EditorTheme, keybindings: KeybindingsManager) => {
|
|
1210
|
+
const ask = new AskComponent(params.question, normalizedContext, params.subtitle, options, allowMultiple, allowFreeform, allowComment, "inline", tui, theme, keybindings, shortcuts, finish);
|
|
1211
|
+
return new DiscussEditorHost(ask, preservedText);
|
|
1212
|
+
});
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1158
1216
|
async function askQuestionBlocking(
|
|
1159
1217
|
ctx: ExtensionContext,
|
|
1160
1218
|
params: AskQuestionParams,
|
|
@@ -1173,6 +1231,15 @@ async function askQuestionBlocking(
|
|
|
1173
1231
|
commentToggle: resolveShortcut(undefined, process.env["PAPYRUS_DISCUSS_COMMENT_TOGGLE_KEY"], DEFAULT_COMMENT_TOGGLE_KEY),
|
|
1174
1232
|
};
|
|
1175
1233
|
|
|
1234
|
+
// "editor" hosts the picker in place of the real input editor (Pi's own slash-command menu's
|
|
1235
|
+
// mechanism) instead of a floating overlay -- degrades to "inline" if setEditorComponent isn't
|
|
1236
|
+
// available in this UI mode (interactive-only, like onTerminalInput below).
|
|
1237
|
+
if (displayMode === "editor" && typeof ctx.ui.setEditorComponent === "function" && typeof ctx.ui.getEditorComponent === "function" && typeof ctx.ui.getEditorText === "function") {
|
|
1238
|
+
const response = await askViaEditorSwap(ctx, params, options, allowMultiple, allowFreeform, allowComment, normalizedContext, shortcuts);
|
|
1239
|
+
return response ? toAskAnswer(response) : undefined;
|
|
1240
|
+
}
|
|
1241
|
+
const effectiveDisplayMode: AskDisplayMode = displayMode === "editor" ? "inline" : displayMode;
|
|
1242
|
+
|
|
1176
1243
|
let overlayHandle: OverlayHandle | undefined;
|
|
1177
1244
|
let removeOverlayInputListener: (() => void) | undefined;
|
|
1178
1245
|
let hasAnnouncedHide = false;
|
|
@@ -1181,7 +1248,7 @@ async function askQuestionBlocking(
|
|
|
1181
1248
|
const factory = (tui: TUI, theme: Theme, keybindings: KeybindingsManager, done: (result: AskResponse | null) => void) => {
|
|
1182
1249
|
if (params.signal) params.signal.addEventListener("abort", () => done(null), { once: true });
|
|
1183
1250
|
if (params.timeout && params.timeout > 0) setTimeout(() => done(null), params.timeout);
|
|
1184
|
-
return new AskComponent(params.question, normalizedContext, params.subtitle, options, allowMultiple, allowFreeform, allowComment,
|
|
1251
|
+
return new AskComponent(params.question, normalizedContext, params.subtitle, options, allowMultiple, allowFreeform, allowComment, effectiveDisplayMode, tui, theme, keybindings, shortcuts, done);
|
|
1185
1252
|
};
|
|
1186
1253
|
|
|
1187
1254
|
const overlayToggle = shortcuts.overlayToggle;
|
|
@@ -1195,7 +1262,7 @@ async function askQuestionBlocking(
|
|
|
1195
1262
|
});
|
|
1196
1263
|
}
|
|
1197
1264
|
|
|
1198
|
-
const customResult = await ctx.ui.custom<AskResponse | null>(factory, buildCustomUIOptions(
|
|
1265
|
+
const customResult = await ctx.ui.custom<AskResponse | null>(factory, buildCustomUIOptions(effectiveDisplayMode, (handle) => { overlayHandle = handle; }));
|
|
1199
1266
|
response = customResult !== undefined ? customResult : await askViaDialogs(ctx.ui, params.question, normalizedContext, options, allowMultiple, allowFreeform, allowComment, params.timeout);
|
|
1200
1267
|
} finally {
|
|
1201
1268
|
removeOverlayInputListener?.();
|
package/package.json
CHANGED