diff --git a/jekyll/editors.markdown b/jekyll/editors.markdown
index 5b774c525..0a9f8aa44 100644
--- a/jekyll/editors.markdown
+++ b/jekyll/editors.markdown
@@ -78,6 +78,9 @@ configuration languages (JSON, Lua, ELisp, etc.).
"inlayHint": {
"implicitHashValue": true,
"implicitRescue": true
+ },
+ "onTypeFormatting": {
+ "commentContinuation": true
}
},
"indexing": {
diff --git a/jekyll/index.markdown b/jekyll/index.markdown
index 5c8a57fc3..6ecf02ef3 100644
--- a/jekyll/index.markdown
+++ b/jekyll/index.markdown
@@ -329,6 +329,18 @@ On type formatting applies changes to the code as the user is typing. For exampl
{: .note }
In VS Code, format on type is disabled by default. You can enable it with `"editor.formatOnType": true`
+By default, breaking a line inside a comment continues the comment on the next line. VS Code users can turn this
+behavior off with the following setting:
+
+```jsonc
+{
+ // Disable comment continuation when breaking lines inside a comment (defaults to true)
+ "rubyLsp.featuresConfiguration.onTypeFormatting.commentContinuation": false
+}
+```
+
+To configure other editors, see the [initialization options](editors#all-initialization-options).
+
diff --git a/lib/ruby_lsp/global_state.rb b/lib/ruby_lsp/global_state.rb
index 82e6edbcf..ba374f4bc 100644
--- a/lib/ruby_lsp/global_state.rb
+++ b/lib/ruby_lsp/global_state.rb
@@ -81,6 +81,10 @@ def initialize
enableAll: false,
enableTestCodeLens: true,
}),
+ onTypeFormatting: RequestConfig.new({
+ enableAll: false,
+ commentContinuation: true,
+ }),
} #: Hash[Symbol, RequestConfig]
end
diff --git a/lib/ruby_lsp/requests/on_type_formatting.rb b/lib/ruby_lsp/requests/on_type_formatting.rb
index da4904e19..e70d84bc3 100644
--- a/lib/ruby_lsp/requests/on_type_formatting.rb
+++ b/lib/ruby_lsp/requests/on_type_formatting.rb
@@ -23,8 +23,8 @@ def provider
/.*\s\bdo\b($|\s)/,
] #: Array[Regexp]
- #: (RubyDocument document, Hash[Symbol, untyped] position, String trigger_character, String client_name) -> void
- def initialize(document, position, trigger_character, client_name)
+ #: (RubyDocument document, Hash[Symbol, untyped] position, String trigger_character, String client_name, ?RequestConfig? config) -> void
+ def initialize(document, position, trigger_character, client_name, config = nil)
super()
@document = document
@lines = @document.source.lines #: Array[String]
@@ -36,6 +36,7 @@ def initialize(document, position, trigger_character, client_name)
@edits = [] #: Array[Interface::TextEdit]
@trigger_character = trigger_character
@client_name = client_name
+ @config = config
end
# @override
@@ -51,9 +52,11 @@ def perform
# But if it's a RBS signature starting with `#:`, we'll ignore it
# so users can immediately continue typing the method definition
if (comment_match = @previous_line.match(/^#(?!:)(\s*)/))
- handle_comment_line(
- comment_match[1], #: as !nil
- )
+ if comment_continuation_enabled?
+ handle_comment_line(
+ comment_match[1], #: as !nil
+ )
+ end
elsif @document.syntax_error?
match = /(<<((-|~)?))(?['"`]?)(?\w+)\k/.match(@previous_line)
heredoc_delimiter = match && match.named_captures["delimiter"]
@@ -73,6 +76,14 @@ def perform
private
+ #: -> bool
+ def comment_continuation_enabled?
+ config = @config
+ return true unless config
+
+ config.enabled?(:commentContinuation) || false
+ end
+
#: -> void
def handle_pipe
current_line = @lines[@position[:line]]
diff --git a/lib/ruby_lsp/server.rb b/lib/ruby_lsp/server.rb
index c700fc6c5..082cce76b 100644
--- a/lib/ruby_lsp/server.rb
+++ b/lib/ruby_lsp/server.rb
@@ -715,6 +715,7 @@ def text_document_on_type_formatting(message)
params[:position],
params[:ch],
@store.client_name,
+ @global_state.feature_configuration(:onTypeFormatting),
).perform,
),
)
diff --git a/test/global_state_test.rb b/test/global_state_test.rb
index 35f96e754..4e33b574b 100644
--- a/test/global_state_test.rb
+++ b/test/global_state_test.rb
@@ -357,6 +357,24 @@ def test_feature_configuration_with_partially_provided_configuration
assert(inlay_hint_config.enabled?(:implicitHashValue))
end
+ def test_on_type_formatting_comment_continuation_configuration
+ state = GlobalState.new
+ on_type_formatting_config = state.feature_configuration(:onTypeFormatting) #: as !nil
+ assert(on_type_formatting_config.enabled?(:commentContinuation))
+
+ state.apply_options({
+ initializationOptions: {
+ featuresConfiguration: {
+ onTypeFormatting: {
+ commentContinuation: false,
+ },
+ },
+ },
+ })
+
+ refute(on_type_formatting_config.enabled?(:commentContinuation))
+ end
+
def test_initialize_features_with_enable_all_configuration
state = GlobalState.new
state.apply_options({
diff --git a/test/requests/on_type_formatting_test.rb b/test/requests/on_type_formatting_test.rb
index 69a75a9fe..e29068f2e 100644
--- a/test/requests/on_type_formatting_test.rb
+++ b/test/requests/on_type_formatting_test.rb
@@ -292,6 +292,76 @@ def test_comment_continuation
assert_equal(expected_edits.to_json, edits.to_json)
end
+ def test_comment_continuation_applies_with_default_configuration
+ document = RubyLsp::RubyDocument.new(
+ source: +"",
+ version: 1,
+ uri: URI("file:///fake.rb"),
+ global_state: @global_state,
+ )
+
+ document.push_edits(
+ [{
+ range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } },
+ text: " # something",
+ }],
+ version: 2,
+ )
+ document.parse!
+
+ edits = RubyLsp::Requests::OnTypeFormatting.new(
+ document,
+ { line: 0, character: 14 },
+ "\n",
+ "Visual Studio Code",
+ @global_state.feature_configuration(:onTypeFormatting),
+ ).perform
+ expected_edits = [
+ {
+ range: { start: { line: 0, character: 14 }, end: { line: 0, character: 14 } },
+ newText: "# ",
+ },
+ ]
+ assert_equal(expected_edits.to_json, edits.to_json)
+ end
+
+ def test_comment_continuation_can_be_disabled_through_configuration
+ @global_state.apply_options({
+ initializationOptions: {
+ featuresConfiguration: {
+ onTypeFormatting: {
+ commentContinuation: false,
+ },
+ },
+ },
+ })
+
+ document = RubyLsp::RubyDocument.new(
+ source: +"",
+ version: 1,
+ uri: URI("file:///fake.rb"),
+ global_state: @global_state,
+ )
+
+ document.push_edits(
+ [{
+ range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } },
+ text: " # something",
+ }],
+ version: 2,
+ )
+ document.parse!
+
+ edits = RubyLsp::Requests::OnTypeFormatting.new(
+ document,
+ { line: 0, character: 14 },
+ "\n",
+ "Visual Studio Code",
+ @global_state.feature_configuration(:onTypeFormatting),
+ ).perform
+ assert_empty(edits)
+ end
+
def test_comment_continuation_does_not_apply_to_rbs_signatures
document = RubyLsp::RubyDocument.new(
source: +"",
diff --git a/test/server_test.rb b/test/server_test.rb
index 1301c8b59..2b71b548e 100644
--- a/test/server_test.rb
+++ b/test/server_test.rb
@@ -853,6 +853,47 @@ def foo
end
end
+ def test_on_type_formatting_comment_continuation_can_be_disabled
+ uri = URI::Generic.from_path(path: "/fake.rb")
+
+ capture_io do
+ @server.process_message(id: 1, method: "initialize", params: {
+ initializationOptions: {
+ featuresConfiguration: {
+ onTypeFormatting: {
+ commentContinuation: false,
+ },
+ },
+ },
+ })
+
+ @server.process_message({
+ method: "textDocument/didOpen",
+ params: {
+ textDocument: {
+ uri: uri,
+ text: "# some comment",
+ version: 1,
+ languageId: "ruby",
+ },
+ },
+ })
+
+ @server.process_message({
+ id: 2,
+ method: "textDocument/onTypeFormatting",
+ params: {
+ textDocument: { uri: uri },
+ position: { line: 1, character: 0 },
+ ch: "\n",
+ },
+ })
+
+ result = find_message(RubyLsp::Result, id: 2)
+ assert_empty(result.response)
+ end
+ end
+
def test_show_window_responses_are_redirected_to_addons
klass = Class.new(RubyLsp::Addon) do
def activate(global_state, outgoing_queue)
diff --git a/vscode/package.json b/vscode/package.json
index aafb95c37..51098c930 100644
--- a/vscode/package.json
+++ b/vscode/package.json
@@ -368,6 +368,20 @@
"default": true
}
}
+ },
+ "onTypeFormatting": {
+ "description": "Customize on type formatting features",
+ "type": "object",
+ "properties": {
+ "enableAll": {
+ "type": "boolean"
+ },
+ "commentContinuation": {
+ "description": "Automatically continue comments when breaking lines inside a comment",
+ "type": "boolean",
+ "default": true
+ }
+ }
}
}
},