-
Notifications
You must be signed in to change notification settings - Fork 210
/
CommandsController.ts
79 lines (67 loc) · 2.94 KB
/
CommandsController.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import type * as vscode from 'vscode'
import { logDebug } from '../log'
import type { CodyCommandArgs } from './types'
import { CommandRunner } from './services/runner'
import type { CommandsProvider } from './services/provider'
import type { CommandResult } from '../main'
/**
* Handles commands execution with commands from CommandsProvider
* Provides additional prompt management and execution logic
*/
class CommandsController implements vscode.Disposable {
private disposables: vscode.Disposable[] = []
// Provider of default commands and custom commands
private provider: CommandsProvider | undefined
public init(provider?: CommandsProvider) {
if (provider) {
this.provider = provider
this.disposables.push(this.provider)
}
}
/**
* Executes a Cody command from user input text and command args.
*
* Handles prompt building and context fetching for commands.
*/
public async execute(text: string, args: CodyCommandArgs): Promise<CommandResult | undefined> {
const commandSplit = text.split(' ')
// The unique key for the command. e.g. /test
const commandKey = commandSplit.shift() || text
const command = this.provider?.get(commandKey)
if (!command) {
logDebug('CommandsController:execute', 'command not found', { verbose: { commandKey } })
return undefined
}
// Additional instruction that will be added to end of prompt in the custom command prompt
// It's added at execution time to allow dynamic arguments
// E.g. if the command is `/edit replace dash with period`,
// the additionalInput is `replace dash with period`
const additionalArgs = commandKey === text ? '' : commandSplit.join(' ')
command.prompt = [command.prompt, additionalArgs].join(' ')?.trim()
// Add shell output as context if any before passing to the runner
const shell = command.context?.command
if (shell) {
const contextFile = await this.provider?.runShell(shell)
args.userContextFiles = contextFile
}
return new CommandRunner(command, args).start()
}
public dispose(): void {
for (const disposable of this.disposables) {
disposable.dispose()
}
this.disposables = []
logDebug('CommandsController:dispose', 'disposed')
}
}
/**
* A aingleton instance of the CommandsController class.
* Activate on extension activation that will initialize the CommandsProvider.
*/
const controller = new CommandsController()
export const setCommandController = (provider?: CommandsProvider) => controller.init(provider)
/**
* Binds the execute method of the CommandsController instance to be exported as a constant function.
* This allows the execute method to be called without needing a reference to the controller instance.
*/
export const executeCodyCommand = controller.execute.bind(controller)