mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 21:43:37 +00:00
Add AssistConfig
This commit is contained in:
parent
131849f2ab
commit
c847c079fd
13 changed files with 129 additions and 39 deletions
27
crates/ra_assists/src/assist_config.rs
Normal file
27
crates/ra_assists/src/assist_config.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
//! Settings for tweaking assists.
|
||||||
|
//!
|
||||||
|
//! The fun thing here is `SnippetCap` -- this type can only be created in this
|
||||||
|
//! module, and we use to statically check that we only produce snippet
|
||||||
|
//! assists if we are allowed to.
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct AssistConfig {
|
||||||
|
pub snippet_cap: Option<SnippetCap>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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: () }) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,10 @@ use ra_syntax::{
|
||||||
};
|
};
|
||||||
use ra_text_edit::TextEditBuilder;
|
use ra_text_edit::TextEditBuilder;
|
||||||
|
|
||||||
use crate::{Assist, AssistId, GroupLabel, ResolvedAssist};
|
use crate::{
|
||||||
|
assist_config::{AssistConfig, SnippetCap},
|
||||||
|
Assist, AssistId, GroupLabel, ResolvedAssist,
|
||||||
|
};
|
||||||
|
|
||||||
/// `AssistContext` allows to apply an assist or check if it could be applied.
|
/// `AssistContext` allows to apply an assist or check if it could be applied.
|
||||||
///
|
///
|
||||||
|
@ -48,6 +51,7 @@ use crate::{Assist, AssistId, GroupLabel, ResolvedAssist};
|
||||||
/// moment, because the LSP API is pretty awkward in this place, and it's much
|
/// moment, because the LSP API is pretty awkward in this place, and it's much
|
||||||
/// easier to just compute the edit eagerly :-)
|
/// easier to just compute the edit eagerly :-)
|
||||||
pub(crate) struct AssistContext<'a> {
|
pub(crate) struct AssistContext<'a> {
|
||||||
|
pub(crate) config: &'a AssistConfig,
|
||||||
pub(crate) sema: Semantics<'a, RootDatabase>,
|
pub(crate) sema: Semantics<'a, RootDatabase>,
|
||||||
pub(crate) db: &'a RootDatabase,
|
pub(crate) db: &'a RootDatabase,
|
||||||
pub(crate) frange: FileRange,
|
pub(crate) frange: FileRange,
|
||||||
|
@ -55,10 +59,14 @@ pub(crate) struct AssistContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AssistContext<'a> {
|
impl<'a> AssistContext<'a> {
|
||||||
pub fn new(sema: Semantics<'a, RootDatabase>, frange: FileRange) -> AssistContext<'a> {
|
pub(crate) fn new(
|
||||||
|
sema: Semantics<'a, RootDatabase>,
|
||||||
|
config: &'a AssistConfig,
|
||||||
|
frange: FileRange,
|
||||||
|
) -> AssistContext<'a> {
|
||||||
let source_file = sema.parse(frange.file_id);
|
let source_file = sema.parse(frange.file_id);
|
||||||
let db = sema.db;
|
let db = sema.db;
|
||||||
AssistContext { sema, db, frange, source_file }
|
AssistContext { config, sema, db, frange, source_file }
|
||||||
}
|
}
|
||||||
|
|
||||||
// NB, this ignores active selection.
|
// NB, this ignores active selection.
|
||||||
|
@ -165,11 +173,17 @@ pub(crate) struct AssistBuilder {
|
||||||
edit: TextEditBuilder,
|
edit: TextEditBuilder,
|
||||||
cursor_position: Option<TextSize>,
|
cursor_position: Option<TextSize>,
|
||||||
file: FileId,
|
file: FileId,
|
||||||
|
is_snippet: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssistBuilder {
|
impl AssistBuilder {
|
||||||
pub(crate) fn new(file: FileId) -> AssistBuilder {
|
pub(crate) fn new(file: FileId) -> AssistBuilder {
|
||||||
AssistBuilder { edit: TextEditBuilder::default(), cursor_position: None, file }
|
AssistBuilder {
|
||||||
|
edit: TextEditBuilder::default(),
|
||||||
|
cursor_position: None,
|
||||||
|
file,
|
||||||
|
is_snippet: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove specified `range` of text.
|
/// Remove specified `range` of text.
|
||||||
|
@ -180,10 +194,30 @@ impl AssistBuilder {
|
||||||
pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) {
|
pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) {
|
||||||
self.edit.insert(offset, text.into())
|
self.edit.insert(offset, text.into())
|
||||||
}
|
}
|
||||||
|
/// Append specified `text` at the given `offset`
|
||||||
|
pub(crate) fn insert_snippet(
|
||||||
|
&mut self,
|
||||||
|
_cap: SnippetCap,
|
||||||
|
offset: TextSize,
|
||||||
|
text: impl Into<String>,
|
||||||
|
) {
|
||||||
|
self.is_snippet = true;
|
||||||
|
self.edit.insert(offset, text.into())
|
||||||
|
}
|
||||||
/// Replaces specified `range` of text with a given string.
|
/// Replaces specified `range` of text with a given string.
|
||||||
pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
|
pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
|
||||||
self.edit.replace(range, replace_with.into())
|
self.edit.replace(range, replace_with.into())
|
||||||
}
|
}
|
||||||
|
/// Append specified `text` at the given `offset`
|
||||||
|
pub(crate) fn replace_snippet(
|
||||||
|
&mut self,
|
||||||
|
_cap: SnippetCap,
|
||||||
|
range: TextRange,
|
||||||
|
replace_with: impl Into<String>,
|
||||||
|
) {
|
||||||
|
self.is_snippet = true;
|
||||||
|
self.edit.replace(range, replace_with.into())
|
||||||
|
}
|
||||||
pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
|
pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
|
||||||
algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
|
algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
|
||||||
}
|
}
|
||||||
|
@ -227,7 +261,12 @@ impl AssistBuilder {
|
||||||
if edit.is_empty() && self.cursor_position.is_none() {
|
if edit.is_empty() && self.cursor_position.is_none() {
|
||||||
panic!("Only call `add_assist` if the assist can be applied")
|
panic!("Only call `add_assist` if the assist can be applied")
|
||||||
}
|
}
|
||||||
|
let mut res =
|
||||||
SingleFileChange { label: change_label, edit, cursor_position: self.cursor_position }
|
SingleFileChange { label: change_label, edit, cursor_position: self.cursor_position }
|
||||||
.into_source_change(self.file)
|
.into_source_change(self.file);
|
||||||
|
if self.is_snippet {
|
||||||
|
res.is_snippet = true;
|
||||||
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ macro_rules! eprintln {
|
||||||
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
|
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod assist_config;
|
||||||
mod assist_context;
|
mod assist_context;
|
||||||
mod marks;
|
mod marks;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -24,6 +25,8 @@ use ra_syntax::TextRange;
|
||||||
|
|
||||||
pub(crate) use crate::assist_context::{AssistContext, Assists};
|
pub(crate) use crate::assist_context::{AssistContext, Assists};
|
||||||
|
|
||||||
|
pub use assist_config::AssistConfig;
|
||||||
|
|
||||||
/// Unique identifier of the assist, should not be shown to the user
|
/// Unique identifier of the assist, should not be shown to the user
|
||||||
/// directly.
|
/// directly.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -54,9 +57,9 @@ impl Assist {
|
||||||
///
|
///
|
||||||
/// Assists are returned in the "unresolved" state, that is only labels are
|
/// Assists are returned in the "unresolved" state, that is only labels are
|
||||||
/// returned, without actual edits.
|
/// returned, without actual edits.
|
||||||
pub fn unresolved(db: &RootDatabase, range: FileRange) -> Vec<Assist> {
|
pub fn unresolved(db: &RootDatabase, config: &AssistConfig, range: FileRange) -> Vec<Assist> {
|
||||||
let sema = Semantics::new(db);
|
let sema = Semantics::new(db);
|
||||||
let ctx = AssistContext::new(sema, range);
|
let ctx = AssistContext::new(sema, config, range);
|
||||||
let mut acc = Assists::new_unresolved(&ctx);
|
let mut acc = Assists::new_unresolved(&ctx);
|
||||||
handlers::all().iter().for_each(|handler| {
|
handlers::all().iter().for_each(|handler| {
|
||||||
handler(&mut acc, &ctx);
|
handler(&mut acc, &ctx);
|
||||||
|
@ -68,9 +71,13 @@ impl Assist {
|
||||||
///
|
///
|
||||||
/// Assists are returned in the "resolved" state, that is with edit fully
|
/// Assists are returned in the "resolved" state, that is with edit fully
|
||||||
/// computed.
|
/// computed.
|
||||||
pub fn resolved(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> {
|
pub fn resolved(
|
||||||
|
db: &RootDatabase,
|
||||||
|
config: &AssistConfig,
|
||||||
|
range: FileRange,
|
||||||
|
) -> Vec<ResolvedAssist> {
|
||||||
let sema = Semantics::new(db);
|
let sema = Semantics::new(db);
|
||||||
let ctx = AssistContext::new(sema, range);
|
let ctx = AssistContext::new(sema, config, range);
|
||||||
let mut acc = Assists::new_resolved(&ctx);
|
let mut acc = Assists::new_resolved(&ctx);
|
||||||
handlers::all().iter().for_each(|handler| {
|
handlers::all().iter().for_each(|handler| {
|
||||||
handler(&mut acc, &ctx);
|
handler(&mut acc, &ctx);
|
||||||
|
|
|
@ -11,7 +11,7 @@ use test_utils::{
|
||||||
RangeOrOffset,
|
RangeOrOffset,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{handlers::Handler, Assist, AssistContext, Assists};
|
use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists};
|
||||||
|
|
||||||
pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
|
pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
|
||||||
let (mut db, file_id) = RootDatabase::with_single_file(text);
|
let (mut db, file_id) = RootDatabase::with_single_file(text);
|
||||||
|
@ -41,14 +41,14 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
|
||||||
let (db, file_id) = crate::tests::with_single_file(&before);
|
let (db, file_id) = crate::tests::with_single_file(&before);
|
||||||
let frange = FileRange { file_id, range: selection.into() };
|
let frange = FileRange { file_id, range: selection.into() };
|
||||||
|
|
||||||
let mut assist = Assist::resolved(&db, frange)
|
let mut assist = Assist::resolved(&db, &AssistConfig::default(), frange)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find(|assist| assist.assist.id.0 == assist_id)
|
.find(|assist| assist.assist.id.0 == assist_id)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
panic!(
|
panic!(
|
||||||
"\n\nAssist is not applicable: {}\nAvailable assists: {}",
|
"\n\nAssist is not applicable: {}\nAvailable assists: {}",
|
||||||
assist_id,
|
assist_id,
|
||||||
Assist::resolved(&db, frange)
|
Assist::resolved(&db, &AssistConfig::default(), frange)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|assist| assist.assist.id.0)
|
.map(|assist| assist.assist.id.0)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
@ -90,7 +90,8 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult) {
|
||||||
let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };
|
let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };
|
||||||
|
|
||||||
let sema = Semantics::new(&db);
|
let sema = Semantics::new(&db);
|
||||||
let ctx = AssistContext::new(sema, frange);
|
let config = AssistConfig::default();
|
||||||
|
let ctx = AssistContext::new(sema, &config, frange);
|
||||||
let mut acc = Assists::new_resolved(&ctx);
|
let mut acc = Assists::new_resolved(&ctx);
|
||||||
handler(&mut acc, &ctx);
|
handler(&mut acc, &ctx);
|
||||||
let mut res = acc.finish_resolved();
|
let mut res = acc.finish_resolved();
|
||||||
|
@ -103,6 +104,7 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult) {
|
||||||
let mut actual = db.file_text(change.file_id).as_ref().to_owned();
|
let mut actual = db.file_text(change.file_id).as_ref().to_owned();
|
||||||
change.edit.apply(&mut actual);
|
change.edit.apply(&mut actual);
|
||||||
|
|
||||||
|
if !source_change.is_snippet {
|
||||||
match source_change.cursor_position {
|
match source_change.cursor_position {
|
||||||
None => {
|
None => {
|
||||||
if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset {
|
if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset {
|
||||||
|
@ -115,7 +117,7 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult) {
|
||||||
}
|
}
|
||||||
Some(off) => actual = add_cursor(&actual, off.offset),
|
Some(off) => actual = add_cursor(&actual, off.offset),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
assert_eq_text!(after, &actual);
|
assert_eq_text!(after, &actual);
|
||||||
}
|
}
|
||||||
(Some(assist), ExpectedResult::Target(target)) => {
|
(Some(assist), ExpectedResult::Target(target)) => {
|
||||||
|
@ -136,7 +138,7 @@ fn assist_order_field_struct() {
|
||||||
let (before_cursor_pos, before) = extract_offset(before);
|
let (before_cursor_pos, before) = extract_offset(before);
|
||||||
let (db, file_id) = with_single_file(&before);
|
let (db, file_id) = with_single_file(&before);
|
||||||
let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) };
|
let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) };
|
||||||
let assists = Assist::resolved(&db, frange);
|
let assists = Assist::resolved(&db, &AssistConfig::default(), frange);
|
||||||
let mut assists = assists.iter();
|
let mut assists = assists.iter();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -159,7 +161,7 @@ fn assist_order_if_expr() {
|
||||||
let (range, before) = extract_range(before);
|
let (range, before) = extract_range(before);
|
||||||
let (db, file_id) = with_single_file(&before);
|
let (db, file_id) = with_single_file(&before);
|
||||||
let frange = FileRange { file_id, range };
|
let frange = FileRange { file_id, range };
|
||||||
let assists = Assist::resolved(&db, frange);
|
let assists = Assist::resolved(&db, &AssistConfig::default(), frange);
|
||||||
let mut assists = assists.iter();
|
let mut assists = assists.iter();
|
||||||
|
|
||||||
assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable");
|
assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable");
|
||||||
|
|
|
@ -59,8 +59,8 @@ pub use crate::completion::{
|
||||||
/// with ordering of completions (currently this is done by the client).
|
/// with ordering of completions (currently this is done by the client).
|
||||||
pub(crate) fn completions(
|
pub(crate) fn completions(
|
||||||
db: &RootDatabase,
|
db: &RootDatabase,
|
||||||
position: FilePosition,
|
|
||||||
config: &CompletionConfig,
|
config: &CompletionConfig,
|
||||||
|
position: FilePosition,
|
||||||
) -> Option<Completions> {
|
) -> Option<Completions> {
|
||||||
let ctx = CompletionContext::new(db, position, config)?;
|
let ctx = CompletionContext::new(db, position, config)?;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub(crate) fn do_completion_with_options(
|
||||||
} else {
|
} else {
|
||||||
single_file_with_position(code)
|
single_file_with_position(code)
|
||||||
};
|
};
|
||||||
let completions = analysis.completions(position, options).unwrap().unwrap();
|
let completions = analysis.completions(options, position).unwrap().unwrap();
|
||||||
let completion_items: Vec<CompletionItem> = completions.into();
|
let completion_items: Vec<CompletionItem> = completions.into();
|
||||||
let mut kind_completions: Vec<CompletionItem> =
|
let mut kind_completions: Vec<CompletionItem> =
|
||||||
completion_items.into_iter().filter(|c| c.completion_kind == kind).collect();
|
completion_items.into_iter().filter(|c| c.completion_kind == kind).collect();
|
||||||
|
|
|
@ -629,6 +629,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
cursor_position: None,
|
cursor_position: None,
|
||||||
|
is_snippet: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
severity: Error,
|
severity: Error,
|
||||||
|
@ -685,6 +686,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
file_system_edits: [],
|
file_system_edits: [],
|
||||||
cursor_position: None,
|
cursor_position: None,
|
||||||
|
is_snippet: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
severity: Error,
|
severity: Error,
|
||||||
|
|
|
@ -82,7 +82,7 @@ pub use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use hir::Documentation;
|
pub use hir::Documentation;
|
||||||
pub use ra_assists::AssistId;
|
pub use ra_assists::{AssistConfig, AssistId};
|
||||||
pub use ra_db::{
|
pub use ra_db::{
|
||||||
Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId,
|
Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId,
|
||||||
};
|
};
|
||||||
|
@ -458,17 +458,17 @@ impl Analysis {
|
||||||
/// Computes completions at the given position.
|
/// Computes completions at the given position.
|
||||||
pub fn completions(
|
pub fn completions(
|
||||||
&self,
|
&self,
|
||||||
position: FilePosition,
|
|
||||||
config: &CompletionConfig,
|
config: &CompletionConfig,
|
||||||
|
position: FilePosition,
|
||||||
) -> Cancelable<Option<Vec<CompletionItem>>> {
|
) -> Cancelable<Option<Vec<CompletionItem>>> {
|
||||||
self.with_db(|db| completion::completions(db, position, config).map(Into::into))
|
self.with_db(|db| completion::completions(db, config, position).map(Into::into))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes assists (aka code actions aka intentions) for the given
|
/// Computes assists (aka code actions aka intentions) for the given
|
||||||
/// position.
|
/// position.
|
||||||
pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<Assist>> {
|
pub fn assists(&self, config: &AssistConfig, frange: FileRange) -> Cancelable<Vec<Assist>> {
|
||||||
self.with_db(|db| {
|
self.with_db(|db| {
|
||||||
ra_assists::Assist::resolved(db, frange)
|
ra_assists::Assist::resolved(db, config, frange)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|assist| Assist {
|
.map(|assist| Assist {
|
||||||
id: assist.assist.id,
|
id: assist.assist.id,
|
||||||
|
|
|
@ -670,6 +670,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
cursor_position: None,
|
cursor_position: None,
|
||||||
|
is_snippet: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -722,6 +723,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
cursor_position: None,
|
cursor_position: None,
|
||||||
|
is_snippet: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -818,6 +820,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
cursor_position: None,
|
cursor_position: None,
|
||||||
|
is_snippet: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,6 +13,7 @@ pub struct SourceChange {
|
||||||
pub source_file_edits: Vec<SourceFileEdit>,
|
pub source_file_edits: Vec<SourceFileEdit>,
|
||||||
pub file_system_edits: Vec<FileSystemEdit>,
|
pub file_system_edits: Vec<FileSystemEdit>,
|
||||||
pub cursor_position: Option<FilePosition>,
|
pub cursor_position: Option<FilePosition>,
|
||||||
|
pub is_snippet: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SourceChange {
|
impl SourceChange {
|
||||||
|
@ -28,6 +29,7 @@ impl SourceChange {
|
||||||
source_file_edits,
|
source_file_edits,
|
||||||
file_system_edits,
|
file_system_edits,
|
||||||
cursor_position: None,
|
cursor_position: None,
|
||||||
|
is_snippet: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +43,7 @@ impl SourceChange {
|
||||||
source_file_edits: edits,
|
source_file_edits: edits,
|
||||||
file_system_edits: vec![],
|
file_system_edits: vec![],
|
||||||
cursor_position: None,
|
cursor_position: None,
|
||||||
|
is_snippet: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +55,7 @@ impl SourceChange {
|
||||||
source_file_edits: vec![],
|
source_file_edits: vec![],
|
||||||
file_system_edits: edits,
|
file_system_edits: edits,
|
||||||
cursor_position: None,
|
cursor_position: None,
|
||||||
|
is_snippet: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +119,7 @@ impl SingleFileChange {
|
||||||
source_file_edits: vec![SourceFileEdit { file_id, edit: self.edit }],
|
source_file_edits: vec![SourceFileEdit { file_id, edit: self.edit }],
|
||||||
file_system_edits: Vec::new(),
|
file_system_edits: Vec::new(),
|
||||||
cursor_position: self.cursor_position.map(|offset| FilePosition { file_id, offset }),
|
cursor_position: self.cursor_position.map(|offset| FilePosition { file_id, offset }),
|
||||||
|
is_snippet: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ pub fn analysis_bench(
|
||||||
if is_completion {
|
if is_completion {
|
||||||
let options = CompletionConfig::default();
|
let options = CompletionConfig::default();
|
||||||
let res = do_work(&mut host, file_id, |analysis| {
|
let res = do_work(&mut host, file_id, |analysis| {
|
||||||
analysis.completions(file_position, &options)
|
analysis.completions(&options, file_position)
|
||||||
});
|
});
|
||||||
if verbosity.is_verbose() {
|
if verbosity.is_verbose() {
|
||||||
println!("\n{:#?}", res);
|
println!("\n{:#?}", res);
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::{ffi::OsString, path::PathBuf};
|
||||||
|
|
||||||
use lsp_types::ClientCapabilities;
|
use lsp_types::ClientCapabilities;
|
||||||
use ra_flycheck::FlycheckConfig;
|
use ra_flycheck::FlycheckConfig;
|
||||||
use ra_ide::{CompletionConfig, InlayHintsConfig};
|
use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig};
|
||||||
use ra_project_model::CargoConfig;
|
use ra_project_model::CargoConfig;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ pub struct Config {
|
||||||
|
|
||||||
pub inlay_hints: InlayHintsConfig,
|
pub inlay_hints: InlayHintsConfig,
|
||||||
pub completion: CompletionConfig,
|
pub completion: CompletionConfig,
|
||||||
|
pub assist: AssistConfig,
|
||||||
pub call_info_full: bool,
|
pub call_info_full: bool,
|
||||||
pub lens: LensConfig,
|
pub lens: LensConfig,
|
||||||
}
|
}
|
||||||
|
@ -136,6 +137,7 @@ impl Default for Config {
|
||||||
add_call_argument_snippets: true,
|
add_call_argument_snippets: true,
|
||||||
..CompletionConfig::default()
|
..CompletionConfig::default()
|
||||||
},
|
},
|
||||||
|
assist: AssistConfig::default(),
|
||||||
call_info_full: true,
|
call_info_full: true,
|
||||||
lens: LensConfig::default(),
|
lens: LensConfig::default(),
|
||||||
}
|
}
|
||||||
|
@ -281,6 +283,7 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.assist.allow_snippets(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(window_caps) = caps.window.as_ref() {
|
if let Some(window_caps) = caps.window.as_ref() {
|
||||||
|
|
|
@ -476,7 +476,7 @@ pub fn handle_completion(
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let items = match world.analysis().completions(position, &world.config.completion)? {
|
let items = match world.analysis().completions(&world.config.completion, position)? {
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
Some(items) => items,
|
Some(items) => items,
|
||||||
};
|
};
|
||||||
|
@ -740,7 +740,9 @@ pub fn handle_code_action(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut grouped_assists: FxHashMap<String, (usize, Vec<Assist>)> = FxHashMap::default();
|
let mut grouped_assists: FxHashMap<String, (usize, Vec<Assist>)> = FxHashMap::default();
|
||||||
for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() {
|
for assist in
|
||||||
|
world.analysis().assists(&world.config.assist, FileRange { file_id, range })?.into_iter()
|
||||||
|
{
|
||||||
match &assist.group_label {
|
match &assist.group_label {
|
||||||
Some(label) => grouped_assists
|
Some(label) => grouped_assists
|
||||||
.entry(label.to_owned())
|
.entry(label.to_owned())
|
||||||
|
|
Loading…
Reference in a new issue