Merge #319
319: Completion icons r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
4e4ca27eab
@ -12,5 +12,5 @@ languageserver-types = "0.53.0"
|
||||
log = "0.4.3"
|
||||
failure = "0.1.2"
|
||||
serde_json = "1.0.24"
|
||||
serde = "1.0.71"
|
||||
serde = { version = "1.0.71", features = ["derive"] }
|
||||
crossbeam-channel = "0.2.4"
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
use crate::Result;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum RawMessage {
|
||||
Request(RawRequest),
|
||||
|
@ -18,7 +18,7 @@
|
||||
},
|
||||
};
|
||||
|
||||
pub use crate::completion::completion_item::{CompletionItem, InsertText};
|
||||
pub use crate::completion::completion_item::{CompletionItem, InsertText, CompletionItemKind};
|
||||
|
||||
/// Main entry point for copmletion. We run comletion as a two-phase process.
|
||||
///
|
||||
|
@ -34,9 +34,8 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
|
||||
}
|
||||
})
|
||||
.for_each(|(label, lookup)| {
|
||||
CompletionItem::new(label)
|
||||
CompletionItem::new(CompletionKind::Magic, label)
|
||||
.lookup_by(lookup)
|
||||
.kind(CompletionKind::Magic)
|
||||
.add_to(acc)
|
||||
});
|
||||
|
||||
|
@ -5,7 +5,14 @@
|
||||
SyntaxKind::*, SyntaxNodeRef,
|
||||
};
|
||||
|
||||
use crate::completion::{CompletionContext, CompletionItem, Completions, CompletionKind::*};
|
||||
use crate::completion::{CompletionContext, CompletionItem, Completions, CompletionKind, CompletionItemKind};
|
||||
|
||||
fn keyword(kw: &str, snippet: &str) -> CompletionItem {
|
||||
CompletionItem::new(CompletionKind::Keyword, kw)
|
||||
.kind(CompletionItemKind::Keyword)
|
||||
.snippet(snippet)
|
||||
.build()
|
||||
}
|
||||
|
||||
pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
if !ctx.is_trivial_path {
|
||||
@ -60,13 +67,6 @@ fn complete_return(fn_def: ast::FnDef, is_stmt: bool) -> Option<CompletionItem>
|
||||
Some(keyword("return", snip))
|
||||
}
|
||||
|
||||
fn keyword(kw: &str, snippet: &str) -> CompletionItem {
|
||||
CompletionItem::new(kw)
|
||||
.kind(Keyword)
|
||||
.snippet(snippet)
|
||||
.build()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::completion::{CompletionKind, check_completion};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
Cancelable,
|
||||
completion::{CompletionItem, Completions, CompletionKind::*, CompletionContext},
|
||||
completion::{CompletionItem, Completions, CompletionKind, CompletionContext},
|
||||
};
|
||||
|
||||
pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> {
|
||||
@ -17,9 +17,9 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> C
|
||||
_ => return Ok(()),
|
||||
};
|
||||
let module_scope = target_module.scope(ctx.db)?;
|
||||
module_scope.entries().for_each(|(name, _res)| {
|
||||
CompletionItem::new(name.to_string())
|
||||
.kind(Reference)
|
||||
module_scope.entries().for_each(|(name, res)| {
|
||||
CompletionItem::new(CompletionKind::Reference, name.to_string())
|
||||
.from_resolution(ctx.db, res)
|
||||
.add_to(acc)
|
||||
});
|
||||
Ok(())
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
use crate::{
|
||||
Cancelable,
|
||||
completion::{CompletionItem, Completions, CompletionKind::*, CompletionContext},
|
||||
completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext},
|
||||
};
|
||||
|
||||
pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> {
|
||||
@ -29,9 +29,9 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
|
||||
}
|
||||
}
|
||||
})
|
||||
.for_each(|(name, _res)| {
|
||||
CompletionItem::new(name.to_string())
|
||||
.kind(Reference)
|
||||
.for_each(|(name, res)| {
|
||||
CompletionItem::new(CompletionKind::Reference, name.to_string())
|
||||
.from_resolution(ctx.db, res)
|
||||
.add_to(acc)
|
||||
});
|
||||
}
|
||||
@ -46,12 +46,12 @@ fn complete_fn(acc: &mut Completions, scopes: &hir::FnScopes, offset: TextUnit)
|
||||
.flat_map(|scope| scopes.entries(scope).iter())
|
||||
.filter(|entry| shadowed.insert(entry.name()))
|
||||
.for_each(|entry| {
|
||||
CompletionItem::new(entry.name().to_string())
|
||||
.kind(Reference)
|
||||
CompletionItem::new(CompletionKind::Reference, entry.name().to_string())
|
||||
.kind(CompletionItemKind::Binding)
|
||||
.add_to(acc)
|
||||
});
|
||||
if scopes.self_param.is_some() {
|
||||
CompletionItem::new("self").kind(Reference).add_to(acc);
|
||||
CompletionItem::new(CompletionKind::Reference, "self").add_to(acc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,38 +1,35 @@
|
||||
use crate::completion::{CompletionItem, Completions, CompletionKind::*, CompletionContext};
|
||||
use crate::completion::{CompletionItem, Completions, CompletionKind, CompletionItemKind, CompletionContext, completion_item::Builder};
|
||||
|
||||
fn snippet(label: &str, snippet: &str) -> Builder {
|
||||
CompletionItem::new(CompletionKind::Snippet, label)
|
||||
.snippet(snippet)
|
||||
.kind(CompletionItemKind::Snippet)
|
||||
}
|
||||
|
||||
pub(super) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
if !(ctx.is_trivial_path && ctx.enclosing_fn.is_some()) {
|
||||
return;
|
||||
}
|
||||
CompletionItem::new("pd")
|
||||
.snippet("eprintln!(\"$0 = {:?}\", $0);")
|
||||
.kind(Snippet)
|
||||
.add_to(acc);
|
||||
CompletionItem::new("ppd")
|
||||
.snippet("eprintln!(\"$0 = {:#?}\", $0);")
|
||||
.kind(Snippet)
|
||||
.add_to(acc);
|
||||
snippet("pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc);
|
||||
snippet("ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc);
|
||||
}
|
||||
|
||||
pub(super) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
if !ctx.is_new_item {
|
||||
return;
|
||||
}
|
||||
CompletionItem::new("Test function")
|
||||
.lookup_by("tfn")
|
||||
.snippet(
|
||||
"\
|
||||
snippet(
|
||||
"Test function",
|
||||
"\
|
||||
#[test]
|
||||
fn ${1:feature}() {
|
||||
$0
|
||||
}",
|
||||
)
|
||||
.kind(Snippet)
|
||||
.add_to(acc);
|
||||
CompletionItem::new("pub(crate)")
|
||||
.snippet("pub(crate) $0")
|
||||
.kind(Snippet)
|
||||
.add_to(acc);
|
||||
)
|
||||
.lookup_by("tfn")
|
||||
.add_to(acc);
|
||||
|
||||
snippet("pub(crate)", "pub(crate) $0").add_to(acc);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,13 +1,17 @@
|
||||
use crate::db;
|
||||
|
||||
/// `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.
|
||||
#[derive(Debug)]
|
||||
pub struct CompletionItem {
|
||||
/// Used only internally in tests, to check only specific kind of
|
||||
/// completion.
|
||||
completion_kind: CompletionKind,
|
||||
label: String,
|
||||
lookup: Option<String>,
|
||||
snippet: Option<String>,
|
||||
/// Used only internally in test, to check only specific kind of completion.
|
||||
kind: CompletionKind,
|
||||
kind: Option<CompletionItemKind>,
|
||||
}
|
||||
|
||||
pub enum InsertText {
|
||||
@ -15,6 +19,15 @@ pub enum InsertText {
|
||||
Snippet { text: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum CompletionItemKind {
|
||||
Snippet,
|
||||
Keyword,
|
||||
Module,
|
||||
Function,
|
||||
Binding,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub(crate) enum CompletionKind {
|
||||
/// Parser-based keyword completion.
|
||||
@ -24,17 +37,17 @@ pub(crate) enum CompletionKind {
|
||||
/// "Secret sauce" completions.
|
||||
Magic,
|
||||
Snippet,
|
||||
Unspecified,
|
||||
}
|
||||
|
||||
impl CompletionItem {
|
||||
pub(crate) fn new(label: impl Into<String>) -> Builder {
|
||||
pub(crate) fn new(completion_kind: CompletionKind, label: impl Into<String>) -> Builder {
|
||||
let label = label.into();
|
||||
Builder {
|
||||
completion_kind,
|
||||
label,
|
||||
lookup: None,
|
||||
snippet: None,
|
||||
kind: CompletionKind::Unspecified,
|
||||
kind: None,
|
||||
}
|
||||
}
|
||||
/// What user sees in pop-up in the UI.
|
||||
@ -57,15 +70,20 @@ pub fn insert_text(&self) -> InsertText {
|
||||
Some(it) => InsertText::Snippet { text: it.clone() },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> Option<CompletionItemKind> {
|
||||
self.kind
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper to make `CompletionItem`s.
|
||||
#[must_use]
|
||||
pub(crate) struct Builder {
|
||||
completion_kind: CompletionKind,
|
||||
label: String,
|
||||
lookup: Option<String>,
|
||||
snippet: Option<String>,
|
||||
kind: CompletionKind,
|
||||
kind: Option<CompletionItemKind>,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
@ -79,6 +97,7 @@ pub(crate) fn build(self) -> CompletionItem {
|
||||
lookup: self.lookup,
|
||||
snippet: self.snippet,
|
||||
kind: self.kind,
|
||||
completion_kind: self.completion_kind,
|
||||
}
|
||||
}
|
||||
pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
|
||||
@ -89,8 +108,25 @@ pub(crate) fn snippet(mut self, snippet: impl Into<String>) -> Builder {
|
||||
self.snippet = Some(snippet.into());
|
||||
self
|
||||
}
|
||||
pub(crate) fn kind(mut self, kind: CompletionKind) -> Builder {
|
||||
self.kind = kind;
|
||||
pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder {
|
||||
self.kind = Some(kind);
|
||||
self
|
||||
}
|
||||
pub(crate) fn from_resolution(
|
||||
mut self,
|
||||
db: &db::RootDatabase,
|
||||
resolution: &hir::Resolution,
|
||||
) -> Builder {
|
||||
if let Some(def_id) = resolution.def_id {
|
||||
if let Ok(def) = def_id.resolve(db) {
|
||||
let kind = match def {
|
||||
hir::Def::Module(..) => CompletionItemKind::Module,
|
||||
hir::Def::Function(..) => CompletionItemKind::Function,
|
||||
_ => return self,
|
||||
};
|
||||
self.kind = Some(kind);
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
@ -154,7 +190,7 @@ fn normalize(expected: &str) -> String {
|
||||
fn debug_render(&self, kind: CompletionKind) -> String {
|
||||
let mut res = String::new();
|
||||
for c in self.buf.iter() {
|
||||
if c.kind == kind {
|
||||
if c.completion_kind == kind {
|
||||
if let Some(lookup) = &c.lookup {
|
||||
res.push_str(lookup);
|
||||
res.push_str(&format!(" {:?}", c.label));
|
||||
|
@ -30,7 +30,7 @@ macro_rules! ctry {
|
||||
};
|
||||
|
||||
pub use crate::{
|
||||
completion::{CompletionItem, InsertText},
|
||||
completion::{CompletionItem, CompletionItemKind, InsertText},
|
||||
};
|
||||
pub use ra_editor::{
|
||||
FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, RunnableKind, StructureNode,
|
||||
|
@ -95,7 +95,7 @@ fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit)
|
||||
r1.start().cmp(&r2.start())
|
||||
}
|
||||
})
|
||||
.map(|(ptr, scope)| *scope)
|
||||
.map(|(_ptr, scope)| *scope)
|
||||
.unwrap_or(original_scope)
|
||||
}
|
||||
|
||||
@ -209,7 +209,6 @@ fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: Sco
|
||||
}
|
||||
}
|
||||
if let Some(expr) = block.expr() {
|
||||
eprintln!("{:?}", expr);
|
||||
scopes.set_scope(expr.syntax(), scope);
|
||||
compute_expr_scopes(expr, scopes, scope);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ macro_rules! ctry {
|
||||
pub use self::{
|
||||
path::{Path, PathKind},
|
||||
krate::Crate,
|
||||
module::{Module, ModuleId, Problem, nameres::ItemMap},
|
||||
module::{Module, ModuleId, Problem, nameres::ItemMap, ModuleScope, Resolution},
|
||||
function::{Function, FnScopes},
|
||||
};
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
arena::{Arena, Id},
|
||||
};
|
||||
|
||||
pub use self::nameres::ModuleScope;
|
||||
pub use self::nameres::{ModuleScope, Resolution};
|
||||
|
||||
/// `Module` is API entry point to get all the information
|
||||
/// about a particular module.
|
||||
|
@ -49,7 +49,7 @@ pub struct ModuleScope {
|
||||
}
|
||||
|
||||
impl ModuleScope {
|
||||
pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a SmolStr, &Resolution)> + 'a {
|
||||
pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a SmolStr, &'a Resolution)> + 'a {
|
||||
self.items.iter()
|
||||
}
|
||||
pub fn get(&self, name: &SmolStr) -> Option<&Resolution> {
|
||||
|
@ -1,8 +1,8 @@
|
||||
use languageserver_types::{
|
||||
self, Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
|
||||
TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier,
|
||||
TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, InsertTextFormat,
|
||||
};
|
||||
use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition};
|
||||
use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition, CompletionItem, CompletionItemKind, InsertText};
|
||||
use ra_editor::{LineCol, LineIndex};
|
||||
use ra_text_edit::{AtomTextEdit, TextEdit};
|
||||
use ra_syntax::{SyntaxKind, TextRange, TextUnit};
|
||||
@ -45,6 +45,46 @@ fn conv(self) -> <Self as Conv>::Output {
|
||||
}
|
||||
}
|
||||
|
||||
impl Conv for CompletionItemKind {
|
||||
type Output = ::languageserver_types::CompletionItemKind;
|
||||
|
||||
fn conv(self) -> <Self as Conv>::Output {
|
||||
use ::languageserver_types::CompletionItemKind::*;
|
||||
match self {
|
||||
CompletionItemKind::Keyword => Keyword,
|
||||
CompletionItemKind::Snippet => Snippet,
|
||||
CompletionItemKind::Module => Module,
|
||||
CompletionItemKind::Function => Function,
|
||||
CompletionItemKind::Binding => Variable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Conv for CompletionItem {
|
||||
type Output = ::languageserver_types::CompletionItem;
|
||||
|
||||
fn conv(self) -> <Self as Conv>::Output {
|
||||
let mut res = ::languageserver_types::CompletionItem {
|
||||
label: self.label().to_string(),
|
||||
filter_text: Some(self.lookup().to_string()),
|
||||
kind: self.kind().map(|it| it.conv()),
|
||||
..Default::default()
|
||||
};
|
||||
match self.insert_text() {
|
||||
InsertText::PlainText { text } => {
|
||||
res.insert_text = Some(text);
|
||||
res.insert_text_format = Some(InsertTextFormat::PlainText);
|
||||
}
|
||||
InsertText::Snippet { text } => {
|
||||
res.insert_text = Some(text);
|
||||
res.insert_text_format = Some(InsertTextFormat::Snippet);
|
||||
res.kind = Some(languageserver_types::CompletionItemKind::Keyword);
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl ConvWith for Position {
|
||||
type Ctx = LineIndex;
|
||||
type Output = TextUnit;
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
use gen_lsp_server::ErrorCode;
|
||||
use languageserver_types::{
|
||||
CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic,
|
||||
CodeActionResponse, Command, Diagnostic,
|
||||
DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind,
|
||||
FoldingRangeParams, InsertTextFormat, Location, MarkupContent, MarkupKind, MarkedString, Position,
|
||||
FoldingRangeParams, Location, MarkupContent, MarkupKind, MarkedString, Position,
|
||||
PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit,
|
||||
WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, HoverContents,
|
||||
};
|
||||
use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FilePosition, InsertText};
|
||||
use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FilePosition};
|
||||
use ra_syntax::{TextUnit, text_utils::intersect};
|
||||
use ra_text_edit::text_utils::contains_offset_nonstrict;
|
||||
use rustc_hash::FxHashMap;
|
||||
@ -419,28 +419,7 @@ pub fn handle_completion(
|
||||
None => return Ok(None),
|
||||
Some(items) => items,
|
||||
};
|
||||
let items = items
|
||||
.into_iter()
|
||||
.map(|item| {
|
||||
let mut res = CompletionItem {
|
||||
label: item.label().to_string(),
|
||||
filter_text: Some(item.lookup().to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
match item.insert_text() {
|
||||
InsertText::PlainText { text } => {
|
||||
res.insert_text = Some(text);
|
||||
res.insert_text_format = Some(InsertTextFormat::PlainText);
|
||||
}
|
||||
InsertText::Snippet { text } => {
|
||||
res.insert_text = Some(text);
|
||||
res.insert_text_format = Some(InsertTextFormat::Snippet);
|
||||
res.kind = Some(CompletionItemKind::Keyword);
|
||||
}
|
||||
}
|
||||
res
|
||||
})
|
||||
.collect();
|
||||
let items = items.into_iter().map(|item| item.conv()).collect();
|
||||
|
||||
Ok(Some(req::CompletionResponse::Array(items)))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user