aboutsummaryrefslogtreecommitdiff
path: root/helix-view
diff options
context:
space:
mode:
authorJoe Neeman2021-06-23 18:35:39 +0000
committerBlaž Hrastnik2021-06-30 08:08:50 +0000
commitc9be480bf86489fbf659b45b107be0d26a076b50 (patch)
tree93272263cd449d39e40848788e036c07f122250f /helix-view
parent3007478567c45274e405ec3b57a273bfa0025cc9 (diff)
Make formatting happen asynchronously.
Diffstat (limited to 'helix-view')
-rw-r--r--helix-view/src/document.rs82
-rw-r--r--helix-view/src/editor.rs4
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)
}