Compare commits

...

6 Commits

Author SHA1 Message Date
Andrei Edell d8730614f4 remove unused metadata import 2025-06-30 17:58:47 -07:00
Andrei Edell 261b0cb2ff also document_uri -> document_path 2025-06-30 17:41:33 -07:00
Andrei Edell 13ba784ec1 prefer paths over URI based on chats with sjf 2025-06-30 17:28:40 -07:00
Andrei Edell 9601e633b3 sjf review cleanups 2025-06-30 13:51:45 -07:00
Andrei Edell ec9f7b1a84 format fix 2025-06-30 12:47:00 -07:00
Andrei Edell 15925c5aea showTextDocument host bridge 2025-06-30 12:41:29 -07:00
13 changed files with 125 additions and 18 deletions
+2 -1
View File
@@ -7,6 +7,7 @@ tmp
*.vsix
.DS_Store
.idea
pnpm-lock.yaml
@@ -37,4 +38,4 @@ src/hosts/vscode/*/methods.ts
src/hosts/vscode/*/index.ts
src/hosts/vscode/client/host-grpc-client.ts
src/hosts/vscode/host-grpc-service-config.ts
src/standalone/server-setup.ts
src/standalone/server-setup.ts
+1
View File
@@ -26,5 +26,6 @@ export const hostServiceNameMap = {
watch: "host.WatchService",
workspace: "host.WorkspaceService",
env: "host.EnvService",
window: "host.WindowService",
// Add new host services here
}
+32
View File
@@ -0,0 +1,32 @@
syntax = "proto3";
package host;
option java_package = "bot.cline.host.proto";
option java_multiple_files = true;
import "common.proto";
// Provides methods for working with IDE windows and editors.
service WindowService {
// Opens a text document in the editor and returns editor information.
rpc showTextDocument(ShowTextDocumentRequest) returns (TextEditorInfo);
}
message ShowTextDocumentRequest {
cline.Metadata metadata = 1;
string path = 2;
optional ShowTextDocumentOptions options = 3;
}
// See https://code.visualstudio.com/api/references/vscode-api#TextDocumentShowOptions
message ShowTextDocumentOptions {
optional bool preview = 1;
optional bool preserve_focus = 2;
optional int32 view_column = 3;
}
message TextEditorInfo {
string document_path = 1;
optional int32 view_column = 2;
bool is_active = 3;
}
+1 -2
View File
@@ -3,7 +3,7 @@ import { RelativePathsRequest, RelativePaths } from "@shared/proto/file"
import { FileMethodHandler } from "./index"
import * as vscode from "vscode"
import * as path from "path"
import { Metadata, StringRequest } from "@shared/proto/common"
import { StringRequest } from "@shared/proto/common"
import { getHostBridgeProvider } from "@hosts/host-providers"
/**
@@ -22,7 +22,6 @@ export const getRelativePaths: FileMethodHandler = async (
// Use the host URI service client instead of directly using vscode.Uri.parse
const parseResponse = await getHostBridgeProvider().uriServiceClient.parse(
StringRequest.create({
metadata: Metadata.create({}),
value: uriString,
}),
)
+2
View File
@@ -3,6 +3,7 @@ import {
WatchServiceClientInterface,
WorkspaceServiceClientInterface,
EnvServiceClientInterface,
WindowServiceClientInterface,
} from "@generated/hosts/host-bridge-client-types"
/**
@@ -13,6 +14,7 @@ export interface HostBridgeClientProvider {
watchServiceClient: WatchServiceClientInterface
workspaceClient: WorkspaceServiceClientInterface
envClient: EnvServiceClientInterface
windowClient: WindowServiceClientInterface
}
/**
@@ -7,4 +7,5 @@ export const vscodeHostBridgeClient: HostBridgeClientProvider = {
watchServiceClient: createGrpcClient(host.WatchServiceDefinition),
workspaceClient: createGrpcClient(host.WorkspaceServiceDefinition),
envClient: createGrpcClient(host.EnvServiceDefinition),
windowClient: createGrpcClient(host.WindowServiceDefinition),
}
@@ -0,0 +1,26 @@
import * as vscode from "vscode"
import { ShowTextDocumentRequest, TextEditorInfo } from "@/shared/proto/host/window"
export async function showTextDocument(request: ShowTextDocumentRequest): Promise<TextEditorInfo> {
// Convert file path to URI
const uri = vscode.Uri.file(request.path)
const options: vscode.TextDocumentShowOptions = {}
if (request.options?.preview !== undefined) {
options.preview = request.options.preview
}
if (request.options?.preserveFocus !== undefined) {
options.preserveFocus = request.options.preserveFocus
}
if (request.options?.viewColumn !== undefined) {
options.viewColumn = request.options.viewColumn
}
const editor = await vscode.window.showTextDocument(uri, options)
return TextEditorInfo.create({
documentPath: editor.document.uri.fsPath,
viewColumn: editor.viewColumn,
isActive: vscode.window.activeTextEditor === editor,
})
}
+33 -11
View File
@@ -9,6 +9,8 @@ import * as diff from "diff"
import { diagnosticsToProblemsString, getNewDiagnostics } from "../diagnostics"
import { detectEncoding } from "../misc/extract-text"
import * as iconv from "iconv-lite"
import { getHostBridgeProvider } from "@/hosts/host-providers"
import { ShowTextDocumentRequest, ShowTextDocumentOptions, TextEditorInfo } from "@/shared/proto/host/window"
export const DIFF_VIEW_URI_SCHEME = "cline-diff"
@@ -236,10 +238,15 @@ export class DiffViewProvider {
// get text after save in case there is any auto-formatting done by the editor
const postSaveContent = updatedDocument.getText()
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), {
preview: false,
preserveFocus: true,
})
await getHostBridgeProvider().windowClient.showTextDocument(
ShowTextDocumentRequest.create({
path: absolutePath,
options: ShowTextDocumentOptions.create({
preview: false,
preserveFocus: true,
}),
}),
)
await this.closeAllDiffViews()
/*
@@ -337,10 +344,15 @@ export class DiffViewProvider {
await updatedDocument.save()
console.log(`File ${absolutePath} has been reverted to its original content.`)
if (this.documentWasOpen) {
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), {
preview: false,
preserveFocus: true,
})
await getHostBridgeProvider().windowClient.showTextDocument(
ShowTextDocumentRequest.create({
path: absolutePath,
options: ShowTextDocumentOptions.create({
preview: false,
preserveFocus: true,
}),
}),
)
}
await this.closeAllDiffViews()
}
@@ -376,9 +388,19 @@ export class DiffViewProvider {
arePathsEqual(tab.input.modified.fsPath, uri.fsPath),
)
if (diffTab && diffTab.input instanceof vscode.TabInputTextDiff) {
const editor = await vscode.window.showTextDocument(diffTab.input.modified, {
preserveFocus: true,
})
const editorInfo = await getHostBridgeProvider().windowClient.showTextDocument(
ShowTextDocumentRequest.create({
path: diffTab.input.modified.fsPath,
options: ShowTextDocumentOptions.create({
preserveFocus: true,
}),
}),
)
// Find the editor that matches the returned path
const editor = vscode.window.visibleTextEditors.find((e) => e.document.uri.fsPath === editorInfo.documentPath)
if (!editor) {
throw new Error("Failed to find opened text editor")
}
return editor
}
// Open new diff editor
@@ -1,6 +1,8 @@
import * as vscode from "vscode"
import { getWorkingState } from "@utils/git"
import { writeTextToClipboard } from "@utils/env"
import { getHostBridgeProvider } from "@/hosts/host-providers"
import { ShowTextDocumentRequest } from "@/shared/proto/host/window"
/**
* Formats the git diff into a prompt for the AI
@@ -130,6 +132,10 @@ async function editCommitMessage(message: string): Promise<void> {
language: "markdown",
})
await vscode.window.showTextDocument(document)
await getHostBridgeProvider().windowClient.showTextDocument(
ShowTextDocumentRequest.create({
path: document.uri.fsPath,
}),
)
vscode.window.showInformationMessage("Edit the commit message and copy when ready")
}
+8 -1
View File
@@ -2,6 +2,8 @@ import { Anthropic } from "@anthropic-ai/sdk"
import os from "os"
import * as path from "path"
import * as vscode from "vscode"
import { getHostBridgeProvider } from "@/hosts/host-providers"
import { ShowTextDocumentRequest, ShowTextDocumentOptions } from "@/shared/proto/host/window"
export async function downloadTask(dateTs: number, conversationHistory: Anthropic.MessageParam[]) {
// File name
@@ -38,7 +40,12 @@ export async function downloadTask(dateTs: number, conversationHistory: Anthropi
try {
// Write content to the selected location
await vscode.workspace.fs.writeFile(saveUri, new TextEncoder().encode(markdownContent))
vscode.window.showTextDocument(saveUri, { preview: true })
await getHostBridgeProvider().windowClient.showTextDocument(
ShowTextDocumentRequest.create({
path: saveUri.fsPath,
options: ShowTextDocumentOptions.create({ preview: true }),
}),
)
} catch (error) {
vscode.window.showErrorMessage(
`Failed to save markdown file: ${error instanceof Error ? error.message : String(error)}`,
+8 -1
View File
@@ -2,6 +2,8 @@ import * as path from "path"
import * as os from "os"
import * as vscode from "vscode"
import { arePathsEqual } from "@utils/path"
import { getHostBridgeProvider } from "@/hosts/host-providers"
import { ShowTextDocumentRequest, ShowTextDocumentOptions } from "@/shared/proto/host/window"
export async function openImage(dataUri: string) {
const matches = dataUri.match(/^data:image\/([a-zA-Z]+);base64,(.+)$/)
@@ -42,7 +44,12 @@ export async function openFile(absolutePath: string) {
} catch {} // not essential, sometimes tab operations fail
const document = await vscode.workspace.openTextDocument(uri)
await vscode.window.showTextDocument(document, { preview: false })
await getHostBridgeProvider().windowClient.showTextDocument(
ShowTextDocumentRequest.create({
path: document.uri.fsPath,
options: ShowTextDocumentOptions.create({ preview: false }),
}),
)
} catch (error) {
vscode.window.showErrorMessage(`Could not open file!`)
}
-1
View File
@@ -139,7 +139,6 @@ export class McpHub {
console.log("[DEBUG] subscribing to mcp file changes")
const cancelSubscription = getHostBridgeProvider().watchServiceClient.subscribeToFile(
SubscribeToFileRequest.create({
metadata: Metadata.create({}),
path: settingsPath,
}),
{
@@ -4,12 +4,14 @@ import {
WatchServiceClientImpl,
WorkspaceServiceClientImpl,
EnvServiceClientImpl,
WindowServiceClientImpl,
} from "@generated/standalone/host-bridge-clients"
import {
UriServiceClientInterface,
WatchServiceClientInterface,
WorkspaceServiceClientInterface,
EnvServiceClientInterface,
WindowServiceClientInterface,
} from "@generated/hosts/host-bridge-client-types"
import { HostBridgeClientProvider } from "@/hosts/host-provider-types"
@@ -23,6 +25,7 @@ export class ExternalHostBridgeClientManager implements HostBridgeClientProvider
watchServiceClient: WatchServiceClientInterface
workspaceClient: WorkspaceServiceClientInterface
envClient: EnvServiceClientInterface
windowClient: WindowServiceClientInterface
constructor() {
const address = process.env.HOST_BRIDGE_ADDRESS || "localhost:50052"
@@ -32,6 +35,7 @@ export class ExternalHostBridgeClientManager implements HostBridgeClientProvider
this.watchServiceClient = new WatchServiceClientImpl(this.channel)
this.workspaceClient = new WorkspaceServiceClientImpl(this.channel)
this.envClient = new EnvServiceClientImpl(this.channel)
this.windowClient = new WindowServiceClientImpl(this.channel)
}
public close(): void {