Skip to content

Comments

Add syntax highlighting for project symbol search#188

Merged
tartarughina merged 4 commits intozed-extensions:mainfrom
da-r-k:feat/label-for-symbol
Feb 24, 2026
Merged

Add syntax highlighting for project symbol search#188
tartarughina merged 4 commits intozed-extensions:mainfrom
da-r-k:feat/label-for-symbol

Conversation

@da-r-k
Copy link
Contributor

@da-r-k da-r-k commented Feb 9, 2026

Summary

Implements label_for_symbol to provide syntax-highlighted labels in the project symbol picker (cmd-t). Currently, Java symbols appear as plain grey text with no highlighting, unlike Rust and other languages that already implement this.

Ref: zed-industries/zed#36383, zed-industries/zed#37176

Changes

  • Add label_for_symbol to the Extension for Java impl
  • Import Symbol and SymbolKind from the extension API
  • Generate Tree-sitter-parseable code snippets for each symbol kind so the Java grammar produces correct AST nodes and syntax highlighting
  • Wrap member-level constructs (methods, fields, constructors) inside class _ { } since Java's Tree-sitter grammar requires class context for these declarations
  • Display symbols in Java declaration order (type before name): void doWork(String, int), String fieldName
  • Show keyword prefixes for type declarations: class, interface, enum, package

Supported symbol kinds

Kind Display example Tree-sitter context
Class class MyClass class MyClass {}
Interface interface Runnable interface Runnable {}
Enum enum Status enum Status {}
Constructor MyClass(String, int) class MyClass { MyClass() {} }
Method void doWork(String, int) class _ { void doWork() {} }
Field String name class _ { String name; }
Constant MAX_SIZE class _ { static final int MAX_SIZE; }
EnumMember ACTIVE enum _ { ACTIVE }
Variable count class _ { int count; }
Package package com.example package com.example;

Screenshot:

image

@cla-bot
Copy link

cla-bot bot commented Feb 9, 2026

We require contributors to sign our Contributor License Agreement, and we don't have @da-r-k on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@da-r-k
Copy link
Contributor Author

da-r-k commented Feb 9, 2026

@cla-bot check

@cla-bot
Copy link

cla-bot bot commented Feb 9, 2026

We require contributors to sign our Contributor License Agreement, and we don't have @da-r-k on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@cla-bot
Copy link

cla-bot bot commented Feb 9, 2026

The cla-bot has been summoned, and re-checked this pull request!

@da-r-k
Copy link
Contributor Author

da-r-k commented Feb 9, 2026

@cla-bot check

@cla-bot cla-bot bot added the cla-signed label Feb 9, 2026
@cla-bot
Copy link

cla-bot bot commented Feb 9, 2026

The cla-bot has been summoned, and re-checked this pull request!

@tartarughina
Copy link
Collaborator

Thanks for the PR.

Please format the code with

cargo fmt --all

and push another commit

@tartarughina
Copy link
Collaborator

@da-r-k I've tried the extension but it doesn't seem to be working as intended.

For example, when searching for the symbol Media, see snippet below, I was just getting Media in the list without any of the additional information about it

@EqualsAndHashCode
public abstract class Media {

    public static final EmptyMedia EMPTY = new EmptyMedia();

}

Are these changes depending on a change to the grammar?

@da-r-k
Copy link
Contributor Author

da-r-k commented Feb 9, 2026

@tartarughina

image

Works for me as expected. The highlighting is based on the LSP response (SymbolKind). Could you check once if you built the correct branch?

@tartarughina
Copy link
Collaborator

@da-r-k@da-r-k, I’ve been using the wrong branch. I assumed gh would have retrieved the correct one, but apparently, it wasn’t the case.
I can now see the changes.

Is fuzzy search something that the LSP needs to support to be used or is it up to us to enable it?

@da-r-k
Copy link
Contributor Author

da-r-k commented Feb 9, 2026

@tartarughina Yes. JDTLS uses CamelCase fuzzy search. So if you search for EmpMe it would return EmptyMedia as one of the results. It works like the regex Emp*Me*

@tartarughina
Copy link
Collaborator

@da-r-k interesting, I didn't know that it was using CamelCase fuzzy. Since that might be new to a lot, do you mind adding a small entry in the README explaining how project symbol works?

The main points would be:

  • the LSP offers it
  • fuzzy search is available but it expects CamelCase queries

