Skip to content

Commit 31c9f70

Browse files
committed
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
1 parent 9fce90b commit 31c9f70

File tree

5 files changed

+54
-10
lines changed

5 files changed

+54
-10
lines changed

packages/types/src/__tests__/index.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,8 @@ describe("GLOBAL_STATE_KEYS", () => {
2222
it("should not contain OpenAI Compatible API key (secret)", () => {
2323
expect(GLOBAL_STATE_KEYS).not.toContain("codebaseIndexOpenAiCompatibleApiKey")
2424
})
25+
26+
it("should contain openTabsAtEndOfList setting", () => {
27+
expect(GLOBAL_STATE_KEYS).toContain("openTabsAtEndOfList")
28+
})
2529
})

packages/types/src/global-settings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ export const globalSettingsSchema = z.object({
108108
rateLimitSeconds: z.number().optional(),
109109
diffEnabled: z.boolean().optional(),
110110
fuzzyMatchThreshold: z.number().optional(),
111+
openTabsAtEndOfList: z.boolean().optional(),
111112
experiments: experimentsSchema.optional(),
112113

113114
codebaseIndexModels: codebaseIndexModelsSchema.optional(),
@@ -251,6 +252,7 @@ export const EVALS_SETTINGS: RooCodeSettings = {
251252

252253
diffEnabled: true,
253254
fuzzyMatchThreshold: 1,
255+
openTabsAtEndOfList: false,
254256

255257
enableCheckpoints: false,
256258

src/core/task/Task.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,21 @@ export class Task extends EventEmitter<ClineEvents> {
260260
this.consecutiveMistakeLimit = consecutiveMistakeLimit ?? DEFAULT_CONSECUTIVE_MISTAKE_LIMIT
261261
this.providerRef = new WeakRef(provider)
262262
this.globalStoragePath = provider.context.globalStorageUri.fsPath
263-
this.diffViewProvider = new DiffViewProvider(this.cwd)
263+
264+
// Get openTabsAtEndOfList setting asynchronously
265+
provider
266+
.getState()
267+
.then((state) => {
268+
const openTabsAtEndOfList = state?.openTabsAtEndOfList ?? false
269+
this.diffViewProvider = new DiffViewProvider(this.cwd, openTabsAtEndOfList)
270+
})
271+
.catch((error) => {
272+
console.error("Failed to get openTabsAtEndOfList setting:", error)
273+
this.diffViewProvider = new DiffViewProvider(this.cwd, false)
274+
})
275+
276+
// Initialize with default value for immediate use
277+
this.diffViewProvider = new DiffViewProvider(this.cwd, false)
264278
this.enableCheckpoints = enableCheckpoints
265279

266280
this.rootTask = rootTask

src/core/webview/ClineProvider.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,7 @@ export class ClineProvider
14401440
alwaysAllowFollowupQuestions,
14411441
followupAutoApproveTimeoutMs,
14421442
diagnosticsEnabled,
1443+
openTabsAtEndOfList,
14431444
} = await this.getState()
14441445

14451446
const telemetryKey = process.env.POSTHOG_API_KEY
@@ -1561,6 +1562,7 @@ export class ClineProvider
15611562
alwaysAllowFollowupQuestions: alwaysAllowFollowupQuestions ?? false,
15621563
followupAutoApproveTimeoutMs: followupAutoApproveTimeoutMs ?? 60000,
15631564
diagnosticsEnabled: diagnosticsEnabled ?? true,
1565+
openTabsAtEndOfList: openTabsAtEndOfList ?? false,
15641566
}
15651567
}
15661568

@@ -1726,6 +1728,7 @@ export class ClineProvider
17261728
codebaseIndexSearchMinScore: stateValues.codebaseIndexConfig?.codebaseIndexSearchMinScore,
17271729
},
17281730
profileThresholds: stateValues.profileThresholds ?? {},
1731+
openTabsAtEndOfList: stateValues.openTabsAtEndOfList ?? false,
17291732
}
17301733
}
17311734

