- {session?.vimMode && activeTab?.type === "file" && (
+ {vimMode && activeTab?.type === "file" && (
- {session?.vimModeState ?? "normal"}
+ {vimModeState ?? "normal"}
)}
{activeTab?.type === "browser" && (
@@ -692,14 +689,14 @@ export function FileEditorSidebarPanel({
{activeTab?.type === "file" && (
diff --git a/frontend/components/FilePathLink/FilePathLink.tsx b/frontend/components/FilePathLink/FilePathLink.tsx
index 94da5bba..7e032325 100644
--- a/frontend/components/FilePathLink/FilePathLink.tsx
+++ b/frontend/components/FilePathLink/FilePathLink.tsx
@@ -16,8 +16,6 @@ interface FilePathLinkProps {
detected: DetectedPath;
/** Working directory for path resolution */
workingDirectory: string;
- /** Session ID for file editor */
- sessionId: string;
/** The text to display (may differ from detected.raw if we only wrap part of it) */
children: ReactNode;
/** Pre-resolved absolute path (if known from index) */
@@ -27,7 +25,6 @@ interface FilePathLinkProps {
export function FilePathLink({
detected,
workingDirectory,
- sessionId,
children,
absolutePath,
}: FilePathLinkProps) {
@@ -35,7 +32,7 @@ export function FilePathLink({
const [loading, setLoading] = useState(false);
const [resolvedPaths, setResolvedPaths] = useState([]);
- const { openFile } = useFileEditorSidebar(sessionId, workingDirectory);
+ const { openFile } = useFileEditorSidebar(workingDirectory);
const handleClick = useCallback(async () => {
if (open) {
diff --git a/frontend/components/Markdown/Markdown.tsx b/frontend/components/Markdown/Markdown.tsx
index 181f6fbc..b5185136 100644
--- a/frontend/components/Markdown/Markdown.tsx
+++ b/frontend/components/Markdown/Markdown.tsx
@@ -76,7 +76,6 @@ function processTextWithFilePaths(text: string, context: MarkdownContextValue):
diff --git a/frontend/hooks/useFileEditorSidebar.ts b/frontend/hooks/useFileEditorSidebar.ts
index 986a6dfe..3c50b965 100644
--- a/frontend/hooks/useFileEditorSidebar.ts
+++ b/frontend/hooks/useFileEditorSidebar.ts
@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useMemo } from "react";
+import { useCallback, useMemo } from "react";
import { readWorkspaceFile, writeWorkspaceFile } from "@/lib/file-editor";
import { notify } from "@/lib/notify";
import {
@@ -6,7 +6,6 @@ import {
fileTabIdFromPath,
selectActiveFileTab,
selectActiveTab,
- selectSessionState,
type Tab,
useFileEditorSidebarStore,
} from "@/store/file-editor-sidebar";
@@ -53,109 +52,80 @@ function detectLanguageFromPath(path: string): string | undefined {
return undefined;
}
-export function useFileEditorSidebar(sessionId: string | null, workingDirectory?: string) {
- useEffect(() => {
- if (sessionId) {
- useFileEditorSidebarStore.getState().ensureSession(sessionId);
- }
- }, [sessionId]);
+export function useFileEditorSidebar(workingDirectory?: string) {
+ // Subscribe to the global store state
+ const state = useFileEditorSidebarStore();
- const session = useFileEditorSidebarStore(
- useCallback((state) => (sessionId ? selectSessionState(state, sessionId) : null), [sessionId])
- );
-
- // Derive active tab and active file from session
- const activeTab = useMemo(() => (session ? selectActiveTab(session) : null), [session]);
- const activeFileTab = useMemo(() => (session ? selectActiveFileTab(session) : null), [session]);
+ // Derive active tab and active file from state
+ const activeTab = useMemo(() => selectActiveTab(state), [state]);
+ const activeFileTab = useMemo(() => selectActiveFileTab(state), [state]);
const activeFile = activeFileTab?.file ?? null;
const actions = useMemo(() => {
return {
setOpen: (open: boolean) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().setOpen(sessionId, open);
+ useFileEditorSidebarStore.getState().setOpen(open);
},
setWidth: (width: number) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().setWidth(sessionId, width);
+ useFileEditorSidebarStore.getState().setWidth(width);
},
setStatus: (status?: string) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().setStatus(sessionId, status);
+ useFileEditorSidebarStore.getState().setStatus(status);
},
setActiveTab: (tabId: string) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().setActiveTab(sessionId, tabId);
+ useFileEditorSidebarStore.getState().setActiveTab(tabId);
},
closeTab: (tabId?: string) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().closeTab(sessionId, tabId);
+ useFileEditorSidebarStore.getState().closeTab(tabId);
},
closeAllTabs: () => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().closeAllTabs(sessionId);
+ useFileEditorSidebarStore.getState().closeAllTabs();
},
closeOtherTabs: (keepTabId: string) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().closeOtherTabs(sessionId, keepTabId);
+ useFileEditorSidebarStore.getState().closeOtherTabs(keepTabId);
},
reorderTabs: (fromIndex: number, toIndex: number) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().reorderTabs(sessionId, fromIndex, toIndex);
+ useFileEditorSidebarStore.getState().reorderTabs(fromIndex, toIndex);
},
updateFileContent: (tabId: string, content: string) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().updateFileContent(sessionId, tabId, content);
+ useFileEditorSidebarStore.getState().updateFileContent(tabId, content);
},
setBrowserPath: (tabId: string, path: string) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().setBrowserPath(sessionId, tabId, path);
+ useFileEditorSidebarStore.getState().setBrowserPath(tabId, path);
},
setVimMode: (enabled: boolean) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().setVimMode(sessionId, enabled);
+ useFileEditorSidebarStore.getState().setVimMode(enabled);
},
setVimModeState: (state: "normal" | "insert" | "visual") => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().setVimModeState(sessionId, state);
+ useFileEditorSidebarStore.getState().setVimModeState(state);
},
setWrap: (enabled: boolean) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().setWrap(sessionId, enabled);
+ useFileEditorSidebarStore.getState().setWrap(enabled);
},
setLineNumbers: (enabled: boolean) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().setLineNumbers(sessionId, enabled);
+ useFileEditorSidebarStore.getState().setLineNumbers(enabled);
},
setRelativeLineNumbers: (enabled: boolean) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().setRelativeLineNumbers(sessionId, enabled);
+ useFileEditorSidebarStore.getState().setRelativeLineNumbers(enabled);
},
addRecentFile: (path: string) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().addRecentFile(sessionId, path);
+ useFileEditorSidebarStore.getState().addRecentFile(path);
},
toggleMarkdownPreview: (tabId: string) => {
- if (!sessionId) return;
- useFileEditorSidebarStore.getState().toggleMarkdownPreview(sessionId, tabId);
+ useFileEditorSidebarStore.getState().toggleMarkdownPreview(tabId);
},
};
- }, [sessionId]);
+ }, []);
const openFile = useCallback(
async (inputPath: string) => {
- if (!sessionId) {
- notify.error("No active session for file open");
- return;
- }
const fullPath = resolvePath(inputPath, workingDirectory);
// If file is already open, just switch to it
const tabId = fileTabIdFromPath(fullPath);
- const state = useFileEditorSidebarStore.getState();
- const currentSession = state.sessions[sessionId];
- if (currentSession?.tabs[tabId]) {
- state.setActiveTab(sessionId, tabId);
+ const currentState = useFileEditorSidebarStore.getState();
+ if (currentState.tabs[tabId]) {
+ currentState.setActiveTab(tabId);
return;
}
@@ -172,7 +142,7 @@ export function useFileEditorSidebar(sessionId: string | null, workingDirectory?
lastReadAt: new Date().toISOString(),
lastSavedAt: result.modifiedAt,
};
- useFileEditorSidebarStore.getState().openFileTab(sessionId, file);
+ useFileEditorSidebarStore.getState().openFileTab(file);
actions.addRecentFile(fullPath);
} catch (error) {
notify.error(`Failed to open file: ${error}`);
@@ -180,32 +150,27 @@ export function useFileEditorSidebar(sessionId: string | null, workingDirectory?
actions.setStatus(undefined);
}
},
- [actions, sessionId, workingDirectory]
+ [actions, workingDirectory]
);
const openBrowser = useCallback(
(initialPath?: string) => {
- if (!sessionId) {
- notify.error("No active session");
- return;
- }
const path = initialPath ?? workingDirectory ?? "";
- useFileEditorSidebarStore.getState().openBrowserTab(sessionId, path);
+ useFileEditorSidebarStore.getState().openBrowserTab(path);
},
- [sessionId, workingDirectory]
+ [workingDirectory]
);
const saveFile = useCallback(
async (tabId?: string) => {
- if (!sessionId || !session) return;
-
- const targetTabId = tabId ?? session.activeTabId;
+ const currentState = useFileEditorSidebarStore.getState();
+ const targetTabId = tabId ?? currentState.activeTabId;
if (!targetTabId) {
notify.info("No file open to save");
return;
}
- const tab = session.tabs[targetTabId];
+ const tab = currentState.tabs[targetTabId];
if (!tab || tab.type !== "file") {
notify.info("Current tab is not a file");
return;
@@ -217,9 +182,7 @@ export function useFileEditorSidebar(sessionId: string | null, workingDirectory?
const result = await writeWorkspaceFile(file.path, file.content, {
expectedModifiedAt: file.lastSavedAt,
});
- useFileEditorSidebarStore
- .getState()
- .markFileSaved(sessionId, targetTabId, result.modifiedAt);
+ useFileEditorSidebarStore.getState().markFileSaved(targetTabId, result.modifiedAt);
notify.success("Saved");
} catch (error) {
notify.error(`Failed to save file: ${error}`);
@@ -227,20 +190,19 @@ export function useFileEditorSidebar(sessionId: string | null, workingDirectory?
actions.setStatus(undefined);
}
},
- [actions, session, sessionId]
+ [actions]
);
const reloadFile = useCallback(
async (tabId?: string) => {
- if (!sessionId || !session) return;
-
- const targetTabId = tabId ?? session.activeTabId;
+ const currentState = useFileEditorSidebarStore.getState();
+ const targetTabId = tabId ?? currentState.activeTabId;
if (!targetTabId) {
notify.info("No file open to reload");
return;
}
- const tab = session.tabs[targetTabId];
+ const tab = currentState.tabs[targetTabId];
if (!tab || tab.type !== "file") {
notify.info("Current tab is not a file");
return;
@@ -258,24 +220,33 @@ export function useFileEditorSidebar(sessionId: string | null, workingDirectory?
lastReadAt: new Date().toISOString(),
lastSavedAt: result.modifiedAt,
};
- useFileEditorSidebarStore.getState().openFileTab(sessionId, newFile);
+ useFileEditorSidebarStore.getState().openFileTab(newFile);
} catch (error) {
notify.error(`Failed to reload file: ${error}`);
} finally {
actions.setStatus(undefined);
}
},
- [actions, session, sessionId]
+ [actions]
);
// Get tabs as array for rendering
const tabs = useMemo((): Tab[] => {
- if (!session) return [];
- return session.tabOrder.map((id) => session.tabs[id]).filter((t): t is Tab => t !== undefined);
- }, [session]);
+ return state.tabOrder.map((id) => state.tabs[id]).filter((t): t is Tab => t !== undefined);
+ }, [state.tabOrder, state.tabs]);
return {
- session,
+ // State (entire store state for convenience, but components should use specific fields)
+ open: state.open,
+ width: state.width,
+ vimMode: state.vimMode,
+ vimModeState: state.vimModeState,
+ wrap: state.wrap,
+ lineNumbers: state.lineNumbers,
+ relativeLineNumbers: state.relativeLineNumbers,
+ recentFiles: state.recentFiles,
+ status: state.status,
+ activeTabId: state.activeTabId,
activeTab,
activeFileTab,
activeFile,
diff --git a/frontend/store/file-editor-sidebar.ts b/frontend/store/file-editor-sidebar.ts
index ce19728b..90b2a3f2 100644
--- a/frontend/store/file-editor-sidebar.ts
+++ b/frontend/store/file-editor-sidebar.ts
@@ -38,7 +38,8 @@ export interface BrowserTab extends BaseTab {
export type Tab = FileTab | BrowserTab;
-export interface FileEditorSessionState {
+// Single global state (no longer per-session)
+interface FileEditorSidebarState {
open: boolean;
width: number;
// Tab-based model
@@ -54,57 +55,37 @@ export interface FileEditorSessionState {
lineNumbers: boolean;
relativeLineNumbers: boolean;
status?: string;
-}
-interface FileEditorSidebarState {
- sessions: Record;
- ensureSession: (sessionId: string) => FileEditorSessionState;
- setOpen: (sessionId: string, open: boolean) => void;
- setWidth: (sessionId: string, width: number) => void;
- setStatus: (sessionId: string, status?: string) => void;
+ // Actions
+ setOpen: (open: boolean) => void;
+ setWidth: (width: number) => void;
+ setStatus: (status?: string) => void;
// Tab operations
- openFileTab: (sessionId: string, file: EditorFileState) => void;
- openBrowserTab: (sessionId: string, initialPath?: string) => void;
- setActiveTab: (sessionId: string, tabId: string) => void;
- closeTab: (sessionId: string, tabId?: string) => void;
- closeAllTabs: (sessionId: string) => void;
- closeOtherTabs: (sessionId: string, keepTabId: string) => void;
- reorderTabs: (sessionId: string, fromIndex: number, toIndex: number) => void;
+ openFileTab: (file: EditorFileState) => void;
+ openBrowserTab: (initialPath?: string) => void;
+ setActiveTab: (tabId: string) => void;
+ closeTab: (tabId?: string) => void;
+ closeAllTabs: () => void;
+ closeOtherTabs: (keepTabId: string) => void;
+ reorderTabs: (fromIndex: number, toIndex: number) => void;
// File tab specific
- updateFileContent: (sessionId: string, tabId: string, content: string) => void;
- markFileSaved: (sessionId: string, tabId: string, timestamp?: string) => void;
- toggleMarkdownPreview: (sessionId: string, tabId: string) => void;
+ updateFileContent: (tabId: string, content: string) => void;
+ markFileSaved: (tabId: string, timestamp?: string) => void;
+ toggleMarkdownPreview: (tabId: string) => void;
// Browser tab specific
- setBrowserPath: (sessionId: string, tabId: string, path: string) => void;
+ setBrowserPath: (tabId: string, path: string) => void;
// Editor settings
- setVimMode: (sessionId: string, enabled: boolean) => void;
- setVimModeState: (sessionId: string, state: "normal" | "insert" | "visual") => void;
- setWrap: (sessionId: string, enabled: boolean) => void;
- setLineNumbers: (sessionId: string, enabled: boolean) => void;
- setRelativeLineNumbers: (sessionId: string, enabled: boolean) => void;
- addRecentFile: (sessionId: string, path: string) => void;
- resetSession: (sessionId: string) => void;
+ setVimMode: (enabled: boolean) => void;
+ setVimModeState: (state: "normal" | "insert" | "visual") => void;
+ setWrap: (enabled: boolean) => void;
+ setLineNumbers: (enabled: boolean) => void;
+ setRelativeLineNumbers: (enabled: boolean) => void;
+ addRecentFile: (path: string) => void;
+ reset: () => void;
}
const DEFAULT_WIDTH = 420;
-function createDefaultSessionState(): FileEditorSessionState {
- return {
- open: false,
- width: DEFAULT_WIDTH,
- tabs: {},
- activeTabId: null,
- tabOrder: [],
- recentFiles: [],
- vimMode: true,
- vimModeState: "normal",
- wrap: false,
- lineNumbers: true,
- relativeLineNumbers: false,
- status: undefined,
- };
-}
-
// Generate unique tab IDs
let tabIdCounter = 0;
function generateTabId(type: TabType): string {
@@ -116,50 +97,56 @@ function getFileTabId(path: string): string {
return `file:${path}`;
}
+// Export for use in hook
+export function fileTabIdFromPath(path: string): string {
+ return getFileTabId(path);
+}
+
+const initialState = {
+ open: false,
+ width: DEFAULT_WIDTH,
+ tabs: {} as Record,
+ activeTabId: null as string | null,
+ tabOrder: [] as string[],
+ recentFiles: [] as string[],
+ vimMode: true,
+ vimModeState: "normal" as const,
+ wrap: false,
+ lineNumbers: true,
+ relativeLineNumbers: false,
+ status: undefined as string | undefined,
+};
+
export const useFileEditorSidebarStore = create()(
- immer((set, get) => ({
- sessions: {},
-
- ensureSession: (sessionId) => {
- const state = get();
- if (!state.sessions[sessionId]) {
- set((draft) => {
- draft.sessions[sessionId] = createDefaultSessionState();
- });
- }
- return get().sessions[sessionId] ?? createDefaultSessionState();
- },
+ immer((set) => ({
+ ...initialState,
- setOpen: (sessionId, open) => {
+ setOpen: (open) => {
set((draft) => {
- const session = draft.sessions[sessionId] ?? createDefaultSessionState();
- draft.sessions[sessionId] = { ...session, open };
+ draft.open = open;
});
},
- setWidth: (sessionId, width) => {
+ setWidth: (width) => {
set((draft) => {
- const session = draft.sessions[sessionId] ?? createDefaultSessionState();
- draft.sessions[sessionId] = { ...session, width };
+ draft.width = width;
});
},
- setStatus: (sessionId, status) => {
+ setStatus: (status) => {
set((draft) => {
- const session = draft.sessions[sessionId] ?? createDefaultSessionState();
- draft.sessions[sessionId] = { ...session, status };
+ draft.status = status;
});
},
- openFileTab: (sessionId, file) => {
+ openFileTab: (file) => {
set((draft) => {
- const session = draft.sessions[sessionId] ?? createDefaultSessionState();
const tabId = getFileTabId(file.path);
// Check if file is already open
- if (session.tabs[tabId]) {
+ if (draft.tabs[tabId]) {
// Just switch to it
- session.activeTabId = tabId;
+ draft.activeTabId = tabId;
} else {
// Create new file tab
const tab: FileTab = {
@@ -167,25 +154,22 @@ export const useFileEditorSidebarStore = create()(
type: "file",
file,
};
- session.tabs[tabId] = tab;
- session.tabOrder.push(tabId);
- session.activeTabId = tabId;
+ draft.tabs[tabId] = tab;
+ draft.tabOrder.push(tabId);
+ draft.activeTabId = tabId;
}
// Auto-open sidebar and add to recent
- session.open = true;
- session.recentFiles = [
- file.path,
- ...session.recentFiles.filter((p) => p !== file.path),
- ].slice(0, 10);
-
- draft.sessions[sessionId] = session;
+ draft.open = true;
+ draft.recentFiles = [file.path, ...draft.recentFiles.filter((p) => p !== file.path)].slice(
+ 0,
+ 10
+ );
});
},
- openBrowserTab: (sessionId, initialPath) => {
+ openBrowserTab: (initialPath) => {
set((draft) => {
- const session = draft.sessions[sessionId] ?? createDefaultSessionState();
const tabId = generateTabId("browser");
const tab: BrowserTab = {
@@ -196,105 +180,88 @@ export const useFileEditorSidebarStore = create()(
},
};
- session.tabs[tabId] = tab;
- session.tabOrder.push(tabId);
- session.activeTabId = tabId;
- session.open = true;
-
- draft.sessions[sessionId] = session;
+ draft.tabs[tabId] = tab;
+ draft.tabOrder.push(tabId);
+ draft.activeTabId = tabId;
+ draft.open = true;
});
},
- setActiveTab: (sessionId, tabId) => {
+ setActiveTab: (tabId) => {
set((draft) => {
- const session = draft.sessions[sessionId];
- if (!session) return;
- if (session.tabs[tabId]) {
- session.activeTabId = tabId;
+ if (draft.tabs[tabId]) {
+ draft.activeTabId = tabId;
}
});
},
- closeTab: (sessionId, tabId) => {
+ closeTab: (tabId) => {
set((draft) => {
- const session = draft.sessions[sessionId];
- if (!session) return;
-
- const targetId = tabId ?? session.activeTabId;
+ const targetId = tabId ?? draft.activeTabId;
if (!targetId) return;
// Remove tab
- delete session.tabs[targetId];
+ delete draft.tabs[targetId];
// Remove from order
- const tabIndex = session.tabOrder.indexOf(targetId);
+ const tabIndex = draft.tabOrder.indexOf(targetId);
if (tabIndex !== -1) {
- session.tabOrder.splice(tabIndex, 1);
+ draft.tabOrder.splice(tabIndex, 1);
}
// Update active tab
- if (session.activeTabId === targetId) {
- if (session.tabOrder.length === 0) {
- session.activeTabId = null;
+ if (draft.activeTabId === targetId) {
+ if (draft.tabOrder.length === 0) {
+ draft.activeTabId = null;
} else {
- const newIndex = Math.min(tabIndex, session.tabOrder.length - 1);
- session.activeTabId = session.tabOrder[newIndex] ?? null;
+ const newIndex = Math.min(tabIndex, draft.tabOrder.length - 1);
+ draft.activeTabId = draft.tabOrder[newIndex] ?? null;
}
}
});
},
- closeAllTabs: (sessionId) => {
+ closeAllTabs: () => {
set((draft) => {
- const session = draft.sessions[sessionId];
- if (!session) return;
- session.tabs = {};
- session.tabOrder = [];
- session.activeTabId = null;
+ draft.tabs = {};
+ draft.tabOrder = [];
+ draft.activeTabId = null;
});
},
- closeOtherTabs: (sessionId, keepTabId) => {
+ closeOtherTabs: (keepTabId) => {
set((draft) => {
- const session = draft.sessions[sessionId];
- if (!session) return;
- const tabToKeep = session.tabs[keepTabId];
+ const tabToKeep = draft.tabs[keepTabId];
if (!tabToKeep) return;
- session.tabs = { [keepTabId]: tabToKeep };
- session.tabOrder = [keepTabId];
- session.activeTabId = keepTabId;
+ draft.tabs = { [keepTabId]: tabToKeep };
+ draft.tabOrder = [keepTabId];
+ draft.activeTabId = keepTabId;
});
},
- reorderTabs: (sessionId, fromIndex, toIndex) => {
+ reorderTabs: (fromIndex, toIndex) => {
set((draft) => {
- const session = draft.sessions[sessionId];
- if (!session) return;
- if (fromIndex < 0 || fromIndex >= session.tabOrder.length) return;
- if (toIndex < 0 || toIndex >= session.tabOrder.length) return;
- const [removed] = session.tabOrder.splice(fromIndex, 1);
+ if (fromIndex < 0 || fromIndex >= draft.tabOrder.length) return;
+ if (toIndex < 0 || toIndex >= draft.tabOrder.length) return;
+ const [removed] = draft.tabOrder.splice(fromIndex, 1);
if (removed) {
- session.tabOrder.splice(toIndex, 0, removed);
+ draft.tabOrder.splice(toIndex, 0, removed);
}
});
},
- updateFileContent: (sessionId, tabId, content) => {
+ updateFileContent: (tabId, content) => {
set((draft) => {
- const session = draft.sessions[sessionId];
- if (!session) return;
- const tab = session.tabs[tabId];
+ const tab = draft.tabs[tabId];
if (!tab || tab.type !== "file") return;
tab.file.content = content;
tab.file.dirty = content !== tab.file.originalContent;
});
},
- markFileSaved: (sessionId, tabId, timestamp) => {
+ markFileSaved: (tabId, timestamp) => {
set((draft) => {
- const session = draft.sessions[sessionId];
- if (!session) return;
- const tab = session.tabs[tabId];
+ const tab = draft.tabs[tabId];
if (!tab || tab.type !== "file") return;
tab.file.dirty = false;
tab.file.originalContent = tab.file.content;
@@ -302,102 +269,75 @@ export const useFileEditorSidebarStore = create()(
});
},
- toggleMarkdownPreview: (sessionId, tabId) => {
+ toggleMarkdownPreview: (tabId) => {
set((draft) => {
- const session = draft.sessions[sessionId];
- if (!session) return;
- const tab = session.tabs[tabId];
+ const tab = draft.tabs[tabId];
if (!tab || tab.type !== "file") return;
if (tab.file.language !== "markdown") return;
tab.file.markdownPreview = !tab.file.markdownPreview;
});
},
- setBrowserPath: (sessionId, tabId, path) => {
+ setBrowserPath: (tabId, path) => {
set((draft) => {
- const session = draft.sessions[sessionId];
- if (!session) return;
- const tab = session.tabs[tabId];
+ const tab = draft.tabs[tabId];
if (!tab || tab.type !== "browser") return;
tab.browser.currentPath = path;
});
},
- setVimMode: (sessionId, enabled) => {
+ setVimMode: (enabled) => {
set((draft) => {
- const session = draft.sessions[sessionId] ?? createDefaultSessionState();
- draft.sessions[sessionId] = { ...session, vimMode: enabled };
+ draft.vimMode = enabled;
});
},
- setVimModeState: (sessionId, state) => {
+ setVimModeState: (state) => {
set((draft) => {
- const session = draft.sessions[sessionId] ?? createDefaultSessionState();
- draft.sessions[sessionId] = { ...session, vimModeState: state };
+ draft.vimModeState = state;
});
},
- setWrap: (sessionId, enabled) => {
+ setWrap: (enabled) => {
set((draft) => {
- const session = draft.sessions[sessionId] ?? createDefaultSessionState();
- draft.sessions[sessionId] = { ...session, wrap: enabled };
+ draft.wrap = enabled;
});
},
- setLineNumbers: (sessionId, enabled) => {
+ setLineNumbers: (enabled) => {
set((draft) => {
- const session = draft.sessions[sessionId] ?? createDefaultSessionState();
- draft.sessions[sessionId] = { ...session, lineNumbers: enabled };
+ draft.lineNumbers = enabled;
});
},
- setRelativeLineNumbers: (sessionId, enabled) => {
+ setRelativeLineNumbers: (enabled) => {
set((draft) => {
- const session = draft.sessions[sessionId] ?? createDefaultSessionState();
- draft.sessions[sessionId] = { ...session, relativeLineNumbers: enabled };
+ draft.relativeLineNumbers = enabled;
});
},
- addRecentFile: (sessionId, path) => {
+ addRecentFile: (path) => {
set((draft) => {
- const session = draft.sessions[sessionId] ?? createDefaultSessionState();
- const existing = session.recentFiles.filter((p) => p !== path);
- draft.sessions[sessionId] = {
- ...session,
- recentFiles: [path, ...existing].slice(0, 10),
- };
+ const existing = draft.recentFiles.filter((p) => p !== path);
+ draft.recentFiles = [path, ...existing].slice(0, 10);
});
},
- resetSession: (sessionId) => {
- set((draft) => {
- draft.sessions[sessionId] = createDefaultSessionState();
- });
+ reset: () => {
+ set(() => ({ ...initialState }));
},
}))
);
-// Cached default state to avoid creating new objects on every selector call
-const DEFAULT_SESSION_STATE: FileEditorSessionState = Object.freeze({
- ...createDefaultSessionState(),
- tabs: Object.freeze({}) as unknown as Record,
- tabOrder: Object.freeze([]) as unknown as string[],
- recentFiles: Object.freeze([]) as unknown as string[],
-});
-
-export function selectSessionState(state: FileEditorSidebarState, sessionId: string) {
- return state.sessions[sessionId] ?? DEFAULT_SESSION_STATE;
-}
-
-// Helper to get active tab from session
-export function selectActiveTab(session: FileEditorSessionState): Tab | null {
- if (!session.activeTabId) return null;
- return session.tabs[session.activeTabId] ?? null;
+// Helper to get active tab
+export function selectActiveTab(state: FileEditorSidebarState): Tab | null {
+ if (!state.activeTabId) return null;
+ return state.tabs[state.activeTabId] ?? null;
}
// Helper to get active file tab (if active tab is a file)
-export function selectActiveFileTab(session: FileEditorSessionState): FileTab | null {
- const tab = selectActiveTab(session);
+export function selectActiveFileTab(state: FileEditorSidebarState): FileTab | null {
+ const tab = selectActiveTab(state);
if (!tab || tab.type !== "file") return null;
return tab;
}
@@ -420,8 +360,3 @@ export function getTabDisplayName(tab: Tab): string {
}
return "Unknown";
}
-
-// Helper to generate stable file tab ID from path
-export function fileTabIdFromPath(path: string): string {
- return `file:${path}`;
-}