src/java.rs Outdated
Comment on lines 547 to 577
SymbolKind::Class => {
// code: "class Name {}" → Tree-sitter: class_declaration
// display: "class Name"
let keyword = "class ";
let code = format!("{keyword}{name} {{}}");

Some(CodeLabel {
spans: vec![CodeLabelSpan::code_range(0..keyword.len() + name.len())],
filter_range: (keyword.len()..keyword.len() + name.len()).into(),
code,
})
}
SymbolKind::Interface => {
let keyword = "interface ";
let code = format!("{keyword}{name} {{}}");

Some(CodeLabel {
spans: vec![CodeLabelSpan::code_range(0..keyword.len() + name.len())],
filter_range: (keyword.len()..keyword.len() + name.len()).into(),
code,
})
}
SymbolKind::Enum => {
let keyword = "enum ";
let code = format!("{keyword}{name} {{}}");

Some(CodeLabel {
spans: vec![CodeLabelSpan::code_range(0..keyword.len() + name.len())],
filter_range: (keyword.len()..keyword.len() + name.len()).into(),
code,
})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is pretty much the same if not for the keyword, cannot we simplify it removing repeated code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — combined Class/Interface/Enum into a single match arm with an inner match for the keyword.

src/java.rs Outdated
})
} else {
// No type info, just show the name
let class_open = "class _ { int ";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it default to int?

src/java.rs Outdated
}
SymbolKind::Constant => {
// Wrap in class; ALL_CAPS names get @constant from highlights.scm regex
let class_open = "class _ { static final int ";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why using int?

src/java.rs Outdated
})
}
SymbolKind::Variable => {
let class_open = "class _ { int ";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above regarding int usage

@da-r-k
Copy link
Contributor Author

da-r-k commented Feb 19, 2026

@tartarughina We do not get a type info from the LSP. That's why I used int. Anyways, JDTLS does not support variables in the workspace/symbols call. It only supports methods and classes afaik

@tartarughina
Copy link
Collaborator

@da-r-k if the type is not returned then let's avoid defaulting to int. Also, if the LSP only supports methods and classes let's clean up unused code

da-r-k and others added 3 commits February 24, 2026 02:11
Implement `label_for_symbol` to provide syntax-highlighted labels in the
project symbol picker (cmd-t). Without this, Java symbols appear as
plain grey text.

Each symbol kind generates a Tree-sitter-parseable code snippet wrapped
in the appropriate context (e.g. methods/fields inside `class _ { }`)
so the Java grammar can produce correct AST nodes for highlighting.

Supported symbols:
- Class, Interface, Enum: keyword prefix + name
- Method/Function: return type + name + params (Java declaration order)
- Constructor: name + params
- Field/Property: type + name (Java declaration order)
- Constant, EnumMember, Variable: highlighted name
- Package/Module/Namespace: keyword prefix + name

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove handlers for symbol kinds that JDTLS workspace/symbol never
returns (Constructor, Field, Constant, EnumMember, Variable, Package).
Deduplicate Class/Interface/Enum into a single match arm. Add README
section documenting project symbol search and CamelCase fuzzy matching.

JDTLS WorkspaceSymbolHandler only searches type names (Class, Interface,
Enum, Annotation) and optionally method names when
includeSourceMethodDeclarations is enabled:
https://github.com/eclipse-jdtls/eclipse.jdt.ls/blob/main/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceSymbolHandler.java

Zed only calls label_for_symbol for workspace/symbol results, not
textDocument/documentSymbol:
https://github.com/zed-industries/zed/blob/main/crates/language_extension/src/extension_lsp_adapter.rs
@da-r-k da-r-k force-pushed the feat/label-for-symbol branch from 195b59e to 6c04d33 Compare February 23, 2026 20:48
@cla-bot
Copy link

cla-bot bot commented Feb 23, 2026

We require contributors to sign our Contributor License Agreement, and we don't have @gitbutler-client on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@cla-bot cla-bot bot removed the cla-signed label Feb 23, 2026
@da-r-k da-r-k force-pushed the feat/label-for-symbol branch from 6c04d33 to 48c4a51 Compare February 23, 2026 20:54
@cla-bot cla-bot bot added the cla-signed label Feb 23, 2026
Remove handlers for symbol kinds that JDTLS workspace/symbol never
returns (Constructor, Field, Constant, EnumMember, Variable, Package).
Deduplicate Class/Interface/Enum into a single match arm. Add README
section documenting project symbol search and CamelCase fuzzy matching.

JDTLS WorkspaceSymbolHandler only searches type names (Class, Interface,
Enum, Annotation) and optionally method names when
includeSourceMethodDeclarations is enabled:
https://github.com/eclipse-jdtls/eclipse.jdt.ls/blob/main/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceSymbolHandler.java

Zed only calls label_for_symbol for workspace/symbol results, not
textDocument/documentSymbol:
https://github.com/zed-industries/zed/blob/main/crates/language_extension/src/extension_lsp_adapter.rs
@da-r-k
Copy link
Contributor Author

da-r-k commented Feb 23, 2026

@tartarughina cleaned up the code to only include supported symbols. The last commit message has code references for all the symbols that are supported.

Copy link
Collaborator

@tartarughina tartarughina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the changes and for updating the README. Looks good to me

@tartarughina tartarughina merged commit 5e372db into zed-extensions:main Feb 24, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants