mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
Merge #665
665: Pr 556 r=matklad a=matklad Rebased #556 Thanks @vemoo, now I can change branches without reopening VS Code! Co-authored-by: Bernardo <berublan@gmail.com>
This commit is contained in:
commit
c869ee219a
6 changed files with 907 additions and 217 deletions
268
Cargo.lock
generated
268
Cargo.lock
generated
|
@ -85,6 +85,11 @@ name = "bit-vec"
|
|||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
|
@ -109,6 +114,15 @@ name = "byteorder"
|
|||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.7.1"
|
||||
|
@ -335,6 +349,16 @@ name = "fake-simd"
|
|||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flexi_logger"
|
||||
version = "0.10.5"
|
||||
|
@ -351,6 +375,24 @@ name = "fnv"
|
|||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fsevent"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fst"
|
||||
version = "0.3.3"
|
||||
|
@ -374,6 +416,11 @@ name = "fuchsia-zircon-sys"
|
|||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "gen_lsp_server"
|
||||
version = "0.1.0"
|
||||
|
@ -436,6 +483,28 @@ name = "indexmap"
|
|||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "insta"
|
||||
version = "0.5.2"
|
||||
|
@ -455,6 +524,15 @@ dependencies = [
|
|||
"serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.0"
|
||||
|
@ -473,11 +551,25 @@ name = "join_to_string"
|
|||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.48"
|
||||
|
@ -511,7 +603,7 @@ version = "0.55.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -553,17 +645,84 @@ name = "memoffset"
|
|||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-extras"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.2.3"
|
||||
name = "notify"
|
||||
version = "4.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -726,7 +885,7 @@ dependencies = [
|
|||
"ra_syntax 0.1.0",
|
||||
"relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"salsa 0.10.0-alpha4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"salsa 0.10.0-alpha5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"test_utils 0.1.0",
|
||||
]
|
||||
|
||||
|
@ -849,7 +1008,11 @@ name = "ra_vfs"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flexi_logger 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"notify 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ra_arena 0.1.0",
|
||||
"relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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"
|
|||
|
||||
[[package]]
|
||||
name = "salsa"
|
||||
version = "0.10.0-alpha4"
|
||||
version = "0.10.0-alpha5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1106,13 +1269,13 @@ dependencies = [
|
|||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"salsa-macros 0.10.0-alpha4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"salsa-macros 0.10.0-alpha5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "salsa-macros"
|
||||
version = "0.10.0-alpha4"
|
||||
version = "0.10.0-alpha5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1198,6 +1361,11 @@ dependencies = [
|
|||
"fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "slug"
|
||||
version = "0.1.4"
|
||||
|
@ -1381,6 +1549,42 @@ dependencies = [
|
|||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-executor"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-io"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-reactor"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tools"
|
||||
version = "0.1.0"
|
||||
|
@ -1555,6 +1759,11 @@ dependencies = [
|
|||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
|
@ -1564,6 +1773,11 @@ dependencies = [
|
|||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
@ -1582,6 +1796,15 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.2"
|
||||
|
@ -1602,10 +1825,12 @@ dependencies = [
|
|||
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
|
||||
"checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a"
|
||||
"checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
|
||||
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
|
||||
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
|
||||
"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
|
||||
"checksum cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "585784cac9b05c93a53b17a0b24a5cdd1dfdda5256f030e089b549d2390cc720"
|
||||
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
|
@ -1633,11 +1858,15 @@ dependencies = [
|
|||
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
|
||||
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
|
||||
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646"
|
||||
"checksum flexi_logger 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bbd731387787f54fa333fa426e173fe42ea3d1123636b2b27ad802025fc5d182"
|
||||
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05"
|
||||
"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874"
|
||||
"checksum fst 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "db72126ca7dff566cdbbdd54af44668c544897d9d3862b198141f176f1238bdf"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
|
||||
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
|
@ -1645,11 +1874,16 @@ dependencies = [
|
|||
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
|
||||
"checksum im 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0627d417829c1d763d602687634869f254fc79f7e22dea6c824dab993db857e4"
|
||||
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
|
||||
"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
|
||||
"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
|
||||
"checksum insta 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff57d9cbc4664b54a972c321155c7703794bc0f5c9944f29c36f40d10d626f3"
|
||||
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
|
||||
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
|
||||
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||
"checksum join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc7a5290e8c2606ce2be49f456d50f69173cb96d1541e4f66e34ac8b331a98f"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
|
||||
"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e"
|
||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||
|
@ -1660,8 +1894,13 @@ dependencies = [
|
|||
"checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8"
|
||||
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
|
||||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||
"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
|
||||
"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d"
|
||||
"checksum notify 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c968cf37cf949114b00d51b0b23536d1c3a4a3963767cf4c969c65a6af78dc7d"
|
||||
"checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238"
|
||||
|
@ -1704,8 +1943,8 @@ dependencies = [
|
|||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum rusty-fork 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9591f190d2852720b679c21f66ad929f9f1d7bb09d1193c26167586029d8489c"
|
||||
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||
"checksum salsa 0.10.0-alpha4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f442595eae948da8fbb2aa1e13940d9d2d70031753a27a5d1434f91b706ff12"
|
||||
"checksum salsa-macros 0.10.0-alpha4 (registry+https://github.com/rust-lang/crates.io-index)" = "2e6c1a1bee4eb44881438e80c1a26db1c3b957b6cc51765615d429019babdec2"
|
||||
"checksum salsa 0.10.0-alpha5 (registry+https://github.com/rust-lang/crates.io-index)" = "8b5e2535d707dc5ced81106d3b71d806cfeef8a6e8a567472fde7ffd56b770dd"
|
||||
"checksum salsa-macros 0.10.0-alpha5 (registry+https://github.com/rust-lang/crates.io-index)" = "e7c5da4c649f6d4fc1864fcd9a379b1f7c6d570b278559c84a6e15981c949cc6"
|
||||
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
|
@ -1715,6 +1954,7 @@ dependencies = [
|
|||
"checksum serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "4b90a9fbe1211e57d3e1c15670f1cb00802988fb23a1a4aad7a2b63544f1920e"
|
||||
"checksum serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0887a8e097a69559b56aa2526bf7aff7c3048cf627dff781f0b56a6001534593"
|
||||
"checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373"
|
||||
"checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15"
|
||||
"checksum smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9af1035bc5d742ab6b7ab16713e41cc2ffe78cb474f6f43cd696b2d16052007e"
|
||||
|
@ -1733,6 +1973,9 @@ dependencies = [
|
|||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0"
|
||||
"checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f"
|
||||
"checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f"
|
||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77"
|
||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||
|
@ -1757,8 +2000,11 @@ dependencies = [
|
|||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum wait-timeout 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b9f3bf741a801531993db6478b95682117471f76916f5e690dd8d45395b09349"
|
||||
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
"checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e"
|
||||
|
|
|
@ -10,9 +10,13 @@ relative-path = "0.4.0"
|
|||
rustc-hash = "1.0"
|
||||
crossbeam-channel = "0.3.5"
|
||||
log = "0.4.6"
|
||||
notify = "4.0.7"
|
||||
drop_bomb = "0.1.0"
|
||||
parking_lot = "0.7.0"
|
||||
|
||||
thread_worker = { path = "../thread_worker" }
|
||||
ra_arena = { path = "../ra_arena" }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
flexi_logger = "0.10.0"
|
||||
|
|
|
@ -1,55 +1,109 @@
|
|||
use std::{
|
||||
fmt,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::{fs, sync::Arc, thread};
|
||||
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
use thread_worker::{WorkerHandle};
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use relative_path::RelativePathBuf;
|
||||
use thread_worker::WorkerHandle;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::{VfsRoot, has_rs_extension};
|
||||
mod watcher;
|
||||
use watcher::Watcher;
|
||||
|
||||
pub(crate) struct Task {
|
||||
pub(crate) root: VfsRoot,
|
||||
pub(crate) path: PathBuf,
|
||||
pub(crate) filter: Box<Fn(&DirEntry) -> bool + Send>,
|
||||
use crate::{RootFilter, Roots, VfsRoot};
|
||||
|
||||
pub(crate) enum Task {
|
||||
AddRoot {
|
||||
root: VfsRoot,
|
||||
filter: Arc<RootFilter>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct TaskResult {
|
||||
pub(crate) root: VfsRoot,
|
||||
pub(crate) files: Vec<(RelativePathBuf, String)>,
|
||||
#[derive(Debug)]
|
||||
pub enum TaskResult {
|
||||
BulkLoadRoot {
|
||||
root: VfsRoot,
|
||||
files: Vec<(RelativePathBuf, String)>,
|
||||
},
|
||||
AddSingleFile {
|
||||
root: VfsRoot,
|
||||
path: RelativePathBuf,
|
||||
text: String,
|
||||
},
|
||||
ChangeSingleFile {
|
||||
root: VfsRoot,
|
||||
path: RelativePathBuf,
|
||||
text: String,
|
||||
},
|
||||
RemoveSingleFile {
|
||||
root: VfsRoot,
|
||||
path: RelativePathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
impl fmt::Debug for TaskResult {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("TaskResult { ... }")
|
||||
pub(crate) struct Worker {
|
||||
worker: thread_worker::Worker<Task, TaskResult>,
|
||||
worker_handle: WorkerHandle,
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
pub(crate) fn start(roots: Arc<Roots>) -> Worker {
|
||||
let (worker, worker_handle) =
|
||||
thread_worker::spawn("vfs", 128, move |input_receiver, output_sender| {
|
||||
let mut watcher = match Watcher::start(roots, output_sender.clone()) {
|
||||
Ok(w) => Some(w),
|
||||
Err(e) => {
|
||||
log::error!("could not start watcher: {}", e);
|
||||
None
|
||||
}
|
||||
};
|
||||
let res = input_receiver
|
||||
.into_iter()
|
||||
.filter_map(|t| handle_task(t, &mut watcher))
|
||||
.try_for_each(|it| output_sender.send(it));
|
||||
if let Some(watcher) = watcher {
|
||||
let _ = watcher.shutdown();
|
||||
}
|
||||
res.unwrap()
|
||||
});
|
||||
Worker {
|
||||
worker,
|
||||
worker_handle,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn sender(&self) -> &Sender<Task> {
|
||||
&self.worker.inp
|
||||
}
|
||||
|
||||
pub(crate) fn receiver(&self) -> &Receiver<TaskResult> {
|
||||
&self.worker.out
|
||||
}
|
||||
|
||||
pub(crate) fn shutdown(self) -> thread::Result<()> {
|
||||
let _ = self.worker.shutdown();
|
||||
self.worker_handle.shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type Worker = thread_worker::Worker<Task, TaskResult>;
|
||||
|
||||
pub(crate) fn start() -> (Worker, WorkerHandle) {
|
||||
thread_worker::spawn("vfs", 128, |input_receiver, output_sender| {
|
||||
input_receiver
|
||||
.into_iter()
|
||||
.map(handle_task)
|
||||
.try_for_each(|it| output_sender.send(it))
|
||||
.unwrap()
|
||||
})
|
||||
fn handle_task(task: Task, watcher: &mut Option<Watcher>) -> Option<TaskResult> {
|
||||
match task {
|
||||
Task::AddRoot { root, filter } => {
|
||||
if let Some(watcher) = watcher {
|
||||
watcher.watch_root(&filter)
|
||||
}
|
||||
log::debug!("loading {} ...", filter.root.as_path().display());
|
||||
let files = load_root(filter.as_ref());
|
||||
log::debug!("... loaded {}", filter.root.as_path().display());
|
||||
Some(TaskResult::BulkLoadRoot { root, files })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_task(task: Task) -> TaskResult {
|
||||
let Task { root, path, filter } = task;
|
||||
log::debug!("loading {} ...", path.as_path().display());
|
||||
let files = load_root(path.as_path(), &*filter);
|
||||
log::debug!("... loaded {}", path.as_path().display());
|
||||
TaskResult { root, files }
|
||||
}
|
||||
|
||||
fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePathBuf, String)> {
|
||||
fn load_root(filter: &RootFilter) -> Vec<(RelativePathBuf, String)> {
|
||||
let mut res = Vec::new();
|
||||
for entry in WalkDir::new(root).into_iter().filter_entry(filter) {
|
||||
for entry in WalkDir::new(&filter.root)
|
||||
.into_iter()
|
||||
.filter_entry(filter.entry_filter())
|
||||
{
|
||||
let entry = match entry {
|
||||
Ok(entry) => entry,
|
||||
Err(e) => {
|
||||
|
@ -61,9 +115,6 @@ fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePa
|
|||
continue;
|
||||
}
|
||||
let path = entry.path();
|
||||
if !has_rs_extension(path) {
|
||||
continue;
|
||||
}
|
||||
let text = match fs::read_to_string(path) {
|
||||
Ok(text) => text,
|
||||
Err(e) => {
|
||||
|
@ -71,7 +122,7 @@ fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePa
|
|||
continue;
|
||||
}
|
||||
};
|
||||
let path = RelativePathBuf::from_path(path.strip_prefix(root).unwrap()).unwrap();
|
||||
let path = RelativePathBuf::from_path(path.strip_prefix(&filter.root).unwrap()).unwrap();
|
||||
res.push((path.to_owned(), text))
|
||||
}
|
||||
res
|
||||
|
|
200
crates/ra_vfs/src/io/watcher.rs
Normal file
200
crates/ra_vfs/src/io/watcher.rs
Normal file
|
@ -0,0 +1,200 @@
|
|||
use crate::{io, RootFilter, Roots, VfsRoot};
|
||||
use crossbeam_channel::Sender;
|
||||
use drop_bomb::DropBomb;
|
||||
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher};
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
sync::{mpsc, Arc},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ChangeKind {
|
||||
Create,
|
||||
Write,
|
||||
Remove,
|
||||
}
|
||||
|
||||
const WATCHER_DELAY: Duration = Duration::from_millis(250);
|
||||
|
||||
pub(crate) struct Watcher {
|
||||
thread: thread::JoinHandle<()>,
|
||||
bomb: DropBomb,
|
||||
watcher: Arc<Mutex<Option<RecommendedWatcher>>>,
|
||||
}
|
||||
|
||||
impl Watcher {
|
||||
pub(crate) fn start(
|
||||
roots: Arc<Roots>,
|
||||
output_sender: Sender<io::TaskResult>,
|
||||
) -> Result<Watcher, Box<std::error::Error>> {
|
||||
let (input_sender, input_receiver) = mpsc::channel();
|
||||
let watcher = Arc::new(Mutex::new(Some(notify::watcher(
|
||||
input_sender,
|
||||
WATCHER_DELAY,
|
||||
)?)));
|
||||
let sender = output_sender.clone();
|
||||
let watcher_clone = watcher.clone();
|
||||
let thread = thread::spawn(move || {
|
||||
let worker = WatcherWorker {
|
||||
roots,
|
||||
watcher: watcher_clone,
|
||||
sender,
|
||||
};
|
||||
input_receiver
|
||||
.into_iter()
|
||||
// forward relevant events only
|
||||
.try_for_each(|change| worker.handle_debounced_event(change))
|
||||
.unwrap()
|
||||
});
|
||||
Ok(Watcher {
|
||||
thread,
|
||||
watcher,
|
||||
bomb: DropBomb::new(format!("Watcher was not shutdown")),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn watch_root(&mut self, filter: &RootFilter) {
|
||||
for res in WalkDir::new(&filter.root)
|
||||
.into_iter()
|
||||
.filter_entry(filter.entry_filter())
|
||||
{
|
||||
match res {
|
||||
Ok(entry) => {
|
||||
if entry.file_type().is_dir() {
|
||||
watch_one(self.watcher.as_ref(), entry.path());
|
||||
}
|
||||
}
|
||||
Err(e) => log::warn!("watcher error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shutdown(mut self) -> thread::Result<()> {
|
||||
self.bomb.defuse();
|
||||
drop(self.watcher.lock().take());
|
||||
let res = self.thread.join();
|
||||
match &res {
|
||||
Ok(()) => log::info!("... Watcher terminated with ok"),
|
||||
Err(_) => log::error!("... Watcher terminated with err"),
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
struct WatcherWorker {
|
||||
watcher: Arc<Mutex<Option<RecommendedWatcher>>>,
|
||||
roots: Arc<Roots>,
|
||||
sender: Sender<io::TaskResult>,
|
||||
}
|
||||
|
||||
impl WatcherWorker {
|
||||
fn handle_debounced_event(&self, ev: DebouncedEvent) -> Result<(), Box<std::error::Error>> {
|
||||
match ev {
|
||||
DebouncedEvent::NoticeWrite(_)
|
||||
| DebouncedEvent::NoticeRemove(_)
|
||||
| DebouncedEvent::Chmod(_) => {
|
||||
// ignore
|
||||
}
|
||||
DebouncedEvent::Rescan => {
|
||||
// TODO rescan all roots
|
||||
}
|
||||
DebouncedEvent::Create(path) => {
|
||||
self.handle_change(path, ChangeKind::Create);
|
||||
}
|
||||
DebouncedEvent::Write(path) => {
|
||||
self.handle_change(path, ChangeKind::Write);
|
||||
}
|
||||
DebouncedEvent::Remove(path) => {
|
||||
self.handle_change(path, ChangeKind::Remove);
|
||||
}
|
||||
DebouncedEvent::Rename(src, dst) => {
|
||||
self.handle_change(src, ChangeKind::Remove);
|
||||
self.handle_change(dst, ChangeKind::Create);
|
||||
}
|
||||
DebouncedEvent::Error(err, path) => {
|
||||
// TODO should we reload the file contents?
|
||||
log::warn!("watcher error \"{}\", {:?}", err, path);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_change(&self, path: PathBuf, kind: ChangeKind) {
|
||||
if let Err(e) = self.try_handle_change(path, kind) {
|
||||
log::warn!("watcher error: {}", e)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_handle_change(
|
||||
&self,
|
||||
path: PathBuf,
|
||||
kind: ChangeKind,
|
||||
) -> Result<(), Box<std::error::Error>> {
|
||||
let (root, rel_path) = match self.roots.find(&path) {
|
||||
Some(x) => x,
|
||||
None => return Ok(()),
|
||||
};
|
||||
match kind {
|
||||
ChangeKind::Create => {
|
||||
if path.is_dir() {
|
||||
self.watch_recursive(&path, root);
|
||||
} else {
|
||||
let text = fs::read_to_string(&path)?;
|
||||
self.sender.send(io::TaskResult::AddSingleFile {
|
||||
root,
|
||||
path: rel_path,
|
||||
text,
|
||||
})?
|
||||
}
|
||||
}
|
||||
ChangeKind::Write => {
|
||||
let text = fs::read_to_string(&path)?;
|
||||
self.sender.send(io::TaskResult::ChangeSingleFile {
|
||||
root,
|
||||
path: rel_path,
|
||||
text,
|
||||
})?
|
||||
}
|
||||
ChangeKind::Remove => self.sender.send(io::TaskResult::RemoveSingleFile {
|
||||
root,
|
||||
path: rel_path,
|
||||
})?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn watch_recursive(&self, dir: &Path, root: VfsRoot) {
|
||||
let filter = &self.roots[root];
|
||||
for res in WalkDir::new(dir)
|
||||
.into_iter()
|
||||
.filter_entry(filter.entry_filter())
|
||||
{
|
||||
match res {
|
||||
Ok(entry) => {
|
||||
if entry.file_type().is_dir() {
|
||||
watch_one(self.watcher.as_ref(), entry.path());
|
||||
} else {
|
||||
// emit only for files otherwise we will cause watch_recursive to be called again with a dir that we are already watching
|
||||
// emit as create because we haven't seen it yet
|
||||
self.handle_change(entry.path().to_path_buf(), ChangeKind::Create);
|
||||
}
|
||||
}
|
||||
Err(e) => log::warn!("watcher error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn watch_one(watcher: &Mutex<Option<RecommendedWatcher>>, dir: &Path) {
|
||||
if let Some(watcher) = watcher.lock().as_mut() {
|
||||
match watcher.watch(dir, RecursiveMode::NonRecursive) {
|
||||
Ok(()) => log::debug!("watching \"{}\"", dir.display()),
|
||||
Err(e) => log::warn!("could not watch \"{}\": {}", dir.display(), e),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,52 +16,77 @@
|
|||
mod io;
|
||||
|
||||
use std::{
|
||||
fmt,
|
||||
mem,
|
||||
thread,
|
||||
cmp::Reverse,
|
||||
fmt, fs, mem,
|
||||
ops::{Deref, DerefMut},
|
||||
path::{Path, PathBuf},
|
||||
ffi::OsStr,
|
||||
sync::Arc,
|
||||
fs,
|
||||
thread,
|
||||
};
|
||||
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use relative_path::RelativePathBuf;
|
||||
use crossbeam_channel::Receiver;
|
||||
use ra_arena::{impl_arena_id, Arena, RawId};
|
||||
use relative_path::{Component, RelativePath, RelativePathBuf};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use walkdir::DirEntry;
|
||||
use thread_worker::WorkerHandle;
|
||||
use ra_arena::{Arena, RawId, impl_arena_id};
|
||||
|
||||
pub use crate::io::TaskResult as VfsTask;
|
||||
use io::{TaskResult, Worker};
|
||||
|
||||
/// `RootFilter` is a predicate that checks if a file can belong to a root. If
|
||||
/// several filters match a file (nested dirs), the most nested one wins.
|
||||
struct RootFilter {
|
||||
pub(crate) struct RootFilter {
|
||||
root: PathBuf,
|
||||
file_filter: fn(&Path) -> bool,
|
||||
filter: fn(&Path, &RelativePath) -> bool,
|
||||
excluded_dirs: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl RootFilter {
|
||||
fn new(root: PathBuf) -> RootFilter {
|
||||
fn new(root: PathBuf, excluded_dirs: Vec<PathBuf>) -> RootFilter {
|
||||
RootFilter {
|
||||
root,
|
||||
file_filter: has_rs_extension,
|
||||
filter: default_filter,
|
||||
excluded_dirs,
|
||||
}
|
||||
}
|
||||
/// Check if this root can contain `path`. NB: even if this returns
|
||||
/// true, the `path` might actually be conained in some nested root.
|
||||
fn can_contain(&self, path: &Path) -> Option<RelativePathBuf> {
|
||||
if !(self.file_filter)(path) {
|
||||
pub(crate) fn can_contain(&self, path: &Path) -> Option<RelativePathBuf> {
|
||||
let rel_path = path.strip_prefix(&self.root).ok()?;
|
||||
let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
|
||||
if !(self.filter)(path, rel_path.as_relative_path()) {
|
||||
return None;
|
||||
}
|
||||
let path = path.strip_prefix(&self.root).ok()?;
|
||||
RelativePathBuf::from_path(path).ok()
|
||||
Some(rel_path)
|
||||
}
|
||||
|
||||
pub(crate) fn entry_filter<'a>(&'a self) -> impl FnMut(&DirEntry) -> bool + 'a {
|
||||
move |entry: &DirEntry| {
|
||||
if entry.file_type().is_dir() && self.excluded_dirs.iter().any(|it| it == entry.path())
|
||||
{
|
||||
// do not walk nested roots
|
||||
false
|
||||
} else {
|
||||
self.can_contain(entry.path()).is_some()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_rs_extension(p: &Path) -> bool {
|
||||
p.extension() == Some(OsStr::new("rs"))
|
||||
pub(crate) fn default_filter(path: &Path, rel_path: &RelativePath) -> bool {
|
||||
if path.is_dir() {
|
||||
for (i, c) in rel_path.components().enumerate() {
|
||||
if let Component::Normal(c) = c {
|
||||
// TODO hardcoded for now
|
||||
if (i == 0 && c == "target") || c == ".git" || c == "node_modules" {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
rel_path.extension() == Some("rs")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
|
@ -75,16 +100,58 @@ impl_arena_id!(VfsFile);
|
|||
struct VfsFileData {
|
||||
root: VfsRoot,
|
||||
path: RelativePathBuf,
|
||||
is_overlayed: bool,
|
||||
text: Arc<String>,
|
||||
}
|
||||
|
||||
pub(crate) struct Roots {
|
||||
roots: Arena<VfsRoot, Arc<RootFilter>>,
|
||||
}
|
||||
|
||||
impl Roots {
|
||||
pub(crate) fn new(mut paths: Vec<PathBuf>) -> Roots {
|
||||
let mut roots = Arena::default();
|
||||
// A hack to make nesting work.
|
||||
paths.sort_by_key(|it| Reverse(it.as_os_str().len()));
|
||||
for (i, path) in paths.iter().enumerate() {
|
||||
let nested_roots = paths[..i]
|
||||
.iter()
|
||||
.filter(|it| it.starts_with(path))
|
||||
.map(|it| it.clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let root_filter = Arc::new(RootFilter::new(path.clone(), nested_roots));
|
||||
|
||||
roots.alloc(root_filter.clone());
|
||||
}
|
||||
Roots { roots }
|
||||
}
|
||||
pub(crate) fn find(&self, path: &Path) -> Option<(VfsRoot, RelativePathBuf)> {
|
||||
self.roots
|
||||
.iter()
|
||||
.find_map(|(root, data)| data.can_contain(path).map(|it| (root, it)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Roots {
|
||||
type Target = Arena<VfsRoot, Arc<RootFilter>>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.roots
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Roots {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.roots
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Vfs {
|
||||
roots: Arena<VfsRoot, RootFilter>,
|
||||
roots: Arc<Roots>,
|
||||
files: Arena<VfsFile, VfsFileData>,
|
||||
root2files: FxHashMap<VfsRoot, FxHashSet<VfsFile>>,
|
||||
pending_changes: Vec<VfsChange>,
|
||||
worker: io::Worker,
|
||||
worker_handle: WorkerHandle,
|
||||
worker: Worker,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Vfs {
|
||||
|
@ -94,44 +161,30 @@ impl fmt::Debug for Vfs {
|
|||
}
|
||||
|
||||
impl Vfs {
|
||||
pub fn new(mut roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) {
|
||||
let (worker, worker_handle) = io::start();
|
||||
pub fn new(roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) {
|
||||
let roots = Arc::new(Roots::new(roots));
|
||||
let worker = io::Worker::start(roots.clone());
|
||||
let mut root2files = FxHashMap::default();
|
||||
|
||||
let mut res = Vfs {
|
||||
roots: Arena::default(),
|
||||
for (root, filter) in roots.iter() {
|
||||
root2files.insert(root, Default::default());
|
||||
worker
|
||||
.sender()
|
||||
.send(io::Task::AddRoot {
|
||||
root,
|
||||
filter: filter.clone(),
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
let res = Vfs {
|
||||
roots,
|
||||
files: Arena::default(),
|
||||
root2files: FxHashMap::default(),
|
||||
root2files,
|
||||
worker,
|
||||
worker_handle,
|
||||
pending_changes: Vec::new(),
|
||||
};
|
||||
|
||||
// A hack to make nesting work.
|
||||
roots.sort_by_key(|it| Reverse(it.as_os_str().len()));
|
||||
for (i, path) in roots.iter().enumerate() {
|
||||
let root = res.roots.alloc(RootFilter::new(path.clone()));
|
||||
res.root2files.insert(root, Default::default());
|
||||
let nested = roots[..i]
|
||||
.iter()
|
||||
.filter(|it| it.starts_with(path))
|
||||
.map(|it| it.clone())
|
||||
.collect::<Vec<_>>();
|
||||
let filter = move |entry: &DirEntry| {
|
||||
if entry.file_type().is_file() {
|
||||
has_rs_extension(entry.path())
|
||||
} else {
|
||||
nested.iter().all(|it| it != entry.path())
|
||||
}
|
||||
};
|
||||
let task = io::Task {
|
||||
root,
|
||||
path: path.clone(),
|
||||
filter: Box::new(filter),
|
||||
};
|
||||
res.worker.inp.send(task).unwrap();
|
||||
}
|
||||
let roots = res.roots.iter().map(|(id, _)| id).collect();
|
||||
(res, roots)
|
||||
let vfs_roots = res.roots.iter().map(|(id, _)| id).collect();
|
||||
(res, vfs_roots)
|
||||
}
|
||||
|
||||
pub fn root2path(&self, root: VfsRoot) -> PathBuf {
|
||||
|
@ -165,7 +218,7 @@ impl Vfs {
|
|||
} else {
|
||||
let text = fs::read_to_string(path).unwrap_or_default();
|
||||
let text = Arc::new(text);
|
||||
let file = self.add_file(root, rel_path.clone(), Arc::clone(&text));
|
||||
let file = self.add_file(root, rel_path.clone(), Arc::clone(&text), false);
|
||||
let change = VfsChange::AddFile {
|
||||
file,
|
||||
text,
|
||||
|
@ -180,85 +233,130 @@ impl Vfs {
|
|||
}
|
||||
|
||||
pub fn task_receiver(&self) -> &Receiver<io::TaskResult> {
|
||||
&self.worker.out
|
||||
self.worker.receiver()
|
||||
}
|
||||
|
||||
pub fn handle_task(&mut self, task: io::TaskResult) {
|
||||
let mut files = Vec::new();
|
||||
// While we were scanning the root in the backgound, a file might have
|
||||
// been open in the editor, so we need to account for that.
|
||||
let exising = self.root2files[&task.root]
|
||||
.iter()
|
||||
.map(|&file| (self.files[file].path.clone(), file))
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
for (path, text) in task.files {
|
||||
if let Some(&file) = exising.get(&path) {
|
||||
let text = Arc::clone(&self.files[file].text);
|
||||
files.push((file, path, text));
|
||||
continue;
|
||||
}
|
||||
let text = Arc::new(text);
|
||||
let file = self.add_file(task.root, path.clone(), Arc::clone(&text));
|
||||
files.push((file, path, text));
|
||||
}
|
||||
match task {
|
||||
TaskResult::BulkLoadRoot { root, files } => {
|
||||
let mut cur_files = Vec::new();
|
||||
// While we were scanning the root in the backgound, a file might have
|
||||
// been open in the editor, so we need to account for that.
|
||||
let exising = self.root2files[&root]
|
||||
.iter()
|
||||
.map(|&file| (self.files[file].path.clone(), file))
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
for (path, text) in files {
|
||||
if let Some(&file) = exising.get(&path) {
|
||||
let text = Arc::clone(&self.files[file].text);
|
||||
cur_files.push((file, path, text));
|
||||
continue;
|
||||
}
|
||||
let text = Arc::new(text);
|
||||
let file = self.add_file(root, path.clone(), Arc::clone(&text), false);
|
||||
cur_files.push((file, path, text));
|
||||
}
|
||||
|
||||
let change = VfsChange::AddRoot {
|
||||
root: task.root,
|
||||
files,
|
||||
};
|
||||
self.pending_changes.push(change);
|
||||
let change = VfsChange::AddRoot {
|
||||
root,
|
||||
files: cur_files,
|
||||
};
|
||||
self.pending_changes.push(change);
|
||||
}
|
||||
TaskResult::AddSingleFile { root, path, text } => {
|
||||
self.do_add_file(root, path, text, false);
|
||||
}
|
||||
TaskResult::ChangeSingleFile { root, path, text } => {
|
||||
if let Some(file) = self.find_file(root, &path) {
|
||||
self.do_change_file(file, text, false);
|
||||
} else {
|
||||
self.do_add_file(root, path, text, false);
|
||||
}
|
||||
}
|
||||
TaskResult::RemoveSingleFile { root, path } => {
|
||||
if let Some(file) = self.find_file(root, &path) {
|
||||
self.do_remove_file(root, path, file, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn do_add_file(
|
||||
&mut self,
|
||||
root: VfsRoot,
|
||||
path: RelativePathBuf,
|
||||
text: String,
|
||||
is_overlay: bool,
|
||||
) -> Option<VfsFile> {
|
||||
let text = Arc::new(text);
|
||||
let file = self.add_file(root, path.clone(), text.clone(), is_overlay);
|
||||
self.pending_changes.push(VfsChange::AddFile {
|
||||
file,
|
||||
root,
|
||||
path,
|
||||
text,
|
||||
});
|
||||
Some(file)
|
||||
}
|
||||
|
||||
fn do_change_file(&mut self, file: VfsFile, text: String, is_overlay: bool) {
|
||||
if !is_overlay && self.files[file].is_overlayed {
|
||||
return;
|
||||
}
|
||||
let text = Arc::new(text);
|
||||
self.change_file(file, text.clone(), is_overlay);
|
||||
self.pending_changes
|
||||
.push(VfsChange::ChangeFile { file, text });
|
||||
}
|
||||
|
||||
fn do_remove_file(
|
||||
&mut self,
|
||||
root: VfsRoot,
|
||||
path: RelativePathBuf,
|
||||
file: VfsFile,
|
||||
is_overlay: bool,
|
||||
) {
|
||||
if !is_overlay && self.files[file].is_overlayed {
|
||||
return;
|
||||
}
|
||||
self.remove_file(file);
|
||||
self.pending_changes
|
||||
.push(VfsChange::RemoveFile { root, path, file });
|
||||
}
|
||||
|
||||
pub fn add_file_overlay(&mut self, path: &Path, text: String) -> Option<VfsFile> {
|
||||
let mut res = None;
|
||||
if let Some((root, path, file)) = self.find_root(path) {
|
||||
let text = Arc::new(text);
|
||||
let change = if let Some(file) = file {
|
||||
res = Some(file);
|
||||
self.change_file(file, Arc::clone(&text));
|
||||
VfsChange::ChangeFile { file, text }
|
||||
if let Some((root, rel_path, file)) = self.find_root(path) {
|
||||
if let Some(file) = file {
|
||||
self.do_change_file(file, text, true);
|
||||
Some(file)
|
||||
} else {
|
||||
let file = self.add_file(root, path.clone(), Arc::clone(&text));
|
||||
res = Some(file);
|
||||
VfsChange::AddFile {
|
||||
file,
|
||||
text,
|
||||
root,
|
||||
path,
|
||||
}
|
||||
};
|
||||
self.pending_changes.push(change);
|
||||
self.do_add_file(root, rel_path, text, true)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
pub fn change_file_overlay(&mut self, path: &Path, new_text: String) {
|
||||
if let Some((_root, _path, file)) = self.find_root(path) {
|
||||
let file = file.expect("can't change a file which wasn't added");
|
||||
let text = Arc::new(new_text);
|
||||
self.change_file(file, Arc::clone(&text));
|
||||
let change = VfsChange::ChangeFile { file, text };
|
||||
self.pending_changes.push(change);
|
||||
self.do_change_file(file, new_text, true);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_file_overlay(&mut self, path: &Path) -> Option<VfsFile> {
|
||||
let mut res = None;
|
||||
if let Some((root, path, file)) = self.find_root(path) {
|
||||
let file = file.expect("can't remove a file which wasn't added");
|
||||
res = Some(file);
|
||||
let full_path = path.to_path(&self.roots[root].root);
|
||||
let change = if let Ok(text) = fs::read_to_string(&full_path) {
|
||||
let text = Arc::new(text);
|
||||
self.change_file(file, Arc::clone(&text));
|
||||
VfsChange::ChangeFile { file, text }
|
||||
if let Ok(text) = fs::read_to_string(&full_path) {
|
||||
self.do_change_file(file, text, true);
|
||||
} else {
|
||||
self.remove_file(file);
|
||||
VfsChange::RemoveFile { root, file, path }
|
||||
};
|
||||
self.pending_changes.push(change);
|
||||
self.do_remove_file(root, path, file, true);
|
||||
}
|
||||
Some(file)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
pub fn commit_changes(&mut self) -> Vec<VfsChange> {
|
||||
|
@ -267,19 +365,31 @@ impl Vfs {
|
|||
|
||||
/// Sutdown the VFS and terminate the background watching thread.
|
||||
pub fn shutdown(self) -> thread::Result<()> {
|
||||
let _ = self.worker.shutdown();
|
||||
self.worker_handle.shutdown()
|
||||
self.worker.shutdown()
|
||||
}
|
||||
|
||||
fn add_file(&mut self, root: VfsRoot, path: RelativePathBuf, text: Arc<String>) -> VfsFile {
|
||||
let data = VfsFileData { root, path, text };
|
||||
fn add_file(
|
||||
&mut self,
|
||||
root: VfsRoot,
|
||||
path: RelativePathBuf,
|
||||
text: Arc<String>,
|
||||
is_overlayed: bool,
|
||||
) -> VfsFile {
|
||||
let data = VfsFileData {
|
||||
root,
|
||||
path,
|
||||
text,
|
||||
is_overlayed,
|
||||
};
|
||||
let file = self.files.alloc(data);
|
||||
self.root2files.get_mut(&root).unwrap().insert(file);
|
||||
file
|
||||
}
|
||||
|
||||
fn change_file(&mut self, file: VfsFile, new_text: Arc<String>) {
|
||||
self.files[file].text = new_text;
|
||||
fn change_file(&mut self, file: VfsFile, new_text: Arc<String>, is_overlayed: bool) {
|
||||
let mut file_data = &mut self.files[file];
|
||||
file_data.text = new_text;
|
||||
file_data.is_overlayed = is_overlayed;
|
||||
}
|
||||
|
||||
fn remove_file(&mut self, file: VfsFile) {
|
||||
|
@ -292,15 +402,16 @@ impl Vfs {
|
|||
}
|
||||
|
||||
fn find_root(&self, path: &Path) -> Option<(VfsRoot, RelativePathBuf, Option<VfsFile>)> {
|
||||
let (root, path) = self
|
||||
.roots
|
||||
.iter()
|
||||
.find_map(|(root, data)| data.can_contain(path).map(|it| (root, it)))?;
|
||||
let file = self.root2files[&root]
|
||||
let (root, path) = self.roots.find(&path)?;
|
||||
let file = self.find_file(root, &path);
|
||||
Some((root, path, file))
|
||||
}
|
||||
|
||||
fn find_file(&self, root: VfsRoot, path: &RelativePath) -> Option<VfsFile> {
|
||||
self.root2files[&root]
|
||||
.iter()
|
||||
.map(|&it| it)
|
||||
.find(|&file| self.files[file].path == path);
|
||||
Some((root, path, file))
|
||||
.find(|&file| self.files[file].path == path)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,47 @@
|
|||
use std::{
|
||||
fs,
|
||||
collections::HashSet,
|
||||
};
|
||||
use std::{collections::HashSet, fs, time::Duration};
|
||||
|
||||
// use flexi_logger::Logger;
|
||||
use crossbeam_channel::RecvTimeoutError;
|
||||
use ra_vfs::{Vfs, VfsChange};
|
||||
use tempfile::tempdir;
|
||||
|
||||
use ra_vfs::{Vfs, VfsChange};
|
||||
fn process_tasks(vfs: &mut Vfs, num_tasks: u32) {
|
||||
for _ in 0..num_tasks {
|
||||
let task = vfs
|
||||
.task_receiver()
|
||||
.recv_timeout(Duration::from_secs(3))
|
||||
.unwrap();
|
||||
log::debug!("{:?}", task);
|
||||
vfs.handle_task(task);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! assert_match {
|
||||
($x:expr, $pat:pat) => {
|
||||
assert_match!($x, $pat, ())
|
||||
};
|
||||
($x:expr, $pat:pat, $assert:expr) => {
|
||||
match $x {
|
||||
$pat => $assert,
|
||||
x => assert!(false, "Expected {}, got {:?}", stringify!($pat), x),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vfs_works() -> std::io::Result<()> {
|
||||
// Logger::with_str("vfs=debug,ra_vfs=debug").start().unwrap();
|
||||
|
||||
let files = [
|
||||
("a/foo.rs", "hello"),
|
||||
("a/bar.rs", "world"),
|
||||
("a/b/baz.rs", "nested hello"),
|
||||
];
|
||||
|
||||
let dir = tempdir()?;
|
||||
let dir = tempdir().unwrap();
|
||||
for (path, text) in files.iter() {
|
||||
let file_path = dir.path().join(path);
|
||||
fs::create_dir_all(file_path.parent().unwrap())?;
|
||||
fs::create_dir_all(file_path.parent().unwrap()).unwrap();
|
||||
fs::write(file_path, text)?
|
||||
}
|
||||
|
||||
|
@ -26,10 +49,7 @@ fn test_vfs_works() -> std::io::Result<()> {
|
|||
let b_root = dir.path().join("a/b");
|
||||
|
||||
let (mut vfs, _) = Vfs::new(vec![a_root, b_root]);
|
||||
for _ in 0..2 {
|
||||
let task = vfs.task_receiver().recv().unwrap();
|
||||
vfs.handle_task(task);
|
||||
}
|
||||
process_tasks(&mut vfs, 2);
|
||||
{
|
||||
let files = vfs
|
||||
.commit_changes()
|
||||
|
@ -58,43 +78,101 @@ fn test_vfs_works() -> std::io::Result<()> {
|
|||
assert_eq!(files, expected_files);
|
||||
}
|
||||
|
||||
vfs.add_file_overlay(&dir.path().join("a/b/baz.rs"), "quux".to_string());
|
||||
let change = vfs.commit_changes().pop().unwrap();
|
||||
match change {
|
||||
VfsChange::ChangeFile { text, .. } => assert_eq!(&*text, "quux"),
|
||||
_ => panic!("unexpected change"),
|
||||
}
|
||||
fs::write(&dir.path().join("a/b/baz.rs"), "quux").unwrap();
|
||||
process_tasks(&mut vfs, 1);
|
||||
assert_match!(
|
||||
vfs.commit_changes().as_slice(),
|
||||
[VfsChange::ChangeFile { text, .. }],
|
||||
assert_eq!(text.as_str(), "quux")
|
||||
);
|
||||
|
||||
vfs.change_file_overlay(&dir.path().join("a/b/baz.rs"), "m".to_string());
|
||||
let change = vfs.commit_changes().pop().unwrap();
|
||||
match change {
|
||||
VfsChange::ChangeFile { text, .. } => assert_eq!(&*text, "m"),
|
||||
_ => panic!("unexpected change"),
|
||||
}
|
||||
vfs.add_file_overlay(&dir.path().join("a/b/baz.rs"), "m".to_string());
|
||||
assert_match!(
|
||||
vfs.commit_changes().as_slice(),
|
||||
[VfsChange::ChangeFile { text, .. }],
|
||||
assert_eq!(text.as_str(), "m")
|
||||
);
|
||||
|
||||
// changing file on disk while overlayed doesn't generate a VfsChange
|
||||
fs::write(&dir.path().join("a/b/baz.rs"), "corge").unwrap();
|
||||
process_tasks(&mut vfs, 1);
|
||||
assert_match!(vfs.commit_changes().as_slice(), []);
|
||||
|
||||
// removing overlay restores data on disk
|
||||
vfs.remove_file_overlay(&dir.path().join("a/b/baz.rs"));
|
||||
let change = vfs.commit_changes().pop().unwrap();
|
||||
match change {
|
||||
VfsChange::ChangeFile { text, .. } => assert_eq!(&*text, "nested hello"),
|
||||
_ => panic!("unexpected change"),
|
||||
}
|
||||
assert_match!(
|
||||
vfs.commit_changes().as_slice(),
|
||||
[VfsChange::ChangeFile { text, .. }],
|
||||
assert_eq!(text.as_str(), "corge")
|
||||
);
|
||||
|
||||
vfs.add_file_overlay(&dir.path().join("a/b/spam.rs"), "spam".to_string());
|
||||
let change = vfs.commit_changes().pop().unwrap();
|
||||
match change {
|
||||
VfsChange::AddFile { text, path, .. } => {
|
||||
assert_eq!(&*text, "spam");
|
||||
assert_match!(
|
||||
vfs.commit_changes().as_slice(),
|
||||
[VfsChange::AddFile { text, path, .. }],
|
||||
{
|
||||
assert_eq!(text.as_str(), "spam");
|
||||
assert_eq!(path, "spam.rs");
|
||||
}
|
||||
_ => panic!("unexpected change"),
|
||||
}
|
||||
);
|
||||
|
||||
vfs.remove_file_overlay(&dir.path().join("a/b/spam.rs"));
|
||||
let change = vfs.commit_changes().pop().unwrap();
|
||||
match change {
|
||||
VfsChange::RemoveFile { .. } => (),
|
||||
_ => panic!("unexpected change"),
|
||||
}
|
||||
assert_match!(
|
||||
vfs.commit_changes().as_slice(),
|
||||
[VfsChange::RemoveFile { path, .. }],
|
||||
assert_eq!(path, "spam.rs")
|
||||
);
|
||||
|
||||
fs::create_dir_all(dir.path().join("a/sub1/sub2")).unwrap();
|
||||
fs::write(dir.path().join("a/sub1/sub2/new.rs"), "new hello").unwrap();
|
||||
process_tasks(&mut vfs, 1);
|
||||
assert_match!(
|
||||
vfs.commit_changes().as_slice(),
|
||||
[VfsChange::AddFile { text, path, .. }],
|
||||
{
|
||||
assert_eq!(text.as_str(), "new hello");
|
||||
assert_eq!(path, "sub1/sub2/new.rs");
|
||||
}
|
||||
);
|
||||
|
||||
fs::rename(
|
||||
&dir.path().join("a/sub1/sub2/new.rs"),
|
||||
&dir.path().join("a/sub1/sub2/new1.rs"),
|
||||
)
|
||||
.unwrap();
|
||||
process_tasks(&mut vfs, 2);
|
||||
assert_match!(
|
||||
vfs.commit_changes().as_slice(),
|
||||
[VfsChange::RemoveFile {
|
||||
path: removed_path, ..
|
||||
}, VfsChange::AddFile {
|
||||
text,
|
||||
path: added_path,
|
||||
..
|
||||
}],
|
||||
{
|
||||
assert_eq!(removed_path, "sub1/sub2/new.rs");
|
||||
assert_eq!(added_path, "sub1/sub2/new1.rs");
|
||||
assert_eq!(text.as_str(), "new hello");
|
||||
}
|
||||
);
|
||||
|
||||
fs::remove_file(&dir.path().join("a/sub1/sub2/new1.rs")).unwrap();
|
||||
process_tasks(&mut vfs, 1);
|
||||
assert_match!(
|
||||
vfs.commit_changes().as_slice(),
|
||||
[VfsChange::RemoveFile { path, .. }],
|
||||
assert_eq!(path, "sub1/sub2/new1.rs")
|
||||
);
|
||||
|
||||
// should be ignored
|
||||
fs::create_dir_all(dir.path().join("a/target")).unwrap();
|
||||
fs::write(&dir.path().join("a/target/new.rs"), "ignore me").unwrap();
|
||||
|
||||
assert_match!(
|
||||
vfs.task_receiver().recv_timeout(Duration::from_millis(300)), // slightly more than watcher debounce delay
|
||||
Err(RecvTimeoutError::Timeout)
|
||||
);
|
||||
|
||||
vfs.shutdown().unwrap();
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue