Repository navigation
How the Files Panel Works
The Files panel is the tree on the right: every workspace folder, each file colored by its git status, opening in editor tabs. The user side is in Files Panel.
People want to browse and open files in the app, and see what git did to each file with the usual U, A, M, D, R, T and C letters. A workspace can be huge (think node_modules), so the panel loads one level at a time, renders only visible rows and frees collapsed folders.
ExplorerTree (explorerTree.svelte.ts) keeps loaded folders in children, keyed by the absolute folder path, and open folders in expanded, as nodes for the library's Tree. Opening a folder loads it:
sequenceDiagram
participant Tree as explorerTree.svelte.ts
participant Api as api.ts
participant Cmd as commands/files.rs
participant Fs as git/files.rs
Tree->>Tree: folderFor(folders, dirPath)
Tree->>Api: listDirectory(folder.root, relative dir, repoRoots)
Api->>Cmd: list_directory
Cmd->>Cmd: canonical_dir, safe_join, canonicalize repo roots
Cmd->>Fs: list_dir(full_dir, dir_path, repo_roots)
Fs->>Fs: deepest repo decides ignored, mark isRepo
Fs-->>Tree: entries (folder-relative), truncated
Tree->>Tree: joinPath to absolute, store in children
list_dir hides .git, follows symlinked folders, and sorts folders first. A folder with more than MAX_ENTRIES (5,000) entries sets truncated and keeps the first 5,000 in sort order. Only the deepest repository that contains the listed folder decides what is ignored, so each call opens at most one repository. A repository root gets isRepo and is never dimmed, even when the parent's .gitignore lists it.
The panel reuses repoStore.statuses instead of asking the backend. workspaceFiles joins every repository's changed files to absolute paths, and three pure helpers in tones.ts turn them into marks:
flowchart TD
F["FileStatus of a file"] --> C{"conflicted?"}
C -->|yes| LC["C, conflict tone"]
C -->|no| U{"work tree untracked or deleted?"}
U -->|yes| LW["U or D"]
U -->|no| S{"staged change?"}
S -->|yes| LS["letter of the staged kind"]
S -->|no| LU["letter of the unstaged kind"]
LC --> P["tonesByPath raises every parent folder<br/>to the strongest tone inside"]
LW --> P
LS --> P
LU --> P
-
marksByPathgives each file its letter and a tooltip such as "Added (staged), modified (not staged)". The work tree wins over the index. -
tonesByPathcolors files and gives every folder the strongest tone of its contents (conflict, then modified, then added, then deleted). -
deletedByFolderlists files deleted from disk, soentriesOfcan show them struck through in the folder they came from.
rows flattens the expanded tree into a list. With several folders, each folder becomes a top-level row. Rows are 24 px high and only the visible slice (plus OVERSCAN rows) is rendered.
An effect watches repoStore.statuses, repoStore.workspaceVersion and repoStore.repos, and after 250 ms refreshLoaded reloads the roots and every expanded folder. For the watcher events, see How folder watching works.
A single click calls repoStore.openFile(path), which opens a preview tab. A double click passes { pin: true }. Arrow keys and Enter move through the tree; Cmd-click, Shift-click and Shift+arrows select several rows (selection.ts). The context menu (openMenu) builds its items from the row:
- Open, Open Preview and Resolve Conflict (
repoStore.openMerge) on files; Expand, Set as Active Repository, Initialize Repository Here and Add or Remove Folder on folders. - New File, Cut, Copy, Paste, Rename, Move to Trash and the rest from
fileOpGroups, plus drag and drop. See How file operations work. -
Add to .gitignore from
ignoreMenu(src/lib/ignore/ignoreActions.ts), for anything inside a repository except its root. -
Reveal in Finder calls the opener plugin's
revealItemInDir.revealLabelinreveal.tsnames it per platform: Reveal in File Explorer on Windows, Open Containing Folder on Linux. -
Open in Integrated Terminal calls
terminalStore.create({ folderPath })withterminalFolderFor: the folder itself, or a file's parent folder. - Copy Path and Copy Relative Path.
Select Opened File (the header crosshair) runs selectOpenedFile: foldersToOpen (locate.ts) lists the folders down to the file, the panel expands and loads them and selects the file, and after a tick centeredScrollTop centers its row. It is greyed out while openedFile is null (a pseudo tab or a file outside the workspace).
A deleted file only gets Show in Changes and the copy items. Files stored in Git LFS get an "LFS" tag: while the panel is open, lfsStore.follow reads each repository's LFS files once per status refresh.
The panel is shown by settings.explorerOpen. The Files icon in RightActivityBar.svelte and Cmd+B call settings.toggleExplorer().
| File | What it does |
|---|---|
src/lib/views/files/FileExplorer.svelte |
The panel: header, the library Tree, clicks and keys |
src/lib/views/files/explorerTree.svelte.ts |
Loaded folders, open folders, selection, the Tree's nodes |
src/lib/views/files/explorerLook.ts |
Row tones and marks |
src/lib/views/files/tones.ts |
marksByPath, tonesByPath, deletedByFolder
|
src/lib/views/files/reveal.ts |
revealLabel, terminalFolderFor
|
src/lib/views/files/locate.ts |
foldersToOpen for Select Opened File (the Tree centers the row) |
src/lib/views/RightActivityBar.svelte |
The Files toggle on the right edge |
src/lib/views/Workspace.svelte (on the library's AppShell), workspaceShortcuts.ts
|
Panel widths and the Cmd+B shortcut |
src/lib/ui/ResizeHandle.svelte |
The drag handle that resizes the side panels |
src-tauri/src/commands/files.rs |
list_directory and read_worktree_file
|
src-tauri/src/git/files.rs |
list_dir, ignore checks, read_file
|
src-tauri/src/commands/mod.rs |
safe_join, which refuses paths that escape the folder |
src/lib/stores/workspacePaths.ts |
folderFor, joinPath, relativeTo, locateAbsolute
|
Load one level at a time. A full tree of a big workspace would cost seconds and memory.
Collapse frees memory. collapse deletes the loaded contents below a folder, so memory does not only grow.
Reuse the store's statuses. A second status call per folder would repeat work the Changes sidebar already did.
The deepest repository decides ignores. Checking every repository would open many per call and could disagree with git about nested repositories.
Show deleted files in place. A struck-through name where the file used to be is clearer than a missing row.
Select the opened file only on request. Following every tab change would open and load many folders, against collapse freeing memory.
Open the terminal in a folder, never on a file. A shell cannot start in a file, so a file opens its parent folder.
The nested repository that showed as an untracked folder is in How Workspaces Work.
The editor could be squeezed too narrow.
- The issue: wide side panels could squeeze the editor below its minimum width.
- Why it happened: the width limits ignored the two activity bars.
-
The fix and why we chose it:
ACTIVITY_BARS(44 px per visible bar) is part of thesidebarMaxandexplorerMaxmath, so the editor keepsMIN_MAIN(360 px) and a panel never goes belowMIN_PANEL(200 px).
A huge folder showed a random 5,000 entries.
- The issue: a folder with more than 5,000 entries showed 5,000 of them, but not the first 5,000 by name.
-
Why it happened:
list_dirstopped reading at the limit in file system order and only then sorted. -
The fix and why we chose it:
list_dirreads every name, keeps the first 5,000 in sort order in a small heap and checks ignores only for those, so memory stays bounded.
-
src-tauri/src/commands/tests.rs:list_directory_sorts_folders_first_and_marks_ignored_entries,list_directory_rejects_paths_outside_the_work_treeandlist_directory_uses_the_deepest_repository_for_ignores. -
src-tauri/src/git/files.rs:cut_off_listings_keep_the_first_entries_in_sorted_order,a_folder_past_the_limit_still_lists_its_folders_first,linked_folders_count_as_folders. -
src/lib/views/files/tones.test.ts: folder tones, status letters, staged new files and deleted files per folder. -
src/lib/views/files/reveal.test.ts: the Reveal label per platform and the terminal folder of a file or folder. -
src/lib/views/files/locate.test.ts: the folders to open for a file, and when and where the list scrolls.
The virtual scrolling and menus need a visual check. See Testing.
- Update this page when
list_dir, the status letters, the row size or the menu items change. - Update Files Panel for any visible change.
- Retake
files-panel.png,files-context-menu.pngandinit-repository.pngwhen the tree or its menu changes. See Docs and Screenshots.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode