Skip to content

Commit 5e372db

Browse files
da-r-kclaude
andauthored
Add syntax highlighting for project symbol search (#188)
Implements `label_for_symbol` to provide syntax-highlighted labels in the project symbol picker (`cmd-t`) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6cda290 commit 5e372db

2 files changed

Lines changed: 72 additions & 1 deletion

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ Here is a common `settings.json` including the above mentioned configurations:
4545
}
4646
```
4747

48+
## Project Symbol Search
49+
50+
The extension supports project-wide symbol search with syntax-highlighted results. This feature is powered by JDTLS and can be accessed via Zed's symbol search.
51+
52+
JDTLS uses **CamelCase fuzzy matching** for symbol queries. For example, searching for `EmpMe` would match `EmptyMedia`. The pattern works like `Emp*Me*`, matching the capital letters of CamelCase names.
53+
4854
## Debugger
4955

5056
Debug support is enabled via our [Fork of Java Debug](https://github.com/zed-industries/java-debug), which the extension will automatically download and start for you. Please refer to the [Zed Documentation](https://zed.dev/docs/debugger#getting-started) for general information about how debugging works in Zed.

src/java.rs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use zed_extension_api::{
1616
self as zed, CodeLabel, CodeLabelSpan, DebugAdapterBinary, DebugTaskDefinition, Extension,
1717
LanguageServerId, LanguageServerInstallationStatus, StartDebuggingRequestArguments,
1818
StartDebuggingRequestArgumentsRequest, Worktree,
19-
lsp::{Completion, CompletionKind},
19+
lsp::{Completion, CompletionKind, Symbol, SymbolKind},
2020
register_extension,
2121
serde_json::{Value, json},
2222
set_language_server_installation_status,
@@ -535,6 +535,71 @@ impl Extension for Java {
535535
_ => None,
536536
})
537537
}
538+
539+
fn label_for_symbol(
540+
&self,
541+
_language_server_id: &LanguageServerId,
542+
symbol: Symbol,
543+
) -> Option<CodeLabel> {
544+
let name = &symbol.name;
545+
546+
match symbol.kind {
547+
SymbolKind::Class | SymbolKind::Interface | SymbolKind::Enum => {
548+
let keyword = match symbol.kind {
549+
SymbolKind::Class => "class ",
550+
SymbolKind::Interface => "interface ",
551+
SymbolKind::Enum => "enum ",
552+
_ => unreachable!(),
553+
};
554+
let code = format!("{keyword}{name} {{}}");
555+
556+
Some(CodeLabel {
557+
spans: vec![CodeLabelSpan::code_range(0..keyword.len() + name.len())],
558+
filter_range: (keyword.len()..keyword.len() + name.len()).into(),
559+
code,
560+
})
561+
}
562+
SymbolKind::Method | SymbolKind::Function => {
563+
// jdtls: "methodName(Type, Type) : ReturnType" or "methodName(Type)"
564+
// display: "ReturnType methodName(Type, Type)" (Java declaration order)
565+
let method_name = name.split('(').next().unwrap_or(name);
566+
let after_name = &name[method_name.len()..];
567+
568+
let (params, return_type) = if let Some((p, r)) = after_name.split_once(" : ") {
569+
(p, Some(r))
570+
} else {
571+
(after_name, None)
572+
};
573+
574+
let ret = return_type.unwrap_or("void");
575+
let class_open = "class _ { ";
576+
let code = format!("{class_open}{ret} {method_name}() {{}} }}");
577+
578+
let ret_start = class_open.len();
579+
let name_start = ret_start + ret.len() + 1;
580+
581+
// Display: "void methodName(String, int)"
582+
let mut spans = vec![
583+
CodeLabelSpan::code_range(ret_start..ret_start + ret.len()),
584+
CodeLabelSpan::literal(" ".to_string(), None),
585+
CodeLabelSpan::code_range(name_start..name_start + method_name.len()),
586+
];
587+
if !params.is_empty() {
588+
spans.push(CodeLabelSpan::literal(params.to_string(), None));
589+
}
590+
591+
// filter on "methodName(params)" portion of displayed text
592+
let type_prefix_len = ret.len() + 1; // "void "
593+
let filter_end = type_prefix_len + method_name.len() + params.len();
594+
Some(CodeLabel {
595+
spans,
596+
filter_range: (type_prefix_len..filter_end).into(),
597+
code,
598+
})
599+
}
600+
_ => None,
601+
}
602+
}
538603
}
539604

540605
register_extension!(Java);

0 commit comments

Comments
 (0)