Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,12 @@ To set up the vscode-java-dependency project, follow these steps:
- Run the "Attach to Plugin" task.
- Note: This task is required only if you want to debug Java code [jdtls.ext](./jdtls.ext). It requires the [vscode-pde](https://marketplace.visualstudio.com/items?itemName=yaozheng.vscode-pde) extension to be installed.

## Java LSP Tool Contract Tests

After installing dependencies, run `npm run test-lsp-tools` for the isolated navigation-tool suite. It compiles TypeScript and starts a separate VS Code test host; no Java server build, Java project, or signed-in Copilot session is required. Set `VSCODE_EXECUTABLE_PATH` to reuse an existing VS Code executable instead of downloading one.

These tests exercise the tool implementations with real VS Code URI, range, error and tool-result types, but mock providers, workspace membership, readiness and telemetry. They cover output contracts, URI handoff, error classification, retry behavior and truncation. They do not validate live JDT search coverage, indexing completeness, Native/CLI reader integration or token savings. The suite also runs as part of `npm test`.

`lmTool.findSymbol` records `initialQueryDurationMs` and `retryQueryDurationMs` separately from total `durationMs`. These measure client-observed provider calls, not internal JDT phases; retry duration is zero when no retry occurs. No query text, source paths or symbol names are added to these events.

Thank you for your contributions and support!
23 changes: 14 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
{
"name": "lsp_java_getFileStructure",
"toolReferenceName": "javaFileStructure",
"modelDescription": "Outline a known Java file (classes, methods, fields with line ranges) to pick a precise read_file range instead of reading the whole file. Needs a path from lsp_java_findSymbol or the user — do not guess. Returns file plus per-symbol readFileRange ({ offset, limit }) for read_file. Use limit to cap outline items (default 20, max 60). Not for workspace search (use lsp_java_findSymbol).",
"modelDescription": "Outline a known workspace Java file with full declaration readFileRange. Use a confirmed path or documentUri; never guess. Only file: workspace documents are supported.",
"displayName": "Java: Get File Structure",
"userDescription": "Get a Java file outline with classes, methods, fields, and line ranges.",
"tags": [
Expand All @@ -69,11 +69,13 @@
"properties": {
"uri": {
"type": "string",
"description": "Workspace-relative path to a Java file, from lsp_java_findSymbol or user input — do not guess."
"description": "File URI or absolute/workspace-relative path."
},
"limit": {
"type": "number",
"description": "Maximum outline items to return (default: 20, max: 60). Use a smaller value when only top-level context is needed."
"type": "integer",
"minimum": 1,
"maximum": 60,
"description": "Output node cap, including children; default 20. Does not bound provider work."
}
},
"required": [
Expand All @@ -84,9 +86,9 @@
{
"name": "lsp_java_findSymbol",
"toolReferenceName": "javaFindSymbol",
"modelDescription": "Find Java class/interface/method/field definitions across the workspace by name or partial identifier. Prefer over grep_search, file_search, or semantic_search for Java symbol lookup. Each result has file and readFileInput ({ filePath, offset, limit }) for read_file; use it when source is needed, or lsp_java_getFileStructure with file for broader context. On empty results don't re-search (it retries internally); retry once only if it reports indexing in progress, else use generic search. Not for non-Java files, literals, comments, or build/XML files.",
"modelDescription": "Find Java types by name/pattern; source methods require opt-in, fields are unsupported. selectionRange is navigation-only. For full source ranges, pass documentUri to lsp_java_getFileStructure when outlineSupported=true.",
"displayName": "Java: Find Symbol",
"userDescription": "Find Java class, method, field, or interface definitions by name.",
"userDescription": "Locate Java types by name; source methods depend on Java symbol-search settings.",
"tags": [
"java",
"lsp",
Expand All @@ -101,11 +103,13 @@
"properties": {
"query": {
"type": "string",
"description": "Symbol name or pattern to search for"
"description": "Java type name or pattern."
},
"limit": {
"type": "number",
"description": "Maximum results (default: 20, max: 50)"
"type": "integer",
"minimum": 1,
"maximum": 50,
"description": "Output result cap; default 20. Does not bound provider work."
}
},
"required": [
Expand Down Expand Up @@ -1192,6 +1196,7 @@
"compile": "tsc -p . && webpack --config webpack.config.js --mode development",
"watch": "webpack --mode development --watch",
"test": "tsc -p . && webpack --config webpack.config.js --mode development && node ./dist/test/index.js",
"test-lsp-tools": "tsc -p . && node ./out/test/runLspToolsTests.js",
"test-e2e": "autotest run-all test/e2e-plans --no-llm",
"build-server": "node scripts/buildJdtlsExt.js",
"vscode:prepublish": "tsc -p ./ && webpack --mode production",
Expand Down
13 changes: 3 additions & 10 deletions resources/instruments/javaLspContext.instructions.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
---
description: Use Java LSP tools for precise Java symbol navigation. Prefer lsp_java_findSymbol and lsp_java_getFileStructure over generic search only when locating Java classes, methods, fields, or file outlines.
description: Java type lookup and known-file outlines.
applyTo: '**/*.java'
---

For Java symbol navigation, two compiler-accurate `lsp_java_*` tools are available and return structured results with smaller, easier-to-interpret payloads than generic search:
Prefer Java LSP tools for type-name lookup and known-file outlines. Use text search for members with unknown containing types or non-symbol content. Do not change Java settings to make a lookup work.

- `lsp_java_findSymbol(query)` — find class/method/field definitions by name across the workspace
- `lsp_java_getFileStructure(uri)` — get file outline (classes, methods, fields) with line ranges

If these tools are not already available in the current tool list, load them with `tool_search` using a query such as `Java LSP symbol navigation lsp_java`.

Use `lsp_java_findSymbol` before `grep_search`, `search_subagent`, `semantic_search`, or `file_search` only when the task is to locate Java symbols by name or partial identifier. If it returns relevant symbols and source is needed, call `read_file` with the returned `readFileInput`, or call `lsp_java_getFileStructure` with the returned `file` when broader file context is needed.

Use `lsp_java_getFileStructure` only with a path confirmed by the user or a previous tool result. Prefer `file` from `lsp_java_findSymbol`; do not guess paths. Its output includes a top-level `file` and per-symbol `readFileRange`; to read a selected symbol, call `read_file` with `filePath=file` and that `readFileRange`. Use `limit` to keep large outlines small. Use generic search for string literals, comments, XML, Gradle/Maven files, non-Java files, or broad conceptual exploration. `lsp_java_findSymbol` already retries internally with a normalized identifier, so do not re-issue the same search on an empty result: if it reports indexing in progress, retry once after a short pause; otherwise fall back to generic search.
Load the `java-lsp-tools` skill as needed for tool discovery, settings, URI/range handoff, reader adaptation and fallback rules.
40 changes: 26 additions & 14 deletions resources/skills/java-lsp-tools/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,41 @@
---
name: java-lsp-tools
description: Compiler-accurate Java symbol navigation via the Java Language Server. Use lsp_java_findSymbol for Java identifiers and lsp_java_getFileStructure for known Java files; prefer them over generic search only for symbol/file-outline navigation.
description: Java LSP navigation, source-range handoff and troubleshooting for type lookup and file outlines.
---

# Java LSP Tools

Two compiler-accurate tools backed by the Java Language Server (jdtls). They return structured JSON that is easier to interpret than generic search results for Java symbol navigation.
Two navigation tools backed by language-service providers, including the Java Language Server (jdtls). Availability and results depend on imported projects, provider scope and Java settings; they do not certify complete coverage.

If these tools are not already available in the current tool list, load them with `tool_search` using a query such as `Java LSP symbol navigation lsp_java`.

## Tools

### `lsp_java_findSymbol`
Search for Java symbol definitions (classes, methods, fields) by name across the workspace. Supports partial matching.
- Input: `{ query, limit? }` — limit defaults to 20, max 50
- Output: `{ results: [{ name, kind, container?, file, startLine, endLine, readFileInput, range }], total }`; `readFileInput` is `{ filePath, offset, limit }` for `read_file`, and `file` can be passed to `lsp_java_getFileStructure`
- **Use instead of** `grep_search`, `file_search`, `semantic_search`, or `search_subagent` when looking for where a Java class/method/field is defined by identifier
- When source is needed for a returned symbol, use its `readFileInput` directly
Locate Java types (classes, interfaces, enums, records) by name or pattern.
- Input: `{ query, limit? }` — integer limit defaults to 20, max 50; caps output only, not provider search work.
- Source methods are searched only when `java.symbols.includeSourceMethodDeclarations` is enabled (off by default). Fields are not searched. Do not change user settings to make a query work.
- Output: `{ results: [{ name, kind, container?, documentUri, file?, outlineSupported, unsupportedReason?, selectionRange: { startLine, endLine } }], total, truncated? }`.
- `selectionRange` contains 1-based inclusive navigation lines, usually only the name. It is **not** a full declaration or implementation read range.
- `documentUri` preserves the provider's exact URI. `file` is an absolute path, present only for supported `file:` workspace documents. `outlineSupported` means the location is eligible for the outline tool, not that the file exists or is readable.
- Prefer this tool for type-name lookup. For a member, inspect the known containing type's file outline; if the type is unknown, use text search.

### `lsp_java_getFileStructure`
Get hierarchical outline of a Java file (classes, methods, fields) with line ranges.
- Input: `{ uri, limit? }` — workspace-relative path plus max outline items. Prefer `file` from `lsp_java_findSymbol`; limit defaults to 20, max 60. Must be a known path from prior tool results or user input — do not guess
- Output: `{ file, symbols: [{ name, kind, startLine, endLine, readFileRange, range, detail?, children? }], truncated? }`; call `read_file` with `filePath=file` and the selected symbol's `readFileRange`
- Input: `{ uri, limit? }` — prefer the exact `documentUri` from a result with `outlineSupported=true`. Confirmed absolute or workspace-relative file paths also work. Do not guess paths. Integer limit defaults to 20, max 60, including child nodes.
- Only `file:` documents within the workspace are supported. The item limit caps output, not provider work.
- Output: `{ documentUri, file, symbols: [{ name, kind, startLine, endLine, readFileRange, range, detail?, children? }], truncated? }`. `file` is absolute. `readFileRange` contains a 1-based `offset` and line-count `limit` covering the provider's full declaration range.
- For a reader accepting `{ filePath, offset, limit }`, use `filePath=file` with the selected symbol's `readFileRange`. Adapt to other reader schemas; Native and CLI parameters are not necessarily identical.
- Select a member before reading a large class. `truncated=true` means count or depth limits omitted symbols; it does not mean the requested member is absent. Use targeted text search when the capped outline omits it.
- **Use before** `read_file` when you need to choose a precise line range in a known Java file

## When to Use

| Task | Use | Not |
|---|---|---|
| Find class/method/field definition | `lsp_java_findSymbol` | `grep_search` |
| Find a type by name | `lsp_java_findSymbol` | Full-file reads |
| Find a member of a known type | Locate type, then `lsp_java_getFileStructure` | Blind member-name workspace search |
| Find a member with unknown containing type | Text search | Assuming method/field search is supported |
| See known Java file outline before reading | `lsp_java_getFileStructure` | `read_file` full file |
| Search non-Java files (xml, gradle) | `grep_search` | lsp tools |
| Search string literals or comments | `grep_search` | lsp tools |
Expand All @@ -36,10 +45,13 @@ Get hierarchical outline of a Java file (classes, methods, fields) with line ran

**lsp_java_findSymbol → lsp_java_getFileStructure → read_file (specific lines only)**

If `lsp_java_findSymbol` returns relevant symbols and source is needed, call `read_file` with the returned `readFileInput`, or call `lsp_java_getFileStructure` with the returned `file` when broader file context is needed.
If `lsp_java_findSymbol` returns a relevant result with `outlineSupported=true` and implementation is needed, pass `documentUri` to `lsp_java_getFileStructure`. Select the appropriate member's full range, then read it. Do not use the workspace symbol's `selectionRange` as a substitute for a full implementation.

## Fallback

- `findSymbol` returns empty → it already retried internally with a normalized identifier, so do not re-issue the same search. If the result says indexing is in progress, retry once after a short pause; otherwise fall back to `grep_search`
- Path error (`fileNotFound`) → use `findSymbol` to discover the correct path first; do not guess paths
- Tool error / jdtls not ready → fall back to `grep_search` + `read_file`, don't retry more than once
- Empty result: normalization is retried internally only when it changes the query. Retry once after initialization if `reason=serverNotFullyReady`; otherwise use text search. Initialization readiness is not index-completeness evidence.
- `outlineSupported=false`: use an authorized document reader supporting `documentUri`. Dependency, virtual, remote and outside-workspace documents are not supported by this outline tool; do not rewrite their URIs as workspace paths or bypass access boundaries.
- `fileNotFound`: confirm the file via type lookup or file search; do not guess.
- `permissionDenied` / `fileSystemUnavailable`: check permissions or the file system connection; symbol search does not repair these failures.
- `ambiguousWorkspacePath`: pass `documentUri` instead of a duplicated workspace-folder display name.
- Other tool errors: fall back to text search and an appropriate reader; do not repeatedly retry.
Loading
Loading