From 8694d60ab3558a4b65cf8b45c5f38580a01097dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Sun, 27 Mar 2022 18:05:50 +0900 Subject: [PATCH] Simplify LSP formatting, feature gate lsp in helix-view --- helix-lsp/src/lib.rs | 16 -------------- helix-term/src/commands.rs | 2 +- helix-view/Cargo.toml | 7 +++--- helix-view/src/document.rs | 44 ++++++++++++++++++++++++++------------ helix-view/src/editor.rs | 17 ++++++++++----- 5 files changed, 47 insertions(+), 39 deletions(-) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index aeda16d0d..327693fba 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -199,22 +199,6 @@ pub mod util { }), ) } - - /// The result of asking the language server to format the document. This can be turned into a - /// `Transaction`, but the advantage of not doing that straight away is that this one is - /// `Send` and `Sync`. - #[derive(Clone, Debug)] - pub struct LspFormatting { - pub doc: Rope, - pub edits: Vec, - pub offset_encoding: OffsetEncoding, - } - - impl From for Transaction { - fn from(fmt: LspFormatting) -> Transaction { - generate_transaction_from_edits(&fmt.doc, fmt.edits, fmt.offset_encoding) - } - } } #[derive(Debug, PartialEq, Clone)] diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index ec55ac66a..5453adebd 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2289,7 +2289,7 @@ async fn make_format_callback( doc_id: DocumentId, doc_version: i32, modified: Modified, - format: impl Future + Send + 'static, + format: impl Future + Send + 'static, ) -> anyhow::Result { let format = format.await; let call: job::Callback = Box::new(move |editor, _compositor| { diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 52b2077a5..e67294514 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -10,7 +10,8 @@ repository = "https://github.com/helix-editor/helix" homepage = "https://helix-editor.com" [features] -# default = ["dap"] +default = ["dap", "lsp"] +lsp = ["helix-lsp"] dap = ["helix-dap", "tokio-stream"] term = ["crossterm"] @@ -18,7 +19,7 @@ term = ["crossterm"] bitflags = "1.3" anyhow = "1" helix-core = { version = "0.6", path = "../helix-core" } -helix-lsp = { version = "0.6", path = "../helix-lsp" } +helix-lsp = { version = "0.6", path = "../helix-lsp", optional = true } helix-dap = { version = "0.6", path = "../helix-dap", optional = true } tokio-stream = { version = "0.1", optional = true } @@ -30,7 +31,7 @@ url = "2" arc-swap = { version = "1.5.0" } -tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] } +tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false } slotmap = "1" diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 9c3853c82..adf0afc50 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -19,7 +19,9 @@ use helix_core::{ ChangeSet, Diagnostic, LineEnding, Rope, RopeBuilder, Selection, State, Syntax, Transaction, DEFAULT_LINE_ENDING, }; -use helix_lsp::util::LspFormatting; + +#[cfg(feature = "lsp")] +use helix_lsp::lsp; use crate::{DocumentId, Editor, ViewId}; @@ -119,6 +121,7 @@ pub struct Document { pub(crate) modified_since_accessed: bool, diagnostics: Vec, + #[cfg(feature = "lsp")] language_server: Option>, } @@ -142,7 +145,6 @@ impl fmt::Debug for Document { .field("version", &self.version) .field("modified_since_accessed", &self.modified_since_accessed) .field("diagnostics", &self.diagnostics) - // .field("language_server", &self.language_server) .finish() } } @@ -330,7 +332,6 @@ where *mut_ref = f(mem::take(mut_ref)); } -use helix_lsp::lsp; use url::Url; impl Document { @@ -359,6 +360,7 @@ impl Document { savepoint: None, last_saved_revision: 0, modified_since_accessed: false, + #[cfg(feature = "lsp")] language_server: None, } } @@ -394,9 +396,10 @@ impl Document { Ok(doc) } + #[cfg(feature = "lsp")] /// The same as [`format`], but only returns formatting changes if auto-formatting /// is configured. - pub fn auto_format(&self) -> Option + 'static> { + pub fn auto_format(&self) -> Option + 'static> { if self.language_config()?.auto_format { self.format() } else { @@ -404,9 +407,12 @@ impl Document { } } + #[cfg(feature = "lsp")] /// If supported, returns the changes that should be applied to this document in order /// to format it nicely. - pub fn format(&self) -> Option + 'static> { + pub fn format(&self) -> Option + 'static> { + use helix_lsp::util::generate_transaction_from_edits; + let language_server = self.language_server()?; let text = self.text.clone(); let offset_encoding = language_server.offset_encoding(); @@ -425,11 +431,7 @@ impl Document { log::warn!("LSP formatting failed: {}", e); Default::default() }); - LspFormatting { - doc: text, - edits, - offset_encoding, - } + generate_transaction_from_edits(&text, edits, offset_encoding) }; Some(fut) } @@ -438,9 +440,10 @@ impl Document { self.save_impl::>(None, force) } + #[cfg(feature = "lsp")] pub fn format_and_save( &mut self, - formatting: Option>, + formatting: Option>, force: bool, ) -> impl Future> { self.save_impl(formatting, force) @@ -452,7 +455,7 @@ impl Document { /// at its `path()`. /// /// If `formatting` is present, it supplies some changes that we apply to the text before saving. - fn save_impl>( + fn save_impl>( &mut self, formatting: Option, force: bool, @@ -462,8 +465,10 @@ impl Document { let mut text = self.text().clone(); let path = self.path.clone().expect("Can't save with no path set!"); - let identifier = self.identifier(); + #[cfg(feature = "lsp")] + let identifier = self.identifier(); + #[cfg(feature = "lsp")] let language_server = self.language_server.clone(); // mark changes up to now as saved @@ -486,7 +491,8 @@ impl Document { } if let Some(fmt) = formatting { - let success = Transaction::from(fmt.await).changes().apply(&mut text); + let transaction = fmt.await; + let success = transaction.changes().apply(&mut text); if !success { // This shouldn't happen, because the transaction changes were generated // from the same text we're saving. @@ -497,6 +503,7 @@ impl Document { let mut file = File::create(path).await?; to_writer(&mut file, encoding, &text).await?; + #[cfg(feature = "lsp")] if let Some(language_server) = language_server { if !language_server.is_initialized() { return Ok(()); @@ -613,6 +620,7 @@ impl Document { self.set_language(language_config, Some(config_loader)); } + #[cfg(feature = "lsp")] /// Set the programming language for the file if you know the language but don't have the /// [`syntax::LanguageConfiguration`] for it. pub fn set_language_by_language_id( @@ -624,6 +632,7 @@ impl Document { self.set_language(language_config, Some(config_loader)); } + #[cfg(feature = "lsp")] /// Set the LSP. pub fn set_language_server(&mut self, language_server: Option>) { self.language_server = language_server; @@ -692,6 +701,7 @@ impl Document { } // emit lsp notification + #[cfg(feature = "lsp")] if let Some(language_server) = self.language_server() { let notify = language_server.text_document_did_change( self.versioned_identifier(), @@ -869,6 +879,7 @@ impl Document { self.version } + #[cfg(feature = "lsp")] /// Language server if it has been initialized. pub fn language_server(&self) -> Option<&helix_lsp::Client> { let server = self.language_server.as_deref()?; @@ -935,15 +946,18 @@ impl Document { // -- LSP methods + #[cfg(feature = "lsp")] #[inline] pub fn identifier(&self) -> lsp::TextDocumentIdentifier { lsp::TextDocumentIdentifier::new(self.url().unwrap()) } + #[cfg(feature = "lsp")] pub fn versioned_identifier(&self) -> lsp::VersionedTextDocumentIdentifier { lsp::VersionedTextDocumentIdentifier::new(self.url().unwrap(), self.version) } + #[cfg(feature = "lsp")] pub fn position( &self, view_id: ViewId, @@ -1003,6 +1017,7 @@ impl Default for Document { mod test { use super::*; + #[cfg(feature = "lsp")] #[test] fn changeset_to_changes_ignore_line_endings() { use helix_lsp::{lsp, Client, OffsetEncoding}; @@ -1037,6 +1052,7 @@ mod test { ); } + #[cfg(feature = "lsp")] #[test] fn changeset_to_changes() { use helix_lsp::{lsp, Client, OffsetEncoding}; diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 1d0e5ba8a..02a7285c4 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -9,8 +9,6 @@ use crate::{ Document, DocumentId, View, ViewId, }; -use futures_util::future; - use std::{ borrow::Cow, collections::{BTreeMap, HashMap}, @@ -37,6 +35,9 @@ use helix_core::{ }; use helix_core::{Position, Selection}; +#[cfg(feature = "lsp")] +use futures_util::future; + #[cfg(feature = "dap")] use futures_util::stream::select_all::SelectAll; #[cfg(feature = "dap")] @@ -436,6 +437,7 @@ pub struct Editor { pub registers: Registers, pub macro_recording: Option<(char, Vec)>, pub theme: Theme, + #[cfg(feature = "lsp")] pub language_servers: helix_lsp::Registry, #[cfg(feature = "dap")] @@ -495,7 +497,6 @@ impl Editor { syn_loader: Arc, config: Box>, ) -> Self { - let language_servers = helix_lsp::Registry::new(); let conf = config.load(); let auto_pairs = (&conf.auto_pairs).into(); @@ -510,7 +511,8 @@ impl Editor { selected_register: None, macro_recording: None, theme: theme_loader.default(), - language_servers, + #[cfg(feature = "lsp")] + language_servers: helix_lsp::Registry::new(), #[cfg(feature = "dap")] debugger: None, #[cfg(feature = "dap")] @@ -581,12 +583,14 @@ impl Editor { self._refresh(); } + #[cfg(feature = "lsp")] /// Refreshes the language server for a given document pub fn refresh_language_server(&mut self, doc_id: DocumentId) -> Option<()> { let doc = self.documents.get_mut(&doc_id)?; Self::launch_language_server(&mut self.language_servers, doc) } + #[cfg(feature = "lsp")] /// Launch a language server for a given document fn launch_language_server(ls: &mut helix_lsp::Registry, doc: &mut Document) -> Option<()> { // if doc doesn't have a URL it's a scratch buffer, ignore it @@ -624,7 +628,7 @@ impl Editor { doc.set_language_server(Some(language_server)); } } - Some(()) + Some(()) // TODO: what's the deal with the return type } fn _refresh(&mut self) { @@ -768,6 +772,7 @@ impl Editor { } else { let mut doc = Document::open(&path, None, Some(self.syn_loader.clone()))?; + #[cfg(feature = "lsp")] let _ = Self::launch_language_server(&mut self.language_servers, &mut doc); self.new_document(doc) @@ -805,6 +810,7 @@ impl Editor { ); } + #[cfg(feature = "lsp")] if let Some(language_server) = doc.language_server() { tokio::spawn(language_server.text_document_did_close(doc.identifier())); } @@ -954,6 +960,7 @@ impl Editor { } } + #[cfg(feature = "lsp")] /// Closes language servers with timeout. The default timeout is 500 ms, use /// `timeout` parameter to override this. pub async fn close_language_servers(