Repository navigation
How Terminal Features Work
Split terminals, find, clickable file paths, dropped files, rename, the visual bell and the optional xterm addons. The shell, the PTY and the views are in How the terminal works; the user side is in Terminal Features.
People expect to split a terminal, search its output with Cmd+F and Cmd+click src/app.ts:12:5 in a compiler error. Memory is a feature in Nibtree, so every optional part has a switch, loads only when it is on, and frees its memory when it is turned off or the terminal closes.
terminalAddonPlan in options.ts turns the settings into what one terminal loads: WebGL, Unicode 11, search and file links. TerminalAddons in addons.ts (inside the lazy xterm.ts chunk) owns them per terminal; each addon is its own chunk, imported the first time it is needed.
flowchart LR
Settings["settings<br/>terminalGpuAcceleration, ..."] --> Plan["terminalAddonPlan"]
Plan --> Effect["TerminalView effect"]
Effect -->|"on (WebGL: once visible)"| Load["import() the addon<br/>loadAddon"]
Effect -->|"off, even hidden"| Free["dispose()"]
Load -->|"WebGL fails or context lost"| Dom["DOM renderer"]
Close["terminal closes"] --> Free
-
WebGL (
@xterm/addon-webgl): loaded when the terminal first shows, since it measures cells as it starts. A failedloadAddon(no WebGL2) oronContextLoss(too many contexts, a GPU reset) disposes it and marks the terminal as broken, so it stays on the DOM renderer until the setting is turned on again. Ligatures are CSS on the DOM renderer's rows, so ligatures on means no WebGL. Hidden terminals keep it: releasing it saved nothing (200 vs 199 MB). -
Unicode 11 (
@xterm/addon-unicode11): registers its width table once per terminal and switchesterm.unicode.activeVersionbetween"11"and"6". xterm cannot unregister a version, so off keeps the small table until the terminal closes. -
Search (
@xterm/addon-search): waits until the find bar first opens; turning Find off closes the bar and disposes the addon with its highlights.
Unicode versions and search decorations are xterm's proposed API, so the terminal is created with allowProposedApi: true. Option as Meta and smooth scrolling are plain options (macOptionIsMeta, smoothScrollDuration) written by applyChangedOptions.
TerminalFindBar.svelte (the library's FloatingFindBar) sits over the terminal's top right corner; TerminalFind (terminalFind.svelte.ts) keeps the query, the toggles and the results. find.ts maps the toggles to xterm's names, builds the highlight colors from the --warning and --term-background tokens (the addon needs opaque #rrggbb), counts ("3 of 12", "1000+") and decides the keys. Typing calls findPrevious with incremental, so the first match is the newest output, and Enter keeps going up. keys.ts returns "find" for Cmd+F (Ctrl+Shift+F elsewhere) only while the setting is on, so with it off the key is left alone.
sequenceDiagram
participant X as xterm (hover)
participant V as TerminalView provider
participant L as fileLinks.ts
participant C as FileExistenceCache
participant R as real_files (Rust)
X->>V: provideLinks(line)
V->>L: lineCells(cells), then fileLinksForLine
L->>L: findPathCandidates, resolve, keep inside the workspace
L->>C: realPaths(paths)
C->>R: unknown paths, one call per line
R-->>C: real path or null per path
L-->>V: links with string offsets
V-->>X: ILink ranges in cells
xterm asks the link provider only for the line under the pointer, so there is no scanning of the whole buffer. findPathCandidates finds path, path:line, path:line:col and path(line,col), skips URLs (the web links addon has them) and adds git's a/ and b/ paths without the prefix. Relative paths resolve against the folder the shell last reported with OSC 7 (parseOsc7), else the start folder. Only paths inside an open workspace folder are checked, with real_files in file_ops.rs (canonical path inside a root, not in .git, a regular file, at most 64 per call, never an error). Its real path answer keeps other letter case to one tab (Windows paths). The cache keeps answers only for what is on screen: onScroll clears it. lineCells maps string offsets to cells, because wide characters take two cells.
Each link starts without an underline. Hovering adds key listeners, and Cmd (Ctrl) down or up flips decorations.underline and pointerCursor, which xterm tracks, so the underline shows only with the modifier. Activating calls navigation.openFileAt.
Every TerminalEntry has a group. Panel terminals with the same group form a split; a new split goes right after its source in the list, so a group's members stay together. splitPanes.ts holds the rules: terminalGroups, groupMembers, normalizeSizes, sizesAfterSplit (halves the source pane), sizesAfterClose (the neighbor takes the room) and resizePanes (a divider moves width between two panes, never below MIN_PANE_WIDTH). Sizes are fractions, kept per group for the session in groupSizes.
TerminalPanel.svelte draws the active terminal's group with the UI library's PaneRow, whose handles resize the split, and registers each pane's ElementHost with setPaneSlot; slotFor sends a panel terminal to its pane, or to the view area while its group is hidden. TerminalFrame hides frames that are not shown, so an empty frame never covers a pane. Focus follows click: focusin on a view calls focusPane, which makes it the active terminal without stealing focus. panelAfterLeave hands over to a pane of the same group first.
TerminalHost listens to onDragDropEvent only while a terminal exists and the setting is on. It finds the view under the point (terminalKeyAt reads the screen's id, terminalScreenId) and sends it a custom event; the view types dropText (POSIX single quotes, double quotes on Windows) with paste. The Files panel skips points over a terminal, so one drop is never handled twice. Rename in place sets the same session-only name as Rename.... onBell flashes a visible terminal or sets bell on the entry, shown as a dot until the terminal shows.
| File | What it does |
|---|---|
src/lib/terminal/addons.ts |
TerminalAddons: search, WebGL with fallback, Unicode 11 |
src/lib/terminal/find.ts, TerminalFindBar.svelte
|
Find logic and the bar |
src/lib/terminal/fileLinks.ts |
Candidates, resolving, OSC 7, cells, FileExistenceCache
|
src/lib/terminal/splitPanes.ts |
Groups and pane sizes |
src/lib/terminal/dropPaths.ts |
Quoting and the drop events |
src/lib/terminal/TerminalView.svelte, terminalActions.ts, terminalLinks.ts, TerminalPanel.svelte, TerminalHost.svelte
|
The glue: keys, clipboard, menu, file links |
src-tauri/src/file_ops.rs (real_files, existing_files), commands/file_ops.rs (real_files) |
The existence check and real path |
Lazy and disposable. Each addon is its own chunk. With every switch off, a terminal loads only xterm, fit and web links, as before. Off frees memory at once, even for hidden terminals; WebGL waits until the terminal shows.
One backend call per hovered line, not a watcher or a file list: hovering is rare and cheap, and the answers go on scroll.
Splits in groups, not a tree. Splitting side by side in a row covers the common case; a row per group keeps the rules small and testable.
Enter goes up in find, since the newest output is at the bottom.
-
src/lib/terminal/find.test.ts,fileLinks.test.ts,splitPanes.test.ts,dropPaths.test.ts. -
keys.test.ts(find and split keys),options.test.ts(terminalAddonPlan, Option as Meta, smooth scrolling),terminalTabs.test.ts(the split rule ofpanelAfterLeave),settingsData.test.ts(the new keys and defaults). -
files_exist_reports_only_files_inside_the_workspaceandreal_files_name_files_the_way_the_disk_doesincommands/tests.rs.
WebGL fallback, hover underlines, drops from Finder and dragging the divider need a check in the real app.
- Update this page, Terminal Features and Settings Reference when a switch, an addon or a rule changes.
- Retake
terminal-find.pngandterminal-split.png(Docs and Screenshots).
The terminal bugs and their fixes are in Terminal Bugs We Fixed.
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