Open chat file links at the referenced line (#2309)
* fix(app): open chat file links at referenced lines Pass chat file locations through the editable CodeMirror path so opening a reference selects and scrolls to its requested line. Cover the real assistant-link flow with a browser regression. * fix(app): repeat chat file navigation Track file navigation separately from stable tab identity so reopening the same path and line recenters both editable and read-only panes. Extend the browser regression to cover moving away and clicking the same link again. * test(app): stabilize repeated file link navigation
This commit is contained in:
@@ -23,6 +23,7 @@ export interface BuildWorkspacePaneContentModelInput {
|
||||
tab: WorkspaceTabDescriptor;
|
||||
normalizedServerId: string;
|
||||
normalizedWorkspaceId: string;
|
||||
fileNavigationRevision?: number;
|
||||
onOpenTab: (target: WorkspaceTabDescriptor["target"]) => void;
|
||||
onCloseCurrentTab: () => void;
|
||||
onRetargetCurrentTab: (target: WorkspaceTabDescriptor["target"]) => void;
|
||||
@@ -34,6 +35,7 @@ export function buildWorkspacePaneContentModel({
|
||||
tab,
|
||||
normalizedServerId,
|
||||
normalizedWorkspaceId,
|
||||
fileNavigationRevision,
|
||||
onOpenTab,
|
||||
onCloseCurrentTab,
|
||||
onRetargetCurrentTab,
|
||||
@@ -51,6 +53,7 @@ export function buildWorkspacePaneContentModel({
|
||||
workspaceId: normalizedWorkspaceId,
|
||||
tabId: tab.tabId,
|
||||
target: tab.target,
|
||||
fileNavigationRevision,
|
||||
openTab: onOpenTab,
|
||||
closeCurrentTab: onCloseCurrentTab,
|
||||
retargetCurrentTab: onRetargetCurrentTab,
|
||||
@@ -85,6 +88,7 @@ export function WorkspacePaneContent({
|
||||
workspaceId: paneContextValue.workspaceId,
|
||||
tabId: paneContextValue.tabId,
|
||||
target: paneContextValue.target,
|
||||
fileNavigationRevision: paneContextValue.fileNavigationRevision,
|
||||
openTab,
|
||||
closeCurrentTab,
|
||||
retargetCurrentTab,
|
||||
@@ -97,6 +101,7 @@ export function WorkspacePaneContent({
|
||||
openImportSheet,
|
||||
openTab,
|
||||
paneContextValue.serverId,
|
||||
paneContextValue.fileNavigationRevision,
|
||||
paneContextValue.tabId,
|
||||
paneContextValue.target,
|
||||
paneContextValue.workspaceId,
|
||||
|
||||
@@ -1773,6 +1773,17 @@ function WorkspaceScreenContent({
|
||||
const openWorkspaceChildTabFocused = useWorkspaceLayoutStore(
|
||||
(state) => state.openChildTabFocused,
|
||||
);
|
||||
// File targets stay identity-stable so the same path reuses its tab. Keep navigation
|
||||
// requests separate so clicking an unchanged path:line can still recenter the pane.
|
||||
const [fileNavigationRevisionByTabId, setFileNavigationRevisionByTabId] = useState<
|
||||
Record<string, number>
|
||||
>({});
|
||||
const requestFileNavigation = useCallback((tabId: string) => {
|
||||
setFileNavigationRevisionByTabId((current) => ({
|
||||
...current,
|
||||
[tabId]: (current[tabId] ?? 0) + 1,
|
||||
}));
|
||||
}, []);
|
||||
const focusWorkspacePane = useWorkspaceLayoutStore((state) => state.focusPane);
|
||||
const hasHydratedWorkspaces = useSessionStore(
|
||||
(state) => state.sessions[normalizedServerId]?.hasHydratedWorkspaces ?? false,
|
||||
@@ -2333,6 +2344,7 @@ function WorkspaceScreenContent({
|
||||
? openWorkspaceChildTabFocused(persistenceKey, target, options.parentTabId)
|
||||
: openWorkspaceTabFocused(persistenceKey, target);
|
||||
if (tabId) {
|
||||
requestFileNavigation(tabId);
|
||||
navigateToTabId(tabId);
|
||||
}
|
||||
},
|
||||
@@ -2342,6 +2354,7 @@ function WorkspaceScreenContent({
|
||||
openWorkspaceChildTabFocused,
|
||||
openWorkspaceTabFocused,
|
||||
persistenceKey,
|
||||
requestFileNavigation,
|
||||
showMobileAgent,
|
||||
],
|
||||
);
|
||||
@@ -2381,6 +2394,7 @@ function WorkspaceScreenContent({
|
||||
? openWorkspaceChildTabFocused(persistenceKey, target, input.parentTabId)
|
||||
: openWorkspaceTabFocused(persistenceKey, target);
|
||||
if (tabId) {
|
||||
requestFileNavigation(tabId);
|
||||
navigateToTabId(tabId);
|
||||
}
|
||||
},
|
||||
@@ -2392,6 +2406,7 @@ function WorkspaceScreenContent({
|
||||
openWorkspaceChildTabFocused,
|
||||
openWorkspaceTabFocused,
|
||||
persistenceKey,
|
||||
requestFileNavigation,
|
||||
splitWorkspacePaneEmpty,
|
||||
uiTabs,
|
||||
workspaceLayout,
|
||||
@@ -3211,6 +3226,7 @@ function WorkspaceScreenContent({
|
||||
tab: input.tab,
|
||||
normalizedServerId,
|
||||
normalizedWorkspaceId,
|
||||
fileNavigationRevision: fileNavigationRevisionByTabId[input.tab.tabId] ?? 0,
|
||||
onOpenTab: (target) => {
|
||||
if (!persistenceKey) {
|
||||
return;
|
||||
@@ -3245,6 +3261,7 @@ function WorkspaceScreenContent({
|
||||
[
|
||||
handleCloseTabById,
|
||||
focusWorkspacePane,
|
||||
fileNavigationRevisionByTabId,
|
||||
handleOpenWorkspaceFileFromPane,
|
||||
navigateToTabId,
|
||||
normalizedServerId,
|
||||
|
||||
Reference in New Issue
Block a user