Use formatting options

Kirill Bulatov created

Change summary

crates/editor/src/editor.rs       |  1 
crates/project/src/lsp_command.rs | 35 ++++++++++++++++++++++++++++++--
crates/project/src/project.rs     | 19 ++++++-----------
crates/rpc/proto/zed.proto        | 11 +++++++--
4 files changed, 48 insertions(+), 18 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -2122,6 +2122,7 @@ impl Editor {
             let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx);
             this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 
+            // When buffer contents is updated and caret is moved, try triggering on type formatting.
             if text.len() == 1 {
                 let input_char = text.chars().next().expect("single char input");
                 if let Some(on_type_format_task) = this.trigger_on_type_format(input_char, cx) {

crates/project/src/lsp_command.rs 🔗

@@ -16,6 +16,15 @@ use language::{
 use lsp::{DocumentHighlightKind, LanguageServer, LanguageServerId, ServerCapabilities};
 use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
 
+pub fn lsp_formatting_options(tab_size: u32) -> lsp::FormattingOptions {
+    lsp::FormattingOptions {
+        tab_size,
+        insert_spaces: true,
+        insert_final_newline: Some(true),
+        ..lsp::FormattingOptions::default()
+    }
+}
+
 #[async_trait(?Send)]
 pub(crate) trait LspCommand: 'static + Sized {
     type Response: 'static + Default + Send;
@@ -112,7 +121,19 @@ pub(crate) struct GetCodeActions {
 pub(crate) struct OnTypeFormatting {
     pub position: PointUtf16,
     pub trigger: String,
-    // TODO kb formatting options?
+    pub options: FormattingOptions,
+}
+
+pub(crate) struct FormattingOptions {
+    tab_size: u32,
+}
+
+impl From<lsp::FormattingOptions> for FormattingOptions {
+    fn from(value: lsp::FormattingOptions) -> Self {
+        Self {
+            tab_size: value.tab_size,
+        }
+    }
 }
 
 #[async_trait(?Send)]
@@ -1634,8 +1655,7 @@ impl LspCommand for OnTypeFormatting {
                 point_to_lsp(self.position),
             ),
             ch: self.trigger.clone(),
-            // TODO kb pass current editor ones
-            options: lsp::FormattingOptions::default(),
+            options: lsp_formatting_options(self.options.tab_size),
         }
     }
 
@@ -1660,6 +1680,9 @@ impl LspCommand for OnTypeFormatting {
         proto::OnTypeFormatting {
             project_id,
             buffer_id: buffer.remote_id(),
+            options: Some(proto::FormattingOptions {
+                tab_size: self.options.tab_size,
+            }),
             position: Some(language::proto::serialize_anchor(
                 &buffer.anchor_before(self.position),
             )),
@@ -1687,6 +1710,12 @@ impl LspCommand for OnTypeFormatting {
         Ok(Self {
             position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
             trigger: message.trigger.clone(),
+            options: message
+                .options
+                .map(|options| options.tab_size)
+                .map(lsp_formatting_options)
+                .unwrap_or_default()
+                .into(),
         })
     }
 

crates/project/src/project.rs 🔗

@@ -3476,12 +3476,7 @@ impl Project {
             language_server
                 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
                     text_document,
-                    options: lsp::FormattingOptions {
-                        tab_size: tab_size.into(),
-                        insert_spaces: true,
-                        insert_final_newline: Some(true),
-                        ..Default::default()
-                    },
+                    options: lsp_command::lsp_formatting_options(tab_size.get()),
                     work_done_progress_params: Default::default(),
                 })
                 .await?
@@ -3497,12 +3492,7 @@ impl Project {
                 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
                     text_document,
                     range: lsp::Range::new(buffer_start, buffer_end),
-                    options: lsp::FormattingOptions {
-                        tab_size: tab_size.into(),
-                        insert_spaces: true,
-                        insert_final_newline: Some(true),
-                        ..Default::default()
-                    },
+                    options: lsp_command::lsp_formatting_options(tab_size.get()),
                     work_done_progress_params: Default::default(),
                 })
                 .await?
@@ -4216,12 +4206,17 @@ impl Project {
         input: char,
         cx: &mut ModelContext<Self>,
     ) -> Task<Result<()>> {
+        let tab_size = buffer.read_with(cx, |buffer, cx| {
+            let language_name = buffer.language().map(|language| language.name());
+            language_settings(language_name.as_deref(), cx).tab_size
+        });
         let position = position.to_point_utf16(buffer.read(cx));
         let edits_task = self.request_lsp(
             buffer.clone(),
             OnTypeFormatting {
                 position,
                 trigger: input.to_string(),
+                options: lsp_command::lsp_formatting_options(tab_size.get()).into(),
             },
             cx,
         );

crates/rpc/proto/zed.proto 🔗

@@ -676,9 +676,14 @@ message PerformRename {
 message OnTypeFormatting {
     uint64 project_id = 1;
     uint64 buffer_id = 2;
-    Anchor position = 3;
-    string trigger = 4;
-    repeated VectorClockEntry version = 5;
+    FormattingOptions options = 3;
+    Anchor position = 4;
+    string trigger = 5;
+    repeated VectorClockEntry version = 6;
+}
+
+message FormattingOptions {
+    uint32 tab_size = 1;
 }
 
 message OnTypeFormattingResponse {