extension.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // This method is called when your extension is deactivated
  2. export function deactivate() {}
  3. import * as vscode from "vscode"
  4. export function activate(context: vscode.ExtensionContext) {
  5. // Register command to open terminal in split screen and run opencode
  6. let openTerminalDisposable = vscode.commands.registerCommand("opencode.openTerminal", async () => {
  7. // Create a new terminal in split screen
  8. const port = Math.floor(Math.random() * (65535 - 16384 + 1)) + 16384
  9. const terminal = vscode.window.createTerminal({
  10. name: "opencode",
  11. iconPath: {
  12. light: vscode.Uri.file(context.asAbsolutePath("images/button-dark.svg")),
  13. dark: vscode.Uri.file(context.asAbsolutePath("images/button-light.svg")),
  14. },
  15. location: {
  16. viewColumn: vscode.ViewColumn.Beside,
  17. preserveFocus: false,
  18. },
  19. env: {
  20. _EXTENSION_OPENCODE_PORT: port.toString(),
  21. },
  22. })
  23. terminal.show(false)
  24. terminal.sendText(`OPENCODE_THEME=system OPENCODE_CALLER=vscode opencode --port ${port}`)
  25. const fileRef = getActiveFile()
  26. if (!fileRef) return
  27. // Wait for the terminal to be ready
  28. let tries = 10
  29. let connected = false
  30. do {
  31. await new Promise((resolve) => setTimeout(resolve, 200))
  32. try {
  33. await fetch(`http://localhost:${port}/app`)
  34. connected = true
  35. break
  36. } catch (e) {}
  37. tries--
  38. } while (tries > 0)
  39. // If connected, append the prompt to the terminal
  40. if (connected) {
  41. await appendPrompt(port, `In ${fileRef}`)
  42. }
  43. })
  44. // Register command to add filepath to terminal
  45. let addFilepathDisposable = vscode.commands.registerCommand("opencode.addFilepathToTerminal", async () => {
  46. const fileRef = getActiveFile()
  47. if (!fileRef) return
  48. const terminal = vscode.window.activeTerminal
  49. if (!terminal) return
  50. // @ts-ignore
  51. const port = terminal.creationOptions.env?.["_EXTENSION_OPENCODE_PORT"]
  52. if (!port) return
  53. await appendPrompt(parseInt(port), fileRef)
  54. terminal.show()
  55. })
  56. context.subscriptions.push(openTerminalDisposable, addFilepathDisposable)
  57. }
  58. async function appendPrompt(port: number, text: string) {
  59. await fetch(`http://localhost:${port}/tui/append-prompt`, {
  60. method: "POST",
  61. headers: {
  62. "Content-Type": "application/json",
  63. },
  64. body: JSON.stringify({ text }),
  65. })
  66. }
  67. function getActiveFile() {
  68. const activeEditor = vscode.window.activeTextEditor
  69. if (!activeEditor) return
  70. const document = activeEditor.document
  71. const workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri)
  72. if (!workspaceFolder) return
  73. // Get the relative path from workspace root
  74. const relativePath = vscode.workspace.asRelativePath(document.uri)
  75. let filepathWithAt = `@${relativePath}`
  76. // Check if there's a selection and add line numbers
  77. const selection = activeEditor.selection
  78. if (!selection.isEmpty) {
  79. // Convert to 1-based line numbers
  80. const startLine = selection.start.line + 1
  81. const endLine = selection.end.line + 1
  82. if (startLine === endLine) {
  83. // Single line selection
  84. filepathWithAt += `#L${startLine}`
  85. } else {
  86. // Multi-line selection
  87. filepathWithAt += `#L${startLine}-${endLine}`
  88. }
  89. }
  90. return filepathWithAt
  91. }