mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
feat: Add openTabsInCorrectGroup setting for better tab management
- Added openTabsInCorrectGroup setting to GlobalState type definition - Created UI toggle in AutoApproveSettings component within File Editing Options section - Added translation strings for the new UI elements - Implemented message handler in webviewMessageHandler.ts - Modified DiffViewProvider to accept provider reference and implement tab placement logic - Updated Task.ts to pass provider to DiffViewProvider - Added setting to ExtensionState and WebviewMessage types - Fixed TypeScript errors by adding openTabsInCorrectGroup to ClineProvider getState() This feature allows Roo to open diff editors and related tabs in the most logical editor group when working with multiple VS Code editor groups, improving navigation and organization for users with complex editor layouts. Fixes #6005
This commit is contained in:
parent
9fce90be9d
commit
9dd88bbcf9
11 changed files with 119 additions and 10 deletions
|
|
@ -107,6 +107,7 @@ export const globalSettingsSchema = z.object({
|
|||
|
||||
rateLimitSeconds: z.number().optional(),
|
||||
diffEnabled: z.boolean().optional(),
|
||||
openTabsInCorrectGroup: z.boolean().optional(),
|
||||
fuzzyMatchThreshold: z.number().optional(),
|
||||
experiments: experimentsSchema.optional(),
|
||||
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ 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)
|
||||
this.diffViewProvider = new DiffViewProvider(this.cwd, provider)
|
||||
this.enableCheckpoints = enableCheckpoints
|
||||
|
||||
this.rootTask = rootTask
|
||||
|
|
|
|||
|
|
@ -1726,6 +1726,7 @@ export class ClineProvider
|
|||
codebaseIndexSearchMinScore: stateValues.codebaseIndexConfig?.codebaseIndexSearchMinScore,
|
||||
},
|
||||
profileThresholds: stateValues.profileThresholds ?? {},
|
||||
openTabsInCorrectGroup: stateValues.openTabsInCorrectGroup ?? false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -932,6 +932,11 @@ export const webviewMessageHandler = async (
|
|||
await updateGlobalState("diffEnabled", diffEnabled)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "openTabsInCorrectGroup":
|
||||
const openTabsInCorrectGroup = message.bool ?? false
|
||||
await updateGlobalState("openTabsInCorrectGroup", openTabsInCorrectGroup)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "enableCheckpoints":
|
||||
const enableCheckpoints = message.bool ?? true
|
||||
await updateGlobalState("enableCheckpoints", enableCheckpoints)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { diagnosticsToProblemsString, getNewDiagnostics } from "../diagnostics"
|
|||
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
import { Task } from "../../core/task/Task"
|
||||
import { DEFAULT_WRITE_DELAY_MS } from "@roo-code/types"
|
||||
import { ClineProvider } from "../../core/webview/ClineProvider"
|
||||
|
||||
import { DecorationController } from "./DecorationController"
|
||||
|
||||
|
|
@ -36,8 +37,16 @@ export class DiffViewProvider {
|
|||
private activeLineController?: DecorationController
|
||||
private streamedLines: string[] = []
|
||||
private preDiagnostics: [vscode.Uri, vscode.Diagnostic[]][] = []
|
||||
private providerRef?: WeakRef<ClineProvider>
|
||||
|
||||
constructor(private cwd: string) {}
|
||||
constructor(
|
||||
private cwd: string,
|
||||
provider?: ClineProvider,
|
||||
) {
|
||||
if (provider) {
|
||||
this.providerRef = new WeakRef(provider)
|
||||
}
|
||||
}
|
||||
|
||||
async open(relPath: string): Promise<void> {
|
||||
this.relPath = relPath
|
||||
|
|
@ -181,7 +190,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
|
||||
|
|
@ -216,22 +228,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(
|
||||
|
|
@ -461,6 +473,53 @@ export class DiffViewProvider {
|
|||
return editor
|
||||
}
|
||||
|
||||
// Determine the view column based on the openTabsInCorrectGroup setting
|
||||
let targetViewColumn = vscode.ViewColumn.Active
|
||||
|
||||
// Check if we should open in the same group as the original file
|
||||
const provider = this.providerRef?.deref()
|
||||
if (provider) {
|
||||
const state = await provider.getState()
|
||||
const openTabsInCorrectGroup = state?.openTabsInCorrectGroup ?? false
|
||||
|
||||
if (openTabsInCorrectGroup) {
|
||||
// Find which tab group contains the original file
|
||||
const originalFileTab = vscode.window.tabGroups.all
|
||||
.flatMap((group) => group.tabs.map((tab) => ({ tab, group })))
|
||||
.find(
|
||||
({ tab }) =>
|
||||
tab.input instanceof vscode.TabInputText && arePathsEqual(tab.input.uri.fsPath, uri.fsPath),
|
||||
)
|
||||
|
||||
if (originalFileTab) {
|
||||
// Use the view column of the group containing the original file
|
||||
targetViewColumn = originalFileTab.group.viewColumn
|
||||
} else {
|
||||
// If the original file isn't open, try to find the most logical group
|
||||
// This could be the group with the most related files (same directory)
|
||||
const fileDir = path.dirname(uri.fsPath)
|
||||
const groupsWithRelatedFiles = vscode.window.tabGroups.all.map((group) => {
|
||||
const relatedFilesCount = group.tabs.filter((tab) => {
|
||||
if (tab.input instanceof vscode.TabInputText) {
|
||||
const tabDir = path.dirname(tab.input.uri.fsPath)
|
||||
return tabDir === fileDir
|
||||
}
|
||||
return false
|
||||
}).length
|
||||
return { group, relatedFilesCount }
|
||||
})
|
||||
|
||||
// Sort by most related files
|
||||
groupsWithRelatedFiles.sort((a, b) => b.relatedFilesCount - a.relatedFilesCount)
|
||||
|
||||
// Use the group with the most related files, or fall back to active
|
||||
if (groupsWithRelatedFiles.length > 0 && groupsWithRelatedFiles[0].relatedFilesCount > 0) {
|
||||
targetViewColumn = groupsWithRelatedFiles[0].group.viewColumn
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Open new diff editor.
|
||||
return new Promise<vscode.TextEditor>((resolve, reject) => {
|
||||
const fileName = path.basename(uri.fsPath)
|
||||
|
|
@ -523,7 +582,7 @@ 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: targetViewColumn, preserveFocus: true })
|
||||
.then(() => {
|
||||
// Execute the diff command after ensuring the file is open as text
|
||||
return vscode.commands.executeCommand(
|
||||
|
|
@ -533,7 +592,7 @@ export class DiffViewProvider {
|
|||
}),
|
||||
uri,
|
||||
`${fileName}: ${fileExists ? `${DIFF_VIEW_LABEL_CHANGES}` : "New File"} (Editable)`,
|
||||
{ preserveFocus: true },
|
||||
{ preserveFocus: true, viewColumn: targetViewColumn },
|
||||
)
|
||||
})
|
||||
.then(
|
||||
|
|
|
|||
|
|
@ -217,6 +217,7 @@ export type ExtensionState = Pick<
|
|||
| "terminalCompressProgressBar"
|
||||
| "diagnosticsEnabled"
|
||||
| "diffEnabled"
|
||||
| "openTabsInCorrectGroup"
|
||||
| "fuzzyMatchThreshold"
|
||||
// | "experiments" // Optional in GlobalSettings, required here.
|
||||
| "language"
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ export interface WebviewMessage {
|
|||
| "ttsSpeed"
|
||||
| "soundVolume"
|
||||
| "diffEnabled"
|
||||
| "openTabsInCorrectGroup"
|
||||
| "enableCheckpoints"
|
||||
| "browserViewportSize"
|
||||
| "screenshotQuality"
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ type AutoApproveSettingsProps = HTMLAttributes<HTMLDivElement> & {
|
|||
followupAutoApproveTimeoutMs?: number
|
||||
allowedCommands?: string[]
|
||||
deniedCommands?: string[]
|
||||
openTabsInCorrectGroup?: boolean
|
||||
setCachedStateField: SetCachedStateField<
|
||||
| "alwaysAllowReadOnly"
|
||||
| "alwaysAllowReadOnlyOutsideWorkspace"
|
||||
|
|
@ -52,6 +53,7 @@ type AutoApproveSettingsProps = HTMLAttributes<HTMLDivElement> & {
|
|||
| "allowedCommands"
|
||||
| "deniedCommands"
|
||||
| "alwaysAllowUpdateTodoList"
|
||||
| "openTabsInCorrectGroup"
|
||||
>
|
||||
}
|
||||
|
||||
|
|
@ -74,6 +76,7 @@ export const AutoApproveSettings = ({
|
|||
alwaysAllowUpdateTodoList,
|
||||
allowedCommands,
|
||||
deniedCommands,
|
||||
openTabsInCorrectGroup,
|
||||
setCachedStateField,
|
||||
...props
|
||||
}: AutoApproveSettingsProps) => {
|
||||
|
|
@ -393,6 +396,27 @@ export const AutoApproveSettings = ({
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* FILE EDITING OPTIONS */}
|
||||
<div className="mt-6">
|
||||
<div className="flex items-center gap-4 font-bold mb-3">
|
||||
<span className="codicon codicon-file-code" />
|
||||
<div>{t("settings:autoApprove.fileEditing.label")}</div>
|
||||
</div>
|
||||
<div className="pl-3 border-l-2 border-vscode-button-background">
|
||||
<VSCodeCheckbox
|
||||
checked={openTabsInCorrectGroup}
|
||||
onChange={(e: any) => setCachedStateField("openTabsInCorrectGroup", e.target.checked)}
|
||||
data-testid="open-tabs-in-correct-group-checkbox">
|
||||
<span className="font-medium">
|
||||
{t("settings:autoApprove.fileEditing.openTabsInCorrectGroup.label")}
|
||||
</span>
|
||||
</VSCodeCheckbox>
|
||||
<div className="text-vscode-descriptionForeground text-sm mt-1">
|
||||
{t("settings:autoApprove.fileEditing.openTabsInCorrectGroup.description")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
alwaysAllowFollowupQuestions,
|
||||
alwaysAllowUpdateTodoList,
|
||||
followupAutoApproveTimeoutMs,
|
||||
openTabsInCorrectGroup,
|
||||
} = cachedState
|
||||
|
||||
const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration])
|
||||
|
|
@ -300,6 +301,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
vscode.postMessage({ type: "remoteBrowserEnabled", bool: remoteBrowserEnabled })
|
||||
vscode.postMessage({ type: "fuzzyMatchThreshold", value: fuzzyMatchThreshold ?? 1.0 })
|
||||
vscode.postMessage({ type: "writeDelayMs", value: writeDelayMs })
|
||||
vscode.postMessage({ type: "openTabsInCorrectGroup", bool: openTabsInCorrectGroup })
|
||||
vscode.postMessage({ type: "screenshotQuality", value: screenshotQuality ?? 75 })
|
||||
vscode.postMessage({ type: "terminalOutputLineLimit", value: terminalOutputLineLimit ?? 500 })
|
||||
vscode.postMessage({ type: "terminalOutputCharacterLimit", value: terminalOutputCharacterLimit ?? 50000 })
|
||||
|
|
@ -619,6 +621,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
followupAutoApproveTimeoutMs={followupAutoApproveTimeoutMs}
|
||||
allowedCommands={allowedCommands}
|
||||
deniedCommands={deniedCommands}
|
||||
openTabsInCorrectGroup={openTabsInCorrectGroup}
|
||||
setCachedStateField={setCachedStateField}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -134,6 +134,8 @@ export interface ExtensionStateContextType extends ExtensionState {
|
|||
routerModels?: RouterModels
|
||||
alwaysAllowUpdateTodoList?: boolean
|
||||
setAlwaysAllowUpdateTodoList: (value: boolean) => void
|
||||
openTabsInCorrectGroup?: boolean
|
||||
setOpenTabsInCorrectGroup: (value: boolean) => void
|
||||
}
|
||||
|
||||
export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
|
||||
|
|
@ -229,6 +231,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||
},
|
||||
codebaseIndexModels: { ollama: {}, openai: {} },
|
||||
alwaysAllowUpdateTodoList: true,
|
||||
openTabsInCorrectGroup: false,
|
||||
})
|
||||
|
||||
const [didHydrateState, setDidHydrateState] = useState(false)
|
||||
|
|
@ -474,6 +477,10 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||
setAlwaysAllowUpdateTodoList: (value) => {
|
||||
setState((prevState) => ({ ...prevState, alwaysAllowUpdateTodoList: value }))
|
||||
},
|
||||
openTabsInCorrectGroup: state.openTabsInCorrectGroup,
|
||||
setOpenTabsInCorrectGroup: (value) => {
|
||||
setState((prevState) => ({ ...prevState, openTabsInCorrectGroup: value }))
|
||||
},
|
||||
}
|
||||
|
||||
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>
|
||||
|
|
|
|||
|
|
@ -197,7 +197,14 @@
|
|||
},
|
||||
"toggleAriaLabel": "Toggle auto-approval",
|
||||
"disabledAriaLabel": "Auto-approval disabled - select options first",
|
||||
"selectOptionsFirst": "Select at least one option below to enable auto-approval"
|
||||
"selectOptionsFirst": "Select at least one option below to enable auto-approval",
|
||||
"fileEditing": {
|
||||
"label": "File Editing Options",
|
||||
"openTabsInCorrectGroup": {
|
||||
"label": "Open tabs in correct group",
|
||||
"description": "When enabled, Roo will open diff tabs beside the original file in the same editor group. When disabled, tabs open in the currently active group."
|
||||
}
|
||||
}
|
||||
},
|
||||
"providers": {
|
||||
"providerDocumentation": "{{provider}} documentation",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue