diff options
49 files changed, 576 insertions, 432 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ece1fd364..a97ed24ba 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -118,6 +118,37 @@ jobs: | |||
118 | name: dist-x86_64-unknown-linux-gnu | 118 | name: dist-x86_64-unknown-linux-gnu |
119 | path: ./dist | 119 | path: ./dist |
120 | 120 | ||
121 | dist-aarch64-unknown-linux-gnu: | ||
122 | name: dist (aarch64-unknown-linux-gnu) | ||
123 | runs-on: ubuntu-16.04 | ||
124 | env: | ||
125 | RA_TARGET: aarch64-unknown-linux-gnu | ||
126 | CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc | ||
127 | |||
128 | steps: | ||
129 | - name: Checkout repository | ||
130 | uses: actions/checkout@v2 | ||
131 | |||
132 | - name: Install Rust toolchain | ||
133 | uses: actions-rs/toolchain@v1 | ||
134 | with: | ||
135 | toolchain: stable | ||
136 | target: aarch64-unknown-linux-gnu | ||
137 | profile: minimal | ||
138 | override: true | ||
139 | |||
140 | - name: Install target toolchain | ||
141 | run: sudo apt-get install gcc-aarch64-linux-gnu | ||
142 | |||
143 | - name: Dist | ||
144 | run: cargo xtask dist | ||
145 | |||
146 | - name: Upload artifacts | ||
147 | uses: actions/upload-artifact@v1 | ||
148 | with: | ||
149 | name: dist-aarch64-unknown-linux-gnu | ||
150 | path: ./dist | ||
151 | |||
121 | dist-x86_64-apple-darwin: | 152 | dist-x86_64-apple-darwin: |
122 | name: dist (x86_64-apple-darwin) | 153 | name: dist (x86_64-apple-darwin) |
123 | runs-on: macos-latest | 154 | runs-on: macos-latest |
@@ -174,7 +205,7 @@ jobs: | |||
174 | publish: | 205 | publish: |
175 | name: publish | 206 | name: publish |
176 | runs-on: ubuntu-16.04 | 207 | runs-on: ubuntu-16.04 |
177 | needs: ['dist-x86_64-pc-windows-msvc', 'dist-aarch64-pc-windows-msvc', 'dist-x86_64-unknown-linux-gnu', 'dist-x86_64-apple-darwin', 'dist-aarch64-apple-darwin'] | 208 | needs: ['dist-x86_64-pc-windows-msvc', 'dist-aarch64-pc-windows-msvc', 'dist-x86_64-unknown-linux-gnu', 'dist-aarch64-unknown-linux-gnu', 'dist-x86_64-apple-darwin', 'dist-aarch64-apple-darwin'] |
178 | steps: | 209 | steps: |
179 | - name: Install Nodejs | 210 | - name: Install Nodejs |
180 | uses: actions/setup-node@v1 | 211 | uses: actions/setup-node@v1 |
@@ -207,6 +238,10 @@ jobs: | |||
207 | path: dist | 238 | path: dist |
208 | - uses: actions/download-artifact@v1 | 239 | - uses: actions/download-artifact@v1 |
209 | with: | 240 | with: |
241 | name: dist-aarch64-unknown-linux-gnu | ||
242 | path: dist | ||
243 | - uses: actions/download-artifact@v1 | ||
244 | with: | ||
210 | name: dist-x86_64-pc-windows-msvc | 245 | name: dist-x86_64-pc-windows-msvc |
211 | path: dist | 246 | path: dist |
212 | - uses: actions/download-artifact@v1 | 247 | - uses: actions/download-artifact@v1 |
diff --git a/Cargo.lock b/Cargo.lock index db8b49122..b52616974 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -502,6 +502,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
502 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" | 502 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" |
503 | 503 | ||
504 | [[package]] | 504 | [[package]] |
505 | name = "hashbrown" | ||
506 | version = "0.10.0" | ||
507 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
508 | checksum = "2140e9c963869f01789fa4fef4805211081ec794af5fc77c0d5b377906118853" | ||
509 | |||
510 | [[package]] | ||
505 | name = "heck" | 511 | name = "heck" |
506 | version = "0.3.2" | 512 | version = "0.3.2" |
507 | source = "registry+https://github.com/rust-lang/crates.io-index" | 513 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -552,7 +558,7 @@ dependencies = [ | |||
552 | "hir_expand", | 558 | "hir_expand", |
553 | "indexmap", | 559 | "indexmap", |
554 | "itertools 0.10.0", | 560 | "itertools 0.10.0", |
555 | "la-arena 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | 561 | "la-arena", |
556 | "log", | 562 | "log", |
557 | "mbe", | 563 | "mbe", |
558 | "once_cell", | 564 | "once_cell", |
@@ -571,7 +577,7 @@ version = "0.0.0" | |||
571 | dependencies = [ | 577 | dependencies = [ |
572 | "base_db", | 578 | "base_db", |
573 | "either", | 579 | "either", |
574 | "la-arena 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | 580 | "la-arena", |
575 | "log", | 581 | "log", |
576 | "mbe", | 582 | "mbe", |
577 | "parser", | 583 | "parser", |
@@ -596,7 +602,7 @@ dependencies = [ | |||
596 | "hir_def", | 602 | "hir_def", |
597 | "hir_expand", | 603 | "hir_expand", |
598 | "itertools 0.10.0", | 604 | "itertools 0.10.0", |
599 | "la-arena 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | 605 | "la-arena", |
600 | "log", | 606 | "log", |
601 | "once_cell", | 607 | "once_cell", |
602 | "profile", | 608 | "profile", |
@@ -686,7 +692,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
686 | checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" | 692 | checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" |
687 | dependencies = [ | 693 | dependencies = [ |
688 | "autocfg", | 694 | "autocfg", |
689 | "hashbrown", | 695 | "hashbrown 0.9.1", |
690 | ] | 696 | ] |
691 | 697 | ||
692 | [[package]] | 698 | [[package]] |
@@ -769,13 +775,7 @@ dependencies = [ | |||
769 | 775 | ||
770 | [[package]] | 776 | [[package]] |
771 | name = "la-arena" | 777 | name = "la-arena" |
772 | version = "0.1.1" | 778 | version = "0.2.0" |
773 | |||
774 | [[package]] | ||
775 | name = "la-arena" | ||
776 | version = "0.1.1" | ||
777 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
778 | checksum = "383ed2a74426d1051751f6483a7160b98f36068224857cd4c953b34719476fc3" | ||
779 | 779 | ||
780 | [[package]] | 780 | [[package]] |
781 | name = "lazy_static" | 781 | name = "lazy_static" |
@@ -1212,7 +1212,7 @@ name = "profile" | |||
1212 | version = "0.0.0" | 1212 | version = "0.0.0" |
1213 | dependencies = [ | 1213 | dependencies = [ |
1214 | "cfg-if 1.0.0", | 1214 | "cfg-if 1.0.0", |
1215 | "la-arena 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1215 | "la-arena", |
1216 | "libc", | 1216 | "libc", |
1217 | "once_cell", | 1217 | "once_cell", |
1218 | "perf-event", | 1218 | "perf-event", |
@@ -1227,7 +1227,7 @@ dependencies = [ | |||
1227 | "cargo_metadata", | 1227 | "cargo_metadata", |
1228 | "cfg", | 1228 | "cfg", |
1229 | "itertools 0.10.0", | 1229 | "itertools 0.10.0", |
1230 | "la-arena 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1230 | "la-arena", |
1231 | "log", | 1231 | "log", |
1232 | "paths", | 1232 | "paths", |
1233 | "proc_macro_api", | 1233 | "proc_macro_api", |
@@ -1325,10 +1325,11 @@ checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" | |||
1325 | 1325 | ||
1326 | [[package]] | 1326 | [[package]] |
1327 | name = "rowan" | 1327 | name = "rowan" |
1328 | version = "0.10.1" | 1328 | version = "0.10.5" |
1329 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1329 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1330 | checksum = "ca9516377b32367ade2fbe1846c75afa4827c8976f1c7d05d5473573d18a1a04" | 1330 | checksum = "e1898adeafc7d3c69913b33ee1acbbb39c726a9dbe05ff77c08b52957643e8db" |
1331 | dependencies = [ | 1331 | dependencies = [ |
1332 | "hashbrown 0.10.0", | ||
1332 | "rustc-hash", | 1333 | "rustc-hash", |
1333 | "smol_str", | 1334 | "smol_str", |
1334 | "text-size", | 1335 | "text-size", |
diff --git a/crates/assists/src/assist_config.rs b/crates/assists/src/assist_config.rs index 4fe8ea761..9cabf037c 100644 --- a/crates/assists/src/assist_config.rs +++ b/crates/assists/src/assist_config.rs | |||
@@ -4,7 +4,7 @@ | |||
4 | //! module, and we use to statically check that we only produce snippet | 4 | //! module, and we use to statically check that we only produce snippet |
5 | //! assists if we are allowed to. | 5 | //! assists if we are allowed to. |
6 | 6 | ||
7 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; | 7 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
8 | 8 | ||
9 | use crate::AssistKind; | 9 | use crate::AssistKind; |
10 | 10 | ||
@@ -14,9 +14,3 @@ pub struct AssistConfig { | |||
14 | pub allowed: Option<Vec<AssistKind>>, | 14 | pub allowed: Option<Vec<AssistKind>>, |
15 | pub insert_use: InsertUseConfig, | 15 | pub insert_use: InsertUseConfig, |
16 | } | 16 | } |
17 | |||
18 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
19 | pub struct InsertUseConfig { | ||
20 | pub merge: Option<MergeBehavior>, | ||
21 | pub prefix_kind: hir::PrefixKind, | ||
22 | } | ||
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs index 55620f0f3..4e2a4fcd9 100644 --- a/crates/assists/src/handlers/auto_import.rs +++ b/crates/assists/src/handlers/auto_import.rs | |||
@@ -1,13 +1,11 @@ | |||
1 | use ide_db::helpers::{ | 1 | use ide_db::helpers::{ |
2 | import_assets::{ImportAssets, ImportCandidate}, | ||
2 | insert_use::{insert_use, ImportScope}, | 3 | insert_use::{insert_use, ImportScope}, |
3 | mod_path_to_ast, | 4 | mod_path_to_ast, |
4 | }; | 5 | }; |
5 | use syntax::ast; | 6 | use syntax::ast; |
6 | 7 | ||
7 | use crate::{ | 8 | use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; |
8 | utils::import_assets::{ImportAssets, ImportCandidate}, | ||
9 | AssistContext, AssistId, AssistKind, Assists, GroupLabel, | ||
10 | }; | ||
11 | 9 | ||
12 | // Feature: Auto Import | 10 | // Feature: Auto Import |
13 | // | 11 | // |
@@ -121,8 +119,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
121 | 119 | ||
122 | fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { | 120 | fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { |
123 | let name = match import_candidate { | 121 | let name = match import_candidate { |
124 | ImportCandidate::UnqualifiedName(candidate) | 122 | ImportCandidate::Path(candidate) => format!("Import {}", &candidate.name), |
125 | | ImportCandidate::QualifierStart(candidate) => format!("Import {}", &candidate.name), | ||
126 | ImportCandidate::TraitAssocItem(candidate) => { | 123 | ImportCandidate::TraitAssocItem(candidate) => { |
127 | format!("Import a trait for item {}", &candidate.name) | 124 | format!("Import a trait for item {}", &candidate.name) |
128 | } | 125 | } |
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs index f7fbf37f4..a7d9fd4dc 100644 --- a/crates/assists/src/handlers/qualify_path.rs +++ b/crates/assists/src/handlers/qualify_path.rs | |||
@@ -1,7 +1,10 @@ | |||
1 | use std::iter; | 1 | use std::iter; |
2 | 2 | ||
3 | use hir::AsName; | 3 | use hir::AsName; |
4 | use ide_db::helpers::mod_path_to_ast; | 4 | use ide_db::helpers::{ |
5 | import_assets::{ImportAssets, ImportCandidate}, | ||
6 | mod_path_to_ast, | ||
7 | }; | ||
5 | use ide_db::RootDatabase; | 8 | use ide_db::RootDatabase; |
6 | use syntax::{ | 9 | use syntax::{ |
7 | ast, | 10 | ast, |
@@ -12,7 +15,6 @@ use test_utils::mark; | |||
12 | 15 | ||
13 | use crate::{ | 16 | use crate::{ |
14 | assist_context::{AssistContext, Assists}, | 17 | assist_context::{AssistContext, Assists}, |
15 | utils::import_assets::{ImportAssets, ImportCandidate}, | ||
16 | AssistId, AssistKind, GroupLabel, | 18 | AssistId, AssistKind, GroupLabel, |
17 | }; | 19 | }; |
18 | 20 | ||
@@ -53,17 +55,18 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
53 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; | 55 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; |
54 | 56 | ||
55 | let qualify_candidate = match candidate { | 57 | let qualify_candidate = match candidate { |
56 | ImportCandidate::QualifierStart(_) => { | 58 | ImportCandidate::Path(candidate) => { |
57 | mark::hit!(qualify_path_qualifier_start); | 59 | if candidate.qualifier.is_some() { |
58 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; | 60 | mark::hit!(qualify_path_qualifier_start); |
59 | let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); | 61 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; |
60 | QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) | 62 | let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); |
61 | } | 63 | QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) |
62 | ImportCandidate::UnqualifiedName(_) => { | 64 | } else { |
63 | mark::hit!(qualify_path_unqualified_name); | 65 | mark::hit!(qualify_path_unqualified_name); |
64 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; | 66 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; |
65 | let generics = path.segment()?.generic_arg_list(); | 67 | let generics = path.segment()?.generic_arg_list(); |
66 | QualifyCandidate::UnqualifiedName(generics) | 68 | QualifyCandidate::UnqualifiedName(generics) |
69 | } | ||
67 | } | 70 | } |
68 | ImportCandidate::TraitAssocItem(_) => { | 71 | ImportCandidate::TraitAssocItem(_) => { |
69 | mark::hit!(qualify_path_trait_assoc_item); | 72 | mark::hit!(qualify_path_trait_assoc_item); |
@@ -186,7 +189,7 @@ fn item_as_trait(item: hir::ItemInNs) -> Option<hir::Trait> { | |||
186 | 189 | ||
187 | fn group_label(candidate: &ImportCandidate) -> GroupLabel { | 190 | fn group_label(candidate: &ImportCandidate) -> GroupLabel { |
188 | let name = match candidate { | 191 | let name = match candidate { |
189 | ImportCandidate::UnqualifiedName(it) | ImportCandidate::QualifierStart(it) => &it.name, | 192 | ImportCandidate::Path(it) => &it.name, |
190 | ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, | 193 | ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, |
191 | }; | 194 | }; |
192 | GroupLabel(format!("Qualify {}", name)) | 195 | GroupLabel(format!("Qualify {}", name)) |
@@ -194,8 +197,13 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel { | |||
194 | 197 | ||
195 | fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { | 198 | fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { |
196 | match candidate { | 199 | match candidate { |
197 | ImportCandidate::UnqualifiedName(_) => format!("Qualify as `{}`", &import), | 200 | ImportCandidate::Path(candidate) => { |
198 | ImportCandidate::QualifierStart(_) => format!("Qualify with `{}`", &import), | 201 | if candidate.qualifier.is_some() { |
202 | format!("Qualify with `{}`", &import) | ||
203 | } else { | ||
204 | format!("Qualify as `{}`", &import) | ||
205 | } | ||
206 | } | ||
199 | ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import), | 207 | ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import), |
200 | ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import), | 208 | ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import), |
201 | } | 209 | } |
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index 3d7971806..14178a651 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -24,7 +24,7 @@ use syntax::TextRange; | |||
24 | 24 | ||
25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; | 25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; |
26 | 26 | ||
27 | pub use assist_config::{AssistConfig, InsertUseConfig}; | 27 | pub use assist_config::AssistConfig; |
28 | 28 | ||
29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
30 | pub enum AssistKind { | 30 | pub enum AssistKind { |
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs index 71431b406..32bd8698b 100644 --- a/crates/assists/src/tests.rs +++ b/crates/assists/src/tests.rs | |||
@@ -3,16 +3,17 @@ mod generated; | |||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ide_db::{ | 4 | use ide_db::{ |
5 | base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}, | 5 | base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}, |
6 | helpers::{insert_use::MergeBehavior, SnippetCap}, | 6 | helpers::{ |
7 | insert_use::{InsertUseConfig, MergeBehavior}, | ||
8 | SnippetCap, | ||
9 | }, | ||
7 | source_change::FileSystemEdit, | 10 | source_change::FileSystemEdit, |
8 | RootDatabase, | 11 | RootDatabase, |
9 | }; | 12 | }; |
10 | use syntax::TextRange; | 13 | use syntax::TextRange; |
11 | use test_utils::{assert_eq_text, extract_offset, extract_range}; | 14 | use test_utils::{assert_eq_text, extract_offset, extract_range}; |
12 | 15 | ||
13 | use crate::{ | 16 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists}; |
14 | handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists, InsertUseConfig, | ||
15 | }; | ||
16 | use stdx::{format_to, trim_indent}; | 17 | use stdx::{format_to, trim_indent}; |
17 | 18 | ||
18 | pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { | 19 | pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index 9ea96eb73..fc9f83bab 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | //! Assorted functions shared by several assists. | 1 | //! Assorted functions shared by several assists. |
2 | pub(crate) mod import_assets; | ||
3 | 2 | ||
4 | use std::ops; | 3 | use std::ops; |
5 | 4 | ||
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 00c9e76f0..c3ce6e51d 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs | |||
@@ -13,6 +13,7 @@ pub(crate) mod postfix; | |||
13 | pub(crate) mod macro_in_item_position; | 13 | pub(crate) mod macro_in_item_position; |
14 | pub(crate) mod trait_impl; | 14 | pub(crate) mod trait_impl; |
15 | pub(crate) mod mod_; | 15 | pub(crate) mod mod_; |
16 | pub(crate) mod flyimport; | ||
16 | 17 | ||
17 | use hir::{ModPath, ScopeDef, Type}; | 18 | use hir::{ModPath, ScopeDef, Type}; |
18 | 19 | ||
diff --git a/crates/completion/src/completions/flyimport.rs b/crates/completion/src/completions/flyimport.rs new file mode 100644 index 000000000..222809638 --- /dev/null +++ b/crates/completion/src/completions/flyimport.rs | |||
@@ -0,0 +1,291 @@ | |||
1 | //! Feature: completion with imports-on-the-fly | ||
2 | //! | ||
3 | //! When completing names in the current scope, proposes additional imports from other modules or crates, | ||
4 | //! if they can be qualified in the scope and their name contains all symbols from the completion input | ||
5 | //! (case-insensitive, in any order or places). | ||
6 | //! | ||
7 | //! ``` | ||
8 | //! fn main() { | ||
9 | //! pda$0 | ||
10 | //! } | ||
11 | //! # pub mod std { pub mod marker { pub struct PhantomData { } } } | ||
12 | //! ``` | ||
13 | //! -> | ||
14 | //! ``` | ||
15 | //! use std::marker::PhantomData; | ||
16 | //! | ||
17 | //! fn main() { | ||
18 | //! PhantomData | ||
19 | //! } | ||
20 | //! # pub mod std { pub mod marker { pub struct PhantomData { } } } | ||
21 | //! ``` | ||
22 | //! | ||
23 | //! .Fuzzy search details | ||
24 | //! | ||
25 | //! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only | ||
26 | //! (i.e. in `HashMap` in the `std::collections::HashMap` path). | ||
27 | //! For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols. | ||
28 | //! | ||
29 | //! .Import configuration | ||
30 | //! | ||
31 | //! It is possible to configure how use-trees are merged with the `importMergeBehavior` setting. | ||
32 | //! Mimics the corresponding behavior of the `Auto Import` feature. | ||
33 | //! | ||
34 | //! .LSP and performance implications | ||
35 | //! | ||
36 | //! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` | ||
37 | //! (case sensitive) resolve client capability in its client capabilities. | ||
38 | //! This way the server is able to defer the costly computations, doing them for a selected completion item only. | ||
39 | //! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, | ||
40 | //! which might be slow ergo the feature is automatically disabled. | ||
41 | //! | ||
42 | //! .Feature toggle | ||
43 | //! | ||
44 | //! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag. | ||
45 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | ||
46 | //! capability enabled. | ||
47 | |||
48 | use either::Either; | ||
49 | use hir::{ModPath, ScopeDef}; | ||
50 | use ide_db::{helpers::insert_use::ImportScope, imports_locator}; | ||
51 | use syntax::AstNode; | ||
52 | use test_utils::mark; | ||
53 | |||
54 | use crate::{ | ||
55 | context::CompletionContext, | ||
56 | render::{render_resolution_with_import, RenderContext}, | ||
57 | ImportEdit, | ||
58 | }; | ||
59 | |||
60 | use super::Completions; | ||
61 | |||
62 | pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | ||
63 | if !ctx.config.enable_autoimport_completions { | ||
64 | return None; | ||
65 | } | ||
66 | if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() { | ||
67 | return None; | ||
68 | } | ||
69 | let potential_import_name = ctx.token.to_string(); | ||
70 | if potential_import_name.len() < 2 { | ||
71 | return None; | ||
72 | } | ||
73 | let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string()); | ||
74 | |||
75 | let current_module = ctx.scope.module()?; | ||
76 | let anchor = ctx.name_ref_syntax.as_ref()?; | ||
77 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | ||
78 | |||
79 | let user_input_lowercased = potential_import_name.to_lowercase(); | ||
80 | let mut all_mod_paths = imports_locator::find_similar_imports( | ||
81 | &ctx.sema, | ||
82 | ctx.krate?, | ||
83 | Some(40), | ||
84 | potential_import_name, | ||
85 | true, | ||
86 | true, | ||
87 | ) | ||
88 | .filter_map(|import_candidate| { | ||
89 | Some(match import_candidate { | ||
90 | Either::Left(module_def) => { | ||
91 | (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def)) | ||
92 | } | ||
93 | Either::Right(macro_def) => { | ||
94 | (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def)) | ||
95 | } | ||
96 | }) | ||
97 | }) | ||
98 | .filter(|(mod_path, _)| mod_path.len() > 1) | ||
99 | .collect::<Vec<_>>(); | ||
100 | |||
101 | all_mod_paths.sort_by_cached_key(|(mod_path, _)| { | ||
102 | compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) | ||
103 | }); | ||
104 | |||
105 | acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| { | ||
106 | render_resolution_with_import( | ||
107 | RenderContext::new(ctx), | ||
108 | ImportEdit { import_path, import_scope: import_scope.clone() }, | ||
109 | &definition, | ||
110 | ) | ||
111 | })); | ||
112 | Some(()) | ||
113 | } | ||
114 | |||
115 | fn compute_fuzzy_completion_order_key( | ||
116 | proposed_mod_path: &ModPath, | ||
117 | user_input_lowercased: &str, | ||
118 | ) -> usize { | ||
119 | mark::hit!(certain_fuzzy_order_test); | ||
120 | let proposed_import_name = match proposed_mod_path.segments.last() { | ||
121 | Some(name) => name.to_string().to_lowercase(), | ||
122 | None => return usize::MAX, | ||
123 | }; | ||
124 | match proposed_import_name.match_indices(user_input_lowercased).next() { | ||
125 | Some((first_matching_index, _)) => first_matching_index, | ||
126 | None => usize::MAX, | ||
127 | } | ||
128 | } | ||
129 | |||
130 | #[cfg(test)] | ||
131 | mod tests { | ||
132 | use expect_test::{expect, Expect}; | ||
133 | use test_utils::mark; | ||
134 | |||
135 | use crate::{ | ||
136 | item::CompletionKind, | ||
137 | test_utils::{check_edit, completion_list}, | ||
138 | }; | ||
139 | |||
140 | fn check(ra_fixture: &str, expect: Expect) { | ||
141 | let actual = completion_list(ra_fixture, CompletionKind::Magic); | ||
142 | expect.assert_eq(&actual); | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn function_fuzzy_completion() { | ||
147 | check_edit( | ||
148 | "stdin", | ||
149 | r#" | ||
150 | //- /lib.rs crate:dep | ||
151 | pub mod io { | ||
152 | pub fn stdin() {} | ||
153 | }; | ||
154 | |||
155 | //- /main.rs crate:main deps:dep | ||
156 | fn main() { | ||
157 | stdi$0 | ||
158 | } | ||
159 | "#, | ||
160 | r#" | ||
161 | use dep::io::stdin; | ||
162 | |||
163 | fn main() { | ||
164 | stdin()$0 | ||
165 | } | ||
166 | "#, | ||
167 | ); | ||
168 | } | ||
169 | |||
170 | #[test] | ||
171 | fn macro_fuzzy_completion() { | ||
172 | check_edit( | ||
173 | "macro_with_curlies!", | ||
174 | r#" | ||
175 | //- /lib.rs crate:dep | ||
176 | /// Please call me as macro_with_curlies! {} | ||
177 | #[macro_export] | ||
178 | macro_rules! macro_with_curlies { | ||
179 | () => {} | ||
180 | } | ||
181 | |||
182 | //- /main.rs crate:main deps:dep | ||
183 | fn main() { | ||
184 | curli$0 | ||
185 | } | ||
186 | "#, | ||
187 | r#" | ||
188 | use dep::macro_with_curlies; | ||
189 | |||
190 | fn main() { | ||
191 | macro_with_curlies! {$0} | ||
192 | } | ||
193 | "#, | ||
194 | ); | ||
195 | } | ||
196 | |||
197 | #[test] | ||
198 | fn struct_fuzzy_completion() { | ||
199 | check_edit( | ||
200 | "ThirdStruct", | ||
201 | r#" | ||
202 | //- /lib.rs crate:dep | ||
203 | pub struct FirstStruct; | ||
204 | pub mod some_module { | ||
205 | pub struct SecondStruct; | ||
206 | pub struct ThirdStruct; | ||
207 | } | ||
208 | |||
209 | //- /main.rs crate:main deps:dep | ||
210 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
211 | |||
212 | fn main() { | ||
213 | this$0 | ||
214 | } | ||
215 | "#, | ||
216 | r#" | ||
217 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
218 | |||
219 | fn main() { | ||
220 | ThirdStruct | ||
221 | } | ||
222 | "#, | ||
223 | ); | ||
224 | } | ||
225 | |||
226 | #[test] | ||
227 | fn fuzzy_completions_come_in_specific_order() { | ||
228 | mark::check!(certain_fuzzy_order_test); | ||
229 | check( | ||
230 | r#" | ||
231 | //- /lib.rs crate:dep | ||
232 | pub struct FirstStruct; | ||
233 | pub mod some_module { | ||
234 | // already imported, omitted | ||
235 | pub struct SecondStruct; | ||
236 | // does not contain all letters from the query, omitted | ||
237 | pub struct UnrelatedOne; | ||
238 | // contains all letters from the query, but not in sequence, displayed last | ||
239 | pub struct ThiiiiiirdStruct; | ||
240 | // contains all letters from the query, but not in the beginning, displayed second | ||
241 | pub struct AfterThirdStruct; | ||
242 | // contains all letters from the query in the begginning, displayed first | ||
243 | pub struct ThirdStruct; | ||
244 | } | ||
245 | |||
246 | //- /main.rs crate:main deps:dep | ||
247 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
248 | |||
249 | fn main() { | ||
250 | hir$0 | ||
251 | } | ||
252 | "#, | ||
253 | expect![[r#" | ||
254 | st dep::some_module::ThirdStruct | ||
255 | st dep::some_module::AfterThirdStruct | ||
256 | st dep::some_module::ThiiiiiirdStruct | ||
257 | "#]], | ||
258 | ); | ||
259 | } | ||
260 | |||
261 | #[test] | ||
262 | fn does_not_propose_names_in_scope() { | ||
263 | check( | ||
264 | r#" | ||
265 | //- /lib.rs crate:dep | ||
266 | pub mod test_mod { | ||
267 | pub trait TestTrait { | ||
268 | const SPECIAL_CONST: u8; | ||
269 | type HumbleType; | ||
270 | fn weird_function(); | ||
271 | fn random_method(&self); | ||
272 | } | ||
273 | pub struct TestStruct {} | ||
274 | impl TestTrait for TestStruct { | ||
275 | const SPECIAL_CONST: u8 = 42; | ||
276 | type HumbleType = (); | ||
277 | fn weird_function() {} | ||
278 | fn random_method(&self) {} | ||
279 | } | ||
280 | } | ||
281 | |||
282 | //- /main.rs crate:main deps:dep | ||
283 | use dep::test_mod::TestStruct; | ||
284 | fn main() { | ||
285 | TestSt$0 | ||
286 | } | ||
287 | "#, | ||
288 | expect![[r#""#]], | ||
289 | ); | ||
290 | } | ||
291 | } | ||
diff --git a/crates/completion/src/completions/keyword.rs b/crates/completion/src/completions/keyword.rs index c1af348dc..47e146128 100644 --- a/crates/completion/src/completions/keyword.rs +++ b/crates/completion/src/completions/keyword.rs | |||
@@ -99,7 +99,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
99 | add_keyword(ctx, acc, "else if", "else if $0 {}"); | 99 | add_keyword(ctx, acc, "else if", "else if $0 {}"); |
100 | } | 100 | } |
101 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | 101 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { |
102 | add_keyword(ctx, acc, "mod", "mod $0 {}"); | 102 | add_keyword(ctx, acc, "mod", "mod $0"); |
103 | } | 103 | } |
104 | if ctx.bind_pat_parent || ctx.ref_pat_parent { | 104 | if ctx.bind_pat_parent || ctx.ref_pat_parent { |
105 | add_keyword(ctx, acc, "mut", "mut "); | 105 | add_keyword(ctx, acc, "mut", "mut "); |
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index 53e1391f3..ac5596ca4 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -2,17 +2,11 @@ | |||
2 | 2 | ||
3 | use std::iter; | 3 | use std::iter; |
4 | 4 | ||
5 | use either::Either; | 5 | use hir::{Adt, ModuleDef, ScopeDef, Type}; |
6 | use hir::{Adt, ModPath, ModuleDef, ScopeDef, Type}; | ||
7 | use ide_db::helpers::insert_use::ImportScope; | ||
8 | use ide_db::imports_locator; | ||
9 | use syntax::AstNode; | 6 | use syntax::AstNode; |
10 | use test_utils::mark; | 7 | use test_utils::mark; |
11 | 8 | ||
12 | use crate::{ | 9 | use crate::{CompletionContext, Completions}; |
13 | render::{render_resolution_with_import, RenderContext}, | ||
14 | CompletionContext, Completions, ImportEdit, | ||
15 | }; | ||
16 | 10 | ||
17 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 11 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
18 | if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { | 12 | if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { |
@@ -45,10 +39,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
45 | } | 39 | } |
46 | acc.add_resolution(ctx, name.to_string(), &res) | 40 | acc.add_resolution(ctx, name.to_string(), &res) |
47 | }); | 41 | }); |
48 | |||
49 | if ctx.config.enable_autoimport_completions { | ||
50 | fuzzy_completion(acc, ctx); | ||
51 | } | ||
52 | } | 42 | } |
53 | 43 | ||
54 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { | 44 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { |
@@ -77,124 +67,13 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
77 | } | 67 | } |
78 | } | 68 | } |
79 | 69 | ||
80 | // Feature: Fuzzy Completion and Autoimports | ||
81 | // | ||
82 | // When completing names in the current scope, proposes additional imports from other modules or crates, | ||
83 | // if they can be qualified in the scope and their name contains all symbols from the completion input | ||
84 | // (case-insensitive, in any order or places). | ||
85 | // | ||
86 | // ``` | ||
87 | // fn main() { | ||
88 | // pda$0 | ||
89 | // } | ||
90 | // # pub mod std { pub mod marker { pub struct PhantomData { } } } | ||
91 | // ``` | ||
92 | // -> | ||
93 | // ``` | ||
94 | // use std::marker::PhantomData; | ||
95 | // | ||
96 | // fn main() { | ||
97 | // PhantomData | ||
98 | // } | ||
99 | // # pub mod std { pub mod marker { pub struct PhantomData { } } } | ||
100 | // ``` | ||
101 | // | ||
102 | // .Fuzzy search details | ||
103 | // | ||
104 | // To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only | ||
105 | // (i.e. in `HashMap` in the `std::collections::HashMap` path). | ||
106 | // For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols. | ||
107 | // | ||
108 | // .Merge Behavior | ||
109 | // | ||
110 | // It is possible to configure how use-trees are merged with the `importMergeBehavior` setting. | ||
111 | // Mimics the corresponding behavior of the `Auto Import` feature. | ||
112 | // | ||
113 | // .LSP and performance implications | ||
114 | // | ||
115 | // The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` | ||
116 | // (case sensitive) resolve client capability in its client capabilities. | ||
117 | // This way the server is able to defer the costly computations, doing them for a selected completion item only. | ||
118 | // For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, | ||
119 | // which might be slow ergo the feature is automatically disabled. | ||
120 | // | ||
121 | // .Feature toggle | ||
122 | // | ||
123 | // The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag. | ||
124 | // Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | ||
125 | // capability enabled. | ||
126 | fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | ||
127 | let potential_import_name = ctx.token.to_string(); | ||
128 | let _p = profile::span("fuzzy_completion").detail(|| potential_import_name.clone()); | ||
129 | |||
130 | if potential_import_name.len() < 2 { | ||
131 | return None; | ||
132 | } | ||
133 | |||
134 | let current_module = ctx.scope.module()?; | ||
135 | let anchor = ctx.name_ref_syntax.as_ref()?; | ||
136 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | ||
137 | |||
138 | let user_input_lowercased = potential_import_name.to_lowercase(); | ||
139 | let mut all_mod_paths = imports_locator::find_similar_imports( | ||
140 | &ctx.sema, | ||
141 | ctx.krate?, | ||
142 | Some(40), | ||
143 | potential_import_name, | ||
144 | true, | ||
145 | true, | ||
146 | ) | ||
147 | .filter_map(|import_candidate| { | ||
148 | Some(match import_candidate { | ||
149 | Either::Left(module_def) => { | ||
150 | (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def)) | ||
151 | } | ||
152 | Either::Right(macro_def) => { | ||
153 | (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def)) | ||
154 | } | ||
155 | }) | ||
156 | }) | ||
157 | .filter(|(mod_path, _)| mod_path.len() > 1) | ||
158 | .collect::<Vec<_>>(); | ||
159 | |||
160 | all_mod_paths.sort_by_cached_key(|(mod_path, _)| { | ||
161 | compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) | ||
162 | }); | ||
163 | |||
164 | acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| { | ||
165 | render_resolution_with_import( | ||
166 | RenderContext::new(ctx), | ||
167 | ImportEdit { import_path, import_scope: import_scope.clone() }, | ||
168 | &definition, | ||
169 | ) | ||
170 | })); | ||
171 | Some(()) | ||
172 | } | ||
173 | |||
174 | fn compute_fuzzy_completion_order_key( | ||
175 | proposed_mod_path: &ModPath, | ||
176 | user_input_lowercased: &str, | ||
177 | ) -> usize { | ||
178 | mark::hit!(certain_fuzzy_order_test); | ||
179 | let proposed_import_name = match proposed_mod_path.segments.last() { | ||
180 | Some(name) => name.to_string().to_lowercase(), | ||
181 | None => return usize::MAX, | ||
182 | }; | ||
183 | match proposed_import_name.match_indices(user_input_lowercased).next() { | ||
184 | Some((first_matching_index, _)) => first_matching_index, | ||
185 | None => usize::MAX, | ||
186 | } | ||
187 | } | ||
188 | |||
189 | #[cfg(test)] | 70 | #[cfg(test)] |
190 | mod tests { | 71 | mod tests { |
191 | use expect_test::{expect, Expect}; | 72 | use expect_test::{expect, Expect}; |
192 | use test_utils::mark; | 73 | use test_utils::mark; |
193 | 74 | ||
194 | use crate::{ | 75 | use crate::{ |
195 | test_utils::{ | 76 | test_utils::{check_edit, completion_list_with_config, TEST_CONFIG}, |
196 | check_edit, check_edit_with_config, completion_list_with_config, TEST_CONFIG, | ||
197 | }, | ||
198 | CompletionConfig, CompletionKind, | 77 | CompletionConfig, CompletionKind, |
199 | }; | 78 | }; |
200 | 79 | ||
@@ -855,128 +734,4 @@ impl My$0 | |||
855 | "#]], | 734 | "#]], |
856 | ) | 735 | ) |
857 | } | 736 | } |
858 | |||
859 | #[test] | ||
860 | fn function_fuzzy_completion() { | ||
861 | check_edit_with_config( | ||
862 | TEST_CONFIG, | ||
863 | "stdin", | ||
864 | r#" | ||
865 | //- /lib.rs crate:dep | ||
866 | pub mod io { | ||
867 | pub fn stdin() {} | ||
868 | }; | ||
869 | |||
870 | //- /main.rs crate:main deps:dep | ||
871 | fn main() { | ||
872 | stdi$0 | ||
873 | } | ||
874 | "#, | ||
875 | r#" | ||
876 | use dep::io::stdin; | ||
877 | |||
878 | fn main() { | ||
879 | stdin()$0 | ||
880 | } | ||
881 | "#, | ||
882 | ); | ||
883 | } | ||
884 | |||
885 | #[test] | ||
886 | fn macro_fuzzy_completion() { | ||
887 | check_edit_with_config( | ||
888 | TEST_CONFIG, | ||
889 | "macro_with_curlies!", | ||
890 | r#" | ||
891 | //- /lib.rs crate:dep | ||
892 | /// Please call me as macro_with_curlies! {} | ||
893 | #[macro_export] | ||
894 | macro_rules! macro_with_curlies { | ||
895 | () => {} | ||
896 | } | ||
897 | |||
898 | //- /main.rs crate:main deps:dep | ||
899 | fn main() { | ||
900 | curli$0 | ||
901 | } | ||
902 | "#, | ||
903 | r#" | ||
904 | use dep::macro_with_curlies; | ||
905 | |||
906 | fn main() { | ||
907 | macro_with_curlies! {$0} | ||
908 | } | ||
909 | "#, | ||
910 | ); | ||
911 | } | ||
912 | |||
913 | #[test] | ||
914 | fn struct_fuzzy_completion() { | ||
915 | check_edit_with_config( | ||
916 | TEST_CONFIG, | ||
917 | "ThirdStruct", | ||
918 | r#" | ||
919 | //- /lib.rs crate:dep | ||
920 | pub struct FirstStruct; | ||
921 | pub mod some_module { | ||
922 | pub struct SecondStruct; | ||
923 | pub struct ThirdStruct; | ||
924 | } | ||
925 | |||
926 | //- /main.rs crate:main deps:dep | ||
927 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
928 | |||
929 | fn main() { | ||
930 | this$0 | ||
931 | } | ||
932 | "#, | ||
933 | r#" | ||
934 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
935 | |||
936 | fn main() { | ||
937 | ThirdStruct | ||
938 | } | ||
939 | "#, | ||
940 | ); | ||
941 | } | ||
942 | |||
943 | #[test] | ||
944 | fn fuzzy_completions_come_in_specific_order() { | ||
945 | mark::check!(certain_fuzzy_order_test); | ||
946 | check_with_config( | ||
947 | TEST_CONFIG, | ||
948 | r#" | ||
949 | //- /lib.rs crate:dep | ||
950 | pub struct FirstStruct; | ||
951 | pub mod some_module { | ||
952 | // already imported, omitted | ||
953 | pub struct SecondStruct; | ||
954 | // does not contain all letters from the query, omitted | ||
955 | pub struct UnrelatedOne; | ||
956 | // contains all letters from the query, but not in sequence, displayed last | ||
957 | pub struct ThiiiiiirdStruct; | ||
958 | // contains all letters from the query, but not in the beginning, displayed second | ||
959 | pub struct AfterThirdStruct; | ||
960 | // contains all letters from the query in the begginning, displayed first | ||
961 | pub struct ThirdStruct; | ||
962 | } | ||
963 | |||
964 | //- /main.rs crate:main deps:dep | ||
965 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
966 | |||
967 | fn main() { | ||
968 | hir$0 | ||
969 | } | ||
970 | "#, | ||
971 | expect![[r#" | ||
972 | fn main() fn main() | ||
973 | st SecondStruct | ||
974 | st FirstStruct | ||
975 | md dep | ||
976 | st dep::some_module::ThirdStruct | ||
977 | st dep::some_module::AfterThirdStruct | ||
978 | st dep::some_module::ThiiiiiirdStruct | ||
979 | "#]], | ||
980 | ); | ||
981 | } | ||
982 | } | 737 | } |
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs index b4439b7d1..58fc700f3 100644 --- a/crates/completion/src/config.rs +++ b/crates/completion/src/config.rs | |||
@@ -4,7 +4,7 @@ | |||
4 | //! module, and we use to statically check that we only produce snippet | 4 | //! module, and we use to statically check that we only produce snippet |
5 | //! completions if we are allowed to. | 5 | //! completions if we are allowed to. |
6 | 6 | ||
7 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; | 7 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
8 | 8 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub struct CompletionConfig { | 10 | pub struct CompletionConfig { |
@@ -13,5 +13,5 @@ pub struct CompletionConfig { | |||
13 | pub add_call_parenthesis: bool, | 13 | pub add_call_parenthesis: bool, |
14 | pub add_call_argument_snippets: bool, | 14 | pub add_call_argument_snippets: bool, |
15 | pub snippet_cap: Option<SnippetCap>, | 15 | pub snippet_cap: Option<SnippetCap>, |
16 | pub merge: Option<MergeBehavior>, | 16 | pub insert_use: InsertUseConfig, |
17 | } | 17 | } |
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs index 6cba88a6b..ee1b822e7 100644 --- a/crates/completion/src/lib.rs +++ b/crates/completion/src/lib.rs | |||
@@ -127,6 +127,7 @@ pub fn completions( | |||
127 | completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); | 127 | completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); |
128 | completions::trait_impl::complete_trait_impl(&mut acc, &ctx); | 128 | completions::trait_impl::complete_trait_impl(&mut acc, &ctx); |
129 | completions::mod_::complete_mod(&mut acc, &ctx); | 129 | completions::mod_::complete_mod(&mut acc, &ctx); |
130 | completions::flyimport::import_on_the_fly(&mut acc, &ctx); | ||
130 | 131 | ||
131 | Some(acc) | 132 | Some(acc) |
132 | } | 133 | } |
@@ -153,7 +154,9 @@ pub fn resolve_completion_edits( | |||
153 | }) | 154 | }) |
154 | .find(|mod_path| mod_path.to_string() == full_import_path)?; | 155 | .find(|mod_path| mod_path.to_string() == full_import_path)?; |
155 | 156 | ||
156 | ImportEdit { import_path, import_scope }.to_text_edit(config.merge).map(|edit| vec![edit]) | 157 | ImportEdit { import_path, import_scope } |
158 | .to_text_edit(config.insert_use.merge) | ||
159 | .map(|edit| vec![edit]) | ||
157 | } | 160 | } |
158 | 161 | ||
159 | #[cfg(test)] | 162 | #[cfg(test)] |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index e93c59f71..820dd01d1 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -51,11 +51,16 @@ pub(crate) fn render_resolution_with_import<'a>( | |||
51 | import_edit: ImportEdit, | 51 | import_edit: ImportEdit, |
52 | resolution: &ScopeDef, | 52 | resolution: &ScopeDef, |
53 | ) -> Option<CompletionItem> { | 53 | ) -> Option<CompletionItem> { |
54 | Render::new(ctx).render_resolution( | 54 | Render::new(ctx) |
55 | import_edit.import_path.segments.last()?.to_string(), | 55 | .render_resolution( |
56 | Some(import_edit), | 56 | import_edit.import_path.segments.last()?.to_string(), |
57 | resolution, | 57 | Some(import_edit), |
58 | ) | 58 | resolution, |
59 | ) | ||
60 | .map(|mut item| { | ||
61 | item.completion_kind = CompletionKind::Magic; | ||
62 | item | ||
63 | }) | ||
59 | } | 64 | } |
60 | 65 | ||
61 | /// Interface for data and methods required for items rendering. | 66 | /// Interface for data and methods required for items rendering. |
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs index 3f4b9d4ac..6ea6da989 100644 --- a/crates/completion/src/test_utils.rs +++ b/crates/completion/src/test_utils.rs | |||
@@ -1,9 +1,12 @@ | |||
1 | //! Runs completion for testing purposes. | 1 | //! Runs completion for testing purposes. |
2 | 2 | ||
3 | use hir::Semantics; | 3 | use hir::{PrefixKind, Semantics}; |
4 | use ide_db::{ | 4 | use ide_db::{ |
5 | base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, | 5 | base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, |
6 | helpers::{insert_use::MergeBehavior, SnippetCap}, | 6 | helpers::{ |
7 | insert_use::{InsertUseConfig, MergeBehavior}, | ||
8 | SnippetCap, | ||
9 | }, | ||
7 | RootDatabase, | 10 | RootDatabase, |
8 | }; | 11 | }; |
9 | use itertools::Itertools; | 12 | use itertools::Itertools; |
@@ -19,7 +22,10 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { | |||
19 | add_call_parenthesis: true, | 22 | add_call_parenthesis: true, |
20 | add_call_argument_snippets: true, | 23 | add_call_argument_snippets: true, |
21 | snippet_cap: SnippetCap::new(true), | 24 | snippet_cap: SnippetCap::new(true), |
22 | merge: Some(MergeBehavior::Full), | 25 | insert_use: InsertUseConfig { |
26 | merge: Some(MergeBehavior::Full), | ||
27 | prefix_kind: PrefixKind::Plain, | ||
28 | }, | ||
23 | }; | 29 | }; |
24 | 30 | ||
25 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. | 31 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
@@ -110,7 +116,7 @@ pub(crate) fn check_edit_with_config( | |||
110 | 116 | ||
111 | let mut combined_edit = completion.text_edit().to_owned(); | 117 | let mut combined_edit = completion.text_edit().to_owned(); |
112 | if let Some(import_text_edit) = | 118 | if let Some(import_text_edit) = |
113 | completion.import_to_add().and_then(|edit| edit.to_text_edit(config.merge)) | 119 | completion.import_to_add().and_then(|edit| edit.to_text_edit(config.insert_use.merge)) |
114 | { | 120 | { |
115 | combined_edit.union(import_text_edit).expect( | 121 | combined_edit.union(import_text_edit).expect( |
116 | "Failed to apply completion resolve changes: change ranges overlap, but should not", | 122 | "Failed to apply completion resolve changes: change ranges overlap, but should not", |
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index 5d21283f7..535221294 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -20,7 +20,7 @@ fst = { version = "0.4", default-features = false } | |||
20 | itertools = "0.10.0" | 20 | itertools = "0.10.0" |
21 | indexmap = "1.4.0" | 21 | indexmap = "1.4.0" |
22 | smallvec = "1.4.0" | 22 | smallvec = "1.4.0" |
23 | la-arena = "0.1.0" | 23 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
24 | 24 | ||
25 | stdx = { path = "../stdx", version = "0.0.0" } | 25 | stdx = { path = "../stdx", version = "0.0.0" } |
26 | base_db = { path = "../base_db", version = "0.0.0" } | 26 | base_db = { path = "../base_db", version = "0.0.0" } |
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs index 237c3d3f9..06f0b9b18 100644 --- a/crates/hir_def/src/adt.rs +++ b/crates/hir_def/src/adt.rs | |||
@@ -8,7 +8,7 @@ use hir_expand::{ | |||
8 | name::{AsName, Name}, | 8 | name::{AsName, Name}, |
9 | InFile, | 9 | InFile, |
10 | }; | 10 | }; |
11 | use la_arena::{map::ArenaMap, Arena}; | 11 | use la_arena::{Arena, ArenaMap}; |
12 | use syntax::ast::{self, NameOwner, VisibilityOwner}; | 12 | use syntax::ast::{self, NameOwner, VisibilityOwner}; |
13 | use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; | 13 | use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; |
14 | 14 | ||
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 5a86823c2..1b09ff816 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -7,7 +7,7 @@ use cfg::{CfgExpr, CfgOptions}; | |||
7 | use either::Either; | 7 | use either::Either; |
8 | use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile}; | 8 | use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile}; |
9 | use itertools::Itertools; | 9 | use itertools::Itertools; |
10 | use la_arena::map::ArenaMap; | 10 | use la_arena::ArenaMap; |
11 | use mbe::ast_to_token_tree; | 11 | use mbe::ast_to_token_tree; |
12 | use syntax::{ | 12 | use syntax::{ |
13 | ast::{self, AstNode, AttrsOwner}, | 13 | ast::{self, AstNode, AttrsOwner}, |
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 43ee57277..344f0b6c0 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -16,7 +16,7 @@ use hir_expand::{ | |||
16 | ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, ExpandResult, | 16 | ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, ExpandResult, |
17 | HirFileId, InFile, MacroDefId, | 17 | HirFileId, InFile, MacroDefId, |
18 | }; | 18 | }; |
19 | use la_arena::{map::ArenaMap, Arena}; | 19 | use la_arena::{Arena, ArenaMap}; |
20 | use rustc_hash::FxHashMap; | 20 | use rustc_hash::FxHashMap; |
21 | use syntax::{ast, AstNode, AstPtr}; | 21 | use syntax::{ast, AstNode, AstPtr}; |
22 | use test_utils::mark; | 22 | use test_utils::mark; |
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs index 0506a7274..6ef9fe790 100644 --- a/crates/hir_def/src/db.rs +++ b/crates/hir_def/src/db.rs | |||
@@ -3,7 +3,7 @@ use std::sync::Arc; | |||
3 | 3 | ||
4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; | 4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; |
5 | use hir_expand::{db::AstDatabase, HirFileId}; | 5 | use hir_expand::{db::AstDatabase, HirFileId}; |
6 | use la_arena::map::ArenaMap; | 6 | use la_arena::ArenaMap; |
7 | use syntax::SmolStr; | 7 | use syntax::SmolStr; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index a293df9f1..5be838f4a 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs | |||
@@ -13,7 +13,7 @@ | |||
13 | //! See also a neighboring `body` module. | 13 | //! See also a neighboring `body` module. |
14 | 14 | ||
15 | use hir_expand::name::Name; | 15 | use hir_expand::name::Name; |
16 | use la_arena::{Idx, RawId}; | 16 | use la_arena::{Idx, RawIdx}; |
17 | use syntax::ast::RangeOp; | 17 | use syntax::ast::RangeOp; |
18 | 18 | ||
19 | use crate::{ | 19 | use crate::{ |
@@ -24,7 +24,7 @@ use crate::{ | |||
24 | 24 | ||
25 | pub type ExprId = Idx<Expr>; | 25 | pub type ExprId = Idx<Expr>; |
26 | pub(crate) fn dummy_expr_id() -> ExprId { | 26 | pub(crate) fn dummy_expr_id() -> ExprId { |
27 | ExprId::from_raw(RawId::from(!0)) | 27 | ExprId::from_raw(RawIdx::from(!0)) |
28 | } | 28 | } |
29 | 29 | ||
30 | pub type PatId = Idx<Pat>; | 30 | pub type PatId = Idx<Pat>; |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 75eab791a..3ace3be1f 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -10,7 +10,7 @@ use hir_expand::{ | |||
10 | name::{name, AsName, Name}, | 10 | name::{name, AsName, Name}, |
11 | InFile, | 11 | InFile, |
12 | }; | 12 | }; |
13 | use la_arena::{map::ArenaMap, Arena}; | 13 | use la_arena::{Arena, ArenaMap}; |
14 | use syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner}; | 14 | use syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner}; |
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 91e42aa0d..9a433b61c 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -20,7 +20,7 @@ use hir_expand::{ | |||
20 | name::{name, AsName, Name}, | 20 | name::{name, AsName, Name}, |
21 | HirFileId, InFile, | 21 | HirFileId, InFile, |
22 | }; | 22 | }; |
23 | use la_arena::{Arena, Idx, RawId}; | 23 | use la_arena::{Arena, Idx, RawIdx}; |
24 | use rustc_hash::FxHashMap; | 24 | use rustc_hash::FxHashMap; |
25 | use smallvec::SmallVec; | 25 | use smallvec::SmallVec; |
26 | use syntax::{ast, match_ast}; | 26 | use syntax::{ast, match_ast}; |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 3b206ef85..5e71ca42c 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -683,12 +683,12 @@ impl Ctx { | |||
683 | } | 683 | } |
684 | 684 | ||
685 | fn next_field_idx(&self) -> Idx<Field> { | 685 | fn next_field_idx(&self) -> Idx<Field> { |
686 | Idx::from_raw(RawId::from( | 686 | Idx::from_raw(RawIdx::from( |
687 | self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32), | 687 | self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32), |
688 | )) | 688 | )) |
689 | } | 689 | } |
690 | fn next_variant_idx(&self) -> Idx<Variant> { | 690 | fn next_variant_idx(&self) -> Idx<Variant> { |
691 | Idx::from_raw(RawId::from( | 691 | Idx::from_raw(RawIdx::from( |
692 | self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), | 692 | self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), |
693 | )) | 693 | )) |
694 | } | 694 | } |
diff --git a/crates/hir_def/src/src.rs b/crates/hir_def/src/src.rs index eb29265d9..751d4c052 100644 --- a/crates/hir_def/src/src.rs +++ b/crates/hir_def/src/src.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Utilities for mapping between hir IDs and the surface syntax. | 1 | //! Utilities for mapping between hir IDs and the surface syntax. |
2 | 2 | ||
3 | use hir_expand::InFile; | 3 | use hir_expand::InFile; |
4 | use la_arena::map::ArenaMap; | 4 | use la_arena::ArenaMap; |
5 | 5 | ||
6 | use crate::{db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc}; | 6 | use crate::{db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc}; |
7 | 7 | ||
diff --git a/crates/hir_def/src/trace.rs b/crates/hir_def/src/trace.rs index 0a9beae8e..6e6ceb8e4 100644 --- a/crates/hir_def/src/trace.rs +++ b/crates/hir_def/src/trace.rs | |||
@@ -9,7 +9,7 @@ | |||
9 | //! absolute offsets. The `Trace` structure (inspired, at least in name, by | 9 | //! absolute offsets. The `Trace` structure (inspired, at least in name, by |
10 | //! Kotlin's `BindingTrace`) allows use the same code to compute both | 10 | //! Kotlin's `BindingTrace`) allows use the same code to compute both |
11 | //! projections. | 11 | //! projections. |
12 | use la_arena::{map::ArenaMap, Arena, Idx, RawId}; | 12 | use la_arena::{Arena, ArenaMap, Idx, RawIdx}; |
13 | 13 | ||
14 | pub(crate) struct Trace<T, V> { | 14 | pub(crate) struct Trace<T, V> { |
15 | arena: Option<Arena<T>>, | 15 | arena: Option<Arena<T>>, |
@@ -30,7 +30,7 @@ impl<T, V> Trace<T, V> { | |||
30 | let id = if let Some(arena) = &mut self.arena { | 30 | let id = if let Some(arena) = &mut self.arena { |
31 | arena.alloc(data()) | 31 | arena.alloc(data()) |
32 | } else { | 32 | } else { |
33 | let id = Idx::<T>::from_raw(RawId::from(self.len)); | 33 | let id = Idx::<T>::from_raw(RawIdx::from(self.len)); |
34 | self.len += 1; | 34 | self.len += 1; |
35 | id | 35 | id |
36 | }; | 36 | }; |
diff --git a/crates/hir_expand/Cargo.toml b/crates/hir_expand/Cargo.toml index b535a3d4f..5271110d2 100644 --- a/crates/hir_expand/Cargo.toml +++ b/crates/hir_expand/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | log = "0.4.8" | 13 | log = "0.4.8" |
14 | either = "1.5.3" | 14 | either = "1.5.3" |
15 | rustc-hash = "1.0.0" | 15 | rustc-hash = "1.0.0" |
16 | la-arena = "0.1.0" | 16 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
17 | 17 | ||
18 | base_db = { path = "../base_db", version = "0.0.0" } | 18 | base_db = { path = "../base_db", version = "0.0.0" } |
19 | syntax = { path = "../syntax", version = "0.0.0" } | 19 | syntax = { path = "../syntax", version = "0.0.0" } |
diff --git a/crates/hir_expand/src/ast_id_map.rs b/crates/hir_expand/src/ast_id_map.rs index f4f6e11fd..2401b0cc5 100644 --- a/crates/hir_expand/src/ast_id_map.rs +++ b/crates/hir_expand/src/ast_id_map.rs | |||
@@ -72,10 +72,12 @@ impl AstIdMap { | |||
72 | // get lower ids then children. That is, adding a new child does not | 72 | // get lower ids then children. That is, adding a new child does not |
73 | // change parent's id. This means that, say, adding a new function to a | 73 | // change parent's id. This means that, say, adding a new function to a |
74 | // trait does not change ids of top-level items, which helps caching. | 74 | // trait does not change ids of top-level items, which helps caching. |
75 | bfs(node, |it| { | 75 | bdfs(node, |it| match ast::Item::cast(it) { |
76 | if let Some(module_item) = ast::Item::cast(it) { | 76 | Some(module_item) => { |
77 | res.alloc(module_item.syntax()); | 77 | res.alloc(module_item.syntax()); |
78 | true | ||
78 | } | 79 | } |
80 | None => false, | ||
79 | }); | 81 | }); |
80 | res | 82 | res |
81 | } | 83 | } |
@@ -105,14 +107,30 @@ impl AstIdMap { | |||
105 | } | 107 | } |
106 | } | 108 | } |
107 | 109 | ||
108 | /// Walks the subtree in bfs order, calling `f` for each node. | 110 | /// Walks the subtree in bdfs order, calling `f` for each node. What is bdfs |
109 | fn bfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode)) { | 111 | /// order? It is a mix of breadth-first and depth first orders. Nodes for which |
112 | /// `f` returns true are visited breadth-first, all the other nodes are explored | ||
113 | /// depth-first. | ||
114 | /// | ||
115 | /// In other words, the size of the bfs queue is bound by the number of "true" | ||
116 | /// nodes. | ||
117 | fn bdfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode) -> bool) { | ||
110 | let mut curr_layer = vec![node.clone()]; | 118 | let mut curr_layer = vec![node.clone()]; |
111 | let mut next_layer = vec![]; | 119 | let mut next_layer = vec![]; |
112 | while !curr_layer.is_empty() { | 120 | while !curr_layer.is_empty() { |
113 | curr_layer.drain(..).for_each(|node| { | 121 | curr_layer.drain(..).for_each(|node| { |
114 | next_layer.extend(node.children()); | 122 | let mut preorder = node.preorder(); |
115 | f(node); | 123 | while let Some(event) = preorder.next() { |
124 | match event { | ||
125 | syntax::WalkEvent::Enter(node) => { | ||
126 | if f(node.clone()) { | ||
127 | next_layer.extend(node.children()); | ||
128 | preorder.skip_subtree(); | ||
129 | } | ||
130 | } | ||
131 | syntax::WalkEvent::Leave(_) => {} | ||
132 | } | ||
133 | } | ||
116 | }); | 134 | }); |
117 | std::mem::swap(&mut curr_layer, &mut next_layer); | 135 | std::mem::swap(&mut curr_layer, &mut next_layer); |
118 | } | 136 | } |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 436c1405b..98434b741 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -20,7 +20,7 @@ scoped-tls = "1" | |||
20 | chalk-solve = { version = "0.47", default-features = false } | 20 | chalk-solve = { version = "0.47", default-features = false } |
21 | chalk-ir = "0.47" | 21 | chalk-ir = "0.47" |
22 | chalk-recursive = "0.47" | 22 | chalk-recursive = "0.47" |
23 | la-arena = "0.1.0" | 23 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
24 | 24 | ||
25 | stdx = { path = "../stdx", version = "0.0.0" } | 25 | stdx = { path = "../stdx", version = "0.0.0" } |
26 | hir_def = { path = "../hir_def", version = "0.0.0" } | 26 | hir_def = { path = "../hir_def", version = "0.0.0" } |
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs index b0e2a3b7d..b3af82444 100644 --- a/crates/hir_ty/src/db.rs +++ b/crates/hir_ty/src/db.rs | |||
@@ -7,7 +7,7 @@ use hir_def::{ | |||
7 | db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId, | 7 | db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId, |
8 | LocalFieldId, TypeParamId, VariantId, | 8 | LocalFieldId, TypeParamId, VariantId, |
9 | }; | 9 | }; |
10 | use la_arena::map::ArenaMap; | 10 | use la_arena::ArenaMap; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | method_resolution::{InherentImpls, TraitImpls}, | 13 | method_resolution::{InherentImpls, TraitImpls}, |
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index 46a806b9a..d08867c70 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -30,7 +30,7 @@ use hir_def::{ | |||
30 | TypeAliasId, VariantId, | 30 | TypeAliasId, VariantId, |
31 | }; | 31 | }; |
32 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; | 32 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; |
33 | use la_arena::map::ArenaMap; | 33 | use la_arena::ArenaMap; |
34 | use rustc_hash::FxHashMap; | 34 | use rustc_hash::FxHashMap; |
35 | use stdx::impl_from; | 35 | use stdx::impl_from; |
36 | use syntax::SmolStr; | 36 | use syntax::SmolStr; |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 68d16f89a..7a734c8b9 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -20,7 +20,7 @@ use hir_def::{ | |||
20 | TypeAliasId, TypeParamId, UnionId, VariantId, | 20 | TypeAliasId, TypeParamId, UnionId, VariantId, |
21 | }; | 21 | }; |
22 | use hir_expand::name::Name; | 22 | use hir_expand::name::Name; |
23 | use la_arena::map::ArenaMap; | 23 | use la_arena::ArenaMap; |
24 | use smallvec::SmallVec; | 24 | use smallvec::SmallVec; |
25 | use stdx::impl_from; | 25 | use stdx::impl_from; |
26 | use test_utils::mark; | 26 | use test_utils::mark; |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index afd552008..f8d69382e 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -80,7 +80,7 @@ pub use crate::{ | |||
80 | HlRange, | 80 | HlRange, |
81 | }, | 81 | }, |
82 | }; | 82 | }; |
83 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind, InsertUseConfig}; | 83 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind}; |
84 | pub use completion::{ | 84 | pub use completion::{ |
85 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, | 85 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, |
86 | InsertTextFormat, | 86 | InsertTextFormat, |
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index c6763ae36..0dcc4dd29 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! A module with ide helpers for high-level ide features. | 1 | //! A module with ide helpers for high-level ide features. |
2 | pub mod insert_use; | 2 | pub mod insert_use; |
3 | pub mod import_assets; | ||
3 | 4 | ||
4 | use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; | 5 | use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; |
5 | use syntax::ast::{self, make}; | 6 | use syntax::ast::{self, make}; |
diff --git a/crates/assists/src/utils/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index 4ce82c1ba..edc3da318 100644 --- a/crates/assists/src/utils/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs | |||
@@ -1,19 +1,17 @@ | |||
1 | //! Look up accessible paths for items. | 1 | //! Look up accessible paths for items. |
2 | use either::Either; | 2 | use either::Either; |
3 | use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics}; | 3 | use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics}; |
4 | use ide_db::{imports_locator, RootDatabase}; | ||
5 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
6 | use syntax::{ast, AstNode, SyntaxNode}; | 5 | use syntax::{ast, AstNode, SyntaxNode}; |
7 | 6 | ||
8 | use crate::assist_config::InsertUseConfig; | 7 | use crate::{imports_locator, RootDatabase}; |
8 | |||
9 | use super::insert_use::InsertUseConfig; | ||
9 | 10 | ||
10 | #[derive(Debug)] | 11 | #[derive(Debug)] |
11 | pub(crate) enum ImportCandidate { | 12 | pub enum ImportCandidate { |
12 | /// Simple name like 'HashMap' | 13 | // A path, qualified (`std::collections::HashMap`) or not (`HashMap`). |
13 | UnqualifiedName(PathImportCandidate), | 14 | Path(PathImportCandidate), |
14 | /// First part of the qualified name. | ||
15 | /// For 'std::collections::HashMap', that will be 'std'. | ||
16 | QualifierStart(PathImportCandidate), | ||
17 | /// A trait associated function (with no self parameter) or associated constant. | 15 | /// A trait associated function (with no self parameter) or associated constant. |
18 | /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type | 16 | /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type |
19 | /// and `name` is the `test_function` | 17 | /// and `name` is the `test_function` |
@@ -25,25 +23,26 @@ pub(crate) enum ImportCandidate { | |||
25 | } | 23 | } |
26 | 24 | ||
27 | #[derive(Debug)] | 25 | #[derive(Debug)] |
28 | pub(crate) struct TraitImportCandidate { | 26 | pub struct TraitImportCandidate { |
29 | pub(crate) ty: hir::Type, | 27 | pub ty: hir::Type, |
30 | pub(crate) name: ast::NameRef, | 28 | pub name: ast::NameRef, |
31 | } | 29 | } |
32 | 30 | ||
33 | #[derive(Debug)] | 31 | #[derive(Debug)] |
34 | pub(crate) struct PathImportCandidate { | 32 | pub struct PathImportCandidate { |
35 | pub(crate) name: ast::NameRef, | 33 | pub qualifier: Option<ast::Path>, |
34 | pub name: ast::NameRef, | ||
36 | } | 35 | } |
37 | 36 | ||
38 | #[derive(Debug)] | 37 | #[derive(Debug)] |
39 | pub(crate) struct ImportAssets { | 38 | pub struct ImportAssets { |
40 | import_candidate: ImportCandidate, | 39 | import_candidate: ImportCandidate, |
41 | module_with_name_to_import: hir::Module, | 40 | module_with_name_to_import: hir::Module, |
42 | syntax_under_caret: SyntaxNode, | 41 | syntax_under_caret: SyntaxNode, |
43 | } | 42 | } |
44 | 43 | ||
45 | impl ImportAssets { | 44 | impl ImportAssets { |
46 | pub(crate) fn for_method_call( | 45 | pub fn for_method_call( |
47 | method_call: ast::MethodCallExpr, | 46 | method_call: ast::MethodCallExpr, |
48 | sema: &Semantics<RootDatabase>, | 47 | sema: &Semantics<RootDatabase>, |
49 | ) -> Option<Self> { | 48 | ) -> Option<Self> { |
@@ -56,7 +55,7 @@ impl ImportAssets { | |||
56 | }) | 55 | }) |
57 | } | 56 | } |
58 | 57 | ||
59 | pub(crate) fn for_regular_path( | 58 | pub fn for_regular_path( |
60 | path_under_caret: ast::Path, | 59 | path_under_caret: ast::Path, |
61 | sema: &Semantics<RootDatabase>, | 60 | sema: &Semantics<RootDatabase>, |
62 | ) -> Option<Self> { | 61 | ) -> Option<Self> { |
@@ -73,24 +72,23 @@ impl ImportAssets { | |||
73 | }) | 72 | }) |
74 | } | 73 | } |
75 | 74 | ||
76 | pub(crate) fn syntax_under_caret(&self) -> &SyntaxNode { | 75 | pub fn syntax_under_caret(&self) -> &SyntaxNode { |
77 | &self.syntax_under_caret | 76 | &self.syntax_under_caret |
78 | } | 77 | } |
79 | 78 | ||
80 | pub(crate) fn import_candidate(&self) -> &ImportCandidate { | 79 | pub fn import_candidate(&self) -> &ImportCandidate { |
81 | &self.import_candidate | 80 | &self.import_candidate |
82 | } | 81 | } |
83 | 82 | ||
84 | fn get_search_query(&self) -> &str { | 83 | fn get_search_query(&self) -> &str { |
85 | match &self.import_candidate { | 84 | match &self.import_candidate { |
86 | ImportCandidate::UnqualifiedName(candidate) | 85 | ImportCandidate::Path(candidate) => candidate.name.text(), |
87 | | ImportCandidate::QualifierStart(candidate) => candidate.name.text(), | ||
88 | ImportCandidate::TraitAssocItem(candidate) | 86 | ImportCandidate::TraitAssocItem(candidate) |
89 | | ImportCandidate::TraitMethod(candidate) => candidate.name.text(), | 87 | | ImportCandidate::TraitMethod(candidate) => candidate.name.text(), |
90 | } | 88 | } |
91 | } | 89 | } |
92 | 90 | ||
93 | pub(crate) fn search_for_imports( | 91 | pub fn search_for_imports( |
94 | &self, | 92 | &self, |
95 | sema: &Semantics<RootDatabase>, | 93 | sema: &Semantics<RootDatabase>, |
96 | config: &InsertUseConfig, | 94 | config: &InsertUseConfig, |
@@ -101,7 +99,7 @@ impl ImportAssets { | |||
101 | 99 | ||
102 | /// This may return non-absolute paths if a part of the returned path is already imported into scope. | 100 | /// This may return non-absolute paths if a part of the returned path is already imported into scope. |
103 | #[allow(dead_code)] | 101 | #[allow(dead_code)] |
104 | pub(crate) fn search_for_relative_paths( | 102 | pub fn search_for_relative_paths( |
105 | &self, | 103 | &self, |
106 | sema: &Semantics<RootDatabase>, | 104 | sema: &Semantics<RootDatabase>, |
107 | ) -> Vec<(hir::ModPath, hir::ItemInNs)> { | 105 | ) -> Vec<(hir::ModPath, hir::ItemInNs)> { |
@@ -253,10 +251,14 @@ impl ImportCandidate { | |||
253 | _ => return None, | 251 | _ => return None, |
254 | } | 252 | } |
255 | } else { | 253 | } else { |
256 | ImportCandidate::QualifierStart(PathImportCandidate { name: qualifier_start }) | 254 | ImportCandidate::Path(PathImportCandidate { |
255 | qualifier: Some(qualifier), | ||
256 | name: qualifier_start, | ||
257 | }) | ||
257 | } | 258 | } |
258 | } else { | 259 | } else { |
259 | ImportCandidate::UnqualifiedName(PathImportCandidate { | 260 | ImportCandidate::Path(PathImportCandidate { |
261 | qualifier: None, | ||
260 | name: segment.syntax().descendants().find_map(ast::NameRef::cast)?, | 262 | name: segment.syntax().descendants().find_map(ast::NameRef::cast)?, |
261 | }) | 263 | }) |
262 | }; | 264 | }; |
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs index d2f9f5d25..877d4f1c7 100644 --- a/crates/ide_db/src/helpers/insert_use.rs +++ b/crates/ide_db/src/helpers/insert_use.rs | |||
@@ -15,6 +15,12 @@ use syntax::{ | |||
15 | }; | 15 | }; |
16 | use test_utils::mark; | 16 | use test_utils::mark; |
17 | 17 | ||
18 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
19 | pub struct InsertUseConfig { | ||
20 | pub merge: Option<MergeBehavior>, | ||
21 | pub prefix_kind: hir::PrefixKind, | ||
22 | } | ||
23 | |||
18 | #[derive(Debug, Clone)] | 24 | #[derive(Debug, Clone)] |
19 | pub enum ImportScope { | 25 | pub enum ImportScope { |
20 | File(ast::SourceFile), | 26 | File(ast::SourceFile), |
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs index e9f23adf8..d111fba92 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/imports_locator.rs | |||
@@ -12,6 +12,8 @@ use crate::{ | |||
12 | use either::Either; | 12 | use either::Either; |
13 | use rustc_hash::FxHashSet; | 13 | use rustc_hash::FxHashSet; |
14 | 14 | ||
15 | const QUERY_SEARCH_LIMIT: usize = 40; | ||
16 | |||
15 | pub fn find_exact_imports<'a>( | 17 | pub fn find_exact_imports<'a>( |
16 | sema: &Semantics<'a, RootDatabase>, | 18 | sema: &Semantics<'a, RootDatabase>, |
17 | krate: Crate, | 19 | krate: Crate, |
@@ -24,11 +26,11 @@ pub fn find_exact_imports<'a>( | |||
24 | { | 26 | { |
25 | let mut local_query = symbol_index::Query::new(name_to_import.clone()); | 27 | let mut local_query = symbol_index::Query::new(name_to_import.clone()); |
26 | local_query.exact(); | 28 | local_query.exact(); |
27 | local_query.limit(40); | 29 | local_query.limit(QUERY_SEARCH_LIMIT); |
28 | local_query | 30 | local_query |
29 | }, | 31 | }, |
30 | import_map::Query::new(name_to_import) | 32 | import_map::Query::new(name_to_import) |
31 | .limit(40) | 33 | .limit(QUERY_SEARCH_LIMIT) |
32 | .name_only() | 34 | .name_only() |
33 | .search_mode(import_map::SearchMode::Equals) | 35 | .search_mode(import_map::SearchMode::Equals) |
34 | .case_sensitive(), | 36 | .case_sensitive(), |
diff --git a/crates/parser/src/syntax_kind.rs b/crates/parser/src/syntax_kind.rs index 63204436c..9ea0e4f9b 100644 --- a/crates/parser/src/syntax_kind.rs +++ b/crates/parser/src/syntax_kind.rs | |||
@@ -6,6 +6,7 @@ mod generated; | |||
6 | pub use self::generated::SyntaxKind; | 6 | pub use self::generated::SyntaxKind; |
7 | 7 | ||
8 | impl From<u16> for SyntaxKind { | 8 | impl From<u16> for SyntaxKind { |
9 | #[inline] | ||
9 | fn from(d: u16) -> SyntaxKind { | 10 | fn from(d: u16) -> SyntaxKind { |
10 | assert!(d <= (SyntaxKind::__LAST as u16)); | 11 | assert!(d <= (SyntaxKind::__LAST as u16)); |
11 | unsafe { std::mem::transmute::<u16, SyntaxKind>(d) } | 12 | unsafe { std::mem::transmute::<u16, SyntaxKind>(d) } |
@@ -13,12 +14,14 @@ impl From<u16> for SyntaxKind { | |||
13 | } | 14 | } |
14 | 15 | ||
15 | impl From<SyntaxKind> for u16 { | 16 | impl From<SyntaxKind> for u16 { |
17 | #[inline] | ||
16 | fn from(k: SyntaxKind) -> u16 { | 18 | fn from(k: SyntaxKind) -> u16 { |
17 | k as u16 | 19 | k as u16 |
18 | } | 20 | } |
19 | } | 21 | } |
20 | 22 | ||
21 | impl SyntaxKind { | 23 | impl SyntaxKind { |
24 | #[inline] | ||
22 | pub fn is_trivia(self) -> bool { | 25 | pub fn is_trivia(self) -> bool { |
23 | matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT) | 26 | matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT) |
24 | } | 27 | } |
diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index 096233a09..9c7ce26be 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | once_cell = "1.3.1" | 13 | once_cell = "1.3.1" |
14 | cfg-if = "1" | 14 | cfg-if = "1" |
15 | libc = "0.2.73" | 15 | libc = "0.2.73" |
16 | la-arena = "0.1.0" | 16 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
17 | 17 | ||
18 | [target.'cfg(target_os = "linux")'.dependencies] | 18 | [target.'cfg(target_os = "linux")'.dependencies] |
19 | perf-event = "0.4" | 19 | perf-event = "0.4" |
diff --git a/crates/project_model/Cargo.toml b/crates/project_model/Cargo.toml index 51e7a7070..436eff16b 100644 --- a/crates/project_model/Cargo.toml +++ b/crates/project_model/Cargo.toml | |||
@@ -17,7 +17,7 @@ serde = { version = "1.0.106", features = ["derive"] } | |||
17 | serde_json = "1.0.48" | 17 | serde_json = "1.0.48" |
18 | anyhow = "1.0.26" | 18 | anyhow = "1.0.26" |
19 | itertools = "0.10.0" | 19 | itertools = "0.10.0" |
20 | la-arena = "0.1.0" | 20 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
21 | 21 | ||
22 | cfg = { path = "../cfg", version = "0.0.0" } | 22 | cfg = { path = "../cfg", version = "0.0.0" } |
23 | base_db = { path = "../base_db", version = "0.0.0" } | 23 | base_db = { path = "../base_db", version = "0.0.0" } |
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs index 7d3fda7a8..a02c8327f 100644 --- a/crates/rust-analyzer/src/cli/analysis_bench.rs +++ b/crates/rust-analyzer/src/cli/analysis_bench.rs | |||
@@ -3,6 +3,7 @@ | |||
3 | use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; | 3 | use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; |
4 | 4 | ||
5 | use anyhow::{bail, format_err, Result}; | 5 | use anyhow::{bail, format_err, Result}; |
6 | use hir::PrefixKind; | ||
6 | use ide::{ | 7 | use ide::{ |
7 | Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, | 8 | Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, |
8 | }; | 9 | }; |
@@ -11,7 +12,7 @@ use ide_db::{ | |||
11 | salsa::{Database, Durability}, | 12 | salsa::{Database, Durability}, |
12 | FileId, | 13 | FileId, |
13 | }, | 14 | }, |
14 | helpers::SnippetCap, | 15 | helpers::{insert_use::InsertUseConfig, SnippetCap}, |
15 | }; | 16 | }; |
16 | use vfs::AbsPathBuf; | 17 | use vfs::AbsPathBuf; |
17 | 18 | ||
@@ -96,7 +97,7 @@ impl BenchCmd { | |||
96 | add_call_parenthesis: true, | 97 | add_call_parenthesis: true, |
97 | add_call_argument_snippets: true, | 98 | add_call_argument_snippets: true, |
98 | snippet_cap: SnippetCap::new(true), | 99 | snippet_cap: SnippetCap::new(true), |
99 | merge: None, | 100 | insert_use: InsertUseConfig { merge: None, prefix_kind: PrefixKind::Plain }, |
100 | }; | 101 | }; |
101 | let res = do_work(&mut host, file_id, |analysis| { | 102 | let res = do_work(&mut host, file_id, |analysis| { |
102 | analysis.completions(&options, file_position) | 103 | analysis.completions(&options, file_position) |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 27b92a5a9..ce9655818 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -11,11 +11,11 @@ use std::{convert::TryFrom, ffi::OsString, iter, path::PathBuf}; | |||
11 | 11 | ||
12 | use flycheck::FlycheckConfig; | 12 | use flycheck::FlycheckConfig; |
13 | use hir::PrefixKind; | 13 | use hir::PrefixKind; |
14 | use ide::{ | 14 | use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; |
15 | AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig, | 15 | use ide_db::helpers::{ |
16 | InsertUseConfig, | 16 | insert_use::{InsertUseConfig, MergeBehavior}, |
17 | SnippetCap, | ||
17 | }; | 18 | }; |
18 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; | ||
19 | use itertools::Itertools; | 19 | use itertools::Itertools; |
20 | use lsp_types::{ClientCapabilities, MarkupKind}; | 20 | use lsp_types::{ClientCapabilities, MarkupKind}; |
21 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; | 21 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; |
@@ -542,11 +542,18 @@ impl Config { | |||
542 | max_length: self.data.inlayHints_maxLength, | 542 | max_length: self.data.inlayHints_maxLength, |
543 | } | 543 | } |
544 | } | 544 | } |
545 | fn merge_behavior(&self) -> Option<MergeBehavior> { | 545 | fn insert_use_config(&self) -> InsertUseConfig { |
546 | match self.data.assist_importMergeBehavior { | 546 | InsertUseConfig { |
547 | MergeBehaviorDef::None => None, | 547 | merge: match self.data.assist_importMergeBehavior { |
548 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), | 548 | MergeBehaviorDef::None => None, |
549 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | 549 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), |
550 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | ||
551 | }, | ||
552 | prefix_kind: match self.data.assist_importPrefix { | ||
553 | ImportPrefixDef::Plain => PrefixKind::Plain, | ||
554 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, | ||
555 | ImportPrefixDef::BySelf => PrefixKind::BySelf, | ||
556 | }, | ||
550 | } | 557 | } |
551 | } | 558 | } |
552 | pub fn completion(&self) -> CompletionConfig { | 559 | pub fn completion(&self) -> CompletionConfig { |
@@ -556,7 +563,7 @@ impl Config { | |||
556 | && completion_item_edit_resolve(&self.caps), | 563 | && completion_item_edit_resolve(&self.caps), |
557 | add_call_parenthesis: self.data.completion_addCallParenthesis, | 564 | add_call_parenthesis: self.data.completion_addCallParenthesis, |
558 | add_call_argument_snippets: self.data.completion_addCallArgumentSnippets, | 565 | add_call_argument_snippets: self.data.completion_addCallArgumentSnippets, |
559 | merge: self.merge_behavior(), | 566 | insert_use: self.insert_use_config(), |
560 | snippet_cap: SnippetCap::new(try_or!( | 567 | snippet_cap: SnippetCap::new(try_or!( |
561 | self.caps | 568 | self.caps |
562 | .text_document | 569 | .text_document |
@@ -575,7 +582,11 @@ impl Config { | |||
575 | snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")), | 582 | snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")), |
576 | allowed: None, | 583 | allowed: None, |
577 | insert_use: InsertUseConfig { | 584 | insert_use: InsertUseConfig { |
578 | merge: self.merge_behavior(), | 585 | merge: match self.data.assist_importMergeBehavior { |
586 | MergeBehaviorDef::None => None, | ||
587 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), | ||
588 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | ||
589 | }, | ||
579 | prefix_kind: match self.data.assist_importPrefix { | 590 | prefix_kind: match self.data.assist_importPrefix { |
580 | ImportPrefixDef::Plain => PrefixKind::Plain, | 591 | ImportPrefixDef::Plain => PrefixKind::Plain, |
581 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, | 592 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index dc67d19a7..1ff2d3fea 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -861,8 +861,9 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError { | |||
861 | 861 | ||
862 | #[cfg(test)] | 862 | #[cfg(test)] |
863 | mod tests { | 863 | mod tests { |
864 | use hir::PrefixKind; | ||
864 | use ide::Analysis; | 865 | use ide::Analysis; |
865 | use ide_db::helpers::SnippetCap; | 866 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
866 | 867 | ||
867 | use super::*; | 868 | use super::*; |
868 | 869 | ||
@@ -887,7 +888,7 @@ mod tests { | |||
887 | add_call_parenthesis: true, | 888 | add_call_parenthesis: true, |
888 | add_call_argument_snippets: true, | 889 | add_call_argument_snippets: true, |
889 | snippet_cap: SnippetCap::new(true), | 890 | snippet_cap: SnippetCap::new(true), |
890 | merge: None, | 891 | insert_use: InsertUseConfig { merge: None, prefix_kind: PrefixKind::Plain }, |
891 | }, | 892 | }, |
892 | ide_db::base_db::FilePosition { file_id, offset }, | 893 | ide_db::base_db::FilePosition { file_id, offset }, |
893 | ) | 894 | ) |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index ad8b797fe..52394b337 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -12,7 +12,7 @@ doctest = false | |||
12 | 12 | ||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.10.0" | 14 | itertools = "0.10.0" |
15 | rowan = "0.10.1" | 15 | rowan = "0.10.3" |
16 | rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index e598c2c84..1edb7713d 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -294,6 +294,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
294 | "x64 linux": "x86_64-unknown-linux-gnu", | 294 | "x64 linux": "x86_64-unknown-linux-gnu", |
295 | "x64 darwin": "x86_64-apple-darwin", | 295 | "x64 darwin": "x86_64-apple-darwin", |
296 | "arm64 win32": "aarch64-pc-windows-msvc", | 296 | "arm64 win32": "aarch64-pc-windows-msvc", |
297 | "arm64 linux": "aarch64-unknown-linux-gnu", | ||
297 | "arm64 darwin": "aarch64-apple-darwin", | 298 | "arm64 darwin": "aarch64-apple-darwin", |
298 | }; | 299 | }; |
299 | const platform = platforms[`${process.arch} ${process.platform}`]; | 300 | const platform = platforms[`${process.arch} ${process.platform}`]; |
diff --git a/lib/arena/Cargo.toml b/lib/arena/Cargo.toml index b9dbb7ef3..f4d2ecb6c 100644 --- a/lib/arena/Cargo.toml +++ b/lib/arena/Cargo.toml | |||
@@ -1,6 +1,6 @@ | |||
1 | [package] | 1 | [package] |
2 | name = "la-arena" | 2 | name = "la-arena" |
3 | version = "0.1.1" | 3 | version = "0.2.0" |
4 | description = "Simple index-based arena without deletion." | 4 | description = "Simple index-based arena without deletion." |
5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
6 | repository = "https://github.com/rust-analyzer/rust-analyzer" | 6 | repository = "https://github.com/rust-analyzer/rust-analyzer" |
diff --git a/lib/arena/src/lib.rs b/lib/arena/src/lib.rs index 78a147c7d..230a50291 100644 --- a/lib/arena/src/lib.rs +++ b/lib/arena/src/lib.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | //! Yet another ID-based arena. | 1 | //! Yet another index-based arena. |
2 | 2 | ||
3 | #![warn(missing_docs)] | 3 | #![warn(missing_docs)] |
4 | 4 | ||
@@ -10,39 +10,40 @@ use std::{ | |||
10 | ops::{Index, IndexMut}, | 10 | ops::{Index, IndexMut}, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | pub mod map; | 13 | mod map; |
14 | pub use map::ArenaMap; | ||
14 | 15 | ||
15 | /// The raw ID of a value in an arena. | 16 | /// The raw index of a value in an arena. |
16 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 17 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
17 | pub struct RawId(u32); | 18 | pub struct RawIdx(u32); |
18 | 19 | ||
19 | impl From<RawId> for u32 { | 20 | impl From<RawIdx> for u32 { |
20 | fn from(raw: RawId) -> u32 { | 21 | fn from(raw: RawIdx) -> u32 { |
21 | raw.0 | 22 | raw.0 |
22 | } | 23 | } |
23 | } | 24 | } |
24 | 25 | ||
25 | impl From<u32> for RawId { | 26 | impl From<u32> for RawIdx { |
26 | fn from(id: u32) -> RawId { | 27 | fn from(idx: u32) -> RawIdx { |
27 | RawId(id) | 28 | RawIdx(idx) |
28 | } | 29 | } |
29 | } | 30 | } |
30 | 31 | ||
31 | impl fmt::Debug for RawId { | 32 | impl fmt::Debug for RawIdx { |
32 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 33 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
33 | self.0.fmt(f) | 34 | self.0.fmt(f) |
34 | } | 35 | } |
35 | } | 36 | } |
36 | 37 | ||
37 | impl fmt::Display for RawId { | 38 | impl fmt::Display for RawIdx { |
38 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 39 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
39 | self.0.fmt(f) | 40 | self.0.fmt(f) |
40 | } | 41 | } |
41 | } | 42 | } |
42 | 43 | ||
43 | /// The ID of a value allocated in an arena that holds `T`s. | 44 | /// The index of a value allocated in an arena that holds `T`s. |
44 | pub struct Idx<T> { | 45 | pub struct Idx<T> { |
45 | raw: RawId, | 46 | raw: RawIdx, |
46 | _ty: PhantomData<fn() -> T>, | 47 | _ty: PhantomData<fn() -> T>, |
47 | } | 48 | } |
48 | 49 | ||
@@ -77,18 +78,18 @@ impl<T> fmt::Debug for Idx<T> { | |||
77 | } | 78 | } |
78 | 79 | ||
79 | impl<T> Idx<T> { | 80 | impl<T> Idx<T> { |
80 | /// Creates a new ID from a [`RawId`]. | 81 | /// Creates a new index from a [`RawIdx`]. |
81 | pub fn from_raw(raw: RawId) -> Self { | 82 | pub fn from_raw(raw: RawIdx) -> Self { |
82 | Idx { raw, _ty: PhantomData } | 83 | Idx { raw, _ty: PhantomData } |
83 | } | 84 | } |
84 | 85 | ||
85 | /// Converts this ID into the underlying [`RawId`]. | 86 | /// Converts this index into the underlying [`RawIdx`]. |
86 | pub fn into_raw(self) -> RawId { | 87 | pub fn into_raw(self) -> RawIdx { |
87 | self.raw | 88 | self.raw |
88 | } | 89 | } |
89 | } | 90 | } |
90 | 91 | ||
91 | /// Yet another ID-based arena. | 92 | /// Yet another index-based arena. |
92 | #[derive(Clone, PartialEq, Eq)] | 93 | #[derive(Clone, PartialEq, Eq)] |
93 | pub struct Arena<T> { | 94 | pub struct Arena<T> { |
94 | data: Vec<T>, | 95 | data: Vec<T>, |
@@ -160,37 +161,37 @@ impl<T> Arena<T> { | |||
160 | self.data.is_empty() | 161 | self.data.is_empty() |
161 | } | 162 | } |
162 | 163 | ||
163 | /// Allocates a new value on the arena, returning the value’s ID. | 164 | /// Allocates a new value on the arena, returning the value’s index. |
164 | /// | 165 | /// |
165 | /// ``` | 166 | /// ``` |
166 | /// let mut arena = la_arena::Arena::new(); | 167 | /// let mut arena = la_arena::Arena::new(); |
167 | /// let id = arena.alloc(50); | 168 | /// let idx = arena.alloc(50); |
168 | /// | 169 | /// |
169 | /// assert_eq!(arena[id], 50); | 170 | /// assert_eq!(arena[idx], 50); |
170 | /// ``` | 171 | /// ``` |
171 | pub fn alloc(&mut self, value: T) -> Idx<T> { | 172 | pub fn alloc(&mut self, value: T) -> Idx<T> { |
172 | let id = RawId(self.data.len() as u32); | 173 | let idx = RawIdx(self.data.len() as u32); |
173 | self.data.push(value); | 174 | self.data.push(value); |
174 | Idx::from_raw(id) | 175 | Idx::from_raw(idx) |
175 | } | 176 | } |
176 | 177 | ||
177 | /// Returns an iterator over the arena’s elements. | 178 | /// Returns an iterator over the arena’s elements. |
178 | /// | 179 | /// |
179 | /// ``` | 180 | /// ``` |
180 | /// let mut arena = la_arena::Arena::new(); | 181 | /// let mut arena = la_arena::Arena::new(); |
181 | /// let id1 = arena.alloc(20); | 182 | /// let idx1 = arena.alloc(20); |
182 | /// let id2 = arena.alloc(40); | 183 | /// let idx2 = arena.alloc(40); |
183 | /// let id3 = arena.alloc(60); | 184 | /// let idx3 = arena.alloc(60); |
184 | /// | 185 | /// |
185 | /// let mut iterator = arena.iter(); | 186 | /// let mut iterator = arena.iter(); |
186 | /// assert_eq!(iterator.next(), Some((id1, &20))); | 187 | /// assert_eq!(iterator.next(), Some((idx1, &20))); |
187 | /// assert_eq!(iterator.next(), Some((id2, &40))); | 188 | /// assert_eq!(iterator.next(), Some((idx2, &40))); |
188 | /// assert_eq!(iterator.next(), Some((id3, &60))); | 189 | /// assert_eq!(iterator.next(), Some((idx3, &60))); |
189 | /// ``` | 190 | /// ``` |
190 | pub fn iter( | 191 | pub fn iter( |
191 | &self, | 192 | &self, |
192 | ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator { | 193 | ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator { |
193 | self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawId(idx as u32)), value)) | 194 | self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value)) |
194 | } | 195 | } |
195 | 196 | ||
196 | /// Reallocates the arena to make it take up as little space as possible. | 197 | /// Reallocates the arena to make it take up as little space as possible. |
diff --git a/lib/arena/src/map.rs b/lib/arena/src/map.rs index 980198247..d8acfe051 100644 --- a/lib/arena/src/map.rs +++ b/lib/arena/src/map.rs | |||
@@ -1,33 +1,34 @@ | |||
1 | //! A map from arena IDs to some other type. Space requirement is O(highest ID). | ||
2 | |||
3 | use std::marker::PhantomData; | 1 | use std::marker::PhantomData; |
4 | 2 | ||
5 | use crate::Idx; | 3 | use crate::Idx; |
6 | 4 | ||
7 | /// A map from arena IDs to some other type. Space requirement is O(highest ID). | 5 | /// A map from arena indexes to some other type. |
6 | /// Space requirement is O(highest index). | ||
8 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | 7 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
9 | pub struct ArenaMap<ID, V> { | 8 | pub struct ArenaMap<IDX, V> { |
10 | v: Vec<Option<V>>, | 9 | v: Vec<Option<V>>, |
11 | _ty: PhantomData<ID>, | 10 | _ty: PhantomData<IDX>, |
12 | } | 11 | } |
13 | 12 | ||
14 | impl<T, V> ArenaMap<Idx<T>, V> { | 13 | impl<T, V> ArenaMap<Idx<T>, V> { |
15 | /// Inserts a value associated with a given arena ID into the map. | 14 | /// Inserts a value associated with a given arena index into the map. |
16 | pub fn insert(&mut self, id: Idx<T>, t: V) { | 15 | pub fn insert(&mut self, idx: Idx<T>, t: V) { |
17 | let idx = Self::to_idx(id); | 16 | let idx = Self::to_idx(idx); |
18 | 17 | ||
19 | self.v.resize_with((idx + 1).max(self.v.len()), || None); | 18 | self.v.resize_with((idx + 1).max(self.v.len()), || None); |
20 | self.v[idx] = Some(t); | 19 | self.v[idx] = Some(t); |
21 | } | 20 | } |
22 | 21 | ||
23 | /// Returns a reference to the value associated with the provided ID if it is present. | 22 | /// Returns a reference to the value associated with the provided index |
24 | pub fn get(&self, id: Idx<T>) -> Option<&V> { | 23 | /// if it is present. |
25 | self.v.get(Self::to_idx(id)).and_then(|it| it.as_ref()) | 24 | pub fn get(&self, idx: Idx<T>) -> Option<&V> { |
25 | self.v.get(Self::to_idx(idx)).and_then(|it| it.as_ref()) | ||
26 | } | 26 | } |
27 | 27 | ||
28 | /// Returns a mutable reference to the value associated with the provided ID if it is present. | 28 | /// Returns a mutable reference to the value associated with the provided index |
29 | pub fn get_mut(&mut self, id: Idx<T>) -> Option<&mut V> { | 29 | /// if it is present. |
30 | self.v.get_mut(Self::to_idx(id)).and_then(|it| it.as_mut()) | 30 | pub fn get_mut(&mut self, idx: Idx<T>) -> Option<&mut V> { |
31 | self.v.get_mut(Self::to_idx(idx)).and_then(|it| it.as_mut()) | ||
31 | } | 32 | } |
32 | 33 | ||
33 | /// Returns an iterator over the values in the map. | 34 | /// Returns an iterator over the values in the map. |
@@ -40,13 +41,13 @@ impl<T, V> ArenaMap<Idx<T>, V> { | |||
40 | self.v.iter_mut().filter_map(|o| o.as_mut()) | 41 | self.v.iter_mut().filter_map(|o| o.as_mut()) |
41 | } | 42 | } |
42 | 43 | ||
43 | /// Returns an iterator over the arena IDs and values in the map. | 44 | /// Returns an iterator over the arena indexes and values in the map. |
44 | pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> { | 45 | pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> { |
45 | self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?))) | 46 | self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?))) |
46 | } | 47 | } |
47 | 48 | ||
48 | fn to_idx(id: Idx<T>) -> usize { | 49 | fn to_idx(idx: Idx<T>) -> usize { |
49 | u32::from(id.into_raw()) as usize | 50 | u32::from(idx.into_raw()) as usize |
50 | } | 51 | } |
51 | 52 | ||
52 | fn from_idx(idx: usize) -> Idx<T> { | 53 | fn from_idx(idx: usize) -> Idx<T> { |
@@ -56,8 +57,8 @@ impl<T, V> ArenaMap<Idx<T>, V> { | |||
56 | 57 | ||
57 | impl<T, V> std::ops::Index<Idx<V>> for ArenaMap<Idx<V>, T> { | 58 | impl<T, V> std::ops::Index<Idx<V>> for ArenaMap<Idx<V>, T> { |
58 | type Output = T; | 59 | type Output = T; |
59 | fn index(&self, id: Idx<V>) -> &T { | 60 | fn index(&self, idx: Idx<V>) -> &T { |
60 | self.v[Self::to_idx(id)].as_ref().unwrap() | 61 | self.v[Self::to_idx(idx)].as_ref().unwrap() |
61 | } | 62 | } |
62 | } | 63 | } |
63 | 64 | ||