mirror of
https://github.com/zed-industries/zed.git
synced 2026-05-24 21:59:04 +00:00
This extracts a `language_core` crate from the existing `language`
crate, and creates a `grammars` data crate. The goal is to separate
tree-sitter grammar infrastructure, language configuration, and LSP
adapter types from the heavier buffer/editor integration layer in
`language`.
## Motivation
The `language` crate pulls in `text`, `theme`, `settings`, `rpc`,
`task`, `fs`, `clock`, `sum_tree`, and `fuzzy` — all of which are needed
for buffer integration (`Buffer`, `SyntaxMap`, `Outline`,
`DiagnosticSet`) but not for grammar parsing or language configuration.
Extracting the core types lets downstream consumers depend on
`language_core` without pulling in the full integration stack.
## Dependency graph after extraction
```
language_core ← gpui, lsp, tree-sitter, util, collections
grammars ← language_core, rust_embed, tree-sitter-{rust,python,...}
language ← language_core, text, theme, settings, rpc, task, fs, ...
languages ← language, grammars
```
## What moved to `language_core`
- `Grammar`, `GrammarId`, and all query config/builder types
- `LanguageConfig`, `LanguageMatcher`, bracket/comment/indent config
types
- `HighlightMap`, `HighlightId` (theme-dependent free functions
`highlight_style` and `highlight_name` stay in `language`)
- `LanguageName`, `LanguageId`
- `LanguageQueries`, `QUERY_FILENAME_PREFIXES`
- `CodeLabel`, `CodeLabelBuilder`, `Symbol`
- `Diagnostic`, `DiagnosticSourceKind`
- `Toolchain`, `ToolchainScope`, `ToolchainList`, `ToolchainMetadata`
- `ManifestName`
- `SoftWrap`
- LSP data types: `BinaryStatus`, `ServerHealth`,
`LanguageServerStatusUpdate`, `PromptResponseContext`, `ToLspPosition`
## What stays in `language`
- `Buffer`, `BufferSnapshot`, `SyntaxMap`, `Outline`, `DiagnosticSet`,
`LanguageScope`
- `LspAdapter`, `CachedLspAdapter`, `LspAdapterDelegate` (reference
`Arc<Language>` and `WorktreeId`)
- `ToolchainLister`, `LanguageToolchainStore` (reference `task` and
`settings` types)
- `ManifestQuery`, `ManifestProvider`, `ManifestDelegate` (reference
`WorktreeId`)
- Parser/query cursor pools, `PLAIN_TEXT`, point conversion functions
## What the `grammars` crate provides
- Embedded `.scm` query files and `config.toml` files for all built-in
languages (via `rust_embed`)
- `load_queries(name)`, `load_config(name)`,
`load_config_for_feature(name, grammars_loaded)`, and `get_file(path)`
functions
- `native_grammars()` for tree-sitter grammar registration (behind
`load-grammars` feature)
## Pre-cleanup (also in this PR)
- Removed unused `Option<&Buffer>` from
`LspAdapter::process_diagnostics`
- Removed unused `&App` from `LspAdapter::retain_old_diagnostic`
- Removed `fs: &dyn Fs` from `ToolchainLister` trait methods
(`PythonToolchainProvider` captures `fs` at construction time instead)
- Moved `Diagnostic`/`DiagnosticSourceKind` out of `buffer.rs` into
their own module
## Backward compatibility
The `language` crate re-exports everything from `language_core`, so
existing `use language::Grammar` (etc.) continues to work unchanged. The
only downstream change required is importing `CodeLabelExt` where
`.fallback_for_completion()` is called on the now-foreign `CodeLabel`
type.
Release Notes:
- N/A
---------
Co-authored-by: Agus Zubiaga <agus@zed.dev>
Co-authored-by: Tom Houlé <tom@tomhoule.com>
122 lines
3.3 KiB
Rust
122 lines
3.3 KiB
Rust
use crate::highlight_map::HighlightId;
|
|
use std::ops::Range;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Symbol {
|
|
pub name: String,
|
|
pub kind: lsp::SymbolKind,
|
|
pub container_name: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
|
pub struct CodeLabel {
|
|
/// The text to display.
|
|
pub text: String,
|
|
/// Syntax highlighting runs.
|
|
pub runs: Vec<(Range<usize>, HighlightId)>,
|
|
/// The portion of the text that should be used in fuzzy filtering.
|
|
pub filter_range: Range<usize>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
|
pub struct CodeLabelBuilder {
|
|
/// The text to display.
|
|
text: String,
|
|
/// Syntax highlighting runs.
|
|
runs: Vec<(Range<usize>, HighlightId)>,
|
|
/// The portion of the text that should be used in fuzzy filtering.
|
|
filter_range: Range<usize>,
|
|
}
|
|
|
|
impl CodeLabel {
|
|
pub fn plain(text: String, filter_text: Option<&str>) -> Self {
|
|
Self::filtered(text.clone(), text.len(), filter_text, Vec::new())
|
|
}
|
|
|
|
pub fn filtered(
|
|
text: String,
|
|
label_len: usize,
|
|
filter_text: Option<&str>,
|
|
runs: Vec<(Range<usize>, HighlightId)>,
|
|
) -> Self {
|
|
assert!(label_len <= text.len());
|
|
let filter_range = filter_text
|
|
.and_then(|filter| text.find(filter).map(|index| index..index + filter.len()))
|
|
.unwrap_or(0..label_len);
|
|
Self::new(text, filter_range, runs)
|
|
}
|
|
|
|
pub fn new(
|
|
text: String,
|
|
filter_range: Range<usize>,
|
|
runs: Vec<(Range<usize>, HighlightId)>,
|
|
) -> Self {
|
|
assert!(
|
|
text.get(filter_range.clone()).is_some(),
|
|
"invalid filter range"
|
|
);
|
|
runs.iter().for_each(|(range, _)| {
|
|
assert!(
|
|
text.get(range.clone()).is_some(),
|
|
"invalid run range with inputs. Requested range {range:?} in text '{text}'",
|
|
);
|
|
});
|
|
Self {
|
|
runs,
|
|
filter_range,
|
|
text,
|
|
}
|
|
}
|
|
|
|
pub fn text(&self) -> &str {
|
|
self.text.as_str()
|
|
}
|
|
|
|
pub fn filter_text(&self) -> &str {
|
|
&self.text[self.filter_range.clone()]
|
|
}
|
|
}
|
|
|
|
impl From<String> for CodeLabel {
|
|
fn from(value: String) -> Self {
|
|
Self::plain(value, None)
|
|
}
|
|
}
|
|
|
|
impl From<&str> for CodeLabel {
|
|
fn from(value: &str) -> Self {
|
|
Self::plain(value.to_string(), None)
|
|
}
|
|
}
|
|
|
|
impl CodeLabelBuilder {
|
|
pub fn respan_filter_range(&mut self, filter_text: Option<&str>) {
|
|
self.filter_range = filter_text
|
|
.and_then(|filter| {
|
|
self.text
|
|
.find(filter)
|
|
.map(|index| index..index + filter.len())
|
|
})
|
|
.unwrap_or(0..self.text.len());
|
|
}
|
|
|
|
pub fn push_str(&mut self, text: &str, highlight: Option<HighlightId>) {
|
|
let start_index = self.text.len();
|
|
self.text.push_str(text);
|
|
if let Some(highlight) = highlight {
|
|
let end_index = self.text.len();
|
|
self.runs.push((start_index..end_index, highlight));
|
|
}
|
|
}
|
|
|
|
pub fn build(mut self) -> CodeLabel {
|
|
if self.filter_range.end == 0 {
|
|
self.respan_filter_range(None);
|
|
}
|
|
CodeLabel {
|
|
text: self.text,
|
|
runs: self.runs,
|
|
filter_range: self.filter_range,
|
|
}
|
|
}
|
|
}
|