rust/crates/ra_ide/src/completion/complete_keyword.rs

459 lines
12 KiB
Rust
Raw Normal View History

//! FIXME: write short doc here
2020-06-11 14:16:35 +02:00
use ra_syntax::ast;
2019-01-08 22:33:36 +03:00
use crate::completion::{
CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
};
2019-01-08 22:33:36 +03:00
pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
// complete keyword "crate" in use stmt
let source_range = ctx.source_range();
2019-01-08 22:33:36 +03:00
match (ctx.use_item_syntax.as_ref(), ctx.path_prefix.as_ref()) {
(Some(_), None) => {
CompletionItem::new(CompletionKind::Keyword, source_range, "crate::")
2019-01-08 22:33:36 +03:00
.kind(CompletionItemKind::Keyword)
.insert_text("crate::")
2019-01-08 22:33:36 +03:00
.add_to(acc);
CompletionItem::new(CompletionKind::Keyword, source_range, "self")
2019-01-08 22:33:36 +03:00
.kind(CompletionItemKind::Keyword)
.add_to(acc);
CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
2019-01-08 22:33:36 +03:00
.kind(CompletionItemKind::Keyword)
.insert_text("super::")
2019-01-08 22:33:36 +03:00
.add_to(acc);
}
(Some(_), Some(_)) => {
CompletionItem::new(CompletionKind::Keyword, source_range, "self")
2019-01-08 22:33:36 +03:00
.kind(CompletionItemKind::Keyword)
.add_to(acc);
CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
2019-01-08 22:33:36 +03:00
.kind(CompletionItemKind::Keyword)
.insert_text("super::")
2019-01-08 22:33:36 +03:00
.add_to(acc);
}
_ => {}
}
}
pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
2020-06-13 13:47:30 +02:00
add_keyword(ctx, acc, "where", "where ");
return;
}
if ctx.unsafe_is_prev {
2020-06-13 13:47:30 +02:00
if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
add_keyword(ctx, acc, "fn", "fn $0() {}")
}
if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
|| ctx.block_expr_parent
{
add_keyword(ctx, acc, "trait", "trait $0 {}");
add_keyword(ctx, acc, "impl", "impl $0 {}");
}
return;
}
2020-06-13 13:47:30 +02:00
if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
add_keyword(ctx, acc, "fn", "fn $0() {}");
}
if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
|| ctx.block_expr_parent
{
add_keyword(ctx, acc, "use", "use ");
add_keyword(ctx, acc, "impl", "impl $0 {}");
add_keyword(ctx, acc, "trait", "trait $0 {}");
}
if ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent {
add_keyword(ctx, acc, "enum", "enum $0 {}");
add_keyword(ctx, acc, "struct", "struct $0 {}");
add_keyword(ctx, acc, "union", "union $0 {}");
}
if ctx.block_expr_parent || ctx.is_match_arm {
add_keyword(ctx, acc, "match", "match $0 {}");
add_keyword(ctx, acc, "loop", "loop {$0}");
}
if ctx.block_expr_parent {
add_keyword(ctx, acc, "while", "while $0 {}");
}
if ctx.if_is_prev || ctx.block_expr_parent {
add_keyword(ctx, acc, "let", "let ");
}
if ctx.if_is_prev || ctx.block_expr_parent || ctx.is_match_arm {
add_keyword(ctx, acc, "if", "if ");
add_keyword(ctx, acc, "if let", "if let ");
}
if ctx.after_if {
add_keyword(ctx, acc, "else", "else {$0}");
add_keyword(ctx, acc, "else if", "else if $0 {}");
}
if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
|| ctx.block_expr_parent
{
add_keyword(ctx, acc, "mod", "mod $0 {}");
}
if ctx.bind_pat_parent || ctx.ref_pat_parent {
add_keyword(ctx, acc, "mut", "mut ");
}
if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
add_keyword(ctx, acc, "const", "const ");
add_keyword(ctx, acc, "type", "type ");
}
if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
|| ctx.block_expr_parent
{
add_keyword(ctx, acc, "static", "static ");
};
if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
|| ctx.block_expr_parent
{
add_keyword(ctx, acc, "extern", "extern ");
}
if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent || ctx.is_match_arm {
add_keyword(ctx, acc, "unsafe", "unsafe ");
}
if ctx.in_loop_body {
if ctx.can_be_stmt {
add_keyword(ctx, acc, "continue", "continue;");
add_keyword(ctx, acc, "break", "break;");
} else {
add_keyword(ctx, acc, "continue", "continue");
add_keyword(ctx, acc, "break", "break");
}
}
if ctx.has_item_list_or_source_file_parent && !ctx.has_trait_parent {
add_keyword(ctx, acc, "pub", "pub ")
}
2019-01-08 22:33:36 +03:00
2020-06-13 01:21:48 +02:00
if !ctx.is_trivial_path {
return;
}
2019-07-19 12:56:47 +03:00
let fn_def = match &ctx.function_syntax {
2019-01-08 22:33:36 +03:00
Some(it) => it,
None => return,
};
2019-07-19 12:56:47 +03:00
acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt));
2019-01-08 22:33:36 +03:00
}
2020-06-13 13:47:30 +02:00
fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
.kind(CompletionItemKind::Keyword);
match ctx.config.snippet_cap {
Some(cap) => res.insert_snippet(cap, snippet),
_ => res.insert_text(if snippet.contains('$') { kw } else { snippet }),
}
.build()
}
fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
acc.add(keyword(ctx, kw, snippet));
}
fn complete_return(
ctx: &CompletionContext,
fn_def: &ast::FnDef,
can_be_stmt: bool,
) -> Option<CompletionItem> {
2019-01-08 22:33:36 +03:00
let snip = match (can_be_stmt, fn_def.ret_type().is_some()) {
(true, true) => "return $0;",
(true, false) => "return;",
(false, true) => "return $0",
(false, false) => "return",
};
Some(keyword(ctx, "return", snip))
2019-01-08 22:33:36 +03:00
}
#[cfg(test)]
mod tests {
2020-06-13 13:57:18 +02:00
use crate::completion::{test_utils::completion_list, CompletionKind};
use insta::assert_snapshot;
2020-06-13 13:57:18 +02:00
fn get_keyword_completions(code: &str) -> String {
completion_list(code, CompletionKind::Keyword)
2020-06-12 08:49:12 +02:00
}
2019-01-08 22:33:36 +03:00
#[test]
fn test_keywords_in_use_stmt() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
2020-06-12 20:30:57 +02:00
get_keyword_completions(r"use <|>"),
2019-11-15 12:56:24 +03:00
@r###"
kw crate::
2020-06-13 13:57:18 +02:00
kw self
kw super::
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
2020-06-13 13:57:18 +02:00
assert_snapshot!(
2020-06-12 20:30:57 +02:00
get_keyword_completions(r"use a::<|>"),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw self
kw super::
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
2020-06-13 13:57:18 +02:00
assert_snapshot!(
2020-06-12 20:30:57 +02:00
get_keyword_completions(r"use a::{b, <|>}"),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw self
kw super::
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
}
#[test]
fn test_keywords_at_source_file_level() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"m<|>"),
@r###"
2020-06-13 13:57:18 +02:00
kw const
kw enum
kw extern
kw fn
kw impl
kw mod
kw pub
kw static
kw struct
kw trait
kw type
kw union
kw unsafe
kw use
"###
);
}
2019-01-08 22:33:36 +03:00
#[test]
fn test_keywords_in_function() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
2020-06-12 20:30:57 +02:00
get_keyword_completions(r"fn quux() { <|> }"),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw const
kw extern
kw fn
kw if
kw if let
kw impl
kw let
kw loop
kw match
kw mod
kw return
kw static
kw trait
kw type
kw unsafe
kw use
kw while
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
}
#[test]
fn test_keywords_inside_block() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"fn quux() { if true { <|> } }"),
@r###"
2020-06-13 13:57:18 +02:00
kw const
kw extern
kw fn
kw if
kw if let
kw impl
kw let
kw loop
kw match
kw mod
kw return
kw static
kw trait
kw type
kw unsafe
kw use
kw while
"###
);
}
#[test]
fn test_keywords_after_if() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(
r"
fn quux() {
if true {
()
} <|>
}
",
),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw const
kw else
kw else if
kw extern
kw fn
kw if
kw if let
kw impl
kw let
kw loop
kw match
kw mod
kw return
kw static
kw trait
kw type
kw unsafe
kw use
kw while
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
}
#[test]
fn test_keywords_in_match_arm() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(
r"
fn quux() -> i32 {
match () {
() => <|>
}
}
",
),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw if
kw if let
kw loop
kw match
kw return
kw unsafe
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
}
#[test]
fn test_keywords_in_trait_def() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"trait My { <|> }"),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw const
kw fn
kw type
kw unsafe
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
}
#[test]
fn test_keywords_in_impl_def() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"impl My { <|> }"),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw const
kw fn
kw pub
kw type
kw unsafe
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
}
#[test]
fn test_keywords_in_loop() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"fn my() { loop { <|> } }"),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw break
kw const
kw continue
kw extern
kw fn
kw if
kw if let
kw impl
kw let
kw loop
kw match
kw mod
kw return
kw static
kw trait
kw type
kw unsafe
kw use
kw while
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
}
#[test]
fn test_keywords_after_unsafe_in_item_list() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"unsafe <|>"),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw fn
kw impl
kw trait
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
}
#[test]
fn test_keywords_after_unsafe_in_block_expr() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"fn my_fn() { unsafe <|> }"),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw fn
kw impl
kw trait
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
}
#[test]
fn test_mut_in_ref_and_in_fn_parameters_list() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"fn my_fn(&<|>) {}"),
@r###"
2020-06-13 13:57:18 +02:00
kw mut
"###
);
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"fn my_fn(<|>) {}"),
@r###"
2020-06-13 13:57:18 +02:00
kw mut
"###
);
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"fn my_fn() { let &<|> }"),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw mut
2019-11-15 12:56:24 +03:00
"###
2019-01-08 22:33:36 +03:00
);
}
#[test]
fn test_where_keyword() {
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"trait A <|>"),
@r###"
2020-06-13 13:57:18 +02:00
kw where
"###
);
2020-06-13 13:57:18 +02:00
assert_snapshot!(
get_keyword_completions(r"impl A <|>"),
2019-11-15 12:56:24 +03:00
@r###"
2020-06-13 13:57:18 +02:00
kw where
2019-11-15 12:56:24 +03:00
"###
);
2019-01-08 22:33:36 +03:00
}
}