aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml4
-rw-r--r--ARCHITECTURE.md133
-rw-r--r--CONTRIBUTING.md64
-rw-r--r--Cargo.lock296
-rw-r--r--README.md91
-rw-r--r--appveyor.yml2
-rw-r--r--crates/ra_analysis/Cargo.toml3
-rw-r--r--crates/ra_analysis/src/db.rs117
-rw-r--r--crates/ra_analysis/src/db/imp.rs153
-rw-r--r--crates/ra_analysis/src/db/mod.rs85
-rw-r--r--crates/ra_analysis/src/descriptors.rs68
-rw-r--r--crates/ra_analysis/src/imp.rs169
-rw-r--r--crates/ra_analysis/src/lib.rs21
-rw-r--r--crates/ra_analysis/src/module_map.rs165
-rw-r--r--crates/ra_analysis/src/queries.rs39
-rw-r--r--crates/ra_analysis/src/roots.rs72
-rw-r--r--crates/ra_analysis/src/symbol_index.rs11
-rw-r--r--crates/ra_analysis/tests/tests.rs102
-rw-r--r--crates/ra_cli/Cargo.toml1
-rw-r--r--crates/ra_editor/Cargo.toml1
-rw-r--r--crates/ra_editor/src/code_actions.rs4
-rw-r--r--crates/ra_editor/src/completion.rs2
-rw-r--r--crates/ra_editor/src/edit.rs2
-rw-r--r--crates/ra_editor/src/folding_ranges.rs177
-rw-r--r--crates/ra_editor/src/lib.rs2
-rw-r--r--crates/ra_editor/src/line_index.rs4
-rw-r--r--crates/ra_editor/src/scope/fn_scope.rs4
-rw-r--r--crates/ra_editor/src/symbols.rs4
-rw-r--r--crates/ra_editor/src/test_utils.rs4
-rw-r--r--crates/ra_editor/src/typing.rs4
-rw-r--r--crates/ra_lsp_server/Cargo.toml1
-rw-r--r--crates/ra_lsp_server/src/caps.rs5
-rw-r--r--crates/ra_lsp_server/src/conv.rs6
-rw-r--r--crates/ra_lsp_server/src/lib.rs6
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs42
-rw-r--r--crates/ra_lsp_server/src/main_loop/mod.rs7
-rw-r--r--crates/ra_lsp_server/src/project_model.rs2
-rw-r--r--crates/ra_lsp_server/src/req.rs1
-rw-r--r--crates/ra_lsp_server/src/server_world.rs3
-rw-r--r--crates/ra_lsp_server/src/thread_watcher.rs2
-rw-r--r--crates/ra_lsp_server/src/vfs.rs2
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs2
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/support.rs2
-rw-r--r--crates/ra_syntax/Cargo.toml1
-rw-r--r--crates/ra_syntax/src/algo/mod.rs2
-rw-r--r--crates/ra_syntax/src/algo/visit.rs2
-rw-r--r--crates/ra_syntax/src/algo/walk.rs2
-rw-r--r--crates/ra_syntax/src/ast/generated.rs26
-rw-r--r--crates/ra_syntax/src/ast/generated.rs.tera2
-rw-r--r--crates/ra_syntax/src/ast/mod.rs30
-rw-r--r--crates/ra_syntax/src/grammar.ron3
-rw-r--r--crates/ra_syntax/src/grammar/expressions/atom.rs2
-rw-r--r--crates/ra_syntax/src/grammar/mod.rs2
-rw-r--r--crates/ra_syntax/src/lexer/comments.rs4
-rw-r--r--crates/ra_syntax/src/lexer/mod.rs2
-rw-r--r--crates/ra_syntax/src/lexer/numbers.rs6
-rw-r--r--crates/ra_syntax/src/lexer/ptr.rs2
-rw-r--r--crates/ra_syntax/src/lexer/strings.rs4
-rw-r--r--crates/ra_syntax/src/lib.rs6
-rw-r--r--crates/ra_syntax/src/parser_api.rs2
-rw-r--r--crates/ra_syntax/src/parser_impl/event.rs2
-rw-r--r--crates/ra_syntax/src/parser_impl/input.rs2
-rw-r--r--crates/ra_syntax/src/parser_impl/mod.rs4
-rw-r--r--crates/ra_syntax/src/reparsing.rs16
-rw-r--r--crates/ra_syntax/src/syntax_kinds/mod.rs2
-rw-r--r--crates/ra_syntax/src/text_utils.rs2
-rw-r--r--crates/ra_syntax/src/token_set.rs4
-rw-r--r--crates/ra_syntax/src/utils.rs2
-rw-r--r--crates/ra_syntax/src/yellow/builder.rs2
-rw-r--r--crates/ra_syntax/src/yellow/mod.rs14
-rw-r--r--crates/ra_syntax/src/yellow/syntax_text.rs2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0035_crate_path_in_call.rs3
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0035_crate_path_in_call.txt41
-rw-r--r--crates/salsa/Cargo.toml8
-rw-r--r--crates/salsa/src/lib.rs293
-rw-r--r--crates/salsa/tests/integration.rs170
-rw-r--r--crates/test_utils/Cargo.toml1
-rw-r--r--crates/test_utils/src/lib.rs38
-rw-r--r--crates/tools/Cargo.toml1
-rw-r--r--editors/code/src/extension.ts4
80 files changed, 1225 insertions, 1369 deletions
diff --git a/.travis.yml b/.travis.yml
index acf1af028..8d420f618 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,9 @@
1cache: cargo
2
1matrix: 3matrix:
2 include: 4 include:
3 - language: rust 5 - language: rust
4 rust: stable 6 rust: beta
5 script: 7 script:
6 - cargo gen-kinds --verify 8 - cargo gen-kinds --verify
7 - cargo gen-tests --verify 9 - cargo gen-tests --verify
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
new file mode 100644
index 000000000..b497cc5d7
--- /dev/null
+++ b/ARCHITECTURE.md
@@ -0,0 +1,133 @@
1# Architecture
2
3This document describes high-level architecture of rust-analyzer.
4If you want to familiarize yourself with the code base, you are just
5in the right place!
6
7
8## Code generation
9
10Some of the components of this repository are generated through automatic
11processes. These are outlined below:
12
13- `gen-kinds`: The kinds of tokens are reused in several places, so a generator
14 is used. We use tera templates to generate the files listed below, based on
15 the grammar described in [grammar.ron]:
16 - [ast/generated.rs][ast generated] in `ra_syntax` based on
17 [ast/generated.tera.rs][ast source]
18 - [syntax_kinds/generated.rs][syntax_kinds generated] in `ra_syntax` based on
19 [syntax_kinds/generated.tera.rs][syntax_kinds source]
20
21[tera]: https://tera.netlify.com/
22[grammar.ron]: ./crates/ra_syntax/src/grammar.ron
23[ast generated]: ./crates/ra_syntax/src/ast/generated.rs
24[ast source]: ./crates/ra_syntax/src/ast/generated.rs.tera
25[syntax_kinds generated]: ./crates/ra_syntax/src/syntax_kinds/generated.rs
26[syntax_kinds source]: ./crates/ra_syntax/src/syntax_kinds/generated.rs.tera
27
28
29## Code Walk-Through
30
31### `crates/ra_syntax`
32
33Rust syntax tree structure and parser. See
34[RFC](https://github.com/rust-lang/rfcs/pull/2256) for some design
35notes.
36
37- [rowan](https://github.com/rust-analyzer/rowan) library is used for constructing syntax trees.
38- `grammar` module is the actual parser. It is a hand-written recursive descent parsers, which
39 produces a sequence of events like "start node X", "finish not Y". It works similarly to [kotlin parser](https://github.com/JetBrains/kotlin/blob/4d951de616b20feca92f3e9cc9679b2de9e65195/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java),
40 which is a good source for inspiration for dealing with syntax errors and incomplete input. Original [libsyntax parser](https://github.com/rust-lang/rust/blob/6b99adeb11313197f409b4f7c4083c2ceca8a4fe/src/libsyntax/parse/parser.rs)
41 is what we use for the definition of the Rust language.
42- `parser_api/parser_impl` bridges the tree-agnostic parser from `grammar` with `rowan` trees.
43 This is the thing that turns a flat list of events into a tree (see `EventProcessor`)
44- `ast` a type safe API on top of the raw `rowan` tree.
45- `grammar.ron` RON description of the grammar, which is used to
46 generate `syntax_kinds` and `ast` modules, using `cargo gen-kinds` command.
47- `algo`: generic tree algorithms, including `walk` for O(1) stack
48 space tree traversal (this is cool) and `visit` for type-driven
49 visiting the nodes (this is double plus cool, if you understand how
50 `Visitor` works, you understand rust-analyzer).
51
52Test for ra_syntax are mostly data-driven: `tests/data/parser` contains a bunch of `.rs`
53(test vectors) and `.txt` files with corresponding syntax trees. During testing, we check
54`.rs` against `.txt`. If the `.txt` file is missing, it is created (this is how you update
55tests). Additionally, running `cargo gen-tests` will walk the grammar module and collect
56all `//test test_name` comments into files inside `tests/data` directory.
57
58See [#93](https://github.com/rust-analyzer/rust-analyzer/pull/93) for an example PR which
59fixes a bug in the grammar.
60
61
62### `crates/ra_editor`
63
64All IDE features which can be implemented if you only have access to a
65single file. `ra_editor` could be used to enhance editing of Rust code
66without the need to fiddle with build-systems, file
67synchronization and such.
68
69In a sense, `ra_editor` is just a bunch of pure functions which take a
70syntax tree as an input.
71
72The tests for `ra_editor` are `#[cfg(test)] mod tests` unit-tests spread
73throughout its modules.
74
75### `crates/salsa`
76
77An implementation of red-green incremental compilation algorithm from
78rust compiler. It makes all rust-analyzer features on-demand. To be replaced
79with `salsa-rs/salsa` soon.
80
81
82### `crates/ra_analysis`
83
84A stateful library for analyzing many Rust files as they change.
85`AnalysisHost` is a mutable entity (clojure's atom) which holds
86current state, incorporates changes and handles out `Analysis` --- an
87immutable consistent snapshot of world state at a point in time, which
88actually powers analysis.
89
90
91### `crates/ra_lsp_server`
92
93An LSP implementation which uses `ra_analysis` for managing state and
94`ra_editor` for actually doing useful stuff.
95
96See [#79](https://github.com/rust-analyzer/rust-analyzer/pull/79/) as an
97example of PR which adds a new feature to `ra_editor` and exposes it
98to `ra_lsp_server`.
99
100
101### `crates/cli`
102
103A CLI interface to rust-analyzer.
104
105### `crate/tools`
106
107Custom Cargo tasks used to develop rust-analyzer:
108
109- `cargo gen-kinds` -- generate `ast` and `syntax_kinds`
110- `cargo gen-tests` -- collect inline tests from grammar
111- `cargo install-code` -- build and install VS Code extension and server
112
113### `editors/code`
114
115VS Code plugin
116
117
118## Common workflows
119
120To try out VS Code extensions, run `cargo install-code`. This installs both the
121`ra_lsp_server` binary and VS Code extension. To install only the binary, `use
122cargo install --path crates/ra_lsp_server --force`
123
124To see logs from the language server, set `RUST_LOG=info` env variable. To see
125all communication between the server and the client, use
126`RUST_LOG=gen_lsp_server=debug` (will print quite a bit of stuff).
127
128To run tests, just `cargo test`.
129
130To work on VS Code extension, launch code inside `editors/code` and use `F5` to
131launch/debug. To automatically apply formatter and linter suggestions, use `npm
132run fix`.
133
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c952078cf..a2efc7afa 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,58 +1,18 @@
1The project is in its early stages: contributions are welcome and would be 1The project is in its early stages: contributions are welcome and would be
2**very** helpful, but the project is not _yet_ optimized for contribution. 2**very** helpful, but the project is not _yet_ optimized for contribution.
3Moreover, it is doubly experimental, so there's no guarantee that any work here 3Moreover, it is doubly experimental, so there's no guarantee that any work here
4would reach production. That said, here are some areas where contributions would 4would reach production.
5be **especially** welcome:
6 5
7- Designing internal data structures: RFC only outlines the constraints, it's an 6To get an idea of how rust-analyzer works, take a look at the [ARCHITECTURE.md](./ARCHITECTURE.md)
8 open question how to satisfy them in the optimal way. See `ARCHITECTURE.md` 7document.
9 for current design questions.
10 8
11- Porting libsyntax parser to rust-analyzer: currently rust-analyzer parses only 9Useful labels on the issue tracker:
12 a tiny subset of Rust. This should be fixed by porting parsing functions from 10 * [E-mentor](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-mentor)
13 libsyntax one by one. Take a look at the [libsyntax parser] for "what to port" 11 issues have links to the code in question and tests,
14 and at the [Kotlin parser] for "how to port". 12 * [E-easy](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy),
13 [E-medium](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-medium),
14 [E-hard](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-hard),
15 labels are *estimates* for how hard would be to write a fix.
15 16
16- Writing validators: by design, rust-analyzer is very lax about the input. For 17There's no formal PR check list: everything that passes CI (we use [bors](https://bors.tech/)) is valid,
17 example, the lexer happily accepts unclosed strings. The idea is that there 18but it's a good idea to write nice commit messages, test code thoroughly, maintain consistent style, etc.
18 should be a higher level visitor, which walks the syntax tree after parsing
19 and produces all the warnings. Alas, there's no such visitor yet :( Would you
20 like to write one? :)
21
22- Creating tests: it would be tremendously helpful to read each of libsyntax and
23 rust-analyzer parser functions and crate a small separate test cases to cover
24 each and every edge case.
25
26- Building stuff with rust-analyzer: it would be really cool to compile
27 rust-analyzer to WASM and add _client side_ syntax validation to rust
28 playground!
29
30Do take a look at the issue tracker.
31
32If you don't know where to start, or have _any_ questions or suggestions, don't
33hesitate to chat at [Gitter]!
34
35# Code generation
36
37Some of the components of this repository are generated through automatic
38processes. These are outlined below:
39
40- `gen-kinds`: The kinds of tokens are reused in several places, so a generator
41 is used. This process uses [tera] to generate, using data in [grammar.ron],
42 the files:
43 - [ast/generated.rs][ast generated] in `ra_syntax` based on
44 [ast/generated.tera.rs][ast source]
45 - [syntax_kinds/generated.rs][syntax_kinds generated] in `ra_syntax` based on
46 [syntax_kinds/generated.tera.rs][syntax_kinds source]
47
48[libsyntax parser]:
49 https://github.com/rust-lang/rust/blob/6b99adeb11313197f409b4f7c4083c2ceca8a4fe/src/libsyntax/parse/parser.rs
50[kotlin parser]:
51 https://github.com/JetBrains/kotlin/blob/4d951de616b20feca92f3e9cc9679b2de9e65195/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java
52[gitter]: https://gitter.im/libsyntax2/Lobby
53[tera]: https://tera.netlify.com/
54[grammar.ron]: ./crates/ra_syntax/src/grammar.ron
55[ast generated]: ./crates/ra_syntax/src/ast/generated.rs
56[ast source]: ./crates/ra_syntax/src/ast/generated.tera.rs
57[syntax_kinds generated]: ./crates/ra_syntax/src/syntax_kinds/generated.rs
58[syntax_kinds source]: ./crates/ra_syntax/src/syntax_kinds/generated.tera.rs
diff --git a/Cargo.lock b/Cargo.lock
index 62feeb539..707257a31 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -15,6 +15,11 @@ dependencies = [
15] 15]
16 16
17[[package]] 17[[package]]
18name = "arrayref"
19version = "0.3.5"
20source = "registry+https://github.com/rust-lang/crates.io-index"
21
22[[package]]
18name = "arrayvec" 23name = "arrayvec"
19version = "0.4.7" 24version = "0.4.7"
20source = "registry+https://github.com/rust-lang/crates.io-index" 25source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -68,6 +73,20 @@ version = "1.0.4"
68source = "registry+https://github.com/rust-lang/crates.io-index" 73source = "registry+https://github.com/rust-lang/crates.io-index"
69 74
70[[package]] 75[[package]]
76name = "block-buffer"
77version = "0.3.3"
78source = "registry+https://github.com/rust-lang/crates.io-index"
79dependencies = [
80 "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
81 "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
82]
83
84[[package]]
85name = "byte-tools"
86version = "0.2.0"
87source = "registry+https://github.com/rust-lang/crates.io-index"
88
89[[package]]
71name = "byteorder" 90name = "byteorder"
72version = "1.2.6" 91version = "1.2.6"
73source = "registry+https://github.com/rust-lang/crates.io-index" 92source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -79,9 +98,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
79dependencies = [ 98dependencies = [
80 "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 99 "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
81 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 100 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
82 "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 101 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
83 "serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 102 "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
84 "serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", 103 "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
85] 104]
86 105
87[[package]] 106[[package]]
@@ -188,6 +207,16 @@ version = "0.5.0"
188source = "registry+https://github.com/rust-lang/crates.io-index" 207source = "registry+https://github.com/rust-lang/crates.io-index"
189 208
190[[package]] 209[[package]]
210name = "derive-new"
211version = "0.5.5"
212source = "registry+https://github.com/rust-lang/crates.io-index"
213dependencies = [
214 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
215 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
216 "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
217]
218
219[[package]]
191name = "deunicode" 220name = "deunicode"
192version = "0.4.3" 221version = "0.4.3"
193source = "registry+https://github.com/rust-lang/crates.io-index" 222source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -198,6 +227,14 @@ version = "2.0.0"
198source = "registry+https://github.com/rust-lang/crates.io-index" 227source = "registry+https://github.com/rust-lang/crates.io-index"
199 228
200[[package]] 229[[package]]
230name = "digest"
231version = "0.7.6"
232source = "registry+https://github.com/rust-lang/crates.io-index"
233dependencies = [
234 "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
235]
236
237[[package]]
201name = "drop_bomb" 238name = "drop_bomb"
202version = "0.1.4" 239version = "0.1.4"
203source = "registry+https://github.com/rust-lang/crates.io-index" 240source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -229,13 +266,18 @@ name = "failure_derive"
229version = "0.1.2" 266version = "0.1.2"
230source = "registry+https://github.com/rust-lang/crates.io-index" 267source = "registry+https://github.com/rust-lang/crates.io-index"
231dependencies = [ 268dependencies = [
232 "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", 269 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
233 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 270 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
234 "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", 271 "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
235 "synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 272 "synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
236] 273]
237 274
238[[package]] 275[[package]]
276name = "fake-simd"
277version = "0.1.2"
278source = "registry+https://github.com/rust-lang/crates.io-index"
279
280[[package]]
239name = "flexi_logger" 281name = "flexi_logger"
240version = "0.9.2" 282version = "0.9.2"
241source = "registry+https://github.com/rust-lang/crates.io-index" 283source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -277,9 +319,17 @@ dependencies = [
277 "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 319 "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
278 "languageserver-types 0.51.0 (registry+https://github.com/rust-lang/crates.io-index)", 320 "languageserver-types 0.51.0 (registry+https://github.com/rust-lang/crates.io-index)",
279 "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", 321 "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
280 "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 322 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
281 "serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 323 "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
282 "serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", 324 "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
325]
326
327[[package]]
328name = "generic-array"
329version = "0.9.0"
330source = "registry+https://github.com/rust-lang/crates.io-index"
331dependencies = [
332 "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
283] 333]
284 334
285[[package]] 335[[package]]
@@ -312,7 +362,7 @@ dependencies = [
312 362
313[[package]] 363[[package]]
314name = "im" 364name = "im"
315version = "12.1.0" 365version = "12.2.0"
316source = "registry+https://github.com/rust-lang/crates.io-index" 366source = "registry+https://github.com/rust-lang/crates.io-index"
317dependencies = [ 367dependencies = [
318 "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 368 "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -320,6 +370,11 @@ dependencies = [
320] 370]
321 371
322[[package]] 372[[package]]
373name = "indexmap"
374version = "1.0.1"
375source = "registry+https://github.com/rust-lang/crates.io-index"
376
377[[package]]
323name = "itertools" 378name = "itertools"
324version = "0.7.8" 379version = "0.7.8"
325source = "registry+https://github.com/rust-lang/crates.io-index" 380source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -343,11 +398,11 @@ version = "0.51.0"
343source = "registry+https://github.com/rust-lang/crates.io-index" 398source = "registry+https://github.com/rust-lang/crates.io-index"
344dependencies = [ 399dependencies = [
345 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 400 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
346 "num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 401 "num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
347 "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 402 "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
348 "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 403 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
349 "serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 404 "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
350 "serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", 405 "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
351 "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 406 "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
352 "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 407 "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
353] 408]
@@ -383,6 +438,11 @@ dependencies = [
383] 438]
384 439
385[[package]] 440[[package]]
441name = "maplit"
442version = "1.0.1"
443source = "registry+https://github.com/rust-lang/crates.io-index"
444
445[[package]]
386name = "matches" 446name = "matches"
387version = "0.1.8" 447version = "0.1.8"
388source = "registry+https://github.com/rust-lang/crates.io-index" 448source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -418,13 +478,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
418 478
419[[package]] 479[[package]]
420name = "num-derive" 480name = "num-derive"
421version = "0.2.2" 481version = "0.2.3"
422source = "registry+https://github.com/rust-lang/crates.io-index" 482source = "registry+https://github.com/rust-lang/crates.io-index"
423dependencies = [ 483dependencies = [
424 "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 484 "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
425 "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", 485 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
426 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 486 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
427 "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", 487 "syn 0.15.11 (registry+https://github.com/rust-lang/crates.io-index)",
428] 488]
429 489
430[[package]] 490[[package]]
@@ -492,38 +552,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
492 552
493[[package]] 553[[package]]
494name = "pest" 554name = "pest"
495version = "1.0.6" 555version = "2.0.1"
496source = "registry+https://github.com/rust-lang/crates.io-index" 556source = "registry+https://github.com/rust-lang/crates.io-index"
557dependencies = [
558 "ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
559]
497 560
498[[package]] 561[[package]]
499name = "pest_derive" 562name = "pest_derive"
500version = "1.0.8" 563version = "2.0.1"
501source = "registry+https://github.com/rust-lang/crates.io-index" 564source = "registry+https://github.com/rust-lang/crates.io-index"
502dependencies = [ 565dependencies = [
503 "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 566 "pest 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
504 "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", 567 "pest_generator 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
505 "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
506] 568]
507 569
508[[package]] 570[[package]]
509name = "proc-macro2" 571name = "pest_generator"
510version = "0.4.19" 572version = "2.0.0"
511source = "registry+https://github.com/rust-lang/crates.io-index" 573source = "registry+https://github.com/rust-lang/crates.io-index"
512dependencies = [ 574dependencies = [
513 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 575 "pest 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
576 "pest_meta 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
577 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
578 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
579 "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
514] 580]
515 581
516[[package]] 582[[package]]
517name = "quote" 583name = "pest_meta"
518version = "0.3.15" 584version = "2.0.3"
585source = "registry+https://github.com/rust-lang/crates.io-index"
586dependencies = [
587 "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
588 "pest 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
589 "sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
590]
591
592[[package]]
593name = "proc-macro2"
594version = "0.4.20"
519source = "registry+https://github.com/rust-lang/crates.io-index" 595source = "registry+https://github.com/rust-lang/crates.io-index"
596dependencies = [
597 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
598]
520 599
521[[package]] 600[[package]]
522name = "quote" 601name = "quote"
523version = "0.6.8" 602version = "0.6.8"
524source = "registry+https://github.com/rust-lang/crates.io-index" 603source = "registry+https://github.com/rust-lang/crates.io-index"
525dependencies = [ 604dependencies = [
526 "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", 605 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
527] 606]
528 607
529[[package]] 608[[package]]
@@ -532,7 +611,7 @@ version = "0.1.0"
532dependencies = [ 611dependencies = [
533 "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 612 "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
534 "fst 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 613 "fst 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
535 "im 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 614 "im 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
536 "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", 615 "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
537 "once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 616 "once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
538 "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", 617 "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -541,7 +620,7 @@ dependencies = [
541 "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 620 "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
542 "relative-path 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 621 "relative-path 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
543 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 622 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
544 "salsa 0.1.0", 623 "salsa 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
545 "test_utils 0.1.0", 624 "test_utils 0.1.0",
546] 625]
547 626
@@ -579,7 +658,7 @@ dependencies = [
579 "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 658 "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
580 "flexi_logger 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", 659 "flexi_logger 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
581 "gen_lsp_server 0.1.0", 660 "gen_lsp_server 0.1.0",
582 "im 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 661 "im 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
583 "languageserver-types 0.51.0 (registry+https://github.com/rust-lang/crates.io-index)", 662 "languageserver-types 0.51.0 (registry+https://github.com/rust-lang/crates.io-index)",
584 "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", 663 "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
585 "ra_analysis 0.1.0", 664 "ra_analysis 0.1.0",
@@ -588,10 +667,10 @@ dependencies = [
588 "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 667 "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
589 "relative-path 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 668 "relative-path 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
590 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 669 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
591 "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 670 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
592 "serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 671 "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
593 "serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", 672 "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
594 "smol_str 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 673 "smol_str 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
595 "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 674 "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
596 "text_unit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 675 "text_unit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
597 "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 676 "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -629,13 +708,21 @@ dependencies = [
629 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 708 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
630 "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 709 "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
631 "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 710 "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
632 "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 711 "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
633 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 712 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
634] 713]
635 714
636[[package]] 715[[package]]
637name = "rand_core" 716name = "rand_core"
638version = "0.2.1" 717version = "0.2.2"
718source = "registry+https://github.com/rust-lang/crates.io-index"
719dependencies = [
720 "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
721]
722
723[[package]]
724name = "rand_core"
725version = "0.3.0"
639source = "registry+https://github.com/rust-lang/crates.io-index" 726source = "registry+https://github.com/rust-lang/crates.io-index"
640 727
641[[package]] 728[[package]]
@@ -712,7 +799,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
712dependencies = [ 799dependencies = [
713 "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", 800 "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
714 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 801 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
715 "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 802 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
716] 803]
717 804
718[[package]] 805[[package]]
@@ -721,7 +808,7 @@ version = "0.1.0"
721source = "registry+https://github.com/rust-lang/crates.io-index" 808source = "registry+https://github.com/rust-lang/crates.io-index"
722dependencies = [ 809dependencies = [
723 "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", 810 "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
724 "smol_str 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 811 "smol_str 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
725 "text_unit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 812 "text_unit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
726] 813]
727 814
@@ -758,10 +845,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
758 845
759[[package]] 846[[package]]
760name = "salsa" 847name = "salsa"
761version = "0.1.0" 848version = "0.5.0"
849source = "registry+https://github.com/rust-lang/crates.io-index"
762dependencies = [ 850dependencies = [
763 "im 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 851 "derive-new 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
852 "indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
853 "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
764 "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", 854 "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
855 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
856 "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
765] 857]
766 858
767[[package]] 859[[package]]
@@ -783,7 +875,7 @@ version = "0.9.0"
783source = "registry+https://github.com/rust-lang/crates.io-index" 875source = "registry+https://github.com/rust-lang/crates.io-index"
784dependencies = [ 876dependencies = [
785 "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 877 "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
786 "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 878 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
787] 879]
788 880
789[[package]] 881[[package]]
@@ -793,30 +885,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
793 885
794[[package]] 886[[package]]
795name = "serde" 887name = "serde"
796version = "1.0.79" 888version = "1.0.80"
797source = "registry+https://github.com/rust-lang/crates.io-index" 889source = "registry+https://github.com/rust-lang/crates.io-index"
798dependencies = [ 890dependencies = [
799 "serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 891 "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
800] 892]
801 893
802[[package]] 894[[package]]
803name = "serde_derive" 895name = "serde_derive"
804version = "1.0.79" 896version = "1.0.80"
805source = "registry+https://github.com/rust-lang/crates.io-index" 897source = "registry+https://github.com/rust-lang/crates.io-index"
806dependencies = [ 898dependencies = [
807 "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", 899 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
808 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 900 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
809 "syn 0.15.7 (registry+https://github.com/rust-lang/crates.io-index)", 901 "syn 0.15.11 (registry+https://github.com/rust-lang/crates.io-index)",
810] 902]
811 903
812[[package]] 904[[package]]
813name = "serde_json" 905name = "serde_json"
814version = "1.0.31" 906version = "1.0.32"
815source = "registry+https://github.com/rust-lang/crates.io-index" 907source = "registry+https://github.com/rust-lang/crates.io-index"
816dependencies = [ 908dependencies = [
817 "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 909 "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
818 "ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 910 "ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
819 "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 911 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
912]
913
914[[package]]
915name = "sha-1"
916version = "0.7.0"
917source = "registry+https://github.com/rust-lang/crates.io-index"
918dependencies = [
919 "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
920 "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
921 "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
922 "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
820] 923]
821 924
822[[package]] 925[[package]]
@@ -837,10 +940,10 @@ dependencies = [
837 940
838[[package]] 941[[package]]
839name = "smol_str" 942name = "smol_str"
840version = "0.1.6" 943version = "0.1.7"
841source = "registry+https://github.com/rust-lang/crates.io-index" 944source = "registry+https://github.com/rust-lang/crates.io-index"
842dependencies = [ 945dependencies = [
843 "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 946 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
844] 947]
845 948
846[[package]] 949[[package]]
@@ -860,48 +963,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
860 963
861[[package]] 964[[package]]
862name = "syn" 965name = "syn"
863version = "0.11.11"
864source = "registry+https://github.com/rust-lang/crates.io-index"
865dependencies = [
866 "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
867 "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
868 "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
869]
870
871[[package]]
872name = "syn"
873version = "0.14.9" 966version = "0.14.9"
874source = "registry+https://github.com/rust-lang/crates.io-index" 967source = "registry+https://github.com/rust-lang/crates.io-index"
875dependencies = [ 968dependencies = [
876 "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", 969 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
877 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 970 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
878 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 971 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
879] 972]
880 973
881[[package]] 974[[package]]
882name = "syn" 975name = "syn"
883version = "0.15.7" 976version = "0.15.11"
884source = "registry+https://github.com/rust-lang/crates.io-index" 977source = "registry+https://github.com/rust-lang/crates.io-index"
885dependencies = [ 978dependencies = [
886 "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", 979 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
887 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 980 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
888 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 981 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
889] 982]
890 983
891[[package]] 984[[package]]
892name = "synom"
893version = "0.11.3"
894source = "registry+https://github.com/rust-lang/crates.io-index"
895dependencies = [
896 "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
897]
898
899[[package]]
900name = "synstructure" 985name = "synstructure"
901version = "0.9.0" 986version = "0.9.0"
902source = "registry+https://github.com/rust-lang/crates.io-index" 987source = "registry+https://github.com/rust-lang/crates.io-index"
903dependencies = [ 988dependencies = [
904 "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", 989 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
905 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 990 "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
906 "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", 991 "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
907 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 992 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -918,7 +1003,7 @@ dependencies = [
918 1003
919[[package]] 1004[[package]]
920name = "tera" 1005name = "tera"
921version = "0.11.16" 1006version = "0.11.17"
922source = "registry+https://github.com/rust-lang/crates.io-index" 1007source = "registry+https://github.com/rust-lang/crates.io-index"
923dependencies = [ 1008dependencies = [
924 "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1009 "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -926,11 +1011,11 @@ dependencies = [
926 "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 1011 "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
927 "humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1012 "humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
928 "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1013 "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
929 "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 1014 "pest 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
930 "pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 1015 "pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
931 "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1016 "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
932 "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 1017 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
933 "serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", 1018 "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
934 "slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 1019 "slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
935 "unic-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 1020 "unic-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
936 "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1021 "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -960,7 +1045,7 @@ name = "text_unit"
960version = "0.1.4" 1045version = "0.1.4"
961source = "registry+https://github.com/rust-lang/crates.io-index" 1046source = "registry+https://github.com/rust-lang/crates.io-index"
962dependencies = [ 1047dependencies = [
963 "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 1048 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
964] 1049]
965 1050
966[[package]] 1051[[package]]
@@ -998,7 +1083,7 @@ dependencies = [
998 "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1083 "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
999 "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", 1084 "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
1000 "ron 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1085 "ron 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
1001 "tera 0.11.16 (registry+https://github.com/rust-lang/crates.io-index)", 1086 "tera 0.11.17 (registry+https://github.com/rust-lang/crates.io-index)",
1002 "walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)", 1087 "walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
1003] 1088]
1004 1089
@@ -1008,6 +1093,11 @@ version = "1.10.0"
1008source = "registry+https://github.com/rust-lang/crates.io-index" 1093source = "registry+https://github.com/rust-lang/crates.io-index"
1009 1094
1010[[package]] 1095[[package]]
1096name = "ucd-trie"
1097version = "0.1.1"
1098source = "registry+https://github.com/rust-lang/crates.io-index"
1099
1100[[package]]
1011name = "ucd-util" 1101name = "ucd-util"
1012version = "0.1.1" 1102version = "0.1.1"
1013source = "registry+https://github.com/rust-lang/crates.io-index" 1103source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1081,11 +1171,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1081 1171
1082[[package]] 1172[[package]]
1083name = "unicode-xid" 1173name = "unicode-xid"
1084version = "0.0.4"
1085source = "registry+https://github.com/rust-lang/crates.io-index"
1086
1087[[package]]
1088name = "unicode-xid"
1089version = "0.1.0" 1174version = "0.1.0"
1090source = "registry+https://github.com/rust-lang/crates.io-index" 1175source = "registry+https://github.com/rust-lang/crates.io-index"
1091 1176
@@ -1112,7 +1197,7 @@ name = "url_serde"
1112version = "0.2.0" 1197version = "0.2.0"
1113source = "registry+https://github.com/rust-lang/crates.io-index" 1198source = "registry+https://github.com/rust-lang/crates.io-index"
1114dependencies = [ 1199dependencies = [
1115 "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", 1200 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
1116 "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1201 "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1117] 1202]
1118 1203
@@ -1176,12 +1261,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1176[metadata] 1261[metadata]
1177"checksum aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a" 1262"checksum aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a"
1178"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 1263"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
1264"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
1179"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" 1265"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
1180"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" 1266"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
1181"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" 1267"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
1182"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" 1268"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"
1183"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" 1269"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
1184"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 1270"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
1271"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
1272"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
1185"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" 1273"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781"
1186"checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1" 1274"checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1"
1187"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" 1275"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
@@ -1195,22 +1283,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1195"checksum crossbeam-epoch 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c90f1474584f38e270b5b613e898c8c328aa4f3dea85e0a27ac2e642f009416" 1283"checksum crossbeam-epoch 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c90f1474584f38e270b5b613e898c8c328aa4f3dea85e0a27ac2e642f009416"
1196"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" 1284"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
1197"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" 1285"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
1286"checksum derive-new 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "899ec79626c14e00ccc9729b4d750bbe67fe76a8f436824c16e0233bbd9d7daa"
1198"checksum deunicode 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" 1287"checksum deunicode 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690"
1199"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 1288"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
1289"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
1200"checksum drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "69b26e475fd29098530e709294e94e661974c851aed42512793f120fed4e199f" 1290"checksum drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "69b26e475fd29098530e709294e94e661974c851aed42512793f120fed4e199f"
1201"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" 1291"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
1202"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" 1292"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02"
1203"checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9" 1293"checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9"
1204"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426" 1294"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
1295"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
1205"checksum flexi_logger 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2103a4bd3f67bf8b3e89fe0695cd13ac23c9968a2a81f2ccf2d95f1bb4e5a520" 1296"checksum flexi_logger 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2103a4bd3f67bf8b3e89fe0695cd13ac23c9968a2a81f2ccf2d95f1bb4e5a520"
1206"checksum fst 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9b0408ab57c1bf7c634b2ac6a165d14f642dc3335a43203090a7f8c78b54577b" 1297"checksum fst 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9b0408ab57c1bf7c634b2ac6a165d14f642dc3335a43203090a7f8c78b54577b"
1207"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 1298"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
1208"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 1299"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
1300"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
1209"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" 1301"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
1210"checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82" 1302"checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82"
1211"checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" 1303"checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e"
1212"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" 1304"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
1213"checksum im 12.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "90742b94a13db9b161eeab35f89bc9723634eb72bfd124f3ebb025734fdfef18" 1305"checksum im 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9c7f9bb8aee47fc16d535a705f7867a9fc83bb822e5e1043bb98e77ffeed3c"
1306"checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220"
1214"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" 1307"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
1215"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" 1308"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
1216"checksum join_to_string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7bddc885f3fd69dd4b5d747c2efe6dd2c36d795ea9938281ed50910e32c95e31" 1309"checksum join_to_string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7bddc885f3fd69dd4b5d747c2efe6dd2c36d795ea9938281ed50910e32c95e31"
@@ -1219,12 +1312,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1219"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" 1312"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
1220"checksum lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775751a3e69bde4df9b38dd00a1b5d6ac13791e4223d4a0506577f0dd27cfb7a" 1313"checksum lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775751a3e69bde4df9b38dd00a1b5d6ac13791e4223d4a0506577f0dd27cfb7a"
1221"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f" 1314"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f"
1315"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
1222"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 1316"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
1223"checksum memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4b3629fe9fdbff6daa6c33b90f7c08355c1aca05a3d01fa8063b822fcf185f3b" 1317"checksum memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4b3629fe9fdbff6daa6c33b90f7c08355c1aca05a3d01fa8063b822fcf185f3b"
1224"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" 1318"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
1225"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" 1319"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
1226"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" 1320"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
1227"checksum num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2c31b75c36a993d30c7a13d70513cb93f02acafdd5b7ba250f9b0e18615de7" 1321"checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d"
1228"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" 1322"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
1229"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" 1323"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
1230"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" 1324"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
@@ -1233,14 +1327,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1233"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" 1327"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
1234"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" 1328"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c"
1235"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" 1329"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
1236"checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" 1330"checksum pest 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c3abb0d36ede865dcc689fd3bee2ff39094eff6e57a814f4a53c3c6108088353"
1237"checksum pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3294f437119209b084c797604295f40227cffa35c57220b1e99a6ff3bf8ee4" 1331"checksum pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b76f477146419bc539a63f4ef40e902166cb43b3e51cecc71d9136fd12c567e7"
1238"checksum proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "ffe022fb8c8bd254524b0b3305906c1921fa37a84a644e29079a9e62200c3901" 1332"checksum pest_generator 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ebee4e9680be4fd162e6f3394ae4192a6b60b1e4d17d845e631f0c68d1a3386"
1239"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" 1333"checksum pest_meta 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f6d5f6f0e6082578c86af197d780dc38328e3f768cec06aac9bc46d714e8221"
1334"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee"
1240"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" 1335"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
1241"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" 1336"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
1242"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" 1337"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
1243"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" 1338"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
1339"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
1244"checksum rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df7a791f788cb4c516f0e091301a29c2b71ef680db5e644a7d68835c8ae6dbfa" 1340"checksum rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df7a791f788cb4c516f0e091301a29c2b71ef680db5e644a7d68835c8ae6dbfa"
1245"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" 1341"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"
1246"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" 1342"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
@@ -1256,32 +1352,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1256"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1352"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
1257"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7" 1353"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7"
1258"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" 1354"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
1355"checksum salsa 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8301c563959d6d50fe0a34817f0d9ff08fe12eda7456e01e2bbde1588ea30602"
1259"checksum same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10f7794e2fda7f594866840e95f5c5962e886e228e68b6505885811a94dd728c" 1356"checksum same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10f7794e2fda7f594866840e95f5c5962e886e228e68b6505885811a94dd728c"
1260"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 1357"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
1261"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1358"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
1262"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1359"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1263"checksum serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "84257ccd054dc351472528c8587b4de2dbf0dc0fe2e634030c1a90bfdacebaa9" 1360"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef"
1264"checksum serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "31569d901045afbff7a9479f793177fe9259819aff10ab4f89ef69bbc5f567fe" 1361"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c"
1265"checksum serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "bb47a3d5c84320222f66d7db21157c4a7407755de41798f9b4c1c40593397b1a" 1362"checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce"
1363"checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded"
1266"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" 1364"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373"
1267"checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d" 1365"checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d"
1268"checksum smol_str 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "248055d41f4c53f8ee7048e8a578a5190d0cca306630718091e4d481735e44b9" 1366"checksum smol_str 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f3ed6f19b800d76574926e458d5f8e2dbea86c2b58c08d33a982448f09ac8d0c"
1269"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 1367"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
1270"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" 1368"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
1271"checksum superslice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50b13d42370e0f5fc62eafdd5c2d20065eaf5458dab215ff3e20e63eea96b30" 1369"checksum superslice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50b13d42370e0f5fc62eafdd5c2d20065eaf5458dab215ff3e20e63eea96b30"
1272"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
1273"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" 1370"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
1274"checksum syn 0.15.7 (registry+https://github.com/rust-lang/crates.io-index)" = "455a6ec9b368f8c479b0ae5494d13b22dc00990d2f00d68c9dc6a2dc4f17f210" 1371"checksum syn 0.15.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b036b7b35e846707c0e55c2c9441fa47867c0f87fca416921db3261b1d8c741a"
1275"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
1276"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7" 1372"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
1277"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" 1373"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
1278"checksum tera 0.11.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4f79f17fe555fffe4838a082a63636883ee13022888dc7bdc99edad8e0a411cd" 1374"checksum tera 0.11.17 (registry+https://github.com/rust-lang/crates.io-index)" = "2829d259c4699fbbe8acb353d231e6da31ff4301c52244413ed29ff6093da412"
1279"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" 1375"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
1280"checksum text_unit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc86da66d0b9aa8d359b0ec31b4342c6bc52637eadef05b91b098551a9f8e9" 1376"checksum text_unit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc86da66d0b9aa8d359b0ec31b4342c6bc52637eadef05b91b098551a9f8e9"
1281"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" 1377"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
1282"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 1378"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
1283"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" 1379"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
1284"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" 1380"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
1381"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77"
1285"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" 1382"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
1286"checksum unic-char-property 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce36d3f7ce754afdbccccf8ff0dd0134e50fb44aaae579f96218856e9e5dbd1e" 1383"checksum unic-char-property 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce36d3f7ce754afdbccccf8ff0dd0134e50fb44aaae579f96218856e9e5dbd1e"
1287"checksum unic-char-range 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab85fab42ad1b26cafc03bf891f69cb4d6e15f491030e89a0122197baa8ae8" 1384"checksum unic-char-range 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab85fab42ad1b26cafc03bf891f69cb4d6e15f491030e89a0122197baa8ae8"
@@ -1293,7 +1390,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1293"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" 1390"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
1294"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" 1391"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
1295"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" 1392"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
1296"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
1297"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1393"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
1298"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" 1394"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
1299"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" 1395"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6"
diff --git a/README.md b/README.md
index 481d065b0..c3056bcfd 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,8 @@ functionality is provided via a language server.
16 16
17## Quick Start 17## Quick Start
18 18
19Rust analyzer builds on stable Rust >= 1.29.0. 19Rust analyzer builds on Rust >= 1.30.0 (currently in beta) and uses
20the 2018 edition.
20 21
21``` 22```
22# run tests 23# run tests
@@ -61,99 +62,20 @@ fold:
61* to quickly bootstrap usable and useful language server: solution 62* to quickly bootstrap usable and useful language server: solution
62 that covers 80% of Rust code will be useful for IDEs, and will be 63 that covers 80% of Rust code will be useful for IDEs, and will be
63 vastly simpler than 100% solution. 64 vastly simpler than 100% solution.
64 65
65* to understand how the consumer-side of compiler API should look like 66* to understand how the consumer-side of compiler API should look like
66 (especially it's on-demand aspects). If you have 67 (especially it's on-demand aspects). If you have
67 `get_expression_type` function, you can write a ton of purely-IDE 68 `get_expression_type` function, you can write a ton of purely-IDE
68 features on top of it, even if the function is only partially 69 features on top of it, even if the function is only partially
69 correct. Plugin in the precise function afterwards should just make 70 correct. Plugin in the precise function afterwards should just make
70 IDE features more reliable. 71 IDE features more reliable.
71 72
72The long term plan is to merge with the mainline rustc compiler, 73The long term plan is to merge with the mainline rustc compiler,
73probably around the HIR boundary? That is, use rust analyzer for 74probably around the HIR boundary? That is, use rust analyzer for
74parsing, macro expansion and related bits of name resolution, but 75parsing, macro expansion and related bits of name resolution, but
75leave the rest (including type inference and trait selection) to the 76leave the rest (including type inference and trait selection) to the
76existing rustc. 77existing rustc.
77 78
78## Code Walk-Through
79
80### `crates/ra_syntax`
81
82Rust syntax tree structure and parser. See
83[RFC](https://github.com/rust-lang/rfcs/pull/2256) for some design
84notes.
85
86- `yellow`, red/green syntax tree, heavily inspired [by this](https://github.com/apple/swift/tree/ab68f0d4cbf99cdfa672f8ffe18e433fddc8b371/lib/Syntax)
87- `grammar`, the actual parser
88- `parser_api/parser_impl` bridges the tree-agnostic parser from `grammar` with `yellow` trees
89- `grammar.ron` RON description of the grammar, which is used to
90 generate `syntax_kinds` and `ast` modules.
91- `algo`: generic tree algorithms, including `walk` for O(1) stack
92 space tree traversal (this is cool) and `visit` for type-driven
93 visiting the nodes (this is double plus cool, if you understand how
94 `Visitor` works, you understand rust-analyzer).
95
96
97### `crates/ra_editor`
98
99All IDE features which can be implemented if you only have access to a
100single file. `ra_editor` could be used to enhance editing of Rust code
101without the need to fiddle with build-systems, file
102synchronization and such.
103
104In a sense, `ra_editor` is just a bunch of pure functions which take a
105syntax tree as an input.
106
107### `crates/salsa`
108
109An implementation of red-green incremental compilation algorithm from
110rust compiler. It makes all rust-analyzer features on-demand.
111
112
113### `crates/ra_analysis`
114
115A stateful library for analyzing many Rust files as they change.
116`AnalysisHost` is a mutable entity (clojure's atom) which holds
117current state, incorporates changes and handles out `Analysis` --- an
118immutable consistent snapshot of world state at a point in time, which
119actually powers analysis.
120
121
122### `crates/ra_lsp_server`
123
124An LSP implementation which uses `ra_analysis` for managing state and
125`ra_editor` for actually doing useful stuff.
126
127
128### `crates/cli`
129
130A CLI interface to libsyntax
131
132### `crate/tools`
133
134Code-gen tasks, used to develop rust-analyzer:
135
136- `cargo gen-kinds` -- generate `ast` and `syntax_kinds`
137- `cargo gen-tests` -- collect inline tests from grammar
138- `cargo install-code` -- build and install VS Code extension and server
139
140### `editors/code`
141
142VS Code plugin
143
144
145## Performance
146
147Non-incremental, but seems pretty fast:
148
149```
150$ cargo build --release --package ra_cli
151$ wc -l ~/projects/rust/src/libsyntax/parse/parser.rs
1527546 /home/matklad/projects/rust/src/libsyntax/parse/parser.rs
153$ ./target/release/ra_cli parse < ~/projects/rust/src/libsyntax/parse/parser.rs --no-dump > /dev/null
154parsing: 21.067065ms
155```
156
157## Getting in touch 79## Getting in touch
158 80
159@matklad can be found at Rust 81@matklad can be found at Rust
@@ -161,6 +83,11 @@ parsing: 21.067065ms
161#ides-and-editors. 83#ides-and-editors.
162 84
163 85
86## Contributing
87
88See [CONTRIBUTING.md](./CONTRIBUTING.md) and [ARCHITECTURE.md](./ARCHITECTURE.md)
89
90
164## License 91## License
165 92
166Rust analyzer is primarily distributed under the terms of both the MIT 93Rust analyzer is primarily distributed under the terms of both the MIT
diff --git a/appveyor.yml b/appveyor.yml
index a6ba3b0e1..a32a1e7b8 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -2,7 +2,7 @@ os: Visual Studio 2015
2 2
3install: 3install:
4 - curl https://win.rustup.rs/ --output rustup-init.exe 4 - curl https://win.rustup.rs/ --output rustup-init.exe
5 - rustup-init -yv --default-toolchain stable --default-host x86_64-pc-windows-msvc 5 - rustup-init -yv --default-toolchain beta --default-host x86_64-pc-windows-msvc
6 - set PATH=%PATH%;%USERPROFILE%\.cargo\bin 6 - set PATH=%PATH%;%USERPROFILE%\.cargo\bin
7 - rustc -vV 7 - rustc -vV
8 - cargo -vV 8 - cargo -vV
diff --git a/crates/ra_analysis/Cargo.toml b/crates/ra_analysis/Cargo.toml
index a82e1761c..17b04182f 100644
--- a/crates/ra_analysis/Cargo.toml
+++ b/crates/ra_analysis/Cargo.toml
@@ -1,4 +1,5 @@
1[package] 1[package]
2edition = "2018"
2name = "ra_analysis" 3name = "ra_analysis"
3version = "0.1.0" 4version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"] 5authors = ["Aleksey Kladov <[email protected]>"]
@@ -14,7 +15,7 @@ fst = "0.3.1"
14im = "12.0.0" 15im = "12.0.0"
15ra_syntax = { path = "../ra_syntax" } 16ra_syntax = { path = "../ra_syntax" }
16ra_editor = { path = "../ra_editor" } 17ra_editor = { path = "../ra_editor" }
17salsa = { path = "../salsa" } 18salsa = "0.5.0"
18rustc-hash = "1.0" 19rustc-hash = "1.0"
19 20
20[dev-dependencies] 21[dev-dependencies]
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
new file mode 100644
index 000000000..c69577233
--- /dev/null
+++ b/crates/ra_analysis/src/db.rs
@@ -0,0 +1,117 @@
1use std::{
2 fmt,
3 sync::Arc,
4 hash::{Hash, Hasher},
5};
6use salsa;
7use rustc_hash::FxHashSet;
8use ra_syntax::File;
9use ra_editor::{LineIndex};
10use crate::{
11 symbol_index::SymbolIndex,
12 module_map::{ModulesDatabase, ModuleTreeQuery, ModuleDescriptorQuery},
13 FileId, FileResolverImp,
14};
15
16#[derive(Default)]
17pub(crate) struct RootDatabase {
18 runtime: salsa::runtime::Runtime<RootDatabase>,
19}
20
21impl fmt::Debug for RootDatabase {
22 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
23 fmt.write_str("RootDatabase { ... }")
24 }
25}
26
27impl salsa::Database for RootDatabase {
28 fn salsa_runtime(&self) -> &salsa::runtime::Runtime<RootDatabase> {
29 &self.runtime
30 }
31}
32
33impl salsa::ParallelDatabase for RootDatabase {
34 fn fork(&self) -> Self {
35 RootDatabase {
36 runtime: self.runtime.fork(),
37 }
38 }
39}
40
41impl Clone for RootDatabase {
42 fn clone(&self) -> RootDatabase {
43 salsa::ParallelDatabase::fork(self)
44 }
45}
46
47salsa::database_storage! {
48 pub(crate) struct RootDatabaseStorage for RootDatabase {
49 impl FilesDatabase {
50 fn file_text() for FileTextQuery;
51 fn file_set() for FileSetQuery;
52 }
53 impl SyntaxDatabase {
54 fn file_syntax() for FileSyntaxQuery;
55 fn file_lines() for FileLinesQuery;
56 fn file_symbols() for FileSymbolsQuery;
57 }
58 impl ModulesDatabase {
59 fn module_tree() for ModuleTreeQuery;
60 fn module_descriptor() for ModuleDescriptorQuery;
61 }
62 }
63}
64
65salsa::query_group! {
66 pub(crate) trait FilesDatabase: salsa::Database {
67 fn file_text(file_id: FileId) -> Arc<String> {
68 type FileTextQuery;
69 storage input;
70 }
71 fn file_set(key: ()) -> Arc<FileSet> {
72 type FileSetQuery;
73 storage input;
74 }
75 }
76}
77
78#[derive(Default, Debug, PartialEq, Eq)]
79pub(crate) struct FileSet {
80 pub(crate) files: FxHashSet<FileId>,
81 pub(crate) resolver: FileResolverImp,
82}
83
84impl Hash for FileSet {
85 fn hash<H: Hasher>(&self, hasher: &mut H) {
86 let mut files = self.files.iter().cloned().collect::<Vec<_>>();
87 files.sort();
88 files.hash(hasher);
89 }
90}
91
92salsa::query_group! {
93 pub(crate) trait SyntaxDatabase: FilesDatabase {
94 fn file_syntax(file_id: FileId) -> File {
95 type FileSyntaxQuery;
96 }
97 fn file_lines(file_id: FileId) -> Arc<LineIndex> {
98 type FileLinesQuery;
99 }
100 fn file_symbols(file_id: FileId) -> Arc<SymbolIndex> {
101 type FileSymbolsQuery;
102 }
103 }
104}
105
106fn file_syntax(db: &impl SyntaxDatabase, file_id: FileId) -> File {
107 let text = db.file_text(file_id);
108 File::parse(&*text)
109}
110fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<LineIndex> {
111 let text = db.file_text(file_id);
112 Arc::new(LineIndex::new(&*text))
113}
114fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<SymbolIndex> {
115 let syntax = db.file_syntax(file_id);
116 Arc::new(SymbolIndex::for_file(file_id, syntax))
117}
diff --git a/crates/ra_analysis/src/db/imp.rs b/crates/ra_analysis/src/db/imp.rs
deleted file mode 100644
index 36f6cf290..000000000
--- a/crates/ra_analysis/src/db/imp.rs
+++ /dev/null
@@ -1,153 +0,0 @@
1use std::{
2 sync::Arc,
3 any::Any,
4 hash::{Hash, Hasher},
5 collections::hash_map::{DefaultHasher},
6 iter,
7};
8use rustc_hash::FxHashMap;
9use salsa;
10use {FileId, imp::FileResolverImp};
11use super::{State, Query, QueryCtx};
12
13pub(super) type Data = Arc<Any + Send + Sync + 'static>;
14
15#[derive(Debug)]
16pub(super) struct Db {
17 names: Arc<FxHashMap<salsa::QueryTypeId, &'static str>>,
18 pub(super) imp: salsa::Db<State, Data>,
19}
20
21impl Db {
22 pub(super) fn new(mut reg: QueryRegistry) -> Db {
23 let config = reg.config.take().unwrap();
24 Db {
25 names: Arc::new(reg.names),
26 imp: salsa::Db::new(config, State::default())
27 }
28 }
29 pub(crate) fn with_changes(&self, new_state: State, changed_files: &[FileId], resolver_changed: bool) -> Db {
30 let names = self.names.clone();
31 let mut invalidations = salsa::Invalidations::new();
32 invalidations.invalidate(FILE_TEXT, changed_files.iter().map(hash).map(salsa::InputFingerprint));
33 if resolver_changed {
34 invalidations.invalidate(FILE_SET, iter::once(salsa::InputFingerprint(hash(&()))));
35 } else {
36 invalidations.invalidate(FILE_SET, iter::empty());
37 }
38 let imp = self.imp.with_ground_data(
39 new_state,
40 invalidations,
41 );
42 Db { names, imp }
43 }
44 pub(super) fn extract_trace(&self, ctx: &salsa::QueryCtx<State, Data>) -> Vec<&'static str> {
45 ctx.trace().into_iter().map(|it| self.names[&it]).collect()
46 }
47}
48
49pub(crate) trait EvalQuery {
50 type Params;
51 type Output;
52 fn query_type(&self) -> salsa::QueryTypeId;
53 fn f(&self) -> salsa::QueryFn<State, Data>;
54 fn get(&self, &QueryCtx, Self::Params) -> Arc<Self::Output>;
55}
56
57impl<T, R> EvalQuery for Query<T, R>
58where
59 T: Hash + Send + Sync + 'static,
60 R: Hash + Send + Sync + 'static,
61{
62 type Params = T;
63 type Output = R;
64 fn query_type(&self) -> salsa::QueryTypeId {
65 salsa::QueryTypeId(self.0)
66 }
67 fn f(&self) -> salsa::QueryFn<State, Data> {
68 let f = self.1;
69 Box::new(move |ctx, data| {
70 let ctx = QueryCtx { imp: ctx };
71 let data: &T = data.downcast_ref().unwrap();
72 let res = f(ctx, data);
73 let h = hash(&res);
74 (Arc::new(res), salsa::OutputFingerprint(h))
75 })
76 }
77 fn get(&self, ctx: &QueryCtx, params: Self::Params) -> Arc<Self::Output> {
78 let query_id = salsa::QueryId(
79 self.query_type(),
80 salsa::InputFingerprint(hash(&params)),
81 );
82 let res = ctx.imp.get(query_id, Arc::new(params));
83 res.downcast().unwrap()
84 }
85}
86
87pub(super) struct QueryRegistry {
88 config: Option<salsa::QueryConfig<State, Data>>,
89 names: FxHashMap<salsa::QueryTypeId, &'static str>,
90}
91
92impl QueryRegistry {
93 pub(super) fn new() -> QueryRegistry {
94 let mut config = salsa::QueryConfig::<State, Data>::new();
95 config = config.with_ground_query(
96 FILE_TEXT, Box::new(|state, params| {
97 let file_id: &FileId = params.downcast_ref().unwrap();
98 let res = state.file_map[file_id].clone();
99 let fingerprint = salsa::OutputFingerprint(hash(&res));
100 (res, fingerprint)
101 })
102 );
103 config = config.with_ground_query(
104 FILE_SET, Box::new(|state, _params| {
105 let file_ids: Vec<FileId> = state.file_map.keys().cloned().collect();
106 let hash = hash(&file_ids);
107 let file_resolver = state.file_resolver.clone();
108 let res = (file_ids, file_resolver);
109 let fingerprint = salsa::OutputFingerprint(hash);
110 (Arc::new(res), fingerprint)
111 })
112 );
113 let mut names = FxHashMap::default();
114 names.insert(FILE_TEXT, "FILE_TEXT");
115 names.insert(FILE_SET, "FILE_SET");
116 QueryRegistry { config: Some(config), names }
117 }
118 pub(super) fn add<Q: EvalQuery>(&mut self, q: Q, name: &'static str) {
119 let id = q.query_type();
120 let prev = self.names.insert(id, name);
121 assert!(prev.is_none(), "duplicate query: {:?}", id);
122 let config = self.config.take().unwrap();
123 let config = config.with_query(id, q.f());
124 self.config= Some(config);
125 }
126}
127
128fn hash<T: Hash>(x: &T) -> u64 {
129 let mut hasher = DefaultHasher::new();
130 x.hash(&mut hasher);
131 hasher.finish()
132}
133
134const FILE_TEXT: salsa::QueryTypeId = salsa::QueryTypeId(0);
135pub(super) fn file_text(ctx: QueryCtx, file_id: FileId) -> Arc<String> {
136 let query_id = salsa::QueryId(
137 FILE_TEXT,
138 salsa::InputFingerprint(hash(&file_id)),
139 );
140 let res = ctx.imp.get(query_id, Arc::new(file_id));
141 res.downcast().unwrap()
142}
143
144const FILE_SET: salsa::QueryTypeId = salsa::QueryTypeId(1);
145pub(super) fn file_set(ctx: QueryCtx) -> Arc<(Vec<FileId>, FileResolverImp)> {
146 let query_id = salsa::QueryId(
147 FILE_SET,
148 salsa::InputFingerprint(hash(&())),
149 );
150 let res = ctx.imp.get(query_id, Arc::new(()));
151 res.downcast().unwrap()
152}
153
diff --git a/crates/ra_analysis/src/db/mod.rs b/crates/ra_analysis/src/db/mod.rs
deleted file mode 100644
index 22769d112..000000000
--- a/crates/ra_analysis/src/db/mod.rs
+++ /dev/null
@@ -1,85 +0,0 @@
1mod imp;
2
3use std::{
4 sync::Arc,
5};
6use im;
7use salsa;
8use {FileId, imp::FileResolverImp};
9
10#[derive(Debug, Default, Clone)]
11pub(crate) struct State {
12 pub(crate) file_map: im::HashMap<FileId, Arc<String>>,
13 pub(crate) file_resolver: FileResolverImp
14}
15
16#[derive(Debug)]
17pub(crate) struct Db {
18 imp: imp::Db,
19}
20
21#[derive(Clone, Copy)]
22pub(crate) struct QueryCtx<'a> {
23 imp: &'a salsa::QueryCtx<State, imp::Data>,
24}
25
26pub(crate) struct Query<T, R>(pub(crate) u16, pub(crate) fn(QueryCtx, &T) -> R);
27
28pub(crate) struct QueryRegistry {
29 imp: imp::QueryRegistry,
30}
31
32impl Default for Db {
33 fn default() -> Db {
34 Db::new()
35 }
36}
37
38impl Db {
39 pub(crate) fn new() -> Db {
40 let reg = QueryRegistry::new();
41 Db { imp: imp::Db::new(reg.imp) }
42 }
43 pub(crate) fn state(&self) -> &State {
44 self.imp.imp.ground_data()
45 }
46 pub(crate) fn with_changes(&self, new_state: State, changed_files: &[FileId], resolver_changed: bool) -> Db {
47 Db { imp: self.imp.with_changes(new_state, changed_files, resolver_changed) }
48 }
49 pub(crate) fn make_query<F: FnOnce(QueryCtx) -> R, R>(&self, f: F) -> R {
50 let ctx = QueryCtx { imp: &self.imp.imp.query_ctx() };
51 f(ctx)
52 }
53 #[allow(unused)]
54 pub(crate) fn trace_query<F: FnOnce(QueryCtx) -> R, R>(&self, f: F) -> (R, Vec<&'static str>) {
55 let ctx = QueryCtx { imp: &self.imp.imp.query_ctx() };
56 let res = f(ctx);
57 let trace = self.imp.extract_trace(ctx.imp);
58 (res, trace)
59 }
60}
61
62impl<'a> QueryCtx<'a> {
63 pub(crate) fn get<Q: imp::EvalQuery>(&self, q: Q, params: Q::Params) -> Arc<Q::Output> {
64 q.get(self, params)
65 }
66}
67
68pub(crate) fn file_text(ctx: QueryCtx, file_id: FileId) -> Arc<String> {
69 imp::file_text(ctx, file_id)
70}
71
72pub(crate) fn file_set(ctx: QueryCtx) -> Arc<(Vec<FileId>, FileResolverImp)> {
73 imp::file_set(ctx)
74}
75impl QueryRegistry {
76 fn new() -> QueryRegistry {
77 let mut reg = QueryRegistry { imp: imp::QueryRegistry::new() };
78 ::queries::register_queries(&mut reg);
79 ::module_map::register_queries(&mut reg);
80 reg
81 }
82 pub(crate) fn add<Q: imp::EvalQuery>(&mut self, q: Q, name: &'static str) {
83 self.imp.add(q, name)
84 }
85}
diff --git a/crates/ra_analysis/src/descriptors.rs b/crates/ra_analysis/src/descriptors.rs
index 0731b5572..8d9f38ca5 100644
--- a/crates/ra_analysis/src/descriptors.rs
+++ b/crates/ra_analysis/src/descriptors.rs
@@ -4,14 +4,15 @@ use std::{
4use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
5use ra_syntax::{ 5use ra_syntax::{
6 SmolStr, 6 SmolStr,
7 ast::{self, NameOwner}, 7 ast::{self, NameOwner, AstNode},
8 text_utils::is_subrange
8}; 9};
9use { 10use crate::{
10 FileId, 11 FileId,
11 imp::FileResolverImp, 12 imp::FileResolverImp,
12}; 13};
13 14
14#[derive(Debug, Hash)] 15#[derive(Debug, PartialEq, Eq, Hash)]
15pub struct ModuleDescriptor { 16pub struct ModuleDescriptor {
16 pub submodules: Vec<Submodule> 17 pub submodules: Vec<Submodule>
17} 18}
@@ -42,7 +43,7 @@ pub struct Submodule {
42 pub name: SmolStr, 43 pub name: SmolStr,
43} 44}
44 45
45#[derive(Hash, Debug)] 46#[derive(Debug, PartialEq, Eq, Hash)]
46pub(crate) struct ModuleTreeDescriptor { 47pub(crate) struct ModuleTreeDescriptor {
47 nodes: Vec<NodeData>, 48 nodes: Vec<NodeData>,
48 links: Vec<LinkData>, 49 links: Vec<LinkData>,
@@ -51,7 +52,7 @@ pub(crate) struct ModuleTreeDescriptor {
51 52
52#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] 53#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
53struct Node(usize); 54struct Node(usize);
54#[derive(Hash, Debug)] 55#[derive(Hash, Debug, PartialEq, Eq)]
55struct NodeData { 56struct NodeData {
56 file_id: FileId, 57 file_id: FileId,
57 links: Vec<Link>, 58 links: Vec<Link>,
@@ -60,7 +61,7 @@ struct NodeData {
60 61
61#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] 62#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
62pub(crate) struct Link(usize); 63pub(crate) struct Link(usize);
63#[derive(Hash, Debug)] 64#[derive(Hash, Debug, PartialEq, Eq)]
64struct LinkData { 65struct LinkData {
65 owner: Node, 66 owner: Node,
66 name: SmolStr, 67 name: SmolStr,
@@ -69,7 +70,7 @@ struct LinkData {
69} 70}
70 71
71 72
72#[derive(Clone, Debug, Hash)] 73#[derive(Clone, Debug, Hash, PartialEq, Eq)]
73pub enum Problem { 74pub enum Problem {
74 UnresolvedModule { 75 UnresolvedModule {
75 candidate: RelativePathBuf, 76 candidate: RelativePathBuf,
@@ -218,3 +219,56 @@ fn resolve_submodule(
218 } 219 }
219 (points_to, problem) 220 (points_to, problem)
220} 221}
222
223#[derive(Debug, Clone)]
224pub struct FnDescriptor {
225 pub name: String,
226 pub label : String,
227 pub ret_type: Option<String>,
228 pub params: Vec<String>,
229}
230
231impl FnDescriptor {
232 pub fn new(node: ast::FnDef) -> Option<Self> {
233 let name = node.name()?.text().to_string();
234
235 // Strip the body out for the label.
236 let label : String = if let Some(body) = node.body() {
237 let body_range = body.syntax().range();
238 let label : String = node.syntax().children()
239 .filter(|child| !is_subrange(body_range, child.range()))
240 .map(|node| node.text().to_string())
241 .collect();
242 label
243 } else {
244 node.syntax().text().to_string()
245 };
246
247 let params = FnDescriptor::param_list(node);
248 let ret_type = node.ret_type().map(|r| r.syntax().text().to_string());
249
250 Some(FnDescriptor {
251 name,
252 ret_type,
253 params,
254 label
255 })
256 }
257
258 fn param_list(node: ast::FnDef) -> Vec<String> {
259 let mut res = vec![];
260 if let Some(param_list) = node.param_list() {
261 if let Some(self_param) = param_list.self_param() {
262 res.push(self_param.syntax().text().to_string())
263 }
264
265 // Maybe use param.pat here? See if we can just extract the name?
266 //res.extend(param_list.params().map(|p| p.syntax().text().to_string()));
267 res.extend(param_list.params()
268 .filter_map(|p| p.pat())
269 .map(|pat| pat.syntax().text().to_string())
270 );
271 }
272 res
273 }
274}
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 47bc0032b..5efcaeca0 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -1,8 +1,8 @@
1use std::{ 1use std::{
2 sync::{ 2 sync::{
3 Arc, 3 Arc,
4 atomic::{AtomicBool, Ordering::SeqCst},
5 }, 4 },
5 hash::{Hash, Hasher},
6 fmt, 6 fmt,
7 collections::VecDeque, 7 collections::VecDeque,
8 iter, 8 iter,
@@ -12,24 +12,38 @@ use relative_path::RelativePath;
12use rustc_hash::FxHashSet; 12use rustc_hash::FxHashSet;
13use ra_editor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit, resolve_local_name}; 13use ra_editor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit, resolve_local_name};
14use ra_syntax::{ 14use ra_syntax::{
15 TextUnit, TextRange, SmolStr, File, AstNode, 15 TextUnit, TextRange, SmolStr, File, AstNode, SyntaxNodeRef,
16 SyntaxKind::*, 16 SyntaxKind::*,
17 ast::{self, NameOwner}, 17 ast::{self, NameOwner, ArgListOwner, Expr},
18}; 18};
19 19
20use { 20use crate::{
21 FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, 21 FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit,
22 JobToken, CrateGraph, CrateId, 22 JobToken, CrateGraph, CrateId,
23 roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot}, 23 roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot},
24 descriptors::{ModuleTreeDescriptor, Problem}, 24 descriptors::{FnDescriptor, ModuleTreeDescriptor, Problem},
25}; 25};
26 26
27
28#[derive(Clone, Debug)] 27#[derive(Clone, Debug)]
29pub(crate) struct FileResolverImp { 28pub(crate) struct FileResolverImp {
30 inner: Arc<FileResolver> 29 inner: Arc<FileResolver>
31} 30}
32 31
32impl PartialEq for FileResolverImp {
33 fn eq(&self, other: &FileResolverImp) -> bool {
34 self.inner() == other.inner()
35 }
36}
37
38impl Eq for FileResolverImp {
39}
40
41impl Hash for FileResolverImp {
42 fn hash<H: Hasher>(&self, hasher: &mut H) {
43 self.inner().hash(hasher);
44 }
45}
46
33impl FileResolverImp { 47impl FileResolverImp {
34 pub(crate) fn new(inner: Arc<FileResolver>) -> FileResolverImp { 48 pub(crate) fn new(inner: Arc<FileResolver>) -> FileResolverImp {
35 FileResolverImp { inner } 49 FileResolverImp { inner }
@@ -40,6 +54,9 @@ impl FileResolverImp {
40 pub(crate) fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> { 54 pub(crate) fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option<FileId> {
41 self.inner.resolve(file_id, path) 55 self.inner.resolve(file_id, path)
42 } 56 }
57 fn inner(&self) -> *const FileResolver {
58 &*self.inner
59 }
43} 60}
44 61
45impl Default for FileResolverImp { 62impl Default for FileResolverImp {
@@ -60,29 +77,27 @@ impl Default for FileResolverImp {
60 77
61#[derive(Debug)] 78#[derive(Debug)]
62pub(crate) struct AnalysisHostImpl { 79pub(crate) struct AnalysisHostImpl {
63 data: Arc<WorldData> 80 data: WorldData
64} 81}
65 82
66impl AnalysisHostImpl { 83impl AnalysisHostImpl {
67 pub fn new() -> AnalysisHostImpl { 84 pub fn new() -> AnalysisHostImpl {
68 AnalysisHostImpl { 85 AnalysisHostImpl {
69 data: Arc::new(WorldData::default()), 86 data: WorldData::default(),
70 } 87 }
71 } 88 }
72 pub fn analysis(&self) -> AnalysisImpl { 89 pub fn analysis(&self) -> AnalysisImpl {
73 AnalysisImpl { 90 AnalysisImpl {
74 needs_reindex: AtomicBool::new(false),
75 data: self.data.clone(), 91 data: self.data.clone(),
76 } 92 }
77 } 93 }
78 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { 94 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) {
79 let data = self.data_mut(); 95 self.data_mut()
80 data.root = Arc::new(data.root.apply_changes(changes, None)); 96 .root.apply_changes(changes, None);
81 } 97 }
82 pub fn set_file_resolver(&mut self, resolver: FileResolverImp) { 98 pub fn set_file_resolver(&mut self, resolver: FileResolverImp) {
83 let data = self.data_mut(); 99 self.data_mut()
84 data.file_resolver = resolver.clone(); 100 .root.apply_changes(&mut iter::empty(), Some(resolver));
85 data.root = Arc::new(data.root.apply_changes(&mut iter::empty(), Some(resolver)));
86 } 101 }
87 pub fn set_crate_graph(&mut self, graph: CrateGraph) { 102 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
88 let mut visited = FxHashSet::default(); 103 let mut visited = FxHashSet::default();
@@ -97,34 +112,24 @@ impl AnalysisHostImpl {
97 self.data_mut().libs.push(Arc::new(root)); 112 self.data_mut().libs.push(Arc::new(root));
98 } 113 }
99 fn data_mut(&mut self) -> &mut WorldData { 114 fn data_mut(&mut self) -> &mut WorldData {
100 Arc::make_mut(&mut self.data) 115 &mut self.data
101 } 116 }
102} 117}
103 118
104pub(crate) struct AnalysisImpl { 119pub(crate) struct AnalysisImpl {
105 needs_reindex: AtomicBool, 120 data: WorldData,
106 data: Arc<WorldData>,
107} 121}
108 122
109impl fmt::Debug for AnalysisImpl { 123impl fmt::Debug for AnalysisImpl {
110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 124 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111 (&*self.data).fmt(f) 125 self.data.fmt(f)
112 }
113}
114
115impl Clone for AnalysisImpl {
116 fn clone(&self) -> AnalysisImpl {
117 AnalysisImpl {
118 needs_reindex: AtomicBool::new(self.needs_reindex.load(SeqCst)),
119 data: Arc::clone(&self.data),
120 }
121 } 126 }
122} 127}
123 128
124impl AnalysisImpl { 129impl AnalysisImpl {
125 fn root(&self, file_id: FileId) -> &SourceRoot { 130 fn root(&self, file_id: FileId) -> &SourceRoot {
126 if self.data.root.contains(file_id) { 131 if self.data.root.contains(file_id) {
127 return &*self.data.root; 132 return &self.data.root;
128 } 133 }
129 &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap() 134 &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap()
130 } 135 }
@@ -306,6 +311,68 @@ impl AnalysisImpl {
306 .collect() 311 .collect()
307 } 312 }
308 313
314 pub fn resolve_callable(&self, file_id: FileId, offset: TextUnit, token: &JobToken)
315 -> Option<(FnDescriptor, Option<usize>)> {
316
317 let root = self.root(file_id);
318 let file = root.syntax(file_id);
319 let syntax = file.syntax();
320
321 // Find the calling expression and it's NameRef
322 let calling_node = FnCallNode::with_node(syntax, offset)?;
323 let name_ref = calling_node.name_ref()?;
324
325 // Resolve the function's NameRef (NOTE: this isn't entirely accurate).
326 let file_symbols = self.index_resolve(name_ref, token);
327 for (_, fs) in file_symbols {
328 if fs.kind == FN_DEF {
329 if let Some(fn_def) = find_node_at_offset(syntax, fs.node_range.start()) {
330 if let Some(descriptor) = FnDescriptor::new(fn_def) {
331 // If we have a calling expression let's find which argument we are on
332 let mut current_parameter = None;
333
334 let num_params = descriptor.params.len();
335 let has_self = fn_def.param_list()
336 .and_then(|l| l.self_param())
337 .is_some();
338
339 if num_params == 1 {
340 if !has_self {
341 current_parameter = Some(1);
342 }
343 } else if num_params > 1 {
344 // Count how many parameters into the call we are.
345 // TODO: This is best effort for now and should be fixed at some point.
346 // It may be better to see where we are in the arg_list and then check
347 // where offset is in that list (or beyond).
348 // Revisit this after we get documentation comments in.
349 if let Some(ref arg_list) = calling_node.arg_list() {
350 let start = arg_list.syntax().range().start();
351
352 let range_search = TextRange::from_to(start, offset);
353 let mut commas: usize = arg_list.syntax().text()
354 .slice(range_search).to_string()
355 .matches(",")
356 .count();
357
358 // If we have a method call eat the first param since it's just self.
359 if has_self {
360 commas = commas + 1;
361 }
362
363 current_parameter = Some(commas);
364 }
365 }
366
367 return Some((descriptor, current_parameter));
368 }
369 }
370 }
371 }
372
373 None
374 }
375
309 fn index_resolve(&self, name_ref: ast::NameRef, token: &JobToken) -> Vec<(FileId, FileSymbol)> { 376 fn index_resolve(&self, name_ref: ast::NameRef, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
310 let name = name_ref.text(); 377 let name = name_ref.text();
311 let mut query = Query::new(name.to_string()); 378 let mut query = Query::new(name.to_string());
@@ -325,9 +392,8 @@ impl AnalysisImpl {
325 392
326#[derive(Default, Clone, Debug)] 393#[derive(Default, Clone, Debug)]
327struct WorldData { 394struct WorldData {
328 file_resolver: FileResolverImp,
329 crate_graph: CrateGraph, 395 crate_graph: CrateGraph,
330 root: Arc<WritableSourceRoot>, 396 root: WritableSourceRoot,
331 libs: Vec<Arc<ReadonlySourceRoot>>, 397 libs: Vec<Arc<ReadonlySourceRoot>>,
332} 398}
333 399
@@ -355,3 +421,46 @@ impl CrateGraph {
355 Some(crate_id) 421 Some(crate_id)
356 } 422 }
357} 423}
424
425enum FnCallNode<'a> {
426 CallExpr(ast::CallExpr<'a>),
427 MethodCallExpr(ast::MethodCallExpr<'a>)
428}
429
430impl<'a> FnCallNode<'a> {
431 pub fn with_node(syntax: SyntaxNodeRef, offset: TextUnit) -> Option<FnCallNode> {
432 if let Some(expr) = find_node_at_offset::<ast::CallExpr>(syntax, offset) {
433 return Some(FnCallNode::CallExpr(expr));
434 }
435 if let Some(expr) = find_node_at_offset::<ast::MethodCallExpr>(syntax, offset) {
436 return Some(FnCallNode::MethodCallExpr(expr));
437 }
438 None
439 }
440
441 pub fn name_ref(&self) -> Option<ast::NameRef> {
442 match *self {
443 FnCallNode::CallExpr(call_expr) => {
444 Some(match call_expr.expr()? {
445 Expr::PathExpr(path_expr) => {
446 path_expr.path()?.segment()?.name_ref()?
447 },
448 _ => return None
449 })
450 },
451
452 FnCallNode::MethodCallExpr(call_expr) => {
453 call_expr.syntax().children()
454 .filter_map(ast::NameRef::cast)
455 .nth(0)
456 }
457 }
458 }
459
460 pub fn arg_list(&self) -> Option<ast::ArgList> {
461 match *self {
462 FnCallNode::CallExpr(expr) => expr.arg_list(),
463 FnCallNode::MethodCallExpr(expr) => expr.arg_list()
464 }
465 }
466}
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 849fd93e4..d8b355a81 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -19,7 +19,6 @@ mod imp;
19mod job; 19mod job;
20mod roots; 20mod roots;
21mod db; 21mod db;
22mod queries;
23mod descriptors; 22mod descriptors;
24 23
25use std::{ 24use std::{
@@ -29,15 +28,18 @@ use std::{
29 28
30use relative_path::{RelativePath, RelativePathBuf}; 29use relative_path::{RelativePath, RelativePathBuf};
31use ra_syntax::{File, TextRange, TextUnit, AtomEdit}; 30use ra_syntax::{File, TextRange, TextUnit, AtomEdit};
32use imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp};
33use rustc_hash::FxHashMap; 31use rustc_hash::FxHashMap;
32use crate::imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp};
34 33
35pub use ra_editor::{ 34pub use ra_editor::{
36 StructureNode, LineIndex, FileSymbol, 35 StructureNode, LineIndex, FileSymbol,
37 Runnable, RunnableKind, HighlightedRange, CompletionItem, 36 Runnable, RunnableKind, HighlightedRange, CompletionItem,
38 Fold, FoldKind 37 Fold, FoldKind
39}; 38};
40pub use job::{JobToken, JobHandle}; 39pub use crate::{
40 job::{JobToken, JobHandle},
41 descriptors::FnDescriptor,
42};
41 43
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 44#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
43pub struct FileId(pub u32); 45pub struct FileId(pub u32);
@@ -159,7 +161,7 @@ impl Query {
159 } 161 }
160} 162}
161 163
162#[derive(Clone, Debug)] 164#[derive(Debug)]
163pub struct Analysis { 165pub struct Analysis {
164 imp: AnalysisImpl 166 imp: AnalysisImpl
165} 167}
@@ -236,6 +238,11 @@ impl Analysis {
236 let file = self.imp.file_syntax(file_id); 238 let file = self.imp.file_syntax(file_id);
237 ra_editor::folding_ranges(&file) 239 ra_editor::folding_ranges(&file)
238 } 240 }
241
242 pub fn resolve_callable(&self, file_id: FileId, offset: TextUnit, token: &JobToken)
243 -> Option<(FnDescriptor, Option<usize>)> {
244 self.imp.resolve_callable(file_id, offset, token)
245 }
239} 246}
240 247
241#[derive(Debug)] 248#[derive(Debug)]
@@ -250,3 +257,9 @@ impl LibraryData {
250 LibraryData { root } 257 LibraryData { root }
251 } 258 }
252} 259}
260
261#[test]
262fn analysis_is_send() {
263 fn is_send<T: Send>() {}
264 is_send::<Analysis>();
265}
diff --git a/crates/ra_analysis/src/module_map.rs b/crates/ra_analysis/src/module_map.rs
index a21f55fff..c1799e3d4 100644
--- a/crates/ra_analysis/src/module_map.rs
+++ b/crates/ra_analysis/src/module_map.rs
@@ -1,157 +1,34 @@
1use std::sync::Arc; 1use std::sync::Arc;
2use { 2use crate::{
3 FileId, 3 FileId,
4 db::{ 4 db::{SyntaxDatabase},
5 Query, QueryRegistry, QueryCtx,
6 file_set
7 },
8 queries::file_syntax,
9 descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, 5 descriptors::{ModuleDescriptor, ModuleTreeDescriptor},
10}; 6};
11 7
12pub(crate) fn register_queries(reg: &mut QueryRegistry) { 8salsa::query_group! {
13 reg.add(MODULE_DESCR, "MODULE_DESCR"); 9 pub(crate) trait ModulesDatabase: SyntaxDatabase {
14 reg.add(MODULE_TREE, "MODULE_TREE"); 10 fn module_tree(key: ()) -> Arc<ModuleTreeDescriptor> {
15} 11 type ModuleTreeQuery;
16
17pub(crate) fn module_tree(ctx: QueryCtx) -> Arc<ModuleTreeDescriptor> {
18 ctx.get(MODULE_TREE, ())
19}
20
21const MODULE_DESCR: Query<FileId, ModuleDescriptor> = Query(30, |ctx, &file_id| {
22 let file = file_syntax(ctx, file_id);
23 ModuleDescriptor::new(file.ast())
24});
25
26const MODULE_TREE: Query<(), ModuleTreeDescriptor> = Query(31, |ctx, _| {
27 let file_set = file_set(ctx);
28 let mut files = Vec::new();
29 for &file_id in file_set.0.iter() {
30 let module_descr = ctx.get(MODULE_DESCR, file_id);
31 files.push((file_id, module_descr));
32 }
33 ModuleTreeDescriptor::new(files.iter().map(|(file_id, descr)| (*file_id, &**descr)), &file_set.1)
34});
35
36#[cfg(test)]
37mod tests {
38 use std::collections::HashMap;
39 use im;
40 use relative_path::{RelativePath, RelativePathBuf};
41 use {
42 db::{Db},
43 imp::FileResolverImp,
44 FileId, FileResolver,
45 };
46 use super::*;
47
48 #[derive(Debug)]
49 struct FileMap(im::HashMap<FileId, RelativePathBuf>);
50
51 impl FileResolver for FileMap {
52 fn file_stem(&self, file_id: FileId) -> String {
53 self.0[&file_id].file_stem().unwrap().to_string()
54 } 12 }
55 fn resolve(&self, file_id: FileId, rel: &RelativePath) -> Option<FileId> { 13 fn module_descriptor(file_id: FileId) -> Arc<ModuleDescriptor> {
56 let path = self.0[&file_id].join(rel).normalize(); 14 type ModuleDescriptorQuery;
57 self.0.iter()
58 .filter_map(|&(id, ref p)| Some(id).filter(|_| p == &path))
59 .next()
60 } 15 }
61 } 16 }
17}
62 18
63 struct Fixture {
64 next_file_id: u32,
65 fm: im::HashMap<FileId, RelativePathBuf>,
66 db: Db,
67 }
68
69 impl Fixture {
70 fn new() -> Fixture {
71 Fixture {
72 next_file_id: 1,
73 fm: im::HashMap::new(),
74 db: Db::new(),
75 }
76 }
77 fn add_file(&mut self, path: &str, text: &str) -> FileId {
78 assert!(path.starts_with("/"));
79 let file_id = FileId(self.next_file_id);
80 self.next_file_id += 1;
81 self.fm.insert(file_id, RelativePathBuf::from(&path[1..]));
82 let mut new_state = self.db.state().clone();
83 new_state.file_map.insert(file_id, Arc::new(text.to_string()));
84 new_state.file_resolver = FileResolverImp::new(
85 Arc::new(FileMap(self.fm.clone()))
86 );
87 self.db = self.db.with_changes(new_state, &[file_id], true);
88 file_id
89 }
90 fn remove_file(&mut self, file_id: FileId) {
91 self.fm.remove(&file_id);
92 let mut new_state = self.db.state().clone();
93 new_state.file_map.remove(&file_id);
94 new_state.file_resolver = FileResolverImp::new(
95 Arc::new(FileMap(self.fm.clone()))
96 );
97 self.db = self.db.with_changes(new_state, &[file_id], true);
98 }
99 fn change_file(&mut self, file_id: FileId, new_text: &str) {
100 let mut new_state = self.db.state().clone();
101 new_state.file_map.insert(file_id, Arc::new(new_text.to_string()));
102 self.db = self.db.with_changes(new_state, &[file_id], false);
103 }
104 fn check_parent_modules(
105 &self,
106 file_id: FileId,
107 expected: &[FileId],
108 queries: &[(&'static str, u64)]
109 ) {
110 let (tree, events) = self.db.trace_query(|ctx| module_tree(ctx));
111 let actual = tree.parent_modules(file_id)
112 .into_iter()
113 .map(|link| link.owner(&tree))
114 .collect::<Vec<_>>();
115 assert_eq!(actual.as_slice(), expected);
116 let mut counts = HashMap::new();
117 events.into_iter()
118 .for_each(|event| *counts.entry(event).or_insert(0) += 1);
119 for &(query_id, expected_count) in queries.iter() {
120 let actual_count = *counts.get(&query_id).unwrap_or(&0);
121 assert_eq!(
122 actual_count,
123 expected_count,
124 "counts for {} differ",
125 query_id,
126 )
127 }
128
129 }
130 }
131
132 #[test]
133 fn test_parent_module() {
134 let mut f = Fixture::new();
135 let foo = f.add_file("/foo.rs", "");
136 f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]);
137
138 let lib = f.add_file("/lib.rs", "mod foo;");
139 f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]);
140 f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 0)]);
141
142 f.change_file(lib, "");
143 f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]);
144
145 f.change_file(lib, "mod foo;");
146 f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]);
147
148 f.change_file(lib, "mod bar;");
149 f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]);
150 19
151 f.change_file(lib, "mod foo;"); 20fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc<ModuleDescriptor> {
152 f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]); 21 let file = db.file_syntax(file_id);
22 Arc::new(ModuleDescriptor::new(file.ast()))
23}
153 24
154 f.remove_file(lib); 25fn module_tree(db: &impl ModulesDatabase, (): ()) -> Arc<ModuleTreeDescriptor> {
155 f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 0)]); 26 let file_set = db.file_set(());
27 let mut files = Vec::new();
28 for &file_id in file_set.files.iter() {
29 let module_descr = db.module_descriptor(file_id);
30 files.push((file_id, module_descr));
156 } 31 }
32 let res = ModuleTreeDescriptor::new(files.iter().map(|(file_id, descr)| (*file_id, &**descr)), &file_set.resolver);
33 Arc::new(res)
157} 34}
diff --git a/crates/ra_analysis/src/queries.rs b/crates/ra_analysis/src/queries.rs
deleted file mode 100644
index 062a2f420..000000000
--- a/crates/ra_analysis/src/queries.rs
+++ /dev/null
@@ -1,39 +0,0 @@
1use std::sync::Arc;
2use ra_syntax::File;
3use ra_editor::LineIndex;
4use {
5 FileId,
6 db::{Query, QueryCtx, QueryRegistry},
7 symbol_index::SymbolIndex,
8};
9
10pub(crate) use db::{file_text, file_set};
11
12pub(crate) fn file_syntax(ctx: QueryCtx, file_id: FileId) -> File {
13 (&*ctx.get(FILE_SYNTAX, file_id)).clone()
14}
15pub(crate) fn file_lines(ctx: QueryCtx, file_id: FileId) -> Arc<LineIndex> {
16 ctx.get(FILE_LINES, file_id)
17}
18pub(crate) fn file_symbols(ctx: QueryCtx, file_id: FileId) -> Arc<SymbolIndex> {
19 ctx.get(FILE_SYMBOLS, file_id)
20}
21
22const FILE_SYNTAX: Query<FileId, File> = Query(16, |ctx, file_id: &FileId| {
23 let text = file_text(ctx, *file_id);
24 File::parse(&*text)
25});
26const FILE_LINES: Query<FileId, LineIndex> = Query(17, |ctx, file_id: &FileId| {
27 let text = file_text(ctx, *file_id);
28 LineIndex::new(&*text)
29});
30const FILE_SYMBOLS: Query<FileId, SymbolIndex> = Query(18, |ctx, file_id: &FileId| {
31 let syntax = file_syntax(ctx, *file_id);
32 SymbolIndex::for_file(*file_id, syntax)
33});
34
35pub(crate) fn register_queries(reg: &mut QueryRegistry) {
36 reg.add(FILE_SYNTAX, "FILE_SYNTAX");
37 reg.add(FILE_LINES, "FILE_LINES");
38 reg.add(FILE_SYMBOLS, "FILE_SYMBOLS");
39}
diff --git a/crates/ra_analysis/src/roots.rs b/crates/ra_analysis/src/roots.rs
index 32a8c5bd0..76bcecd38 100644
--- a/crates/ra_analysis/src/roots.rs
+++ b/crates/ra_analysis/src/roots.rs
@@ -5,16 +5,18 @@ use std::{
5 5
6use once_cell::sync::OnceCell; 6use once_cell::sync::OnceCell;
7use rayon::prelude::*; 7use rayon::prelude::*;
8use rustc_hash::FxHashMap; 8use salsa::Database;
9use rustc_hash::{FxHashMap, FxHashSet};
9use ra_editor::LineIndex; 10use ra_editor::LineIndex;
10use ra_syntax::File; 11use ra_syntax::File;
11 12
12use { 13use crate::{
13 FileId, 14 FileId,
14 imp::FileResolverImp, 15 imp::FileResolverImp,
15 symbol_index::SymbolIndex, 16 symbol_index::SymbolIndex,
16 descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, 17 descriptors::{ModuleDescriptor, ModuleTreeDescriptor},
17 db::Db, 18 db::{self, FilesDatabase, SyntaxDatabase},
19 module_map::ModulesDatabase,
18}; 20};
19 21
20pub(crate) trait SourceRoot { 22pub(crate) trait SourceRoot {
@@ -25,62 +27,68 @@ pub(crate) trait SourceRoot {
25 fn symbols(&self, acc: &mut Vec<Arc<SymbolIndex>>); 27 fn symbols(&self, acc: &mut Vec<Arc<SymbolIndex>>);
26} 28}
27 29
28#[derive(Default, Debug)] 30#[derive(Default, Debug, Clone)]
29pub(crate) struct WritableSourceRoot { 31pub(crate) struct WritableSourceRoot {
30 db: Db, 32 db: db::RootDatabase,
31} 33}
32 34
33impl WritableSourceRoot { 35impl WritableSourceRoot {
34 pub fn apply_changes( 36 pub fn apply_changes(
35 &self, 37 &mut self,
36 changes: &mut dyn Iterator<Item=(FileId, Option<String>)>, 38 changes: &mut dyn Iterator<Item=(FileId, Option<String>)>,
37 file_resolver: Option<FileResolverImp>, 39 file_resolver: Option<FileResolverImp>,
38 ) -> WritableSourceRoot { 40 ) {
39 let resolver_changed = file_resolver.is_some(); 41 let mut changed = FxHashSet::default();
40 let mut changed_files = Vec::new(); 42 let mut removed = FxHashSet::default();
41 let mut new_state = self.db.state().clone();
42
43 for (file_id, text) in changes { 43 for (file_id, text) in changes {
44 changed_files.push(file_id);
45 match text { 44 match text {
46 Some(text) => {
47 new_state.file_map.insert(file_id, Arc::new(text));
48 },
49 None => { 45 None => {
50 new_state.file_map.remove(&file_id); 46 removed.insert(file_id);
47 }
48 Some(text) => {
49 self.db.query(db::FileTextQuery)
50 .set(file_id, Arc::new(text));
51 changed.insert(file_id);
51 } 52 }
52 } 53 }
53 } 54 }
54 if let Some(file_resolver) = file_resolver { 55 let file_set = self.db.file_set(());
55 new_state.file_resolver = file_resolver 56 let mut files: FxHashSet<FileId> = file_set
56 } 57 .files
57 WritableSourceRoot { 58 .clone();
58 db: self.db.with_changes(new_state, &changed_files, resolver_changed) 59 for file_id in removed {
60 files.remove(&file_id);
59 } 61 }
62 files.extend(changed);
63 let resolver = file_resolver.unwrap_or_else(|| file_set.resolver.clone());
64 self.db.query(db::FileSetQuery)
65 .set((), Arc::new(db::FileSet { files, resolver }));
60 } 66 }
61} 67}
62 68
63impl SourceRoot for WritableSourceRoot { 69impl SourceRoot for WritableSourceRoot {
64 fn module_tree(&self) -> Arc<ModuleTreeDescriptor> { 70 fn module_tree(&self) -> Arc<ModuleTreeDescriptor> {
65 self.db.make_query(::module_map::module_tree) 71 self.db.module_tree(())
66 } 72 }
67
68 fn contains(&self, file_id: FileId) -> bool { 73 fn contains(&self, file_id: FileId) -> bool {
69 self.db.state().file_map.contains_key(&file_id) 74 self.db.file_set(())
75 .files
76 .contains(&file_id)
70 } 77 }
71 fn lines(&self, file_id: FileId) -> Arc<LineIndex> { 78 fn lines(&self, file_id: FileId) -> Arc<LineIndex> {
72 self.db.make_query(|ctx| ::queries::file_lines(ctx, file_id)) 79 self.db.file_lines(file_id)
73 } 80 }
74 fn syntax(&self, file_id: FileId) -> File { 81 fn syntax(&self, file_id: FileId) -> File {
75 self.db.make_query(|ctx| ::queries::file_syntax(ctx, file_id)) 82 self.db.file_syntax(file_id)
76 } 83 }
77 fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) { 84 fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) {
78 self.db.make_query(|ctx| { 85 let db = &self.db;
79 let file_set = ::queries::file_set(ctx); 86 let symbols = db.file_set(());
80 let syms = file_set.0.iter() 87 let symbols = symbols
81 .map(|file_id| ::queries::file_symbols(ctx, *file_id)); 88 .files
82 acc.extend(syms); 89 .iter()
83 }); 90 .map(|&file_id| db.file_symbols(file_id));
91 acc.extend(symbols);
84 } 92 }
85} 93}
86 94
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs
index ffbb6a29f..54672fde4 100644
--- a/crates/ra_analysis/src/symbol_index.rs
+++ b/crates/ra_analysis/src/symbol_index.rs
@@ -9,7 +9,7 @@ use ra_syntax::{
9}; 9};
10use fst::{self, Streamer}; 10use fst::{self, Streamer};
11use rayon::prelude::*; 11use rayon::prelude::*;
12use {Query, FileId, JobToken}; 12use crate::{Query, FileId, JobToken};
13 13
14#[derive(Debug)] 14#[derive(Debug)]
15pub(crate) struct SymbolIndex { 15pub(crate) struct SymbolIndex {
@@ -17,6 +17,15 @@ pub(crate) struct SymbolIndex {
17 map: fst::Map, 17 map: fst::Map,
18} 18}
19 19
20impl PartialEq for SymbolIndex {
21 fn eq(&self, other: &SymbolIndex) -> bool {
22 self.symbols == other.symbols
23 }
24}
25
26impl Eq for SymbolIndex {
27}
28
20impl Hash for SymbolIndex { 29impl Hash for SymbolIndex {
21 fn hash<H: Hasher>(&self, hasher: &mut H) { 30 fn hash<H: Hasher>(&self, hasher: &mut H) {
22 self.symbols.hash(hasher) 31 self.symbols.hash(hasher)
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index a886cd0ff..2d3679fa9 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -1,6 +1,8 @@
1extern crate relative_path; 1extern crate relative_path;
2extern crate ra_analysis; 2extern crate ra_analysis;
3extern crate rustc_hash; 3extern crate rustc_hash;
4extern crate ra_editor;
5extern crate ra_syntax;
4extern crate test_utils; 6extern crate test_utils;
5 7
6use std::{ 8use std::{
@@ -9,8 +11,8 @@ use std::{
9 11
10use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
11use relative_path::{RelativePath, RelativePathBuf}; 13use relative_path::{RelativePath, RelativePathBuf};
12use ra_analysis::{Analysis, AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId}; 14use ra_analysis::{Analysis, AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId, FnDescriptor};
13use test_utils::assert_eq_dbg; 15use test_utils::{assert_eq_dbg, extract_offset};
14 16
15#[derive(Debug)] 17#[derive(Debug)]
16struct FileMap(Vec<(FileId, RelativePathBuf)>); 18struct FileMap(Vec<(FileId, RelativePathBuf)>);
@@ -39,7 +41,7 @@ impl FileResolver for FileMap {
39 } 41 }
40} 42}
41 43
42fn analysis_host(files: &'static [(&'static str, &'static str)]) -> AnalysisHost { 44fn analysis_host(files: &[(&str, &str)]) -> AnalysisHost {
43 let mut host = AnalysisHost::new(); 45 let mut host = AnalysisHost::new();
44 let mut file_map = Vec::new(); 46 let mut file_map = Vec::new();
45 for (id, &(path, contents)) in files.iter().enumerate() { 47 for (id, &(path, contents)) in files.iter().enumerate() {
@@ -53,10 +55,20 @@ fn analysis_host(files: &'static [(&'static str, &'static str)]) -> AnalysisHost
53 host 55 host
54} 56}
55 57
56fn analysis(files: &'static [(&'static str, &'static str)]) -> Analysis { 58fn analysis(files: &[(&str, &str)]) -> Analysis {
57 analysis_host(files).analysis() 59 analysis_host(files).analysis()
58} 60}
59 61
62fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) {
63 let (offset, code) = extract_offset(text);
64 let code = code.as_str();
65
66 let (_handle, token) = JobHandle::new();
67 let snap = analysis(&[("/lib.rs", code)]);
68
69 snap.resolve_callable(FileId(1), offset, &token).unwrap()
70}
71
60#[test] 72#[test]
61fn test_resolve_module() { 73fn test_resolve_module() {
62 let snap = analysis(&[ 74 let snap = analysis(&[
@@ -145,3 +157,85 @@ fn test_resolve_crate_root() {
145 vec![CrateId(1)], 157 vec![CrateId(1)],
146 ); 158 );
147} 159}
160
161#[test]
162fn test_fn_signature_two_args_first() {
163 let (desc, param) = get_signature(
164r#"fn foo(x: u32, y: u32) -> u32 {x + y}
165fn bar() { foo(<|>3, ); }"#);
166
167 assert_eq!(desc.name, "foo".to_string());
168 assert_eq!(desc.params, vec!("x".to_string(),"y".to_string()));
169 assert_eq!(desc.ret_type, Some("-> u32".into()));
170 assert_eq!(param, Some(0));
171}
172
173#[test]
174fn test_fn_signature_two_args_second() {
175 let (desc, param) = get_signature(
176 r#"fn foo(x: u32, y: u32) -> u32 {x + y}
177fn bar() { foo(3, <|>); }"#);
178
179 assert_eq!(desc.name, "foo".to_string());
180 assert_eq!(desc.params, vec!("x".to_string(),"y".to_string()));
181 assert_eq!(desc.ret_type, Some("-> u32".into()));
182 assert_eq!(param, Some(1));
183}
184
185#[test]
186fn test_fn_signature_for_impl() {
187 let (desc, param) = get_signature(
188r#"struct F; impl F { pub fn new() { F{}} }
189fn bar() {let _ : F = F::new(<|>);}"#);
190
191 assert_eq!(desc.name, "new".to_string());
192 assert_eq!(desc.params, Vec::<String>::new());
193 assert_eq!(desc.ret_type, None);
194 assert_eq!(param, None);
195}
196
197#[test]
198fn test_fn_signature_for_method_self() {
199 let (desc, param) = get_signature(
200r#"struct F;
201impl F {
202 pub fn new() -> F{
203 F{}
204 }
205
206 pub fn do_it(&self) {}
207}
208
209fn bar() {
210 let f : F = F::new();
211 f.do_it(<|>);
212}"#);
213
214 assert_eq!(desc.name, "do_it".to_string());
215 assert_eq!(desc.params, vec!["&self".to_string()]);
216 assert_eq!(desc.ret_type, None);
217 assert_eq!(param, None);
218}
219
220#[test]
221fn test_fn_signature_for_method_with_arg() {
222 let (desc, param) = get_signature(
223r#"struct F;
224impl F {
225 pub fn new() -> F{
226 F{}
227 }
228
229 pub fn do_it(&self, x: i32) {}
230}
231
232fn bar() {
233 let f : F = F::new();
234 f.do_it(<|>);
235}"#);
236
237 assert_eq!(desc.name, "do_it".to_string());
238 assert_eq!(desc.params, vec!["&self".to_string(), "x".to_string()]);
239 assert_eq!(desc.ret_type, None);
240 assert_eq!(param, Some(1));
241}
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index 5e7bf3ed4..0b8d6f3dd 100644
--- a/crates/ra_cli/Cargo.toml
+++ b/crates/ra_cli/Cargo.toml
@@ -1,4 +1,5 @@
1[package] 1[package]
2edition = "2018"
2name = "ra_cli" 3name = "ra_cli"
3version = "0.1.0" 4version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"] 5authors = ["Aleksey Kladov <[email protected]>"]
diff --git a/crates/ra_editor/Cargo.toml b/crates/ra_editor/Cargo.toml
index 91cefc8d7..7791da156 100644
--- a/crates/ra_editor/Cargo.toml
+++ b/crates/ra_editor/Cargo.toml
@@ -1,4 +1,5 @@
1[package] 1[package]
2edition = "2018"
2name = "ra_editor" 3name = "ra_editor"
3version = "0.1.0" 4version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"] 5authors = ["Aleksey Kladov <[email protected]>"]
diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs
index 216d592ff..7b0a48c81 100644
--- a/crates/ra_editor/src/code_actions.rs
+++ b/crates/ra_editor/src/code_actions.rs
@@ -11,7 +11,7 @@ use ra_syntax::{
11 }, 11 },
12}; 12};
13 13
14use {EditBuilder, Edit, find_node_at_offset}; 14use crate::{EditBuilder, Edit, find_node_at_offset};
15 15
16#[derive(Debug)] 16#[derive(Debug)]
17pub struct LocalEdit { 17pub struct LocalEdit {
@@ -136,7 +136,7 @@ fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<Synta
136#[cfg(test)] 136#[cfg(test)]
137mod tests { 137mod tests {
138 use super::*; 138 use super::*;
139 use test_utils::{check_action, check_action_range}; 139 use crate::test_utils::{check_action, check_action_range};
140 140
141 #[test] 141 #[test]
142 fn test_swap_comma() { 142 fn test_swap_comma() {
diff --git a/crates/ra_editor/src/completion.rs b/crates/ra_editor/src/completion.rs
index 20b8484b3..b6095dca9 100644
--- a/crates/ra_editor/src/completion.rs
+++ b/crates/ra_editor/src/completion.rs
@@ -9,7 +9,7 @@ use ra_syntax::{
9 text_utils::is_subrange, 9 text_utils::is_subrange,
10}; 10};
11 11
12use { 12use crate::{
13 AtomEdit, find_node_at_offset, 13 AtomEdit, find_node_at_offset,
14 scope::{FnScopes, ModuleScope}, 14 scope::{FnScopes, ModuleScope},
15}; 15};
diff --git a/crates/ra_editor/src/edit.rs b/crates/ra_editor/src/edit.rs
index 2839ac20a..46e687319 100644
--- a/crates/ra_editor/src/edit.rs
+++ b/crates/ra_editor/src/edit.rs
@@ -1,4 +1,4 @@
1use {TextRange, TextUnit}; 1use crate::{TextRange, TextUnit};
2use ra_syntax::{ 2use ra_syntax::{
3 AtomEdit, 3 AtomEdit,
4 text_utils::contains_offset_nonstrict, 4 text_utils::contains_offset_nonstrict,
diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs
index 3aabd54ae..a1699d449 100644
--- a/crates/ra_editor/src/folding_ranges.rs
+++ b/crates/ra_editor/src/folding_ranges.rs
@@ -1,8 +1,10 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast,
5 AstNode,
4 File, TextRange, SyntaxNodeRef, 6 File, TextRange, SyntaxNodeRef,
5 SyntaxKind, 7 SyntaxKind::{self, *},
6 Direction, 8 Direction,
7}; 9};
8 10
@@ -20,67 +22,97 @@ pub struct Fold {
20 22
21pub fn folding_ranges(file: &File) -> Vec<Fold> { 23pub fn folding_ranges(file: &File) -> Vec<Fold> {
22 let mut res = vec![]; 24 let mut res = vec![];
23 let mut visited = FxHashSet::default(); 25 let mut visited_comments = FxHashSet::default();
24 26
25 for node in file.syntax().descendants() { 27 for node in file.syntax().descendants() {
26 if visited.contains(&node) { 28 // Fold items that span multiple lines
29 if let Some(kind) = fold_kind(node.kind()) {
30 if has_newline(node) {
31 res.push(Fold { range: node.range(), kind });
32 }
33 }
34
35 // Also fold groups of comments
36 if visited_comments.contains(&node) {
27 continue; 37 continue;
28 } 38 }
39 if node.kind() == COMMENT {
40 contiguous_range_for_comment(node, &mut visited_comments)
41 .map(|range| res.push(Fold { range, kind: FoldKind::Comment }));
42 }
43 }
44
45 res
46}
29 47
30 let range_and_kind = match node.kind() { 48fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
31 SyntaxKind::COMMENT => ( 49 match kind {
32 contiguous_range_for(SyntaxKind::COMMENT, node, &mut visited), 50 COMMENT => Some(FoldKind::Comment),
33 Some(FoldKind::Comment), 51 USE_ITEM => Some(FoldKind::Imports),
34 ), 52 _ => None
35 SyntaxKind::USE_ITEM => ( 53 }
36 contiguous_range_for(SyntaxKind::USE_ITEM, node, &mut visited), 54}
37 Some(FoldKind::Imports), 55
38 ), 56fn has_newline(
39 _ => (None, None), 57 node: SyntaxNodeRef,
40 }; 58) -> bool {
41 59 for descendant in node.descendants() {
42 match range_and_kind { 60 if let Some(ws) = ast::Whitespace::cast(descendant) {
43 (Some(range), Some(kind)) => { 61 if ws.has_newlines() {
44 res.push(Fold { 62 return true;
45 range: range, 63 }
46 kind: kind 64 } else if let Some(comment) = ast::Comment::cast(descendant) {
47 }); 65 if comment.has_newlines() {
66 return true;
48 } 67 }
49 _ => {}
50 } 68 }
51 } 69 }
52 70
53 res 71 false
54} 72}
55 73
56fn contiguous_range_for<'a>( 74fn contiguous_range_for_comment<'a>(
57 kind: SyntaxKind, 75 first: SyntaxNodeRef<'a>,
58 node: SyntaxNodeRef<'a>,
59 visited: &mut FxHashSet<SyntaxNodeRef<'a>>, 76 visited: &mut FxHashSet<SyntaxNodeRef<'a>>,
60) -> Option<TextRange> { 77) -> Option<TextRange> {
61 visited.insert(node); 78 visited.insert(first);
62 79
63 let left = node; 80 // Only fold comments of the same flavor
64 let mut right = node; 81 let group_flavor = ast::Comment::cast(first)?.flavor();
65 for node in node.siblings(Direction::Next) { 82
66 visited.insert(node); 83 let mut last = first;
67 match node.kind() { 84 for node in first.siblings(Direction::Next) {
68 SyntaxKind::WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), 85 if let Some(ws) = ast::Whitespace::cast(node) {
69 k => { 86 // There is a blank line, which means the group ends here
70 if k == kind { 87 if ws.count_newlines_lazy().take(2).count() == 2 {
71 right = node 88 break;
72 } else { 89 }
73 break; 90
74 } 91 // Ignore whitespace without blank lines
92 continue;
93 }
94
95 match ast::Comment::cast(node) {
96 Some(next_comment) if next_comment.flavor() == group_flavor => {
97 visited.insert(node);
98 last = node;
99 }
100 // The comment group ends because either:
101 // * An element of a different kind was reached
102 // * A comment of a different flavor was reached
103 _ => {
104 break
75 } 105 }
76 } 106 }
77 } 107 }
78 if left != right { 108
109 if first != last {
79 Some(TextRange::from_to( 110 Some(TextRange::from_to(
80 left.range().start(), 111 first.range().start(),
81 right.range().end(), 112 last.range().end(),
82 )) 113 ))
83 } else { 114 } else {
115 // The group consists of only one element, therefore it cannot be folded
84 None 116 None
85 } 117 }
86} 118}
@@ -88,52 +120,65 @@ fn contiguous_range_for<'a>(
88#[cfg(test)] 120#[cfg(test)]
89mod tests { 121mod tests {
90 use super::*; 122 use super::*;
123 use test_utils::extract_ranges;
124
125 fn do_check(text: &str, fold_kinds: &[FoldKind]) {
126 let (ranges, text) = extract_ranges(text);
127 let file = File::parse(&text);
128 let folds = folding_ranges(&file);
129
130 assert_eq!(folds.len(), ranges.len());
131 for ((fold, range), fold_kind) in folds.into_iter().zip(ranges.into_iter()).zip(fold_kinds.into_iter()) {
132 assert_eq!(fold.range.start(), range.start());
133 assert_eq!(fold.range.end(), range.end());
134 assert_eq!(&fold.kind, fold_kind);
135 }
136 }
91 137
92 #[test] 138 #[test]
93 fn test_fold_comments() { 139 fn test_fold_comments() {
94 let text = r#" 140 let text = r#"
95// Hello 141<|>// Hello
96// this is a multiline 142// this is a multiline
97// comment 143// comment
98// 144//<|>
99 145
100// But this is not 146// But this is not
101 147
102fn main() { 148fn main() {
103 // We should 149 <|>// We should
104 // also 150 // also
105 // fold 151 // fold
106 // this one. 152 // this one.<|>
153 <|>//! But this one is different
154 //! because it has another flavor<|>
155 <|>/* As does this
156 multiline comment */<|>
107}"#; 157}"#;
108 158
109 let file = File::parse(&text); 159 let fold_kinds = &[
110 let folds = folding_ranges(&file); 160 FoldKind::Comment,
111 assert_eq!(folds.len(), 2); 161 FoldKind::Comment,
112 assert_eq!(folds[0].range.start(), 1.into()); 162 FoldKind::Comment,
113 assert_eq!(folds[0].range.end(), 46.into()); 163 FoldKind::Comment,
114 assert_eq!(folds[0].kind, FoldKind::Comment); 164 ];
115 165 do_check(text, fold_kinds);
116 assert_eq!(folds[1].range.start(), 84.into());
117 assert_eq!(folds[1].range.end(), 137.into());
118 assert_eq!(folds[1].kind, FoldKind::Comment);
119 } 166 }
120 167
121 #[test] 168 #[test]
122 fn test_fold_imports() { 169 fn test_fold_imports() {
123 let text = r#" 170 let text = r#"
124use std::str; 171<|>use std::{
125use std::vec; 172 str,
126use std::io as iop; 173 vec,
174 io as iop
175};<|>
127 176
128fn main() { 177fn main() {
129}"#; 178}"#;
130 179
131 let file = File::parse(&text); 180 let folds = &[FoldKind::Imports];
132 let folds = folding_ranges(&file); 181 do_check(text, folds);
133 assert_eq!(folds.len(), 1);
134 assert_eq!(folds[0].range.start(), 1.into());
135 assert_eq!(folds[0].range.end(), 48.into());
136 assert_eq!(folds[0].kind, FoldKind::Imports);
137 } 182 }
138 183
139 184
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index 710afc65d..bd61fd191 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -164,7 +164,7 @@ pub fn resolve_local_name(file: &File, offset: TextUnit, name_ref: ast::NameRef)
164#[cfg(test)] 164#[cfg(test)]
165mod tests { 165mod tests {
166 use super::*; 166 use super::*;
167 use test_utils::{assert_eq_dbg, extract_offset, add_cursor}; 167 use crate::test_utils::{assert_eq_dbg, extract_offset, add_cursor};
168 168
169 #[test] 169 #[test]
170 fn test_highlighting() { 170 fn test_highlighting() {
diff --git a/crates/ra_editor/src/line_index.rs b/crates/ra_editor/src/line_index.rs
index 9cd8da3a8..95d64b8a8 100644
--- a/crates/ra_editor/src/line_index.rs
+++ b/crates/ra_editor/src/line_index.rs
@@ -1,7 +1,7 @@
1use superslice::Ext; 1use superslice::Ext;
2use ::TextUnit; 2use crate::TextUnit;
3 3
4#[derive(Clone, Debug, Hash)] 4#[derive(Clone, Debug, Hash, PartialEq, Eq)]
5pub struct LineIndex { 5pub struct LineIndex {
6 newlines: Vec<TextUnit>, 6 newlines: Vec<TextUnit>,
7} 7}
diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs
index 9a48bda02..99d698b60 100644
--- a/crates/ra_editor/src/scope/fn_scope.rs
+++ b/crates/ra_editor/src/scope/fn_scope.rs
@@ -174,7 +174,7 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
174 } 174 }
175 } 175 }
176 ast::Expr::LambdaExpr(e) => { 176 ast::Expr::LambdaExpr(e) => {
177 let mut scope = scopes.new_scope(scope); 177 let scope = scopes.new_scope(scope);
178 scopes.add_params_bindings(scope, e.param_list()); 178 scopes.add_params_bindings(scope, e.param_list());
179 if let Some(body) = e.body() { 179 if let Some(body) = e.body() {
180 scopes.set_scope(body.syntax(), scope); 180 scopes.set_scope(body.syntax(), scope);
@@ -256,7 +256,7 @@ pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> O
256mod tests { 256mod tests {
257 use super::*; 257 use super::*;
258 use ra_syntax::File; 258 use ra_syntax::File;
259 use {find_node_at_offset, test_utils::extract_offset}; 259 use crate::{find_node_at_offset, test_utils::extract_offset};
260 260
261 fn do_check(code: &str, expected: &[&str]) { 261 fn do_check(code: &str, expected: &[&str]) {
262 let (off, code) = extract_offset(code); 262 let (off, code) = extract_offset(code);
diff --git a/crates/ra_editor/src/symbols.rs b/crates/ra_editor/src/symbols.rs
index e5cc5ca28..d9e4b2df7 100644
--- a/crates/ra_editor/src/symbols.rs
+++ b/crates/ra_editor/src/symbols.rs
@@ -6,7 +6,7 @@ use ra_syntax::{
6 walk::{walk, WalkEvent}, 6 walk::{walk, WalkEvent},
7 }, 7 },
8}; 8};
9use TextRange; 9use crate::TextRange;
10 10
11#[derive(Debug, Clone)] 11#[derive(Debug, Clone)]
12pub struct StructureNode { 12pub struct StructureNode {
@@ -17,7 +17,7 @@ pub struct StructureNode {
17 pub kind: SyntaxKind, 17 pub kind: SyntaxKind,
18} 18}
19 19
20#[derive(Debug, Clone, Hash)] 20#[derive(Debug, Clone, PartialEq, Eq, Hash)]
21pub struct FileSymbol { 21pub struct FileSymbol {
22 pub name: SmolStr, 22 pub name: SmolStr,
23 pub node_range: TextRange, 23 pub node_range: TextRange,
diff --git a/crates/ra_editor/src/test_utils.rs b/crates/ra_editor/src/test_utils.rs
index c4ea4db6c..49eb530d5 100644
--- a/crates/ra_editor/src/test_utils.rs
+++ b/crates/ra_editor/src/test_utils.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{File, TextUnit, TextRange}; 1use ra_syntax::{File, TextUnit, TextRange};
2pub use _test_utils::*; 2pub use crate::_test_utils::*;
3use LocalEdit; 3use crate::LocalEdit;
4 4
5pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>> ( 5pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>> (
6 before: &str, 6 before: &str,
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs
index 1dc658f9b..542b9e10b 100644
--- a/crates/ra_editor/src/typing.rs
+++ b/crates/ra_editor/src/typing.rs
@@ -10,7 +10,7 @@ use ra_syntax::{
10 SyntaxKind::*, 10 SyntaxKind::*,
11}; 11};
12 12
13use {LocalEdit, EditBuilder, find_node_at_offset}; 13use crate::{LocalEdit, EditBuilder, find_node_at_offset};
14 14
15pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { 15pub fn join_lines(file: &File, range: TextRange) -> LocalEdit {
16 let range = if range.is_empty() { 16 let range = if range.is_empty() {
@@ -244,7 +244,7 @@ fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str {
244#[cfg(test)] 244#[cfg(test)]
245mod tests { 245mod tests {
246 use super::*; 246 use super::*;
247 use test_utils::{check_action, extract_range, extract_offset, add_cursor}; 247 use crate::test_utils::{check_action, extract_range, extract_offset, add_cursor};
248 248
249 fn check_join_lines(before: &str, after: &str) { 249 fn check_join_lines(before: &str, after: &str) {
250 check_action(before, after, |file, offset| { 250 check_action(before, after, |file, offset| {
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index 1fe6b2ebe..2b3257117 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -1,4 +1,5 @@
1[package] 1[package]
2edition = "2018"
2name = "ra_lsp_server" 3name = "ra_lsp_server"
3version = "0.1.0" 4version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"] 5authors = ["Aleksey Kladov <[email protected]>"]
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index 3c628f29c..5598ec75f 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -7,6 +7,7 @@ use languageserver_types::{
7 TextDocumentSyncKind, 7 TextDocumentSyncKind,
8 ExecuteCommandOptions, 8 ExecuteCommandOptions,
9 CompletionOptions, 9 CompletionOptions,
10 SignatureHelpOptions,
10 DocumentOnTypeFormattingOptions, 11 DocumentOnTypeFormattingOptions,
11}; 12};
12 13
@@ -26,7 +27,9 @@ pub fn server_capabilities() -> ServerCapabilities {
26 resolve_provider: None, 27 resolve_provider: None,
27 trigger_characters: None, 28 trigger_characters: None,
28 }), 29 }),
29 signature_help_provider: None, 30 signature_help_provider: Some(SignatureHelpOptions {
31 trigger_characters: Some(vec!["(".to_string(), ",".to_string()])
32 }),
30 definition_provider: Some(true), 33 definition_provider: Some(true),
31 type_definition_provider: None, 34 type_definition_provider: None,
32 implementation_provider: None, 35 implementation_provider: None,
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 08a656569..a75b160c5 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -7,7 +7,7 @@ use ra_editor::{LineIndex, LineCol, Edit, AtomEdit};
7use ra_syntax::{SyntaxKind, TextUnit, TextRange}; 7use ra_syntax::{SyntaxKind, TextUnit, TextRange};
8use ra_analysis::{FileId, SourceChange, SourceFileEdit, FileSystemEdit}; 8use ra_analysis::{FileId, SourceChange, SourceFileEdit, FileSystemEdit};
9 9
10use { 10use crate::{
11 Result, 11 Result,
12 server_world::ServerWorld, 12 server_world::ServerWorld,
13 req, 13 req,
@@ -299,7 +299,7 @@ pub fn to_location(
299 Ok(loc) 299 Ok(loc)
300} 300}
301 301
302pub trait MapConvWith<'a>: Sized { 302pub trait MapConvWith<'a>: Sized + 'a {
303 type Ctx; 303 type Ctx;
304 type Output; 304 type Output;
305 305
@@ -309,7 +309,7 @@ pub trait MapConvWith<'a>: Sized {
309} 309}
310 310
311impl<'a, I> MapConvWith<'a> for I 311impl<'a, I> MapConvWith<'a> for I
312 where I: Iterator, 312 where I: Iterator + 'a,
313 I::Item: ConvWith 313 I::Item: ConvWith
314{ 314{
315 type Ctx = <I::Item as ConvWith>::Ctx; 315 type Ctx = <I::Item as ConvWith>::Ctx;
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs
index 60652d55e..7224b1476 100644
--- a/crates/ra_lsp_server/src/lib.rs
+++ b/crates/ra_lsp_server/src/lib.rs
@@ -34,5 +34,7 @@ mod project_model;
34pub mod thread_watcher; 34pub mod thread_watcher;
35 35
36pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 36pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
37pub use caps::server_capabilities; 37pub use crate::{
38pub use main_loop::main_loop; 38 main_loop::main_loop,
39 caps::server_capabilities,
40};
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index ab8be15e9..5acb39b60 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -13,7 +13,7 @@ use ra_syntax::{
13 text_utils::contains_offset_nonstrict 13 text_utils::contains_offset_nonstrict
14}; 14};
15 15
16use ::{ 16use crate::{
17 req::{self, Decoration}, Result, 17 req::{self, Decoration}, Result,
18 conv::{Conv, ConvWith, TryConvWith, MapConvWith, to_location}, 18 conv::{Conv, ConvWith, TryConvWith, MapConvWith, to_location},
19 server_world::ServerWorld, 19 server_world::ServerWorld,
@@ -411,6 +411,42 @@ pub fn handle_folding_range(
411 Ok(res) 411 Ok(res)
412} 412}
413 413
414pub fn handle_signature_help(
415 world: ServerWorld,
416 params: req::TextDocumentPositionParams,
417 token: JobToken,
418) -> Result<Option<req::SignatureHelp>> {
419 use languageserver_types::{ParameterInformation, SignatureInformation};
420
421 let file_id = params.text_document.try_conv_with(&world)?;
422 let line_index = world.analysis().file_line_index(file_id);
423 let offset = params.position.conv_with(&line_index);
424
425 if let Some((descriptor, active_param)) = world.analysis().resolve_callable(file_id, offset, &token) {
426 let parameters : Vec<ParameterInformation> =
427 descriptor.params.iter().map(|param|
428 ParameterInformation {
429 label: param.clone(),
430 documentation: None
431 }
432 ).collect();
433
434 let sig_info = SignatureInformation {
435 label: descriptor.label,
436 documentation: None,
437 parameters: Some(parameters)
438 };
439
440 Ok(Some(req::SignatureHelp {
441 signatures: vec![sig_info],
442 active_signature: Some(0),
443 active_parameter: active_param.map(|a| a as u64)
444 }))
445 } else {
446 Ok(None)
447 }
448}
449
414pub fn handle_code_action( 450pub fn handle_code_action(
415 world: ServerWorld, 451 world: ServerWorld,
416 params: req::CodeActionParams, 452 params: req::CodeActionParams,
@@ -442,7 +478,7 @@ pub fn handle_code_action(
442} 478}
443 479
444pub fn publish_diagnostics( 480pub fn publish_diagnostics(
445 world: ServerWorld, 481 world: &ServerWorld,
446 file_id: FileId, 482 file_id: FileId,
447) -> Result<req::PublishDiagnosticsParams> { 483) -> Result<req::PublishDiagnosticsParams> {
448 let uri = world.file_id_to_uri(file_id)?; 484 let uri = world.file_id_to_uri(file_id)?;
@@ -461,7 +497,7 @@ pub fn publish_diagnostics(
461} 497}
462 498
463pub fn publish_decorations( 499pub fn publish_decorations(
464 world: ServerWorld, 500 world: &ServerWorld,
465 file_id: FileId, 501 file_id: FileId,
466) -> Result<req::PublishDecorationsParams> { 502) -> Result<req::PublishDecorationsParams> {
467 let uri = world.file_id_to_uri(file_id)?; 503 let uri = world.file_id_to_uri(file_id)?;
diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop/mod.rs
index 402615e42..cf2477cb5 100644
--- a/crates/ra_lsp_server/src/main_loop/mod.rs
+++ b/crates/ra_lsp_server/src/main_loop/mod.rs
@@ -16,7 +16,7 @@ use gen_lsp_server::{
16}; 16};
17use rustc_hash::FxHashMap; 17use rustc_hash::FxHashMap;
18 18
19use { 19use crate::{
20 req, 20 req,
21 Result, 21 Result,
22 vfs::{self, FileEvent}, 22 vfs::{self, FileEvent},
@@ -255,6 +255,7 @@ fn on_request(
255 .on::<req::Completion>(handlers::handle_completion)? 255 .on::<req::Completion>(handlers::handle_completion)?
256 .on::<req::CodeActionRequest>(handlers::handle_code_action)? 256 .on::<req::CodeActionRequest>(handlers::handle_code_action)?
257 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)? 257 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
258 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)?
258 .finish(); 259 .finish();
259 match req { 260 match req {
260 Ok((id, handle)) => { 261 Ok((id, handle)) => {
@@ -390,7 +391,7 @@ fn update_file_notifications_on_threadpool(
390) { 391) {
391 pool.spawn(move || { 392 pool.spawn(move || {
392 for file_id in subscriptions { 393 for file_id in subscriptions {
393 match handlers::publish_diagnostics(world.clone(), file_id) { 394 match handlers::publish_diagnostics(&world, file_id) {
394 Err(e) => { 395 Err(e) => {
395 error!("failed to compute diagnostics: {:?}", e) 396 error!("failed to compute diagnostics: {:?}", e)
396 } 397 }
@@ -399,7 +400,7 @@ fn update_file_notifications_on_threadpool(
399 sender.send(Task::Notify(not)); 400 sender.send(Task::Notify(not));
400 } 401 }
401 } 402 }
402 match handlers::publish_decorations(world.clone(), file_id) { 403 match handlers::publish_decorations(&world, file_id) {
403 Err(e) => { 404 Err(e) => {
404 error!("failed to compute decorations: {:?}", e) 405 error!("failed to compute decorations: {:?}", e)
405 } 406 }
diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs
index 43e4fd654..c144d9596 100644
--- a/crates/ra_lsp_server/src/project_model.rs
+++ b/crates/ra_lsp_server/src/project_model.rs
@@ -5,7 +5,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
5use cargo_metadata::{metadata_run, CargoOpt}; 5use cargo_metadata::{metadata_run, CargoOpt};
6use ra_syntax::SmolStr; 6use ra_syntax::SmolStr;
7 7
8use { 8use crate::{
9 Result, 9 Result,
10 thread_watcher::{Worker, ThreadWatcher}, 10 thread_watcher::{Worker, ThreadWatcher},
11}; 11};
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index f80957589..1630edf7f 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -14,6 +14,7 @@ pub use languageserver_types::{
14 CompletionParams, CompletionResponse, 14 CompletionParams, CompletionResponse,
15 DocumentOnTypeFormattingParams, 15 DocumentOnTypeFormattingParams,
16 TextDocumentEdit, 16 TextDocumentEdit,
17 SignatureHelp, Hover
17}; 18};
18 19
19pub enum SyntaxTree {} 20pub enum SyntaxTree {}
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs
index c4cdf83d4..9b3013ae8 100644
--- a/crates/ra_lsp_server/src/server_world.rs
+++ b/crates/ra_lsp_server/src/server_world.rs
@@ -8,7 +8,7 @@ use rustc_hash::FxHashMap;
8use languageserver_types::Url; 8use languageserver_types::Url;
9use ra_analysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId, LibraryData, FileResolver}; 9use ra_analysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId, LibraryData, FileResolver};
10 10
11use { 11use crate::{
12 Result, 12 Result,
13 path_map::{PathMap, Root}, 13 path_map::{PathMap, Root},
14 vfs::{FileEvent, FileEventKind}, 14 vfs::{FileEvent, FileEventKind},
@@ -23,7 +23,6 @@ pub struct ServerWorldState {
23 pub mem_map: FxHashMap<FileId, Option<String>>, 23 pub mem_map: FxHashMap<FileId, Option<String>>,
24} 24}
25 25
26#[derive(Clone)]
27pub struct ServerWorld { 26pub struct ServerWorld {
28 pub workspaces: Arc<Vec<CargoWorkspace>>, 27 pub workspaces: Arc<Vec<CargoWorkspace>>,
29 pub analysis: Analysis, 28 pub analysis: Analysis,
diff --git a/crates/ra_lsp_server/src/thread_watcher.rs b/crates/ra_lsp_server/src/thread_watcher.rs
index 86a3a91e0..3257effcb 100644
--- a/crates/ra_lsp_server/src/thread_watcher.rs
+++ b/crates/ra_lsp_server/src/thread_watcher.rs
@@ -1,7 +1,7 @@
1use std::thread; 1use std::thread;
2use crossbeam_channel::{bounded, unbounded, Sender, Receiver}; 2use crossbeam_channel::{bounded, unbounded, Sender, Receiver};
3use drop_bomb::DropBomb; 3use drop_bomb::DropBomb;
4use Result; 4use crate::Result;
5 5
6pub struct Worker<I, O> { 6pub struct Worker<I, O> {
7 pub inp: Sender<I>, 7 pub inp: Sender<I>,
diff --git a/crates/ra_lsp_server/src/vfs.rs b/crates/ra_lsp_server/src/vfs.rs
index a1c1783f2..d8f9b1aac 100644
--- a/crates/ra_lsp_server/src/vfs.rs
+++ b/crates/ra_lsp_server/src/vfs.rs
@@ -5,7 +5,7 @@ use std::{
5 5
6use walkdir::WalkDir; 6use walkdir::WalkDir;
7 7
8use { 8use crate::{
9 thread_watcher::{Worker, ThreadWatcher}, 9 thread_watcher::{Worker, ThreadWatcher},
10}; 10};
11 11
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index dced45f55..7265b5999 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/main.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs
@@ -12,7 +12,7 @@ mod support;
12 12
13use ra_lsp_server::req::{Runnables, RunnablesParams}; 13use ra_lsp_server::req::{Runnables, RunnablesParams};
14 14
15use support::project; 15use crate::support::project;
16 16
17 17
18const LOG: &'static str = ""; 18const LOG: &'static str = "";
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs
index 8fe2aa816..d1339f62f 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/support.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs
@@ -25,7 +25,7 @@ use ra_lsp_server::{main_loop, req, thread_watcher::{ThreadWatcher, Worker}};
25 25
26pub fn project(fixture: &str) -> Server { 26pub fn project(fixture: &str) -> Server {
27 static INIT: Once = Once::new(); 27 static INIT: Once = Once::new();
28 INIT.call_once(|| Logger::with_env_or_str(::LOG).start().unwrap()); 28 INIT.call_once(|| Logger::with_env_or_str(crate::LOG).start().unwrap());
29 29
30 let tmp_dir = TempDir::new("test-project") 30 let tmp_dir = TempDir::new("test-project")
31 .unwrap(); 31 .unwrap();
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 6345e4725..34bb1c591 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -1,4 +1,5 @@
1[package] 1[package]
2edition = "2018"
2name = "ra_syntax" 3name = "ra_syntax"
3version = "0.1.0" 4version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"] 5authors = ["Aleksey Kladov <[email protected]>"]
diff --git a/crates/ra_syntax/src/algo/mod.rs b/crates/ra_syntax/src/algo/mod.rs
index a6678093d..e686a5704 100644
--- a/crates/ra_syntax/src/algo/mod.rs
+++ b/crates/ra_syntax/src/algo/mod.rs
@@ -1,7 +1,7 @@
1pub mod walk; 1pub mod walk;
2pub mod visit; 2pub mod visit;
3 3
4use { 4use crate::{
5 SyntaxNodeRef, TextUnit, TextRange, 5 SyntaxNodeRef, TextUnit, TextRange,
6 text_utils::{contains_offset_nonstrict, is_subrange}, 6 text_utils::{contains_offset_nonstrict, is_subrange},
7}; 7};
diff --git a/crates/ra_syntax/src/algo/visit.rs b/crates/ra_syntax/src/algo/visit.rs
index 9f1c127c7..1ae988a87 100644
--- a/crates/ra_syntax/src/algo/visit.rs
+++ b/crates/ra_syntax/src/algo/visit.rs
@@ -1,5 +1,5 @@
1use std::marker::PhantomData; 1use std::marker::PhantomData;
2use {SyntaxNodeRef, AstNode}; 2use crate::{SyntaxNodeRef, AstNode};
3 3
4 4
5pub fn visitor<'a, T>() -> impl Visitor<'a, Output=T> { 5pub fn visitor<'a, T>() -> impl Visitor<'a, Output=T> {
diff --git a/crates/ra_syntax/src/algo/walk.rs b/crates/ra_syntax/src/algo/walk.rs
index 8e294d965..d34415626 100644
--- a/crates/ra_syntax/src/algo/walk.rs
+++ b/crates/ra_syntax/src/algo/walk.rs
@@ -1,4 +1,4 @@
1use { 1use crate::{
2 SyntaxNodeRef, 2 SyntaxNodeRef,
3 algo::generate, 3 algo::generate,
4}; 4};
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index ef7b5b1a1..160d186b8 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1,7 +1,7 @@
1// This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run 1// This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run
2// Do not edit manually 2// Do not edit manually
3 3
4use { 4use crate::{
5 ast, 5 ast,
6 SyntaxNodeRef, AstNode, 6 SyntaxNodeRef, AstNode,
7 SyntaxKind::*, 7 SyntaxKind::*,
@@ -1387,7 +1387,11 @@ impl<'a> AstNode<'a> for PathExpr<'a> {
1387 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } 1387 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
1388} 1388}
1389 1389
1390impl<'a> PathExpr<'a> {} 1390impl<'a> PathExpr<'a> {
1391 pub fn path(self) -> Option<Path<'a>> {
1392 super::child_opt(self)
1393 }
1394}
1391 1395
1392// PathPat 1396// PathPat
1393#[derive(Debug, Clone, Copy)] 1397#[derive(Debug, Clone, Copy)]
@@ -2193,3 +2197,21 @@ impl<'a> WhileExpr<'a> {
2193 } 2197 }
2194} 2198}
2195 2199
2200// Whitespace
2201#[derive(Debug, Clone, Copy)]
2202pub struct Whitespace<'a> {
2203 syntax: SyntaxNodeRef<'a>,
2204}
2205
2206impl<'a> AstNode<'a> for Whitespace<'a> {
2207 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
2208 match syntax.kind() {
2209 WHITESPACE => Some(Whitespace { syntax }),
2210 _ => None,
2211 }
2212 }
2213 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
2214}
2215
2216impl<'a> Whitespace<'a> {}
2217
diff --git a/crates/ra_syntax/src/ast/generated.rs.tera b/crates/ra_syntax/src/ast/generated.rs.tera
index ffa9c4134..5cb7a35ed 100644
--- a/crates/ra_syntax/src/ast/generated.rs.tera
+++ b/crates/ra_syntax/src/ast/generated.rs.tera
@@ -3,7 +3,7 @@ the below applies to the result of this template
3#}// This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run 3#}// This file is automatically generated based on the file `./generated.rs.tera` when `cargo gen-kinds` is run
4// Do not edit manually 4// Do not edit manually
5 5
6use { 6use crate::{
7 ast, 7 ast,
8 SyntaxNodeRef, AstNode, 8 SyntaxNodeRef, AstNode,
9 SyntaxKind::*, 9 SyntaxKind::*,
diff --git a/crates/ra_syntax/src/ast/mod.rs b/crates/ra_syntax/src/ast/mod.rs
index 10dac72e5..88193a1ed 100644
--- a/crates/ra_syntax/src/ast/mod.rs
+++ b/crates/ra_syntax/src/ast/mod.rs
@@ -4,7 +4,7 @@ use std::marker::PhantomData;
4 4
5use itertools::Itertools; 5use itertools::Itertools;
6 6
7use { 7use crate::{
8 SmolStr, SyntaxNodeRef, SyntaxKind::*, 8 SmolStr, SyntaxNodeRef, SyntaxKind::*,
9 yellow::{RefRoot, SyntaxNodeChildren}, 9 yellow::{RefRoot, SyntaxNodeChildren},
10}; 10};
@@ -100,8 +100,8 @@ impl<'a> Lifetime<'a> {
100} 100}
101 101
102impl<'a> Comment<'a> { 102impl<'a> Comment<'a> {
103 pub fn text(&self) -> SmolStr { 103 pub fn text(&self) -> &SmolStr {
104 self.syntax().leaf_text().unwrap().clone() 104 self.syntax().leaf_text().unwrap()
105 } 105 }
106 106
107 pub fn flavor(&self) -> CommentFlavor { 107 pub fn flavor(&self) -> CommentFlavor {
@@ -120,9 +120,17 @@ impl<'a> Comment<'a> {
120 pub fn prefix(&self) -> &'static str { 120 pub fn prefix(&self) -> &'static str {
121 self.flavor().prefix() 121 self.flavor().prefix()
122 } 122 }
123
124 pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> {
125 self.text().chars().filter(|&c| c == '\n').map(|_| &())
126 }
127
128 pub fn has_newlines(&self) -> bool {
129 self.count_newlines_lazy().count() > 0
130 }
123} 131}
124 132
125#[derive(Debug)] 133#[derive(Debug, PartialEq, Eq)]
126pub enum CommentFlavor { 134pub enum CommentFlavor {
127 Line, 135 Line,
128 Doc, 136 Doc,
@@ -142,6 +150,20 @@ impl CommentFlavor {
142 } 150 }
143} 151}
144 152
153impl<'a> Whitespace<'a> {
154 pub fn text(&self) -> &SmolStr {
155 &self.syntax().leaf_text().unwrap()
156 }
157
158 pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> {
159 self.text().chars().filter(|&c| c == '\n').map(|_| &())
160 }
161
162 pub fn has_newlines(&self) -> bool {
163 self.count_newlines_lazy().count() > 0
164 }
165}
166
145impl<'a> Name<'a> { 167impl<'a> Name<'a> {
146 pub fn text(&self) -> SmolStr { 168 pub fn text(&self) -> SmolStr {
147 let ident = self.syntax().first_child() 169 let ident = self.syntax().first_child()
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 9da0c2c13..ea8063d3b 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -342,7 +342,7 @@ Grammar(
342 "TupleExpr": (), 342 "TupleExpr": (),
343 "ArrayExpr": (), 343 "ArrayExpr": (),
344 "ParenExpr": (), 344 "ParenExpr": (),
345 "PathExpr": (), 345 "PathExpr": (options: ["Path"]),
346 "LambdaExpr": ( 346 "LambdaExpr": (
347 options: [ 347 options: [
348 "ParamList", 348 "ParamList",
@@ -538,5 +538,6 @@ Grammar(
538 options: [ "NameRef" ] 538 options: [ "NameRef" ]
539 ), 539 ),
540 "Comment": (), 540 "Comment": (),
541 "Whitespace": (),
541 }, 542 },
542) 543)
diff --git a/crates/ra_syntax/src/grammar/expressions/atom.rs b/crates/ra_syntax/src/grammar/expressions/atom.rs
index a720d255f..e21de68c5 100644
--- a/crates/ra_syntax/src/grammar/expressions/atom.rs
+++ b/crates/ra_syntax/src/grammar/expressions/atom.rs
@@ -30,7 +30,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
30 token_set_union![ 30 token_set_union![
31 LITERAL_FIRST, 31 LITERAL_FIRST,
32 token_set![L_CURLY, L_PAREN, L_BRACK, PIPE, MOVE_KW, IF_KW, WHILE_KW, MATCH_KW, UNSAFE_KW, 32 token_set![L_CURLY, L_PAREN, L_BRACK, PIPE, MOVE_KW, IF_KW, WHILE_KW, MATCH_KW, UNSAFE_KW,
33 RETURN_KW, IDENT, SELF_KW, SUPER_KW, COLONCOLON, BREAK_KW, CONTINUE_KW, LIFETIME ], 33 RETURN_KW, IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLONCOLON, BREAK_KW, CONTINUE_KW, LIFETIME ],
34 ]; 34 ];
35 35
36const EXPR_RECOVERY_SET: TokenSet = 36const EXPR_RECOVERY_SET: TokenSet =
diff --git a/crates/ra_syntax/src/grammar/mod.rs b/crates/ra_syntax/src/grammar/mod.rs
index 2cb11dc1e..1199ba230 100644
--- a/crates/ra_syntax/src/grammar/mod.rs
+++ b/crates/ra_syntax/src/grammar/mod.rs
@@ -31,7 +31,7 @@ mod type_args;
31mod type_params; 31mod type_params;
32mod types; 32mod types;
33 33
34use { 34use crate::{
35 token_set::TokenSet, 35 token_set::TokenSet,
36 parser_api::{Marker, CompletedMarker, Parser}, 36 parser_api::{Marker, CompletedMarker, Parser},
37 SyntaxKind::{self, *}, 37 SyntaxKind::{self, *},
diff --git a/crates/ra_syntax/src/lexer/comments.rs b/crates/ra_syntax/src/lexer/comments.rs
index eb417c2dc..afe6886a1 100644
--- a/crates/ra_syntax/src/lexer/comments.rs
+++ b/crates/ra_syntax/src/lexer/comments.rs
@@ -1,6 +1,6 @@
1use lexer::ptr::Ptr; 1use crate::lexer::ptr::Ptr;
2 2
3use SyntaxKind::{self, *}; 3use crate::SyntaxKind::{self, *};
4 4
5pub(crate) fn scan_shebang(ptr: &mut Ptr) -> bool { 5pub(crate) fn scan_shebang(ptr: &mut Ptr) -> bool {
6 if ptr.at_str("!/") { 6 if ptr.at_str("!/") {
diff --git a/crates/ra_syntax/src/lexer/mod.rs b/crates/ra_syntax/src/lexer/mod.rs
index 3e11db88b..9dc0b63d6 100644
--- a/crates/ra_syntax/src/lexer/mod.rs
+++ b/crates/ra_syntax/src/lexer/mod.rs
@@ -4,7 +4,7 @@ mod numbers;
4mod ptr; 4mod ptr;
5mod strings; 5mod strings;
6 6
7use { 7use crate::{
8 SyntaxKind::{self, *}, 8 SyntaxKind::{self, *},
9 TextUnit, 9 TextUnit,
10}; 10};
diff --git a/crates/ra_syntax/src/lexer/numbers.rs b/crates/ra_syntax/src/lexer/numbers.rs
index 22e7d4e99..46daf5e52 100644
--- a/crates/ra_syntax/src/lexer/numbers.rs
+++ b/crates/ra_syntax/src/lexer/numbers.rs
@@ -1,7 +1,7 @@
1use lexer::classes::*; 1use crate::lexer::classes::*;
2use lexer::ptr::Ptr; 2use crate::lexer::ptr::Ptr;
3 3
4use SyntaxKind::{self, *}; 4use crate::SyntaxKind::{self, *};
5 5
6pub(crate) fn scan_number(c: char, ptr: &mut Ptr) -> SyntaxKind { 6pub(crate) fn scan_number(c: char, ptr: &mut Ptr) -> SyntaxKind {
7 if c == '0' { 7 if c == '0' {
diff --git a/crates/ra_syntax/src/lexer/ptr.rs b/crates/ra_syntax/src/lexer/ptr.rs
index c9a5354ea..c4708cb1c 100644
--- a/crates/ra_syntax/src/lexer/ptr.rs
+++ b/crates/ra_syntax/src/lexer/ptr.rs
@@ -1,4 +1,4 @@
1use TextUnit; 1use crate::TextUnit;
2 2
3use std::str::Chars; 3use std::str::Chars;
4 4
diff --git a/crates/ra_syntax/src/lexer/strings.rs b/crates/ra_syntax/src/lexer/strings.rs
index 5ff483d14..bceacdcac 100644
--- a/crates/ra_syntax/src/lexer/strings.rs
+++ b/crates/ra_syntax/src/lexer/strings.rs
@@ -1,6 +1,6 @@
1use SyntaxKind::{self, *}; 1use crate::SyntaxKind::{self, *};
2 2
3use lexer::ptr::Ptr; 3use crate::lexer::ptr::Ptr;
4 4
5pub(crate) fn is_string_literal_start(c: char, c1: Option<char>, c2: Option<char>) -> bool { 5pub(crate) fn is_string_literal_start(c: char, c1: Option<char>, c2: Option<char>) -> bool {
6 match (c, c1, c2) { 6 match (c, c1, c2) {
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 703469629..7eba5ee61 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -46,7 +46,7 @@ mod yellow;
46pub mod utils; 46pub mod utils;
47pub mod text_utils; 47pub mod text_utils;
48 48
49pub use { 49pub use crate::{
50 rowan::{SmolStr, TextRange, TextUnit}, 50 rowan::{SmolStr, TextRange, TextUnit},
51 ast::AstNode, 51 ast::AstNode,
52 lexer::{tokenize, Token}, 52 lexer::{tokenize, Token},
@@ -55,11 +55,11 @@ pub use {
55 reparsing::AtomEdit, 55 reparsing::AtomEdit,
56}; 56};
57 57
58use { 58use crate::{
59 yellow::{GreenNode}, 59 yellow::{GreenNode},
60}; 60};
61 61
62#[derive(Clone, Debug, Hash)] 62#[derive(Clone, Debug, Hash, PartialEq, Eq)]
63pub struct File { 63pub struct File {
64 root: SyntaxNode 64 root: SyntaxNode
65} 65}
diff --git a/crates/ra_syntax/src/parser_api.rs b/crates/ra_syntax/src/parser_api.rs
index 772d753af..cc23bb75e 100644
--- a/crates/ra_syntax/src/parser_api.rs
+++ b/crates/ra_syntax/src/parser_api.rs
@@ -1,4 +1,4 @@
1use { 1use crate::{
2 token_set::TokenSet, 2 token_set::TokenSet,
3 parser_impl::ParserImpl, 3 parser_impl::ParserImpl,
4 SyntaxKind::{self, ERROR}, 4 SyntaxKind::{self, ERROR},
diff --git a/crates/ra_syntax/src/parser_impl/event.rs b/crates/ra_syntax/src/parser_impl/event.rs
index 95e5ce4cc..928d2cc7a 100644
--- a/crates/ra_syntax/src/parser_impl/event.rs
+++ b/crates/ra_syntax/src/parser_impl/event.rs
@@ -8,7 +8,7 @@
8//! `start node`, `finish node`, and `FileBuilder` converts 8//! `start node`, `finish node`, and `FileBuilder` converts
9//! this stream to a real tree. 9//! this stream to a real tree.
10use std::mem; 10use std::mem;
11use { 11use crate::{
12 TextUnit, TextRange, SmolStr, 12 TextUnit, TextRange, SmolStr,
13 lexer::Token, 13 lexer::Token,
14 parser_impl::Sink, 14 parser_impl::Sink,
diff --git a/crates/ra_syntax/src/parser_impl/input.rs b/crates/ra_syntax/src/parser_impl/input.rs
index c0fe4d488..ac6d900d8 100644
--- a/crates/ra_syntax/src/parser_impl/input.rs
+++ b/crates/ra_syntax/src/parser_impl/input.rs
@@ -1,4 +1,4 @@
1use {lexer::Token, SyntaxKind, SyntaxKind::EOF, TextRange, TextUnit}; 1use crate::{lexer::Token, SyntaxKind, SyntaxKind::EOF, TextRange, TextUnit};
2 2
3use std::ops::{Add, AddAssign}; 3use std::ops::{Add, AddAssign};
4 4
diff --git a/crates/ra_syntax/src/parser_impl/mod.rs b/crates/ra_syntax/src/parser_impl/mod.rs
index 8d74cef0e..c2a6448e7 100644
--- a/crates/ra_syntax/src/parser_impl/mod.rs
+++ b/crates/ra_syntax/src/parser_impl/mod.rs
@@ -3,7 +3,7 @@ mod input;
3 3
4use std::cell::Cell; 4use std::cell::Cell;
5 5
6use { 6use crate::{
7 TextUnit, SmolStr, 7 TextUnit, SmolStr,
8 lexer::Token, 8 lexer::Token,
9 parser_api::Parser, 9 parser_api::Parser,
@@ -13,7 +13,7 @@ use {
13 }, 13 },
14}; 14};
15 15
16use SyntaxKind::{self, EOF, TOMBSTONE}; 16use crate::SyntaxKind::{self, EOF, TOMBSTONE};
17 17
18pub(crate) trait Sink { 18pub(crate) trait Sink {
19 type Tree; 19 type Tree;
diff --git a/crates/ra_syntax/src/reparsing.rs b/crates/ra_syntax/src/reparsing.rs
index d8b6a6a10..16272fe88 100644
--- a/crates/ra_syntax/src/reparsing.rs
+++ b/crates/ra_syntax/src/reparsing.rs
@@ -1,14 +1,14 @@
1use algo; 1use crate::algo;
2use grammar; 2use crate::grammar;
3use lexer::{tokenize, Token}; 3use crate::lexer::{tokenize, Token};
4use yellow::{self, GreenNode, SyntaxNodeRef, SyntaxError}; 4use crate::yellow::{self, GreenNode, SyntaxNodeRef, SyntaxError};
5use parser_impl; 5use crate::parser_impl;
6use parser_api::Parser; 6use crate::parser_api::Parser;
7use { 7use crate::{
8 TextUnit, TextRange, 8 TextUnit, TextRange,
9 SyntaxKind::*, 9 SyntaxKind::*,
10}; 10};
11use text_utils::replace_range; 11use crate::text_utils::replace_range;
12 12
13#[derive(Debug, Clone)] 13#[derive(Debug, Clone)]
14pub struct AtomEdit { 14pub struct AtomEdit {
diff --git a/crates/ra_syntax/src/syntax_kinds/mod.rs b/crates/ra_syntax/src/syntax_kinds/mod.rs
index 332cd13ac..3041e5633 100644
--- a/crates/ra_syntax/src/syntax_kinds/mod.rs
+++ b/crates/ra_syntax/src/syntax_kinds/mod.rs
@@ -1,7 +1,7 @@
1mod generated; 1mod generated;
2 2
3use std::fmt; 3use std::fmt;
4use SyntaxKind::*; 4use crate::SyntaxKind::*;
5 5
6pub use self::generated::SyntaxKind; 6pub use self::generated::SyntaxKind;
7 7
diff --git a/crates/ra_syntax/src/text_utils.rs b/crates/ra_syntax/src/text_utils.rs
index 58ae1e43e..adf26ef30 100644
--- a/crates/ra_syntax/src/text_utils.rs
+++ b/crates/ra_syntax/src/text_utils.rs
@@ -1,4 +1,4 @@
1use {TextRange, TextUnit}; 1use crate::{TextRange, TextUnit};
2 2
3pub fn contains_offset_nonstrict(range: TextRange, offset: TextUnit) -> bool { 3pub fn contains_offset_nonstrict(range: TextRange, offset: TextUnit) -> bool {
4 range.start() <= offset && offset <= range.end() 4 range.start() <= offset && offset <= range.end()
diff --git a/crates/ra_syntax/src/token_set.rs b/crates/ra_syntax/src/token_set.rs
index c83fba81b..d407dfa48 100644
--- a/crates/ra_syntax/src/token_set.rs
+++ b/crates/ra_syntax/src/token_set.rs
@@ -1,4 +1,4 @@
1use SyntaxKind; 1use crate::SyntaxKind;
2 2
3#[derive(Clone, Copy)] 3#[derive(Clone, Copy)]
4pub(crate) struct TokenSet(pub(crate) u128); 4pub(crate) struct TokenSet(pub(crate) u128);
@@ -29,7 +29,7 @@ macro_rules! token_set_union {
29 29
30#[test] 30#[test]
31fn token_set_works_for_tokens() { 31fn token_set_works_for_tokens() {
32 use SyntaxKind::*; 32 use crate::SyntaxKind::*;
33 let ts = token_set! { EOF, SHEBANG }; 33 let ts = token_set! { EOF, SHEBANG };
34 assert!(ts.contains(EOF)); 34 assert!(ts.contains(EOF));
35 assert!(ts.contains(SHEBANG)); 35 assert!(ts.contains(SHEBANG));
diff --git a/crates/ra_syntax/src/utils.rs b/crates/ra_syntax/src/utils.rs
index e274f7471..df1f4b372 100644
--- a/crates/ra_syntax/src/utils.rs
+++ b/crates/ra_syntax/src/utils.rs
@@ -1,5 +1,5 @@
1use std::fmt::Write; 1use std::fmt::Write;
2use { 2use crate::{
3 algo::walk::{walk, WalkEvent}, 3 algo::walk::{walk, WalkEvent},
4 SyntaxKind, File, SyntaxNodeRef 4 SyntaxKind, File, SyntaxNodeRef
5}; 5};
diff --git a/crates/ra_syntax/src/yellow/builder.rs b/crates/ra_syntax/src/yellow/builder.rs
index c307b2bd0..67a1a382b 100644
--- a/crates/ra_syntax/src/yellow/builder.rs
+++ b/crates/ra_syntax/src/yellow/builder.rs
@@ -1,5 +1,5 @@
1use rowan::GreenNodeBuilder; 1use rowan::GreenNodeBuilder;
2use { 2use crate::{
3 TextUnit, SmolStr, 3 TextUnit, SmolStr,
4 parser_impl::Sink, 4 parser_impl::Sink,
5 yellow::{GreenNode, SyntaxError, RaTypes}, 5 yellow::{GreenNode, SyntaxError, RaTypes},
diff --git a/crates/ra_syntax/src/yellow/mod.rs b/crates/ra_syntax/src/yellow/mod.rs
index 710320f47..ab9bca0f0 100644
--- a/crates/ra_syntax/src/yellow/mod.rs
+++ b/crates/ra_syntax/src/yellow/mod.rs
@@ -6,7 +6,7 @@ use std::{
6 hash::{Hash, Hasher}, 6 hash::{Hash, Hasher},
7}; 7};
8use rowan::Types; 8use rowan::Types;
9use {SyntaxKind, TextUnit, TextRange, SmolStr}; 9use crate::{SyntaxKind, TextUnit, TextRange, SmolStr};
10use self::syntax_text::SyntaxText; 10use self::syntax_text::SyntaxText;
11 11
12pub use rowan::{TreeRoot}; 12pub use rowan::{TreeRoot};
@@ -70,16 +70,16 @@ impl<'a> SyntaxNodeRef<'a> {
70 self.0.leaf_text() 70 self.0.leaf_text()
71 } 71 }
72 pub fn ancestors(self) -> impl Iterator<Item=SyntaxNodeRef<'a>> { 72 pub fn ancestors(self) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
73 ::algo::generate(Some(self), |&node| node.parent()) 73 crate::algo::generate(Some(self), |&node| node.parent())
74 } 74 }
75 pub fn descendants(self) -> impl Iterator<Item=SyntaxNodeRef<'a>> { 75 pub fn descendants(self) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
76 ::algo::walk::walk(self).filter_map(|event| match event { 76 crate::algo::walk::walk(self).filter_map(|event| match event {
77 ::algo::walk::WalkEvent::Enter(node) => Some(node), 77 crate::algo::walk::WalkEvent::Enter(node) => Some(node),
78 ::algo::walk::WalkEvent::Exit(_) => None, 78 crate::algo::walk::WalkEvent::Exit(_) => None,
79 }) 79 })
80 } 80 }
81 pub fn siblings(self, direction: Direction) -> impl Iterator<Item=SyntaxNodeRef<'a>> { 81 pub fn siblings(self, direction: Direction) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
82 ::algo::generate(Some(self), move |&node| match direction { 82 crate::algo::generate(Some(self), move |&node| match direction {
83 Direction::Next => node.next_sibling(), 83 Direction::Next => node.next_sibling(),
84 Direction::Prev => node.prev_sibling(), 84 Direction::Prev => node.prev_sibling(),
85 }) 85 })
@@ -156,7 +156,7 @@ impl<R: TreeRoot<RaTypes>> Iterator for SyntaxNodeChildren<R> {
156 156
157 157
158fn has_short_text(kind: SyntaxKind) -> bool { 158fn has_short_text(kind: SyntaxKind) -> bool {
159 use SyntaxKind::*; 159 use crate::SyntaxKind::*;
160 match kind { 160 match kind {
161 IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true, 161 IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true,
162 _ => false, 162 _ => false,
diff --git a/crates/ra_syntax/src/yellow/syntax_text.rs b/crates/ra_syntax/src/yellow/syntax_text.rs
index 0db1049de..ae33b993d 100644
--- a/crates/ra_syntax/src/yellow/syntax_text.rs
+++ b/crates/ra_syntax/src/yellow/syntax_text.rs
@@ -2,7 +2,7 @@ use std::{
2 fmt, ops, 2 fmt, ops,
3}; 3};
4 4
5use { 5use crate::{
6 SyntaxNodeRef, TextRange, TextUnit, 6 SyntaxNodeRef, TextRange, TextUnit,
7 text_utils::{intersect, contains_offset_nonstrict}, 7 text_utils::{intersect, contains_offset_nonstrict},
8}; 8};
diff --git a/crates/ra_syntax/tests/data/parser/ok/0035_crate_path_in_call.rs b/crates/ra_syntax/tests/data/parser/ok/0035_crate_path_in_call.rs
new file mode 100644
index 000000000..f1ed30220
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/ok/0035_crate_path_in_call.rs
@@ -0,0 +1,3 @@
1fn main() {
2 make_query(crate::module_map::module_tree);
3}
diff --git a/crates/ra_syntax/tests/data/parser/ok/0035_crate_path_in_call.txt b/crates/ra_syntax/tests/data/parser/ok/0035_crate_path_in_call.txt
new file mode 100644
index 000000000..364315180
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/ok/0035_crate_path_in_call.txt
@@ -0,0 +1,41 @@
1ROOT@[0; 62)
2 FN_DEF@[0; 61)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK@[10; 61)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 EXPR_STMT@[16; 59)
15 CALL_EXPR@[16; 58)
16 PATH_EXPR@[16; 26)
17 PATH@[16; 26)
18 PATH_SEGMENT@[16; 26)
19 NAME_REF@[16; 26)
20 IDENT@[16; 26) "make_query"
21 ARG_LIST@[26; 58)
22 L_PAREN@[26; 27)
23 PATH_EXPR@[27; 57)
24 PATH@[27; 57)
25 PATH@[27; 44)
26 PATH@[27; 32)
27 PATH_SEGMENT@[27; 32)
28 CRATE_KW@[27; 32)
29 COLONCOLON@[32; 34)
30 PATH_SEGMENT@[34; 44)
31 NAME_REF@[34; 44)
32 IDENT@[34; 44) "module_map"
33 COLONCOLON@[44; 46)
34 PATH_SEGMENT@[46; 57)
35 NAME_REF@[46; 57)
36 IDENT@[46; 57) "module_tree"
37 R_PAREN@[57; 58)
38 SEMI@[58; 59)
39 WHITESPACE@[59; 60)
40 R_CURLY@[60; 61)
41 WHITESPACE@[61; 62)
diff --git a/crates/salsa/Cargo.toml b/crates/salsa/Cargo.toml
deleted file mode 100644
index 9eb83234f..000000000
--- a/crates/salsa/Cargo.toml
+++ /dev/null
@@ -1,8 +0,0 @@
1[package]
2name = "salsa"
3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5
6[dependencies]
7parking_lot = "0.6.3"
8im = "12.0.0"
diff --git a/crates/salsa/src/lib.rs b/crates/salsa/src/lib.rs
deleted file mode 100644
index 35deed374..000000000
--- a/crates/salsa/src/lib.rs
+++ /dev/null
@@ -1,293 +0,0 @@
1extern crate im;
2extern crate parking_lot;
3
4use std::{
5 sync::Arc,
6 collections::{HashSet, HashMap},
7 cell::RefCell,
8};
9use parking_lot::Mutex;
10
11pub type GroundQueryFn<T, D> = Box<Fn(&T, &D) -> (D, OutputFingerprint) + Send + Sync + 'static>;
12pub type QueryFn<T, D> = Box<Fn(&QueryCtx<T, D>, &D) -> (D, OutputFingerprint) + Send + Sync + 'static>;
13
14#[derive(Debug)]
15pub struct Db<T, D> {
16 db: Arc<DbState<T, D>>,
17 query_config: Arc<QueryConfig<T, D>>,
18}
19
20pub struct QueryConfig<T, D> {
21 ground_fn: HashMap<QueryTypeId, GroundQueryFn<T, D>>,
22 query_fn: HashMap<QueryTypeId, QueryFn<T, D>>,
23}
24
25impl<T, D> ::std::fmt::Debug for QueryConfig<T, D> {
26 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
27 ::std::fmt::Display::fmt("QueryConfig { ... }", f)
28 }
29}
30
31#[derive(Debug)]
32struct DbState<T, D> {
33 ground_data: T,
34 gen: Gen,
35 graph: Mutex<im::HashMap<QueryId, (Gen, Arc<QueryRecord<D>>)>>,
36}
37
38#[derive(Debug)]
39struct QueryRecord<D> {
40 params: D,
41 output: D,
42 output_fingerprint: OutputFingerprint,
43 deps: Vec<(QueryId, OutputFingerprint)>,
44}
45
46impl<T, D> DbState<T, D> {
47 fn record(
48 &self,
49 query_id: QueryId,
50 params: D,
51 output: D,
52 output_fingerprint: OutputFingerprint,
53 deps: Vec<(QueryId, OutputFingerprint)>,
54 ) {
55 let gen = self.gen;
56 let record = QueryRecord {
57 params,
58 output,
59 output_fingerprint,
60 deps,
61 };
62 self.graph.lock().insert(query_id, (gen, Arc::new(record)));
63 }
64}
65
66impl<T, D> QueryConfig<T, D> {
67 pub fn new() -> Self {
68 QueryConfig {
69 ground_fn: HashMap::new(),
70 query_fn: HashMap::new(),
71 }
72 }
73 pub fn with_ground_query(
74 mut self,
75 query_type: QueryTypeId,
76 query_fn: GroundQueryFn<T, D>
77 ) -> Self {
78 let prev = self.ground_fn.insert(query_type, query_fn);
79 assert!(prev.is_none());
80 self
81 }
82 pub fn with_query(
83 mut self,
84 query_type: QueryTypeId,
85 query_fn: QueryFn<T, D>,
86 ) -> Self {
87 let prev = self.query_fn.insert(query_type, query_fn);
88 assert!(prev.is_none());
89 self
90 }
91}
92
93pub struct QueryCtx<T, D> {
94 db: Arc<DbState<T, D>>,
95 query_config: Arc<QueryConfig<T, D>>,
96 stack: RefCell<Vec<Vec<(QueryId, OutputFingerprint)>>>,
97 executed: RefCell<Vec<QueryTypeId>>,
98}
99
100impl<T, D> QueryCtx<T, D>
101where
102 D: Clone
103{
104 fn new(db: &Db<T, D>) -> QueryCtx<T, D> {
105 QueryCtx {
106 db: Arc::clone(&db.db),
107 query_config: Arc::clone(&db.query_config),
108 stack: RefCell::new(vec![Vec::new()]),
109 executed: RefCell::new(Vec::new()),
110 }
111 }
112 pub fn get(
113 &self,
114 query_id: QueryId,
115 params: D,
116 ) -> D {
117 let (res, output_fingerprint) = self.get_inner(query_id, params);
118 self.record_dep(query_id, output_fingerprint);
119 res
120 }
121 pub fn trace(&self) -> Vec<QueryTypeId> {
122 ::std::mem::replace(&mut *self.executed.borrow_mut(), Vec::new())
123 }
124
125 fn get_inner(
126 &self,
127 query_id: QueryId,
128 params: D,
129 ) -> (D, OutputFingerprint) {
130 let (gen, record) = {
131 let guard = self.db.graph.lock();
132 match guard.get(&query_id).map(|it| it.clone()){
133 None => {
134 drop(guard);
135 return self.force(query_id, params);
136 },
137 Some(it) => it,
138 }
139 };
140 if gen == self.db.gen {
141 return (record.output.clone(), record.output_fingerprint)
142 }
143 if self.query_config.ground_fn.contains_key(&query_id.0) {
144 let (invalidated, record) = {
145 let guard = self.db.graph.lock();
146 let (gen, ref record) = guard[&query_id];
147 (gen == INVALIDATED, record.clone())
148 };
149 if invalidated {
150 return self.force(query_id, params);
151 } else {
152 return (record.output.clone(), record.output_fingerprint);
153 }
154 }
155 for (dep_query_id, prev_fingerprint) in record.deps.iter().cloned() {
156 let dep_params: D = {
157 let guard = self.db.graph.lock();
158 guard[&dep_query_id]
159 .1
160 .params
161 .clone()
162 };
163 if prev_fingerprint != self.get_inner(dep_query_id, dep_params).1 {
164 return self.force(query_id, params)
165 }
166 }
167 let gen = self.db.gen;
168 {
169 let mut guard = self.db.graph.lock();
170 guard[&query_id].0 = gen;
171 }
172 (record.output.clone(), record.output_fingerprint)
173 }
174 fn force(
175 &self,
176 query_id: QueryId,
177 params: D,
178 ) -> (D, OutputFingerprint) {
179 self.executed.borrow_mut().push(query_id.0);
180 self.stack.borrow_mut().push(Vec::new());
181
182 let (res, output_fingerprint) = if let Some(f) = self.query_config.ground_fn.get(&query_id.0) {
183 f(&self.db.ground_data, &params)
184 } else if let Some(f) = self.query_config.query_fn.get(&query_id.0) {
185 f(self, &params)
186 } else {
187 panic!("unknown query type: {:?}", query_id.0);
188 };
189
190 let res: D = res.into();
191
192 let deps = self.stack.borrow_mut().pop().unwrap();
193 self.db.record(query_id, params, res.clone(), output_fingerprint, deps);
194 (res, output_fingerprint)
195 }
196 fn record_dep(
197 &self,
198 query_id: QueryId,
199 output_fingerprint: OutputFingerprint,
200 ) -> () {
201 let mut stack = self.stack.borrow_mut();
202 let deps = stack.last_mut().unwrap();
203 deps.push((query_id, output_fingerprint))
204 }
205}
206
207pub struct Invalidations {
208 types: HashSet<QueryTypeId>,
209 ids: Vec<QueryId>,
210}
211
212impl Invalidations {
213 pub fn new() -> Invalidations {
214 Invalidations {
215 types: HashSet::new(),
216 ids: Vec::new(),
217 }
218 }
219 pub fn invalidate(
220 &mut self,
221 query_type: QueryTypeId,
222 params: impl Iterator<Item=InputFingerprint>,
223 ) {
224 self.types.insert(query_type);
225 self.ids.extend(params.map(|it| QueryId(query_type, it)))
226 }
227}
228
229impl<T, D> Db<T, D>
230where
231 D: Clone
232{
233 pub fn new(query_config: QueryConfig<T, D>, ground_data: T) -> Db<T, D> {
234 Db {
235 db: Arc::new(DbState { ground_data, gen: Gen(0), graph: Default::default() }),
236 query_config: Arc::new(query_config),
237 }
238 }
239 pub fn ground_data(&self) -> &T {
240 &self.db.ground_data
241 }
242 pub fn with_ground_data(
243 &self,
244 ground_data: T,
245 invalidations: Invalidations,
246 ) -> Db<T, D> {
247 for id in self.query_config.ground_fn.keys() {
248 assert!(
249 invalidations.types.contains(id),
250 "all ground queries must be invalidated"
251 );
252 }
253
254 let gen = Gen(self.db.gen.0 + 1);
255 let mut graph = self.db.graph.lock().clone();
256 for id in invalidations.ids {
257 if let Some((gen, _)) = graph.get_mut(&id) {
258 *gen = INVALIDATED;
259 }
260 }
261 let graph = Mutex::new(graph);
262 Db {
263 db: Arc::new(DbState { ground_data, gen, graph }),
264 query_config: Arc::clone(&self.query_config)
265 }
266 }
267 pub fn query_ctx(&self) -> QueryCtx<T, D> {
268 QueryCtx::new(self)
269 }
270 pub fn get(
271 &self,
272 query_id: QueryId,
273 params: D,
274 ) -> (D, Vec<QueryTypeId>) {
275 let ctx = self.query_ctx();
276 let res = ctx.get(query_id, params.into());
277 let executed = ::std::mem::replace(&mut *ctx.executed.borrow_mut(), Vec::new());
278 (res, executed)
279 }
280}
281
282#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
283struct Gen(u64);
284const INVALIDATED: Gen = Gen(!0);
285#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
286pub struct InputFingerprint(pub u64);
287#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
288pub struct OutputFingerprint(pub u64);
289#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
290pub struct QueryTypeId(pub u16);
291#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
292pub struct QueryId(pub QueryTypeId, pub InputFingerprint);
293
diff --git a/crates/salsa/tests/integration.rs b/crates/salsa/tests/integration.rs
deleted file mode 100644
index aed9219be..000000000
--- a/crates/salsa/tests/integration.rs
+++ /dev/null
@@ -1,170 +0,0 @@
1extern crate salsa;
2use std::{
3 iter::once,
4 sync::Arc,
5 collections::hash_map::{HashMap, DefaultHasher},
6 any::Any,
7 hash::{Hash, Hasher},
8};
9
10type State = HashMap<u32, String>;
11type Data = Arc<Any + Send + Sync + 'static>;
12const GET_TEXT: salsa::QueryTypeId = salsa::QueryTypeId(1);
13const GET_FILES: salsa::QueryTypeId = salsa::QueryTypeId(2);
14const FILE_NEWLINES: salsa::QueryTypeId = salsa::QueryTypeId(3);
15const TOTAL_NEWLINES: salsa::QueryTypeId = salsa::QueryTypeId(4);
16
17fn mk_ground_query<T, R>(
18 state: &State,
19 params: &Data,
20 f: fn(&State, &T) -> R,
21) -> (Data, salsa::OutputFingerprint)
22where
23 T: 'static,
24 R: Hash + Send + Sync + 'static,
25{
26 let params = params.downcast_ref().unwrap();
27 let result = f(state, params);
28 let fingerprint = o_print(&result);
29 (Arc::new(result), fingerprint)
30}
31
32fn get<T, R>(db: &salsa::Db<State, Data>, query_type: salsa::QueryTypeId, param: T) -> (Arc<R>, Vec<salsa::QueryTypeId>)
33where
34 T: Hash + Send + Sync + 'static,
35 R: Send + Sync + 'static,
36{
37 let i_print = i_print(&param);
38 let param = Arc::new(param);
39 let (res, trace) = db.get(salsa::QueryId(query_type, i_print), param);
40 (res.downcast().unwrap(), trace)
41}
42
43struct QueryCtx<'a>(&'a salsa::QueryCtx<State, Data>);
44
45impl<'a> QueryCtx<'a> {
46 fn get_text(&self, id: u32) -> Arc<String> {
47 let i_print = i_print(&id);
48 let text = self.0.get(salsa::QueryId(GET_TEXT, i_print), Arc::new(id));
49 text.downcast().unwrap()
50 }
51 fn get_files(&self) -> Arc<Vec<u32>> {
52 let i_print = i_print(&());
53 let files = self.0.get(salsa::QueryId(GET_FILES, i_print), Arc::new(()));
54 let res = files.downcast().unwrap();
55 res
56 }
57 fn get_n_lines(&self, id: u32) -> usize {
58 let i_print = i_print(&id);
59 let n_lines = self.0.get(salsa::QueryId(FILE_NEWLINES, i_print), Arc::new(id));
60 *n_lines.downcast().unwrap()
61 }
62}
63
64fn mk_query<T, R>(
65 query_ctx: &salsa::QueryCtx<State, Data>,
66 params: &Data,
67 f: fn(QueryCtx, &T) -> R,
68) -> (Data, salsa::OutputFingerprint)
69where
70 T: 'static,
71 R: Hash + Send + Sync + 'static,
72{
73 let params: &T = params.downcast_ref().unwrap();
74 let query_ctx = QueryCtx(query_ctx);
75 let result = f(query_ctx, params);
76 let fingerprint = o_print(&result);
77 (Arc::new(result), fingerprint)
78}
79
80fn mk_queries() -> salsa::QueryConfig<State, Data> {
81 salsa::QueryConfig::<State, Data>::new()
82 .with_ground_query(GET_TEXT, Box::new(|state, id| {
83 mk_ground_query::<u32, String>(state, id, |state, id| state[id].clone())
84 }))
85 .with_ground_query(GET_FILES, Box::new(|state, id| {
86 mk_ground_query::<(), Vec<u32>>(state, id, |state, &()| state.keys().cloned().collect())
87 }))
88 .with_query(FILE_NEWLINES, Box::new(|query_ctx, id| {
89 mk_query(query_ctx, id, |query_ctx, &id| {
90 let text = query_ctx.get_text(id);
91 text.lines().count()
92 })
93 }))
94 .with_query(TOTAL_NEWLINES, Box::new(|query_ctx, id| {
95 mk_query(query_ctx, id, |query_ctx, &()| {
96 let mut total = 0;
97 for &id in query_ctx.get_files().iter() {
98 total += query_ctx.get_n_lines(id)
99 }
100 total
101 })
102 }))
103}
104
105#[test]
106fn test_number_of_lines() {
107 let mut state = State::new();
108 let db = salsa::Db::new(mk_queries(), state.clone());
109 let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ());
110 assert_eq!(*newlines, 0);
111 assert_eq!(trace.len(), 2);
112 let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ());
113 assert_eq!(*newlines, 0);
114 assert_eq!(trace.len(), 0);
115
116 state.insert(1, "hello\nworld".to_string());
117 let mut inv = salsa::Invalidations::new();
118 inv.invalidate(GET_TEXT, once(i_print(&1u32)));
119 inv.invalidate(GET_FILES, once(i_print(&())));
120 let db = db.with_ground_data(state.clone(), inv);
121 let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ());
122 assert_eq!(*newlines, 2);
123 assert_eq!(trace.len(), 4);
124
125 state.insert(2, "spam\neggs".to_string());
126 let mut inv = salsa::Invalidations::new();
127 inv.invalidate(GET_TEXT, once(i_print(&2u32)));
128 inv.invalidate(GET_FILES, once(i_print(&())));
129 let db = db.with_ground_data(state.clone(), inv);
130 let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ());
131 assert_eq!(*newlines, 4);
132 assert_eq!(trace.len(), 4);
133
134 let mut invs = vec![];
135 for i in 0..10 {
136 let id = i + 10;
137 invs.push(i_print(&id));
138 state.insert(id, "spam".to_string());
139 }
140 let mut inv = salsa::Invalidations::new();
141 inv.invalidate(GET_TEXT, invs.into_iter());
142 inv.invalidate(GET_FILES, once(i_print(&())));
143 let db = db.with_ground_data(state.clone(), inv);
144 let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ());
145 assert_eq!(*newlines, 14);
146 assert_eq!(trace.len(), 22);
147
148 state.insert(15, String::new());
149 let mut inv = salsa::Invalidations::new();
150 inv.invalidate(GET_TEXT, once(i_print(&15u32)));
151 inv.invalidate(GET_FILES, once(i_print(&())));
152 let db = db.with_ground_data(state.clone(), inv);
153 let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ());
154 assert_eq!(*newlines, 13);
155 assert_eq!(trace.len(), 4);
156}
157
158fn o_print<T: Hash>(x: &T) -> salsa::OutputFingerprint {
159 let mut hasher = DefaultHasher::new();
160 x.hash(&mut hasher);
161 let hash = hasher.finish();
162 salsa::OutputFingerprint(hash)
163}
164
165fn i_print<T: Hash>(x: &T) -> salsa::InputFingerprint {
166 let mut hasher = DefaultHasher::new();
167 x.hash(&mut hasher);
168 let hash = hasher.finish();
169 salsa::InputFingerprint(hash)
170}
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml
index 41316581e..fe0998ab8 100644
--- a/crates/test_utils/Cargo.toml
+++ b/crates/test_utils/Cargo.toml
@@ -1,4 +1,5 @@
1[package] 1[package]
2edition = "2018"
2name = "test_utils" 3name = "test_utils"
3version = "0.1.0" 4version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"] 5authors = ["Aleksey Kladov <[email protected]>"]
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 068eb80ce..ee73153f0 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -38,22 +38,44 @@ pub fn assert_eq_dbg(expected: &str, actual: &impl fmt::Debug) {
38} 38}
39 39
40pub fn extract_offset(text: &str) -> (TextUnit, String) { 40pub fn extract_offset(text: &str) -> (TextUnit, String) {
41 let cursor = "<|>"; 41 match try_extract_offset(text) {
42 let cursor_pos = match text.find(cursor) {
43 None => panic!("text should contain cursor marker"), 42 None => panic!("text should contain cursor marker"),
44 Some(pos) => pos, 43 Some(result) => result,
45 }; 44 }
45}
46
47pub fn try_extract_offset(text: &str) -> Option<(TextUnit, String)> {
48 let cursor = "<|>";
49 let cursor_pos = text.find(cursor)?;
46 let mut new_text = String::with_capacity(text.len() - cursor.len()); 50 let mut new_text = String::with_capacity(text.len() - cursor.len());
47 new_text.push_str(&text[..cursor_pos]); 51 new_text.push_str(&text[..cursor_pos]);
48 new_text.push_str(&text[cursor_pos + cursor.len()..]); 52 new_text.push_str(&text[cursor_pos + cursor.len()..]);
49 let cursor_pos = TextUnit::from(cursor_pos as u32); 53 let cursor_pos = TextUnit::from(cursor_pos as u32);
50 (cursor_pos, new_text) 54 Some((cursor_pos, new_text))
51} 55}
52 56
53pub fn extract_range(text: &str) -> (TextRange, String) { 57pub fn extract_range(text: &str) -> (TextRange, String) {
54 let (start, text) = extract_offset(text); 58 match try_extract_range(text) {
55 let (end, text) = extract_offset(&text); 59 None => panic!("text should contain cursor marker"),
56 (TextRange::from_to(start, end), text) 60 Some(result) => result,
61 }
62}
63
64pub fn try_extract_range(text: &str) -> Option<(TextRange, String)> {
65 let (start, text) = try_extract_offset(text)?;
66 let (end, text) = try_extract_offset(&text)?;
67 Some((TextRange::from_to(start, end), text))
68}
69
70pub fn extract_ranges(text: &str) -> (Vec<TextRange>, String) {
71 let mut ranges = Vec::new();
72 let mut text = String::from(text);
73 while let Some((range, new_text)) = try_extract_range(&text) {
74 text = new_text;
75 ranges.push(range);
76 }
77
78 (ranges, text)
57} 79}
58 80
59pub fn add_cursor(text: &str, offset: TextUnit) -> String { 81pub fn add_cursor(text: &str, offset: TextUnit) -> String {
diff --git a/crates/tools/Cargo.toml b/crates/tools/Cargo.toml
index d03910986..e2fecc60d 100644
--- a/crates/tools/Cargo.toml
+++ b/crates/tools/Cargo.toml
@@ -1,4 +1,5 @@
1[package] 1[package]
2edition = "2018"
2name = "tools" 3name = "tools"
3version = "0.1.0" 4version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"] 5authors = ["Aleksey Kladov <[email protected]>"]
diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts
index ff8f23c7a..d1c525f68 100644
--- a/editors/code/src/extension.ts
+++ b/editors/code/src/extension.ts
@@ -20,8 +20,8 @@ export function activate(context: vscode.ExtensionContext) {
20 f: (...args: any[]) => Promise<boolean> 20 f: (...args: any[]) => Promise<boolean>
21 ) { 21 ) {
22 const defaultCmd = `default:${name}`; 22 const defaultCmd = `default:${name}`;
23 const original = async (...args: any[]) => 23 const original = (...args: any[]) =>
24 await vscode.commands.executeCommand(defaultCmd, ...args); 24 vscode.commands.executeCommand(defaultCmd, ...args);
25 25
26 registerCommand(name, async (...args: any[]) => { 26 registerCommand(name, async (...args: any[]) => {
27 const editor = vscode.window.activeTextEditor; 27 const editor = vscode.window.activeTextEditor;