src/integrations/editor/DiffViewProvider.ts

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,14 @@ export class DiffViewProvider {
3636
private activeLineController?: DecorationController
3737
private streamedLines: string[] = []
3838
private preDiagnostics: [vscode.Uri, vscode.Diagnostic[]][] = []
39+
private openTabsAtEndOfList: boolean
3940

40-
constructor(private cwd: string) {}
41+
constructor(
42+
private cwd: string,
43+
openTabsAtEndOfList: boolean = false,
44+
) {
45+
this.openTabsAtEndOfList = openTabsAtEndOfList
46+
}
4147

4248
async open(relPath: string): Promise<void> {
4349
this.relPath = relPath
@@ -181,7 +187,10 @@ export class DiffViewProvider {
181187
}
182188
}
183189

184-
async saveChanges(diagnosticsEnabled: boolean = true, writeDelayMs: number = DEFAULT_WRITE_DELAY_MS): Promise<{
190+
async saveChanges(
191+
diagnosticsEnabled: boolean = true,
192+
writeDelayMs: number = DEFAULT_WRITE_DELAY_MS,
193+
): Promise<{
185194
newProblemsMessage: string | undefined
186195
userEdits: string | undefined
187196
finalContent: string | undefined
@@ -198,7 +207,11 @@ export class DiffViewProvider {
198207
await updatedDocument.save()
199208
}
200209

201-
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), { preview: false, preserveFocus: true })
210+
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), {
211+
preview: false,
212+
preserveFocus: true,
213+
viewColumn: this.openTabsAtEndOfList ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active,
214+
})
202215
await this.closeAllDiffViews()
203216

204217
// Getting diagnostics before and after the file edit is a better approach than
@@ -216,22 +229,22 @@ export class DiffViewProvider {
216229
// and can address them accordingly. If problems don't change immediately after
217230
// applying a fix, won't be notified, which is generally fine since the
218231
// initial fix is usually correct and it may just take time for linters to catch up.
219-
232+
220233
let newProblemsMessage = ""
221-
234+
222235
if (diagnosticsEnabled) {
223236
// Add configurable delay to allow linters time to process and clean up issues
224237
// like unused imports (especially important for Go and other languages)
225238
// Ensure delay is non-negative
226239
const safeDelayMs = Math.max(0, writeDelayMs)
227-
240+
228241
try {
229242
await delay(safeDelayMs)
230243
} catch (error) {
231244
// Log error but continue - delay failure shouldn't break the save operation
232245
console.warn(`Failed to apply write delay: ${error}`)
233246
}
234-
247+
235248
const postDiagnostics = vscode.languages.getDiagnostics()
236249

237250
const newProblems = await diagnosticsToProblemsString(
@@ -391,6 +404,7 @@ export class DiffViewProvider {
391404
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), {
392405
preview: false,
393406
preserveFocus: true,
407+
viewColumn: this.openTabsAtEndOfList ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active,
394408
})
395409
}
396410

@@ -523,7 +537,11 @@ export class DiffViewProvider {
523537
// Pre-open the file as a text document to ensure it doesn't open in preview mode
524538
// This fixes issues with files that have custom editor associations (like markdown preview)
525539
vscode.window
526-
.showTextDocument(uri, { preview: false, viewColumn: vscode.ViewColumn.Active, preserveFocus: true })
540+
.showTextDocument(uri, {
541+
preview: false,
542+
viewColumn: this.openTabsAtEndOfList ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active,
543+
preserveFocus: true,
544+
})
527545
.then(() => {
528546
// Execute the diff command after ensuring the file is open as text
529547
return vscode.commands.executeCommand(
@@ -533,7 +551,10 @@ export class DiffViewProvider {
533551
}),
534552
uri,
535553
`${fileName}: ${fileExists ? `${DIFF_VIEW_LABEL_CHANGES}` : "New File"} (Editable)`,
536-
{ preserveFocus: true },
554+
{
555+
preserveFocus: true,
556+
viewColumn: this.openTabsAtEndOfList ? vscode.ViewColumn.Beside : undefined,
557+
},
537558
)
538559
})
539560
.then(

0 commit comments

Comments
 (0)