diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 207c41e7cd..eccfb0c059 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -317,8 +317,8 @@ pub struct Chunk<'a> { pub struct Diff { pub(crate) base_version: clock::Global, - line_ending: LineEnding, - edits: Vec<(Range, Arc)>, + pub(crate) line_ending: LineEnding, + pub(crate) edits: Vec<(Range, Arc)>, } #[derive(Clone, Copy)] diff --git a/crates/language/src/proto.rs b/crates/language/src/proto.rs index c4abe39d47..5da1d5713f 100644 --- a/crates/language/src/proto.rs +++ b/crates/language/src/proto.rs @@ -1,6 +1,6 @@ use crate::{ diagnostic_set::DiagnosticEntry, CodeAction, CodeLabel, Completion, CursorShape, Diagnostic, - Language, + Diff, Language, }; use anyhow::{anyhow, Result}; use clock::ReplicaId; @@ -587,3 +587,42 @@ pub fn serialize_version(version: &clock::Global) -> Vec proto::Diff { + proto::Diff { + version: serialize_version(&diff.base_version), + line_ending: serialize_line_ending(diff.line_ending) as i32, + edits: diff + .edits + .into_iter() + .map(|(range, edit)| proto::DiffEdit { + range: Some(proto::Range { + start: range.start as u64, + end: range.end as u64, + }), + edit: edit.to_string(), + }) + .collect(), + } +} + +pub fn deserialize_diff(diff: proto::Diff) -> Diff { + Diff { + base_version: deserialize_version(&diff.version), + line_ending: deserialize_line_ending( + rpc::proto::LineEnding::from_i32(diff.line_ending) + .unwrap_or_else(|| panic!("invalid line ending {}", diff.line_ending)), + ), + edits: diff + .edits + .into_iter() + .map(|edit| { + let range = edit.range.expect("incorrect edit without a range"); + ( + range.start as usize..range.end as usize, + Arc::from(edit.edit.as_str()), + ) + }) + .collect(), + } +} diff --git a/crates/prettier/src/prettier.rs b/crates/prettier/src/prettier.rs index 2df96224b6..5647123c75 100644 --- a/crates/prettier/src/prettier.rs +++ b/crates/prettier/src/prettier.rs @@ -3,11 +3,12 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use anyhow::Context; -use client::Client; +use client::{proto, Client}; use collections::{HashMap, HashSet}; use fs::Fs; use gpui::{AsyncAppContext, ModelHandle}; use language::language_settings::language_settings; +use language::proto::deserialize_diff; use language::{Buffer, BundledFormatter, Diff}; use lsp::request::Request; use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId}; @@ -28,6 +29,7 @@ pub struct Local { } pub struct Remote { + project_id: u64, worktree_id: Option, prettier_dir: PathBuf, client: Arc, @@ -61,8 +63,14 @@ impl Prettier { ".editorconfig", ]; - pub fn remote(worktree_id: Option, prettier_dir: PathBuf, client: Arc) -> Self { + pub fn remote( + project_id: u64, + worktree_id: Option, + prettier_dir: PathBuf, + client: Arc, + ) -> Self { Self::Remote(Remote { + project_id, worktree_id, prettier_dir, client, @@ -80,7 +88,7 @@ impl Prettier { .components() .into_iter() .take_while(|path_component| { - path_component.as_os_str().to_str() != Some("node_modules") + path_component.as_os_str().to_string_lossy() != "node_modules" }) .collect::(); @@ -137,7 +145,7 @@ impl Prettier { for path_component in file_to_format.components().into_iter() { current_path = current_path.join(path_component); paths_to_check.push_front(current_path.clone()); - if path_component.as_os_str().to_str() == Some("node_modules") { + if path_component.as_os_str().to_string_lossy() == "node_modules" { break; } } @@ -219,14 +227,18 @@ impl Prettier { pub async fn invoke( &self, - buffer: &ModelHandle, + buffer: Option<&ModelHandle>, buffer_path: Option, method: &str, cx: &AsyncAppContext, ) -> anyhow::Result> { match method { Format::METHOD => self - .format(buffer, buffer_path, cx) + .format( + buffer.expect("missing buffer for format invocation"), + buffer_path, + cx, + ) .await .context("invoke method") .map(Some), @@ -374,7 +386,21 @@ impl Prettier { let diff_task = buffer.read_with(cx, |buffer, cx| buffer.diff(response.text, cx)); Ok(diff_task.await) } - Self::Remote(remote) => todo!("TODO kb"), + Self::Remote(remote) => buffer + .read_with(cx, |buffer, _| { + remote.client.request(proto::InvokePrettierForBuffer { + buffer_id: Some(buffer.remote_id()), + worktree_id: self.worktree_id().map(|id| id as u64), + method: Format::METHOD.to_string(), + project_id: remote.project_id, + prettier_path: remote.prettier_dir.to_string_lossy().to_string(), + }) + }) + .await + .context("prettier diff invoke")? + .diff + .map(deserialize_diff) + .context("missing diff after prettier diff invocation"), } } @@ -385,7 +411,23 @@ impl Prettier { .request::(()) .await .context("prettier clear cache"), - Self::Remote(remote) => todo!("TODO kb"), + Self::Remote(remote) => remote + .client + .request(proto::InvokePrettierForBuffer { + buffer_id: None, + worktree_id: self.worktree_id().map(|id| id as u64), + method: ClearCache::METHOD.to_string(), + project_id: remote.project_id, + prettier_path: remote.prettier_dir.to_string_lossy().to_string(), + }) + .await + .map(|response| { + debug_assert!( + response.diff.is_none(), + "Cleare cache invocation returned diff data" + ) + }) + .context("prettier invoke clear cache"), } } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index f3a92ad00f..9a1d78f083 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -37,7 +37,7 @@ use language::{ point_to_lsp, proto::{ deserialize_anchor, deserialize_fingerprint, deserialize_line_ending, deserialize_version, - serialize_anchor, serialize_version, split_operations, + serialize_anchor, serialize_diff, serialize_version, split_operations, }, range_from_lsp, range_to_lsp, Bias, Buffer, BufferSnapshot, BundledFormatter, CachedLspAdapter, CodeAction, CodeLabel, Completion, Diagnostic, DiagnosticEntry, DiagnosticSet, Diff, @@ -6382,7 +6382,7 @@ impl Project { .filter(|(path, _, _)| { !path .components() - .any(|component| component.as_os_str().to_str() == Some("node_modules")) + .any(|component| component.as_os_str().to_string_lossy() == "node_modules") }) .find(|(path, _, _)| prettier_config_files.contains(path.as_ref())); let current_worktree_id = worktree.read(cx).id(); @@ -8324,14 +8324,14 @@ impl Project { this.prettier_instances .get(&( envelope.payload.worktree_id.map(WorktreeId::from_proto), - PathBuf::from(&envelope.payload.buffer_path), + PathBuf::from(&envelope.payload.prettier_path), )) .cloned() }) .with_context(|| { format!( - "Missing prettier for worktree {:?} and path {}", - envelope.payload.worktree_id, envelope.payload.buffer_path, + "Missing prettier for worktree {:?} and path {:?}", + envelope.payload.worktree_id, envelope.payload.prettier_path, ) })? .await; @@ -8340,25 +8340,27 @@ impl Project { Err(e) => anyhow::bail!("Prettier instance failed to start: {e:#}"), }; - let buffer = this - .update(&mut cx, |this, cx| { - this.opened_buffers - .get(&envelope.payload.buffer_id) - .and_then(|buffer| buffer.upgrade(cx)) - }) - .with_context(|| format!("unknown buffer id {}", envelope.payload.buffer_id))?; + let buffer = this.update(&mut cx, |this, cx| { + envelope + .payload + .buffer_id + .and_then(|id| this.opened_buffers.get(&id)) + .and_then(|buffer| buffer.upgrade(cx)) + }); - let buffer_path = buffer.read_with(&cx, |buffer, cx| { - File::from_dyn(buffer.file()).map(|f| f.full_path(cx)) + let buffer_path = buffer.as_ref().and_then(|buffer| { + buffer.read_with(&cx, |buffer, cx| { + File::from_dyn(buffer.file()).map(|f| f.full_path(cx)) + }) }); let diff = prettier - .invoke(&buffer, buffer_path, &envelope.payload.method, &cx) + .invoke(buffer.as_ref(), buffer_path, &envelope.payload.method, &cx) .await .with_context(|| format!("prettier invoke method {}", &envelope.payload.method))?; Ok(proto::InvokePrettierForBufferResponse { - diff: todo!("TODO kb serialize diff"), + diff: diff.map(serialize_diff), }) } @@ -8523,6 +8525,7 @@ impl Project { .map(|prettier_path| { let prettier_task = Task::ready( Ok(Arc::new(Prettier::remote( + project_id, worktree_id.map(|id| id.to_usize()), prettier_path.clone(), client, diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 0622fcef90..cbd334e334 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -1574,8 +1574,8 @@ message PrettierInstanceForBufferResponse { message InvokePrettierForBuffer { uint64 project_id = 1; - string buffer_path = 2; - uint64 buffer_id = 3; + optional uint64 buffer_id = 3; + string prettier_path = 2; optional uint64 worktree_id = 4; string method = 5; } @@ -1585,7 +1585,12 @@ message InvokePrettierForBufferResponse { } message Diff { - VectorClockEntry version = 1; - string line_ending = 2; - string edits = 3; + repeated VectorClockEntry version = 1; + LineEnding line_ending = 2; + repeated DiffEdit edits = 3; +} + +message DiffEdit { + Range range = 1; + string edit = 2; }