mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-11 20:58:54 +00:00
Add Markup type
This commit is contained in:
parent
7db795e747
commit
e8bb153b19
5 changed files with 79 additions and 59 deletions
|
@ -16,6 +16,7 @@ use crate::{
|
||||||
display::{
|
display::{
|
||||||
macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav, TryToNav,
|
macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav, TryToNav,
|
||||||
},
|
},
|
||||||
|
markup::Markup,
|
||||||
runnables::runnable,
|
runnables::runnable,
|
||||||
FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
|
FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
|
||||||
};
|
};
|
||||||
|
@ -68,8 +69,8 @@ pub struct HoverGotoTypeData {
|
||||||
/// Contains the results when hovering over an item
|
/// Contains the results when hovering over an item
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct HoverResult {
|
pub struct HoverResult {
|
||||||
results: Vec<String>,
|
pub markup: Markup,
|
||||||
actions: Vec<HoverAction>,
|
pub actions: Vec<HoverAction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HoverResult {
|
impl HoverResult {
|
||||||
|
@ -78,22 +79,7 @@ impl HoverResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.results.is_empty()
|
self.markup.is_empty()
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.results.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn actions(&self) -> &[HoverAction] {
|
|
||||||
&self.actions
|
|
||||||
}
|
|
||||||
/// Returns the results converted into markup
|
|
||||||
/// for displaying in a UI
|
|
||||||
///
|
|
||||||
/// Does not process actions!
|
|
||||||
pub fn to_markup(&self) -> String {
|
|
||||||
self.results.join("\n\n___\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_action(&mut self, action: HoverAction) {
|
fn push_action(&mut self, action: HoverAction) {
|
||||||
|
@ -128,7 +114,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
|
||||||
if let Some(definition) = definition {
|
if let Some(definition) = definition {
|
||||||
let range = sema.original_range(&node).range;
|
let range = sema.original_range(&node).range;
|
||||||
if let Some(text) = hover_text_from_name_kind(db, definition) {
|
if let Some(text) = hover_text_from_name_kind(db, definition) {
|
||||||
res.results.push(text);
|
res.markup.push_section(&text);
|
||||||
}
|
}
|
||||||
if !res.is_empty() {
|
if !res.is_empty() {
|
||||||
if let Some(action) = show_implementations_action(db, definition) {
|
if let Some(action) = show_implementations_action(db, definition) {
|
||||||
|
@ -168,7 +154,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
|
||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
res.results.push(rust_code_markup(&ty.display(db)));
|
res.markup.push_section(&rust_code_markup(&ty.display(db)));
|
||||||
let range = sema.original_range(&node).range;
|
let range = sema.original_range(&node).range;
|
||||||
Some(RangeInfo::new(range, res))
|
Some(RangeInfo::new(range, res))
|
||||||
}
|
}
|
||||||
|
@ -406,19 +392,12 @@ mod tests {
|
||||||
fn check_hover_result(ra_fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) {
|
fn check_hover_result(ra_fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) {
|
||||||
let (analysis, position) = analysis_and_position(ra_fixture);
|
let (analysis, position) = analysis_and_position(ra_fixture);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
let mut results = hover.info.results.clone();
|
let expected = expected.join("\n\n___\n");
|
||||||
results.sort();
|
let actual = trim_markup(hover.info.markup.as_str());
|
||||||
|
assert_eq!(expected, actual);
|
||||||
for (markup, expected) in
|
|
||||||
results.iter().zip(expected.iter().chain(std::iter::repeat(&"<missing>")))
|
|
||||||
{
|
|
||||||
assert_eq!(trim_markup(&markup), *expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(hover.info.len(), expected.len());
|
|
||||||
|
|
||||||
let content = analysis.db.file_text(position.file_id);
|
let content = analysis.db.file_text(position.file_id);
|
||||||
(content[hover.range].to_string(), hover.info.actions().to_vec())
|
(content[hover.range].to_string(), hover.info.actions.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_hover_no_result(ra_fixture: &str) {
|
fn check_hover_no_result(ra_fixture: &str) {
|
||||||
|
@ -439,7 +418,7 @@ fn main() {
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(hover.range, TextRange::new(58.into(), 63.into()));
|
assert_eq!(hover.range, TextRange::new(58.into(), 63.into()));
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), ("u32"));
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("u32"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -638,7 +617,7 @@ fn main() {
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), ("Option\n```\n\n```rust\nSome"));
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("Option\n```\n\n```rust\nSome"));
|
||||||
|
|
||||||
let (analysis, position) = analysis_and_position(
|
let (analysis, position) = analysis_and_position(
|
||||||
"
|
"
|
||||||
|
@ -651,7 +630,7 @@ fn main() {
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), ("Option<i32>"));
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("Option<i32>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -708,14 +687,14 @@ The Some variant
|
||||||
fn hover_for_local_variable() {
|
fn hover_for_local_variable() {
|
||||||
let (analysis, position) = analysis_and_position("fn func(foo: i32) { fo<|>o; }");
|
let (analysis, position) = analysis_and_position("fn func(foo: i32) { fo<|>o; }");
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), "i32");
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), "i32");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hover_for_local_variable_pat() {
|
fn hover_for_local_variable_pat() {
|
||||||
let (analysis, position) = analysis_and_position("fn func(fo<|>o: i32) {}");
|
let (analysis, position) = analysis_and_position("fn func(fo<|>o: i32) {}");
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), "i32");
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), "i32");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -726,14 +705,14 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), "i32");
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), "i32");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hover_for_param_edge() {
|
fn hover_for_param_edge() {
|
||||||
let (analysis, position) = analysis_and_position("fn func(<|>foo: i32) {}");
|
let (analysis, position) = analysis_and_position("fn func(<|>foo: i32) {}");
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), "i32");
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), "i32");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -754,7 +733,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), ("Thing"));
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("Thing"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -778,7 +757,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
trim_markup(&hover.info.results[0]),
|
trim_markup(&hover.info.markup.as_str()),
|
||||||
("wrapper::Thing\n```\n\n```rust\nfn new() -> Thing")
|
("wrapper::Thing\n```\n\n```rust\nfn new() -> Thing")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -802,7 +781,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), ("const C: u32"));
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("const C: u32"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -818,7 +797,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), ("Thing"));
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("Thing"));
|
||||||
|
|
||||||
/* FIXME: revive these tests
|
/* FIXME: revive these tests
|
||||||
let (analysis, position) = analysis_and_position(
|
let (analysis, position) = analysis_and_position(
|
||||||
|
@ -833,7 +812,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
);
|
);
|
||||||
|
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), ("Thing"));
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("Thing"));
|
||||||
|
|
||||||
let (analysis, position) = analysis_and_position(
|
let (analysis, position) = analysis_and_position(
|
||||||
"
|
"
|
||||||
|
@ -846,7 +825,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), ("enum Thing"));
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("enum Thing"));
|
||||||
|
|
||||||
let (analysis, position) = analysis_and_position(
|
let (analysis, position) = analysis_and_position(
|
||||||
"
|
"
|
||||||
|
@ -858,7 +837,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), ("enum Thing"));
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("enum Thing"));
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -875,7 +854,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), "i32");
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), "i32");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -892,7 +871,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), ("macro_rules! foo"));
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("macro_rules! foo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -903,7 +882,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
let hover = analysis.hover(position).unwrap().unwrap();
|
let hover = analysis.hover(position).unwrap().unwrap();
|
||||||
assert_eq!(trim_markup(&hover.info.results[0]), "i32");
|
assert_eq!(trim_markup(&hover.info.markup.as_str()), "i32");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -17,6 +17,7 @@ macro_rules! eprintln {
|
||||||
|
|
||||||
pub mod mock_analysis;
|
pub mod mock_analysis;
|
||||||
|
|
||||||
|
mod markup;
|
||||||
mod prime_caches;
|
mod prime_caches;
|
||||||
mod status;
|
mod status;
|
||||||
mod completion;
|
mod completion;
|
||||||
|
@ -68,6 +69,7 @@ pub use crate::{
|
||||||
folding_ranges::{Fold, FoldKind},
|
folding_ranges::{Fold, FoldKind},
|
||||||
hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
|
hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
|
||||||
inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
|
inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
|
||||||
|
markup::Markup,
|
||||||
references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
|
references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
|
||||||
runnables::{Runnable, RunnableKind, TestId},
|
runnables::{Runnable, RunnableKind, TestId},
|
||||||
syntax_highlighting::{
|
syntax_highlighting::{
|
||||||
|
|
38
crates/ra_ide/src/markup.rs
Normal file
38
crates/ra_ide/src/markup.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//! Markdown formatting.
|
||||||
|
//!
|
||||||
|
//! Sometimes, we want to display a "rich text" in the UI. At the moment, we use
|
||||||
|
//! markdown for this purpose. It doesn't feel like a right option, but that's
|
||||||
|
//! what is used by LSP, so let's keep it simple.
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct Markup {
|
||||||
|
text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Markup> for String {
|
||||||
|
fn from(markup: Markup) -> Self {
|
||||||
|
markup.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Markup {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&self.text, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Markup {
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
self.text.as_str()
|
||||||
|
}
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.text.is_empty()
|
||||||
|
}
|
||||||
|
pub fn push_section(&mut self, section: &str) {
|
||||||
|
if !self.text.is_empty() {
|
||||||
|
self.text.push_str("\n\n___\n");
|
||||||
|
}
|
||||||
|
self.text.push_str(section);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,10 +12,10 @@ use lsp_types::{
|
||||||
CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
|
CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
|
||||||
CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
|
CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
|
||||||
CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams, DocumentHighlight,
|
CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams, DocumentHighlight,
|
||||||
DocumentSymbol, FoldingRange, FoldingRangeParams, HoverContents, Location, MarkupContent,
|
DocumentSymbol, FoldingRange, FoldingRangeParams, HoverContents, Location, Position,
|
||||||
MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensParams,
|
PrepareRenameResponse, Range, RenameParams, SemanticTokensParams, SemanticTokensRangeParams,
|
||||||
SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
|
SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, TextDocumentIdentifier,
|
||||||
TextDocumentIdentifier, Url, WorkspaceEdit,
|
Url, WorkspaceEdit,
|
||||||
};
|
};
|
||||||
use ra_ide::{
|
use ra_ide::{
|
||||||
FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query,
|
FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query,
|
||||||
|
@ -584,13 +584,10 @@ pub(crate) fn handle_hover(
|
||||||
let range = to_proto::range(&line_index, info.range);
|
let range = to_proto::range(&line_index, info.range);
|
||||||
let hover = lsp_ext::Hover {
|
let hover = lsp_ext::Hover {
|
||||||
hover: lsp_types::Hover {
|
hover: lsp_types::Hover {
|
||||||
contents: HoverContents::Markup(MarkupContent {
|
contents: HoverContents::Markup(to_proto::markup_content(info.info.markup)),
|
||||||
kind: MarkupKind::Markdown,
|
|
||||||
value: crate::markdown::format_docs(&info.info.to_markup()),
|
|
||||||
}),
|
|
||||||
range: Some(range),
|
range: Some(range),
|
||||||
},
|
},
|
||||||
actions: prepare_hover_actions(&snap, position.file_id, info.info.actions()),
|
actions: prepare_hover_actions(&snap, position.file_id, &info.info.actions),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Some(hover))
|
Ok(Some(hover))
|
||||||
|
|
|
@ -6,8 +6,8 @@ use ra_db::{FileId, FileRange};
|
||||||
use ra_ide::{
|
use ra_ide::{
|
||||||
Assist, AssistKind, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold,
|
Assist, AssistKind, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold,
|
||||||
FoldKind, FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange,
|
FoldKind, FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange,
|
||||||
Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess,
|
Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget,
|
||||||
ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit,
|
ReferenceAccess, ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit,
|
||||||
};
|
};
|
||||||
use ra_syntax::{SyntaxKind, TextRange, TextSize};
|
use ra_syntax::{SyntaxKind, TextRange, TextSize};
|
||||||
|
|
||||||
|
@ -696,6 +696,10 @@ pub(crate) fn runnable(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn markup_content(markup: Markup) -> lsp_types::MarkupContent {
|
||||||
|
lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value: markup.into() }
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use ra_ide::Analysis;
|
use ra_ide::Analysis;
|
||||||
|
|
Loading…
Reference in a new issue