Plugin API 1.3 adds what commit-message generators and before-commit checks need:
- `menu = "commit.message"`: a plugin command, with the plugin's icon, in the toolbar above the commit message of the Commit tool window and the Commit dialog.
- `commit.pending-commit()` (`vcs.read`): what Commit would commit right now, per file its repository, path, status and a `git diff` of only the included files and changed blocks against HEAD (1 MiB in all), plus the message, Amend and a revision. The diff is made by the same selection the commit uses, in a copy of the index, so the index and the working tree stay as they are; unsaved editors of the included files are saved first, as Commit does. Only in trusted projects.
- `commit.set-commit-message(revision, message)` (`vcs.write`): replaces the message only while the draft is still at that revision, so text the user typed meanwhile is never overwritten (`stale`).
- `[[contributes.commitChecks]]` and the optional `commit-checker` export (worlds `plugin-commit-checks` / `commit-checks`): checks listed in Commit Options (on by default, `vcs.commit.disabledPluginChecks` turns them off) and run after the IDE's own; their problems, optionally with a location, stop the commit until Commit Anyway.
The window answers the host through `CommitRequested` / `plugin_answer_commit`, also for remote windows. The Rust SDK gains `host::pending_commit`, `host::set_commit_message`, `openidea_plugin::commit` and their mock; a `commit` test fixture exercises them. All components are rebuilt for the WIT change.
Refs #1650
Plugin API 1.3 gains an optional hover-provider export (worlds plugin-hover
and hover): hover(doc, at) returns Markdown and the range it describes. A
plugin declares the hover kind under [[contributes.providers]] for any
language; the host asks it with the language server, under the edit-path
budget, and shows the server's hover first and each plugin's below a rule.
Declaring the kind needs engines.openidea ^1.3. The Rust SDK gains
openidea_plugin::hover and register_plugin!(T, hover); every shipped
component is rebuilt for the WIT change.
* fix(vfs): warn when the inotify watch limit leaves folders unwatched
When watch() hits the OS watch limit mid-tree (inotify ENOSPC/EMFILE), the affected directories were silently never watched: the project stayed stale with no hint. Record the failure on DirState and surface it through the new Watcher::unwatched_reason() — the host emits the 'sync may be slow' warning once the project opens and once on the first event batch after a late failure (deferred walk / update_watches).
Fixes#1915
* fix(vfs): latch the startup watch-limit warning so batches don't repeat it
The New Branch dialog refused any existing local name, so a branch could not be moved to a selected commit. When the name matches a local branch of the target repository, the dialog now offers an unchecked Overwrite existing branch option (git switch -C / git branch --force); the consent clears when the name changes, and Git's checkout checks keep the old tip and local changes if switching fails. New Branch from a Git Log commit also targets that commit's repository in a multi-repository project.
Co-authored-by: shohruh-genius <[email protected]>
Stop flipped the session back to Run as soon as the direct child exited, but a shell, Maven or the debug adapter can exit while the application it started still holds its port, so the next Run failed with "port already in use". The console also went quiet on a debug Stop because the DAP session was disconnected before java-debug drained the program's output, and closing a window killed running programs with SIGKILL at once.
Run and Debug sessions now stay in a stopping state from the Stop press until the whole process group (or the debuggee's pid tree) is gone. As in IntelliJ IDEA, the first Stop only interrupts and waits, and a second Stop kills; the Stop button turns into Kill process meanwhile. A rerun or restart waits for the old process without a time limit, and the termination time limit setting now only bounds a configuration's stop command. Debug launches record the program pid from the adapter's process/processid event, signal its pid tree and keep the adapter attached until the program exits; closing a project also stops debug sessions under its root. Closing a window with running programs shows a Terminating panel with Kill process and closes once they are gone.
Co-authored-by: misswell <[email protected]>
Inside PHP strings, plugin completions were buried under project file paths and go to definition mixed the plugin's answer with the server's guesses and with IDE helper stubs. Now path items are left out when a plugin answered at that position, and in PHP and Blade paths only show once the string reads like a path. Inside a string literal (checked on the document's syntax tree) plugin definitions replace the server's; elsewhere both are kept, the plugin's first, so e.g. MyBatis mapper navigation still offers jdtls' answer. Generated helpers (_ide_helper*.php, .phpstorm.meta.php, vendor/_laravel_ide*) give way to real declarations, an empty plugin answer is marked incomplete so typing asks again, and a callable accepted before a closing quote no longer gets ().
Closes#1336
Co-authored-by: yzPeedro <[email protected]>
A plugin view declared with `location = "services"` (plugin API 1.3, `engines.openidea ^1.3`) shows its tree in the Services tool window, next to Docker and the run configurations. The nodes, the toolbar (acting on one selected node) and their events come from `view-provider`; `viewItem.context` menus give the nodes a right-click menu. The pane beside the tree comes from a new optional export, `service-provider.detail(view, key)` (worlds `plugin-services` / `services`), which returns typed tabs: a message, read-only text or a process log. The IDE switches tabs without calling the plugin.
For a log, the UI names only the node and tab (`plugin_service_log`); the host asks the plugin for the pane again and runs its program with the plugin's `process:` grant in the project root, with the arguments of the toggles that are on, streaming its output into the log pane Docker uses until it exits (the exit code is shown), the pane closes or the Services window is hidden. A cancelled request starts nothing, lines are cut at 16 KiB, and revoking the grant or cancelling kills the program and what it started. The log pane moves to `src/ui/LogPane` and drops output that arrives after its source was stopped. The Rust SDK gains `openidea_plugin::services` (`Services`, `Tab`, `Pane`, `ProcessLog`). All components are rebuilt for the WIT change.
Closes#1736
Co-authored-by: arnaud-ritti <[email protected]>
* feat(maven): go to declaration for POM properties and parent-managed dependencies
Ctrl/Cmd-click (or Go to Declaration) on a `${property}` reference in a
pom.xml opens the `<properties>` entry that defines it - the POM's own,
else the first one along the parent chain (a child's definition wins; an
active profile's counts as the POM's own) - and a dependency / plugin
whose version a `<dependencyManagement>` / `<pluginManagement>` entry
provides opens that managing declaration. The chain follows
`<relativePath>` in the project and the local repository (Settings >
Maven's, else ~/.m2) for external parents, which open read-only as plain
files; `project.*` built-ins go to their coordinate elements. When
nothing resolves under the caret, nothing navigates: the usual 'Cannot
find declaration to go to' hint shows instead.
The backend answers a caret position (0-based line / UTF-16 column) with
the winner's file, range and kind (maven_goto_declaration), reusing the
build model's POM reader and parent resolver (ide_build::maven) instead
of a new parser. The frontend contribution (build-tools.pomNavigation)
claims only positions that can resolve - inside a `${...}` reference or
a <dependency> / <plugin> element - so the Cmd-hover underline stays out
of the rest of the file.
Refs #1735
* test(maven): normalize expected goto paths like the parent chain does
parent_chain resolves every path it returns through dunce::canonicalize,
but the goto_declaration tests compared those results against raw temp
paths, which differ on the CI runners: on macOS the temp dir sits behind
the /var -> /private/var symlink and on Windows under the RUNNER~1 8.3
short name with backslash separators, so the Rust (macos-latest) and
Rust (windows-latest) jobs failed in the new assertions while the
functionality itself was right.
Feed the expected paths through the same canonicalization call before
comparing, mirroring the production behavior on every platform; on a
plain Linux checkout the canonical form equals the raw path, so the
assertions stay equivalent there.
Refs #1735
* feat(sdk): create Python environments with uv and Poetry in Add Interpreter
Add a VenvTool parameter to sdk_python_create_venv so the Add Python
Interpreter dialog can build a new environment with virtualenv, uv or
Poetry, matching what the environment discovery already finds. Poetry
keeps envs in its own cache, so the dialog disables the location field
for it and resolves the interpreter via 'poetry env info --path'.
Fixesl0ng-ai/openidea#1776
* fix(i18n): update text catalogs for the new env-tool strings
The Add Interpreter dialog gained uv/Poetry labels and per-tool notes,
and its spinner text changed from 'Creating virtual environment' to
'Creating environment'. Add the new zh entries and rename the stale
key in every catalog so the text-catalog test passes.
* fix(agent): don't release an idle native agent while background tasks are running
A turn's background tasks (Claude Code's run_in_background commands) outlive
the turn: release_when_idle only checked for a running turn and open
permission requests, so five minutes after the turn ended it stopped the
agent process and orphaned whatever still ran, its result never reaching
the conversation.
Claude Code reports its live background tasks in stream-json mode: a
system/background_tasks_changed event carries the full list on every
change. The driver now translates it into an openidea_background_tasks
session update (like openidea_retry), the task keeps the list, and the
idle release waits while it isn't empty: it checks again after the usual
delay, and when the last task is done its report voids the pending
schedule and starts the delay over from then. A (re)started process
starts with no tasks, so a stale list can never hold the agent up.
Signed-off-by: Inf1mum <[email protected]>
* feat(agents): show the agent's background tasks above the composer
A grey bar above the composer lists what the agent runs in the
background (shells, monitors), with how long each has been running and
a Stop button per task. The task now carries the background tasks the
agent reports, with when each was first seen, and clears them when the
process ends. Stop asks Claude Code to end that one task through a new
_openidea/stop_task request; the composer's Stop keeps ending only the
turn (perTaskStopAffordance).
Closes#1788
---------
Signed-off-by: Inf1mum <[email protected]>
Co-authored-by: Inf1mum <[email protected]>
Co-authored-by: NealimeKenna <[email protected]>
Plugin API 1.3 adds an optional semantic-tokens-provider export (world plugin-semantic-tokens). A plugin declares the semantic-tokens kind under [[contributes.providers]] for any language, including ones it does not contribute, and returns single-line tokens with LSP token kinds and modifiers. The host asks it with the other editor providers (50 ms / 500 ms) when the editor requests semantic tokens and joins the result with the language server's: plugin tokens replace the server tokens they overlap, so the colour scheme styles them like any semantic token. Declaring the kind needs engines.openidea ^1.3.
API 1.2 shipped with 0.1.38, so wit/ and the SDK's copy, ENGINE_VERSION and both API_VERSION constants move to 1.3 and every shipped component is rebuilt. The SDK gains openidea_plugin::semantic_tokens, and register_plugin! accepts any combination of optional exports (providers, views, indexing, syntax, semantic_tokens) instead of a fixed list of pairs.
A PHP without the Xdebug extension ignores the -dxdebug.* options php-debug
starts it with, so a PHP debug session ran past every breakpoint and nothing
said why. Starting one now checks the PHP that will run (with XDEBUG_MODE=off,
in the session's folder, where a version manager's php shim picks the PHP) and
warns when Xdebug is not loaded, with Open PHP Settings; the session still
starts. Settings > PHP > CLI Interpreter shows the Xdebug version of the
selected PHP, or Not installed.
Co-authored-by: arookieofc <[email protected]>
Project scope visits hidden files and folders (the search engine's
walk_files documents exactly that), but find-files left every dot-folder
out on both paths: the index filter dropped them and the disk walk ran
with hidden(true). Hidden folders are now visited like anywhere else;
only .git internals stay out.
Fixes#1850
Plugin API 1.2 adds `ui.pick`, `ui.pick-many`, `ui.input`, `ui.confirm` and `views.reveal`. The dialogs show in the window whose command or event asked and block that call until the user answers; the wait is added to the call's deadline, so it doesn't use up the time budget. They need no capability and return `invalid` without a window (events without a client, rendering, editor providers). Prompts are withdrawn when the call is cancelled or the plugin stops, and reach remote windows through the dispatcher (`plugin_answer_prompt`). `views.reveal` brings one of the plugin's declared views to the front. The Rust SDK and its mock gain `pick`, `pick_many`, `input`, `confirm` and `reveal_view`. All components are rebuilt for the WIT change.
Closes#1768
Co-authored-by: arnaud-ritti <[email protected]>
Plugin API 1.2 adds `ui.set-context(key, value)` and `ui.remove-context(key)`: a plugin sets `plugin.<id>.<key>` for `when` clauses, typed as `context-value` (flag, number or text), in the window the call came from or every window outside a command or event; a window's value wins over the global one. Keys are 1-64 of `A-Za-z0-9_-`, at most 100 per plugin, kept across window reloads and idle reclaim, dropped when the plugin stops or the window closes; remote windows get them through the dispatcher. The Rust SDK takes `impl Into<ContextValue>`. All components are rebuilt for the WIT change.
Closes#1622
Co-authored-by: arnaud-ritti <[email protected]>
Plugin API 1.2 adds `invocation.selected-paths`: the files and folders a Project view or editor tab menu ran the command on, as absolute paths (the command's argument stays the first of them, so existing plugins see no change). The frontend passes the menu's selection to `plugin_run_command` on the desktop and through the remote dispatcher; the Rust SDK and its mock gain `Invocation::selected_paths`. All components are rebuilt for the WIT change.
Closes#1621
Co-authored-by: arnaud-ritti <[email protected]>
A plugin can declare `[[contributes.menus]]` with `menu = "viewItem.context"` and `view = "<its view>"`. Right-clicking an item of that tree or list view lists the matching commands, each run with the item's key as argument; `when` sees `viewItem` (the key) and `viewItemKind` (the key up to its first `:`). Validation refuses the menu without `view`, with an undeclared or web view, `view` on another menu, and (new in API 1.2) a manifest whose engines.openidea still admits older IDEs.
Closes#1618
Co-authored-by: arnaud-ritti <[email protected]>
A plugin can set `icon` (and `icon-dark`) in plugin.toml. The SVGs go through the existing sanitiser (16 KiB each), ship with the package, and show in Settings › Plugins (list rows and detail header) and the marketplace, whose index entries carry them; the IDE sanitises index icons again and drops unsafe ones.
IDEs before plugin API 1.2 refuse a manifest with `icon`, so Manifest::needs_api refuses one whose engines.openidea still admits them (check and install), keeping the index from offering such a package to older IDEs.
Closes#1732
Co-authored-by: arnaud-ritti <[email protected]>
* feat(trust): let users add trusted folders from settings
The trusted-locations check already matches projects by path prefix, but
the only way to populate it was the "Trust projects in…" checkbox on the
first-open dialog — a folder could never be trusted ahead of time.
Add a project_trust_add_location command that canonicalizes the picked
directory, rejects non-directories, and deduplicates, plus an "Add
folder…" button on the Project Trust settings page backed by the native
directory picker.
Fixes#1743
* fix(trust): translate the trusted-location additions into Chinese
The zh source-text catalog must cover every literal UI text; the three
new strings in the trusted-locations settings page were missing.
Language smoke / Language smoke (go) (push) Failing after 6s
Language smoke / Language smoke (java) (push) Failing after 5s
Language smoke / Language smoke (kotlin) (push) Failing after 5s
Language smoke / Language smoke (python) (push) Failing after 4s
Language smoke / Language smoke (typescript) (push) Failing after 4s
Language smoke / Language smoke (rust) (push) Failing after 5s
CI / Rust (ubuntu-22.04) (push) Failing after 43s
CI / Plugins (SDK, official, fixtures) (push) Failing after 1m19s
CI / Remote server (linux musl) (push) Failing after 1m32s
CI / Cargo deny (push) Successful in 54s
CI / E2E (push) Successful in 15m57s
CI / Frontend (push) Successful in 24m49s
CI / Rust (macos-latest) (push) Canceled after 0s
CI / Rust (windows-latest) (push) Canceled after 0s
* fix(build): scope Kotlin bridge to linked Maven modules
* fix(run): resolve nested Go modules for context runs
* fix(gradle): discover nested builds and select compatible JVMs
* fix(workspace): share project discovery and module ownership
* fix(run): keep root toolchains for nested modules and resolve them once per module
- Python run configurations of a nested module without its own virtualenv use the closest one up to the project root.
- Gradle builds and runs fall back to the JDK matching the project's Java version when the Gradle version is unknown.
- Module-local interpreters and toolchains are resolved lazily, once per owning module.
- Tests build expected paths per segment so they hold on Windows.
Closing a window stops what its project started, but a quit that exits without closing the windows first (the Dock's Quit, a logout) left every run's process tree alive: a server kept its port and the next run failed with "port already in use". The desktop exit handler now kills every run's process tree and every terminal shell, as the remote server's shutdown already does.
Fixes#1691
Update Project
- The update summary and View Commits cover only the incoming commits
(merge base with the tracked branch before and after), not rebased local
commits or the merge commit.
- An update that stops on conflicts opens the Conflicts dialog instead of an
error balloon.
- The Update dialog remembers the chosen method, has "Don't show again", and
"Reset to the Remote Branch" (fetch, drop local commits, keep local changes).
Push
- A rejected push asks Merge / Rebase (Rebase Anyway with unpushed merges) with
"remember and update silently", updates every repository and pushes again,
up to ten times, without an error balloon first.
- A tag that already exists, a hook or server refusal is not treated as a
non-fast-forward rejection; a stale force-with-lease offers "Force push anyway".
- Run Git hooks (--no-verify) when a pre-push hook exists; Set upstream also when
pushing to another branch name; multi-repository push continues past failures.
- Tags: Push to <remote> and Delete (Restore, Delete on Remote).
Rebase
- Reword in an interactive rebase keeps message lines starting with '#'.
- Continue stages edits of files already staged; other unstaged changes report
a clear error with Stage and Retry, Show Files and Abort.
- A stopped rebase or merge offers Abort in its error balloon; resolving the
last conflict from the Conflicts dialog continues by itself.
- Branch menu rebase/merge use the full branch ref when a tag has the same name.
- Files keep their changelists while local changes are set aside.
File history follows renames done in merges and history merged from other
branches, and names the path of each revision.
Configuration navigation from YAML/properties still waited for a cold index the first
time and repeated the lookup between the ⌘-hover probe and the click.
- Trusted projects with a Maven/Gradle/Eclipse build file start Java shortly after
opening. Once JDT reports ServiceReady, the app calls the new
openidea.java.configuration.warmup command: a low-priority background job builds
the configuration index one project at a time (open YAML/properties modules first),
waits for workspace builds, has a 30 s budget per project, and only fills free cache
room.
- Index builds take a cancellable per-project lock instead of one global lock, so a
background build never delays another project, and a warmed snapshot is dropped
if the Java model changed meanwhile.
- In YAML/properties the editor underlines the whole key (hyphens and dots
included), hover and Go to Definition share one bounded request per key, and the
declaration chooser names the whole key.
Bundle java-usages 1.6.0 is rebuilt reproducibly with build.py against JDT LS
1.63.0-202610191322 (SHA-256 33cfa1bb…). The real-JDT harness checks that the first
lookup reuses the warmed index.
Co-authored-by: qjlqyf <[email protected]>
* fix(vcs): keep local changes and staging intact across commit, checkout and history edits
- Commit: changes left out of a commit keep their staged state. The commit is
made from a copy of the index (included files staged there, excluded ones
reset to HEAD), so the user's index and other repositories are untouched.
- Smart Checkout restores staged changes as staged; untracked files a checkout
would overwrite are listed instead of a raw git error.
- Edit Commit Message rewrites the commit and its descendants without a rebase,
so the working tree and local changes stay as they are.
- Edit Commit Message, Drop and Squash offer Undo in their notification while
the branch hasn't moved since.
- Interactive rebases (Drop, Squash, Interactively Rebase) put local changes
aside themselves and bring them back with their staged state once the rebase
is over, also after a stop for conflicts.
- Undo Commit asks for the target changelist (a new one named after the
commit) and puts the commit message back into the commit message field.
- Cherry-pick and revert skip commits whose changes are already applied instead
of stopping with an empty commit; commits cherry-picked from a protected
branch get "(cherry picked from commit …)".
- Commit tool window: Commit File…, Accept Yours / Accept Theirs on conflicted
files and Copy as Patch to Clipboard.
* fix(vcs): restore staged changes after merge, rebase and update; roll back partial multi-repository operations
- Merge, rebase, pull / Update Project and the rebase of a diverged checkout put
local changes aside themselves and bring them back with --index, so staged
changes stay staged (git's --autostash restored them unstaged). An operation
stopped on conflicts keeps them aside until it is continued, skipped, aborted
or concluded by a commit.
- Checkout, New Branch, Merge, Rebase and Delete over several repositories:
when one repository fails after others succeeded, ask whether to roll those
back (check out the previous branch, delete the new branch, reset to the
commit before, restore the branch); not when it stopped on conflicts.
- Fixup… / Squash Into…: while the prepared message is in the field, the second
commit button is Commit and Rebase, which commits and autosquashes the new
commit into its target.
- Undo on a history rewrite replaces its notification, so the link is gone once
used.
Plugin API 1.2 gains an optional document-indexer export (plugin-indexing world). A plugin returns per document the keys it defines and refers to, aliases between key prefixes and gutter markers; the host indexes a trusted project in cancellable background batches, keeps the project-wide graph, and answers Go to Declaration / Ctrl-click and multi-target gutter markers from memory without calling the plugin again. Edits and file changes invalidate the affected entries; reload, disable or a failing runtime drops the plugin's graph.
The interface is limited to cross-file associations: icons chosen by file content and embedded-language regions are separate concerns for later interfaces. The plugin navigation choosers' titles are translated.
Co-authored-by: qjlqyf <[email protected]>
Go to Implementation on a type or method declared in a dependency listed only the project's implementations once the project had one. openidea.java.implementations (java-usages 1.5.0) now answers {locations, complete}, complete when the type is declared in the sources, and also searches the Kotlin bridge's classes. When not complete, the chooser opens with the project's implementations (searching…) through the new lsp_goto_implementation channel and fills in the dependencies' when the standard request ends; closing it cancels the search.
Language smoke / Language smoke (go) (push) Failing after 6s
Language smoke / Language smoke (kotlin) (push) Failing after 6s
Language smoke / Language smoke (java) (push) Failing after 7s
Language smoke / Language smoke (python) (push) Failing after 3s
Language smoke / Language smoke (typescript) (push) Failing after 5s
Language smoke / Language smoke (rust) (push) Failing after 5s
CI / Plugins (SDK, official, fixtures) (push) Successful in 3m9s
CI / Cargo deny (push) Successful in 52s
CI / Remote server (linux musl) (push) Successful in 5m57s
CI / E2E (push) Failing after 15m55s
CI / Frontend (push) Successful in 25m38s
CI / Rust (ubuntu-22.04) (push) Failing after 46m4s
CI / Rust (macos-latest) (push) Canceled after 0s
CI / Rust (windows-latest) (push) Canceled after 0s
A run target can be a Docker image or a Compose service: the configuration runs as a local docker run --rm / docker compose run --rm with the project bind-mounted, so the console, PTY, stdin, Stop and test parsers work unchanged. Only daemons on this machine are accepted; on Linux the container runs as the project folder's owner; Stop runs docker stop with the same docker CLI. Debugging, coverage and profiling stay on this machine. Refs #1083 (step A1).
Co-authored-by: andreabasile <[email protected]>
The fake PHP logged its run before reading the pause file, so a test that reset the pause on seeing the run could make that run skip its pause on a slow machine and finish before the next save cancelled it.
A program started through runInTerminal had stdin from /dev/null, and CodeLLDB's launcher only hands the program a terminal it can read from when it runs on one. runInTerminal now starts the command on a pseudo-terminal, forwards its output to the console (CRLF as LF, without CodeLLDB's clear-screen request) and reports that the program takes input; while it runs, the console's input line goes to it, while paused it evaluates as before. debugpy and js-debug programs started in a terminal get the same.
PHP files and composer.json of a Composer project show a banner when vendor/autoload.php is missing or a package of composer.lock is not installed at its locked version (packages-dev only unless the install used --no-dev; config.vendor-dir honoured). Install runs composer install in the Run tool window with the PHP of Settings › PHP first on PATH; Ignore hides it until the project is reopened. Rechecked when composer.json, composer.lock or vendor change; not shown in an untrusted project. A Composer Install action does the same.
close_project was a synchronous command, so it ran on the UI thread and dropped the project there: stopping its file watcher and index worker waits for the batch of file events they are applying, many while a build or rust-analyzer writes output. The command now runs off the main thread, and the project is dropped on the project shutdown thread, which a project opened next still waits for (the index database is released first). The window Destroyed path gets the same.
When a .php file has a .php-cs-fixer.php or .php-cs-fixer.dist.php above it and vendor/bin/php-cs-fixer is installed, Reformat Code and format on save run PHP-CS-Fixer on a temporary copy of the unsaved text with that configuration and apply the result as edits. PHP comes from the PHP interpreter setting, or PATH. A selection formats the whole file, with a note. Without a configuration, the language server keeps formatting.
project.find-files walked the whole tree on every call; MyBatis Navigator calls it from editor providers interrupted after 500 ms, so on a large project each call timed out, counted as a crash, and the plugin was stopped after three. The host now answers from the project index (VCS-ignored and hidden files left out, as in the walk) and only walks the disk when no index covers the root yet.
A process: permission allowed while its program was missing has no pinned binary, so installing the program and restarting changes nothing. The error now says the program must be on PATH and that the permission has to be cleared and selected again in Settings › Plugins.
An external write that keeps a file's byte length and mtime was missed twice: the Maven launch fingerprint reused the stale class snapshot, and watcher events for clean open documents were dropped by the (mtime, length) stamp check.
The launch fingerprint now records a blake3 content hash for project files (toolchain inputs such as the JDK's lib/modules keep the stamp only) and bumps its version. Watcher events for clean documents compare the disk bytes with what saving the buffer would write; blind focus scans keep the stamp dedup, and forced refreshes after IDE disk operations still reload clean buffers.
Co-authored-by: qtvbwfn <[email protected]>
Running a .php file or a #!/usr/bin/env php script used the PATH php: the file producer resolves tools on PATH and the settings pass only replaces a bare php command. A new sdk_php_effective command returns the configured interpreter (like sdk_python_effective) and the producer prefers it; the not-found text points to the PHP settings page.
Fixes#1555
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Ruff is now an external formatter for Python next to the Ruff language server: Settings › Languages & Frameworks › Ruff has the executable path, a configuration directory (or file), the provider preference, enabled languages, run-on-save, and Reformat with Ruff. Formatting runs on the unsaved document through stdin (with Ruff's --range for selections, in 1-based code-point columns) and never writes the file first. The configuration directory is shared with Ruff LSP, which can then start without a root marker. Tools that can't format a language are rejected even when requested.
Co-authored-by: muutot <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Git log's changed-files pane can show the lines a commit added and deleted per file and as a total per directory and for the selection, from git diff --numstat -z -M over the same revision pairs as the file list (renames matched by either name). Off by default; turned on in Settings › Version Control › Log or the pane's View Options, so selecting a commit runs no extra diff unless asked.
Co-authored-by: liqiujiong <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Ruby LSP showed Crashed and restarted for two reasons. A version-manager shim for ruby-lsp exists for every Ruby that ever had the gem, so when the active Ruby lacked it the shim exited on every start while the IDE counted the server as installed. And the IDE-managed copy lived in a gem home under Application Support, whose space broke ruby-lsp's re-exec through Bundler.
Shims that can't run the tool now count as missing. ruby-lsp is installed with the project's own Ruby (gem install in the project, so a version manager picks its Ruby). Its executable is looked up in that Ruby's gem bindir and user bin when they are off PATH (Homebrew), and those directories are added to the server's PATH.
Co-authored-by: kjeldahl <[email protected]>
PHPStan results were only visible in a terminal. Saving a PHP file in a trusted project with vendor/bin/phpstan now runs phpstan analyse --error-format=json on the saved files (debounced, from the project root, on the selected PHP with XDEBUG_MODE=off) and shows its errors at their lines in the editor and Problems, with the PHPStan identifier as the code; saving the fixed code clears them. Settings > Editor > Inspections lists PHPStan under PHP with each reported identifier, so rules can be turned off or re-graded, and Settings > Languages & Frameworks > PHP > PHPStan selects another configuration file. A failing run is reported once as a notification; a newer save cancels a check in progress, and Restricted Mode stops it.
Closes#1212
Co-authored-by: DanielADK <[email protected]>
Parsing Minitest's console output needs -v, gives no file or line for passing tests and depends on how output interleaves. Ruby test runs (ruby and rake test configurations in the console) now load a small Minitest reporter through RUBYLIB/RUBYOPT that prints one record per test on stdout with its status, time, failure text and real file and line. The console strips the records and the test tree is built from them, so jump to source gets exact locations; the text parser stays as the fallback. It works on Minitest 5 and 6 (6 no longer loads plugins on its own, so a small hook registers the reporter once Minitest is loaded).
Co-authored-by: kjeldahl <[email protected]>
Ruby had no coverage runner. Run with Coverage now works for ruby, bundle, rake, rspec and rails test configurations through SimpleCov, read from its .resultset.json (lines and branches). A project that starts SimpleCov itself keeps its own setup; otherwise a small preload starts it and writes the report to the IDE's run directory, so nothing is written into the project. The preload is loaded through RUBYLIB and a bare -r in RUBYOPT, because RUBYOPT can't take the spaces in the macOS data directory, and it steps aside in the bundle exec launcher, which loads it before Bundler puts the project's gems on the load path. A CI .resultset.json can be imported through Import a Coverage Report.
Co-authored-by: kjeldahl <[email protected]>
* fix(notebook): send the notebook path to the UI with forward slashes
On Windows a notebook's snapshot and output events carried its canonical
path as `to_string_lossy()` (`C:\a\b.ipynb`), and the UI uses that path as
the notebook tab's identity, while the project tree and editor name the same
file `C:/a/b.ipynb`. NotebookSnapshot.path and NotebookOutputEvent.path are
now IpcPath, like the other path fields on the IPC boundary (#1456 did the
same for Spring route sources and Add to .gitignore).
* chore: regenerate bindings for the notebook IpcPath fields
---------
Co-authored-by: l0ng-ai <[email protected]>
* perf(vcs): filter the Git log with git log instead of a background search index
The log built a persistent inverted index of every commit's message, authors and
changed paths in the background, with a progress bar above the commit list, and
walked trees itself to filter by path. Building it took minutes on large
repositories, and filters were slow until it finished.
- Text: plain text uses `git log --fixed-strings --grep` (with
`--regexp-ignore-case` unless Match Case is on); text of 4+ hex digits also
matches hash prefixes. Regex filters still match in-process.
- Paths: `git log -- :(literal)<paths>` replaces the in-process path walk and
its per-commit tree cache. It uses git's history simplification and, when the
repository has a changed-path commit-graph, its Bloom filters. Glob characters
in a path are literal.
- Authors match against the commit metadata cache.
- Removed the search tables, `index_log`, the `vcs_log_index` command and the
indexing progress bar. The commit metadata cache stays.
* docs(contributing): ask for screenshots only when a change alters what users see
Removing a feature together with its UI, copy-only and non-visual changes now
describe what was checked instead of attaching before/after screenshots.
* fix(vcs): match case-insensitive non-ASCII Git log text in process
git folds case only for ASCII under the C locale it runs with, so a
case-insensitive filter like "ärger" missed "Ärger". Such text is now
matched against commit messages directly. Path and text selection also
ignore log.showSignature and log.follow from the user's config.
* fix(plugins): hand plugins paths in one form on Windows
Plugins got the project root, editor path, provider documents, code action edits, vcs-status roots and find-files results as D:\… while event paths from the UI use /, so Checkstyle could not find the project of a saved file. The host now converts every path it hands to plugins with ipc_path::to_ipc.
* fix(checkstyle): match native Windows report paths
* test(plugins): use workbench IPC paths in host fixtures
Two opens of one window could each find no current project and build a full project (index, language servers, watchers); the second replaced the first without closing it, leaving two jdtls on one workspace. open_project and open_light now hold a per-window lock from the check to the insert.
The main toolbar gear's Theme submenu and Settings › Appearance › Theme preview the theme under the pointer after the same delay as Quick Switch Scheme, and closing without a choice brings the selected theme back. Choosing a theme while it was previewed left the preview flag on, so the start-up theme cache kept the previous theme; `setTheme` now ends the preview.
Import Theme from JetBrains IDE… lists one row per theme plugin and installs it without switching the theme, like any theme plugin install. It reads only the newest settings folder of each product, so folders left behind by upgrades don't list their plugins again.
Co-authored-by: ldg030201 <[email protected]>
* perf(vfs): list directories off the main thread and reuse the repository lookup
Opening a folder on a network share (\\wsl.localhost\<distro>\...) is slow
because every listing ran on the main thread and walked up to the repository
root and ran a repository discovery again.
- fs_read_dir runs on the blocking pool.
- GitignoreStack::cached keeps the repository root and the repo-level rules
for a few seconds. An edit of .git/info/exclude is still seen at once (its
mtime and size are checked) and every .gitignore / .ignore is read fresh.
Refs #916
* feat(remote): open WSL projects through a WSL transport
A folder of a WSL distro (\\wsl.localhost\<distro>\... or \\wsl$\...) now opens
as a remote project whose openidea-server runs inside the distro, so the
terminal, SDK discovery, run, language servers and git are native Linux.
- RemoteTarget (ssh | wsl) replaces the SSH configuration id in the remote
launch, connection, session and recents; old recents are read as SSH and a
WSL target never inherits the legacy trust migration.
- remote_wsl: probe the distro, stream the server into ~/.openidea/server and
start it with `wsl.exe -d <distro> --exec <bin> --stdio`. Distro names are
validated and every command goes through --exec with positional arguments.
- wsl_distros / wsl_resolve commands; File > Open, the CLI and recents route
WSL folders to the distro and focus the window that already has them.
- Remote Development dialog: SSH/WSL choice with the detected distros; the
status bar shows `WSL: <distro>` / `SSH: <host>`.
- ide-jsonrpc: skip the NUL left at the start of a line by UTF-16 output of
wsl.exe, which made the first message of the server disappear.
Not run on Windows yet: only a stand-in for wsl.exe is tested.
Refs #925, #327, #721
* fix(remote): satisfy clippy in WSL output decoding
* style(run): format run types
* fix: regenerate bindings and drop untranslated WSL catalog entry
* test(i18n): list WSL as an untranslated product name
* fix(run): pick build wrappers and shell quoting by the execution host
A remote window runs commands on its Linux or macOS server, so a Windows
desktop no longer selects gradlew.bat, mvnw.cmd or Windows quoting for it.
* fix(welcome): open legacy WSL UNC recents and sessions through the distro
Recents and the restored session called the local openProject for a
\\wsl.localhost folder saved before WSL projects, which fails with OS
error 123. They now resolve it like the other entry points.
* fix(windows): keep WSL files out of remote project launches
path_launch tested the WSL share before is_dir, so a first-instance CLI
launch with a WSL file opened a remote project instead of LightEdit.
* fix(remote): run-command OS comes from the remote host, not an assumption
The server's OS was dropped after connect, so a restored session had none and
isWindows() assumed every remote host is Unix. Keep it on the connection and
the session, and resolve it through hostOs().
---------
Co-authored-by: NguyenBang <[email protected]>
Co-authored-by: NguyenBang <[email protected]>
Co-authored-by: l0ng-ai <[email protected]>
Linked builds are saved normalised (canonical, forward slashes), but unlinking
compared the paths it was given verbatim, so a build outside the project could
not be unlinked on Windows (C:\… vs C:/…), nor through a symlinked path. Unlink
now normalises each path the way linking saves it. The Gradle linkage tests also
create the platform's wrapper (gradlew.bat on Windows) and compare canonical
paths without the \\?\ prefix.