Skip to content

Commit 517b545

Browse files
authored
Merge pull request #807 from samhvw8/feat/terminal-menu-context
feat: add terminal context menu command
2 parents e0f0aa7 + 679866c commit 517b545

File tree

8 files changed

+259
-1
lines changed

8 files changed

+259
-1
lines changed

package.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,31 @@
123123
"command": "roo-cline.addToContext",
124124
"title": "Roo Code: Add To Context",
125125
"category": "Roo Code"
126+
},
127+
{
128+
"command": "roo-cline.terminalAddToContext",
129+
"title": "Roo Code: Add Terminal Content to Context",
130+
"category": "Terminal"
131+
},
132+
{
133+
"command": "roo-cline.terminalFixCommand",
134+
"title": "Roo Code: Fix This Command",
135+
"category": "Terminal"
136+
},
137+
{
138+
"command": "roo-cline.terminalExplainCommand",
139+
"title": "Roo Code: Explain This Command",
140+
"category": "Terminal"
141+
},
142+
{
143+
"command": "roo-cline.terminalFixCommandInCurrentTask",
144+
"title": "Roo Code: Fix This Command (Current Task)",
145+
"category": "Terminal"
146+
},
147+
{
148+
"command": "roo-cline.terminalExplainCommandInCurrentTask",
149+
"title": "Roo Code: Explain This Command (Current Task)",
150+
"category": "Terminal"
126151
}
127152
],
128153
"menus": {
@@ -148,6 +173,28 @@
148173
"group": "Roo Code@4"
149174
}
150175
],
176+
"terminal/context": [
177+
{
178+
"command": "roo-cline.terminalAddToContext",
179+
"group": "Roo Code@1"
180+
},
181+
{
182+
"command": "roo-cline.terminalFixCommand",
183+
"group": "Roo Code@2"
184+
},
185+
{
186+
"command": "roo-cline.terminalExplainCommand",
187+
"group": "Roo Code@3"
188+
},
189+
{
190+
"command": "roo-cline.terminalFixCommandInCurrentTask",
191+
"group": "Roo Code@5"
192+
},
193+
{
194+
"command": "roo-cline.terminalExplainCommandInCurrentTask",
195+
"group": "Roo Code@6"
196+
}
197+
],
151198
"view/title": [
152199
{
153200
"command": "roo-cline.plusButtonClicked",

src/activate/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export { handleUri } from "./handleUri"
22
export { registerCommands } from "./registerCommands"
33
export { registerCodeActions } from "./registerCodeActions"
4+
export { registerTerminalActions } from "./registerTerminalActions"
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import * as vscode from "vscode"
2+
import { ClineProvider } from "../core/webview/ClineProvider"
3+
import { TerminalManager } from "../integrations/terminal/TerminalManager"
4+
5+
const TERMINAL_COMMAND_IDS = {
6+
ADD_TO_CONTEXT: "roo-cline.terminalAddToContext",
7+
FIX: "roo-cline.terminalFixCommand",
8+
FIX_IN_CURRENT_TASK: "roo-cline.terminalFixCommandInCurrentTask",
9+
EXPLAIN: "roo-cline.terminalExplainCommand",
10+
EXPLAIN_IN_CURRENT_TASK: "roo-cline.terminalExplainCommandInCurrentTask",
11+
} as const
12+
13+
export const registerTerminalActions = (context: vscode.ExtensionContext) => {
14+
const terminalManager = new TerminalManager()
15+
16+
registerTerminalAction(context, terminalManager, TERMINAL_COMMAND_IDS.ADD_TO_CONTEXT, "TERMINAL_ADD_TO_CONTEXT")
17+
18+
registerTerminalActionPair(
19+
context,
20+
terminalManager,
21+
TERMINAL_COMMAND_IDS.FIX,
22+
"TERMINAL_FIX",
23+
"What would you like Roo to fix?",
24+
)
25+
26+
registerTerminalActionPair(
27+
context,
28+
terminalManager,
29+
TERMINAL_COMMAND_IDS.EXPLAIN,
30+
"TERMINAL_EXPLAIN",
31+
"What would you like Roo to explain?",
32+
)
33+
}
34+
35+
const registerTerminalAction = (
36+
context: vscode.ExtensionContext,
37+
terminalManager: TerminalManager,
38+
command: string,
39+
promptType: "TERMINAL_ADD_TO_CONTEXT" | "TERMINAL_FIX" | "TERMINAL_EXPLAIN",
40+
inputPrompt?: string,
41+
) => {
42+
context.subscriptions.push(
43+
vscode.commands.registerCommand(command, async (args: any) => {
44+
let content = args.selection
45+
if (!content || content === "") {
46+
content = await terminalManager.getTerminalContents(promptType === "TERMINAL_ADD_TO_CONTEXT" ? -1 : 1)
47+
}
48+
49+
if (!content) {
50+
vscode.window.showWarningMessage("No terminal content selected")
51+
return
52+
}
53+
54+
const params: Record<string, any> = {
55+
terminalContent: content,
56+
}
57+
58+
if (inputPrompt) {
59+
params.userInput =
60+
(await vscode.window.showInputBox({
61+
prompt: inputPrompt,
62+
})) ?? ""
63+
}
64+
65+
await ClineProvider.handleTerminalAction(command, promptType, params)
66+
}),
67+
)
68+
}
69+
70+
const registerTerminalActionPair = (
71+
context: vscode.ExtensionContext,
72+
terminalManager: TerminalManager,
73+
baseCommand: string,
74+
promptType: "TERMINAL_ADD_TO_CONTEXT" | "TERMINAL_FIX" | "TERMINAL_EXPLAIN",
75+
inputPrompt?: string,
76+
) => {
77+
// Register new task version
78+
registerTerminalAction(context, terminalManager, baseCommand, promptType, inputPrompt)
79+
// Register current task version
80+
registerTerminalAction(context, terminalManager, `${baseCommand}InCurrentTask`, promptType, inputPrompt)
81+
}

src/core/webview/ClineProvider.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,41 @@ export class ClineProvider implements vscode.WebviewViewProvider {
256256
await visibleProvider.initClineWithTask(prompt)
257257
}
258258

259+
public static async handleTerminalAction(
260+
command: string,
261+
promptType: "TERMINAL_ADD_TO_CONTEXT" | "TERMINAL_FIX" | "TERMINAL_EXPLAIN",
262+
params: Record<string, string | any[]>,
263+
): Promise<void> {
264+
const visibleProvider = await ClineProvider.getInstance()
265+
if (!visibleProvider) {
266+
return
267+
}
268+
269+
const { customSupportPrompts } = await visibleProvider.getState()
270+
271+
const prompt = supportPrompt.create(promptType, params, customSupportPrompts)
272+
273+
if (command.endsWith("AddToContext")) {
274+
await visibleProvider.postMessageToWebview({
275+
type: "invoke",
276+
invoke: "setChatBoxMessage",
277+
text: prompt,
278+
})
279+
return
280+
}
281+
282+
if (visibleProvider.cline && command.endsWith("InCurrentTask")) {
283+
await visibleProvider.postMessageToWebview({
284+
type: "invoke",
285+
invoke: "sendMessage",
286+
text: prompt,
287+
})
288+
return
289+
}
290+
291+
await visibleProvider.initClineWithTask(prompt)
292+
}
293+
259294
async resolveWebviewView(webviewView: vscode.WebviewView | vscode.WebviewPanel) {
260295
this.outputChannel.appendLine("Resolving webview view")
261296
this.view = webviewView

src/extension.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { createClineAPI } from "./exports"
55
import "./utils/path" // Necessary to have access to String.prototype.toPosix.
66
import { CodeActionProvider } from "./core/CodeActionProvider"
77
import { DIFF_VIEW_URI_SCHEME } from "./integrations/editor/DiffViewProvider"
8-
import { handleUri, registerCommands, registerCodeActions } from "./activate"
8+
import { handleUri, registerCommands, registerCodeActions, registerTerminalActions } from "./activate"
99

1010
/**
1111
* Built using https://github.com/microsoft/vscode-webview-ui-toolkit
@@ -78,6 +78,7 @@ export function activate(context: vscode.ExtensionContext) {
7878
)
7979

8080
registerCodeActions(context)
81+
registerTerminalActions(context)
8182

8283
return createClineAPI(outputChannel, sidebarProvider)
8384
}

src/integrations/terminal/TerminalActions.ts

Whitespace-only changes.

src/integrations/terminal/TerminalManager.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,57 @@ export class TerminalManager {
224224
this.disposables.forEach((disposable) => disposable.dispose())
225225
this.disposables = []
226226
}
227+
228+
/**
229+
* Gets the terminal contents based on the number of commands to include
230+
* @param commands Number of previous commands to include (-1 for all)
231+
* @returns The selected terminal contents
232+
*/
233+
public async getTerminalContents(commands = -1): Promise<string> {
234+
// Save current clipboard content
235+
const tempCopyBuffer = await vscode.env.clipboard.readText()
236+
237+
try {
238+
// Select terminal content
239+
if (commands < 0) {
240+
await vscode.commands.executeCommand("workbench.action.terminal.selectAll")
241+
} else {
242+
for (let i = 0; i < commands; i++) {
243+
await vscode.commands.executeCommand("workbench.action.terminal.selectToPreviousCommand")
244+
}
245+
}
246+
247+
// Copy selection and clear it
248+
await vscode.commands.executeCommand("workbench.action.terminal.copySelection")
249+
await vscode.commands.executeCommand("workbench.action.terminal.clearSelection")
250+
251+
// Get copied content
252+
let terminalContents = (await vscode.env.clipboard.readText()).trim()
253+
254+
// Restore original clipboard content
255+
await vscode.env.clipboard.writeText(tempCopyBuffer)
256+
257+
if (tempCopyBuffer === terminalContents) {
258+
// No terminal content was copied
259+
return ""
260+
}
261+
262+
// Process multi-line content
263+
const lines = terminalContents.split("\n")
264+
const lastLine = lines.pop()?.trim()
265+
if (lastLine) {
266+
let i = lines.length - 1
267+
while (i >= 0 && !lines[i].trim().startsWith(lastLine)) {
268+
i--
269+
}
270+
terminalContents = lines.slice(Math.max(i, 0)).join("\n")
271+
}
272+
273+
return terminalContents
274+
} catch (error) {
275+
// Ensure clipboard is restored even if an error occurs
276+
await vscode.env.clipboard.writeText(tempCopyBuffer)
277+
throw error
278+
}
279+
}
227280
}

src/shared/support-prompt.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,46 @@ Provide the improved code along with explanations for each enhancement.`,
101101
\${selectedText}
102102
\`\`\``,
103103
},
104+
TERMINAL_ADD_TO_CONTEXT: {
105+
label: "Add Terminal Content to Context",
106+
description:
107+
"Add terminal output to your current task or conversation. Useful for providing command outputs or logs. Available in the terminal context menu (right-click on selected terminal content).",
108+
template: `\${userInput}
109+
Terminal output:
110+
\`\`\`
111+
\${terminalContent}
112+
\`\`\``,
113+
},
114+
TERMINAL_FIX: {
115+
label: "Fix Terminal Command",
116+
description:
117+
"Get help fixing terminal commands that failed or need improvement. Available in the terminal context menu (right-click on selected terminal content).",
118+
template: `\${userInput}
119+
Fix this terminal command:
120+
\`\`\`
121+
\${terminalContent}
122+
\`\`\`
123+
124+
Please:
125+
1. Identify any issues in the command
126+
2. Provide the corrected command
127+
3. Explain what was fixed and why`,
128+
},
129+
TERMINAL_EXPLAIN: {
130+
label: "Explain Terminal Command",
131+
description:
132+
"Get detailed explanations of terminal commands and their outputs. Available in the terminal context menu (right-click on selected terminal content).",
133+
template: `\${userInput}
134+
Explain this terminal command:
135+
\`\`\`
136+
\${terminalContent}
137+
\`\`\`
138+
139+
Please provide:
140+
1. What the command does
141+
2. Explanation of each part/flag
142+
3. Expected output and behavior`,
143+
},
104144
} as const
105145

106146
type SupportPromptType = keyof typeof supportPromptConfigs

0 commit comments

Comments
 (0)