aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--Cargo.lock78
-rw-r--r--ROADMAP.md77
-rw-r--r--crates/gen_lsp_server/src/lib.rs2
-rw-r--r--crates/ra_analysis/src/completion/mod.rs (renamed from crates/ra_analysis/src/completion.rs)328
-rw-r--r--crates/ra_analysis/src/completion/reference_completion.rs316
-rw-r--r--crates/ra_analysis/src/db.rs8
-rw-r--r--crates/ra_analysis/src/descriptors/function/scope.rs6
-rw-r--r--crates/ra_analysis/src/descriptors/module/imp.rs16
-rw-r--r--crates/ra_analysis/src/descriptors/module/mod.rs43
-rw-r--r--crates/ra_analysis/src/descriptors/module/scope.rs6
-rw-r--r--crates/ra_analysis/src/imp.rs41
-rw-r--r--crates/ra_analysis/src/lib.rs23
-rw-r--r--crates/ra_analysis/src/symbol_index.rs8
-rw-r--r--crates/ra_analysis/src/syntax_ptr.rs11
-rw-r--r--crates/ra_analysis/tests/tests.rs41
-rw-r--r--crates/ra_cli/src/main.rs10
-rw-r--r--crates/ra_editor/src/code_actions.rs19
-rw-r--r--crates/ra_editor/src/extend_selection.rs6
-rw-r--r--crates/ra_editor/src/folding_ranges.rs6
-rw-r--r--crates/ra_editor/src/lib.rs18
-rw-r--r--crates/ra_editor/src/line_index.rs219
-rw-r--r--crates/ra_editor/src/symbols.rs40
-rw-r--r--crates/ra_editor/src/test_utils.rs14
-rw-r--r--crates/ra_editor/src/typing.rs16
-rw-r--r--crates/ra_lsp_server/Cargo.toml2
-rw-r--r--crates/ra_lsp_server/src/caps.rs2
-rw-r--r--crates/ra_lsp_server/src/conv.rs23
-rw-r--r--crates/ra_lsp_server/src/main.rs41
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs28
-rw-r--r--crates/ra_lsp_server/src/main_loop/mod.rs24
-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/ast/generated.rs1326
-rw-r--r--crates/ra_syntax/src/ast/generated.rs.tera16
-rw-r--r--crates/ra_syntax/src/ast/mod.rs30
-rw-r--r--crates/ra_syntax/src/grammar.ron16
-rw-r--r--crates/ra_syntax/src/grammar/mod.rs2
-rw-r--r--crates/ra_syntax/src/lexer/ptr.rs3
-rw-r--r--crates/ra_syntax/src/lib.rs37
-rw-r--r--crates/ra_syntax/src/parser_impl/event.rs2
-rw-r--r--crates/ra_syntax/src/reparsing.rs8
-rw-r--r--crates/ra_syntax/src/string_lexing/byte.rs51
-rw-r--r--crates/ra_syntax/src/string_lexing/byte_string.rs51
-rw-r--r--crates/ra_syntax/src/string_lexing/char.rs176
-rw-r--r--crates/ra_syntax/src/string_lexing/mod.rs314
-rw-r--r--crates/ra_syntax/src/string_lexing/parser.rs201
-rw-r--r--crates/ra_syntax/src/string_lexing/string.rs46
-rw-r--r--crates/ra_syntax/src/syntax_kinds/generated.rs4
-rw-r--r--crates/ra_syntax/src/utils.rs5
-rw-r--r--crates/ra_syntax/src/validation.rs78
-rw-r--r--crates/ra_syntax/src/validation/byte.rs211
-rw-r--r--crates/ra_syntax/src/validation/byte_string.rs178
-rw-r--r--crates/ra_syntax/src/validation/char.rs276
-rw-r--r--crates/ra_syntax/src/validation/mod.rs24
-rw-r--r--crates/ra_syntax/src/validation/string.rs168
-rw-r--r--crates/ra_syntax/src/yellow/syntax_error.rs55
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0000_struct_field_missing_comma.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0001_item_recovery_in_file.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0002_duplicate_shebang.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0003_C++_semicolon.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0004_use_path_bad_segment.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0005_attribute_recover.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0006_named_field_recovery.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0007_stray_curly_in_file.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0008_item_block_recovery.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0009_broken_struct_type_parameter.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0010_unsafe_lambda_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0011_extern_struct.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0012_broken_lambda.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0013_invalid_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0014_where_no_bounds.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0015_curly_in_params.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0016_missing_semi.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0017_incomplete_binexpr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0018_incomplete_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0019_let_recover.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0020_fn_recover.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0021_incomplete_param.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0022_bad_exprs.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0023_mismatched_paren.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0024_many_type_parens.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0025_nope.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0026_imp_recovery.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0027_incomplere_where_for.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0001_const_unsafe_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0002_const_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0003_extern_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0004_extern_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0005_extern_crate.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0007_unsafe_trait.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0008_unsafe_impl.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0009_unsafe_auto_trait.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0010_unsafe_default_impl.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0011_unsafe_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0012_unsafe_extern_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0013_unsafe_block_in_mod.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0014_type_item_type_params.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0015_type_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0016_type_item_where_clause.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0017_paren_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0018_unit_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0019_singleton_tuple_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0020_never_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0021_pointer_type_no_mutability.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0022_pointer_type_mut.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0023_array_type_missing_semi.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0024_array_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0025_slice_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0026_reference_type;.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0027_placeholder_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0028_fn_pointer_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0030_fn_pointer_type_with_ret.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0031_for_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0032_path_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0034_bind_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0035_ref_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0036_placeholder_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0037_crate_visibility.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0038_function_ret_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0039_path_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0040_expr_literals.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0041_type_param_bounds.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0042_type_param_default.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0043_call_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0044_ref_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0045_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0046_default_impl.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0047_impl_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0048_impl_item_neg.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0049_trait_item_list.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0050_let_stmt;.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0051_method_call_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0052_field_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0053_block_items.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0054_field_pat_list.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0055_self_param.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0056_trait_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0057_auto_trait.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0058_type_arg.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0059_function_where_clause.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0060_function_type_params.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0061_struct_lit.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0063_impl_trait_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0063_lambda_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0064_param_list.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0065_if_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0066_lambda_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0067_block_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0068_pub_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0068_return_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0069_match_arm.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0070_match_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0071_tuple_pat_fields.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0072_path_part.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0073_impl_item_list.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0074_unary_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0075_try_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0076_cond.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0077_while_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0078_mod_contents.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0079_cast_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0080_tuple_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0081_index_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0082_tuple_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0083_postfix_range.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0084_loop_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0085_for_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0085_match_arms_commas.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0086_array_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0086_no_semi_after_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0089_slice_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0091_fn_decl.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0092_literal_pattern.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0093_path_fn_trait_args.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0094_range_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0095_path_type_with_bounds.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0096_value_parameters_no_patterns.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0097_param_list_opt_patterns.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0098_where_clause.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0099_crate_keyword_vis.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0100_dyn_trait_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0101_qual_paths.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0102_full_range_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0103_field_attrs.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0104_arb_self_types.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0105_continue_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0106_break_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0107_label.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0108_misplaced_label_err.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0109_struct_items.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0110_union_items.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0111_impl_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0112_crate_path.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0000_empty.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0001_struct_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0002_struct_item_field.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0004_file_shebang.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0005_fn_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0006_inner_attributes.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0008_mod_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0009_use_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0010_use_path_segments.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0011_outer_attribute.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0012_visibility.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0013_use_path_self_super.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0014_use_tree.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0015_use_tree.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0016_struct_flavors.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0017_attr_trailing_comma.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0018_struct_type_params.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0019_enums.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0020_type_param_bounds.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0021_extern_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0022_empty_extern_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0023_static_items.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0024_const_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0025_extern_fn_in_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0026_const_fn_in_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0027_unsafe_fn_in_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0028_operator_binding_power.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0029_range_forms.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0030_traits.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0031_extern.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0032_where_for.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0033_label_break.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0034_macro_2.0.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0034_macro_stuck.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0035_crate_path_in_call.txt2
-rw-r--r--crates/ra_syntax/tests/test.rs4
-rw-r--r--editors/code/src/server.ts5
-rw-r--r--editors/emacs/ra.el41
237 files changed, 3847 insertions, 1313 deletions
diff --git a/.travis.yml b/.travis.yml
index 49d53859d..4c691f670 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,8 @@
1cache: cargo 1cache: cargo
2before_cache: 2before_cache:
3 - find ./target/debug -type f -maxdepth 1 -delete 3 - find ./target/debug -type f -maxdepth 1 -delete
4 - rm -fr ./target/debug/{deps,.fingerprint}/{*ra_*,*test*} 4 - rm -fr ./target/debug/{deps,.fingerprint}/{*ra_*,*test*,*tools*,*gen_lsp*}
5 - rm -f ./target/.rustc_info.json
5 6
6env: 7env:
7 - CARGO_INCREMENTAL=0 8 - CARGO_INCREMENTAL=0
diff --git a/Cargo.lock b/Cargo.lock
index 80fbda23c..18aac79ab 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -174,7 +174,7 @@ dependencies = [
174 "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", 174 "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
175 "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 175 "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
176 "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 176 "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
177 "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 177 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
178 "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 178 "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
179 "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 179 "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
180 "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 180 "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -188,7 +188,7 @@ dependencies = [
188 "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", 188 "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
189 "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 189 "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
190 "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 190 "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
191 "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 191 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
192 "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 192 "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
193 "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 193 "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
194] 194]
@@ -208,12 +208,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
208 208
209[[package]] 209[[package]]
210name = "derive-new" 210name = "derive-new"
211version = "0.5.5" 211version = "0.5.6"
212source = "registry+https://github.com/rust-lang/crates.io-index" 212source = "registry+https://github.com/rust-lang/crates.io-index"
213dependencies = [ 213dependencies = [
214 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", 214 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
215 "quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 215 "quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
216 "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", 216 "syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)",
217] 217]
218 218
219[[package]] 219[[package]]
@@ -268,7 +268,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
268dependencies = [ 268dependencies = [
269 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", 269 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
270 "quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 270 "quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
271 "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", 271 "syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)",
272 "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 272 "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
273] 273]
274 274
@@ -279,13 +279,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
279 279
280[[package]] 280[[package]]
281name = "flexi_logger" 281name = "flexi_logger"
282version = "0.9.3" 282version = "0.10.0"
283source = "registry+https://github.com/rust-lang/crates.io-index" 283source = "registry+https://github.com/rust-lang/crates.io-index"
284dependencies = [ 284dependencies = [
285 "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 285 "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
286 "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 286 "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
287 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 287 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
288 "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 288 "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
289] 289]
290 290
291[[package]] 291[[package]]
@@ -317,7 +317,7 @@ version = "0.1.0"
317dependencies = [ 317dependencies = [
318 "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 318 "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
319 "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 319 "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
320 "languageserver-types 0.51.0 (registry+https://github.com/rust-lang/crates.io-index)", 320 "languageserver-types 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
321 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 321 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
322 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", 322 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
323 "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", 323 "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -394,7 +394,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
394 394
395[[package]] 395[[package]]
396name = "languageserver-types" 396name = "languageserver-types"
397version = "0.51.0" 397version = "0.51.1"
398source = "registry+https://github.com/rust-lang/crates.io-index" 398source = "registry+https://github.com/rust-lang/crates.io-index"
399dependencies = [ 399dependencies = [
400 "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)",
@@ -403,17 +403,14 @@ dependencies = [
403 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", 403 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
404 "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", 404 "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
405 "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", 405 "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
406 "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 406 "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
407 "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)",
408] 408]
409 409
410[[package]] 410[[package]]
411name = "lazy_static" 411name = "lazy_static"
412version = "1.1.0" 412version = "1.2.0"
413source = "registry+https://github.com/rust-lang/crates.io-index" 413source = "registry+https://github.com/rust-lang/crates.io-index"
414dependencies = [
415 "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
416]
417 414
418[[package]] 415[[package]]
419name = "libc" 416name = "libc"
@@ -484,7 +481,7 @@ dependencies = [
484 "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 481 "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
485 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", 482 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
486 "quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 483 "quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
487 "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", 484 "syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)",
488] 485]
489 486
490[[package]] 487[[package]]
@@ -605,7 +602,7 @@ dependencies = [
605 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 602 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
606 "ra_editor 0.1.0", 603 "ra_editor 0.1.0",
607 "ra_syntax 0.1.0", 604 "ra_syntax 0.1.0",
608 "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 605 "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
609 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 606 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
610 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 607 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
611 "salsa 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 608 "salsa 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -645,15 +642,15 @@ dependencies = [
645 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 642 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
646 "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 643 "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
647 "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 644 "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
648 "flexi_logger 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", 645 "flexi_logger 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
649 "gen_lsp_server 0.1.0", 646 "gen_lsp_server 0.1.0",
650 "im 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 647 "im 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
651 "languageserver-types 0.51.0 (registry+https://github.com/rust-lang/crates.io-index)", 648 "languageserver-types 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
652 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 649 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
653 "ra_analysis 0.1.0", 650 "ra_analysis 0.1.0",
654 "ra_editor 0.1.0", 651 "ra_editor 0.1.0",
655 "ra_syntax 0.1.0", 652 "ra_syntax 0.1.0",
656 "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 653 "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
657 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 654 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
658 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 655 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
659 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", 656 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -671,6 +668,7 @@ dependencies = [
671name = "ra_syntax" 668name = "ra_syntax"
672version = "0.1.0" 669version = "0.1.0"
673dependencies = [ 670dependencies = [
671 "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
674 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 672 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
675 "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", 673 "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
676 "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", 674 "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -718,7 +716,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
718 716
719[[package]] 717[[package]]
720name = "rayon" 718name = "rayon"
721version = "1.0.2" 719version = "1.0.3"
722source = "registry+https://github.com/rust-lang/crates.io-index" 720source = "registry+https://github.com/rust-lang/crates.io-index"
723dependencies = [ 721dependencies = [
724 "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 722 "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -732,7 +730,7 @@ version = "1.4.1"
732source = "registry+https://github.com/rust-lang/crates.io-index" 730source = "registry+https://github.com/rust-lang/crates.io-index"
733dependencies = [ 731dependencies = [
734 "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 732 "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
735 "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 733 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
736 "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 734 "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
737 "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 735 "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
738] 736]
@@ -752,7 +750,7 @@ dependencies = [
752 750
753[[package]] 751[[package]]
754name = "regex" 752name = "regex"
755version = "1.0.5" 753version = "1.0.6"
756source = "registry+https://github.com/rust-lang/crates.io-index" 754source = "registry+https://github.com/rust-lang/crates.io-index"
757dependencies = [ 755dependencies = [
758 "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 756 "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -839,7 +837,7 @@ name = "salsa"
839version = "0.8.0" 837version = "0.8.0"
840source = "registry+https://github.com/rust-lang/crates.io-index" 838source = "registry+https://github.com/rust-lang/crates.io-index"
841dependencies = [ 839dependencies = [
842 "derive-new 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", 840 "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
843 "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 841 "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
844 "lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 842 "lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
845 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 843 "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -890,7 +888,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
890dependencies = [ 888dependencies = [
891 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", 889 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
892 "quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 890 "quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
893 "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", 891 "syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)",
894] 892]
895 893
896[[package]] 894[[package]]
@@ -965,7 +963,7 @@ dependencies = [
965 963
966[[package]] 964[[package]]
967name = "syn" 965name = "syn"
968version = "0.15.17" 966version = "0.15.18"
969source = "registry+https://github.com/rust-lang/crates.io-index" 967source = "registry+https://github.com/rust-lang/crates.io-index"
970dependencies = [ 968dependencies = [
971 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", 969 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -980,7 +978,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
980dependencies = [ 978dependencies = [
981 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", 979 "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
982 "quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 980 "quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
983 "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", 981 "syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)",
984 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 982 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
985] 983]
986 984
@@ -1002,15 +1000,15 @@ dependencies = [
1002 "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 1000 "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
1003 "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 1001 "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
1004 "humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1002 "humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1005 "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1003 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1006 "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1004 "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1007 "pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1005 "pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1008 "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1006 "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
1009 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", 1007 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
1010 "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", 1008 "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
1011 "slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 1009 "slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
1012 "unic-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 1010 "unic-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
1013 "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1011 "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
1014] 1012]
1015 1013
1016[[package]] 1014[[package]]
@@ -1064,7 +1062,7 @@ name = "thread_local"
1064version = "0.3.6" 1062version = "0.3.6"
1065source = "registry+https://github.com/rust-lang/crates.io-index" 1063source = "registry+https://github.com/rust-lang/crates.io-index"
1066dependencies = [ 1064dependencies = [
1067 "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1065 "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1068] 1066]
1069 1067
1070[[package]] 1068[[package]]
@@ -1185,7 +1183,7 @@ dependencies = [
1185 1183
1186[[package]] 1184[[package]]
1187name = "url" 1185name = "url"
1188version = "1.7.1" 1186version = "1.7.2"
1189source = "registry+https://github.com/rust-lang/crates.io-index" 1187source = "registry+https://github.com/rust-lang/crates.io-index"
1190dependencies = [ 1188dependencies = [
1191 "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1189 "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1199,7 +1197,7 @@ version = "0.2.0"
1199source = "registry+https://github.com/rust-lang/crates.io-index" 1197source = "registry+https://github.com/rust-lang/crates.io-index"
1200dependencies = [ 1198dependencies = [
1201 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", 1199 "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
1202 "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1200 "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
1203] 1201]
1204 1202
1205[[package]] 1203[[package]]
@@ -1284,7 +1282,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1284"checksum crossbeam-epoch 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c90f1474584f38e270b5b613e898c8c328aa4f3dea85e0a27ac2e642f009416" 1282"checksum crossbeam-epoch 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c90f1474584f38e270b5b613e898c8c328aa4f3dea85e0a27ac2e642f009416"
1285"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" 1283"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
1286"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" 1284"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
1287"checksum derive-new 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "899ec79626c14e00ccc9729b4d750bbe67fe76a8f436824c16e0233bbd9d7daa" 1285"checksum derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6ca414e896ae072546f4d789f452daaecf60ddee4c9df5dc6d5936d769e3d87c"
1288"checksum deunicode 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" 1286"checksum deunicode 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690"
1289"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 1287"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
1290"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" 1288"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
@@ -1294,7 +1292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1294"checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7" 1292"checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7"
1295"checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596" 1293"checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596"
1296"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 1294"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
1297"checksum flexi_logger 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7992096ba2290bd35b86b282e72edae518a25aa9a067ff417bc017ae63ac5e22" 1295"checksum flexi_logger 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "553854ebfebeae44ba699a9dc7d53a4036ccc01cd1e144aea0e3054c54383733"
1298"checksum fst 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9b0408ab57c1bf7c634b2ac6a165d14f642dc3335a43203090a7f8c78b54577b" 1296"checksum fst 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9b0408ab57c1bf7c634b2ac6a165d14f642dc3335a43203090a7f8c78b54577b"
1299"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 1297"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
1300"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 1298"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
@@ -1308,8 +1306,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1308"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" 1306"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
1309"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" 1307"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
1310"checksum join_to_string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7bddc885f3fd69dd4b5d747c2efe6dd2c36d795ea9938281ed50910e32c95e31" 1308"checksum join_to_string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7bddc885f3fd69dd4b5d747c2efe6dd2c36d795ea9938281ed50910e32c95e31"
1311"checksum languageserver-types 0.51.0 (registry+https://github.com/rust-lang/crates.io-index)" = "caecadd973c43c93f5ce96fa457da310113d867af28808a8ed74023e9887a39e" 1309"checksum languageserver-types 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)" = "68de833188ada4e175d04a028f03f244f6370eedbcc75a05604d47d925933f69"
1312"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" 1310"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
1313"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" 1311"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
1314"checksum lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775751a3e69bde4df9b38dd00a1b5d6ac13791e4223d4a0506577f0dd27cfb7a" 1312"checksum lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775751a3e69bde4df9b38dd00a1b5d6ac13791e4223d4a0506577f0dd27cfb7a"
1315"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" 1313"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
@@ -1337,11 +1335,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1337"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" 1335"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
1338"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" 1336"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" 1337"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
1340"checksum rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df7a791f788cb4c516f0e091301a29c2b71ef680db5e644a7d68835c8ae6dbfa" 1338"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473"
1341"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" 1339"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"
1342"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" 1340"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
1343"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" 1341"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
1344"checksum regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2069749032ea3ec200ca51e4a31df41759190a88edca0d2d86ee8bedf7073341" 1342"checksum regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ee84f70c8c08744ea9641a731c7fadb475bf2ecc52d7f627feb833e0b3990467"
1345"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d" 1343"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d"
1346"checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c" 1344"checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c"
1347"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" 1345"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
@@ -1368,7 +1366,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1368"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" 1366"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
1369"checksum superslice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50b13d42370e0f5fc62eafdd5c2d20065eaf5458dab215ff3e20e63eea96b30" 1367"checksum superslice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50b13d42370e0f5fc62eafdd5c2d20065eaf5458dab215ff3e20e63eea96b30"
1370"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" 1368"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
1371"checksum syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)" = "3391038ebc3e4ab24eb028cb0ef2f2dc4ba0cbf72ee895ed6a6fad730640b5bc" 1369"checksum syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)" = "90c39a061e2f412a9f869540471ab679e85e50c6b05604daf28bc3060f75c430"
1372"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" 1370"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
1373"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" 1371"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
1374"checksum tera 0.11.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac6d8ad623a7efcfb4367ce2a36f84ef849d5aa3c7bcf2e0324c4cbcc57ebaf" 1372"checksum tera 0.11.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac6d8ad623a7efcfb4367ce2a36f84ef849d5aa3c7bcf2e0324c4cbcc57ebaf"
@@ -1393,7 +1391,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1393"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" 1391"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
1394"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1392"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
1395"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" 1393"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
1396"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" 1394"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
1397"checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" 1395"checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea"
1398"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" 1396"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
1399"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 1397"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
diff --git a/ROADMAP.md b/ROADMAP.md
new file mode 100644
index 000000000..951a092b4
--- /dev/null
+++ b/ROADMAP.md
@@ -0,0 +1,77 @@
1# Rust Analyzer Roadmap 01
2
3Written on 2018-11-06, extends approximately to February 2019.
4After that, we should coordinate with the compiler/rls developers to align goals and share code and experience.
5
6
7# Overall Goals
8
9The mission is:
10 * Provide an excellent "code analyzed as you type" IDE experience for the Rust language,
11 * Implement the bulk of the features in Rust itself.
12
13
14High-level architecture constraints:
15 * Long-term, replace the current rustc frontend.
16 It's *obvious* that the code should be shared, but OTOH, all great IDEs started as from-scratch rewrites.
17 * Don't hard-code a particular protocol or mode of operation.
18 Produce a library which could be used for implementing an LSP server, or for in-process embedding.
19 * As long as possible, stick with stable Rust (NB: we currently use beta for 2018 edition and salsa).
20
21
22# Current Goals
23
24Ideally, we would be coordinating with the compiler/rls teams, but they are busy working on making Rust 2018 at the moment.
25The sync-up point will happen some time after the edition, probably early 2019.
26In the meantime, the goal is to **experiment**, specifically, to figure out how a from-scratch written RLS might look like.
27
28
29## Data Storage and Protocol implementation
30
31The fundamental part of any architecture is who owns which data, how the data is mutated and how the data is exposed to user.
32For storage we use the [salsa](http://github.com/salsa-rs/salsa) library, which provides a solid model that seems to be the way to go.
33
34Modification to source files is mostly driven by the language client, but we also should support watching the file system. The current
35file watching implementation is a stub.
36
37**Action Item:** implement reliable file watching service.
38
39We also should extract LSP bits as a reusable library. There's already `gen_lsp_server`, but it is pretty limited.
40
41**Action Item:** try using `gen_lsp_server` in more than one language server, for example for TOML and Nix.
42
43The ideal architecture for `gen_lsp_server` is still unclear. I'd rather avoid futures: they bring significant runtime complexity
44(call stacks become insane) and the performance benefits are negligible for our use case (one thread per request is perfectly OK given
45the low amount of requests a language server receives). The current interface is based on crossbeam-channel, but it's not clear
46if that is the best choice.
47
48
49## Low-effort, high payoff features
50
51Implementing 20% of type inference will give use 80% of completion.
52Thus it makes sense to partially implement name resolution, type inference and trait matching, even though there is a chance that
53this code is replaced later on when we integrate with the compiler
54
55Specifically, we need to:
56
57* **Action Item:** implement path resolution, so that we get completion in imports and such.
58* **Action Item:** implement simple type inference, so that we get completion for inherent methods.
59* **Action Item:** implement nicer completion infrastructure, so that we have icons, snippets, doc comments, after insert callbacks, ...
60
61
62## Dragons to kill
63
64To make experiments most effective, we should try to prototype solutions for the hardest problems.
65In the case of Rust, the two hardest problems are:
66 * Conditional compilation and source/model mismatch.
67 A single source file might correspond to several entities in the semantic model.
68 For example, different cfg flags produce effectively different crates from the same source.
69 * Macros are intertwined with name resolution in a single fix-point iteration algorithm.
70 This is just plain hard to implement, but also interacts poorly with on-demand.
71
72
73For the first bullet point, we need to design descriptors infra and explicit mapping step between sources and semantic model, which is intentionally fuzzy in one direction.
74The **action item** here is basically "write code, see what works, keep high-level picture in mind".
75
76For the second bullet point, there's hope that salsa with its deep memoization will result in a fast enough solution even without being fully on-demand.
77Again, the **action item** is to write the code and see what works. Salsa itself uses macros heavily, so it should be a great test.
diff --git a/crates/gen_lsp_server/src/lib.rs b/crates/gen_lsp_server/src/lib.rs
index e45a6b5e2..5dab8f408 100644
--- a/crates/gen_lsp_server/src/lib.rs
+++ b/crates/gen_lsp_server/src/lib.rs
@@ -1,4 +1,4 @@
1//! A language server scaffold, exposing synchroneous crossbeam-channel based API. 1//! A language server scaffold, exposing a synchronous crossbeam-channel based API.
2//! This crate handles protocol handshaking and parsing messages, while you 2//! This crate handles protocol handshaking and parsing messages, while you
3//! control the message dispatch loop yourself. 3//! control the message dispatch loop yourself.
4//! 4//!
diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion/mod.rs
index 7c3476e5c..2e082705e 100644
--- a/crates/ra_analysis/src/completion.rs
+++ b/crates/ra_analysis/src/completion/mod.rs
@@ -1,20 +1,20 @@
1mod reference_completion;
2
1use ra_editor::find_node_at_offset; 3use ra_editor::find_node_at_offset;
2use ra_syntax::{ 4use ra_syntax::{
3 algo::visit::{visitor, visitor_ctx, Visitor, VisitorCtx}, 5 algo::find_leaf_at_offset,
4 ast::{self, AstChildren, LoopBodyOwner, ModuleItemOwner}, 6 algo::visit::{visitor_ctx, VisitorCtx},
5 AstNode, AtomEdit, File, 7 ast,
6 SyntaxKind::*, 8 AstNode, AtomEdit,
7 SyntaxNodeRef, TextUnit, 9 SyntaxNodeRef,
8}; 10};
9use rustc_hash::{FxHashMap, FxHashSet}; 11use rustc_hash::{FxHashMap};
10 12
11use crate::{ 13use crate::{
12 db::{self, SyntaxDatabase}, 14 db::{self, SyntaxDatabase},
13 descriptors::function::FnScopes, 15 descriptors::{DescriptorDatabase, module::ModuleSource},
14 descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource}, 16 input::{FilesDatabase},
15 descriptors::DescriptorDatabase, 17 Cancelable, FilePosition
16 input::FilesDatabase,
17 Cancelable, FilePosition,
18}; 18};
19 19
20#[derive(Debug)] 20#[derive(Debug)]
@@ -27,175 +27,65 @@ pub struct CompletionItem {
27 pub snippet: Option<String>, 27 pub snippet: Option<String>,
28} 28}
29 29
30pub(crate) fn resolve_based_completion( 30pub(crate) fn completions(
31 db: &db::RootDatabase, 31 db: &db::RootDatabase,
32 position: FilePosition, 32 position: FilePosition,
33) -> Cancelable<Option<Vec<CompletionItem>>> { 33) -> Cancelable<Option<Vec<CompletionItem>>> {
34 let source_root_id = db.file_source_root(position.file_id); 34 let original_file = db.file_syntax(position.file_id);
35 let file = db.file_syntax(position.file_id); 35 // Insert a fake ident to get a valid parse tree
36 let module_tree = db.module_tree(source_root_id)?;
37 let module_id = match module_tree.any_module_for_source(ModuleSource::File(position.file_id)) {
38 None => return Ok(None),
39 Some(it) => it,
40 };
41 let file = { 36 let file = {
42 let edit = AtomEdit::insert(position.offset, "intellijRulezz".to_string()); 37 let edit = AtomEdit::insert(position.offset, "intellijRulezz".to_string());
43 file.reparse(&edit) 38 original_file.reparse(&edit)
39 };
40
41 let leaf = match find_leaf_at_offset(original_file.syntax(), position.offset).left_biased() {
42 None => return Ok(None),
43 Some(it) => it,
44 }; 44 };
45 let target_module_id = match find_target_module(&module_tree, module_id, &file, position.offset) 45 let source_root_id = db.file_source_root(position.file_id);
46 { 46 let module_tree = db.module_tree(source_root_id)?;
47 let module_source = ModuleSource::for_node(position.file_id, leaf);
48 let module_id = match module_tree.any_module_for_source(module_source) {
47 None => return Ok(None), 49 None => return Ok(None),
48 Some(it) => it, 50 Some(it) => it,
49 }; 51 };
50 let module_scope = db.module_scope(source_root_id, target_module_id)?;
51 let res: Vec<_> = module_scope
52 .entries()
53 .iter()
54 .map(|entry| CompletionItem {
55 label: entry.name().to_string(),
56 lookup: None,
57 snippet: None,
58 })
59 .collect();
60 Ok(Some(res))
61}
62
63pub(crate) fn find_target_module(
64 module_tree: &ModuleTree,
65 module_id: ModuleId,
66 file: &File,
67 offset: TextUnit,
68) -> Option<ModuleId> {
69 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset)?;
70 let mut crate_path = crate_path(name_ref)?;
71
72 crate_path.pop();
73 let mut target_module = module_id.root(&module_tree);
74 for name in crate_path {
75 target_module = target_module.child(module_tree, name.text().as_str())?;
76 }
77 Some(target_module)
78}
79 52
80fn crate_path(name_ref: ast::NameRef) -> Option<Vec<ast::NameRef>> {
81 let mut path = name_ref
82 .syntax()
83 .parent()
84 .and_then(ast::PathSegment::cast)?
85 .parent_path();
86 let mut res = Vec::new(); 53 let mut res = Vec::new();
87 loop {
88 let segment = path.segment()?;
89 match segment.kind()? {
90 ast::PathSegmentKind::Name(name) => res.push(name),
91 ast::PathSegmentKind::CrateKw => break,
92 ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw => return None,
93 }
94 path = path.qualifier()?;
95 }
96 res.reverse();
97 Some(res)
98}
99
100pub(crate) fn scope_completion(
101 db: &db::RootDatabase,
102 position: FilePosition,
103) -> Option<Vec<CompletionItem>> {
104 let original_file = db.file_syntax(position.file_id);
105 // Insert a fake ident to get a valid parse tree
106 let file = {
107 let edit = AtomEdit::insert(position.offset, "intellijRulezz".to_string());
108 original_file.reparse(&edit)
109 };
110 let mut has_completions = false; 54 let mut has_completions = false;
111 let mut res = Vec::new(); 55 // First, let's try to complete a reference to some declaration.
112 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { 56 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
113 has_completions = true; 57 has_completions = true;
114 complete_name_ref(&file, name_ref, &mut res); 58 reference_completion::completions(
59 &mut res,
60 db,
61 source_root_id,
62 &module_tree,
63 module_id,
64 &file,
65 name_ref,
66 )?;
115 // special case, `trait T { fn foo(i_am_a_name_ref) {} }` 67 // special case, `trait T { fn foo(i_am_a_name_ref) {} }`
116 if is_node::<ast::Param>(name_ref.syntax()) { 68 if is_node::<ast::Param>(name_ref.syntax()) {
117 param_completions(name_ref.syntax(), &mut res); 69 param_completions(name_ref.syntax(), &mut res);
118 } 70 }
119 let name_range = name_ref.syntax().range();
120 let top_node = name_ref
121 .syntax()
122 .ancestors()
123 .take_while(|it| it.range() == name_range)
124 .last()
125 .unwrap();
126 match top_node.parent().map(|it| it.kind()) {
127 Some(ROOT) | Some(ITEM_LIST) => complete_mod_item_snippets(&mut res),
128 _ => (),
129 }
130 } 71 }
72
73 // Otherwise, if this is a declaration, use heuristics to suggest a name.
131 if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) { 74 if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) {
132 if is_node::<ast::Param>(name.syntax()) { 75 if is_node::<ast::Param>(name.syntax()) {
133 has_completions = true; 76 has_completions = true;
134 param_completions(name.syntax(), &mut res); 77 param_completions(name.syntax(), &mut res);
135 } 78 }
136 } 79 }
137 if has_completions { 80 let res = if has_completions { Some(res) } else { None };
138 Some(res) 81 Ok(res)
139 } else {
140 None
141 }
142}
143
144fn complete_module_items(
145 file: &File,
146 items: AstChildren<ast::ModuleItem>,
147 this_item: Option<ast::NameRef>,
148 acc: &mut Vec<CompletionItem>,
149) {
150 let scope = ModuleScope::new(items); // FIXME
151 acc.extend(
152 scope
153 .entries()
154 .iter()
155 .filter(|entry| {
156 let syntax = entry.ptr().resolve(file);
157 Some(syntax.borrowed()) != this_item.map(|it| it.syntax())
158 })
159 .map(|entry| CompletionItem {
160 label: entry.name().to_string(),
161 lookup: None,
162 snippet: None,
163 }),
164 );
165}
166
167fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) {
168 if !is_node::<ast::Path>(name_ref.syntax()) {
169 return;
170 }
171 let mut visited_fn = false;
172 for node in name_ref.syntax().ancestors() {
173 if let Some(items) = visitor()
174 .visit::<ast::Root, _>(|it| Some(it.items()))
175 .visit::<ast::Module, _>(|it| Some(it.item_list()?.items()))
176 .accept(node)
177 {
178 if let Some(items) = items {
179 complete_module_items(file, items, Some(name_ref), acc);
180 }
181 break;
182 } else if !visited_fn {
183 if let Some(fn_def) = ast::FnDef::cast(node) {
184 visited_fn = true;
185 complete_expr_keywords(&file, fn_def, name_ref, acc);
186 complete_expr_snippets(acc);
187 let scopes = FnScopes::new(fn_def);
188 complete_fn(name_ref, &scopes, acc);
189 }
190 }
191 }
192} 82}
193 83
194fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) { 84fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) {
195 let mut params = FxHashMap::default(); 85 let mut params = FxHashMap::default();
196 for node in ctx.ancestors() { 86 for node in ctx.ancestors() {
197 let _ = visitor_ctx(&mut params) 87 let _ = visitor_ctx(&mut params)
198 .visit::<ast::Root, _>(process) 88 .visit::<ast::SourceFile, _>(process)
199 .visit::<ast::ItemList, _>(process) 89 .visit::<ast::ItemList, _>(process)
200 .accept(node); 90 .accept(node);
201 } 91 }
@@ -238,140 +128,6 @@ fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool {
238 } 128 }
239} 129}
240 130
241fn complete_expr_keywords(
242 file: &File,
243 fn_def: ast::FnDef,
244 name_ref: ast::NameRef,
245 acc: &mut Vec<CompletionItem>,
246) {
247 acc.push(keyword("if", "if $0 {}"));
248 acc.push(keyword("match", "match $0 {}"));
249 acc.push(keyword("while", "while $0 {}"));
250 acc.push(keyword("loop", "loop {$0}"));
251
252 if let Some(off) = name_ref.syntax().range().start().checked_sub(2.into()) {
253 if let Some(if_expr) = find_node_at_offset::<ast::IfExpr>(file.syntax(), off) {
254 if if_expr.syntax().range().end() < name_ref.syntax().range().start() {
255 acc.push(keyword("else", "else {$0}"));
256 acc.push(keyword("else if", "else if $0 {}"));
257 }
258 }
259 }
260 if is_in_loop_body(name_ref) {
261 acc.push(keyword("continue", "continue"));
262 acc.push(keyword("break", "break"));
263 }
264 acc.extend(complete_return(fn_def, name_ref));
265}
266
267fn is_in_loop_body(name_ref: ast::NameRef) -> bool {
268 for node in name_ref.syntax().ancestors() {
269 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR {
270 break;
271 }
272 let loop_body = visitor()
273 .visit::<ast::ForExpr, _>(LoopBodyOwner::loop_body)
274 .visit::<ast::WhileExpr, _>(LoopBodyOwner::loop_body)
275 .visit::<ast::LoopExpr, _>(LoopBodyOwner::loop_body)
276 .accept(node);
277 if let Some(Some(body)) = loop_body {
278 if name_ref
279 .syntax()
280 .range()
281 .is_subrange(&body.syntax().range())
282 {
283 return true;
284 }
285 }
286 }
287 false
288}
289
290fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<CompletionItem> {
291 // let is_last_in_block = name_ref.syntax().ancestors().filter_map(ast::Expr::cast)
292 // .next()
293 // .and_then(|it| it.syntax().parent())
294 // .and_then(ast::Block::cast)
295 // .is_some();
296
297 // if is_last_in_block {
298 // return None;
299 // }
300
301 let is_stmt = match name_ref
302 .syntax()
303 .ancestors()
304 .filter_map(ast::ExprStmt::cast)
305 .next()
306 {
307 None => false,
308 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(),
309 };
310 let snip = match (is_stmt, fn_def.ret_type().is_some()) {
311 (true, true) => "return $0;",
312 (true, false) => "return;",
313 (false, true) => "return $0",
314 (false, false) => "return",
315 };
316 Some(keyword("return", snip))
317}
318
319fn keyword(kw: &str, snip: &str) -> CompletionItem {
320 CompletionItem {
321 label: kw.to_string(),
322 lookup: None,
323 snippet: Some(snip.to_string()),
324 }
325}
326
327fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) {
328 acc.push(CompletionItem {
329 label: "pd".to_string(),
330 lookup: None,
331 snippet: Some("eprintln!(\"$0 = {:?}\", $0);".to_string()),
332 });
333 acc.push(CompletionItem {
334 label: "ppd".to_string(),
335 lookup: None,
336 snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()),
337 });
338}
339
340fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) {
341 acc.push(CompletionItem {
342 label: "tfn".to_string(),
343 lookup: None,
344 snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()),
345 });
346 acc.push(CompletionItem {
347 label: "pub(crate)".to_string(),
348 lookup: None,
349 snippet: Some("pub(crate) $0".to_string()),
350 })
351}
352
353fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
354 let mut shadowed = FxHashSet::default();
355 acc.extend(
356 scopes
357 .scope_chain(name_ref.syntax())
358 .flat_map(|scope| scopes.entries(scope).iter())
359 .filter(|entry| shadowed.insert(entry.name()))
360 .map(|entry| CompletionItem {
361 label: entry.name().to_string(),
362 lookup: None,
363 snippet: None,
364 }),
365 );
366 if scopes.self_param.is_some() {
367 acc.push(CompletionItem {
368 label: "self".to_string(),
369 lookup: None,
370 snippet: None,
371 })
372 }
373}
374
375#[cfg(test)] 131#[cfg(test)]
376mod tests { 132mod tests {
377 use test_utils::assert_eq_dbg; 133 use test_utils::assert_eq_dbg;
@@ -382,7 +138,8 @@ mod tests {
382 138
383 fn check_scope_completion(code: &str, expected_completions: &str) { 139 fn check_scope_completion(code: &str, expected_completions: &str) {
384 let (analysis, position) = single_file_with_position(code); 140 let (analysis, position) = single_file_with_position(code);
385 let completions = scope_completion(&analysis.imp.db, position) 141 let completions = completions(&analysis.imp.db, position)
142 .unwrap()
386 .unwrap() 143 .unwrap()
387 .into_iter() 144 .into_iter()
388 .filter(|c| c.snippet.is_none()) 145 .filter(|c| c.snippet.is_none())
@@ -392,7 +149,8 @@ mod tests {
392 149
393 fn check_snippet_completion(code: &str, expected_completions: &str) { 150 fn check_snippet_completion(code: &str, expected_completions: &str) {
394 let (analysis, position) = single_file_with_position(code); 151 let (analysis, position) = single_file_with_position(code);
395 let completions = scope_completion(&analysis.imp.db, position) 152 let completions = completions(&analysis.imp.db, position)
153 .unwrap()
396 .unwrap() 154 .unwrap()
397 .into_iter() 155 .into_iter()
398 .filter(|c| c.snippet.is_some()) 156 .filter(|c| c.snippet.is_some())
diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs
new file mode 100644
index 000000000..6c5fd0be6
--- /dev/null
+++ b/crates/ra_analysis/src/completion/reference_completion.rs
@@ -0,0 +1,316 @@
1use rustc_hash::{FxHashSet};
2use ra_editor::find_node_at_offset;
3use ra_syntax::{
4 algo::visit::{visitor, Visitor},
5 SourceFileNode, AstNode,
6 ast::{self, LoopBodyOwner},
7 SyntaxKind::*,
8};
9
10use crate::{
11 db::RootDatabase,
12 input::{SourceRootId},
13 completion::CompletionItem,
14 descriptors::module::{ModuleId, ModuleTree},
15 descriptors::function::FnScopes,
16 descriptors::DescriptorDatabase,
17 Cancelable
18};
19
20pub(super) fn completions(
21 acc: &mut Vec<CompletionItem>,
22 db: &RootDatabase,
23 source_root_id: SourceRootId,
24 module_tree: &ModuleTree,
25 module_id: ModuleId,
26 file: &SourceFileNode,
27 name_ref: ast::NameRef,
28) -> Cancelable<()> {
29 let kind = match classify_name_ref(name_ref) {
30 Some(it) => it,
31 None => return Ok(()),
32 };
33
34 match kind {
35 NameRefKind::LocalRef { enclosing_fn } => {
36 if let Some(fn_def) = enclosing_fn {
37 let scopes = FnScopes::new(fn_def);
38 complete_fn(name_ref, &scopes, acc);
39 complete_expr_keywords(&file, fn_def, name_ref, acc);
40 complete_expr_snippets(acc);
41 }
42
43 let module_scope = db.module_scope(source_root_id, module_id)?;
44 acc.extend(
45 module_scope
46 .entries()
47 .iter()
48 .filter(|entry| {
49 // Don't expose this item
50 !entry.ptr().range().is_subrange(&name_ref.syntax().range())
51 })
52 .map(|entry| CompletionItem {
53 label: entry.name().to_string(),
54 lookup: None,
55 snippet: None,
56 }),
57 );
58 }
59 NameRefKind::CratePath(path) => {
60 complete_path(acc, db, source_root_id, module_tree, module_id, path)?
61 }
62 NameRefKind::BareIdentInMod => {
63 let name_range = name_ref.syntax().range();
64 let top_node = name_ref
65 .syntax()
66 .ancestors()
67 .take_while(|it| it.range() == name_range)
68 .last()
69 .unwrap();
70 match top_node.parent().map(|it| it.kind()) {
71 Some(SOURCE_FILE) | Some(ITEM_LIST) => complete_mod_item_snippets(acc),
72 _ => (),
73 }
74 }
75 }
76 Ok(())
77}
78
79enum NameRefKind<'a> {
80 /// NameRef is a part of single-segment path, for example, a refernece to a
81 /// local variable.
82 LocalRef {
83 enclosing_fn: Option<ast::FnDef<'a>>,
84 },
85 /// NameRef is the last segment in crate:: path
86 CratePath(Vec<ast::NameRef<'a>>),
87 /// NameRef is bare identifier at the module's root.
88 /// Used for keyword completion
89 BareIdentInMod,
90}
91
92fn classify_name_ref(name_ref: ast::NameRef) -> Option<NameRefKind> {
93 let name_range = name_ref.syntax().range();
94 let top_node = name_ref
95 .syntax()
96 .ancestors()
97 .take_while(|it| it.range() == name_range)
98 .last()
99 .unwrap();
100 match top_node.parent().map(|it| it.kind()) {
101 Some(SOURCE_FILE) | Some(ITEM_LIST) => return Some(NameRefKind::BareIdentInMod),
102 _ => (),
103 }
104
105 let parent = name_ref.syntax().parent()?;
106 if let Some(segment) = ast::PathSegment::cast(parent) {
107 let path = segment.parent_path();
108 if let Some(crate_path) = crate_path(path) {
109 return Some(NameRefKind::CratePath(crate_path));
110 }
111 if path.qualifier().is_none() {
112 let enclosing_fn = name_ref
113 .syntax()
114 .ancestors()
115 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
116 .find_map(ast::FnDef::cast);
117 return Some(NameRefKind::LocalRef { enclosing_fn });
118 }
119 }
120 None
121}
122
123fn crate_path(mut path: ast::Path) -> Option<Vec<ast::NameRef>> {
124 let mut res = Vec::new();
125 loop {
126 let segment = path.segment()?;
127 match segment.kind()? {
128 ast::PathSegmentKind::Name(name) => res.push(name),
129 ast::PathSegmentKind::CrateKw => break,
130 ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw => return None,
131 }
132 path = qualifier(path)?;
133 }
134 res.reverse();
135 return Some(res);
136
137 fn qualifier(path: ast::Path) -> Option<ast::Path> {
138 if let Some(q) = path.qualifier() {
139 return Some(q);
140 }
141 // TODO: this bottom up traversal is not too precise.
142 // Should we handle do a top-down analysiss, recording results?
143 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
144 let use_tree = use_tree_list.parent_use_tree();
145 use_tree.path()
146 }
147}
148
149fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
150 let mut shadowed = FxHashSet::default();
151 acc.extend(
152 scopes
153 .scope_chain(name_ref.syntax())
154 .flat_map(|scope| scopes.entries(scope).iter())
155 .filter(|entry| shadowed.insert(entry.name()))
156 .map(|entry| CompletionItem {
157 label: entry.name().to_string(),
158 lookup: None,
159 snippet: None,
160 }),
161 );
162 if scopes.self_param.is_some() {
163 acc.push(CompletionItem {
164 label: "self".to_string(),
165 lookup: None,
166 snippet: None,
167 })
168 }
169}
170
171fn complete_path(
172 acc: &mut Vec<CompletionItem>,
173 db: &RootDatabase,
174 source_root_id: SourceRootId,
175 module_tree: &ModuleTree,
176 module_id: ModuleId,
177 crate_path: Vec<ast::NameRef>,
178) -> Cancelable<()> {
179 let target_module_id = match find_target_module(module_tree, module_id, crate_path) {
180 None => return Ok(()),
181 Some(it) => it,
182 };
183 let module_scope = db.module_scope(source_root_id, target_module_id)?;
184 let completions = module_scope.entries().iter().map(|entry| CompletionItem {
185 label: entry.name().to_string(),
186 lookup: None,
187 snippet: None,
188 });
189 acc.extend(completions);
190 Ok(())
191}
192
193fn find_target_module(
194 module_tree: &ModuleTree,
195 module_id: ModuleId,
196 mut crate_path: Vec<ast::NameRef>,
197) -> Option<ModuleId> {
198 crate_path.pop();
199 let mut target_module = module_id.root(&module_tree);
200 for name in crate_path {
201 target_module = target_module.child(module_tree, name.text().as_str())?;
202 }
203 Some(target_module)
204}
205
206fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) {
207 acc.push(CompletionItem {
208 label: "tfn".to_string(),
209 lookup: None,
210 snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()),
211 });
212 acc.push(CompletionItem {
213 label: "pub(crate)".to_string(),
214 lookup: None,
215 snippet: Some("pub(crate) $0".to_string()),
216 })
217}
218
219fn complete_expr_keywords(
220 file: &SourceFileNode,
221 fn_def: ast::FnDef,
222 name_ref: ast::NameRef,
223 acc: &mut Vec<CompletionItem>,
224) {
225 acc.push(keyword("if", "if $0 {}"));
226 acc.push(keyword("match", "match $0 {}"));
227 acc.push(keyword("while", "while $0 {}"));
228 acc.push(keyword("loop", "loop {$0}"));
229
230 if let Some(off) = name_ref.syntax().range().start().checked_sub(2.into()) {
231 if let Some(if_expr) = find_node_at_offset::<ast::IfExpr>(file.syntax(), off) {
232 if if_expr.syntax().range().end() < name_ref.syntax().range().start() {
233 acc.push(keyword("else", "else {$0}"));
234 acc.push(keyword("else if", "else if $0 {}"));
235 }
236 }
237 }
238 if is_in_loop_body(name_ref) {
239 acc.push(keyword("continue", "continue"));
240 acc.push(keyword("break", "break"));
241 }
242 acc.extend(complete_return(fn_def, name_ref));
243}
244
245fn is_in_loop_body(name_ref: ast::NameRef) -> bool {
246 for node in name_ref.syntax().ancestors() {
247 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR {
248 break;
249 }
250 let loop_body = visitor()
251 .visit::<ast::ForExpr, _>(LoopBodyOwner::loop_body)
252 .visit::<ast::WhileExpr, _>(LoopBodyOwner::loop_body)
253 .visit::<ast::LoopExpr, _>(LoopBodyOwner::loop_body)
254 .accept(node);
255 if let Some(Some(body)) = loop_body {
256 if name_ref
257 .syntax()
258 .range()
259 .is_subrange(&body.syntax().range())
260 {
261 return true;
262 }
263 }
264 }
265 false
266}
267
268fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<CompletionItem> {
269 // let is_last_in_block = name_ref.syntax().ancestors().filter_map(ast::Expr::cast)
270 // .next()
271 // .and_then(|it| it.syntax().parent())
272 // .and_then(ast::Block::cast)
273 // .is_some();
274
275 // if is_last_in_block {
276 // return None;
277 // }
278
279 let is_stmt = match name_ref
280 .syntax()
281 .ancestors()
282 .filter_map(ast::ExprStmt::cast)
283 .next()
284 {
285 None => false,
286 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(),
287 };
288 let snip = match (is_stmt, fn_def.ret_type().is_some()) {
289 (true, true) => "return $0;",
290 (true, false) => "return;",
291 (false, true) => "return $0",
292 (false, false) => "return",
293 };
294 Some(keyword("return", snip))
295}
296
297fn keyword(kw: &str, snip: &str) -> CompletionItem {
298 CompletionItem {
299 label: kw.to_string(),
300 lookup: None,
301 snippet: Some(snip.to_string()),
302 }
303}
304
305fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) {
306 acc.push(CompletionItem {
307 label: "pd".to_string(),
308 lookup: None,
309 snippet: Some("eprintln!(\"$0 = {:?}\", $0);".to_string()),
310 });
311 acc.push(CompletionItem {
312 label: "ppd".to_string(),
313 lookup: None,
314 snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()),
315 });
316}
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index 627512553..194f1a6b0 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_editor::LineIndex; 3use ra_editor::LineIndex;
4use ra_syntax::{File, SyntaxNode}; 4use ra_syntax::{SourceFileNode, SyntaxNode};
5use salsa::{self, Database}; 5use salsa::{self, Database};
6 6
7use crate::{ 7use crate::{
@@ -85,7 +85,7 @@ salsa::database_storage! {
85 85
86salsa::query_group! { 86salsa::query_group! {
87 pub(crate) trait SyntaxDatabase: crate::input::FilesDatabase { 87 pub(crate) trait SyntaxDatabase: crate::input::FilesDatabase {
88 fn file_syntax(file_id: FileId) -> File { 88 fn file_syntax(file_id: FileId) -> SourceFileNode {
89 type FileSyntaxQuery; 89 type FileSyntaxQuery;
90 } 90 }
91 fn file_lines(file_id: FileId) -> Arc<LineIndex> { 91 fn file_lines(file_id: FileId) -> Arc<LineIndex> {
@@ -103,9 +103,9 @@ salsa::query_group! {
103 } 103 }
104} 104}
105 105
106fn file_syntax(db: &impl SyntaxDatabase, file_id: FileId) -> File { 106fn file_syntax(db: &impl SyntaxDatabase, file_id: FileId) -> SourceFileNode {
107 let text = db.file_text(file_id); 107 let text = db.file_text(file_id);
108 File::parse(&*text) 108 SourceFileNode::parse(&*text)
109} 109}
110fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<LineIndex> { 110fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<LineIndex> {
111 let text = db.file_text(file_id); 111 let text = db.file_text(file_id);
diff --git a/crates/ra_analysis/src/descriptors/function/scope.rs b/crates/ra_analysis/src/descriptors/function/scope.rs
index 62b46ffba..bbe16947c 100644
--- a/crates/ra_analysis/src/descriptors/function/scope.rs
+++ b/crates/ra_analysis/src/descriptors/function/scope.rs
@@ -272,7 +272,7 @@ pub fn resolve_local_name<'a>(
272#[cfg(test)] 272#[cfg(test)]
273mod tests { 273mod tests {
274 use ra_editor::find_node_at_offset; 274 use ra_editor::find_node_at_offset;
275 use ra_syntax::File; 275 use ra_syntax::SourceFileNode;
276 use test_utils::extract_offset; 276 use test_utils::extract_offset;
277 277
278 use super::*; 278 use super::*;
@@ -287,7 +287,7 @@ mod tests {
287 buf.push_str(&code[off..]); 287 buf.push_str(&code[off..]);
288 buf 288 buf
289 }; 289 };
290 let file = File::parse(&code); 290 let file = SourceFileNode::parse(&code);
291 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); 291 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
292 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); 292 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
293 let scopes = FnScopes::new(fn_def); 293 let scopes = FnScopes::new(fn_def);
@@ -376,7 +376,7 @@ mod tests {
376 376
377 fn do_check_local_name(code: &str, expected_offset: u32) { 377 fn do_check_local_name(code: &str, expected_offset: u32) {
378 let (off, code) = extract_offset(code); 378 let (off, code) = extract_offset(code);
379 let file = File::parse(&code); 379 let file = SourceFileNode::parse(&code);
380 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); 380 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
381 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); 381 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
382 382
diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs
index b5c232ea4..ade96ddc0 100644
--- a/crates/ra_analysis/src/descriptors/module/imp.rs
+++ b/crates/ra_analysis/src/descriptors/module/imp.rs
@@ -41,8 +41,8 @@ pub(crate) fn submodules(
41 db::check_canceled(db)?; 41 db::check_canceled(db)?;
42 let file_id = source.file_id(); 42 let file_id = source.file_id();
43 let submodules = match source.resolve(db) { 43 let submodules = match source.resolve(db) {
44 ModuleSourceNode::Root(it) => collect_submodules(file_id, it.borrowed()), 44 ModuleSourceNode::SourceFile(it) => collect_submodules(file_id, it.borrowed()),
45 ModuleSourceNode::Inline(it) => it 45 ModuleSourceNode::Module(it) => it
46 .borrowed() 46 .borrowed()
47 .item_list() 47 .item_list()
48 .map(|it| collect_submodules(file_id, it)) 48 .map(|it| collect_submodules(file_id, it))
@@ -89,8 +89,8 @@ pub(crate) fn module_scope(
89 let tree = db.module_tree(source_root_id)?; 89 let tree = db.module_tree(source_root_id)?;
90 let source = module_id.source(&tree).resolve(db); 90 let source = module_id.source(&tree).resolve(db);
91 let res = match source { 91 let res = match source {
92 ModuleSourceNode::Root(root) => ModuleScope::new(root.borrowed().items()), 92 ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()),
93 ModuleSourceNode::Inline(inline) => match inline.borrowed().item_list() { 93 ModuleSourceNode::Module(it) => match it.borrowed().item_list() {
94 Some(items) => ModuleScope::new(items.items()), 94 Some(items) => ModuleScope::new(items.items()),
95 None => ModuleScope::new(std::iter::empty()), 95 None => ModuleScope::new(std::iter::empty()),
96 }, 96 },
@@ -121,7 +121,7 @@ fn create_module_tree<'a>(
121 121
122 let source_root = db.source_root(source_root); 122 let source_root = db.source_root(source_root);
123 for &file_id in source_root.files.iter() { 123 for &file_id in source_root.files.iter() {
124 let source = ModuleSource::File(file_id); 124 let source = ModuleSource::SourceFile(file_id);
125 if visited.contains(&source) { 125 if visited.contains(&source) {
126 continue; // TODO: use explicit crate_roots here 126 continue; // TODO: use explicit crate_roots here
127 } 127 }
@@ -181,7 +181,7 @@ fn build_subtree(
181 visited, 181 visited,
182 roots, 182 roots,
183 Some(link), 183 Some(link),
184 ModuleSource::File(file_id), 184 ModuleSource::SourceFile(file_id),
185 ), 185 ),
186 }) 186 })
187 .collect::<Cancelable<Vec<_>>>()?; 187 .collect::<Cancelable<Vec<_>>>()?;
@@ -213,8 +213,8 @@ fn resolve_submodule(
213 file_resolver: &FileResolverImp, 213 file_resolver: &FileResolverImp,
214) -> (Vec<FileId>, Option<Problem>) { 214) -> (Vec<FileId>, Option<Problem>) {
215 let file_id = match source { 215 let file_id = match source {
216 ModuleSource::File(it) => it, 216 ModuleSource::SourceFile(it) => it,
217 ModuleSource::Inline(..) => { 217 ModuleSource::Module(..) => {
218 // TODO 218 // TODO
219 return (Vec::new(), None); 219 return (Vec::new(), None);
220 } 220 }
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs
index 03330240d..bc1148b22 100644
--- a/crates/ra_analysis/src/descriptors/module/mod.rs
+++ b/crates/ra_analysis/src/descriptors/module/mod.rs
@@ -3,7 +3,7 @@ pub(crate) mod scope;
3 3
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, AstNode, NameOwner}, 5 ast::{self, AstNode, NameOwner},
6 SmolStr, SyntaxNode, 6 SmolStr, SyntaxNode, SyntaxNodeRef,
7}; 7};
8use relative_path::RelativePathBuf; 8use relative_path::RelativePathBuf;
9 9
@@ -41,19 +41,18 @@ impl ModuleTree {
41 41
42/// `ModuleSource` is the syntax tree element that produced this module: 42/// `ModuleSource` is the syntax tree element that produced this module:
43/// either a file, or an inlinde module. 43/// either a file, or an inlinde module.
44/// TODO: we don't produce Inline modules yet
45#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 44#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
46pub(crate) enum ModuleSource { 45pub(crate) enum ModuleSource {
47 File(FileId), 46 SourceFile(FileId),
48 #[allow(dead_code)] 47 #[allow(dead_code)]
49 Inline(SyntaxPtr), 48 Module(SyntaxPtr),
50} 49}
51 50
52/// An owned syntax node for a module. Unlike `ModuleSource`, 51/// An owned syntax node for a module. Unlike `ModuleSource`,
53/// this holds onto the AST for the whole file. 52/// this holds onto the AST for the whole file.
54enum ModuleSourceNode { 53enum ModuleSourceNode {
55 Root(ast::RootNode), 54 SourceFile(ast::SourceFileNode),
56 Inline(ast::ModuleNode), 55 Module(ast::ModuleNode),
57} 56}
58 57
59#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] 58#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
@@ -135,14 +134,14 @@ impl LinkId {
135 ) -> ast::ModuleNode { 134 ) -> ast::ModuleNode {
136 let owner = self.owner(tree); 135 let owner = self.owner(tree);
137 match owner.source(tree).resolve(db) { 136 match owner.source(tree).resolve(db) {
138 ModuleSourceNode::Root(root) => { 137 ModuleSourceNode::SourceFile(root) => {
139 let ast = imp::modules(root.borrowed()) 138 let ast = imp::modules(root.borrowed())
140 .find(|(name, _)| name == &tree.link(self).name) 139 .find(|(name, _)| name == &tree.link(self).name)
141 .unwrap() 140 .unwrap()
142 .1; 141 .1;
143 ast.owned() 142 ast.owned()
144 } 143 }
145 ModuleSourceNode::Inline(it) => it, 144 ModuleSourceNode::Module(it) => it,
146 } 145 }
147 } 146 }
148} 147}
@@ -155,37 +154,47 @@ struct ModuleData {
155} 154}
156 155
157impl ModuleSource { 156impl ModuleSource {
157 pub(crate) fn for_node(file_id: FileId, node: SyntaxNodeRef) -> ModuleSource {
158 for node in node.ancestors() {
159 if let Some(m) = ast::Module::cast(node) {
160 if !m.has_semi() {
161 return ModuleSource::new_inline(file_id, m);
162 }
163 }
164 }
165 ModuleSource::SourceFile(file_id)
166 }
158 pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { 167 pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource {
159 assert!(!module.has_semi()); 168 assert!(!module.has_semi());
160 let ptr = SyntaxPtr::new(file_id, module.syntax()); 169 let ptr = SyntaxPtr::new(file_id, module.syntax());
161 ModuleSource::Inline(ptr) 170 ModuleSource::Module(ptr)
162 } 171 }
163 172
164 pub(crate) fn as_file(self) -> Option<FileId> { 173 pub(crate) fn as_file(self) -> Option<FileId> {
165 match self { 174 match self {
166 ModuleSource::File(f) => Some(f), 175 ModuleSource::SourceFile(f) => Some(f),
167 ModuleSource::Inline(..) => None, 176 ModuleSource::Module(..) => None,
168 } 177 }
169 } 178 }
170 179
171 pub(crate) fn file_id(self) -> FileId { 180 pub(crate) fn file_id(self) -> FileId {
172 match self { 181 match self {
173 ModuleSource::File(f) => f, 182 ModuleSource::SourceFile(f) => f,
174 ModuleSource::Inline(ptr) => ptr.file_id(), 183 ModuleSource::Module(ptr) => ptr.file_id(),
175 } 184 }
176 } 185 }
177 186
178 fn resolve(self, db: &impl SyntaxDatabase) -> ModuleSourceNode { 187 fn resolve(self, db: &impl SyntaxDatabase) -> ModuleSourceNode {
179 match self { 188 match self {
180 ModuleSource::File(file_id) => { 189 ModuleSource::SourceFile(file_id) => {
181 let syntax = db.file_syntax(file_id); 190 let syntax = db.file_syntax(file_id);
182 ModuleSourceNode::Root(syntax.ast().owned()) 191 ModuleSourceNode::SourceFile(syntax.ast().owned())
183 } 192 }
184 ModuleSource::Inline(ptr) => { 193 ModuleSource::Module(ptr) => {
185 let syntax = db.resolve_syntax_ptr(ptr); 194 let syntax = db.resolve_syntax_ptr(ptr);
186 let syntax = syntax.borrowed(); 195 let syntax = syntax.borrowed();
187 let module = ast::Module::cast(syntax).unwrap(); 196 let module = ast::Module::cast(syntax).unwrap();
188 ModuleSourceNode::Inline(module.owned()) 197 ModuleSourceNode::Module(module.owned())
189 } 198 }
190 } 199 }
191 } 200 }
diff --git a/crates/ra_analysis/src/descriptors/module/scope.rs b/crates/ra_analysis/src/descriptors/module/scope.rs
index 215b31f8e..4490228e4 100644
--- a/crates/ra_analysis/src/descriptors/module/scope.rs
+++ b/crates/ra_analysis/src/descriptors/module/scope.rs
@@ -25,7 +25,7 @@ enum EntryKind {
25} 25}
26 26
27impl ModuleScope { 27impl ModuleScope {
28 pub(crate) fn new<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> ModuleScope { 28 pub(super) fn new<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> ModuleScope {
29 let mut entries = Vec::new(); 29 let mut entries = Vec::new();
30 for item in items { 30 for item in items {
31 let entry = match item { 31 let entry = match item {
@@ -95,10 +95,10 @@ fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) {
95#[cfg(test)] 95#[cfg(test)]
96mod tests { 96mod tests {
97 use super::*; 97 use super::*;
98 use ra_syntax::{ast::ModuleItemOwner, File}; 98 use ra_syntax::{ast::ModuleItemOwner, SourceFileNode};
99 99
100 fn do_check(code: &str, expected: &[&str]) { 100 fn do_check(code: &str, expected: &[&str]) {
101 let file = File::parse(&code); 101 let file = SourceFileNode::parse(&code);
102 let scope = ModuleScope::new(file.ast().items()); 102 let scope = ModuleScope::new(file.ast().items());
103 let actual = scope.entries.iter().map(|it| it.name()).collect::<Vec<_>>(); 103 let actual = scope.entries.iter().map(|it| it.name()).collect::<Vec<_>>();
104 assert_eq!(expected, actual.as_slice()); 104 assert_eq!(expected, actual.as_slice());
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 819827b95..74c248a96 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -7,7 +7,7 @@ use std::{
7use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit}; 7use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit};
8use ra_syntax::{ 8use ra_syntax::{
9 ast::{self, ArgListOwner, Expr, NameOwner}, 9 ast::{self, ArgListOwner, Expr, NameOwner},
10 AstNode, File, SmolStr, 10 AstNode, SourceFileNode, SmolStr,
11 SyntaxKind::*, 11 SyntaxKind::*,
12 SyntaxNodeRef, TextRange, TextUnit, 12 SyntaxNodeRef, TextRange, TextUnit,
13}; 13};
@@ -17,7 +17,7 @@ use rustc_hash::FxHashSet;
17use salsa::{Database, ParallelDatabase}; 17use salsa::{Database, ParallelDatabase};
18 18
19use crate::{ 19use crate::{
20 completion::{resolve_based_completion, scope_completion, CompletionItem}, 20 completion::{completions, CompletionItem},
21 db::{self, FileSyntaxQuery, SyntaxDatabase}, 21 db::{self, FileSyntaxQuery, SyntaxDatabase},
22 descriptors::{ 22 descriptors::{
23 function::{FnDescriptor, FnId}, 23 function::{FnDescriptor, FnId},
@@ -27,7 +27,7 @@ use crate::{
27 input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, 27 input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
28 symbol_index::SymbolIndex, 28 symbol_index::SymbolIndex,
29 AnalysisChange, Cancelable, CrateGraph, CrateId, Diagnostic, FileId, FileResolver, 29 AnalysisChange, Cancelable, CrateGraph, CrateId, Diagnostic, FileId, FileResolver,
30 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileEdit, 30 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit,
31}; 31};
32 32
33#[derive(Clone, Debug)] 33#[derive(Clone, Debug)]
@@ -180,7 +180,7 @@ impl fmt::Debug for AnalysisImpl {
180} 180}
181 181
182impl AnalysisImpl { 182impl AnalysisImpl {
183 pub fn file_syntax(&self, file_id: FileId) -> File { 183 pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode {
184 self.db.file_syntax(file_id) 184 self.db.file_syntax(file_id)
185 } 185 }
186 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { 186 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> {
@@ -226,7 +226,7 @@ impl AnalysisImpl {
226 let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) 226 let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset)
227 { 227 {
228 Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m), 228 Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m),
229 _ => ModuleSource::File(position.file_id), 229 _ => ModuleSource::SourceFile(position.file_id),
230 }; 230 };
231 231
232 let res = module_tree 232 let res = module_tree
@@ -254,7 +254,7 @@ impl AnalysisImpl {
254 let module_tree = self.module_tree(file_id)?; 254 let module_tree = self.module_tree(file_id)?;
255 let crate_graph = self.db.crate_graph(); 255 let crate_graph = self.db.crate_graph();
256 let res = module_tree 256 let res = module_tree
257 .modules_for_source(ModuleSource::File(file_id)) 257 .modules_for_source(ModuleSource::SourceFile(file_id))
258 .into_iter() 258 .into_iter()
259 .map(|it| it.root(&module_tree)) 259 .map(|it| it.root(&module_tree))
260 .filter_map(|it| it.source(&module_tree).as_file()) 260 .filter_map(|it| it.source(&module_tree).as_file())
@@ -267,18 +267,7 @@ impl AnalysisImpl {
267 self.db.crate_graph().crate_roots[&crate_id] 267 self.db.crate_graph().crate_roots[&crate_id]
268 } 268 }
269 pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { 269 pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> {
270 let mut res = Vec::new(); 270 completions(&self.db, position)
271 let mut has_completions = false;
272 if let Some(scope_based) = scope_completion(&self.db, position) {
273 res.extend(scope_based);
274 has_completions = true;
275 }
276 if let Some(scope_based) = resolve_based_completion(&self.db, position)? {
277 res.extend(scope_based);
278 has_completions = true;
279 }
280 let res = if has_completions { Some(res) } else { None };
281 Ok(res)
282 } 271 }
283 pub fn approximately_resolve_symbol( 272 pub fn approximately_resolve_symbol(
284 &self, 273 &self,
@@ -364,6 +353,16 @@ impl AnalysisImpl {
364 ret 353 ret
365 } 354 }
366 355
356 pub fn doc_comment_for(
357 &self,
358 file_id: FileId,
359 symbol: FileSymbol,
360 ) -> Cancelable<Option<String>> {
361 let file = self.db.file_syntax(file_id);
362
363 Ok(symbol.docs(&file))
364 }
365
367 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { 366 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> {
368 let module_tree = self.module_tree(file_id)?; 367 let module_tree = self.module_tree(file_id)?;
369 let syntax = self.db.file_syntax(file_id); 368 let syntax = self.db.file_syntax(file_id);
@@ -376,7 +375,7 @@ impl AnalysisImpl {
376 fix: None, 375 fix: None,
377 }) 376 })
378 .collect::<Vec<_>>(); 377 .collect::<Vec<_>>();
379 if let Some(m) = module_tree.any_module_for_source(ModuleSource::File(file_id)) { 378 if let Some(m) = module_tree.any_module_for_source(ModuleSource::SourceFile(file_id)) {
380 for (name_node, problem) in m.problems(&module_tree, &*self.db) { 379 for (name_node, problem) in m.problems(&module_tree, &*self.db) {
381 let diag = match problem { 380 let diag = match problem {
382 Problem::UnresolvedModule { candidate } => { 381 Problem::UnresolvedModule { candidate } => {
@@ -538,7 +537,7 @@ impl AnalysisImpl {
538 Some(name) => name.text(), 537 Some(name) => name.text(),
539 None => return Vec::new(), 538 None => return Vec::new(),
540 }; 539 };
541 let module_id = match module_tree.any_module_for_source(ModuleSource::File(file_id)) { 540 let module_id = match module_tree.any_module_for_source(ModuleSource::SourceFile(file_id)) {
542 Some(id) => id, 541 Some(id) => id,
543 None => return Vec::new(), 542 None => return Vec::new(),
544 }; 543 };
@@ -552,7 +551,7 @@ impl AnalysisImpl {
552 551
553impl SourceChange { 552impl SourceChange {
554 pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange { 553 pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange {
555 let file_edit = SourceFileEdit { 554 let file_edit = SourceFileNodeEdit {
556 file_id, 555 file_id,
557 edits: edit.edit.into_atoms(), 556 edits: edit.edit.into_atoms(),
558 }; 557 };
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 0ea9ebee7..ab0e3cb0c 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -1,5 +1,5 @@
1//! ra_analyzer crate is the brain of Rust analyzer. It relies on the `salsa` 1//! ra_analyzer crate is the brain of Rust analyzer. It relies on the `salsa`
2//! crate, which provides and incremental on-deman database of facts. 2//! crate, which provides and incremental on-demand database of facts.
3 3
4extern crate fst; 4extern crate fst;
5extern crate ra_editor; 5extern crate ra_editor;
@@ -20,7 +20,7 @@ pub mod mock_analysis;
20 20
21use std::{fmt, sync::Arc}; 21use std::{fmt, sync::Arc};
22 22
23use ra_syntax::{AtomEdit, File, TextRange, TextUnit}; 23use ra_syntax::{AtomEdit, SourceFileNode, TextRange, TextUnit};
24use rayon::prelude::*; 24use rayon::prelude::*;
25use relative_path::RelativePathBuf; 25use relative_path::RelativePathBuf;
26 26
@@ -128,13 +128,13 @@ pub struct FilePosition {
128#[derive(Debug)] 128#[derive(Debug)]
129pub struct SourceChange { 129pub struct SourceChange {
130 pub label: String, 130 pub label: String,
131 pub source_file_edits: Vec<SourceFileEdit>, 131 pub source_file_edits: Vec<SourceFileNodeEdit>,
132 pub file_system_edits: Vec<FileSystemEdit>, 132 pub file_system_edits: Vec<FileSystemEdit>,
133 pub cursor_position: Option<FilePosition>, 133 pub cursor_position: Option<FilePosition>,
134} 134}
135 135
136#[derive(Debug)] 136#[derive(Debug)]
137pub struct SourceFileEdit { 137pub struct SourceFileNodeEdit {
138 pub file_id: FileId, 138 pub file_id: FileId,
139 pub edits: Vec<AtomEdit>, 139 pub edits: Vec<AtomEdit>,
140} 140}
@@ -204,16 +204,16 @@ pub struct Analysis {
204} 204}
205 205
206impl Analysis { 206impl Analysis {
207 pub fn file_syntax(&self, file_id: FileId) -> File { 207 pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode {
208 self.imp.file_syntax(file_id).clone() 208 self.imp.file_syntax(file_id).clone()
209 } 209 }
210 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { 210 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> {
211 self.imp.file_line_index(file_id) 211 self.imp.file_line_index(file_id)
212 } 212 }
213 pub fn extend_selection(&self, file: &File, range: TextRange) -> TextRange { 213 pub fn extend_selection(&self, file: &SourceFileNode, range: TextRange) -> TextRange {
214 ra_editor::extend_selection(file, range).unwrap_or(range) 214 ra_editor::extend_selection(file, range).unwrap_or(range)
215 } 215 }
216 pub fn matching_brace(&self, file: &File, offset: TextUnit) -> Option<TextUnit> { 216 pub fn matching_brace(&self, file: &SourceFileNode, offset: TextUnit) -> Option<TextUnit> {
217 ra_editor::matching_brace(file, offset) 217 ra_editor::matching_brace(file, offset)
218 } 218 }
219 pub fn syntax_tree(&self, file_id: FileId) -> String { 219 pub fn syntax_tree(&self, file_id: FileId) -> String {
@@ -258,6 +258,13 @@ impl Analysis {
258 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { 258 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
259 Ok(self.imp.find_all_refs(position)) 259 Ok(self.imp.find_all_refs(position))
260 } 260 }
261 pub fn doc_comment_for(
262 &self,
263 file_id: FileId,
264 symbol: FileSymbol,
265 ) -> Cancelable<Option<String>> {
266 self.imp.doc_comment_for(file_id, symbol)
267 }
261 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { 268 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
262 self.imp.parent_module(position) 269 self.imp.parent_module(position)
263 } 270 }
@@ -302,7 +309,7 @@ pub struct LibraryData {
302impl LibraryData { 309impl LibraryData {
303 pub fn prepare(files: Vec<(FileId, String)>, file_resolver: Arc<FileResolver>) -> LibraryData { 310 pub fn prepare(files: Vec<(FileId, String)>, file_resolver: Arc<FileResolver>) -> LibraryData {
304 let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, text)| { 311 let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, text)| {
305 let file = File::parse(text); 312 let file = SourceFileNode::parse(text);
306 (*file_id, file) 313 (*file_id, file)
307 })); 314 }));
308 LibraryData { 315 LibraryData {
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs
index b57ad5d33..3a0667ecd 100644
--- a/crates/ra_analysis/src/symbol_index.rs
+++ b/crates/ra_analysis/src/symbol_index.rs
@@ -6,7 +6,7 @@ use std::{
6use fst::{self, Streamer}; 6use fst::{self, Streamer};
7use ra_editor::{file_symbols, FileSymbol}; 7use ra_editor::{file_symbols, FileSymbol};
8use ra_syntax::{ 8use ra_syntax::{
9 File, 9 SourceFileNode,
10 SyntaxKind::{self, *}, 10 SyntaxKind::{self, *},
11}; 11};
12use rayon::prelude::*; 12use rayon::prelude::*;
@@ -34,7 +34,9 @@ impl Hash for SymbolIndex {
34} 34}
35 35
36impl SymbolIndex { 36impl SymbolIndex {
37 pub(crate) fn for_files(files: impl ParallelIterator<Item = (FileId, File)>) -> SymbolIndex { 37 pub(crate) fn for_files(
38 files: impl ParallelIterator<Item = (FileId, SourceFileNode)>,
39 ) -> SymbolIndex {
38 let mut symbols = files 40 let mut symbols = files
39 .flat_map(|(file_id, file)| { 41 .flat_map(|(file_id, file)| {
40 file_symbols(&file) 42 file_symbols(&file)
@@ -51,7 +53,7 @@ impl SymbolIndex {
51 SymbolIndex { symbols, map } 53 SymbolIndex { symbols, map }
52 } 54 }
53 55
54 pub(crate) fn for_file(file_id: FileId, file: File) -> SymbolIndex { 56 pub(crate) fn for_file(file_id: FileId, file: SourceFileNode) -> SymbolIndex {
55 SymbolIndex::for_files(rayon::iter::once((file_id, file))) 57 SymbolIndex::for_files(rayon::iter::once((file_id, file)))
56 } 58 }
57} 59}
diff --git a/crates/ra_analysis/src/syntax_ptr.rs b/crates/ra_analysis/src/syntax_ptr.rs
index 4afb1fc93..194b94584 100644
--- a/crates/ra_analysis/src/syntax_ptr.rs
+++ b/crates/ra_analysis/src/syntax_ptr.rs
@@ -1,4 +1,4 @@
1use ra_syntax::{File, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange}; 1use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange};
2 2
3use crate::db::SyntaxDatabase; 3use crate::db::SyntaxDatabase;
4use crate::FileId; 4use crate::FileId;
@@ -43,7 +43,7 @@ impl LocalSyntaxPtr {
43 } 43 }
44 } 44 }
45 45
46 pub(crate) fn resolve(self, file: &File) -> SyntaxNode { 46 pub(crate) fn resolve(self, file: &SourceFileNode) -> SyntaxNode {
47 let mut curr = file.syntax(); 47 let mut curr = file.syntax();
48 loop { 48 loop {
49 if curr.range() == self.range && curr.kind() == self.kind { 49 if curr.range() == self.range && curr.kind() == self.kind {
@@ -62,12 +62,17 @@ impl LocalSyntaxPtr {
62 local: self, 62 local: self,
63 } 63 }
64 } 64 }
65
66 // Seems unfortunate to expose
67 pub(crate) fn range(self) -> TextRange {
68 self.range
69 }
65} 70}
66 71
67#[test] 72#[test]
68fn test_local_syntax_ptr() { 73fn test_local_syntax_ptr() {
69 use ra_syntax::{ast, AstNode}; 74 use ra_syntax::{ast, AstNode};
70 let file = File::parse("struct Foo { f: u32, }"); 75 let file = SourceFileNode::parse("struct Foo { f: u32, }");
71 let field = file 76 let field = file
72 .syntax() 77 .syntax()
73 .descendants() 78 .descendants()
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index c605d34f0..719c166b5 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -452,3 +452,44 @@ fn test_complete_crate_path() {
452 &completions, 452 &completions,
453 ); 453 );
454} 454}
455
456#[test]
457fn test_complete_crate_path_with_braces() {
458 let (analysis, position) = analysis_and_position(
459 "
460 //- /lib.rs
461 mod foo;
462 struct Spam;
463 //- /foo.rs
464 use crate::{Sp<|>};
465 ",
466 );
467 let completions = analysis.completions(position).unwrap().unwrap();
468 assert_eq_dbg(
469 r#"[CompletionItem { label: "foo", lookup: None, snippet: None },
470 CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
471 &completions,
472 );
473}
474
475#[test]
476fn test_complete_crate_path_in_nested_tree() {
477 let (analysis, position) = analysis_and_position(
478 "
479 //- /lib.rs
480 mod foo;
481 pub mod bar {
482 pub mod baz {
483 pub struct Spam;
484 }
485 }
486 //- /foo.rs
487 use crate::{bar::{baz::Sp<|>}};
488 ",
489 );
490 let completions = analysis.completions(position).unwrap().unwrap();
491 assert_eq_dbg(
492 r#"[CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
493 &completions,
494 );
495}
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index 239d846b3..5ca86df4d 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -11,7 +11,7 @@ use std::{fs, io::Read, path::Path, time::Instant};
11use clap::{App, Arg, SubCommand}; 11use clap::{App, Arg, SubCommand};
12use join_to_string::join; 12use join_to_string::join;
13use ra_editor::{extend_selection, file_structure, syntax_tree}; 13use ra_editor::{extend_selection, file_structure, syntax_tree};
14use ra_syntax::{File, TextRange}; 14use ra_syntax::{SourceFileNode, TextRange};
15use tools::collect_tests; 15use tools::collect_tests;
16 16
17type Result<T> = ::std::result::Result<T, failure::Error>; 17type Result<T> = ::std::result::Result<T, failure::Error>;
@@ -79,9 +79,9 @@ fn main() -> Result<()> {
79 Ok(()) 79 Ok(())
80} 80}
81 81
82fn file() -> Result<File> { 82fn file() -> Result<SourceFileNode> {
83 let text = read_stdin()?; 83 let text = read_stdin()?;
84 Ok(File::parse(&text)) 84 Ok(SourceFileNode::parse(&text))
85} 85}
86 86
87fn read_stdin() -> Result<String> { 87fn read_stdin() -> Result<String> {
@@ -100,12 +100,12 @@ fn render_test(file: &Path, line: usize) -> Result<(String, String)> {
100 None => bail!("No test found at line {} at {}", line, file.display()), 100 None => bail!("No test found at line {} at {}", line, file.display()),
101 Some((_start_line, test)) => test, 101 Some((_start_line, test)) => test,
102 }; 102 };
103 let file = File::parse(&test.text); 103 let file = SourceFileNode::parse(&test.text);
104 let tree = syntax_tree(&file); 104 let tree = syntax_tree(&file);
105 Ok((test.text, tree)) 105 Ok((test.text, tree))
106} 106}
107 107
108fn selections(file: &File, start: u32, end: u32) -> String { 108fn selections(file: &SourceFileNode, start: u32, end: u32) -> String {
109 let mut ranges = Vec::new(); 109 let mut ranges = Vec::new();
110 let mut cur = Some(TextRange::from_to((start - 1).into(), (end - 1).into())); 110 let mut cur = Some(TextRange::from_to((start - 1).into(), (end - 1).into()));
111 while let Some(r) = cur { 111 while let Some(r) = cur {
diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs
index ef6df0d53..0139b19d3 100644
--- a/crates/ra_editor/src/code_actions.rs
+++ b/crates/ra_editor/src/code_actions.rs
@@ -3,7 +3,7 @@ use join_to_string::join;
3use ra_syntax::{ 3use ra_syntax::{
4 algo::{find_covering_node, find_leaf_at_offset}, 4 algo::{find_covering_node, find_leaf_at_offset},
5 ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner}, 5 ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner},
6 Direction, File, 6 Direction, SourceFileNode,
7 SyntaxKind::{COMMA, WHITESPACE}, 7 SyntaxKind::{COMMA, WHITESPACE},
8 SyntaxNodeRef, TextRange, TextUnit, 8 SyntaxNodeRef, TextRange, TextUnit,
9}; 9};
@@ -16,7 +16,10 @@ pub struct LocalEdit {
16 pub cursor_position: Option<TextUnit>, 16 pub cursor_position: Option<TextUnit>,
17} 17}
18 18
19pub fn flip_comma<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> LocalEdit + 'a> { 19pub fn flip_comma<'a>(
20 file: &'a SourceFileNode,
21 offset: TextUnit,
22) -> Option<impl FnOnce() -> LocalEdit + 'a> {
20 let syntax = file.syntax(); 23 let syntax = file.syntax();
21 24
22 let comma = find_leaf_at_offset(syntax, offset).find(|leaf| leaf.kind() == COMMA)?; 25 let comma = find_leaf_at_offset(syntax, offset).find(|leaf| leaf.kind() == COMMA)?;
@@ -33,7 +36,10 @@ pub fn flip_comma<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce()
33 }) 36 })
34} 37}
35 38
36pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> LocalEdit + 'a> { 39pub fn add_derive<'a>(
40 file: &'a SourceFileNode,
41 offset: TextUnit,
42) -> Option<impl FnOnce() -> LocalEdit + 'a> {
37 let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?; 43 let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
38 Some(move || { 44 Some(move || {
39 let derive_attr = nominal 45 let derive_attr = nominal
@@ -58,7 +64,10 @@ pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce()
58 }) 64 })
59} 65}
60 66
61pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> LocalEdit + 'a> { 67pub fn add_impl<'a>(
68 file: &'a SourceFileNode,
69 offset: TextUnit,
70) -> Option<impl FnOnce() -> LocalEdit + 'a> {
62 let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?; 71 let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
63 let name = nominal.name()?; 72 let name = nominal.name()?;
64 73
@@ -98,7 +107,7 @@ pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() ->
98} 107}
99 108
100pub fn introduce_variable<'a>( 109pub fn introduce_variable<'a>(
101 file: &'a File, 110 file: &'a SourceFileNode,
102 range: TextRange, 111 range: TextRange,
103) -> Option<impl FnOnce() -> LocalEdit + 'a> { 112) -> Option<impl FnOnce() -> LocalEdit + 'a> {
104 let node = find_covering_node(file.syntax(), range); 113 let node = find_covering_node(file.syntax(), range);
diff --git a/crates/ra_editor/src/extend_selection.rs b/crates/ra_editor/src/extend_selection.rs
index 9d8df25c3..8f11d5364 100644
--- a/crates/ra_editor/src/extend_selection.rs
+++ b/crates/ra_editor/src/extend_selection.rs
@@ -1,11 +1,11 @@
1use ra_syntax::{ 1use ra_syntax::{
2 algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset}, 2 algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset},
3 Direction, File, 3 Direction, SourceFileNode,
4 SyntaxKind::*, 4 SyntaxKind::*,
5 SyntaxNodeRef, TextRange, TextUnit, 5 SyntaxNodeRef, TextRange, TextUnit,
6}; 6};
7 7
8pub fn extend_selection(file: &File, range: TextRange) -> Option<TextRange> { 8pub fn extend_selection(file: &SourceFileNode, range: TextRange) -> Option<TextRange> {
9 let syntax = file.syntax(); 9 let syntax = file.syntax();
10 extend(syntax.borrowed(), range) 10 extend(syntax.borrowed(), range)
11} 11}
@@ -120,7 +120,7 @@ mod tests {
120 120
121 fn do_check(before: &str, afters: &[&str]) { 121 fn do_check(before: &str, afters: &[&str]) {
122 let (cursor, before) = extract_offset(before); 122 let (cursor, before) = extract_offset(before);
123 let file = File::parse(&before); 123 let file = SourceFileNode::parse(&before);
124 let mut range = TextRange::offset_len(cursor, 0.into()); 124 let mut range = TextRange::offset_len(cursor, 0.into());
125 for &after in afters { 125 for &after in afters {
126 range = extend_selection(&file, range).unwrap(); 126 range = extend_selection(&file, range).unwrap();
diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs
index 0803c8891..2a8fa3cda 100644
--- a/crates/ra_editor/src/folding_ranges.rs
+++ b/crates/ra_editor/src/folding_ranges.rs
@@ -1,7 +1,7 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast, AstNode, Direction, File, 4 ast, AstNode, Direction, SourceFileNode,
5 SyntaxKind::{self, *}, 5 SyntaxKind::{self, *},
6 SyntaxNodeRef, TextRange, 6 SyntaxNodeRef, TextRange,
7}; 7};
@@ -18,7 +18,7 @@ pub struct Fold {
18 pub kind: FoldKind, 18 pub kind: FoldKind,
19} 19}
20 20
21pub fn folding_ranges(file: &File) -> Vec<Fold> { 21pub fn folding_ranges(file: &SourceFileNode) -> Vec<Fold> {
22 let mut res = vec![]; 22 let mut res = vec![];
23 let mut visited_comments = FxHashSet::default(); 23 let mut visited_comments = FxHashSet::default();
24 let mut visited_imports = FxHashSet::default(); 24 let mut visited_imports = FxHashSet::default();
@@ -171,7 +171,7 @@ mod tests {
171 171
172 fn do_check(text: &str, fold_kinds: &[FoldKind]) { 172 fn do_check(text: &str, fold_kinds: &[FoldKind]) {
173 let (ranges, text) = extract_ranges(text); 173 let (ranges, text) = extract_ranges(text);
174 let file = File::parse(&text); 174 let file = SourceFileNode::parse(&text);
175 let folds = folding_ranges(&file); 175 let folds = folding_ranges(&file);
176 176
177 assert_eq!( 177 assert_eq!(
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index f92181b86..ff4e8303d 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -30,7 +30,7 @@ pub use ra_syntax::AtomEdit;
30use ra_syntax::{ 30use ra_syntax::{
31 algo::find_leaf_at_offset, 31 algo::find_leaf_at_offset,
32 ast::{self, AstNode, NameOwner}, 32 ast::{self, AstNode, NameOwner},
33 File, 33 SourceFileNode,
34 Location, 34 Location,
35 SyntaxKind::{self, *}, 35 SyntaxKind::{self, *},
36 SyntaxNodeRef, TextRange, TextUnit, 36 SyntaxNodeRef, TextRange, TextUnit,
@@ -60,7 +60,7 @@ pub enum RunnableKind {
60 Bin, 60 Bin,
61} 61}
62 62
63pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> { 63pub fn matching_brace(file: &SourceFileNode, offset: TextUnit) -> Option<TextUnit> {
64 const BRACES: &[SyntaxKind] = &[ 64 const BRACES: &[SyntaxKind] = &[
65 L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE, 65 L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE,
66 ]; 66 ];
@@ -78,7 +78,7 @@ pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> {
78 Some(matching_node.range().start()) 78 Some(matching_node.range().start())
79} 79}
80 80
81pub fn highlight(file: &File) -> Vec<HighlightedRange> { 81pub fn highlight(file: &SourceFileNode) -> Vec<HighlightedRange> {
82 let mut res = Vec::new(); 82 let mut res = Vec::new();
83 for node in file.syntax().descendants() { 83 for node in file.syntax().descendants() {
84 let tag = match node.kind() { 84 let tag = match node.kind() {
@@ -100,7 +100,7 @@ pub fn highlight(file: &File) -> Vec<HighlightedRange> {
100 res 100 res
101} 101}
102 102
103pub fn diagnostics(file: &File) -> Vec<Diagnostic> { 103pub fn diagnostics(file: &SourceFileNode) -> Vec<Diagnostic> {
104 fn location_to_range(location: Location) -> TextRange { 104 fn location_to_range(location: Location) -> TextRange {
105 match location { 105 match location {
106 Location::Offset(offset) => TextRange::offset_len(offset, 1.into()), 106 Location::Offset(offset) => TextRange::offset_len(offset, 1.into()),
@@ -117,11 +117,11 @@ pub fn diagnostics(file: &File) -> Vec<Diagnostic> {
117 .collect() 117 .collect()
118} 118}
119 119
120pub fn syntax_tree(file: &File) -> String { 120pub fn syntax_tree(file: &SourceFileNode) -> String {
121 ::ra_syntax::utils::dump_tree(file.syntax()) 121 ::ra_syntax::utils::dump_tree(file.syntax())
122} 122}
123 123
124pub fn runnables(file: &File) -> Vec<Runnable> { 124pub fn runnables(file: &SourceFileNode) -> Vec<Runnable> {
125 file.syntax() 125 file.syntax()
126 .descendants() 126 .descendants()
127 .filter_map(ast::FnDef::cast) 127 .filter_map(ast::FnDef::cast)
@@ -163,7 +163,7 @@ mod tests {
163 163
164 #[test] 164 #[test]
165 fn test_highlighting() { 165 fn test_highlighting() {
166 let file = File::parse( 166 let file = SourceFileNode::parse(
167 r#" 167 r#"
168// comment 168// comment
169fn main() {} 169fn main() {}
@@ -184,7 +184,7 @@ fn main() {}
184 184
185 #[test] 185 #[test]
186 fn test_runnables() { 186 fn test_runnables() {
187 let file = File::parse( 187 let file = SourceFileNode::parse(
188 r#" 188 r#"
189fn main() {} 189fn main() {}
190 190
@@ -209,7 +209,7 @@ fn test_foo() {}
209 fn test_matching_brace() { 209 fn test_matching_brace() {
210 fn do_check(before: &str, after: &str) { 210 fn do_check(before: &str, after: &str) {
211 let (pos, before) = extract_offset(before); 211 let (pos, before) = extract_offset(before);
212 let file = File::parse(&before); 212 let file = SourceFileNode::parse(&before);
213 let new_pos = match matching_brace(&file, pos) { 213 let new_pos = match matching_brace(&file, pos) {
214 None => pos, 214 None => pos,
215 Some(pos) => pos, 215 Some(pos) => pos,
diff --git a/crates/ra_editor/src/line_index.rs b/crates/ra_editor/src/line_index.rs
index 9abbb0d09..aab7e4081 100644
--- a/crates/ra_editor/src/line_index.rs
+++ b/crates/ra_editor/src/line_index.rs
@@ -1,43 +1,124 @@
1use crate::TextUnit; 1use crate::TextUnit;
2use rustc_hash::FxHashMap;
2use superslice::Ext; 3use superslice::Ext;
3 4
4#[derive(Clone, Debug, Hash, PartialEq, Eq)] 5#[derive(Clone, Debug, PartialEq, Eq)]
5pub struct LineIndex { 6pub struct LineIndex {
6 newlines: Vec<TextUnit>, 7 newlines: Vec<TextUnit>,
8 utf16_lines: FxHashMap<u32, Vec<Utf16Char>>,
7} 9}
8 10
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub struct LineCol { 12pub struct LineCol {
11 pub line: u32, 13 pub line: u32,
12 pub col: TextUnit, 14 pub col_utf16: u32,
15}
16
17#[derive(Clone, Debug, Hash, PartialEq, Eq)]
18struct Utf16Char {
19 start: TextUnit,
20 end: TextUnit,
21}
22
23impl Utf16Char {
24 fn len(&self) -> TextUnit {
25 self.end - self.start
26 }
13} 27}
14 28
15impl LineIndex { 29impl LineIndex {
16 pub fn new(text: &str) -> LineIndex { 30 pub fn new(text: &str) -> LineIndex {
31 let mut utf16_lines = FxHashMap::default();
32 let mut utf16_chars = Vec::new();
33
17 let mut newlines = vec![0.into()]; 34 let mut newlines = vec![0.into()];
18 let mut curr = 0.into(); 35 let mut curr_row = 0.into();
36 let mut curr_col = 0.into();
37 let mut line = 0;
19 for c in text.chars() { 38 for c in text.chars() {
20 curr += TextUnit::of_char(c); 39 curr_row += TextUnit::of_char(c);
21 if c == '\n' { 40 if c == '\n' {
22 newlines.push(curr); 41 newlines.push(curr_row);
42
43 // Save any utf-16 characters seen in the previous line
44 if utf16_chars.len() > 0 {
45 utf16_lines.insert(line, utf16_chars);
46 utf16_chars = Vec::new();
47 }
48
49 // Prepare for processing the next line
50 curr_col = 0.into();
51 line += 1;
52 continue;
23 } 53 }
54
55 let char_len = TextUnit::of_char(c);
56 if char_len.to_usize() > 1 {
57 utf16_chars.push(Utf16Char {
58 start: curr_col,
59 end: curr_col + char_len,
60 });
61 }
62
63 curr_col += char_len;
64 }
65 LineIndex {
66 newlines,
67 utf16_lines,
24 } 68 }
25 LineIndex { newlines }
26 } 69 }
27 70
28 pub fn line_col(&self, offset: TextUnit) -> LineCol { 71 pub fn line_col(&self, offset: TextUnit) -> LineCol {
29 let line = self.newlines.upper_bound(&offset) - 1; 72 let line = self.newlines.upper_bound(&offset) - 1;
30 let line_start_offset = self.newlines[line]; 73 let line_start_offset = self.newlines[line];
31 let col = offset - line_start_offset; 74 let col = offset - line_start_offset;
75
32 LineCol { 76 LineCol {
33 line: line as u32, 77 line: line as u32,
34 col, 78 col_utf16: self.utf8_to_utf16_col(line as u32, col) as u32,
35 } 79 }
36 } 80 }
37 81
38 pub fn offset(&self, line_col: LineCol) -> TextUnit { 82 pub fn offset(&self, line_col: LineCol) -> TextUnit {
39 //TODO: return Result 83 //TODO: return Result
40 self.newlines[line_col.line as usize] + line_col.col 84 let col = self.utf16_to_utf8_col(line_col.line, line_col.col_utf16);
85 self.newlines[line_col.line as usize] + col
86 }
87
88 fn utf8_to_utf16_col(&self, line: u32, mut col: TextUnit) -> usize {
89 if let Some(utf16_chars) = self.utf16_lines.get(&line) {
90 let mut correction = TextUnit::from_usize(0);
91 for c in utf16_chars {
92 if col >= c.end {
93 correction += c.len() - TextUnit::from_usize(1);
94 } else {
95 // From here on, all utf16 characters come *after* the character we are mapping,
96 // so we don't need to take them into account
97 break;
98 }
99 }
100
101 col -= correction;
102 }
103
104 col.to_usize()
105 }
106
107 fn utf16_to_utf8_col(&self, line: u32, col: u32) -> TextUnit {
108 let mut col: TextUnit = col.into();
109 if let Some(utf16_chars) = self.utf16_lines.get(&line) {
110 for c in utf16_chars {
111 if col >= c.start {
112 col += c.len() - TextUnit::from_usize(1);
113 } else {
114 // From here on, all utf16 characters come *after* the character we are mapping,
115 // so we don't need to take them into account
116 break;
117 }
118 }
119 }
120
121 col
41 } 122 }
42} 123}
43 124
@@ -49,63 +130,63 @@ fn test_line_index() {
49 index.line_col(0.into()), 130 index.line_col(0.into()),
50 LineCol { 131 LineCol {
51 line: 0, 132 line: 0,
52 col: 0.into() 133 col_utf16: 0
53 } 134 }
54 ); 135 );
55 assert_eq!( 136 assert_eq!(
56 index.line_col(1.into()), 137 index.line_col(1.into()),
57 LineCol { 138 LineCol {
58 line: 0, 139 line: 0,
59 col: 1.into() 140 col_utf16: 1
60 } 141 }
61 ); 142 );
62 assert_eq!( 143 assert_eq!(
63 index.line_col(5.into()), 144 index.line_col(5.into()),
64 LineCol { 145 LineCol {
65 line: 0, 146 line: 0,
66 col: 5.into() 147 col_utf16: 5
67 } 148 }
68 ); 149 );
69 assert_eq!( 150 assert_eq!(
70 index.line_col(6.into()), 151 index.line_col(6.into()),
71 LineCol { 152 LineCol {
72 line: 1, 153 line: 1,
73 col: 0.into() 154 col_utf16: 0
74 } 155 }
75 ); 156 );
76 assert_eq!( 157 assert_eq!(
77 index.line_col(7.into()), 158 index.line_col(7.into()),
78 LineCol { 159 LineCol {
79 line: 1, 160 line: 1,
80 col: 1.into() 161 col_utf16: 1
81 } 162 }
82 ); 163 );
83 assert_eq!( 164 assert_eq!(
84 index.line_col(8.into()), 165 index.line_col(8.into()),
85 LineCol { 166 LineCol {
86 line: 1, 167 line: 1,
87 col: 2.into() 168 col_utf16: 2
88 } 169 }
89 ); 170 );
90 assert_eq!( 171 assert_eq!(
91 index.line_col(10.into()), 172 index.line_col(10.into()),
92 LineCol { 173 LineCol {
93 line: 1, 174 line: 1,
94 col: 4.into() 175 col_utf16: 4
95 } 176 }
96 ); 177 );
97 assert_eq!( 178 assert_eq!(
98 index.line_col(11.into()), 179 index.line_col(11.into()),
99 LineCol { 180 LineCol {
100 line: 1, 181 line: 1,
101 col: 5.into() 182 col_utf16: 5
102 } 183 }
103 ); 184 );
104 assert_eq!( 185 assert_eq!(
105 index.line_col(12.into()), 186 index.line_col(12.into()),
106 LineCol { 187 LineCol {
107 line: 1, 188 line: 1,
108 col: 6.into() 189 col_utf16: 6
109 } 190 }
110 ); 191 );
111 192
@@ -115,35 +196,129 @@ fn test_line_index() {
115 index.line_col(0.into()), 196 index.line_col(0.into()),
116 LineCol { 197 LineCol {
117 line: 0, 198 line: 0,
118 col: 0.into() 199 col_utf16: 0
119 } 200 }
120 ); 201 );
121 assert_eq!( 202 assert_eq!(
122 index.line_col(1.into()), 203 index.line_col(1.into()),
123 LineCol { 204 LineCol {
124 line: 1, 205 line: 1,
125 col: 0.into() 206 col_utf16: 0
126 } 207 }
127 ); 208 );
128 assert_eq!( 209 assert_eq!(
129 index.line_col(2.into()), 210 index.line_col(2.into()),
130 LineCol { 211 LineCol {
131 line: 1, 212 line: 1,
132 col: 1.into() 213 col_utf16: 1
133 } 214 }
134 ); 215 );
135 assert_eq!( 216 assert_eq!(
136 index.line_col(6.into()), 217 index.line_col(6.into()),
137 LineCol { 218 LineCol {
138 line: 1, 219 line: 1,
139 col: 5.into() 220 col_utf16: 5
140 } 221 }
141 ); 222 );
142 assert_eq!( 223 assert_eq!(
143 index.line_col(7.into()), 224 index.line_col(7.into()),
144 LineCol { 225 LineCol {
145 line: 2, 226 line: 2,
146 col: 0.into() 227 col_utf16: 0
147 } 228 }
148 ); 229 );
149} 230}
231
232#[cfg(test)]
233mod test_utf8_utf16_conv {
234 use super::*;
235
236 #[test]
237 fn test_char_len() {
238 assert_eq!('メ'.len_utf8(), 3);
239 assert_eq!('メ'.len_utf16(), 1);
240 }
241
242 #[test]
243 fn test_empty_index() {
244 let col_index = LineIndex::new(
245 "
246const C: char = 'x';
247",
248 );
249 assert_eq!(col_index.utf16_lines.len(), 0);
250 }
251
252 #[test]
253 fn test_single_char() {
254 let col_index = LineIndex::new(
255 "
256const C: char = 'メ';
257",
258 );
259
260 assert_eq!(col_index.utf16_lines.len(), 1);
261 assert_eq!(col_index.utf16_lines[&1].len(), 1);
262 assert_eq!(
263 col_index.utf16_lines[&1][0],
264 Utf16Char {
265 start: 17.into(),
266 end: 20.into()
267 }
268 );
269
270 // UTF-8 to UTF-16, no changes
271 assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
272
273 // UTF-8 to UTF-16
274 assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20);
275
276 // UTF-16 to UTF-8, no changes
277 assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextUnit::from(15));
278
279 // UTF-16 to UTF-8
280 assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextUnit::from(21));
281 }
282
283 #[test]
284 fn test_string() {
285 let col_index = LineIndex::new(
286 "
287const C: char = \"メ メ\";
288",
289 );
290
291 assert_eq!(col_index.utf16_lines.len(), 1);
292 assert_eq!(col_index.utf16_lines[&1].len(), 2);
293 assert_eq!(
294 col_index.utf16_lines[&1][0],
295 Utf16Char {
296 start: 17.into(),
297 end: 20.into()
298 }
299 );
300 assert_eq!(
301 col_index.utf16_lines[&1][1],
302 Utf16Char {
303 start: 21.into(),
304 end: 24.into()
305 }
306 );
307
308 // UTF-8 to UTF-16
309 assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
310
311 assert_eq!(col_index.utf8_to_utf16_col(1, 21.into()), 19);
312 assert_eq!(col_index.utf8_to_utf16_col(1, 25.into()), 21);
313
314 assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15);
315
316 // UTF-16 to UTF-8
317 assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextUnit::from_usize(15));
318
319 assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextUnit::from_usize(20));
320 assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextUnit::from_usize(23));
321
322 assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextUnit::from_usize(15));
323 }
324}
diff --git a/crates/ra_editor/src/symbols.rs b/crates/ra_editor/src/symbols.rs
index 4e602d0e3..6d3b0514a 100644
--- a/crates/ra_editor/src/symbols.rs
+++ b/crates/ra_editor/src/symbols.rs
@@ -2,8 +2,8 @@ use crate::TextRange;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 algo::visit::{visitor, Visitor}, 4 algo::visit::{visitor, Visitor},
5 ast::{self, NameOwner}, 5 ast::{self, DocCommentsOwner, NameOwner},
6 AstNode, File, SmolStr, SyntaxKind, SyntaxNodeRef, WalkEvent, 6 AstNode, SourceFileNode, SmolStr, SyntaxKind, SyntaxNodeRef, WalkEvent,
7}; 7};
8 8
9#[derive(Debug, Clone)] 9#[derive(Debug, Clone)]
@@ -22,7 +22,37 @@ pub struct FileSymbol {
22 pub kind: SyntaxKind, 22 pub kind: SyntaxKind,
23} 23}
24 24
25pub fn file_symbols(file: &File) -> Vec<FileSymbol> { 25impl FileSymbol {
26 pub fn docs(&self, file: &SourceFileNode) -> Option<String> {
27 file.syntax()
28 .descendants()
29 .filter(|node| node.kind() == self.kind && node.range() == self.node_range)
30 .filter_map(|node: SyntaxNodeRef| {
31 fn doc_comments<'a, N: DocCommentsOwner<'a>>(node: N) -> Option<String> {
32 let comments = node.doc_comment_text();
33 if comments.is_empty() {
34 None
35 } else {
36 Some(comments)
37 }
38 }
39
40 visitor()
41 .visit(doc_comments::<ast::FnDef>)
42 .visit(doc_comments::<ast::StructDef>)
43 .visit(doc_comments::<ast::EnumDef>)
44 .visit(doc_comments::<ast::TraitDef>)
45 .visit(doc_comments::<ast::Module>)
46 .visit(doc_comments::<ast::TypeDef>)
47 .visit(doc_comments::<ast::ConstDef>)
48 .visit(doc_comments::<ast::StaticDef>)
49 .accept(node)?
50 })
51 .nth(0)
52 }
53}
54
55pub fn file_symbols(file: &SourceFileNode) -> Vec<FileSymbol> {
26 file.syntax().descendants().filter_map(to_symbol).collect() 56 file.syntax().descendants().filter_map(to_symbol).collect()
27} 57}
28 58
@@ -47,7 +77,7 @@ fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> {
47 .accept(node)? 77 .accept(node)?
48} 78}
49 79
50pub fn file_structure(file: &File) -> Vec<StructureNode> { 80pub fn file_structure(file: &SourceFileNode) -> Vec<StructureNode> {
51 let mut res = Vec::new(); 81 let mut res = Vec::new();
52 let mut stack = Vec::new(); 82 let mut stack = Vec::new();
53 83
@@ -123,7 +153,7 @@ mod tests {
123 153
124 #[test] 154 #[test]
125 fn test_file_structure() { 155 fn test_file_structure() {
126 let file = File::parse( 156 let file = SourceFileNode::parse(
127 r#" 157 r#"
128struct Foo { 158struct Foo {
129 x: i32 159 x: i32
diff --git a/crates/ra_editor/src/test_utils.rs b/crates/ra_editor/src/test_utils.rs
index bc3d700f6..cbeb6433b 100644
--- a/crates/ra_editor/src/test_utils.rs
+++ b/crates/ra_editor/src/test_utils.rs
@@ -1,10 +1,14 @@
1use crate::LocalEdit; 1use crate::LocalEdit;
2pub use crate::_test_utils::*; 2pub use crate::_test_utils::*;
3use ra_syntax::{File, TextRange, TextUnit}; 3use ra_syntax::{SourceFileNode, TextRange, TextUnit};
4 4
5pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>>(before: &str, after: &str, f: F) { 5pub fn check_action<F: Fn(&SourceFileNode, TextUnit) -> Option<LocalEdit>>(
6 before: &str,
7 after: &str,
8 f: F,
9) {
6 let (before_cursor_pos, before) = extract_offset(before); 10 let (before_cursor_pos, before) = extract_offset(before);
7 let file = File::parse(&before); 11 let file = SourceFileNode::parse(&before);
8 let result = f(&file, before_cursor_pos).expect("code action is not applicable"); 12 let result = f(&file, before_cursor_pos).expect("code action is not applicable");
9 let actual = result.edit.apply(&before); 13 let actual = result.edit.apply(&before);
10 let actual_cursor_pos = match result.cursor_position { 14 let actual_cursor_pos = match result.cursor_position {
@@ -15,13 +19,13 @@ pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>>(before: &str, a
15 assert_eq_text!(after, &actual); 19 assert_eq_text!(after, &actual);
16} 20}
17 21
18pub fn check_action_range<F: Fn(&File, TextRange) -> Option<LocalEdit>>( 22pub fn check_action_range<F: Fn(&SourceFileNode, TextRange) -> Option<LocalEdit>>(
19 before: &str, 23 before: &str,
20 after: &str, 24 after: &str,
21 f: F, 25 f: F,
22) { 26) {
23 let (range, before) = extract_range(before); 27 let (range, before) = extract_range(before);
24 let file = File::parse(&before); 28 let file = SourceFileNode::parse(&before);
25 let result = f(&file, range).expect("code action is not applicable"); 29 let result = f(&file, range).expect("code action is not applicable");
26 let actual = result.edit.apply(&before); 30 let actual = result.edit.apply(&before);
27 let actual_cursor_pos = match result.cursor_position { 31 let actual_cursor_pos = match result.cursor_position {
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs
index 5a457d148..f894d8392 100644
--- a/crates/ra_editor/src/typing.rs
+++ b/crates/ra_editor/src/typing.rs
@@ -4,14 +4,14 @@ use ra_syntax::{
4 algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset}, 4 algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset},
5 ast, 5 ast,
6 text_utils::{contains_offset_nonstrict, intersect}, 6 text_utils::{contains_offset_nonstrict, intersect},
7 AstNode, File, SyntaxKind, 7 AstNode, SourceFileNode, SyntaxKind,
8 SyntaxKind::*, 8 SyntaxKind::*,
9 SyntaxNodeRef, TextRange, TextUnit, 9 SyntaxNodeRef, TextRange, TextUnit,
10}; 10};
11 11
12use crate::{find_node_at_offset, EditBuilder, LocalEdit}; 12use crate::{find_node_at_offset, EditBuilder, LocalEdit};
13 13
14pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { 14pub fn join_lines(file: &SourceFileNode, range: TextRange) -> LocalEdit {
15 let range = if range.is_empty() { 15 let range = if range.is_empty() {
16 let syntax = file.syntax(); 16 let syntax = file.syntax();
17 let text = syntax.text().slice(range.start()..); 17 let text = syntax.text().slice(range.start()..);
@@ -55,7 +55,7 @@ pub fn join_lines(file: &File, range: TextRange) -> LocalEdit {
55 } 55 }
56} 56}
57 57
58pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> { 58pub fn on_enter(file: &SourceFileNode, offset: TextUnit) -> Option<LocalEdit> {
59 let comment = find_leaf_at_offset(file.syntax(), offset) 59 let comment = find_leaf_at_offset(file.syntax(), offset)
60 .left_biased() 60 .left_biased()
61 .and_then(ast::Comment::cast)?; 61 .and_then(ast::Comment::cast)?;
@@ -80,7 +80,7 @@ pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> {
80 }) 80 })
81} 81}
82 82
83fn node_indent<'a>(file: &'a File, node: SyntaxNodeRef) -> Option<&'a str> { 83fn node_indent<'a>(file: &'a SourceFileNode, node: SyntaxNodeRef) -> Option<&'a str> {
84 let ws = match find_leaf_at_offset(file.syntax(), node.range().start()) { 84 let ws = match find_leaf_at_offset(file.syntax(), node.range().start()) {
85 LeafAtOffset::Between(l, r) => { 85 LeafAtOffset::Between(l, r) => {
86 assert!(r == node); 86 assert!(r == node);
@@ -100,7 +100,7 @@ fn node_indent<'a>(file: &'a File, node: SyntaxNodeRef) -> Option<&'a str> {
100 Some(&text[pos..]) 100 Some(&text[pos..])
101} 101}
102 102
103pub fn on_eq_typed(file: &File, offset: TextUnit) -> Option<LocalEdit> { 103pub fn on_eq_typed(file: &SourceFileNode, offset: TextUnit) -> Option<LocalEdit> {
104 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; 104 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
105 if let_stmt.has_semi() { 105 if let_stmt.has_semi() {
106 return None; 106 return None;
@@ -390,7 +390,7 @@ fn foo() {
390 390
391 fn check_join_lines_sel(before: &str, after: &str) { 391 fn check_join_lines_sel(before: &str, after: &str) {
392 let (sel, before) = extract_range(before); 392 let (sel, before) = extract_range(before);
393 let file = File::parse(&before); 393 let file = SourceFileNode::parse(&before);
394 let result = join_lines(&file, sel); 394 let result = join_lines(&file, sel);
395 let actual = result.edit.apply(&before); 395 let actual = result.edit.apply(&before);
396 assert_eq_text!(after, &actual); 396 assert_eq_text!(after, &actual);
@@ -469,7 +469,7 @@ pub fn handle_find_matching_brace() {
469 fn test_on_eq_typed() { 469 fn test_on_eq_typed() {
470 fn do_check(before: &str, after: &str) { 470 fn do_check(before: &str, after: &str) {
471 let (offset, before) = extract_offset(before); 471 let (offset, before) = extract_offset(before);
472 let file = File::parse(&before); 472 let file = SourceFileNode::parse(&before);
473 let result = on_eq_typed(&file, offset).unwrap(); 473 let result = on_eq_typed(&file, offset).unwrap();
474 let actual = result.edit.apply(&before); 474 let actual = result.edit.apply(&before);
475 assert_eq_text!(after, &actual); 475 assert_eq_text!(after, &actual);
@@ -513,7 +513,7 @@ fn foo() {
513 fn test_on_enter() { 513 fn test_on_enter() {
514 fn apply_on_enter(before: &str) -> Option<String> { 514 fn apply_on_enter(before: &str) -> Option<String> {
515 let (offset, before) = extract_offset(before); 515 let (offset, before) = extract_offset(before);
516 let file = File::parse(&before); 516 let file = SourceFileNode::parse(&before);
517 let result = on_enter(&file, offset)?; 517 let result = on_enter(&file, offset)?;
518 let actual = result.edit.apply(&before); 518 let actual = result.edit.apply(&before);
519 let actual = add_cursor(&actual, result.cursor_position.unwrap()); 519 let actual = add_cursor(&actual, result.cursor_position.unwrap());
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index f29dafc17..79d86f9b2 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -14,7 +14,7 @@ serde = "1.0.71"
14serde_derive = "1.0.71" 14serde_derive = "1.0.71"
15drop_bomb = "0.1.0" 15drop_bomb = "0.1.0"
16crossbeam-channel = "0.2.4" 16crossbeam-channel = "0.2.4"
17flexi_logger = "0.9.1" 17flexi_logger = "0.10.0"
18log = "0.4.3" 18log = "0.4.3"
19url_serde = "0.2.0" 19url_serde = "0.2.0"
20languageserver-types = "0.51.0" 20languageserver-types = "0.51.0"
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index 0d02c8073..bcf857fce 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -16,7 +16,7 @@ pub fn server_capabilities() -> ServerCapabilities {
16 save: None, 16 save: None,
17 }, 17 },
18 )), 18 )),
19 hover_provider: None, 19 hover_provider: Some(true),
20 completion_provider: Some(CompletionOptions { 20 completion_provider: Some(CompletionOptions {
21 resolve_provider: None, 21 resolve_provider: None,
22 trigger_characters: None, 22 trigger_characters: None,
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index fa04f4b00..5d5a0c55e 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -2,7 +2,7 @@ use languageserver_types::{
2 Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, 2 Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
3 TextDocumentItem, TextDocumentPositionParams, TextEdit, Url, VersionedTextDocumentIdentifier, 3 TextDocumentItem, TextDocumentPositionParams, TextEdit, Url, VersionedTextDocumentIdentifier,
4}; 4};
5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition}; 5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileNodeEdit, FilePosition};
6use ra_editor::{AtomEdit, Edit, LineCol, LineIndex}; 6use ra_editor::{AtomEdit, Edit, LineCol, LineIndex};
7use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 7use ra_syntax::{SyntaxKind, TextRange, TextUnit};
8 8
@@ -49,10 +49,9 @@ impl ConvWith for Position {
49 type Output = TextUnit; 49 type Output = TextUnit;
50 50
51 fn conv_with(self, line_index: &LineIndex) -> TextUnit { 51 fn conv_with(self, line_index: &LineIndex) -> TextUnit {
52 // TODO: UTF-16
53 let line_col = LineCol { 52 let line_col = LineCol {
54 line: self.line as u32, 53 line: self.line as u32,
55 col: (self.character as u32).into(), 54 col_utf16: self.character as u32,
56 }; 55 };
57 line_index.offset(line_col) 56 line_index.offset(line_col)
58 } 57 }
@@ -64,8 +63,10 @@ impl ConvWith for TextUnit {
64 63
65 fn conv_with(self, line_index: &LineIndex) -> Position { 64 fn conv_with(self, line_index: &LineIndex) -> Position {
66 let line_col = line_index.line_col(self); 65 let line_col = line_index.line_col(self);
67 // TODO: UTF-16 66 Position::new(
68 Position::new(u64::from(line_col.line), u64::from(u32::from(line_col.col))) 67 u64::from(line_col.line),
68 u64::from(u32::from(line_col.col_utf16)),
69 )
69 } 70 }
70} 71}
71 72
@@ -203,8 +204,10 @@ impl TryConvWith for SourceChange {
203 .map(|it| it.edits.as_slice()) 204 .map(|it| it.edits.as_slice())
204 .unwrap_or(&[]); 205 .unwrap_or(&[]);
205 let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits); 206 let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits);
206 let position = 207 let position = Position::new(
207 Position::new(u64::from(line_col.line), u64::from(u32::from(line_col.col))); 208 u64::from(line_col.line),
209 u64::from(u32::from(line_col.col_utf16)),
210 );
208 Some(TextDocumentPositionParams { 211 Some(TextDocumentPositionParams {
209 text_document: TextDocumentIdentifier::new(pos.file_id.try_conv_with(world)?), 212 text_document: TextDocumentIdentifier::new(pos.file_id.try_conv_with(world)?),
210 position, 213 position,
@@ -247,17 +250,17 @@ fn translate_offset_with_edit(
247 if in_edit_line_col.line == 0 { 250 if in_edit_line_col.line == 0 {
248 LineCol { 251 LineCol {
249 line: edit_line_col.line, 252 line: edit_line_col.line,
250 col: edit_line_col.col + in_edit_line_col.col, 253 col_utf16: edit_line_col.col_utf16 + in_edit_line_col.col_utf16,
251 } 254 }
252 } else { 255 } else {
253 LineCol { 256 LineCol {
254 line: edit_line_col.line + in_edit_line_col.line, 257 line: edit_line_col.line + in_edit_line_col.line,
255 col: in_edit_line_col.col, 258 col_utf16: in_edit_line_col.col_utf16,
256 } 259 }
257 } 260 }
258} 261}
259 262
260impl TryConvWith for SourceFileEdit { 263impl TryConvWith for SourceFileNodeEdit {
261 type Ctx = ServerWorld; 264 type Ctx = ServerWorld;
262 type Output = TextDocumentEdit; 265 type Output = TextDocumentEdit;
263 fn try_conv_with(self, world: &ServerWorld) -> Result<TextDocumentEdit> { 266 fn try_conv_with(self, world: &ServerWorld) -> Result<TextDocumentEdit> {
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs
index c07eb0140..26bcddd8e 100644
--- a/crates/ra_lsp_server/src/main.rs
+++ b/crates/ra_lsp_server/src/main.rs
@@ -2,10 +2,14 @@
2extern crate log; 2extern crate log;
3#[macro_use] 3#[macro_use]
4extern crate failure; 4extern crate failure;
5#[macro_use]
6extern crate serde_derive;
7extern crate serde;
5extern crate flexi_logger; 8extern crate flexi_logger;
6extern crate gen_lsp_server; 9extern crate gen_lsp_server;
7extern crate ra_lsp_server; 10extern crate ra_lsp_server;
8 11
12use serde::Deserialize;
9use flexi_logger::{Duplicate, Logger}; 13use flexi_logger::{Duplicate, Logger};
10use gen_lsp_server::{run_server, stdio_transport}; 14use gen_lsp_server::{run_server, stdio_transport};
11use ra_lsp_server::Result; 15use ra_lsp_server::Result;
@@ -30,6 +34,12 @@ fn main() -> Result<()> {
30 } 34 }
31} 35}
32 36
37#[derive(Deserialize)]
38#[serde(rename_all = "camelCase")]
39struct InitializationOptions {
40 publish_decorations: bool,
41}
42
33fn main_inner() -> Result<()> { 43fn main_inner() -> Result<()> {
34 let (receiver, sender, threads) = stdio_transport(); 44 let (receiver, sender, threads) = stdio_transport();
35 let cwd = ::std::env::current_dir()?; 45 let cwd = ::std::env::current_dir()?;
@@ -42,7 +52,12 @@ fn main_inner() -> Result<()> {
42 .root_uri 52 .root_uri
43 .and_then(|it| it.to_file_path().ok()) 53 .and_then(|it| it.to_file_path().ok())
44 .unwrap_or(cwd); 54 .unwrap_or(cwd);
45 ra_lsp_server::main_loop(false, root, r, s) 55 let publish_decorations = params
56 .initialization_options
57 .and_then(|v| InitializationOptions::deserialize(v).ok())
58 .map(|it| it.publish_decorations)
59 == Some(true);
60 ra_lsp_server::main_loop(false, root, publish_decorations, r, s)
46 }, 61 },
47 )?; 62 )?;
48 info!("shutting down IO..."); 63 info!("shutting down IO...");
@@ -50,3 +65,27 @@ fn main_inner() -> Result<()> {
50 info!("... IO is down"); 65 info!("... IO is down");
51 Ok(()) 66 Ok(())
52} 67}
68
69/*
70 (let ((backend (eglot-xref-backend)))
71 (mapcar
72 (lambda (xref)
73 (let ((loc (xref-item-location xref)))
74 (propertize
75 (concat
76 (when (xref-file-location-p loc)
77 (with-slots (file line column) loc
78 (format "%s:%s:%s:"
79 (propertize (file-relative-name file)
80 'face 'compilation-info)
81 (propertize (format "%s" line)
82 'face 'compilation-line
83 )
84 column)))
85 (xref-item-summary xref))
86 'xref xref)))
87 (xref-backend-apropos backend "Analysis"))
88 )
89
90
91*/
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 5314a333e..c872b0dc4 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -4,9 +4,9 @@ use gen_lsp_server::ErrorCode;
4use languageserver_types::{ 4use languageserver_types::{
5 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic, 5 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic,
6 DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, 6 DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind,
7 FoldingRangeParams, InsertTextFormat, Location, MarkupContent, MarkupKind, Position, 7 FoldingRangeParams, InsertTextFormat, Location, MarkupContent, MarkupKind, MarkedString, Position,
8 PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, 8 PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit,
9 WorkspaceEdit, ParameterInformation, SignatureInformation, 9 WorkspaceEdit, ParameterInformation, SignatureInformation, Hover, HoverContents,
10}; 10};
11use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FilePosition}; 11use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FilePosition};
12use ra_syntax::text_utils::contains_offset_nonstrict; 12use ra_syntax::text_utils::contains_offset_nonstrict;
@@ -478,6 +478,30 @@ pub fn handle_signature_help(
478 } 478 }
479} 479}
480 480
481pub fn handle_hover(
482 world: ServerWorld,
483 params: req::TextDocumentPositionParams,
484) -> Result<Option<Hover>> {
485 let position = params.try_conv_with(&world)?;
486 let line_index = world.analysis().file_line_index(position.file_id);
487
488 for (file_id, symbol) in world.analysis().approximately_resolve_symbol(position)? {
489 let range = symbol.node_range.conv_with(&line_index);
490 let comment = world.analysis.doc_comment_for(file_id, symbol)?;
491
492 if comment.is_some() {
493 let contents = HoverContents::Scalar(MarkedString::String(comment.unwrap()));
494
495 return Ok(Some(Hover {
496 contents,
497 range: Some(range),
498 }));
499 }
500 }
501
502 Ok(None)
503}
504
481pub fn handle_prepare_rename( 505pub fn handle_prepare_rename(
482 world: ServerWorld, 506 world: ServerWorld,
483 params: req::TextDocumentPositionParams, 507 params: req::TextDocumentPositionParams,
diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop/mod.rs
index 229d1b0f7..78d93741a 100644
--- a/crates/ra_lsp_server/src/main_loop/mod.rs
+++ b/crates/ra_lsp_server/src/main_loop/mod.rs
@@ -48,6 +48,7 @@ enum Task {
48pub fn main_loop( 48pub fn main_loop(
49 internal_mode: bool, 49 internal_mode: bool,
50 root: PathBuf, 50 root: PathBuf,
51 publish_decorations: bool,
51 msg_receiver: &Receiver<RawMessage>, 52 msg_receiver: &Receiver<RawMessage>,
52 msg_sender: &Sender<RawMessage>, 53 msg_sender: &Sender<RawMessage>,
53) -> Result<()> { 54) -> Result<()> {
@@ -67,6 +68,7 @@ pub fn main_loop(
67 let mut subs = Subscriptions::new(); 68 let mut subs = Subscriptions::new();
68 let main_res = main_loop_inner( 69 let main_res = main_loop_inner(
69 internal_mode, 70 internal_mode,
71 publish_decorations,
70 root, 72 root,
71 &pool, 73 &pool,
72 msg_sender, 74 msg_sender,
@@ -99,6 +101,7 @@ pub fn main_loop(
99 101
100fn main_loop_inner( 102fn main_loop_inner(
101 internal_mode: bool, 103 internal_mode: bool,
104 publish_decorations: bool,
102 ws_root: PathBuf, 105 ws_root: PathBuf,
103 pool: &ThreadPool, 106 pool: &ThreadPool,
104 msg_sender: &Sender<RawMessage>, 107 msg_sender: &Sender<RawMessage>,
@@ -210,6 +213,7 @@ fn main_loop_inner(
210 update_file_notifications_on_threadpool( 213 update_file_notifications_on_threadpool(
211 pool, 214 pool,
212 state.snapshot(), 215 state.snapshot(),
216 publish_decorations,
213 task_sender.clone(), 217 task_sender.clone(),
214 subs.subscriptions(), 218 subs.subscriptions(),
215 ) 219 )
@@ -259,6 +263,7 @@ fn on_request(
259 .on::<req::CodeActionRequest>(handlers::handle_code_action)? 263 .on::<req::CodeActionRequest>(handlers::handle_code_action)?
260 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)? 264 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
261 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)? 265 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)?
266 .on::<req::HoverRequest>(handlers::handle_hover)?
262 .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)? 267 .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)?
263 .on::<req::Rename>(handlers::handle_rename)? 268 .on::<req::Rename>(handlers::handle_rename)?
264 .on::<req::References>(handlers::handle_references)? 269 .on::<req::References>(handlers::handle_references)?
@@ -415,6 +420,7 @@ impl<'a> PoolDispatcher<'a> {
415fn update_file_notifications_on_threadpool( 420fn update_file_notifications_on_threadpool(
416 pool: &ThreadPool,