on master help sign in
Configure language servers via LanguageConfiguration.
commitbb87b08fc9677ddf0f083a2297c23c17144470e2 authorBlaž Hrastnik <blaz@mxxn.io> dateSun 14 Mar 2021, 17:13 (6 years ago) parent1cf887d
4 files changed+59−38
helix-core/src/syntax.rs+18−4 helix-lsp/src/lib.rs+26−16 helix-view/src/document.rs+13−17 helix-view/src/editor.rs+2−1
helix-core/src/syntax.rs+18−4
@@ -11,20 +11,27 @@ use once_cell::sync::{Lazy, OnceCell};
1111
1212// largely based on tree-sitter/cli/src/loader.rs
1313pub struct LanguageConfiguration {
14− pub(crate) scope: String, // source.rust
15− pub(crate) file_types: Vec<String>, // filename ends_with? <Gemfile, rb, etc>
14+ pub scope: String, // source.rust
15+ pub file_types: Vec<String>, // filename ends_with? <Gemfile, rb, etc>
16+ pub roots: Vec<String>, // these indicate project roots <.git, Cargo.toml>
1617
17− pub(crate) path: PathBuf,
18+ pub path: PathBuf,
19+ // root_path for tree-sitter (^)
1820
1921 // content_regex
2022 // injection_regex
2123 // first_line_regex
2224 //
23− // root_path
2425 //
2526 pub(crate) language_id: Lang,
2627 pub(crate) highlight_config: OnceCell<Option<Arc<HighlightConfiguration>>>,
2728 // tags_config OnceCell<> https://github.com/tree-sitter/tree-sitter/pull/583
29+ pub language_server_config: Option<LanguageServerConfiguration>,
30+}
31+
32+pub struct LanguageServerConfiguration {
33+ pub command: String,
34+ pub args: Vec<String>,
2835}
2936
3037impl LanguageConfiguration {
@@ -90,6 +97,11 @@ impl Loader {
9097 highlight_config: OnceCell::new(),
9198 //
9299 path: "../helix-syntax/languages/tree-sitter-rust".into(),
100+ roots: vec![],
101+ language_server_config: Some(LanguageServerConfiguration {
102+ command: "rust-analyzer".to_string(),
103+ args: vec![],
104+ }),
93105 },
94106 LanguageConfiguration {
95107 scope: "source.toml".to_string(),
@@ -98,6 +110,8 @@ impl Loader {
98110 highlight_config: OnceCell::new(),
99111 //
100112 path: "../helix-syntax/languages/tree-sitter-toml".into(),
113+ roots: vec![],
114+ language_server_config: None,
101115 },
102116 ];
103117
helix-lsp/src/lib.rs+26−16
@@ -10,6 +10,8 @@ pub use once_cell::sync::{Lazy, OnceCell};
1010pub use client::Client;
1111pub use lsp::{Position, Url};
1212
13+use helix_core::syntax::LanguageConfiguration;
14+
1315use thiserror::Error;
1416
1517use std::{collections::HashMap, sync::Arc};
@@ -106,7 +108,7 @@ use crate::select_all::SelectAll;
106108use smol::channel::Receiver;
107109
108110pub struct Registry {
109− inner: HashMap<LanguageId, OnceCell<Arc<Client>>>,
111+ inner: HashMap<LanguageId, Arc<Client>>,
110112
111113 pub incoming: SelectAll<Receiver<Call>>,
112114}
@@ -119,35 +121,43 @@ impl Default for Registry {
119121
120122impl Registry {
121123 pub fn new() -> Self {
122− let mut inner = HashMap::new();
123−
124− inner.insert("source.rust".to_string(), OnceCell::new());
125−
126124 Self {
127− inner,
125+ inner: HashMap::new(),
128126 incoming: SelectAll::new(),
129127 }
130128 }
131129
132− pub fn get(&self, id: &str, ex: &smol::Executor) -> Option<Arc<Client>> {
133− // TODO: use get_or_try_init and propagate the error
134− self.inner
135− .get(id)
136− .map(|cell| {
137− cell.get_or_init(|| {
130+ pub fn get(
131+ &mut self,
132+ language_config: &LanguageConfiguration,
133+ ex: &smol::Executor,
134+ ) -> Option<Arc<Client>> {
135+ // TODO: propagate the error
136+ if let Some(config) = &language_config.language_server_config {
137+ // avoid borrow issues
138+ let inner = &mut self.inner;
139+ let s_incoming = &self.incoming;
140+
141+ let language_server = inner
142+ .entry(language_config.scope.clone()) // can't use entry with Borrow keys: https://github.com/rust-lang/rfcs/pull/1769
143+ .or_insert_with(|| {
138144 // TODO: lookup defaults for id (name, args)
139145
140146 // initialize a new client
141− let (mut client, incoming) = Client::start(&ex, "rust-analyzer", &[]);
147+ let (mut client, incoming) = Client::start(&ex, &config.command, &config.args);
142148 // TODO: run this async without blocking
143149 smol::block_on(client.initialize()).unwrap();
144150
145− self.incoming.push(incoming);
151+ s_incoming.push(incoming);
146152
147153 Arc::new(client)
148154 })
149− })
150− .cloned()
155+ .clone();
156+
157+ return Some(language_server);
158+ }
159+
160+ None
151161 }
152162}
153163
helix-view/src/document.rs+13−17
@@ -4,7 +4,8 @@ use std::path::{Path, PathBuf};
44use std::sync::Arc;
55
66use helix_core::{
7− syntax::LOADER, ChangeSet, Diagnostic, History, Rope, Selection, State, Syntax, Transaction,
7+ syntax::{LanguageConfiguration, LOADER},
8+ ChangeSet, Diagnostic, History, Rope, Selection, State, Syntax, Transaction,
89};
910
1011#[derive(Copy, Clone, PartialEq, Eq, Hash)]
@@ -26,8 +27,8 @@ pub struct Document {
2627
2728 /// Tree-sitter AST tree
2829 pub syntax: Option<Syntax>,
29− /// Corresponding language scope name. Usually `source.<lang>`.
30− language: Option<String>,
30+ // /// Corresponding language scope name. Usually `source.<lang>`.
31+ pub(crate) language: Option<Arc<LanguageConfiguration>>,
3132
3233 /// Pending changes since last history commit.
3334 changes: ChangeSet,
@@ -144,20 +145,13 @@ impl Document {
144145 scopes: &[String],
145146 ) {
146147 if let Some(language_config) = language_config {
147− // TODO: maybe just keep an Arc<> pointer to the language_config?
148− self.language = Some(language_config.scope().to_string());
149−
150− // TODO: this ties lsp support to tree-sitter enabled languages for now. Language
151− // config should use Option<HighlightConfig> to let us have non-tree-sitter configs.
152−
153− let highlight_config = language_config
154− .highlight_config(scopes)
155− .expect("No highlight_config found!");
156− // TODO: config.configure(scopes) is now delayed, is that ok?
157−
158− let syntax = Syntax::new(&self.state.doc, highlight_config);
148+ if let Some(highlight_config) = language_config.highlight_config(scopes) {
149+ let syntax = Syntax::new(&self.state.doc, highlight_config);
150+ self.syntax = Some(syntax);
151+ // TODO: config.configure(scopes) is now delayed, is that ok?
152+ }
159153
160− self.syntax = Some(syntax);
154+ self.language = Some(language_config);
161155 } else {
162156 self.syntax = None;
163157 self.language = None;
@@ -286,7 +280,9 @@ impl Document {
286280 #[inline]
287281 /// Corresponding language scope name. Usually `source.<lang>`.
288282 pub fn language(&self) -> Option<&str> {
289− self.language.as_deref()
283+ self.language
284+ .as_ref()
285+ .map(|language| language.scope.as_str())
290286 }
291287
292288 #[inline]
helix-view/src/editor.rs+2−1
@@ -39,7 +39,8 @@ impl Editor {
3939
4040 // try to find a language server based on the language name
4141 let language_server = doc
42− .language()
42+ .language
43+ .as_ref()
4344 .and_then(|language| self.language_servers.get(language, &executor));
4445
4546 if let Some(language_server) = language_server {