causing some symbolic operations (such as `find_referencing_symbols`) to report stale information.
An explicit file system synchronisation mechanism is now used to detect changes prior to the
affected tool executions.
Note that tools like `find_symbol` and `get_symbols_overview` do not need the synchronisation,
because they explicitly open all the relevant files themselves.
Resolves#1718
Co-authored-by: Niccolò Franzin <niccolo@cognitivext.com>
- PHP/Intelephense: expose `file_filter` via `ls_specific_settings["php"]`, so that additional
extensions containing PHP sources (e.g. Drupal's `.module` / `.install` / `.inc` / `.theme`)
become visible to the symbol tools and are indexed by the language server
- PHP: treat `.phtml` files as PHP sources by default (all PHP language servers)
* Do not unnecessarily call apply_ex instead of apply (timeout can occur)
* Increase tool timeout to 10 minutes (for slow CI cases)
* TestPromptProvision: Raise exceptions in apply_ex (such that outputs don't
inadvertently check against exception messages)
Resolves#1695
gopls reports the document-symbol range of single type/var/const
declarations starting at the identifier (after the keyword), unlike func
declarations whose range includes the func keyword. Serena derives both
the displayed body and the replacement range from that range, so the
keyword was dropped from both for these declarations and a
keyword-inclusive edit corrupted the file (type Foo became type type Foo).
Override request_document_symbols in gopls to extend the range start back
to the keyword when only the keyword and indentation precede the
identifier, recomputing the body so it stays consistent with the
replacement range. Funcs, grouped declarations, and selectionRange are
left untouched.
Adds a unit test for the symbol body and range plus an end-to-end
replace_symbol_body round-trip regression test.
* Java (JDT-LS): allow registering additional JRE/JDK runtimes via config
JDT-LS resolves each imported module's JRE_CONTAINER/.../JavaSE-NN/
classpath entry against its own "Installed JREs" list, which Serena
previously hardcoded to a single JavaSE-21 entry pointing at the
bundled JRE. Projects whose source/target level exceeds that bundled
JDK (e.g. sourceCompatibility = VERSION_25) get a container that never
resolves, so every JDK type -- java.lang.Object, java.util.*, etc. --
comes back "cannot be resolved", silently breaking diagnostics and
cross-module resolution. There was no config key to tell JDT-LS about
an installed newer JDK.
Add an optional `runtimes` list under ls_specific_settings.java,
mirroring VS Code's java.configuration.runtimes shape (name, path,
optional default/sources/javadoc). Entries are validated (name+path
required, path must exist) via the new _resolve_configured_runtimes(),
then merged with the bundled JavaSE-21 default: configured runtimes
extend the list; an entry reusing the "JavaSE-21" name overrides the
bundled one; if a configured entry claims `default`, the bundled
runtime's own default flag is cleared so JDT-LS doesn't see two
defaults. The `runtimes` key is also added to the JDTLS workspace-hash
inputs so changing it lands in a fresh workspace instead of reusing a
stale Buildship/Maven import.
Testing: added 14 unit tests in
test/solidlsp/java/test_jdtls_path_resolution.py covering
_resolve_configured_runtimes validation (missing keys, wrong types,
nonexistent paths) and the merge behavior in
_create_base_initialize_params (extension, name-collision override,
default hand-off). Ran `poe format`, `poe type-check`, and
`pytest test/solidlsp/java -m "not java"` (69 passed, 8 deselected
real-JDTLS tests that require a JDK) locally.
Fixes#1478
* docs: document java.runtimes in configuration guide
Address review feedback on #1715 by documenting ls_specific_settings.java.runtimes
in 050_configuration.md (settings table, note, and example).
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: arimu1 <19286898+arimu1@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
loadLastExecution()'s success handler only called displayLastExecution()
when the backend returned a non-null last_execution, so on a fresh server
(no tool run yet) the initial "Loading..." placeholder was never replaced.
displayLastExecution(null) already renders the correct empty state
("No executions yet.") — it just wasn't being called.
Add the missing else branch, mirroring how the Tool Usage and Executions
Queue panels already handle their empty states.
Fixes#1713
Co-authored-by: arimu1 <19286898+arimu1@users.noreply.github.com>
An LSP server can end a symbol range one line past EOF: the convention
for a range covering whole lines ends it at the start of the following,
non-existent line. SymbolBody.get_text indexes self._lines[end_line]
directly, so that well-defined case raised IndexError.
get_text now corrects exactly that case (end_line == len(lines), end_col=0) to end
at the actual last line, in get_text itself so it also applies to a
cached SymbolBody, not just a freshly constructed one. Any other
out-of-range end_line now raises InvalidTextLocationError.
Fixes#1498
`search_text` mapped the match's exclusive end index to a line number via
`get_line_from_index`, which resolves an index at a line start to the following
line. A match ending with a newline was therefore attributed one line too many,
and `context_lines_after` was shifted by the same amount.
FileUtils.read_file has two return paths with different newline semantics.
The primary path, open(file_path, encoding=encoding).read(), uses the default
newline=None and therefore applies universal newlines, so CR never reaches
callers. The charset_normalizer fallback decodes the raw bytes instead
(match.raw.decode(match.encoding)), which performs no newline translation, so
any file that fails to decode with the project's configured encoding re-enters
Serena carrying its CR characters.
Normalize to LF at the fallback's return, matching the primary path.
- read via `ReadFileTool`
- searched via `SearchForPatternTool`
when using plugin version 2023.3.3+ (yet unreleased)
This is enabled via JetBrainsFileProxy (which reads the file through the IDE)
read_file determined line indices via Python's splitlines, which breaks on
\f, \v, \x1c-\x1e, \x85, U+2028 and U+2029 in addition to the LSP-compliant
line breaks counted by delete_lines/replace_lines. In a file containing any
of those characters the indices reported by read_file referred to different
physical lines than the editing tools operate on, so an edit made after the
required read_file could silently hit the wrong line.
Use TextUtils.split_lines, as already applied to search_text and
MatchedConsecutiveLines.from_file_contents. Files whose line breaks are all
LSP-compliant are decomposed exactly as before.
delete_lines/replace_lines address the position one line past the last line
(line == number of lines, col 0). get_index_from_line_col cannot resolve that
position when the file has no trailing newline (no closing newline to count),
so delete_text_between_positions raised InvalidTextLocationError and the delete
crashed on a very common file shape.
Clamp that past-EOF end position to end-of-file in delete_text_between_positions,
mirroring the guard insert_text_at_position already has. A file with no trailing
newline now deletes its last line identically to one with a trailing newline.
Adds TextUtils unit tests and a CHANGELOG entry.