aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock266
-rw-r--r--crates/ra_db/src/lib.rs27
-rw-r--r--crates/ra_hir/src/db.rs8
-rw-r--r--crates/ra_hir/src/ids.rs9
-rw-r--r--crates/ra_hir/src/mock.rs12
-rw-r--r--crates/ra_hir/src/nameres/lower.rs2
-rw-r--r--crates/ra_hir/src/nameres/tests.rs2
-rw-r--r--crates/ra_hir/src/query_definitions.rs7
-rw-r--r--crates/ra_hir/src/source_binder.rs4
-rw-r--r--crates/ra_hir/src/ty/tests.rs4
-rw-r--r--crates/ra_ide_api/src/call_info.rs6
-rw-r--r--crates/ra_ide_api/src/completion.rs4
-rw-r--r--crates/ra_ide_api/src/db.rs24
-rw-r--r--crates/ra_ide_api/src/extend_selection.rs4
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs4
-rw-r--r--crates/ra_ide_api/src/hover.rs8
-rw-r--r--crates/ra_ide_api/src/imp.rs12
-rw-r--r--crates/ra_ide_api/src/lib.rs20
-rw-r--r--crates/ra_ide_api/src/rename.rs4
-rw-r--r--crates/ra_ide_api/src/runnables.rs4
-rw-r--r--crates/ra_ide_api/src/status.rs4
-rw-r--r--crates/ra_ide_api/src/symbol_index.rs12
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs4
-rw-r--r--crates/ra_ide_api_light/src/snapshots/tests__file_structure.snap26
-rw-r--r--crates/ra_ide_api_light/src/structure.rs1
-rw-r--r--crates/ra_syntax/src/grammar/types.rs24
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0117_macro_call_type.rs2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0117_macro_call_type.txt43
-rw-r--r--crates/ra_vfs/Cargo.toml4
-rw-r--r--crates/ra_vfs/src/io.rs131
-rw-r--r--crates/ra_vfs/src/io/watcher.rs200
-rw-r--r--crates/ra_vfs/src/lib.rs361
-rw-r--r--crates/ra_vfs/tests/vfs.rs166
33 files changed, 1092 insertions, 317 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3b8df0c8a..db09967ba 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -87,6 +87,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
87 87
88[[package]] 88[[package]]
89name = "bitflags" 89name = "bitflags"
90version = "0.7.0"
91source = "registry+https://github.com/rust-lang/crates.io-index"
92
93[[package]]
94name = "bitflags"
90version = "1.0.4" 95version = "1.0.4"
91source = "registry+https://github.com/rust-lang/crates.io-index" 96source = "registry+https://github.com/rust-lang/crates.io-index"
92 97
@@ -110,6 +115,15 @@ version = "1.3.1"
110source = "registry+https://github.com/rust-lang/crates.io-index" 115source = "registry+https://github.com/rust-lang/crates.io-index"
111 116
112[[package]] 117[[package]]
118name = "bytes"
119version = "0.4.11"
120source = "registry+https://github.com/rust-lang/crates.io-index"
121dependencies = [
122 "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
123 "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
124]
125
126[[package]]
113name = "cargo_metadata" 127name = "cargo_metadata"
114version = "0.7.1" 128version = "0.7.1"
115source = "registry+https://github.com/rust-lang/crates.io-index" 129source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -336,6 +350,16 @@ version = "0.1.2"
336source = "registry+https://github.com/rust-lang/crates.io-index" 350source = "registry+https://github.com/rust-lang/crates.io-index"
337 351
338[[package]] 352[[package]]
353name = "filetime"
354version = "0.2.4"
355source = "registry+https://github.com/rust-lang/crates.io-index"
356dependencies = [
357 "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
358 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
359 "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
360]
361
362[[package]]
339name = "flexi_logger" 363name = "flexi_logger"
340version = "0.10.5" 364version = "0.10.5"
341source = "registry+https://github.com/rust-lang/crates.io-index" 365source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -352,6 +376,24 @@ version = "1.0.6"
352source = "registry+https://github.com/rust-lang/crates.io-index" 376source = "registry+https://github.com/rust-lang/crates.io-index"
353 377
354[[package]] 378[[package]]
379name = "fsevent"
380version = "0.2.17"
381source = "registry+https://github.com/rust-lang/crates.io-index"
382dependencies = [
383 "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
384 "fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
385 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
386]
387
388[[package]]
389name = "fsevent-sys"
390version = "0.1.6"
391source = "registry+https://github.com/rust-lang/crates.io-index"
392dependencies = [
393 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
394]
395
396[[package]]
355name = "fst" 397name = "fst"
356version = "0.3.3" 398version = "0.3.3"
357source = "registry+https://github.com/rust-lang/crates.io-index" 399source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -375,6 +417,11 @@ version = "0.3.3"
375source = "registry+https://github.com/rust-lang/crates.io-index" 417source = "registry+https://github.com/rust-lang/crates.io-index"
376 418
377[[package]] 419[[package]]
420name = "futures"
421version = "0.1.25"
422source = "registry+https://github.com/rust-lang/crates.io-index"
423
424[[package]]
378name = "gen_lsp_server" 425name = "gen_lsp_server"
379version = "0.1.0" 426version = "0.1.0"
380dependencies = [ 427dependencies = [
@@ -437,6 +484,28 @@ version = "1.0.2"
437source = "registry+https://github.com/rust-lang/crates.io-index" 484source = "registry+https://github.com/rust-lang/crates.io-index"
438 485
439[[package]] 486[[package]]
487name = "inotify"
488version = "0.6.1"
489source = "registry+https://github.com/rust-lang/crates.io-index"
490dependencies = [
491 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
492 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
493 "inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
494 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
495 "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
496 "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
497 "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
498]
499
500[[package]]
501name = "inotify-sys"
502version = "0.1.3"
503source = "registry+https://github.com/rust-lang/crates.io-index"
504dependencies = [
505 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
506]
507
508[[package]]
440name = "insta" 509name = "insta"
441version = "0.5.2" 510version = "0.5.2"
442source = "registry+https://github.com/rust-lang/crates.io-index" 511source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -456,6 +525,15 @@ dependencies = [
456] 525]
457 526
458[[package]] 527[[package]]
528name = "iovec"
529version = "0.1.2"
530source = "registry+https://github.com/rust-lang/crates.io-index"
531dependencies = [
532 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
533 "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
534]
535
536[[package]]
459name = "itertools" 537name = "itertools"
460version = "0.8.0" 538version = "0.8.0"
461source = "registry+https://github.com/rust-lang/crates.io-index" 539source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -474,11 +552,25 @@ version = "0.1.3"
474source = "registry+https://github.com/rust-lang/crates.io-index" 552source = "registry+https://github.com/rust-lang/crates.io-index"
475 553
476[[package]] 554[[package]]
555name = "kernel32-sys"
556version = "0.2.2"
557source = "registry+https://github.com/rust-lang/crates.io-index"
558dependencies = [
559 "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
560 "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
561]
562
563[[package]]
477name = "lazy_static" 564name = "lazy_static"
478version = "1.2.0" 565version = "1.2.0"
479source = "registry+https://github.com/rust-lang/crates.io-index" 566source = "registry+https://github.com/rust-lang/crates.io-index"
480 567
481[[package]] 568[[package]]
569name = "lazycell"
570version = "1.2.1"
571source = "registry+https://github.com/rust-lang/crates.io-index"
572
573[[package]]
482name = "libc" 574name = "libc"
483version = "0.2.48" 575version = "0.2.48"
484source = "registry+https://github.com/rust-lang/crates.io-index" 576source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -511,7 +603,7 @@ version = "0.55.1"
511source = "registry+https://github.com/rust-lang/crates.io-index" 603source = "registry+https://github.com/rust-lang/crates.io-index"
512dependencies = [ 604dependencies = [
513 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 605 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
514 "num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 606 "num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
515 "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 607 "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
516 "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", 608 "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
517 "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", 609 "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -554,16 +646,83 @@ version = "0.2.1"
554source = "registry+https://github.com/rust-lang/crates.io-index" 646source = "registry+https://github.com/rust-lang/crates.io-index"
555 647
556[[package]] 648[[package]]
649name = "mio"
650version = "0.6.16"
651source = "registry+https://github.com/rust-lang/crates.io-index"
652dependencies = [
653 "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
654 "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
655 "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
656 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
657 "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
658 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
659 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
660 "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
661 "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
662 "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
663 "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
664]
665
666[[package]]
667name = "mio-extras"
668version = "2.0.5"
669source = "registry+https://github.com/rust-lang/crates.io-index"
670dependencies = [
671 "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
672 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
673 "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
674 "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
675]
676
677[[package]]
678name = "miow"
679version = "0.2.1"
680source = "registry+https://github.com/rust-lang/crates.io-index"
681dependencies = [
682 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
683 "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
684 "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
685 "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
686]
687
688[[package]]
689name = "net2"
690version = "0.2.33"
691source = "registry+https://github.com/rust-lang/crates.io-index"
692dependencies = [
693 "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
694 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
695 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
696]
697
698[[package]]
557name = "nodrop" 699name = "nodrop"
558version = "0.1.13" 700version = "0.1.13"
559source = "registry+https://github.com/rust-lang/crates.io-index" 701source = "registry+https://github.com/rust-lang/crates.io-index"
560 702
561[[package]] 703[[package]]
704name = "notify"
705version = "4.0.7"
706source = "registry+https://github.com/rust-lang/crates.io-index"
707dependencies = [
708 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
709 "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
710 "fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
711 "fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
712 "inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
713 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
714 "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
715 "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
716 "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
717 "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
718 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
719]
720
721[[package]]
562name = "num-derive" 722name = "num-derive"
563version = "0.2.3" 723version = "0.2.4"
564source = "registry+https://github.com/rust-lang/crates.io-index" 724source = "registry+https://github.com/rust-lang/crates.io-index"
565dependencies = [ 725dependencies = [
566 "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
567 "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", 726 "proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)",
568 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 727 "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
569 "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", 728 "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -726,7 +885,7 @@ dependencies = [
726 "ra_syntax 0.1.0", 885 "ra_syntax 0.1.0",
727 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 886 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
728 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 887 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
729 "salsa 0.10.0-alpha4 (registry+https://github.com/rust-lang/crates.io-index)", 888 "salsa 0.10.0-alpha5 (registry+https://github.com/rust-lang/crates.io-index)",
730 "test_utils 0.1.0", 889 "test_utils 0.1.0",
731] 890]
732 891
@@ -849,7 +1008,11 @@ name = "ra_vfs"
849version = "0.1.0" 1008version = "0.1.0"
850dependencies = [ 1009dependencies = [
851 "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 1010 "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
1011 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
1012 "flexi_logger 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
852 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1013 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1014 "notify 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
1015 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
853 "ra_arena 0.1.0", 1016 "ra_arena 0.1.0",
854 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1017 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
855 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1018 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1097,7 +1260,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1097 1260
1098[[package]] 1261[[package]]
1099name = "salsa" 1262name = "salsa"
1100version = "0.10.0-alpha4" 1263version = "0.10.0-alpha5"
1101source = "registry+https://github.com/rust-lang/crates.io-index" 1264source = "registry+https://github.com/rust-lang/crates.io-index"
1102dependencies = [ 1265dependencies = [
1103 "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", 1266 "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1106,13 +1269,13 @@ dependencies = [
1106 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1269 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1107 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1270 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1108 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1271 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1109 "salsa-macros 0.10.0-alpha4 (registry+https://github.com/rust-lang/crates.io-index)", 1272 "salsa-macros 0.10.0-alpha5 (registry+https://github.com/rust-lang/crates.io-index)",
1110 "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 1273 "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
1111] 1274]
1112 1275
1113[[package]] 1276[[package]]
1114name = "salsa-macros" 1277name = "salsa-macros"
1115version = "0.10.0-alpha4" 1278version = "0.10.0-alpha5"
1116source = "registry+https://github.com/rust-lang/crates.io-index" 1279source = "registry+https://github.com/rust-lang/crates.io-index"
1117dependencies = [ 1280dependencies = [
1118 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1281 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1199,6 +1362,11 @@ dependencies = [
1199] 1362]
1200 1363
1201[[package]] 1364[[package]]
1365name = "slab"
1366version = "0.4.2"
1367source = "registry+https://github.com/rust-lang/crates.io-index"
1368
1369[[package]]
1202name = "slug" 1370name = "slug"
1203version = "0.1.4" 1371version = "0.1.4"
1204source = "registry+https://github.com/rust-lang/crates.io-index" 1372source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1382,6 +1550,42 @@ dependencies = [
1382] 1550]
1383 1551
1384[[package]] 1552[[package]]
1553name = "tokio-executor"
1554version = "0.1.6"
1555source = "registry+https://github.com/rust-lang/crates.io-index"
1556dependencies = [
1557 "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
1558 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
1559]
1560
1561[[package]]
1562name = "tokio-io"
1563version = "0.1.11"
1564source = "registry+https://github.com/rust-lang/crates.io-index"
1565dependencies = [
1566 "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
1567 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
1568 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1569]
1570
1571[[package]]
1572name = "tokio-reactor"
1573version = "0.1.8"
1574source = "registry+https://github.com/rust-lang/crates.io-index"
1575dependencies = [
1576 "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
1577 "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
1578 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1579 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
1580 "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
1581 "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
1582 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1583 "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
1584 "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
1585 "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
1586]
1587
1588[[package]]
1385name = "tools" 1589name = "tools"
1386version = "0.1.0" 1590version = "0.1.0"
1387dependencies = [ 1591dependencies = [
@@ -1557,6 +1761,11 @@ dependencies = [
1557 1761
1558[[package]] 1762[[package]]
1559name = "winapi" 1763name = "winapi"
1764version = "0.2.8"
1765source = "registry+https://github.com/rust-lang/crates.io-index"
1766
1767[[package]]
1768name = "winapi"
1560version = "0.3.6" 1769version = "0.3.6"
1561source = "registry+https://github.com/rust-lang/crates.io-index" 1770source = "registry+https://github.com/rust-lang/crates.io-index"
1562dependencies = [ 1771dependencies = [
@@ -1565,6 +1774,11 @@ dependencies = [
1565] 1774]
1566 1775
1567[[package]] 1776[[package]]
1777name = "winapi-build"
1778version = "0.1.1"
1779source = "registry+https://github.com/rust-lang/crates.io-index"
1780
1781[[package]]
1568name = "winapi-i686-pc-windows-gnu" 1782name = "winapi-i686-pc-windows-gnu"
1569version = "0.4.0" 1783version = "0.4.0"
1570source = "registry+https://github.com/rust-lang/crates.io-index" 1784source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1583,6 +1797,15 @@ version = "0.4.0"
1583source = "registry+https://github.com/rust-lang/crates.io-index" 1797source = "registry+https://github.com/rust-lang/crates.io-index"
1584 1798
1585[[package]] 1799[[package]]
1800name = "ws2_32-sys"
1801version = "0.2.1"
1802source = "registry+https://github.com/rust-lang/crates.io-index"
1803dependencies = [
1804 "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
1805 "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
1806]
1807
1808[[package]]
1586name = "yaml-rust" 1809name = "yaml-rust"
1587version = "0.4.2" 1810version = "0.4.2"
1588source = "registry+https://github.com/rust-lang/crates.io-index" 1811source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1602,10 +1825,12 @@ dependencies = [
1602"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 1825"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
1603"checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a" 1826"checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a"
1604"checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf" 1827"checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf"
1828"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
1605"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 1829"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
1606"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" 1830"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
1607"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" 1831"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
1608"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" 1832"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
1833"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
1609"checksum cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "585784cac9b05c93a53b17a0b24a5cdd1dfdda5256f030e089b549d2390cc720" 1834"checksum cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "585784cac9b05c93a53b17a0b24a5cdd1dfdda5256f030e089b549d2390cc720"
1610"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" 1835"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
1611"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" 1836"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
@@ -1633,11 +1858,15 @@ dependencies = [
1633"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" 1858"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
1634"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" 1859"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
1635"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 1860"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
1861"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646"
1636"checksum flexi_logger 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bbd731387787f54fa333fa426e173fe42ea3d1123636b2b27ad802025fc5d182" 1862"checksum flexi_logger 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bbd731387787f54fa333fa426e173fe42ea3d1123636b2b27ad802025fc5d182"
1637"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" 1863"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
1864"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05"
1865"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874"
1638"checksum fst 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "db72126ca7dff566cdbbdd54af44668c544897d9d3862b198141f176f1238bdf" 1866"checksum fst 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "db72126ca7dff566cdbbdd54af44668c544897d9d3862b198141f176f1238bdf"
1639"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 1867"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
1640"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 1868"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
1869"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
1641"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" 1870"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
1642"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" 1871"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
1643"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 1872"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
@@ -1645,11 +1874,16 @@ dependencies = [
1645"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" 1874"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
1646"checksum im 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0627d417829c1d763d602687634869f254fc79f7e22dea6c824dab993db857e4" 1875"checksum im 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0627d417829c1d763d602687634869f254fc79f7e22dea6c824dab993db857e4"
1647"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" 1876"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
1877"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
1878"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
1648"checksum insta 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff57d9cbc4664b54a972c321155c7703794bc0f5c9944f29c36f40d10d626f3" 1879"checksum insta 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff57d9cbc4664b54a972c321155c7703794bc0f5c9944f29c36f40d10d626f3"
1880"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
1649"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" 1881"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
1650"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" 1882"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
1651"checksum join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc7a5290e8c2606ce2be49f456d50f69173cb96d1541e4f66e34ac8b331a98f" 1883"checksum join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc7a5290e8c2606ce2be49f456d50f69173cb96d1541e4f66e34ac8b331a98f"
1884"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
1652"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" 1885"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
1886"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
1653"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" 1887"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
1654"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" 1888"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e"
1655"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" 1889"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
@@ -1660,8 +1894,13 @@ dependencies = [
1660"checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8" 1894"checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8"
1661"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" 1895"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
1662"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" 1896"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
1897"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
1898"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
1899"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
1900"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
1663"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 1901"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
1664"checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d" 1902"checksum notify 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c968cf37cf949114b00d51b0b23536d1c3a4a3963767cf4c969c65a6af78dc7d"
1903"checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d"
1665"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" 1904"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
1666"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" 1905"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
1667"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" 1906"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238"
@@ -1704,8 +1943,8 @@ dependencies = [
1704"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1943"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
1705"checksum rusty-fork 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9591f190d2852720b679c21f66ad929f9f1d7bb09d1193c26167586029d8489c" 1944"checksum rusty-fork 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9591f190d2852720b679c21f66ad929f9f1d7bb09d1193c26167586029d8489c"
1706"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" 1945"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
1707"checksum salsa 0.10.0-alpha4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f442595eae948da8fbb2aa1e13940d9d2d70031753a27a5d1434f91b706ff12" 1946"checksum salsa 0.10.0-alpha5 (registry+https://github.com/rust-lang/crates.io-index)" = "8b5e2535d707dc5ced81106d3b71d806cfeef8a6e8a567472fde7ffd56b770dd"
1708"checksum salsa-macros 0.10.0-alpha4 (registry+https://github.com/rust-lang/crates.io-index)" = "2e6c1a1bee4eb44881438e80c1a26db1c3b957b6cc51765615d429019babdec2" 1947"checksum salsa-macros 0.10.0-alpha5 (registry+https://github.com/rust-lang/crates.io-index)" = "e7c5da4c649f6d4fc1864fcd9a379b1f7c6d570b278559c84a6e15981c949cc6"
1709"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" 1948"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
1710"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 1949"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
1711"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1950"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
@@ -1715,6 +1954,7 @@ dependencies = [
1715"checksum serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "4b90a9fbe1211e57d3e1c15670f1cb00802988fb23a1a4aad7a2b63544f1920e" 1954"checksum serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "4b90a9fbe1211e57d3e1c15670f1cb00802988fb23a1a4aad7a2b63544f1920e"
1716"checksum serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0887a8e097a69559b56aa2526bf7aff7c3048cf627dff781f0b56a6001534593" 1955"checksum serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0887a8e097a69559b56aa2526bf7aff7c3048cf627dff781f0b56a6001534593"
1717"checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded" 1956"checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded"
1957"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
1718"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" 1958"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373"
1719"checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15" 1959"checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15"
1720"checksum smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9af1035bc5d742ab6b7ab16713e41cc2ffe78cb474f6f43cd696b2d16052007e" 1960"checksum smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9af1035bc5d742ab6b7ab16713e41cc2ffe78cb474f6f43cd696b2d16052007e"
@@ -1733,6 +1973,9 @@ dependencies = [
1733"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 1973"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
1734"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" 1974"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
1735"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 1975"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
1976"checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0"
1977"checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f"
1978"checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f"
1736"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" 1979"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
1737"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77" 1980"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77"
1738"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" 1981"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
@@ -1757,8 +2000,11 @@ dependencies = [
1757"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 2000"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
1758"checksum wait-timeout 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b9f3bf741a801531993db6478b95682117471f76916f5e690dd8d45395b09349" 2001"checksum wait-timeout 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b9f3bf741a801531993db6478b95682117471f76916f5e690dd8d45395b09349"
1759"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" 2002"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
2003"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
1760"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" 2004"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
2005"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
1761"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2006"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1762"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" 2007"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
1763"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2008"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
2009"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
1764"checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e" 2010"checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e"
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 3a0aa7d24..6e17f33f0 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -20,7 +20,7 @@ pub use crate::{
20 loc2id::LocationIntener, 20 loc2id::LocationIntener,
21}; 21};
22 22
23pub trait BaseDatabase: salsa::Database + panic::RefUnwindSafe { 23pub trait CheckCanceled: salsa::Database + panic::RefUnwindSafe {
24 /// Aborts current query if there are pending changes. 24 /// Aborts current query if there are pending changes.
25 /// 25 ///
26 /// rust-analyzer needs to be able to answer semantic questions about the 26 /// rust-analyzer needs to be able to answer semantic questions about the
@@ -63,11 +63,15 @@ pub struct FileRange {
63 pub range: TextRange, 63 pub range: TextRange,
64} 64}
65 65
66#[salsa::query_group(FilesDatabaseStorage)] 66/// Database which stores all significant input facts: source code and project
67pub trait FilesDatabase: salsa::Database { 67/// model. Everything else in rust-analyzer is derived from these queries.
68#[salsa::query_group(SourceDatabaseStorage)]
69pub trait SourceDatabase: salsa::Database + CheckCanceled {
68 /// Text of the file. 70 /// Text of the file.
69 #[salsa::input] 71 #[salsa::input]
70 fn file_text(&self, file_id: FileId) -> Arc<String>; 72 fn file_text(&self, file_id: FileId) -> Arc<String>;
73 // Parses the file into the syntax tree.
74 fn parse(&self, file_id: FileId) -> TreeArc<SourceFile>;
71 /// Path to a file, relative to the root of its source root. 75 /// Path to a file, relative to the root of its source root.
72 #[salsa::input] 76 #[salsa::input]
73 fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf; 77 fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf;
@@ -78,20 +82,12 @@ pub trait FilesDatabase: salsa::Database {
78 #[salsa::input] 82 #[salsa::input]
79 fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>; 83 fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
80 fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>; 84 fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>;
81 /// The set of "local" (that is, from the current workspace) roots.
82 /// Files in local roots are assumed to change frequently.
83 #[salsa::input]
84 fn local_roots(&self) -> Arc<Vec<SourceRootId>>;
85 /// The set of roots for crates.io libraries.
86 /// Files in libraries are assumed to never change.
87 #[salsa::input]
88 fn library_roots(&self) -> Arc<Vec<SourceRootId>>;
89 /// The crate graph. 85 /// The crate graph.
90 #[salsa::input] 86 #[salsa::input]
91 fn crate_graph(&self) -> Arc<CrateGraph>; 87 fn crate_graph(&self) -> Arc<CrateGraph>;
92} 88}
93 89
94fn source_root_crates(db: &impl FilesDatabase, id: SourceRootId) -> Arc<Vec<CrateId>> { 90fn source_root_crates(db: &impl SourceDatabase, id: SourceRootId) -> Arc<Vec<CrateId>> {
95 let root = db.source_root(id); 91 let root = db.source_root(id);
96 let graph = db.crate_graph(); 92 let graph = db.crate_graph();
97 let res = root 93 let res = root
@@ -102,12 +98,7 @@ fn source_root_crates(db: &impl FilesDatabase, id: SourceRootId) -> Arc<Vec<Crat
102 Arc::new(res) 98 Arc::new(res)
103} 99}
104 100
105#[salsa::query_group(SyntaxDatabaseStorage)] 101fn parse(db: &impl SourceDatabase, file_id: FileId) -> TreeArc<SourceFile> {
106pub trait SyntaxDatabase: FilesDatabase + BaseDatabase {
107 fn source_file(&self, file_id: FileId) -> TreeArc<SourceFile>;
108}
109
110fn source_file(db: &impl SyntaxDatabase, file_id: FileId) -> TreeArc<SourceFile> {
111 let text = db.file_text(file_id); 102 let text = db.file_text(file_id);
112 SourceFile::parse(&*text) 103 SourceFile::parse(&*text)
113} 104}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index dfbf41bd6..5df4bd4a1 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; 3use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
4use ra_db::{SyntaxDatabase, CrateId, salsa}; 4use ra_db::{SourceDatabase, CrateId, salsa};
5 5
6use crate::{ 6use crate::{
7 MacroCallId, HirFileId, 7 MacroCallId, HirFileId,
@@ -19,9 +19,9 @@ use crate::{
19}; 19};
20 20
21#[salsa::query_group(HirDatabaseStorage)] 21#[salsa::query_group(HirDatabaseStorage)]
22pub trait HirDatabase: SyntaxDatabase + AsRef<HirInterner> { 22pub trait HirDatabase: SourceDatabase + AsRef<HirInterner> {
23 #[salsa::invoke(HirFileId::hir_source_file)] 23 #[salsa::invoke(HirFileId::hir_parse)]
24 fn hir_source_file(&self, file_id: HirFileId) -> TreeArc<SourceFile>; 24 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>;
25 25
26 #[salsa::invoke(crate::macros::expand_macro_invocation)] 26 #[salsa::invoke(crate::macros::expand_macro_invocation)]
27 fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>; 27 fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>;
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 5272656ec..7dd4b540e 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -86,12 +86,9 @@ impl HirFileId {
86 } 86 }
87 } 87 }
88 88
89 pub(crate) fn hir_source_file( 89 pub(crate) fn hir_parse(db: &impl HirDatabase, file_id: HirFileId) -> TreeArc<SourceFile> {
90 db: &impl HirDatabase,
91 file_id: HirFileId,
92 ) -> TreeArc<SourceFile> {
93 match file_id.0 { 90 match file_id.0 {
94 HirFileIdRepr::File(file_id) => db.source_file(file_id), 91 HirFileIdRepr::File(file_id) => db.parse(file_id),
95 HirFileIdRepr::Macro(m) => { 92 HirFileIdRepr::Macro(m) => {
96 if let Some(exp) = db.expand_macro_invocation(m) { 93 if let Some(exp) = db.expand_macro_invocation(m) {
97 return exp.file(); 94 return exp.file();
@@ -370,7 +367,7 @@ impl SourceFileItems {
370 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(), 367 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
371 ); 368 );
372 } 369 }
373 pub fn id_of_source_file(&self) -> SourceFileItemId { 370 pub fn id_of_parse(&self) -> SourceFileItemId {
374 let (id, _syntax) = self.arena.iter().next().unwrap(); 371 let (id, _syntax) = self.arena.iter().next().unwrap();
375 id 372 id
376 } 373 }
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 2dc252b1e..7da15eca0 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -2,7 +2,7 @@ use std::{sync::Arc, panic};
2 2
3use parking_lot::Mutex; 3use parking_lot::Mutex;
4use ra_db::{ 4use ra_db::{
5 BaseDatabase, FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, FilesDatabase, salsa, 5 CheckCanceled, FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa,
6}; 6};
7use relative_path::RelativePathBuf; 7use relative_path::RelativePathBuf;
8use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; 8use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
@@ -11,11 +11,7 @@ use crate::{db, HirInterner};
11 11
12pub const WORKSPACE: SourceRootId = SourceRootId(0); 12pub const WORKSPACE: SourceRootId = SourceRootId(0);
13 13
14#[salsa::database( 14#[salsa::database(ra_db::SourceDatabaseStorage, db::HirDatabaseStorage)]
15 ra_db::FilesDatabaseStorage,
16 ra_db::SyntaxDatabaseStorage,
17 db::HirDatabaseStorage
18)]
19#[derive(Debug)] 15#[derive(Debug)]
20pub(crate) struct MockDatabase { 16pub(crate) struct MockDatabase {
21 events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>, 17 events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>,
@@ -144,8 +140,6 @@ impl Default for MockDatabase {
144 file_counter: 0, 140 file_counter: 0,
145 }; 141 };
146 db.set_crate_graph(Default::default()); 142 db.set_crate_graph(Default::default());
147 db.set_local_roots(Default::default());
148 db.set_library_roots(Default::default());
149 db 143 db
150 } 144 }
151} 145}
@@ -161,7 +155,7 @@ impl salsa::ParallelDatabase for MockDatabase {
161 } 155 }
162} 156}
163 157
164impl BaseDatabase for MockDatabase {} 158impl CheckCanceled for MockDatabase {}
165 159
166impl AsRef<HirInterner> for MockDatabase { 160impl AsRef<HirInterner> for MockDatabase {
167 fn as_ref(&self) -> &HirInterner { 161 fn as_ref(&self) -> &HirInterner {
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
index b4fe99ea7..1d77548f3 100644
--- a/crates/ra_hir/src/nameres/lower.rs
+++ b/crates/ra_hir/src/nameres/lower.rs
@@ -129,7 +129,7 @@ impl LoweredModule {
129 let id = loc.id(db); 129 let id = loc.id(db);
130 let file_id = HirFileId::from(id); 130 let file_id = HirFileId::from(id);
131 //FIXME: expand recursively 131 //FIXME: expand recursively
132 for item in db.hir_source_file(file_id).items() { 132 for item in db.hir_parse(file_id).items() {
133 self.add_def_id(source_map, db, module, file_id, item); 133 self.add_def_id(source_map, db, module, file_id, item);
134 } 134 }
135 } 135 }
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 24936976c..e72781f51 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -1,6 +1,6 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_db::{CrateGraph, SourceRootId, FilesDatabase}; 3use ra_db::{CrateGraph, SourceRootId, SourceDatabase};
4use relative_path::RelativePath; 4use relative_path::RelativePath;
5use test_utils::{assert_eq_text, covers}; 5use test_utils::{assert_eq_text, covers};
6 6
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index cf8c7e435..61c93a964 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -23,7 +23,7 @@ pub(super) fn fn_scopes(db: &impl HirDatabase, func: Function) -> Arc<FnScopes>
23} 23}
24 24
25pub(super) fn file_items(db: &impl HirDatabase, file_id: HirFileId) -> Arc<SourceFileItems> { 25pub(super) fn file_items(db: &impl HirDatabase, file_id: HirFileId) -> Arc<SourceFileItems> {
26 let source_file = db.hir_source_file(file_id); 26 let source_file = db.hir_parse(file_id);
27 let res = SourceFileItems::new(file_id, &source_file); 27 let res = SourceFileItems::new(file_id, &source_file);
28 Arc::new(res) 28 Arc::new(res)
29} 29}
@@ -34,10 +34,7 @@ pub(super) fn file_item(
34) -> TreeArc<SyntaxNode> { 34) -> TreeArc<SyntaxNode> {
35 match source_item_id.item_id { 35 match source_item_id.item_id {
36 Some(id) => db.file_items(source_item_id.file_id)[id].to_owned(), 36 Some(id) => db.file_items(source_item_id.file_id)[id].to_owned(),
37 None => db 37 None => db.hir_parse(source_item_id.file_id).syntax().to_owned(),
38 .hir_source_file(source_item_id.file_id)
39 .syntax()
40 .to_owned(),
41 } 38 }
42} 39}
43 40
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index dbe040805..c0b3f1cd4 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -43,7 +43,7 @@ pub fn module_from_declaration(
43 43
44/// Locates the module by position in the source code. 44/// Locates the module by position in the source code.
45pub fn module_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Module> { 45pub fn module_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Module> {
46 let file = db.source_file(position.file_id); 46 let file = db.parse(position.file_id);
47 match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) { 47 match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) {
48 Some(m) if !m.has_semi() => module_from_inline(db, position.file_id.into(), m), 48 Some(m) if !m.has_semi() => module_from_inline(db, position.file_id.into(), m),
49 _ => module_from_file_id(db, position.file_id.into()), 49 _ => module_from_file_id(db, position.file_id.into()),
@@ -95,7 +95,7 @@ fn module_from_source(db: &impl HirDatabase, source: SourceItemId) -> Option<Mod
95} 95}
96 96
97pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> { 97pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> {
98 let file = db.source_file(position.file_id); 98 let file = db.parse(position.file_id);
99 let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?; 99 let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?;
100 function_from_source(db, position.file_id, fn_def) 100 function_from_source(db, position.file_id, fn_def)
101} 101}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 389bdaf23..e0b0689f8 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2use std::fmt::Write; 2use std::fmt::Write;
3 3
4use ra_db::{SyntaxDatabase, salsa::Database}; 4use ra_db::{SourceDatabase, salsa::Database};
5use ra_syntax::ast::{self, AstNode}; 5use ra_syntax::ast::{self, AstNode};
6 6
7use crate::{ 7use crate::{
@@ -547,7 +547,7 @@ fn quux() {
547 547
548fn infer(content: &str) -> String { 548fn infer(content: &str) -> String {
549 let (db, _, file_id) = MockDatabase::with_single_file(content); 549 let (db, _, file_id) = MockDatabase::with_single_file(content);
550 let source_file = db.source_file(file_id); 550 let source_file = db.parse(file_id);
551 let mut acc = String::new(); 551 let mut acc = String::new();
552 for fn_def in source_file 552 for fn_def in source_file
553 .syntax() 553 .syntax()
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs
index 0449c1902..3267fff96 100644
--- a/crates/ra_ide_api/src/call_info.rs
+++ b/crates/ra_ide_api/src/call_info.rs
@@ -1,4 +1,4 @@
1use ra_db::SyntaxDatabase; 1use ra_db::SourceDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, SyntaxNode, TextUnit, TextRange, 3 AstNode, SyntaxNode, TextUnit, TextRange,
4 SyntaxKind::FN_DEF, 4 SyntaxKind::FN_DEF,
@@ -10,7 +10,7 @@ use crate::{FilePosition, CallInfo, db::RootDatabase};
10 10
11/// Computes parameter information for the given call expression. 11/// Computes parameter information for the given call expression.
12pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { 12pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
13 let file = db.source_file(position.file_id); 13 let file = db.parse(position.file_id);
14 let syntax = file.syntax(); 14 let syntax = file.syntax();
15 15
16 // Find the calling expression and it's NameRef 16 // Find the calling expression and it's NameRef
@@ -22,7 +22,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
22 let symbol = file_symbols 22 let symbol = file_symbols
23 .into_iter() 23 .into_iter()
24 .find(|it| it.ptr.kind() == FN_DEF)?; 24 .find(|it| it.ptr.kind() == FN_DEF)?;
25 let fn_file = db.source_file(symbol.file_id); 25 let fn_file = db.parse(symbol.file_id);
26 let fn_def = symbol.ptr.to_node(&fn_file); 26 let fn_def = symbol.ptr.to_node(&fn_file);
27 let fn_def = ast::FnDef::cast(fn_def).unwrap(); 27 let fn_def = ast::FnDef::cast(fn_def).unwrap();
28 let mut call_info = CallInfo::new(fn_def)?; 28 let mut call_info = CallInfo::new(fn_def)?;
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index 565d57c37..b1867de42 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -9,7 +9,7 @@ mod complete_path;
9mod complete_scope; 9mod complete_scope;
10mod complete_postfix; 10mod complete_postfix;
11 11
12use ra_db::SyntaxDatabase; 12use ra_db::SourceDatabase;
13 13
14use crate::{ 14use crate::{
15 db, 15 db,
@@ -45,7 +45,7 @@ pub use crate::completion::completion_item::{CompletionItem, CompletionItemKind,
45/// identifier prefix/fuzzy match should be done higher in the stack, together 45/// identifier prefix/fuzzy match should be done higher in the stack, together
46/// with ordering of completions (currently this is done by the client). 46/// with ordering of completions (currently this is done by the client).
47pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Option<Completions> { 47pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Option<Completions> {
48 let original_file = db.source_file(position.file_id); 48 let original_file = db.parse(position.file_id);
49 let ctx = CompletionContext::new(db, &original_file, position)?; 49 let ctx = CompletionContext::new(db, &original_file, position)?;
50 50
51 let mut acc = Completions::default(); 51 let mut acc = Completions::default();
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs
index 30891aed4..3da93ec35 100644
--- a/crates/ra_ide_api/src/db.rs
+++ b/crates/ra_ide_api/src/db.rs
@@ -1,15 +1,14 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_db::{ 3use ra_db::{
4 BaseDatabase, FileId, Canceled, 4 CheckCanceled, FileId, Canceled, SourceDatabase,
5 salsa::{self, Database}, 5 salsa,
6}; 6};
7 7
8use crate::{symbol_index, LineIndex}; 8use crate::{LineIndex, symbol_index::{self, SymbolsDatabase}};
9 9
10#[salsa::database( 10#[salsa::database(
11 ra_db::FilesDatabaseStorage, 11 ra_db::SourceDatabaseStorage,
12 ra_db::SyntaxDatabaseStorage,
13 LineIndexDatabaseStorage, 12 LineIndexDatabaseStorage,
14 symbol_index::SymbolsDatabaseStorage, 13 symbol_index::SymbolsDatabaseStorage,
15 hir::db::HirDatabaseStorage 14 hir::db::HirDatabaseStorage
@@ -35,12 +34,9 @@ impl Default for RootDatabase {
35 runtime: salsa::Runtime::default(), 34 runtime: salsa::Runtime::default(),
36 interner: Default::default(), 35 interner: Default::default(),
37 }; 36 };
38 db.query_mut(ra_db::CrateGraphQuery) 37 db.set_crate_graph(Default::default());
39 .set((), Default::default()); 38 db.set_local_roots(Default::default());
40 db.query_mut(ra_db::LocalRootsQuery) 39 db.set_library_roots(Default::default());
41 .set((), Default::default());
42 db.query_mut(ra_db::LibraryRootsQuery)
43 .set((), Default::default());
44 db 40 db
45 } 41 }
46} 42}
@@ -54,7 +50,7 @@ impl salsa::ParallelDatabase for RootDatabase {
54 } 50 }
55} 51}
56 52
57impl BaseDatabase for RootDatabase {} 53impl CheckCanceled for RootDatabase {}
58 54
59impl AsRef<hir::HirInterner> for RootDatabase { 55impl AsRef<hir::HirInterner> for RootDatabase {
60 fn as_ref(&self) -> &hir::HirInterner { 56 fn as_ref(&self) -> &hir::HirInterner {
@@ -63,11 +59,11 @@ impl AsRef<hir::HirInterner> for RootDatabase {
63} 59}
64 60
65#[salsa::query_group(LineIndexDatabaseStorage)] 61#[salsa::query_group(LineIndexDatabaseStorage)]
66pub(crate) trait LineIndexDatabase: ra_db::FilesDatabase + BaseDatabase { 62pub(crate) trait LineIndexDatabase: ra_db::SourceDatabase + CheckCanceled {
67 fn line_index(&self, file_id: FileId) -> Arc<LineIndex>; 63 fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
68} 64}
69 65
70fn line_index(db: &impl ra_db::FilesDatabase, file_id: FileId) -> Arc<LineIndex> { 66fn line_index(db: &impl ra_db::SourceDatabase, file_id: FileId) -> Arc<LineIndex> {
71 let text = db.file_text(file_id); 67 let text = db.file_text(file_id);
72 Arc::new(LineIndex::new(&*text)) 68 Arc::new(LineIndex::new(&*text))
73} 69}
diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs
index 718b4def5..cd2ebe471 100644
--- a/crates/ra_ide_api/src/extend_selection.rs
+++ b/crates/ra_ide_api/src/extend_selection.rs
@@ -1,4 +1,4 @@
1use ra_db::SyntaxDatabase; 1use ra_db::SourceDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 SyntaxNode, AstNode, SourceFile, 3 SyntaxNode, AstNode, SourceFile,
4 ast, algo::find_covering_node, 4 ast, algo::find_covering_node,
@@ -10,7 +10,7 @@ use crate::{
10}; 10};
11 11
12pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { 12pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange {
13 let source_file = db.source_file(frange.file_id); 13 let source_file = db.parse(frange.file_id);
14 if let Some(range) = extend_selection_in_macro(db, &source_file, frange) { 14 if let Some(range) = extend_selection_in_macro(db, &source_file, frange) {
15 return range; 15 return range;
16 } 16 }
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index dc0c50918..2a20c20ee 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -1,4 +1,4 @@
1use ra_db::{FileId, SyntaxDatabase}; 1use ra_db::{FileId, SourceDatabase};
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, ast, 3 AstNode, ast,
4 algo::find_node_at_offset, 4 algo::find_node_at_offset,
@@ -11,7 +11,7 @@ pub(crate) fn goto_definition(
11 db: &RootDatabase, 11 db: &RootDatabase,
12 position: FilePosition, 12 position: FilePosition,
13) -> Option<RangeInfo<Vec<NavigationTarget>>> { 13) -> Option<RangeInfo<Vec<NavigationTarget>>> {
14 let file = db.source_file(position.file_id); 14 let file = db.parse(position.file_id);
15 let syntax = file.syntax(); 15 let syntax = file.syntax();
16 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { 16 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
17 let navs = reference_definition(db, position.file_id, name_ref).to_vec(); 17 let navs = reference_definition(db, position.file_id, name_ref).to_vec();
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 4d4bfbc4d..ff9ae2d9c 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -1,4 +1,4 @@
1use ra_db::{SyntaxDatabase}; 1use ra_db::SourceDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, SyntaxNode, TreeArc, ast, 3 AstNode, SyntaxNode, TreeArc, ast,
4 algo::{find_covering_node, find_node_at_offset, find_leaf_at_offset, visit::{visitor, Visitor}}, 4 algo::{find_covering_node, find_node_at_offset, find_leaf_at_offset, visit::{visitor, Visitor}},
@@ -7,7 +7,7 @@ use ra_syntax::{
7use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget}; 7use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget};
8 8
9pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<String>> { 9pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<String>> {
10 let file = db.source_file(position.file_id); 10 let file = db.parse(position.file_id);
11 let mut res = Vec::new(); 11 let mut res = Vec::new();
12 12
13 let mut range = None; 13 let mut range = None;
@@ -53,7 +53,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
53} 53}
54 54
55pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { 55pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
56 let file = db.source_file(frange.file_id); 56 let file = db.parse(frange.file_id);
57 let syntax = file.syntax(); 57 let syntax = file.syntax();
58 let leaf_node = find_covering_node(syntax, frange.range); 58 let leaf_node = find_covering_node(syntax, frange.range);
59 // if we picked identifier, expand to pattern/expression 59 // if we picked identifier, expand to pattern/expression
@@ -88,7 +88,7 @@ fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> {
88 88
89impl NavigationTarget { 89impl NavigationTarget {
90 fn node(&self, db: &RootDatabase) -> Option<TreeArc<SyntaxNode>> { 90 fn node(&self, db: &RootDatabase) -> Option<TreeArc<SyntaxNode>> {
91 let source_file = db.source_file(self.file_id()); 91 let source_file = db.parse(self.file_id());
92 let source_file = source_file.syntax(); 92 let source_file = source_file.syntax();
93 let node = source_file 93 let node = source_file
94 .descendants() 94 .descendants()
diff --git a/crates/ra_ide_api/src/imp.rs b/crates/ra_ide_api/src/imp.rs
index bd9e3f1e3..399433a01 100644
--- a/crates/ra_ide_api/src/imp.rs
+++ b/crates/ra_ide_api/src/imp.rs
@@ -4,7 +4,7 @@ use hir::{
4 self, Problem, source_binder 4 self, Problem, source_binder
5}; 5};
6use ra_db::{ 6use ra_db::{
7 FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase, 7 SourceDatabase, SourceRoot, SourceRootId,
8 salsa::{Database, SweepStrategy}, 8 salsa::{Database, SweepStrategy},
9}; 9};
10use ra_ide_api_light::{self, assists, LocalEdit, Severity}; 10use ra_ide_api_light::{self, assists, LocalEdit, Severity};
@@ -76,9 +76,9 @@ impl db::RootDatabase {
76 /// syntax trees. However, if we actually do that, everything is recomputed 76 /// syntax trees. However, if we actually do that, everything is recomputed
77 /// for some reason. Needs investigation. 77 /// for some reason. Needs investigation.
78 pub(crate) fn collect_garbage(&mut self) { 78 pub(crate) fn collect_garbage(&mut self) {
79 self.query(ra_db::SourceFileQuery) 79 self.query(ra_db::ParseQuery)
80 .sweep(SweepStrategy::default().discard_values()); 80 .sweep(SweepStrategy::default().discard_values());
81 self.query(hir::db::HirSourceFileQuery) 81 self.query(hir::db::HirParseQuery)
82 .sweep(SweepStrategy::default().discard_values()); 82 .sweep(SweepStrategy::default().discard_values());
83 self.query(hir::db::FileItemsQuery) 83 self.query(hir::db::FileItemsQuery)
84 .sweep(SweepStrategy::default().discard_values()); 84 .sweep(SweepStrategy::default().discard_values());
@@ -102,7 +102,7 @@ impl db::RootDatabase {
102 } 102 }
103 103
104 pub(crate) fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> { 104 pub(crate) fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> {
105 let file = self.source_file(position.file_id); 105 let file = self.parse(position.file_id);
106 // Find the binding associated with the offset 106 // Find the binding associated with the offset
107 let (binding, descr) = match find_binding(self, &file, position) { 107 let (binding, descr) = match find_binding(self, &file, position) {
108 None => return Vec::new(), 108 None => return Vec::new(),
@@ -150,7 +150,7 @@ impl db::RootDatabase {
150 } 150 }
151 151
152 pub(crate) fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { 152 pub(crate) fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
153 let syntax = self.source_file(file_id); 153 let syntax = self.parse(file_id);
154 154
155 let mut res = ra_ide_api_light::diagnostics(&syntax) 155 let mut res = ra_ide_api_light::diagnostics(&syntax)
156 .into_iter() 156 .into_iter()
@@ -214,7 +214,7 @@ impl db::RootDatabase {
214 } 214 }
215 215
216 pub(crate) fn assists(&self, frange: FileRange) -> Vec<SourceChange> { 216 pub(crate) fn assists(&self, frange: FileRange) -> Vec<SourceChange> {
217 let file = self.source_file(frange.file_id); 217 let file = self.parse(frange.file_id);
218 assists::assists(&file, frange.range) 218 assists::assists(&file, frange.range)
219 .into_iter() 219 .into_iter()
220 .map(|local_edit| SourceChange::from_local_edit(frange.file_id, local_edit)) 220 .map(|local_edit| SourceChange::from_local_edit(frange.file_id, local_edit))
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index ffd026b04..43c8bea71 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -34,7 +34,7 @@ use std::{fmt, sync::Arc};
34use ra_syntax::{SourceFile, TreeArc, TextRange, TextUnit}; 34use ra_syntax::{SourceFile, TreeArc, TextRange, TextUnit};
35use ra_text_edit::TextEdit; 35use ra_text_edit::TextEdit;
36use ra_db::{ 36use ra_db::{
37 SyntaxDatabase, FilesDatabase, BaseDatabase, 37 SourceDatabase, CheckCanceled,
38 salsa::{self, ParallelDatabase}, 38 salsa::{self, ParallelDatabase},
39}; 39};
40use rayon::prelude::*; 40use rayon::prelude::*;
@@ -313,7 +313,7 @@ impl Analysis {
313 313
314 /// Gets the syntax tree of the file. 314 /// Gets the syntax tree of the file.
315 pub fn parse(&self, file_id: FileId) -> TreeArc<SourceFile> { 315 pub fn parse(&self, file_id: FileId) -> TreeArc<SourceFile> {
316 self.db.source_file(file_id).clone() 316 self.db.parse(file_id).clone()
317 } 317 }
318 318
319 /// Gets the file's `LineIndex`: data structure to convert between absolute 319 /// Gets the file's `LineIndex`: data structure to convert between absolute
@@ -330,21 +330,21 @@ impl Analysis {
330 /// Returns position of the mathcing brace (all types of braces are 330 /// Returns position of the mathcing brace (all types of braces are
331 /// supported). 331 /// supported).
332 pub fn matching_brace(&self, position: FilePosition) -> Option<TextUnit> { 332 pub fn matching_brace(&self, position: FilePosition) -> Option<TextUnit> {
333 let file = self.db.source_file(position.file_id); 333 let file = self.db.parse(position.file_id);
334 ra_ide_api_light::matching_brace(&file, position.offset) 334 ra_ide_api_light::matching_brace(&file, position.offset)
335 } 335 }
336 336
337 /// Returns a syntax tree represented as `String`, for debug purposes. 337 /// Returns a syntax tree represented as `String`, for debug purposes.
338 // FIXME: use a better name here. 338 // FIXME: use a better name here.
339 pub fn syntax_tree(&self, file_id: FileId) -> String { 339 pub fn syntax_tree(&self, file_id: FileId) -> String {
340 let file = self.db.source_file(file_id); 340 let file = self.db.parse(file_id);
341 ra_ide_api_light::syntax_tree(&file) 341 ra_ide_api_light::syntax_tree(&file)
342 } 342 }
343 343
344 /// Returns an edit to remove all newlines in the range, cleaning up minor 344 /// Returns an edit to remove all newlines in the range, cleaning up minor
345 /// stuff like trailing commas. 345 /// stuff like trailing commas.
346 pub fn join_lines(&self, frange: FileRange) -> SourceChange { 346 pub fn join_lines(&self, frange: FileRange) -> SourceChange {
347 let file = self.db.source_file(frange.file_id); 347 let file = self.db.parse(frange.file_id);
348 SourceChange::from_local_edit( 348 SourceChange::from_local_edit(
349 frange.file_id, 349 frange.file_id,
350 ra_ide_api_light::join_lines(&file, frange.range), 350 ra_ide_api_light::join_lines(&file, frange.range),
@@ -354,7 +354,7 @@ impl Analysis {
354 /// Returns an edit which should be applied when opening a new line, fixing 354 /// Returns an edit which should be applied when opening a new line, fixing
355 /// up minor stuff like continuing the comment. 355 /// up minor stuff like continuing the comment.
356 pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> { 356 pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> {
357 let file = self.db.source_file(position.file_id); 357 let file = self.db.parse(position.file_id);
358 let edit = ra_ide_api_light::on_enter(&file, position.offset)?; 358 let edit = ra_ide_api_light::on_enter(&file, position.offset)?;
359 Some(SourceChange::from_local_edit(position.file_id, edit)) 359 Some(SourceChange::from_local_edit(position.file_id, edit))
360 } 360 }
@@ -363,14 +363,14 @@ impl Analysis {
363 /// this works when adding `let =`. 363 /// this works when adding `let =`.
364 // FIXME: use a snippet completion instead of this hack here. 364 // FIXME: use a snippet completion instead of this hack here.
365 pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> { 365 pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> {
366 let file = self.db.source_file(position.file_id); 366 let file = self.db.parse(position.file_id);
367 let edit = ra_ide_api_light::on_eq_typed(&file, position.offset)?; 367 let edit = ra_ide_api_light::on_eq_typed(&file, position.offset)?;
368 Some(SourceChange::from_local_edit(position.file_id, edit)) 368 Some(SourceChange::from_local_edit(position.file_id, edit))
369 } 369 }
370 370
371 /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. 371 /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately.
372 pub fn on_dot_typed(&self, position: FilePosition) -> Option<SourceChange> { 372 pub fn on_dot_typed(&self, position: FilePosition) -> Option<SourceChange> {
373 let file = self.db.source_file(position.file_id); 373 let file = self.db.parse(position.file_id);
374 let edit = ra_ide_api_light::on_dot_typed(&file, position.offset)?; 374 let edit = ra_ide_api_light::on_dot_typed(&file, position.offset)?;
375 Some(SourceChange::from_local_edit(position.file_id, edit)) 375 Some(SourceChange::from_local_edit(position.file_id, edit))
376 } 376 }
@@ -378,13 +378,13 @@ impl Analysis {
378 /// Returns a tree representation of symbols in the file. Useful to draw a 378 /// Returns a tree representation of symbols in the file. Useful to draw a
379 /// file outline. 379 /// file outline.
380 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { 380 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> {
381 let file = self.db.source_file(file_id); 381 let file = self.db.parse(file_id);
382 ra_ide_api_light::file_structure(&file) 382 ra_ide_api_light::file_structure(&file)
383 } 383 }
384 384
385 /// Returns the set of folding ranges. 385 /// Returns the set of folding ranges.
386 pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> { 386 pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> {
387 let file = self.db.source_file(file_id); 387 let file = self.db.parse(file_id);
388 ra_ide_api_light::folding_ranges(&file) 388 ra_ide_api_light::folding_ranges(&file)
389 } 389 }
390 390
diff --git a/crates/ra_ide_api/src/rename.rs b/crates/ra_ide_api/src/rename.rs
index 5b767addd..db5ccf969 100644
--- a/crates/ra_ide_api/src/rename.rs
+++ b/crates/ra_ide_api/src/rename.rs
@@ -17,7 +17,7 @@ use crate::{
17 SourceChange, 17 SourceChange,
18 SourceFileEdit, 18 SourceFileEdit,
19}; 19};
20use ra_db::{FilesDatabase, SyntaxDatabase}; 20use ra_db::SourceDatabase;
21use relative_path::RelativePath; 21use relative_path::RelativePath;
22 22
23pub(crate) fn rename( 23pub(crate) fn rename(
@@ -25,7 +25,7 @@ pub(crate) fn rename(
25 position: FilePosition, 25 position: FilePosition,
26 new_name: &str, 26 new_name: &str,
27) -> Option<SourceChange> { 27) -> Option<SourceChange> {
28 let source_file = db.source_file(position.file_id); 28 let source_file = db.parse(position.file_id);
29 let syntax = source_file.syntax(); 29 let syntax = source_file.syntax();
30 30
31 if let Some((ast_name, ast_module)) = find_name_and_module_at_offset(syntax, position) { 31 if let Some((ast_name, ast_module)) = find_name_and_module_at_offset(syntax, position) {
diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs
index 0f9f8deb3..dc8c40ea6 100644
--- a/crates/ra_ide_api/src/runnables.rs
+++ b/crates/ra_ide_api/src/runnables.rs
@@ -3,7 +3,7 @@ use ra_syntax::{
3 TextRange, SyntaxNode, 3 TextRange, SyntaxNode,
4 ast::{self, AstNode, NameOwner, ModuleItemOwner}, 4 ast::{self, AstNode, NameOwner, ModuleItemOwner},
5}; 5};
6use ra_db::SyntaxDatabase; 6use ra_db::SourceDatabase;
7 7
8use crate::{db::RootDatabase, FileId}; 8use crate::{db::RootDatabase, FileId};
9 9
@@ -22,7 +22,7 @@ pub enum RunnableKind {
22} 22}
23 23
24pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { 24pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
25 let source_file = db.source_file(file_id); 25 let source_file = db.parse(file_id);
26 source_file 26 source_file
27 .syntax() 27 .syntax()
28 .descendants() 28 .descendants()
diff --git a/crates/ra_ide_api/src/status.rs b/crates/ra_ide_api/src/status.rs
index 59159df98..e11eed223 100644
--- a/crates/ra_ide_api/src/status.rs
+++ b/crates/ra_ide_api/src/status.rs
@@ -6,7 +6,7 @@ use std::{
6 6
7use ra_syntax::{AstNode, TreeArc, SourceFile}; 7use ra_syntax::{AstNode, TreeArc, SourceFile};
8use ra_db::{ 8use ra_db::{
9 SourceFileQuery, FileTextQuery, SourceRootId, 9 ParseQuery, FileTextQuery, SourceRootId,
10 salsa::{Database, debug::{DebugQueryTable, TableEntry}}, 10 salsa::{Database, debug::{DebugQueryTable, TableEntry}},
11}; 11};
12 12
@@ -17,7 +17,7 @@ use crate::{
17 17
18pub(crate) fn status(db: &RootDatabase) -> String { 18pub(crate) fn status(db: &RootDatabase) -> String {
19 let files_stats = db.query(FileTextQuery).entries::<FilesStats>(); 19 let files_stats = db.query(FileTextQuery).entries::<FilesStats>();
20 let syntax_tree_stats = db.query(SourceFileQuery).entries::<SyntaxTreeStats>(); 20 let syntax_tree_stats = db.query(ParseQuery).entries::<SyntaxTreeStats>();
21 let symbols_stats = db 21 let symbols_stats = db
22 .query(LibrarySymbolsQuery) 22 .query(LibrarySymbolsQuery)
23 .entries::<LibrarySymbolsStats>(); 23 .entries::<LibrarySymbolsStats>();
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index e073a349e..72c93f530 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -34,7 +34,7 @@ use ra_syntax::{
34 ast::{self, NameOwner}, 34 ast::{self, NameOwner},
35}; 35};
36use ra_db::{ 36use ra_db::{
37 SourceRootId, FilesDatabase, 37 SourceRootId, SourceDatabase,
38 salsa::{self, ParallelDatabase}, 38 salsa::{self, ParallelDatabase},
39}; 39};
40use rayon::prelude::*; 40use rayon::prelude::*;
@@ -49,11 +49,19 @@ pub(crate) trait SymbolsDatabase: hir::db::HirDatabase {
49 fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>; 49 fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>;
50 #[salsa::input] 50 #[salsa::input]
51 fn library_symbols(&self, id: SourceRootId) -> Arc<SymbolIndex>; 51 fn library_symbols(&self, id: SourceRootId) -> Arc<SymbolIndex>;
52 /// The set of "local" (that is, from the current workspace) roots.
53 /// Files in local roots are assumed to change frequently.
54 #[salsa::input]
55 fn local_roots(&self) -> Arc<Vec<SourceRootId>>;
56 /// The set of roots for crates.io libraries.
57 /// Files in libraries are assumed to never change.
58 #[salsa::input]
59 fn library_roots(&self) -> Arc<Vec<SourceRootId>>;
52} 60}
53 61
54fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> { 62fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
55 db.check_canceled(); 63 db.check_canceled();
56 let source_file = db.source_file(file_id); 64 let source_file = db.parse(file_id);
57 let mut symbols = source_file 65 let mut symbols = source_file
58 .syntax() 66 .syntax()
59 .descendants() 67 .descendants()
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index a4d3ad005..26bde495b 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -1,5 +1,5 @@
1use ra_syntax::{ast, AstNode,}; 1use ra_syntax::{ast, AstNode,};
2use ra_db::SyntaxDatabase; 2use ra_db::SourceDatabase;
3 3
4use crate::{ 4use crate::{
5 FileId, HighlightedRange, 5 FileId, HighlightedRange,
@@ -7,7 +7,7 @@ use crate::{
7}; 7};
8 8
9pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { 9pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
10 let source_file = db.source_file(file_id); 10 let source_file = db.parse(file_id);
11 let mut res = ra_ide_api_light::highlight(source_file.syntax()); 11 let mut res = ra_ide_api_light::highlight(source_file.syntax());
12 for macro_call in source_file 12 for macro_call in source_file
13 .syntax() 13 .syntax()
diff --git a/crates/ra_ide_api_light/src/snapshots/tests__file_structure.snap b/crates/ra_ide_api_light/src/snapshots/tests__file_structure.snap
index b96398950..270f75a56 100644
--- a/crates/ra_ide_api_light/src/snapshots/tests__file_structure.snap
+++ b/crates/ra_ide_api_light/src/snapshots/tests__file_structure.snap
@@ -1,8 +1,8 @@
1--- 1---
2created: "2019-01-24T18:04:00.090162+00:00" 2created: "2019-01-26T07:11:02.463391362+00:00"
3creator: insta@0.4.0 3creator: insta@0.5.2
4expression: structure 4expression: structure
5source: "crates\\ra_ide_api_light\\src\\structure.rs" 5source: crates/ra_ide_api_light/src/structure.rs
6--- 6---
7[ 7[
8 StructureNode { 8 StructureNode {
@@ -78,6 +78,26 @@ source: "crates\\ra_ide_api_light\\src\\structure.rs"
78 detail: None 78 detail: None
79 }, 79 },
80 StructureNode { 80 StructureNode {
81 parent: Some(
82 6
83 ),
84 label: "X",
85 navigation_range: [169; 170),
86 node_range: [169; 170),
87 kind: ENUM_VARIANT,
88 detail: None
89 },
90 StructureNode {
91 parent: Some(
92 6
93 ),
94 label: "Y",
95 navigation_range: [172; 173),
96 node_range: [172; 178),
97 kind: ENUM_VARIANT,
98 detail: None
99 },
100 StructureNode {
81 parent: None, 101 parent: None,
82 label: "T", 102 label: "T",
83 navigation_range: [186; 187), 103 navigation_range: [186; 187),
diff --git a/crates/ra_ide_api_light/src/structure.rs b/crates/ra_ide_api_light/src/structure.rs
index e3713c217..4e080ed03 100644
--- a/crates/ra_ide_api_light/src/structure.rs
+++ b/crates/ra_ide_api_light/src/structure.rs
@@ -103,6 +103,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
103 .visit(decl::<ast::StructDef>) 103 .visit(decl::<ast::StructDef>)
104 .visit(|nfd: &ast::NamedFieldDef| decl_with_type_ref(nfd, nfd.type_ref())) 104 .visit(|nfd: &ast::NamedFieldDef| decl_with_type_ref(nfd, nfd.type_ref()))
105 .visit(decl::<ast::EnumDef>) 105 .visit(decl::<ast::EnumDef>)
106 .visit(decl::<ast::EnumVariant>)
106 .visit(decl::<ast::TraitDef>) 107 .visit(decl::<ast::TraitDef>)
107 .visit(decl::<ast::Module>) 108 .visit(decl::<ast::Module>)
108 .visit(|td: &ast::TypeDef| decl_with_type_ref(td, td.type_ref())) 109 .visit(|td: &ast::TypeDef| decl_with_type_ref(td, td.type_ref()))
diff --git a/crates/ra_syntax/src/grammar/types.rs b/crates/ra_syntax/src/grammar/types.rs
index 21d89d83b..adc189a29 100644
--- a/crates/ra_syntax/src/grammar/types.rs
+++ b/crates/ra_syntax/src/grammar/types.rs
@@ -29,7 +29,7 @@ fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) {
29 DYN_KW => dyn_trait_type(p), 29 DYN_KW => dyn_trait_type(p),
30 // Some path types are not allowed to have bounds (no plus) 30 // Some path types are not allowed to have bounds (no plus)
31 L_ANGLE => path_type_(p, allow_bounds), 31 L_ANGLE => path_type_(p, allow_bounds),
32 _ if paths::is_path_start(p) => path_type_(p, allow_bounds), 32 _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds),
33 _ => { 33 _ => {
34 p.err_recover("expected type", TYPE_RECOVERY_SET); 34 p.err_recover("expected type", TYPE_RECOVERY_SET);
35 } 35 }
@@ -243,6 +243,28 @@ pub(super) fn path_type(p: &mut Parser) {
243 path_type_(p, true) 243 path_type_(p, true)
244} 244}
245 245
246// test macro_call_type
247// type A = foo!();
248// type B = crate::foo!();
249fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) {
250 assert!(paths::is_path_start(p) || p.at(L_ANGLE));
251 let m = p.start();
252 paths::type_path(p);
253
254 let kind = if p.at(EXCL) {
255 items::macro_call_after_excl(p);
256 MACRO_CALL
257 } else {
258 PATH_TYPE
259 };
260
261 if allow_bounds && p.eat(PLUS) {
262 type_params::bounds_without_colon(p);
263 }
264
265 m.complete(p, kind);
266}
267
246pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) { 268pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) {
247 assert!(paths::is_path_start(p) || p.at(L_ANGLE)); 269 assert!(paths::is_path_start(p) || p.at(L_ANGLE));
248 let m = p.start(); 270 let m = p.start();
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0117_macro_call_type.rs b/crates/ra_syntax/tests/data/parser/inline/ok/0117_macro_call_type.rs
new file mode 100644
index 000000000..edb470c89
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0117_macro_call_type.rs
@@ -0,0 +1,2 @@
1type A = foo!();
2type B = crate::foo!();
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0117_macro_call_type.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0117_macro_call_type.txt
new file mode 100644
index 000000000..b2d95451c
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0117_macro_call_type.txt
@@ -0,0 +1,43 @@
1SOURCE_FILE@[0; 41)
2 TYPE_DEF@[0; 16)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "A"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 MACRO_CALL@[9; 15)
11 PATH@[9; 12)
12 PATH_SEGMENT@[9; 12)
13 NAME_REF@[9; 12)
14 IDENT@[9; 12) "foo"
15 EXCL@[12; 13)
16 TOKEN_TREE@[13; 15)
17 L_PAREN@[13; 14)
18 R_PAREN@[14; 15)
19 SEMI@[15; 16)
20 WHITESPACE@[16; 17)
21 TYPE_DEF@[17; 40)
22 TYPE_KW@[17; 21)
23 WHITESPACE@[21; 22)
24 NAME@[22; 23)
25 IDENT@[22; 23) "B"
26 WHITESPACE@[23; 24)
27 EQ@[24; 25)
28 WHITESPACE@[25; 26)
29 MACRO_CALL@[26; 39)
30 PATH@[26; 36)
31 PATH@[26; 31)
32 PATH_SEGMENT@[26; 31)
33 CRATE_KW@[26; 31)
34 COLONCOLON@[31; 33)
35 PATH_SEGMENT@[33; 36)
36 NAME_REF@[33; 36)
37 IDENT@[33; 36) "foo"
38 EXCL@[36; 37)
39 TOKEN_TREE@[37; 39)
40 L_PAREN@[37; 38)
41 R_PAREN@[38; 39)
42 SEMI@[39; 40)
43 WHITESPACE@[40; 41)
diff --git a/crates/ra_vfs/Cargo.toml b/crates/ra_vfs/Cargo.toml
index e637063c9..383381d2a 100644
--- a/crates/ra_vfs/Cargo.toml
+++ b/crates/ra_vfs/Cargo.toml
@@ -10,9 +10,13 @@ relative-path = "0.4.0"
10rustc-hash = "1.0" 10rustc-hash = "1.0"
11crossbeam-channel = "0.3.5" 11crossbeam-channel = "0.3.5"
12log = "0.4.6" 12log = "0.4.6"
13notify = "4.0.7"
14drop_bomb = "0.1.0"
15parking_lot = "0.7.0"
13 16
14thread_worker = { path = "../thread_worker" } 17thread_worker = { path = "../thread_worker" }
15ra_arena = { path = "../ra_arena" } 18ra_arena = { path = "../ra_arena" }
16 19
17[dev-dependencies] 20[dev-dependencies]
18tempfile = "3" 21tempfile = "3"
22flexi_logger = "0.10.0"
diff --git a/crates/ra_vfs/src/io.rs b/crates/ra_vfs/src/io.rs
index 80328ad18..7ca1e9835 100644
--- a/crates/ra_vfs/src/io.rs
+++ b/crates/ra_vfs/src/io.rs
@@ -1,55 +1,109 @@
1use std::{ 1use std::{fs, sync::Arc, thread};
2 fmt,
3 fs,
4 path::{Path, PathBuf},
5};
6 2
7use walkdir::{DirEntry, WalkDir}; 3use crossbeam_channel::{Receiver, Sender};
8use thread_worker::{WorkerHandle};
9use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
5use thread_worker::WorkerHandle;
6use walkdir::WalkDir;
10 7
11use crate::{VfsRoot, has_rs_extension}; 8mod watcher;
9use watcher::Watcher;
12 10
13pub(crate) struct Task { 11use crate::{RootFilter, Roots, VfsRoot};
14 pub(crate) root: VfsRoot, 12
15 pub(crate) path: PathBuf, 13pub(crate) enum Task {
16 pub(crate) filter: Box<Fn(&DirEntry) -> bool + Send>, 14 AddRoot {
15 root: VfsRoot,
16 filter: Arc<RootFilter>,
17 },
17} 18}
18 19
19pub struct TaskResult { 20#[derive(Debug)]
20 pub(crate) root: VfsRoot, 21pub enum TaskResult {
21 pub(crate) files: Vec<(RelativePathBuf, String)>, 22 BulkLoadRoot {
23 root: VfsRoot,
24 files: Vec<(RelativePathBuf, String)>,
25 },
26 AddSingleFile {
27 root: VfsRoot,
28 path: RelativePathBuf,
29 text: String,
30 },
31 ChangeSingleFile {
32 root: VfsRoot,
33 path: RelativePathBuf,
34 text: String,
35 },
36 RemoveSingleFile {
37 root: VfsRoot,
38 path: RelativePathBuf,
39 },
22} 40}
23 41
24impl fmt::Debug for TaskResult { 42pub(crate) struct Worker {
25 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 43 worker: thread_worker::Worker<Task, TaskResult>,
26 f.write_str("TaskResult { ... }") 44 worker_handle: WorkerHandle,
27 }
28} 45}
29 46
30pub(crate) type Worker = thread_worker::Worker<Task, TaskResult>; 47impl Worker {
48 pub(crate) fn start(roots: Arc<Roots>) -> Worker {
49 let (worker, worker_handle) =
50 thread_worker::spawn("vfs", 128, move |input_receiver, output_sender| {
51 let mut watcher = match Watcher::start(roots, output_sender.clone()) {
52 Ok(w) => Some(w),
53 Err(e) => {
54 log::error!("could not start watcher: {}", e);
55 None
56 }
57 };
58 let res = input_receiver
59 .into_iter()
60 .filter_map(|t| handle_task(t, &mut watcher))
61 .try_for_each(|it| output_sender.send(it));
62 if let Some(watcher) = watcher {
63 let _ = watcher.shutdown();
64 }
65 res.unwrap()
66 });
67 Worker {
68 worker,
69 worker_handle,
70 }
71 }
72
73 pub(crate) fn sender(&self) -> &Sender<Task> {
74 &self.worker.inp
75 }
76
77 pub(crate) fn receiver(&self) -> &Receiver<TaskResult> {
78 &self.worker.out
79 }
31 80
32pub(crate) fn start() -> (Worker, WorkerHandle) { 81 pub(crate) fn shutdown(self) -> thread::Result<()> {
33 thread_worker::spawn("vfs", 128, |input_receiver, output_sender| { 82 let _ = self.worker.shutdown();
34 input_receiver 83 self.worker_handle.shutdown()
35 .into_iter() 84 }
36 .map(handle_task)
37 .try_for_each(|it| output_sender.send(it))
38 .unwrap()
39 })
40} 85}
41 86
42fn handle_task(task: Task) -> TaskResult { 87fn handle_task(task: Task, watcher: &mut Option<Watcher>) -> Option<TaskResult> {
43 let Task { root, path, filter } = task; 88 match task {
44 log::debug!("loading {} ...", path.as_path().display()); 89 Task::AddRoot { root, filter } => {
45 let files = load_root(path.as_path(), &*filter); 90 if let Some(watcher) = watcher {
46 log::debug!("... loaded {}", path.as_path().display()); 91 watcher.watch_root(&filter)
47 TaskResult { root, files } 92 }
93 log::debug!("loading {} ...", filter.root.as_path().display());
94 let files = load_root(filter.as_ref());
95 log::debug!("... loaded {}", filter.root.as_path().display());
96 Some(TaskResult::BulkLoadRoot { root, files })
97 }
98 }
48} 99}
49 100
50fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePathBuf, String)> { 101fn load_root(filter: &RootFilter) -> Vec<(RelativePathBuf, String)> {
51 let mut res = Vec::new(); 102 let mut res = Vec::new();
52 for entry in WalkDir::new(root).into_iter().filter_entry(filter) { 103 for entry in WalkDir::new(&filter.root)
104 .into_iter()
105 .filter_entry(filter.entry_filter())
106 {
53 let entry = match entry { 107 let entry = match entry {
54 Ok(entry) => entry, 108 Ok(entry) => entry,
55 Err(e) => { 109 Err(e) => {
@@ -61,9 +115,6 @@ fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePa
61 continue; 115 continue;
62 } 116 }
63 let path = entry.path(); 117 let path = entry.path();
64 if !has_rs_extension(path) {
65 continue;
66 }
67 let text = match fs::read_to_string(path) { 118 let text = match fs::read_to_string(path) {
68 Ok(text) => text, 119 Ok(text) => text,
69 Err(e) => { 120 Err(e) => {
@@ -71,7 +122,7 @@ fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePa
71 continue; 122 continue;
72 } 123 }
73 }; 124 };
74 let path = RelativePathBuf::from_path(path.strip_prefix(root).unwrap()).unwrap(); 125 let path = RelativePathBuf::from_path(path.strip_prefix(&filter.root).unwrap()).unwrap();
75 res.push((path.to_owned(), text)) 126 res.push((path.to_owned(), text))
76 } 127 }
77 res 128 res
diff --git a/crates/ra_vfs/src/io/watcher.rs b/crates/ra_vfs/src/io/watcher.rs
new file mode 100644
index 000000000..ff6775f59
--- /dev/null
+++ b/crates/ra_vfs/src/io/watcher.rs
@@ -0,0 +1,200 @@
1use crate::{io, RootFilter, Roots, VfsRoot};
2use crossbeam_channel::Sender;
3use drop_bomb::DropBomb;
4use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher};
5use parking_lot::Mutex;
6use std::{
7 fs,
8 path::{Path, PathBuf},
9 sync::{mpsc, Arc},
10 thread,
11 time::Duration,
12};
13use walkdir::WalkDir;
14
15#[derive(Debug)]
16enum ChangeKind {
17 Create,
18 Write,
19 Remove,
20}
21
22const WATCHER_DELAY: Duration = Duration::from_millis(250);
23
24pub(crate) struct Watcher {
25 thread: thread::JoinHandle<()>,
26 bomb: DropBomb,
27 watcher: Arc<Mutex<Option<RecommendedWatcher>>>,
28}
29
30impl Watcher {
31 pub(crate) fn start(
32 roots: Arc<Roots>,
33 output_sender: Sender<io::TaskResult>,
34 ) -> Result<Watcher, Box<std::error::Error>> {
35 let (input_sender, input_receiver) = mpsc::channel();
36 let watcher = Arc::new(Mutex::new(Some(notify::watcher(
37 input_sender,
38 WATCHER_DELAY,
39 )?)));
40 let sender = output_sender.clone();
41 let watcher_clone = watcher.clone();
42 let thread = thread::spawn(move || {
43 let worker = WatcherWorker {
44 roots,
45 watcher: watcher_clone,
46 sender,
47 };
48 input_receiver
49 .into_iter()
50 // forward relevant events only
51 .try_for_each(|change| worker.handle_debounced_event(change))
52 .unwrap()
53 });
54 Ok(Watcher {
55 thread,
56 watcher,
57 bomb: DropBomb::new(format!("Watcher was not shutdown")),
58 })
59 }
60
61 pub fn watch_root(&mut self, filter: &RootFilter) {
62 for res in WalkDir::new(&filter.root)
63 .into_iter()
64 .filter_entry(filter.entry_filter())
65 {
66 match res {
67 Ok(entry) => {
68 if entry.file_type().is_dir() {
69 watch_one(self.watcher.as_ref(), entry.path());
70 }
71 }
72 Err(e) => log::warn!("watcher error: {}", e),
73 }
74 }
75 }
76
77 pub fn shutdown(mut self) -> thread::Result<()> {
78 self.bomb.defuse();
79 drop(self.watcher.lock().take());
80 let res = self.thread.join();
81 match &res {
82 Ok(()) => log::info!("... Watcher terminated with ok"),
83 Err(_) => log::error!("... Watcher terminated with err"),
84 }
85 res
86 }
87}
88
89struct WatcherWorker {
90 watcher: Arc<Mutex<Option<RecommendedWatcher>>>,
91 roots: Arc<Roots>,
92 sender: Sender<io::TaskResult>,
93}
94
95impl WatcherWorker {
96 fn handle_debounced_event(&self, ev: DebouncedEvent) -> Result<(), Box<std::error::Error>> {
97 match ev {
98 DebouncedEvent::NoticeWrite(_)
99 | DebouncedEvent::NoticeRemove(_)
100 | DebouncedEvent::Chmod(_) => {
101 // ignore
102 }
103 DebouncedEvent::Rescan => {
104 // TODO rescan all roots
105 }
106 DebouncedEvent::Create(path) => {
107 self.handle_change(path, ChangeKind::Create);
108 }
109 DebouncedEvent::Write(path) => {
110 self.handle_change(path, ChangeKind::Write);
111 }
112 DebouncedEvent::Remove(path) => {
113 self.handle_change(path, ChangeKind::Remove);
114 }
115 DebouncedEvent::Rename(src, dst) => {
116 self.handle_change(src, ChangeKind::Remove);
117 self.handle_change(dst, ChangeKind::Create);
118 }
119 DebouncedEvent::Error(err, path) => {
120 // TODO should we reload the file contents?
121 log::warn!("watcher error \"{}\", {:?}", err, path);
122 }
123 }
124 Ok(())
125 }
126
127 fn handle_change(&self, path: PathBuf, kind: ChangeKind) {
128 if let Err(e) = self.try_handle_change(path, kind) {
129 log::warn!("watcher error: {}", e)
130 }
131 }
132
133 fn try_handle_change(
134 &self,
135 path: PathBuf,
136 kind: ChangeKind,
137 ) -> Result<(), Box<std::error::Error>> {
138 let (root, rel_path) = match self.roots.find(&path) {
139 Some(x) => x,
140 None => return Ok(()),
141 };
142 match kind {
143 ChangeKind::Create => {
144 if path.is_dir() {
145 self.watch_recursive(&path, root);
146 } else {
147 let text = fs::read_to_string(&path)?;
148 self.sender.send(io::TaskResult::AddSingleFile {
149 root,
150 path: rel_path,
151 text,
152 })?
153 }
154 }
155 ChangeKind::Write => {
156 let text = fs::read_to_string(&path)?;
157 self.sender.send(io::TaskResult::ChangeSingleFile {
158 root,
159 path: rel_path,
160 text,
161 })?
162 }
163 ChangeKind::Remove => self.sender.send(io::TaskResult::RemoveSingleFile {
164 root,
165 path: rel_path,
166 })?,
167 }
168 Ok(())
169 }
170
171 fn watch_recursive(&self, dir: &Path, root: VfsRoot) {
172 let filter = &self.roots[root];
173 for res in WalkDir::new(dir)
174 .into_iter()
175 .filter_entry(filter.entry_filter())
176 {
177 match res {
178 Ok(entry) => {
179 if entry.file_type().is_dir() {
180 watch_one(self.watcher.as_ref(), entry.path());
181 } else {
182 // emit only for files otherwise we will cause watch_recursive to be called again with a dir that we are already watching
183 // emit as create because we haven't seen it yet
184 self.handle_change(entry.path().to_path_buf(), ChangeKind::Create);
185 }
186 }
187 Err(e) => log::warn!("watcher error: {}", e),
188 }
189 }
190 }
191}
192
193fn watch_one(watcher: &Mutex<Option<RecommendedWatcher>>, dir: &Path) {
194 if let Some(watcher) = watcher.lock().as_mut() {
195 match watcher.watch(dir, RecursiveMode::NonRecursive) {
196 Ok(()) => log::debug!("watching \"{}\"", dir.display()),
197 Err(e) => log::warn!("could not watch \"{}\": {}", dir.display(), e),
198 }
199 }
200}
diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs
index cdea18d73..70a13f765 100644
--- a/crates/ra_vfs/src/lib.rs
+++ b/crates/ra_vfs/src/lib.rs
@@ -16,52 +16,77 @@
16mod io; 16mod io;
17 17
18use std::{ 18use std::{
19 fmt,
20 mem,
21 thread,
22 cmp::Reverse, 19 cmp::Reverse,
20 fmt, fs, mem,
21 ops::{Deref, DerefMut},
23 path::{Path, PathBuf}, 22 path::{Path, PathBuf},
24 ffi::OsStr,
25 sync::Arc, 23 sync::Arc,
26 fs, 24 thread,
27}; 25};
28 26
29use rustc_hash::{FxHashMap, FxHashSet};
30use relative_path::RelativePathBuf;
31use crossbeam_channel::Receiver; 27use crossbeam_channel::Receiver;
28use ra_arena::{impl_arena_id, Arena, RawId};
29use relative_path::{Component, RelativePath, RelativePathBuf};
30use rustc_hash::{FxHashMap, FxHashSet};
32use walkdir::DirEntry; 31use walkdir::DirEntry;
33use thread_worker::WorkerHandle;
34use ra_arena::{Arena, RawId, impl_arena_id};
35 32
36pub use crate::io::TaskResult as VfsTask; 33pub use crate::io::TaskResult as VfsTask;
34use io::{TaskResult, Worker};
37 35
38/// `RootFilter` is a predicate that checks if a file can belong to a root. If 36/// `RootFilter` is a predicate that checks if a file can belong to a root. If
39/// several filters match a file (nested dirs), the most nested one wins. 37/// several filters match a file (nested dirs), the most nested one wins.
40struct RootFilter { 38pub(crate) struct RootFilter {
41 root: PathBuf, 39 root: PathBuf,
42 file_filter: fn(&Path) -> bool, 40 filter: fn(&Path, &RelativePath) -> bool,
41 excluded_dirs: Vec<PathBuf>,
43} 42}
44 43
45impl RootFilter { 44impl RootFilter {
46 fn new(root: PathBuf) -> RootFilter { 45 fn new(root: PathBuf, excluded_dirs: Vec<PathBuf>) -> RootFilter {
47 RootFilter { 46 RootFilter {
48 root, 47 root,
49 file_filter: has_rs_extension, 48 filter: default_filter,
49 excluded_dirs,
50 } 50 }
51 } 51 }
52 /// Check if this root can contain `path`. NB: even if this returns 52 /// Check if this root can contain `path`. NB: even if this returns
53 /// true, the `path` might actually be conained in some nested root. 53 /// true, the `path` might actually be conained in some nested root.
54 fn can_contain(&self, path: &Path) -> Option<RelativePathBuf> { 54 pub(crate) fn can_contain(&self, path: &Path) -> Option<RelativePathBuf> {
55 if !(self.file_filter)(path) { 55 let rel_path = path.strip_prefix(&self.root).ok()?;
56 let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
57 if !(self.filter)(path, rel_path.as_relative_path()) {
56 return None; 58 return None;
57 } 59 }
58 let path = path.strip_prefix(&self.root).ok()?; 60 Some(rel_path)
59 RelativePathBuf::from_path(path).ok() 61 }
62
63 pub(crate) fn entry_filter<'a>(&'a self) -> impl FnMut(&DirEntry) -> bool + 'a {
64 move |entry: &DirEntry| {
65 if entry.file_type().is_dir() && self.excluded_dirs.iter().any(|it| it == entry.path())
66 {
67 // do not walk nested roots
68 false
69 } else {
70 self.can_contain(entry.path()).is_some()
71 }
72 }
60 } 73 }
61} 74}
62 75
63fn has_rs_extension(p: &Path) -> bool { 76pub(crate) fn default_filter(path: &Path, rel_path: &RelativePath) -> bool {
64 p.extension() == Some(OsStr::new("rs")) 77 if path.is_dir() {
78 for (i, c) in rel_path.components().enumerate() {
79 if let Component::Normal(c) = c {
80 // TODO hardcoded for now
81 if (i == 0 && c == "target") || c == ".git" || c == "node_modules" {
82 return false;
83 }
84 }
85 }
86 true
87 } else {
88 rel_path.extension() == Some("rs")
89 }
65} 90}
66 91
67#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 92#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -75,16 +100,58 @@ impl_arena_id!(VfsFile);
75struct VfsFileData { 100struct VfsFileData {
76 root: VfsRoot, 101 root: VfsRoot,
77 path: RelativePathBuf, 102 path: RelativePathBuf,
103 is_overlayed: bool,
78 text: Arc<String>, 104 text: Arc<String>,
79} 105}
80 106
107pub(crate) struct Roots {
108 roots: Arena<VfsRoot, Arc<RootFilter>>,
109}
110
111impl Roots {
112 pub(crate) fn new(mut paths: Vec<PathBuf>) -> Roots {
113 let mut roots = Arena::default();
114 // A hack to make nesting work.
115 paths.sort_by_key(|it| Reverse(it.as_os_str().len()));
116 for (i, path) in paths.iter().enumerate() {
117 let nested_roots = paths[..i]
118 .iter()
119 .filter(|it| it.starts_with(path))
120 .map(|it| it.clone())
121 .collect::<Vec<_>>();
122
123 let root_filter = Arc::new(RootFilter::new(path.clone(), nested_roots));
124
125 roots.alloc(root_filter.clone());
126 }
127 Roots { roots }
128 }
129 pub(crate) fn find(&self, path: &Path) -> Option<(VfsRoot, RelativePathBuf)> {
130 self.roots
131 .iter()
132 .find_map(|(root, data)| data.can_contain(path).map(|it| (root, it)))
133 }
134}
135
136impl Deref for Roots {
137 type Target = Arena<VfsRoot, Arc<RootFilter>>;
138 fn deref(&self) -> &Self::Target {
139 &self.roots
140 }
141}
142
143impl DerefMut for Roots {
144 fn deref_mut(&mut self) -> &mut Self::Target {
145 &mut self.roots
146 }
147}
148
81pub struct Vfs { 149pub struct Vfs {
82 roots: Arena<VfsRoot, RootFilter>, 150 roots: Arc<Roots>,
83 files: Arena<VfsFile, VfsFileData>, 151 files: Arena<VfsFile, VfsFileData>,
84 root2files: FxHashMap<VfsRoot, FxHashSet<VfsFile>>, 152 root2files: FxHashMap<VfsRoot, FxHashSet<VfsFile>>,
85 pending_changes: Vec<VfsChange>, 153 pending_changes: Vec<VfsChange>,
86 worker: io::Worker, 154 worker: Worker,
87 worker_handle: WorkerHandle,
88} 155}
89 156
90impl fmt::Debug for Vfs { 157impl fmt::Debug for Vfs {
@@ -94,44 +161,30 @@ impl fmt::Debug for Vfs {
94} 161}
95 162
96impl Vfs { 163impl Vfs {
97 pub fn new(mut roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) { 164 pub fn new(roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) {
98 let (worker, worker_handle) = io::start(); 165 let roots = Arc::new(Roots::new(roots));
99 166 let worker = io::Worker::start(roots.clone());
100 let mut res = Vfs { 167 let mut root2files = FxHashMap::default();
101 roots: Arena::default(), 168
169 for (root, filter) in roots.iter() {
170 root2files.insert(root, Default::default());
171 worker
172 .sender()
173 .send(io::Task::AddRoot {
174 root,
175 filter: filter.clone(),
176 })
177 .unwrap();
178 }
179 let res = Vfs {
180 roots,
102 files: Arena::default(), 181 files: Arena::default(),
103 root2files: FxHashMap::default(), 182 root2files,
104 worker, 183 worker,
105 worker_handle,
106 pending_changes: Vec::new(), 184 pending_changes: Vec::new(),
107 }; 185 };
108 186 let vfs_roots = res.roots.iter().map(|(id, _)| id).collect();
109 // A hack to make nesting work. 187 (res, vfs_roots)
110 roots.sort_by_key(|it| Reverse(it.as_os_str().len()));
111 for (i, path) in roots.iter().enumerate() {
112 let root = res.roots.alloc(RootFilter::new(path.clone()));
113 res.root2files.insert(root, Default::default());
114 let nested = roots[..i]
115 .iter()
116 .filter(|it| it.starts_with(path))
117 .map(|it| it.clone())
118 .collect::<Vec<_>>();
119 let filter = move |entry: &DirEntry| {
120 if entry.file_type().is_file() {
121 has_rs_extension(entry.path())
122 } else {
123 nested.iter().all(|it| it != entry.path())
124 }
125 };
126 let task = io::Task {
127 root,
128 path: path.clone(),
129 filter: Box::new(filter),
130 };
131 res.worker.inp.send(task).unwrap();
132 }
133 let roots = res.roots.iter().map(|(id, _)| id).collect();
134 (res, roots)
135 } 188 }
136 189
137 pub fn root2path(&self, root: VfsRoot) -> PathBuf { 190 pub fn root2path(&self, root: VfsRoot) -> PathBuf {
@@ -165,7 +218,7 @@ impl Vfs {
165 } else { 218 } else {
166 let text = fs::read_to_string(path).unwrap_or_default(); 219 let text = fs::read_to_string(path).unwrap_or_default();
167 let text = Arc::new(text); 220 let text = Arc::new(text);
168 let file = self.add_file(root, rel_path.clone(), Arc::clone(&text)); 221 let file = self.add_file(root, rel_path.clone(), Arc::clone(&text), false);
169 let change = VfsChange::AddFile { 222 let change = VfsChange::AddFile {
170 file, 223 file,
171 text, 224 text,
@@ -180,85 +233,132 @@ impl Vfs {
180 } 233 }
181 234
182 pub fn task_receiver(&self) -> &Receiver<io::TaskResult> { 235 pub fn task_receiver(&self) -> &Receiver<io::TaskResult> {
183 &self.worker.out 236 self.worker.receiver()
184 } 237 }
185 238
186 pub fn handle_task(&mut self, task: io::TaskResult) { 239 pub fn handle_task(&mut self, task: io::TaskResult) {
187 let mut files = Vec::new(); 240 match task {
188 // While we were scanning the root in the backgound, a file might have 241 TaskResult::BulkLoadRoot { root, files } => {
189 // been open in the editor, so we need to account for that. 242 let mut cur_files = Vec::new();
190 let exising = self.root2files[&task.root] 243 // While we were scanning the root in the backgound, a file might have
191 .iter() 244 // been open in the editor, so we need to account for that.
192 .map(|&file| (self.files[file].path.clone(), file)) 245 let exising = self.root2files[&root]
193 .collect::<FxHashMap<_, _>>(); 246 .iter()
194 for (path, text) in task.files { 247 .map(|&file| (self.files[file].path.clone(), file))
195 if let Some(&file) = exising.get(&path) { 248 .collect::<FxHashMap<_, _>>();
196 let text = Arc::clone(&self.files[file].text); 249 for (path, text) in files {
197 files.push((file, path, text)); 250 if let Some(&file) = exising.get(&path) {
198 continue; 251 let text = Arc::clone(&self.files[file].text);
252 cur_files.push((file, path, text));
253 continue;
254 }
255 let text = Arc::new(text);
256 let file = self.add_file(root, path.clone(), Arc::clone(&text), false);
257 cur_files.push((file, path, text));
258 }
259
260 let change = VfsChange::AddRoot {
261 root,
262 files: cur_files,
263 };
264 self.pending_changes.push(change);
265 }
266 TaskResult::AddSingleFile { root, path, text } => {
267 if self.find_file(root, &path).is_none() {
268 self.do_add_file(root, path, text, false);
269 }
270 }
271 TaskResult::ChangeSingleFile { root, path, text } => {
272 if let Some(file) = self.find_file(root, &path) {
273 self.do_change_file(file, text, false);
274 } else {
275 self.do_add_file(root, path, text, false);
276 }
277 }
278 TaskResult::RemoveSingleFile { root, path } => {
279 if let Some(file) = self.find_file(root, &path) {
280 self.do_remove_file(root, path, file, false);
281 }
199 } 282 }
200 let text = Arc::new(text);
201 let file = self.add_file(task.root, path.clone(), Arc::clone(&text));
202 files.push((file, path, text));
203 } 283 }
284 }
204 285
205 let change = VfsChange::AddRoot { 286 fn do_add_file(
206 root: task.root, 287 &mut self,
207 files, 288 root: VfsRoot,
208 }; 289 path: RelativePathBuf,
209 self.pending_changes.push(change); 290 text: String,
291 is_overlay: bool,
292 ) -> Option<VfsFile> {
293 let text = Arc::new(text);
294 let file = self.add_file(root, path.clone(), text.clone(), is_overlay);
295 self.pending_changes.push(VfsChange::AddFile {
296 file,
297 root,
298 path,
299 text,
300 });
301 Some(file)
302 }
303
304 fn do_change_file(&mut self, file: VfsFile, text: String, is_overlay: bool) {
305 if !is_overlay && self.files[file].is_overlayed {
306 return;
307 }
308 let text = Arc::new(text);
309 self.change_file(file, text.clone(), is_overlay);
310 self.pending_changes
311 .push(VfsChange::ChangeFile { file, text });
312 }
313
314 fn do_remove_file(
315 &mut self,
316 root: VfsRoot,
317 path: RelativePathBuf,
318 file: VfsFile,
319 is_overlay: bool,
320 ) {
321 if !is_overlay && self.files[file].is_overlayed {
322 return;
323 }
324 self.remove_file(file);
325 self.pending_changes
326 .push(VfsChange::RemoveFile { root, path, file });
210 } 327 }
211 328
212 pub fn add_file_overlay(&mut self, path: &Path, text: String) -> Option<VfsFile> { 329 pub fn add_file_overlay(&mut self, path: &Path, text: String) -> Option<VfsFile> {
213 let mut res = None; 330 if let Some((root, rel_path, file)) = self.find_root(path) {
214 if let Some((root, path, file)) = self.find_root(path) { 331 if let Some(file) = file {
215 let text = Arc::new(text); 332 self.do_change_file(file, text, true);
216 let change = if let Some(file) = file { 333 Some(file)
217 res = Some(file);
218 self.change_file(file, Arc::clone(&text));
219 VfsChange::ChangeFile { file, text }
220 } else { 334 } else {
221 let file = self.add_file(root, path.clone(), Arc::clone(&text)); 335 self.do_add_file(root, rel_path, text, true)
222 res = Some(file); 336 }
223 VfsChange::AddFile { 337 } else {
224 file, 338 None
225 text,
226 root,
227 path,
228 }
229 };
230 self.pending_changes.push(change);
231 } 339 }
232 res
233 } 340 }
234 341
235 pub fn change_file_overlay(&mut self, path: &Path, new_text: String) { 342 pub fn change_file_overlay(&mut self, path: &Path, new_text: String) {
236 if let Some((_root, _path, file)) = self.find_root(path) { 343 if let Some((_root, _path, file)) = self.find_root(path) {
237 let file = file.expect("can't change a file which wasn't added"); 344 let file = file.expect("can't change a file which wasn't added");
238 let text = Arc::new(new_text); 345 self.do_change_file(file, new_text, true);
239 self.change_file(file, Arc::clone(&text));
240 let change = VfsChange::ChangeFile { file, text };
241 self.pending_changes.push(change);
242 } 346 }
243 } 347 }
244 348
245 pub fn remove_file_overlay(&mut self, path: &Path) -> Option<VfsFile> { 349 pub fn remove_file_overlay(&mut self, path: &Path) -> Option<VfsFile> {
246 let mut res = None;
247 if let Some((root, path, file)) = self.find_root(path) { 350 if let Some((root, path, file)) = self.find_root(path) {
248 let file = file.expect("can't remove a file which wasn't added"); 351 let file = file.expect("can't remove a file which wasn't added");
249 res = Some(file);
250 let full_path = path.to_path(&self.roots[root].root); 352 let full_path = path.to_path(&self.roots[root].root);
251 let change = if let Ok(text) = fs::read_to_string(&full_path) { 353 if let Ok(text) = fs::read_to_string(&full_path) {
252 let text = Arc::new(text); 354 self.do_change_file(file, text, true);
253 self.change_file(file, Arc::clone(&text));
254 VfsChange::ChangeFile { file, text }
255 } else { 355 } else {
256 self.remove_file(file); 356 self.do_remove_file(root, path, file, true);
257 VfsChange::RemoveFile { root, file, path } 357 }
258 }; 358 Some(file)
259 self.pending_changes.push(change); 359 } else {
360 None
260 } 361 }
261 res
262 } 362 }
263 363
264 pub fn commit_changes(&mut self) -> Vec<VfsChange> { 364 pub fn commit_changes(&mut self) -> Vec<VfsChange> {
@@ -267,19 +367,31 @@ impl Vfs {
267 367
268 /// Sutdown the VFS and terminate the background watching thread. 368 /// Sutdown the VFS and terminate the background watching thread.
269 pub fn shutdown(self) -> thread::Result<()> { 369 pub fn shutdown(self) -> thread::Result<()> {
270 let _ = self.worker.shutdown(); 370 self.worker.shutdown()
271 self.worker_handle.shutdown()
272 } 371 }
273 372
274 fn add_file(&mut self, root: VfsRoot, path: RelativePathBuf, text: Arc<String>) -> VfsFile { 373 fn add_file(
275 let data = VfsFileData { root, path, text }; 374 &mut self,
375 root: VfsRoot,
376 path: RelativePathBuf,
377 text: Arc<String>,
378 is_overlayed: bool,
379 ) -> VfsFile {
380 let data = VfsFileData {
381 root,
382 path,
383 text,
384 is_overlayed,
385 };
276 let file = self.files.alloc(data); 386 let file = self.files.alloc(data);
277 self.root2files.get_mut(&root).unwrap().insert(file); 387 self.root2files.get_mut(&root).unwrap().insert(file);
278 file 388 file
279 } 389 }
280 390
281 fn change_file(&mut self, file: VfsFile, new_text: Arc<String>) { 391 fn change_file(&mut self, file: VfsFile, new_text: Arc<String>, is_overlayed: bool) {
282 self.files[file].text = new_text; 392 let mut file_data = &mut self.files[file];
393 file_data.text = new_text;
394 file_data.is_overlayed = is_overlayed;
283 } 395 }
284 396
285 fn remove_file(&mut self, file: VfsFile) { 397 fn remove_file(&mut self, file: VfsFile) {
@@ -292,15 +404,16 @@ impl Vfs {
292 } 404 }
293 405
294 fn find_root(&self, path: &Path) -> Option<(VfsRoot, RelativePathBuf, Option<VfsFile>)> { 406 fn find_root(&self, path: &Path) -> Option<(VfsRoot, RelativePathBuf, Option<VfsFile>)> {
295 let (root, path) = self 407 let (root, path) = self.roots.find(&path)?;
296 .roots 408 let file = self.find_file(root, &path);
297 .iter() 409 Some((root, path, file))
298 .find_map(|(root, data)| data.can_contain(path).map(|it| (root, it)))?; 410 }
299 let file = self.root2files[&root] 411
412 fn find_file(&self, root: VfsRoot, path: &RelativePath) -> Option<VfsFile> {
413 self.root2files[&root]
300 .iter() 414 .iter()
301 .map(|&it| it) 415 .map(|&it| it)
302 .find(|&file| self.files[file].path == path); 416 .find(|&file| self.files[file].path == path)
303 Some((root, path, file))
304 } 417 }
305} 418}
306 419
diff --git a/crates/ra_vfs/tests/vfs.rs b/crates/ra_vfs/tests/vfs.rs
index f56fc4603..545e1dbdd 100644
--- a/crates/ra_vfs/tests/vfs.rs
+++ b/crates/ra_vfs/tests/vfs.rs
@@ -1,24 +1,47 @@
1use std::{ 1use std::{collections::HashSet, fs, time::Duration};
2 fs,
3 collections::HashSet,
4};
5 2
3// use flexi_logger::Logger;
4use crossbeam_channel::RecvTimeoutError;
5use ra_vfs::{Vfs, VfsChange};
6use tempfile::tempdir; 6use tempfile::tempdir;
7 7
8use ra_vfs::{Vfs, VfsChange}; 8fn process_tasks(vfs: &mut Vfs, num_tasks: u32) {
9 for _ in 0..num_tasks {
10 let task = vfs
11 .task_receiver()
12 .recv_timeout(Duration::from_secs(3))
13 .unwrap();
14 log::debug!("{:?}", task);
15 vfs.handle_task(task);
16 }
17}
18
19macro_rules! assert_match {
20 ($x:expr, $pat:pat) => {
21 assert_match!($x, $pat, ())
22 };
23 ($x:expr, $pat:pat, $assert:expr) => {
24 match $x {
25 $pat => $assert,
26 x => assert!(false, "Expected {}, got {:?}", stringify!($pat), x),
27 };
28 };
29}
9 30
10#[test] 31#[test]
11fn test_vfs_works() -> std::io::Result<()> { 32fn test_vfs_works() -> std::io::Result<()> {
33 // Logger::with_str("vfs=debug,ra_vfs=debug").start().unwrap();
34
12 let files = [ 35 let files = [
13 ("a/foo.rs", "hello"), 36 ("a/foo.rs", "hello"),
14 ("a/bar.rs", "world"), 37 ("a/bar.rs", "world"),
15 ("a/b/baz.rs", "nested hello"), 38 ("a/b/baz.rs", "nested hello"),
16 ]; 39 ];
17 40
18 let dir = tempdir()?; 41 let dir = tempdir().unwrap();
19 for (path, text) in files.iter() { 42 for (path, text) in files.iter() {
20 let file_path = dir.path().join(path); 43 let file_path = dir.path().join(path);
21 fs::create_dir_all(file_path.parent().unwrap())?; 44 fs::create_dir_all(file_path.parent().unwrap()).unwrap();
22 fs::write(file_path, text)? 45 fs::write(file_path, text)?
23 } 46 }
24 47
@@ -26,10 +49,7 @@ fn test_vfs_works() -> std::io::Result<()> {
26 let b_root = dir.path().join("a/b"); 49 let b_root = dir.path().join("a/b");
27 50
28 let (mut vfs, _) = Vfs::new(vec![a_root, b_root]); 51 let (mut vfs, _) = Vfs::new(vec![a_root, b_root]);
29 for _ in 0..2 { 52 process_tasks(&mut vfs, 2);
30 let task = vfs.task_receiver().recv().unwrap();
31 vfs.handle_task(task);
32 }
33 { 53 {
34 let files = vfs 54 let files = vfs
35 .commit_changes() 55 .commit_changes()
@@ -58,44 +78,114 @@ fn test_vfs_works() -> std::io::Result<()> {
58 assert_eq!(files, expected_files); 78 assert_eq!(files, expected_files);
59 } 79 }
60 80
61 vfs.add_file_overlay(&dir.path().join("a/b/baz.rs"), "quux".to_string()); 81 fs::write(&dir.path().join("a/b/baz.rs"), "quux").unwrap();
62 let change = vfs.commit_changes().pop().unwrap(); 82 process_tasks(&mut vfs, 1);
63 match change { 83 assert_match!(
64 VfsChange::ChangeFile { text, .. } => assert_eq!(&*text, "quux"), 84 vfs.commit_changes().as_slice(),
65 _ => panic!("unexpected change"), 85 [VfsChange::ChangeFile { text, .. }],
66 } 86 assert_eq!(text.as_str(), "quux")
87 );
67 88
68 vfs.change_file_overlay(&dir.path().join("a/b/baz.rs"), "m".to_string()); 89 vfs.add_file_overlay(&dir.path().join("a/b/baz.rs"), "m".to_string());
69 let change = vfs.commit_changes().pop().unwrap(); 90 assert_match!(
70 match change { 91 vfs.commit_changes().as_slice(),
71 VfsChange::ChangeFile { text, .. } => assert_eq!(&*text, "m"), 92 [VfsChange::ChangeFile { text, .. }],
72 _ => panic!("unexpected change"), 93 assert_eq!(text.as_str(), "m")
73 } 94 );
74 95
96 // changing file on disk while overlayed doesn't generate a VfsChange
97 fs::write(&dir.path().join("a/b/baz.rs"), "corge").unwrap();
98 process_tasks(&mut vfs, 1);
99 assert_match!(vfs.commit_changes().as_slice(), []);
100
101 // removing overlay restores data on disk
75 vfs.remove_file_overlay(&dir.path().join("a/b/baz.rs")); 102 vfs.remove_file_overlay(&dir.path().join("a/b/baz.rs"));
76 let change = vfs.commit_changes().pop().unwrap(); 103 assert_match!(
77 match change { 104 vfs.commit_changes().as_slice(),
78 VfsChange::ChangeFile { text, .. } => assert_eq!(&*text, "nested hello"), 105 [VfsChange::ChangeFile { text, .. }],
79 _ => panic!("unexpected change"), 106 assert_eq!(text.as_str(), "corge")
80 } 107 );
81 108
82 vfs.add_file_overlay(&dir.path().join("a/b/spam.rs"), "spam".to_string()); 109 vfs.add_file_overlay(&dir.path().join("a/b/spam.rs"), "spam".to_string());
83 let change = vfs.commit_changes().pop().unwrap(); 110 assert_match!(
84 match change { 111 vfs.commit_changes().as_slice(),
85 VfsChange::AddFile { text, path, .. } => { 112 [VfsChange::AddFile { text, path, .. }],
86 assert_eq!(&*text, "spam"); 113 {
114 assert_eq!(text.as_str(), "spam");
87 assert_eq!(path, "spam.rs"); 115 assert_eq!(path, "spam.rs");
88 } 116 }
89 _ => panic!("unexpected change"), 117 );
90 }
91 118
92 vfs.remove_file_overlay(&dir.path().join("a/b/spam.rs")); 119 vfs.remove_file_overlay(&dir.path().join("a/b/spam.rs"));
93 let change = vfs.commit_changes().pop().unwrap(); 120 assert_match!(
94 match change { 121 vfs.commit_changes().as_slice(),
95 VfsChange::RemoveFile { .. } => (), 122 [VfsChange::RemoveFile { path, .. }],
96 _ => panic!("unexpected change"), 123 assert_eq!(path, "spam.rs")
124 );
125
126 fs::create_dir_all(dir.path().join("a/sub1/sub2")).unwrap();
127 fs::write(dir.path().join("a/sub1/sub2/new.rs"), "new hello").unwrap();
128 process_tasks(&mut vfs, 1);
129 assert_match!(
130 vfs.commit_changes().as_slice(),
131 [VfsChange::AddFile { text, path, .. }],
132 {
133 assert_eq!(text.as_str(), "new hello");
134 assert_eq!(path, "sub1/sub2/new.rs");
135 }
136 );
137
138 fs::rename(
139 &dir.path().join("a/sub1/sub2/new.rs"),
140 &dir.path().join("a/sub1/sub2/new1.rs"),
141 )
142 .unwrap();
143 process_tasks(&mut vfs, 2);
144 assert_match!(
145 vfs.commit_changes().as_slice(),
146 [VfsChange::RemoveFile {
147 path: removed_path, ..
148 }, VfsChange::AddFile {
149 text,
150 path: added_path,
151 ..
152 }],
153 {
154 assert_eq!(removed_path, "sub1/sub2/new.rs");
155 assert_eq!(added_path, "sub1/sub2/new1.rs");
156 assert_eq!(text.as_str(), "new hello");
157 }
158 );
159
160 fs::remove_file(&dir.path().join("a/sub1/sub2/new1.rs")).unwrap();
161 process_tasks(&mut vfs, 1);
162 assert_match!(
163 vfs.commit_changes().as_slice(),
164 [VfsChange::RemoveFile { path, .. }],
165 assert_eq!(path, "sub1/sub2/new1.rs")
166 );
167
168 {
169 vfs.add_file_overlay(&dir.path().join("a/memfile.rs"), "memfile".to_string());
170 assert_match!(
171 vfs.commit_changes().as_slice(),
172 [VfsChange::AddFile { text, .. }],
173 assert_eq!(text.as_str(), "memfile")
174 );
175 fs::write(&dir.path().join("a/memfile.rs"), "ignore me").unwrap();
176 process_tasks(&mut vfs, 1);
177 assert_match!(vfs.commit_changes().as_slice(), []);
97 } 178 }
98 179
180 // should be ignored
181 fs::create_dir_all(dir.path().join("a/target")).unwrap();
182 fs::write(&dir.path().join("a/target/new.rs"), "ignore me").unwrap();
183
184 assert_match!(
185 vfs.task_receiver().recv_timeout(Duration::from_millis(300)), // slightly more than watcher debounce delay
186 Err(RecvTimeoutError::Timeout)
187 );
188
99 vfs.shutdown().unwrap(); 189 vfs.shutdown().unwrap();
100 Ok(()) 190 Ok(())
101} 191}