aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/release.yaml9
-rw-r--r--Cargo.lock12
-rw-r--r--crates/ide/src/display/navigation_target.rs8
-rw-r--r--crates/ide/src/references/rename.rs103
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs191
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs51
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html12
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html12
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_injection.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html32
-rw-r--r--crates/ide_assists/src/ast_transform.rs33
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs10
-rw-r--r--crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs516
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs208
-rw-r--r--crates/ide_assists/src/handlers/merge_imports.rs2
-rw-r--r--crates/ide_assists/src/handlers/reorder_fields.rs8
-rw-r--r--crates/ide_assists/src/handlers/reorder_impl.rs20
-rw-r--r--crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs34
-rw-r--r--crates/ide_assists/src/lib.rs2
-rw-r--r--crates/ide_assists/src/tests.rs5
-rw-r--r--crates/ide_assists/src/tests/generated.rs41
-rw-r--r--crates/ide_assists/src/utils.rs3
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs2
-rw-r--r--crates/ide_completion/src/item.rs8
-rw-r--r--crates/ide_completion/src/lib.rs2
-rw-r--r--crates/ide_completion/src/test_utils.rs5
-rw-r--r--crates/ide_db/src/helpers.rs3
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs587
-rw-r--r--crates/ide_db/src/helpers/insert_use/tests.rs42
-rw-r--r--crates/ide_db/src/helpers/merge_imports.rs309
-rw-r--r--crates/ide_db/src/search.rs58
-rw-r--r--crates/project_model/src/build_data.rs2
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/build.rs62
-rw-r--r--crates/rust-analyzer/src/config.rs5
-rw-r--r--crates/rust-analyzer/src/main_loop.rs6
-rw-r--r--crates/stdx/src/lib.rs15
-rw-r--r--crates/syntax/src/algo.rs19
-rw-r--r--crates/syntax/src/ast/make.rs27
-rw-r--r--crates/syntax/src/ast/node_ext.rs22
-rw-r--r--crates/syntax/src/ted.rs17
-rw-r--r--docs/user/generated_config.adoc5
-rw-r--r--editors/code/package-lock.json891
-rw-r--r--editors/code/package.json5
-rw-r--r--editors/code/src/config.ts1
-rw-r--r--editors/code/src/inlay_hints.ts52
-rw-r--r--xtask/src/dist.rs34
-rw-r--r--xtask/src/flags.rs9
-rw-r--r--xtask/src/main.rs8
-rw-r--r--xtask/src/release.rs11
51 files changed, 2200 insertions, 1329 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 307096ef3..d5c93f69b 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -109,12 +109,7 @@ jobs:
109 node-version: 12.x 109 node-version: 12.x
110 110
111 - name: Dist 111 - name: Dist
112 if: github.ref == 'refs/heads/release' 112 run: cargo xtask dist --client-patch-version $GITHUB_RUN_NUMBER
113 run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER
114
115 - name: Dist
116 if: github.ref != 'refs/heads/release'
117 run: cargo xtask dist --nightly --client 0.3.$GITHUB_RUN_NUMBER-nightly
118 113
119 - name: Run analysis-stats on rust-analyzer 114 - name: Run analysis-stats on rust-analyzer
120 run: target/${{ env.RA_TARGET }}/release/rust-analyzer analysis-stats . 115 run: target/${{ env.RA_TARGET }}/release/rust-analyzer analysis-stats .
@@ -266,7 +261,7 @@ jobs:
266 with: 261 with:
267 node-version: 12.x 262 node-version: 12.x
268 263
269 - run: echo "TAG=$(date --iso --utc)" >> $GITHUB_ENV 264 - run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV
270 if: github.ref == 'refs/heads/release' 265 if: github.ref == 'refs/heads/release'
271 - run: echo "TAG=nightly" >> $GITHUB_ENV 266 - run: echo "TAG=nightly" >> $GITHUB_ENV
272 if: github.ref != 'refs/heads/release' 267 if: github.ref != 'refs/heads/release'
diff --git a/Cargo.lock b/Cargo.lock
index 907973412..ba6862e98 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -841,9 +841,9 @@ dependencies = [
841 841
842[[package]] 842[[package]]
843name = "lsp-server" 843name = "lsp-server"
844version = "0.5.0" 844version = "0.5.1"
845source = "registry+https://github.com/rust-lang/crates.io-index" 845source = "registry+https://github.com/rust-lang/crates.io-index"
846checksum = "69b18dfe0e4a380b872aa79d8e0ee6c3d7a9682466e84b83ad807c88b3545f79" 846checksum = "6825d7042d5ca1825a366c40c9446928ec7b30e2be97243a13b164aee6583992"
847dependencies = [ 847dependencies = [
848 "crossbeam-channel", 848 "crossbeam-channel",
849 "log", 849 "log",
@@ -1303,9 +1303,9 @@ dependencies = [
1303 1303
1304[[package]] 1304[[package]]
1305name = "regex" 1305name = "regex"
1306version = "1.4.5" 1306version = "1.4.6"
1307source = "registry+https://github.com/rust-lang/crates.io-index" 1307source = "registry+https://github.com/rust-lang/crates.io-index"
1308checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" 1308checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759"
1309dependencies = [ 1309dependencies = [
1310 "regex-syntax", 1310 "regex-syntax",
1311] 1311]
@@ -1582,9 +1582,9 @@ dependencies = [
1582 1582
1583[[package]] 1583[[package]]
1584name = "syn" 1584name = "syn"
1585version = "1.0.69" 1585version = "1.0.70"
1586source = "registry+https://github.com/rust-lang/crates.io-index" 1586source = "registry+https://github.com/rust-lang/crates.io-index"
1587checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" 1587checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883"
1588dependencies = [ 1588dependencies = [
1589 "proc-macro2", 1589 "proc-macro2",
1590 "quote", 1590 "quote",
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 364be260c..2079c22a3 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -20,7 +20,7 @@ use syntax::{
20 20
21use crate::FileSymbol; 21use crate::FileSymbol;
22 22
23/// `NavigationTarget` represents and element in the editor's UI which you can 23/// `NavigationTarget` represents an element in the editor's UI which you can
24/// click on to navigate to a particular piece of code. 24/// click on to navigate to a particular piece of code.
25/// 25///
26/// Typically, a `NavigationTarget` corresponds to some element in the source 26/// Typically, a `NavigationTarget` corresponds to some element in the source
@@ -35,12 +35,10 @@ pub struct NavigationTarget {
35 /// Clients should use this range to answer "is the cursor inside the 35 /// Clients should use this range to answer "is the cursor inside the
36 /// element?" question. 36 /// element?" question.
37 pub full_range: TextRange, 37 pub full_range: TextRange,
38 /// A "most interesting" range withing the `full_range`. 38 /// A "most interesting" range within the `full_range`.
39 /// 39 ///
40 /// Typically, `full_range` is the whole syntax node, including doc 40 /// Typically, `full_range` is the whole syntax node, including doc
41 /// comments, and `focus_range` is the range of the identifier. "Most 41 /// comments, and `focus_range` is the range of the identifier.
42 /// interesting" range within the full range, typically the range of
43 /// identifier.
44 /// 42 ///
45 /// Clients should place the cursor on this range when navigating to this target. 43 /// Clients should place the cursor on this range when navigating to this target.
46 pub focus_range: Option<TextRange>, 44 pub focus_range: Option<TextRange>,
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 2408a0181..175e7a31d 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -50,6 +50,17 @@ pub(crate) fn prepare_rename(
50 let sema = Semantics::new(db); 50 let sema = Semantics::new(db);
51 let source_file = sema.parse(position.file_id); 51 let source_file = sema.parse(position.file_id);
52 let syntax = source_file.syntax(); 52 let syntax = source_file.syntax();
53
54 let def = find_definition(&sema, syntax, position)?;
55 match def {
56 Definition::SelfType(_) => bail!("Cannot rename `Self`"),
57 Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"),
58 _ => {}
59 };
60 let nav =
61 def.try_to_nav(sema.db).ok_or_else(|| format_err!("No references found at position"))?;
62 nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?;
63
53 let name_like = sema 64 let name_like = sema
54 .find_node_at_offset_with_descend(&syntax, position.offset) 65 .find_node_at_offset_with_descend(&syntax, position.offset)
55 .ok_or_else(|| format_err!("No references found at position"))?; 66 .ok_or_else(|| format_err!("No references found at position"))?;
@@ -507,7 +518,8 @@ fn source_edit_from_def(
507 def.try_to_nav(sema.db).ok_or_else(|| format_err!("No references found at position"))?; 518 def.try_to_nav(sema.db).ok_or_else(|| format_err!("No references found at position"))?;
508 519
509 let mut replacement_text = String::new(); 520 let mut replacement_text = String::new();
510 let mut repl_range = nav.focus_or_full_range(); 521 let mut repl_range =
522 nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?;
511 if let Definition::Local(local) = def { 523 if let Definition::Local(local) = def {
512 if let Either::Left(pat) = local.source(sema.db).value { 524 if let Either::Left(pat) = local.source(sema.db).value {
513 if matches!( 525 if matches!(
@@ -626,6 +638,49 @@ foo!(Foo$0);",
626 } 638 }
627 639
628 #[test] 640 #[test]
641 fn test_prepare_rename_tuple_field() {
642 check_prepare(
643 r#"
644struct Foo(i32);
645
646fn baz() {
647 let mut x = Foo(4);
648 x.0$0 = 5;
649}
650"#,
651 expect![[r#"No identifier available to rename"#]],
652 );
653 }
654
655 #[test]
656 fn test_prepare_rename_builtin() {
657 check_prepare(
658 r#"
659fn foo() {
660 let x: i32$0 = 0;
661}
662"#,
663 expect![[r#"Cannot rename builtin type"#]],
664 );
665 }
666
667 #[test]
668 fn test_prepare_rename_self() {
669 check_prepare(
670 r#"
671struct Foo {}
672
673impl Foo {
674 fn foo(self) -> Self$0 {
675 self
676 }
677}
678"#,
679 expect![[r#"Cannot rename `Self`"#]],
680 );
681 }
682
683 #[test]
629 fn test_rename_to_underscore() { 684 fn test_rename_to_underscore() {
630 check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#); 685 check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#);
631 } 686 }
@@ -1787,4 +1842,50 @@ fn foo() {
1787"#, 1842"#,
1788 ) 1843 )
1789 } 1844 }
1845
1846 #[test]
1847 fn test_rename_tuple_field() {
1848 check(
1849 "foo",
1850 r#"
1851struct Foo(i32);
1852
1853fn baz() {
1854 let mut x = Foo(4);
1855 x.0$0 = 5;
1856}
1857"#,
1858 "error: No identifier available to rename",
1859 );
1860 }
1861
1862 #[test]
1863 fn test_rename_builtin() {
1864 check(
1865 "foo",
1866 r#"
1867fn foo() {
1868 let x: i32$0 = 0;
1869}
1870"#,
1871 "error: Cannot rename builtin type",
1872 );
1873 }
1874
1875 #[test]
1876 fn test_rename_self() {
1877 check(
1878 "foo",
1879 r#"
1880struct Foo {}
1881
1882impl Foo {
1883 fn foo(self) -> Self$0 {
1884 self
1885 }
1886}
1887"#,
1888 "error: Cannot rename `Self`",
1889 );
1890 }
1790} 1891}
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 18552459b..b586dcc17 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -1,6 +1,6 @@
1//! Computes color for a single element. 1//! Computes color for a single element.
2 2
3use hir::{AsAssocItem, AssocItemContainer, Semantics, VariantDef}; 3use hir::{AsAssocItem, Semantics};
4use ide_db::{ 4use ide_db::{
5 defs::{Definition, NameClass, NameRefClass}, 5 defs::{Definition, NameClass, NameRefClass},
6 RootDatabase, SymbolKind, 6 RootDatabase, SymbolKind,
@@ -45,28 +45,26 @@ pub(super) fn element(
45 }; 45 };
46 46
47 match name_kind { 47 match name_kind {
48 Some(NameClass::ExternCrate(_)) => HlTag::Symbol(SymbolKind::Module).into(), 48 Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(),
49 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, 49 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition,
50 Some(NameClass::ConstReference(def)) => highlight_def(db, def), 50 Some(NameClass::ConstReference(def)) => highlight_def(db, def),
51 Some(NameClass::PatFieldShorthand { field_ref, .. }) => { 51 Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
52 let mut h = HlTag::Symbol(SymbolKind::Field).into(); 52 let mut h = HlTag::Symbol(SymbolKind::Field).into();
53 if let Definition::Field(field) = field_ref { 53 if let Definition::Field(field) = field_ref {
54 if let VariantDef::Union(_) = field.parent_def(db) { 54 if let hir::VariantDef::Union(_) = field.parent_def(db) {
55 h |= HlMod::Unsafe; 55 h |= HlMod::Unsafe;
56 } 56 }
57 } 57 }
58
59 h 58 h
60 } 59 }
61 None => highlight_name_by_syntax(name) | HlMod::Definition, 60 None => highlight_name_by_syntax(name) | HlMod::Definition,
62 } 61 }
63 } 62 }
64
65 // Highlight references like the definitions they resolve to 63 // Highlight references like the definitions they resolve to
66 NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => { 64 NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => {
67 // even though we track whether we are in an attribute or not we still need this special case 65 // even though we track whether we are in an attribute or not we still need this special case
68 // as otherwise we would emit unresolved references for name refs inside attributes 66 // as otherwise we would emit unresolved references for name refs inside attributes
69 Highlight::from(HlTag::Symbol(SymbolKind::Function)) 67 SymbolKind::Function.into()
70 } 68 }
71 NAME_REF => { 69 NAME_REF => {
72 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); 70 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
@@ -74,7 +72,7 @@ pub(super) fn element(
74 let is_self = name_ref.self_token().is_some(); 72 let is_self = name_ref.self_token().is_some();
75 let h = match NameRefClass::classify(sema, &name_ref) { 73 let h = match NameRefClass::classify(sema, &name_ref) {
76 Some(name_kind) => match name_kind { 74 Some(name_kind) => match name_kind {
77 NameRefClass::ExternCrate(_) => HlTag::Symbol(SymbolKind::Module).into(), 75 NameRefClass::ExternCrate(_) => SymbolKind::Module.into(),
78 NameRefClass::Definition(def) => { 76 NameRefClass::Definition(def) => {
79 if let Definition::Local(local) = &def { 77 if let Definition::Local(local) = &def {
80 if let Some(name) = local.name(db) { 78 if let Some(name) = local.name(db) {
@@ -95,7 +93,7 @@ pub(super) fn element(
95 if let Some(parent) = name_ref.syntax().parent() { 93 if let Some(parent) = name_ref.syntax().parent() {
96 if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { 94 if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) {
97 if let Definition::Field(field) = def { 95 if let Definition::Field(field) = def {
98 if let VariantDef::Union(_) = field.parent_def(db) { 96 if let hir::VariantDef::Union(_) = field.parent_def(db) {
99 h |= HlMod::Unsafe; 97 h |= HlMod::Unsafe;
100 } 98 }
101 } 99 }
@@ -104,9 +102,7 @@ pub(super) fn element(
104 102
105 h 103 h
106 } 104 }
107 NameRefClass::FieldShorthand { .. } => { 105 NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(),
108 HlTag::Symbol(SymbolKind::Field).into()
109 }
110 }, 106 },
111 None if syntactic_name_ref_highlighting => { 107 None if syntactic_name_ref_highlighting => {
112 highlight_name_ref_by_syntax(name_ref, sema) 108 highlight_name_ref_by_syntax(name_ref, sema)
@@ -114,7 +110,7 @@ pub(super) fn element(
114 None => HlTag::UnresolvedReference.into(), 110 None => HlTag::UnresolvedReference.into(),
115 }; 111 };
116 if h.tag == HlTag::Symbol(SymbolKind::Module) && is_self { 112 if h.tag == HlTag::Symbol(SymbolKind::Module) && is_self {
117 HlTag::Symbol(SymbolKind::SelfParam).into() 113 SymbolKind::SelfParam.into()
118 } else { 114 } else {
119 h 115 h
120 } 116 }
@@ -135,7 +131,7 @@ pub(super) fn element(
135 INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(), 131 INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
136 BYTE => HlTag::ByteLiteral.into(), 132 BYTE => HlTag::ByteLiteral.into(),
137 CHAR => HlTag::CharLiteral.into(), 133 CHAR => HlTag::CharLiteral.into(),
138 QUESTION => Highlight::new(HlTag::Operator(HlOperator::Other)) | HlMod::ControlFlow, 134 QUESTION => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow,
139 LIFETIME => { 135 LIFETIME => {
140 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); 136 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap();
141 137
@@ -143,44 +139,31 @@ pub(super) fn element(
143 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, 139 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition,
144 None => match NameRefClass::classify_lifetime(sema, &lifetime) { 140 None => match NameRefClass::classify_lifetime(sema, &lifetime) {
145 Some(NameRefClass::Definition(def)) => highlight_def(db, def), 141 Some(NameRefClass::Definition(def)) => highlight_def(db, def),
146 _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)), 142 _ => SymbolKind::LifetimeParam.into(),
147 }, 143 },
148 _ => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)) | HlMod::Definition, 144 _ => Highlight::from(SymbolKind::LifetimeParam) | HlMod::Definition,
149 } 145 }
150 } 146 }
151 p if p.is_punct() => match p { 147 p if p.is_punct() => match p {
152 T![&] if element.parent().and_then(ast::BinExpr::cast).is_some() => { 148 T![&] if parent_matches::<ast::BinExpr>(&element) => HlOperator::Bitwise.into(),
153 HlTag::Operator(HlOperator::Bitwise).into()
154 }
155 T![&] => { 149 T![&] => {
156 let h = HlTag::Operator(HlOperator::Other).into(); 150 let h = HlTag::Operator(HlOperator::Other).into();
157 let is_unsafe = element 151 let is_unsafe = element
158 .parent() 152 .parent()
159 .and_then(ast::RefExpr::cast) 153 .and_then(ast::RefExpr::cast)
160 .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr)) 154 .map_or(false, |ref_expr| sema.is_unsafe_ref_expr(&ref_expr));
161 .unwrap_or(false);
162 if is_unsafe { 155 if is_unsafe {
163 h | HlMod::Unsafe 156 h | HlMod::Unsafe
164 } else { 157 } else {
165 h 158 h
166 } 159 }
167 } 160 }
168 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => { 161 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => HlOperator::Other.into(),
169 HlTag::Operator(HlOperator::Other).into() 162 T![!] if parent_matches::<ast::MacroCall>(&element) => SymbolKind::Macro.into(),
170 } 163 T![!] if parent_matches::<ast::NeverType>(&element) => HlTag::BuiltinType.into(),
171 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { 164 T![!] if parent_matches::<ast::PrefixExpr>(&element) => HlOperator::Logical.into(),
172 HlTag::Symbol(SymbolKind::Macro).into() 165 T![*] if parent_matches::<ast::PtrType>(&element) => HlTag::Keyword.into(),
173 } 166 T![*] if parent_matches::<ast::PrefixExpr>(&element) => {
174 T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => {
175 HlTag::BuiltinType.into()
176 }
177 T![!] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
178 HlTag::Operator(HlOperator::Logical).into()
179 }
180 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => {
181 HlTag::Keyword.into()
182 }
183 T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
184 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; 167 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
185 168
186 let expr = prefix_expr.expr()?; 169 let expr = prefix_expr.expr()?;
@@ -188,12 +171,12 @@ pub(super) fn element(
188 if ty.is_raw_ptr() { 171 if ty.is_raw_ptr() {
189 HlTag::Operator(HlOperator::Other) | HlMod::Unsafe 172 HlTag::Operator(HlOperator::Other) | HlMod::Unsafe
190 } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() { 173 } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() {
191 HlTag::Operator(HlOperator::Other).into() 174 HlOperator::Other.into()
192 } else { 175 } else {
193 HlTag::Punctuation(HlPunct::Other).into() 176 HlPunct::Other.into()
194 } 177 }
195 } 178 }
196 T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { 179 T![-] if parent_matches::<ast::PrefixExpr>(&element) => {
197 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; 180 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
198 181
199 let expr = prefix_expr.expr()?; 182 let expr = prefix_expr.expr()?;
@@ -203,41 +186,31 @@ pub(super) fn element(
203 } 186 }
204 .into() 187 .into()
205 } 188 }
206 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { 189 _ if parent_matches::<ast::PrefixExpr>(&element) => HlOperator::Other.into(),
207 HlTag::Operator(HlOperator::Other).into()
208 }
209 T![+] | T![-] | T![*] | T![/] | T![+=] | T![-=] | T![*=] | T![/=] 190 T![+] | T![-] | T![*] | T![/] | T![+=] | T![-=] | T![*=] | T![/=]
210 if element.parent().and_then(ast::BinExpr::cast).is_some() => 191 if parent_matches::<ast::BinExpr>(&element) =>
211 { 192 {
212 HlTag::Operator(HlOperator::Arithmetic).into() 193 HlOperator::Arithmetic.into()
213 } 194 }
214 T![|] | T![&] | T![!] | T![^] | T![|=] | T![&=] | T![^=] 195 T![|] | T![&] | T![!] | T![^] | T![|=] | T![&=] | T![^=]
215 if element.parent().and_then(ast::BinExpr::cast).is_some() => 196 if parent_matches::<ast::BinExpr>(&element) =>
216 { 197 {
217 HlTag::Operator(HlOperator::Bitwise).into() 198 HlOperator::Bitwise.into()
218 } 199 }
219 T![&&] | T![||] if element.parent().and_then(ast::BinExpr::cast).is_some() => { 200 T![&&] | T![||] if parent_matches::<ast::BinExpr>(&element) => {
220 HlTag::Operator(HlOperator::Logical).into() 201 HlOperator::Logical.into()
221 } 202 }
222 T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=] 203 T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=]
223 if element.parent().and_then(ast::BinExpr::cast).is_some() => 204 if parent_matches::<ast::BinExpr>(&element) =>
224 { 205 {
225 HlTag::Operator(HlOperator::Comparison).into() 206 HlOperator::Comparison.into()
226 }
227 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => {
228 HlTag::Operator(HlOperator::Other).into()
229 }
230 _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => {
231 HlTag::Operator(HlOperator::Other).into()
232 } 207 }
233 _ if element.parent().and_then(ast::RangePat::cast).is_some() => { 208 _ if parent_matches::<ast::BinExpr>(&element) => HlOperator::Other.into(),
234 HlTag::Operator(HlOperator::Other).into() 209 _ if parent_matches::<ast::RangeExpr>(&element) => HlOperator::Other.into(),
235 } 210 _ if parent_matches::<ast::RangePat>(&element) => HlOperator::Other.into(),
236 _ if element.parent().and_then(ast::RestPat::cast).is_some() => { 211 _ if parent_matches::<ast::RestPat>(&element) => HlOperator::Other.into(),
237 HlTag::Operator(HlOperator::Other).into() 212 _ if parent_matches::<ast::Attr>(&element) => HlTag::Attribute.into(),
238 } 213 kind => match kind {
239 _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(),
240 kind => HlTag::Punctuation(match kind {
241 T!['['] | T![']'] => HlPunct::Bracket, 214 T!['['] | T![']'] => HlPunct::Bracket,
242 T!['{'] | T!['}'] => HlPunct::Brace, 215 T!['{'] | T!['}'] => HlPunct::Brace,
243 T!['('] | T![')'] => HlPunct::Parenthesis, 216 T!['('] | T![')'] => HlPunct::Parenthesis,
@@ -247,22 +220,24 @@ pub(super) fn element(
247 T![;] => HlPunct::Semi, 220 T![;] => HlPunct::Semi,
248 T![.] => HlPunct::Dot, 221 T![.] => HlPunct::Dot,
249 _ => HlPunct::Other, 222 _ => HlPunct::Other,
250 }) 223 }
251 .into(), 224 .into(),
252 }, 225 },
253 226
254 k if k.is_keyword() => { 227 k if k.is_keyword() => {
255 let h = Highlight::new(HlTag::Keyword); 228 let h = Highlight::new(HlTag::Keyword);
256 match k { 229 match k {
257 T![break] 230 T![await]
231 | T![break]
258 | T![continue] 232 | T![continue]
259 | T![else] 233 | T![else]
260 | T![if] 234 | T![if]
235 | T![in]
261 | T![loop] 236 | T![loop]
262 | T![match] 237 | T![match]
263 | T![return] 238 | T![return]
264 | T![while] 239 | T![while]
265 | T![in] => h | HlMod::ControlFlow, 240 | T![yield] => h | HlMod::ControlFlow,
266 T![for] if !is_child_of_impl(&element) => h | HlMod::ControlFlow, 241 T![for] if !is_child_of_impl(&element) => h | HlMod::ControlFlow,
267 T![unsafe] => h | HlMod::Unsafe, 242 T![unsafe] => h | HlMod::Unsafe,
268 T![true] | T![false] => HlTag::BoolLiteral.into(), 243 T![true] | T![false] => HlTag::BoolLiteral.into(),
@@ -301,7 +276,6 @@ pub(super) fn element(
301 hash((name, shadow_count)) 276 hash((name, shadow_count))
302 } 277 }
303} 278}
304
305fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { 279fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
306 match def { 280 match def {
307 Definition::Macro(_) => HlTag::Symbol(SymbolKind::Macro), 281 Definition::Macro(_) => HlTag::Symbol(SymbolKind::Macro),
@@ -312,17 +286,22 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
312 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); 286 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function));
313 if let Some(item) = func.as_assoc_item(db) { 287 if let Some(item) = func.as_assoc_item(db) {
314 h |= HlMod::Associated; 288 h |= HlMod::Associated;
315 if func.self_param(db).is_none() { 289 match func.self_param(db) {
316 h |= HlMod::Static 290 Some(sp) => {
291 if let hir::Access::Exclusive = sp.access(db) {
292 h |= HlMod::Mutable;
293 }
294 }
295 None => h |= HlMod::Static,
317 } 296 }
318 297
319 match item.container(db) { 298 match item.container(db) {
320 AssocItemContainer::Impl(i) => { 299 hir::AssocItemContainer::Impl(i) => {
321 if i.trait_(db).is_some() { 300 if i.trait_(db).is_some() {
322 h |= HlMod::Trait; 301 h |= HlMod::Trait;
323 } 302 }
324 } 303 }
325 AssocItemContainer::Trait(_t) => { 304 hir::AssocItemContainer::Trait(_t) => {
326 h |= HlMod::Trait; 305 h |= HlMod::Trait;
327 } 306 }
328 } 307 }
@@ -342,12 +321,12 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
342 if let Some(item) = konst.as_assoc_item(db) { 321 if let Some(item) = konst.as_assoc_item(db) {
343 h |= HlMod::Associated; 322 h |= HlMod::Associated;
344 match item.container(db) { 323 match item.container(db) {
345 AssocItemContainer::Impl(i) => { 324 hir::AssocItemContainer::Impl(i) => {
346 if i.trait_(db).is_some() { 325 if i.trait_(db).is_some() {
347 h |= HlMod::Trait; 326 h |= HlMod::Trait;
348 } 327 }
349 } 328 }
350 AssocItemContainer::Trait(_t) => { 329 hir::AssocItemContainer::Trait(_t) => {
351 h |= HlMod::Trait; 330 h |= HlMod::Trait;
352 } 331 }
353 } 332 }
@@ -361,12 +340,12 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
361 if let Some(item) = type_.as_assoc_item(db) { 340 if let Some(item) = type_.as_assoc_item(db) {
362 h |= HlMod::Associated; 341 h |= HlMod::Associated;
363 match item.container(db) { 342 match item.container(db) {
364 AssocItemContainer::Impl(i) => { 343 hir::AssocItemContainer::Impl(i) => {
365 if i.trait_(db).is_some() { 344 if i.trait_(db).is_some() {
366 h |= HlMod::Trait; 345 h |= HlMod::Trait;
367 } 346 }
368 } 347 }
369 AssocItemContainer::Trait(_t) => { 348 hir::AssocItemContainer::Trait(_t) => {
370 h |= HlMod::Trait; 349 h |= HlMod::Trait;
371 } 350 }
372 } 351 }
@@ -425,7 +404,7 @@ fn highlight_method_call(
425 method_call: &ast::MethodCallExpr, 404 method_call: &ast::MethodCallExpr,
426) -> Option<Highlight> { 405) -> Option<Highlight> {
427 let func = sema.resolve_method_call(&method_call)?; 406 let func = sema.resolve_method_call(&method_call)?;
428 let mut h = HlTag::Symbol(SymbolKind::Function).into(); 407 let mut h = SymbolKind::Function.into();
429 h |= HlMod::Associated; 408 h |= HlMod::Associated;
430 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { 409 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) {
431 h |= HlMod::Unsafe; 410 h |= HlMod::Unsafe;
@@ -461,20 +440,20 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
461 }; 440 };
462 441
463 let tag = match parent.kind() { 442 let tag = match parent.kind() {
464 STRUCT => HlTag::Symbol(SymbolKind::Struct), 443 STRUCT => SymbolKind::Struct,
465 ENUM => HlTag::Symbol(SymbolKind::Enum), 444 ENUM => SymbolKind::Enum,
466 VARIANT => HlTag::Symbol(SymbolKind::Variant), 445 VARIANT => SymbolKind::Variant,
467 UNION => HlTag::Symbol(SymbolKind::Union), 446 UNION => SymbolKind::Union,
468 TRAIT => HlTag::Symbol(SymbolKind::Trait), 447 TRAIT => SymbolKind::Trait,
469 TYPE_ALIAS => HlTag::Symbol(SymbolKind::TypeAlias), 448 TYPE_ALIAS => SymbolKind::TypeAlias,
470 TYPE_PARAM => HlTag::Symbol(SymbolKind::TypeParam), 449 TYPE_PARAM => SymbolKind::TypeParam,
471 RECORD_FIELD => HlTag::Symbol(SymbolKind::Field), 450 RECORD_FIELD => SymbolKind::Field,
472 MODULE => HlTag::Symbol(SymbolKind::Module), 451 MODULE => SymbolKind::Module,
473 FN => HlTag::Symbol(SymbolKind::Function), 452 FN => SymbolKind::Function,
474 CONST => HlTag::Symbol(SymbolKind::Const), 453 CONST => SymbolKind::Const,
475 STATIC => HlTag::Symbol(SymbolKind::Static), 454 STATIC => SymbolKind::Static,
476 IDENT_PAT => HlTag::Symbol(SymbolKind::Local), 455 IDENT_PAT => SymbolKind::Local,
477 _ => default, 456 _ => return default.into(),
478 }; 457 };
479 458
480 tag.into() 459 tag.into()
@@ -492,20 +471,15 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
492 METHOD_CALL_EXPR => { 471 METHOD_CALL_EXPR => {
493 return ast::MethodCallExpr::cast(parent) 472 return ast::MethodCallExpr::cast(parent)
494 .and_then(|it| highlight_method_call(sema, &it)) 473 .and_then(|it| highlight_method_call(sema, &it))
495 .unwrap_or_else(|| HlTag::Symbol(SymbolKind::Function).into()); 474 .unwrap_or_else(|| SymbolKind::Function.into());
496 } 475 }
497 FIELD_EXPR => { 476 FIELD_EXPR => {
498 let h = HlTag::Symbol(SymbolKind::Field); 477 let h = HlTag::Symbol(SymbolKind::Field);
499 let is_union = ast::FieldExpr::cast(parent) 478 let is_union = ast::FieldExpr::cast(parent)
500 .and_then(|field_expr| { 479 .and_then(|field_expr| sema.resolve_field(&field_expr))
501 let field = sema.resolve_field(&field_expr)?; 480 .map_or(false, |field| {
502 Some(if let VariantDef::Union(_) = field.parent_def(sema.db) { 481 matches!(field.parent_def(sema.db), hir::VariantDef::Union(_))
503 true 482 });
504 } else {
505 false
506 })
507 })
508 .unwrap_or(false);
509 if is_union { 483 if is_union {
510 h | HlMod::Unsafe 484 h | HlMod::Unsafe
511 } else { 485 } else {
@@ -522,9 +496,9 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
522 _ => { 496 _ => {
523 // within path, decide whether it is module or adt by checking for uppercase name 497 // within path, decide whether it is module or adt by checking for uppercase name
524 return if name.text().chars().next().unwrap_or_default().is_uppercase() { 498 return if name.text().chars().next().unwrap_or_default().is_uppercase() {
525 HlTag::Symbol(SymbolKind::Struct) 499 SymbolKind::Struct
526 } else { 500 } else {
527 HlTag::Symbol(SymbolKind::Module) 501 SymbolKind::Module
528 } 502 }
529 .into(); 503 .into();
530 } 504 }
@@ -535,11 +509,11 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
535 }; 509 };
536 510
537 match parent.kind() { 511 match parent.kind() {
538 CALL_EXPR => HlTag::Symbol(SymbolKind::Function).into(), 512 CALL_EXPR => SymbolKind::Function.into(),
539 _ => if name.text().chars().next().unwrap_or_default().is_uppercase() { 513 _ => if name.text().chars().next().unwrap_or_default().is_uppercase() {
540 HlTag::Symbol(SymbolKind::Struct) 514 SymbolKind::Struct
541 } else { 515 } else {
542 HlTag::Symbol(SymbolKind::Const) 516 SymbolKind::Const
543 } 517 }
544 .into(), 518 .into(),
545 } 519 }
@@ -574,6 +548,11 @@ fn parents_match(mut node: NodeOrToken<SyntaxNode, SyntaxToken>, mut kinds: &[Sy
574 kinds.len() == 0 548 kinds.len() == 0
575} 549}
576 550
551#[inline]
552fn parent_matches<N: AstNode>(element: &SyntaxElement) -> bool {
553 element.parent().map_or(false, |it| N::can_cast(it.kind()))
554}
555
577fn is_child_of_impl(element: &SyntaxElement) -> bool { 556fn is_child_of_impl(element: &SyntaxElement) -> bool {
578 match element.parent() { 557 match element.parent() {
579 Some(e) => e.kind() == IMPL, 558 Some(e) => e.kind() == IMPL,
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index e58392d67..a304b3250 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -40,28 +40,33 @@ pub enum HlTag {
40#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 40#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
41#[repr(u8)] 41#[repr(u8)]
42pub enum HlMod { 42pub enum HlMod {
43 /// Used for items in traits and impls.
44 Associated = 0,
43 /// Used to differentiate individual elements within attributes. 45 /// Used to differentiate individual elements within attributes.
44 Attribute = 0, 46 Attribute,
47 /// Callable item or value.
48 Callable,
49 /// Value that is being consumed in a function call
50 Consuming,
45 /// Used with keywords like `if` and `break`. 51 /// Used with keywords like `if` and `break`.
46 ControlFlow, 52 ControlFlow,
47 /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is 53 /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is
48 /// not. 54 /// not.
49 Definition, 55 Definition,
56 /// Doc-strings like this one.
50 Documentation, 57 Documentation,
58 /// Highlighting injection like rust code in doc strings or ra_fixture.
51 Injected, 59 Injected,
52 Mutable,
53 Consuming,
54 Callable,
55 /// Used for associated functions
56 Static,
57 /// Used for items in impls&traits.
58 Associated,
59 /// Used for intra doc links in doc injection. 60 /// Used for intra doc links in doc injection.
60 IntraDocLink, 61 IntraDocLink,
62 /// Mutable binding.
63 Mutable,
64 /// Used for associated functions.
65 Static,
61 /// Used for items in traits and trait impls. 66 /// Used for items in traits and trait impls.
62 Trait, 67 Trait,
63 68 // Keep this last!
64 /// Keep this last! 69 /// Used for unsafe functions, mutable statics, union accesses and unsafe operations.
65 Unsafe, 70 Unsafe,
66} 71}
67 72
@@ -169,17 +174,17 @@ impl fmt::Display for HlTag {
169 174
170impl HlMod { 175impl HlMod {
171 const ALL: &'static [HlMod; HlMod::Unsafe as u8 as usize + 1] = &[ 176 const ALL: &'static [HlMod; HlMod::Unsafe as u8 as usize + 1] = &[
177 HlMod::Associated,
172 HlMod::Attribute, 178 HlMod::Attribute,
179 HlMod::Callable,
180 HlMod::Consuming,
173 HlMod::ControlFlow, 181 HlMod::ControlFlow,
174 HlMod::Definition, 182 HlMod::Definition,
175 HlMod::Documentation, 183 HlMod::Documentation,
176 HlMod::IntraDocLink,
177 HlMod::Injected, 184 HlMod::Injected,
185 HlMod::IntraDocLink,
178 HlMod::Mutable, 186 HlMod::Mutable,
179 HlMod::Consuming,
180 HlMod::Callable,
181 HlMod::Static, 187 HlMod::Static,
182 HlMod::Associated,
183 HlMod::Trait, 188 HlMod::Trait,
184 HlMod::Unsafe, 189 HlMod::Unsafe,
185 ]; 190 ];
@@ -229,6 +234,24 @@ impl From<HlTag> for Highlight {
229 } 234 }
230} 235}
231 236
237impl From<HlOperator> for Highlight {
238 fn from(op: HlOperator) -> Highlight {
239 Highlight::new(HlTag::Operator(op))
240 }
241}
242
243impl From<HlPunct> for Highlight {
244 fn from(punct: HlPunct) -> Highlight {
245 Highlight::new(HlTag::Punctuation(punct))
246 }
247}
248
249impl From<SymbolKind> for Highlight {
250 fn from(sym: SymbolKind) -> Highlight {
251 Highlight::new(HlTag::Symbol(sym))
252 }
253}
254
232impl Highlight { 255impl Highlight {
233 pub(crate) fn new(tag: HlTag) -> Highlight { 256 pub(crate) fn new(tag: HlTag) -> Highlight {
234 Highlight { tag, mods: HlMods::default() } 257 Highlight { tag, mods: HlMods::default() }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 8cde3906c..a0ea1db34 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -42,17 +42,17 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
42<span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="brace">{</span><span class="brace">}</span> 42<span class="keyword">struct</span> <span class="struct declaration">foo</span> <span class="brace">{</span><span class="brace">}</span>
43 43
44<span class="keyword">impl</span> <span class="struct">foo</span> <span class="brace">{</span> 44<span class="keyword">impl</span> <span class="struct">foo</span> <span class="brace">{</span>
45 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 45 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function associated declaration static">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
46 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 46 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function associated declaration">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
47<span class="brace">}</span> 47<span class="brace">}</span>
48 48
49<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span> 49<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span>
50 <span class="keyword">fn</span> <span class="function declaration static associated trait">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 50 <span class="keyword">fn</span> <span class="function associated declaration static trait">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
51 <span class="keyword">fn</span> <span class="function declaration associated trait">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 51 <span class="keyword">fn</span> <span class="function associated declaration trait">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
52<span class="brace">}</span> 52<span class="brace">}</span>
53 53
54<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span> 54<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span>
55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated trait">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function associated declaration static trait">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
56 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated trait">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 56 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function associated declaration trait">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
57<span class="brace">}</span> 57<span class="brace">}</span>
58 </code></pre> \ No newline at end of file 58 </code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 6ee6d85fb..638f42c2f 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -50,7 +50,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
50 <span class="comment">// KILLER WHALE</span> 50 <span class="comment">// KILLER WHALE</span>
51 <span class="comment documentation">/// </span><span class="string_literal injected"> Ishmael."</span><span class="semicolon injected">;</span> 51 <span class="comment documentation">/// </span><span class="string_literal injected"> Ishmael."</span><span class="semicolon injected">;</span>
52 <span class="comment documentation">/// ```</span> 52 <span class="comment documentation">/// ```</span>
53 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration associated">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="semicolon">;</span> 53 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant associated declaration">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="semicolon">;</span>
54 54
55 <span class="comment documentation">/// Constructs a new `Foo`.</span> 55 <span class="comment documentation">/// Constructs a new `Foo`.</span>
56 <span class="comment documentation">///</span> 56 <span class="comment documentation">///</span>
@@ -60,7 +60,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
60 <span class="comment documentation">/// #</span><span class="none injected"> </span><span class="attribute attribute injected">#</span><span class="attribute attribute injected">!</span><span class="attribute attribute injected">[</span><span class="function attribute injected">allow</span><span class="parenthesis attribute injected">(</span><span class="attribute attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute attribute injected">]</span> 60 <span class="comment documentation">/// #</span><span class="none injected"> </span><span class="attribute attribute injected">#</span><span class="attribute attribute injected">!</span><span class="attribute attribute injected">[</span><span class="function attribute injected">allow</span><span class="parenthesis attribute injected">(</span><span class="attribute attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute attribute injected">]</span>
61 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="keyword injected">mut</span><span class="none injected"> </span><span class="variable declaration injected mutable">foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> 61 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="keyword injected">mut</span><span class="none injected"> </span><span class="variable declaration injected mutable">foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
62 <span class="comment documentation">/// ```</span> 62 <span class="comment documentation">/// ```</span>
63 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration static associated">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="brace">{</span> 63 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function associated declaration static">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="brace">{</span>
64 <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">bar</span><span class="colon">:</span> <span class="bool_literal">true</span> <span class="brace">}</span> 64 <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">bar</span><span class="colon">:</span> <span class="bool_literal">true</span> <span class="brace">}</span>
65 <span class="brace">}</span> 65 <span class="brace">}</span>
66 66
@@ -94,15 +94,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
94 <span class="comment documentation">/// ```sh</span> 94 <span class="comment documentation">/// ```sh</span>
95 <span class="comment documentation">/// echo 1</span> 95 <span class="comment documentation">/// echo 1</span>
96 <span class="comment documentation">/// ```</span> 96 <span class="comment documentation">/// ```</span>
97 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">foo</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="brace">{</span> 97 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function associated declaration">foo</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="brace">{</span>
98 <span class="bool_literal">true</span> 98 <span class="bool_literal">true</span>
99 <span class="brace">}</span> 99 <span class="brace">}</span>
100<span class="brace">}</span> 100<span class="brace">}</span>
101 101
102<span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span> 102<span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span>
103<span class="comment documentation">/// This function is &gt; </span><span class="function documentation intra_doc_link injected">[`all_the_links`](all_the_links)</span><span class="comment documentation"> &lt;</span> 103<span class="comment documentation">/// This function is &gt; </span><span class="function documentation injected intra_doc_link">[`all_the_links`](all_the_links)</span><span class="comment documentation"> &lt;</span>
104<span class="comment documentation">/// [`noop`](noop) is a macro below</span> 104<span class="comment documentation">/// [`noop`](noop) is a macro below</span>
105<span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Item`]</span><span class="comment documentation"> is a struct in the module </span><span class="module documentation intra_doc_link injected">[`module`]</span> 105<span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[`Item`]</span><span class="comment documentation"> is a struct in the module </span><span class="module documentation injected intra_doc_link">[`module`]</span>
106<span class="comment documentation">///</span> 106<span class="comment documentation">///</span>
107<span class="comment documentation">/// [`Item`]: module::Item</span> 107<span class="comment documentation">/// [`Item`]: module::Item</span>
108<span class="comment documentation">/// [mix_and_match]: ThisShouldntResolve</span> 108<span class="comment documentation">/// [mix_and_match]: ThisShouldntResolve</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 7c6694a27..6202a03ce 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -42,7 +42,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
42<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 42<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
43 <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span> 43 <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
44 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span> 44 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span>
45 <span class="keyword">fn</span> <span class="function declaration static associated trait">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 45 <span class="keyword">fn</span> <span class="function associated declaration static trait">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
46 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> 46 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span>
47 <span class="brace">}</span> 47 <span class="brace">}</span>
48 <span class="brace">}</span><span class="string_literal">"#</span> 48 <span class="brace">}</span><span class="string_literal">"#</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 72910421d..68165bdbf 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -47,7 +47,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
47<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="semicolon">;</span> 47<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="semicolon">;</span>
48 48
49<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="brace">{</span> 49<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="brace">{</span>
50 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration associated unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 50 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function associated declaration unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
51<span class="brace">}</span> 51<span class="brace">}</span>
52 52
53<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="brace">{</span> 53<span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="brace">{</span>
@@ -62,11 +62,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
62<span class="brace">}</span> 62<span class="brace">}</span>
63 63
64<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> 64<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span>
65 <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> 65 <span class="keyword">fn</span> <span class="function associated declaration trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
66<span class="brace">}</span> 66<span class="brace">}</span>
67 67
68<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span> 68<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span>
69 <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 69 <span class="keyword">fn</span> <span class="function associated declaration trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
70<span class="brace">}</span> 70<span class="brace">}</span>
71 71
72<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 72<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index c43bcb691..df4192194 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -67,25 +67,25 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
67<span class="brace">}</span> 67<span class="brace">}</span>
68 68
69<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span> 69<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span>
70 <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span> 70 <span class="keyword">fn</span> <span class="function associated declaration trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span>
71<span class="brace">}</span> 71<span class="brace">}</span>
72 72
73<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span> 73<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span>
74 <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span> 74 <span class="keyword">fn</span> <span class="function associated declaration trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
75 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 75 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
76 <span class="brace">}</span> 76 <span class="brace">}</span>
77<span class="brace">}</span> 77<span class="brace">}</span>
78 78
79<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span> 79<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="brace">{</span>
80 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">Foo</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span> 80 <span class="keyword">fn</span> <span class="function associated declaration">baz</span><span class="parenthesis">(</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">Foo</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
81 <span class="value_param">f</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="self_keyword mutable consuming">self</span><span class="parenthesis">)</span> 81 <span class="value_param">f</span><span class="operator">.</span><span class="function associated consuming">baz</span><span class="parenthesis">(</span><span class="self_keyword consuming mutable">self</span><span class="parenthesis">)</span>
82 <span class="brace">}</span> 82 <span class="brace">}</span>
83 83
84 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span> 84 <span class="keyword">fn</span> <span class="function associated declaration mutable">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
85 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span> 85 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
86 <span class="brace">}</span> 86 <span class="brace">}</span>
87 87
88 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span> 88 <span class="keyword">fn</span> <span class="function associated declaration">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
89 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 89 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
90 <span class="brace">}</span> 90 <span class="brace">}</span>
91<span class="brace">}</span> 91<span class="brace">}</span>
@@ -96,15 +96,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
96<span class="brace">}</span> 96<span class="brace">}</span>
97 97
98<span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="brace">{</span> 98<span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="brace">{</span>
99 <span class="keyword">fn</span> <span class="function declaration associated">baz</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">FooCopy</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span> 99 <span class="keyword">fn</span> <span class="function associated declaration">baz</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">f</span><span class="colon">:</span> <span class="struct">FooCopy</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
100 <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="parenthesis">)</span> 100 <span class="value_param">f</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="self_keyword">self</span><span class="parenthesis">)</span>
101 <span class="brace">}</span> 101 <span class="brace">}</span>
102 102
103 <span class="keyword">fn</span> <span class="function declaration associated">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span> 103 <span class="keyword">fn</span> <span class="function associated declaration mutable">qux</span><span class="parenthesis">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword declaration mutable">self</span><span class="parenthesis">)</span> <span class="brace">{</span>
104 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span> 104 <span class="self_keyword mutable">self</span><span class="operator">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
105 <span class="brace">}</span> 105 <span class="brace">}</span>
106 106
107 <span class="keyword">fn</span> <span class="function declaration associated">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span> 107 <span class="keyword">fn</span> <span class="function associated declaration">quop</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">u32</span> <span class="brace">{</span>
108 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 108 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
109 <span class="brace">}</span> 109 <span class="brace">}</span>
110<span class="brace">}</span> 110<span class="brace">}</span>
@@ -128,7 +128,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
128<span class="brace">}</span> 128<span class="brace">}</span>
129 129
130<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="semicolon">;</span> 130<span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="semicolon">;</span>
131<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="angle">&lt;</span><span class="type_param declaration">F</span><span class="colon">:</span> <span class="trait">Fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="value_param declaration callable">f</span><span class="colon">:</span> <span class="type_param">F</span><span class="parenthesis">)</span> <span class="brace">{</span> 131<span class="keyword">fn</span> <span class="function declaration">baz</span><span class="angle">&lt;</span><span class="type_param declaration">F</span><span class="colon">:</span> <span class="trait">Fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="value_param callable declaration">f</span><span class="colon">:</span> <span class="type_param">F</span><span class="parenthesis">)</span> <span class="brace">{</span>
132 <span class="value_param callable">f</span><span class="parenthesis">(</span><span class="parenthesis">)</span> 132 <span class="value_param callable">f</span><span class="parenthesis">(</span><span class="parenthesis">)</span>
133<span class="brace">}</span> 133<span class="brace">}</span>
134 134
@@ -199,16 +199,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
199 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span> 199 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span>
200 <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span> 200 <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="brace">{</span> <span class="field">x</span><span class="comma">,</span> <span class="field">y</span><span class="colon">:</span> <span class="variable mutable">x</span> <span class="brace">}</span><span class="semicolon">;</span>
201 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> 201 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
202 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> 202 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated mutable">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
203 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function consuming associated">baz</span><span class="parenthesis">(</span><span class="variable consuming">foo2</span><span class="parenthesis">)</span><span class="semicolon">;</span> 203 <span class="variable mutable">foo</span><span class="operator">.</span><span class="function associated consuming">baz</span><span class="parenthesis">(</span><span class="variable consuming">foo2</span><span class="parenthesis">)</span><span class="semicolon">;</span>
204 204
205 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="brace">{</span> <span class="field">x</span> <span class="brace">}</span><span class="semicolon">;</span> 205 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="brace">{</span> <span class="field">x</span> <span class="brace">}</span><span class="semicolon">;</span>
206 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> 206 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">quop</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
207 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function mutable associated">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> 207 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated mutable">qux</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
208 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="variable mutable">copy</span><span class="parenthesis">)</span><span class="semicolon">;</span> 208 <span class="variable mutable">copy</span><span class="operator">.</span><span class="function associated">baz</span><span class="parenthesis">(</span><span class="variable mutable">copy</span><span class="parenthesis">)</span><span class="semicolon">;</span>
209 209
210 <span class="keyword">let</span> <span class="variable declaration callable">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="semicolon">;</span> 210 <span class="keyword">let</span> <span class="variable callable declaration">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="semicolon">;</span>
211 <span class="keyword">let</span> <span class="variable declaration callable">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="semicolon">;</span> 211 <span class="keyword">let</span> <span class="variable callable declaration">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="semicolon">;</span>
212 212
213 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span> 213 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span>
214 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span> 214 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span>
@@ -228,7 +228,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
228<span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span> 228<span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span>
229 229
230<span class="keyword">impl</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="angle">&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">T</span><span class="angle">&gt;</span> <span class="brace">{</span> 230<span class="keyword">impl</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="angle">&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">T</span><span class="angle">&gt;</span> <span class="brace">{</span>
231 <span class="keyword">fn</span> <span class="function declaration associated">and</span><span class="angle">&lt;</span><span class="type_param declaration">U</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">other</span><span class="colon">:</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">U</span><span class="angle">&gt;</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="comma">,</span> <span class="type_param">U</span><span class="parenthesis">)</span><span class="angle">&gt;</span> <span class="brace">{</span> 231 <span class="keyword">fn</span> <span class="function associated declaration">and</span><span class="angle">&lt;</span><span class="type_param declaration">U</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="self_keyword declaration">self</span><span class="comma">,</span> <span class="value_param declaration">other</span><span class="colon">:</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="type_param">U</span><span class="angle">&gt;</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="enum">Option</span><span class="angle">&lt;</span><span class="parenthesis">(</span><span class="type_param">T</span><span class="comma">,</span> <span class="type_param">U</span><span class="parenthesis">)</span><span class="angle">&gt;</span> <span class="brace">{</span>
232 <span class="keyword control">match</span> <span class="value_param">other</span> <span class="brace">{</span> 232 <span class="keyword control">match</span> <span class="value_param">other</span> <span class="brace">{</span>
233 <span class="enum_variant">None</span> <span class="operator">=&gt;</span> <span class="macro">unimplemented!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span> 233 <span class="enum_variant">None</span> <span class="operator">=&gt;</span> <span class="macro">unimplemented!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
234 <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="comma">,</span> 234 <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="comma">,</span>
diff --git a/crates/ide_assists/src/ast_transform.rs b/crates/ide_assists/src/ast_transform.rs
index 4a3ed7783..e5ae718c9 100644
--- a/crates/ide_assists/src/ast_transform.rs
+++ b/crates/ide_assists/src/ast_transform.rs
@@ -3,20 +3,27 @@ use hir::{HirDisplay, PathResolution, SemanticsScope};
3use ide_db::helpers::mod_path_to_ast; 3use ide_db::helpers::mod_path_to_ast;
4use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
5use syntax::{ 5use syntax::{
6 algo::SyntaxRewriter,
7 ast::{self, AstNode}, 6 ast::{self, AstNode},
8 SyntaxNode, 7 ted, SyntaxNode,
9}; 8};
10 9
11pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N { 10pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: &N) {
12 SyntaxRewriter::from_fn(|element| match element { 11 let mut skip_to = None;
13 syntax::SyntaxElement::Node(n) => { 12 for event in node.syntax().preorder() {
14 let replacement = transformer.get_substitution(&n, transformer)?; 13 match event {
15 Some(replacement.into()) 14 syntax::WalkEvent::Enter(node) if skip_to.is_none() => {
15 skip_to = transformer.get_substitution(&node, transformer).zip(Some(node));
16 }
17 syntax::WalkEvent::Enter(_) => (),
18 syntax::WalkEvent::Leave(node) => match &skip_to {
19 Some((replacement, skip_target)) if *skip_target == node => {
20 ted::replace(node, replacement.clone_for_update());
21 skip_to.take();
22 }
23 _ => (),
24 },
16 } 25 }
17 _ => None, 26 }
18 })
19 .rewrite_ast(&node)
20} 27}
21 28
22/// `AstTransform` helps with applying bulk transformations to syntax nodes. 29/// `AstTransform` helps with applying bulk transformations to syntax nodes.
@@ -191,11 +198,9 @@ impl<'a> AstTransform<'a> for QualifyPaths<'a> {
191 let found_path = from.find_use_path(self.source_scope.db.upcast(), def)?; 198 let found_path = from.find_use_path(self.source_scope.db.upcast(), def)?;
192 let mut path = mod_path_to_ast(&found_path); 199 let mut path = mod_path_to_ast(&found_path);
193 200
194 let type_args = p 201 let type_args = p.segment().and_then(|s| s.generic_arg_list());
195 .segment()
196 .and_then(|s| s.generic_arg_list())
197 .map(|arg_list| apply(recur, arg_list));
198 if let Some(type_args) = type_args { 202 if let Some(type_args) = type_args {
203 apply(recur, &type_args);
199 let last_segment = path.segment().unwrap(); 204 let last_segment = path.segment().unwrap();
200 path = path.with_segment(last_segment.with_generic_args(type_args)) 205 path = path.with_segment(last_segment.with_generic_args(type_args))
201 } 206 }
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 49aa70f74..a454a2af3 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -93,7 +93,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
93 93
94 let range = ctx.sema.original_range(&syntax_under_caret).range; 94 let range = ctx.sema.original_range(&syntax_under_caret).range;
95 let group_label = group_label(import_assets.import_candidate()); 95 let group_label = group_label(import_assets.import_candidate());
96 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?; 96 let scope = ImportScope::find_insert_use_container_with_macros(&syntax_under_caret, &ctx.sema)?;
97 for import in proposed_imports { 97 for import in proposed_imports {
98 acc.add_group( 98 acc.add_group(
99 &group_label, 99 &group_label,
@@ -101,9 +101,11 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
101 format!("Import `{}`", import.import_path), 101 format!("Import `{}`", import.import_path),
102 range, 102 range,
103 |builder| { 103 |builder| {
104 let rewriter = 104 let scope = match scope.clone() {
105 insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use); 105 ImportScope::File(it) => ImportScope::File(builder.make_ast_mut(it)),
106 builder.rewrite(rewriter); 106 ImportScope::Module(it) => ImportScope::Module(builder.make_ast_mut(it)),
107 };
108 insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use);
107 }, 109 },
108 ); 110 );
109 } 111 }
diff --git a/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
new file mode 100644
index 000000000..b5b5ada5e
--- /dev/null
+++ b/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -0,0 +1,516 @@
1use ide_db::defs::{Definition, NameRefClass};
2use syntax::{
3 ast::{self, AstNode, GenericParamsOwner, VisibilityOwner},
4 match_ast, SyntaxNode,
5};
6
7use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};
8
9// Assist: convert_tuple_struct_to_named_struct
10//
11// Converts tuple struct to struct with named fields.
12//
13// ```
14// struct Point$0(f32, f32);
15//
16// impl Point {
17// pub fn new(x: f32, y: f32) -> Self {
18// Point(x, y)
19// }
20//
21// pub fn x(&self) -> f32 {
22// self.0
23// }
24//
25// pub fn y(&self) -> f32 {
26// self.1
27// }
28// }
29// ```
30// ->
31// ```
32// struct Point { field1: f32, field2: f32 }
33//
34// impl Point {
35// pub fn new(x: f32, y: f32) -> Self {
36// Point { field1: x, field2: y }
37// }
38//
39// pub fn x(&self) -> f32 {
40// self.field1
41// }
42//
43// pub fn y(&self) -> f32 {
44// self.field2
45// }
46// }
47// ```
48pub(crate) fn convert_tuple_struct_to_named_struct(
49 acc: &mut Assists,
50 ctx: &AssistContext,
51) -> Option<()> {
52 let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
53 let tuple_fields = match strukt.field_list()? {
54 ast::FieldList::TupleFieldList(it) => it,
55 ast::FieldList::RecordFieldList(_) => return None,
56 };
57 let strukt_def = ctx.sema.to_def(&strukt)?;
58
59 let target = strukt.syntax().text_range();
60 acc.add(
61 AssistId("convert_tuple_struct_to_named_struct", AssistKind::RefactorRewrite),
62 "Convert to named struct",
63 target,
64 |edit| {
65 let names = generate_names(tuple_fields.fields());
66 edit_field_references(ctx, edit, tuple_fields.fields(), &names);
67 edit_struct_references(ctx, edit, strukt_def, &names);
68 edit_struct_def(ctx, edit, &strukt, tuple_fields, names);
69 },
70 )
71}
72
73fn edit_struct_def(
74 ctx: &AssistContext,
75 edit: &mut AssistBuilder,
76 strukt: &ast::Struct,
77 tuple_fields: ast::TupleFieldList,
78 names: Vec<ast::Name>,
79) {
80 let record_fields = tuple_fields
81 .fields()
82 .zip(names)
83 .filter_map(|(f, name)| Some(ast::make::record_field(f.visibility(), name, f.ty()?)));
84 let record_fields = ast::make::record_field_list(record_fields);
85 let tuple_fields_text_range = tuple_fields.syntax().text_range();
86
87 edit.edit_file(ctx.frange.file_id);
88
89 if let Some(w) = strukt.where_clause() {
90 edit.delete(w.syntax().text_range());
91 edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
92 edit.insert(tuple_fields_text_range.start(), w.syntax().text());
93 edit.insert(tuple_fields_text_range.start(), ",");
94 edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
95 } else {
96 edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
97 }
98
99 edit.replace(tuple_fields_text_range, record_fields.to_string());
100 strukt.semicolon_token().map(|t| edit.delete(t.text_range()));
101}
102
103fn edit_struct_references(
104 ctx: &AssistContext,
105 edit: &mut AssistBuilder,
106 strukt: hir::Struct,
107 names: &[ast::Name],
108) {
109 let strukt_def = Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(strukt)));
110 let usages = strukt_def.usages(&ctx.sema).include_self_kw_refs(true).all();
111
112 let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> {
113 match_ast! {
114 match node {
115 ast::TupleStructPat(tuple_struct_pat) => {
116 edit.replace(
117 tuple_struct_pat.syntax().text_range(),
118 ast::make::record_pat_with_fields(
119 tuple_struct_pat.path()?,
120 ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
121 |(pat, name)| {
122 ast::make::record_pat_field(
123 ast::make::name_ref(&name.to_string()),
124 pat,
125 )
126 },
127 )),
128 )
129 .to_string(),
130 );
131 },
132 // for tuple struct creations like Foo(42)
133 ast::CallExpr(call_expr) => {
134 let path = call_expr.syntax().descendants().find_map(ast::PathExpr::cast).and_then(|expr| expr.path())?;
135
136 // this also includes method calls like Foo::new(42), we should skip them
137 if let Some(name_ref) = path.segment().and_then(|s| s.name_ref()) {
138 match NameRefClass::classify(&ctx.sema, &name_ref) {
139 Some(NameRefClass::Definition(Definition::SelfType(_))) => {},
140 Some(NameRefClass::Definition(def)) if def == strukt_def => {},
141 _ => return None,
142 };
143 }
144
145 let arg_list = call_expr.syntax().descendants().find_map(ast::ArgList::cast)?;
146
147 edit.replace(
148 call_expr.syntax().text_range(),
149 ast::make::record_expr(
150 path,
151 ast::make::record_expr_field_list(arg_list.args().zip(names).map(
152 |(expr, name)| {
153 ast::make::record_expr_field(
154 ast::make::name_ref(&name.to_string()),
155 Some(expr),
156 )
157 },
158 )),
159 )
160 .to_string(),
161 );
162 },
163 _ => return None,
164 }
165 }
166 Some(())
167 };
168
169 for (file_id, refs) in usages {
170 edit.edit_file(file_id);
171 for r in refs {
172 for node in r.name.syntax().ancestors() {
173 if edit_node(edit, node).is_some() {
174 break;
175 }
176 }
177 }
178 }
179}
180
181fn edit_field_references(
182 ctx: &AssistContext,
183 edit: &mut AssistBuilder,
184 fields: impl Iterator<Item = ast::TupleField>,
185 names: &[ast::Name],
186) {
187 for (field, name) in fields.zip(names) {
188 let field = match ctx.sema.to_def(&field) {
189 Some(it) => it,
190 None => continue,
191 };
192 let def = Definition::Field(field);
193 let usages = def.usages(&ctx.sema).all();
194 for (file_id, refs) in usages {
195 edit.edit_file(file_id);
196 for r in refs {
197 if let Some(name_ref) = r.name.as_name_ref() {
198 edit.replace(name_ref.syntax().text_range(), name.text());
199 }
200 }
201 }
202 }
203}
204
205fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> {
206 fields.enumerate().map(|(i, _)| ast::make::name(&format!("field{}", i + 1))).collect()
207}
208
209#[cfg(test)]
210mod tests {
211 use crate::tests::{check_assist, check_assist_not_applicable};
212
213 use super::*;
214
215 #[test]
216 fn not_applicable_other_than_tuple_struct() {
217 check_assist_not_applicable(
218 convert_tuple_struct_to_named_struct,
219 r#"struct Foo$0 { bar: u32 };"#,
220 );
221 check_assist_not_applicable(convert_tuple_struct_to_named_struct, r#"struct Foo$0;"#);
222 }
223
224 #[test]
225 fn convert_simple_struct() {
226 check_assist(
227 convert_tuple_struct_to_named_struct,
228 r#"
229struct Inner;
230struct A$0(Inner);
231
232impl A {
233 fn new(inner: Inner) -> A {
234 A(inner)
235 }
236
237 fn new_with_default() -> A {
238 A::new(Inner)
239 }
240
241 fn into_inner(self) -> Inner {
242 self.0
243 }
244}"#,
245 r#"
246struct Inner;
247struct A { field1: Inner }
248
249impl A {
250 fn new(inner: Inner) -> A {
251 A { field1: inner }
252 }
253
254 fn new_with_default() -> A {
255 A::new(Inner)
256 }
257
258 fn into_inner(self) -> Inner {
259 self.field1
260 }
261}"#,
262 );
263 }
264
265 #[test]
266 fn convert_struct_referenced_via_self_kw() {
267 check_assist(
268 convert_tuple_struct_to_named_struct,
269 r#"
270struct Inner;
271struct A$0(Inner);
272
273impl A {
274 fn new(inner: Inner) -> Self {
275 Self(inner)
276 }
277
278 fn new_with_default() -> Self {
279 Self::new(Inner)
280 }
281
282 fn into_inner(self) -> Inner {
283 self.0
284 }
285}"#,
286 r#"
287struct Inner;
288struct A { field1: Inner }
289
290impl A {
291 fn new(inner: Inner) -> Self {
292 Self { field1: inner }
293 }
294
295 fn new_with_default() -> Self {
296 Self::new(Inner)
297 }
298
299 fn into_inner(self) -> Inner {
300 self.field1
301 }
302}"#,
303 );
304 }
305
306 #[test]
307 fn convert_destructured_struct() {
308 check_assist(
309 convert_tuple_struct_to_named_struct,
310 r#"
311struct Inner;
312struct A$0(Inner);
313
314impl A {
315 fn into_inner(self) -> Inner {
316 let A(first) = self;
317 first
318 }
319
320 fn into_inner_via_self(self) -> Inner {
321 let Self(first) = self;
322 first
323 }
324}"#,
325 r#"
326struct Inner;
327struct A { field1: Inner }
328
329impl A {
330 fn into_inner(self) -> Inner {
331 let A { field1: first } = self;
332 first
333 }
334
335 fn into_inner_via_self(self) -> Inner {
336 let Self { field1: first } = self;
337 first
338 }
339}"#,
340 );
341 }
342
343 #[test]
344 fn convert_struct_with_visibility() {
345 check_assist(
346 convert_tuple_struct_to_named_struct,
347 r#"
348struct A$0(pub u32, pub(crate) u64);
349
350impl A {
351 fn new() -> A {
352 A(42, 42)
353 }
354
355 fn into_first(self) -> u32 {
356 self.0
357 }
358
359 fn into_second(self) -> u64 {
360 self.1
361 }
362}"#,
363 r#"
364struct A { pub field1: u32, pub(crate) field2: u64 }
365
366impl A {
367 fn new() -> A {
368 A { field1: 42, field2: 42 }
369 }
370
371 fn into_first(self) -> u32 {
372 self.field1
373 }
374
375 fn into_second(self) -> u64 {
376 self.field2
377 }
378}"#,
379 );
380 }
381
382 #[test]
383 fn convert_struct_with_wrapped_references() {
384 check_assist(
385 convert_tuple_struct_to_named_struct,
386 r#"
387struct Inner$0(u32);
388struct Outer(Inner);
389
390impl Outer {
391 fn new() -> Self {
392 Self(Inner(42))
393 }
394
395 fn into_inner(self) -> u32 {
396 (self.0).0
397 }
398
399 fn into_inner_destructed(self) -> u32 {
400 let Outer(Inner(x)) = self;
401 x
402 }
403}"#,
404 r#"
405struct Inner { field1: u32 }
406struct Outer(Inner);
407
408impl Outer {
409 fn new() -> Self {
410 Self(Inner { field1: 42 })
411 }
412
413 fn into_inner(self) -> u32 {
414 (self.0).field1
415 }
416
417 fn into_inner_destructed(self) -> u32 {
418 let Outer(Inner { field1: x }) = self;
419 x
420 }
421}"#,
422 );
423
424 check_assist(
425 convert_tuple_struct_to_named_struct,
426 r#"
427struct Inner(u32);
428struct Outer$0(Inner);
429
430impl Outer {
431 fn new() -> Self {
432 Self(Inner(42))
433 }
434
435 fn into_inner(self) -> u32 {
436 (self.0).0
437 }
438
439 fn into_inner_destructed(self) -> u32 {
440 let Outer(Inner(x)) = self;
441 x
442 }
443}"#,
444 r#"
445struct Inner(u32);
446struct Outer { field1: Inner }
447
448impl Outer {
449 fn new() -> Self {
450 Self { field1: Inner(42) }
451 }
452
453 fn into_inner(self) -> u32 {
454 (self.field1).0
455 }
456
457 fn into_inner_destructed(self) -> u32 {
458 let Outer { field1: Inner(x) } = self;
459 x
460 }
461}"#,
462 );
463 }
464
465 #[test]
466 fn convert_struct_with_multi_file_references() {
467 check_assist(
468 convert_tuple_struct_to_named_struct,
469 r#"
470//- /main.rs
471struct Inner;
472struct A$0(Inner);
473
474mod foo;
475
476//- /foo.rs
477use crate::{A, Inner};
478fn f() {
479 let a = A(Inner);
480}
481"#,
482 r#"
483//- /main.rs
484struct Inner;
485struct A { field1: Inner }
486
487mod foo;
488
489//- /foo.rs
490use crate::{A, Inner};
491fn f() {
492 let a = A { field1: Inner };
493}
494"#,
495 );
496 }
497
498 #[test]
499 fn convert_struct_with_where_clause() {
500 check_assist(
501 convert_tuple_struct_to_named_struct,
502 r#"
503struct Wrap$0<T>(T)
504where
505 T: Display;
506"#,
507 r#"
508struct Wrap<T>
509where
510 T: Display,
511{ field1: T }
512
513"#,
514 );
515 }
516}
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index a8d6355bd..66f274fa7 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -5,7 +5,7 @@ use hir::{Module, ModuleDef, Name, Variant};
5use ide_db::{ 5use ide_db::{
6 defs::Definition, 6 defs::Definition,
7 helpers::{ 7 helpers::{
8 insert_use::{insert_use, ImportScope}, 8 insert_use::{insert_use, ImportScope, InsertUseConfig},
9 mod_path_to_ast, 9 mod_path_to_ast,
10 }, 10 },
11 search::FileReference, 11 search::FileReference,
@@ -13,9 +13,9 @@ use ide_db::{
13}; 13};
14use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
15use syntax::{ 15use syntax::{
16 algo::{find_node_at_offset, SyntaxRewriter}, 16 algo::find_node_at_offset,
17 ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner}, 17 ast::{self, make, AstNode, NameOwner, VisibilityOwner},
18 SourceFile, SyntaxElement, SyntaxNode, T, 18 ted, SyntaxNode, T,
19}; 19};
20 20
21use crate::{AssistContext, AssistId, AssistKind, Assists}; 21use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -62,40 +62,50 @@ pub(crate) fn extract_struct_from_enum_variant(
62 let mut visited_modules_set = FxHashSet::default(); 62 let mut visited_modules_set = FxHashSet::default();
63 let current_module = enum_hir.module(ctx.db()); 63 let current_module = enum_hir.module(ctx.db());
64 visited_modules_set.insert(current_module); 64 visited_modules_set.insert(current_module);
65 let mut def_rewriter = None; 65 // record file references of the file the def resides in, we only want to swap to the edited file in the builder once
66 let mut def_file_references = None;
66 for (file_id, references) in usages { 67 for (file_id, references) in usages {
67 let mut rewriter = SyntaxRewriter::default();
68 let source_file = ctx.sema.parse(file_id);
69 for reference in references {
70 update_reference(
71 ctx,
72 &mut rewriter,
73 reference,
74 &source_file,
75 &enum_module_def,
76 &variant_hir_name,
77 &mut visited_modules_set,
78 );
79 }
80 if file_id == ctx.frange.file_id { 68 if file_id == ctx.frange.file_id {
81 def_rewriter = Some(rewriter); 69 def_file_references = Some(references);
82 continue; 70 continue;
83 } 71 }
84 builder.edit_file(file_id); 72 builder.edit_file(file_id);
85 builder.rewrite(rewriter); 73 let source_file = builder.make_ast_mut(ctx.sema.parse(file_id));
74 let processed = process_references(
75 ctx,
76 &mut visited_modules_set,
77 source_file.syntax(),
78 &enum_module_def,
79 &variant_hir_name,
80 references,
81 );
82 processed.into_iter().for_each(|(path, node, import)| {
83 apply_references(ctx.config.insert_use, path, node, import)
84 });
86 } 85 }
87 let mut rewriter = def_rewriter.unwrap_or_default();
88 update_variant(&mut rewriter, &variant);
89 extract_struct_def(
90 &mut rewriter,
91 &enum_ast,
92 variant_name.clone(),
93 &field_list,
94 &variant.parent_enum().syntax().clone().into(),
95 enum_ast.visibility(),
96 );
97 builder.edit_file(ctx.frange.file_id); 86 builder.edit_file(ctx.frange.file_id);
98 builder.rewrite(rewriter); 87 let source_file = builder.make_ast_mut(ctx.sema.parse(ctx.frange.file_id));
88 let variant = builder.make_ast_mut(variant.clone());
89 if let Some(references) = def_file_references {
90 let processed = process_references(
91 ctx,
92 &mut visited_modules_set,
93 source_file.syntax(),
94 &enum_module_def,
95 &variant_hir_name,
96 references,
97 );
98 processed.into_iter().for_each(|(path, node, import)| {
99 apply_references(ctx.config.insert_use, path, node, import)
100 });
101 }
102
103 let def = create_struct_def(variant_name.clone(), &field_list, enum_ast.visibility());
104 let start_offset = &variant.parent_enum().syntax().clone();
105 ted::insert_raw(ted::Position::before(start_offset), def.syntax());
106 ted::insert_raw(ted::Position::before(start_offset), &make::tokens::blank_line());
107
108 update_variant(&variant);
99 }, 109 },
100 ) 110 )
101} 111}
@@ -136,34 +146,11 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va
136 .any(|(name, _)| name.to_string() == variant_name.to_string()) 146 .any(|(name, _)| name.to_string() == variant_name.to_string())
137} 147}
138 148
139fn insert_import( 149fn create_struct_def(
140 ctx: &AssistContext,
141 rewriter: &mut SyntaxRewriter,
142 scope_node: &SyntaxNode,
143 module: &Module,
144 enum_module_def: &ModuleDef,
145 variant_hir_name: &Name,
146) -> Option<()> {
147 let db = ctx.db();
148 let mod_path =
149 module.find_use_path_prefixed(db, *enum_module_def, ctx.config.insert_use.prefix_kind);
150 if let Some(mut mod_path) = mod_path {
151 mod_path.pop_segment();
152 mod_path.push_segment(variant_hir_name.clone());
153 let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?;
154 *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use);
155 }
156 Some(())
157}
158
159fn extract_struct_def(
160 rewriter: &mut SyntaxRewriter,
161 enum_: &ast::Enum,
162 variant_name: ast::Name, 150 variant_name: ast::Name,
163 field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>, 151 field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
164 start_offset: &SyntaxElement,
165 visibility: Option<ast::Visibility>, 152 visibility: Option<ast::Visibility>,
166) -> Option<()> { 153) -> ast::Struct {
167 let pub_vis = Some(make::visibility_pub()); 154 let pub_vis = Some(make::visibility_pub());
168 let field_list = match field_list { 155 let field_list = match field_list {
169 Either::Left(field_list) => { 156 Either::Left(field_list) => {
@@ -180,65 +167,90 @@ fn extract_struct_def(
180 .into(), 167 .into(),
181 }; 168 };
182 169
183 rewriter.insert_before( 170 make::struct_(visibility, variant_name, None, field_list).clone_for_update()
184 start_offset,
185 make::struct_(visibility, variant_name, None, field_list).syntax(),
186 );
187 rewriter.insert_before(start_offset, &make::tokens::blank_line());
188
189 if let indent_level @ 1..=usize::MAX = IndentLevel::from_node(enum_.syntax()).0 as usize {
190 rewriter
191 .insert_before(start_offset, &make::tokens::whitespace(&" ".repeat(4 * indent_level)));
192 }
193 Some(())
194} 171}
195 172
196fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Option<()> { 173fn update_variant(variant: &ast::Variant) -> Option<()> {
197 let name = variant.name()?; 174 let name = variant.name()?;
198 let tuple_field = make::tuple_field(None, make::ty(&name.text())); 175 let tuple_field = make::tuple_field(None, make::ty(&name.text()));
199 let replacement = make::variant( 176 let replacement = make::variant(
200 name, 177 name,
201 Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))), 178 Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))),
202 ); 179 )
203 rewriter.replace(variant.syntax(), replacement.syntax()); 180 .clone_for_update();
181 ted::replace(variant.syntax(), replacement.syntax());
204 Some(()) 182 Some(())
205} 183}
206 184
207fn update_reference( 185fn apply_references(
186 insert_use_cfg: InsertUseConfig,
187 segment: ast::PathSegment,
188 node: SyntaxNode,
189 import: Option<(ImportScope, hir::ModPath)>,
190) {
191 if let Some((scope, path)) = import {
192 insert_use(&scope, mod_path_to_ast(&path), insert_use_cfg);
193 }
194 ted::insert_raw(
195 ted::Position::before(segment.syntax()),
196 make::path_from_text(&format!("{}", segment)).clone_for_update().syntax(),
197 );
198 ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['(']));
199 ted::insert_raw(ted::Position::after(&node), make::token(T![')']));
200}
201
202fn process_references(
208 ctx: &AssistContext, 203 ctx: &AssistContext,
209 rewriter: &mut SyntaxRewriter, 204 visited_modules: &mut FxHashSet<Module>,
210 reference: FileReference, 205 source_file: &SyntaxNode,
211 source_file: &SourceFile,
212 enum_module_def: &ModuleDef, 206 enum_module_def: &ModuleDef,
213 variant_hir_name: &Name, 207 variant_hir_name: &Name,
214 visited_modules_set: &mut FxHashSet<Module>, 208 refs: Vec<FileReference>,
215) -> Option<()> { 209) -> Vec<(ast::PathSegment, SyntaxNode, Option<(ImportScope, hir::ModPath)>)> {
210 // we have to recollect here eagerly as we are about to edit the tree we need to calculate the changes
211 // and corresponding nodes up front
212 refs.into_iter()
213 .flat_map(|reference| {
214 let (segment, scope_node, module) =
215 reference_to_node(&ctx.sema, source_file, reference)?;
216 if !visited_modules.contains(&module) {
217 let mod_path = module.find_use_path_prefixed(
218 ctx.sema.db,
219 *enum_module_def,
220 ctx.config.insert_use.prefix_kind,
221 );
222 if let Some(mut mod_path) = mod_path {
223 mod_path.pop_segment();
224 mod_path.push_segment(variant_hir_name.clone());
225 let scope = ImportScope::find_insert_use_container(&scope_node)?;
226 visited_modules.insert(module);
227 return Some((segment, scope_node, Some((scope, mod_path))));
228 }
229 }
230 Some((segment, scope_node, None))
231 })
232 .collect()
233}
234
235fn reference_to_node(
236 sema: &hir::Semantics<RootDatabase>,
237 source_file: &SyntaxNode,
238 reference: FileReference,
239) -> Option<(ast::PathSegment, SyntaxNode, hir::Module)> {
216 let offset = reference.range.start(); 240 let offset = reference.range.start();
217 let (segment, expr) = if let Some(path_expr) = 241 if let Some(path_expr) = find_node_at_offset::<ast::PathExpr>(source_file, offset) {
218 find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset)
219 {
220 // tuple variant 242 // tuple variant
221 (path_expr.path()?.segment()?, path_expr.syntax().parent()?) 243 Some((path_expr.path()?.segment()?, path_expr.syntax().parent()?))
222 } else if let Some(record_expr) = 244 } else if let Some(record_expr) = find_node_at_offset::<ast::RecordExpr>(source_file, offset) {
223 find_node_at_offset::<ast::RecordExpr>(source_file.syntax(), offset)
224 {
225 // record variant 245 // record variant
226 (record_expr.path()?.segment()?, record_expr.syntax().clone()) 246 Some((record_expr.path()?.segment()?, record_expr.syntax().clone()))
227 } else { 247 } else {
228 return None; 248 None
229 };
230
231 let module = ctx.sema.scope(&expr).module()?;
232 if !visited_modules_set.contains(&module) {
233 if insert_import(ctx, rewriter, &expr, &module, enum_module_def, variant_hir_name).is_some()
234 {
235 visited_modules_set.insert(module);
236 }
237 } 249 }
238 rewriter.insert_after(segment.syntax(), &make::token(T!['('])); 250 .and_then(|(segment, expr)| {
239 rewriter.insert_after(segment.syntax(), segment.syntax()); 251 let module = sema.scope(&expr).module()?;
240 rewriter.insert_after(&expr, &make::token(T![')'])); 252 Some((segment, expr, module))
241 Some(()) 253 })
242} 254}
243 255
244#[cfg(test)] 256#[cfg(test)]
@@ -345,7 +357,7 @@ mod my_mod {
345 357
346 pub struct MyField(pub u8, pub u8); 358 pub struct MyField(pub u8, pub u8);
347 359
348 pub enum MyEnum { 360pub enum MyEnum {
349 MyField(MyField), 361 MyField(MyField),
350 } 362 }
351 } 363 }
diff --git a/crates/ide_assists/src/handlers/merge_imports.rs b/crates/ide_assists/src/handlers/merge_imports.rs
index 8e0794218..add7b8e37 100644
--- a/crates/ide_assists/src/handlers/merge_imports.rs
+++ b/crates/ide_assists/src/handlers/merge_imports.rs
@@ -1,4 +1,4 @@
1use ide_db::helpers::insert_use::{try_merge_imports, try_merge_trees, MergeBehavior}; 1use ide_db::helpers::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior};
2use syntax::{algo::neighbor, ast, ted, AstNode}; 2use syntax::{algo::neighbor, ast, ted, AstNode};
3 3
4use crate::{ 4use crate::{
diff --git a/crates/ide_assists/src/handlers/reorder_fields.rs b/crates/ide_assists/src/handlers/reorder_fields.rs
index 1a95135ca..e90bbdbcf 100644
--- a/crates/ide_assists/src/handlers/reorder_fields.rs
+++ b/crates/ide_assists/src/handlers/reorder_fields.rs
@@ -83,11 +83,9 @@ fn replace<T: AstNode + PartialEq>(
83 fields: impl Iterator<Item = T>, 83 fields: impl Iterator<Item = T>,
84 sorted_fields: impl IntoIterator<Item = T>, 84 sorted_fields: impl IntoIterator<Item = T>,
85) { 85) {
86 fields.zip(sorted_fields).filter(|(field, sorted)| field != sorted).for_each( 86 fields.zip(sorted_fields).for_each(|(field, sorted_field)| {
87 |(field, sorted_field)| { 87 ted::replace(field.syntax(), sorted_field.syntax().clone_for_update())
88 ted::replace(field.syntax(), sorted_field.syntax().clone_for_update()); 88 });
89 },
90 );
91} 89}
92 90
93fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> { 91fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
diff --git a/crates/ide_assists/src/handlers/reorder_impl.rs b/crates/ide_assists/src/handlers/reorder_impl.rs
index f976e73ad..72d889248 100644
--- a/crates/ide_assists/src/handlers/reorder_impl.rs
+++ b/crates/ide_assists/src/handlers/reorder_impl.rs
@@ -4,9 +4,8 @@ use rustc_hash::FxHashMap;
4use hir::{PathResolution, Semantics}; 4use hir::{PathResolution, Semantics};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use syntax::{ 6use syntax::{
7 algo,
8 ast::{self, NameOwner}, 7 ast::{self, NameOwner},
9 AstNode, 8 ted, AstNode,
10}; 9};
11 10
12use crate::{AssistContext, AssistId, AssistKind, Assists}; 11use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -75,13 +74,16 @@ pub(crate) fn reorder_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
75 } 74 }
76 75
77 let target = items.syntax().text_range(); 76 let target = items.syntax().text_range();
78 acc.add(AssistId("reorder_impl", AssistKind::RefactorRewrite), "Sort methods", target, |edit| { 77 acc.add(
79 let mut rewriter = algo::SyntaxRewriter::default(); 78 AssistId("reorder_impl", AssistKind::RefactorRewrite),
80 for (old, new) in methods.iter().zip(&sorted) { 79 "Sort methods",
81 rewriter.replace(old.syntax(), new.syntax()); 80 target,
82 } 81 |builder| {
83 edit.rewrite(rewriter); 82 methods.into_iter().zip(sorted).for_each(|(old, new)| {
84 }) 83 ted::replace(builder.make_ast_mut(old).syntax(), new.clone_for_update().syntax())
84 });
85 },
86 )
85} 87}
86 88
87fn compute_method_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> { 89fn compute_method_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
index 36d2e0331..99ba79860 100644
--- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -1,5 +1,5 @@
1use ide_db::helpers::insert_use::{insert_use, ImportScope}; 1use ide_db::helpers::insert_use::{insert_use, ImportScope};
2use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode}; 2use syntax::{ast, match_ast, ted, AstNode, SyntaxNode};
3 3
4use crate::{AssistContext, AssistId, AssistKind, Assists}; 4use crate::{AssistContext, AssistId, AssistKind, Assists};
5 5
@@ -31,7 +31,7 @@ pub(crate) fn replace_qualified_name_with_use(
31 } 31 }
32 32
33 let target = path.syntax().text_range(); 33 let target = path.syntax().text_range();
34 let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?; 34 let scope = ImportScope::find_insert_use_container_with_macros(path.syntax(), &ctx.sema)?;
35 let syntax = scope.as_syntax_node(); 35 let syntax = scope.as_syntax_node();
36 acc.add( 36 acc.add(
37 AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite), 37 AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
@@ -40,18 +40,17 @@ pub(crate) fn replace_qualified_name_with_use(
40 |builder| { 40 |builder| {
41 // Now that we've brought the name into scope, re-qualify all paths that could be 41 // Now that we've brought the name into scope, re-qualify all paths that could be
42 // affected (that is, all paths inside the node we added the `use` to). 42 // affected (that is, all paths inside the node we added the `use` to).
43 let mut rewriter = SyntaxRewriter::default(); 43 let syntax = builder.make_mut(syntax.clone());
44 shorten_paths(&mut rewriter, syntax.clone(), &path);
45 if let Some(ref import_scope) = ImportScope::from(syntax.clone()) { 44 if let Some(ref import_scope) = ImportScope::from(syntax.clone()) {
46 rewriter += insert_use(import_scope, path, ctx.config.insert_use); 45 shorten_paths(&syntax, &path.clone_for_update());
47 builder.rewrite(rewriter); 46 insert_use(import_scope, path, ctx.config.insert_use);
48 } 47 }
49 }, 48 },
50 ) 49 )
51} 50}
52 51
53/// Adds replacements to `re` that shorten `path` in all descendants of `node`. 52/// Adds replacements to `re` that shorten `path` in all descendants of `node`.
54fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: &ast::Path) { 53fn shorten_paths(node: &SyntaxNode, path: &ast::Path) {
55 for child in node.children() { 54 for child in node.children() {
56 match_ast! { 55 match_ast! {
57 match child { 56 match child {
@@ -60,34 +59,26 @@ fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path:
60 ast::Use(_it) => continue, 59 ast::Use(_it) => continue,
61 // Don't descend into submodules, they don't have the same `use` items in scope. 60 // Don't descend into submodules, they don't have the same `use` items in scope.
62 ast::Module(_it) => continue, 61 ast::Module(_it) => continue,
63 62 ast::Path(p) => if maybe_replace_path(p.clone(), path.clone()).is_none() {
64 ast::Path(p) => { 63 shorten_paths(p.syntax(), path);
65 match maybe_replace_path(rewriter, p.clone(), path.clone()) {
66 Some(()) => {},
67 None => shorten_paths(rewriter, p.syntax().clone(), path),
68 }
69 }, 64 },
70 _ => shorten_paths(rewriter, child, path), 65 _ => shorten_paths(&child, path),
71 } 66 }
72 } 67 }
73 } 68 }
74} 69}
75 70
76fn maybe_replace_path( 71fn maybe_replace_path(path: ast::Path, target: ast::Path) -> Option<()> {
77 rewriter: &mut SyntaxRewriter<'static>,
78 path: ast::Path,
79 target: ast::Path,
80) -> Option<()> {
81 if !path_eq(path.clone(), target) { 72 if !path_eq(path.clone(), target) {
82 return None; 73 return None;
83 } 74 }
84 75
85 // Shorten `path`, leaving only its last segment. 76 // Shorten `path`, leaving only its last segment.
86 if let Some(parent) = path.qualifier() { 77 if let Some(parent) = path.qualifier() {
87 rewriter.delete(parent.syntax()); 78 ted::remove(parent.syntax());
88 } 79 }
89 if let Some(double_colon) = path.coloncolon_token() { 80 if let Some(double_colon) = path.coloncolon_token() {
90 rewriter.delete(&double_colon); 81 ted::remove(&double_colon);
91 } 82 }
92 83
93 Some(()) 84 Some(())
@@ -150,6 +141,7 @@ Debug
150 ", 141 ",
151 ); 142 );
152 } 143 }
144
153 #[test] 145 #[test]
154 fn test_replace_add_use_no_anchor_with_item_below() { 146 fn test_replace_add_use_no_anchor_with_item_below() {
155 check_assist( 147 check_assist(
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index 8996c1b61..88ae5c9a9 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -120,6 +120,7 @@ mod handlers {
120 mod convert_comment_block; 120 mod convert_comment_block;
121 mod convert_iter_for_each_to_for; 121 mod convert_iter_for_each_to_for;
122 mod convert_into_to_from; 122 mod convert_into_to_from;
123 mod convert_tuple_struct_to_named_struct;
123 mod early_return; 124 mod early_return;
124 mod expand_glob_import; 125 mod expand_glob_import;
125 mod extract_function; 126 mod extract_function;
@@ -190,6 +191,7 @@ mod handlers {
190 convert_comment_block::convert_comment_block, 191 convert_comment_block::convert_comment_block,
191 convert_iter_for_each_to_for::convert_iter_for_each_to_for, 192 convert_iter_for_each_to_for::convert_iter_for_each_to_for,
192 convert_into_to_from::convert_into_to_from, 193 convert_into_to_from::convert_into_to_from,
194 convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
193 early_return::convert_to_guarded_return, 195 early_return::convert_to_guarded_return,
194 expand_glob_import::expand_glob_import, 196 expand_glob_import::expand_glob_import,
195 extract_struct_from_enum_variant::extract_struct_from_enum_variant, 197 extract_struct_from_enum_variant::extract_struct_from_enum_variant,
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index 49533e7d2..6f4f97361 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -4,10 +4,7 @@ use expect_test::expect;
4use hir::Semantics; 4use hir::Semantics;
5use ide_db::{ 5use ide_db::{
6 base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}, 6 base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt},
7 helpers::{ 7 helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap},
8 insert_use::{InsertUseConfig, MergeBehavior},
9 SnippetCap,
10 },
11 source_change::FileSystemEdit, 8 source_change::FileSystemEdit,
12 RootDatabase, 9 RootDatabase,
13}; 10};
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index 41559b43a..59bcef8fb 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -292,6 +292,47 @@ fn main() {
292} 292}
293 293
294#[test] 294#[test]
295fn doctest_convert_tuple_struct_to_named_struct() {
296 check_doc_test(
297 "convert_tuple_struct_to_named_struct",
298 r#####"
299struct Point$0(f32, f32);
300
301impl Point {
302 pub fn new(x: f32, y: f32) -> Self {
303 Point(x, y)
304 }
305
306 pub fn x(&self) -> f32 {
307 self.0
308 }
309
310 pub fn y(&self) -> f32 {
311 self.1
312 }
313}
314"#####,
315 r#####"
316struct Point { field1: f32, field2: f32 }
317
318impl Point {
319 pub fn new(x: f32, y: f32) -> Self {
320 Point { field1: x, field2: y }
321 }
322
323 pub fn x(&self) -> f32 {
324 self.field1
325 }
326
327 pub fn y(&self) -> f32 {
328 self.field2
329 }
330}
331"#####,
332 )
333}
334
335#[test]
295fn doctest_expand_glob_import() { 336fn doctest_expand_glob_import() {
296 check_doc_test( 337 check_doc_test(
297 "expand_glob_import", 338 "expand_glob_import",
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs
index d67524937..5a90ad715 100644
--- a/crates/ide_assists/src/utils.rs
+++ b/crates/ide_assists/src/utils.rs
@@ -140,7 +140,8 @@ pub fn add_trait_assoc_items_to_impl(
140 140
141 let items = items 141 let items = items
142 .into_iter() 142 .into_iter()
143 .map(|it| ast_transform::apply(&*ast_transform, it)) 143 .map(|it| it.clone_for_update())
144 .inspect(|it| ast_transform::apply(&*ast_transform, it))
144 .map(|it| match it { 145 .map(|it| match it {
145 ast::AssocItem::Fn(def) => ast::AssocItem::Fn(add_body(def)), 146 ast::AssocItem::Fn(def) => ast::AssocItem::Fn(add_body(def)),
146 ast::AssocItem::TypeAlias(def) => ast::AssocItem::TypeAlias(def.remove_bounds()), 147 ast::AssocItem::TypeAlias(def) => ast::AssocItem::TypeAlias(def.remove_bounds()),
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 8e211ae1e..9d5b61562 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -132,7 +132,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
132 132
133 let user_input_lowercased = potential_import_name.to_lowercase(); 133 let user_input_lowercased = potential_import_name.to_lowercase();
134 let import_assets = import_assets(ctx, potential_import_name)?; 134 let import_assets = import_assets(ctx, potential_import_name)?;
135 let import_scope = ImportScope::find_insert_use_container( 135 let import_scope = ImportScope::find_insert_use_container_with_macros(
136 position_for_import(ctx, Some(import_assets.import_candidate()))?, 136 position_for_import(ctx, Some(import_assets.import_candidate()))?,
137 &ctx.sema, 137 &ctx.sema,
138 )?; 138 )?;
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 16991b688..99edb9499 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -377,11 +377,11 @@ impl ImportEdit {
377 pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> { 377 pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> {
378 let _p = profile::span("ImportEdit::to_text_edit"); 378 let _p = profile::span("ImportEdit::to_text_edit");
379 379
380 let rewriter = 380 let new_ast = self.scope.clone_for_update();
381 insert_use::insert_use(&self.scope, mod_path_to_ast(&self.import.import_path), cfg); 381 insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), cfg);
382 let old_ast = rewriter.rewrite_root()?;
383 let mut import_insert = TextEdit::builder(); 382 let mut import_insert = TextEdit::builder();
384 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert); 383 algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node())
384 .into_text_edit(&mut import_insert);
385 385
386 Some(import_insert.finish()) 386 Some(import_insert.finish())
387 } 387 }
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 6f3d5c5c5..e32633565 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -179,7 +179,7 @@ pub fn resolve_completion_edits(
179) -> Option<Vec<TextEdit>> { 179) -> Option<Vec<TextEdit>> {
180 let ctx = CompletionContext::new(db, position, config)?; 180 let ctx = CompletionContext::new(db, position, config)?;
181 let position_for_import = position_for_import(&ctx, None)?; 181 let position_for_import = position_for_import(&ctx, None)?;
182 let scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?; 182 let scope = ImportScope::find_insert_use_container_with_macros(position_for_import, &ctx.sema)?;
183 183
184 let current_module = ctx.sema.scope(position_for_import).module()?; 184 let current_module = ctx.sema.scope(position_for_import).module()?;
185 let current_crate = current_module.krate(); 185 let current_crate = current_module.krate();
diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/test_utils.rs
index 9da844031..c9857ec5f 100644
--- a/crates/ide_completion/src/test_utils.rs
+++ b/crates/ide_completion/src/test_utils.rs
@@ -3,10 +3,7 @@
3use hir::{PrefixKind, Semantics}; 3use hir::{PrefixKind, Semantics};
4use ide_db::{ 4use ide_db::{
5 base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, 5 base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
6 helpers::{ 6 helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap},
7 insert_use::{InsertUseConfig, MergeBehavior},
8 SnippetCap,
9 },
10 RootDatabase, 7 RootDatabase,
11}; 8};
12use itertools::Itertools; 9use itertools::Itertools;
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index 720de0d1f..21b48237a 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -1,6 +1,7 @@
1//! A module with ide helpers for high-level ide features. 1//! A module with ide helpers for high-level ide features.
2pub mod insert_use;
3pub mod import_assets; 2pub mod import_assets;
3pub mod insert_use;
4pub mod merge_imports;
4pub mod rust_doc; 5pub mod rust_doc;
5 6
6use std::collections::VecDeque; 7use std::collections::VecDeque;
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index be3a22725..55cdc4da3 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -1,19 +1,17 @@
1//! Handle syntactic aspects of inserting a new `use`. 1//! Handle syntactic aspects of inserting a new `use`.
2use std::{cmp::Ordering, iter::successors}; 2use std::cmp::Ordering;
3 3
4use hir::Semantics; 4use hir::Semantics;
5use itertools::{EitherOrBoth, Itertools};
6use syntax::{ 5use syntax::{
7 algo::SyntaxRewriter, 6 algo,
8 ast::{ 7 ast::{self, make, AstNode, PathSegmentKind},
9 self, 8 ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
10 edit::{AstNodeEdit, IndentLevel},
11 make, AstNode, AttrsOwner, PathSegmentKind, VisibilityOwner,
12 },
13 AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken,
14}; 9};
15 10
16use crate::RootDatabase; 11use crate::{
12 helpers::merge_imports::{try_merge_imports, use_tree_path_cmp, MergeBehavior},
13 RootDatabase,
14};
17 15
18pub use hir::PrefixKind; 16pub use hir::PrefixKind;
19 17
@@ -42,13 +40,18 @@ impl ImportScope {
42 } 40 }
43 41
44 /// Determines the containing syntax node in which to insert a `use` statement affecting `position`. 42 /// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
45 pub fn find_insert_use_container( 43 pub fn find_insert_use_container_with_macros(
46 position: &SyntaxNode, 44 position: &SyntaxNode,
47 sema: &Semantics<'_, RootDatabase>, 45 sema: &Semantics<'_, RootDatabase>,
48 ) -> Option<Self> { 46 ) -> Option<Self> {
49 sema.ancestors_with_macros(position.clone()).find_map(Self::from) 47 sema.ancestors_with_macros(position.clone()).find_map(Self::from)
50 } 48 }
51 49
50 /// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
51 pub fn find_insert_use_container(position: &SyntaxNode) -> Option<Self> {
52 std::iter::successors(Some(position.clone()), SyntaxNode::parent).find_map(Self::from)
53 }
54
52 pub fn as_syntax_node(&self) -> &SyntaxNode { 55 pub fn as_syntax_node(&self) -> &SyntaxNode {
53 match self { 56 match self {
54 ImportScope::File(file) => file.syntax(), 57 ImportScope::File(file) => file.syntax(),
@@ -56,434 +59,32 @@ impl ImportScope {
56 } 59 }
57 } 60 }
58 61
59 fn indent_level(&self) -> IndentLevel { 62 pub fn clone_for_update(&self) -> Self {
60 match self { 63 match self {
61 ImportScope::File(file) => file.indent_level(), 64 ImportScope::File(file) => ImportScope::File(file.clone_for_update()),
62 ImportScope::Module(item_list) => item_list.indent_level() + 1, 65 ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()),
63 } 66 }
64 } 67 }
65
66 fn first_insert_pos(&self) -> (InsertPosition<SyntaxElement>, AddBlankLine) {
67 match self {
68 ImportScope::File(_) => (InsertPosition::First, AddBlankLine::AfterTwice),
69 // don't insert the imports before the item list's opening curly brace
70 ImportScope::Module(item_list) => item_list
71 .l_curly_token()
72 .map(|b| (InsertPosition::After(b.into()), AddBlankLine::Around))
73 .unwrap_or((InsertPosition::First, AddBlankLine::AfterTwice)),
74 }
75 }
76
77 fn insert_pos_after_last_inner_element(&self) -> (InsertPosition<SyntaxElement>, AddBlankLine) {
78 self.as_syntax_node()
79 .children_with_tokens()
80 .filter(|child| match child {
81 NodeOrToken::Node(node) => is_inner_attribute(node.clone()),
82 NodeOrToken::Token(token) => is_inner_comment(token.clone()),
83 })
84 .last()
85 .map(|last_inner_element| {
86 (InsertPosition::After(last_inner_element), AddBlankLine::BeforeTwice)
87 })
88 .unwrap_or_else(|| self.first_insert_pos())
89 }
90}
91
92fn is_inner_attribute(node: SyntaxNode) -> bool {
93 ast::Attr::cast(node).map(|attr| attr.kind()) == Some(ast::AttrKind::Inner)
94}
95
96fn is_inner_comment(token: SyntaxToken) -> bool {
97 ast::Comment::cast(token).and_then(|comment| comment.kind().doc)
98 == Some(ast::CommentPlacement::Inner)
99} 68}
100 69
101/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. 70/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
102pub fn insert_use<'a>( 71pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) {
103 scope: &ImportScope,
104 path: ast::Path,
105 cfg: InsertUseConfig,
106) -> SyntaxRewriter<'a> {
107 let _p = profile::span("insert_use"); 72 let _p = profile::span("insert_use");
108 let mut rewriter = SyntaxRewriter::default(); 73 let use_item =
109 let use_item = make::use_(None, make::use_tree(path.clone(), None, None, false)); 74 make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update();
110 // merge into existing imports if possible 75 // merge into existing imports if possible
111 if let Some(mb) = cfg.merge { 76 if let Some(mb) = cfg.merge {
112 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { 77 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) {
113 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { 78 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) {
114 rewriter.replace(existing_use.syntax(), merged.syntax()); 79 ted::replace(existing_use.syntax(), merged.syntax());
115 return rewriter; 80 return;
116 } 81 }
117 } 82 }
118 } 83 }
119 84
120 // either we weren't allowed to merge or there is no import that fits the merge conditions 85 // either we weren't allowed to merge or there is no import that fits the merge conditions
121 // so look for the place we have to insert to 86 // so look for the place we have to insert to
122 let (insert_position, add_blank) = find_insert_position(scope, path, cfg.group); 87 insert_use_(scope, path, cfg.group, use_item);
123
124 let indent = if let ident_level @ 1..=usize::MAX = scope.indent_level().0 as usize {
125 Some(make::tokens::whitespace(&" ".repeat(4 * ident_level)).into())
126 } else {
127 None
128 };
129
130 let to_insert: Vec<SyntaxElement> = {
131 let mut buf = Vec::new();
132
133 match add_blank {
134 AddBlankLine::Before | AddBlankLine::Around => {
135 buf.push(make::tokens::single_newline().into())
136 }
137 AddBlankLine::BeforeTwice => buf.push(make::tokens::blank_line().into()),
138 _ => (),
139 }
140
141 if add_blank.has_before() {
142 if let Some(indent) = indent.clone() {
143 cov_mark::hit!(insert_use_indent_before);
144 buf.push(indent);
145 }
146 }
147
148 buf.push(use_item.syntax().clone().into());
149
150 match add_blank {
151 AddBlankLine::After | AddBlankLine::Around => {
152 buf.push(make::tokens::single_newline().into())
153 }
154 AddBlankLine::AfterTwice => buf.push(make::tokens::blank_line().into()),
155 _ => (),
156 }
157
158 // only add indentation *after* our stuff if there's another node directly after it
159 if add_blank.has_after() && matches!(insert_position, InsertPosition::Before(_)) {
160 if let Some(indent) = indent {
161 cov_mark::hit!(insert_use_indent_after);
162 buf.push(indent);
163 }
164 } else if add_blank.has_after() && matches!(insert_position, InsertPosition::After(_)) {
165 cov_mark::hit!(insert_use_no_indent_after);
166 }
167
168 buf
169 };
170
171 match insert_position {
172 InsertPosition::First => {
173 rewriter.insert_many_as_first_children(scope.as_syntax_node(), to_insert)
174 }
175 InsertPosition::Last => return rewriter, // actually unreachable
176 InsertPosition::Before(anchor) => rewriter.insert_many_before(&anchor, to_insert),
177 InsertPosition::After(anchor) => rewriter.insert_many_after(&anchor, to_insert),
178 }
179 rewriter
180}
181
182fn eq_visibility(vis0: Option<ast::Visibility>, vis1: Option<ast::Visibility>) -> bool {
183 match (vis0, vis1) {
184 (None, None) => true,
185 // FIXME: Don't use the string representation to check for equality
186 // spaces inside of the node would break this comparison
187 (Some(vis0), Some(vis1)) => vis0.to_string() == vis1.to_string(),
188 _ => false,
189 }
190}
191
192fn eq_attrs(
193 attrs0: impl Iterator<Item = ast::Attr>,
194 attrs1: impl Iterator<Item = ast::Attr>,
195) -> bool {
196 let attrs0 = attrs0.map(|attr| attr.to_string());
197 let attrs1 = attrs1.map(|attr| attr.to_string());
198 attrs0.eq(attrs1)
199}
200
201pub fn try_merge_imports(
202 lhs: &ast::Use,
203 rhs: &ast::Use,
204 merge_behavior: MergeBehavior,
205) -> Option<ast::Use> {
206 // don't merge imports with different visibilities
207 if !eq_visibility(lhs.visibility(), rhs.visibility()) {
208 return None;
209 }
210 if !eq_attrs(lhs.attrs(), rhs.attrs()) {
211 return None;
212 }
213
214 let lhs_tree = lhs.use_tree()?;
215 let rhs_tree = rhs.use_tree()?;
216 let merged = try_merge_trees(&lhs_tree, &rhs_tree, merge_behavior)?;
217 Some(lhs.with_use_tree(merged).clone_for_update())
218}
219
220pub fn try_merge_trees(
221 lhs: &ast::UseTree,
222 rhs: &ast::UseTree,
223 merge: MergeBehavior,
224) -> Option<ast::UseTree> {
225 let lhs_path = lhs.path()?;
226 let rhs_path = rhs.path()?;
227
228 let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;
229 let (lhs, rhs) = if is_simple_path(lhs)
230 && is_simple_path(rhs)
231 && lhs_path == lhs_prefix
232 && rhs_path == rhs_prefix
233 {
234 (lhs.clone(), rhs.clone())
235 } else {
236 (lhs.split_prefix(&lhs_prefix), rhs.split_prefix(&rhs_prefix))
237 };
238 recursive_merge(&lhs, &rhs, merge).map(|it| it.clone_for_update())
239}
240
241/// Recursively "zips" together lhs and rhs.
242fn recursive_merge(
243 lhs: &ast::UseTree,
244 rhs: &ast::UseTree,
245 merge: MergeBehavior,
246) -> Option<ast::UseTree> {
247 let mut use_trees = lhs
248 .use_tree_list()
249 .into_iter()
250 .flat_map(|list| list.use_trees())
251 // we use Option here to early return from this function(this is not the same as a `filter` op)
252 .map(|tree| match merge.is_tree_allowed(&tree) {
253 true => Some(tree),
254 false => None,
255 })
256 .collect::<Option<Vec<_>>>()?;
257 use_trees.sort_unstable_by(|a, b| path_cmp_for_sort(a.path(), b.path()));
258 for rhs_t in rhs.use_tree_list().into_iter().flat_map(|list| list.use_trees()) {
259 if !merge.is_tree_allowed(&rhs_t) {
260 return None;
261 }
262 let rhs_path = rhs_t.path();
263 match use_trees.binary_search_by(|lhs_t| {
264 let (lhs_t, rhs_t) = match lhs_t
265 .path()
266 .zip(rhs_path.clone())
267 .and_then(|(lhs, rhs)| common_prefix(&lhs, &rhs))
268 {
269 Some((lhs_p, rhs_p)) => (lhs_t.split_prefix(&lhs_p), rhs_t.split_prefix(&rhs_p)),
270 None => (lhs_t.clone(), rhs_t.clone()),
271 };
272
273 path_cmp_bin_search(lhs_t.path(), rhs_t.path())
274 }) {
275 Ok(idx) => {
276 let lhs_t = &mut use_trees[idx];
277 let lhs_path = lhs_t.path()?;
278 let rhs_path = rhs_path?;
279 let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;
280 if lhs_prefix == lhs_path && rhs_prefix == rhs_path {
281 let tree_is_self = |tree: ast::UseTree| {
282 tree.path().as_ref().map(path_is_self).unwrap_or(false)
283 };
284 // check if only one of the two trees has a tree list, and whether that then contains `self` or not.
285 // If this is the case we can skip this iteration since the path without the list is already included in the other one via `self`
286 let tree_contains_self = |tree: &ast::UseTree| {
287 tree.use_tree_list()
288 .map(|tree_list| tree_list.use_trees().any(tree_is_self))
289 .unwrap_or(false)
290 };
291 match (tree_contains_self(&lhs_t), tree_contains_self(&rhs_t)) {
292 (true, false) => continue,
293 (false, true) => {
294 *lhs_t = rhs_t;
295 continue;
296 }
297 _ => (),
298 }
299
300 // glob imports arent part of the use-tree lists so we need to special handle them here as well
301 // this special handling is only required for when we merge a module import into a glob import of said module
302 // see the `merge_self_glob` or `merge_mod_into_glob` tests
303 if lhs_t.star_token().is_some() || rhs_t.star_token().is_some() {
304 *lhs_t = make::use_tree(
305 make::path_unqualified(make::path_segment_self()),
306 None,
307 None,
308 false,
309 );
310 use_trees.insert(idx, make::glob_use_tree());
311 continue;
312 }
313
314 if lhs_t.use_tree_list().is_none() && rhs_t.use_tree_list().is_none() {
315 continue;
316 }
317 }
318 let lhs = lhs_t.split_prefix(&lhs_prefix);
319 let rhs = rhs_t.split_prefix(&rhs_prefix);
320 match recursive_merge(&lhs, &rhs, merge) {
321 Some(use_tree) => use_trees[idx] = use_tree,
322 None => return None,
323 }
324 }
325 Err(_)
326 if merge == MergeBehavior::Last
327 && use_trees.len() > 0
328 && rhs_t.use_tree_list().is_some() =>
329 {
330 return None
331 }
332 Err(idx) => {
333 use_trees.insert(idx, rhs_t);
334 }
335 }
336 }
337 Some(lhs.with_use_tree_list(make::use_tree_list(use_trees)))
338}
339
340/// Traverses both paths until they differ, returning the common prefix of both.
341fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> {
342 let mut res = None;
343 let mut lhs_curr = first_path(&lhs);
344 let mut rhs_curr = first_path(&rhs);
345 loop {
346 match (lhs_curr.segment(), rhs_curr.segment()) {
347 (Some(lhs), Some(rhs)) if lhs.syntax().text() == rhs.syntax().text() => (),
348 _ => break res,
349 }
350 res = Some((lhs_curr.clone(), rhs_curr.clone()));
351
352 match lhs_curr.parent_path().zip(rhs_curr.parent_path()) {
353 Some((lhs, rhs)) => {
354 lhs_curr = lhs;
355 rhs_curr = rhs;
356 }
357 _ => break res,
358 }
359 }
360}
361
362fn is_simple_path(use_tree: &ast::UseTree) -> bool {
363 use_tree.use_tree_list().is_none() && use_tree.star_token().is_none()
364}
365
366fn path_is_self(path: &ast::Path) -> bool {
367 path.segment().and_then(|seg| seg.self_token()).is_some() && path.qualifier().is_none()
368}
369
370#[inline]
371fn first_segment(path: &ast::Path) -> Option<ast::PathSegment> {
372 first_path(path).segment()
373}
374
375fn first_path(path: &ast::Path) -> ast::Path {
376 successors(Some(path.clone()), ast::Path::qualifier).last().unwrap()
377}
378
379fn segment_iter(path: &ast::Path) -> impl Iterator<Item = ast::PathSegment> + Clone {
380 // cant make use of SyntaxNode::siblings, because the returned Iterator is not clone
381 successors(first_segment(path), |p| p.parent_path().parent_path().and_then(|p| p.segment()))
382}
383
384fn path_len(path: ast::Path) -> usize {
385 segment_iter(&path).count()
386}
387
388/// Orders paths in the following way:
389/// the sole self token comes first, after that come uppercase identifiers, then lowercase identifiers
390// FIXME: rustfmt sorts lowercase idents before uppercase, in general we want to have the same ordering rustfmt has
391// which is `self` and `super` first, then identifier imports with lowercase ones first, then glob imports and at last list imports.
392// Example foo::{self, foo, baz, Baz, Qux, *, {Bar}}
393fn path_cmp_for_sort(a: Option<ast::Path>, b: Option<ast::Path>) -> Ordering {
394 match (a, b) {
395 (None, None) => Ordering::Equal,
396 (None, Some(_)) => Ordering::Less,
397 (Some(_), None) => Ordering::Greater,
398 (Some(ref a), Some(ref b)) => match (path_is_self(a), path_is_self(b)) {
399 (true, true) => Ordering::Equal,
400 (true, false) => Ordering::Less,
401 (false, true) => Ordering::Greater,
402 (false, false) => path_cmp_short(a, b),
403 },
404 }
405}
406
407/// Path comparison func for binary searching for merging.
408fn path_cmp_bin_search(lhs: Option<ast::Path>, rhs: Option<ast::Path>) -> Ordering {
409 match (lhs.as_ref().and_then(first_segment), rhs.as_ref().and_then(first_segment)) {
410 (None, None) => Ordering::Equal,
411 (None, Some(_)) => Ordering::Less,
412 (Some(_), None) => Ordering::Greater,
413 (Some(ref a), Some(ref b)) => path_segment_cmp(a, b),
414 }
415}
416
417/// Short circuiting comparison, if both paths are equal until one of them ends they are considered
418/// equal
419fn path_cmp_short(a: &ast::Path, b: &ast::Path) -> Ordering {
420 let a = segment_iter(a);
421 let b = segment_iter(b);
422 // cmp_by would be useful for us here but that is currently unstable
423 // cmp doesnt work due the lifetimes on text's return type
424 a.zip(b)
425 .find_map(|(a, b)| match path_segment_cmp(&a, &b) {
426 Ordering::Equal => None,
427 ord => Some(ord),
428 })
429 .unwrap_or(Ordering::Equal)
430}
431
432/// Compares to paths, if one ends earlier than the other the has_tl parameters decide which is
433/// greater as a a path that has a tree list should be greater, while one that just ends without
434/// a tree list should be considered less.
435fn use_tree_path_cmp(a: &ast::Path, a_has_tl: bool, b: &ast::Path, b_has_tl: bool) -> Ordering {
436 let a_segments = segment_iter(a);
437 let b_segments = segment_iter(b);
438 // cmp_by would be useful for us here but that is currently unstable
439 // cmp doesnt work due the lifetimes on text's return type
440 a_segments
441 .zip_longest(b_segments)
442 .find_map(|zipped| match zipped {
443 EitherOrBoth::Both(ref a, ref b) => match path_segment_cmp(a, b) {
444 Ordering::Equal => None,
445 ord => Some(ord),
446 },
447 EitherOrBoth::Left(_) if !b_has_tl => Some(Ordering::Greater),
448 EitherOrBoth::Left(_) => Some(Ordering::Less),
449 EitherOrBoth::Right(_) if !a_has_tl => Some(Ordering::Less),
450 EitherOrBoth::Right(_) => Some(Ordering::Greater),
451 })
452 .unwrap_or(Ordering::Equal)
453}
454
455fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering {
456 let a = a.kind().and_then(|kind| match kind {
457 PathSegmentKind::Name(name_ref) => Some(name_ref),
458 _ => None,
459 });
460 let b = b.kind().and_then(|kind| match kind {
461 PathSegmentKind::Name(name_ref) => Some(name_ref),
462 _ => None,
463 });
464 a.as_ref().map(ast::NameRef::text).cmp(&b.as_ref().map(ast::NameRef::text))
465}
466
467/// What type of merges are allowed.
468#[derive(Copy, Clone, Debug, PartialEq, Eq)]
469pub enum MergeBehavior {
470 /// Merge everything together creating deeply nested imports.
471 Full,
472 /// Only merge the last import level, doesn't allow import nesting.
473 Last,
474}
475
476impl MergeBehavior {
477 #[inline]
478 fn is_tree_allowed(&self, tree: &ast::UseTree) -> bool {
479 match self {
480 MergeBehavior::Full => true,
481 // only simple single segment paths are allowed
482 MergeBehavior::Last => {
483 tree.use_tree_list().is_none() && tree.path().map(path_len) <= Some(1)
484 }
485 }
486 }
487} 88}
488 89
489#[derive(Eq, PartialEq, PartialOrd, Ord)] 90#[derive(Eq, PartialEq, PartialOrd, Ord)]
@@ -500,7 +101,7 @@ impl ImportGroup {
500 fn new(path: &ast::Path) -> ImportGroup { 101 fn new(path: &ast::Path) -> ImportGroup {
501 let default = ImportGroup::ExternCrate; 102 let default = ImportGroup::ExternCrate;
502 103
503 let first_segment = match first_segment(path) { 104 let first_segment = match path.first_segment() {
504 Some(it) => it, 105 Some(it) => it,
505 None => return default, 106 None => return default,
506 }; 107 };
@@ -520,32 +121,15 @@ impl ImportGroup {
520 } 121 }
521} 122}
522 123
523#[derive(PartialEq, Eq)] 124fn insert_use_(
524enum AddBlankLine {
525 Before,
526 BeforeTwice,
527 Around,
528 After,
529 AfterTwice,
530}
531
532impl AddBlankLine {
533 fn has_before(&self) -> bool {
534 matches!(self, AddBlankLine::Before | AddBlankLine::BeforeTwice | AddBlankLine::Around)
535 }
536 fn has_after(&self) -> bool {
537 matches!(self, AddBlankLine::After | AddBlankLine::AfterTwice | AddBlankLine::Around)
538 }
539}
540
541fn find_insert_position(
542 scope: &ImportScope, 125 scope: &ImportScope,
543 insert_path: ast::Path, 126 insert_path: ast::Path,
544 group_imports: bool, 127 group_imports: bool,
545) -> (InsertPosition<SyntaxElement>, AddBlankLine) { 128 use_item: ast::Use,
129) {
130 let scope_syntax = scope.as_syntax_node();
546 let group = ImportGroup::new(&insert_path); 131 let group = ImportGroup::new(&insert_path);
547 let path_node_iter = scope 132 let path_node_iter = scope_syntax
548 .as_syntax_node()
549 .children() 133 .children()
550 .filter_map(|node| ast::Use::cast(node.clone()).zip(Some(node))) 134 .filter_map(|node| ast::Use::cast(node.clone()).zip(Some(node)))
551 .flat_map(|(use_, node)| { 135 .flat_map(|(use_, node)| {
@@ -557,9 +141,14 @@ fn find_insert_position(
557 141
558 if !group_imports { 142 if !group_imports {
559 if let Some((_, _, node)) = path_node_iter.last() { 143 if let Some((_, _, node)) = path_node_iter.last() {
560 return (InsertPosition::After(node.into()), AddBlankLine::Before); 144 cov_mark::hit!(insert_no_grouping_last);
145 ted::insert(ted::Position::after(node), use_item.syntax());
146 } else {
147 cov_mark::hit!(insert_no_grouping_last2);
148 ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line());
149 ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax());
561 } 150 }
562 return (InsertPosition::First, AddBlankLine::AfterTwice); 151 return;
563 } 152 }
564 153
565 // Iterator that discards anything thats not in the required grouping 154 // Iterator that discards anything thats not in the required grouping
@@ -572,43 +161,91 @@ fn find_insert_position(
572 // track the last element we iterated over, if this is still None after the iteration then that means we never iterated in the first place 161 // track the last element we iterated over, if this is still None after the iteration then that means we never iterated in the first place
573 let mut last = None; 162 let mut last = None;
574 // find the element that would come directly after our new import 163 // find the element that would come directly after our new import
575 let post_insert = group_iter.inspect(|(.., node)| last = Some(node.clone())).find( 164 let post_insert: Option<(_, _, SyntaxNode)> = group_iter
576 |&(ref path, has_tl, _)| { 165 .inspect(|(.., node)| last = Some(node.clone()))
166 .find(|&(ref path, has_tl, _)| {
577 use_tree_path_cmp(&insert_path, false, path, has_tl) != Ordering::Greater 167 use_tree_path_cmp(&insert_path, false, path, has_tl) != Ordering::Greater
578 }, 168 });
579 );
580 169
581 match post_insert { 170 if let Some((.., node)) = post_insert {
171 cov_mark::hit!(insert_group);
582 // insert our import before that element 172 // insert our import before that element
583 Some((.., node)) => (InsertPosition::Before(node.into()), AddBlankLine::After), 173 return ted::insert(ted::Position::before(node), use_item.syntax());
174 }
175 if let Some(node) = last {
176 cov_mark::hit!(insert_group_last);
584 // there is no element after our new import, so append it to the end of the group 177 // there is no element after our new import, so append it to the end of the group
585 None => match last { 178 return ted::insert(ted::Position::after(node), use_item.syntax());
586 Some(node) => (InsertPosition::After(node.into()), AddBlankLine::Before), 179 }
587 // the group we were looking for actually doesnt exist, so insert 180
181 // the group we were looking for actually doesn't exist, so insert
182
183 let mut last = None;
184 // find the group that comes after where we want to insert
185 let post_group = path_node_iter
186 .inspect(|(.., node)| last = Some(node.clone()))
187 .find(|(p, ..)| ImportGroup::new(p) > group);
188 if let Some((.., node)) = post_group {
189 cov_mark::hit!(insert_group_new_group);
190 ted::insert(ted::Position::before(&node), use_item.syntax());
191 if let Some(node) = algo::non_trivia_sibling(node.into(), Direction::Prev) {
192 ted::insert(ted::Position::after(node), make::tokens::single_newline());
193 }
194 return;
195 }
196 // there is no such group, so append after the last one
197 if let Some(node) = last {
198 cov_mark::hit!(insert_group_no_group);
199 ted::insert(ted::Position::after(&node), use_item.syntax());
200 ted::insert(ted::Position::after(node), make::tokens::single_newline());
201 return;
202 }
203 // there are no imports in this file at all
204 if let Some(last_inner_element) = scope_syntax
205 .children_with_tokens()
206 .filter(|child| match child {
207 NodeOrToken::Node(node) => is_inner_attribute(node.clone()),
208 NodeOrToken::Token(token) => is_inner_comment(token.clone()),
209 })
210 .last()
211 {
212 cov_mark::hit!(insert_group_empty_inner_attr);
213 ted::insert(ted::Position::after(&last_inner_element), use_item.syntax());
214 ted::insert(ted::Position::after(last_inner_element), make::tokens::single_newline());
215 return;
216 }
217 match scope {
218 ImportScope::File(_) => {
219 cov_mark::hit!(insert_group_empty_file);
220 ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line());
221 ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax())
222 }
223 // don't insert the imports before the item list's opening curly brace
224 ImportScope::Module(item_list) => match item_list.l_curly_token() {
225 Some(b) => {
226 cov_mark::hit!(insert_group_empty_module);
227 ted::insert(ted::Position::after(&b), make::tokens::single_newline());
228 ted::insert(ted::Position::after(&b), use_item.syntax());
229 }
588 None => { 230 None => {
589 // similar concept here to the `last` from above 231 // This should never happens, broken module syntax node
590 let mut last = None; 232 ted::insert(
591 // find the group that comes after where we want to insert 233 ted::Position::first_child_of(scope_syntax),
592 let post_group = path_node_iter 234 make::tokens::blank_line(),
593 .inspect(|(.., node)| last = Some(node.clone())) 235 );
594 .find(|(p, ..)| ImportGroup::new(p) > group); 236 ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax());
595 match post_group {
596 Some((.., node)) => {
597 (InsertPosition::Before(node.into()), AddBlankLine::AfterTwice)
598 }
599 // there is no such group, so append after the last one
600 None => match last {
601 Some(node) => {
602 (InsertPosition::After(node.into()), AddBlankLine::BeforeTwice)
603 }
604 // there are no imports in this file at all
605 None => scope.insert_pos_after_last_inner_element(),
606 },
607 }
608 } 237 }
609 }, 238 },
610 } 239 }
611} 240}
612 241
242fn is_inner_attribute(node: SyntaxNode) -> bool {
243 ast::Attr::cast(node).map(|attr| attr.kind()) == Some(ast::AttrKind::Inner)
244}
245
246fn is_inner_comment(token: SyntaxToken) -> bool {
247 ast::Comment::cast(token).and_then(|comment| comment.kind().doc)
248 == Some(ast::CommentPlacement::Inner)
249}
613#[cfg(test)] 250#[cfg(test)]
614mod tests; 251mod tests;
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
index 3d151e629..048c213e2 100644
--- a/crates/ide_db/src/helpers/insert_use/tests.rs
+++ b/crates/ide_db/src/helpers/insert_use/tests.rs
@@ -5,6 +5,7 @@ use test_utils::assert_eq_text;
5 5
6#[test] 6#[test]
7fn insert_not_group() { 7fn insert_not_group() {
8 cov_mark::check!(insert_no_grouping_last);
8 check( 9 check(
9 "use external_crate2::bar::A", 10 "use external_crate2::bar::A",
10 r" 11 r"
@@ -27,6 +28,21 @@ use external_crate2::bar::A;",
27} 28}
28 29
29#[test] 30#[test]
31fn insert_not_group_empty() {
32 cov_mark::check!(insert_no_grouping_last2);
33 check(
34 "use external_crate2::bar::A",
35 r"",
36 r"use external_crate2::bar::A;
37
38",
39 None,
40 false,
41 false,
42 );
43}
44
45#[test]
30fn insert_existing() { 46fn insert_existing() {
31 check_full("std::fs", "use std::fs;", "use std::fs;") 47 check_full("std::fs", "use std::fs;", "use std::fs;")
32} 48}
@@ -51,21 +67,21 @@ use std::bar::G;",
51 67
52#[test] 68#[test]
53fn insert_start_indent() { 69fn insert_start_indent() {
54 cov_mark::check!(insert_use_indent_after);
55 check_none( 70 check_none(
56 "std::bar::AA", 71 "std::bar::AA",
57 r" 72 r"
58 use std::bar::B; 73 use std::bar::B;
59 use std::bar::D;", 74 use std::bar::C;",
60 r" 75 r"
61 use std::bar::AA; 76 use std::bar::AA;
62 use std::bar::B; 77 use std::bar::B;
63 use std::bar::D;", 78 use std::bar::C;",
64 ) 79 );
65} 80}
66 81
67#[test] 82#[test]
68fn insert_middle() { 83fn insert_middle() {
84 cov_mark::check!(insert_group);
69 check_none( 85 check_none(
70 "std::bar::EE", 86 "std::bar::EE",
71 r" 87 r"
@@ -102,6 +118,7 @@ fn insert_middle_indent() {
102 118
103#[test] 119#[test]
104fn insert_end() { 120fn insert_end() {
121 cov_mark::check!(insert_group_last);
105 check_none( 122 check_none(
106 "std::bar::ZZ", 123 "std::bar::ZZ",
107 r" 124 r"
@@ -120,7 +137,6 @@ use std::bar::ZZ;",
120 137
121#[test] 138#[test]
122fn insert_end_indent() { 139fn insert_end_indent() {
123 cov_mark::check!(insert_use_indent_before);
124 check_none( 140 check_none(
125 "std::bar::ZZ", 141 "std::bar::ZZ",
126 r" 142 r"
@@ -201,6 +217,7 @@ fn insert_first_matching_group() {
201 217
202#[test] 218#[test]
203fn insert_missing_group_std() { 219fn insert_missing_group_std() {
220 cov_mark::check!(insert_group_new_group);
204 check_none( 221 check_none(
205 "std::fmt", 222 "std::fmt",
206 r" 223 r"
@@ -216,6 +233,7 @@ fn insert_missing_group_std() {
216 233
217#[test] 234#[test]
218fn insert_missing_group_self() { 235fn insert_missing_group_self() {
236 cov_mark::check!(insert_group_no_group);
219 check_none( 237 check_none(
220 "self::fmt", 238 "self::fmt",
221 r" 239 r"
@@ -242,6 +260,7 @@ fn main() {}",
242 260
243#[test] 261#[test]
244fn insert_empty_file() { 262fn insert_empty_file() {
263 cov_mark::check!(insert_group_empty_file);
245 // empty files will get two trailing newlines 264 // empty files will get two trailing newlines
246 // this is due to the test case insert_no_imports above 265 // this is due to the test case insert_no_imports above
247 check_full( 266 check_full(
@@ -255,7 +274,7 @@ fn insert_empty_file() {
255 274
256#[test] 275#[test]
257fn insert_empty_module() { 276fn insert_empty_module() {
258 cov_mark::check!(insert_use_no_indent_after); 277 cov_mark::check!(insert_group_empty_module);
259 check( 278 check(
260 "foo::bar", 279 "foo::bar",
261 "mod x {}", 280 "mod x {}",
@@ -270,6 +289,7 @@ fn insert_empty_module() {
270 289
271#[test] 290#[test]
272fn insert_after_inner_attr() { 291fn insert_after_inner_attr() {
292 cov_mark::check!(insert_group_empty_inner_attr);
273 check_full( 293 check_full(
274 "foo::bar", 294 "foo::bar",
275 r"#![allow(unused_imports)]", 295 r"#![allow(unused_imports)]",
@@ -615,7 +635,7 @@ fn check(
615 if module { 635 if module {
616 syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone(); 636 syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone();
617 } 637 }
618 let file = super::ImportScope::from(syntax).unwrap(); 638 let file = super::ImportScope::from(syntax.clone_for_update()).unwrap();
619 let path = ast::SourceFile::parse(&format!("use {};", path)) 639 let path = ast::SourceFile::parse(&format!("use {};", path))
620 .tree() 640 .tree()
621 .syntax() 641 .syntax()
@@ -623,12 +643,8 @@ fn check(
623 .find_map(ast::Path::cast) 643 .find_map(ast::Path::cast)
624 .unwrap(); 644 .unwrap();
625 645
626 let rewriter = insert_use( 646 insert_use(&file, path, InsertUseConfig { merge: mb, prefix_kind: PrefixKind::Plain, group });
627 &file, 647 let result = file.as_syntax_node().to_string();
628 path,
629 InsertUseConfig { merge: mb, prefix_kind: PrefixKind::Plain, group },
630 );
631 let result = rewriter.rewrite(file.as_syntax_node()).to_string();
632 assert_eq_text!(ra_fixture_after, &result); 648 assert_eq_text!(ra_fixture_after, &result);
633} 649}
634 650
diff --git a/crates/ide_db/src/helpers/merge_imports.rs b/crates/ide_db/src/helpers/merge_imports.rs
new file mode 100644
index 000000000..3f5bbef7f
--- /dev/null
+++ b/crates/ide_db/src/helpers/merge_imports.rs
@@ -0,0 +1,309 @@
1//! Handle syntactic aspects of merging UseTrees.
2use std::cmp::Ordering;
3
4use itertools::{EitherOrBoth, Itertools};
5use syntax::ast::{
6 self, edit::AstNodeEdit, make, AstNode, AttrsOwner, PathSegmentKind, VisibilityOwner,
7};
8
9/// What type of merges are allowed.
10#[derive(Copy, Clone, Debug, PartialEq, Eq)]
11pub enum MergeBehavior {
12 /// Merge everything together creating deeply nested imports.
13 Full,
14 /// Only merge the last import level, doesn't allow import nesting.
15 Last,
16}
17
18impl MergeBehavior {
19 #[inline]
20 fn is_tree_allowed(&self, tree: &ast::UseTree) -> bool {
21 match self {
22 MergeBehavior::Full => true,
23 // only simple single segment paths are allowed
24 MergeBehavior::Last => {
25 tree.use_tree_list().is_none() && tree.path().map(path_len) <= Some(1)
26 }
27 }
28 }
29}
30
31pub fn try_merge_imports(
32 lhs: &ast::Use,
33 rhs: &ast::Use,
34 merge_behavior: MergeBehavior,
35) -> Option<ast::Use> {
36 // don't merge imports with different visibilities
37 if !eq_visibility(lhs.visibility(), rhs.visibility()) {
38 return None;
39 }
40 if !eq_attrs(lhs.attrs(), rhs.attrs()) {
41 return None;
42 }
43
44 let lhs_tree = lhs.use_tree()?;
45 let rhs_tree = rhs.use_tree()?;
46 let merged = try_merge_trees(&lhs_tree, &rhs_tree, merge_behavior)?;
47 Some(lhs.with_use_tree(merged).clone_for_update())
48}
49
50pub fn try_merge_trees(
51 lhs: &ast::UseTree,
52 rhs: &ast::UseTree,
53 merge: MergeBehavior,
54) -> Option<ast::UseTree> {
55 let lhs_path = lhs.path()?;
56 let rhs_path = rhs.path()?;
57
58 let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;
59 let (lhs, rhs) = if lhs.is_simple_path()
60 && rhs.is_simple_path()
61 && lhs_path == lhs_prefix
62 && rhs_path == rhs_prefix
63 {
64 (lhs.clone(), rhs.clone())
65 } else {
66 (lhs.split_prefix(&lhs_prefix), rhs.split_prefix(&rhs_prefix))
67 };
68 recursive_merge(&lhs, &rhs, merge)
69}
70
71/// Recursively "zips" together lhs and rhs.
72fn recursive_merge(
73 lhs: &ast::UseTree,
74 rhs: &ast::UseTree,
75 merge: MergeBehavior,
76) -> Option<ast::UseTree> {
77 let mut use_trees = lhs
78 .use_tree_list()
79 .into_iter()
80 .flat_map(|list| list.use_trees())
81 // we use Option here to early return from this function(this is not the same as a `filter` op)
82 .map(|tree| match merge.is_tree_allowed(&tree) {
83 true => Some(tree),
84 false => None,
85 })
86 .collect::<Option<Vec<_>>>()?;
87 use_trees.sort_unstable_by(|a, b| path_cmp_for_sort(a.path(), b.path()));
88 for rhs_t in rhs.use_tree_list().into_iter().flat_map(|list| list.use_trees()) {
89 if !merge.is_tree_allowed(&rhs_t) {
90 return None;
91 }
92 let rhs_path = rhs_t.path();
93 match use_trees.binary_search_by(|lhs_t| {
94 let (lhs_t, rhs_t) = match lhs_t
95 .path()
96 .zip(rhs_path.clone())
97 .and_then(|(lhs, rhs)| common_prefix(&lhs, &rhs))
98 {
99 Some((lhs_p, rhs_p)) => (lhs_t.split_prefix(&lhs_p), rhs_t.split_prefix(&rhs_p)),
100 None => (lhs_t.clone(), rhs_t.clone()),
101 };
102
103 path_cmp_bin_search(lhs_t.path(), rhs_t.path())
104 }) {
105 Ok(idx) => {
106 let lhs_t = &mut use_trees[idx];
107 let lhs_path = lhs_t.path()?;
108 let rhs_path = rhs_path?;
109 let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;
110 if lhs_prefix == lhs_path && rhs_prefix == rhs_path {
111 let tree_is_self = |tree: ast::UseTree| {
112 tree.path().as_ref().map(path_is_self).unwrap_or(false)
113 };
114 // check if only one of the two trees has a tree list, and whether that then contains `self` or not.
115 // If this is the case we can skip this iteration since the path without the list is already included in the other one via `self`
116 let tree_contains_self = |tree: &ast::UseTree| {
117 tree.use_tree_list()
118 .map(|tree_list| tree_list.use_trees().any(tree_is_self))
119 .unwrap_or(false)
120 };
121 match (tree_contains_self(&lhs_t), tree_contains_self(&rhs_t)) {
122 (true, false) => continue,
123 (false, true) => {
124 *lhs_t = rhs_t;
125 continue;
126 }
127 _ => (),
128 }
129
130 // glob imports arent part of the use-tree lists so we need to special handle them here as well
131 // this special handling is only required for when we merge a module import into a glob import of said module
132 // see the `merge_self_glob` or `merge_mod_into_glob` tests
133 if lhs_t.star_token().is_some() || rhs_t.star_token().is_some() {
134 *lhs_t = make::use_tree(
135 make::path_unqualified(make::path_segment_self()),
136 None,
137 None,
138 false,
139 );
140 use_trees.insert(idx, make::glob_use_tree());
141 continue;
142 }
143
144 if lhs_t.use_tree_list().is_none() && rhs_t.use_tree_list().is_none() {
145 continue;
146 }
147 }
148 let lhs = lhs_t.split_prefix(&lhs_prefix);
149 let rhs = rhs_t.split_prefix(&rhs_prefix);
150 match recursive_merge(&lhs, &rhs, merge) {
151 Some(use_tree) => use_trees[idx] = use_tree,
152 None => return None,
153 }
154 }
155 Err(_)
156 if merge == MergeBehavior::Last
157 && use_trees.len() > 0
158 && rhs_t.use_tree_list().is_some() =>
159 {
160 return None
161 }
162 Err(idx) => {
163 use_trees.insert(idx, rhs_t);
164 }
165 }
166 }
167
168 Some(if let Some(old) = lhs.use_tree_list() {
169 lhs.replace_descendant(old, make::use_tree_list(use_trees)).clone_for_update()
170 } else {
171 lhs.clone()
172 })
173}
174
175/// Traverses both paths until they differ, returning the common prefix of both.
176fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> {
177 let mut res = None;
178 let mut lhs_curr = lhs.first_qualifier_or_self();
179 let mut rhs_curr = rhs.first_qualifier_or_self();
180 loop {
181 match (lhs_curr.segment(), rhs_curr.segment()) {
182 (Some(lhs), Some(rhs)) if lhs.syntax().text() == rhs.syntax().text() => (),
183 _ => break res,
184 }
185 res = Some((lhs_curr.clone(), rhs_curr.clone()));
186
187 match lhs_curr.parent_path().zip(rhs_curr.parent_path()) {
188 Some((lhs, rhs)) => {
189 lhs_curr = lhs;
190 rhs_curr = rhs;
191 }
192 _ => break res,
193 }
194 }
195}
196
197/// Orders paths in the following way:
198/// the sole self token comes first, after that come uppercase identifiers, then lowercase identifiers
199// FIXME: rustfmt sorts lowercase idents before uppercase, in general we want to have the same ordering rustfmt has
200// which is `self` and `super` first, then identifier imports with lowercase ones first, then glob imports and at last list imports.
201// Example foo::{self, foo, baz, Baz, Qux, *, {Bar}}
202fn path_cmp_for_sort(a: Option<ast::Path>, b: Option<ast::Path>) -> Ordering {
203 match (a, b) {
204 (None, None) => Ordering::Equal,
205 (None, Some(_)) => Ordering::Less,
206 (Some(_), None) => Ordering::Greater,
207 (Some(ref a), Some(ref b)) => match (path_is_self(a), path_is_self(b)) {
208 (true, true) => Ordering::Equal,
209 (true, false) => Ordering::Less,
210 (false, true) => Ordering::Greater,
211 (false, false) => path_cmp_short(a, b),
212 },
213 }
214}
215
216/// Path comparison func for binary searching for merging.
217fn path_cmp_bin_search(lhs: Option<ast::Path>, rhs: Option<ast::Path>) -> Ordering {
218 match (
219 lhs.as_ref().and_then(ast::Path::first_segment),
220 rhs.as_ref().and_then(ast::Path::first_segment),
221 ) {
222 (None, None) => Ordering::Equal,
223 (None, Some(_)) => Ordering::Less,
224 (Some(_), None) => Ordering::Greater,
225 (Some(ref a), Some(ref b)) => path_segment_cmp(a, b),
226 }
227}
228
229/// Short circuiting comparison, if both paths are equal until one of them ends they are considered
230/// equal
231fn path_cmp_short(a: &ast::Path, b: &ast::Path) -> Ordering {
232 let a = a.segments();
233 let b = b.segments();
234 // cmp_by would be useful for us here but that is currently unstable
235 // cmp doesn't work due the lifetimes on text's return type
236 a.zip(b)
237 .find_map(|(a, b)| match path_segment_cmp(&a, &b) {
238 Ordering::Equal => None,
239 ord => Some(ord),
240 })
241 .unwrap_or(Ordering::Equal)
242}
243
244/// Compares two paths, if one ends earlier than the other the has_tl parameters decide which is
245/// greater as a a path that has a tree list should be greater, while one that just ends without
246/// a tree list should be considered less.
247pub(super) fn use_tree_path_cmp(
248 a: &ast::Path,
249 a_has_tl: bool,
250 b: &ast::Path,
251 b_has_tl: bool,
252) -> Ordering {
253 let a_segments = a.segments();
254 let b_segments = b.segments();
255 // cmp_by would be useful for us here but that is currently unstable
256 // cmp doesn't work due the lifetimes on text's return type
257 a_segments
258 .zip_longest(b_segments)
259 .find_map(|zipped| match zipped {
260 EitherOrBoth::Both(ref a, ref b) => match path_segment_cmp(a, b) {
261 Ordering::Equal => None,
262 ord => Some(ord),
263 },
264 EitherOrBoth::Left(_) if !b_has_tl => Some(Ordering::Greater),
265 EitherOrBoth::Left(_) => Some(Ordering::Less),
266 EitherOrBoth::Right(_) if !a_has_tl => Some(Ordering::Less),
267 EitherOrBoth::Right(_) => Some(Ordering::Greater),
268 })
269 .unwrap_or(Ordering::Equal)
270}
271
272fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering {
273 let a = a.kind().and_then(|kind| match kind {
274 PathSegmentKind::Name(name_ref) => Some(name_ref),
275 _ => None,
276 });
277 let b = b.kind().and_then(|kind| match kind {
278 PathSegmentKind::Name(name_ref) => Some(name_ref),
279 _ => None,
280 });
281 a.as_ref().map(ast::NameRef::text).cmp(&b.as_ref().map(ast::NameRef::text))
282}
283
284fn eq_visibility(vis0: Option<ast::Visibility>, vis1: Option<ast::Visibility>) -> bool {
285 match (vis0, vis1) {
286 (None, None) => true,
287 // FIXME: Don't use the string representation to check for equality
288 // spaces inside of the node would break this comparison
289 (Some(vis0), Some(vis1)) => vis0.to_string() == vis1.to_string(),
290 _ => false,
291 }
292}
293
294fn eq_attrs(
295 attrs0: impl Iterator<Item = ast::Attr>,
296 attrs1: impl Iterator<Item = ast::Attr>,
297) -> bool {
298 let attrs0 = attrs0.map(|attr| attr.to_string());
299 let attrs1 = attrs1.map(|attr| attr.to_string());
300 attrs0.eq(attrs1)
301}
302
303fn path_is_self(path: &ast::Path) -> bool {
304 path.segment().and_then(|seg| seg.self_token()).is_some() && path.qualifier().is_none()
305}
306
307fn path_len(path: ast::Path) -> usize {
308 path.segments().count()
309}
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index b55e3851e..8f899ea56 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -7,7 +7,9 @@
7use std::{convert::TryInto, mem}; 7use std::{convert::TryInto, mem};
8 8
9use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; 9use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
10use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility}; 10use hir::{
11 DefWithBody, HasAttrs, HasSource, InFile, ModuleDef, ModuleSource, Semantics, Visibility,
12};
11use once_cell::unsync::Lazy; 13use once_cell::unsync::Lazy;
12use rustc_hash::FxHashMap; 14use rustc_hash::FxHashMap;
13use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; 15use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
@@ -295,7 +297,7 @@ impl Definition {
295 } 297 }
296 298
297 pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> { 299 pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {
298 FindUsages { def: self, sema, scope: None } 300 FindUsages { def: self, sema, scope: None, include_self_kw_refs: false }
299 } 301 }
300} 302}
301 303
@@ -303,9 +305,15 @@ pub struct FindUsages<'a> {
303 def: &'a Definition, 305 def: &'a Definition,
304 sema: &'a Semantics<'a, RootDatabase>, 306 sema: &'a Semantics<'a, RootDatabase>,
305 scope: Option<SearchScope>, 307 scope: Option<SearchScope>,
308 include_self_kw_refs: bool,
306} 309}
307 310
308impl<'a> FindUsages<'a> { 311impl<'a> FindUsages<'a> {
312 pub fn include_self_kw_refs(mut self, include: bool) -> FindUsages<'a> {
313 self.include_self_kw_refs = include;
314 self
315 }
316
309 pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> { 317 pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> {
310 self.set_scope(Some(scope)) 318 self.set_scope(Some(scope))
311 } 319 }
@@ -352,6 +360,8 @@ impl<'a> FindUsages<'a> {
352 }; 360 };
353 361
354 let pat = name.as_str(); 362 let pat = name.as_str();
363 let search_for_self = self.include_self_kw_refs;
364
355 for (file_id, search_range) in search_scope { 365 for (file_id, search_range) in search_scope {
356 let text = sema.db.file_text(file_id); 366 let text = sema.db.file_text(file_id);
357 let search_range = 367 let search_range =
@@ -359,31 +369,47 @@ impl<'a> FindUsages<'a> {
359 369
360 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone()); 370 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
361 371
362 for (idx, _) in text.match_indices(pat) { 372 let mut handle_match = |idx: usize| -> bool {
363 let offset: TextSize = idx.try_into().unwrap(); 373 let offset: TextSize = idx.try_into().unwrap();
364 if !search_range.contains_inclusive(offset) { 374 if !search_range.contains_inclusive(offset) {
365 continue; 375 return false;
366 } 376 }
367 377
368 if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) { 378 if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) {
369 match name { 379 match name {
370 ast::NameLike::NameRef(name_ref) => { 380 ast::NameLike::NameRef(name_ref) => {
371 if self.found_name_ref(&name_ref, sink) { 381 if self.found_name_ref(&name_ref, sink) {
372 return; 382 return true;
373 } 383 }
374 } 384 }
375 ast::NameLike::Name(name) => { 385 ast::NameLike::Name(name) => {
376 if self.found_name(&name, sink) { 386 if self.found_name(&name, sink) {
377 return; 387 return true;
378 } 388 }
379 } 389 }
380 ast::NameLike::Lifetime(lifetime) => { 390 ast::NameLike::Lifetime(lifetime) => {
381 if self.found_lifetime(&lifetime, sink) { 391 if self.found_lifetime(&lifetime, sink) {
382 return; 392 return true;
383 } 393 }
384 } 394 }
385 } 395 }
386 } 396 }
397
398 return false;
399 };
400
401 for (idx, _) in text.match_indices(pat) {
402 if handle_match(idx) {
403 return;
404 }
405 }
406
407 if search_for_self {
408 for (idx, _) in text.match_indices("Self") {
409 if handle_match(idx) {
410 return;
411 }
412 }
387 } 413 }
388 } 414 }
389 } 415 }
@@ -422,6 +448,24 @@ impl<'a> FindUsages<'a> {
422 }; 448 };
423 sink(file_id, reference) 449 sink(file_id, reference)
424 } 450 }
451 Some(NameRefClass::Definition(Definition::SelfType(impl_))) => {
452 let ty = impl_.self_ty(self.sema.db);
453
454 if let Some(adt) = ty.as_adt() {
455 if &Definition::ModuleDef(ModuleDef::Adt(adt)) == self.def {
456 let FileRange { file_id, range } =
457 self.sema.original_range(name_ref.syntax());
458 let reference = FileReference {
459 range,
460 name: ast::NameLike::NameRef(name_ref.clone()),
461 access: None,
462 };
463 return sink(file_id, reference);
464 }
465 }
466
467 false
468 }
425 Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => { 469 Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => {
426 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); 470 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
427 let reference = match self.def { 471 let reference = match self.def {
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs
index faca336de..7b88dca63 100644
--- a/crates/project_model/src/build_data.rs
+++ b/crates/project_model/src/build_data.rs
@@ -143,7 +143,7 @@ impl WorkspaceBuildData {
143 cmd.env("RA_RUSTC_WRAPPER", "1"); 143 cmd.env("RA_RUSTC_WRAPPER", "1");
144 } 144 }
145 145
146 cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]) 146 cmd.args(&["check", "--quiet", "--workspace", "--message-format=json", "--manifest-path"])
147 .arg(cargo_toml.as_ref()); 147 .arg(cargo_toml.as_ref());
148 148
149 // --all-targets includes tests, benches and examples in addition to the 149 // --all-targets includes tests, benches and examples in addition to the
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 0571a912c..3e8f4bf89 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -33,7 +33,7 @@ serde_path_to_error = "0.1"
33threadpool = "1.7.1" 33threadpool = "1.7.1"
34rayon = "1.5" 34rayon = "1.5"
35mimalloc = { version = "0.1.19", default-features = false, optional = true } 35mimalloc = { version = "0.1.19", default-features = false, optional = true }
36lsp-server = "0.5.0" 36lsp-server = "0.5.1"
37tracing = "0.1" 37tracing = "0.1"
38tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } 38tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
39tracing-tree = { version = "0.1.4" } 39tracing-tree = { version = "0.1.4" }
diff --git a/crates/rust-analyzer/build.rs b/crates/rust-analyzer/build.rs
index 13b903891..bca6611d6 100644
--- a/crates/rust-analyzer/build.rs
+++ b/crates/rust-analyzer/build.rs
@@ -1,13 +1,10 @@
1//! Just embed git-hash to `--version` 1//! Construct version in the `commit-hash date chanel` format
2 2
3use std::{env, path::PathBuf, process::Command}; 3use std::{env, path::PathBuf, process::Command};
4 4
5fn main() { 5fn main() {
6 set_rerun(); 6 set_rerun();
7 7 println!("cargo:rustc-env=REV={}", rev())
8 let rev =
9 env::var("RUST_ANALYZER_REV").ok().or_else(rev).unwrap_or_else(|| "???????".to_string());
10 println!("cargo:rustc-env=REV={}", rev)
11} 8}
12 9
13fn set_rerun() { 10fn set_rerun() {
@@ -18,29 +15,52 @@ fn set_rerun() {
18 ); 15 );
19 16
20 while manifest_dir.parent().is_some() { 17 while manifest_dir.parent().is_some() {
21 if manifest_dir.join(".git/HEAD").exists() { 18 let head_ref = manifest_dir.join(".git/HEAD");
22 let git_dir = manifest_dir.join(".git"); 19 if head_ref.exists() {
23 20 println!("cargo:rerun-if-changed={}", head_ref.display());
24 println!("cargo:rerun-if-changed={}", git_dir.join("HEAD").display());
25 // current branch ref
26 if let Ok(output) =
27 Command::new("git").args(&["rev-parse", "--symbolic-full-name", "HEAD"]).output()
28 {
29 if let Ok(ref_link) = String::from_utf8(output.stdout) {
30 println!("cargo:rerun-if-changed={}", git_dir.join(ref_link).display());
31 }
32 }
33 return; 21 return;
34 } 22 }
35 23
36 manifest_dir.pop(); 24 manifest_dir.pop();
37 } 25 }
26
38 println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!"); 27 println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!");
39} 28}
40 29
41fn rev() -> Option<String> { 30fn rev() -> String {
42 let output = 31 if let Ok(rev) = env::var("RUST_ANALYZER_REV") {
43 Command::new("git").args(&["describe", "--tags", "--exclude", "nightly"]).output().ok()?; 32 return rev;
33 }
34
35 if let Some(commit_hash) = commit_hash() {
36 let mut buf = commit_hash;
37
38 if let Some(date) = build_date() {
39 buf.push(' ');
40 buf.push_str(&date);
41 }
42
43 let channel = env::var("RUST_ANALYZER_CHANNEL").unwrap_or_else(|_| "dev".to_string());
44 buf.push(' ');
45 buf.push_str(&channel);
46
47 return buf;
48 }
49
50 "???????".to_string()
51}
52
53fn commit_hash() -> Option<String> {
54 output_to_string("git rev-parse --short HEAD")
55}
56
57fn build_date() -> Option<String> {
58 output_to_string("date -u +%Y-%m-%d")
59}
60
61fn output_to_string(command: &str) -> Option<String> {
62 let args = command.split_ascii_whitespace().collect::<Vec<_>>();
63 let output = Command::new(args[0]).args(&args[1..]).output().ok()?;
44 let stdout = String::from_utf8(output.stdout).ok()?; 64 let stdout = String::from_utf8(output.stdout).ok()?;
45 Some(stdout) 65 Some(stdout.trim().to_string())
46} 66}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 1109d2daf..28bbbce19 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -12,7 +12,8 @@ use std::{ffi::OsString, iter, path::PathBuf};
12use flycheck::FlycheckConfig; 12use flycheck::FlycheckConfig;
13use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; 13use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig};
14use ide_db::helpers::{ 14use ide_db::helpers::{
15 insert_use::{InsertUseConfig, MergeBehavior, PrefixKind}, 15 insert_use::{InsertUseConfig, PrefixKind},
16 merge_imports::MergeBehavior,
16 SnippetCap, 17 SnippetCap,
17}; 18};
18use lsp_types::{ClientCapabilities, MarkupKind}; 19use lsp_types::{ClientCapabilities, MarkupKind};
@@ -144,6 +145,8 @@ config_data! {
144 inlayHints_parameterHints: bool = "true", 145 inlayHints_parameterHints: bool = "true",
145 /// Whether to show inlay type hints for variables. 146 /// Whether to show inlay type hints for variables.
146 inlayHints_typeHints: bool = "true", 147 inlayHints_typeHints: bool = "true",
148 /// Whether inlay hints font size should be smaller than editor's font size.
149 inlayHints_smallerHints: bool = "true",
147 150
148 /// Whether to show `Debug` lens. Only applies when 151 /// Whether to show `Debug` lens. Only applies when
149 /// `#rust-analyzer.lens.enable#` is set. 152 /// `#rust-analyzer.lens.enable#` is set.
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 6ea775d68..a766aacad 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -571,6 +571,12 @@ impl GlobalState {
571 this.cancel(id); 571 this.cancel(id);
572 Ok(()) 572 Ok(())
573 })? 573 })?
574 .on::<lsp_types::notification::WorkDoneProgressCancel>(|_this, _params| {
575 // Just ignore this. It is OK to continue sending progress
576 // notifications for this token, as the client can't know when
577 // we accepted notification.
578 Ok(())
579 })?
574 .on::<lsp_types::notification::DidOpenTextDocument>(|this, params| { 580 .on::<lsp_types::notification::DidOpenTextDocument>(|this, params| {
575 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) { 581 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
576 if this 582 if this
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 857567a85..1b6211044 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -14,18 +14,8 @@ pub fn is_ci() -> bool {
14 14
15#[must_use] 15#[must_use]
16pub fn timeit(label: &'static str) -> impl Drop { 16pub fn timeit(label: &'static str) -> impl Drop {
17 struct Guard { 17 let start = Instant::now();
18 label: &'static str, 18 defer(move || eprintln!("{}: {:.2?}", label, start.elapsed()))
19 start: Instant,
20 }
21
22 impl Drop for Guard {
23 fn drop(&mut self) {
24 eprintln!("{}: {:.2?}", self.label, self.start.elapsed())
25 }
26 }
27
28 Guard { label, start: Instant::now() }
29} 19}
30 20
31/// Prints backtrace to stderr, useful for debugging. 21/// Prints backtrace to stderr, useful for debugging.
@@ -179,6 +169,7 @@ where
179 start..start + len 169 start..start + len
180} 170}
181 171
172#[must_use]
182pub fn defer<F: FnOnce()>(f: F) -> impl Drop { 173pub fn defer<F: FnOnce()>(f: F) -> impl Drop {
183 struct D<F: FnOnce()>(Option<F>); 174 struct D<F: FnOnce()>(Option<F>);
184 impl<F: FnOnce()> Drop for D<F> { 175 impl<F: FnOnce()> Drop for D<F> {
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs
index a153a9e1c..c9229c4e0 100644
--- a/crates/syntax/src/algo.rs
+++ b/crates/syntax/src/algo.rs
@@ -342,10 +342,10 @@ enum InsertPos {
342 342
343#[derive(Default)] 343#[derive(Default)]
344pub struct SyntaxRewriter<'a> { 344pub struct SyntaxRewriter<'a> {
345 f: Option<Box<dyn Fn(&SyntaxElement) -> Option<SyntaxElement> + 'a>>,
346 //FIXME: add debug_assertions that all elements are in fact from the same file. 345 //FIXME: add debug_assertions that all elements are in fact from the same file.
347 replacements: FxHashMap<SyntaxElement, Replacement>, 346 replacements: FxHashMap<SyntaxElement, Replacement>,
348 insertions: IndexMap<InsertPos, Vec<SyntaxElement>>, 347 insertions: IndexMap<InsertPos, Vec<SyntaxElement>>,
348 _pd: std::marker::PhantomData<&'a ()>,
349} 349}
350 350
351impl fmt::Debug for SyntaxRewriter<'_> { 351impl fmt::Debug for SyntaxRewriter<'_> {
@@ -357,14 +357,7 @@ impl fmt::Debug for SyntaxRewriter<'_> {
357 } 357 }
358} 358}
359 359
360impl<'a> SyntaxRewriter<'a> { 360impl SyntaxRewriter<'_> {
361 pub fn from_fn(f: impl Fn(&SyntaxElement) -> Option<SyntaxElement> + 'a) -> SyntaxRewriter<'a> {
362 SyntaxRewriter {
363 f: Some(Box::new(f)),
364 replacements: FxHashMap::default(),
365 insertions: IndexMap::default(),
366 }
367 }
368 pub fn delete<T: Clone + Into<SyntaxElement>>(&mut self, what: &T) { 361 pub fn delete<T: Clone + Into<SyntaxElement>>(&mut self, what: &T) {
369 let what = what.clone().into(); 362 let what = what.clone().into();
370 let replacement = Replacement::Delete; 363 let replacement = Replacement::Delete;
@@ -470,7 +463,7 @@ impl<'a> SyntaxRewriter<'a> {
470 pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { 463 pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode {
471 let _p = profile::span("rewrite"); 464 let _p = profile::span("rewrite");
472 465
473 if self.f.is_none() && self.replacements.is_empty() && self.insertions.is_empty() { 466 if self.replacements.is_empty() && self.insertions.is_empty() {
474 return node.clone(); 467 return node.clone();
475 } 468 }
476 let green = self.rewrite_children(node); 469 let green = self.rewrite_children(node);
@@ -495,7 +488,6 @@ impl<'a> SyntaxRewriter<'a> {
495 } 488 }
496 } 489 }
497 490
498 assert!(self.f.is_none());
499 self.replacements 491 self.replacements
500 .keys() 492 .keys()
501 .filter_map(element_to_node_or_parent) 493 .filter_map(element_to_node_or_parent)
@@ -510,10 +502,6 @@ impl<'a> SyntaxRewriter<'a> {
510 } 502 }
511 503
512 fn replacement(&self, element: &SyntaxElement) -> Option<Replacement> { 504 fn replacement(&self, element: &SyntaxElement) -> Option<Replacement> {
513 if let Some(f) = &self.f {
514 assert!(self.replacements.is_empty());
515 return f(element).map(Replacement::Single);
516 }
517 self.replacements.get(element).cloned() 505 self.replacements.get(element).cloned()
518 } 506 }
519 507
@@ -574,7 +562,6 @@ fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, row
574 562
575impl ops::AddAssign for SyntaxRewriter<'_> { 563impl ops::AddAssign for SyntaxRewriter<'_> {
576 fn add_assign(&mut self, rhs: SyntaxRewriter) { 564 fn add_assign(&mut self, rhs: SyntaxRewriter) {
577 assert!(rhs.f.is_none());
578 self.replacements.extend(rhs.replacements); 565 self.replacements.extend(rhs.replacements);
579 for (pos, insertions) in rhs.insertions.into_iter() { 566 for (pos, insertions) in rhs.insertions.into_iter() {
580 match self.insertions.entry(pos) { 567 match self.insertions.entry(pos) {
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 4cf6f871e..42da09606 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -137,6 +137,17 @@ pub fn use_(visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast:
137 ast_from_text(&format!("{}use {};", visibility, use_tree)) 137 ast_from_text(&format!("{}use {};", visibility, use_tree))
138} 138}
139 139
140pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr {
141 ast_from_text(&format!("fn f() {{ {} {} }}", path, fields))
142}
143
144pub fn record_expr_field_list(
145 fields: impl IntoIterator<Item = ast::RecordExprField>,
146) -> ast::RecordExprFieldList {
147 let fields = fields.into_iter().join(", ");
148 ast_from_text(&format!("fn f() {{ S {{ {} }} }}", fields))
149}
150
140pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField { 151pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField {
141 return match expr { 152 return match expr {
142 Some(expr) => from_text(&format!("{}: {}", name, expr)), 153 Some(expr) => from_text(&format!("{}: {}", name, expr)),
@@ -339,6 +350,21 @@ pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) ->
339 } 350 }
340} 351}
341 352
353pub fn record_pat_with_fields(path: ast::Path, fields: ast::RecordPatFieldList) -> ast::RecordPat {
354 ast_from_text(&format!("fn f({} {}: ()))", path, fields))
355}
356
357pub fn record_pat_field_list(
358 fields: impl IntoIterator<Item = ast::RecordPatField>,
359) -> ast::RecordPatFieldList {
360 let fields = fields.into_iter().join(", ");
361 ast_from_text(&format!("fn f(S {{ {} }}: ()))", fields))
362}
363
364pub fn record_pat_field(name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPatField {
365 ast_from_text(&format!("fn f(S {{ {}: {} }}: ()))", name_ref, pat))
366}
367
342/// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise. 368/// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
343pub fn path_pat(path: ast::Path) -> ast::Pat { 369pub fn path_pat(path: ast::Path) -> ast::Pat {
344 return from_text(&path.to_string()); 370 return from_text(&path.to_string());
@@ -606,6 +632,7 @@ pub mod tokens {
606 SOURCE_FILE 632 SOURCE_FILE
607 .tree() 633 .tree()
608 .syntax() 634 .syntax()
635 .clone_for_update()
609 .descendants_with_tokens() 636 .descendants_with_tokens()
610 .filter_map(|it| it.into_token()) 637 .filter_map(|it| it.into_token())
611 .find(|it| it.kind() == WHITESPACE && it.text() == "\n\n") 638 .find(|it| it.kind() == WHITESPACE && it.text() == "\n\n")
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 171099661..492fbc4a0 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -1,7 +1,7 @@
1//! Various extension methods to ast Nodes, which are hard to code-generate. 1//! Various extension methods to ast Nodes, which are hard to code-generate.
2//! Extensions for various expressions live in a sibling `expr_extensions` module. 2//! Extensions for various expressions live in a sibling `expr_extensions` module.
3 3
4use std::fmt; 4use std::{fmt, iter::successors};
5 5
6use itertools::Itertools; 6use itertools::Itertools;
7use parser::SyntaxKind; 7use parser::SyntaxKind;
@@ -237,6 +237,26 @@ impl ast::Path {
237 None => self.segment(), 237 None => self.segment(),
238 } 238 }
239 } 239 }
240
241 pub fn first_qualifier_or_self(&self) -> ast::Path {
242 successors(Some(self.clone()), ast::Path::qualifier).last().unwrap()
243 }
244
245 pub fn first_segment(&self) -> Option<ast::PathSegment> {
246 self.first_qualifier_or_self().segment()
247 }
248
249 pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
250 // cant make use of SyntaxNode::siblings, because the returned Iterator is not clone
251 successors(self.first_segment(), |p| {
252 p.parent_path().parent_path().and_then(|p| p.segment())
253 })
254 }
255}
256impl ast::UseTree {
257 pub fn is_simple_path(&self) -> bool {
258 self.use_tree_list().is_none() && self.star_token().is_none()
259 }
240} 260}
241 261
242impl ast::UseTreeList { 262impl ast::UseTreeList {
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs
index 450f2e447..91a06101f 100644
--- a/crates/syntax/src/ted.rs
+++ b/crates/syntax/src/ted.rs
@@ -7,7 +7,7 @@ use std::{mem, ops::RangeInclusive};
7use parser::T; 7use parser::T;
8 8
9use crate::{ 9use crate::{
10 ast::{edit::IndentLevel, make}, 10 ast::{self, edit::IndentLevel, make, AstNode},
11 SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, 11 SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken,
12}; 12};
13 13
@@ -147,6 +147,16 @@ pub fn append_child_raw(node: &(impl Into<SyntaxNode> + Clone), child: impl Elem
147fn ws_before(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> { 147fn ws_before(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> {
148 let prev = match &position.repr { 148 let prev = match &position.repr {
149 PositionRepr::FirstChild(_) => return None, 149 PositionRepr::FirstChild(_) => return None,
150 PositionRepr::After(it) if it.kind() == SyntaxKind::L_CURLY => {
151 if new.kind() == SyntaxKind::USE {
152 if let Some(item_list) = it.parent().and_then(ast::ItemList::cast) {
153 let mut indent = IndentLevel::from_element(&item_list.syntax().clone().into());
154 indent.0 += 1;
155 return Some(make::tokens::whitespace(&format!("\n{}", indent)));
156 }
157 }
158 it
159 }
150 PositionRepr::After(it) => it, 160 PositionRepr::After(it) => it,
151 }; 161 };
152 ws_between(prev, new) 162 ws_between(prev, new)
@@ -173,7 +183,10 @@ fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option<SyntaxToken
173 } 183 }
174 184
175 if right.kind() == SyntaxKind::USE { 185 if right.kind() == SyntaxKind::USE {
176 let indent = IndentLevel::from_element(left); 186 let mut indent = IndentLevel::from_element(left);
187 if left.kind() == SyntaxKind::USE {
188 indent.0 = IndentLevel::from_element(right).0.max(indent.0);
189 }
177 return Some(make::tokens::whitespace(&format!("\n{}", indent))); 190 return Some(make::tokens::whitespace(&format!("\n{}", indent)));
178 } 191 }
179 Some(make::tokens::single_space()) 192 Some(make::tokens::single_space())
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index e28423e99..db3c5f7bb 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -234,6 +234,11 @@ site.
234-- 234--
235Whether to show inlay type hints for variables. 235Whether to show inlay type hints for variables.
236-- 236--
237[[rust-analyzer.inlayHints.smallerHints]]rust-analyzer.inlayHints.smallerHints (default: `true`)::
238+
239--
240Whether inlay hints font size should be smaller than editor's font size.
241--
237[[rust-analyzer.lens.debug]]rust-analyzer.lens.debug (default: `true`):: 242[[rust-analyzer.lens.debug]]rust-analyzer.lens.debug (default: `true`)::
238+ 243+
239-- 244--
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 198c17556..df0c512d6 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -53,9 +53,9 @@
53 "dev": true 53 "dev": true
54 }, 54 },
55 "node_modules/@babel/highlight": { 55 "node_modules/@babel/highlight": {
56 "version": "7.12.13", 56 "version": "7.13.10",
57 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", 57 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz",
58 "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", 58 "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==",
59 "dev": true, 59 "dev": true,
60 "dependencies": { 60 "dependencies": {
61 "@babel/helper-validator-identifier": "^7.12.11", 61 "@babel/helper-validator-identifier": "^7.12.11",
@@ -135,9 +135,9 @@
135 } 135 }
136 }, 136 },
137 "node_modules/@eslint/eslintrc": { 137 "node_modules/@eslint/eslintrc": {
138 "version": "0.3.0", 138 "version": "0.4.0",
139 "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", 139 "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
140 "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", 140 "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
141 "dev": true, 141 "dev": true,
142 "dependencies": { 142 "dependencies": {
143 "ajv": "^6.12.4", 143 "ajv": "^6.12.4",
@@ -147,7 +147,6 @@
147 "ignore": "^4.0.6", 147 "ignore": "^4.0.6",
148 "import-fresh": "^3.2.1", 148 "import-fresh": "^3.2.1",
149 "js-yaml": "^3.13.1", 149 "js-yaml": "^3.13.1",
150 "lodash": "^4.17.20",
151 "minimatch": "^3.0.4", 150 "minimatch": "^3.0.4",
152 "strip-json-comments": "^3.1.1" 151 "strip-json-comments": "^3.1.1"
153 }, 152 },
@@ -155,6 +154,30 @@
155 "node": "^10.12.0 || >=12.0.0" 154 "node": "^10.12.0 || >=12.0.0"
156 } 155 }
157 }, 156 },
157 "node_modules/@eslint/eslintrc/node_modules/globals": {
158 "version": "12.4.0",
159 "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
160 "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
161 "dev": true,
162 "dependencies": {
163 "type-fest": "^0.8.1"
164 },
165 "engines": {
166 "node": ">=8"
167 },
168 "funding": {
169 "url": "https://github.com/sponsors/sindresorhus"
170 }
171 },
172 "node_modules/@eslint/eslintrc/node_modules/type-fest": {
173 "version": "0.8.1",
174 "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
175 "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
176 "dev": true,
177 "engines": {
178 "node": ">=8"
179 }
180 },
158 "node_modules/@nodelib/fs.scandir": { 181 "node_modules/@nodelib/fs.scandir": {
159 "version": "2.1.4", 182 "version": "2.1.4",
160 "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", 183 "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
@@ -212,9 +235,9 @@
212 } 235 }
213 }, 236 },
214 "node_modules/@rollup/plugin-node-resolve": { 237 "node_modules/@rollup/plugin-node-resolve": {
215 "version": "11.2.0", 238 "version": "11.2.1",
216 "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.0.tgz", 239 "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz",
217 "integrity": "sha512-qHjNIKYt5pCcn+5RUBQxK8krhRvf1HnyVgUCcFFcweDS7fhkOLZeYh0mhHK6Ery8/bb9tvN/ubPzmfF0qjDCTA==", 240 "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==",
218 "dev": true, 241 "dev": true,
219 "dependencies": { 242 "dependencies": {
220 "@rollup/pluginutils": "^3.1.0", 243 "@rollup/pluginutils": "^3.1.0",
@@ -286,15 +309,15 @@
286 "dev": true 309 "dev": true
287 }, 310 },
288 "node_modules/@types/minimatch": { 311 "node_modules/@types/minimatch": {
289 "version": "3.0.3", 312 "version": "3.0.4",
290 "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", 313 "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz",
291 "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", 314 "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==",
292 "dev": true 315 "dev": true
293 }, 316 },
294 "node_modules/@types/mocha": { 317 "node_modules/@types/mocha": {
295 "version": "8.2.1", 318 "version": "8.2.2",
296 "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.1.tgz", 319 "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.2.tgz",
297 "integrity": "sha512-NysN+bNqj6E0Hv4CTGWSlPzMW6vTKjDpOteycDkV4IWBsO+PU48JonrPzV9ODjiI2XrjmA05KInLgF5ivZ/YGQ==", 320 "integrity": "sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw==",
298 "dev": true 321 "dev": true
299 }, 322 },
300 "node_modules/@types/node": { 323 "node_modules/@types/node": {
@@ -304,9 +327,9 @@
304 "dev": true 327 "dev": true
305 }, 328 },
306 "node_modules/@types/node-fetch": { 329 "node_modules/@types/node-fetch": {
307 "version": "2.5.8", 330 "version": "2.5.10",
308 "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.8.tgz", 331 "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.10.tgz",
309 "integrity": "sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==", 332 "integrity": "sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==",
310 "dev": true, 333 "dev": true,
311 "dependencies": { 334 "dependencies": {
312 "@types/node": "*", 335 "@types/node": "*",
@@ -323,19 +346,19 @@
323 } 346 }
324 }, 347 },
325 "node_modules/@types/vscode": { 348 "node_modules/@types/vscode": {
326 "version": "1.53.0", 349 "version": "1.55.0",
327 "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.53.0.tgz", 350 "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.55.0.tgz",
328 "integrity": "sha512-XjFWbSPOM0EKIT2XhhYm3D3cx3nn3lshMUcWNy1eqefk+oqRuBq8unVb6BYIZqXy9lQZyeUl7eaBCOZWv+LcXQ==", 351 "integrity": "sha512-49hysH7jneTQoSC8TWbAi7nKK9Lc5osQNjmDHVosrcU8o3jecD9GrK0Qyul8q4aGPSXRfNGqIp9CBdb13akETg==",
329 "dev": true 352 "dev": true
330 }, 353 },
331 "node_modules/@typescript-eslint/eslint-plugin": { 354 "node_modules/@typescript-eslint/eslint-plugin": {
332 "version": "4.15.2", 355 "version": "4.22.0",
333 "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.2.tgz", 356 "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.0.tgz",
334 "integrity": "sha512-uiQQeu9tWl3f1+oK0yoAv9lt/KXO24iafxgQTkIYO/kitruILGx3uH+QtIAHqxFV+yIsdnJH+alel9KuE3J15Q==", 357 "integrity": "sha512-U8SP9VOs275iDXaL08Ln1Fa/wLXfj5aTr/1c0t0j6CdbOnxh+TruXu1p4I0NAvdPBQgoPjHsgKn28mOi0FzfoA==",
335 "dev": true, 358 "dev": true,
336 "dependencies": { 359 "dependencies": {
337 "@typescript-eslint/experimental-utils": "4.15.2", 360 "@typescript-eslint/experimental-utils": "4.22.0",
338 "@typescript-eslint/scope-manager": "4.15.2", 361 "@typescript-eslint/scope-manager": "4.22.0",
339 "debug": "^4.1.1", 362 "debug": "^4.1.1",
340 "functional-red-black-tree": "^1.0.1", 363 "functional-red-black-tree": "^1.0.1",
341 "lodash": "^4.17.15", 364 "lodash": "^4.17.15",
@@ -361,15 +384,15 @@
361 } 384 }
362 }, 385 },
363 "node_modules/@typescript-eslint/experimental-utils": { 386 "node_modules/@typescript-eslint/experimental-utils": {
364 "version": "4.15.2", 387 "version": "4.22.0",
365 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.2.tgz", 388 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz",
366 "integrity": "sha512-Fxoshw8+R5X3/Vmqwsjc8nRO/7iTysRtDqx6rlfLZ7HbT8TZhPeQqbPjTyk2RheH3L8afumecTQnUc9EeXxohQ==", 389 "integrity": "sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg==",
367 "dev": true, 390 "dev": true,
368 "dependencies": { 391 "dependencies": {
369 "@types/json-schema": "^7.0.3", 392 "@types/json-schema": "^7.0.3",
370 "@typescript-eslint/scope-manager": "4.15.2", 393 "@typescript-eslint/scope-manager": "4.22.0",
371 "@typescript-eslint/types": "4.15.2", 394 "@typescript-eslint/types": "4.22.0",
372 "@typescript-eslint/typescript-estree": "4.15.2", 395 "@typescript-eslint/typescript-estree": "4.22.0",
373 "eslint-scope": "^5.0.0", 396 "eslint-scope": "^5.0.0",
374 "eslint-utils": "^2.0.0" 397 "eslint-utils": "^2.0.0"
375 }, 398 },
@@ -385,14 +408,14 @@
385 } 408 }
386 }, 409 },
387 "node_modules/@typescript-eslint/parser": { 410 "node_modules/@typescript-eslint/parser": {
388 "version": "4.15.2", 411 "version": "4.22.0",
389 "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.15.2.tgz", 412 "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.22.0.tgz",
390 "integrity": "sha512-SHeF8xbsC6z2FKXsaTb1tBCf0QZsjJ94H6Bo51Y1aVEZ4XAefaw5ZAilMoDPlGghe+qtq7XdTiDlGfVTOmvA+Q==", 413 "integrity": "sha512-z/bGdBJJZJN76nvAY9DkJANYgK3nlRstRRi74WHm3jjgf2I8AglrSY+6l7ogxOmn55YJ6oKZCLLy+6PW70z15Q==",
391 "dev": true, 414 "dev": true,
392 "dependencies": { 415 "dependencies": {
393 "@typescript-eslint/scope-manager": "4.15.2", 416 "@typescript-eslint/scope-manager": "4.22.0",
394 "@typescript-eslint/types": "4.15.2", 417 "@typescript-eslint/types": "4.22.0",
395 "@typescript-eslint/typescript-estree": "4.15.2", 418 "@typescript-eslint/typescript-estree": "4.22.0",
396 "debug": "^4.1.1" 419 "debug": "^4.1.1"
397 }, 420 },
398 "engines": { 421 "engines": {
@@ -412,13 +435,13 @@
412 } 435 }
413 }, 436 },
414 "node_modules/@typescript-eslint/scope-manager": { 437 "node_modules/@typescript-eslint/scope-manager": {
415 "version": "4.15.2", 438 "version": "4.22.0",
416 "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.2.tgz", 439 "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz",
417 "integrity": "sha512-Zm0tf/MSKuX6aeJmuXexgdVyxT9/oJJhaCkijv0DvJVT3ui4zY6XYd6iwIo/8GEZGy43cd7w1rFMiCLHbRzAPQ==", 440 "integrity": "sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q==",
418 "dev": true, 441 "dev": true,
419 "dependencies": { 442 "dependencies": {
420 "@typescript-eslint/types": "4.15.2", 443 "@typescript-eslint/types": "4.22.0",
421 "@typescript-eslint/visitor-keys": "4.15.2" 444 "@typescript-eslint/visitor-keys": "4.22.0"
422 }, 445 },
423 "engines": { 446 "engines": {
424 "node": "^8.10.0 || ^10.13.0 || >=11.10.1" 447 "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
@@ -429,9 +452,9 @@
429 } 452 }
430 }, 453 },
431 "node_modules/@typescript-eslint/types": { 454 "node_modules/@typescript-eslint/types": {
432 "version": "4.15.2", 455 "version": "4.22.0",
433 "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.15.2.tgz", 456 "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.0.tgz",
434 "integrity": "sha512-r7lW7HFkAarfUylJ2tKndyO9njwSyoy6cpfDKWPX6/ctZA+QyaYscAHXVAfJqtnY6aaTwDYrOhp+ginlbc7HfQ==", 457 "integrity": "sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA==",
435 "dev": true, 458 "dev": true,
436 "engines": { 459 "engines": {
437 "node": "^8.10.0 || ^10.13.0 || >=11.10.1" 460 "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
@@ -442,13 +465,13 @@
442 } 465 }
443 }, 466 },
444 "node_modules/@typescript-eslint/typescript-estree": { 467 "node_modules/@typescript-eslint/typescript-estree": {
445 "version": "4.15.2", 468 "version": "4.22.0",
446 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.2.tgz", 469 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz",
447 "integrity": "sha512-cGR8C2g5SPtHTQvAymEODeqx90pJHadWsgTtx6GbnTWKqsg7yp6Eaya9nFzUd4KrKhxdYTTFBiYeTPQaz/l8bw==", 470 "integrity": "sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg==",
448 "dev": true, 471 "dev": true,
449 "dependencies": { 472 "dependencies": {
450 "@typescript-eslint/types": "4.15.2", 473 "@typescript-eslint/types": "4.22.0",
451 "@typescript-eslint/visitor-keys": "4.15.2", 474 "@typescript-eslint/visitor-keys": "4.22.0",
452 "debug": "^4.1.1", 475 "debug": "^4.1.1",
453 "globby": "^11.0.1", 476 "globby": "^11.0.1",
454 "is-glob": "^4.0.1", 477 "is-glob": "^4.0.1",
@@ -469,12 +492,12 @@
469 } 492 }
470 }, 493 },
471 "node_modules/@typescript-eslint/visitor-keys": { 494 "node_modules/@typescript-eslint/visitor-keys": {
472 "version": "4.15.2", 495 "version": "4.22.0",
473 "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.2.tgz", 496 "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz",
474 "integrity": "sha512-TME1VgSb7wTwgENN5KVj4Nqg25hP8DisXxNBojM4Nn31rYaNDIocNm5cmjOFfh42n7NVERxWrDFoETO/76ePyg==", 497 "integrity": "sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw==",
475 "dev": true, 498 "dev": true,
476 "dependencies": { 499 "dependencies": {
477 "@typescript-eslint/types": "4.15.2", 500 "@typescript-eslint/types": "4.22.0",
478 "eslint-visitor-keys": "^2.0.0" 501 "eslint-visitor-keys": "^2.0.0"
479 }, 502 },
480 "engines": { 503 "engines": {
@@ -573,9 +596,9 @@
573 } 596 }
574 }, 597 },
575 "node_modules/anymatch": { 598 "node_modules/anymatch": {
576 "version": "3.1.1", 599 "version": "3.1.2",
577 "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", 600 "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
578 "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", 601 "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
579 "dev": true, 602 "dev": true,
580 "dependencies": { 603 "dependencies": {
581 "normalize-path": "^3.0.0", 604 "normalize-path": "^3.0.0",
@@ -631,9 +654,9 @@
631 } 654 }
632 }, 655 },
633 "node_modules/balanced-match": { 656 "node_modules/balanced-match": {
634 "version": "1.0.0", 657 "version": "1.0.2",
635 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 658 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
636 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 659 "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
637 }, 660 },
638 "node_modules/big-integer": { 661 "node_modules/big-integer": {
639 "version": "1.6.48", 662 "version": "1.6.48",
@@ -772,9 +795,9 @@
772 } 795 }
773 }, 796 },
774 "node_modules/chalk": { 797 "node_modules/chalk": {
775 "version": "4.1.0", 798 "version": "4.1.1",
776 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", 799 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
777 "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", 800 "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
778 "dev": true, 801 "dev": true,
779 "dependencies": { 802 "dependencies": {
780 "ansi-styles": "^4.1.0", 803 "ansi-styles": "^4.1.0",
@@ -788,35 +811,33 @@
788 } 811 }
789 }, 812 },
790 "node_modules/cheerio": { 813 "node_modules/cheerio": {
791 "version": "1.0.0-rc.5", 814 "version": "1.0.0-rc.6",
792 "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.5.tgz", 815 "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.6.tgz",
793 "integrity": "sha512-yoqps/VCaZgN4pfXtenwHROTp8NG6/Hlt4Jpz2FEP0ZJQ+ZUkVDd0hAPDNKhj3nakpfPt/CNs57yEtxD1bXQiw==", 816 "integrity": "sha512-hjx1XE1M/D5pAtMgvWwE21QClmAEeGHOIDfycgmndisdNgI6PE1cGRQkMGBcsbUbmEQyWu5PJLUcAOjtQS8DWw==",
794 "dev": true, 817 "dev": true,
795 "dependencies": { 818 "dependencies": {
796 "cheerio-select-tmp": "^0.1.0", 819 "cheerio-select": "^1.3.0",
797 "dom-serializer": "~1.2.0", 820 "dom-serializer": "^1.3.1",
798 "domhandler": "^4.0.0", 821 "domhandler": "^4.1.0",
799 "entities": "~2.1.0", 822 "htmlparser2": "^6.1.0",
800 "htmlparser2": "^6.0.0", 823 "parse5": "^6.0.1",
801 "parse5": "^6.0.0", 824 "parse5-htmlparser2-tree-adapter": "^6.0.1"
802 "parse5-htmlparser2-tree-adapter": "^6.0.0"
803 }, 825 },
804 "engines": { 826 "engines": {
805 "node": ">= 0.12" 827 "node": ">= 0.12"
806 } 828 }
807 }, 829 },
808 "node_modules/cheerio-select-tmp": { 830 "node_modules/cheerio-select": {
809 "version": "0.1.1", 831 "version": "1.4.0",
810 "resolved": "https://registry.npmjs.org/cheerio-select-tmp/-/cheerio-select-tmp-0.1.1.tgz", 832 "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.4.0.tgz",
811 "integrity": "sha512-YYs5JvbpU19VYJyj+F7oYrIE2BOll1/hRU7rEy/5+v9BzkSo3bK81iAeeQEMI92vRIxz677m72UmJUiVwwgjfQ==", 833 "integrity": "sha512-sobR3Yqz27L553Qa7cK6rtJlMDbiKPdNywtR95Sj/YgfpLfy0u6CGJuaBKe5YE/vTc23SCRKxWSdlon/w6I/Ew==",
812 "deprecated": "Use cheerio-select instead",
813 "dev": true, 834 "dev": true,
814 "dependencies": { 835 "dependencies": {
815 "css-select": "^3.1.2", 836 "css-select": "^4.1.2",
816 "css-what": "^4.0.0", 837 "css-what": "^5.0.0",
817 "domelementtype": "^2.1.0", 838 "domelementtype": "^2.2.0",
818 "domhandler": "^4.0.0", 839 "domhandler": "^4.2.0",
819 "domutils": "^2.4.4" 840 "domutils": "^2.6.0"
820 }, 841 },
821 "funding": { 842 "funding": {
822 "url": "https://github.com/sponsors/fb55" 843 "url": "https://github.com/sponsors/fb55"
@@ -830,7 +851,6 @@
830 "dependencies": { 851 "dependencies": {
831 "anymatch": "~3.1.1", 852 "anymatch": "~3.1.1",
832 "braces": "~3.0.2", 853 "braces": "~3.0.2",
833 "fsevents": "~2.3.1",
834 "glob-parent": "~5.1.0", 854 "glob-parent": "~5.1.0",
835 "is-binary-path": "~2.1.0", 855 "is-binary-path": "~2.1.0",
836 "is-glob": "~4.0.1", 856 "is-glob": "~4.0.1",
@@ -929,15 +949,15 @@
929 } 949 }
930 }, 950 },
931 "node_modules/css-select": { 951 "node_modules/css-select": {
932 "version": "3.1.2", 952 "version": "4.1.2",
933 "resolved": "https://registry.npmjs.org/css-select/-/css-select-3.1.2.tgz", 953 "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.2.tgz",
934 "integrity": "sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==", 954 "integrity": "sha512-nu5ye2Hg/4ISq4XqdLY2bEatAcLIdt3OYGFc9Tm9n7VSlFBcfRv0gBNksHRgSdUDQGtN3XrZ94ztW+NfzkFSUw==",
935 "dev": true, 955 "dev": true,
936 "dependencies": { 956 "dependencies": {
937 "boolbase": "^1.0.0", 957 "boolbase": "^1.0.0",
938 "css-what": "^4.0.0", 958 "css-what": "^5.0.0",
939 "domhandler": "^4.0.0", 959 "domhandler": "^4.2.0",
940 "domutils": "^2.4.3", 960 "domutils": "^2.6.0",
941 "nth-check": "^2.0.0" 961 "nth-check": "^2.0.0"
942 }, 962 },
943 "funding": { 963 "funding": {
@@ -945,9 +965,9 @@
945 } 965 }
946 }, 966 },
947 "node_modules/css-what": { 967 "node_modules/css-what": {
948 "version": "4.0.0", 968 "version": "5.0.0",
949 "resolved": "https://registry.npmjs.org/css-what/-/css-what-4.0.0.tgz", 969 "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.0.tgz",
950 "integrity": "sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==", 970 "integrity": "sha512-qxyKHQvgKwzwDWC/rGbT821eJalfupxYW2qbSJSAtdSTimsr/MlaGONoNLllaUPZWf8QnbcKM/kPVYUQuEKAFA==",
951 "dev": true, 971 "dev": true,
952 "engines": { 972 "engines": {
953 "node": ">= 6" 973 "node": ">= 6"
@@ -1048,9 +1068,9 @@
1048 } 1068 }
1049 }, 1069 },
1050 "node_modules/dom-serializer": { 1070 "node_modules/dom-serializer": {
1051 "version": "1.2.0", 1071 "version": "1.3.1",
1052 "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", 1072 "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.1.tgz",
1053 "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==", 1073 "integrity": "sha512-Pv2ZluG5ife96udGgEDovOOOA5UELkltfJpnIExPrAk1LTvecolUGn6lIaoLh86d83GiB86CjzciMd9BuRB71Q==",
1054 "dev": true, 1074 "dev": true,
1055 "dependencies": { 1075 "dependencies": {
1056 "domelementtype": "^2.0.1", 1076 "domelementtype": "^2.0.1",
@@ -1062,9 +1082,9 @@
1062 } 1082 }
1063 }, 1083 },
1064 "node_modules/domelementtype": { 1084 "node_modules/domelementtype": {
1065 "version": "2.1.0", 1085 "version": "2.2.0",
1066 "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", 1086 "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
1067 "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==", 1087 "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
1068 "dev": true, 1088 "dev": true,
1069 "funding": [ 1089 "funding": [
1070 { 1090 {
@@ -1074,12 +1094,12 @@
1074 ] 1094 ]
1075 }, 1095 },
1076 "node_modules/domhandler": { 1096 "node_modules/domhandler": {
1077 "version": "4.0.0", 1097 "version": "4.2.0",
1078 "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", 1098 "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz",
1079 "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", 1099 "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==",
1080 "dev": true, 1100 "dev": true,
1081 "dependencies": { 1101 "dependencies": {
1082 "domelementtype": "^2.1.0" 1102 "domelementtype": "^2.2.0"
1083 }, 1103 },
1084 "engines": { 1104 "engines": {
1085 "node": ">= 4" 1105 "node": ">= 4"
@@ -1089,14 +1109,14 @@
1089 } 1109 }
1090 }, 1110 },
1091 "node_modules/domutils": { 1111 "node_modules/domutils": {
1092 "version": "2.4.4", 1112 "version": "2.6.0",
1093 "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.4.tgz", 1113 "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.6.0.tgz",
1094 "integrity": "sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==", 1114 "integrity": "sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA==",
1095 "dev": true, 1115 "dev": true,
1096 "dependencies": { 1116 "dependencies": {
1097 "dom-serializer": "^1.0.1", 1117 "dom-serializer": "^1.0.1",
1098 "domelementtype": "^2.0.1", 1118 "domelementtype": "^2.2.0",
1099 "domhandler": "^4.0.0" 1119 "domhandler": "^4.2.0"
1100 }, 1120 },
1101 "funding": { 1121 "funding": {
1102 "url": "https://github.com/fb55/domutils?sponsor=1" 1122 "url": "https://github.com/fb55/domutils?sponsor=1"
@@ -1167,9 +1187,9 @@
1167 } 1187 }
1168 }, 1188 },
1169 "node_modules/entities": { 1189 "node_modules/entities": {
1170 "version": "2.1.0", 1190 "version": "2.2.0",
1171 "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", 1191 "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
1172 "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", 1192 "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
1173 "dev": true, 1193 "dev": true,
1174 "funding": { 1194 "funding": {
1175 "url": "https://github.com/fb55/entities?sponsor=1" 1195 "url": "https://github.com/fb55/entities?sponsor=1"
@@ -1197,13 +1217,13 @@
1197 } 1217 }
1198 }, 1218 },
1199 "node_modules/eslint": { 1219 "node_modules/eslint": {
1200 "version": "7.20.0", 1220 "version": "7.25.0",
1201 "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz", 1221 "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.25.0.tgz",
1202 "integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==", 1222 "integrity": "sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw==",
1203 "dev": true, 1223 "dev": true,
1204 "dependencies": { 1224 "dependencies": {
1205 "@babel/code-frame": "7.12.11", 1225 "@babel/code-frame": "7.12.11",
1206 "@eslint/eslintrc": "^0.3.0", 1226 "@eslint/eslintrc": "^0.4.0",
1207 "ajv": "^6.10.0", 1227 "ajv": "^6.10.0",
1208 "chalk": "^4.0.0", 1228 "chalk": "^4.0.0",
1209 "cross-spawn": "^7.0.2", 1229 "cross-spawn": "^7.0.2",
@@ -1216,10 +1236,10 @@
1216 "espree": "^7.3.1", 1236 "espree": "^7.3.1",
1217 "esquery": "^1.4.0", 1237 "esquery": "^1.4.0",
1218 "esutils": "^2.0.2", 1238 "esutils": "^2.0.2",
1219 "file-entry-cache": "^6.0.0", 1239 "file-entry-cache": "^6.0.1",
1220 "functional-red-black-tree": "^1.0.1", 1240 "functional-red-black-tree": "^1.0.1",
1221 "glob-parent": "^5.0.0", 1241 "glob-parent": "^5.0.0",
1222 "globals": "^12.1.0", 1242 "globals": "^13.6.0",
1223 "ignore": "^4.0.6", 1243 "ignore": "^4.0.6",
1224 "import-fresh": "^3.0.0", 1244 "import-fresh": "^3.0.0",
1225 "imurmurhash": "^0.1.4", 1245 "imurmurhash": "^0.1.4",
@@ -1227,7 +1247,7 @@
1227 "js-yaml": "^3.13.1", 1247 "js-yaml": "^3.13.1",
1228 "json-stable-stringify-without-jsonify": "^1.0.1", 1248 "json-stable-stringify-without-jsonify": "^1.0.1",
1229 "levn": "^0.4.1", 1249 "levn": "^0.4.1",
1230 "lodash": "^4.17.20", 1250 "lodash": "^4.17.21",
1231 "minimatch": "^3.0.4", 1251 "minimatch": "^3.0.4",
1232 "natural-compare": "^1.4.0", 1252 "natural-compare": "^1.4.0",
1233 "optionator": "^0.9.1", 1253 "optionator": "^0.9.1",
@@ -1434,9 +1454,9 @@
1434 "dev": true 1454 "dev": true
1435 }, 1455 },
1436 "node_modules/fastq": { 1456 "node_modules/fastq": {
1437 "version": "1.10.1", 1457 "version": "1.11.0",
1438 "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.1.tgz", 1458 "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
1439 "integrity": "sha512-AWuv6Ery3pM+dY7LYS8YIaCiQvUaos9OB1RyNgaOWnaX+Tik7Onvcsf8x8c+YtDeT0maYLniBip2hox5KtEXXA==", 1459 "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
1440 "dev": true, 1460 "dev": true,
1441 "dependencies": { 1461 "dependencies": {
1442 "reusify": "^1.0.4" 1462 "reusify": "^1.0.4"
@@ -1622,9 +1642,9 @@
1622 } 1642 }
1623 }, 1643 },
1624 "node_modules/glob-parent": { 1644 "node_modules/glob-parent": {
1625 "version": "5.1.1", 1645 "version": "5.1.2",
1626 "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 1646 "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
1627 "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 1647 "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
1628 "dev": true, 1648 "dev": true,
1629 "dependencies": { 1649 "dependencies": {
1630 "is-glob": "^4.0.1" 1650 "is-glob": "^4.0.1"
@@ -1634,12 +1654,12 @@
1634 } 1654 }
1635 }, 1655 },
1636 "node_modules/globals": { 1656 "node_modules/globals": {
1637 "version": "12.4.0", 1657 "version": "13.8.0",
1638 "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", 1658 "resolved": "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz",
1639 "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", 1659 "integrity": "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==",
1640 "dev": true, 1660 "dev": true,
1641 "dependencies": { 1661 "dependencies": {
1642 "type-fest": "^0.8.1" 1662 "type-fest": "^0.20.2"
1643 }, 1663 },
1644 "engines": { 1664 "engines": {
1645 "node": ">=8" 1665 "node": ">=8"
@@ -1649,9 +1669,9 @@
1649 } 1669 }
1650 }, 1670 },
1651 "node_modules/globby": { 1671 "node_modules/globby": {
1652 "version": "11.0.2", 1672 "version": "11.0.3",
1653 "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", 1673 "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
1654 "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", 1674 "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
1655 "dev": true, 1675 "dev": true,
1656 "dependencies": { 1676 "dependencies": {
1657 "array-union": "^2.1.0", 1677 "array-union": "^2.1.0",
@@ -1723,9 +1743,9 @@
1723 } 1743 }
1724 }, 1744 },
1725 "node_modules/htmlparser2": { 1745 "node_modules/htmlparser2": {
1726 "version": "6.0.0", 1746 "version": "6.1.0",
1727 "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.0.0.tgz", 1747 "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
1728 "integrity": "sha512-numTQtDZMoh78zJpaNdJ9MXb2cv5G3jwUoe3dMQODubZvLoGvTE/Ofp6sHvH8OGKcN/8A47pGLi/k58xHP/Tfw==", 1748 "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
1729 "dev": true, 1749 "dev": true,
1730 "funding": [ 1750 "funding": [
1731 "https://github.com/fb55/htmlparser2?sponsor=1", 1751 "https://github.com/fb55/htmlparser2?sponsor=1",
@@ -1737,7 +1757,7 @@
1737 "dependencies": { 1757 "dependencies": {
1738 "domelementtype": "^2.0.1", 1758 "domelementtype": "^2.0.1",
1739 "domhandler": "^4.0.0", 1759 "domhandler": "^4.0.0",
1740 "domutils": "^2.4.4", 1760 "domutils": "^2.5.2",
1741 "entities": "^2.0.0" 1761 "entities": "^2.0.0"
1742 } 1762 }
1743 }, 1763 },
@@ -1830,9 +1850,9 @@
1830 } 1850 }
1831 }, 1851 },
1832 "node_modules/is-core-module": { 1852 "node_modules/is-core-module": {
1833 "version": "2.2.0", 1853 "version": "2.3.0",
1834 "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", 1854 "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.3.0.tgz",
1835 "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", 1855 "integrity": "sha512-xSphU2KG9867tsYdLD4RWQ1VqdFl4HTO9Thf3I/3dLEfr0dbPTWKsuCKrgqMljg4nPE+Gq0VCnzT3gr0CyBmsw==",
1836 "dev": true, 1856 "dev": true,
1837 "dependencies": { 1857 "dependencies": {
1838 "has": "^1.0.3" 1858 "has": "^1.0.3"
@@ -2005,6 +2025,24 @@
2005 "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 2025 "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
2006 "dev": true 2026 "dev": true
2007 }, 2027 },
2028 "node_modules/lodash.clonedeep": {
2029 "version": "4.5.0",
2030 "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
2031 "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
2032 "dev": true
2033 },
2034 "node_modules/lodash.flatten": {
2035 "version": "4.4.0",
2036 "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
2037 "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=",
2038 "dev": true
2039 },
2040 "node_modules/lodash.truncate": {
2041 "version": "4.4.2",
2042 "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
2043 "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
2044 "dev": true
2045 },
2008 "node_modules/log-symbols": { 2046 "node_modules/log-symbols": {
2009 "version": "4.0.0", 2047 "version": "4.0.0",
2010 "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", 2048 "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
@@ -2075,16 +2113,16 @@
2075 } 2113 }
2076 }, 2114 },
2077 "node_modules/micromatch": { 2115 "node_modules/micromatch": {
2078 "version": "4.0.2", 2116 "version": "4.0.4",
2079 "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", 2117 "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
2080 "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", 2118 "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
2081 "dev": true, 2119 "dev": true,
2082 "dependencies": { 2120 "dependencies": {
2083 "braces": "^3.0.1", 2121 "braces": "^3.0.1",
2084 "picomatch": "^2.0.5" 2122 "picomatch": "^2.2.3"
2085 }, 2123 },
2086 "engines": { 2124 "engines": {
2087 "node": ">=8" 2125 "node": ">=8.6"
2088 } 2126 }
2089 }, 2127 },
2090 "node_modules/mime": { 2128 "node_modules/mime": {
@@ -2100,21 +2138,21 @@
2100 } 2138 }
2101 }, 2139 },
2102 "node_modules/mime-db": { 2140 "node_modules/mime-db": {
2103 "version": "1.46.0", 2141 "version": "1.47.0",
2104 "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", 2142 "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz",
2105 "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", 2143 "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==",
2106 "dev": true, 2144 "dev": true,
2107 "engines": { 2145 "engines": {
2108 "node": ">= 0.6" 2146 "node": ">= 0.6"
2109 } 2147 }
2110 }, 2148 },
2111 "node_modules/mime-types": { 2149 "node_modules/mime-types": {
2112 "version": "2.1.29", 2150 "version": "2.1.30",
2113 "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", 2151 "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz",
2114 "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", 2152 "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==",
2115 "dev": true, 2153 "dev": true,
2116 "dependencies": { 2154 "dependencies": {
2117 "mime-db": "1.46.0" 2155 "mime-db": "1.47.0"
2118 }, 2156 },
2119 "engines": { 2157 "engines": {
2120 "node": ">= 0.6" 2158 "node": ">= 0.6"
@@ -2150,9 +2188,9 @@
2150 } 2188 }
2151 }, 2189 },
2152 "node_modules/mocha": { 2190 "node_modules/mocha": {
2153 "version": "8.3.0", 2191 "version": "8.3.2",
2154 "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.0.tgz", 2192 "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.2.tgz",
2155 "integrity": "sha512-TQqyC89V1J/Vxx0DhJIXlq9gbbL9XFNdeLQ1+JsnZsVaSOV1z3tWfw0qZmQJGQRIfkvZcs7snQnZnOCKoldq1Q==", 2193 "integrity": "sha512-UdmISwr/5w+uXLPKspgoV7/RXZwKRTiTjJ2/AC5ZiEztIoOYdfKb19+9jNmEInzx5pBsCyJQzarAxqIGBNYJhg==",
2156 "dev": true, 2194 "dev": true,
2157 "dependencies": { 2195 "dependencies": {
2158 "@ungap/promise-all-settled": "1.1.2", 2196 "@ungap/promise-all-settled": "1.1.2",
@@ -2474,9 +2512,9 @@
2474 "dev": true 2512 "dev": true
2475 }, 2513 },
2476 "node_modules/picomatch": { 2514 "node_modules/picomatch": {
2477 "version": "2.2.2", 2515 "version": "2.2.3",
2478 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 2516 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz",
2479 "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", 2517 "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==",
2480 "dev": true, 2518 "dev": true,
2481 "engines": { 2519 "engines": {
2482 "node": ">=8.6" 2520 "node": ">=8.6"
@@ -2525,9 +2563,9 @@
2525 } 2563 }
2526 }, 2564 },
2527 "node_modules/queue-microtask": { 2565 "node_modules/queue-microtask": {
2528 "version": "1.2.2", 2566 "version": "1.2.3",
2529 "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz", 2567 "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
2530 "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==", 2568 "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
2531 "dev": true, 2569 "dev": true,
2532 "funding": [ 2570 "funding": [
2533 { 2571 {
@@ -2676,13 +2714,10 @@
2676 } 2714 }
2677 }, 2715 },
2678 "node_modules/rollup": { 2716 "node_modules/rollup": {
2679 "version": "2.39.1", 2717 "version": "2.45.2",
2680 "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.39.1.tgz", 2718 "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.45.2.tgz",
2681 "integrity": "sha512-9rfr0Z6j+vE+eayfNVFr1KZ+k+jiUl2+0e4quZafy1x6SFCjzFspfRSO2ZZQeWeX9noeDTUDgg6eCENiEPFvQg==", 2719 "integrity": "sha512-kRRU7wXzFHUzBIv0GfoFFIN3m9oteY4uAsKllIpQDId5cfnkWF2J130l+27dzDju0E6MScKiV0ZM5Bw8m4blYQ==",
2682 "dev": true, 2720 "dev": true,
2683 "dependencies": {
2684 "fsevents": "~2.3.1"
2685 },
2686 "bin": { 2721 "bin": {
2687 "rollup": "dist/bin/rollup" 2722 "rollup": "dist/bin/rollup"
2688 }, 2723 },
@@ -2737,9 +2772,9 @@
2737 ] 2772 ]
2738 }, 2773 },
2739 "node_modules/semver": { 2774 "node_modules/semver": {
2740 "version": "7.3.4", 2775 "version": "7.3.5",
2741 "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", 2776 "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
2742 "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", 2777 "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
2743 "dependencies": { 2778 "dependencies": {
2744 "lru-cache": "^6.0.0" 2779 "lru-cache": "^6.0.0"
2745 }, 2780 },
@@ -2846,9 +2881,9 @@
2846 "dev": true 2881 "dev": true
2847 }, 2882 },
2848 "node_modules/string-width": { 2883 "node_modules/string-width": {
2849 "version": "4.2.0", 2884 "version": "4.2.2",
2850 "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 2885 "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
2851 "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 2886 "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
2852 "dev": true, 2887 "dev": true,
2853 "dependencies": { 2888 "dependencies": {
2854 "emoji-regex": "^8.0.0", 2889 "emoji-regex": "^8.0.0",
@@ -2896,24 +2931,27 @@
2896 } 2931 }
2897 }, 2932 },
2898 "node_modules/table": { 2933 "node_modules/table": {
2899 "version": "6.0.7", 2934 "version": "6.5.1",
2900 "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", 2935 "resolved": "https://registry.npmjs.org/table/-/table-6.5.1.tgz",
2901 "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", 2936 "integrity": "sha512-xGDXWTBJxahkzPQCsn1S9ESHEenU7TbMD5Iv4FeopXv/XwJyWatFjfbor+6ipI10/MNPXBYUamYukOrbPZ9L/w==",
2902 "dev": true, 2937 "dev": true,
2903 "dependencies": { 2938 "dependencies": {
2904 "ajv": "^7.0.2", 2939 "ajv": "^8.0.1",
2905 "lodash": "^4.17.20", 2940 "lodash.clonedeep": "^4.5.0",
2941 "lodash.flatten": "^4.4.0",
2942 "lodash.truncate": "^4.4.2",
2906 "slice-ansi": "^4.0.0", 2943 "slice-ansi": "^4.0.0",
2907 "string-width": "^4.2.0" 2944 "string-width": "^4.2.0",
2945 "strip-ansi": "^6.0.0"
2908 }, 2946 },
2909 "engines": { 2947 "engines": {
2910 "node": ">=10.0.0" 2948 "node": ">=10.0.0"
2911 } 2949 }
2912 }, 2950 },
2913 "node_modules/table/node_modules/ajv": { 2951 "node_modules/table/node_modules/ajv": {
2914 "version": "7.1.1", 2952 "version": "8.1.0",
2915 "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz", 2953 "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.1.0.tgz",
2916 "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==", 2954 "integrity": "sha512-B/Sk2Ix7A36fs/ZkuGLIR86EdjbgR6fsAcbx9lOP/QBSXujDNbVmIS/U4Itz5k8fPFDeVZl/zQ/gJW4Jrq6XjQ==",
2917 "dev": true, 2955 "dev": true,
2918 "dependencies": { 2956 "dependencies": {
2919 "fast-deep-equal": "^3.1.1", 2957 "fast-deep-equal": "^3.1.1",
@@ -2969,15 +3007,15 @@
2969 "dev": true 3007 "dev": true
2970 }, 3008 },
2971 "node_modules/tslib": { 3009 "node_modules/tslib": {
2972 "version": "2.1.0", 3010 "version": "2.2.0",
2973 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", 3011 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
2974 "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", 3012 "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==",
2975 "dev": true 3013 "dev": true
2976 }, 3014 },
2977 "node_modules/tsutils": { 3015 "node_modules/tsutils": {
2978 "version": "3.20.0", 3016 "version": "3.21.0",
2979 "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.20.0.tgz", 3017 "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
2980 "integrity": "sha512-RYbuQuvkhuqVeXweWT3tJLKOEJ/UUw9GjNEZGWdrLLlM+611o1gwLHBpxoFJKKl25fLprp2eVthtKs5JOrNeXg==", 3018 "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
2981 "dev": true, 3019 "dev": true,
2982 "dependencies": { 3020 "dependencies": {
2983 "tslib": "^1.8.1" 3021 "tslib": "^1.8.1"
@@ -3017,12 +3055,15 @@
3017 } 3055 }
3018 }, 3056 },
3019 "node_modules/type-fest": { 3057 "node_modules/type-fest": {
3020 "version": "0.8.1", 3058 "version": "0.20.2",
3021 "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", 3059 "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
3022 "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", 3060 "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
3023 "dev": true, 3061 "dev": true,
3024 "engines": { 3062 "engines": {
3025 "node": ">=8" 3063 "node": ">=10"
3064 },
3065 "funding": {
3066 "url": "https://github.com/sponsors/sindresorhus"
3026 } 3067 }
3027 }, 3068 },
3028 "node_modules/typed-rest-client": { 3069 "node_modules/typed-rest-client": {
@@ -3036,9 +3077,9 @@
3036 } 3077 }
3037 }, 3078 },
3038 "node_modules/typescript": { 3079 "node_modules/typescript": {
3039 "version": "4.1.5", 3080 "version": "4.2.4",
3040 "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz", 3081 "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
3041 "integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==", 3082 "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
3042 "dev": true, 3083 "dev": true,
3043 "bin": { 3084 "bin": {
3044 "tsc": "bin/tsc", 3085 "tsc": "bin/tsc",
@@ -3119,15 +3160,15 @@
3119 "dev": true 3160 "dev": true
3120 }, 3161 },
3121 "node_modules/v8-compile-cache": { 3162 "node_modules/v8-compile-cache": {
3122 "version": "2.2.0", 3163 "version": "2.3.0",
3123 "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", 3164 "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
3124 "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", 3165 "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
3125 "dev": true 3166 "dev": true
3126 }, 3167 },
3127 "node_modules/vsce": { 3168 "node_modules/vsce": {
3128 "version": "1.85.0", 3169 "version": "1.87.1",
3129 "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.85.0.tgz", 3170 "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.87.1.tgz",
3130 "integrity": "sha512-YVFwjXWvHRwk75mm3iL4Wr3auCdbBPTv2amtLf97ccqH0hkt0ZVBddu7iOs4HSEbSr9xiiaZwQHUsqMm6Ks0ag==", 3171 "integrity": "sha512-3tSUWZl9AmhZrqy/UVUpdPODSzBiCGjIr/AMSSgF2PuFLSdrh+6kiOr2Ath7bpQEXOxf55hNgz3qdO5MuEJmww==",
3131 "dev": true, 3172 "dev": true,
3132 "dependencies": { 3173 "dependencies": {
3133 "azure-devops-node-api": "^7.2.0", 3174 "azure-devops-node-api": "^7.2.0",
@@ -3283,9 +3324,9 @@
3283 "integrity": "sha512-VGzh06oynbYa6JbTKUbxOEZN7CYEtWhN7DK5wfzUpeCJl8X8xZX39g2PVfpqXrIEduu7dcJgK007KgnX9tHNKA==" 3324 "integrity": "sha512-VGzh06oynbYa6JbTKUbxOEZN7CYEtWhN7DK5wfzUpeCJl8X8xZX39g2PVfpqXrIEduu7dcJgK007KgnX9tHNKA=="
3284 }, 3325 },
3285 "node_modules/vscode-test": { 3326 "node_modules/vscode-test": {
3286 "version": "1.5.1", 3327 "version": "1.5.2",
3287 "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.5.1.tgz", 3328 "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.5.2.tgz",
3288 "integrity": "sha512-tDloz6euDne+GeUSglhufL0c2xhuYAPAT74hjsuGxfflALfXF9bYnJ7ehZEeVkr/ZnQEh/T8EBrfPL+m0h5qEQ==", 3329 "integrity": "sha512-x9PVfKxF6EInH9iSFGQi0V8H5zIW1fC7RAer6yNQR6sy3WyOwlWkuT3I+wf75xW/cO53hxMi1aj/EvqQfDFOAg==",
3289 "dev": true, 3330 "dev": true,
3290 "dependencies": { 3331 "dependencies": {
3291 "http-proxy-agent": "^4.0.1", 3332 "http-proxy-agent": "^4.0.1",
@@ -3403,9 +3444,9 @@
3403 "dev": true 3444 "dev": true
3404 }, 3445 },
3405 "node_modules/y18n": { 3446 "node_modules/y18n": {
3406 "version": "5.0.5", 3447 "version": "5.0.8",
3407 "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", 3448 "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
3408 "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", 3449 "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
3409 "dev": true, 3450 "dev": true,
3410 "engines": { 3451 "engines": {
3411 "node": ">=10" 3452 "node": ">=10"
@@ -3507,9 +3548,9 @@
3507 "dev": true 3548 "dev": true
3508 }, 3549 },
3509 "@babel/highlight": { 3550 "@babel/highlight": {
3510 "version": "7.12.13", 3551 "version": "7.13.10",
3511 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", 3552 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz",
3512 "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", 3553 "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==",
3513 "dev": true, 3554 "dev": true,
3514 "requires": { 3555 "requires": {
3515 "@babel/helper-validator-identifier": "^7.12.11", 3556 "@babel/helper-validator-identifier": "^7.12.11",
@@ -3576,9 +3617,9 @@
3576 } 3617 }
3577 }, 3618 },
3578 "@eslint/eslintrc": { 3619 "@eslint/eslintrc": {
3579 "version": "0.3.0", 3620 "version": "0.4.0",
3580 "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", 3621 "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
3581 "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", 3622 "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
3582 "dev": true, 3623 "dev": true,
3583 "requires": { 3624 "requires": {
3584 "ajv": "^6.12.4", 3625 "ajv": "^6.12.4",
@@ -3588,9 +3629,25 @@
3588 "ignore": "^4.0.6", 3629 "ignore": "^4.0.6",
3589 "import-fresh": "^3.2.1", 3630 "import-fresh": "^3.2.1",
3590 "js-yaml": "^3.13.1", 3631 "js-yaml": "^3.13.1",
3591 "lodash": "^4.17.20",
3592 "minimatch": "^3.0.4", 3632 "minimatch": "^3.0.4",
3593 "strip-json-comments": "^3.1.1" 3633 "strip-json-comments": "^3.1.1"
3634 },
3635 "dependencies": {
3636 "globals": {
3637 "version": "12.4.0",
3638 "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
3639 "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
3640 "dev": true,
3641 "requires": {
3642 "type-fest": "^0.8.1"
3643 }
3644 },
3645 "type-fest": {
3646 "version": "0.8.1",
3647 "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
3648 "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
3649 "dev": true
3650 }
3594 } 3651 }
3595 }, 3652 },
3596 "@nodelib/fs.scandir": { 3653 "@nodelib/fs.scandir": {
@@ -3635,9 +3692,9 @@
3635 } 3692 }
3636 }, 3693 },
3637 "@rollup/plugin-node-resolve": { 3694 "@rollup/plugin-node-resolve": {
3638 "version": "11.2.0", 3695 "version": "11.2.1",
3639 "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.0.tgz", 3696 "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz",
3640 "integrity": "sha512-qHjNIKYt5pCcn+5RUBQxK8krhRvf1HnyVgUCcFFcweDS7fhkOLZeYh0mhHK6Ery8/bb9tvN/ubPzmfF0qjDCTA==", 3697 "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==",
3641 "dev": true, 3698 "dev": true,
3642 "requires": { 3699 "requires": {
3643 "@rollup/pluginutils": "^3.1.0", 3700 "@rollup/pluginutils": "^3.1.0",
@@ -3696,15 +3753,15 @@
3696 "dev": true 3753 "dev": true
3697 }, 3754 },
3698 "@types/minimatch": { 3755 "@types/minimatch": {
3699 "version": "3.0.3", 3756 "version": "3.0.4",
3700 "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", 3757 "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz",
3701 "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", 3758 "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==",
3702 "dev": true 3759 "dev": true
3703 }, 3760 },
3704 "@types/mocha": { 3761 "@types/mocha": {
3705 "version": "8.2.1", 3762 "version": "8.2.2",
3706 "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.1.tgz", 3763 "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.2.tgz",
3707 "integrity": "sha512-NysN+bNqj6E0Hv4CTGWSlPzMW6vTKjDpOteycDkV4IWBsO+PU48JonrPzV9ODjiI2XrjmA05KInLgF5ivZ/YGQ==", 3764 "integrity": "sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw==",
3708 "dev": true 3765 "dev": true
3709 }, 3766 },
3710 "@types/node": { 3767 "@types/node": {
@@ -3714,9 +3771,9 @@
3714 "dev": true 3771 "dev": true
3715 }, 3772 },
3716 "@types/node-fetch": { 3773 "@types/node-fetch": {
3717 "version": "2.5.8", 3774 "version": "2.5.10",
3718 "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.8.tgz", 3775 "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.10.tgz",
3719 "integrity": "sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==", 3776 "integrity": "sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==",
3720 "dev": true, 3777 "dev": true,
3721 "requires": { 3778 "requires": {
3722 "@types/node": "*", 3779 "@types/node": "*",
@@ -3733,19 +3790,19 @@
3733 } 3790 }
3734 }, 3791 },
3735 "@types/vscode": { 3792 "@types/vscode": {
3736 "version": "1.53.0", 3793 "version": "1.55.0",
3737 "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.53.0.tgz", 3794 "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.55.0.tgz",
3738 "integrity": "sha512-XjFWbSPOM0EKIT2XhhYm3D3cx3nn3lshMUcWNy1eqefk+oqRuBq8unVb6BYIZqXy9lQZyeUl7eaBCOZWv+LcXQ==", 3795 "integrity": "sha512-49hysH7jneTQoSC8TWbAi7nKK9Lc5osQNjmDHVosrcU8o3jecD9GrK0Qyul8q4aGPSXRfNGqIp9CBdb13akETg==",
3739 "dev": true 3796 "dev": true
3740 }, 3797 },
3741 "@typescript-eslint/eslint-plugin": { 3798 "@typescript-eslint/eslint-plugin": {
3742 "version": "4.15.2", 3799 "version": "4.22.0",
3743 "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.2.tgz", 3800 "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.0.tgz",
3744 "integrity": "sha512-uiQQeu9tWl3f1+oK0yoAv9lt/KXO24iafxgQTkIYO/kitruILGx3uH+QtIAHqxFV+yIsdnJH+alel9KuE3J15Q==", 3801 "integrity": "sha512-U8SP9VOs275iDXaL08Ln1Fa/wLXfj5aTr/1c0t0j6CdbOnxh+TruXu1p4I0NAvdPBQgoPjHsgKn28mOi0FzfoA==",
3745 "dev": true, 3802 "dev": true,
3746 "requires": { 3803 "requires": {
3747 "@typescript-eslint/experimental-utils": "4.15.2", 3804 "@typescript-eslint/experimental-utils": "4.22.0",
3748 "@typescript-eslint/scope-manager": "4.15.2", 3805 "@typescript-eslint/scope-manager": "4.22.0",
3749 "debug": "^4.1.1", 3806 "debug": "^4.1.1",
3750 "functional-red-black-tree": "^1.0.1", 3807 "functional-red-black-tree": "^1.0.1",
3751 "lodash": "^4.17.15", 3808 "lodash": "^4.17.15",
@@ -3755,55 +3812,55 @@
3755 } 3812 }
3756 }, 3813 },
3757 "@typescript-eslint/experimental-utils": { 3814 "@typescript-eslint/experimental-utils": {
3758 "version": "4.15.2", 3815 "version": "4.22.0",
3759 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.2.tgz", 3816 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz",
3760 "integrity": "sha512-Fxoshw8+R5X3/Vmqwsjc8nRO/7iTysRtDqx6rlfLZ7HbT8TZhPeQqbPjTyk2RheH3L8afumecTQnUc9EeXxohQ==", 3817 "integrity": "sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg==",
3761 "dev": true, 3818 "dev": true,
3762 "requires": { 3819 "requires": {
3763 "@types/json-schema": "^7.0.3", 3820 "@types/json-schema": "^7.0.3",
3764 "@typescript-eslint/scope-manager": "4.15.2", 3821 "@typescript-eslint/scope-manager": "4.22.0",
3765 "@typescript-eslint/types": "4.15.2", 3822 "@typescript-eslint/types": "4.22.0",
3766 "@typescript-eslint/typescript-estree": "4.15.2", 3823 "@typescript-eslint/typescript-estree": "4.22.0",
3767 "eslint-scope": "^5.0.0", 3824 "eslint-scope": "^5.0.0",
3768 "eslint-utils": "^2.0.0" 3825 "eslint-utils": "^2.0.0"
3769 } 3826 }
3770 }, 3827 },
3771 "@typescript-eslint/parser": { 3828 "@typescript-eslint/parser": {
3772 "version": "4.15.2", 3829 "version": "4.22.0",
3773 "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.15.2.tgz", 3830 "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.22.0.tgz",
3774 "integrity": "sha512-SHeF8xbsC6z2FKXsaTb1tBCf0QZsjJ94H6Bo51Y1aVEZ4XAefaw5ZAilMoDPlGghe+qtq7XdTiDlGfVTOmvA+Q==", 3831 "integrity": "sha512-z/bGdBJJZJN76nvAY9DkJANYgK3nlRstRRi74WHm3jjgf2I8AglrSY+6l7ogxOmn55YJ6oKZCLLy+6PW70z15Q==",
3775 "dev": true, 3832 "dev": true,
3776 "requires": { 3833 "requires": {
3777 "@typescript-eslint/scope-manager": "4.15.2", 3834 "@typescript-eslint/scope-manager": "4.22.0",
3778 "@typescript-eslint/types": "4.15.2", 3835 "@typescript-eslint/types": "4.22.0",
3779 "@typescript-eslint/typescript-estree": "4.15.2", 3836 "@typescript-eslint/typescript-estree": "4.22.0",
3780 "debug": "^4.1.1" 3837 "debug": "^4.1.1"
3781 } 3838 }
3782 }, 3839 },
3783 "@typescript-eslint/scope-manager": { 3840 "@typescript-eslint/scope-manager": {
3784 "version": "4.15.2", 3841 "version": "4.22.0",
3785 "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.2.tgz", 3842 "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz",
3786 "integrity": "sha512-Zm0tf/MSKuX6aeJmuXexgdVyxT9/oJJhaCkijv0DvJVT3ui4zY6XYd6iwIo/8GEZGy43cd7w1rFMiCLHbRzAPQ==", 3843 "integrity": "sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q==",
3787 "dev": true, 3844 "dev": true,
3788 "requires": { 3845 "requires": {
3789 "@typescript-eslint/types": "4.15.2", 3846 "@typescript-eslint/types": "4.22.0",
3790 "@typescript-eslint/visitor-keys": "4.15.2" 3847 "@typescript-eslint/visitor-keys": "4.22.0"
3791 } 3848 }
3792 }, 3849 },
3793 "@typescript-eslint/types": { 3850 "@typescript-eslint/types": {
3794 "version": "4.15.2", 3851 "version": "4.22.0",
3795 "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.15.2.tgz", 3852 "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.0.tgz",
3796 "integrity": "sha512-r7lW7HFkAarfUylJ2tKndyO9njwSyoy6cpfDKWPX6/ctZA+QyaYscAHXVAfJqtnY6aaTwDYrOhp+ginlbc7HfQ==", 3853 "integrity": "sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA==",
3797 "dev": true 3854 "dev": true
3798 }, 3855 },
3799 "@typescript-eslint/typescript-estree": { 3856 "@typescript-eslint/typescript-estree": {
3800 "version": "4.15.2", 3857 "version": "4.22.0",
3801 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.15.2.tgz", 3858 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz",
3802 "integrity": "sha512-cGR8C2g5SPtHTQvAymEODeqx90pJHadWsgTtx6GbnTWKqsg7yp6Eaya9nFzUd4KrKhxdYTTFBiYeTPQaz/l8bw==", 3859 "integrity": "sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg==",
3803 "dev": true, 3860 "dev": true,
3804 "requires": { 3861 "requires": {
3805 "@typescript-eslint/types": "4.15.2", 3862 "@typescript-eslint/types": "4.22.0",
3806 "@typescript-eslint/visitor-keys": "4.15.2", 3863 "@typescript-eslint/visitor-keys": "4.22.0",
3807 "debug": "^4.1.1", 3864 "debug": "^4.1.1",
3808 "globby": "^11.0.1", 3865 "globby": "^11.0.1",
3809 "is-glob": "^4.0.1", 3866 "is-glob": "^4.0.1",
@@ -3812,12 +3869,12 @@
3812 } 3869 }
3813 }, 3870 },
3814 "@typescript-eslint/visitor-keys": { 3871 "@typescript-eslint/visitor-keys": {
3815 "version": "4.15.2", 3872 "version": "4.22.0",
3816 "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.15.2.tgz", 3873 "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz",
3817 "integrity": "sha512-TME1VgSb7wTwgENN5KVj4Nqg25hP8DisXxNBojM4Nn31rYaNDIocNm5cmjOFfh42n7NVERxWrDFoETO/76ePyg==", 3874 "integrity": "sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw==",
3818 "dev": true, 3875 "dev": true,
3819 "requires": { 3876 "requires": {
3820 "@typescript-eslint/types": "4.15.2", 3877 "@typescript-eslint/types": "4.22.0",
3821 "eslint-visitor-keys": "^2.0.0" 3878 "eslint-visitor-keys": "^2.0.0"
3822 } 3879 }
3823 }, 3880 },
@@ -3882,9 +3939,9 @@
3882 } 3939 }
3883 }, 3940 },
3884 "anymatch": { 3941 "anymatch": {
3885 "version": "3.1.1", 3942 "version": "3.1.2",
3886 "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", 3943 "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
3887 "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", 3944 "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
3888 "dev": true, 3945 "dev": true,
3889 "requires": { 3946 "requires": {
3890 "normalize-path": "^3.0.0", 3947 "normalize-path": "^3.0.0",
@@ -3931,9 +3988,9 @@
3931 } 3988 }
3932 }, 3989 },
3933 "balanced-match": { 3990 "balanced-match": {
3934 "version": "1.0.0", 3991 "version": "1.0.2",
3935 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 3992 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
3936 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 3993 "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
3937 }, 3994 },
3938 "big-integer": { 3995 "big-integer": {
3939 "version": "1.6.48", 3996 "version": "1.6.48",
@@ -4039,9 +4096,9 @@
4039 } 4096 }
4040 }, 4097 },
4041 "chalk": { 4098 "chalk": {
4042 "version": "4.1.0", 4099 "version": "4.1.1",
4043 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", 4100 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
4044 "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", 4101 "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
4045 "dev": true, 4102 "dev": true,
4046 "requires": { 4103 "requires": {
4047 "ansi-styles": "^4.1.0", 4104 "ansi-styles": "^4.1.0",
@@ -4049,31 +4106,30 @@
4049 } 4106 }
4050 }, 4107 },
4051 "cheerio": { 4108 "cheerio": {
4052 "version": "1.0.0-rc.5", 4109 "version": "1.0.0-rc.6",
4053 "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.5.tgz", 4110 "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.6.tgz",
4054 "integrity": "sha512-yoqps/VCaZgN4pfXtenwHROTp8NG6/Hlt4Jpz2FEP0ZJQ+ZUkVDd0hAPDNKhj3nakpfPt/CNs57yEtxD1bXQiw==", 4111 "integrity": "sha512-hjx1XE1M/D5pAtMgvWwE21QClmAEeGHOIDfycgmndisdNgI6PE1cGRQkMGBcsbUbmEQyWu5PJLUcAOjtQS8DWw==",
4055 "dev": true, 4112 "dev": true,
4056 "requires": { 4113 "requires": {
4057 "cheerio-select-tmp": "^0.1.0", 4114 "cheerio-select": "^1.3.0",
4058 "dom-serializer": "~1.2.0", 4115 "dom-serializer": "^1.3.1",
4059 "domhandler": "^4.0.0", 4116 "domhandler": "^4.1.0",
4060 "entities": "~2.1.0", 4117 "htmlparser2": "^6.1.0",
4061 "htmlparser2": "^6.0.0", 4118 "parse5": "^6.0.1",
4062 "parse5": "^6.0.0", 4119 "parse5-htmlparser2-tree-adapter": "^6.0.1"
4063 "parse5-htmlparser2-tree-adapter": "^6.0.0"
4064 } 4120 }
4065 }, 4121 },
4066 "cheerio-select-tmp": { 4122 "cheerio-select": {
4067 "version": "0.1.1", 4123 "version": "1.4.0",
4068 "resolved": "https://registry.npmjs.org/cheerio-select-tmp/-/cheerio-select-tmp-0.1.1.tgz", 4124 "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.4.0.tgz",
4069 "integrity": "sha512-YYs5JvbpU19VYJyj+F7oYrIE2BOll1/hRU7rEy/5+v9BzkSo3bK81iAeeQEMI92vRIxz677m72UmJUiVwwgjfQ==", 4125 "integrity": "sha512-sobR3Yqz27L553Qa7cK6rtJlMDbiKPdNywtR95Sj/YgfpLfy0u6CGJuaBKe5YE/vTc23SCRKxWSdlon/w6I/Ew==",
4070 "dev": true, 4126 "dev": true,
4071 "requires": { 4127 "requires": {
4072 "css-select": "^3.1.2", 4128 "css-select": "^4.1.2",
4073 "css-what": "^4.0.0", 4129 "css-what": "^5.0.0",
4074 "domelementtype": "^2.1.0", 4130 "domelementtype": "^2.2.0",
4075 "domhandler": "^4.0.0", 4131 "domhandler": "^4.2.0",
4076 "domutils": "^2.4.4" 4132 "domutils": "^2.6.0"
4077 } 4133 }
4078 }, 4134 },
4079 "chokidar": { 4135 "chokidar": {
@@ -4168,22 +4224,22 @@
4168 } 4224 }
4169 }, 4225 },
4170 "css-select": { 4226 "css-select": {
4171 "version": "3.1.2", 4227 "version": "4.1.2",
4172 "resolved": "https://registry.npmjs.org/css-select/-/css-select-3.1.2.tgz", 4228 "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.2.tgz",
4173 "integrity": "sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==", 4229 "integrity": "sha512-nu5ye2Hg/4ISq4XqdLY2bEatAcLIdt3OYGFc9Tm9n7VSlFBcfRv0gBNksHRgSdUDQGtN3XrZ94ztW+NfzkFSUw==",
4174 "dev": true, 4230 "dev": true,
4175 "requires": { 4231 "requires": {
4176 "boolbase": "^1.0.0", 4232 "boolbase": "^1.0.0",
4177 "css-what": "^4.0.0", 4233 "css-what": "^5.0.0",
4178 "domhandler": "^4.0.0", 4234 "domhandler": "^4.2.0",
4179 "domutils": "^2.4.3", 4235 "domutils": "^2.6.0",
4180 "nth-check": "^2.0.0" 4236 "nth-check": "^2.0.0"
4181 } 4237 }
4182 }, 4238 },
4183 "css-what": { 4239 "css-what": {
4184 "version": "4.0.0", 4240 "version": "5.0.0",
4185 "resolved": "https://registry.npmjs.org/css-what/-/css-what-4.0.0.tgz", 4241 "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.0.tgz",
4186 "integrity": "sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==", 4242 "integrity": "sha512-qxyKHQvgKwzwDWC/rGbT821eJalfupxYW2qbSJSAtdSTimsr/MlaGONoNLllaUPZWf8QnbcKM/kPVYUQuEKAFA==",
4187 "dev": true 4243 "dev": true
4188 }, 4244 },
4189 "debug": { 4245 "debug": {
@@ -4249,9 +4305,9 @@
4249 } 4305 }
4250 }, 4306 },
4251 "dom-serializer": { 4307 "dom-serializer": {
4252 "version": "1.2.0", 4308 "version": "1.3.1",
4253 "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", 4309 "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.1.tgz",
4254 "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==", 4310 "integrity": "sha512-Pv2ZluG5ife96udGgEDovOOOA5UELkltfJpnIExPrAk1LTvecolUGn6lIaoLh86d83GiB86CjzciMd9BuRB71Q==",
4255 "dev": true, 4311 "dev": true,
4256 "requires": { 4312 "requires": {
4257 "domelementtype": "^2.0.1", 4313 "domelementtype": "^2.0.1",
@@ -4260,29 +4316,29 @@
4260 } 4316 }
4261 }, 4317 },
4262 "domelementtype": { 4318 "domelementtype": {
4263 "version": "2.1.0", 4319 "version": "2.2.0",
4264 "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", 4320 "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
4265 "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==", 4321 "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
4266 "dev": true 4322 "dev": true
4267 }, 4323 },
4268 "domhandler": { 4324 "domhandler": {
4269 "version": "4.0.0", 4325 "version": "4.2.0",
4270 "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", 4326 "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz",
4271 "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", 4327 "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==",
4272 "dev": true, 4328 "dev": true,
4273 "requires": { 4329 "requires": {
4274 "domelementtype": "^2.1.0" 4330 "domelementtype": "^2.2.0"
4275 } 4331 }
4276 }, 4332 },
4277 "domutils": { 4333 "domutils": {
4278 "version": "2.4.4", 4334 "version": "2.6.0",
4279 "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.4.tgz", 4335 "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.6.0.tgz",
4280 "integrity": "sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==", 4336 "integrity": "sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA==",
4281 "dev": true, 4337 "dev": true,
4282 "requires": { 4338 "requires": {
4283 "dom-serializer": "^1.0.1", 4339 "dom-serializer": "^1.0.1",
4284 "domelementtype": "^2.0.1", 4340 "domelementtype": "^2.2.0",
4285 "domhandler": "^4.0.0" 4341 "domhandler": "^4.2.0"
4286 } 4342 }
4287 }, 4343 },
4288 "duplexer2": { 4344 "duplexer2": {
@@ -4346,9 +4402,9 @@
4346 } 4402 }
4347 }, 4403 },
4348 "entities": { 4404 "entities": {
4349 "version": "2.1.0", 4405 "version": "2.2.0",
4350 "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", 4406 "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
4351 "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", 4407 "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
4352 "dev": true 4408 "dev": true
4353 }, 4409 },
4354 "escalade": { 4410 "escalade": {
@@ -4364,13 +4420,13 @@
4364 "dev": true 4420 "dev": true
4365 }, 4421 },
4366 "eslint": { 4422 "eslint": {
4367 "version": "7.20.0", 4423 "version": "7.25.0",
4368 "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz", 4424 "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.25.0.tgz",
4369 "integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==", 4425 "integrity": "sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw==",
4370 "dev": true, 4426 "dev": true,
4371 "requires": { 4427 "requires": {
4372 "@babel/code-frame": "7.12.11", 4428 "@babel/code-frame": "7.12.11",
4373 "@eslint/eslintrc": "^0.3.0", 4429 "@eslint/eslintrc": "^0.4.0",
4374 "ajv": "^6.10.0", 4430 "ajv": "^6.10.0",
4375 "chalk": "^4.0.0", 4431 "chalk": "^4.0.0",
4376 "cross-spawn": "^7.0.2", 4432 "cross-spawn": "^7.0.2",
@@ -4383,10 +4439,10 @@
4383 "espree": "^7.3.1", 4439 "espree": "^7.3.1",
4384 "esquery": "^1.4.0", 4440 "esquery": "^1.4.0",
4385 "esutils": "^2.0.2", 4441 "esutils": "^2.0.2",
4386 "file-entry-cache": "^6.0.0", 4442 "file-entry-cache": "^6.0.1",
4387 "functional-red-black-tree": "^1.0.1", 4443 "functional-red-black-tree": "^1.0.1",
4388 "glob-parent": "^5.0.0", 4444 "glob-parent": "^5.0.0",
4389 "globals": "^12.1.0", 4445 "globals": "^13.6.0",
4390 "ignore": "^4.0.6", 4446 "ignore": "^4.0.6",
4391 "import-fresh": "^3.0.0", 4447 "import-fresh": "^3.0.0",
4392 "imurmurhash": "^0.1.4", 4448 "imurmurhash": "^0.1.4",
@@ -4394,7 +4450,7 @@
4394 "js-yaml": "^3.13.1", 4450 "js-yaml": "^3.13.1",
4395 "json-stable-stringify-without-jsonify": "^1.0.1", 4451 "json-stable-stringify-without-jsonify": "^1.0.1",
4396 "levn": "^0.4.1", 4452 "levn": "^0.4.1",
4397 "lodash": "^4.17.20", 4453 "lodash": "^4.17.21",
4398 "minimatch": "^3.0.4", 4454 "minimatch": "^3.0.4",
4399 "natural-compare": "^1.4.0", 4455 "natural-compare": "^1.4.0",
4400 "optionator": "^0.9.1", 4456 "optionator": "^0.9.1",
@@ -4551,9 +4607,9 @@
4551 "dev": true 4607 "dev": true
4552 }, 4608 },
4553 "fastq": { 4609 "fastq": {
4554 "version": "1.10.1", 4610 "version": "1.11.0",
4555 "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.1.tgz", 4611 "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
4556 "integrity": "sha512-AWuv6Ery3pM+dY7LYS8YIaCiQvUaos9OB1RyNgaOWnaX+Tik7Onvcsf8x8c+YtDeT0maYLniBip2hox5KtEXXA==", 4612 "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
4557 "dev": true, 4613 "dev": true,
4558 "requires": { 4614 "requires": {
4559 "reusify": "^1.0.4" 4615 "reusify": "^1.0.4"
@@ -4698,27 +4754,27 @@
4698 } 4754 }
4699 }, 4755 },
4700 "glob-parent": { 4756 "glob-parent": {
4701 "version": "5.1.1", 4757 "version": "5.1.2",
4702 "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 4758 "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
4703 "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 4759 "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
4704 "dev": true, 4760 "dev": true,
4705 "requires": { 4761 "requires": {
4706 "is-glob": "^4.0.1" 4762 "is-glob": "^4.0.1"
4707 } 4763 }
4708 }, 4764 },
4709 "globals": { 4765 "globals": {
4710 "version": "12.4.0", 4766 "version": "13.8.0",
4711 "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", 4767 "resolved": "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz",
4712 "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", 4768 "integrity": "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==",
4713 "dev": true, 4769 "dev": true,
4714 "requires": { 4770 "requires": {
4715 "type-fest": "^0.8.1" 4771 "type-fest": "^0.20.2"
4716 } 4772 }
4717 }, 4773 },
4718 "globby": { 4774 "globby": {
4719 "version": "11.0.2", 4775 "version": "11.0.3",
4720 "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", 4776 "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
4721 "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", 4777 "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
4722 "dev": true, 4778 "dev": true,
4723 "requires": { 4779 "requires": {
4724 "array-union": "^2.1.0", 4780 "array-union": "^2.1.0",
@@ -4771,14 +4827,14 @@
4771 "dev": true 4827 "dev": true
4772 }, 4828 },
4773 "htmlparser2": { 4829 "htmlparser2": {
4774 "version": "6.0.0", 4830 "version": "6.1.0",
4775 "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.0.0.tgz", 4831 "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
4776 "integrity": "sha512-numTQtDZMoh78zJpaNdJ9MXb2cv5G3jwUoe3dMQODubZvLoGvTE/Ofp6sHvH8OGKcN/8A47pGLi/k58xHP/Tfw==", 4832 "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
4777 "dev": true, 4833 "dev": true,
4778 "requires": { 4834 "requires": {
4779 "domelementtype": "^2.0.1", 4835 "domelementtype": "^2.0.1",
4780 "domhandler": "^4.0.0", 4836 "domhandler": "^4.0.0",
4781 "domutils": "^2.4.4", 4837 "domutils": "^2.5.2",
4782 "entities": "^2.0.0" 4838 "entities": "^2.0.0"
4783 } 4839 }
4784 }, 4840 },
@@ -4850,9 +4906,9 @@
4850 } 4906 }
4851 }, 4907 },
4852 "is-core-module": { 4908 "is-core-module": {
4853 "version": "2.2.0", 4909 "version": "2.3.0",
4854 "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", 4910 "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.3.0.tgz",
4855 "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", 4911 "integrity": "sha512-xSphU2KG9867tsYdLD4RWQ1VqdFl4HTO9Thf3I/3dLEfr0dbPTWKsuCKrgqMljg4nPE+Gq0VCnzT3gr0CyBmsw==",
4856 "dev": true, 4912 "dev": true,
4857 "requires": { 4913 "requires": {
4858 "has": "^1.0.3" 4914 "has": "^1.0.3"
@@ -4992,6 +5048,24 @@
4992 "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 5048 "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
4993 "dev": true 5049 "dev": true
4994 }, 5050 },
5051 "lodash.clonedeep": {
5052 "version": "4.5.0",
5053 "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
5054 "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
5055 "dev": true
5056 },
5057 "lodash.flatten": {
5058 "version": "4.4.0",
5059 "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
5060 "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=",
5061 "dev": true
5062 },
5063 "lodash.truncate": {
5064 "version": "4.4.2",
5065 "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
5066 "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
5067 "dev": true
5068 },
4995 "log-symbols": { 5069 "log-symbols": {
4996 "version": "4.0.0", 5070 "version": "4.0.0",
4997 "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", 5071 "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
@@ -5052,13 +5126,13 @@
5052 "dev": true 5126 "dev": true
5053 }, 5127 },
5054 "micromatch": { 5128 "micromatch": {
5055 "version": "4.0.2", 5129 "version": "4.0.4",
5056 "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", 5130 "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
5057 "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", 5131 "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
5058 "dev": true, 5132 "dev": true,
5059 "requires": { 5133 "requires": {
5060 "braces": "^3.0.1", 5134 "braces": "^3.0.1",
5061 "picomatch": "^2.0.5" 5135 "picomatch": "^2.2.3"
5062 } 5136 }
5063 }, 5137 },
5064 "mime": { 5138 "mime": {
@@ -5068,18 +5142,18 @@
5068 "dev": true 5142 "dev": true
5069 }, 5143 },
5070 "mime-db": { 5144 "mime-db": {
5071 "version": "1.46.0", 5145 "version": "1.47.0",
5072 "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", 5146 "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz",
5073 "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", 5147 "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==",
5074 "dev": true 5148 "dev": true
5075 }, 5149 },
5076 "mime-types": { 5150 "mime-types": {
5077 "version": "2.1.29", 5151 "version": "2.1.30",
5078 "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", 5152 "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz",
5079 "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", 5153 "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==",
5080 "dev": true, 5154 "dev": true,
5081 "requires": { 5155 "requires": {
5082 "mime-db": "1.46.0" 5156 "mime-db": "1.47.0"
5083 } 5157 }
5084 }, 5158 },
5085 "minimatch": { 5159 "minimatch": {
@@ -5106,9 +5180,9 @@
5106 } 5180 }
5107 }, 5181 },
5108 "mocha": { 5182 "mocha": {
5109 "version": "8.3.0", 5183 "version": "8.3.2",
5110 "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.0.tgz", 5184 "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.2.tgz",
5111 "integrity": "sha512-TQqyC89V1J/Vxx0DhJIXlq9gbbL9XFNdeLQ1+JsnZsVaSOV1z3tWfw0qZmQJGQRIfkvZcs7snQnZnOCKoldq1Q==", 5185 "integrity": "sha512-UdmISwr/5w+uXLPKspgoV7/RXZwKRTiTjJ2/AC5ZiEztIoOYdfKb19+9jNmEInzx5pBsCyJQzarAxqIGBNYJhg==",
5112 "dev": true, 5186 "dev": true,
5113 "requires": { 5187 "requires": {
5114 "@ungap/promise-all-settled": "1.1.2", 5188 "@ungap/promise-all-settled": "1.1.2",
@@ -5360,9 +5434,9 @@
5360 "dev": true 5434 "dev": true
5361 }, 5435 },
5362 "picomatch": { 5436 "picomatch": {
5363 "version": "2.2.2", 5437 "version": "2.2.3",
5364 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 5438 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz",
5365 "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", 5439 "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==",
5366 "dev": true 5440 "dev": true
5367 }, 5441 },
5368 "prelude-ls": { 5442 "prelude-ls": {
@@ -5396,9 +5470,9 @@
5396 "dev": true 5470 "dev": true
5397 }, 5471 },
5398 "queue-microtask": { 5472 "queue-microtask": {
5399 "version": "1.2.2", 5473 "version": "1.2.3",
5400 "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz", 5474 "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
5401 "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==", 5475 "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
5402 "dev": true 5476 "dev": true
5403 }, 5477 },
5404 "randombytes": { 5478 "randombytes": {
@@ -5501,9 +5575,9 @@
5501 } 5575 }
5502 }, 5576 },
5503 "rollup": { 5577 "rollup": {
5504 "version": "2.39.1", 5578 "version": "2.45.2",
5505 "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.39.1.tgz", 5579 "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.45.2.tgz",
5506 "integrity": "sha512-9rfr0Z6j+vE+eayfNVFr1KZ+k+jiUl2+0e4quZafy1x6SFCjzFspfRSO2ZZQeWeX9noeDTUDgg6eCENiEPFvQg==", 5580 "integrity": "sha512-kRRU7wXzFHUzBIv0GfoFFIN3m9oteY4uAsKllIpQDId5cfnkWF2J130l+27dzDju0E6MScKiV0ZM5Bw8m4blYQ==",
5507 "dev": true, 5581 "dev": true,
5508 "requires": { 5582 "requires": {
5509 "fsevents": "~2.3.1" 5583 "fsevents": "~2.3.1"
@@ -5525,9 +5599,9 @@
5525 "dev": true 5599 "dev": true
5526 }, 5600 },
5527 "semver": { 5601 "semver": {
5528 "version": "7.3.4", 5602 "version": "7.3.5",
5529 "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", 5603 "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
5530 "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", 5604 "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
5531 "requires": { 5605 "requires": {
5532 "lru-cache": "^6.0.0" 5606 "lru-cache": "^6.0.0"
5533 } 5607 }
@@ -5615,9 +5689,9 @@
5615 } 5689 }
5616 }, 5690 },
5617 "string-width": { 5691 "string-width": {
5618 "version": "4.2.0", 5692 "version": "4.2.2",
5619 "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 5693 "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
5620 "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 5694 "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
5621 "dev": true, 5695 "dev": true,
5622 "requires": { 5696 "requires": {
5623 "emoji-regex": "^8.0.0", 5697 "emoji-regex": "^8.0.0",
@@ -5650,21 +5724,24 @@
5650 } 5724 }
5651 }, 5725 },
5652 "table": { 5726 "table": {
5653 "version": "6.0.7", 5727 "version": "6.5.1",
5654 "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", 5728 "resolved": "https://registry.npmjs.org/table/-/table-6.5.1.tgz",
5655 "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", 5729 "integrity": "sha512-xGDXWTBJxahkzPQCsn1S9ESHEenU7TbMD5Iv4FeopXv/XwJyWatFjfbor+6ipI10/MNPXBYUamYukOrbPZ9L/w==",
5656 "dev": true, 5730 "dev": true,
5657 "requires": { 5731 "requires": {
5658 "ajv": "^7.0.2", 5732 "ajv": "^8.0.1",
5659 "lodash": "^4.17.20", 5733 "lodash.clonedeep": "^4.5.0",
5734 "lodash.flatten": "^4.4.0",
5735 "lodash.truncate": "^4.4.2",
5660 "slice-ansi": "^4.0.0", 5736 "slice-ansi": "^4.0.0",
5661 "string-width": "^4.2.0" 5737 "string-width": "^4.2.0",
5738 "strip-ansi": "^6.0.0"
5662 }, 5739 },
5663 "dependencies": { 5740 "dependencies": {
5664 "ajv": { 5741 "ajv": {
5665 "version": "7.1.1", 5742 "version": "8.1.0",
5666 "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz", 5743 "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.1.0.tgz",
5667 "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==", 5744 "integrity": "sha512-B/Sk2Ix7A36fs/ZkuGLIR86EdjbgR6fsAcbx9lOP/QBSXujDNbVmIS/U4Itz5k8fPFDeVZl/zQ/gJW4Jrq6XjQ==",
5668 "dev": true, 5745 "dev": true,
5669 "requires": { 5746 "requires": {
5670 "fast-deep-equal": "^3.1.1", 5747 "fast-deep-equal": "^3.1.1",
@@ -5712,15 +5789,15 @@
5712 "dev": true 5789 "dev": true
5713 }, 5790 },
5714 "tslib": { 5791 "tslib": {
5715 "version": "2.1.0", 5792 "version": "2.2.0",
5716 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", 5793 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
5717 "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", 5794 "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==",
5718 "dev": true 5795 "dev": true
5719 }, 5796 },
5720 "tsutils": { 5797 "tsutils": {
5721 "version": "3.20.0", 5798 "version": "3.21.0",
5722 "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.20.0.tgz", 5799 "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
5723 "integrity": "sha512-RYbuQuvkhuqVeXweWT3tJLKOEJ/UUw9GjNEZGWdrLLlM+611o1gwLHBpxoFJKKl25fLprp2eVthtKs5JOrNeXg==", 5800 "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
5724 "dev": true, 5801 "dev": true,
5725 "requires": { 5802 "requires": {
5726 "tslib": "^1.8.1" 5803 "tslib": "^1.8.1"
@@ -5750,9 +5827,9 @@
5750 } 5827 }
5751 }, 5828 },
5752 "type-fest": { 5829 "type-fest": {
5753 "version": "0.8.1", 5830 "version": "0.20.2",
5754 "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", 5831 "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
5755 "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", 5832 "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
5756 "dev": true 5833 "dev": true
5757 }, 5834 },
5758 "typed-rest-client": { 5835 "typed-rest-client": {
@@ -5766,9 +5843,9 @@
5766 } 5843 }
5767 }, 5844 },
5768 "typescript": { 5845 "typescript": {
5769 "version": "4.1.5", 5846 "version": "4.2.4",
5770 "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz", 5847 "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
5771 "integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==", 5848 "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
5772 "dev": true 5849 "dev": true
5773 }, 5850 },
5774 "typescript-formatter": { 5851 "typescript-formatter": {
@@ -5833,15 +5910,15 @@
5833 "dev": true 5910 "dev": true
5834 }, 5911 },
5835 "v8-compile-cache": { 5912 "v8-compile-cache": {
5836 "version": "2.2.0", 5913 "version": "2.3.0",
5837 "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", 5914 "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
5838 "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", 5915 "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
5839 "dev": true 5916 "dev": true
5840 }, 5917 },
5841 "vsce": { 5918 "vsce": {
5842 "version": "1.85.0", 5919 "version": "1.87.1",
5843 "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.85.0.tgz", 5920 "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.87.1.tgz",
5844 "integrity": "sha512-YVFwjXWvHRwk75mm3iL4Wr3auCdbBPTv2amtLf97ccqH0hkt0ZVBddu7iOs4HSEbSr9xiiaZwQHUsqMm6Ks0ag==", 5921 "integrity": "sha512-3tSUWZl9AmhZrqy/UVUpdPODSzBiCGjIr/AMSSgF2PuFLSdrh+6kiOr2Ath7bpQEXOxf55hNgz3qdO5MuEJmww==",
5845 "dev": true, 5922 "dev": true,
5846 "requires": { 5923 "requires": {
5847 "azure-devops-node-api": "^7.2.0", 5924 "azure-devops-node-api": "^7.2.0",
@@ -5966,9 +6043,9 @@
5966 "integrity": "sha512-VGzh06oynbYa6JbTKUbxOEZN7CYEtWhN7DK5wfzUpeCJl8X8xZX39g2PVfpqXrIEduu7dcJgK007KgnX9tHNKA==" 6043 "integrity": "sha512-VGzh06oynbYa6JbTKUbxOEZN7CYEtWhN7DK5wfzUpeCJl8X8xZX39g2PVfpqXrIEduu7dcJgK007KgnX9tHNKA=="
5967 }, 6044 },
5968 "vscode-test": { 6045 "vscode-test": {
5969 "version": "1.5.1", 6046 "version": "1.5.2",
5970 "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.5.1.tgz", 6047 "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.5.2.tgz",
5971 "integrity": "sha512-tDloz6euDne+GeUSglhufL0c2xhuYAPAT74hjsuGxfflALfXF9bYnJ7ehZEeVkr/ZnQEh/T8EBrfPL+m0h5qEQ==", 6048 "integrity": "sha512-x9PVfKxF6EInH9iSFGQi0V8H5zIW1fC7RAer6yNQR6sy3WyOwlWkuT3I+wf75xW/cO53hxMi1aj/EvqQfDFOAg==",
5972 "dev": true, 6049 "dev": true,
5973 "requires": { 6050 "requires": {
5974 "http-proxy-agent": "^4.0.1", 6051 "http-proxy-agent": "^4.0.1",
@@ -6058,9 +6135,9 @@
6058 "dev": true 6135 "dev": true
6059 }, 6136 },
6060 "y18n": { 6137 "y18n": {
6061 "version": "5.0.5", 6138 "version": "5.0.8",
6062 "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", 6139 "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
6063 "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", 6140 "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
6064 "dev": true 6141 "dev": true
6065 }, 6142 },
6066 "yallist": { 6143 "yallist": {
diff --git a/editors/code/package.json b/editors/code/package.json
index fa5632f90..97d92e43c 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -653,6 +653,11 @@
653 "default": true, 653 "default": true,
654 "type": "boolean" 654 "type": "boolean"
655 }, 655 },
656 "rust-analyzer.inlayHints.smallerHints": {
657 "markdownDescription": "Whether inlay hints font size should be smaller than editor's font size.",
658 "default": true,
659 "type": "boolean"
660 },
656 "rust-analyzer.lens.debug": { 661 "rust-analyzer.lens.debug": {
657 "markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", 662 "markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
658 "default": true, 663 "default": true,
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 82f0a0566..03f7d7cc3 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -115,6 +115,7 @@ export class Config {
115 typeHints: this.get<boolean>("inlayHints.typeHints"), 115 typeHints: this.get<boolean>("inlayHints.typeHints"),
116 parameterHints: this.get<boolean>("inlayHints.parameterHints"), 116 parameterHints: this.get<boolean>("inlayHints.parameterHints"),
117 chainingHints: this.get<boolean>("inlayHints.chainingHints"), 117 chainingHints: this.get<boolean>("inlayHints.chainingHints"),
118 smallerHints: this.get<boolean>("inlayHints.smallerHints"),
118 maxLength: this.get<null | number>("inlayHints.maxLength"), 119 maxLength: this.get<null | number>("inlayHints.maxLength"),
119 }; 120 };
120 } 121 }
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts
index 61db6b8d0..c23d6f738 100644
--- a/editors/code/src/inlay_hints.ts
+++ b/editors/code/src/inlay_hints.ts
@@ -5,6 +5,17 @@ import * as ra from './lsp_ext';
5import { Ctx, Disposable } from './ctx'; 5import { Ctx, Disposable } from './ctx';
6import { sendRequestWithRetry, isRustDocument, RustDocument, RustEditor, sleep } from './util'; 6import { sendRequestWithRetry, isRustDocument, RustDocument, RustEditor, sleep } from './util';
7 7
8interface InlayHintStyle {
9 decorationType: vscode.TextEditorDecorationType;
10 toDecoration(hint: ra.InlayHint, conv: lc.Protocol2CodeConverter): vscode.DecorationOptions;
11};
12
13interface InlayHintsStyles {
14 typeHints: InlayHintStyle;
15 paramHints: InlayHintStyle;
16 chainingHints: InlayHintStyle;
17}
18
8 19
9export function activateInlayHints(ctx: Ctx) { 20export function activateInlayHints(ctx: Ctx) {
10 const maybeUpdater = { 21 const maybeUpdater = {
@@ -19,6 +30,7 @@ export function activateInlayHints(ctx: Ctx) {
19 30
20 await sleep(100); 31 await sleep(100);
21 if (this.updater) { 32 if (this.updater) {
33 this.updater.updateInlayHintsStyles();
22 this.updater.syncCacheAndRenderHints(); 34 this.updater.syncCacheAndRenderHints();
23 } else { 35 } else {
24 this.updater = new HintsUpdater(ctx); 36 this.updater = new HintsUpdater(ctx);
@@ -39,11 +51,7 @@ export function activateInlayHints(ctx: Ctx) {
39 maybeUpdater.onConfigChange().catch(console.error); 51 maybeUpdater.onConfigChange().catch(console.error);
40} 52}
41 53
42const typeHints = createHintStyle("type"); 54function createHintStyle(hintKind: "type" | "parameter" | "chaining", smallerHints: boolean): InlayHintStyle {
43const paramHints = createHintStyle("parameter");
44const chainingHints = createHintStyle("chaining");
45
46function createHintStyle(hintKind: "type" | "parameter" | "chaining") {
47 // U+200C is a zero-width non-joiner to prevent the editor from forming a ligature 55 // U+200C is a zero-width non-joiner to prevent the editor from forming a ligature
48 // between code and type hints 56 // between code and type hints
49 const [pos, render] = ({ 57 const [pos, render] = ({
@@ -61,7 +69,7 @@ function createHintStyle(hintKind: "type" | "parameter" | "chaining") {
61 backgroundColor: bg, 69 backgroundColor: bg,
62 fontStyle: "normal", 70 fontStyle: "normal",
63 fontWeight: "normal", 71 fontWeight: "normal",
64 textDecoration: ";font-size:smaller", 72 textDecoration: smallerHints ? ";font-size:smaller" : "none",
65 }, 73 },
66 }), 74 }),
67 toDecoration(hint: ra.InlayHint, conv: lc.Protocol2CodeConverter): vscode.DecorationOptions { 75 toDecoration(hint: ra.InlayHint, conv: lc.Protocol2CodeConverter): vscode.DecorationOptions {
@@ -73,9 +81,23 @@ function createHintStyle(hintKind: "type" | "parameter" | "chaining") {
73 }; 81 };
74} 82}
75 83
84const smallHintsStyles = {
85 typeHints: createHintStyle("type", true),
86 paramHints: createHintStyle("parameter", true),
87 chainingHints: createHintStyle("chaining", true),
88};
89
90const biggerHintsStyles = {
91 typeHints: createHintStyle("type", false),
92 paramHints: createHintStyle("parameter", false),
93 chainingHints: createHintStyle("chaining", false),
94};
95
76class HintsUpdater implements Disposable { 96class HintsUpdater implements Disposable {
77 private sourceFiles = new Map<string, RustSourceFile>(); // map Uri -> RustSourceFile 97 private sourceFiles = new Map<string, RustSourceFile>(); // map Uri -> RustSourceFile
78 private readonly disposables: Disposable[] = []; 98 private readonly disposables: Disposable[] = [];
99 private pendingDisposeDecorations: undefined | InlayHintsStyles = undefined;
100 private inlayHintsStyles!: InlayHintsStyles;
79 101
80 constructor(private readonly ctx: Ctx) { 102 constructor(private readonly ctx: Ctx) {
81 vscode.window.onDidChangeVisibleTextEditors( 103 vscode.window.onDidChangeVisibleTextEditors(
@@ -100,6 +122,7 @@ class HintsUpdater implements Disposable {
100 } 122 }
101 )); 123 ));
102 124
125 this.updateInlayHintsStyles();
103 this.syncCacheAndRenderHints(); 126 this.syncCacheAndRenderHints();
104 } 127 }
105 128
@@ -114,6 +137,15 @@ class HintsUpdater implements Disposable {
114 this.syncCacheAndRenderHints(); 137 this.syncCacheAndRenderHints();
115 } 138 }
116 139
140 updateInlayHintsStyles() {
141 const inlayHintsStyles = this.ctx.config.inlayHints.smallerHints ? smallHintsStyles : biggerHintsStyles;
142
143 if (inlayHintsStyles !== this.inlayHintsStyles) {
144 this.pendingDisposeDecorations = this.inlayHintsStyles;
145 this.inlayHintsStyles = inlayHintsStyles;
146 }
147 }
148
117 syncCacheAndRenderHints() { 149 syncCacheAndRenderHints() {
118 this.sourceFiles.forEach((file, uri) => this.fetchHints(file).then(hints => { 150 this.sourceFiles.forEach((file, uri) => this.fetchHints(file).then(hints => {
119 if (!hints) return; 151 if (!hints) return;
@@ -161,12 +193,20 @@ class HintsUpdater implements Disposable {
161 } 193 }
162 194
163 private renderDecorations(editor: RustEditor, decorations: InlaysDecorations) { 195 private renderDecorations(editor: RustEditor, decorations: InlaysDecorations) {
196 const { typeHints, paramHints, chainingHints } = this.inlayHintsStyles;
197 if (this.pendingDisposeDecorations !== undefined) {
198 const { typeHints, paramHints, chainingHints } = this.pendingDisposeDecorations;
199 editor.setDecorations(typeHints.decorationType, []);
200 editor.setDecorations(paramHints.decorationType, []);
201 editor.setDecorations(chainingHints.decorationType, []);
202 }
164 editor.setDecorations(typeHints.decorationType, decorations.type); 203 editor.setDecorations(typeHints.decorationType, decorations.type);
165 editor.setDecorations(paramHints.decorationType, decorations.param); 204 editor.setDecorations(paramHints.decorationType, decorations.param);
166 editor.setDecorations(chainingHints.decorationType, decorations.chaining); 205 editor.setDecorations(chainingHints.decorationType, decorations.chaining);
167 } 206 }
168 207
169 private hintsToDecorations(hints: ra.InlayHint[]): InlaysDecorations { 208 private hintsToDecorations(hints: ra.InlayHint[]): InlaysDecorations {
209 const { typeHints, paramHints, chainingHints } = this.inlayHintsStyles;
170 const decorations: InlaysDecorations = { type: [], param: [], chaining: [] }; 210 const decorations: InlaysDecorations = { type: [], param: [], chaining: [] };
171 const conv = this.ctx.client.protocol2CodeConverter; 211 const conv = this.ctx.client.protocol2CodeConverter;
172 212
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index f2503f807..12a7fea1e 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -7,26 +7,31 @@ use std::{
7 7
8use anyhow::Result; 8use anyhow::Result;
9use flate2::{write::GzEncoder, Compression}; 9use flate2::{write::GzEncoder, Compression};
10use xshell::{cmd, cp, mkdir_p, pushd, read_file, rm_rf, write_file}; 10use xshell::{cmd, cp, mkdir_p, pushd, pushenv, read_file, rm_rf, write_file};
11 11
12use crate::{date_iso, project_root}; 12use crate::{date_iso, flags, project_root};
13 13
14pub(crate) struct DistCmd { 14impl flags::Dist {
15 pub(crate) nightly: bool,
16 pub(crate) client_version: Option<String>,
17}
18
19impl DistCmd {
20 pub(crate) fn run(self) -> Result<()> { 15 pub(crate) fn run(self) -> Result<()> {
16 let stable =
17 std::env::var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release";
18
21 let dist = project_root().join("dist"); 19 let dist = project_root().join("dist");
22 rm_rf(&dist)?; 20 rm_rf(&dist)?;
23 mkdir_p(&dist)?; 21 mkdir_p(&dist)?;
24 22
25 if let Some(version) = self.client_version { 23 if let Some(patch_version) = self.client_patch_version {
26 let release_tag = if self.nightly { "nightly".to_string() } else { date_iso()? }; 24 let version = if stable {
25 format!("0.2.{}", patch_version)
26 } else {
27 // A hack to make VS Code prefer nightly over stable.
28 format!("0.3.{}", patch_version)
29 };
30 let release_tag = if stable { date_iso()? } else { "nightly".to_string() };
27 dist_client(&version, &release_tag)?; 31 dist_client(&version, &release_tag)?;
28 } 32 }
29 dist_server()?; 33 let release_channel = if stable { "stable" } else { "nightly" };
34 dist_server(release_channel)?;
30 Ok(()) 35 Ok(())
31 } 36 }
32} 37}
@@ -39,7 +44,9 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> {
39 44
40 patch 45 patch
41 .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version)) 46 .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version))
42 .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag)); 47 .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
48 .replace(r#""$generated-start": false,"#, "")
49 .replace(",\n \"$generated-end\": false", "");
43 50
44 if nightly { 51 if nightly {
45 patch.replace( 52 patch.replace(
@@ -57,7 +64,8 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> {
57 Ok(()) 64 Ok(())
58} 65}
59 66
60fn dist_server() -> Result<()> { 67fn dist_server(release_channel: &str) -> Result<()> {
68 let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
61 let target = get_target(); 69 let target = get_target();
62 if target.contains("-linux-gnu") || target.contains("-linux-musl") { 70 if target.contains("-linux-gnu") || target.contains("-linux-musl") {
63 env::set_var("CC", "clang"); 71 env::set_var("CC", "clang");
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index 4cd2b1ddb..f80a5dd16 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -37,8 +37,7 @@ xflags::xflags! {
37 optional --dry-run 37 optional --dry-run
38 } 38 }
39 cmd dist { 39 cmd dist {
40 optional --nightly 40 optional --client-patch-version version: String
41 optional --client version: String
42 } 41 }
43 cmd metrics { 42 cmd metrics {
44 optional --dry-run 43 optional --dry-run
@@ -86,9 +85,6 @@ pub struct Install {
86} 85}
87 86
88#[derive(Debug)] 87#[derive(Debug)]
89pub struct Lint;
90
91#[derive(Debug)]
92pub struct FuzzTests; 88pub struct FuzzTests;
93 89
94#[derive(Debug)] 90#[derive(Debug)]
@@ -106,8 +102,7 @@ pub struct Promote {
106 102
107#[derive(Debug)] 103#[derive(Debug)]
108pub struct Dist { 104pub struct Dist {
109 pub nightly: bool, 105 pub client_patch_version: Option<String>,
110 pub client: Option<String>,
111} 106}
112 107
113#[derive(Debug)] 108#[derive(Debug)]
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 960927fc0..ce3353410 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -28,8 +28,6 @@ use std::{
28use walkdir::{DirEntry, WalkDir}; 28use walkdir::{DirEntry, WalkDir};
29use xshell::{cmd, cp, pushd, pushenv}; 29use xshell::{cmd, cp, pushd, pushenv};
30 30
31use crate::dist::DistCmd;
32
33fn main() -> Result<()> { 31fn main() -> Result<()> {
34 let _d = pushd(project_root())?; 32 let _d = pushd(project_root())?;
35 33
@@ -44,9 +42,7 @@ fn main() -> Result<()> {
44 flags::XtaskCmd::PreCache(cmd) => cmd.run(), 42 flags::XtaskCmd::PreCache(cmd) => cmd.run(),
45 flags::XtaskCmd::Release(cmd) => cmd.run(), 43 flags::XtaskCmd::Release(cmd) => cmd.run(),
46 flags::XtaskCmd::Promote(cmd) => cmd.run(), 44 flags::XtaskCmd::Promote(cmd) => cmd.run(),
47 flags::XtaskCmd::Dist(flags) => { 45 flags::XtaskCmd::Dist(cmd) => cmd.run(),
48 DistCmd { nightly: flags.nightly, client_version: flags.client }.run()
49 }
50 flags::XtaskCmd::Metrics(cmd) => cmd.run(), 46 flags::XtaskCmd::Metrics(cmd) => cmd.run(),
51 flags::XtaskCmd::Bb(cmd) => { 47 flags::XtaskCmd::Bb(cmd) => {
52 { 48 {
@@ -112,7 +108,7 @@ fn run_fuzzer() -> Result<()> {
112} 108}
113 109
114fn date_iso() -> Result<String> { 110fn date_iso() -> Result<String> {
115 let res = cmd!("date --iso --utc").read()?; 111 let res = cmd!("date -u +%Y-%m-%d").read()?;
116 Ok(res) 112 Ok(res)
117} 113}
118 114
diff --git a/xtask/src/release.rs b/xtask/src/release.rs
index 22bb50467..452f351d0 100644
--- a/xtask/src/release.rs
+++ b/xtask/src/release.rs
@@ -10,7 +10,16 @@ impl flags::Release {
10 cmd!("git switch release").run()?; 10 cmd!("git switch release").run()?;
11 cmd!("git fetch upstream --tags --force").run()?; 11 cmd!("git fetch upstream --tags --force").run()?;
12 cmd!("git reset --hard tags/nightly").run()?; 12 cmd!("git reset --hard tags/nightly").run()?;
13 cmd!("git push").run()?; 13 // The `release` branch sometimes has a couple of cherry-picked
14 // commits for patch releases. If that's the case, just overwrite
15 // it. As we are setting `release` branch to an up-to-date `nightly`
16 // tag, this shouldn't be problematic in general.
17 //
18 // Note that, as we tag releases, we don't worry about "losing"
19 // commits -- they'll be kept alive by the tag. More generally, we
20 // don't care about historic releases all that much, it's fine even
21 // to delete old tags.
22 cmd!("git push --force").run()?;
14 } 23 }
15 codegen::docs()?; 24 codegen::docs()?;
16 25