Split draft

This commit is contained in:
Kirill Bulatov 2020-03-31 23:39:46 +03:00
parent bc71631e75
commit d35b943520
3 changed files with 85 additions and 59 deletions

View file

@ -32,6 +32,12 @@ use crate::{
pub use crate::completion::completion_item::{
CompletionItem, CompletionItemKind, InsertTextFormat,
};
use either::Either;
use hir::{StructField, Type};
use ra_syntax::{
ast::{self, NameOwner},
SmolStr,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CompletionConfig {
@ -98,3 +104,57 @@ pub(crate) fn completions(
Some(acc)
}
pub(crate) fn get_missing_fields(
ctx: &CompletionContext,
record: Either<&ast::RecordLit, &ast::RecordPat>,
) -> Option<Vec<(StructField, Type)>> {
let (ty, variant) = match record {
Either::Left(record_lit) => (
ctx.sema.type_of_expr(&record_lit.clone().into())?,
ctx.sema.resolve_record_literal(record_lit)?,
),
Either::Right(record_pat) => (
ctx.sema.type_of_pat(&record_pat.clone().into())?,
ctx.sema.resolve_record_pattern(record_pat)?,
),
};
let already_present_names = get_already_present_names(record);
Some(
ty.variant_fields(ctx.db, variant)
.into_iter()
.filter(|(field, _)| {
!already_present_names.contains(&SmolStr::from(field.name(ctx.db).to_string()))
})
.collect(),
)
}
fn get_already_present_names(record: Either<&ast::RecordLit, &ast::RecordPat>) -> Vec<SmolStr> {
// TODO kb have a single match
match record {
Either::Left(record_lit) => record_lit
.record_field_list()
.map(|field_list| field_list.fields())
.map(|fields| {
fields
.into_iter()
.filter_map(|field| field.name_ref())
.map(|name_ref| name_ref.text().clone())
.collect()
})
.unwrap_or_default(),
Either::Right(record_pat) => record_pat
.record_field_pat_list()
.map(|pat_list| pat_list.bind_pats())
.map(|bind_pats| {
bind_pats
.into_iter()
.filter_map(|pat| pat.name())
.map(|name| name.text().clone())
.collect()
})
.unwrap_or_default(),
}
}

View file

@ -1,36 +1,19 @@
//! FIXME: write short doc here
use super::get_missing_fields;
use crate::completion::{CompletionContext, Completions};
use ra_syntax::SmolStr;
use either::Either;
/// Complete fields in fields literals.
pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionContext) {
let (ty, variant) = match ctx.record_lit_syntax.as_ref().and_then(|it| {
Some((ctx.sema.type_of_expr(&it.clone().into())?, ctx.sema.resolve_record_literal(it)?))
}) {
Some(it) => it,
_ => return,
};
let already_present_names: Vec<SmolStr> = ctx
.record_lit_syntax
.as_ref()
.and_then(|record_literal| record_literal.record_field_list())
.map(|field_list| field_list.fields())
.map(|fields| {
fields
.into_iter()
.filter_map(|field| field.name_ref())
.map(|name_ref| name_ref.text().clone())
.collect()
})
.unwrap_or_default();
for (field, field_ty) in ty.variant_fields(ctx.db, variant) {
if !already_present_names.contains(&SmolStr::from(field.name(ctx.db).to_string())) {
acc.add_field(ctx, field, &field_ty);
}
pub(super) fn complete_record_literal(
acc: &mut Completions,
ctx: &CompletionContext,
) -> Option<()> {
let record_lit = ctx.record_lit_syntax.as_ref()?;
for (field, field_ty) in get_missing_fields(ctx, Either::Left(record_lit))? {
acc.add_field(ctx, field, &field_ty);
}
Some(())
}
#[cfg(test)]

View file

@ -1,35 +1,18 @@
//! FIXME: write short doc here
use super::get_missing_fields;
use crate::completion::{CompletionContext, Completions};
use ra_syntax::{ast::NameOwner, SmolStr};
use either::Either;
pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionContext) {
let (ty, variant) = match ctx.record_lit_pat.as_ref().and_then(|it| {
Some((ctx.sema.type_of_pat(&it.clone().into())?, ctx.sema.resolve_record_pattern(it)?))
}) {
Some(it) => it,
_ => return,
};
let already_present_names: Vec<SmolStr> = ctx
.record_lit_pat
.as_ref()
.and_then(|record_pat| record_pat.record_field_pat_list())
.map(|pat_list| pat_list.bind_pats())
.map(|bind_pats| {
bind_pats
.into_iter()
.filter_map(|pat| pat.name())
.map(|name| name.text().clone())
.collect()
})
.unwrap_or_default();
for (field, field_ty) in ty.variant_fields(ctx.db, variant) {
if !already_present_names.contains(&SmolStr::from(field.name(ctx.db).to_string())) {
acc.add_field(ctx, field, &field_ty);
}
pub(super) fn complete_record_pattern(
acc: &mut Completions,
ctx: &CompletionContext,
) -> Option<()> {
let record_pat = ctx.record_lit_pat.as_ref()?;
for (field, field_ty) in get_missing_fields(ctx, Either::Right(record_pat))? {
acc.add_field(ctx, field, &field_ty);
}
Some(())
}
#[cfg(test)]
@ -151,7 +134,7 @@ mod tests {
bar: 3,
baz: 4,
};
if let S { foo1, foo2, <|> } = s {}
if let S { foo1, foo2: a, <|> } = s {}
}
",
);
@ -159,16 +142,16 @@ mod tests {
[
CompletionItem {
label: "bar",
source_range: [369; 369),
delete: [369; 369),
source_range: [372; 372),
delete: [372; 372),
insert: "bar",
kind: Field,
detail: "u32",
},
CompletionItem {
label: "baz",
source_range: [369; 369),
delete: [369; 369),
source_range: [372; 372),
delete: [372; 372),
insert: "baz",
kind: Field,
detail: "u32",