Extract language_core and grammars crates from language (#52238)

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>
This commit is contained in:
authored and GitHub committed 2026-03-25 23:41:09 +00:00
1 parent 3684b5a42f
commit 3ce0cd11ec
219 files changed
+2569 -2185

No files matched your search

+14 -6
View File
@@ -39,7 +39,6 @@ use util::fs::{make_file_executable, remove_matching};
use util::paths::PathStyle;
use util::rel_path::RelPath;
use crate::LanguageDir;
use http_client::github_download::{GithubBinaryMetadata, download_server_binary};
use parking_lot::Mutex;
use std::str::FromStr;
@@ -53,7 +52,7 @@ use task::{ShellKind, TaskTemplate, TaskTemplates, VariableName};
use util::{ResultExt, maybe};
pub(crate) fn semantic_token_rules() -> SemanticTokenRules {
let content = LanguageDir::get("python/semantic_token_rules.json")
let content = grammars::get_file("python/semantic_token_rules.json")
.expect("missing python/semantic_token_rules.json");
let json = std::str::from_utf8(&content.data).expect("invalid utf-8 in semantic_token_rules");
settings::parse_json_with_comments::<SemanticTokenRules>(json)
@@ -1121,7 +1120,15 @@ fn python_env_kind_display(k: &PythonEnvironmentKind) -> &'static str {
}
}
pub(crate) struct PythonToolchainProvider;
pub(crate) struct PythonToolchainProvider {
fs: Arc<dyn Fs>,
}
impl PythonToolchainProvider {
pub fn new(fs: Arc<dyn Fs>) -> Self {
Self { fs }
}
}
static ENV_PRIORITY_LIST: &[PythonEnvironmentKind] = &[
// Prioritize non-Conda environments.
@@ -1236,8 +1243,8 @@ impl ToolchainLister for PythonToolchainProvider {
worktree_root: PathBuf,
subroot_relative_path: Arc<RelPath>,
project_env: Option<HashMap<String, String>>,
fs: &dyn Fs,
) -> ToolchainList {
let fs = &*self.fs;
let env = project_env.unwrap_or_default();
let environment = EnvironmentApi::from_env(&env);
let locators = pet::locators::create_locators(
@@ -1368,8 +1375,8 @@ impl ToolchainLister for PythonToolchainProvider {
&self,
path: PathBuf,
env: Option<HashMap<String, String>>,
fs: &dyn Fs,
) -> anyhow::Result<Toolchain> {
let fs = &*self.fs;
let env = env.unwrap_or_default();
let environment = EnvironmentApi::from_env(&env);
let locators = pet::locators::create_locators(
@@ -2664,7 +2671,8 @@ mod tests {
});
});
let provider = PythonToolchainProvider;
let fs = project::FakeFs::new(cx.executor());
let provider = PythonToolchainProvider::new(fs);
let malicious_name = "foo; rm -rf /";
let manager_executable = std::env::current_exe().unwrap();