mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-09 21:26:14 +03:00
Allow controlling Tailwind via the language_servers
setting (#11012)
This PR adds the ability for the Tailwind language server (`tailwindcss-language-server`) to be controlled by the `language_servers` setting. Now in your settings you can indicate that the Tailwind language server should be used for a given language, even if that language does not have the Tailwind language server registered for it already: ```json { "languages": { "My Language": { "language_servers": ["tailwindcss-language-server", "..."] } } } ``` Release Notes: - N/A
This commit is contained in:
parent
c833a7e662
commit
3eac581a62
@ -46,6 +46,8 @@ struct LanguageRegistryState {
|
|||||||
available_languages: Vec<AvailableLanguage>,
|
available_languages: Vec<AvailableLanguage>,
|
||||||
grammars: HashMap<Arc<str>, AvailableGrammar>,
|
grammars: HashMap<Arc<str>, AvailableGrammar>,
|
||||||
lsp_adapters: HashMap<Arc<str>, Vec<Arc<CachedLspAdapter>>>,
|
lsp_adapters: HashMap<Arc<str>, Vec<Arc<CachedLspAdapter>>>,
|
||||||
|
available_lsp_adapters:
|
||||||
|
HashMap<LanguageServerName, Arc<dyn Fn() -> Arc<CachedLspAdapter> + 'static + Send + Sync>>,
|
||||||
loading_languages: HashMap<LanguageId, Vec<oneshot::Sender<Result<Arc<Language>>>>>,
|
loading_languages: HashMap<LanguageId, Vec<oneshot::Sender<Result<Arc<Language>>>>>,
|
||||||
subscription: (watch::Sender<()>, watch::Receiver<()>),
|
subscription: (watch::Sender<()>, watch::Receiver<()>),
|
||||||
theme: Option<Arc<Theme>>,
|
theme: Option<Arc<Theme>>,
|
||||||
@ -153,6 +155,7 @@ impl LanguageRegistry {
|
|||||||
language_settings: Default::default(),
|
language_settings: Default::default(),
|
||||||
loading_languages: Default::default(),
|
loading_languages: Default::default(),
|
||||||
lsp_adapters: Default::default(),
|
lsp_adapters: Default::default(),
|
||||||
|
available_lsp_adapters: HashMap::default(),
|
||||||
subscription: watch::channel(),
|
subscription: watch::channel(),
|
||||||
theme: Default::default(),
|
theme: Default::default(),
|
||||||
version: 0,
|
version: 0,
|
||||||
@ -213,6 +216,38 @@ impl LanguageRegistry {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Registers an available language server adapter.
|
||||||
|
///
|
||||||
|
/// The language server is registered under the language server name, but
|
||||||
|
/// not bound to a particular language.
|
||||||
|
///
|
||||||
|
/// When a language wants to load this particular language server, it will
|
||||||
|
/// invoke the `load` function.
|
||||||
|
pub fn register_available_lsp_adapter(
|
||||||
|
&self,
|
||||||
|
name: LanguageServerName,
|
||||||
|
load: impl Fn() -> Arc<dyn LspAdapter> + 'static + Send + Sync,
|
||||||
|
) {
|
||||||
|
self.state.write().available_lsp_adapters.insert(
|
||||||
|
name,
|
||||||
|
Arc::new(move || {
|
||||||
|
let lsp_adapter = load();
|
||||||
|
CachedLspAdapter::new(lsp_adapter, true)
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads the language server adapter for the language server with the given name.
|
||||||
|
pub fn load_available_lsp_adapter(
|
||||||
|
&self,
|
||||||
|
name: &LanguageServerName,
|
||||||
|
) -> Option<Arc<CachedLspAdapter>> {
|
||||||
|
let state = self.state.read();
|
||||||
|
let load_lsp_adapter = state.available_lsp_adapters.get(name)?;
|
||||||
|
|
||||||
|
Some(load_lsp_adapter())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn register_lsp_adapter(&self, language_name: Arc<str>, adapter: Arc<dyn LspAdapter>) {
|
pub fn register_lsp_adapter(&self, language_name: Arc<str>, adapter: Arc<dyn LspAdapter>) {
|
||||||
self.state
|
self.state
|
||||||
.write()
|
.write()
|
||||||
|
@ -789,5 +789,24 @@ mod tests {
|
|||||||
),
|
),
|
||||||
language_server_names(&["deno", "eslint", "tailwind"])
|
language_server_names(&["deno", "eslint", "tailwind"])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Adding a language server not in the list of available languages servers adds it to the list.
|
||||||
|
assert_eq!(
|
||||||
|
LanguageSettings::resolve_language_servers(
|
||||||
|
&[
|
||||||
|
"my-cool-language-server".into(),
|
||||||
|
LanguageSettings::REST_OF_LANGUAGE_SERVERS.into()
|
||||||
|
],
|
||||||
|
&available_language_servers
|
||||||
|
),
|
||||||
|
language_server_names(&[
|
||||||
|
"my-cool-language-server",
|
||||||
|
"typescript-language-server",
|
||||||
|
"biome",
|
||||||
|
"deno",
|
||||||
|
"eslint",
|
||||||
|
"tailwind",
|
||||||
|
])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,10 +107,7 @@ pub fn init(
|
|||||||
language!("cpp", vec![Arc::new(c::CLspAdapter)]);
|
language!("cpp", vec![Arc::new(c::CLspAdapter)]);
|
||||||
language!(
|
language!(
|
||||||
"css",
|
"css",
|
||||||
vec![
|
vec![Arc::new(css::CssLspAdapter::new(node_runtime.clone())),]
|
||||||
Arc::new(css::CssLspAdapter::new(node_runtime.clone())),
|
|
||||||
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
language!("go", vec![Arc::new(go::GoLspAdapter)]);
|
language!("go", vec![Arc::new(go::GoLspAdapter)]);
|
||||||
language!("gomod");
|
language!("gomod");
|
||||||
@ -160,13 +157,7 @@ pub fn init(
|
|||||||
))]
|
))]
|
||||||
);
|
);
|
||||||
language!("ruby", vec![Arc::new(ruby::RubyLanguageServer)]);
|
language!("ruby", vec![Arc::new(ruby::RubyLanguageServer)]);
|
||||||
language!(
|
language!("erb", vec![Arc::new(ruby::RubyLanguageServer),]);
|
||||||
"erb",
|
|
||||||
vec![
|
|
||||||
Arc::new(ruby::RubyLanguageServer),
|
|
||||||
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
language!("regex");
|
language!("regex");
|
||||||
language!(
|
language!(
|
||||||
"yaml",
|
"yaml",
|
||||||
@ -174,14 +165,42 @@ pub fn init(
|
|||||||
);
|
);
|
||||||
language!("proto");
|
language!("proto");
|
||||||
|
|
||||||
|
// Register Tailwind globally as an available language server.
|
||||||
|
//
|
||||||
|
// This will allow users to add Tailwind support for a given language via
|
||||||
|
// the `language_servers` setting:
|
||||||
|
//
|
||||||
|
// ```json
|
||||||
|
// {
|
||||||
|
// "languages": {
|
||||||
|
// "My Language": {
|
||||||
|
// "language_servers": ["tailwindcss-language-server", "..."]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
languages.register_available_lsp_adapter(
|
||||||
|
LanguageServerName("tailwindcss-language-server".into()),
|
||||||
|
{
|
||||||
|
let node_runtime = node_runtime.clone();
|
||||||
|
move || Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone()))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Register Tailwind for the existing languages that should have it by default.
|
||||||
|
//
|
||||||
|
// This can be driven by the `language_servers` setting once we have a way for
|
||||||
|
// extensions to provide their own default value for that setting.
|
||||||
let tailwind_languages = [
|
let tailwind_languages = [
|
||||||
"Astro",
|
"Astro",
|
||||||
|
"CSS",
|
||||||
|
"ERB",
|
||||||
"HEEX",
|
"HEEX",
|
||||||
"HTML",
|
"HTML",
|
||||||
|
"JavaScript",
|
||||||
"PHP",
|
"PHP",
|
||||||
"Svelte",
|
"Svelte",
|
||||||
"TSX",
|
"TSX",
|
||||||
"JavaScript",
|
|
||||||
"Vue.js",
|
"Vue.js",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -3066,12 +3066,34 @@ impl Project {
|
|||||||
.map(|lsp_adapter| lsp_adapter.name.clone())
|
.map(|lsp_adapter| lsp_adapter.name.clone())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let enabled_language_servers =
|
let desired_language_servers =
|
||||||
settings.customized_language_servers(&available_language_servers);
|
settings.customized_language_servers(&available_language_servers);
|
||||||
let enabled_lsp_adapters = available_lsp_adapters
|
|
||||||
.into_iter()
|
let mut enabled_lsp_adapters: Vec<Arc<CachedLspAdapter>> = Vec::new();
|
||||||
.filter(|adapter| enabled_language_servers.contains(&adapter.name))
|
for desired_language_server in desired_language_servers {
|
||||||
.collect::<Vec<_>>();
|
if let Some(adapter) = available_lsp_adapters
|
||||||
|
.iter()
|
||||||
|
.find(|adapter| adapter.name == desired_language_server)
|
||||||
|
{
|
||||||
|
enabled_lsp_adapters.push(adapter.clone());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(adapter) = self
|
||||||
|
.languages
|
||||||
|
.load_available_lsp_adapter(&desired_language_server)
|
||||||
|
{
|
||||||
|
self.languages()
|
||||||
|
.register_lsp_adapter(language.name(), adapter.adapter.clone());
|
||||||
|
enabled_lsp_adapters.push(adapter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log::warn!(
|
||||||
|
"no language server found matching '{}'",
|
||||||
|
desired_language_server.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"starting language servers for {language}: {adapters}",
|
"starting language servers for {language}: {adapters}",
|
||||||
@ -3083,7 +3105,7 @@ impl Project {
|
|||||||
);
|
);
|
||||||
|
|
||||||
for adapter in enabled_lsp_adapters {
|
for adapter in enabled_lsp_adapters {
|
||||||
self.start_language_server(worktree, adapter.clone(), language.clone(), cx);
|
self.start_language_server(worktree, adapter, language.clone(), cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user