|
|
@@ -32,7 +32,7 @@ import { sendShowWebviewEvent } from "./core/controller/ui/subscribeToShowWebvie
|
|
|
import { HookDiscoveryCache } from "./core/hooks/HookDiscoveryCache"
|
|
|
import { HookProcessRegistry } from "./core/hooks/HookProcessRegistry"
|
|
|
import { workspaceResolver } from "./core/workspace"
|
|
|
-import { getContextForCommand, showWebview } from "./hosts/vscode/commandUtils"
|
|
|
+import { findMatchingNotebookCell, getContextForCommand, showWebview } from "./hosts/vscode/commandUtils"
|
|
|
import { abortCommitGeneration, generateCommitMsg } from "./hosts/vscode/commit-message-generator"
|
|
|
import {
|
|
|
disposeVscodeCommentReviewController,
|
|
|
@@ -395,6 +395,107 @@ export async function activate(context: vscode.ExtensionContext) {
|
|
|
}),
|
|
|
)
|
|
|
|
|
|
+ // Register Jupyter Notebook command handlers
|
|
|
+ const NOTEBOOK_EDIT_INSTRUCTIONS = `Special considerations for using replace_in_file on *.ipynb files:
|
|
|
+* Jupyter notebook files are JSON format with specific structure for source code cells
|
|
|
+* Source code in cells is stored as JSON string arrays ending with explicit \\n characters and commas
|
|
|
+* Always match the exact JSON format including quotes, commas, and escaped newlines.`
|
|
|
+
|
|
|
+ // Helper to get notebook context for Jupyter commands
|
|
|
+ async function getNotebookCommandContext(range?: vscode.Range, diagnostics?: vscode.Diagnostic[]) {
|
|
|
+ const activeNotebook = vscode.window.activeNotebookEditor
|
|
|
+ if (!activeNotebook) {
|
|
|
+ HostProvider.window.showMessage({
|
|
|
+ type: ShowMessageType.ERROR,
|
|
|
+ message: "No active Jupyter notebook found. Please open a .ipynb file first.",
|
|
|
+ })
|
|
|
+ return null
|
|
|
+ }
|
|
|
+
|
|
|
+ const ctx = await getContextForCommand(range, diagnostics)
|
|
|
+ if (!ctx) {
|
|
|
+ return null
|
|
|
+ }
|
|
|
+
|
|
|
+ const filePath = ctx.commandContext.filePath || ""
|
|
|
+ let cellJson: string | null = null
|
|
|
+ if (activeNotebook.notebook.cellCount > 0) {
|
|
|
+ const cellIndex = activeNotebook.notebook.cellAt(activeNotebook.selection.start).index
|
|
|
+ cellJson = await findMatchingNotebookCell(filePath, cellIndex)
|
|
|
+ }
|
|
|
+
|
|
|
+ return { ...ctx, cellJson }
|
|
|
+ }
|
|
|
+
|
|
|
+ context.subscriptions.push(
|
|
|
+ vscode.commands.registerCommand(
|
|
|
+ commands.JupyterGenerateCell,
|
|
|
+ async (range?: vscode.Range, diagnostics?: vscode.Diagnostic[]) => {
|
|
|
+ const userPrompt = await showJupyterPromptInput(
|
|
|
+ "Generate Notebook Cell",
|
|
|
+ "Enter your prompt for generating notebook cell (press Enter to confirm & Esc to cancel)",
|
|
|
+ )
|
|
|
+ if (!userPrompt) return
|
|
|
+
|
|
|
+ const ctx = await getNotebookCommandContext(range, diagnostics)
|
|
|
+ if (!ctx) return
|
|
|
+
|
|
|
+ const notebookContext = `User prompt: ${userPrompt}
|
|
|
+Insert a new Jupyter notebook cell above or below the current cell based on user prompt.
|
|
|
+${NOTEBOOK_EDIT_INSTRUCTIONS}
|
|
|
+
|
|
|
+Current Notebook Cell Context (JSON, sanitized of image data):
|
|
|
+\`\`\`json
|
|
|
+${ctx.cellJson || "{}"}
|
|
|
+\`\`\``
|
|
|
+
|
|
|
+ await addToCline(ctx.controller, ctx.commandContext, notebookContext)
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ )
|
|
|
+
|
|
|
+ context.subscriptions.push(
|
|
|
+ vscode.commands.registerCommand(
|
|
|
+ commands.JupyterExplainCell,
|
|
|
+ async (range?: vscode.Range, diagnostics?: vscode.Diagnostic[]) => {
|
|
|
+ const ctx = await getNotebookCommandContext(range, diagnostics)
|
|
|
+ if (!ctx) return
|
|
|
+
|
|
|
+ const notebookContext = ctx.cellJson
|
|
|
+ ? `\n\nCurrent Notebook Cell Context (JSON, sanitized of image data):\n\`\`\`json\n${ctx.cellJson}\n\`\`\``
|
|
|
+ : undefined
|
|
|
+
|
|
|
+ await explainWithCline(ctx.controller, ctx.commandContext, notebookContext)
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ )
|
|
|
+
|
|
|
+ context.subscriptions.push(
|
|
|
+ vscode.commands.registerCommand(
|
|
|
+ commands.JupyterImproveCell,
|
|
|
+ async (range?: vscode.Range, diagnostics?: vscode.Diagnostic[]) => {
|
|
|
+ const userPrompt = await showJupyterPromptInput(
|
|
|
+ "Improve Notebook Cell",
|
|
|
+ "Enter your prompt for improving the current notebook cell (press Enter to confirm & Esc to cancel)",
|
|
|
+ )
|
|
|
+ if (!userPrompt) return
|
|
|
+
|
|
|
+ const ctx = await getNotebookCommandContext(range, diagnostics)
|
|
|
+ if (!ctx) return
|
|
|
+
|
|
|
+ const notebookContext = `User prompt: ${userPrompt}
|
|
|
+${NOTEBOOK_EDIT_INSTRUCTIONS}
|
|
|
+
|
|
|
+Current Notebook Cell Context (JSON, sanitized of image data):
|
|
|
+\`\`\`json
|
|
|
+${ctx.cellJson || "{}"}
|
|
|
+\`\`\``
|
|
|
+
|
|
|
+ await improveWithCline(ctx.controller, ctx.commandContext, notebookContext)
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ )
|
|
|
+
|
|
|
// Register the openWalkthrough command handler
|
|
|
context.subscriptions.push(
|
|
|
vscode.commands.registerCommand(commands.Walkthrough, async () => {
|
|
|
@@ -445,6 +546,52 @@ export async function activate(context: vscode.ExtensionContext) {
|
|
|
return createClineAPI(webview.controller)
|
|
|
}
|
|
|
|
|
|
+async function showJupyterPromptInput(title: string, placeholder: string): Promise<string | undefined> {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ const quickPick = vscode.window.createQuickPick()
|
|
|
+ quickPick.title = title
|
|
|
+ quickPick.placeholder = placeholder
|
|
|
+ quickPick.ignoreFocusOut = true
|
|
|
+
|
|
|
+ // Allow free text input
|
|
|
+ quickPick.canSelectMany = false
|
|
|
+
|
|
|
+ let userInput = ""
|
|
|
+
|
|
|
+ quickPick.onDidChangeValue((value) => {
|
|
|
+ userInput = value
|
|
|
+ // Update items to show the current input
|
|
|
+ if (value) {
|
|
|
+ quickPick.items = [
|
|
|
+ {
|
|
|
+ label: "$(check) Use this prompt",
|
|
|
+ detail: value,
|
|
|
+ alwaysShow: true,
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ } else {
|
|
|
+ quickPick.items = []
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ quickPick.onDidAccept(() => {
|
|
|
+ if (userInput) {
|
|
|
+ resolve(userInput)
|
|
|
+ quickPick.hide()
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ quickPick.onDidHide(() => {
|
|
|
+ if (!userInput) {
|
|
|
+ resolve(undefined)
|
|
|
+ }
|
|
|
+ quickPick.dispose()
|
|
|
+ })
|
|
|
+
|
|
|
+ quickPick.show()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
function setupHostProvider(context: ExtensionContext) {
|
|
|
console.log("Setting up vscode host providers...")
|
|
|
|