summaryrefslogtreecommitdiff
path: root/helix-view/src/document.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-view/src/document.rs')
-rw-r--r--helix-view/src/document.rs112
1 files changed, 77 insertions, 35 deletions
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs
index eb376567..bd3c465d 100644
--- a/helix-view/src/document.rs
+++ b/helix-view/src/document.rs
@@ -6,7 +6,7 @@ use futures_util::FutureExt;
use helix_core::auto_pairs::AutoPairs;
use helix_core::doc_formatter::TextFormat;
use helix_core::encoding::Encoding;
-use helix_core::syntax::Highlight;
+use helix_core::syntax::{Highlight, LanguageServerFeature};
use helix_core::text_annotations::{InlineAnnotation, TextAnnotations};
use helix_core::Range;
use helix_vcs::{DiffHandle, DiffProviderRegistry};
@@ -179,8 +179,8 @@ pub struct Document {
version: i32, // should be usize?
pub(crate) modified_since_accessed: bool,
- diagnostics: Vec<Diagnostic>,
- language_server: Option<Arc<helix_lsp::Client>>,
+ pub(crate) diagnostics: Vec<Diagnostic>,
+ pub(crate) language_servers: HashMap<LanguageServerName, Arc<Client>>,
diff_handle: Option<DiffHandle>,
version_control_head: Option<Arc<ArcSwap<Box<str>>>>,
@@ -580,7 +580,7 @@ where
*mut_ref = f(mem::take(mut_ref));
}
-use helix_lsp::lsp;
+use helix_lsp::{lsp, Client, LanguageServerName};
use url::Url;
impl Document {
@@ -616,7 +616,7 @@ impl Document {
last_saved_time: SystemTime::now(),
last_saved_revision: 0,
modified_since_accessed: false,
- language_server: None,
+ language_servers: HashMap::new(),
diff_handle: None,
config,
version_control_head: None,
@@ -730,10 +730,12 @@ impl Document {
return Some(formatting_future.boxed());
};
- let language_server = self.language_server()?;
let text = self.text.clone();
+ // finds first language server that supports formatting and then formats
+ let language_server = self
+ .language_servers_with_feature(LanguageServerFeature::Format)
+ .next()?;
let offset_encoding = language_server.offset_encoding();
-
let request = language_server.text_document_formatting(
self.identifier(),
lsp::FormattingOptions {
@@ -797,13 +799,12 @@ impl Document {
if self.path.is_none() {
bail!("Can't save with no path set!");
}
-
self.path.as_ref().unwrap().clone()
}
};
let identifier = self.path().map(|_| self.identifier());
- let language_server = self.language_server.clone();
+ let language_servers = self.language_servers.clone();
// mark changes up to now as saved
let current_rev = self.get_current_revision();
@@ -847,14 +848,13 @@ impl Document {
text: text.clone(),
};
- if let Some(language_server) = language_server {
+ for (_, language_server) in language_servers {
if !language_server.is_initialized() {
return Ok(event);
}
-
- if let Some(identifier) = identifier {
+ if let Some(identifier) = &identifier {
if let Some(notification) =
- language_server.text_document_did_save(identifier, &text)
+ language_server.text_document_did_save(identifier.clone(), &text)
{
notification.await?;
}
@@ -1004,11 +1004,6 @@ impl Document {
Ok(())
}
- /// Set the LSP.
- pub fn set_language_server(&mut self, language_server: Option<Arc<helix_lsp::Client>>) {
- self.language_server = language_server;
- }
-
/// Select text within the [`Document`].
pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) {
// TODO: use a transaction?
@@ -1159,7 +1154,7 @@ impl Document {
if emit_lsp_notification {
// emit lsp notification
- if let Some(language_server) = self.language_server() {
+ for language_server in self.language_servers() {
let notify = language_server.text_document_did_change(
self.versioned_identifier(),
&old_doc,
@@ -1415,18 +1410,13 @@ impl Document {
.map(|language| language.language_id.as_str())
}
- /// Language ID for the document. Either the `language-id` from the
- /// `language-server` configuration, or the document language if no
- /// `language-id` has been specified.
+ /// Language ID for the document. Either the `language-id`,
+ /// or the document language name if no `language-id` has been specified.
pub fn language_id(&self) -> Option<&str> {
- let language_config = self.language.as_deref()?;
-
- language_config
- .language_server
- .as_ref()?
- .language_id
+ self.language_config()?
+ .language_server_language_id
.as_deref()
- .or(Some(language_config.language_id.as_str()))
+ .or_else(|| self.language_name())
}
/// Corresponding [`LanguageConfiguration`].
@@ -1439,10 +1429,45 @@ impl Document {
self.version
}
- /// Language server if it has been initialized.
- pub fn language_server(&self) -> Option<&helix_lsp::Client> {
- let server = self.language_server.as_deref()?;
- server.is_initialized().then_some(server)
+ /// maintains the order as configured in the language_servers TOML array
+ pub fn language_servers(&self) -> impl Iterator<Item = &helix_lsp::Client> {
+ self.language_config().into_iter().flat_map(move |config| {
+ config.language_servers.iter().filter_map(move |features| {
+ let ls = &**self.language_servers.get(&features.name)?;
+ if ls.is_initialized() {
+ Some(ls)
+ } else {
+ None
+ }
+ })
+ })
+ }
+
+ pub fn remove_language_server_by_name(&mut self, name: &str) -> Option<Arc<Client>> {
+ self.language_servers.remove(name)
+ }
+
+ pub fn language_servers_with_feature(
+ &self,
+ feature: LanguageServerFeature,
+ ) -> impl Iterator<Item = &helix_lsp::Client> {
+ self.language_config().into_iter().flat_map(move |config| {
+ config.language_servers.iter().filter_map(move |features| {
+ let ls = &**self.language_servers.get(&features.name)?;
+ if ls.is_initialized()
+ && ls.supports_feature(feature)
+ && features.has_feature(feature)
+ {
+ Some(ls)
+ } else {
+ None
+ }
+ })
+ })
+ }
+
+ pub fn supports_language_server(&self, id: usize) -> bool {
+ self.language_servers().any(|l| l.id() == id)
}
pub fn diff_handle(&self) -> Option<&DiffHandle> {
@@ -1565,12 +1590,29 @@ impl Document {
&self.diagnostics
}
- pub fn set_diagnostics(&mut self, diagnostics: Vec<Diagnostic>) {
- self.diagnostics = diagnostics;
+ pub fn shown_diagnostics(&self) -> impl Iterator<Item = &Diagnostic> + DoubleEndedIterator {
+ self.diagnostics.iter().filter(|d| {
+ self.language_servers_with_feature(LanguageServerFeature::Diagnostics)
+ .any(|ls| ls.id() == d.language_server_id)
+ })
+ }
+
+ pub fn replace_diagnostics(
+ &mut self,
+ mut diagnostics: Vec<Diagnostic>,
+ language_server_id: usize,
+ ) {
+ self.clear_diagnostics(language_server_id);
+ self.diagnostics.append(&mut diagnostics);
self.diagnostics
.sort_unstable_by_key(|diagnostic| diagnostic.range);
}
+ pub fn clear_diagnostics(&mut self, language_server_id: usize) {
+ self.diagnostics
+ .retain(|d| d.language_server_id != language_server_id);
+ }
+
/// Get the document's auto pairs. If the document has a recognized
/// language config with auto pairs configured, returns that;
/// otherwise, falls back to the global auto pairs config. If the global