mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-20 00:02:11 +00:00
Refactor selectors: replace show/hide pairs with single showSelector helper
This commit is contained in:
parent
fd7f20f968
commit
dbd5f5eb0b
1 changed files with 221 additions and 265 deletions
|
|
@ -10,6 +10,7 @@ import type { AssistantMessage, Message } from "@mariozechner/pi-ai";
|
||||||
import type { SlashCommand } from "@mariozechner/pi-tui";
|
import type { SlashCommand } from "@mariozechner/pi-tui";
|
||||||
import {
|
import {
|
||||||
CombinedAutocompleteProvider,
|
CombinedAutocompleteProvider,
|
||||||
|
type Component,
|
||||||
Container,
|
Container,
|
||||||
Input,
|
Input,
|
||||||
Loader,
|
Loader,
|
||||||
|
|
@ -72,15 +73,6 @@ export class InteractiveMode {
|
||||||
// Tool execution tracking: toolCallId -> component
|
// Tool execution tracking: toolCallId -> component
|
||||||
private pendingTools = new Map<string, ToolExecutionComponent>();
|
private pendingTools = new Map<string, ToolExecutionComponent>();
|
||||||
|
|
||||||
// Selector components
|
|
||||||
private thinkingSelector: ThinkingSelectorComponent | null = null;
|
|
||||||
private queueModeSelector: QueueModeSelectorComponent | null = null;
|
|
||||||
private themeSelector: ThemeSelectorComponent | null = null;
|
|
||||||
private modelSelector: ModelSelectorComponent | null = null;
|
|
||||||
private userMessageSelector: UserMessageSelectorComponent | null = null;
|
|
||||||
private sessionSelector: SessionSelectorComponent | null = null;
|
|
||||||
private oauthSelector: OAuthSelectorComponent | null = null;
|
|
||||||
|
|
||||||
// Track if this is the first user message (to skip spacer)
|
// Track if this is the first user message (to skip spacer)
|
||||||
private isFirstUserMessage = true;
|
private isFirstUserMessage = true;
|
||||||
|
|
||||||
|
|
@ -891,66 +883,68 @@ export class InteractiveMode {
|
||||||
// Selectors
|
// Selectors
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a selector component in place of the editor.
|
||||||
|
* @param create Factory that receives a `done` callback and returns the component and focus target
|
||||||
|
*/
|
||||||
|
private showSelector(create: (done: () => void) => { component: Component; focus: Component }): void {
|
||||||
|
const done = () => {
|
||||||
|
this.editorContainer.clear();
|
||||||
|
this.editorContainer.addChild(this.editor);
|
||||||
|
this.ui.setFocus(this.editor);
|
||||||
|
};
|
||||||
|
const { component, focus } = create(done);
|
||||||
|
this.editorContainer.clear();
|
||||||
|
this.editorContainer.addChild(component);
|
||||||
|
this.ui.setFocus(focus);
|
||||||
|
this.ui.requestRender();
|
||||||
|
}
|
||||||
|
|
||||||
private showThinkingSelector(): void {
|
private showThinkingSelector(): void {
|
||||||
this.thinkingSelector = new ThinkingSelectorComponent(
|
this.showSelector((done) => {
|
||||||
|
const selector = new ThinkingSelectorComponent(
|
||||||
this.session.thinkingLevel,
|
this.session.thinkingLevel,
|
||||||
(level) => {
|
(level) => {
|
||||||
this.session.setThinkingLevel(level);
|
this.session.setThinkingLevel(level);
|
||||||
this.updateEditorBorderColor();
|
this.updateEditorBorderColor();
|
||||||
this.chatContainer.addChild(new Spacer(1));
|
this.chatContainer.addChild(new Spacer(1));
|
||||||
this.chatContainer.addChild(new Text(theme.fg("dim", `Thinking level: ${level}`), 1, 0));
|
this.chatContainer.addChild(new Text(theme.fg("dim", `Thinking level: ${level}`), 1, 0));
|
||||||
this.hideThinkingSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.hideThinkingSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.editorContainer.clear();
|
return { component: selector, focus: selector.getSelectList() };
|
||||||
this.editorContainer.addChild(this.thinkingSelector);
|
});
|
||||||
this.ui.setFocus(this.thinkingSelector.getSelectList());
|
|
||||||
this.ui.requestRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private hideThinkingSelector(): void {
|
|
||||||
this.editorContainer.clear();
|
|
||||||
this.editorContainer.addChild(this.editor);
|
|
||||||
this.thinkingSelector = null;
|
|
||||||
this.ui.setFocus(this.editor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private showQueueModeSelector(): void {
|
private showQueueModeSelector(): void {
|
||||||
this.queueModeSelector = new QueueModeSelectorComponent(
|
this.showSelector((done) => {
|
||||||
|
const selector = new QueueModeSelectorComponent(
|
||||||
this.session.queueMode,
|
this.session.queueMode,
|
||||||
(mode) => {
|
(mode) => {
|
||||||
this.session.setQueueMode(mode);
|
this.session.setQueueMode(mode);
|
||||||
this.chatContainer.addChild(new Spacer(1));
|
this.chatContainer.addChild(new Spacer(1));
|
||||||
this.chatContainer.addChild(new Text(theme.fg("dim", `Queue mode: ${mode}`), 1, 0));
|
this.chatContainer.addChild(new Text(theme.fg("dim", `Queue mode: ${mode}`), 1, 0));
|
||||||
this.hideQueueModeSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.hideQueueModeSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.editorContainer.clear();
|
return { component: selector, focus: selector.getSelectList() };
|
||||||
this.editorContainer.addChild(this.queueModeSelector);
|
});
|
||||||
this.ui.setFocus(this.queueModeSelector.getSelectList());
|
|
||||||
this.ui.requestRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private hideQueueModeSelector(): void {
|
|
||||||
this.editorContainer.clear();
|
|
||||||
this.editorContainer.addChild(this.editor);
|
|
||||||
this.queueModeSelector = null;
|
|
||||||
this.ui.setFocus(this.editor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private showThemeSelector(): void {
|
private showThemeSelector(): void {
|
||||||
const currentTheme = this.settingsManager.getTheme() || "dark";
|
const currentTheme = this.settingsManager.getTheme() || "dark";
|
||||||
this.themeSelector = new ThemeSelectorComponent(
|
this.showSelector((done) => {
|
||||||
|
const selector = new ThemeSelectorComponent(
|
||||||
currentTheme,
|
currentTheme,
|
||||||
(themeName) => {
|
(themeName) => {
|
||||||
const result = setTheme(themeName);
|
const result = setTheme(themeName);
|
||||||
|
|
@ -971,11 +965,11 @@ export class InteractiveMode {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.hideThemeSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.hideThemeSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
(themeName) => {
|
(themeName) => {
|
||||||
|
|
@ -986,21 +980,13 @@ export class InteractiveMode {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.editorContainer.clear();
|
return { component: selector, focus: selector.getSelectList() };
|
||||||
this.editorContainer.addChild(this.themeSelector);
|
});
|
||||||
this.ui.setFocus(this.themeSelector.getSelectList());
|
|
||||||
this.ui.requestRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private hideThemeSelector(): void {
|
|
||||||
this.editorContainer.clear();
|
|
||||||
this.editorContainer.addChild(this.editor);
|
|
||||||
this.themeSelector = null;
|
|
||||||
this.ui.setFocus(this.editor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private showModelSelector(): void {
|
private showModelSelector(): void {
|
||||||
this.modelSelector = new ModelSelectorComponent(
|
this.showSelector((done) => {
|
||||||
|
const selector = new ModelSelectorComponent(
|
||||||
this.ui,
|
this.ui,
|
||||||
this.session.model,
|
this.session.model,
|
||||||
this.settingsManager,
|
this.settingsManager,
|
||||||
|
|
@ -1009,25 +995,16 @@ export class InteractiveMode {
|
||||||
this.sessionManager.saveModelChange(model.provider, model.id);
|
this.sessionManager.saveModelChange(model.provider, model.id);
|
||||||
this.chatContainer.addChild(new Spacer(1));
|
this.chatContainer.addChild(new Spacer(1));
|
||||||
this.chatContainer.addChild(new Text(theme.fg("dim", `Model: ${model.id}`), 1, 0));
|
this.chatContainer.addChild(new Text(theme.fg("dim", `Model: ${model.id}`), 1, 0));
|
||||||
this.hideModelSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.hideModelSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.editorContainer.clear();
|
return { component: selector, focus: selector };
|
||||||
this.editorContainer.addChild(this.modelSelector);
|
});
|
||||||
this.ui.setFocus(this.modelSelector);
|
|
||||||
this.ui.requestRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private hideModelSelector(): void {
|
|
||||||
this.editorContainer.clear();
|
|
||||||
this.editorContainer.addChild(this.editor);
|
|
||||||
this.modelSelector = null;
|
|
||||||
this.ui.setFocus(this.editor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private showUserMessageSelector(): void {
|
private showUserMessageSelector(): void {
|
||||||
|
|
@ -1040,7 +1017,8 @@ export class InteractiveMode {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.userMessageSelector = new UserMessageSelectorComponent(
|
this.showSelector((done) => {
|
||||||
|
const selector = new UserMessageSelectorComponent(
|
||||||
userMessages.map((m) => ({ index: m.entryIndex, text: m.text })),
|
userMessages.map((m) => ({ index: m.entryIndex, text: m.text })),
|
||||||
(entryIndex) => {
|
(entryIndex) => {
|
||||||
const selectedText = this.session.branch(entryIndex);
|
const selectedText = this.session.branch(entryIndex);
|
||||||
|
|
@ -1050,43 +1028,33 @@ export class InteractiveMode {
|
||||||
this.chatContainer.addChild(new Spacer(1));
|
this.chatContainer.addChild(new Spacer(1));
|
||||||
this.chatContainer.addChild(new Text(theme.fg("dim", "Branched to new session"), 1, 0));
|
this.chatContainer.addChild(new Text(theme.fg("dim", "Branched to new session"), 1, 0));
|
||||||
this.editor.setText(selectedText);
|
this.editor.setText(selectedText);
|
||||||
this.hideUserMessageSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.hideUserMessageSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.editorContainer.clear();
|
return { component: selector, focus: selector.getMessageList() };
|
||||||
this.editorContainer.addChild(this.userMessageSelector);
|
});
|
||||||
this.ui.setFocus(this.userMessageSelector.getMessageList());
|
|
||||||
this.ui.requestRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private hideUserMessageSelector(): void {
|
|
||||||
this.editorContainer.clear();
|
|
||||||
this.editorContainer.addChild(this.editor);
|
|
||||||
this.userMessageSelector = null;
|
|
||||||
this.ui.setFocus(this.editor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private showSessionSelector(): void {
|
private showSessionSelector(): void {
|
||||||
this.sessionSelector = new SessionSelectorComponent(
|
this.showSelector((done) => {
|
||||||
|
const selector = new SessionSelectorComponent(
|
||||||
this.sessionManager,
|
this.sessionManager,
|
||||||
async (sessionPath) => {
|
async (sessionPath) => {
|
||||||
this.hideSessionSelector();
|
done();
|
||||||
await this.handleResumeSession(sessionPath);
|
await this.handleResumeSession(sessionPath);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.hideSessionSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.editorContainer.clear();
|
return { component: selector, focus: selector.getSessionList() };
|
||||||
this.editorContainer.addChild(this.sessionSelector);
|
});
|
||||||
this.ui.setFocus(this.sessionSelector.getSessionList());
|
|
||||||
this.ui.requestRender();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleResumeSession(sessionPath: string): Promise<void> {
|
private async handleResumeSession(sessionPath: string): Promise<void> {
|
||||||
|
|
@ -1115,13 +1083,6 @@ export class InteractiveMode {
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
private hideSessionSelector(): void {
|
|
||||||
this.editorContainer.clear();
|
|
||||||
this.editorContainer.addChild(this.editor);
|
|
||||||
this.sessionSelector = null;
|
|
||||||
this.ui.setFocus(this.editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async showOAuthSelector(mode: "login" | "logout"): Promise<void> {
|
private async showOAuthSelector(mode: "login" | "logout"): Promise<void> {
|
||||||
if (mode === "logout") {
|
if (mode === "logout") {
|
||||||
const loggedInProviders = listOAuthProviders();
|
const loggedInProviders = listOAuthProviders();
|
||||||
|
|
@ -1135,10 +1096,11 @@ export class InteractiveMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.oauthSelector = new OAuthSelectorComponent(
|
this.showSelector((done) => {
|
||||||
|
const selector = new OAuthSelectorComponent(
|
||||||
mode,
|
mode,
|
||||||
async (providerId: string) => {
|
async (providerId: string) => {
|
||||||
this.hideOAuthSelector();
|
done();
|
||||||
|
|
||||||
if (mode === "login") {
|
if (mode === "login") {
|
||||||
this.chatContainer.addChild(new Spacer(1));
|
this.chatContainer.addChild(new Spacer(1));
|
||||||
|
|
@ -1159,7 +1121,11 @@ export class InteractiveMode {
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
|
|
||||||
const openCmd =
|
const openCmd =
|
||||||
process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
process.platform === "darwin"
|
||||||
|
? "open"
|
||||||
|
: process.platform === "win32"
|
||||||
|
? "start"
|
||||||
|
: "xdg-open";
|
||||||
exec(`${openCmd} "${url}"`);
|
exec(`${openCmd} "${url}"`);
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
|
|
@ -1208,22 +1174,12 @@ export class InteractiveMode {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.hideOAuthSelector();
|
done();
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
return { component: selector, focus: selector };
|
||||||
this.editorContainer.clear();
|
});
|
||||||
this.editorContainer.addChild(this.oauthSelector);
|
|
||||||
this.ui.setFocus(this.oauthSelector);
|
|
||||||
this.ui.requestRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private hideOAuthSelector(): void {
|
|
||||||
this.editorContainer.clear();
|
|
||||||
this.editorContainer.addChild(this.editor);
|
|
||||||
this.oauthSelector = null;
|
|
||||||
this.ui.setFocus(this.editor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue