feat(vscode): add context menu commands (#83)
* Fix bun lock * Add Context Menu * Make it always visible * Add Improve and Explain Command
This commit is contained in:
@@ -61,8 +61,45 @@
|
||||
{
|
||||
"command": "openchamber.showOpenCodeStatus",
|
||||
"title": "OpenChamber: Show OpenCode Status"
|
||||
},
|
||||
{
|
||||
"command": "openchamber.addToContext",
|
||||
"title": "Add to Context"
|
||||
},
|
||||
{
|
||||
"command": "openchamber.explain",
|
||||
"title": "Explain"
|
||||
},
|
||||
{
|
||||
"command": "openchamber.improveCode",
|
||||
"title": "Improve Code"
|
||||
}
|
||||
],
|
||||
"submenus": [
|
||||
{
|
||||
"id": "openchamber.submenu",
|
||||
"label": "OpenChamber"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"editor/context": [
|
||||
{
|
||||
"submenu": "openchamber.submenu",
|
||||
"group": "navigation"
|
||||
}
|
||||
],
|
||||
"openchamber.submenu": [
|
||||
{
|
||||
"command": "openchamber.explain"
|
||||
},
|
||||
{
|
||||
"command": "openchamber.improveCode"
|
||||
},
|
||||
{
|
||||
"command": "openchamber.addToContext"
|
||||
}
|
||||
]
|
||||
},
|
||||
"configuration": {
|
||||
"title": "OpenChamber",
|
||||
"properties": {
|
||||
|
||||
@@ -86,6 +86,32 @@ export class ChatViewProvider implements vscode.WebviewViewProvider {
|
||||
// Send to webview if it exists
|
||||
this._sendCachedState();
|
||||
}
|
||||
|
||||
public addTextToInput(text: string) {
|
||||
if (this._view) {
|
||||
// Reveal the webview panel
|
||||
this._view.show(true);
|
||||
|
||||
this._view.webview.postMessage({
|
||||
type: 'command',
|
||||
command: 'addToContext',
|
||||
payload: { text }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public createNewSessionWithPrompt(prompt: string) {
|
||||
if (this._view) {
|
||||
// Reveal the webview panel
|
||||
this._view.show(true);
|
||||
|
||||
this._view.webview.postMessage({
|
||||
type: 'command',
|
||||
command: 'createSessionWithPrompt',
|
||||
payload: { prompt }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _sendCachedState() {
|
||||
if (!this._view) {
|
||||
|
||||
@@ -59,6 +59,104 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
})
|
||||
);
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand('openchamber.addToContext', async () => {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
vscode.window.showWarningMessage('OpenChamber [Add to Context]:No active editor');
|
||||
return;
|
||||
}
|
||||
|
||||
const selection = editor.selection;
|
||||
const selectedText = editor.document.getText(selection);
|
||||
|
||||
if (!selectedText) {
|
||||
vscode.window.showWarningMessage('OpenChamber [Add to Context]: No text selected');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get file info for context
|
||||
const filePath = vscode.workspace.asRelativePath(editor.document.uri);
|
||||
const languageId = editor.document.languageId;
|
||||
|
||||
// Get line numbers (1-based for display)
|
||||
const startLine = selection.start.line + 1;
|
||||
const endLine = selection.end.line + 1;
|
||||
const lineRange = startLine === endLine ? `${startLine}` : `${startLine}-${endLine}`;
|
||||
|
||||
// Format as file path with line numbers, followed by markdown code block
|
||||
const contextText = `${filePath}:${lineRange}\n\`\`\`${languageId}\n${selectedText}\n\`\`\``;
|
||||
|
||||
// Send to webview and reveal the panel
|
||||
chatViewProvider?.addTextToInput(contextText);
|
||||
|
||||
// Focus the chat panel
|
||||
vscode.commands.executeCommand('openchamber.chatView.focus');
|
||||
})
|
||||
);
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand('openchamber.explain', async () => {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
vscode.window.showWarningMessage('OpenChamber [Explain]: No active editor');
|
||||
return;
|
||||
}
|
||||
|
||||
const selection = editor.selection;
|
||||
const selectedText = editor.document.getText(selection);
|
||||
const filePath = vscode.workspace.asRelativePath(editor.document.uri);
|
||||
const languageId = editor.document.languageId;
|
||||
|
||||
let prompt: string;
|
||||
|
||||
if (selectedText) {
|
||||
// Selection exists - explain the selected code
|
||||
const startLine = selection.start.line + 1;
|
||||
const endLine = selection.end.line + 1;
|
||||
const lineRange = startLine === endLine ? `${startLine}` : `${startLine}-${endLine}`;
|
||||
prompt = `Explain the following Code / Text:\n\n${filePath}:${lineRange}\n\`\`\`${languageId}\n${selectedText}\n\`\`\``;
|
||||
} else {
|
||||
// No selection - explain the entire file
|
||||
prompt = `Explain the following Code / Text:\n\n${filePath}`;
|
||||
}
|
||||
|
||||
// Create new session and send the prompt
|
||||
chatViewProvider?.createNewSessionWithPrompt(prompt);
|
||||
vscode.commands.executeCommand('openchamber.chatView.focus');
|
||||
})
|
||||
);
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand('openchamber.improveCode', async () => {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
vscode.window.showWarningMessage('OpenChamber [Improve Code]: No active editor');
|
||||
return;
|
||||
}
|
||||
|
||||
const selection = editor.selection;
|
||||
const selectedText = editor.document.getText(selection);
|
||||
|
||||
if (!selectedText) {
|
||||
vscode.window.showWarningMessage('OpenChamber [Improve Code]: No text selected');
|
||||
return;
|
||||
}
|
||||
|
||||
const filePath = vscode.workspace.asRelativePath(editor.document.uri);
|
||||
const languageId = editor.document.languageId;
|
||||
const startLine = selection.start.line + 1;
|
||||
const endLine = selection.end.line + 1;
|
||||
const lineRange = startLine === endLine ? `${startLine}` : `${startLine}-${endLine}`;
|
||||
|
||||
const prompt = `Improve the following Code:\n\n${filePath}:${lineRange}\n\`\`\`${languageId}\n${selectedText}\n\`\`\``;
|
||||
|
||||
// Create new session and send the prompt
|
||||
chatViewProvider?.createNewSessionWithPrompt(prompt);
|
||||
vscode.commands.executeCommand('openchamber.chatView.focus');
|
||||
})
|
||||
);
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand('openchamber.showOpenCodeStatus', async () => {
|
||||
const config = vscode.workspace.getConfiguration('openchamber');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createVSCodeAPIs } from './api';
|
||||
import { onThemeChange, proxyApiRequest, sendBridgeMessage, startSseProxy, stopSseProxy } from './api/bridge';
|
||||
import { onCommand, onThemeChange, proxyApiRequest, sendBridgeMessage, startSseProxy, stopSseProxy } from './api/bridge';
|
||||
import type { RuntimeAPIs } from '../../ui/src/lib/api/types';
|
||||
import {
|
||||
buildVSCodeThemeFromPalette,
|
||||
@@ -566,6 +566,57 @@ window.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
return originalFetch(input as RequestInfo, init);
|
||||
};
|
||||
|
||||
// Listen for addToContext command from extension
|
||||
onCommand('addToContext', (payload) => {
|
||||
const { text } = payload as { text: string };
|
||||
|
||||
// Import the store dynamically to avoid circular dependencies
|
||||
import('../../ui/src/stores/useSessionStore').then(({ useSessionStore }) => {
|
||||
const store = useSessionStore.getState();
|
||||
const currentText = store.pendingInputText || '';
|
||||
// Append to existing text with double newline separator
|
||||
const newText = currentText ? `${currentText}\n\n${text}` : text;
|
||||
store.setPendingInputText(newText);
|
||||
});
|
||||
});
|
||||
|
||||
// Listen for createSessionWithPrompt command from extension (Explain, Improve Code)
|
||||
onCommand('createSessionWithPrompt', (payload) => {
|
||||
const { prompt } = payload as { prompt: string };
|
||||
|
||||
Promise.all([
|
||||
import('../../ui/src/stores/useSessionStore'),
|
||||
import('../../ui/src/stores/useConfigStore'),
|
||||
]).then(([{ useSessionStore }, { useConfigStore }]) => {
|
||||
const sessionStore = useSessionStore.getState();
|
||||
const configStore = useConfigStore.getState();
|
||||
|
||||
// Open a new session draft first
|
||||
sessionStore.openNewSessionDraft();
|
||||
|
||||
// Get current provider/model/agent configuration
|
||||
const { currentProviderId, currentModelId, currentAgentName } = configStore;
|
||||
|
||||
if (currentProviderId && currentModelId) {
|
||||
// Send the message - this will create the session from the draft and send
|
||||
sessionStore.sendMessage(
|
||||
prompt,
|
||||
currentProviderId,
|
||||
currentModelId,
|
||||
currentAgentName ?? undefined,
|
||||
undefined, // attachments
|
||||
undefined, // agentMentionName
|
||||
undefined // additionalParts
|
||||
).catch((error: unknown) => {
|
||||
console.error('[OpenChamber] Failed to send prompt:', error);
|
||||
});
|
||||
} else {
|
||||
// If no provider/model configured, just set the text and let user send manually
|
||||
sessionStore.setPendingInputText(prompt);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
import('../../ui/src/main')
|
||||
.then(async () => {
|
||||
await waitForUiMount();
|
||||
|
||||
Reference in New Issue
Block a user