diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/display.rs | 29 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 230 | ||||
-rw-r--r-- | crates/ra_ide/src/markup.rs | 16 |
3 files changed, 113 insertions, 162 deletions
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs index 827c094e7..70d2a2dd1 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs | |||
@@ -6,13 +6,10 @@ mod navigation_target; | |||
6 | mod structure; | 6 | mod structure; |
7 | mod short_label; | 7 | mod short_label; |
8 | 8 | ||
9 | use std::fmt::Display; | ||
10 | |||
11 | use ra_syntax::{ | 9 | use ra_syntax::{ |
12 | ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner}, | 10 | ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner}, |
13 | SyntaxKind::{ATTR, COMMENT}, | 11 | SyntaxKind::{ATTR, COMMENT}, |
14 | }; | 12 | }; |
15 | use stdx::format_to; | ||
16 | 13 | ||
17 | pub use function_signature::FunctionSignature; | 14 | pub use function_signature::FunctionSignature; |
18 | pub use navigation_target::NavigationTarget; | 15 | pub use navigation_target::NavigationTarget; |
@@ -69,29 +66,3 @@ pub(crate) fn macro_label(node: &ast::MacroCall) -> String { | |||
69 | let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" }; | 66 | let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" }; |
70 | format!("{}macro_rules! {}", vis, name) | 67 | format!("{}macro_rules! {}", vis, name) |
71 | } | 68 | } |
72 | |||
73 | pub(crate) fn rust_code_markup(code: &impl Display) -> String { | ||
74 | rust_code_markup_with_doc(code, None, None) | ||
75 | } | ||
76 | |||
77 | pub(crate) fn rust_code_markup_with_doc( | ||
78 | code: &impl Display, | ||
79 | doc: Option<&str>, | ||
80 | mod_path: Option<&str>, | ||
81 | ) -> String { | ||
82 | let mut buf = String::new(); | ||
83 | |||
84 | if let Some(mod_path) = mod_path { | ||
85 | if !mod_path.is_empty() { | ||
86 | format_to!(buf, "```rust\n{}\n```\n\n", mod_path); | ||
87 | } | ||
88 | } | ||
89 | format_to!(buf, "```rust\n{}\n```", code); | ||
90 | |||
91 | if let Some(doc) = doc { | ||
92 | format_to!(buf, "\n___"); | ||
93 | format_to!(buf, "\n\n{}", doc); | ||
94 | } | ||
95 | |||
96 | buf | ||
97 | } | ||
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index a18c43003..a4c97e7f9 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -1,5 +1,3 @@ | |||
1 | use std::iter::once; | ||
2 | |||
3 | use hir::{ | 1 | use hir::{ |
4 | Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, | 2 | Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, |
5 | Module, ModuleDef, ModuleSource, Semantics, | 3 | Module, ModuleDef, ModuleSource, Semantics, |
@@ -11,16 +9,15 @@ use ra_ide_db::{ | |||
11 | RootDatabase, | 9 | RootDatabase, |
12 | }; | 10 | }; |
13 | use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 11 | use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
12 | use stdx::format_to; | ||
13 | use test_utils::mark; | ||
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | display::{ | 16 | display::{macro_label, ShortLabel, ToNav, TryToNav}, |
17 | macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav, TryToNav, | ||
18 | }, | ||
19 | markup::Markup, | 17 | markup::Markup, |
20 | runnables::runnable, | 18 | runnables::runnable, |
21 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, | 19 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, |
22 | }; | 20 | }; |
23 | use test_utils::mark; | ||
24 | 21 | ||
25 | #[derive(Clone, Debug, PartialEq, Eq)] | 22 | #[derive(Clone, Debug, PartialEq, Eq)] |
26 | pub struct HoverConfig { | 23 | pub struct HoverConfig { |
@@ -73,20 +70,6 @@ pub struct HoverResult { | |||
73 | pub actions: Vec<HoverAction>, | 70 | pub actions: Vec<HoverAction>, |
74 | } | 71 | } |
75 | 72 | ||
76 | impl HoverResult { | ||
77 | pub fn new() -> HoverResult { | ||
78 | Self::default() | ||
79 | } | ||
80 | |||
81 | pub fn is_empty(&self) -> bool { | ||
82 | self.markup.is_empty() | ||
83 | } | ||
84 | |||
85 | fn push_action(&mut self, action: HoverAction) { | ||
86 | self.actions.push(action); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | // Feature: Hover | 73 | // Feature: Hover |
91 | // | 74 | // |
92 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. | 75 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. |
@@ -97,38 +80,32 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
97 | let token = pick_best(file.token_at_offset(position.offset))?; | 80 | let token = pick_best(file.token_at_offset(position.offset))?; |
98 | let token = sema.descend_into_macros(token); | 81 | let token = sema.descend_into_macros(token); |
99 | 82 | ||
100 | let mut res = HoverResult::new(); | 83 | let mut res = HoverResult::default(); |
101 | 84 | ||
102 | let node = token.parent(); | 85 | let node = token.parent(); |
103 | let definition = match_ast! { | 86 | let definition = match_ast! { |
104 | match node { | 87 | match node { |
105 | ast::NameRef(name_ref) => { | 88 | ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition()), |
106 | classify_name_ref(&sema, &name_ref).map(|d| d.definition()) | 89 | ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition()), |
107 | }, | ||
108 | ast::Name(name) => { | ||
109 | classify_name(&sema, &name).map(|d| d.definition()) | ||
110 | }, | ||
111 | _ => None, | 90 | _ => None, |
112 | } | 91 | } |
113 | }; | 92 | }; |
114 | if let Some(definition) = definition { | 93 | if let Some(definition) = definition { |
115 | let range = sema.original_range(&node).range; | 94 | if let Some(markup) = hover_for_definition(db, definition) { |
116 | if let Some(text) = hover_text_from_name_kind(db, definition) { | 95 | res.markup = markup; |
117 | res.markup.push_section(&text); | ||
118 | } | ||
119 | if !res.is_empty() { | ||
120 | if let Some(action) = show_implementations_action(db, definition) { | 96 | if let Some(action) = show_implementations_action(db, definition) { |
121 | res.push_action(action); | 97 | res.actions.push(action); |
122 | } | 98 | } |
123 | 99 | ||
124 | if let Some(action) = runnable_action(&sema, definition, position.file_id) { | 100 | if let Some(action) = runnable_action(&sema, definition, position.file_id) { |
125 | res.push_action(action); | 101 | res.actions.push(action); |
126 | } | 102 | } |
127 | 103 | ||
128 | if let Some(action) = goto_type_action(db, definition) { | 104 | if let Some(action) = goto_type_action(db, definition) { |
129 | res.push_action(action); | 105 | res.actions.push(action); |
130 | } | 106 | } |
131 | 107 | ||
108 | let range = sema.original_range(&node).range; | ||
132 | return Some(RangeInfo::new(range, res)); | 109 | return Some(RangeInfo::new(range, res)); |
133 | } | 110 | } |
134 | } | 111 | } |
@@ -139,22 +116,16 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
139 | 116 | ||
140 | let ty = match_ast! { | 117 | let ty = match_ast! { |
141 | match node { | 118 | match node { |
142 | ast::MacroCall(_it) => { | 119 | ast::Expr(it) => sema.type_of_expr(&it)?, |
143 | // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve. | 120 | ast::Pat(it) => sema.type_of_pat(&it)?, |
144 | // (e.g expanding a builtin macro). So we give up here. | 121 | // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve. |
145 | return None; | 122 | // (e.g expanding a builtin macro). So we give up here. |
146 | }, | 123 | ast::MacroCall(_it) => return None, |
147 | ast::Expr(it) => { | 124 | _ => return None, |
148 | sema.type_of_expr(&it) | ||
149 | }, | ||
150 | ast::Pat(it) => { | ||
151 | sema.type_of_pat(&it) | ||
152 | }, | ||
153 | _ => None, | ||
154 | } | 125 | } |
155 | }?; | 126 | }; |
156 | 127 | ||
157 | res.markup.push_section(&rust_code_markup(&ty.display(db))); | 128 | res.markup = Markup::fenced_block(&ty.display(db)); |
158 | let range = sema.original_range(&node).range; | 129 | let range = sema.original_range(&node).range; |
159 | Some(RangeInfo::new(range, res)) | 130 | Some(RangeInfo::new(range, res)) |
160 | } | 131 | } |
@@ -235,7 +206,11 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | |||
235 | .into_iter() | 206 | .into_iter() |
236 | .filter_map(|it| { | 207 | .filter_map(|it| { |
237 | Some(HoverGotoTypeData { | 208 | Some(HoverGotoTypeData { |
238 | mod_path: mod_path(db, &it)?, | 209 | mod_path: render_path( |
210 | db, | ||
211 | it.module(db)?, | ||
212 | it.name(db).map(|name| name.to_string()), | ||
213 | ), | ||
239 | nav: it.try_to_nav(db)?, | 214 | nav: it.try_to_nav(db)?, |
240 | }) | 215 | }) |
241 | }) | 216 | }) |
@@ -247,15 +222,28 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | |||
247 | } | 222 | } |
248 | } | 223 | } |
249 | 224 | ||
250 | fn hover_text( | 225 | fn hover_markup( |
251 | docs: Option<String>, | 226 | docs: Option<String>, |
252 | desc: Option<String>, | 227 | desc: Option<String>, |
253 | mod_path: Option<String>, | 228 | mod_path: Option<String>, |
254 | ) -> Option<String> { | 229 | ) -> Option<Markup> { |
255 | if let Some(desc) = desc { | 230 | match desc { |
256 | Some(rust_code_markup_with_doc(&desc, docs.as_deref(), mod_path.as_deref())) | 231 | Some(desc) => { |
257 | } else { | 232 | let mut buf = String::new(); |
258 | docs | 233 | |
234 | if let Some(mod_path) = mod_path { | ||
235 | if !mod_path.is_empty() { | ||
236 | format_to!(buf, "```rust\n{}\n```\n\n", mod_path); | ||
237 | } | ||
238 | } | ||
239 | format_to!(buf, "```rust\n{}\n```", desc); | ||
240 | |||
241 | if let Some(doc) = docs { | ||
242 | format_to!(buf, "\n___\n\n{}", doc); | ||
243 | } | ||
244 | Some(buf.into()) | ||
245 | } | ||
246 | None => docs.map(Markup::from), | ||
259 | } | 247 | } |
260 | } | 248 | } |
261 | 249 | ||
@@ -277,43 +265,35 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> | |||
277 | .map(|name| name.to_string()) | 265 | .map(|name| name.to_string()) |
278 | } | 266 | } |
279 | 267 | ||
280 | fn determine_mod_path(db: &RootDatabase, module: Module, name: Option<String>) -> String { | 268 | fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> String { |
281 | once(db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string)) | 269 | let crate_name = |
282 | .chain( | 270 | db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string); |
283 | module | 271 | let module_path = module |
284 | .path_to_root(db) | 272 | .path_to_root(db) |
285 | .into_iter() | 273 | .into_iter() |
286 | .rev() | 274 | .rev() |
287 | .map(|it| it.name(db).map(|name| name.to_string())), | 275 | .flat_map(|it| it.name(db).map(|name| name.to_string())); |
288 | ) | 276 | crate_name.into_iter().chain(module_path).chain(item_name).join("::") |
289 | .chain(once(name)) | ||
290 | .flatten() | ||
291 | .join("::") | ||
292 | } | ||
293 | |||
294 | // returns None only for ModuleDef::BuiltinType | ||
295 | fn mod_path(db: &RootDatabase, item: &ModuleDef) -> Option<String> { | ||
296 | Some(determine_mod_path(db, item.module(db)?, item.name(db).map(|name| name.to_string()))) | ||
297 | } | 277 | } |
298 | 278 | ||
299 | fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { | 279 | fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { |
300 | def.module(db).map(|module| determine_mod_path(db, module, definition_owner_name(db, def))) | 280 | def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def))) |
301 | } | 281 | } |
302 | 282 | ||
303 | fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> { | 283 | fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { |
304 | let mod_path = definition_mod_path(db, &def); | 284 | let mod_path = definition_mod_path(db, &def); |
305 | return match def { | 285 | return match def { |
306 | Definition::Macro(it) => { | 286 | Definition::Macro(it) => { |
307 | let src = it.source(db); | 287 | let src = it.source(db); |
308 | let docs = Documentation::from_ast(&src.value).map(Into::into); | 288 | let docs = Documentation::from_ast(&src.value).map(Into::into); |
309 | hover_text(docs, Some(macro_label(&src.value)), mod_path) | 289 | hover_markup(docs, Some(macro_label(&src.value)), mod_path) |
310 | } | 290 | } |
311 | Definition::Field(it) => { | 291 | Definition::Field(it) => { |
312 | let src = it.source(db); | 292 | let src = it.source(db); |
313 | match src.value { | 293 | match src.value { |
314 | FieldSource::Named(it) => { | 294 | FieldSource::Named(it) => { |
315 | let docs = Documentation::from_ast(&it).map(Into::into); | 295 | let docs = Documentation::from_ast(&it).map(Into::into); |
316 | hover_text(docs, it.short_label(), mod_path) | 296 | hover_markup(docs, it.short_label(), mod_path) |
317 | } | 297 | } |
318 | _ => None, | 298 | _ => None, |
319 | } | 299 | } |
@@ -322,7 +302,7 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
322 | ModuleDef::Module(it) => match it.definition_source(db).value { | 302 | ModuleDef::Module(it) => match it.definition_source(db).value { |
323 | ModuleSource::Module(it) => { | 303 | ModuleSource::Module(it) => { |
324 | let docs = Documentation::from_ast(&it).map(Into::into); | 304 | let docs = Documentation::from_ast(&it).map(Into::into); |
325 | hover_text(docs, it.short_label(), mod_path) | 305 | hover_markup(docs, it.short_label(), mod_path) |
326 | } | 306 | } |
327 | _ => None, | 307 | _ => None, |
328 | }, | 308 | }, |
@@ -335,23 +315,23 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
335 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), | 315 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), |
336 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), | 316 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), |
337 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), | 317 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), |
338 | ModuleDef::BuiltinType(it) => Some(it.to_string()), | 318 | ModuleDef::BuiltinType(it) => return Some(it.to_string().into()), |
339 | }, | 319 | }, |
340 | Definition::Local(it) => Some(rust_code_markup(&it.ty(db).display(db))), | 320 | Definition::Local(it) => return Some(Markup::fenced_block(&it.ty(db).display(db))), |
341 | Definition::TypeParam(_) | Definition::SelfType(_) => { | 321 | Definition::TypeParam(_) | Definition::SelfType(_) => { |
342 | // FIXME: Hover for generic param | 322 | // FIXME: Hover for generic param |
343 | None | 323 | None |
344 | } | 324 | } |
345 | }; | 325 | }; |
346 | 326 | ||
347 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String> | 327 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> |
348 | where | 328 | where |
349 | D: HasSource<Ast = A>, | 329 | D: HasSource<Ast = A>, |
350 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner, | 330 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner, |
351 | { | 331 | { |
352 | let src = def.source(db); | 332 | let src = def.source(db); |
353 | let docs = Documentation::from_ast(&src.value).map(Into::into); | 333 | let docs = Documentation::from_ast(&src.value).map(Into::into); |
354 | hover_text(docs, src.value.short_label(), mod_path) | 334 | hover_markup(docs, src.value.short_label(), mod_path) |
355 | } | 335 | } |
356 | } | 336 | } |
357 | 337 | ||
@@ -388,7 +368,7 @@ mod tests { | |||
388 | let content = analysis.db.file_text(position.file_id); | 368 | let content = analysis.db.file_text(position.file_id); |
389 | let hovered_element = &content[hover.range]; | 369 | let hovered_element = &content[hover.range]; |
390 | 370 | ||
391 | let actual = format!("{}:\n{}\n", hovered_element, hover.info.markup); | 371 | let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup); |
392 | expect.assert_eq(&actual) | 372 | expect.assert_eq(&actual) |
393 | } | 373 | } |
394 | 374 | ||
@@ -409,7 +389,7 @@ fn main() { | |||
409 | } | 389 | } |
410 | "#, | 390 | "#, |
411 | expect![[r#" | 391 | expect![[r#" |
412 | foo(): | 392 | *foo()* |
413 | ```rust | 393 | ```rust |
414 | u32 | 394 | u32 |
415 | ``` | 395 | ``` |
@@ -441,7 +421,7 @@ fn main() { | |||
441 | } | 421 | } |
442 | "#, | 422 | "#, |
443 | expect![[r#" | 423 | expect![[r#" |
444 | iter: | 424 | *iter* |
445 | ```rust | 425 | ```rust |
446 | Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>> | 426 | Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>> |
447 | ``` | 427 | ``` |
@@ -459,7 +439,7 @@ pub fn foo() -> u32 { 1 } | |||
459 | fn main() { let foo_test = fo<|>o(); } | 439 | fn main() { let foo_test = fo<|>o(); } |
460 | "#, | 440 | "#, |
461 | expect![[r#" | 441 | expect![[r#" |
462 | foo: | 442 | *foo* |
463 | ```rust | 443 | ```rust |
464 | pub fn foo() -> u32 | 444 | pub fn foo() -> u32 |
465 | ``` | 445 | ``` |
@@ -486,7 +466,7 @@ mod c; | |||
486 | fn main() { let foo_test = fo<|>o(); } | 466 | fn main() { let foo_test = fo<|>o(); } |
487 | "#, | 467 | "#, |
488 | expect![[r#" | 468 | expect![[r#" |
489 | foo: | 469 | *foo* |
490 | ```rust | 470 | ```rust |
491 | {unknown} | 471 | {unknown} |
492 | ``` | 472 | ``` |
@@ -503,7 +483,7 @@ pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { } | |||
503 | fn main() { let foo_test = fo<|>o(); } | 483 | fn main() { let foo_test = fo<|>o(); } |
504 | "#, | 484 | "#, |
505 | expect![[r#" | 485 | expect![[r#" |
506 | foo: | 486 | *foo* |
507 | ```rust | 487 | ```rust |
508 | pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str | 488 | pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str |
509 | ``` | 489 | ``` |
@@ -520,7 +500,7 @@ pub fn foo<|>(a: u32, b: u32) -> u32 {} | |||
520 | fn main() { } | 500 | fn main() { } |
521 | "#, | 501 | "#, |
522 | expect![[r#" | 502 | expect![[r#" |
523 | foo: | 503 | *foo* |
524 | ```rust | 504 | ```rust |
525 | pub fn foo(a: u32, b: u32) -> u32 | 505 | pub fn foo(a: u32, b: u32) -> u32 |
526 | ``` | 506 | ``` |
@@ -540,7 +520,7 @@ fn main() { | |||
540 | } | 520 | } |
541 | "#, | 521 | "#, |
542 | expect![[r#" | 522 | expect![[r#" |
543 | field_a: | 523 | *field_a* |
544 | ```rust | 524 | ```rust |
545 | Foo | 525 | Foo |
546 | ``` | 526 | ``` |
@@ -561,7 +541,7 @@ fn main() { | |||
561 | } | 541 | } |
562 | "#, | 542 | "#, |
563 | expect![[r#" | 543 | expect![[r#" |
564 | field_a: | 544 | *field_a* |
565 | ```rust | 545 | ```rust |
566 | Foo | 546 | Foo |
567 | ``` | 547 | ``` |
@@ -578,7 +558,7 @@ fn main() { | |||
578 | check( | 558 | check( |
579 | r#"const foo<|>: u32 = 0;"#, | 559 | r#"const foo<|>: u32 = 0;"#, |
580 | expect![[r#" | 560 | expect![[r#" |
581 | foo: | 561 | *foo* |
582 | ```rust | 562 | ```rust |
583 | const foo: u32 | 563 | const foo: u32 |
584 | ``` | 564 | ``` |
@@ -587,7 +567,7 @@ fn main() { | |||
587 | check( | 567 | check( |
588 | r#"static foo<|>: u32 = 0;"#, | 568 | r#"static foo<|>: u32 = 0;"#, |
589 | expect![[r#" | 569 | expect![[r#" |
590 | foo: | 570 | *foo* |
591 | ```rust | 571 | ```rust |
592 | static foo: u32 | 572 | static foo: u32 |
593 | ``` | 573 | ``` |
@@ -605,7 +585,7 @@ fn main() { | |||
605 | let zz<|> = Test { t: 23u8, k: 33 }; | 585 | let zz<|> = Test { t: 23u8, k: 33 }; |
606 | }"#, | 586 | }"#, |
607 | expect![[r#" | 587 | expect![[r#" |
608 | zz: | 588 | *zz* |
609 | ```rust | 589 | ```rust |
610 | Test<i32, u8> | 590 | Test<i32, u8> |
611 | ``` | 591 | ``` |
@@ -623,7 +603,7 @@ use Option::Some; | |||
623 | fn main() { So<|>me(12); } | 603 | fn main() { So<|>me(12); } |
624 | "#, | 604 | "#, |
625 | expect![[r#" | 605 | expect![[r#" |
626 | Some: | 606 | *Some* |
627 | ```rust | 607 | ```rust |
628 | Option | 608 | Option |
629 | ``` | 609 | ``` |
@@ -642,7 +622,7 @@ use Option::Some; | |||
642 | fn main() { let b<|>ar = Some(12); } | 622 | fn main() { let b<|>ar = Some(12); } |
643 | "#, | 623 | "#, |
644 | expect![[r#" | 624 | expect![[r#" |
645 | bar: | 625 | *bar* |
646 | ```rust | 626 | ```rust |
647 | Option<i32> | 627 | Option<i32> |
648 | ``` | 628 | ``` |
@@ -660,7 +640,7 @@ enum Option<T> { | |||
660 | } | 640 | } |
661 | "#, | 641 | "#, |
662 | expect![[r#" | 642 | expect![[r#" |
663 | None: | 643 | *None* |
664 | ```rust | 644 | ```rust |
665 | Option | 645 | Option |
666 | ``` | 646 | ``` |
@@ -685,7 +665,7 @@ fn main() { | |||
685 | } | 665 | } |
686 | "#, | 666 | "#, |
687 | expect![[r#" | 667 | expect![[r#" |
688 | Some: | 668 | *Some* |
689 | ```rust | 669 | ```rust |
690 | Option | 670 | Option |
691 | ``` | 671 | ``` |
@@ -705,7 +685,7 @@ fn main() { | |||
705 | check( | 685 | check( |
706 | r#"fn func(foo: i32) { fo<|>o; }"#, | 686 | r#"fn func(foo: i32) { fo<|>o; }"#, |
707 | expect![[r#" | 687 | expect![[r#" |
708 | foo: | 688 | *foo* |
709 | ```rust | 689 | ```rust |
710 | i32 | 690 | i32 |
711 | ``` | 691 | ``` |
@@ -718,7 +698,7 @@ fn main() { | |||
718 | check( | 698 | check( |
719 | r#"fn func(fo<|>o: i32) {}"#, | 699 | r#"fn func(fo<|>o: i32) {}"#, |
720 | expect![[r#" | 700 | expect![[r#" |
721 | foo: | 701 | *foo* |
722 | ```rust | 702 | ```rust |
723 | i32 | 703 | i32 |
724 | ``` | 704 | ``` |
@@ -731,7 +711,7 @@ fn main() { | |||
731 | check( | 711 | check( |
732 | r#"fn func(foo: i32) { if true { <|>foo; }; }"#, | 712 | r#"fn func(foo: i32) { if true { <|>foo; }; }"#, |
733 | expect![[r#" | 713 | expect![[r#" |
734 | foo: | 714 | *foo* |
735 | ```rust | 715 | ```rust |
736 | i32 | 716 | i32 |
737 | ``` | 717 | ``` |
@@ -744,7 +724,7 @@ fn main() { | |||
744 | check( | 724 | check( |
745 | r#"fn func(<|>foo: i32) {}"#, | 725 | r#"fn func(<|>foo: i32) {}"#, |
746 | expect![[r#" | 726 | expect![[r#" |
747 | foo: | 727 | *foo* |
748 | ```rust | 728 | ```rust |
749 | i32 | 729 | i32 |
750 | ``` | 730 | ``` |
@@ -765,7 +745,7 @@ impl Thing { | |||
765 | fn main() { let foo_<|>test = Thing::new(); } | 745 | fn main() { let foo_<|>test = Thing::new(); } |
766 | "#, | 746 | "#, |
767 | expect![[r#" | 747 | expect![[r#" |
768 | foo_test: | 748 | *foo_test* |
769 | ```rust | 749 | ```rust |
770 | Thing | 750 | Thing |
771 | ``` | 751 | ``` |
@@ -788,7 +768,7 @@ mod wrapper { | |||
788 | fn main() { let foo_test = wrapper::Thing::new<|>(); } | 768 | fn main() { let foo_test = wrapper::Thing::new<|>(); } |
789 | "#, | 769 | "#, |
790 | expect![[r#" | 770 | expect![[r#" |
791 | new: | 771 | *new* |
792 | ```rust | 772 | ```rust |
793 | wrapper::Thing | 773 | wrapper::Thing |
794 | ``` | 774 | ``` |
@@ -818,7 +798,7 @@ fn main() { | |||
818 | } | 798 | } |
819 | "#, | 799 | "#, |
820 | expect![[r#" | 800 | expect![[r#" |
821 | C: | 801 | *C* |
822 | ```rust | 802 | ```rust |
823 | const C: u32 | 803 | const C: u32 |
824 | ``` | 804 | ``` |
@@ -836,7 +816,7 @@ impl Thing { | |||
836 | } | 816 | } |
837 | "#, | 817 | "#, |
838 | expect![[r#" | 818 | expect![[r#" |
839 | Self { x: 0 }: | 819 | *Self { x: 0 }* |
840 | ```rust | 820 | ```rust |
841 | Thing | 821 | Thing |
842 | ``` | 822 | ``` |
@@ -895,7 +875,7 @@ fn y() { | |||
895 | } | 875 | } |
896 | "#, | 876 | "#, |
897 | expect![[r#" | 877 | expect![[r#" |
898 | x: | 878 | *x* |
899 | ```rust | 879 | ```rust |
900 | i32 | 880 | i32 |
901 | ``` | 881 | ``` |
@@ -912,7 +892,7 @@ macro_rules! foo { () => {} } | |||
912 | fn f() { fo<|>o!(); } | 892 | fn f() { fo<|>o!(); } |
913 | "#, | 893 | "#, |
914 | expect![[r#" | 894 | expect![[r#" |
915 | foo: | 895 | *foo* |
916 | ```rust | 896 | ```rust |
917 | macro_rules! foo | 897 | macro_rules! foo |
918 | ``` | 898 | ``` |
@@ -925,7 +905,7 @@ fn f() { fo<|>o!(); } | |||
925 | check( | 905 | check( |
926 | r#"struct TS(String, i32<|>);"#, | 906 | r#"struct TS(String, i32<|>);"#, |
927 | expect![[r#" | 907 | expect![[r#" |
928 | i32: | 908 | *i32* |
929 | i32 | 909 | i32 |
930 | "#]], | 910 | "#]], |
931 | ) | 911 | ) |
@@ -942,7 +922,7 @@ id! { | |||
942 | } | 922 | } |
943 | "#, | 923 | "#, |
944 | expect![[r#" | 924 | expect![[r#" |
945 | foo: | 925 | *foo* |
946 | ```rust | 926 | ```rust |
947 | fn foo() | 927 | fn foo() |
948 | ``` | 928 | ``` |
@@ -958,7 +938,7 @@ macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | |||
958 | fn foo(bar:u32) { let a = id!(ba<|>r); } | 938 | fn foo(bar:u32) { let a = id!(ba<|>r); } |
959 | "#, | 939 | "#, |
960 | expect![[r#" | 940 | expect![[r#" |
961 | bar: | 941 | *bar* |
962 | ```rust | 942 | ```rust |
963 | u32 | 943 | u32 |
964 | ``` | 944 | ``` |
@@ -975,7 +955,7 @@ macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } | |||
975 | fn foo(bar:u32) { let a = id!(ba<|>r); } | 955 | fn foo(bar:u32) { let a = id!(ba<|>r); } |
976 | "#, | 956 | "#, |
977 | expect![[r#" | 957 | expect![[r#" |
978 | bar: | 958 | *bar* |
979 | ```rust | 959 | ```rust |
980 | u32 | 960 | u32 |
981 | ``` | 961 | ``` |
@@ -993,7 +973,7 @@ fn bar() -> u32 { 0 } | |||
993 | fn foo() { let a = id!([0u32, bar(<|>)] ); } | 973 | fn foo() { let a = id!([0u32, bar(<|>)] ); } |
994 | "#, | 974 | "#, |
995 | expect![[r#" | 975 | expect![[r#" |
996 | bar(): | 976 | *bar()* |
997 | ```rust | 977 | ```rust |
998 | u32 | 978 | u32 |
999 | ``` | 979 | ``` |
@@ -1012,7 +992,7 @@ fn foo() { | |||
1012 | } | 992 | } |
1013 | "#, | 993 | "#, |
1014 | expect![[r#" | 994 | expect![[r#" |
1015 | "Tracks": | 995 | *"Tracks"* |
1016 | ```rust | 996 | ```rust |
1017 | &str | 997 | &str |
1018 | ``` | 998 | ``` |
@@ -1033,7 +1013,7 @@ fn foo() { | |||
1033 | } | 1013 | } |
1034 | "#, | 1014 | "#, |
1035 | expect![[r#" | 1015 | expect![[r#" |
1036 | bar: | 1016 | *bar* |
1037 | ```rust | 1017 | ```rust |
1038 | fn bar() -> bool | 1018 | fn bar() -> bool |
1039 | ``` | 1019 | ``` |
@@ -1065,7 +1045,7 @@ fn foo() { } | |||
1065 | fn bar() { fo<|>o(); } | 1045 | fn bar() { fo<|>o(); } |
1066 | ", | 1046 | ", |
1067 | expect![[r#" | 1047 | expect![[r#" |
1068 | foo: | 1048 | *foo* |
1069 | ```rust | 1049 | ```rust |
1070 | fn foo() | 1050 | fn foo() |
1071 | ``` | 1051 | ``` |
@@ -1081,7 +1061,7 @@ fn bar() { fo<|>o(); } | |||
1081 | check( | 1061 | check( |
1082 | r#"async fn foo<|>() {}"#, | 1062 | r#"async fn foo<|>() {}"#, |
1083 | expect![[r#" | 1063 | expect![[r#" |
1084 | foo: | 1064 | *foo* |
1085 | ```rust | 1065 | ```rust |
1086 | async fn foo() | 1066 | async fn foo() |
1087 | ``` | 1067 | ``` |
@@ -1090,7 +1070,7 @@ fn bar() { fo<|>o(); } | |||
1090 | check( | 1070 | check( |
1091 | r#"pub const unsafe fn foo<|>() {}"#, | 1071 | r#"pub const unsafe fn foo<|>() {}"#, |
1092 | expect![[r#" | 1072 | expect![[r#" |
1093 | foo: | 1073 | *foo* |
1094 | ```rust | 1074 | ```rust |
1095 | pub const unsafe fn foo() | 1075 | pub const unsafe fn foo() |
1096 | ``` | 1076 | ``` |
@@ -1099,7 +1079,7 @@ fn bar() { fo<|>o(); } | |||
1099 | check( | 1079 | check( |
1100 | r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#, | 1080 | r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#, |
1101 | expect![[r#" | 1081 | expect![[r#" |
1102 | foo: | 1082 | *foo* |
1103 | ```rust | 1083 | ```rust |
1104 | pub(crate) async unsafe extern "C" fn foo() | 1084 | pub(crate) async unsafe extern "C" fn foo() |
1105 | ``` | 1085 | ``` |
@@ -1136,7 +1116,7 @@ mod my { pub struct Bar; } | |||
1136 | fn my() {} | 1116 | fn my() {} |
1137 | "#, | 1117 | "#, |
1138 | expect![[r#" | 1118 | expect![[r#" |
1139 | my: | 1119 | *my* |
1140 | ```rust | 1120 | ```rust |
1141 | mod my | 1121 | mod my |
1142 | ``` | 1122 | ``` |
@@ -1154,7 +1134,7 @@ struct Bar; | |||
1154 | fn foo() { let bar = Ba<|>r; } | 1134 | fn foo() { let bar = Ba<|>r; } |
1155 | "#, | 1135 | "#, |
1156 | expect![[r#" | 1136 | expect![[r#" |
1157 | Bar: | 1137 | *Bar* |
1158 | ```rust | 1138 | ```rust |
1159 | struct Bar | 1139 | struct Bar |
1160 | ``` | 1140 | ``` |
@@ -1175,7 +1155,7 @@ struct Bar; | |||
1175 | fn foo() { let bar = Ba<|>r; } | 1155 | fn foo() { let bar = Ba<|>r; } |
1176 | "#, | 1156 | "#, |
1177 | expect![[r#" | 1157 | expect![[r#" |
1178 | Bar: | 1158 | *Bar* |
1179 | ```rust | 1159 | ```rust |
1180 | struct Bar | 1160 | struct Bar |
1181 | ``` | 1161 | ``` |
@@ -1198,7 +1178,7 @@ struct Bar; | |||
1198 | fn foo() { let bar = Ba<|>r; } | 1178 | fn foo() { let bar = Ba<|>r; } |
1199 | "#, | 1179 | "#, |
1200 | expect![[r#" | 1180 | expect![[r#" |
1201 | Bar: | 1181 | *Bar* |
1202 | ```rust | 1182 | ```rust |
1203 | struct Bar | 1183 | struct Bar |
1204 | ``` | 1184 | ``` |
@@ -1234,7 +1214,7 @@ bar!(); | |||
1234 | fn foo() { let bar = Bar; bar.fo<|>o(); } | 1214 | fn foo() { let bar = Bar; bar.fo<|>o(); } |
1235 | "#, | 1215 | "#, |
1236 | expect![[r#" | 1216 | expect![[r#" |
1237 | foo: | 1217 | *foo* |
1238 | ```rust | 1218 | ```rust |
1239 | Bar | 1219 | Bar |
1240 | ``` | 1220 | ``` |
@@ -1270,7 +1250,7 @@ bar!(); | |||
1270 | fn foo() { let bar = Bar; bar.fo<|>o(); } | 1250 | fn foo() { let bar = Bar; bar.fo<|>o(); } |
1271 | "#, | 1251 | "#, |
1272 | expect![[r#" | 1252 | expect![[r#" |
1273 | foo: | 1253 | *foo* |
1274 | ```rust | 1254 | ```rust |
1275 | Bar | 1255 | Bar |
1276 | ``` | 1256 | ``` |
diff --git a/crates/ra_ide/src/markup.rs b/crates/ra_ide/src/markup.rs index 2f2b3cc25..60c193c40 100644 --- a/crates/ra_ide/src/markup.rs +++ b/crates/ra_ide/src/markup.rs | |||
@@ -16,6 +16,12 @@ impl From<Markup> for String { | |||
16 | } | 16 | } |
17 | } | 17 | } |
18 | 18 | ||
19 | impl From<String> for Markup { | ||
20 | fn from(text: String) -> Self { | ||
21 | Markup { text } | ||
22 | } | ||
23 | } | ||
24 | |||
19 | impl fmt::Display for Markup { | 25 | impl fmt::Display for Markup { |
20 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 26 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
21 | fmt::Display::fmt(&self.text, f) | 27 | fmt::Display::fmt(&self.text, f) |
@@ -26,13 +32,7 @@ impl Markup { | |||
26 | pub fn as_str(&self) -> &str { | 32 | pub fn as_str(&self) -> &str { |
27 | self.text.as_str() | 33 | self.text.as_str() |
28 | } | 34 | } |
29 | pub fn is_empty(&self) -> bool { | 35 | pub fn fenced_block(contents: &impl fmt::Display) -> Markup { |
30 | self.text.is_empty() | 36 | format!("```rust\n{}\n```", contents).into() |
31 | } | ||
32 | pub fn push_section(&mut self, section: &str) { | ||
33 | if !self.text.is_empty() { | ||
34 | self.text.push_str("\n\n___\n"); | ||
35 | } | ||
36 | self.text.push_str(section); | ||
37 | } | 37 | } |
38 | } | 38 | } |