diff options
author | Joe Neeman | 2021-06-23 18:35:39 +0000 |
---|---|---|
committer | Blaž Hrastnik | 2021-06-30 08:08:50 +0000 |
commit | c9be480bf86489fbf659b45b107be0d26a076b50 (patch) | |
tree | 93272263cd449d39e40848788e036c07f122250f /helix-view | |
parent | 3007478567c45274e405ec3b57a273bfa0025cc9 (diff) |
Make formatting happen asynchronously.
Diffstat (limited to 'helix-view')
-rw-r--r-- | helix-view/src/document.rs | 82 | ||||
-rw-r--r-- | helix-view/src/editor.rs | 4 |
2 files changed, 60 insertions, 26 deletions
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index dcacdb5e..80ef54d5 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -16,6 +16,7 @@ use helix_core::{ ChangeSet, Diagnostic, LineEnding, Rope, RopeBuilder, Selection, State, Syntax, Transaction, DEFAULT_LINE_ENDING, }; +use helix_lsp::util::LspFormatting; use crate::{DocumentId, Theme, ViewId}; @@ -472,39 +473,55 @@ impl Document { Ok(doc) } - // TODO: remove view_id dependency here - pub fn format(&mut self, view_id: ViewId) { - if let Some(language_server) = self.language_server() { - // TODO: await, no blocking - let transaction = helix_lsp::block_on(language_server.text_document_formatting( - self.identifier(), - lsp::FormattingOptions::default(), - None, - )) - .map(|edits| { - helix_lsp::util::generate_transaction_from_edits( - self.text(), + pub fn format(&self) -> Option<impl Future<Output = LspFormatting> + 'static> { + if let Some(language_server) = self.language_server.clone() { + let text = self.text.clone(); + let id = self.identifier(); + let fut = async move { + let edits = language_server + .text_document_formatting(id, lsp::FormattingOptions::default(), None) + .await + .unwrap_or_else(|e| { + log::warn!("LSP formatting failed: {}", e); + Default::default() + }); + LspFormatting { + doc: text, edits, - language_server.offset_encoding(), - ) - }); - - if let Ok(transaction) = transaction { - self.apply(&transaction, view_id); - self.append_changes_to_history(view_id); - } + offset_encoding: language_server.offset_encoding(), + } + }; + Some(fut) + } else { + None } } + pub fn save(&mut self) -> impl Future<Output = Result<(), anyhow::Error>> { + self.save_impl::<futures_util::future::Ready<_>>(None) + } + + pub fn format_and_save( + &mut self, + formatting: Option<impl Future<Output = LspFormatting>>, + ) -> impl Future<Output = anyhow::Result<()>> { + self.save_impl(formatting) + } + // TODO: do we need some way of ensuring two save operations on the same doc can't run at once? // or is that handled by the OS/async layer /// The `Document`'s text is encoded according to its encoding and written to the file located /// at its `path()`. - pub fn save(&mut self) -> impl Future<Output = Result<(), anyhow::Error>> { + /// + /// If `formatting` is present, it supplies some changes that we apply to the text before saving. + fn save_impl<F: Future<Output = LspFormatting>>( + &mut self, + formatting: Option<F>, + ) -> impl Future<Output = Result<(), anyhow::Error>> { // we clone and move text + path into the future so that we asynchronously save the current // state without blocking any further edits. - let text = self.text().clone(); + let mut text = self.text().clone(); let path = self.path.clone().expect("Can't save with no path set!"); // TODO: handle no path let identifier = self.identifier(); @@ -512,10 +529,7 @@ impl Document { let language_server = self.language_server.clone(); - // reset the modified flag - let history = self.history.take(); - self.last_saved_revision = history.current_revision(); - self.history.set(history); + self.reset_modified(); let encoding = self.encoding; @@ -531,6 +545,15 @@ impl Document { } } + if let Some(fmt) = formatting { + let success = Transaction::from(fmt.await).changes().apply(&mut text); + if !success { + // This shouldn't happen, because the transaction changes were generated + // from the same text we're saving. + log::error!("failed to apply format changes before saving"); + } + } + let mut file = File::create(path).await?; to_writer(&mut file, encoding, &text).await?; @@ -877,6 +900,13 @@ impl Document { current_revision != self.last_saved_revision || !self.changes.is_empty() } + pub fn reset_modified(&mut self) { + let history = self.history.take(); + let current_revision = history.current_revision(); + self.history.set(history); + self.last_saved_revision = current_revision; + } + pub fn mode(&self) -> Mode { self.mode } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 0a2dc54d..a16cc50f 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -270,6 +270,10 @@ impl Editor { self.documents.get(id) } + pub fn document_mut(&mut self, id: DocumentId) -> Option<&mut Document> { + self.documents.get_mut(id) + } + pub fn documents(&self) -> impl Iterator<Item = &Document> { self.documents.iter().map(|(_id, doc)| doc) } |