about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhamidreza kalbasi <hamidrezakalbasi@protonmail.com>2021-09-10 20:00:53 +0430
committerhamidreza kalbasi <hamidrezakalbasi@protonmail.com>2021-09-26 10:04:02 +0330
commite803bd25c4adf4c5487e7b0f6495dfab07b11daf (patch)
treed88d5452b9c5c297716dbf2ab36c9fab0d3c30fd
parent1103e390e049cea91f9b06bad9f0885c7a43cf6c (diff)
downloadrust-e803bd25c4adf4c5487e7b0f6495dfab07b11daf.tar.gz
rust-e803bd25c4adf4c5487e7b0f6495dfab07b11daf.zip
add hover
-rw-r--r--crates/ide/src/lib.rs2
-rw-r--r--crates/ide/src/static_index.rs63
-rw-r--r--crates/rust-analyzer/src/cli/lsif.rs57
-rw-r--r--crates/rust-analyzer/src/cli/lsif/lsif_types.rs35
4 files changed, 108 insertions, 49 deletions
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 3879da6d039..5b2384a054c 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -87,7 +87,7 @@ pub use crate::{
     references::ReferenceSearchResult,
     rename::RenameError,
     runnables::{Runnable, RunnableKind, TestId},
-    static_index::{StaticIndex, StaticIndexedFile},
+    static_index::{StaticIndex, StaticIndexedFile, TokenStaticData},
     syntax_highlighting::{
         tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag},
         HlRange,
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 806230544f3..ab7a829bcab 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -2,11 +2,13 @@
 //! read-only code browsers and emitting LSIF
 
 use hir::{db::HirDatabase, Crate, Module};
-use ide_db::base_db::{FileId, SourceDatabaseExt};
+use ide_db::base_db::{FileId, FileRange, SourceDatabaseExt};
 use ide_db::RootDatabase;
 use rustc_hash::FxHashSet;
+use syntax::TextRange;
+use syntax::{AstNode, SyntaxKind::*, T};
 
-use crate::{Analysis, Cancellable, Fold};
+use crate::{Analysis, Cancellable, Fold, HoverConfig, HoverDocFormat, HoverResult};
 
 /// A static representation of fully analyzed source code.
 ///
@@ -15,9 +17,15 @@ pub struct StaticIndex {
     pub files: Vec<StaticIndexedFile>,
 }
 
+pub struct TokenStaticData {
+    pub range: TextRange,
+    pub hover: Option<HoverResult>,
+}
+
 pub struct StaticIndexedFile {
     pub file_id: FileId,
     pub folds: Vec<Fold>,
+    pub tokens: Vec<TokenStaticData>,
 }
 
 fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
@@ -46,17 +54,48 @@ impl StaticIndex {
         let mut result_files = Vec::<StaticIndexedFile>::new();
         for module in work {
             let file_id = module.definition_source(db).file_id.original_file(db);
-            if !visited_files.contains(&file_id) {
-                //let path = vfs.file_path(file_id);
-                //let path = path.as_path().unwrap();
-                //let doc_id = lsif.add(Element::Vertex(Vertex::Document(Document {
-                //    language_id: Language::Rust,
-                //    uri: lsp_types::Url::from_file_path(path).unwrap(),
-                //})));
-                let folds = analysis.folding_ranges(file_id)?;
-                result_files.push(StaticIndexedFile { file_id, folds });
-                visited_files.insert(file_id);
+            if visited_files.contains(&file_id) {
+                continue;
             }
+            let folds = analysis.folding_ranges(file_id)?;
+            // hovers
+            let sema = hir::Semantics::new(db);
+            let tokens_or_nodes = sema.parse(file_id).syntax().clone();
+            let tokens = tokens_or_nodes.descendants_with_tokens().filter_map(|x| match x {
+                syntax::NodeOrToken::Node(_) => None,
+                syntax::NodeOrToken::Token(x) => Some(x),
+            });
+            let hover_config =
+                HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) };
+            let tokens = tokens
+                .filter(|token| match token.kind() {
+                    IDENT
+                    | INT_NUMBER
+                    | LIFETIME_IDENT
+                    | T![self]
+                    | T![super]
+                    | T![crate]
+                    | T!['(']
+                    | T![')'] => true,
+                    _ => false,
+                })
+                .map(|token| {
+                    let range = token.text_range();
+                    let hover = analysis
+                        .hover(
+                            &hover_config,
+                            FileRange {
+                                file_id,
+                                range: TextRange::new(range.start(), range.start()),
+                            },
+                        )?
+                        .map(|x| x.info);
+                    Ok(TokenStaticData { range, hover })
+                })
+                .collect::<Result<Vec<_>, _>>()?;
+            result_files.push(StaticIndexedFile { file_id, folds, tokens });
+            // mark the file
+            visited_files.insert(file_id);
         }
         Ok(StaticIndex { files: result_files })
     }
diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs
index 2ba965a15d4..12a9919e369 100644
--- a/crates/rust-analyzer/src/cli/lsif.rs
+++ b/crates/rust-analyzer/src/cli/lsif.rs
@@ -2,11 +2,11 @@
 
 use std::env;
 
-use ide::{StaticIndex, StaticIndexedFile};
+use ide::{StaticIndex, StaticIndexedFile, TokenStaticData};
 use ide_db::LineIndexDatabase;
 
 use ide_db::base_db::salsa::{self, ParallelDatabase};
