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
|
// largely based on tree-sitter/cli/src/loader.rs
|
||||||
pub struct LanguageConfiguration {
|
pub struct LanguageConfiguration {
|
||||||
pub(crate) scope: String, // source.rust
|
pub scope: String, // source.rust
|
||||||
pub(crate) file_types: Vec<String>, // filename ends_with? <Gemfile, rb, etc>
|
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
|
// content_regex
|
||||||
// injection_regex
|
// injection_regex
|
||||||
// first_line_regex
|
// first_line_regex
|
||||||
//
|
//
|
||||||
// root_path
|
|
||||||
//
|
//
|
||||||
pub(crate) language_id: Lang,
|
pub(crate) language_id: Lang,
|
||||||
pub(crate) highlight_config: OnceCell<Option<Arc<HighlightConfiguration>>>,
|
pub(crate) highlight_config: OnceCell<Option<Arc<HighlightConfiguration>>>,
|
||||||
// tags_config OnceCell<> https://github.com/tree-sitter/tree-sitter/pull/583
|
// 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 {
|
impl LanguageConfiguration {
|
||||||
@ -90,6 +97,11 @@ fn init() -> Loader {
|
|||||||
highlight_config: OnceCell::new(),
|
highlight_config: OnceCell::new(),
|
||||||
//
|
//
|
||||||
path: "../helix-syntax/languages/tree-sitter-rust".into(),
|
path: "../helix-syntax/languages/tree-sitter-rust".into(),
|
||||||
|
roots: vec![],
|
||||||
|
language_server_config: Some(LanguageServerConfiguration {
|
||||||
|
command: "rust-analyzer".to_string(),
|
||||||
|
args: vec![],
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
LanguageConfiguration {
|
LanguageConfiguration {
|
||||||
scope: "source.toml".to_string(),
|
scope: "source.toml".to_string(),
|
||||||
@ -98,6 +110,8 @@ fn init() -> Loader {
|
|||||||
highlight_config: OnceCell::new(),
|
highlight_config: OnceCell::new(),
|
||||||
//
|
//
|
||||||
path: "../helix-syntax/languages/tree-sitter-toml".into(),
|
path: "../helix-syntax/languages/tree-sitter-toml".into(),
|
||||||
|
roots: vec![],
|
||||||
|
language_server_config: None,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
pub use client::Client;
|
pub use client::Client;
|
||||||
pub use lsp::{Position, Url};
|
pub use lsp::{Position, Url};
|
||||||
|
|
||||||
|
use helix_core::syntax::LanguageConfiguration;
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
@ -106,7 +108,7 @@ pub fn parse(method: &str, params: jsonrpc::Params) -> Notification {
|
|||||||
use smol::channel::Receiver;
|
use smol::channel::Receiver;
|
||||||
|
|
||||||
pub struct Registry {
|
pub struct Registry {
|
||||||
inner: HashMap<LanguageId, OnceCell<Arc<Client>>>,
|
inner: HashMap<LanguageId, Arc<Client>>,
|
||||||
|
|
||||||
pub incoming: SelectAll<Receiver<Call>>,
|
pub incoming: SelectAll<Receiver<Call>>,
|
||||||
}
|
}
|
||||||
@ -119,35 +121,43 @@ fn default() -> Self {
|
|||||||
|
|
||||||
impl Registry {
|
impl Registry {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut inner = HashMap::new();
|
|
||||||
|
|
||||||
inner.insert("source.rust".to_string(), OnceCell::new());
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
inner,
|
inner: HashMap::new(),
|
||||||
incoming: SelectAll::new(),
|
incoming: SelectAll::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, id: &str, ex: &smol::Executor) -> Option<Arc<Client>> {
|
pub fn get(
|
||||||
// TODO: use get_or_try_init and propagate the error
|
&mut self,
|
||||||
self.inner
|
language_config: &LanguageConfiguration,
|
||||||
.get(id)
|
ex: &smol::Executor,
|
||||||
.map(|cell| {
|
) -> Option<Arc<Client>> {
|
||||||
cell.get_or_init(|| {
|
// 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)
|
// TODO: lookup defaults for id (name, args)
|
||||||
|
|
||||||
// initialize a new client
|
// 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
|
// TODO: run this async without blocking
|
||||||
smol::block_on(client.initialize()).unwrap();
|
smol::block_on(client.initialize()).unwrap();
|
||||||
|
|
||||||
self.incoming.push(incoming);
|
s_incoming.push(incoming);
|
||||||
|
|
||||||
Arc::new(client)
|
Arc::new(client)
|
||||||
})
|
})
|
||||||
})
|
.clone();
|
||||||
.cloned()
|
|
||||||
|
return Some(language_server);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use helix_core::{
|
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)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
@ -26,8 +27,8 @@ pub struct Document {
|
|||||||
|
|
||||||
/// Tree-sitter AST tree
|
/// Tree-sitter AST tree
|
||||||
pub syntax: Option<Syntax>,
|
pub syntax: Option<Syntax>,
|
||||||
/// Corresponding language scope name. Usually `source.<lang>`.
|
// /// Corresponding language scope name. Usually `source.<lang>`.
|
||||||
language: Option<String>,
|
pub(crate) language: Option<Arc<LanguageConfiguration>>,
|
||||||
|
|
||||||
/// Pending changes since last history commit.
|
/// Pending changes since last history commit.
|
||||||
changes: ChangeSet,
|
changes: ChangeSet,
|
||||||
@ -144,20 +145,13 @@ pub fn set_language(
|
|||||||
scopes: &[String],
|
scopes: &[String],
|
||||||
) {
|
) {
|
||||||
if let Some(language_config) = language_config {
|
if let Some(language_config) = language_config {
|
||||||
// TODO: maybe just keep an Arc<> pointer to the language_config?
|
if let Some(highlight_config) = language_config.highlight_config(scopes) {
|
||||||
self.language = Some(language_config.scope().to_string());
|
|
||||||
|
|
||||||
// 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);
|
let syntax = Syntax::new(&self.state.doc, highlight_config);
|
||||||
|
|
||||||
self.syntax = Some(syntax);
|
self.syntax = Some(syntax);
|
||||||
|
// TODO: config.configure(scopes) is now delayed, is that ok?
|
||||||
|
}
|
||||||
|
|
||||||
|
self.language = Some(language_config);
|
||||||
} else {
|
} else {
|
||||||
self.syntax = None;
|
self.syntax = None;
|
||||||
self.language = None;
|
self.language = None;
|
||||||
@ -286,7 +280,9 @@ pub fn mode(&self) -> Mode {
|
|||||||
#[inline]
|
#[inline]
|
||||||
/// Corresponding language scope name. Usually `source.<lang>`.
|
/// Corresponding language scope name. Usually `source.<lang>`.
|
||||||
pub fn language(&self) -> Option<&str> {
|
pub fn language(&self) -> Option<&str> {
|
||||||
self.language.as_deref()
|
self.language
|
||||||
|
.as_ref()
|
||||||
|
.map(|language| language.scope.as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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
|
// try to find a language server based on the language name
|
||||||
let language_server = doc
|
let language_server = doc
|
||||||
.language()
|
.language
|
||||||
|
.as_ref()
|
||||||
.and_then(|language| self.language_servers.get(language, &executor));
|
.and_then(|language| self.language_servers.get(language, &executor));
|
||||||
|
|
||||||
if let Some(language_server) = language_server {
|
if let Some(language_server) = language_server {
|
||||||
|
Loading…
Reference in New Issue
Block a user