aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Pullar-Strecker <[email protected]>2020-06-09 04:43:57 +0100
committerZac Pullar-Strecker <[email protected]>2020-06-30 09:02:46 +0100
commit2023af53f09ed9466c6d7442d6830276eba19b45 (patch)
tree84924a0e47a70b0255b1811f127147e9a9d92682
parent2bd717139918e15e537dcd833bb003e85d24b3d1 (diff)
Hover doc link rewriting
-rw-r--r--Cargo.lock236
-rw-r--r--crates/ra_ide/Cargo.toml4
-rw-r--r--crates/ra_ide/src/hover.rs102
-rw-r--r--crates/ra_ide/src/lib.rs5
-rw-r--r--crates/ra_syntax/src/ast/test.txt15
-rw-r--r--crates/ra_syntax/src/ast/traits.rs36
-rw-r--r--crates/rust-analyzer/src/handlers.rs1
7 files changed, 382 insertions, 17 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ca3d14a09..bc36f0fab 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -95,6 +95,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
95checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 95checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
96 96
97[[package]] 97[[package]]
98name = "block-buffer"
99version = "0.7.3"
100source = "registry+https://github.com/rust-lang/crates.io-index"
101checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
102dependencies = [
103 "block-padding",
104 "byte-tools",
105 "byteorder",
106 "generic-array",
107]
108
109[[package]]
110name = "block-padding"
111version = "0.1.5"
112source = "registry+https://github.com/rust-lang/crates.io-index"
113checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
114dependencies = [
115 "byte-tools",
116]
117
118[[package]]
98name = "bstr" 119name = "bstr"
99version = "0.2.13" 120version = "0.2.13"
100source = "registry+https://github.com/rust-lang/crates.io-index" 121source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -104,6 +125,12 @@ dependencies = [
104] 125]
105 126
106[[package]] 127[[package]]
128name = "byte-tools"
129version = "0.3.1"
130source = "registry+https://github.com/rust-lang/crates.io-index"
131checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
132
133[[package]]
107name = "byteorder" 134name = "byteorder"
108version = "1.3.4" 135version = "1.3.4"
109source = "registry+https://github.com/rust-lang/crates.io-index" 136source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -196,15 +223,18 @@ dependencies = [
196] 223]
197 224
198[[package]] 225[[package]]
199name = "clicolors-control" 226name = "clap"
200version = "1.0.1" 227version = "2.33.1"
201source = "registry+https://github.com/rust-lang/crates.io-index" 228source = "registry+https://github.com/rust-lang/crates.io-index"
202checksum = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" 229checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
203dependencies = [ 230dependencies = [
231 "ansi_term",
204 "atty", 232 "atty",
205 "lazy_static", 233 "bitflags",
206 "libc", 234 "strsim",
207 "winapi 0.3.9", 235 "textwrap",
236 "unicode-width",
237 "vec_map",
208] 238]
209 239
210[[package]] 240[[package]]
@@ -217,12 +247,28 @@ dependencies = [
217] 247]
218 248
219[[package]] 249[[package]]
250name = "comrak"
251version = "0.7.0"
252source = "registry+https://github.com/rust-lang/crates.io-index"
253checksum = "e17058cc536cf290563e88787d7b9e6030ce4742943017cc2ffb71f88034021c"
254dependencies = [
255 "clap",
256 "entities",
257 "lazy_static",
258 "pest",
259 "pest_derive",
260 "regex",
261 "twoway",
262 "typed-arena",
263 "unicode_categories",
264]
265
266[[package]]
220name = "console" 267name = "console"
221version = "0.10.3" 268version = "0.11.3"
222source = "registry+https://github.com/rust-lang/crates.io-index" 269source = "registry+https://github.com/rust-lang/crates.io-index"
223checksum = "2586208b33573b7f76ccfbe5adb076394c88deaf81b84d7213969805b0a952a7" 270checksum = "8c0994e656bba7b922d8dd1245db90672ffb701e684e45be58f20719d69abc5a"
224dependencies = [ 271dependencies = [
225 "clicolors-control",
226 "encode_unicode", 272 "encode_unicode",
227 "lazy_static", 273 "lazy_static",
228 "libc", 274 "libc",
@@ -310,6 +356,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
310checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 356checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
311 357
312[[package]] 358[[package]]
359name = "digest"
360version = "0.8.1"
361source = "registry+https://github.com/rust-lang/crates.io-index"
362checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
363dependencies = [
364 "generic-array",
365]
366
367[[package]]
313name = "drop_bomb" 368name = "drop_bomb"
314version = "0.1.4" 369version = "0.1.4"
315source = "registry+https://github.com/rust-lang/crates.io-index" 370source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -343,6 +398,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
343checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 398checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
344 399
345[[package]] 400[[package]]
401name = "entities"
402version = "1.0.1"
403source = "registry+https://github.com/rust-lang/crates.io-index"
404checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca"
405
406[[package]]
346name = "env_logger" 407name = "env_logger"
347version = "0.7.1" 408version = "0.7.1"
348source = "registry+https://github.com/rust-lang/crates.io-index" 409source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -352,6 +413,12 @@ dependencies = [
352] 413]
353 414
354[[package]] 415[[package]]
416name = "fake-simd"
417version = "0.1.2"
418source = "registry+https://github.com/rust-lang/crates.io-index"
419checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
420
421[[package]]
355name = "filetime" 422name = "filetime"
356version = "0.2.10" 423version = "0.2.10"
357source = "registry+https://github.com/rust-lang/crates.io-index" 424source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -435,6 +502,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
435checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 502checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
436 503
437[[package]] 504[[package]]
505name = "generic-array"
506version = "0.12.3"
507source = "registry+https://github.com/rust-lang/crates.io-index"
508checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
509dependencies = [
510 "typenum",
511]
512
513[[package]]
438name = "getrandom" 514name = "getrandom"
439version = "0.1.14" 515version = "0.1.14"
440source = "registry+https://github.com/rust-lang/crates.io-index" 516source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -544,9 +620,9 @@ dependencies = [
544 620
545[[package]] 621[[package]]
546name = "insta" 622name = "insta"
547version = "0.16.0" 623version = "0.16.1"
548source = "registry+https://github.com/rust-lang/crates.io-index" 624source = "registry+https://github.com/rust-lang/crates.io-index"
549checksum = "8386e795fb3927131ea4cede203c529a333652eb6dc4ff29616b832b27e9b096" 625checksum = "617e921abc813f96a3b00958c079e7bf1e2db998f8a04f1546dd967373a418ee"
550dependencies = [ 626dependencies = [
551 "console", 627 "console",
552 "difference", 628 "difference",
@@ -712,6 +788,12 @@ dependencies = [
712] 788]
713 789
714[[package]] 790[[package]]
791name = "maplit"
792version = "1.0.2"
793source = "registry+https://github.com/rust-lang/crates.io-index"
794checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
795
796[[package]]
715name = "matchers" 797name = "matchers"
716version = "0.0.1" 798version = "0.0.1"
717source = "registry+https://github.com/rust-lang/crates.io-index" 799source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -882,6 +964,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
882checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" 964checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
883 965
884[[package]] 966[[package]]
967name = "opaque-debug"
968version = "0.2.3"
969source = "registry+https://github.com/rust-lang/crates.io-index"
970checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
971
972[[package]]
885name = "parking_lot" 973name = "parking_lot"
886version = "0.11.0" 974version = "0.11.0"
887source = "registry+https://github.com/rust-lang/crates.io-index" 975source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -937,6 +1025,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
937checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1025checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
938 1026
939[[package]] 1027[[package]]
1028name = "pest"
1029version = "2.1.3"
1030source = "registry+https://github.com/rust-lang/crates.io-index"
1031checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
1032dependencies = [
1033 "ucd-trie",
1034]
1035
1036[[package]]
1037name = "pest_derive"
1038version = "2.1.0"
1039source = "registry+https://github.com/rust-lang/crates.io-index"
1040checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
1041dependencies = [
1042 "pest",
1043 "pest_generator",
1044]
1045
1046[[package]]
1047name = "pest_generator"
1048version = "2.1.3"
1049source = "registry+https://github.com/rust-lang/crates.io-index"
1050checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
1051dependencies = [
1052 "pest",
1053 "pest_meta",
1054 "proc-macro2",
1055 "quote",
1056 "syn",
1057]
1058
1059[[package]]
1060name = "pest_meta"
1061version = "2.1.3"
1062source = "registry+https://github.com/rust-lang/crates.io-index"
1063checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
1064dependencies = [
1065 "maplit",
1066 "pest",
1067 "sha-1",
1068]
1069
1070[[package]]
940name = "petgraph" 1071name = "petgraph"
941version = "0.5.1" 1072version = "0.5.1"
942source = "registry+https://github.com/rust-lang/crates.io-index" 1073source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1133,6 +1264,7 @@ dependencies = [
1133name = "ra_ide" 1264name = "ra_ide"
1134version = "0.1.0" 1265version = "0.1.0"
1135dependencies = [ 1266dependencies = [
1267 "comrak",
1136 "either", 1268 "either",
1137 "indexmap", 1269 "indexmap",
1138 "insta", 1270 "insta",
@@ -1143,8 +1275,10 @@ dependencies = [
1143 "ra_db", 1275 "ra_db",
1144 "ra_fmt", 1276 "ra_fmt",
1145 "ra_hir", 1277 "ra_hir",
1278 "ra_hir_def",
1146 "ra_ide_db", 1279 "ra_ide_db",
1147 "ra_prof", 1280 "ra_prof",
1281 "ra_project_model",
1148 "ra_ssr", 1282 "ra_ssr",
1149 "ra_syntax", 1283 "ra_syntax",
1150 "ra_text_edit", 1284 "ra_text_edit",
@@ -1152,6 +1286,7 @@ dependencies = [
1152 "rustc-hash", 1286 "rustc-hash",
1153 "stdx", 1287 "stdx",
1154 "test_utils", 1288 "test_utils",
1289 "url",
1155] 1290]
1156 1291
1157[[package]] 1292[[package]]
@@ -1654,6 +1789,18 @@ dependencies = [
1654] 1789]
1655 1790
1656[[package]] 1791[[package]]
1792name = "sha-1"
1793version = "0.8.2"
1794source = "registry+https://github.com/rust-lang/crates.io-index"
1795checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
1796dependencies = [
1797 "block-buffer",
1798 "digest",
1799 "fake-simd",
1800 "opaque-debug",
1801]
1802
1803[[package]]
1657name = "sharded-slab" 1804name = "sharded-slab"
1658version = "0.0.9" 1805version = "0.0.9"
1659source = "registry+https://github.com/rust-lang/crates.io-index" 1806source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1688,6 +1835,12 @@ name = "stdx"
1688version = "0.1.0" 1835version = "0.1.0"
1689 1836
1690[[package]] 1837[[package]]
1838name = "strsim"
1839version = "0.8.0"
1840source = "registry+https://github.com/rust-lang/crates.io-index"
1841checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
1842
1843[[package]]
1691name = "superslice" 1844name = "superslice"
1692version = "1.0.0" 1845version = "1.0.0"
1693source = "registry+https://github.com/rust-lang/crates.io-index" 1846source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1767,6 +1920,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1767checksum = "f03e7efdedc3bc78cb2337f1e2785c39e45f5ef762d9e4ebb137fff7380a6d8a" 1920checksum = "f03e7efdedc3bc78cb2337f1e2785c39e45f5ef762d9e4ebb137fff7380a6d8a"
1768 1921
1769[[package]] 1922[[package]]
1923name = "textwrap"
1924version = "0.11.0"
1925source = "registry+https://github.com/rust-lang/crates.io-index"
1926checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
1927dependencies = [
1928 "unicode-width",
1929]
1930
1931[[package]]
1770name = "thin-dst" 1932name = "thin-dst"
1771version = "1.1.0" 1933version = "1.1.0"
1772source = "registry+https://github.com/rust-lang/crates.io-index" 1934source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1879,6 +2041,40 @@ dependencies = [
1879] 2041]
1880 2042
1881[[package]] 2043[[package]]
2044name = "twoway"
2045version = "0.2.1"
2046source = "registry+https://github.com/rust-lang/crates.io-index"
2047checksum = "6b40075910de3a912adbd80b5d8bad6ad10a23eeb1f5bf9d4006839e899ba5bc"
2048dependencies = [
2049 "memchr",
2050 "unchecked-index",
2051]
2052
2053[[package]]
2054name = "typed-arena"
2055version = "1.7.0"
2056source = "registry+https://github.com/rust-lang/crates.io-index"
2057checksum = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d"
2058
2059[[package]]
2060name = "typenum"
2061version = "1.12.0"
2062source = "registry+https://github.com/rust-lang/crates.io-index"
2063checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
2064
2065[[package]]
2066name = "ucd-trie"
2067version = "0.1.3"
2068source = "registry+https://github.com/rust-lang/crates.io-index"
2069checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
2070
2071[[package]]
2072name = "unchecked-index"
2073version = "0.2.2"
2074source = "registry+https://github.com/rust-lang/crates.io-index"
2075checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c"
2076
2077[[package]]
1882name = "unicode-bidi" 2078name = "unicode-bidi"
1883version = "0.3.4" 2079version = "0.3.4"
1884source = "registry+https://github.com/rust-lang/crates.io-index" 2080source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1903,12 +2099,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1903checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" 2099checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
1904 2100
1905[[package]] 2101[[package]]
2102name = "unicode-width"
2103version = "0.1.8"
2104source = "registry+https://github.com/rust-lang/crates.io-index"
2105checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
2106
2107[[package]]
1906name = "unicode-xid" 2108name = "unicode-xid"
1907version = "0.2.1" 2109version = "0.2.1"
1908source = "registry+https://github.com/rust-lang/crates.io-index" 2110source = "registry+https://github.com/rust-lang/crates.io-index"
1909checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 2111checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
1910 2112
1911[[package]] 2113[[package]]
2114name = "unicode_categories"
2115version = "0.1.1"
2116source = "registry+https://github.com/rust-lang/crates.io-index"
2117checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
2118
2119[[package]]
1912name = "url" 2120name = "url"
1913version = "2.1.1" 2121version = "2.1.1"
1914source = "registry+https://github.com/rust-lang/crates.io-index" 2122source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1921,6 +2129,12 @@ dependencies = [
1921] 2129]
1922 2130
1923[[package]] 2131[[package]]
2132name = "vec_map"
2133version = "0.8.2"
2134source = "registry+https://github.com/rust-lang/crates.io-index"
2135checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
2136
2137[[package]]
1924name = "vfs" 2138name = "vfs"
1925version = "0.1.0" 2139version = "0.1.0"
1926dependencies = [ 2140dependencies = [
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml
index bbc6a5c9b..e5fdf5aa1 100644
--- a/crates/ra_ide/Cargo.toml
+++ b/crates/ra_ide/Cargo.toml
@@ -17,6 +17,8 @@ itertools = "0.9.0"
17log = "0.4.8" 17log = "0.4.8"
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19rand = { version = "0.7.3", features = ["small_rng"] } 19rand = { version = "0.7.3", features = ["small_rng"] }
20comrak = "0.7.0"
21url = "*"
20 22
21stdx = { path = "../stdx" } 23stdx = { path = "../stdx" }
22 24
@@ -30,6 +32,8 @@ ra_prof = { path = "../ra_prof" }
30test_utils = { path = "../test_utils" } 32test_utils = { path = "../test_utils" }
31ra_assists = { path = "../ra_assists" } 33ra_assists = { path = "../ra_assists" }
32ra_ssr = { path = "../ra_ssr" } 34ra_ssr = { path = "../ra_ssr" }
35ra_project_model = { path = "../ra_project_model" }
36ra_hir_def = { path = "../ra_hir_def" }
33 37
34# ra_ide should depend only on the top-level `hir` package. if you need 38# ra_ide should depend only on the top-level `hir` package. if you need
35# something from some `hir_xxx` subpackage, reexport the API via `hir`. 39# something from some `hir_xxx` subpackage, reexport the API via `hir`.
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index c3e36a387..079195184 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -1,8 +1,8 @@
1use std::iter::once; 1use std::iter::once;
2 2
3use hir::{ 3use hir::{
4 Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, 4 Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef,
5 Module, ModuleDef, ModuleSource, Semantics, 5 ModuleSource, Semantics, Module, Documentation
6}; 6};
7use itertools::Itertools; 7use itertools::Itertools;
8use ra_db::SourceDatabase; 8use ra_db::SourceDatabase;
@@ -11,6 +11,8 @@ use ra_ide_db::{
11 RootDatabase, 11 RootDatabase,
12}; 12};
13use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; 13use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset};
14use ra_project_model::ProjectWorkspace;
15use ra_hir_def::{item_scope::ItemInNs, db::DefDatabase, ModuleDefId};
14 16
15use crate::{ 17use crate::{
16 display::{ 18 display::{
@@ -65,6 +67,13 @@ pub struct HoverGotoTypeData {
65 pub nav: NavigationTarget, 67 pub nav: NavigationTarget,
66} 68}
67 69
70use std::path::{Path, PathBuf};
71use std::sync::Arc;
72use comrak::{parse_document,format_commonmark, ComrakOptions, Arena};
73use comrak::nodes::NodeValue;
74use url::Url;
75use ra_ide_db::imports_locator::ImportsLocator;
76
68/// Contains the results when hovering over an item 77/// Contains the results when hovering over an item
69#[derive(Debug, Default)] 78#[derive(Debug, Default)]
70pub struct HoverResult { 79pub struct HoverResult {
@@ -118,7 +127,7 @@ impl HoverResult {
118// 127//
119// Shows additional information, like type of an expression or documentation for definition when "focusing" code. 128// Shows additional information, like type of an expression or documentation for definition when "focusing" code.
120// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. 129// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
121pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { 130pub(crate) fn hover(db: &RootDatabase, position: FilePosition, workspaces: Arc<Vec<ProjectWorkspace>>) -> Option<RangeInfo<HoverResult>> {
122 let sema = Semantics::new(db); 131 let sema = Semantics::new(db);
123 let file = sema.parse(position.file_id).syntax().clone(); 132 let file = sema.parse(position.file_id).syntax().clone();
124 let token = pick_best(file.token_at_offset(position.offset))?; 133 let token = pick_best(file.token_at_offset(position.offset))?;
@@ -138,7 +147,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
138 } 147 }
139 } { 148 } {
140 let range = sema.original_range(&node).range; 149 let range = sema.original_range(&node).range;
141 res.extend(hover_text_from_name_kind(db, name_kind)); 150 let text = hover_text_from_name_kind(db, name_kind.clone()).map(|text| rewrite_links(db, &text, &name_kind, workspaces).unwrap_or(text));
151 res.extend(text);
142 152
143 if !res.is_empty() { 153 if !res.is_empty() {
144 if let Some(action) = show_implementations_action(db, name_kind) { 154 if let Some(action) = show_implementations_action(db, name_kind) {
@@ -379,6 +389,90 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin
379 } 389 }
380} 390}
381 391
392/// Rewrite documentation links in markdown to point to local documentation/docs.rs
393fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition, workspaces: Arc<Vec<ProjectWorkspace>>) -> Option<String> {
394 // FIXME: Fail early
395 if let (Some(name), Some(module)) = (definition.name(db), definition.module(db)) {
396 let krate_name = module.krate().display_name(db)?;
397 let arena = Arena::new();
398 let doc = parse_document(&arena, markdown, &ComrakOptions::default());
399 let path = module.path_to_root(db);
400 let mut doc_target_dirs = workspaces
401 .iter()
402 .filter_map(|workspace| if let ProjectWorkspace::Cargo{cargo: cargo_workspace, ..} = workspace {Some(cargo_workspace)} else {None})
403 .map(|workspace| workspace.workspace_root())
404 // TODO: `target` is configurable in cargo config, we should respect it
405 .map(|root| root.join("target/doc"));
406
407 iter_nodes(doc, &|node| {
408 match &mut node.data.borrow_mut().value {
409 &mut NodeValue::Link(ref mut link) => {
410 match Url::parse(&String::from_utf8(link.url.clone()).unwrap()) {
411 // If this is a valid absolute URL don't touch it
412 Ok(_) => (),
413 // If contains .html file-based link to new page
414 // If starts with #fragment file-based link to fragment on current page
415 // If contains :: module-based link
416 Err(_) => {
417 let link_str = String::from_utf8(link.url.clone()).unwrap();
418 let resolved = try_resolve_path(db, &mut doc_target_dirs.clone(), definition, &link_str)
419 .or_else(|| try_resolve_intra(db, &mut doc_target_dirs.clone(), definition, &link_str));
420
421 if let Some(resolved) = resolved {
422 link.url = resolved.as_bytes().to_vec();
423 }
424
425 }
426 }
427 },
428 _ => ()
429 }
430 });
431 let mut out = Vec::new();
432 format_commonmark(doc, &ComrakOptions::default(), &mut out);
433 Some(String::from_utf8(out).unwrap())
434 } else {
435 // eprintln!("WARN: Unable to determine name or module for hover; link rewriting disabled.");
436 None
437 }
438}
439
440/// Try to resolve path to local documentation via intra-doc-links (i.e. `super::gateway::Shard`)
441fn try_resolve_intra(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = PathBuf>, definition: &Definition, link: &str) -> Option<String> {
442 None
443}
444
445/// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`)
446fn try_resolve_path(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = PathBuf>, definition: &Definition, link: &str) -> Option<String> {
447 let ns = if let Definition::ModuleDef(moddef) = definition {
448 ItemInNs::Types(moddef.clone().into())
449 } else {
450 return None;
451 };
452 let krate = definition.module(db)?.krate();
453 let import_map = db.import_map(krate.into());
454 let base = import_map.path_of(ns).unwrap();
455 let base = base.segments.iter().map(|name| format!("{}", name)).collect::<PathBuf>();
456
457 doc_target_dirs
458 .map(|dir| dir.join(format!("{}", krate.display_name(db).unwrap())).join(base.join("..").join(link)))
459 .inspect(|path| eprintln!("candidate {}", path.display()))
460 .filter(|path| path.exists())
461 // slice out the UNC '\?\' added by canonicalize
462 .map(|path| format!("file:///{}", path.display()))
463 // \. is treated as an escape in vscode's markdown hover rendering
464 .map(|path_str| path_str.replace("\\", "/"))
465 .next()
466}
467
468fn iter_nodes<'a, F>(node: &'a comrak::nodes::AstNode<'a>, f: &F)
469 where F : Fn(&'a comrak::nodes::AstNode<'a>) {
470 f(node);
471 for c in node.children() {
472 iter_nodes(c, f);
473 }
474}
475
382fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { 476fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
383 return tokens.max_by_key(priority); 477 return tokens.max_by_key(priority);
384 fn priority(n: &SyntaxToken) -> usize { 478 fn priority(n: &SyntaxToken) -> usize {
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index ecac5134e..d56d52d30 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -54,6 +54,7 @@ use ra_ide_db::{
54 LineIndexDatabase, 54 LineIndexDatabase,
55}; 55};
56use ra_syntax::{SourceFile, TextRange, TextSize}; 56use ra_syntax::{SourceFile, TextRange, TextSize};
57use ra_project_model::ProjectWorkspace;
57 58
58use crate::display::ToNav; 59use crate::display::ToNav;
59 60
@@ -389,8 +390,8 @@ impl Analysis {
389 } 390 }
390 391
391 /// Returns a short text describing element at position. 392 /// Returns a short text describing element at position.
392 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<HoverResult>>> { 393 pub fn hover(&self, position: FilePosition, workspaces: Arc<Vec<ProjectWorkspace>>) -> Cancelable<Option<RangeInfo<HoverResult>>> {
393 self.with_db(|db| hover::hover(db, position)) 394 self.with_db(|db| hover::hover(db, position, workspaces))
394 } 395 }
395 396
396 /// Computes parameter information for the given call expression. 397 /// Computes parameter information for the given call expression.
diff --git a/crates/ra_syntax/src/ast/test.txt b/crates/ra_syntax/src/ast/test.txt
new file mode 100644
index 000000000..f746bf1e7
--- /dev/null
+++ b/crates/ra_syntax/src/ast/test.txt
@@ -0,0 +1,15 @@
1The context is a general utility struct provided on event dispatches, which
2helps with dealing with the current "context" of the event dispatch.
3The context also acts as a general high-level interface over the associated
4[`Shard`] which received the event, or the low-level [`http`] module.
5
6The context contains "shortcuts", like for interacting with the shard.
7Methods like [`set_activity`] will unlock the shard and perform an update for
8you to save a bit of work.
9
10A context will only live for the event it was dispatched for. After the
11event handler finished, it is destroyed and will not be re-used.
12
13[`Shard`]: ../gateway/struct.Shard.html
14[`http`]: ../http/index.html
15[`set_activity`]: #method.set_activity
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs
index a8f2454fd..323d78bbc 100644
--- a/crates/ra_syntax/src/ast/traits.rs
+++ b/crates/ra_syntax/src/ast/traits.rs
@@ -146,3 +146,39 @@ impl Iterator for CommentIter {
146 self.iter.by_ref().find_map(|el| el.into_token().and_then(ast::Comment::cast)) 146 self.iter.by_ref().find_map(|el| el.into_token().and_then(ast::Comment::cast))
147 } 147 }
148} 148}
149
150#[cfg(test)]
151mod tests {
152 use comrak::{parse_document,format_commonmark, ComrakOptions, Arena};
153 use comrak::nodes::{AstNode, NodeValue};
154
155 fn iter_nodes<'a, F>(node: &'a AstNode<'a>, f: &F)
156 where F : Fn(&'a AstNode<'a>) {
157 f(node);
158 for c in node.children() {
159 iter_nodes(c, f);
160 }
161 }
162
163 #[allow(non_snake_case)]
164 #[test]
165 fn test_link_rewrite() {
166 let src = include_str!("./test.txt");
167
168 let arena = Arena::new();
169 let doc = parse_document(&arena, src, &ComrakOptions::default());
170
171 iter_nodes(doc, &|node| {
172 match &mut node.data.borrow_mut().value {
173 &mut NodeValue::Link(ref mut link) => {
174 link.url = "https://www.google.com".as_bytes().to_vec();
175 },
176 _ => ()
177 }
178 });
179
180 let mut out = Vec::new();
181 format_commonmark(doc, &ComrakOptions::default(), &mut out);
182 panic!("{}", String::from_utf8(out).unwrap());
183 }
184}
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index e35a5e846..19da25f96 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -5,6 +5,7 @@
5use std::{ 5use std::{
6 io::Write as _, 6 io::Write as _,
7 process::{self, Stdio}, 7 process::{self, Stdio},
8 sync::Arc
8}; 9};
9 10
10use lsp_server::ErrorCode; 11use lsp_server::ErrorCode;