diff options
-rw-r--r-- | crates/ra_hir_def/src/adt.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 38 | ||||
-rw-r--r-- | crates/ra_hir_def/src/expr.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/pat.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/patterns.rs | 46 | ||||
-rw-r--r-- | crates/ra_ide/src/references/rename.rs | 106 | ||||
-rw-r--r-- | crates/ra_mbe/src/subtree_source.rs | 5 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 22 | ||||
-rw-r--r-- | docs/user/features.md | 30 | ||||
-rw-r--r-- | docs/user/readme.adoc | 19 |
10 files changed, 238 insertions, 35 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 985f409e8..2bdfc2b8d 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs | |||
@@ -174,6 +174,7 @@ impl HasChildSource for VariantId { | |||
174 | } | 174 | } |
175 | } | 175 | } |
176 | 176 | ||
177 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
177 | pub enum StructKind { | 178 | pub enum StructKind { |
178 | Tuple, | 179 | Tuple, |
179 | Record, | 180 | Record, |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index b1626fa11..b3fb6d452 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -15,6 +15,7 @@ use ra_syntax::{ | |||
15 | use test_utils::tested_by; | 15 | use test_utils::tested_by; |
16 | 16 | ||
17 | use crate::{ | 17 | use crate::{ |
18 | adt::StructKind, | ||
18 | body::{Body, BodySourceMap, Expander, PatPtr}, | 19 | body::{Body, BodySourceMap, Expander, PatPtr}, |
19 | builtin_type::{BuiltinFloat, BuiltinInt}, | 20 | builtin_type::{BuiltinFloat, BuiltinInt}, |
20 | db::DefDatabase, | 21 | db::DefDatabase, |
@@ -22,11 +23,12 @@ use crate::{ | |||
22 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, | 23 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, |
23 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | 24 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, |
24 | }, | 25 | }, |
26 | item_scope::BuiltinShadowMode, | ||
25 | path::GenericArgs, | 27 | path::GenericArgs, |
26 | path::Path, | 28 | path::Path, |
27 | type_ref::{Mutability, TypeRef}, | 29 | type_ref::{Mutability, TypeRef}, |
28 | ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, StaticLoc, | 30 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, |
29 | StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, | 31 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, |
30 | }; | 32 | }; |
31 | 33 | ||
32 | pub(super) fn lower( | 34 | pub(super) fn lower( |
@@ -571,7 +573,37 @@ where | |||
571 | let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | 573 | let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); |
572 | let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); | 574 | let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); |
573 | let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); | 575 | let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); |
574 | Pat::Bind { name, mode: annotation, subpat } | 576 | if annotation == BindingAnnotation::Unannotated && subpat.is_none() { |
577 | // This could also be a single-segment path pattern. To | ||
578 | // decide that, we need to try resolving the name. | ||
579 | let (resolved, _) = self.expander.crate_def_map.resolve_path( | ||
580 | self.db, | ||
581 | self.expander.module.local_id, | ||
582 | &name.clone().into(), | ||
583 | BuiltinShadowMode::Other, | ||
584 | ); | ||
585 | match resolved.take_values() { | ||
586 | Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()), | ||
587 | Some(ModuleDefId::EnumVariantId(_)) => { | ||
588 | // this is only really valid for unit variants, but | ||
589 | // shadowing other enum variants with a pattern is | ||
590 | // an error anyway | ||
591 | Pat::Path(name.into()) | ||
592 | } | ||
593 | Some(ModuleDefId::AdtId(AdtId::StructId(s))) | ||
594 | if self.db.struct_data(s).variant_data.kind() != StructKind::Record => | ||
595 | { | ||
596 | // Funnily enough, record structs *can* be shadowed | ||
597 | // by pattern bindings (but unit or tuple structs | ||
598 | // can't). | ||
599 | Pat::Path(name.into()) | ||
600 | } | ||
601 | // shadowing statics is an error as well, so we just ignore that case here | ||
602 | _ => Pat::Bind { name, mode: annotation, subpat }, | ||
603 | } | ||
604 | } else { | ||
605 | Pat::Bind { name, mode: annotation, subpat } | ||
606 | } | ||
575 | } | 607 | } |
576 | ast::Pat::TupleStructPat(p) => { | 608 | ast::Pat::TupleStructPat(p) => { |
577 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | 609 | let path = p.path().and_then(|path| self.expander.parse_path(path)); |
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index 9707c5527..66d004717 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs | |||
@@ -48,7 +48,7 @@ pub enum Literal { | |||
48 | 48 | ||
49 | #[derive(Debug, Clone, Eq, PartialEq)] | 49 | #[derive(Debug, Clone, Eq, PartialEq)] |
50 | pub enum Expr { | 50 | pub enum Expr { |
51 | /// This is produced if syntax tree does not have a required expression piece. | 51 | /// This is produced if the syntax tree does not have a required expression piece. |
52 | Missing, | 52 | Missing, |
53 | Path(Path), | 53 | Path(Path), |
54 | If { | 54 | If { |
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs index a495ecbfe..bf8ea192b 100644 --- a/crates/ra_hir_ty/src/infer/pat.rs +++ b/crates/ra_hir_ty/src/infer/pat.rs | |||
@@ -189,7 +189,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
189 | }; | 189 | }; |
190 | // use a new type variable if we got Ty::Unknown here | 190 | // use a new type variable if we got Ty::Unknown here |
191 | let ty = self.insert_type_vars_shallow(ty); | 191 | let ty = self.insert_type_vars_shallow(ty); |
192 | self.unify(&ty, expected); | 192 | if !self.unify(&ty, expected) { |
193 | // FIXME record mismatch, we need to change the type of self.type_mismatches for that | ||
194 | } | ||
193 | let ty = self.resolve_ty_as_possible(ty); | 195 | let ty = self.resolve_ty_as_possible(ty); |
194 | self.write_pat_ty(pat, ty.clone()); | 196 | self.write_pat_ty(pat, ty.clone()); |
195 | ty | 197 | ty |
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs index e25d6dbc4..81d00c2af 100644 --- a/crates/ra_hir_ty/src/tests/patterns.rs +++ b/crates/ra_hir_ty/src/tests/patterns.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use super::infer; | 1 | use super::{infer, infer_with_mismatches}; |
2 | use insta::assert_snapshot; | 2 | use insta::assert_snapshot; |
3 | use test_utils::covers; | 3 | use test_utils::covers; |
4 | 4 | ||
@@ -236,3 +236,47 @@ fn test(a1: A<u32>, o: Option<u64>) { | |||
236 | "### | 236 | "### |
237 | ); | 237 | ); |
238 | } | 238 | } |
239 | |||
240 | #[test] | ||
241 | fn infer_const_pattern() { | ||
242 | assert_snapshot!( | ||
243 | infer_with_mismatches(r#" | ||
244 | enum Option<T> { None } | ||
245 | use Option::None; | ||
246 | struct Foo; | ||
247 | const Bar: usize = 1; | ||
248 | |||
249 | fn test() { | ||
250 | let a: Option<u32> = None; | ||
251 | let b: Option<i64> = match a { | ||
252 | None => None, | ||
253 | }; | ||
254 | let _: () = match () { Foo => Foo }; // Expected mismatch | ||
255 | let _: () = match () { Bar => Bar }; // Expected mismatch | ||
256 | } | ||
257 | "#, true), | ||
258 | @r###" | ||
259 | [74; 75) '1': usize | ||
260 | [88; 310) '{ ...atch }': () | ||
261 | [98; 99) 'a': Option<u32> | ||
262 | [115; 119) 'None': Option<u32> | ||
263 | [129; 130) 'b': Option<i64> | ||
264 | [146; 183) 'match ... }': Option<i64> | ||
265 | [152; 153) 'a': Option<u32> | ||
266 | [164; 168) 'None': Option<u32> | ||
267 | [172; 176) 'None': Option<i64> | ||
268 | [193; 194) '_': () | ||
269 | [201; 224) 'match ... Foo }': Foo | ||
270 | [207; 209) '()': () | ||
271 | [212; 215) 'Foo': Foo | ||
272 | [219; 222) 'Foo': Foo | ||
273 | [255; 256) '_': () | ||
274 | [263; 286) 'match ... Bar }': usize | ||
275 | [269; 271) '()': () | ||
276 | [274; 277) 'Bar': usize | ||
277 | [281; 284) 'Bar': usize | ||
278 | [201; 224): expected (), got Foo | ||
279 | [263; 286): expected (), got usize | ||
280 | "### | ||
281 | ); | ||
282 | } | ||
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs index c46b78cb6..bdb90020b 100644 --- a/crates/ra_ide/src/references/rename.rs +++ b/crates/ra_ide/src/references/rename.rs | |||
@@ -98,6 +98,17 @@ fn rename_mod( | |||
98 | }; | 98 | }; |
99 | source_file_edits.push(edit); | 99 | source_file_edits.push(edit); |
100 | 100 | ||
101 | if let Some(RangeInfo { range: _, info: refs }) = find_all_refs(db, position, None) { | ||
102 | let ref_edits = refs.references.into_iter().map(|reference| { | ||
103 | source_edit_from_file_id_range( | ||
104 | reference.file_range.file_id, | ||
105 | reference.file_range.range, | ||
106 | new_name, | ||
107 | ) | ||
108 | }); | ||
109 | source_file_edits.extend(ref_edits); | ||
110 | } | ||
111 | |||
101 | Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits)) | 112 | Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits)) |
102 | } | 113 | } |
103 | 114 | ||
@@ -383,6 +394,101 @@ mod tests { | |||
383 | ); | 394 | ); |
384 | } | 395 | } |
385 | 396 | ||
397 | #[test] | ||
398 | fn test_module_rename_in_path() { | ||
399 | test_rename( | ||
400 | r#" | ||
401 | mod <|>foo { | ||
402 | pub fn bar() {} | ||
403 | } | ||
404 | |||
405 | fn main() { | ||
406 | foo::bar(); | ||
407 | }"#, | ||
408 | "baz", | ||
409 | r#" | ||
410 | mod baz { | ||
411 | pub fn bar() {} | ||
412 | } | ||
413 | |||
414 | fn main() { | ||
415 | baz::bar(); | ||
416 | }"#, | ||
417 | ); | ||
418 | } | ||
419 | |||
420 | #[test] | ||
421 | fn test_rename_mod_filename_and_path() { | ||
422 | let (analysis, position) = analysis_and_position( | ||
423 | " | ||
424 | //- /lib.rs | ||
425 | mod bar; | ||
426 | fn f() { | ||
427 | bar::foo::fun() | ||
428 | } | ||
429 | |||
430 | //- /bar.rs | ||
431 | pub mod foo<|>; | ||
432 | |||
433 | //- /bar/foo.rs | ||
434 | // pub fn fun() {} | ||
435 | ", | ||
436 | ); | ||
437 | let new_name = "foo2"; | ||
438 | let source_change = analysis.rename(position, new_name).unwrap(); | ||
439 | assert_debug_snapshot!(&source_change, | ||
440 | @r###" | ||
441 | Some( | ||
442 | RangeInfo { | ||
443 | range: [8; 11), | ||
444 | info: SourceChange { | ||
445 | label: "rename", | ||
446 | source_file_edits: [ | ||
447 | SourceFileEdit { | ||
448 | file_id: FileId( | ||
449 | 2, | ||
450 | ), | ||
451 | edit: TextEdit { | ||
452 | atoms: [ | ||
453 | AtomTextEdit { | ||
454 | delete: [8; 11), | ||
455 | insert: "foo2", | ||
456 | }, | ||
457 | ], | ||
458 | }, | ||
459 | }, | ||
460 | SourceFileEdit { | ||
461 | file_id: FileId( | ||
462 | 1, | ||
463 | ), | ||
464 | edit: TextEdit { | ||
465 | atoms: [ | ||
466 | AtomTextEdit { | ||
467 | delete: [27; 30), | ||
468 | insert: "foo2", | ||
469 | }, | ||
470 | ], | ||
471 | }, | ||
472 | }, | ||
473 | ], | ||
474 | file_system_edits: [ | ||
475 | MoveFile { | ||
476 | src: FileId( | ||
477 | 3, | ||
478 | ), | ||
479 | dst_source_root: SourceRootId( | ||
480 | 0, | ||
481 | ), | ||
482 | dst_path: "bar/foo2.rs", | ||
483 | }, | ||
484 | ], | ||
485 | cursor_position: None, | ||
486 | }, | ||
487 | }, | ||
488 | ) | ||
489 | "###); | ||
490 | } | ||
491 | |||
386 | fn test_rename(text: &str, new_name: &str, expected: &str) { | 492 | fn test_rename(text: &str, new_name: &str, expected: &str) { |
387 | let (analysis, position) = single_file_with_position(text); | 493 | let (analysis, position) = single_file_with_position(text); |
388 | let source_change = analysis.rename(position, new_name).unwrap(); | 494 | let source_change = analysis.rename(position, new_name).unwrap(); |
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs index dacca8279..91e324db9 100644 --- a/crates/ra_mbe/src/subtree_source.rs +++ b/crates/ra_mbe/src/subtree_source.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_parser::{Token, TokenSource}; | 3 | use ra_parser::{Token, TokenSource}; |
4 | use ra_syntax::{lex_single_valid_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; | 4 | use ra_syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; |
5 | use std::cell::{Cell, Ref, RefCell}; | 5 | use std::cell::{Cell, Ref, RefCell}; |
6 | use tt::buffer::{Cursor, TokenBuffer}; | 6 | use tt::buffer::{Cursor, TokenBuffer}; |
7 | 7 | ||
@@ -129,7 +129,8 @@ fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken { | |||
129 | } | 129 | } |
130 | 130 | ||
131 | fn convert_literal(l: &tt::Literal) -> TtToken { | 131 | fn convert_literal(l: &tt::Literal) -> TtToken { |
132 | let kind = lex_single_valid_syntax_kind(&l.text) | 132 | let kind = lex_single_syntax_kind(&l.text) |
133 | .map(|(kind, _error)| kind) | ||
133 | .filter(|kind| kind.is_literal()) | 134 | .filter(|kind| kind.is_literal()) |
134 | .unwrap_or_else(|| match l.text.as_ref() { | 135 | .unwrap_or_else(|| match l.text.as_ref() { |
135 | "true" => T![true], | 136 | "true" => T![true], |
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index e0d689704..cb228702f 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -1374,14 +1374,22 @@ pub(crate) struct MacroFixture { | |||
1374 | 1374 | ||
1375 | impl MacroFixture { | 1375 | impl MacroFixture { |
1376 | pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree { | 1376 | pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree { |
1377 | let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); | 1377 | self.try_expand_tt(invocation).unwrap() |
1378 | } | ||
1379 | |||
1380 | fn try_expand_tt(&self, invocation: &str) -> Result<tt::Subtree, ExpandError> { | ||
1381 | let source_file = ast::SourceFile::parse(invocation).tree(); | ||
1378 | let macro_invocation = | 1382 | let macro_invocation = |
1379 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | 1383 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); |
1380 | 1384 | ||
1381 | let (invocation_tt, _) = | 1385 | let (invocation_tt, _) = |
1382 | ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); | 1386 | ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); |
1383 | 1387 | ||
1384 | self.rules.expand(&invocation_tt).unwrap() | 1388 | self.rules.expand(&invocation_tt) |
1389 | } | ||
1390 | |||
1391 | fn assert_expand_err(&self, invocation: &str, err: &ExpandError) { | ||
1392 | assert_eq!(self.try_expand_tt(invocation).as_ref(), Err(err)); | ||
1385 | } | 1393 | } |
1386 | 1394 | ||
1387 | fn expand_items(&self, invocation: &str) -> SyntaxNode { | 1395 | fn expand_items(&self, invocation: &str) -> SyntaxNode { |
@@ -1539,3 +1547,13 @@ fn test_repeat_bad_var() { | |||
1539 | ) | 1547 | ) |
1540 | .assert_expand_items("foo!(b0 b1);", "b0 b1"); | 1548 | .assert_expand_items("foo!(b0 b1);", "b0 b1"); |
1541 | } | 1549 | } |
1550 | |||
1551 | #[test] | ||
1552 | fn test_expand_bad_literal() { | ||
1553 | parse_macro( | ||
1554 | r#" | ||
1555 | macro_rules! foo { ($i:literal) => {}; } | ||
1556 | "#, | ||
1557 | ) | ||
1558 | .assert_expand_err(r#"foo!(&k");"#, &ExpandError::NoMatchingRule); | ||
1559 | } | ||
diff --git a/docs/user/features.md b/docs/user/features.md index a00fa35da..f705e5115 100644 --- a/docs/user/features.md +++ b/docs/user/features.md | |||
@@ -1,10 +1,10 @@ | |||
1 | This documents is an index of features that rust-analyzer language server | 1 | This document is an index of features that the rust-analyzer language server |
2 | provides. Shortcuts are for the default VS Code layout. If there's no shortcut, | 2 | provides. Shortcuts are for the default VS Code layout. If there's no shortcut, |
3 | you can use <kbd>Ctrl+Shift+P</kbd> to search for the corresponding action. | 3 | you can use <kbd>Ctrl+Shift+P</kbd> to search for the corresponding action. |
4 | 4 | ||
5 | ### Workspace Symbol <kbd>ctrl+t</kbd> | 5 | ### Workspace Symbol <kbd>ctrl+t</kbd> |
6 | 6 | ||
7 | Uses fuzzy-search to find types, modules and function by name across your | 7 | Uses fuzzy-search to find types, modules and functions by name across your |
8 | project and dependencies. This is **the** most useful feature, which improves code | 8 | project and dependencies. This is **the** most useful feature, which improves code |
9 | navigation tremendously. It mostly works on top of the built-in LSP | 9 | navigation tremendously. It mostly works on top of the built-in LSP |
10 | functionality, however `#` and `*` symbols can be used to narrow down the | 10 | functionality, however `#` and `*` symbols can be used to narrow down the |
@@ -13,7 +13,7 @@ search. Specifically, | |||
13 | - `Foo` searches for `Foo` type in the current workspace | 13 | - `Foo` searches for `Foo` type in the current workspace |
14 | - `foo#` searches for `foo` function in the current workspace | 14 | - `foo#` searches for `foo` function in the current workspace |
15 | - `Foo*` searches for `Foo` type among dependencies, including `stdlib` | 15 | - `Foo*` searches for `Foo` type among dependencies, including `stdlib` |
16 | - `foo#*` searches for `foo` function among dependencies. | 16 | - `foo#*` searches for `foo` function among dependencies |
17 | 17 | ||
18 | That is, `#` switches from "types" to all symbols, `*` switches from the current | 18 | That is, `#` switches from "types" to all symbols, `*` switches from the current |
19 | workspace to dependencies. | 19 | workspace to dependencies. |
@@ -30,7 +30,7 @@ Provides a tree of the symbols defined in the file. Can be used to | |||
30 | 30 | ||
31 | Some features trigger on typing certain characters: | 31 | Some features trigger on typing certain characters: |
32 | 32 | ||
33 | - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression. | 33 | - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression |
34 | - Enter inside comments automatically inserts `///` | 34 | - Enter inside comments automatically inserts `///` |
35 | - typing `.` in a chain method call auto-indents | 35 | - typing `.` in a chain method call auto-indents |
36 | 36 | ||
@@ -58,7 +58,7 @@ Navigates to the type of an identifier. | |||
58 | 58 | ||
59 | #### Run | 59 | #### Run |
60 | 60 | ||
61 | Shows popup suggesting to run a test/benchmark/binary **at the current cursor | 61 | Shows a popup suggesting to run a test/benchmark/binary **at the current cursor |
62 | location**. Super useful for repeatedly running just a single test. Do bind this | 62 | location**. Super useful for repeatedly running just a single test. Do bind this |
63 | to a shortcut! | 63 | to a shortcut! |
64 | 64 | ||
@@ -87,15 +87,15 @@ Shows the full macro expansion of the macro at current cursor. | |||
87 | 87 | ||
88 | #### Status | 88 | #### Status |
89 | 89 | ||
90 | Shows internal statistic about memory usage of rust-analyzer | 90 | Shows internal statistic about memory usage of rust-analyzer. |
91 | 91 | ||
92 | #### Show RA Version | 92 | #### Show RA Version |
93 | 93 | ||
94 | Show current rust-analyzer version | 94 | Show current rust-analyzer version. |
95 | 95 | ||
96 | #### Run garbage collection | 96 | #### Run Garbage Collection |
97 | 97 | ||
98 | Manually triggers GC | 98 | Manually triggers GC. |
99 | 99 | ||
100 | #### Start Cargo Watch | 100 | #### Start Cargo Watch |
101 | 101 | ||
@@ -103,7 +103,7 @@ Start `cargo watch` for live error highlighting. Will prompt to install if it's | |||
103 | 103 | ||
104 | #### Stop Cargo Watch | 104 | #### Stop Cargo Watch |
105 | 105 | ||
106 | Stop `cargo watch` | 106 | Stop `cargo watch`. |
107 | 107 | ||
108 | ### Assists (Code Actions) | 108 | ### Assists (Code Actions) |
109 | 109 | ||
@@ -122,11 +122,11 @@ is placed at the appropriate position. Even though `if` is easy to type, you | |||
122 | still want to complete it, to get ` { }` for free! `return` is inserted with a | 122 | still want to complete it, to get ` { }` for free! `return` is inserted with a |
123 | space or `;` depending on the return type of the function. | 123 | space or `;` depending on the return type of the function. |
124 | 124 | ||
125 | When completing a function call, `()` are automatically inserted. If function | 125 | When completing a function call, `()` are automatically inserted. If a function |
126 | takes arguments, cursor is positioned inside the parenthesis. | 126 | takes arguments, the cursor is positioned inside the parenthesis. |
127 | 127 | ||
128 | There are postifx completions, which can be triggerd by typing something like | 128 | There are postifx completions, which can be triggerd by typing something like |
129 | `foo().if`. The word after `.` determines postifx completion, possible variants are: | 129 | `foo().if`. The word after `.` determines postifx completion. Possible variants are: |
130 | 130 | ||
131 | - `expr.if` -> `if expr {}` | 131 | - `expr.if` -> `if expr {}` |
132 | - `expr.match` -> `match expr {}` | 132 | - `expr.match` -> `match expr {}` |
@@ -147,12 +147,12 @@ There also snippet completions: | |||
147 | 147 | ||
148 | - `tfn` -> `#[test] fn f(){}` | 148 | - `tfn` -> `#[test] fn f(){}` |
149 | 149 | ||
150 | ### Code highlighting | 150 | ### Code Highlighting |
151 | 151 | ||
152 | Experimental feature to let rust-analyzer highlight Rust code instead of using the | 152 | Experimental feature to let rust-analyzer highlight Rust code instead of using the |
153 | default highlighter. | 153 | default highlighter. |
154 | 154 | ||
155 | #### Rainbow highlighting | 155 | #### Rainbow Highlighting |
156 | 156 | ||
157 | Experimental feature that, given code highlighting using rust-analyzer is | 157 | Experimental feature that, given code highlighting using rust-analyzer is |
158 | active, will pick unique colors for identifiers. | 158 | active, will pick unique colors for identifiers. |
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc index 74fda0abe..f1386a8f9 100644 --- a/docs/user/readme.adoc +++ b/docs/user/readme.adoc | |||
@@ -6,10 +6,10 @@ | |||
6 | 6 | ||
7 | // Master copy of this document lives in the https://github.com/rust-analyzer/rust-analyzer repository | 7 | // Master copy of this document lives in the https://github.com/rust-analyzer/rust-analyzer repository |
8 | 8 | ||
9 | At it's core, rust-analyzer is a *library* for semantic analysis of the Rust code as it changes over time. | 9 | At its core, rust-analyzer is a *library* for semantic analysis of Rust code as it changes over time. |
10 | This manual focuses on a specific usage of the library -- the implementation of | 10 | This manual focuses on a specific usage of the library -- the implementation of |
11 | https://microsoft.github.io/language-server-protocol/[Language Server Protocol]. | 11 | https://microsoft.github.io/language-server-protocol/[Language Server Protocol]. |
12 | LSP allows various code editors, like VS Code, Emacs or Vim, to implement semantic feature like completion or goto definition by talking to an external language server process. | 12 | LSP allows various code editors, like VS Code, Emacs or Vim, to implement semantic features like completion or goto definition by talking to an external language server process. |
13 | 13 | ||
14 | To improve this document, send a pull request against | 14 | To improve this document, send a pull request against |
15 | https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/readme.adoc[this file]. | 15 | https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/readme.adoc[this file]. |
@@ -36,10 +36,9 @@ https://github.com/rust-analyzer/rust-analyzer/tree/master/editors/code[in tree] | |||
36 | 36 | ||
37 | You can install the latest release of the plugin from | 37 | You can install the latest release of the plugin from |
38 | https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[the marketplace]. | 38 | https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[the marketplace]. |
39 | By default, the plugin will download the matching version of the server as well. | 39 | By default, the plugin will prompt you to download the matching version of the server as well: |
40 | 40 | ||
41 | // FIXME: update the image (its text has changed) | 41 | image::https://user-images.githubusercontent.com/9021944/75067008-17502500-54ba-11ea-835a-f92aac50e866.png[] |
42 | image::https://user-images.githubusercontent.com/36276403/74103174-a40df100-4b52-11ea-81f4-372c70797924.png[] | ||
43 | 42 | ||
44 | The server binary is stored in `~/.config/Code/User/globalStorage/matklad.rust-analyzer`. | 43 | The server binary is stored in `~/.config/Code/User/globalStorage/matklad.rust-analyzer`. |
45 | 44 | ||
@@ -60,7 +59,7 @@ $ cargo xtask install | |||
60 | ---- | 59 | ---- |
61 | 60 | ||
62 | You'll need Cargo, nodejs and npm for this. | 61 | You'll need Cargo, nodejs and npm for this. |
63 | To make VS Code use the freshly build server, add this to the settings: | 62 | To make VS Code use the freshly built server, add this to the settings: |
64 | 63 | ||
65 | [source,json] | 64 | [source,json] |
66 | ---- | 65 | ---- |
@@ -72,7 +71,7 @@ Note that installing via `xtask install` does not work for VS Code Remote, inste | |||
72 | === Language Server Binary | 71 | === Language Server Binary |
73 | 72 | ||
74 | Other editors generally require `rust-analyzer` binary to be in `$PATH`. | 73 | Other editors generally require `rust-analyzer` binary to be in `$PATH`. |
75 | You can download pre-build binary from | 74 | You can download the pre-built binary from |
76 | https://github.com/rust-analyzer/rust-analyzer/releases[releases] | 75 | https://github.com/rust-analyzer/rust-analyzer/releases[releases] |
77 | page, or you can install it from source using the following command: | 76 | page, or you can install it from source using the following command: |
78 | 77 | ||
@@ -85,7 +84,7 @@ $ cargo xtask install --server | |||
85 | 84 | ||
86 | Emacs support is maintained https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-rust.el[upstream]. | 85 | Emacs support is maintained https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-rust.el[upstream]. |
87 | 86 | ||
88 | 1. Install recent version of `emacs-lsp` package by following the instructions https://github.com/emacs-lsp/lsp-mode[here]. | 87 | 1. Install the most recent version of `emacs-lsp` package by following the instructions https://github.com/emacs-lsp/lsp-mode[here]. |
89 | 2. Set `lsp-rust-server` to `'rust-analyzer`. | 88 | 2. Set `lsp-rust-server` to `'rust-analyzer`. |
90 | 3. Run `lsp` in a Rust buffer. | 89 | 3. Run `lsp` in a Rust buffer. |
91 | 4. (Optionally) bind commands like `lsp-rust-analyzer-join-lines`, `lsp-extend-selection` and `lsp-rust-analyzer-expand-macro` to keys. | 90 | 4. (Optionally) bind commands like `lsp-rust-analyzer-join-lines`, `lsp-extend-selection` and `lsp-rust-analyzer-expand-macro` to keys. |
@@ -112,7 +111,7 @@ The are several LSP client implementations for vim: | |||
112 | https://github.com/autozimu/LanguageClient-neovim[here] | 111 | https://github.com/autozimu/LanguageClient-neovim[here] |
113 | * The github project wiki has extra tips on configuration | 112 | * The github project wiki has extra tips on configuration |
114 | 113 | ||
115 | 2. Configure by adding this to your vim/neovim config file (replacing the existing rust specific line if it exists): | 114 | 2. Configure by adding this to your vim/neovim config file (replacing the existing Rust-specific line if it exists): |
116 | + | 115 | + |
117 | [source,vim] | 116 | [source,vim] |
118 | ---- | 117 | ---- |
@@ -123,7 +122,7 @@ let g:LanguageClient_serverCommands = { | |||
123 | 122 | ||
124 | ==== nvim-lsp | 123 | ==== nvim-lsp |
125 | 124 | ||
126 | NeoVim 0.5 (not yet released) has built in language server support. | 125 | NeoVim 0.5 (not yet released) has built-in language server support. |
127 | For a quick start configuration of rust-analyzer, use https://github.com/neovim/nvim-lsp#rust_analyzer[neovim/nvim-lsp]. | 126 | For a quick start configuration of rust-analyzer, use https://github.com/neovim/nvim-lsp#rust_analyzer[neovim/nvim-lsp]. |
128 | Once `neovim/nvim-lsp` is installed, use `lua require'nvim_lsp'.rust_analyzer.setup({})` in your `init.vim`. | 127 | Once `neovim/nvim-lsp` is installed, use `lua require'nvim_lsp'.rust_analyzer.setup({})` in your `init.vim`. |
129 | 128 | ||