-use lsp_types::NumberOrString;
+use lsp_types::{Hover, HoverContents, NumberOrString};
 use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
 use vfs::AbsPathBuf;
 
@@ -56,6 +56,38 @@ impl LsifManager {
     fn emit(&self, data: &str) {
         println!("{}", data);
     }
+
+    fn add_tokens(
+        &mut self,
+        line_index: &LineIndex,
+        doc_id: Id,
+        tokens: Vec<TokenStaticData>,
+    ) {
+        let tokens_id = tokens
+            .into_iter()
+            .map(|token| {
+                let token_id = self
+                    .add(Element::Vertex(Vertex::Range(to_proto::range(line_index, token.range))));
+                if let Some(hover) = token.hover {
+                    let hover_id = self.add(Element::Vertex(Vertex::HoverResult {
+                        result: Hover {
+                            contents: HoverContents::Markup(to_proto::markup_content(hover.markup)),
+                            range: None,
+                        },
+                    }));
+                    self.add(Element::Edge(Edge::Hover(EdgeData {
+                        in_v: hover_id.into(),
+                        out_v: token_id.into(),
+                    })));
+                }
+                token_id.into()
+            })
+            .collect();
+        self.add(Element::Edge(Edge::Contains(EdgeDataMultiIn {
+            in_vs: tokens_id,
+            out_v: doc_id.into(),
+        })));
+    }
 }
 
 impl flags::Lsif {
@@ -85,7 +117,7 @@ impl flags::Lsif {
             position_encoding: Encoding::Utf16,
             tool_info: None,
         }));
-        for StaticIndexedFile { file_id, folds } in si.files {
+        for StaticIndexedFile { file_id, folds, tokens } in si.files {
             let path = vfs.file_path(file_id);
             let path = path.as_path().unwrap();
             let doc_id = lsif.add(Element::Vertex(Vertex::Document(Document {
@@ -94,26 +126,21 @@ impl flags::Lsif {
             })));
             let text = analysis.file_text(file_id)?;
             let line_index = db.line_index(file_id);
+            let line_index = LineIndex {
+                index: line_index.clone(),
+                encoding: OffsetEncoding::Utf16,
+                endings: LineEndings::Unix,
+            };
             let result = folds
                 .into_iter()
-                .map(|it| {
-                    to_proto::folding_range(
-                        &*text,
-                        &LineIndex {
-                            index: line_index.clone(),
-                            encoding: OffsetEncoding::Utf16,
-                            endings: LineEndings::Unix,
-                        },
-                        false,
-                        it,
-                    )
-                })
+                .map(|it| to_proto::folding_range(&*text, &line_index, false, it))
                 .collect();
             let folding_id = lsif.add(Element::Vertex(Vertex::FoldingRangeResult { result }));
             lsif.add(Element::Edge(Edge::FoldingRange(EdgeData {
                 in_v: folding_id.into(),
                 out_v: doc_id.into(),
             })));
+            lsif.add_tokens(&line_index, doc_id, tokens);
         }
         Ok(())
     }
diff --git a/crates/rust-analyzer/src/cli/lsif/lsif_types.rs b/crates/rust-analyzer/src/cli/lsif/lsif_types.rs
index 1681840f29d..7bb59f6429d 100644
--- a/crates/rust-analyzer/src/cli/lsif/lsif_types.rs
+++ b/crates/rust-analyzer/src/cli/lsif/lsif_types.rs
@@ -1,7 +1,7 @@
 //! This module provides LSIF types. This module is a temporary solution
 //! and it will go to its own repository in future
 
-use lsp_types::FoldingRange;
+use lsp_types::{FoldingRange, Hover};
 use serde::{Deserialize, Serialize};
 
 pub(crate) type RangeId = lsp_types::NumberOrString;
@@ -82,13 +82,16 @@ pub(crate) enum Vertex {
     FoldingRangeResult {
         result: Vec<FoldingRange>,
     },
+    HoverResult {
+        result: Hover,
+    }
 }
 
 #[derive(Debug, PartialEq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[serde(tag = "label")]
 pub(crate) enum Edge {
-    Contains(EdgeData),
+    Contains(EdgeDataMultiIn),
     RefersTo(EdgeData),
     Item(Item),
 
@@ -123,6 +126,15 @@ pub(crate) struct EdgeData {
 }
 
 #[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub(crate) struct EdgeDataMultiIn {
+    pub(crate) in_vs: Vec<lsp_types::NumberOrString>,
+    pub(crate) out_v: lsp_types::NumberOrString,
+}
+
+
+
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 #[serde(untagged)]
 pub(crate) enum DefinitionResultType {
     Scalar(LocationOrRangeId),
@@ -233,25 +245,6 @@ mod tests {
     }
 
     #[test]
-    fn contains() {
-        let data = Entry {
-            id: lsp_types::NumberOrString::Number(5),
-            data: Element::Edge(Edge::Contains(EdgeData {
-                in_v: lsp_types::NumberOrString::Number(4),
-                out_v: lsp_types::NumberOrString::Number(1),
-            })),
-        };
-
-        let text = r#"{ "id": 5, "type": "edge", "label": "contains", "outV": 1, "inV": 4}"#
-            .replace(' ', "");
-
-        assert_eq!(
-            serde_json::from_str::<serde_json::Value>(&text).unwrap(),
-            serde_json::to_value(&data).unwrap()
-        );
-    }
-
-    #[test]
     fn refers_to() {
         let data = Entry {
             id: lsp_types::NumberOrString::Number(5),