mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-01 20:31:59 +00:00
Merge pull request #20015 from Veykril/push-wsxzsuurqwwr
Some checks are pending
metrics / build_metrics (push) Waiting to run
metrics / other_metrics (diesel-1.4.8) (push) Blocked by required conditions
metrics / other_metrics (hyper-0.14.18) (push) Blocked by required conditions
metrics / other_metrics (ripgrep-13.0.0) (push) Blocked by required conditions
metrics / other_metrics (self) (push) Blocked by required conditions
metrics / other_metrics (webrender-2022) (push) Blocked by required conditions
metrics / generate_final_metrics (push) Blocked by required conditions
rustdoc / rustdoc (push) Waiting to run
Some checks are pending
metrics / build_metrics (push) Waiting to run
metrics / other_metrics (diesel-1.4.8) (push) Blocked by required conditions
metrics / other_metrics (hyper-0.14.18) (push) Blocked by required conditions
metrics / other_metrics (ripgrep-13.0.0) (push) Blocked by required conditions
metrics / other_metrics (self) (push) Blocked by required conditions
metrics / other_metrics (webrender-2022) (push) Blocked by required conditions
metrics / generate_final_metrics (push) Blocked by required conditions
rustdoc / rustdoc (push) Waiting to run
feat: Insert required parentheses when typing `+` in dyn trait type
This commit is contained in:
commit
2c25e436c7
6 changed files with 92 additions and 8 deletions
|
|
@ -409,7 +409,7 @@ impl Analysis {
|
||||||
self.with_db(|db| typing::on_enter(db, position))
|
self.with_db(|db| typing::on_enter(db, position))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const SUPPORTED_TRIGGER_CHARS: &'static str = typing::TRIGGER_CHARS;
|
pub const SUPPORTED_TRIGGER_CHARS: &[char] = typing::TRIGGER_CHARS;
|
||||||
|
|
||||||
/// Returns an edit which should be applied after a character was typed.
|
/// Returns an edit which should be applied after a character was typed.
|
||||||
///
|
///
|
||||||
|
|
@ -421,7 +421,7 @@ impl Analysis {
|
||||||
char_typed: char,
|
char_typed: char,
|
||||||
) -> Cancellable<Option<SourceChange>> {
|
) -> Cancellable<Option<SourceChange>> {
|
||||||
// Fast path to not even parse the file.
|
// Fast path to not even parse the file.
|
||||||
if !typing::TRIGGER_CHARS.contains(char_typed) {
|
if !typing::TRIGGER_CHARS.contains(&char_typed) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
mod on_enter;
|
mod on_enter;
|
||||||
|
|
||||||
|
use either::Either;
|
||||||
use hir::EditionedFileId;
|
use hir::EditionedFileId;
|
||||||
use ide_db::{FilePosition, RootDatabase, base_db::RootQueryDb};
|
use ide_db::{FilePosition, RootDatabase, base_db::RootQueryDb};
|
||||||
use span::Edition;
|
use span::Edition;
|
||||||
|
|
@ -33,7 +34,7 @@ use crate::SourceChange;
|
||||||
pub(crate) use on_enter::on_enter;
|
pub(crate) use on_enter::on_enter;
|
||||||
|
|
||||||
// Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
|
// Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
|
||||||
pub(crate) const TRIGGER_CHARS: &str = ".=<>{(|";
|
pub(crate) const TRIGGER_CHARS: &[char] = &['.', '=', '<', '>', '{', '(', '|', '+'];
|
||||||
|
|
||||||
struct ExtendedTextEdit {
|
struct ExtendedTextEdit {
|
||||||
edit: TextEdit,
|
edit: TextEdit,
|
||||||
|
|
@ -66,7 +67,7 @@ pub(crate) fn on_char_typed(
|
||||||
position: FilePosition,
|
position: FilePosition,
|
||||||
char_typed: char,
|
char_typed: char,
|
||||||
) -> Option<SourceChange> {
|
) -> Option<SourceChange> {
|
||||||
if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
|
if !TRIGGER_CHARS.contains(&char_typed) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
// FIXME: We need to figure out the edition of the file here, but that means hitting the
|
// FIXME: We need to figure out the edition of the file here, but that means hitting the
|
||||||
|
|
@ -101,6 +102,7 @@ fn on_char_typed_(
|
||||||
'>' => on_right_angle_typed(&file.tree(), offset),
|
'>' => on_right_angle_typed(&file.tree(), offset),
|
||||||
'{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition),
|
'{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition),
|
||||||
'|' => on_pipe_typed(&file.tree(), offset),
|
'|' => on_pipe_typed(&file.tree(), offset),
|
||||||
|
'+' => on_plus_typed(&file.tree(), offset),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
.map(conv)
|
.map(conv)
|
||||||
|
|
@ -402,6 +404,28 @@ fn on_pipe_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
|
||||||
Some(TextEdit::insert(after_lpipe, "|".to_owned()))
|
Some(TextEdit::insert(after_lpipe, "|".to_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_plus_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
|
||||||
|
let plus_token = file.syntax().token_at_offset(offset).right_biased()?;
|
||||||
|
if plus_token.kind() != SyntaxKind::PLUS {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut ancestors = plus_token.parent_ancestors();
|
||||||
|
ancestors.next().and_then(ast::TypeBoundList::cast)?;
|
||||||
|
let trait_type =
|
||||||
|
ancestors.next().and_then(<Either<ast::DynTraitType, ast::ImplTraitType>>::cast)?;
|
||||||
|
let kind = ancestors.next()?.kind();
|
||||||
|
|
||||||
|
if ast::RefType::can_cast(kind) || ast::PtrType::can_cast(kind) || ast::RetType::can_cast(kind)
|
||||||
|
{
|
||||||
|
let mut builder = TextEdit::builder();
|
||||||
|
builder.insert(trait_type.syntax().text_range().start(), "(".to_owned());
|
||||||
|
builder.insert(trait_type.syntax().text_range().end(), ")".to_owned());
|
||||||
|
Some(builder.finish())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }`
|
/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }`
|
||||||
fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
|
fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
|
||||||
let file_text = file.syntax().text();
|
let file_text = file.syntax().text();
|
||||||
|
|
@ -1594,6 +1618,66 @@ fn foo() {
|
||||||
fn foo() {
|
fn foo() {
|
||||||
let $0
|
let $0
|
||||||
}
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn adds_parentheses_around_trait_object_in_ref_type() {
|
||||||
|
type_char(
|
||||||
|
'+',
|
||||||
|
r#"
|
||||||
|
fn foo(x: &dyn A$0) {}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn foo(x: &(dyn A+)) {}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
type_char(
|
||||||
|
'+',
|
||||||
|
r#"
|
||||||
|
fn foo(x: &'static dyn A$0B) {}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn foo(x: &'static (dyn A+B)) {}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
type_char_noop(
|
||||||
|
'+',
|
||||||
|
r#"
|
||||||
|
fn foo(x: &(dyn A$0)) {}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
type_char_noop(
|
||||||
|
'+',
|
||||||
|
r#"
|
||||||
|
fn foo(x: Box<dyn A$0>) {}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn adds_parentheses_around_trait_object_in_ptr_type() {
|
||||||
|
type_char(
|
||||||
|
'+',
|
||||||
|
r#"
|
||||||
|
fn foo(x: *const dyn A$0) {}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn foo(x: *const (dyn A+)) {}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn adds_parentheses_around_trait_object_in_return_type() {
|
||||||
|
type_char(
|
||||||
|
'+',
|
||||||
|
r#"
|
||||||
|
fn foo(x: fn() -> dyn A$0) {}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn foo(x: fn() -> (dyn A+)) {}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -344,7 +344,7 @@ config_data! {
|
||||||
/// - typing `{` in a use item adds a closing `}` in the right place
|
/// - typing `{` in a use item adds a closing `}` in the right place
|
||||||
/// - typing `>` to complete a return type `->` will insert a whitespace after it
|
/// - typing `>` to complete a return type `->` will insert a whitespace after it
|
||||||
/// - typing `<` in a path or type position inserts a closing `>` after the path or type.
|
/// - typing `<` in a path or type position inserts a closing `>` after the path or type.
|
||||||
typing_triggerChars: Option<String> = Some("=.".to_owned()),
|
typing_triggerChars: Option<String> = Some("=.+".to_owned()),
|
||||||
|
|
||||||
|
|
||||||
/// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`].
|
/// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`].
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
|
||||||
_ => Some(OneOf::Left(false)),
|
_ => Some(OneOf::Left(false)),
|
||||||
},
|
},
|
||||||
document_on_type_formatting_provider: Some({
|
document_on_type_formatting_provider: Some({
|
||||||
let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.chars();
|
let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.iter();
|
||||||
DocumentOnTypeFormattingOptions {
|
DocumentOnTypeFormattingOptions {
|
||||||
first_trigger_character: chars.next().unwrap().to_string(),
|
first_trigger_character: chars.next().unwrap().to_string(),
|
||||||
more_trigger_character: Some(chars.map(|c| c.to_string()).collect()),
|
more_trigger_character: Some(chars.map(|c| c.to_string()).collect()),
|
||||||
|
|
|
||||||
|
|
@ -1410,7 +1410,7 @@ Show documentation.
|
||||||
|
|
||||||
## rust-analyzer.typing.triggerChars {#typing.triggerChars}
|
## rust-analyzer.typing.triggerChars {#typing.triggerChars}
|
||||||
|
|
||||||
Default: `"=."`
|
Default: `"=.+"`
|
||||||
|
|
||||||
Specify the characters allowed to invoke special on typing triggers.
|
Specify the characters allowed to invoke special on typing triggers.
|
||||||
- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression
|
- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression
|
||||||
|
|
|
||||||
|
|
@ -2836,7 +2836,7 @@
|
||||||
"properties": {
|
"properties": {
|
||||||
"rust-analyzer.typing.triggerChars": {
|
"rust-analyzer.typing.triggerChars": {
|
||||||
"markdownDescription": "Specify the characters allowed to invoke special on typing triggers.\n- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression\n- typing `=` between two expressions adds `;` when in statement position\n- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position\n- typing `.` in a chain method call auto-indents\n- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression\n- typing `{` in a use item adds a closing `}` in the right place\n- typing `>` to complete a return type `->` will insert a whitespace after it\n- typing `<` in a path or type position inserts a closing `>` after the path or type.",
|
"markdownDescription": "Specify the characters allowed to invoke special on typing triggers.\n- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression\n- typing `=` between two expressions adds `;` when in statement position\n- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position\n- typing `.` in a chain method call auto-indents\n- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression\n- typing `{` in a use item adds a closing `}` in the right place\n- typing `>` to complete a return type `->` will insert a whitespace after it\n- typing `<` in a path or type position inserts a closing `>` after the path or type.",
|
||||||
"default": "=.",
|
"default": "=.+",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
"string"
|
"string"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue