//! module, and we use to statically check that we only produce snippet
//! assists if we are allowed to.
-use hir::PrefixKind;
-use ide_db::helpers::insert_use::MergeBehavior;
+use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap};
use crate::AssistKind;
pub insert_use: InsertUseConfig,
}
-impl AssistConfig {
- pub fn allow_snippets(&mut self, yes: bool) {
- self.snippet_cap = if yes { Some(SnippetCap { _private: () }) } else { None }
- }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct SnippetCap {
- _private: (),
-}
-
-impl Default for AssistConfig {
- fn default() -> Self {
- AssistConfig {
- snippet_cap: Some(SnippetCap { _private: () }),
- allowed: None,
- insert_use: InsertUseConfig::default(),
- }
- }
-}
-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct InsertUseConfig {
pub merge: Option<MergeBehavior>,
- pub prefix_kind: PrefixKind,
-}
-
-impl Default for InsertUseConfig {
- fn default() -> Self {
- InsertUseConfig { merge: Some(MergeBehavior::Full), prefix_kind: PrefixKind::Plain }
- }
+ pub prefix_kind: hir::PrefixKind,
}
use algo::find_covering_element;
use hir::Semantics;
-use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange};
+use ide_db::{
+ base_db::{AnchoredPathBuf, FileId, FileRange},
+ helpers::SnippetCap,
+};
use ide_db::{
label::Label,
source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
};
use text_edit::{TextEdit, TextEditBuilder};
-use crate::{
- assist_config::{AssistConfig, SnippetCap},
- Assist, AssistId, AssistKind, GroupLabel,
-};
+use crate::{assist_config::AssistConfig, Assist, AssistId, AssistKind, GroupLabel};
/// `AssistContext` allows to apply an assist or check if it could be applied.
///
use hir::HirDisplay;
-use ide_db::base_db::FileId;
+use ide_db::{base_db::FileId, helpers::SnippetCap};
use rustc_hash::{FxHashMap, FxHashSet};
use syntax::{
ast::{
};
use crate::{
- assist_config::SnippetCap,
utils::{render_snippet, Cursor},
AssistContext, AssistId, AssistKind, Assists,
};
pub(crate) use crate::assist_context::{AssistContext, Assists};
-pub use assist_config::AssistConfig;
+pub use assist_config::{AssistConfig, InsertUseConfig};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AssistKind {
mod generated;
use hir::Semantics;
-use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
-use ide_db::source_change::FileSystemEdit;
-use ide_db::RootDatabase;
+use ide_db::{
+ base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt},
+ helpers::{insert_use::MergeBehavior, SnippetCap},
+ source_change::FileSystemEdit,
+ RootDatabase,
+};
use syntax::TextRange;
use test_utils::{assert_eq_text, extract_offset, extract_range};
-use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists};
+use crate::{
+ handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists, InsertUseConfig,
+};
use stdx::{format_to, trim_indent};
+pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
+ snippet_cap: SnippetCap::new(true),
+ allowed: None,
+ insert_use: InsertUseConfig {
+ merge: Some(MergeBehavior::Full),
+ prefix_kind: hir::PrefixKind::Plain,
+ },
+};
+
pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
RootDatabase::with_single_file(text)
}
let before = db.file_text(file_id).to_string();
let frange = FileRange { file_id, range: selection.into() };
- let assist = Assist::get(&db, &AssistConfig::default(), true, frange)
+ let assist = Assist::get(&db, &TEST_CONFIG, true, frange)
.into_iter()
.find(|assist| assist.id.0 == assist_id)
.unwrap_or_else(|| {
panic!(
"\n\nAssist is not applicable: {}\nAvailable assists: {}",
assist_id,
- Assist::get(&db, &AssistConfig::default(), false, frange)
+ Assist::get(&db, &TEST_CONFIG, false, frange)
.into_iter()
.map(|assist| assist.id.0)
.collect::<Vec<_>>()
let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };
let sema = Semantics::new(&db);
- let config = AssistConfig::default();
+ let config = TEST_CONFIG;
let ctx = AssistContext::new(sema, &config, frange);
let mut acc = Assists::new(&ctx, true);
handler(&mut acc, &ctx);
let (before_cursor_pos, before) = extract_offset(before);
let (db, file_id) = with_single_file(&before);
let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) };
- let assists = Assist::get(&db, &AssistConfig::default(), false, frange);
+ let assists = Assist::get(&db, &TEST_CONFIG, false, frange);
let mut assists = assists.iter();
assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)");
let (range, before) = extract_range(before);
let (db, file_id) = with_single_file(&before);
let frange = FileRange { file_id, range };
- let assists = Assist::get(&db, &AssistConfig::default(), false, frange);
+ let assists = Assist::get(&db, &TEST_CONFIG, false, frange);
let mut assists = assists.iter();
assert_eq!(assists.next().expect("expected assist").label, "Extract into variable");
let frange = FileRange { file_id, range };
{
- let mut cfg = AssistConfig::default();
+ let mut cfg = TEST_CONFIG;
cfg.allowed = Some(vec![AssistKind::Refactor]);
let assists = Assist::get(&db, &cfg, false, frange);
}
{
- let mut cfg = AssistConfig::default();
+ let mut cfg = TEST_CONFIG;
cfg.allowed = Some(vec![AssistKind::RefactorExtract]);
let assists = Assist::get(&db, &cfg, false, frange);
assert_eq!(assists.len(), 1);
}
{
- let mut cfg = AssistConfig::default();
+ let mut cfg = TEST_CONFIG;
cfg.allowed = Some(vec![AssistKind::QuickFix]);
let assists = Assist::get(&db, &cfg, false, frange);
assert!(assists.is_empty(), "All asserts but quickfixes should be filtered out");
use std::ops;
use hir::HasSource;
-use ide_db::RootDatabase;
+use ide_db::{helpers::SnippetCap, RootDatabase};
use itertools::Itertools;
use syntax::{
ast::edit::AstNodeEdit,
SyntaxNode, TextSize, T,
};
-use crate::{
- assist_config::SnippetCap,
- ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
-};
+use crate::ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams};
pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr {
extract_trivial_expression(&block)
mod format_like;
-use ide_db::ty_filter::TryEnum;
+use ide_db::{helpers::SnippetCap, ty_filter::TryEnum};
use syntax::{
ast::{self, AstNode, AstToken},
SyntaxKind::{BLOCK_EXPR, EXPR_STMT},
};
use text_edit::TextEdit;
-use self::format_like::add_format_like_completions;
use crate::{
- config::SnippetCap,
+ completions::postfix::format_like::add_format_like_completions,
context::CompletionContext,
item::{Builder, CompletionKind},
CompletionItem, CompletionItemKind, Completions,
// + `logw` -> `log::warn!(...)`
// + `loge` -> `log::error!(...)`
-use crate::{
- completions::postfix::postfix_snippet, config::SnippetCap, context::CompletionContext,
- Completions,
-};
+use ide_db::helpers::SnippetCap;
use syntax::ast::{self, AstToken};
+use crate::{completions::postfix::postfix_snippet, context::CompletionContext, Completions};
+
/// Mapping ("postfix completion item" => "macro to use")
static KINDS: &[(&str, &str)] = &[
("format", "format!"),
//! This file provides snippet completions, like `pd` => `eprintln!(...)`.
+use ide_db::helpers::SnippetCap;
+
use crate::{
- config::SnippetCap, item::Builder, CompletionContext, CompletionItem, CompletionItemKind,
- CompletionKind, Completions,
+ item::Builder, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
+ Completions,
};
fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
use test_utils::mark;
use crate::{
- test_utils::{check_edit, check_edit_with_config, completion_list_with_config},
+ test_utils::{
+ check_edit, check_edit_with_config, completion_list_with_config, TEST_CONFIG,
+ },
CompletionConfig, CompletionKind,
};
fn check(ra_fixture: &str, expect: Expect) {
- check_with_config(CompletionConfig::default(), ra_fixture, expect);
+ check_with_config(TEST_CONFIG, ra_fixture, expect);
}
fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) {
expect.assert_eq(&actual)
}
- fn fuzzy_completion_config() -> CompletionConfig {
- CompletionConfig::default()
- }
-
#[test]
fn self_fulfilling_completion() {
mark::check!(self_fulfilling_completion);
#[test]
fn function_fuzzy_completion() {
check_edit_with_config(
- fuzzy_completion_config(),
+ TEST_CONFIG,
"stdin",
r#"
//- /lib.rs crate:dep
#[test]
fn macro_fuzzy_completion() {
check_edit_with_config(
- fuzzy_completion_config(),
+ TEST_CONFIG,
"macro_with_curlies!",
r#"
//- /lib.rs crate:dep
#[test]
fn struct_fuzzy_completion() {
check_edit_with_config(
- fuzzy_completion_config(),
+ TEST_CONFIG,
"ThirdStruct",
r#"
//- /lib.rs crate:dep
fn fuzzy_completions_come_in_specific_order() {
mark::check!(certain_fuzzy_order_test);
check_with_config(
- fuzzy_completion_config(),
+ TEST_CONFIG,
r#"
//- /lib.rs crate:dep
pub struct FirstStruct;
//! module, and we use to statically check that we only produce snippet
//! completions if we are allowed to.
-use ide_db::helpers::insert_use::MergeBehavior;
+use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CompletionConfig {
pub snippet_cap: Option<SnippetCap>,
pub merge: Option<MergeBehavior>,
}
-
-impl CompletionConfig {
- pub fn allow_snippets(&mut self, yes: bool) {
- self.snippet_cap = if yes { Some(SnippetCap { _private: () }) } else { None }
- }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct SnippetCap {
- _private: (),
-}
-
-impl Default for CompletionConfig {
- fn default() -> Self {
- CompletionConfig {
- enable_postfix_completions: true,
- enable_autoimport_completions: true,
- add_call_parenthesis: true,
- add_call_argument_snippets: true,
- snippet_cap: Some(SnippetCap { _private: () }),
- merge: Some(MergeBehavior::Full),
- }
- }
-}
use hir::{Documentation, ModPath, Mutability};
use ide_db::helpers::{
insert_use::{self, ImportScope, MergeBehavior},
- mod_path_to_ast,
+ mod_path_to_ast, SnippetCap,
};
use syntax::{algo, TextRange};
use text_edit::TextEdit;
-use crate::config::SnippetCap;
-
/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[cfg(test)]
mod tests {
- use crate::config::CompletionConfig;
- use crate::test_utils;
+ use crate::test_utils::{self, TEST_CONFIG};
struct DetailAndDocumentation<'a> {
detail: &'a str,
fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
let (db, position) = test_utils::position(ra_fixture);
- let config = CompletionConfig::default();
+ let config = TEST_CONFIG;
let completions: Vec<_> = crate::completions(&db, &config, position).unwrap().into();
for item in completions {
if item.detail() == Some(expected.detail) {
fn check_no_completion(ra_fixture: &str) {
let (db, position) = test_utils::position(ra_fixture);
- let config = CompletionConfig::default();
+ let config = TEST_CONFIG;
let completions: Option<Vec<String>> = crate::completions(&db, &config, position)
.and_then(|completions| {
mod builder_ext;
use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type};
-use ide_db::RootDatabase;
+use ide_db::{helpers::SnippetCap, RootDatabase};
use syntax::TextRange;
use test_utils::mark;
use crate::{
- config::SnippetCap, item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind,
- CompletionKind, CompletionScore,
+ item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
+ CompletionScore,
};
use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro};
use test_utils::mark;
use crate::{
- test_utils::{check_edit, do_completion, get_all_items},
- CompletionConfig, CompletionKind, CompletionScore,
+ test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG},
+ CompletionKind, CompletionScore,
};
fn check(ra_fixture: &str, expect: Expect) {
}
}
- let mut completions = get_all_items(CompletionConfig::default(), ra_fixture);
+ let mut completions = get_all_items(TEST_CONFIG, ra_fixture);
completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string()));
let actual = completions
.into_iter()
use test_utils::mark;
use crate::{
- test_utils::{check_edit, check_edit_with_config},
+ test_utils::{check_edit, check_edit_with_config, TEST_CONFIG},
CompletionConfig,
};
fn suppress_arg_snippets() {
mark::check!(suppress_arg_snippets);
check_edit_with_config(
- CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() },
+ CompletionConfig { add_call_argument_snippets: false, ..TEST_CONFIG },
"with_args",
r#"
fn with_args(x: i32, y: String) {}
//! Renderer for patterns.
use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind};
+use ide_db::helpers::SnippetCap;
use itertools::Itertools;
-use crate::{
- config::SnippetCap, item::CompletionKind, render::RenderContext, CompletionItem,
- CompletionItemKind,
-};
+use crate::{item::CompletionKind, render::RenderContext, CompletionItem, CompletionItemKind};
fn visible_fields(
ctx: &RenderContext<'_>,
//! Runs completion for testing purposes.
use hir::Semantics;
-use ide_db::base_db::{fixture::ChangeFixture, FileLoader, FilePosition};
-use ide_db::RootDatabase;
+use ide_db::{
+ base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
+ helpers::{insert_use::MergeBehavior, SnippetCap},
+ RootDatabase,
+};
use itertools::Itertools;
use stdx::{format_to, trim_indent};
use syntax::{AstNode, NodeOrToken, SyntaxElement};
use crate::{item::CompletionKind, CompletionConfig, CompletionItem};
+pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
+ enable_postfix_completions: true,
+ enable_autoimport_completions: true,
+ add_call_parenthesis: true,
+ add_call_argument_snippets: true,
+ snippet_cap: SnippetCap::new(true),
+ merge: Some(MergeBehavior::Full),
+};
+
/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
let change_fixture = ChangeFixture::parse(ra_fixture);
}
pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
- do_completion_with_config(CompletionConfig::default(), code, kind)
+ do_completion_with_config(TEST_CONFIG, code, kind)
}
pub(crate) fn do_completion_with_config(
}
pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String {
- completion_list_with_config(CompletionConfig::default(), code, kind)
+ completion_list_with_config(TEST_CONFIG, code, kind)
}
pub(crate) fn completion_list_with_config(
}
pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
- check_edit_with_config(CompletionConfig::default(), what, ra_fixture_before, ra_fixture_after)
+ check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after)
}
pub(crate) fn check_edit_with_config(
HighlightedRange,
},
};
-pub use assists::{Assist, AssistConfig, AssistId, AssistKind};
+pub use assists::{Assist, AssistConfig, AssistId, AssistKind, InsertUseConfig};
pub use completion::{
CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit,
InsertTextFormat,
//! A module with ide helpers for high-level ide features.
-use crate::RootDatabase;
+pub mod insert_use;
+
use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
use syntax::ast::{self, make};
-pub mod insert_use;
+use crate::RootDatabase;
/// Converts the mod path struct into its ast representation.
pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
Some(def)
}
}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct SnippetCap {
+ _private: (),
+}
+
+impl SnippetCap {
+ pub const fn new(allow_snippets: bool) -> Option<SnippetCap> {
+ if allow_snippets {
+ Some(SnippetCap { _private: () })
+ } else {
+ None
+ }
+ }
+}
use ide::{
Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol,
};
-use ide_db::base_db::{
- salsa::{Database, Durability},
- FileId,
+use ide_db::{
+ base_db::{
+ salsa::{Database, Durability},
+ FileId,
+ },
+ helpers::SnippetCap,
};
use vfs::AbsPathBuf;
let file_position = FilePosition { file_id, offset };
if is_completion {
- let options = CompletionConfig::default();
+ let options = CompletionConfig {
+ enable_postfix_completions: true,
+ enable_autoimport_completions: true,
+ add_call_parenthesis: true,
+ add_call_argument_snippets: true,
+ snippet_cap: SnippetCap::new(true),
+ merge: None,
+ };
let res = do_work(&mut host, file_id, |analysis| {
analysis.completions(&options, file_position)
});
use flycheck::FlycheckConfig;
use hir::PrefixKind;
-use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig};
-use ide_db::helpers::insert_use::MergeBehavior;
+use ide::{
+ AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig,
+ InsertUseConfig,
+};
+use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap};
use itertools::Itertools;
use lsp_types::{ClientCapabilities, MarkupKind};
use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest};
}
}
pub fn completion(&self) -> CompletionConfig {
- let mut res = CompletionConfig::default();
- res.enable_postfix_completions = self.data.completion_postfix_enable;
- res.enable_autoimport_completions =
- self.data.completion_autoimport_enable && completion_item_edit_resolve(&self.caps);
- res.add_call_parenthesis = self.data.completion_addCallParenthesis;
- res.add_call_argument_snippets = self.data.completion_addCallArgumentSnippets;
- res.merge = self.merge_behavior();
-
- res.allow_snippets(try_or!(
- self.caps
- .text_document
- .as_ref()?
- .completion
- .as_ref()?
- .completion_item
- .as_ref()?
- .snippet_support?,
- false
- ));
- res
+ CompletionConfig {
+ enable_postfix_completions: self.data.completion_postfix_enable,
+ enable_autoimport_completions: self.data.completion_autoimport_enable
+ && completion_item_edit_resolve(&self.caps),
+ add_call_parenthesis: self.data.completion_addCallParenthesis,
+ add_call_argument_snippets: self.data.completion_addCallArgumentSnippets,
+ merge: self.merge_behavior(),
+ snippet_cap: SnippetCap::new(try_or!(
+ self.caps
+ .text_document
+ .as_ref()?
+ .completion
+ .as_ref()?
+ .completion_item
+ .as_ref()?
+ .snippet_support?,
+ false
+ )),
+ }
}
pub fn assist(&self) -> AssistConfig {
- let mut res = AssistConfig::default();
- res.insert_use.merge = self.merge_behavior();
- res.insert_use.prefix_kind = match self.data.assist_importPrefix {
- ImportPrefixDef::Plain => PrefixKind::Plain,
- ImportPrefixDef::ByCrate => PrefixKind::ByCrate,
- ImportPrefixDef::BySelf => PrefixKind::BySelf,
- };
- res.allow_snippets(self.experimental("snippetTextEdit"));
- res
+ AssistConfig {
+ snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")),
+ allowed: None,
+ insert_use: InsertUseConfig {
+ merge: self.merge_behavior(),
+ prefix_kind: match self.data.assist_importPrefix {
+ ImportPrefixDef::Plain => PrefixKind::Plain,
+ ImportPrefixDef::ByCrate => PrefixKind::ByCrate,
+ ImportPrefixDef::BySelf => PrefixKind::BySelf,
+ },
+ },
+ }
}
pub fn call_info_full(&self) -> bool {
self.data.callInfo_full
#[cfg(test)]
mod tests {
use ide::Analysis;
+ use ide_db::helpers::SnippetCap;
use super::*;
let (analysis, file_id) = Analysis::from_single_file(text);
let completions: Vec<(String, Option<String>)> = analysis
.completions(
- &ide::CompletionConfig::default(),
+ &ide::CompletionConfig {
+ enable_postfix_completions: true,
+ enable_autoimport_completions: true,
+ add_call_parenthesis: true,
+ add_call_argument_snippets: true,
+ snippet_cap: SnippetCap::new(true),
+ merge: None,
+ },
ide_db::base_db::FilePosition { file_id, offset },
)
.unwrap()