* fix(terminal): Line height, colour palette and tab names
- Line height: with "Use editor font" the terminal took the editor's roomier
line height (about 1.33 cells), stretching ASCII art and box drawing. It now
always uses Settings › Tools › Terminal › Line height (default 1.0); that
field moves out of the "Use editor font" group since it applies either way.
- Colours: the terminal gets its own --terminal-ansi-* palette (the light and
Darcula terminal colours); the Run console keeps --ansi-*. High-contrast and
palette themes keep their console colours. Colours below a 4.5:1 contrast
with the background are adjusted (xterm's minimumContrastRatio), so yellow
stays readable on white.
- Tab names: tabs keep their default name ("Local", "Local (2)") at the prompt
and show the title a program sets only while a command runs. Shell
integration now marks command start and end (OSC 133 C / D) for zsh,
bash 4.4+ (PS0) and fish.
* fix(themes): Document the terminal ANSI palette for theme plugins
The --terminal-ansi-* tokens belong in a theme's editor colour scheme, like
--ansi-*. The theme plugin template sets them and the token reference lists them.
Switching between agent session tabs in the editor now moves the Agents
tool window's selection to that task, expanding its group (e.g. Archived)
when it is collapsed. The list also opens with the active session selected.
Tabs of other kinds leave the selection as it is.
The editor service gains activeInput() and onActiveInputChange() so
features can follow the active tab of any kind.
Run oxfmt once over the whole repository (formatting only, no logic changes) and add `pnpm format:check` to the frontend CI job so unformatted code no longer builds up. `.oxfmtrc.json` now skips the generated theme docs, test fixtures and code blocks inside Markdown.
Co-authored-by: jaw52 <53564781+jaw52@users.noreply.github.com>
The Branch filter in the Git log opens a popup with a search field instead of a plain menu. Branches are fuzzy-matched with highlights and grouped under HEAD, Local and Remote; arrow keys skip the group headers and Enter applies the filter. The list is virtualized so large repositories stay responsive, and Select… still opens the multi-branch / custom revision chooser.
Co-authored-by: zzxzz12345 <8338183+zzxzz12345@users.noreply.github.com>
Dragging the bottom tool window edge over a terminal refit xterm on every
pointer move and sent each intermediate size to the shell, which redrew its
prompt every time. Terminals now refit at most every 100 ms while their host
keeps resizing, plus once when it stops, and the process only learns the size
once it has held for 150 ms. This covers the Terminal tool window and terminals
embedded in Run consoles.
Resizing the width of an agent conversation reflowed every entry, including the
off-screen ones (14-16 ms per move in a long session). Entries now use
content-visibility: auto, so only the visible ones are laid out.
Code previews (Find in Files, Usages) are non-editable CodeMirror views, so their text inherited the workbench's user-select: none and had no tab stop: it couldn't be focused, selected with the keyboard or copied. Previews now opt their content back in with the shared selectable-text class and take a tab stop; editing stays blocked. Same root cause as the read-only diff panes (#126).
Read-only revision panes inherited the workbench's user-select: none and had no tab stop, so text couldn't be selected with the mouse or keyboard or copied. The viewer content now allows text selection and read-only panes take focus; editing stays blocked.
Once focusable, these panes picked up CodeMirror's dark-theme focused selection colour, which outranked the viewer's rule and made selected text unreadable in light themes; the viewer's selection rule now matches that specificity.
Co-authored-by: dvictor357 <187467850+dvictor357@users.noreply.github.com>
When a list item's text was followed by a nested list and a selection ended at
the end of that text, WebKit painted a thin strip of selection from there to the
right edge. The text of such items now gets its own block.
Dragging a tool window edge set an inherited custom property on the tool window
grid, so every pointer move restyled the whole workbench below it. With a long
agent conversation open each move cost 150-400 ms. The grid track variables are
now registered as non-inherited, and the side splitter sets flex-grow on its two
areas instead of inherited variables on the side.
* feat(agents): Show subagents as their own conversations
Agents that support ACP subagent sessions (Claude Code, Codex) now run each
subagent as a child session. Its tool calls and messages no longer mix into
the task's conversation: the parent shows a card per subagent with its state,
tool call count, latest step, task and result, and the card opens the
subagent's own conversation.
- Route session/update by session id; subagent settings and usage stay out
of the task.
- Subagent permission requests are answered in the task's conversation,
named after the subagent.
- Subagent conversations are saved with the task; a running subagent is
marked stopped after a restart.
- A running subagent can be stopped on its own.
* fix(agents): Save a subagent's state when it changes after the turn
Removing a language server (disabled in settings via stop_unlisted, or a fallback detached when its preferred server comes back) only emitted a stopped state, and the status bar list only refreshed for unknown servers, so the removed server stayed until the project was reopened. Both paths now go through forget(), which drops the server and emits IdeEvent::LanguageServerRemoved; the frontend drops the entry and ignores stale lsp_servers results that still contain it. Stopped servers no longer count towards "+N".
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
ty (`ty server`) joins basedpyright and Pyright as a Python language server (fallback, gets the project venv like the others, installable from Tools). Settings › Language Servers gets a Python language server picker: Automatic (first available), basedpyright, Pyright, ty or None, written through the per-server enabled settings (null globally / true in a project for enabled, false for disabled); other combinations show as Custom combination. Picker text is translated; the hint sits on its own line.
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
Co-authored-by: zzxzz12345 <8338183+zzxzz12345@users.noreply.github.com>
* fix(agents): Leave changes made before a local checkout task out of its changes
A task in the project's own checkout listed every uncommitted and untracked
file as its own. The files already changed when the task starts are now
recorded with their size and modification time, and drop out of the task's
changes until they are edited again.
* feat(agents): Show the current branch for a local checkout task
* fix(app): Survive panics in background work and log them
A panic in background work (a spell check, an LSP handler) aborted the whole
app and left nothing behind: the message went to stderr, which a launched app
doesn't keep, and the stripped binary gave crash reports no function names.
- Release builds unwind, so a panic fails one task or command instead of
quitting the IDE. Commands already turn a panicked blocking task into an
error, and the existing catch_unwind around JSON-RPC notification handlers
now takes effect.
- A panic hook appends the thread, location, message and backtrace to the
log file synchronously, before the non-blocking writer could lose them.
- Release builds keep the symbol table (strip = "debuginfo"), so crash
reports and logged backtraces name functions.
* test(app): Match the panic location with file!() so the test passes on Windows
pnpm lint runs oxlint and pnpm format runs oxfmt: lint ~0.3s instead of ~20s, format check ~0.2s instead of ~11s, with far less memory. Configs come from the official migration tools (.oxlintrc.json from eslint.config.js, .oxfmtrc.json from the Prettier config); six new findings fixed or suppressed in 4 files. No code is reformatted.
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
Co-authored-by: jaw52 <53564781+jaw52@users.noreply.github.com>
known_run stepped one byte past the delimiter before a word run, which lands inside a multi-byte character (Chinese punctuation, emoji) and panics when slicing. It now steps past the whole character. Regression test with Chinese punctuation and emoji.
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
Co-authored-by: zzxzz12345 <8338183+zzxzz12345@users.noreply.github.com>
Fixes#117
Inside an AppImage, AppRun and the linuxdeploy GTK/GStreamer hooks point LD_LIBRARY_PATH, PATH, XDG_DATA_DIRS, GIO_MODULE_DIR, GTK_PATH, GST_PLUGIN_* … into the mounted image, and every child inherited them, so host programs loaded the image's older libraries (curl + bundled nghttp2 → symbol lookup error when installing Kotlin LSP). ide_core::process::prepare (formerly no_window) now gives children the host environment back: entries inside $APPDIR are dropped (a <NAME>_ORIG wins), emptied variables and the runtime's launch variables are removed, explicit call-site values are kept; the IDE process itself is unchanged. Covers all spawn sites that used no_window plus terminal/run PTYs, run configuration environments and stop commands, login-shell probes, attach ps/kill, docker PATH, tool search PATH and the Linux browser opener. No-op outside an AppImage. Not verified on a Linux AppImage.
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
Multi-repo branch popup matches actions by their translated label (highlights and Chinese search now work) and translates its group headers. Conflict counts, relative times (shared dateFormat), in-progress operation titles, git operation progress/results, branch widget tooltips, diff/hunk counts, worktree markers, PR author line and review placeholders go through tx; the default "Changes" changelist shows its translated name. HexViewer read-only leaves the untranslated allowlist. 92 zh entries.
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
Hard-coded UI text, titles and aria-labels in about 110 components (Git panels, hierarchy, pull requests, dialogs, settings, welcome) now go through tx; spliced fragments became whole sentences (fileCount, noneFoundLabel, hierarchyTitle) and pull request states use keyed messages. 225 zh entries added, stale fragment entries removed.
Also: tx used as a tag without interpolations (tx`No checks`) now looks the text up exactly instead of as a template, so it is translated like tx("No checks"); the text-catalog test checks such tags as plain literals. Check and test counts reuse the existing "{count} passed" / "{failed} failing" entries.
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
Co-authored-by: jaw52 <53564781+jaw52@users.noreply.github.com>
A local-checkout task shows the repository's current branch in its header, and
Changes compares against it; both follow branch switches. The header also shows
the time the agent has spent on the task's turns.
A usage update without a cost (Claude sends one for its rate limits) no longer
clears the session cost.
With a line height above 1, xterm's DOM renderer stretched the cursor cell
over the full row. Size it to the font's own height and centre it with the glyphs.
- The title bar project popup lists Remote Development… next to Open… and Clone Repository….
- Opening a remote project follows "Open project in" (new window / this window / ask) when this window already has a project, and confirms leaving the current one first.
- A remote project already open in another window focuses that window.
- A new window connects to the host itself and shows the connection progress on its welcome screen.
- Recent remote projects get Open in New Window.
- Agents sits right after Project on the left stripe.
- The separator between a stripe's primary and split windows only shows
while a button is dragged, as a drop target.
- "Show tool window names" is off by default: stripes start at their
narrowest width with icons only.
* feat(spell): Fewer false typos: programming terms, British spellings, possessives
- Bundle ~8.7k programming terms, tool and library names from cspell-dicts (MIT),
plus a hand-kept list of tool names, file names and abbreviations. These pass on
their own but never as part of an identifier compound.
- Accept en_GB spellings (colour, behaviour, normalise, cancelled) alongside en_US.
- Possessives of known words pass (backend's); programming terms take -ed / -ing /
-able endings (stringified, memoizing).
- Plurals of terms no longer accept doubled or already-inflected forms (filess,
contextes, checkings), and agent nouns aren't built from abbreviations (perfer).
- A word split from a known term is checked as the whole term (IntelliJ, PostgreSQL).
- Settings › Natural Languages lists English (USA, UK).
* chore: Regenerate bindings
The task title starts as the first line of the prompt. When the agent sends
a session_info_update with a title, the task takes that title, saves it and
shows it in the Agents list.
Replace the mark, app icon, wordmarks and splash logo with the new
design: an orange-framed dark tile with a monospace "oi" on a light
rounded backdrop. Platform icons (png/icns/ico) are regenerated from
src-tauri/icons/source/openidea.svg.
- Group pages open with a short description and list their pages as
indented links.
- The page tree starts collapsed, expanding only the current page's
ancestors.
- The Settings window title bar sits on the dialog surface without a
hairline.
The bar read the theme's default --accent as soon as the tokens loaded,
so a custom accent flashed back to the default until settings arrived.
It now prefers the accent remembered from the last session.
* feat(agents): Select, copy, quote and search the conversation
- Conversation text can be selected and copied.
- Selected text gets a Quote button that replies to it in the composer.
- Messages have Copy on hover; your own messages also have Edit and
Resend and Send Again.
- Code blocks are highlighted and have a Copy button.
- File paths in replies (`src/lib.rs:12`) open in the editor when the
file exists.
- Find in Conversation (⌘F / Ctrl+F) highlights every match and steps
through them, opening collapsed tool output.
- Jump to Bottom appears after scrolling up.
- Your messages show when they were sent and how long the agent took;
a running turn shows its elapsed time.
* feat(agents): Quote a selection from the context menu
* feat(agents): Drop Jump to Bottom from the conversation
* feat(agents): Drop the hover Copy button from agent messages
* fix(agents): Highlight only the find matches on screen
WebKit paints a highlight range inside a collapsed tool output over the
text next to it. Matches in collapsed output still count, and stepping
to one expands it.
* fix(agents): Repaint find highlights as the search changes
WebKit doesn't repaint where a replaced highlight object was, so matches
of an earlier search stayed painted; each highlight is now one object
changed in place.
* feat(editor): Drag tabs and files between split panes
HTML5 drag and drop never reaches the webview while native file drop is
enabled, so tab, project-file and changelist drags did nothing. They now
run on pointer events:
- Drag an editor tab onto another pane, or onto a pane's edge to split it.
- Drag files from the Project view into an editor pane (center opens them
there, an edge opens them in a new split).
- Drag files between changelists in the Commit view.
- "Drag-and-drop with Alt pressed only" applies to tabs and stripe buttons.
* fix(lsp): Deliver server settings and start servers on a supported JDK
- workspace/configuration answers a server's own section (basedpyright)
from its settings block; basedpyright runs in "standard" mode and keeps
auto search paths on, so `src/` layouts resolve from `tests/`.
- jdtls: formatting follows the editor indent, calls complete without
guessed arguments, and JDK internals stay out of completion.
- `max-java` in a language server config picks an installed JDK no newer
than that (kotlin-language-server fails on JDK 25).
- Server initialization may take up to 5 minutes (first Gradle import).
- `lsp_resend_diagnostics` re-emits stored diagnostics after a reload.
- Spelling only checks declared names (not called methods like
`substring`) and accepts plurals of known software terms.
* feat(editor): Quick fixes, completion and navigation while typing
Quick fixes
- Errors get a red quick-fix bulb; Apply Quick Fix (⌥⇧↵) fixes the most
severe problem at the caret, and the error hover offers the fix directly.
- Code generated by a code action is re-indented to the file's style.
- Python: Implement abstract methods (⌃I or the bulb) from the bases.
- Duplicate code actions are listed once.
Completion
- Overloads sharing a name, and a name importable from several modules,
are no longer merged into one entry.
- Auto-import entries show the module they import from.
- Call snippets without a stop (`new ArrayList<>()`) leave the caret inside
the parentheses with parameter info, or past them when nothing takes
arguments; parameter info also opens after server call snippets.
- The selected item is resolved ahead of acceptance, so its auto-import
is applied (rust-analyzer).
Navigation and diagnostics
- Language server requests wait for pending edits, so Go to Declaration
right after typing answers for the current text; an empty answer right
after an edit is retried while the server catches up.
- Diagnostics come back after a window reload; error underlines stay
visible under typo / unused highlighting.
- Implementation gutter markers no longer refresh in a loop while the
server reports progress.
- A missing alternative server no longer shows as a server error.
* chore(lint): Skip agent worktrees under .claude
* fix(editor): Skip cancelled LSP requests and limit generated-code reformat
- Requests cancelled while waiting for pending edits are not sent.
- Code generated by an action is reformatted per changed hunk, so an added
import doesn't reformat the code between it and the generated lines.
- A long busy spell caused by a settle refresh re-runs it only once.
- Files dropped on a file row of another changelist move to that changelist.
- Python Implement methods: a nested class without bases ends the lookup,
class bodies continue through unindented string lines, and
`@abstractproperty` stubs become `@property`.
- Resend diagnostics goes through the host ops, and custom servers get
`max_java`.
* fix(editor): Rank the exact type first in Java constructor completion
jdtls appends the call or body to filterText (`String(${0})`); matching
on the label instead lets typing `String` rank `String` above
`StringBuilder` and the other types sharing its sort text.
* fix(editor): List identical completion items once
kotlin-language-server repeats a class once per classpath entry declaring
it, so `String()` and `String` were listed three times each.
* fix(editor): Keep the internal cancellation message out of the UI text catalog
Language servers can be configured from settings.toml (global or project) and Settings › Language Servers: arguments, environment, initialization options and workspace settings per server, enable/disable, and any stdio LSP server can be added for a language. Settings-only changes are pushed with workspace/didChangeConfiguration; launch changes restart the server.
Also: re-enabling a server now detaches and stops the fallback that stood in for it, and a server added from the dialog is written as its own [languageServers.<name>] table.
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
`ide-lsp` tests failed intermittently (about 1 run in 4, more under load).
The main cause, requests from the other side starting before earlier notifications, is fixed on main by b5bc150; this adds a regression test for it in `ide-jsonrpc`, documents that `on_notification` must not wait for the remote side, and drops the 200 ms polling workaround in `ide-agent` that papered over the same race for `session/request_permission`.
Test-only races fixed: mock replies are held with a gate instead of fixed sleeps and timing asserts; the indexing-retry test ends indexing after the first reply; the crash test counts Ready/Crashed transitions instead of reading the last status; the mock records a notification and applies its effect under one lock; `eventually` waits up to a deadline; `tcp_server` reserves its port with a bound socket and waits for the server's start marker.
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
A save that ran after delete (from the turn ending or the agent exiting)
wrote the task file back, so the task returned on the next load. Deleting
now marks the task under the lock that saving holds.
- Save the Rust cache only on main; pull requests restore it.
- Check bindings against the file nextest's export_bindings already wrote
instead of compiling the test again.
- Run e2e in its own job on the Playwright image, in parallel with the
frontend checks, without installing browsers on each run.
- Cancel a run in progress when a newer push arrives, on main too.
Requests from the other side were handed to the blocking pool as soon as
they were read, while notifications run in order on their own thread, so a
request could be handled before an earlier didOpen. Requests now start from
the same ordered queue.
Jump to Source moves next to Next Difference in the diff toolbar, with the edit (pencil) icon. Diffs where neither side is a file on disk (Git Log commit files, Compare Branches, multi-commit diffs) now offer it when the path still exists in the working copy; files deleted by the commit don't.
Jumping from a pane that isn't the opened file used the other pane's caret. The caret line is now mapped through the diff to the target (the other pane's document, or the working copy read at click time including unsaved edits); the column is kept only when the line is unchanged.
Co-authored-by: itning <19759891+itning@users.noreply.github.com>
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
Adds gutter markers for type hierarchies: ↓ "Is implemented / Has subclasses / Is overridden" on types and methods with implementations, ↑ "Implements / Overrides method in X" on methods that implement or override a supertype method. One target navigates, several open the Choose Implementation popup. Settings › Editor › General › Gutter Icons gets two toggles.
Markers come from the language server: a new batched `lsp_implementations` command (up to 4 concurrent, cancellable, sharing the goto query path) for ↓, and the Super Method lookup for ↑, which now prefers the overload with matching parameters (also fixes ⌘U on overloads). Only declarations near the viewport are queried, debounced, cached per document version and cancelled when superseded. Works for any server with implementation / type hierarchy support; servers without type hierarchy show ↓ only.
Fixes#99
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
In Git Log's Branches pane a single click filtered the log and a double click checked the branch out. Now a click only selects; double click or Enter shows the log of that ref (also the current branch and HEAD), and Enter on a multi-selection filters by all selected branches in tree order. Checkout stays in the context menu. The pane keeps its own selection and follows filter changes made elsewhere. Cmd/Ctrl+C copies the selected branches as full refs, one per line (HEAD as `HEAD`), leaving copy in the search field and elsewhere untouched.
Co-authored-by: itning <19759891+itning@users.noreply.github.com>
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn