From e6cff7a7db75f0a970b45e072ead20cd6e212f45 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 17 Dec 2025 19:47:20 +0800 Subject: [PATCH] Add config completion.addSemicolonToJumps Example --- ```rust fn f() -> i32 { if true { $0 } } ``` **addSemicolonToJumps: true (default)** ```rust fn f() -> i32 { if true { return $0; } } ``` **addSemicolonToJumps: false** ```rust fn f() -> i32 { if true { return $0 } } ``` --- crates/ide-completion/src/completions/expr.rs | 8 +++++--- crates/ide-completion/src/config.rs | 1 + crates/ide-completion/src/tests.rs | 1 + crates/ide-completion/src/tests/expression.rs | 16 ++++++++++++++-- crates/rust-analyzer/src/config.rs | 4 ++++ .../rust-analyzer/src/integrated_benchmarks.rs | 3 +++ docs/book/src/configuration_generated.md | 7 +++++++ editors/code/package.json | 10 ++++++++++ 8 files changed, 45 insertions(+), 5 deletions(-) diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index 77734c5d6f98..23f11d988dbf 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -406,14 +406,15 @@ pub(crate) fn complete_expr_path( } if let Some(loop_ty) = innermost_breakable_ty { - if in_block_expr { + let semicolon = in_block_expr && ctx.config.add_semicolon_to_jumps; + if semicolon { add_keyword("continue", "continue;"); } else { add_keyword("continue", "continue"); } add_keyword( "break", - match (loop_ty.is_unit(), in_block_expr) { + match (loop_ty.is_unit(), semicolon) { (true, true) => "break;", (true, false) => "break", (false, true) => "break $0;", @@ -423,9 +424,10 @@ pub(crate) fn complete_expr_path( } if let Some(ret_ty) = innermost_ret_ty { + let semicolon = in_block_expr && ctx.config.add_semicolon_to_jumps; add_keyword( "return", - match (ret_ty.is_unit(), in_block_expr) { + match (ret_ty.is_unit(), semicolon) { (true, true) => { cov_mark::hit!(return_unit_block); "return;" diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs index 5623257a2792..dd748edb438c 100644 --- a/crates/ide-completion/src/config.rs +++ b/crates/ide-completion/src/config.rs @@ -24,6 +24,7 @@ pub struct CompletionConfig<'a> { pub term_search_fuel: u64, pub full_function_signatures: bool, pub callable: Option, + pub add_semicolon_to_jumps: bool, pub add_semicolon_to_unit: bool, pub snippet_cap: Option, pub insert_use: InsertUseConfig, diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs index cb1adfcfb65e..5e1380b8f4dd 100644 --- a/crates/ide-completion/src/tests.rs +++ b/crates/ide-completion/src/tests.rs @@ -71,6 +71,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig<'_> = CompletionConfig { term_search_fuel: 200, full_function_signatures: false, callable: Some(CallableSnippets::FillArguments), + add_semicolon_to_jumps: true, add_semicolon_to_unit: true, snippet_cap: SnippetCap::new(true), insert_use: InsertUseConfig { diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index 78f003dd210b..256e72d19c64 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -5,8 +5,8 @@ use crate::{ CompletionConfig, config::AutoImportExclusionType, tests::{ - BASE_ITEMS_FIXTURE, TEST_CONFIG, check, check_edit, check_with_base_items, - completion_list_with_config, + BASE_ITEMS_FIXTURE, TEST_CONFIG, check, check_edit, check_edit_with_config, + check_with_base_items, completion_list_with_config, }, }; @@ -1077,6 +1077,12 @@ fn return_value_block() { r#"fn f() -> i32 { if true { $0 } }"#, r#"fn f() -> i32 { if true { return $0; } }"#, ); + check_edit_with_config( + CompletionConfig { add_semicolon_to_jumps: false, ..TEST_CONFIG }, + "return", + r#"fn f() -> i32 { if true { $0 } }"#, + r#"fn f() -> i32 { if true { return $0 } }"#, + ); } #[test] @@ -1093,6 +1099,12 @@ fn return_value_no_block() { fn break_unit_block() { check_edit("break", r#"fn f() { loop { break; $0 } }"#, r#"fn f() { loop { break; break; } }"#); check_edit("break", r#"fn f() { loop { $0 } }"#, r#"fn f() { loop { break; } }"#); + check_edit_with_config( + CompletionConfig { add_semicolon_to_jumps: false, ..TEST_CONFIG }, + "break", + r#"fn f() { loop { $0 } }"#, + r#"fn f() { loop { break } }"#, + ); } #[test] diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 007725be7406..48b6f2286253 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -592,6 +592,9 @@ config_data! { /// Term search fuel in "units of work" for assists (Defaults to 1800). assist_termSearch_fuel: usize = 1800, + /// Automatically add a semicolon when completing break, continue and return. + completion_addSemicolonToJumps: bool = true, + /// Automatically add a semicolon when completing unit-returning functions. /// /// In `match` arms it completes a comma instead. @@ -1759,6 +1762,7 @@ impl Config { CallableCompletionDef::AddParentheses => Some(CallableSnippets::AddParentheses), CallableCompletionDef::None => None, }, + add_semicolon_to_jumps: *self.completion_addSemicolonToJumps(source_root), add_semicolon_to_unit: *self.completion_addSemicolonToUnit(source_root), snippet_cap: SnippetCap::new(self.completion_snippet()), insert_use: self.insert_use_config(source_root), diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index 38ee9cbe7fc8..b95ba907c19f 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -180,6 +180,7 @@ fn integrated_completion_benchmark() { prefer_absolute: false, snippets: Vec::new(), limit: None, + add_semicolon_to_jumps: true, add_semicolon_to_unit: true, fields_to_resolve: CompletionFieldsToResolve::empty(), exclude_flyimport: vec![], @@ -235,6 +236,7 @@ fn integrated_completion_benchmark() { prefer_absolute: false, snippets: Vec::new(), limit: None, + add_semicolon_to_jumps: true, add_semicolon_to_unit: true, fields_to_resolve: CompletionFieldsToResolve::empty(), exclude_flyimport: vec![], @@ -288,6 +290,7 @@ fn integrated_completion_benchmark() { prefer_absolute: false, snippets: Vec::new(), limit: None, + add_semicolon_to_jumps: true, add_semicolon_to_unit: true, fields_to_resolve: CompletionFieldsToResolve::empty(), exclude_flyimport: vec![], diff --git a/docs/book/src/configuration_generated.md b/docs/book/src/configuration_generated.md index 1f5c672233ae..72a782ef3d8b 100644 --- a/docs/book/src/configuration_generated.md +++ b/docs/book/src/configuration_generated.md @@ -359,6 +359,13 @@ If false, `-p ` will be passed instead if applicable. In case it is not check will be performed. +## rust-analyzer.completion.addSemicolonToJumps {#completion.addSemicolonToJumps} + +Default: `true` + +Automatically add a semicolon when completing break, continue and return. + + ## rust-analyzer.completion.addSemicolonToUnit {#completion.addSemicolonToUnit} Default: `true` diff --git a/editors/code/package.json b/editors/code/package.json index 98fe6a558b80..551959aa0527 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1253,6 +1253,16 @@ } } }, + { + "title": "Completion", + "properties": { + "rust-analyzer.completion.addSemicolonToJumps": { + "markdownDescription": "Automatically add a semicolon when completing break, continue and return.", + "default": true, + "type": "boolean" + } + } + }, { "title": "Completion", "properties": {