diff options
-rw-r--r-- | Cargo.lock | 16 | ||||
-rw-r--r-- | crates/gen_lsp_server/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_lsp_server/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 2 | ||||
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 173 |
5 files changed, 184 insertions, 11 deletions
diff --git a/Cargo.lock b/Cargo.lock index f09cf98c8..5912659d4 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -46,7 +46,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
46 | 46 | ||
47 | [[package]] | 47 | [[package]] |
48 | name = "backtrace" | 48 | name = "backtrace" |
49 | version = "0.3.13" | 49 | version = "0.3.14" |
50 | source = "registry+https://github.com/rust-lang/crates.io-index" | 50 | source = "registry+https://github.com/rust-lang/crates.io-index" |
51 | dependencies = [ | 51 | dependencies = [ |
52 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | 52 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", |
@@ -319,7 +319,7 @@ name = "error-chain" | |||
319 | version = "0.12.0" | 319 | version = "0.12.0" |
320 | source = "registry+https://github.com/rust-lang/crates.io-index" | 320 | source = "registry+https://github.com/rust-lang/crates.io-index" |
321 | dependencies = [ | 321 | dependencies = [ |
322 | "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", | 322 | "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", |
323 | ] | 323 | ] |
324 | 324 | ||
325 | [[package]] | 325 | [[package]] |
@@ -327,7 +327,7 @@ name = "failure" | |||
327 | version = "0.1.5" | 327 | version = "0.1.5" |
328 | source = "registry+https://github.com/rust-lang/crates.io-index" | 328 | source = "registry+https://github.com/rust-lang/crates.io-index" |
329 | dependencies = [ | 329 | dependencies = [ |
330 | "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", | 330 | "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", |
331 | "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", | 331 | "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", |
332 | ] | 332 | ] |
333 | 333 | ||
@@ -431,7 +431,7 @@ dependencies = [ | |||
431 | "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", | 431 | "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", |
432 | "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", | 432 | "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", |
433 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | 433 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", |
434 | "lsp-types 0.55.4 (registry+https://github.com/rust-lang/crates.io-index)", | 434 | "lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)", |
435 | "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", | 435 | "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", |
436 | "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", | 436 | "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", |
437 | ] | 437 | ] |
@@ -633,7 +633,7 @@ dependencies = [ | |||
633 | 633 | ||
634 | [[package]] | 634 | [[package]] |
635 | name = "lsp-types" | 635 | name = "lsp-types" |
636 | version = "0.55.4" | 636 | version = "0.56.0" |
637 | source = "registry+https://github.com/rust-lang/crates.io-index" | 637 | source = "registry+https://github.com/rust-lang/crates.io-index" |
638 | dependencies = [ | 638 | dependencies = [ |
639 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", | 639 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", |
@@ -1043,7 +1043,7 @@ dependencies = [ | |||
1043 | "flexi_logger 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", | 1043 | "flexi_logger 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", |
1044 | "gen_lsp_server 0.1.0", | 1044 | "gen_lsp_server 0.1.0", |
1045 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | 1045 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", |
1046 | "lsp-types 0.55.4 (registry+https://github.com/rust-lang/crates.io-index)", | 1046 | "lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)", |
1047 | "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1047 | "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1048 | "ra_arena 0.1.0", | 1048 | "ra_arena 0.1.0", |
1049 | "ra_ide_api 0.1.0", | 1049 | "ra_ide_api 0.1.0", |
@@ -1892,7 +1892,7 @@ dependencies = [ | |||
1892 | "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" | 1892 | "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" |
1893 | "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" | 1893 | "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" |
1894 | "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" | 1894 | "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" |
1895 | "checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5" | 1895 | "checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4" |
1896 | "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" | 1896 | "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" |
1897 | "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" | 1897 | "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" |
1898 | "checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a" | 1898 | "checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a" |
@@ -1964,7 +1964,7 @@ dependencies = [ | |||
1964 | "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" | 1964 | "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" |
1965 | "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" | 1965 | "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" |
1966 | "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" | 1966 | "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" |
1967 | "checksum lsp-types 0.55.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6392b5843615b8a2adeebe87b83fdd29567c0870baba3407a67e6dbfee4712f8" | 1967 | "checksum lsp-types 0.56.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31954f2cf354421e6f99a48fdcfd5c3113c675a0db311960ffdac0b8d45cf09c" |
1968 | "checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" | 1968 | "checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" |
1969 | "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" | 1969 | "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" |
1970 | "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" | 1970 | "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" |
diff --git a/crates/gen_lsp_server/Cargo.toml b/crates/gen_lsp_server/Cargo.toml index a252c911c..9e0d819d0 100644 --- a/crates/gen_lsp_server/Cargo.toml +++ b/crates/gen_lsp_server/Cargo.toml | |||
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" | |||
8 | description = "Generic LSP server scaffold." | 8 | description = "Generic LSP server scaffold." |
9 | 9 | ||
10 | [dependencies] | 10 | [dependencies] |
11 | lsp-types = "0.55.0" | 11 | lsp-types = "0.56.0" |
12 | log = "0.4.3" | 12 | log = "0.4.3" |
13 | failure = "0.1.4" | 13 | failure = "0.1.4" |
14 | serde_json = "1.0.34" | 14 | serde_json = "1.0.34" |
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index 6342e0628..ef6dea393 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -15,7 +15,7 @@ crossbeam-channel = "0.3.5" | |||
15 | flexi_logger = "0.10.0" | 15 | flexi_logger = "0.10.0" |
16 | log = "0.4.3" | 16 | log = "0.4.3" |
17 | url_serde = "0.2.0" | 17 | url_serde = "0.2.0" |
18 | lsp-types = "0.55.0" | 18 | lsp-types = "0.56.0" |
19 | rustc-hash = "1.0" | 19 | rustc-hash = "1.0" |
20 | parking_lot = "0.7.0" | 20 | parking_lot = "0.7.0" |
21 | 21 | ||
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 9208ee473..9abd4054e 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -419,7 +419,7 @@ pub fn handle_signature_help( | |||
419 | Ok(Some(req::SignatureHelp { | 419 | Ok(Some(req::SignatureHelp { |
420 | signatures: vec![sig_info], | 420 | signatures: vec![sig_info], |
421 | active_signature: Some(0), | 421 | active_signature: Some(0), |
422 | active_parameter: call_info.active_parameter.map(|it| it as u64), | 422 | active_parameter: call_info.active_parameter.map(|it| it as i64), |
423 | })) | 423 | })) |
424 | } else { | 424 | } else { |
425 | Ok(None) | 425 | Ok(None) |
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index dc4b779e8..e7d402446 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -14,6 +14,8 @@ | |||
14 | //! CST). The actual parser live in a separate `ra_parser` crate, thought the | 14 | //! CST). The actual parser live in a separate `ra_parser` crate, thought the |
15 | //! lexer lives in this crate. | 15 | //! lexer lives in this crate. |
16 | //! | 16 | //! |
17 | //! See `api_walkthrough` test in this file for a quick API tour! | ||
18 | //! | ||
17 | //! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256> | 19 | //! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256> |
18 | //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md> | 20 | //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md> |
19 | 21 | ||
@@ -87,3 +89,174 @@ pub fn check_fuzz_invariants(text: &str) { | |||
87 | validation::validate_block_structure(root); | 89 | validation::validate_block_structure(root); |
88 | let _ = file.errors(); | 90 | let _ = file.errors(); |
89 | } | 91 | } |
92 | |||
93 | /// This test does not assert anything and instead just shows off the crate's | ||
94 | /// API. | ||
95 | #[test] | ||
96 | fn api_walkthrough() { | ||
97 | use ast::{ModuleItemOwner, NameOwner}; | ||
98 | |||
99 | let source_code = " | ||
100 | fn foo() { | ||
101 | 1 + 1 | ||
102 | } | ||
103 | "; | ||
104 | // `SourceFile` is the main entry point. | ||
105 | // | ||
106 | // Note how `parse` does not return a `Result`: even completely invalid | ||
107 | // source code might be parsed. | ||
108 | let file = SourceFile::parse(source_code); | ||
109 | |||
110 | // Due to the way ownership is set up, owned syntax Nodes always live behind | ||
111 | // a `TreeArc` smart pointer. `TreeArc` is roughly an `std::sync::Arc` which | ||
112 | // points to the whole file instead of an individual node. | ||
113 | let file: TreeArc<SourceFile> = file; | ||
114 | |||
115 | // `SourceFile` is the root of the syntax tree. We can iterate file's items: | ||
116 | let mut func = None; | ||
117 | for item in file.items() { | ||
118 | match item.kind() { | ||
119 | ast::ModuleItemKind::FnDef(f) => func = Some(f), | ||
120 | _ => unreachable!(), | ||
121 | } | ||
122 | } | ||
123 | // The returned items are always references. | ||
124 | let func: &ast::FnDef = func.unwrap(); | ||
125 | |||
126 | // All nodes implement `ToOwned` trait, with `Owned = TreeArc<Self>`. | ||
127 | // `to_owned` is a cheap operation: atomic increment. | ||
128 | let _owned_func: TreeArc<ast::FnDef> = func.to_owned(); | ||
129 | |||
130 | // Each AST node has a bunch of getters for children. All getters return | ||
131 | // `Option`s though, to account for incomplete code. Some getters are common | ||
132 | // for several kinds of node. In this case, a trait like `ast::NameOwner` | ||
133 | // usually exists. By convention, all ast types should be used with `ast::` | ||
134 | // qualifier. | ||
135 | let name: Option<&ast::Name> = func.name(); | ||
136 | let name = name.unwrap(); | ||
137 | assert_eq!(name.text(), "foo"); | ||
138 | |||
139 | // Let's get the `1 + 1` expression! | ||
140 | let block: &ast::Block = func.body().unwrap(); | ||
141 | let expr: &ast::Expr = block.expr().unwrap(); | ||
142 | |||
143 | // "Enum"-like nodes are represented using the "kind" pattern. It allows us | ||
144 | // to match exhaustively against all flavors of nodes, while maintaining | ||
145 | // internal representation flexibility. The drawback is that one can't write | ||
146 | // nested matches as one pattern. | ||
147 | let bin_expr: &ast::BinExpr = match expr.kind() { | ||
148 | ast::ExprKind::BinExpr(e) => e, | ||
149 | _ => unreachable!(), | ||
150 | }; | ||
151 | |||
152 | // Besides the "typed" AST API, there's an untyped CST one as well. | ||
153 | // To switch from AST to CST, call `.syntax()` method: | ||
154 | let expr_syntax: &SyntaxNode = expr.syntax(); | ||
155 | |||
156 | // Note how `expr` and `bin_expr` are in fact the same node underneath: | ||
157 | assert!(std::ptr::eq(expr_syntax, bin_expr.syntax())); | ||
158 | |||
159 | // To go from CST to AST, `AstNode::cast` function is used: | ||
160 | let expr = match ast::Expr::cast(expr_syntax) { | ||
161 | Some(e) => e, | ||
162 | None => unreachable!(), | ||
163 | }; | ||
164 | |||
165 | // Note how expr is also a reference! | ||
166 | let expr: &ast::Expr = expr; | ||
167 | |||
168 | // This is possible because the underlying representation is the same: | ||
169 | assert_eq!( | ||
170 | expr as *const ast::Expr as *const u8, | ||
171 | expr_syntax as *const SyntaxNode as *const u8 | ||
172 | ); | ||
173 | |||
174 | // The two properties each syntax node has is a `SyntaxKind`: | ||
175 | assert_eq!(expr_syntax.kind(), SyntaxKind::BIN_EXPR); | ||
176 | |||
177 | // And text range: | ||
178 | assert_eq!(expr_syntax.range(), TextRange::from_to(32.into(), 37.into())); | ||
179 | |||
180 | // You can get node's text as a `SyntaxText` object, which will traverse the | ||
181 | // tree collecting token's text: | ||
182 | let text: SyntaxText<'_> = expr_syntax.text(); | ||
183 | assert_eq!(text.to_string(), "1 + 1"); | ||
184 | |||
185 | // There's a bunch of traversal methods on `SyntaxNode`: | ||
186 | assert_eq!(expr_syntax.parent(), Some(block.syntax())); | ||
187 | assert_eq!(block.syntax().first_child().map(|it| it.kind()), Some(SyntaxKind::L_CURLY)); | ||
188 | assert_eq!(expr_syntax.next_sibling().map(|it| it.kind()), Some(SyntaxKind::WHITESPACE)); | ||
189 | |||
190 | // As well as some iterator helpers: | ||
191 | let f = expr_syntax.ancestors().find_map(ast::FnDef::cast); | ||
192 | assert_eq!(f, Some(&*func)); | ||
193 | assert!(expr_syntax.siblings(Direction::Next).any(|it| it.kind() == SyntaxKind::R_CURLY)); | ||
194 | assert_eq!( | ||
195 | expr_syntax.descendants().count(), | ||
196 | 8, // 5 tokens `1`, ` `, `+`, ` `, `!` | ||
197 | // 2 child literal expressions: `1`, `1` | ||
198 | // 1 the node itself: `1 + 1` | ||
199 | ); | ||
200 | |||
201 | // There's also a `preorder` method with a more fine-grained iteration control: | ||
202 | let mut buf = String::new(); | ||
203 | let mut indent = 0; | ||
204 | for event in expr_syntax.preorder() { | ||
205 | match event { | ||
206 | WalkEvent::Enter(node) => { | ||
207 | buf += &format!( | ||
208 | "{:indent$}{:?} {:?}\n", | ||
209 | " ", | ||
210 | node.text(), | ||
211 | node.kind(), | ||
212 | indent = indent | ||
213 | ); | ||
214 | indent += 2; | ||
215 | } | ||
216 | WalkEvent::Leave(_) => indent -= 2, | ||
217 | } | ||
218 | } | ||
219 | assert_eq!(indent, 0); | ||
220 | assert_eq!( | ||
221 | buf.trim(), | ||
222 | r#" | ||
223 | "1 + 1" BIN_EXPR | ||
224 | "1" LITERAL | ||
225 | "1" INT_NUMBER | ||
226 | " " WHITESPACE | ||
227 | "+" PLUS | ||
228 | " " WHITESPACE | ||
229 | "1" LITERAL | ||
230 | "1" INT_NUMBER | ||
231 | "# | ||
232 | .trim() | ||
233 | ); | ||
234 | |||
235 | // To recursively process the tree, there are three approaches: | ||
236 | // 1. explicitly call getter methods on AST nodes. | ||
237 | // 2. use descendants and `AstNode::cast`. | ||
238 | // 3. use descendants and the visitor. | ||
239 | // | ||
240 | // Here's how the first one looks like: | ||
241 | let exprs_cast: Vec<String> = file | ||
242 | .syntax() | ||
243 | .descendants() | ||
244 | .filter_map(ast::Expr::cast) | ||
245 | .map(|expr| expr.syntax().text().to_string()) | ||
246 | .collect(); | ||
247 | |||
248 | // An alternative is to use a visitor. The visitor does not do traversal | ||
249 | // automatically (so it's more akin to a generic lambda) and is constructed | ||
250 | // from closures. This seems more flexible than a single generated visitor | ||
251 | // trait. | ||
252 | use algo::visit::{visitor, Visitor}; | ||
253 | let mut exprs_visit = Vec::new(); | ||
254 | for node in file.syntax().descendants() { | ||
255 | if let Some(result) = | ||
256 | visitor().visit::<ast::Expr, _>(|expr| expr.syntax().text().to_string()).accept(node) | ||
257 | { | ||
258 | exprs_visit.push(result); | ||
259 | } | ||
260 | } | ||
261 | assert_eq!(exprs_cast, exprs_visit); | ||
262 | } | ||