diff --git a/crates/gen_lsp_server/Cargo.toml b/crates/gen_lsp_server/Cargo.toml index 5f90d39d6c33..9776a82e375e 100644 --- a/crates/gen_lsp_server/Cargo.toml +++ b/crates/gen_lsp_server/Cargo.toml @@ -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" diff --git a/crates/gen_lsp_server/src/msg.rs b/crates/gen_lsp_server/src/msg.rs index ef6358cb1719..af901d0d2966 100644 --- a/crates/gen_lsp_server/src/msg.rs +++ b/crates/gen_lsp_server/src/msg.rs @@ -7,7 +7,7 @@ use failure::{bail, format_err}; use crate::Result; -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] pub enum RawMessage { Request(RawRequest), diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion.rs index 2d61a3aef53e..d742d62955a0 100644 --- a/crates/ra_analysis/src/completion.rs +++ b/crates/ra_analysis/src/completion.rs @@ -18,7 +18,7 @@ use crate::{ }, }; -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. /// diff --git a/crates/ra_analysis/src/completion/complete_fn_param.rs b/crates/ra_analysis/src/completion/complete_fn_param.rs index 6a6213e67bfb..bb5fdfda0418 100644 --- a/crates/ra_analysis/src/completion/complete_fn_param.rs +++ b/crates/ra_analysis/src/completion/complete_fn_param.rs @@ -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) }); diff --git a/crates/ra_analysis/src/completion/complete_keyword.rs b/crates/ra_analysis/src/completion/complete_keyword.rs index dead15bb6f05..5427fcb11f2f 100644 --- a/crates/ra_analysis/src/completion/complete_keyword.rs +++ b/crates/ra_analysis/src/completion/complete_keyword.rs @@ -5,7 +5,14 @@ use ra_syntax::{ 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 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}; diff --git a/crates/ra_analysis/src/completion/complete_path.rs b/crates/ra_analysis/src/completion/complete_path.rs index 5fc24af7209c..ad4d68a3326b 100644 --- a/crates/ra_analysis/src/completion/complete_path.rs +++ b/crates/ra_analysis/src/completion/complete_path.rs @@ -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(()) diff --git a/crates/ra_analysis/src/completion/complete_scope.rs b/crates/ra_analysis/src/completion/complete_scope.rs index d07c0e46d974..82610d63f136 100644 --- a/crates/ra_analysis/src/completion/complete_scope.rs +++ b/crates/ra_analysis/src/completion/complete_scope.rs @@ -3,7 +3,7 @@ use ra_syntax::TextUnit; 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); } } diff --git a/crates/ra_analysis/src/completion/complete_snippet.rs b/crates/ra_analysis/src/completion/complete_snippet.rs index ccd68832b4ab..fb9da0a4f8d5 100644 --- a/crates/ra_analysis/src/completion/complete_snippet.rs +++ b/crates/ra_analysis/src/completion/complete_snippet.rs @@ -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)] diff --git a/crates/ra_analysis/src/completion/completion_item.rs b/crates/ra_analysis/src/completion/completion_item.rs index d5d751759858..911f08468ea4 100644 --- a/crates/ra_analysis/src/completion/completion_item.rs +++ b/crates/ra_analysis/src/completion/completion_item.rs @@ -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, snippet: Option, - /// Used only internally in test, to check only specific kind of completion. - kind: CompletionKind, + kind: Option, } 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) -> Builder { + pub(crate) fn new(completion_kind: CompletionKind, label: impl Into) -> 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 @@ impl CompletionItem { Some(it) => InsertText::Snippet { text: it.clone() }, } } + + pub fn kind(&self) -> Option { + self.kind + } } /// A helper to make `CompletionItem`s. #[must_use] pub(crate) struct Builder { + completion_kind: CompletionKind, label: String, lookup: Option, snippet: Option, - kind: CompletionKind, + kind: Option, } impl Builder { @@ -79,6 +97,7 @@ impl Builder { lookup: self.lookup, snippet: self.snippet, kind: self.kind, + completion_kind: self.completion_kind, } } pub(crate) fn lookup_by(mut self, lookup: impl Into) -> Builder { @@ -89,8 +108,25 @@ impl 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 @@ impl Completions { 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)); diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index b2f4cd228b00..6fd1578801e0 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -30,7 +30,7 @@ use crate::{ }; pub use crate::{ - completion::{CompletionItem, InsertText}, + completion::{CompletionItem, CompletionItemKind, InsertText}, }; pub use ra_editor::{ FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, RunnableKind, StructureNode, diff --git a/crates/ra_hir/src/function/scope.rs b/crates/ra_hir/src/function/scope.rs index 9f1aa1ef2d87..77be25f1a8bc 100644 --- a/crates/ra_hir/src/function/scope.rs +++ b/crates/ra_hir/src/function/scope.rs @@ -95,7 +95,7 @@ impl FnScopes { 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); } diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 5941a9ea3d9a..f56214b47a7e 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -39,7 +39,7 @@ use crate::{ 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}, }; diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs index d5866f6ef5cb..cd31e8cfe647 100644 --- a/crates/ra_hir/src/module.rs +++ b/crates/ra_hir/src/module.rs @@ -16,7 +16,7 @@ use crate::{ 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. diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index f44abc73062f..39e891cda5a6 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs @@ -49,7 +49,7 @@ pub struct ModuleScope { } impl ModuleScope { - pub fn entries<'a>(&'a self) -> impl Iterator + 'a { + pub fn entries<'a>(&'a self) -> impl Iterator + 'a { self.items.iter() } pub fn get(&self, name: &SmolStr) -> Option<&Resolution> { diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 218ded4eecf9..051f1f995b3c 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -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 @@ impl Conv for SyntaxKind { } } +impl Conv for CompletionItemKind { + type Output = ::languageserver_types::CompletionItemKind; + + fn conv(self) -> ::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) -> ::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; diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 2dfeb061a148..252d1ba3ead1 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -2,13 +2,13 @@ use std::collections::HashMap; 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))) }