From f7ecf9c830e1c92a59bb13a11b08a1bb5a7da39e Mon Sep 17 00:00:00 2001 From: PiergiorgioZagaria Date: Fri, 8 Jul 2022 10:44:52 +0200 Subject: [PATCH] Use only stdio type formatters --- helix-core/src/syntax.rs | 2 - helix-term/src/commands/typed.rs | 15 ++-- helix-view/src/document.rs | 133 ++++++++++--------------------- languages.toml | 2 + 4 files changed, 49 insertions(+), 103 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 56b7218e55e0..a890182bf930 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -136,8 +136,6 @@ pub struct FormatterConfiguration { #[serde(default)] #[serde(skip_serializing_if = "Vec::is_empty")] pub args: Vec, - #[serde(rename = "type")] - pub type_: FormatterType, } #[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize)] diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 2da06340a4f6..66b1d678bde7 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -239,7 +239,7 @@ fn write_impl( ) -> anyhow::Result<()> { let auto_format = cx.editor.config().auto_format; let jobs = &mut cx.jobs; - let (view, doc) = current!(cx.editor); + let doc = doc_mut!(cx.editor); if let Some(ref path) = path { doc.set_path(Some(path.as_ref().as_ref())) @@ -249,7 +249,7 @@ fn write_impl( bail!("cannot write a buffer without a filename"); } let fmt = if auto_format { - doc.auto_format(view.id).map(|fmt| { + doc.auto_format().map(|fmt| { let shared = fmt.shared(); let callback = make_format_callback( doc.id(), @@ -322,8 +322,8 @@ fn format( return Ok(()); } - let (view, doc) = current!(cx.editor); - if let Some(format) = doc.format(view.id) { + let doc = doc!(cx.editor); + if let Some(format) = doc.format() { let callback = make_format_callback(doc.id(), doc.version(), Modified::LeaveModified, format); cx.jobs.callback(callback); @@ -552,10 +552,7 @@ fn write_all_impl( let jobs = &mut cx.jobs; // save all documents // Saves only visible buffers? How do we reload the not visible ones? - for (view, _) in cx.editor.tree.views() { - let id = view.doc; - let doc = cx.editor.documents.get_mut(&id).unwrap(); - + for doc in &mut cx.editor.documents.values_mut() { if doc.path().is_none() { errors.push_str("cannot write a buffer without a filename\n"); continue; @@ -566,7 +563,7 @@ fn write_all_impl( } let fmt = if auto_format { - doc.auto_format(view.id).map(|fmt| { + doc.auto_format().map(|fmt| { let shared = fmt.shared(); let callback = make_format_callback( doc.id(), diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index c7c67deafefe..198474f00765 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -2,7 +2,6 @@ use anyhow::{anyhow, bail, Context, Error}; use futures_util::future::BoxFuture; use futures_util::FutureExt; use helix_core::auto_pairs::AutoPairs; -use helix_core::syntax::FormatterType; use helix_core::Range; use serde::de::{self, Deserialize, Deserializer}; use serde::Serialize; @@ -400,12 +399,9 @@ impl Document { /// The same as [`format`], but only returns formatting changes if auto-formatting /// is configured. - pub fn auto_format( - &mut self, - view_id: ViewId, - ) -> Option>> { + pub fn auto_format(&self) -> Option>> { if self.language_config()?.auto_format { - self.format(view_id) + self.format() } else { None } @@ -415,97 +411,50 @@ impl Document { /// to format it nicely. // We can't use anyhow::Result here since the output of the future has to be // clonable to be used as shared future. So use a custom error type. - pub fn format( - &mut self, - view_id: ViewId, - ) -> Option>> { + pub fn format(&self) -> Option>> { if let Some(formatter) = self.language_config().and_then(|c| c.formatter.clone()) { use std::process::Stdio; - match formatter.type_ { - FormatterType::Stdio => { - let text = self.text().clone(); - let mut process = tokio::process::Command::new(&formatter.command); - process - .args(&formatter.args) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - - let formatting_future = async move { - let mut process = - process - .spawn() - .map_err(|e| FormatterError::SpawningFailed { - command: formatter.command.clone(), - error: e.kind(), - })?; - { - let mut stdin = - process.stdin.take().ok_or(FormatterError::BrokenStdin)?; - stdin - .write_all(&text.bytes().collect::>()) - .await - .map_err(|_| FormatterError::BrokenStdin)?; - } - - let output = process - .wait_with_output() - .await - .map_err(|_| FormatterError::WaitForOutputFailed)?; - - if !output.stderr.is_empty() { - return Err(FormatterError::Stderr( - String::from_utf8_lossy(&output.stderr).to_string(), - )); - } - - let str = String::from_utf8(output.stdout) - .map_err(|_| FormatterError::InvalidUtf8Output)?; - - Ok(helix_core::diff::compare_ropes(&text, &Rope::from(str))) - }; - return Some(formatting_future.boxed()); + let text = self.text().clone(); + let mut process = tokio::process::Command::new(&formatter.command); + process + .args(&formatter.args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + + let formatting_future = async move { + let mut process = process + .spawn() + .map_err(|e| FormatterError::SpawningFailed { + command: formatter.command.clone(), + error: e.kind(), + })?; + { + let mut stdin = process.stdin.take().ok_or(FormatterError::BrokenStdin)?; + stdin + .write_all(&text.bytes().collect::>()) + .await + .map_err(|_| FormatterError::BrokenStdin)?; } - FormatterType::File => { - let path = self.path()?.clone(); - let process = std::process::Command::new(&formatter.command) - .args(&formatter.args) - .arg(path.to_str().unwrap_or("")) - .stderr(Stdio::piped()) - .spawn(); - - // File type formatters are run synchronously since the doc - // has to be reloaded from disk rather than being resolved - // through a transaction. - let format_and_reload = || -> Result<(), FormatterError> { - let process = process.map_err(|e| FormatterError::SpawningFailed { - command: formatter.command.clone(), - error: e.kind(), - })?; - let output = process - .wait_with_output() - .map_err(|_| FormatterError::WaitForOutputFailed)?; - - if !output.stderr.is_empty() { - return Err(FormatterError::Stderr( - String::from_utf8_lossy(&output.stderr).to_string(), - )); - } else if let Err(e) = self.reload(view_id) { - return Err(FormatterError::DiskReloadError(e.to_string())); - } - - Ok(()) - }; - - let format_result = format_and_reload(); - let text = self.text().clone(); - - // Generate an empty transaction as a placeholder - let future = async move { format_result.map(|_| Transaction::new(&text)) }; - return Some(future.boxed()); + + let output = process + .wait_with_output() + .await + .map_err(|_| FormatterError::WaitForOutputFailed)?; + + if !output.stderr.is_empty() { + return Err(FormatterError::Stderr( + String::from_utf8_lossy(&output.stderr).to_string(), + )); } + + let str = String::from_utf8(output.stdout) + .map_err(|_| FormatterError::InvalidUtf8Output)?; + + Ok(helix_core::diff::compare_ropes(&text, &Rope::from(str))) }; - } + return Some(formatting_future.boxed()); + }; let language_server = self.language_server()?; let text = self.text.clone(); diff --git a/languages.toml b/languages.toml index d7462bb8c583..faa02bcd52f9 100644 --- a/languages.toml +++ b/languages.toml @@ -679,6 +679,8 @@ auto-format = true comment-token = "//" language-server = { command = "zls" } indent = { tab-width = 4, unit = " " } +formatter = { command = "zig" , args = ["fmt", "--stdin"] } + [[grammar]] name = "zig"