From a878fcaeeed9dd4ce32d020406d4e54d6caacf7f Mon Sep 17 00:00:00 2001 From: Vitaly Slobodin Date: Tue, 13 Aug 2024 18:22:58 +0200 Subject: [PATCH] Fix Ruby LSP formatting range to comply with LSP specification The current implementation of formatting does not use the proper range for a response. Consider the following Ruby code: ```ruby class A def my_method [1] end end ``` Let's pretend that our RuboCop configuration specifies omitting whitespaces inside array declarations, which means the code above is not properly formatted. The code should be formatted like this: ```ruby class A def my_method [ 1 ] end end ``` When a client asks Ruby LSP to format the first code, the server sends a response (taken from the Zed editor) where the reported `end` property of the `Range` interface has `line` and `character` keys that do not match the source document. Both of them equal the character size of the document. ```json { "id":6, "result":[ { "range":{ "start":{ "line":0, "character":0 }, "end":{ "line":43, "character":43 } }, "newText":"class A\n def my_method\n [ 1 ]\n end\nend\n" } ], "jsonrpc":"2.0" } ``` For some reason, Visual Studio Code considers this response valid, and the code is formatted properly. However, some editors perform a check to ensure that the reported response from Ruby LSP is not out of bounds of the current text document. According to the LSP specification from the link below: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#range A range in a text document expressed as (zero-based) start and end positions. The correct response should be: ```json { "id":35, "result":[ { "range":{ "start":{ "line":0, "character":0 }, "end":{ "line":5, "character":0 } }, "newText":"class A\n def my_method\n [ 1 ]\n end\nend\n" } ], "jsonrpc":"2.0" } ``` --- lib/ruby_lsp/requests/formatting.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ruby_lsp/requests/formatting.rb b/lib/ruby_lsp/requests/formatting.rb index 7dd9b8141..a2b7abf87 100644 --- a/lib/ruby_lsp/requests/formatting.rb +++ b/lib/ruby_lsp/requests/formatting.rb @@ -58,14 +58,16 @@ def perform formatted_text = @active_formatter.run_formatting(@uri, @document) return unless formatted_text + lines = @document.source.lines size = @document.source.size + return if formatted_text.size == size && formatted_text == @document.source [ Interface::TextEdit.new( range: Interface::Range.new( start: Interface::Position.new(line: 0, character: 0), - end: Interface::Position.new(line: size, character: size), + end: Interface::Position.new(line: lines.size, character: 0), ), new_text: formatted_text, ),