diff --git a/Cargo.lock b/Cargo.lock index 8b1278b3dc..120669f037 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5520,6 +5520,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "prettier" version = "0.1.0" +dependencies = [ + "anyhow", + "fs", + "gpui", + "language", +] [[package]] name = "pretty_assertions" @@ -5635,6 +5641,7 @@ dependencies = [ "lsp", "parking_lot 0.11.2", "postage", + "prettier", "pretty_assertions", "rand 0.8.5", "regex", diff --git a/crates/language/src/language_settings.rs b/crates/language/src/language_settings.rs index c3f706802a..8778ba8d64 100644 --- a/crates/language/src/language_settings.rs +++ b/crates/language/src/language_settings.rs @@ -149,10 +149,15 @@ pub enum ShowWhitespaceSetting { All, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] +#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum Formatter { + #[default] + Auto, LanguageServer, + Prettier { + config: (), // Support some of the most important settings in the prettier-vscode extension. + }, External { command: Arc, arguments: Arc<[String]>, diff --git a/crates/prettier/Cargo.toml b/crates/prettier/Cargo.toml index 798899df0e..c2e4b2a3cc 100644 --- a/crates/prettier/Cargo.toml +++ b/crates/prettier/Cargo.toml @@ -3,7 +3,18 @@ name = "prettier" version = "0.1.0" edition = "2021" -[dependencies] - [lib] path = "src/prettier.rs" + +[dependencies] +language = { path = "../language" } +gpui = { path = "../gpui" } +fs = { path = "../fs" } + +anyhow.workspace = true + + +[dev-dependencies] +language = { path = "../language", features = ["test-support"] } +gpui = { path = "../gpui", features = ["test-support"] } +fs = { path = "../fs", features = ["test-support"] } diff --git a/crates/prettier/src/prettier.rs b/crates/prettier/src/prettier.rs index 7d12d9af81..9b1b9c1e9d 100644 --- a/crates/prettier/src/prettier.rs +++ b/crates/prettier/src/prettier.rs @@ -1,14 +1,46 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right +pub use std::path::{Path, PathBuf}; +pub use std::sync::Arc; + +use fs::Fs; +use gpui::ModelHandle; +use language::{Buffer, Diff}; + +pub struct Prettier { + _private: (), } -#[cfg(test)] -mod tests { - use super::*; +type NodeRuntime = (); - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); +impl Prettier { + // This was taken from the prettier-vscode extension. + pub const CONFIG_FILE_NAMES: &'static [&'static str] = &[ + ".prettierrc", + ".prettierrc.json", + ".prettierrc.json5", + ".prettierrc.yaml", + ".prettierrc.yml", + ".prettierrc.toml", + ".prettierrc.js", + ".prettierrc.cjs", + "package.json", + "prettier.config.js", + "prettier.config.cjs", + ".editorconfig", + ]; + + pub async fn locate(starting_path: Option<&Path>, fs: Arc) -> PathBuf { + todo!() + } + + pub async fn start(prettier_path: &Path, node: Arc) -> anyhow::Result { + todo!() + } + + pub async fn format(&self, buffer: &ModelHandle) -> anyhow::Result { + todo!() + } + + pub async fn clear_cache(&self) -> anyhow::Result<()> { + todo!() } } diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index ffea6646e9..c22193f130 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -31,6 +31,7 @@ git = { path = "../git" } gpui = { path = "../gpui" } language = { path = "../language" } lsp = { path = "../lsp" } +prettier = { path = "../prettier" } rpc = { path = "../rpc" } settings = { path = "../settings" } sum_tree = { path = "../sum_tree" } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index a50e02a631..42b0a13c51 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -50,6 +50,7 @@ use lsp::{ }; use lsp_command::*; use postage::watch; +use prettier::Prettier; use project_settings::{LspSettings, ProjectSettings}; use rand::prelude::*; use search::SearchQuery; @@ -152,6 +153,7 @@ pub struct Project { copilot_lsp_subscription: Option, copilot_log_subscription: Option, current_lsp_settings: HashMap, LspSettings>, + prettier_instances: HashMap<(WorktreeId, PathBuf), Shared>>>>, } struct DelayedDebounced { @@ -660,6 +662,7 @@ impl Project { copilot_lsp_subscription, copilot_log_subscription: None, current_lsp_settings: settings::get::(cx).lsp.clone(), + prettier_instances: HashMap::default(), } }) } @@ -757,6 +760,7 @@ impl Project { copilot_lsp_subscription, copilot_log_subscription: None, current_lsp_settings: settings::get::(cx).lsp.clone(), + prettier_instances: HashMap::default(), }; for worktree in worktrees { let _ = this.add_worktree(&worktree, cx); @@ -4027,6 +4031,7 @@ impl Project { enum FormatOperation { Lsp(Vec<(Range, String)>), External(Diff), + Prettier(Diff), } // Apply language-specific formatting using either a language server @@ -4062,8 +4067,8 @@ impl Project { | (_, FormatOnSave::External { command, arguments }) => { if let Some(buffer_abs_path) = buffer_abs_path { format_operation = Self::format_via_external_command( - &buffer, - &buffer_abs_path, + buffer, + buffer_abs_path, &command, &arguments, &mut cx, @@ -4076,6 +4081,45 @@ impl Project { .map(FormatOperation::External); } } + (Formatter::Auto, FormatOnSave::On | FormatOnSave::Off) => { + if let Some(prettier) = this.update(&mut cx, |project, _| { + project.prettier_instance_for_buffer(buffer) + }) { + format_operation = Some(FormatOperation::Prettier( + prettier + .format(buffer) + .await + .context("autoformatting via prettier")?, + )); + } else if let Some((language_server, buffer_abs_path)) = + language_server.as_ref().zip(buffer_abs_path.as_ref()) + { + format_operation = Some(FormatOperation::Lsp( + Self::format_via_lsp( + &this, + &buffer, + buffer_abs_path, + &language_server, + tab_size, + &mut cx, + ) + .await + .context("failed to format via language server")?, + )); + } + } + (Formatter::Prettier { .. }, FormatOnSave::On | FormatOnSave::Off) => { + if let Some(prettier) = this.update(&mut cx, |project, _| { + project.prettier_instance_for_buffer(buffer) + }) { + format_operation = Some(FormatOperation::Prettier( + prettier + .format(buffer) + .await + .context("formatting via prettier")?, + )); + } + } }; buffer.update(&mut cx, |b, cx| { @@ -4100,6 +4144,9 @@ impl Project { FormatOperation::External(diff) => { b.apply_diff(diff, cx); } + FormatOperation::Prettier(diff) => { + b.apply_diff(diff, cx); + } } if let Some(transaction_id) = whitespace_transaction_id { @@ -8109,6 +8156,11 @@ impl Project { Vec::new() } } + + fn prettier_instance_for_buffer(&self, buffer: &ModelHandle) -> Option { + // TODO kb + None + } } fn subscribe_for_copilot_events(