Configure language servers via LanguageConfiguration.

imgbot
Blaž Hrastnik 3 years ago
parent 1cf887dea9
commit bb87b08fc9

@ -11,20 +11,27 @@ use once_cell::sync::{Lazy, OnceCell};
// 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 @@ impl 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 @@ impl 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 once_cell::sync::{Lazy, OnceCell};
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 @@ use crate::select_all::SelectAll;
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 @@ impl Default for Registry {
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::path::{Path, PathBuf};
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 @@ impl Document {
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());
// 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);
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?
}
self.syntax = Some(syntax);
self.language = Some(language_config);
} else {
self.syntax = None;
self.language = None;
@ -286,7 +280,9 @@ impl Document {
#[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 @@ impl Editor {
// 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…
Cancel
Save