Merge pull request #714 from RooVetGit/opened_tabs_and_selection_mentions

Mention shortcuts to open tabs
This commit is contained in:
Matt Rubens
2025-02-01 12:23:39 -05:00
committed by GitHub
13 changed files with 117 additions and 222 deletions

View File

@@ -5,9 +5,25 @@ const vscode = {
createTextEditorDecorationType: jest.fn().mockReturnValue({
dispose: jest.fn(),
}),
tabGroups: {
onDidChangeTabs: jest.fn(() => {
return {
dispose: jest.fn(),
}
}),
all: [],
},
},
workspace: {
onDidSaveTextDocument: jest.fn(),
createFileSystemWatcher: jest.fn().mockReturnValue({
onDidCreate: jest.fn().mockReturnValue({ dispose: jest.fn() }),
onDidDelete: jest.fn().mockReturnValue({ dispose: jest.fn() }),
dispose: jest.fn(),
}),
fs: {
stat: jest.fn(),
},
},
Disposable: class {
dispose() {}
@@ -57,6 +73,17 @@ const vscode = {
Development: 2,
Test: 3,
},
FileType: {
Unknown: 0,
File: 1,
Directory: 2,
SymbolicLink: 64,
},
TabInputText: class {
constructor(uri) {
this.uri = uri
}
},
}
module.exports = vscode

View File

@@ -128,6 +128,7 @@ jest.mock("vscode", () => {
visibleTextEditors: [mockTextEditor],
tabGroups: {
all: [mockTabGroup],
onDidChangeTabs: jest.fn(() => ({ dispose: jest.fn() })),
},
},
workspace: {

View File

@@ -2,6 +2,7 @@ import * as vscode from "vscode"
import * as path from "path"
import { listFiles } from "../../services/glob/list-files"
import { ClineProvider } from "../../core/webview/ClineProvider"
import { toRelativePath } from "../../utils/path"
const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0)
const MAX_INITIAL_FILES = 1_000
@@ -48,6 +49,23 @@ class WorkspaceTracker {
)
this.disposables.push(watcher)
this.disposables.push(vscode.window.tabGroups.onDidChangeTabs(() => this.workspaceDidUpdate()))
}
private getOpenedTabsInfo() {
return vscode.window.tabGroups.all.flatMap((group) =>
group.tabs
.filter((tab) => tab.input instanceof vscode.TabInputText)
.map((tab) => {
const path = (tab.input as vscode.TabInputText).uri.fsPath
return {
label: tab.label,
isActive: tab.isActive,
path: toRelativePath(path, cwd || ""),
}
}),
)
}
private workspaceDidUpdate() {
@@ -59,12 +77,12 @@ class WorkspaceTracker {
if (!cwd) {
return
}
const relativeFilePaths = Array.from(this.filePaths).map((file) => toRelativePath(file, cwd))
this.providerRef.deref()?.postMessageToWebview({
type: "workspaceUpdated",
filePaths: Array.from(this.filePaths).map((file) => {
const relativePath = path.relative(cwd, file).toPosix()
return file.endsWith("/") ? relativePath + "/" : relativePath
}),
filePaths: relativeFilePaths,
openedTabs: this.getOpenedTabsInfo(),
})
this.updateTimer = null
}, 300) // Debounce for 300ms

View File

@@ -16,6 +16,12 @@ const mockWatcher = {
}
jest.mock("vscode", () => ({
window: {
tabGroups: {
onDidChangeTabs: jest.fn(() => ({ dispose: jest.fn() })),
all: [],
},
},
workspace: {
workspaceFolders: [
{
@@ -61,6 +67,7 @@ describe("WorkspaceTracker", () => {
expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({
type: "workspaceUpdated",
filePaths: expect.arrayContaining(["file1.ts", "file2.ts"]),
openedTabs: [],
})
expect((mockProvider.postMessageToWebview as jest.Mock).mock.calls[0][0].filePaths).toHaveLength(2)
})
@@ -74,6 +81,7 @@ describe("WorkspaceTracker", () => {
expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({
type: "workspaceUpdated",
filePaths: ["newfile.ts"],
openedTabs: [],
})
})
@@ -92,6 +100,7 @@ describe("WorkspaceTracker", () => {
expect(mockProvider.postMessageToWebview).toHaveBeenLastCalledWith({
type: "workspaceUpdated",
filePaths: [],
openedTabs: [],
})
})
@@ -106,6 +115,7 @@ describe("WorkspaceTracker", () => {
expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({
type: "workspaceUpdated",
filePaths: expect.arrayContaining(["newdir"]),
openedTabs: [],
})
const lastCall = (mockProvider.postMessageToWebview as jest.Mock).mock.calls.slice(-1)[0]
expect(lastCall[0].filePaths).toHaveLength(1)
@@ -126,6 +136,7 @@ describe("WorkspaceTracker", () => {
expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({
type: "workspaceUpdated",
filePaths: expect.arrayContaining(expectedFiles),
openedTabs: [],
})
expect(calls[0][0].filePaths).toHaveLength(1000)

View File

@@ -57,6 +57,11 @@ export interface ExtensionMessage {
lmStudioModels?: string[]
vsCodeLmModels?: { vendor?: string; family?: string; version?: string; id?: string }[]
filePaths?: string[]
openedTabs?: Array<{
label: string
isActive: boolean
path?: string
}>
partialMessage?: ClineMessage
glamaModels?: Record<string, ModelInfo>
openRouterModels?: Record<string, ModelInfo>

View File

@@ -99,3 +99,8 @@ export function getReadablePath(cwd: string, relPath?: string): string {
}
}
}
export const toRelativePath = (filePath: string, cwd: string) => {
const relativePath = path.relative(cwd, filePath).toPosix()
return filePath.endsWith("/") ? relativePath + "/" : relativePath
}