From 90e69ce37ac7e862e3d27717277e0e47df88f09b Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Sun, 10 Sep 2023 23:41:21 +0200 Subject: [PATCH 1/4] Read typstfmt config from files, if possible --- src/server/formatting.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/server/formatting.rs b/src/server/formatting.rs index c3a1e6ba..229fc187 100644 --- a/src/server/formatting.rs +++ b/src/server/formatting.rs @@ -1,10 +1,14 @@ +use std::{fs::File, io::Read}; + use tower_lsp::lsp_types::{Position, Range, Registration, TextEdit, Unregistration}; use typst::syntax::Source; +use typstfmt_lib::Config as FmtConfig; use super::TypstServer; const FORMATTING_REGISTRATION_ID: &str = "formatting"; const DOCUMENT_FORMATTING_METHOD_ID: &str = "textDocument/formatting"; +const CONFIG_PATH: &str = "typstfmt-config.toml"; pub fn get_formatting_registration() -> Registration { Registration { @@ -24,7 +28,7 @@ pub fn get_formatting_unregistration() -> Unregistration { impl TypstServer { pub fn format_document(&self, source: &Source) -> anyhow::Result> { let original_text = source.text(); - let res = typstfmt_lib::format(original_text, typstfmt_lib::Config::default()); + let res = typstfmt_lib::format(original_text, self.get_fmt_config()); Ok(vec![TextEdit { new_text: res, @@ -40,4 +44,27 @@ impl TypstServer { ), }]) } + + fn get_fmt_config(&self) -> FmtConfig { + // Ignoring all errors since we're returning the default config in case + // we can't find something more specific + let mut config_file: Option = File::options().read(true).open(CONFIG_PATH).ok(); + + if config_file.is_none() { + if let Some(root_path) = &self.config.blocking_read().root_path { + let mut root_path = root_path.clone(); + root_path.push(CONFIG_PATH); + config_file = File::options().read(true).open(root_path).ok(); + } + } + + config_file + .map(|mut f| { + let mut buf = String::default(); + let _ = f.read_to_string(&mut buf); + FmtConfig::from_toml(&buf).ok() + }) + .flatten() + .unwrap_or_default() + } } From 6f93e3000b4d91280b82888e49e2b2717c3c9f5a Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Mon, 11 Sep 2023 21:14:15 +0200 Subject: [PATCH 2/4] Asyncify format_document and its IO --- src/server/formatting.rs | 30 +++++++++++++++--------------- src/server/lsp.rs | 8 ++++---- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/server/formatting.rs b/src/server/formatting.rs index 229fc187..2694fd19 100644 --- a/src/server/formatting.rs +++ b/src/server/formatting.rs @@ -1,4 +1,5 @@ -use std::{fs::File, io::Read}; +use tokio::fs::File; +use tokio::io::AsyncReadExt; use tower_lsp::lsp_types::{Position, Range, Registration, TextEdit, Unregistration}; use typst::syntax::Source; @@ -26,9 +27,9 @@ pub fn get_formatting_unregistration() -> Unregistration { } impl TypstServer { - pub fn format_document(&self, source: &Source) -> anyhow::Result> { + pub async fn format_document(&self, source: &Source) -> anyhow::Result> { let original_text = source.text(); - let res = typstfmt_lib::format(original_text, self.get_fmt_config()); + let res = typstfmt_lib::format(original_text, self.get_fmt_config().await); Ok(vec![TextEdit { new_text: res, @@ -45,26 +46,25 @@ impl TypstServer { }]) } - fn get_fmt_config(&self) -> FmtConfig { + async fn get_fmt_config(&self) -> FmtConfig { // Ignoring all errors since we're returning the default config in case // we can't find something more specific - let mut config_file: Option = File::options().read(true).open(CONFIG_PATH).ok(); + let mut config_file: Option = File::options().read(true).open(CONFIG_PATH).await.ok(); if config_file.is_none() { - if let Some(root_path) = &self.config.blocking_read().root_path { + if let Some(root_path) = &self.config.read().await.root_path { let mut root_path = root_path.clone(); root_path.push(CONFIG_PATH); - config_file = File::options().read(true).open(root_path).ok(); + config_file = File::options().read(true).open(root_path).await.ok(); } } - config_file - .map(|mut f| { - let mut buf = String::default(); - let _ = f.read_to_string(&mut buf); - FmtConfig::from_toml(&buf).ok() - }) - .flatten() - .unwrap_or_default() + if let Some(mut f) = config_file { + let mut buf = String::default(); + let _ = f.read_to_string(&mut buf).await; + FmtConfig::from_toml(&buf).unwrap_or_default() + } else { + FmtConfig::default() + } } } diff --git a/src/server/lsp.rs b/src/server/lsp.rs index 607960ff..346370d0 100644 --- a/src/server/lsp.rs +++ b/src/server/lsp.rs @@ -25,7 +25,7 @@ use super::semantic_tokens::{ get_semantic_tokens_options, get_semantic_tokens_registration, get_semantic_tokens_unregistration, }; -use super::TypstServer; +use super::{TypstServer, SourceScope}; #[async_trait] impl LanguageServer for TypstServer { @@ -605,14 +605,14 @@ impl LanguageServer for TypstServer { ) -> jsonrpc::Result>> { let uri = params.text_document.uri; - let edits = self + let SourceScope { source, project: _ } = self .scope_with_source(&uri) .await .map_err(|err| { error!(%err, %uri, "error getting document to format"); jsonrpc::Error::internal_error() - })? - .run(|source, _| self.format_document(source)) + })?; + let edits = self.format_document(&source).await .map_err(|err| { error!(%err, %uri, "error formatting document"); jsonrpc::Error::internal_error() From f04288a952f369e4844a93c40d1da6c5a65dd31c Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Thu, 14 Sep 2023 21:58:33 +0200 Subject: [PATCH 3/4] Surface errors from reading toml --- src/server/formatting.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/server/formatting.rs b/src/server/formatting.rs index 2694fd19..e8a14d83 100644 --- a/src/server/formatting.rs +++ b/src/server/formatting.rs @@ -1,3 +1,6 @@ +use std::path::PathBuf; + +use anyhow::Context; use tokio::fs::File; use tokio::io::AsyncReadExt; @@ -29,7 +32,7 @@ pub fn get_formatting_unregistration() -> Unregistration { impl TypstServer { pub async fn format_document(&self, source: &Source) -> anyhow::Result> { let original_text = source.text(); - let res = typstfmt_lib::format(original_text, self.get_fmt_config().await); + let res = typstfmt_lib::format(original_text, self.get_fmt_config().await?); Ok(vec![TextEdit { new_text: res, @@ -46,25 +49,28 @@ impl TypstServer { }]) } - async fn get_fmt_config(&self) -> FmtConfig { + async fn get_fmt_config(&self) -> anyhow::Result { // Ignoring all errors since we're returning the default config in case // we can't find something more specific - let mut config_file: Option = File::options().read(true).open(CONFIG_PATH).await.ok(); + let mut path = PathBuf::from(CONFIG_PATH); + let mut config_file: Option = File::options().read(true).open(&path).await.ok(); if config_file.is_none() { if let Some(root_path) = &self.config.read().await.root_path { - let mut root_path = root_path.clone(); - root_path.push(CONFIG_PATH); - config_file = File::options().read(true).open(root_path).await.ok(); + path = root_path.clone(); + path.push(CONFIG_PATH); + config_file = File::options().read(true).open(&path).await.ok(); } } if let Some(mut f) = config_file { let mut buf = String::default(); let _ = f.read_to_string(&mut buf).await; - FmtConfig::from_toml(&buf).unwrap_or_default() + // An error here should be surfaced to the user though + FmtConfig::from_toml(&buf) + .map_err(|s| anyhow::anyhow!(s)) } else { - FmtConfig::default() + Ok(FmtConfig::default()) } } } From 523eb03db00beb38f00e18d50bf75bc41079bb62 Mon Sep 17 00:00:00 2001 From: nvarner Date: Fri, 29 Sep 2023 18:27:57 -0400 Subject: [PATCH 4/4] read config files from cache --- src/server/formatting.rs | 60 +++++++++++++++++++--------------------- src/server/lsp.rs | 9 +++--- 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/src/server/formatting.rs b/src/server/formatting.rs index e8a14d83..6d39fce6 100644 --- a/src/server/formatting.rs +++ b/src/server/formatting.rs @@ -1,12 +1,9 @@ -use std::path::PathBuf; - -use anyhow::Context; -use tokio::fs::File; -use tokio::io::AsyncReadExt; - +use anyhow::anyhow; use tower_lsp::lsp_types::{Position, Range, Registration, TextEdit, Unregistration}; -use typst::syntax::Source; -use typstfmt_lib::Config as FmtConfig; +use typst::syntax::{FileId, Source, VirtualPath}; +use typstfmt_lib::Config; + +use crate::workspace::project::Project; use super::TypstServer; @@ -30,9 +27,14 @@ pub fn get_formatting_unregistration() -> Unregistration { } impl TypstServer { - pub async fn format_document(&self, source: &Source) -> anyhow::Result> { + pub async fn format_document( + &self, + project: Project, + source: Source, + ) -> anyhow::Result> { + let config = get_config(&project).await?; let original_text = source.text(); - let res = typstfmt_lib::format(original_text, self.get_fmt_config().await?); + let res = typstfmt_lib::format(original_text, config); Ok(vec![TextEdit { new_text: res, @@ -48,29 +50,23 @@ impl TypstServer { ), }]) } +} - async fn get_fmt_config(&self) -> anyhow::Result { - // Ignoring all errors since we're returning the default config in case - // we can't find something more specific - let mut path = PathBuf::from(CONFIG_PATH); - let mut config_file: Option = File::options().read(true).open(&path).await.ok(); +async fn get_config(project: &Project) -> anyhow::Result { + config_from_file(project) + .await + .unwrap_or_else(|| Ok(Config::default())) +} - if config_file.is_none() { - if let Some(root_path) = &self.config.read().await.root_path { - path = root_path.clone(); - path.push(CONFIG_PATH); - config_file = File::options().read(true).open(&path).await.ok(); - } - } +async fn config_from_file(project: &Project) -> Option> { + let file_id = FileId::new(None, VirtualPath::new(CONFIG_PATH)); + let file = project.read_bytes_by_id(file_id).await.ok()?; + let bytes = file.as_slice(); + Some(config_from_bytes(bytes)) +} - if let Some(mut f) = config_file { - let mut buf = String::default(); - let _ = f.read_to_string(&mut buf).await; - // An error here should be surfaced to the user though - FmtConfig::from_toml(&buf) - .map_err(|s| anyhow::anyhow!(s)) - } else { - Ok(FmtConfig::default()) - } - } +fn config_from_bytes(bytes: &[u8]) -> anyhow::Result { + let string = std::str::from_utf8(bytes)?; + let config = Config::from_toml(string).map_err(|err| anyhow!("{err}"))?; + Ok(config) } diff --git a/src/server/lsp.rs b/src/server/lsp.rs index 346370d0..ad8ff858 100644 --- a/src/server/lsp.rs +++ b/src/server/lsp.rs @@ -25,7 +25,7 @@ use super::semantic_tokens::{ get_semantic_tokens_options, get_semantic_tokens_registration, get_semantic_tokens_unregistration, }; -use super::{TypstServer, SourceScope}; +use super::TypstServer; #[async_trait] impl LanguageServer for TypstServer { @@ -605,14 +605,15 @@ impl LanguageServer for TypstServer { ) -> jsonrpc::Result>> { let uri = params.text_document.uri; - let SourceScope { source, project: _ } = self + let edits = self .scope_with_source(&uri) .await .map_err(|err| { error!(%err, %uri, "error getting document to format"); jsonrpc::Error::internal_error() - })?; - let edits = self.format_document(&source).await + })? + .run2(|source, project| self.format_document(project, source)) + .await .map_err(|err| { error!(%err, %uri, "error formatting document"); jsonrpc::Error::internal_error()