From 636d4880c4b9403aa45d837c62f4b812d0520cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felici=C3=A1n=20N=C3=A9meth?= Date: Sun, 27 Mar 2022 10:45:57 +0200 Subject: [PATCH 1/3] internal: Allow OnTypeFormatting to send SnippetTextEdit But continue to send TextEdit only. --- crates/ide/src/typing.rs | 22 ++++++++++++++++------ crates/rust-analyzer/src/handlers.rs | 6 +++--- crates/rust-analyzer/src/lsp_ext.rs | 17 +++++++++++++++-- crates/rust-analyzer/src/main_loop.rs | 2 +- docs/dev/lsp-extensions.md | 6 +++--- 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs index a75e6be8b8a..d423d8a0546 100644 --- a/crates/ide/src/typing.rs +++ b/crates/ide/src/typing.rs @@ -34,6 +34,11 @@ // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`. pub(crate) const TRIGGER_CHARS: &str = ".=>{"; +struct ExtendedTextEdit { + edit: TextEdit, + is_snippet: bool, +} + // Feature: On Typing Assists // // Some features trigger on typing certain characters: @@ -68,22 +73,27 @@ pub(crate) fn on_char_typed( return None; } let edit = on_char_typed_inner(file, position.offset, char_typed)?; - Some(SourceChange::from_text_edit(position.file_id, edit)) + let mut sc = SourceChange::from_text_edit(position.file_id, edit.edit); + sc.is_snippet = edit.is_snippet; + Some(sc) } fn on_char_typed_inner( file: &Parse, offset: TextSize, char_typed: char, -) -> Option { +) -> Option { + fn conv(text_edit: Option) -> Option { + Some(ExtendedTextEdit { edit: text_edit?, is_snippet: false }) + } if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { return None; } match char_typed { - '.' => on_dot_typed(&file.tree(), offset), - '=' => on_eq_typed(&file.tree(), offset), - '>' => on_arrow_typed(&file.tree(), offset), - '{' => on_opening_brace_typed(file, offset), + '.' => conv(on_dot_typed(&file.tree(), offset)), + '=' => conv(on_eq_typed(&file.tree(), offset)), + '>' => conv(on_arrow_typed(&file.tree(), offset)), + '{' => conv(on_opening_brace_typed(file, offset)), _ => unreachable!(), } } diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 261c02816d5..a16f0d904ce 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -276,7 +276,7 @@ pub(crate) fn handle_on_enter( pub(crate) fn handle_on_type_formatting( snap: GlobalStateSnapshot, params: lsp_types::DocumentOnTypeFormattingParams, -) -> Result>> { +) -> Result>> { let _p = profile::span("handle_on_type_formatting"); let mut position = from_proto::file_position(&snap, params.text_document_position)?; let line_index = snap.file_line_index(position.file_id)?; @@ -306,9 +306,9 @@ pub(crate) fn handle_on_type_formatting( }; // This should be a single-file edit - let (_, edit) = edit.source_file_edits.into_iter().next().unwrap(); + let (_, text_edit) = edit.source_file_edits.into_iter().next().unwrap(); - let change = to_proto::text_edit_vec(&line_index, edit); + let change = to_proto::snippet_text_edit_vec(&line_index, edit.is_snippet, text_edit); Ok(Some(change)) } diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index c1b230bd9df..5f0e108624b 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -4,8 +4,8 @@ use lsp_types::request::Request; use lsp_types::{ - notification::Notification, CodeActionKind, PartialResultParams, Position, Range, - TextDocumentIdentifier, WorkDoneProgressParams, + notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams, + PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams, }; use serde::{Deserialize, Serialize}; @@ -512,6 +512,19 @@ pub enum WorkspaceSymbolSearchKind { AllSymbols, } +/// The document on type formatting request is sent from the client to +/// the server to format parts of the document during typing. This is +/// almost same as lsp_types::request::OnTypeFormatting, but the +/// result has SnippetTextEdit in it instead of TextEdit. +#[derive(Debug)] +pub enum OnTypeFormatting {} + +impl Request for OnTypeFormatting { + type Params = DocumentOnTypeFormattingParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/onTypeFormatting"; +} + #[derive(Debug, Serialize, Deserialize)] pub struct CompletionResolveData { pub position: lsp_types::TextDocumentPositionParams, diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index b5ac55e60d6..3c879687433 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -605,7 +605,7 @@ fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> .on::(handlers::handle_open_cargo_toml) .on::(handlers::handle_move_item) .on::(handlers::handle_workspace_symbol) - .on::(handlers::handle_on_type_formatting) + .on::(handlers::handle_on_type_formatting) .on::(handlers::handle_document_symbol) .on::(handlers::handle_goto_definition) .on::(handlers::handle_goto_declaration) diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 875561608dc..983d8e1ac09 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@