feat: add openTabsAtEndOfList setting to control tab placement

- Add openTabsAtEndOfList setting to global-settings schema with default value false
- Update ClineProvider to include the setting in state management
- Modify DiffViewProvider to use ViewColumn.Beside when setting is enabled
- Add test coverage for the new setting

Fixes #6006
This commit is contained in:
Roo Code 2025-07-21 12:45:43 +00:00
parent 9fce90be9d
commit 31c9f70afd
5 changed files with 54 additions and 10 deletions

View file

@ -22,4 +22,8 @@ describe("GLOBAL_STATE_KEYS", () => {
it("should not contain OpenAI Compatible API key (secret)", () => {
expect(GLOBAL_STATE_KEYS).not.toContain("codebaseIndexOpenAiCompatibleApiKey")
})
it("should contain openTabsAtEndOfList setting", () => {
expect(GLOBAL_STATE_KEYS).toContain("openTabsAtEndOfList")
})
})

View file

@ -108,6 +108,7 @@ export const globalSettingsSchema = z.object({
rateLimitSeconds: z.number().optional(),
diffEnabled: z.boolean().optional(),
fuzzyMatchThreshold: z.number().optional(),
openTabsAtEndOfList: z.boolean().optional(),
experiments: experimentsSchema.optional(),
codebaseIndexModels: codebaseIndexModelsSchema.optional(),
@ -251,6 +252,7 @@ export const EVALS_SETTINGS: RooCodeSettings = {
diffEnabled: true,
fuzzyMatchThreshold: 1,
openTabsAtEndOfList: false,
enableCheckpoints: false,

View file

@ -260,7 +260,21 @@ export class Task extends EventEmitter<ClineEvents> {
this.consecutiveMistakeLimit = consecutiveMistakeLimit ?? DEFAULT_CONSECUTIVE_MISTAKE_LIMIT
this.providerRef = new WeakRef(provider)
this.globalStoragePath = provider.context.globalStorageUri.fsPath
this.diffViewProvider = new DiffViewProvider(this.cwd)
// Get openTabsAtEndOfList setting asynchronously
provider
.getState()
.then((state) => {
const openTabsAtEndOfList = state?.openTabsAtEndOfList ?? false
this.diffViewProvider = new DiffViewProvider(this.cwd, openTabsAtEndOfList)
})
.catch((error) => {
console.error("Failed to get openTabsAtEndOfList setting:", error)
this.diffViewProvider = new DiffViewProvider(this.cwd, false)
})
// Initialize with default value for immediate use
this.diffViewProvider = new DiffViewProvider(this.cwd, false)
this.enableCheckpoints = enableCheckpoints
this.rootTask = rootTask

View file

@ -1440,6 +1440,7 @@ export class ClineProvider
alwaysAllowFollowupQuestions,
followupAutoApproveTimeoutMs,
diagnosticsEnabled,
openTabsAtEndOfList,
} = await this.getState()
const telemetryKey = process.env.POSTHOG_API_KEY
@ -1561,6 +1562,7 @@ export class ClineProvider
alwaysAllowFollowupQuestions: alwaysAllowFollowupQuestions ?? false,
followupAutoApproveTimeoutMs: followupAutoApproveTimeoutMs ?? 60000,
diagnosticsEnabled: diagnosticsEnabled ?? true,
openTabsAtEndOfList: openTabsAtEndOfList ?? false,
}
}
@ -1726,6 +1728,7 @@ export class ClineProvider
codebaseIndexSearchMinScore: stateValues.codebaseIndexConfig?.codebaseIndexSearchMinScore,
},
profileThresholds: stateValues.profileThresholds ?? {},
openTabsAtEndOfList: stateValues.openTabsAtEndOfList ?? false,
}
}

View file

@ -36,8 +36,14 @@ export class DiffViewProvider {
private activeLineController?: DecorationController
private streamedLines: string[] = []
private preDiagnostics: [vscode.Uri, vscode.Diagnostic[]][] = []
private openTabsAtEndOfList: boolean
constructor(private cwd: string) {}
constructor(
private cwd: string,
openTabsAtEndOfList: boolean = false,
) {
this.openTabsAtEndOfList = openTabsAtEndOfList
}
async open(relPath: string): Promise<void> {
this.relPath = relPath
@ -181,7 +187,10 @@ export class DiffViewProvider {
}
}
async saveChanges(diagnosticsEnabled: boolean = true, writeDelayMs: number = DEFAULT_WRITE_DELAY_MS): Promise<{
async saveChanges(
diagnosticsEnabled: boolean = true,
writeDelayMs: number = DEFAULT_WRITE_DELAY_MS,
): Promise<{
newProblemsMessage: string | undefined
userEdits: string | undefined
finalContent: string | undefined
@ -198,7 +207,11 @@ export class DiffViewProvider {
await updatedDocument.save()
}
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), { preview: false, preserveFocus: true })
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), {
preview: false,
preserveFocus: true,
viewColumn: this.openTabsAtEndOfList ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active,
})
await this.closeAllDiffViews()
// Getting diagnostics before and after the file edit is a better approach than
@ -216,22 +229,22 @@ export class DiffViewProvider {
// and can address them accordingly. If problems don't change immediately after
// applying a fix, won't be notified, which is generally fine since the
// initial fix is usually correct and it may just take time for linters to catch up.
let newProblemsMessage = ""
if (diagnosticsEnabled) {
// Add configurable delay to allow linters time to process and clean up issues
// like unused imports (especially important for Go and other languages)
// Ensure delay is non-negative
const safeDelayMs = Math.max(0, writeDelayMs)
try {
await delay(safeDelayMs)
} catch (error) {
// Log error but continue - delay failure shouldn't break the save operation
console.warn(`Failed to apply write delay: ${error}`)
}
const postDiagnostics = vscode.languages.getDiagnostics()
const newProblems = await diagnosticsToProblemsString(
@ -391,6 +404,7 @@ export class DiffViewProvider {
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), {
preview: false,
preserveFocus: true,
viewColumn: this.openTabsAtEndOfList ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active,
})
}
@ -523,7 +537,11 @@ export class DiffViewProvider {
// Pre-open the file as a text document to ensure it doesn't open in preview mode
// This fixes issues with files that have custom editor associations (like markdown preview)
vscode.window
.showTextDocument(uri, { preview: false, viewColumn: vscode.ViewColumn.Active, preserveFocus: true })
.showTextDocument(uri, {
preview: false,
viewColumn: this.openTabsAtEndOfList ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active,
preserveFocus: true,
})
.then(() => {
// Execute the diff command after ensuring the file is open as text
return vscode.commands.executeCommand(
@ -533,7 +551,10 @@ export class DiffViewProvider {
}),
uri,
`${fileName}: ${fileExists ? `${DIFF_VIEW_LABEL_CHANGES}` : "New File"} (Editable)`,
{ preserveFocus: true },
{
preserveFocus: true,
viewColumn: this.openTabsAtEndOfList ? vscode.ViewColumn.Beside : undefined,
},
)
})
.then(