mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-26 03:13:29 +04:00
Configure language servers via LanguageConfiguration.
This commit is contained in:
parent
1cf887dea9
commit
bb87b08fc9
@ -11,20 +11,27 @@
|
||||
|
||||
// largely based on tree-sitter/cli/src/loader.rs
|
||||
pub struct LanguageConfiguration {
|
||||
pub(crate) scope: String, // source.rust
|
||||
pub(crate) file_types: Vec<String>, // filename ends_with? <Gemfile, rb, etc>
|
||||
pub scope: String, // source.rust
|
||||
pub file_types: Vec<String>, // filename ends_with? <Gemfile, rb, etc>
|
||||
pub roots: Vec<String>, // these indicate project roots <.git, Cargo.toml>
|
||||
|
||||
pub(crate) path: PathBuf,
|
||||
pub path: PathBuf,
|
||||
// root_path for tree-sitter (^)
|
||||
|
||||
// content_regex
|
||||
// injection_regex
|
||||
// first_line_regex
|
||||
//
|
||||
// root_path
|
||||
//
|
||||
pub(crate) language_id: Lang,
|
||||
pub(crate) highlight_config: OnceCell<Option<Arc<HighlightConfiguration>>>,
|
||||
// tags_config OnceCell<> https://github.com/tree-sitter/tree-sitter/pull/583
|
||||
pub language_server_config: Option<LanguageServerConfiguration>,
|
||||
}
|
||||
|
||||
pub struct LanguageServerConfiguration {
|
||||
pub command: String,
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
impl LanguageConfiguration {
|
||||
@ -90,6 +97,11 @@ fn init() -> Loader {
|
||||
highlight_config: OnceCell::new(),
|
||||
//
|
||||
path: "../helix-syntax/languages/tree-sitter-rust".into(),
|
||||
roots: vec![],
|
||||
language_server_config: Some(LanguageServerConfiguration {
|
||||
command: "rust-analyzer".to_string(),
|
||||
args: vec![],
|
||||
}),
|
||||
},
|
||||
LanguageConfiguration {
|
||||
scope: "source.toml".to_string(),
|
||||
@ -98,6 +110,8 @@ fn init() -> Loader {
|
||||
highlight_config: OnceCell::new(),
|
||||
//
|
||||
path: "../helix-syntax/languages/tree-sitter-toml".into(),
|
||||
roots: vec![],
|
||||
language_server_config: None,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
pub use client::Client;
|
||||
pub use lsp::{Position, Url};
|
||||
|
||||
use helix_core::syntax::LanguageConfiguration;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
@ -106,7 +108,7 @@ pub fn parse(method: &str, params: jsonrpc::Params) -> Notification {
|
||||
use smol::channel::Receiver;
|
||||
|
||||
pub struct Registry {
|
||||
inner: HashMap<LanguageId, OnceCell<Arc<Client>>>,
|
||||
inner: HashMap<LanguageId, Arc<Client>>,
|
||||
|
||||
pub incoming: SelectAll<Receiver<Call>>,
|
||||
}
|
||||
@ -119,35 +121,43 @@ fn default() -> Self {
|
||||
|
||||
impl Registry {
|
||||
pub fn new() -> Self {
|
||||
let mut inner = HashMap::new();
|
||||
|
||||
inner.insert("source.rust".to_string(), OnceCell::new());
|
||||
|
||||
Self {
|
||||
inner,
|
||||
inner: HashMap::new(),
|
||||
incoming: SelectAll::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, id: &str, ex: &smol::Executor) -> Option<Arc<Client>> {
|
||||
// TODO: use get_or_try_init and propagate the error
|
||||
self.inner
|
||||
.get(id)
|
||||
.map(|cell| {
|
||||
cell.get_or_init(|| {
|
||||
pub fn get(
|
||||
&mut self,
|
||||
language_config: &LanguageConfiguration,
|
||||
ex: &smol::Executor,
|
||||
) -> Option<Arc<Client>> {
|
||||
// TODO: propagate the error
|
||||
if let Some(config) = &language_config.language_server_config {
|
||||
// avoid borrow issues
|
||||
let inner = &mut self.inner;
|
||||
let s_incoming = &self.incoming;
|
||||
|
||||
let language_server = inner
|
||||
.entry(language_config.scope.clone()) // can't use entry with Borrow keys: https://github.com/rust-lang/rfcs/pull/1769
|
||||
.or_insert_with(|| {
|
||||
// TODO: lookup defaults for id (name, args)
|
||||
|
||||
// initialize a new client
|
||||
let (mut client, incoming) = Client::start(&ex, "rust-analyzer", &[]);
|
||||
let (mut client, incoming) = Client::start(&ex, &config.command, &config.args);
|
||||
// TODO: run this async without blocking
|
||||
smol::block_on(client.initialize()).unwrap();
|
||||
|
||||
self.incoming.push(incoming);
|
||||
s_incoming.push(incoming);
|
||||
|
||||
Arc::new(client)
|
||||
})
|
||||
})
|
||||
.cloned()
|
||||
.clone();
|
||||
|
||||
return Some(language_server);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use helix_core::{
|
||||
syntax::LOADER, ChangeSet, Diagnostic, History, Rope, Selection, State, Syntax, Transaction,
|
||||
syntax::{LanguageConfiguration, LOADER},
|
||||
ChangeSet, Diagnostic, History, Rope, Selection, State, Syntax, Transaction,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
@ -26,8 +27,8 @@ pub struct Document {
|
||||
|
||||
/// Tree-sitter AST tree
|
||||
pub syntax: Option<Syntax>,
|
||||
/// Corresponding language scope name. Usually `source.<lang>`.
|
||||
language: Option<String>,
|
||||
// /// Corresponding language scope name. Usually `source.<lang>`.
|
||||
pub(crate) language: Option<Arc<LanguageConfiguration>>,
|
||||
|
||||
/// Pending changes since last history commit.
|
||||
changes: ChangeSet,
|
||||
@ -144,20 +145,13 @@ pub fn set_language(
|
||||
scopes: &[String],
|
||||
) {
|
||||
if let Some(language_config) = language_config {
|
||||
// TODO: maybe just keep an Arc<> pointer to the language_config?
|
||||
self.language = Some(language_config.scope().to_string());
|
||||
if let Some(highlight_config) = language_config.highlight_config(scopes) {
|
||||
let syntax = Syntax::new(&self.state.doc, highlight_config);
|
||||
self.syntax = Some(syntax);
|
||||
// TODO: config.configure(scopes) is now delayed, is that ok?
|
||||
}
|
||||
|
||||
// TODO: this ties lsp support to tree-sitter enabled languages for now. Language
|
||||
// config should use Option<HighlightConfig> to let us have non-tree-sitter configs.
|
||||
|
||||
let highlight_config = language_config
|
||||
.highlight_config(scopes)
|
||||
.expect("No highlight_config found!");
|
||||
// TODO: config.configure(scopes) is now delayed, is that ok?
|
||||
|
||||
let syntax = Syntax::new(&self.state.doc, highlight_config);
|
||||
|
||||
self.syntax = Some(syntax);
|
||||
self.language = Some(language_config);
|
||||
} else {
|
||||
self.syntax = None;
|
||||
self.language = None;
|
||||
@ -286,7 +280,9 @@ pub fn mode(&self) -> Mode {
|
||||
#[inline]
|
||||
/// Corresponding language scope name. Usually `source.<lang>`.
|
||||
pub fn language(&self) -> Option<&str> {
|
||||
self.language.as_deref()
|
||||
self.language
|
||||
.as_ref()
|
||||
.map(|language| language.scope.as_str())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -39,7 +39,8 @@ pub fn open(&mut self, path: PathBuf, executor: &smol::Executor) -> Result<(), E
|
||||
|
||||
// try to find a language server based on the language name
|
||||
let language_server = doc
|
||||
.language()
|
||||
.language
|
||||
.as_ref()
|
||||
.and_then(|language| self.language_servers.get(language, &executor));
|
||||
|
||||
if let Some(language_server) = language_server {
|
||||
|
Loading…
Reference in New Issue
Block a user