diff options
136 files changed, 5156 insertions, 3196 deletions
diff --git a/.github/actions/github-release/main.js b/.github/actions/github-release/main.js index 2c7eedbe2..b499cd0fd 100644 --- a/.github/actions/github-release/main.js +++ b/.github/actions/github-release/main.js | |||
@@ -16,7 +16,7 @@ async function runOnce() { | |||
16 | const slug = process.env.GITHUB_REPOSITORY; | 16 | const slug = process.env.GITHUB_REPOSITORY; |
17 | const owner = slug.split('/')[0]; | 17 | const owner = slug.split('/')[0]; |
18 | const repo = slug.split('/')[1]; | 18 | const repo = slug.split('/')[1]; |
19 | const sha = process.env.GITHUB_SHA; | 19 | const sha = process.env.HEAD_SHA; |
20 | 20 | ||
21 | core.info(`files: ${files}`); | 21 | core.info(`files: ${files}`); |
22 | core.info(`name: ${name}`); | 22 | core.info(`name: ${name}`); |
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 00f299ff1..ed9191c49 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml | |||
@@ -97,7 +97,13 @@ jobs: | |||
97 | 97 | ||
98 | typescript: | 98 | typescript: |
99 | name: TypeScript | 99 | name: TypeScript |
100 | runs-on: ubuntu-latest | 100 | strategy: |
101 | fail-fast: false | ||
102 | matrix: | ||
103 | os: [ubuntu-latest, windows-latest, macos-latest] | ||
104 | |||
105 | runs-on: ${{ matrix.os }} | ||
106 | |||
101 | steps: | 107 | steps: |
102 | - name: Checkout repository | 108 | - name: Checkout repository |
103 | uses: actions/checkout@v2 | 109 | uses: actions/checkout@v2 |
@@ -111,10 +117,19 @@ jobs: | |||
111 | working-directory: ./editors/code | 117 | working-directory: ./editors/code |
112 | 118 | ||
113 | - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; } | 119 | - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; } |
120 | if: runner.os == 'Linux' | ||
114 | working-directory: ./editors/code | 121 | working-directory: ./editors/code |
115 | 122 | ||
116 | - run: npm run lint | 123 | - run: npm run lint |
117 | working-directory: ./editors/code | 124 | working-directory: ./editors/code |
118 | 125 | ||
126 | - name: Run vscode tests | ||
127 | uses: GabrielBB/[email protected] | ||
128 | env: | ||
129 | VSCODE_CLI: 1 | ||
130 | with: | ||
131 | run: npm --prefix ./editors/code test | ||
132 | # working-directory: ./editors/code # does not work: https://github.com/GabrielBB/xvfb-action/issues/8 | ||
133 | |||
119 | - run: npm run package --scripts-prepend-node-path | 134 | - run: npm run package --scripts-prepend-node-path |
120 | working-directory: ./editors/code | 135 | working-directory: ./editors/code |
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 29ac89549..1ae8ed1b6 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -6,7 +6,7 @@ on: | |||
6 | push: | 6 | push: |
7 | branches: | 7 | branches: |
8 | - release | 8 | - release |
9 | - nightly | 9 | - trigger-nightly |
10 | 10 | ||
11 | env: | 11 | env: |
12 | CARGO_INCREMENTAL: 0 | 12 | CARGO_INCREMENTAL: 0 |
@@ -88,6 +88,9 @@ jobs: | |||
88 | - name: Checkout repository | 88 | - name: Checkout repository |
89 | uses: actions/checkout@v2 | 89 | uses: actions/checkout@v2 |
90 | 90 | ||
91 | - run: echo "::set-env name=HEAD_SHA::$(git rev-parse HEAD)" | ||
92 | - run: 'echo "HEAD_SHA: $HEAD_SHA"' | ||
93 | |||
91 | - uses: actions/download-artifact@v1 | 94 | - uses: actions/download-artifact@v1 |
92 | with: | 95 | with: |
93 | name: dist-macos-latest | 96 | name: dist-macos-latest |
diff --git a/.vscode/launch.json b/.vscode/launch.json index 6a2fff906..8ca27d878 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json | |||
@@ -71,6 +71,28 @@ | |||
71 | } | 71 | } |
72 | }, | 72 | }, |
73 | { | 73 | { |
74 | // Used for testing the extension with a local build of the LSP server (in `target/release`) | ||
75 | // with all other extendions loaded. | ||
76 | "name": "Run With Extensions", | ||
77 | "type": "extensionHost", | ||
78 | "request": "launch", | ||
79 | "runtimeExecutable": "${execPath}", | ||
80 | "args": [ | ||
81 | "--disable-extension", "matklad.rust-analyzer", | ||
82 | "--extensionDevelopmentPath=${workspaceFolder}/editors/code" | ||
83 | ], | ||
84 | "outFiles": [ | ||
85 | "${workspaceFolder}/editors/code/out/**/*.js" | ||
86 | ], | ||
87 | "preLaunchTask": "Build Server (Release) and Extension", | ||
88 | "skipFiles": [ | ||
89 | "<node_internals>/**/*.js" | ||
90 | ], | ||
91 | "env": { | ||
92 | "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/release/rust-analyzer" | ||
93 | } | ||
94 | }, | ||
95 | { | ||
74 | // Used to attach LLDB to a running LSP server. | 96 | // Used to attach LLDB to a running LSP server. |
75 | // NOTE: Might require root permissions. For this run: | 97 | // NOTE: Might require root permissions. For this run: |
76 | // | 98 | // |
@@ -87,5 +109,17 @@ | |||
87 | "rust" | 109 | "rust" |
88 | ] | 110 | ] |
89 | }, | 111 | }, |
112 | { | ||
113 | "name": "Run Unit Tests", | ||
114 | "type": "extensionHost", | ||
115 | "request": "launch", | ||
116 | "runtimeExecutable": "${execPath}", | ||
117 | "args": [ | ||
118 | "--extensionDevelopmentPath=${workspaceFolder}/editors/code", | ||
119 | "--extensionTestsPath=${workspaceFolder}/editors/code/out/tests/unit" ], | ||
120 | "sourceMaps": true, | ||
121 | "outFiles": [ "${workspaceFolder}/editors/code/out/tests/unit/**/*.js" ], | ||
122 | "preLaunchTask": "Pretest" | ||
123 | } | ||
90 | ] | 124 | ] |
91 | } | 125 | } |
diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 0969ce89a..a25dff19e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json | |||
@@ -40,6 +40,18 @@ | |||
40 | "command": "cargo build --release --package rust-analyzer", | 40 | "command": "cargo build --release --package rust-analyzer", |
41 | "problemMatcher": "$rustc" | 41 | "problemMatcher": "$rustc" |
42 | }, | 42 | }, |
43 | { | ||
44 | "label": "Pretest", | ||
45 | "group": "build", | ||
46 | "isBackground": false, | ||
47 | "type": "npm", | ||
48 | "script": "pretest", | ||
49 | "path": "editors/code/", | ||
50 | "problemMatcher": { | ||
51 | "base": "$tsc", | ||
52 | "fileLocation": ["relative", "${workspaceFolder}/editors/code/"] | ||
53 | } | ||
54 | }, | ||
43 | 55 | ||
44 | { | 56 | { |
45 | "label": "Build Server and Extension", | 57 | "label": "Build Server and Extension", |
diff --git a/Cargo.lock b/Cargo.lock index c06236692..1f4c0cb53 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -101,9 +101,9 @@ dependencies = [ | |||
101 | 101 | ||
102 | [[package]] | 102 | [[package]] |
103 | name = "cc" | 103 | name = "cc" |
104 | version = "1.0.53" | 104 | version = "1.0.54" |
105 | source = "registry+https://github.com/rust-lang/crates.io-index" | 105 | source = "registry+https://github.com/rust-lang/crates.io-index" |
106 | checksum = "404b1fe4f65288577753b17e3b36a04596ee784493ec249bf81c7f2d2acd751c" | 106 | checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" |
107 | 107 | ||
108 | [[package]] | 108 | [[package]] |
109 | name = "cfg-if" | 109 | name = "cfg-if" |
@@ -114,7 +114,7 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" | |||
114 | [[package]] | 114 | [[package]] |
115 | name = "chalk-derive" | 115 | name = "chalk-derive" |
116 | version = "0.10.1-dev" | 116 | version = "0.10.1-dev" |
117 | source = "git+https://github.com/rust-lang/chalk.git?rev=3e9c2503ae9c5277c2acb74624dc267876dd89b3#3e9c2503ae9c5277c2acb74624dc267876dd89b3" | 117 | source = "git+https://github.com/rust-lang/chalk.git?rev=eaab84b394007d1bed15f5470409a6ea02900a96#eaab84b394007d1bed15f5470409a6ea02900a96" |
118 | dependencies = [ | 118 | dependencies = [ |
119 | "proc-macro2", | 119 | "proc-macro2", |
120 | "quote", | 120 | "quote", |
@@ -125,7 +125,7 @@ dependencies = [ | |||
125 | [[package]] | 125 | [[package]] |
126 | name = "chalk-engine" | 126 | name = "chalk-engine" |
127 | version = "0.10.1-dev" | 127 | version = "0.10.1-dev" |
128 | source = "git+https://github.com/rust-lang/chalk.git?rev=3e9c2503ae9c5277c2acb74624dc267876dd89b3#3e9c2503ae9c5277c2acb74624dc267876dd89b3" | 128 | source = "git+https://github.com/rust-lang/chalk.git?rev=eaab84b394007d1bed15f5470409a6ea02900a96#eaab84b394007d1bed15f5470409a6ea02900a96" |
129 | dependencies = [ | 129 | dependencies = [ |
130 | "chalk-macros", | 130 | "chalk-macros", |
131 | "rustc-hash", | 131 | "rustc-hash", |
@@ -134,7 +134,7 @@ dependencies = [ | |||
134 | [[package]] | 134 | [[package]] |
135 | name = "chalk-ir" | 135 | name = "chalk-ir" |
136 | version = "0.10.1-dev" | 136 | version = "0.10.1-dev" |
137 | source = "git+https://github.com/rust-lang/chalk.git?rev=3e9c2503ae9c5277c2acb74624dc267876dd89b3#3e9c2503ae9c5277c2acb74624dc267876dd89b3" | 137 | source = "git+https://github.com/rust-lang/chalk.git?rev=eaab84b394007d1bed15f5470409a6ea02900a96#eaab84b394007d1bed15f5470409a6ea02900a96" |
138 | dependencies = [ | 138 | dependencies = [ |
139 | "chalk-derive", | 139 | "chalk-derive", |
140 | "chalk-engine", | 140 | "chalk-engine", |
@@ -144,7 +144,7 @@ dependencies = [ | |||
144 | [[package]] | 144 | [[package]] |
145 | name = "chalk-macros" | 145 | name = "chalk-macros" |
146 | version = "0.10.1-dev" | 146 | version = "0.10.1-dev" |
147 | source = "git+https://github.com/rust-lang/chalk.git?rev=3e9c2503ae9c5277c2acb74624dc267876dd89b3#3e9c2503ae9c5277c2acb74624dc267876dd89b3" | 147 | source = "git+https://github.com/rust-lang/chalk.git?rev=eaab84b394007d1bed15f5470409a6ea02900a96#eaab84b394007d1bed15f5470409a6ea02900a96" |
148 | dependencies = [ | 148 | dependencies = [ |
149 | "lazy_static", | 149 | "lazy_static", |
150 | ] | 150 | ] |
@@ -152,7 +152,7 @@ dependencies = [ | |||
152 | [[package]] | 152 | [[package]] |
153 | name = "chalk-rust-ir" | 153 | name = "chalk-rust-ir" |
154 | version = "0.10.1-dev" | 154 | version = "0.10.1-dev" |
155 | source = "git+https://github.com/rust-lang/chalk.git?rev=3e9c2503ae9c5277c2acb74624dc267876dd89b3#3e9c2503ae9c5277c2acb74624dc267876dd89b3" | 155 | source = "git+https://github.com/rust-lang/chalk.git?rev=eaab84b394007d1bed15f5470409a6ea02900a96#eaab84b394007d1bed15f5470409a6ea02900a96" |
156 | dependencies = [ | 156 | dependencies = [ |
157 | "chalk-derive", | 157 | "chalk-derive", |
158 | "chalk-engine", | 158 | "chalk-engine", |
@@ -163,14 +163,14 @@ dependencies = [ | |||
163 | [[package]] | 163 | [[package]] |
164 | name = "chalk-solve" | 164 | name = "chalk-solve" |
165 | version = "0.10.1-dev" | 165 | version = "0.10.1-dev" |
166 | source = "git+https://github.com/rust-lang/chalk.git?rev=3e9c2503ae9c5277c2acb74624dc267876dd89b3#3e9c2503ae9c5277c2acb74624dc267876dd89b3" | 166 | source = "git+https://github.com/rust-lang/chalk.git?rev=eaab84b394007d1bed15f5470409a6ea02900a96#eaab84b394007d1bed15f5470409a6ea02900a96" |
167 | dependencies = [ | 167 | dependencies = [ |
168 | "chalk-derive", | 168 | "chalk-derive", |
169 | "chalk-engine", | 169 | "chalk-engine", |
170 | "chalk-ir", | 170 | "chalk-ir", |
171 | "chalk-macros", | 171 | "chalk-macros", |
172 | "chalk-rust-ir", | 172 | "chalk-rust-ir", |
173 | "ena 0.13.1", | 173 | "ena", |
174 | "itertools", | 174 | "itertools", |
175 | "petgraph", | 175 | "petgraph", |
176 | "rustc-hash", | 176 | "rustc-hash", |
@@ -309,15 +309,6 @@ checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" | |||
309 | 309 | ||
310 | [[package]] | 310 | [[package]] |
311 | name = "ena" | 311 | name = "ena" |
312 | version = "0.13.1" | ||
313 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
314 | checksum = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36" | ||
315 | dependencies = [ | ||
316 | "log", | ||
317 | ] | ||
318 | |||
319 | [[package]] | ||
320 | name = "ena" | ||
321 | version = "0.14.0" | 312 | version = "0.14.0" |
322 | source = "registry+https://github.com/rust-lang/crates.io-index" | 313 | source = "registry+https://github.com/rust-lang/crates.io-index" |
323 | checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" | 314 | checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" |
@@ -354,9 +345,9 @@ dependencies = [ | |||
354 | 345 | ||
355 | [[package]] | 346 | [[package]] |
356 | name = "fixedbitset" | 347 | name = "fixedbitset" |
357 | version = "0.1.9" | 348 | version = "0.2.0" |
358 | source = "registry+https://github.com/rust-lang/crates.io-index" | 349 | source = "registry+https://github.com/rust-lang/crates.io-index" |
359 | checksum = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" | 350 | checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" |
360 | 351 | ||
361 | [[package]] | 352 | [[package]] |
362 | name = "fnv" | 353 | name = "fnv" |
@@ -391,9 +382,9 @@ dependencies = [ | |||
391 | 382 | ||
392 | [[package]] | 383 | [[package]] |
393 | name = "fst" | 384 | name = "fst" |
394 | version = "0.4.3" | 385 | version = "0.4.4" |
395 | source = "registry+https://github.com/rust-lang/crates.io-index" | 386 | source = "registry+https://github.com/rust-lang/crates.io-index" |
396 | checksum = "81f9cac32c1741cdf6b66be7dcf0d9c7f25ccf12f8aa84c16cfa31f9f14513b3" | 387 | checksum = "a7293de202dbfe786c0b3fe6110a027836c5438ed06db7b715c9955ff4bfea51" |
397 | 388 | ||
398 | [[package]] | 389 | [[package]] |
399 | name = "fuchsia-zircon" | 390 | name = "fuchsia-zircon" |
@@ -658,9 +649,9 @@ dependencies = [ | |||
658 | 649 | ||
659 | [[package]] | 650 | [[package]] |
660 | name = "lsp-server" | 651 | name = "lsp-server" |
661 | version = "0.3.1" | 652 | version = "0.3.2" |
662 | source = "registry+https://github.com/rust-lang/crates.io-index" | 653 | source = "registry+https://github.com/rust-lang/crates.io-index" |
663 | checksum = "5383e043329615624bbf45e1ba27bd75c176762b2592855c659bc28ac580a06b" | 654 | checksum = "dccec31bfd027ac0dd288a78e19005fd89624d9099456e284b5241316a6c3072" |
664 | dependencies = [ | 655 | dependencies = [ |
665 | "crossbeam-channel", | 656 | "crossbeam-channel", |
666 | "log", | 657 | "log", |
@@ -814,12 +805,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
814 | checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" | 805 | checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" |
815 | 806 | ||
816 | [[package]] | 807 | [[package]] |
817 | name = "ordermap" | ||
818 | version = "0.3.5" | ||
819 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
820 | checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" | ||
821 | |||
822 | [[package]] | ||
823 | name = "parking_lot" | 808 | name = "parking_lot" |
824 | version = "0.10.2" | 809 | version = "0.10.2" |
825 | source = "registry+https://github.com/rust-lang/crates.io-index" | 810 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -845,9 +830,9 @@ dependencies = [ | |||
845 | 830 | ||
846 | [[package]] | 831 | [[package]] |
847 | name = "paste" | 832 | name = "paste" |
848 | version = "0.1.12" | 833 | version = "0.1.13" |
849 | source = "registry+https://github.com/rust-lang/crates.io-index" | 834 | source = "registry+https://github.com/rust-lang/crates.io-index" |
850 | checksum = "0a229b1c58c692edcaa5b9b0948084f130f55d2dcc15b02fcc5340b2b4521476" | 835 | checksum = "678f27e19361472a23717f11d229a7522ef64605baf0715c896a94b8b6b13a06" |
851 | dependencies = [ | 836 | dependencies = [ |
852 | "paste-impl", | 837 | "paste-impl", |
853 | "proc-macro-hack", | 838 | "proc-macro-hack", |
@@ -855,9 +840,9 @@ dependencies = [ | |||
855 | 840 | ||
856 | [[package]] | 841 | [[package]] |
857 | name = "paste-impl" | 842 | name = "paste-impl" |
858 | version = "0.1.12" | 843 | version = "0.1.13" |
859 | source = "registry+https://github.com/rust-lang/crates.io-index" | 844 | source = "registry+https://github.com/rust-lang/crates.io-index" |
860 | checksum = "2e0bf239e447e67ff6d16a8bb5e4d4bd2343acf5066061c0e8e06ac5ba8ca68c" | 845 | checksum = "149089128a45d8e377677b08873b4bad2a56618f80e4f28a83862ba250994a30" |
861 | dependencies = [ | 846 | dependencies = [ |
862 | "proc-macro-hack", | 847 | "proc-macro-hack", |
863 | "proc-macro2", | 848 | "proc-macro2", |
@@ -873,12 +858,12 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" | |||
873 | 858 | ||
874 | [[package]] | 859 | [[package]] |
875 | name = "petgraph" | 860 | name = "petgraph" |
876 | version = "0.4.13" | 861 | version = "0.5.1" |
877 | source = "registry+https://github.com/rust-lang/crates.io-index" | 862 | source = "registry+https://github.com/rust-lang/crates.io-index" |
878 | checksum = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" | 863 | checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" |
879 | dependencies = [ | 864 | dependencies = [ |
880 | "fixedbitset", | 865 | "fixedbitset", |
881 | "ordermap", | 866 | "indexmap", |
882 | ] | 867 | ] |
883 | 868 | ||
884 | [[package]] | 869 | [[package]] |
@@ -907,9 +892,9 @@ checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" | |||
907 | 892 | ||
908 | [[package]] | 893 | [[package]] |
909 | name = "proc-macro2" | 894 | name = "proc-macro2" |
910 | version = "1.0.13" | 895 | version = "1.0.17" |
911 | source = "registry+https://github.com/rust-lang/crates.io-index" | 896 | source = "registry+https://github.com/rust-lang/crates.io-index" |
912 | checksum = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639" | 897 | checksum = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101" |
913 | dependencies = [ | 898 | dependencies = [ |
914 | "unicode-xid", | 899 | "unicode-xid", |
915 | ] | 900 | ] |
@@ -1053,7 +1038,7 @@ dependencies = [ | |||
1053 | "chalk-ir", | 1038 | "chalk-ir", |
1054 | "chalk-rust-ir", | 1039 | "chalk-rust-ir", |
1055 | "chalk-solve", | 1040 | "chalk-solve", |
1056 | "ena 0.14.0", | 1041 | "ena", |
1057 | "insta", | 1042 | "insta", |
1058 | "itertools", | 1043 | "itertools", |
1059 | "log", | 1044 | "log", |
@@ -1387,17 +1372,20 @@ dependencies = [ | |||
1387 | "lsp-types", | 1372 | "lsp-types", |
1388 | "parking_lot", | 1373 | "parking_lot", |
1389 | "pico-args", | 1374 | "pico-args", |
1375 | "ra_cfg", | ||
1390 | "ra_db", | 1376 | "ra_db", |
1391 | "ra_flycheck", | 1377 | "ra_flycheck", |
1392 | "ra_hir", | 1378 | "ra_hir", |
1393 | "ra_hir_def", | 1379 | "ra_hir_def", |
1394 | "ra_hir_ty", | 1380 | "ra_hir_ty", |
1395 | "ra_ide", | 1381 | "ra_ide", |
1382 | "ra_mbe", | ||
1396 | "ra_proc_macro_srv", | 1383 | "ra_proc_macro_srv", |
1397 | "ra_prof", | 1384 | "ra_prof", |
1398 | "ra_project_model", | 1385 | "ra_project_model", |
1399 | "ra_syntax", | 1386 | "ra_syntax", |
1400 | "ra_text_edit", | 1387 | "ra_text_edit", |
1388 | "ra_tt", | ||
1401 | "ra_vfs", | 1389 | "ra_vfs", |
1402 | "rand", | 1390 | "rand", |
1403 | "relative-path", | 1391 | "relative-path", |
@@ -1413,9 +1401,9 @@ dependencies = [ | |||
1413 | 1401 | ||
1414 | [[package]] | 1402 | [[package]] |
1415 | name = "rustc-ap-rustc_lexer" | 1403 | name = "rustc-ap-rustc_lexer" |
1416 | version = "656.0.0" | 1404 | version = "660.0.0" |
1417 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1418 | checksum = "9cbba98ec46e96a4663197dfa8c0378752de2006e314e5400c0ca74929d6692f" | 1406 | checksum = "30760dbcc7667c9e0da561e980e24867ca7f4526ce060a3d7e6d9dcfeaae88d1" |
1419 | dependencies = [ | 1407 | dependencies = [ |
1420 | "unicode-xid", | 1408 | "unicode-xid", |
1421 | ] | 1409 | ] |
@@ -1610,9 +1598,9 @@ checksum = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" | |||
1610 | 1598 | ||
1611 | [[package]] | 1599 | [[package]] |
1612 | name = "syn" | 1600 | name = "syn" |
1613 | version = "1.0.22" | 1601 | version = "1.0.23" |
1614 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1602 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1615 | checksum = "1425de3c33b0941002740a420b1a906a350b88d08b82b2c8a01035a3f9447bac" | 1603 | checksum = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269" |
1616 | dependencies = [ | 1604 | dependencies = [ |
1617 | "proc-macro2", | 1605 | "proc-macro2", |
1618 | "quote", | 1606 | "quote", |
@@ -1669,6 +1657,9 @@ name = "test_utils" | |||
1669 | version = "0.1.0" | 1657 | version = "0.1.0" |
1670 | dependencies = [ | 1658 | dependencies = [ |
1671 | "difference", | 1659 | "difference", |
1660 | "ra_cfg", | ||
1661 | "relative-path", | ||
1662 | "rustc-hash", | ||
1672 | "serde_json", | 1663 | "serde_json", |
1673 | "text-size", | 1664 | "text-size", |
1674 | ] | 1665 | ] |
@@ -2,6 +2,8 @@ status = [ | |||
2 | "Rust (ubuntu-latest)", | 2 | "Rust (ubuntu-latest)", |
3 | "Rust (windows-latest)", | 3 | "Rust (windows-latest)", |
4 | "Rust (macos-latest)", | 4 | "Rust (macos-latest)", |
5 | "TypeScript" | 5 | "TypeScript (ubuntu-latest)", |
6 | "TypeScript (windows-latest)", | ||
7 | "TypeScript (macos-latest)", | ||
6 | ] | 8 | ] |
7 | delete_merged_branches = true | 9 | delete_merged_branches = true |
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 005c17776..5b1a4680b 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs | |||
@@ -5,7 +5,7 @@ use hir::Semantics; | |||
5 | use ra_db::{FileId, FileRange}; | 5 | use ra_db::{FileId, FileRange}; |
6 | use ra_fmt::{leading_indent, reindent}; | 6 | use ra_fmt::{leading_indent, reindent}; |
7 | use ra_ide_db::{ | 7 | use ra_ide_db::{ |
8 | source_change::{SingleFileChange, SourceChange}, | 8 | source_change::{SourceChange, SourceFileEdit}, |
9 | RootDatabase, | 9 | RootDatabase, |
10 | }; | 10 | }; |
11 | use ra_syntax::{ | 11 | use ra_syntax::{ |
@@ -150,11 +150,10 @@ impl Assists { | |||
150 | self.add_impl(label, f) | 150 | self.add_impl(label, f) |
151 | } | 151 | } |
152 | fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { | 152 | fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { |
153 | let change_label = label.label.clone(); | ||
154 | let source_change = if self.resolve { | 153 | let source_change = if self.resolve { |
155 | let mut builder = AssistBuilder::new(self.file); | 154 | let mut builder = AssistBuilder::new(self.file); |
156 | f(&mut builder); | 155 | f(&mut builder); |
157 | Some(builder.finish(change_label)) | 156 | Some(builder.finish()) |
158 | } else { | 157 | } else { |
159 | None | 158 | None |
160 | }; | 159 | }; |
@@ -171,19 +170,13 @@ impl Assists { | |||
171 | 170 | ||
172 | pub(crate) struct AssistBuilder { | 171 | pub(crate) struct AssistBuilder { |
173 | edit: TextEditBuilder, | 172 | edit: TextEditBuilder, |
174 | cursor_position: Option<TextSize>, | ||
175 | file: FileId, | 173 | file: FileId, |
176 | is_snippet: bool, | 174 | is_snippet: bool, |
177 | } | 175 | } |
178 | 176 | ||
179 | impl AssistBuilder { | 177 | impl AssistBuilder { |
180 | pub(crate) fn new(file: FileId) -> AssistBuilder { | 178 | pub(crate) fn new(file: FileId) -> AssistBuilder { |
181 | AssistBuilder { | 179 | AssistBuilder { edit: TextEditBuilder::default(), file, is_snippet: false } |
182 | edit: TextEditBuilder::default(), | ||
183 | cursor_position: None, | ||
184 | file, | ||
185 | is_snippet: false, | ||
186 | } | ||
187 | } | 180 | } |
188 | 181 | ||
189 | /// Remove specified `range` of text. | 182 | /// Remove specified `range` of text. |
@@ -241,10 +234,6 @@ impl AssistBuilder { | |||
241 | algo::diff(&node, &new).into_text_edit(&mut self.edit) | 234 | algo::diff(&node, &new).into_text_edit(&mut self.edit) |
242 | } | 235 | } |
243 | 236 | ||
244 | /// Specify desired position of the cursor after the assist is applied. | ||
245 | pub(crate) fn set_cursor(&mut self, offset: TextSize) { | ||
246 | self.cursor_position = Some(offset) | ||
247 | } | ||
248 | // FIXME: better API | 237 | // FIXME: better API |
249 | pub(crate) fn set_file(&mut self, assist_file: FileId) { | 238 | pub(crate) fn set_file(&mut self, assist_file: FileId) { |
250 | self.file = assist_file; | 239 | self.file = assist_file; |
@@ -256,14 +245,10 @@ impl AssistBuilder { | |||
256 | &mut self.edit | 245 | &mut self.edit |
257 | } | 246 | } |
258 | 247 | ||
259 | fn finish(self, change_label: String) -> SourceChange { | 248 | fn finish(self) -> SourceChange { |
260 | let edit = self.edit.finish(); | 249 | let edit = self.edit.finish(); |
261 | if edit.is_empty() && self.cursor_position.is_none() { | 250 | let source_file_edit = SourceFileEdit { file_id: self.file, edit }; |
262 | panic!("Only call `add_assist` if the assist can be applied") | 251 | let mut res: SourceChange = source_file_edit.into(); |
263 | } | ||
264 | let mut res = | ||
265 | SingleFileChange { label: change_label, edit, cursor_position: self.cursor_position } | ||
266 | .into_source_change(self.file); | ||
267 | if self.is_snippet { | 252 | if self.is_snippet { |
268 | res.is_snippet = true; | 253 | res.is_snippet = true; |
269 | } | 254 | } |
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index 770049212..ab20c6649 100644 --- a/crates/ra_assists/src/handlers/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs | |||
@@ -86,11 +86,7 @@ mod tests { | |||
86 | 86 | ||
87 | #[test] | 87 | #[test] |
88 | fn add_explicit_type_works_for_simple_expr() { | 88 | fn add_explicit_type_works_for_simple_expr() { |
89 | check_assist( | 89 | check_assist(add_explicit_type, "fn f() { let a<|> = 1; }", "fn f() { let a: i32 = 1; }"); |
90 | add_explicit_type, | ||
91 | "fn f() { let a<|> = 1; }", | ||
92 | "fn f() { let a<|>: i32 = 1; }", | ||
93 | ); | ||
94 | } | 90 | } |
95 | 91 | ||
96 | #[test] | 92 | #[test] |
@@ -98,7 +94,7 @@ mod tests { | |||
98 | check_assist( | 94 | check_assist( |
99 | add_explicit_type, | 95 | add_explicit_type, |
100 | "fn f() { let a<|>: _ = 1; }", | 96 | "fn f() { let a<|>: _ = 1; }", |
101 | "fn f() { let a<|>: i32 = 1; }", | 97 | "fn f() { let a: i32 = 1; }", |
102 | ); | 98 | ); |
103 | } | 99 | } |
104 | 100 | ||
@@ -122,7 +118,7 @@ mod tests { | |||
122 | } | 118 | } |
123 | 119 | ||
124 | fn f() { | 120 | fn f() { |
125 | let a<|>: Option<i32> = Option::Some(1); | 121 | let a: Option<i32> = Option::Some(1); |
126 | }"#, | 122 | }"#, |
127 | ); | 123 | ); |
128 | } | 124 | } |
@@ -132,7 +128,7 @@ mod tests { | |||
132 | check_assist( | 128 | check_assist( |
133 | add_explicit_type, | 129 | add_explicit_type, |
134 | r"macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }", | 130 | r"macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }", |
135 | r"macro_rules! v { () => {0u64} } fn f() { let a<|>: u64 = v!(); }", | 131 | r"macro_rules! v { () => {0u64} } fn f() { let a: u64 = v!(); }", |
136 | ); | 132 | ); |
137 | } | 133 | } |
138 | 134 | ||
@@ -140,8 +136,8 @@ mod tests { | |||
140 | fn add_explicit_type_works_for_macro_call_recursive() { | 136 | fn add_explicit_type_works_for_macro_call_recursive() { |
141 | check_assist( | 137 | check_assist( |
142 | add_explicit_type, | 138 | add_explicit_type, |
143 | "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|> = v!(); }", | 139 | r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|> = v!(); }"#, |
144 | "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|>: u64 = v!(); }", | 140 | r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a: u64 = v!(); }"#, |
145 | ); | 141 | ); |
146 | } | 142 | } |
147 | 143 | ||
@@ -208,7 +204,7 @@ struct Test<K, T = u8> { | |||
208 | } | 204 | } |
209 | 205 | ||
210 | fn main() { | 206 | fn main() { |
211 | let test<|>: Test<i32> = Test { t: 23, k: 33 }; | 207 | let test: Test<i32> = Test { t: 23, k: 33 }; |
212 | }"#, | 208 | }"#, |
213 | ); | 209 | ); |
214 | } | 210 | } |
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs index 5f6c8b19a..6a675e812 100644 --- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs +++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs | |||
@@ -101,7 +101,7 @@ mod tests { | |||
101 | check_assist( | 101 | check_assist( |
102 | add_from_impl_for_enum, | 102 | add_from_impl_for_enum, |
103 | "enum A { <|>One(u32) }", | 103 | "enum A { <|>One(u32) }", |
104 | r#"enum A { <|>One(u32) } | 104 | r#"enum A { One(u32) } |
105 | 105 | ||
106 | impl From<u32> for A { | 106 | impl From<u32> for A { |
107 | fn from(v: u32) -> Self { | 107 | fn from(v: u32) -> Self { |
@@ -116,7 +116,7 @@ impl From<u32> for A { | |||
116 | check_assist( | 116 | check_assist( |
117 | add_from_impl_for_enum, | 117 | add_from_impl_for_enum, |
118 | r#"enum A { <|>One(foo::bar::baz::Boo) }"#, | 118 | r#"enum A { <|>One(foo::bar::baz::Boo) }"#, |
119 | r#"enum A { <|>One(foo::bar::baz::Boo) } | 119 | r#"enum A { One(foo::bar::baz::Boo) } |
120 | 120 | ||
121 | impl From<foo::bar::baz::Boo> for A { | 121 | impl From<foo::bar::baz::Boo> for A { |
122 | fn from(v: foo::bar::baz::Boo) -> Self { | 122 | fn from(v: foo::bar::baz::Boo) -> Self { |
@@ -178,7 +178,7 @@ impl From<String> for A { | |||
178 | pub trait From<T> { | 178 | pub trait From<T> { |
179 | fn from(T) -> Self; | 179 | fn from(T) -> Self; |
180 | }"#, | 180 | }"#, |
181 | r#"enum A { <|>One(u32), Two(String), } | 181 | r#"enum A { One(u32), Two(String), } |
182 | 182 | ||
183 | impl From<u32> for A { | 183 | impl From<u32> for A { |
184 | fn from(v: u32) -> Self { | 184 | fn from(v: u32) -> Self { |
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs index 0feba5e11..233e8fb8e 100644 --- a/crates/ra_assists/src/handlers/apply_demorgan.rs +++ b/crates/ra_assists/src/handlers/apply_demorgan.rs | |||
@@ -63,22 +63,22 @@ mod tests { | |||
63 | 63 | ||
64 | #[test] | 64 | #[test] |
65 | fn demorgan_turns_and_into_or() { | 65 | fn demorgan_turns_and_into_or() { |
66 | check_assist(apply_demorgan, "fn f() { !x &&<|> !x }", "fn f() { !(x ||<|> x) }") | 66 | check_assist(apply_demorgan, "fn f() { !x &&<|> !x }", "fn f() { !(x || x) }") |
67 | } | 67 | } |
68 | 68 | ||
69 | #[test] | 69 | #[test] |
70 | fn demorgan_turns_or_into_and() { | 70 | fn demorgan_turns_or_into_and() { |
71 | check_assist(apply_demorgan, "fn f() { !x ||<|> !x }", "fn f() { !(x &&<|> x) }") | 71 | check_assist(apply_demorgan, "fn f() { !x ||<|> !x }", "fn f() { !(x && x) }") |
72 | } | 72 | } |
73 | 73 | ||
74 | #[test] | 74 | #[test] |
75 | fn demorgan_removes_inequality() { | 75 | fn demorgan_removes_inequality() { |
76 | check_assist(apply_demorgan, "fn f() { x != x ||<|> !x }", "fn f() { !(x == x &&<|> x) }") | 76 | check_assist(apply_demorgan, "fn f() { x != x ||<|> !x }", "fn f() { !(x == x && x) }") |
77 | } | 77 | } |
78 | 78 | ||
79 | #[test] | 79 | #[test] |
80 | fn demorgan_general_case() { | 80 | fn demorgan_general_case() { |
81 | check_assist(apply_demorgan, "fn f() { x ||<|> x }", "fn f() { !(!x &&<|> !x) }") | 81 | check_assist(apply_demorgan, "fn f() { x ||<|> x }", "fn f() { !(!x && !x) }") |
82 | } | 82 | } |
83 | 83 | ||
84 | #[test] | 84 | #[test] |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index f6d25579e..edf96d50e 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -298,7 +298,7 @@ mod tests { | |||
298 | } | 298 | } |
299 | ", | 299 | ", |
300 | r" | 300 | r" |
301 | <|>use PubMod::PubStruct; | 301 | use PubMod::PubStruct; |
302 | 302 | ||
303 | PubStruct | 303 | PubStruct |
304 | 304 | ||
@@ -329,7 +329,7 @@ mod tests { | |||
329 | macro_rules! foo { | 329 | macro_rules! foo { |
330 | ($i:ident) => { fn foo(a: $i) {} } | 330 | ($i:ident) => { fn foo(a: $i) {} } |
331 | } | 331 | } |
332 | foo!(Pub<|>Struct); | 332 | foo!(PubStruct); |
333 | 333 | ||
334 | pub mod PubMod { | 334 | pub mod PubMod { |
335 | pub struct PubStruct; | 335 | pub struct PubStruct; |
@@ -360,7 +360,7 @@ mod tests { | |||
360 | use PubMod::{PubStruct2, PubStruct1}; | 360 | use PubMod::{PubStruct2, PubStruct1}; |
361 | 361 | ||
362 | struct Test { | 362 | struct Test { |
363 | test: Pub<|>Struct2<u8>, | 363 | test: PubStruct2<u8>, |
364 | } | 364 | } |
365 | 365 | ||
366 | pub mod PubMod { | 366 | pub mod PubMod { |
@@ -393,7 +393,7 @@ mod tests { | |||
393 | r" | 393 | r" |
394 | use PubMod3::PubStruct; | 394 | use PubMod3::PubStruct; |
395 | 395 | ||
396 | PubSt<|>ruct | 396 | PubStruct |
397 | 397 | ||
398 | pub mod PubMod1 { | 398 | pub mod PubMod1 { |
399 | pub struct PubStruct; | 399 | pub struct PubStruct; |
@@ -474,7 +474,7 @@ mod tests { | |||
474 | r" | 474 | r" |
475 | use PubMod::test_function; | 475 | use PubMod::test_function; |
476 | 476 | ||
477 | test_function<|> | 477 | test_function |
478 | 478 | ||
479 | pub mod PubMod { | 479 | pub mod PubMod { |
480 | pub fn test_function() {}; | 480 | pub fn test_function() {}; |
@@ -501,7 +501,7 @@ mod tests { | |||
501 | r"use crate_with_macro::foo; | 501 | r"use crate_with_macro::foo; |
502 | 502 | ||
503 | fn main() { | 503 | fn main() { |
504 | foo<|> | 504 | foo |
505 | } | 505 | } |
506 | ", | 506 | ", |
507 | ); | 507 | ); |
@@ -587,7 +587,7 @@ fn main() { | |||
587 | } | 587 | } |
588 | 588 | ||
589 | fn main() { | 589 | fn main() { |
590 | TestStruct::test_function<|> | 590 | TestStruct::test_function |
591 | } | 591 | } |
592 | ", | 592 | ", |
593 | ); | 593 | ); |
@@ -620,7 +620,7 @@ fn main() { | |||
620 | } | 620 | } |
621 | 621 | ||
622 | fn main() { | 622 | fn main() { |
623 | TestStruct::TEST_CONST<|> | 623 | TestStruct::TEST_CONST |
624 | } | 624 | } |
625 | ", | 625 | ", |
626 | ); | 626 | ); |
@@ -659,7 +659,7 @@ fn main() { | |||
659 | } | 659 | } |
660 | 660 | ||
661 | fn main() { | 661 | fn main() { |
662 | test_mod::TestStruct::test_function<|> | 662 | test_mod::TestStruct::test_function |
663 | } | 663 | } |
664 | ", | 664 | ", |
665 | ); | 665 | ); |
@@ -730,7 +730,7 @@ fn main() { | |||
730 | } | 730 | } |
731 | 731 | ||
732 | fn main() { | 732 | fn main() { |
733 | test_mod::TestStruct::TEST_CONST<|> | 733 | test_mod::TestStruct::TEST_CONST |
734 | } | 734 | } |
735 | ", | 735 | ", |
736 | ); | 736 | ); |
@@ -803,7 +803,7 @@ fn main() { | |||
803 | 803 | ||
804 | fn main() { | 804 | fn main() { |
805 | let test_struct = test_mod::TestStruct {}; | 805 | let test_struct = test_mod::TestStruct {}; |
806 | test_struct.test_meth<|>od() | 806 | test_struct.test_method() |
807 | } | 807 | } |
808 | ", | 808 | ", |
809 | ); | 809 | ); |
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs index fbe459c9c..c21d75be0 100644 --- a/crates/ra_assists/src/handlers/change_visibility.rs +++ b/crates/ra_assists/src/handlers/change_visibility.rs | |||
@@ -118,17 +118,13 @@ mod tests { | |||
118 | 118 | ||
119 | #[test] | 119 | #[test] |
120 | fn change_visibility_adds_pub_crate_to_items() { | 120 | fn change_visibility_adds_pub_crate_to_items() { |
121 | check_assist(change_visibility, "<|>fn foo() {}", "<|>pub(crate) fn foo() {}"); | 121 | check_assist(change_visibility, "<|>fn foo() {}", "pub(crate) fn foo() {}"); |
122 | check_assist(change_visibility, "f<|>n foo() {}", "pub(crate) f<|>n foo() {}"); | 122 | check_assist(change_visibility, "f<|>n foo() {}", "pub(crate) fn foo() {}"); |
123 | check_assist(change_visibility, "<|>struct Foo {}", "<|>pub(crate) struct Foo {}"); | 123 | check_assist(change_visibility, "<|>struct Foo {}", "pub(crate) struct Foo {}"); |
124 | check_assist(change_visibility, "<|>mod foo {}", "<|>pub(crate) mod foo {}"); | 124 | check_assist(change_visibility, "<|>mod foo {}", "pub(crate) mod foo {}"); |
125 | check_assist(change_visibility, "<|>trait Foo {}", "<|>pub(crate) trait Foo {}"); | 125 | check_assist(change_visibility, "<|>trait Foo {}", "pub(crate) trait Foo {}"); |
126 | check_assist(change_visibility, "m<|>od {}", "pub(crate) m<|>od {}"); | 126 | check_assist(change_visibility, "m<|>od {}", "pub(crate) mod {}"); |
127 | check_assist( | 127 | check_assist(change_visibility, "unsafe f<|>n foo() {}", "pub(crate) unsafe fn foo() {}"); |
128 | change_visibility, | ||
129 | "unsafe f<|>n foo() {}", | ||
130 | "pub(crate) unsafe f<|>n foo() {}", | ||
131 | ); | ||
132 | } | 128 | } |
133 | 129 | ||
134 | #[test] | 130 | #[test] |
@@ -136,9 +132,9 @@ mod tests { | |||
136 | check_assist( | 132 | check_assist( |
137 | change_visibility, | 133 | change_visibility, |
138 | r"struct S { <|>field: u32 }", | 134 | r"struct S { <|>field: u32 }", |
139 | r"struct S { <|>pub(crate) field: u32 }", | 135 | r"struct S { pub(crate) field: u32 }", |
140 | ); | 136 | ); |
141 | check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( <|>pub(crate) u32 )"); | 137 | check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( pub(crate) u32 )"); |
142 | } | 138 | } |
143 | 139 | ||
144 | #[test] | 140 | #[test] |
@@ -152,17 +148,17 @@ mod tests { | |||
152 | 148 | ||
153 | #[test] | 149 | #[test] |
154 | fn change_visibility_pub_to_pub_crate() { | 150 | fn change_visibility_pub_to_pub_crate() { |
155 | check_assist(change_visibility, "<|>pub fn foo() {}", "<|>pub(crate) fn foo() {}") | 151 | check_assist(change_visibility, "<|>pub fn foo() {}", "pub(crate) fn foo() {}") |
156 | } | 152 | } |
157 | 153 | ||
158 | #[test] | 154 | #[test] |
159 | fn change_visibility_pub_crate_to_pub() { | 155 | fn change_visibility_pub_crate_to_pub() { |
160 | check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "<|>pub fn foo() {}") | 156 | check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "pub fn foo() {}") |
161 | } | 157 | } |
162 | 158 | ||
163 | #[test] | 159 | #[test] |
164 | fn change_visibility_const() { | 160 | fn change_visibility_const() { |
165 | check_assist(change_visibility, "<|>const FOO = 3u8;", "<|>pub(crate) const FOO = 3u8;"); | 161 | check_assist(change_visibility, "<|>const FOO = 3u8;", "pub(crate) const FOO = 3u8;"); |
166 | } | 162 | } |
167 | 163 | ||
168 | #[test] | 164 | #[test] |
@@ -183,7 +179,7 @@ mod tests { | |||
183 | // comments | 179 | // comments |
184 | 180 | ||
185 | #[derive(Debug)] | 181 | #[derive(Debug)] |
186 | <|>pub(crate) struct Foo; | 182 | pub(crate) struct Foo; |
187 | ", | 183 | ", |
188 | ) | 184 | ) |
189 | } | 185 | } |
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index 66b296081..4cc75a7ce 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -97,7 +97,6 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) | |||
97 | } | 97 | } |
98 | 98 | ||
99 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; | 99 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; |
100 | let cursor_position = ctx.offset(); | ||
101 | 100 | ||
102 | let target = if_expr.syntax().text_range(); | 101 | let target = if_expr.syntax().text_range(); |
103 | acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| { | 102 | acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| { |
@@ -148,7 +147,6 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) | |||
148 | } | 147 | } |
149 | }; | 148 | }; |
150 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); | 149 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); |
151 | edit.set_cursor(cursor_position); | ||
152 | 150 | ||
153 | fn replace( | 151 | fn replace( |
154 | new_expr: &SyntaxNode, | 152 | new_expr: &SyntaxNode, |
@@ -207,7 +205,7 @@ mod tests { | |||
207 | r#" | 205 | r#" |
208 | fn main() { | 206 | fn main() { |
209 | bar(); | 207 | bar(); |
210 | if<|> !true { | 208 | if !true { |
211 | return; | 209 | return; |
212 | } | 210 | } |
213 | foo(); | 211 | foo(); |
@@ -237,7 +235,7 @@ mod tests { | |||
237 | r#" | 235 | r#" |
238 | fn main(n: Option<String>) { | 236 | fn main(n: Option<String>) { |
239 | bar(); | 237 | bar(); |
240 | le<|>t n = match n { | 238 | let n = match n { |
241 | Some(it) => it, | 239 | Some(it) => it, |
242 | _ => return, | 240 | _ => return, |
243 | }; | 241 | }; |
@@ -263,7 +261,7 @@ mod tests { | |||
263 | "#, | 261 | "#, |
264 | r#" | 262 | r#" |
265 | fn main() { | 263 | fn main() { |
266 | le<|>t x = match Err(92) { | 264 | let x = match Err(92) { |
267 | Ok(it) => it, | 265 | Ok(it) => it, |
268 | _ => return, | 266 | _ => return, |
269 | }; | 267 | }; |
@@ -291,7 +289,7 @@ mod tests { | |||
291 | r#" | 289 | r#" |
292 | fn main(n: Option<String>) { | 290 | fn main(n: Option<String>) { |
293 | bar(); | 291 | bar(); |
294 | le<|>t n = match n { | 292 | let n = match n { |
295 | Ok(it) => it, | 293 | Ok(it) => it, |
296 | _ => return, | 294 | _ => return, |
297 | }; | 295 | }; |
@@ -321,7 +319,7 @@ mod tests { | |||
321 | r#" | 319 | r#" |
322 | fn main() { | 320 | fn main() { |
323 | while true { | 321 | while true { |
324 | if<|> !true { | 322 | if !true { |
325 | continue; | 323 | continue; |
326 | } | 324 | } |
327 | foo(); | 325 | foo(); |
@@ -349,7 +347,7 @@ mod tests { | |||
349 | r#" | 347 | r#" |
350 | fn main() { | 348 | fn main() { |
351 | while true { | 349 | while true { |
352 | le<|>t n = match n { | 350 | let n = match n { |
353 | Some(it) => it, | 351 | Some(it) => it, |
354 | _ => continue, | 352 | _ => continue, |
355 | }; | 353 | }; |
@@ -378,7 +376,7 @@ mod tests { | |||
378 | r#" | 376 | r#" |
379 | fn main() { | 377 | fn main() { |
380 | loop { | 378 | loop { |
381 | if<|> !true { | 379 | if !true { |
382 | continue; | 380 | continue; |
383 | } | 381 | } |
384 | foo(); | 382 | foo(); |
@@ -406,7 +404,7 @@ mod tests { | |||
406 | r#" | 404 | r#" |
407 | fn main() { | 405 | fn main() { |
408 | loop { | 406 | loop { |
409 | le<|>t n = match n { | 407 | let n = match n { |
410 | Some(it) => it, | 408 | Some(it) => it, |
411 | _ => continue, | 409 | _ => continue, |
412 | }; | 410 | }; |
diff --git a/crates/ra_assists/src/handlers/flip_binexpr.rs b/crates/ra_assists/src/handlers/flip_binexpr.rs index 692ba4895..573196576 100644 --- a/crates/ra_assists/src/handlers/flip_binexpr.rs +++ b/crates/ra_assists/src/handlers/flip_binexpr.rs | |||
@@ -85,17 +85,13 @@ mod tests { | |||
85 | check_assist( | 85 | check_assist( |
86 | flip_binexpr, | 86 | flip_binexpr, |
87 | "fn f() { let res = 1 ==<|> 2; }", | 87 | "fn f() { let res = 1 ==<|> 2; }", |
88 | "fn f() { let res = 2 ==<|> 1; }", | 88 | "fn f() { let res = 2 == 1; }", |
89 | ) | 89 | ) |
90 | } | 90 | } |
91 | 91 | ||
92 | #[test] | 92 | #[test] |
93 | fn flip_binexpr_works_for_gt() { | 93 | fn flip_binexpr_works_for_gt() { |
94 | check_assist( | 94 | check_assist(flip_binexpr, "fn f() { let res = 1 ><|> 2; }", "fn f() { let res = 2 < 1; }") |
95 | flip_binexpr, | ||
96 | "fn f() { let res = 1 ><|> 2; }", | ||
97 | "fn f() { let res = 2 <<|> 1; }", | ||
98 | ) | ||
99 | } | 95 | } |
100 | 96 | ||
101 | #[test] | 97 | #[test] |
@@ -103,7 +99,7 @@ mod tests { | |||
103 | check_assist( | 99 | check_assist( |
104 | flip_binexpr, | 100 | flip_binexpr, |
105 | "fn f() { let res = 1 <=<|> 2; }", | 101 | "fn f() { let res = 1 <=<|> 2; }", |
106 | "fn f() { let res = 2 >=<|> 1; }", | 102 | "fn f() { let res = 2 >= 1; }", |
107 | ) | 103 | ) |
108 | } | 104 | } |
109 | 105 | ||
@@ -112,7 +108,7 @@ mod tests { | |||
112 | check_assist( | 108 | check_assist( |
113 | flip_binexpr, | 109 | flip_binexpr, |
114 | "fn f() { let res = (1 + 1) ==<|> (2 + 2); }", | 110 | "fn f() { let res = (1 + 1) ==<|> (2 + 2); }", |
115 | "fn f() { let res = (2 + 2) ==<|> (1 + 1); }", | 111 | "fn f() { let res = (2 + 2) == (1 + 1); }", |
116 | ) | 112 | ) |
117 | } | 113 | } |
118 | 114 | ||
@@ -132,7 +128,7 @@ mod tests { | |||
132 | fn dyn_eq(&self, other: &dyn Diagnostic) -> bool { | 128 | fn dyn_eq(&self, other: &dyn Diagnostic) -> bool { |
133 | match other.downcast_ref::<Self>() { | 129 | match other.downcast_ref::<Self>() { |
134 | None => false, | 130 | None => false, |
135 | Some(it) => self ==<|> it, | 131 | Some(it) => self == it, |
136 | } | 132 | } |
137 | } | 133 | } |
138 | "#, | 134 | "#, |
diff --git a/crates/ra_assists/src/handlers/flip_comma.rs b/crates/ra_assists/src/handlers/flip_comma.rs index dfe2a7fed..a57a1c463 100644 --- a/crates/ra_assists/src/handlers/flip_comma.rs +++ b/crates/ra_assists/src/handlers/flip_comma.rs | |||
@@ -45,7 +45,7 @@ mod tests { | |||
45 | check_assist( | 45 | check_assist( |
46 | flip_comma, | 46 | flip_comma, |
47 | "fn foo(x: i32,<|> y: Result<(), ()>) {}", | 47 | "fn foo(x: i32,<|> y: Result<(), ()>) {}", |
48 | "fn foo(y: Result<(), ()>,<|> x: i32) {}", | 48 | "fn foo(y: Result<(), ()>, x: i32) {}", |
49 | ) | 49 | ) |
50 | } | 50 | } |
51 | 51 | ||
diff --git a/crates/ra_assists/src/handlers/flip_trait_bound.rs b/crates/ra_assists/src/handlers/flip_trait_bound.rs index 8a08702ab..0115adc8b 100644 --- a/crates/ra_assists/src/handlers/flip_trait_bound.rs +++ b/crates/ra_assists/src/handlers/flip_trait_bound.rs | |||
@@ -60,7 +60,7 @@ mod tests { | |||
60 | check_assist( | 60 | check_assist( |
61 | flip_trait_bound, | 61 | flip_trait_bound, |
62 | "struct S<T> where T: A <|>+ B { }", | 62 | "struct S<T> where T: A <|>+ B { }", |
63 | "struct S<T> where T: B <|>+ A { }", | 63 | "struct S<T> where T: B + A { }", |
64 | ) | 64 | ) |
65 | } | 65 | } |
66 | 66 | ||
@@ -69,13 +69,13 @@ mod tests { | |||
69 | check_assist( | 69 | check_assist( |
70 | flip_trait_bound, | 70 | flip_trait_bound, |
71 | "impl X for S<T> where T: A +<|> B { }", | 71 | "impl X for S<T> where T: A +<|> B { }", |
72 | "impl X for S<T> where T: B +<|> A { }", | 72 | "impl X for S<T> where T: B + A { }", |
73 | ) | 73 | ) |
74 | } | 74 | } |
75 | 75 | ||
76 | #[test] | 76 | #[test] |
77 | fn flip_trait_bound_works_for_fn() { | 77 | fn flip_trait_bound_works_for_fn() { |
78 | check_assist(flip_trait_bound, "fn f<T: A <|>+ B>(t: T) { }", "fn f<T: B <|>+ A>(t: T) { }") | 78 | check_assist(flip_trait_bound, "fn f<T: A <|>+ B>(t: T) { }", "fn f<T: B + A>(t: T) { }") |
79 | } | 79 | } |
80 | 80 | ||
81 | #[test] | 81 | #[test] |
@@ -83,7 +83,7 @@ mod tests { | |||
83 | check_assist( | 83 | check_assist( |
84 | flip_trait_bound, | 84 | flip_trait_bound, |
85 | "fn f<T>(t: T) where T: A +<|> B { }", | 85 | "fn f<T>(t: T) where T: A +<|> B { }", |
86 | "fn f<T>(t: T) where T: B +<|> A { }", | 86 | "fn f<T>(t: T) where T: B + A { }", |
87 | ) | 87 | ) |
88 | } | 88 | } |
89 | 89 | ||
@@ -92,7 +92,7 @@ mod tests { | |||
92 | check_assist( | 92 | check_assist( |
93 | flip_trait_bound, | 93 | flip_trait_bound, |
94 | "fn f<T>(t: T) where T: A <|>+ 'static { }", | 94 | "fn f<T>(t: T) where T: A <|>+ 'static { }", |
95 | "fn f<T>(t: T) where T: 'static <|>+ A { }", | 95 | "fn f<T>(t: T) where T: 'static + A { }", |
96 | ) | 96 | ) |
97 | } | 97 | } |
98 | 98 | ||
@@ -101,7 +101,7 @@ mod tests { | |||
101 | check_assist( | 101 | check_assist( |
102 | flip_trait_bound, | 102 | flip_trait_bound, |
103 | "struct S<T> where T: A<T> <|>+ b_mod::B<T> + C<T> { }", | 103 | "struct S<T> where T: A<T> <|>+ b_mod::B<T> + C<T> { }", |
104 | "struct S<T> where T: b_mod::B<T> <|>+ A<T> + C<T> { }", | 104 | "struct S<T> where T: b_mod::B<T> + A<T> + C<T> { }", |
105 | ) | 105 | ) |
106 | } | 106 | } |
107 | 107 | ||
@@ -110,7 +110,7 @@ mod tests { | |||
110 | check_assist( | 110 | check_assist( |
111 | flip_trait_bound, | 111 | flip_trait_bound, |
112 | "struct S<T> where T: A + B + C + D + E + F +<|> G + H + I + J { }", | 112 | "struct S<T> where T: A + B + C + D + E + F +<|> G + H + I + J { }", |
113 | "struct S<T> where T: A + B + C + D + E + G +<|> F + H + I + J { }", | 113 | "struct S<T> where T: A + B + C + D + E + G + F + H + I + J { }", |
114 | ) | 114 | ) |
115 | } | 115 | } |
116 | } | 116 | } |
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index 46d675a4e..d26e68847 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs | |||
@@ -116,7 +116,6 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | |||
116 | let replacement = if should_wrap { init_in_paren.clone() } else { init_str.clone() }; | 116 | let replacement = if should_wrap { init_in_paren.clone() } else { init_str.clone() }; |
117 | builder.replace(desc.file_range.range, replacement) | 117 | builder.replace(desc.file_range.range, replacement) |
118 | } | 118 | } |
119 | builder.set_cursor(delete_range.start()) | ||
120 | }) | 119 | }) |
121 | } | 120 | } |
122 | 121 | ||
@@ -149,7 +148,7 @@ fn foo() { | |||
149 | r" | 148 | r" |
150 | fn bar(a: usize) {} | 149 | fn bar(a: usize) {} |
151 | fn foo() { | 150 | fn foo() { |
152 | <|>1 + 1; | 151 | 1 + 1; |
153 | if 1 > 10 { | 152 | if 1 > 10 { |
154 | } | 153 | } |
155 | 154 | ||
@@ -183,7 +182,7 @@ fn foo() { | |||
183 | r" | 182 | r" |
184 | fn bar(a: usize) {} | 183 | fn bar(a: usize) {} |
185 | fn foo() { | 184 | fn foo() { |
186 | <|>(1 + 1) + 1; | 185 | (1 + 1) + 1; |
187 | if (1 + 1) > 10 { | 186 | if (1 + 1) > 10 { |
188 | } | 187 | } |
189 | 188 | ||
@@ -217,7 +216,7 @@ fn foo() { | |||
217 | r" | 216 | r" |
218 | fn bar(a: usize) {} | 217 | fn bar(a: usize) {} |
219 | fn foo() { | 218 | fn foo() { |
220 | <|>bar(1) + 1; | 219 | bar(1) + 1; |
221 | if bar(1) > 10 { | 220 | if bar(1) > 10 { |
222 | } | 221 | } |
223 | 222 | ||
@@ -251,7 +250,7 @@ fn foo() { | |||
251 | r" | 250 | r" |
252 | fn bar(a: usize): usize { a } | 251 | fn bar(a: usize): usize { a } |
253 | fn foo() { | 252 | fn foo() { |
254 | <|>(bar(1) as u64) + 1; | 253 | (bar(1) as u64) + 1; |
255 | if (bar(1) as u64) > 10 { | 254 | if (bar(1) as u64) > 10 { |
256 | } | 255 | } |
257 | 256 | ||
@@ -283,7 +282,7 @@ fn foo() { | |||
283 | }", | 282 | }", |
284 | r" | 283 | r" |
285 | fn foo() { | 284 | fn foo() { |
286 | <|>{ 10 + 1 } + 1; | 285 | { 10 + 1 } + 1; |
287 | if { 10 + 1 } > 10 { | 286 | if { 10 + 1 } > 10 { |
288 | } | 287 | } |
289 | 288 | ||
@@ -315,7 +314,7 @@ fn foo() { | |||
315 | }", | 314 | }", |
316 | r" | 315 | r" |
317 | fn foo() { | 316 | fn foo() { |
318 | <|>( 10 + 1 ) + 1; | 317 | ( 10 + 1 ) + 1; |
319 | if ( 10 + 1 ) > 10 { | 318 | if ( 10 + 1 ) > 10 { |
320 | } | 319 | } |
321 | 320 | ||
@@ -353,7 +352,7 @@ fn foo() { | |||
353 | }", | 352 | }", |
354 | r" | 353 | r" |
355 | fn foo() { | 354 | fn foo() { |
356 | <|>let b = bar(10 + 1) * 10; | 355 | let b = bar(10 + 1) * 10; |
357 | let c = bar(10 + 1) as usize; | 356 | let c = bar(10 + 1) as usize; |
358 | }", | 357 | }", |
359 | ); | 358 | ); |
@@ -373,7 +372,7 @@ fn foo() { | |||
373 | r" | 372 | r" |
374 | fn foo() { | 373 | fn foo() { |
375 | let x = vec![1, 2, 3]; | 374 | let x = vec![1, 2, 3]; |
376 | <|>let b = x[0] * 10; | 375 | let b = x[0] * 10; |
377 | let c = x[0] as usize; | 376 | let c = x[0] as usize; |
378 | }", | 377 | }", |
379 | ); | 378 | ); |
@@ -393,7 +392,7 @@ fn foo() { | |||
393 | r" | 392 | r" |
394 | fn foo() { | 393 | fn foo() { |
395 | let bar = vec![1]; | 394 | let bar = vec![1]; |
396 | <|>let b = bar.len() * 10; | 395 | let b = bar.len() * 10; |
397 | let c = bar.len() as usize; | 396 | let c = bar.len() as usize; |
398 | }", | 397 | }", |
399 | ); | 398 | ); |
@@ -421,7 +420,7 @@ struct Bar { | |||
421 | 420 | ||
422 | fn foo() { | 421 | fn foo() { |
423 | let bar = Bar { foo: 1 }; | 422 | let bar = Bar { foo: 1 }; |
424 | <|>let b = bar.foo * 10; | 423 | let b = bar.foo * 10; |
425 | let c = bar.foo as usize; | 424 | let c = bar.foo as usize; |
426 | }", | 425 | }", |
427 | ); | 426 | ); |
@@ -442,7 +441,7 @@ fn foo() -> Option<usize> { | |||
442 | r" | 441 | r" |
443 | fn foo() -> Option<usize> { | 442 | fn foo() -> Option<usize> { |
444 | let bar = Some(1); | 443 | let bar = Some(1); |
445 | <|>let b = bar? * 10; | 444 | let b = bar? * 10; |
446 | let c = bar? as usize; | 445 | let c = bar? as usize; |
447 | None | 446 | None |
448 | }", | 447 | }", |
@@ -462,7 +461,7 @@ fn foo() { | |||
462 | r" | 461 | r" |
463 | fn foo() { | 462 | fn foo() { |
464 | let bar = 10; | 463 | let bar = 10; |
465 | <|>let b = &bar * 10; | 464 | let b = &bar * 10; |
466 | }", | 465 | }", |
467 | ); | 466 | ); |
468 | } | 467 | } |
@@ -478,7 +477,7 @@ fn foo() { | |||
478 | }", | 477 | }", |
479 | r" | 478 | r" |
480 | fn foo() { | 479 | fn foo() { |
481 | <|>let b = (10, 20)[0]; | 480 | let b = (10, 20)[0]; |
482 | }", | 481 | }", |
483 | ); | 482 | ); |
484 | } | 483 | } |
@@ -494,7 +493,7 @@ fn foo() { | |||
494 | }", | 493 | }", |
495 | r" | 494 | r" |
496 | fn foo() { | 495 | fn foo() { |
497 | <|>let b = [1, 2, 3].len(); | 496 | let b = [1, 2, 3].len(); |
498 | }", | 497 | }", |
499 | ); | 498 | ); |
500 | } | 499 | } |
@@ -511,7 +510,7 @@ fn foo() { | |||
511 | }", | 510 | }", |
512 | r" | 511 | r" |
513 | fn foo() { | 512 | fn foo() { |
514 | <|>let b = (10 + 20) * 10; | 513 | let b = (10 + 20) * 10; |
515 | let c = (10 + 20) as usize; | 514 | let c = (10 + 20) as usize; |
516 | }", | 515 | }", |
517 | ); | 516 | ); |
@@ -531,7 +530,7 @@ fn foo() { | |||
531 | r" | 530 | r" |
532 | fn foo() { | 531 | fn foo() { |
533 | let d = 10; | 532 | let d = 10; |
534 | <|>let b = d * 10; | 533 | let b = d * 10; |
535 | let c = d as usize; | 534 | let c = d as usize; |
536 | }", | 535 | }", |
537 | ); | 536 | ); |
@@ -549,7 +548,7 @@ fn foo() { | |||
549 | }", | 548 | }", |
550 | r" | 549 | r" |
551 | fn foo() { | 550 | fn foo() { |
552 | <|>let b = { 10 } * 10; | 551 | let b = { 10 } * 10; |
553 | let c = { 10 } as usize; | 552 | let c = { 10 } as usize; |
554 | }", | 553 | }", |
555 | ); | 554 | ); |
@@ -569,7 +568,7 @@ fn foo() { | |||
569 | }", | 568 | }", |
570 | r" | 569 | r" |
571 | fn foo() { | 570 | fn foo() { |
572 | <|>let b = (10 + 20) * 10; | 571 | let b = (10 + 20) * 10; |
573 | let c = (10 + 20, 20); | 572 | let c = (10 + 20, 20); |
574 | let d = [10 + 20, 10]; | 573 | let d = [10 + 20, 10]; |
575 | let e = (10 + 20); | 574 | let e = (10 + 20); |
@@ -588,7 +587,7 @@ fn foo() { | |||
588 | }", | 587 | }", |
589 | r" | 588 | r" |
590 | fn foo() { | 589 | fn foo() { |
591 | <|>for i in vec![10, 20] {} | 590 | for i in vec![10, 20] {} |
592 | }", | 591 | }", |
593 | ); | 592 | ); |
594 | } | 593 | } |
@@ -604,7 +603,7 @@ fn foo() { | |||
604 | }", | 603 | }", |
605 | r" | 604 | r" |
606 | fn foo() { | 605 | fn foo() { |
607 | <|>while 1 > 0 {} | 606 | while 1 > 0 {} |
608 | }", | 607 | }", |
609 | ); | 608 | ); |
610 | } | 609 | } |
@@ -622,7 +621,7 @@ fn foo() { | |||
622 | }", | 621 | }", |
623 | r" | 622 | r" |
624 | fn foo() { | 623 | fn foo() { |
625 | <|>loop { | 624 | loop { |
626 | break 1 + 1; | 625 | break 1 + 1; |
627 | } | 626 | } |
628 | }", | 627 | }", |
@@ -640,7 +639,7 @@ fn foo() { | |||
640 | }", | 639 | }", |
641 | r" | 640 | r" |
642 | fn foo() { | 641 | fn foo() { |
643 | <|>return 1 > 0; | 642 | return 1 > 0; |
644 | }", | 643 | }", |
645 | ); | 644 | ); |
646 | } | 645 | } |
@@ -656,7 +655,7 @@ fn foo() { | |||
656 | }", | 655 | }", |
657 | r" | 656 | r" |
658 | fn foo() { | 657 | fn foo() { |
659 | <|>match 1 > 0 {} | 658 | match 1 > 0 {} |
660 | }", | 659 | }", |
661 | ); | 660 | ); |
662 | } | 661 | } |
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index 56c610fed..31d6539f7 100644 --- a/crates/ra_assists/src/handlers/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs | |||
@@ -4,7 +4,7 @@ use ra_syntax::{ | |||
4 | BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, | 4 | BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, |
5 | WHITESPACE, | 5 | WHITESPACE, |
6 | }, | 6 | }, |
7 | SyntaxNode, TextSize, | 7 | SyntaxNode, |
8 | }; | 8 | }; |
9 | use stdx::format_to; | 9 | use stdx::format_to; |
10 | use test_utils::mark; | 10 | use test_utils::mark; |
@@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, Assists}; | |||
23 | // -> | 23 | // -> |
24 | // ``` | 24 | // ``` |
25 | // fn main() { | 25 | // fn main() { |
26 | // let var_name = (1 + 2); | 26 | // let $0var_name = (1 + 2); |
27 | // var_name * 4; | 27 | // var_name * 4; |
28 | // } | 28 | // } |
29 | // ``` | 29 | // ``` |
@@ -46,14 +46,13 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
46 | acc.add(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { | 46 | acc.add(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { |
47 | let mut buf = String::new(); | 47 | let mut buf = String::new(); |
48 | 48 | ||
49 | let cursor_offset = if wrap_in_block { | 49 | if wrap_in_block { |
50 | buf.push_str("{ let var_name = "); | 50 | buf.push_str("{ let var_name = "); |
51 | TextSize::of("{ let ") | ||
52 | } else { | 51 | } else { |
53 | buf.push_str("let var_name = "); | 52 | buf.push_str("let var_name = "); |
54 | TextSize::of("let ") | ||
55 | }; | 53 | }; |
56 | format_to!(buf, "{}", expr.syntax()); | 54 | format_to!(buf, "{}", expr.syntax()); |
55 | |||
57 | let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); | 56 | let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); |
58 | let is_full_stmt = if let Some(expr_stmt) = &full_stmt { | 57 | let is_full_stmt = if let Some(expr_stmt) = &full_stmt { |
59 | Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone()) | 58 | Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone()) |
@@ -65,28 +64,43 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
65 | if full_stmt.unwrap().semicolon_token().is_none() { | 64 | if full_stmt.unwrap().semicolon_token().is_none() { |
66 | buf.push_str(";"); | 65 | buf.push_str(";"); |
67 | } | 66 | } |
68 | edit.replace(expr.syntax().text_range(), buf); | 67 | let offset = expr.syntax().text_range(); |
69 | } else { | 68 | match ctx.config.snippet_cap { |
70 | buf.push_str(";"); | 69 | Some(cap) => { |
71 | 70 | let snip = buf.replace("let var_name", "let $0var_name"); | |
72 | // We want to maintain the indent level, | 71 | edit.replace_snippet(cap, offset, snip) |
73 | // but we do not want to duplicate possible | 72 | } |
74 | // extra newlines in the indent block | 73 | None => edit.replace(offset, buf), |
75 | let text = indent.text(); | ||
76 | if text.starts_with('\n') { | ||
77 | buf.push_str("\n"); | ||
78 | buf.push_str(text.trim_start_matches('\n')); | ||
79 | } else { | ||
80 | buf.push_str(text); | ||
81 | } | 74 | } |
75 | return; | ||
76 | } | ||
82 | 77 | ||
83 | edit.replace(expr.syntax().text_range(), "var_name".to_string()); | 78 | buf.push_str(";"); |
84 | edit.insert(anchor_stmt.text_range().start(), buf); | 79 | |
85 | if wrap_in_block { | 80 | // We want to maintain the indent level, |
86 | edit.insert(anchor_stmt.text_range().end(), " }"); | 81 | // but we do not want to duplicate possible |
82 | // extra newlines in the indent block | ||
83 | let text = indent.text(); | ||
84 | if text.starts_with('\n') { | ||
85 | buf.push_str("\n"); | ||
86 | buf.push_str(text.trim_start_matches('\n')); | ||
87 | } else { | ||
88 | buf.push_str(text); | ||
89 | } | ||
90 | |||
91 | edit.replace(expr.syntax().text_range(), "var_name".to_string()); | ||
92 | let offset = anchor_stmt.text_range().start(); | ||
93 | match ctx.config.snippet_cap { | ||
94 | Some(cap) => { | ||
95 | let snip = buf.replace("let var_name", "let $0var_name"); | ||
96 | edit.insert_snippet(cap, offset, snip) | ||
87 | } | 97 | } |
98 | None => edit.insert(offset, buf), | ||
99 | } | ||
100 | |||
101 | if wrap_in_block { | ||
102 | edit.insert(anchor_stmt.text_range().end(), " }"); | ||
88 | } | 103 | } |
89 | edit.set_cursor(anchor_stmt.text_range().start() + cursor_offset); | ||
90 | }) | 104 | }) |
91 | } | 105 | } |
92 | 106 | ||
@@ -144,15 +158,15 @@ mod tests { | |||
144 | fn test_introduce_var_simple() { | 158 | fn test_introduce_var_simple() { |
145 | check_assist( | 159 | check_assist( |
146 | introduce_variable, | 160 | introduce_variable, |
147 | " | 161 | r#" |
148 | fn foo() { | 162 | fn foo() { |
149 | foo(<|>1 + 1<|>); | 163 | foo(<|>1 + 1<|>); |
150 | }", | 164 | }"#, |
151 | " | 165 | r#" |
152 | fn foo() { | 166 | fn foo() { |
153 | let <|>var_name = 1 + 1; | 167 | let $0var_name = 1 + 1; |
154 | foo(var_name); | 168 | foo(var_name); |
155 | }", | 169 | }"#, |
156 | ); | 170 | ); |
157 | } | 171 | } |
158 | 172 | ||
@@ -167,14 +181,14 @@ fn foo() { | |||
167 | mark::check!(test_introduce_var_expr_stmt); | 181 | mark::check!(test_introduce_var_expr_stmt); |
168 | check_assist( | 182 | check_assist( |
169 | introduce_variable, | 183 | introduce_variable, |
170 | " | 184 | r#" |
171 | fn foo() { | 185 | fn foo() { |
172 | <|>1 + 1<|>; | 186 | <|>1 + 1<|>; |
173 | }", | 187 | }"#, |
174 | " | 188 | r#" |
175 | fn foo() { | 189 | fn foo() { |
176 | let <|>var_name = 1 + 1; | 190 | let $0var_name = 1 + 1; |
177 | }", | 191 | }"#, |
178 | ); | 192 | ); |
179 | check_assist( | 193 | check_assist( |
180 | introduce_variable, | 194 | introduce_variable, |
@@ -185,7 +199,7 @@ fn foo() { | |||
185 | }", | 199 | }", |
186 | " | 200 | " |
187 | fn foo() { | 201 | fn foo() { |
188 | let <|>var_name = { let x = 0; x }; | 202 | let $0var_name = { let x = 0; x }; |
189 | something_else(); | 203 | something_else(); |
190 | }", | 204 | }", |
191 | ); | 205 | ); |
@@ -201,7 +215,7 @@ fn foo() { | |||
201 | }", | 215 | }", |
202 | " | 216 | " |
203 | fn foo() { | 217 | fn foo() { |
204 | let <|>var_name = 1; | 218 | let $0var_name = 1; |
205 | var_name + 1; | 219 | var_name + 1; |
206 | }", | 220 | }", |
207 | ); | 221 | ); |
@@ -218,7 +232,7 @@ fn foo() { | |||
218 | }", | 232 | }", |
219 | " | 233 | " |
220 | fn foo() { | 234 | fn foo() { |
221 | let <|>var_name = 1 + 1; | 235 | let $0var_name = 1 + 1; |
222 | bar(var_name) | 236 | bar(var_name) |
223 | }", | 237 | }", |
224 | ); | 238 | ); |
@@ -230,7 +244,7 @@ fn foo() { | |||
230 | }", | 244 | }", |
231 | " | 245 | " |
232 | fn foo() { | 246 | fn foo() { |
233 | let <|>var_name = bar(1 + 1); | 247 | let $0var_name = bar(1 + 1); |
234 | var_name | 248 | var_name |
235 | }", | 249 | }", |
236 | ) | 250 | ) |
@@ -253,7 +267,7 @@ fn main() { | |||
253 | fn main() { | 267 | fn main() { |
254 | let x = true; | 268 | let x = true; |
255 | let tuple = match x { | 269 | let tuple = match x { |
256 | true => { let <|>var_name = 2 + 2; (var_name, true) } | 270 | true => { let $0var_name = 2 + 2; (var_name, true) } |
257 | _ => (0, false) | 271 | _ => (0, false) |
258 | }; | 272 | }; |
259 | } | 273 | } |
@@ -283,7 +297,7 @@ fn main() { | |||
283 | let tuple = match x { | 297 | let tuple = match x { |
284 | true => { | 298 | true => { |
285 | let y = 1; | 299 | let y = 1; |
286 | let <|>var_name = 2 + y; | 300 | let $0var_name = 2 + y; |
287 | (var_name, true) | 301 | (var_name, true) |
288 | } | 302 | } |
289 | _ => (0, false) | 303 | _ => (0, false) |
@@ -304,7 +318,7 @@ fn main() { | |||
304 | ", | 318 | ", |
305 | " | 319 | " |
306 | fn main() { | 320 | fn main() { |
307 | let lambda = |x: u32| { let <|>var_name = x * 2; var_name }; | 321 | let lambda = |x: u32| { let $0var_name = x * 2; var_name }; |
308 | } | 322 | } |
309 | ", | 323 | ", |
310 | ); | 324 | ); |
@@ -321,7 +335,7 @@ fn main() { | |||
321 | ", | 335 | ", |
322 | " | 336 | " |
323 | fn main() { | 337 | fn main() { |
324 | let lambda = |x: u32| { let <|>var_name = x * 2; var_name }; | 338 | let lambda = |x: u32| { let $0var_name = x * 2; var_name }; |
325 | } | 339 | } |
326 | ", | 340 | ", |
327 | ); | 341 | ); |
@@ -338,7 +352,7 @@ fn main() { | |||
338 | ", | 352 | ", |
339 | " | 353 | " |
340 | fn main() { | 354 | fn main() { |
341 | let <|>var_name = Some(true); | 355 | let $0var_name = Some(true); |
342 | let o = var_name; | 356 | let o = var_name; |
343 | } | 357 | } |
344 | ", | 358 | ", |
@@ -356,7 +370,7 @@ fn main() { | |||
356 | ", | 370 | ", |
357 | " | 371 | " |
358 | fn main() { | 372 | fn main() { |
359 | let <|>var_name = bar.foo(); | 373 | let $0var_name = bar.foo(); |
360 | let v = var_name; | 374 | let v = var_name; |
361 | } | 375 | } |
362 | ", | 376 | ", |
@@ -374,7 +388,7 @@ fn foo() -> u32 { | |||
374 | ", | 388 | ", |
375 | " | 389 | " |
376 | fn foo() -> u32 { | 390 | fn foo() -> u32 { |
377 | let <|>var_name = 2 + 2; | 391 | let $0var_name = 2 + 2; |
378 | return var_name; | 392 | return var_name; |
379 | } | 393 | } |
380 | ", | 394 | ", |
@@ -396,7 +410,7 @@ fn foo() -> u32 { | |||
396 | fn foo() -> u32 { | 410 | fn foo() -> u32 { |
397 | 411 | ||
398 | 412 | ||
399 | let <|>var_name = 2 + 2; | 413 | let $0var_name = 2 + 2; |
400 | return var_name; | 414 | return var_name; |
401 | } | 415 | } |
402 | ", | 416 | ", |
@@ -413,7 +427,7 @@ fn foo() -> u32 { | |||
413 | " | 427 | " |
414 | fn foo() -> u32 { | 428 | fn foo() -> u32 { |
415 | 429 | ||
416 | let <|>var_name = 2 + 2; | 430 | let $0var_name = 2 + 2; |
417 | return var_name; | 431 | return var_name; |
418 | } | 432 | } |
419 | ", | 433 | ", |
@@ -438,7 +452,7 @@ fn foo() -> u32 { | |||
438 | // bar | 452 | // bar |
439 | 453 | ||
440 | 454 | ||
441 | let <|>var_name = 2 + 2; | 455 | let $0var_name = 2 + 2; |
442 | return var_name; | 456 | return var_name; |
443 | } | 457 | } |
444 | ", | 458 | ", |
@@ -459,7 +473,7 @@ fn main() { | |||
459 | " | 473 | " |
460 | fn main() { | 474 | fn main() { |
461 | let result = loop { | 475 | let result = loop { |
462 | let <|>var_name = 2 + 2; | 476 | let $0var_name = 2 + 2; |
463 | break var_name; | 477 | break var_name; |
464 | }; | 478 | }; |
465 | } | 479 | } |
@@ -478,7 +492,7 @@ fn main() { | |||
478 | ", | 492 | ", |
479 | " | 493 | " |
480 | fn main() { | 494 | fn main() { |
481 | let <|>var_name = 0f32 as u32; | 495 | let $0var_name = 0f32 as u32; |
482 | let v = var_name; | 496 | let v = var_name; |
483 | } | 497 | } |
484 | ", | 498 | ", |
diff --git a/crates/ra_assists/src/handlers/invert_if.rs b/crates/ra_assists/src/handlers/invert_if.rs index 527c7caef..59d278eb9 100644 --- a/crates/ra_assists/src/handlers/invert_if.rs +++ b/crates/ra_assists/src/handlers/invert_if.rs | |||
@@ -72,7 +72,7 @@ mod tests { | |||
72 | check_assist( | 72 | check_assist( |
73 | invert_if, | 73 | invert_if, |
74 | "fn f() { i<|>f x != 3 { 1 } else { 3 + 2 } }", | 74 | "fn f() { i<|>f x != 3 { 1 } else { 3 + 2 } }", |
75 | "fn f() { i<|>f x == 3 { 3 + 2 } else { 1 } }", | 75 | "fn f() { if x == 3 { 3 + 2 } else { 1 } }", |
76 | ) | 76 | ) |
77 | } | 77 | } |
78 | 78 | ||
@@ -81,7 +81,7 @@ mod tests { | |||
81 | check_assist( | 81 | check_assist( |
82 | invert_if, | 82 | invert_if, |
83 | "fn f() { <|>if !cond { 3 * 2 } else { 1 } }", | 83 | "fn f() { <|>if !cond { 3 * 2 } else { 1 } }", |
84 | "fn f() { <|>if cond { 1 } else { 3 * 2 } }", | 84 | "fn f() { if cond { 1 } else { 3 * 2 } }", |
85 | ) | 85 | ) |
86 | } | 86 | } |
87 | 87 | ||
@@ -90,7 +90,7 @@ mod tests { | |||
90 | check_assist( | 90 | check_assist( |
91 | invert_if, | 91 | invert_if, |
92 | "fn f() { i<|>f cond { 3 * 2 } else { 1 } }", | 92 | "fn f() { i<|>f cond { 3 * 2 } else { 1 } }", |
93 | "fn f() { i<|>f !cond { 1 } else { 3 * 2 } }", | 93 | "fn f() { if !cond { 1 } else { 3 * 2 } }", |
94 | ) | 94 | ) |
95 | } | 95 | } |
96 | 96 | ||
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index ac3e53c27..972d16241 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs | |||
@@ -58,8 +58,6 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<() | |||
58 | let target = tree.syntax().text_range(); | 58 | let target = tree.syntax().text_range(); |
59 | acc.add(AssistId("merge_imports"), "Merge imports", target, |builder| { | 59 | acc.add(AssistId("merge_imports"), "Merge imports", target, |builder| { |
60 | builder.rewrite(rewriter); | 60 | builder.rewrite(rewriter); |
61 | // FIXME: we only need because our diff is imprecise | ||
62 | builder.set_cursor(offset); | ||
63 | }) | 61 | }) |
64 | } | 62 | } |
65 | 63 | ||
@@ -142,7 +140,7 @@ use std::fmt<|>::Debug; | |||
142 | use std::fmt::Display; | 140 | use std::fmt::Display; |
143 | ", | 141 | ", |
144 | r" | 142 | r" |
145 | use std::fmt<|>::{Debug, Display}; | 143 | use std::fmt::{Debug, Display}; |
146 | ", | 144 | ", |
147 | ) | 145 | ) |
148 | } | 146 | } |
@@ -156,7 +154,7 @@ use std::fmt::Debug; | |||
156 | use std::fmt<|>::Display; | 154 | use std::fmt<|>::Display; |
157 | ", | 155 | ", |
158 | r" | 156 | r" |
159 | use std::fmt:<|>:{Display, Debug}; | 157 | use std::fmt::{Display, Debug}; |
160 | ", | 158 | ", |
161 | ); | 159 | ); |
162 | } | 160 | } |
@@ -169,7 +167,7 @@ use std::fmt:<|>:{Display, Debug}; | |||
169 | use std::{fmt<|>::Debug, fmt::Display}; | 167 | use std::{fmt<|>::Debug, fmt::Display}; |
170 | ", | 168 | ", |
171 | r" | 169 | r" |
172 | use std::{fmt<|>::{Debug, Display}}; | 170 | use std::{fmt::{Debug, Display}}; |
173 | ", | 171 | ", |
174 | ); | 172 | ); |
175 | check_assist( | 173 | check_assist( |
@@ -178,7 +176,7 @@ use std::{fmt<|>::{Debug, Display}}; | |||
178 | use std::{fmt::Debug, fmt<|>::Display}; | 176 | use std::{fmt::Debug, fmt<|>::Display}; |
179 | ", | 177 | ", |
180 | r" | 178 | r" |
181 | use std::{fmt::<|>{Display, Debug}}; | 179 | use std::{fmt::{Display, Debug}}; |
182 | ", | 180 | ", |
183 | ); | 181 | ); |
184 | } | 182 | } |
@@ -192,7 +190,7 @@ use std<|>::cell::*; | |||
192 | use std::str; | 190 | use std::str; |
193 | ", | 191 | ", |
194 | r" | 192 | r" |
195 | use std<|>::{cell::*, str}; | 193 | use std::{cell::*, str}; |
196 | ", | 194 | ", |
197 | ) | 195 | ) |
198 | } | 196 | } |
@@ -206,7 +204,7 @@ use std<|>::cell::*; | |||
206 | use std::str::*; | 204 | use std::str::*; |
207 | ", | 205 | ", |
208 | r" | 206 | r" |
209 | use std<|>::{cell::*, str::*}; | 207 | use std::{cell::*, str::*}; |
210 | ", | 208 | ", |
211 | ) | 209 | ) |
212 | } | 210 | } |
@@ -222,7 +220,7 @@ use foo::baz; | |||
222 | /// Doc comment | 220 | /// Doc comment |
223 | ", | 221 | ", |
224 | r" | 222 | r" |
225 | use foo<|>::{bar, baz}; | 223 | use foo::{bar, baz}; |
226 | 224 | ||
227 | /// Doc comment | 225 | /// Doc comment |
228 | ", | 226 | ", |
@@ -241,7 +239,7 @@ use { | |||
241 | ", | 239 | ", |
242 | r" | 240 | r" |
243 | use { | 241 | use { |
244 | foo<|>::{bar, baz}, | 242 | foo::{bar, baz}, |
245 | }; | 243 | }; |
246 | ", | 244 | ", |
247 | ); | 245 | ); |
@@ -255,7 +253,7 @@ use { | |||
255 | ", | 253 | ", |
256 | r" | 254 | r" |
257 | use { | 255 | use { |
258 | foo::{bar<|>, baz}, | 256 | foo::{bar, baz}, |
259 | }; | 257 | }; |
260 | ", | 258 | ", |
261 | ); | 259 | ); |
@@ -272,7 +270,7 @@ use foo::<|>{ | |||
272 | }; | 270 | }; |
273 | ", | 271 | ", |
274 | r" | 272 | r" |
275 | use foo::{<|> | 273 | use foo::{ |
276 | FooBar, | 274 | FooBar, |
277 | bar::baz}; | 275 | bar::baz}; |
278 | ", | 276 | ", |
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs index d4e38aa6a..ca04ec671 100644 --- a/crates/ra_assists/src/handlers/merge_match_arms.rs +++ b/crates/ra_assists/src/handlers/merge_match_arms.rs | |||
@@ -3,7 +3,7 @@ use std::iter::successors; | |||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | algo::neighbor, | 4 | algo::neighbor, |
5 | ast::{self, AstNode}, | 5 | ast::{self, AstNode}, |
6 | Direction, TextSize, | 6 | Direction, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{AssistContext, AssistId, Assists, TextRange}; | 9 | use crate::{AssistContext, AssistId, Assists, TextRange}; |
@@ -41,17 +41,6 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
41 | let current_expr = current_arm.expr()?; | 41 | let current_expr = current_arm.expr()?; |
42 | let current_text_range = current_arm.syntax().text_range(); | 42 | let current_text_range = current_arm.syntax().text_range(); |
43 | 43 | ||
44 | enum CursorPos { | ||
45 | InExpr(TextSize), | ||
46 | InPat(TextSize), | ||
47 | } | ||
48 | let cursor_pos = ctx.offset(); | ||
49 | let cursor_pos = if current_expr.syntax().text_range().contains(cursor_pos) { | ||
50 | CursorPos::InExpr(current_text_range.end() - cursor_pos) | ||
51 | } else { | ||
52 | CursorPos::InPat(cursor_pos) | ||
53 | }; | ||
54 | |||
55 | // We check if the following match arms match this one. We could, but don't, | 44 | // We check if the following match arms match this one. We could, but don't, |
56 | // compare to the previous match arm as well. | 45 | // compare to the previous match arm as well. |
57 | let arms_to_merge = successors(Some(current_arm), |it| neighbor(it, Direction::Next)) | 46 | let arms_to_merge = successors(Some(current_arm), |it| neighbor(it, Direction::Next)) |
@@ -87,10 +76,6 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
87 | let start = arms_to_merge.first().unwrap().syntax().text_range().start(); | 76 | let start = arms_to_merge.first().unwrap().syntax().text_range().start(); |
88 | let end = arms_to_merge.last().unwrap().syntax().text_range().end(); | 77 | let end = arms_to_merge.last().unwrap().syntax().text_range().end(); |
89 | 78 | ||
90 | edit.set_cursor(match cursor_pos { | ||
91 | CursorPos::InExpr(back_offset) => start + TextSize::of(&arm) - back_offset, | ||
92 | CursorPos::InPat(offset) => offset, | ||
93 | }); | ||
94 | edit.replace(TextRange::new(start, end), arm); | 79 | edit.replace(TextRange::new(start, end), arm); |
95 | }) | 80 | }) |
96 | } | 81 | } |
@@ -132,7 +117,7 @@ mod tests { | |||
132 | fn main() { | 117 | fn main() { |
133 | let x = X::A; | 118 | let x = X::A; |
134 | let y = match x { | 119 | let y = match x { |
135 | X::A | X::B => { 1i32<|> } | 120 | X::A | X::B => { 1i32 } |
136 | X::C => { 2i32 } | 121 | X::C => { 2i32 } |
137 | } | 122 | } |
138 | } | 123 | } |
@@ -164,7 +149,7 @@ mod tests { | |||
164 | fn main() { | 149 | fn main() { |
165 | let x = X::A; | 150 | let x = X::A; |
166 | let y = match x { | 151 | let y = match x { |
167 | X::A | X::B | X::C | X::D => {<|> 1i32 }, | 152 | X::A | X::B | X::C | X::D => { 1i32 }, |
168 | X::E => { 2i32 }, | 153 | X::E => { 2i32 }, |
169 | } | 154 | } |
170 | } | 155 | } |
@@ -197,7 +182,7 @@ mod tests { | |||
197 | let x = X::A; | 182 | let x = X::A; |
198 | let y = match x { | 183 | let y = match x { |
199 | X::A => { 1i32 }, | 184 | X::A => { 1i32 }, |
200 | _ => { 2i<|>32 } | 185 | _ => { 2i32 } |
201 | } | 186 | } |
202 | } | 187 | } |
203 | "#, | 188 | "#, |
@@ -226,7 +211,7 @@ mod tests { | |||
226 | 211 | ||
227 | fn main() { | 212 | fn main() { |
228 | match X::A { | 213 | match X::A { |
229 | X::A<|> | X::B | X::C => 92, | 214 | X::A | X::B | X::C => 92, |
230 | X::D => 62, | 215 | X::D => 62, |
231 | _ => panic!(), | 216 | _ => panic!(), |
232 | } | 217 | } |
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs index a41aacfc3..be2a7eddc 100644 --- a/crates/ra_assists/src/handlers/move_bounds.rs +++ b/crates/ra_assists/src/handlers/move_bounds.rs | |||
@@ -99,7 +99,7 @@ mod tests { | |||
99 | fn foo<T: u32, <|>F: FnOnce(T) -> T>() {} | 99 | fn foo<T: u32, <|>F: FnOnce(T) -> T>() {} |
100 | "#, | 100 | "#, |
101 | r#" | 101 | r#" |
102 | fn foo<T, <|>F>() where T: u32, F: FnOnce(T) -> T {} | 102 | fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {} |
103 | "#, | 103 | "#, |
104 | ); | 104 | ); |
105 | } | 105 | } |
@@ -112,7 +112,7 @@ mod tests { | |||
112 | impl<U: u32, <|>T> A<U, T> {} | 112 | impl<U: u32, <|>T> A<U, T> {} |
113 | "#, | 113 | "#, |
114 | r#" | 114 | r#" |
115 | impl<U, <|>T> A<U, T> where U: u32 {} | 115 | impl<U, T> A<U, T> where U: u32 {} |
116 | "#, | 116 | "#, |
117 | ); | 117 | ); |
118 | } | 118 | } |
@@ -125,7 +125,7 @@ mod tests { | |||
125 | struct A<<|>T: Iterator<Item = u32>> {} | 125 | struct A<<|>T: Iterator<Item = u32>> {} |
126 | "#, | 126 | "#, |
127 | r#" | 127 | r#" |
128 | struct A<<|>T> where T: Iterator<Item = u32> {} | 128 | struct A<T> where T: Iterator<Item = u32> {} |
129 | "#, | 129 | "#, |
130 | ); | 130 | ); |
131 | } | 131 | } |
@@ -138,7 +138,7 @@ mod tests { | |||
138 | struct Pair<<|>T: u32>(T, T); | 138 | struct Pair<<|>T: u32>(T, T); |
139 | "#, | 139 | "#, |
140 | r#" | 140 | r#" |
141 | struct Pair<<|>T>(T, T) where T: u32; | 141 | struct Pair<T>(T, T) where T: u32; |
142 | "#, | 142 | "#, |
143 | ); | 143 | ); |
144 | } | 144 | } |
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs index fc0335b57..7edcf0748 100644 --- a/crates/ra_assists/src/handlers/move_guard.rs +++ b/crates/ra_assists/src/handlers/move_guard.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | ast, | 2 | ast::{AstNode, IfExpr, MatchArm}, |
3 | ast::{AstNode, AstToken, IfExpr, MatchArm}, | 3 | SyntaxKind::WHITESPACE, |
4 | TextSize, | ||
5 | }; | 4 | }; |
6 | 5 | ||
7 | use crate::{AssistContext, AssistId, Assists}; | 6 | use crate::{AssistContext, AssistId, Assists}; |
@@ -42,24 +41,15 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) -> | |||
42 | 41 | ||
43 | let target = guard.syntax().text_range(); | 42 | let target = guard.syntax().text_range(); |
44 | acc.add(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| { | 43 | acc.add(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| { |
45 | let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { | 44 | match space_before_guard { |
46 | Some(tok) => { | 45 | Some(element) if element.kind() == WHITESPACE => { |
47 | if ast::Whitespace::cast(tok.clone()).is_some() { | 46 | edit.delete(element.text_range()); |
48 | let ele = tok.text_range(); | ||
49 | edit.delete(ele); | ||
50 | ele.len() | ||
51 | } else { | ||
52 | TextSize::from(0) | ||
53 | } | ||
54 | } | 47 | } |
55 | _ => TextSize::from(0), | 48 | _ => (), |
56 | }; | 49 | }; |
57 | 50 | ||
58 | edit.delete(guard.syntax().text_range()); | 51 | edit.delete(guard.syntax().text_range()); |
59 | edit.replace_node_and_indent(arm_expr.syntax(), buf); | 52 | edit.replace_node_and_indent(arm_expr.syntax(), buf); |
60 | edit.set_cursor( | ||
61 | arm_expr.syntax().text_range().start() + TextSize::from(3) - offseting_amount, | ||
62 | ); | ||
63 | }) | 53 | }) |
64 | } | 54 | } |
65 | 55 | ||
@@ -124,7 +114,6 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex | |||
124 | } | 114 | } |
125 | 115 | ||
126 | edit.insert(match_pat.syntax().text_range().end(), buf); | 116 | edit.insert(match_pat.syntax().text_range().end(), buf); |
127 | edit.set_cursor(match_pat.syntax().text_range().end() + TextSize::from(1)); | ||
128 | }, | 117 | }, |
129 | ) | 118 | ) |
130 | } | 119 | } |
@@ -172,7 +161,7 @@ mod tests { | |||
172 | let t = 'a'; | 161 | let t = 'a'; |
173 | let chars = "abcd"; | 162 | let chars = "abcd"; |
174 | match t { | 163 | match t { |
175 | '\r' => if chars.clone().next() == Some('\n') { <|>false }, | 164 | '\r' => if chars.clone().next() == Some('\n') { false }, |
176 | _ => true | 165 | _ => true |
177 | } | 166 | } |
178 | } | 167 | } |
@@ -195,7 +184,7 @@ mod tests { | |||
195 | r#" | 184 | r#" |
196 | fn f() { | 185 | fn f() { |
197 | match x { | 186 | match x { |
198 | y @ 4 | y @ 5 => if y > 5 { <|>true }, | 187 | y @ 4 | y @ 5 => if y > 5 { true }, |
199 | _ => false | 188 | _ => false |
200 | } | 189 | } |
201 | } | 190 | } |
@@ -222,7 +211,7 @@ mod tests { | |||
222 | let t = 'a'; | 211 | let t = 'a'; |
223 | let chars = "abcd"; | 212 | let chars = "abcd"; |
224 | match t { | 213 | match t { |
225 | '\r' <|>if chars.clone().next() == Some('\n') => false, | 214 | '\r' if chars.clone().next() == Some('\n') => false, |
226 | _ => true | 215 | _ => true |
227 | } | 216 | } |
228 | } | 217 | } |
@@ -266,7 +255,7 @@ mod tests { | |||
266 | let t = 'a'; | 255 | let t = 'a'; |
267 | let chars = "abcd"; | 256 | let chars = "abcd"; |
268 | match t { | 257 | match t { |
269 | '\r' <|>if chars.clone().next().is_some() => { }, | 258 | '\r' if chars.clone().next().is_some() => { }, |
270 | _ => true | 259 | _ => true |
271 | } | 260 | } |
272 | } | 261 | } |
@@ -296,7 +285,7 @@ mod tests { | |||
296 | let mut t = 'a'; | 285 | let mut t = 'a'; |
297 | let chars = "abcd"; | 286 | let chars = "abcd"; |
298 | match t { | 287 | match t { |
299 | '\r' <|>if chars.clone().next().is_some() => { | 288 | '\r' if chars.clone().next().is_some() => { |
300 | t = 'e'; | 289 | t = 'e'; |
301 | false | 290 | false |
302 | }, | 291 | }, |
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs index c20ffe0b3..16002d2ac 100644 --- a/crates/ra_assists/src/handlers/raw_string.rs +++ b/crates/ra_assists/src/handlers/raw_string.rs | |||
@@ -164,7 +164,7 @@ mod test { | |||
164 | "#, | 164 | "#, |
165 | r##" | 165 | r##" |
166 | fn f() { | 166 | fn f() { |
167 | let s = <|>r#"random | 167 | let s = r#"random |
168 | string"#; | 168 | string"#; |
169 | } | 169 | } |
170 | "##, | 170 | "##, |
@@ -182,7 +182,7 @@ string"#; | |||
182 | "#, | 182 | "#, |
183 | r##" | 183 | r##" |
184 | fn f() { | 184 | fn f() { |
185 | format!(<|>r#"x = {}"#, 92) | 185 | format!(r#"x = {}"#, 92) |
186 | } | 186 | } |
187 | "##, | 187 | "##, |
188 | ) | 188 | ) |
@@ -199,7 +199,7 @@ string"#; | |||
199 | "###, | 199 | "###, |
200 | r####" | 200 | r####" |
201 | fn f() { | 201 | fn f() { |
202 | let s = <|>r#"#random## | 202 | let s = r#"#random## |
203 | string"#; | 203 | string"#; |
204 | } | 204 | } |
205 | "####, | 205 | "####, |
@@ -217,7 +217,7 @@ string"#; | |||
217 | "###, | 217 | "###, |
218 | r####" | 218 | r####" |
219 | fn f() { | 219 | fn f() { |
220 | let s = <|>r###"#random"## | 220 | let s = r###"#random"## |
221 | string"###; | 221 | string"###; |
222 | } | 222 | } |
223 | "####, | 223 | "####, |
@@ -235,7 +235,7 @@ string"###; | |||
235 | "#, | 235 | "#, |
236 | r##" | 236 | r##" |
237 | fn f() { | 237 | fn f() { |
238 | let s = <|>r#"random string"#; | 238 | let s = r#"random string"#; |
239 | } | 239 | } |
240 | "##, | 240 | "##, |
241 | ) | 241 | ) |
@@ -289,7 +289,7 @@ string"###; | |||
289 | "#, | 289 | "#, |
290 | r##" | 290 | r##" |
291 | fn f() { | 291 | fn f() { |
292 | let s = <|>r#"random string"#; | 292 | let s = r#"random string"#; |
293 | } | 293 | } |
294 | "##, | 294 | "##, |
295 | ) | 295 | ) |
@@ -306,7 +306,7 @@ string"###; | |||
306 | "##, | 306 | "##, |
307 | r###" | 307 | r###" |
308 | fn f() { | 308 | fn f() { |
309 | let s = <|>r##"random"string"##; | 309 | let s = r##"random"string"##; |
310 | } | 310 | } |
311 | "###, | 311 | "###, |
312 | ) | 312 | ) |
@@ -348,7 +348,7 @@ string"###; | |||
348 | "##, | 348 | "##, |
349 | r#" | 349 | r#" |
350 | fn f() { | 350 | fn f() { |
351 | let s = <|>r"random string"; | 351 | let s = r"random string"; |
352 | } | 352 | } |
353 | "#, | 353 | "#, |
354 | ) | 354 | ) |
@@ -365,7 +365,7 @@ string"###; | |||
365 | "##, | 365 | "##, |
366 | r#" | 366 | r#" |
367 | fn f() { | 367 | fn f() { |
368 | let s = <|>r"random\"str\"ing"; | 368 | let s = r"random\"str\"ing"; |
369 | } | 369 | } |
370 | "#, | 370 | "#, |
371 | ) | 371 | ) |
@@ -382,7 +382,7 @@ string"###; | |||
382 | "###, | 382 | "###, |
383 | r##" | 383 | r##" |
384 | fn f() { | 384 | fn f() { |
385 | let s = <|>r#"random string"#; | 385 | let s = r#"random string"#; |
386 | } | 386 | } |
387 | "##, | 387 | "##, |
388 | ) | 388 | ) |
@@ -436,7 +436,7 @@ string"###; | |||
436 | "##, | 436 | "##, |
437 | r#" | 437 | r#" |
438 | fn f() { | 438 | fn f() { |
439 | let s = <|>"random string"; | 439 | let s = "random string"; |
440 | } | 440 | } |
441 | "#, | 441 | "#, |
442 | ) | 442 | ) |
@@ -453,7 +453,7 @@ string"###; | |||
453 | "##, | 453 | "##, |
454 | r#" | 454 | r#" |
455 | fn f() { | 455 | fn f() { |
456 | let s = <|>"random\"str\"ing"; | 456 | let s = "random\"str\"ing"; |
457 | } | 457 | } |
458 | "#, | 458 | "#, |
459 | ) | 459 | ) |
@@ -470,7 +470,7 @@ string"###; | |||
470 | "###, | 470 | "###, |
471 | r##" | 471 | r##" |
472 | fn f() { | 472 | fn f() { |
473 | let s = <|>"random string"; | 473 | let s = "random string"; |
474 | } | 474 | } |
475 | "##, | 475 | "##, |
476 | ) | 476 | ) |
diff --git a/crates/ra_assists/src/handlers/remove_dbg.rs b/crates/ra_assists/src/handlers/remove_dbg.rs index 8eef578cf..961ee1731 100644 --- a/crates/ra_assists/src/handlers/remove_dbg.rs +++ b/crates/ra_assists/src/handlers/remove_dbg.rs | |||
@@ -29,26 +29,6 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
29 | 29 | ||
30 | let macro_range = macro_call.syntax().text_range(); | 30 | let macro_range = macro_call.syntax().text_range(); |
31 | 31 | ||
32 | // If the cursor is inside the macro call, we'll try to maintain the cursor | ||
33 | // position by subtracting the length of dbg!( from the start of the file | ||
34 | // range, otherwise we'll default to using the start of the macro call | ||
35 | let cursor_pos = { | ||
36 | let file_range = ctx.frange.range; | ||
37 | |||
38 | let offset_start = file_range | ||
39 | .start() | ||
40 | .checked_sub(macro_range.start()) | ||
41 | .unwrap_or_else(|| TextSize::from(0)); | ||
42 | |||
43 | let dbg_size = TextSize::of("dbg!("); | ||
44 | |||
45 | if offset_start > dbg_size { | ||
46 | file_range.start() - dbg_size | ||
47 | } else { | ||
48 | macro_range.start() | ||
49 | } | ||
50 | }; | ||
51 | |||
52 | let macro_content = { | 32 | let macro_content = { |
53 | let macro_args = macro_call.token_tree()?.syntax().clone(); | 33 | let macro_args = macro_call.token_tree()?.syntax().clone(); |
54 | 34 | ||
@@ -58,9 +38,8 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
58 | }; | 38 | }; |
59 | 39 | ||
60 | let target = macro_call.syntax().text_range(); | 40 | let target = macro_call.syntax().text_range(); |
61 | acc.add(AssistId("remove_dbg"), "Remove dbg!()", target, |edit| { | 41 | acc.add(AssistId("remove_dbg"), "Remove dbg!()", target, |builder| { |
62 | edit.replace(macro_range, macro_content); | 42 | builder.replace(macro_range, macro_content); |
63 | edit.set_cursor(cursor_pos); | ||
64 | }) | 43 | }) |
65 | } | 44 | } |
66 | 45 | ||
@@ -94,13 +73,13 @@ mod tests { | |||
94 | 73 | ||
95 | #[test] | 74 | #[test] |
96 | fn test_remove_dbg() { | 75 | fn test_remove_dbg() { |
97 | check_assist(remove_dbg, "<|>dbg!(1 + 1)", "<|>1 + 1"); | 76 | check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1"); |
98 | 77 | ||
99 | check_assist(remove_dbg, "dbg!<|>((1 + 1))", "<|>(1 + 1)"); | 78 | check_assist(remove_dbg, "dbg!<|>((1 + 1))", "(1 + 1)"); |
100 | 79 | ||
101 | check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 <|>+ 1"); | 80 | check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 + 1"); |
102 | 81 | ||
103 | check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = <|>1 + 1"); | 82 | check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = 1 + 1"); |
104 | 83 | ||
105 | check_assist( | 84 | check_assist( |
106 | remove_dbg, | 85 | remove_dbg, |
@@ -113,7 +92,7 @@ fn foo(n: usize) { | |||
113 | ", | 92 | ", |
114 | " | 93 | " |
115 | fn foo(n: usize) { | 94 | fn foo(n: usize) { |
116 | if let Some(_) = n.<|>checked_sub(4) { | 95 | if let Some(_) = n.checked_sub(4) { |
117 | // ... | 96 | // ... |
118 | } | 97 | } |
119 | } | 98 | } |
@@ -122,8 +101,8 @@ fn foo(n: usize) { | |||
122 | } | 101 | } |
123 | #[test] | 102 | #[test] |
124 | fn test_remove_dbg_with_brackets_and_braces() { | 103 | fn test_remove_dbg_with_brackets_and_braces() { |
125 | check_assist(remove_dbg, "dbg![<|>1 + 1]", "<|>1 + 1"); | 104 | check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1"); |
126 | check_assist(remove_dbg, "dbg!{<|>1 + 1}", "<|>1 + 1"); | 105 | check_assist(remove_dbg, "dbg!{<|>1 + 1}", "1 + 1"); |
127 | } | 106 | } |
128 | 107 | ||
129 | #[test] | 108 | #[test] |
diff --git a/crates/ra_assists/src/handlers/remove_mut.rs b/crates/ra_assists/src/handlers/remove_mut.rs index dce546db7..fe4eada03 100644 --- a/crates/ra_assists/src/handlers/remove_mut.rs +++ b/crates/ra_assists/src/handlers/remove_mut.rs | |||
@@ -26,8 +26,7 @@ pub(crate) fn remove_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
26 | }; | 26 | }; |
27 | 27 | ||
28 | let target = mut_token.text_range(); | 28 | let target = mut_token.text_range(); |
29 | acc.add(AssistId("remove_mut"), "Remove `mut` keyword", target, |edit| { | 29 | acc.add(AssistId("remove_mut"), "Remove `mut` keyword", target, |builder| { |
30 | edit.set_cursor(delete_from); | 30 | builder.delete(TextRange::new(delete_from, delete_to)); |
31 | edit.delete(TextRange::new(delete_from, delete_to)); | ||
32 | }) | 31 | }) |
33 | } | 32 | } |
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs index 757f6406e..897da2832 100644 --- a/crates/ra_assists/src/handlers/reorder_fields.rs +++ b/crates/ra_assists/src/handlers/reorder_fields.rs | |||
@@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, Assists}; | |||
23 | // ``` | 23 | // ``` |
24 | // | 24 | // |
25 | pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 25 | pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
26 | reorder::<ast::RecordLit>(acc, ctx.clone()).or_else(|| reorder::<ast::RecordPat>(acc, ctx)) | 26 | reorder::<ast::RecordLit>(acc, ctx).or_else(|| reorder::<ast::RecordPat>(acc, ctx)) |
27 | } | 27 | } |
28 | 28 | ||
29 | fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 29 | fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
@@ -140,7 +140,7 @@ mod tests { | |||
140 | "#, | 140 | "#, |
141 | r#" | 141 | r#" |
142 | struct Foo {foo: i32, bar: i32}; | 142 | struct Foo {foo: i32, bar: i32}; |
143 | const test: Foo = <|>Foo {foo: 1, bar: 0} | 143 | const test: Foo = Foo {foo: 1, bar: 0} |
144 | "#, | 144 | "#, |
145 | ) | 145 | ) |
146 | } | 146 | } |
@@ -164,7 +164,7 @@ mod tests { | |||
164 | 164 | ||
165 | fn f(f: Foo) -> { | 165 | fn f(f: Foo) -> { |
166 | match f { | 166 | match f { |
167 | <|>Foo { ref mut bar, baz: 0, .. } => (), | 167 | Foo { ref mut bar, baz: 0, .. } => (), |
168 | _ => () | 168 | _ => () |
169 | } | 169 | } |
170 | } | 170 | } |
@@ -202,7 +202,7 @@ mod tests { | |||
202 | impl Foo { | 202 | impl Foo { |
203 | fn new() -> Foo { | 203 | fn new() -> Foo { |
204 | let foo = String::new(); | 204 | let foo = String::new(); |
205 | <|>Foo { | 205 | Foo { |
206 | foo, | 206 | foo, |
207 | bar: foo.clone(), | 207 | bar: foo.clone(), |
208 | extra: "Extra field", | 208 | extra: "Extra field", |
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs index 65f5fc6ab..e016f51c3 100644 --- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -68,7 +68,6 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
68 | .indent(IndentLevel::from_node(if_expr.syntax())) | 68 | .indent(IndentLevel::from_node(if_expr.syntax())) |
69 | }; | 69 | }; |
70 | 70 | ||
71 | edit.set_cursor(if_expr.syntax().text_range().start()); | ||
72 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); | 71 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); |
73 | }) | 72 | }) |
74 | } | 73 | } |
@@ -83,7 +82,7 @@ mod tests { | |||
83 | fn test_replace_if_let_with_match_unwraps_simple_expressions() { | 82 | fn test_replace_if_let_with_match_unwraps_simple_expressions() { |
84 | check_assist( | 83 | check_assist( |
85 | replace_if_let_with_match, | 84 | replace_if_let_with_match, |
86 | " | 85 | r#" |
87 | impl VariantData { | 86 | impl VariantData { |
88 | pub fn is_struct(&self) -> bool { | 87 | pub fn is_struct(&self) -> bool { |
89 | if <|>let VariantData::Struct(..) = *self { | 88 | if <|>let VariantData::Struct(..) = *self { |
@@ -92,16 +91,16 @@ impl VariantData { | |||
92 | false | 91 | false |
93 | } | 92 | } |
94 | } | 93 | } |
95 | } ", | 94 | } "#, |
96 | " | 95 | r#" |
97 | impl VariantData { | 96 | impl VariantData { |
98 | pub fn is_struct(&self) -> bool { | 97 | pub fn is_struct(&self) -> bool { |
99 | <|>match *self { | 98 | match *self { |
100 | VariantData::Struct(..) => true, | 99 | VariantData::Struct(..) => true, |
101 | _ => false, | 100 | _ => false, |
102 | } | 101 | } |
103 | } | 102 | } |
104 | } ", | 103 | } "#, |
105 | ) | 104 | ) |
106 | } | 105 | } |
107 | 106 | ||
@@ -109,7 +108,7 @@ impl VariantData { | |||
109 | fn test_replace_if_let_with_match_doesnt_unwrap_multiline_expressions() { | 108 | fn test_replace_if_let_with_match_doesnt_unwrap_multiline_expressions() { |
110 | check_assist( | 109 | check_assist( |
111 | replace_if_let_with_match, | 110 | replace_if_let_with_match, |
112 | " | 111 | r#" |
113 | fn foo() { | 112 | fn foo() { |
114 | if <|>let VariantData::Struct(..) = a { | 113 | if <|>let VariantData::Struct(..) = a { |
115 | bar( | 114 | bar( |
@@ -118,10 +117,10 @@ fn foo() { | |||
118 | } else { | 117 | } else { |
119 | false | 118 | false |
120 | } | 119 | } |
121 | } ", | 120 | } "#, |
122 | " | 121 | r#" |
123 | fn foo() { | 122 | fn foo() { |
124 | <|>match a { | 123 | match a { |
125 | VariantData::Struct(..) => { | 124 | VariantData::Struct(..) => { |
126 | bar( | 125 | bar( |
127 | 123 | 126 | 123 |
@@ -129,7 +128,7 @@ fn foo() { | |||
129 | } | 128 | } |
130 | _ => false, | 129 | _ => false, |
131 | } | 130 | } |
132 | } ", | 131 | } "#, |
133 | ) | 132 | ) |
134 | } | 133 | } |
135 | 134 | ||
@@ -137,7 +136,7 @@ fn foo() { | |||
137 | fn replace_if_let_with_match_target() { | 136 | fn replace_if_let_with_match_target() { |
138 | check_assist_target( | 137 | check_assist_target( |
139 | replace_if_let_with_match, | 138 | replace_if_let_with_match, |
140 | " | 139 | r#" |
141 | impl VariantData { | 140 | impl VariantData { |
142 | pub fn is_struct(&self) -> bool { | 141 | pub fn is_struct(&self) -> bool { |
143 | if <|>let VariantData::Struct(..) = *self { | 142 | if <|>let VariantData::Struct(..) = *self { |
@@ -146,7 +145,7 @@ impl VariantData { | |||
146 | false | 145 | false |
147 | } | 146 | } |
148 | } | 147 | } |
149 | } ", | 148 | } "#, |
150 | "if let VariantData::Struct(..) = *self { | 149 | "if let VariantData::Struct(..) = *self { |
151 | true | 150 | true |
152 | } else { | 151 | } else { |
@@ -176,7 +175,7 @@ enum Option<T> { Some(T), None } | |||
176 | use Option::*; | 175 | use Option::*; |
177 | 176 | ||
178 | fn foo(x: Option<i32>) { | 177 | fn foo(x: Option<i32>) { |
179 | <|>match x { | 178 | match x { |
180 | Some(x) => println!("{}", x), | 179 | Some(x) => println!("{}", x), |
181 | None => println!("none"), | 180 | None => println!("none"), |
182 | } | 181 | } |
@@ -206,7 +205,7 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
206 | use Result::*; | 205 | use Result::*; |
207 | 206 | ||
208 | fn foo(x: Result<i32, ()>) { | 207 | fn foo(x: Result<i32, ()>) { |
209 | <|>match x { | 208 | match x { |
210 | Ok(x) => println!("{}", x), | 209 | Ok(x) => println!("{}", x), |
211 | Err(_) => println!("none"), | 210 | Err(_) => println!("none"), |
212 | } | 211 | } |
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs index 482957dc6..761557ac0 100644 --- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs | |||
@@ -58,12 +58,9 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> | |||
58 | let stmt = make::expr_stmt(if_); | 58 | let stmt = make::expr_stmt(if_); |
59 | 59 | ||
60 | let placeholder = stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap(); | 60 | let placeholder = stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap(); |
61 | let target_offset = | ||
62 | let_stmt.syntax().text_range().start() + placeholder.syntax().text_range().start(); | ||
63 | let stmt = stmt.replace_descendant(placeholder.into(), original_pat); | 61 | let stmt = stmt.replace_descendant(placeholder.into(), original_pat); |
64 | 62 | ||
65 | edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); | 63 | edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); |
66 | edit.set_cursor(target_offset); | ||
67 | }) | 64 | }) |
68 | } | 65 | } |
69 | 66 | ||
@@ -88,7 +85,7 @@ fn main() { | |||
88 | enum E<T> { X(T), Y(T) } | 85 | enum E<T> { X(T), Y(T) } |
89 | 86 | ||
90 | fn main() { | 87 | fn main() { |
91 | if let <|>x = E::X(92) { | 88 | if let x = E::X(92) { |
92 | } | 89 | } |
93 | } | 90 | } |
94 | ", | 91 | ", |
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs index d9f84208d..0197a8cf0 100644 --- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -89,7 +89,7 @@ std::fmt::Debug<|> | |||
89 | " | 89 | " |
90 | use std::fmt::Debug; | 90 | use std::fmt::Debug; |
91 | 91 | ||
92 | Debug<|> | 92 | Debug |
93 | ", | 93 | ", |
94 | ); | 94 | ); |
95 | } | 95 | } |
@@ -106,7 +106,7 @@ fn main() { | |||
106 | " | 106 | " |
107 | use std::fmt::Debug; | 107 | use std::fmt::Debug; |
108 | 108 | ||
109 | Debug<|> | 109 | Debug |
110 | 110 | ||
111 | fn main() { | 111 | fn main() { |
112 | } | 112 | } |
@@ -130,7 +130,7 @@ use std::fmt::Debug; | |||
130 | fn main() { | 130 | fn main() { |
131 | } | 131 | } |
132 | 132 | ||
133 | Debug<|> | 133 | Debug |
134 | ", | 134 | ", |
135 | ); | 135 | ); |
136 | } | 136 | } |
@@ -145,7 +145,7 @@ std::fmt<|>::Debug | |||
145 | " | 145 | " |
146 | use std::fmt; | 146 | use std::fmt; |
147 | 147 | ||
148 | fmt<|>::Debug | 148 | fmt::Debug |
149 | ", | 149 | ", |
150 | ); | 150 | ); |
151 | } | 151 | } |
@@ -164,7 +164,7 @@ impl std::fmt::Debug<|> for Foo { | |||
164 | use stdx; | 164 | use stdx; |
165 | use std::fmt::Debug; | 165 | use std::fmt::Debug; |
166 | 166 | ||
167 | impl Debug<|> for Foo { | 167 | impl Debug for Foo { |
168 | } | 168 | } |
169 | ", | 169 | ", |
170 | ); | 170 | ); |
@@ -181,7 +181,7 @@ impl std::fmt::Debug<|> for Foo { | |||
181 | " | 181 | " |
182 | use std::fmt::Debug; | 182 | use std::fmt::Debug; |
183 | 183 | ||
184 | impl Debug<|> for Foo { | 184 | impl Debug for Foo { |
185 | } | 185 | } |
186 | ", | 186 | ", |
187 | ); | 187 | ); |
@@ -198,7 +198,7 @@ impl Debug<|> for Foo { | |||
198 | " | 198 | " |
199 | use std::fmt::Debug; | 199 | use std::fmt::Debug; |
200 | 200 | ||
201 | impl Debug<|> for Foo { | 201 | impl Debug for Foo { |
202 | } | 202 | } |
203 | ", | 203 | ", |
204 | ); | 204 | ); |
@@ -217,7 +217,7 @@ impl std::io<|> for Foo { | |||
217 | " | 217 | " |
218 | use std::{io, fmt}; | 218 | use std::{io, fmt}; |
219 | 219 | ||
220 | impl io<|> for Foo { | 220 | impl io for Foo { |
221 | } | 221 | } |
222 | ", | 222 | ", |
223 | ); | 223 | ); |
@@ -236,7 +236,7 @@ impl std::fmt::Debug<|> for Foo { | |||
236 | " | 236 | " |
237 | use std::fmt::{self, Debug, }; | 237 | use std::fmt::{self, Debug, }; |
238 | 238 | ||
239 | impl Debug<|> for Foo { | 239 | impl Debug for Foo { |
240 | } | 240 | } |
241 | ", | 241 | ", |
242 | ); | 242 | ); |
@@ -255,7 +255,7 @@ impl std::fmt<|> for Foo { | |||
255 | " | 255 | " |
256 | use std::fmt::{self, Debug}; | 256 | use std::fmt::{self, Debug}; |
257 | 257 | ||
258 | impl fmt<|> for Foo { | 258 | impl fmt for Foo { |
259 | } | 259 | } |
260 | ", | 260 | ", |
261 | ); | 261 | ); |
@@ -274,7 +274,7 @@ impl std::fmt::nested<|> for Foo { | |||
274 | " | 274 | " |
275 | use std::fmt::{Debug, nested::{Display, self}}; | 275 | use std::fmt::{Debug, nested::{Display, self}}; |
276 | 276 | ||
277 | impl nested<|> for Foo { | 277 | impl nested for Foo { |
278 | } | 278 | } |
279 | ", | 279 | ", |
280 | ); | 280 | ); |
@@ -293,7 +293,7 @@ impl std::fmt::nested<|> for Foo { | |||
293 | " | 293 | " |
294 | use std::fmt::{Debug, nested::{self, Display}}; | 294 | use std::fmt::{Debug, nested::{self, Display}}; |
295 | 295 | ||
296 | impl nested<|> for Foo { | 296 | impl nested for Foo { |
297 | } | 297 | } |
298 | ", | 298 | ", |
299 | ); | 299 | ); |
@@ -312,7 +312,7 @@ impl std::fmt::nested::Debug<|> for Foo { | |||
312 | " | 312 | " |
313 | use std::fmt::{Debug, nested::{Display, Debug}}; | 313 | use std::fmt::{Debug, nested::{Display, Debug}}; |
314 | 314 | ||
315 | impl Debug<|> for Foo { | 315 | impl Debug for Foo { |
316 | } | 316 | } |
317 | ", | 317 | ", |
318 | ); | 318 | ); |
@@ -331,7 +331,7 @@ impl std::fmt::nested::Display<|> for Foo { | |||
331 | " | 331 | " |
332 | use std::fmt::{nested::Display, Debug}; | 332 | use std::fmt::{nested::Display, Debug}; |
333 | 333 | ||
334 | impl Display<|> for Foo { | 334 | impl Display for Foo { |
335 | } | 335 | } |
336 | ", | 336 | ", |
337 | ); | 337 | ); |
@@ -350,7 +350,7 @@ impl std::fmt::Display<|> for Foo { | |||
350 | " | 350 | " |
351 | use std::fmt::{Display, nested::Debug}; | 351 | use std::fmt::{Display, nested::Debug}; |
352 | 352 | ||
353 | impl Display<|> for Foo { | 353 | impl Display for Foo { |
354 | } | 354 | } |
355 | ", | 355 | ", |
356 | ); | 356 | ); |
@@ -374,7 +374,7 @@ use crate::{ | |||
374 | AssocItem, | 374 | AssocItem, |
375 | }; | 375 | }; |
376 | 376 | ||
377 | fn foo() { lower<|>::trait_env() } | 377 | fn foo() { lower::trait_env() } |
378 | ", | 378 | ", |
379 | ); | 379 | ); |
380 | } | 380 | } |
@@ -392,7 +392,7 @@ impl foo::Debug<|> for Foo { | |||
392 | " | 392 | " |
393 | use std::fmt as foo; | 393 | use std::fmt as foo; |
394 | 394 | ||
395 | impl Debug<|> for Foo { | 395 | impl Debug for Foo { |
396 | } | 396 | } |
397 | ", | 397 | ", |
398 | ); | 398 | ); |
@@ -435,7 +435,7 @@ mod foo { | |||
435 | mod bar { | 435 | mod bar { |
436 | use std::fmt::Debug; | 436 | use std::fmt::Debug; |
437 | 437 | ||
438 | Debug<|> | 438 | Debug |
439 | } | 439 | } |
440 | } | 440 | } |
441 | ", | 441 | ", |
@@ -458,7 +458,7 @@ fn main() { | |||
458 | use std::fmt::Debug; | 458 | use std::fmt::Debug; |
459 | 459 | ||
460 | fn main() { | 460 | fn main() { |
461 | Debug<|> | 461 | Debug |
462 | } | 462 | } |
463 | ", | 463 | ", |
464 | ); | 464 | ); |
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs index b379b55a8..cff7dfb81 100644 --- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -9,7 +9,10 @@ use ra_syntax::{ | |||
9 | AstNode, | 9 | AstNode, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; | 12 | use crate::{ |
13 | utils::{render_snippet, Cursor, TryEnum}, | ||
14 | AssistContext, AssistId, Assists, | ||
15 | }; | ||
13 | 16 | ||
14 | // Assist: replace_unwrap_with_match | 17 | // Assist: replace_unwrap_with_match |
15 | // | 18 | // |
@@ -29,7 +32,7 @@ use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; | |||
29 | // let x: Result<i32, i32> = Result::Ok(92); | 32 | // let x: Result<i32, i32> = Result::Ok(92); |
30 | // let y = match x { | 33 | // let y = match x { |
31 | // Ok(a) => a, | 34 | // Ok(a) => a, |
32 | // _ => unreachable!(), | 35 | // $0_ => unreachable!(), |
33 | // }; | 36 | // }; |
34 | // } | 37 | // } |
35 | // ``` | 38 | // ``` |
@@ -43,7 +46,7 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
43 | let ty = ctx.sema.type_of_expr(&caller)?; | 46 | let ty = ctx.sema.type_of_expr(&caller)?; |
44 | let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case(); | 47 | let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case(); |
45 | let target = method_call.syntax().text_range(); | 48 | let target = method_call.syntax().text_range(); |
46 | acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |edit| { | 49 | acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |builder| { |
47 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); | 50 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); |
48 | let it = make::bind_pat(make::name("a")).into(); | 51 | let it = make::bind_pat(make::name("a")).into(); |
49 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | 52 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); |
@@ -58,16 +61,30 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
58 | let match_expr = make::expr_match(caller.clone(), match_arm_list) | 61 | let match_expr = make::expr_match(caller.clone(), match_arm_list) |
59 | .indent(IndentLevel::from_node(method_call.syntax())); | 62 | .indent(IndentLevel::from_node(method_call.syntax())); |
60 | 63 | ||
61 | edit.set_cursor(caller.syntax().text_range().start()); | 64 | let range = method_call.syntax().text_range(); |
62 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); | 65 | match ctx.config.snippet_cap { |
66 | Some(cap) => { | ||
67 | let err_arm = match_expr | ||
68 | .syntax() | ||
69 | .descendants() | ||
70 | .filter_map(ast::MatchArm::cast) | ||
71 | .last() | ||
72 | .unwrap(); | ||
73 | let snippet = | ||
74 | render_snippet(cap, match_expr.syntax(), Cursor::Before(err_arm.syntax())); | ||
75 | builder.replace_snippet(cap, range, snippet) | ||
76 | } | ||
77 | None => builder.replace(range, match_expr.to_string()), | ||
78 | } | ||
63 | }) | 79 | }) |
64 | } | 80 | } |
65 | 81 | ||
66 | #[cfg(test)] | 82 | #[cfg(test)] |
67 | mod tests { | 83 | mod tests { |
68 | use super::*; | ||
69 | use crate::tests::{check_assist, check_assist_target}; | 84 | use crate::tests::{check_assist, check_assist_target}; |
70 | 85 | ||
86 | use super::*; | ||
87 | |||
71 | #[test] | 88 | #[test] |
72 | fn test_replace_result_unwrap_with_match() { | 89 | fn test_replace_result_unwrap_with_match() { |
73 | check_assist( | 90 | check_assist( |
@@ -85,9 +102,9 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
85 | fn i<T>(a: T) -> T { a } | 102 | fn i<T>(a: T) -> T { a } |
86 | fn main() { | 103 | fn main() { |
87 | let x: Result<i32, i32> = Result::Ok(92); | 104 | let x: Result<i32, i32> = Result::Ok(92); |
88 | let y = <|>match i(x) { | 105 | let y = match i(x) { |
89 | Ok(a) => a, | 106 | Ok(a) => a, |
90 | _ => unreachable!(), | 107 | $0_ => unreachable!(), |
91 | }; | 108 | }; |
92 | } | 109 | } |
93 | ", | 110 | ", |
@@ -111,9 +128,9 @@ enum Option<T> { Some(T), None } | |||
111 | fn i<T>(a: T) -> T { a } | 128 | fn i<T>(a: T) -> T { a } |
112 | fn main() { | 129 | fn main() { |
113 | let x = Option::Some(92); | 130 | let x = Option::Some(92); |
114 | let y = <|>match i(x) { | 131 | let y = match i(x) { |
115 | Some(a) => a, | 132 | Some(a) => a, |
116 | _ => unreachable!(), | 133 | $0_ => unreachable!(), |
117 | }; | 134 | }; |
118 | } | 135 | } |
119 | ", | 136 | ", |
@@ -137,9 +154,9 @@ enum Result<T, E> { Ok(T), Err(E) } | |||
137 | fn i<T>(a: T) -> T { a } | 154 | fn i<T>(a: T) -> T { a } |
138 | fn main() { | 155 | fn main() { |
139 | let x: Result<i32, i32> = Result::Ok(92); | 156 | let x: Result<i32, i32> = Result::Ok(92); |
140 | let y = <|>match i(x) { | 157 | let y = match i(x) { |
141 | Ok(a) => a, | 158 | Ok(a) => a, |
142 | _ => unreachable!(), | 159 | $0_ => unreachable!(), |
143 | }.count_zeroes(); | 160 | }.count_zeroes(); |
144 | } | 161 | } |
145 | ", | 162 | ", |
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs index b2757e50c..c7a874480 100644 --- a/crates/ra_assists/src/handlers/split_import.rs +++ b/crates/ra_assists/src/handlers/split_import.rs | |||
@@ -26,12 +26,10 @@ pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
26 | if new_tree == use_tree { | 26 | if new_tree == use_tree { |
27 | return None; | 27 | return None; |
28 | } | 28 | } |
29 | let cursor = ctx.offset(); | ||
30 | 29 | ||
31 | let target = colon_colon.text_range(); | 30 | let target = colon_colon.text_range(); |
32 | acc.add(AssistId("split_import"), "Split import", target, |edit| { | 31 | acc.add(AssistId("split_import"), "Split import", target, |edit| { |
33 | edit.replace_ast(use_tree, new_tree); | 32 | edit.replace_ast(use_tree, new_tree); |
34 | edit.set_cursor(cursor); | ||
35 | }) | 33 | }) |
36 | } | 34 | } |
37 | 35 | ||
@@ -46,7 +44,7 @@ mod tests { | |||
46 | check_assist( | 44 | check_assist( |
47 | split_import, | 45 | split_import, |
48 | "use crate::<|>db::RootDatabase;", | 46 | "use crate::<|>db::RootDatabase;", |
49 | "use crate::<|>{db::RootDatabase};", | 47 | "use crate::{db::RootDatabase};", |
50 | ) | 48 | ) |
51 | } | 49 | } |
52 | 50 | ||
@@ -55,7 +53,7 @@ mod tests { | |||
55 | check_assist( | 53 | check_assist( |
56 | split_import, | 54 | split_import, |
57 | "use crate:<|>:db::{RootDatabase, FileSymbol}", | 55 | "use crate:<|>:db::{RootDatabase, FileSymbol}", |
58 | "use crate:<|>:{db::{RootDatabase, FileSymbol}}", | 56 | "use crate::{db::{RootDatabase, FileSymbol}}", |
59 | ) | 57 | ) |
60 | } | 58 | } |
61 | 59 | ||
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs index b76182d79..8440c7d0f 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -62,7 +62,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
62 | let range_to_del_else_if = TextRange::new(ancestor_then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); | 62 | let range_to_del_else_if = TextRange::new(ancestor_then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); |
63 | let range_to_del_rest = TextRange::new(then_branch.syntax().text_range().end(), if_expr.syntax().text_range().end()); | 63 | let range_to_del_rest = TextRange::new(then_branch.syntax().text_range().end(), if_expr.syntax().text_range().end()); |
64 | 64 | ||
65 | edit.set_cursor(ancestor_then_branch.syntax().text_range().end()); | ||
66 | edit.delete(range_to_del_rest); | 65 | edit.delete(range_to_del_rest); |
67 | edit.delete(range_to_del_else_if); | 66 | edit.delete(range_to_del_else_if); |
68 | edit.replace(target, update_expr_string(then_branch.to_string(), &[' ', '{'])); | 67 | edit.replace(target, update_expr_string(then_branch.to_string(), &[' ', '{'])); |
@@ -79,7 +78,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
79 | return acc.add(assist_id, assist_label, target, |edit| { | 78 | return acc.add(assist_id, assist_label, target, |edit| { |
80 | let range_to_del = TextRange::new(then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); | 79 | let range_to_del = TextRange::new(then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); |
81 | 80 | ||
82 | edit.set_cursor(then_branch.syntax().text_range().end()); | ||
83 | edit.delete(range_to_del); | 81 | edit.delete(range_to_del); |
84 | edit.replace(target, update_expr_string(else_block.to_string(), &[' ', '{'])); | 82 | edit.replace(target, update_expr_string(else_block.to_string(), &[' ', '{'])); |
85 | }); | 83 | }); |
@@ -97,8 +95,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
97 | 95 | ||
98 | let target = expr_to_unwrap.syntax().text_range(); | 96 | let target = expr_to_unwrap.syntax().text_range(); |
99 | acc.add(assist_id, assist_label, target, |edit| { | 97 | acc.add(assist_id, assist_label, target, |edit| { |
100 | edit.set_cursor(expr.syntax().text_range().start()); | ||
101 | |||
102 | edit.replace( | 98 | edit.replace( |
103 | expr.syntax().text_range(), | 99 | expr.syntax().text_range(), |
104 | update_expr_string(expr_to_unwrap.to_string(), &[' ', '{', '\n']), | 100 | update_expr_string(expr_to_unwrap.to_string(), &[' ', '{', '\n']), |
@@ -154,7 +150,7 @@ mod tests { | |||
154 | r#" | 150 | r#" |
155 | fn main() { | 151 | fn main() { |
156 | bar(); | 152 | bar(); |
157 | <|>foo(); | 153 | foo(); |
158 | 154 | ||
159 | //comment | 155 | //comment |
160 | bar(); | 156 | bar(); |
@@ -188,7 +184,7 @@ mod tests { | |||
188 | 184 | ||
189 | //comment | 185 | //comment |
190 | bar(); | 186 | bar(); |
191 | }<|> | 187 | } |
192 | println!("bar"); | 188 | println!("bar"); |
193 | } | 189 | } |
194 | "#, | 190 | "#, |
@@ -222,7 +218,7 @@ mod tests { | |||
222 | 218 | ||
223 | //comment | 219 | //comment |
224 | //bar(); | 220 | //bar(); |
225 | }<|> | 221 | } |
226 | println!("bar"); | 222 | println!("bar"); |
227 | } | 223 | } |
228 | "#, | 224 | "#, |
@@ -258,7 +254,7 @@ mod tests { | |||
258 | //bar(); | 254 | //bar(); |
259 | } else if false { | 255 | } else if false { |
260 | println!("bar"); | 256 | println!("bar"); |
261 | }<|> | 257 | } |
262 | println!("foo"); | 258 | println!("foo"); |
263 | } | 259 | } |
264 | "#, | 260 | "#, |
@@ -298,7 +294,7 @@ mod tests { | |||
298 | println!("bar"); | 294 | println!("bar"); |
299 | } else if true { | 295 | } else if true { |
300 | println!("foo"); | 296 | println!("foo"); |
301 | }<|> | 297 | } |
302 | println!("else"); | 298 | println!("else"); |
303 | } | 299 | } |
304 | "#, | 300 | "#, |
@@ -336,7 +332,7 @@ mod tests { | |||
336 | //bar(); | 332 | //bar(); |
337 | } else if false { | 333 | } else if false { |
338 | println!("bar"); | 334 | println!("bar"); |
339 | }<|> | 335 | } |
340 | println!("foo"); | 336 | println!("foo"); |
341 | } | 337 | } |
342 | "#, | 338 | "#, |
@@ -383,7 +379,7 @@ mod tests { | |||
383 | "#, | 379 | "#, |
384 | r#" | 380 | r#" |
385 | fn main() { | 381 | fn main() { |
386 | <|>if true { | 382 | if true { |
387 | foo(); | 383 | foo(); |
388 | 384 | ||
389 | //comment | 385 | //comment |
@@ -417,7 +413,7 @@ mod tests { | |||
417 | r#" | 413 | r#" |
418 | fn main() { | 414 | fn main() { |
419 | for i in 0..5 { | 415 | for i in 0..5 { |
420 | <|>foo(); | 416 | foo(); |
421 | 417 | ||
422 | //comment | 418 | //comment |
423 | bar(); | 419 | bar(); |
@@ -447,7 +443,7 @@ mod tests { | |||
447 | "#, | 443 | "#, |
448 | r#" | 444 | r#" |
449 | fn main() { | 445 | fn main() { |
450 | <|>if true { | 446 | if true { |
451 | foo(); | 447 | foo(); |
452 | 448 | ||
453 | //comment | 449 | //comment |
@@ -480,7 +476,7 @@ mod tests { | |||
480 | "#, | 476 | "#, |
481 | r#" | 477 | r#" |
482 | fn main() { | 478 | fn main() { |
483 | <|>if true { | 479 | if true { |
484 | foo(); | 480 | foo(); |
485 | 481 | ||
486 | //comment | 482 | //comment |
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs index 9ba3da786..62dd3547f 100644 --- a/crates/ra_assists/src/tests.rs +++ b/crates/ra_assists/src/tests.rs | |||
@@ -7,8 +7,7 @@ use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; | |||
7 | use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; | 7 | use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; |
8 | use ra_syntax::TextRange; | 8 | use ra_syntax::TextRange; |
9 | use test_utils::{ | 9 | use test_utils::{ |
10 | add_cursor, assert_eq_text, extract_offset, extract_range, extract_range_or_offset, | 10 | assert_eq_text, extract_offset, extract_range, extract_range_or_offset, RangeOrOffset, |
11 | RangeOrOffset, | ||
12 | }; | 11 | }; |
13 | 12 | ||
14 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists}; | 13 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists}; |
@@ -103,21 +102,6 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult) { | |||
103 | 102 | ||
104 | let mut actual = db.file_text(change.file_id).as_ref().to_owned(); | 103 | let mut actual = db.file_text(change.file_id).as_ref().to_owned(); |
105 | change.edit.apply(&mut actual); | 104 | change.edit.apply(&mut actual); |
106 | |||
107 | if !source_change.is_snippet { | ||
108 | match source_change.cursor_position { | ||
109 | None => { | ||
110 | if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset { | ||
111 | let off = change | ||
112 | .edit | ||
113 | .apply_to_offset(before_cursor_pos) | ||
114 | .expect("cursor position is affected by the edit"); | ||
115 | actual = add_cursor(&actual, off) | ||
116 | } | ||
117 | } | ||
118 | Some(off) => actual = add_cursor(&actual, off.offset), | ||
119 | }; | ||
120 | } | ||
121 | assert_eq_text!(after, &actual); | 105 | assert_eq_text!(after, &actual); |
122 | } | 106 | } |
123 | (Some(assist), ExpectedResult::Target(target)) => { | 107 | (Some(assist), ExpectedResult::Target(target)) => { |
diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs index 3e6654c17..250e56a69 100644 --- a/crates/ra_assists/src/tests/generated.rs +++ b/crates/ra_assists/src/tests/generated.rs | |||
@@ -443,7 +443,7 @@ fn main() { | |||
443 | "#####, | 443 | "#####, |
444 | r#####" | 444 | r#####" |
445 | fn main() { | 445 | fn main() { |
446 | let var_name = (1 + 2); | 446 | let $0var_name = (1 + 2); |
447 | var_name * 4; | 447 | var_name * 4; |
448 | } | 448 | } |
449 | "#####, | 449 | "#####, |
@@ -764,7 +764,7 @@ fn main() { | |||
764 | let x: Result<i32, i32> = Result::Ok(92); | 764 | let x: Result<i32, i32> = Result::Ok(92); |
765 | let y = match x { | 765 | let y = match x { |
766 | Ok(a) => a, | 766 | Ok(a) => a, |
767 | _ => unreachable!(), | 767 | $0_ => unreachable!(), |
768 | }; | 768 | }; |
769 | } | 769 | } |
770 | "#####, | 770 | "#####, |
diff --git a/crates/ra_cfg/src/cfg_expr.rs b/crates/ra_cfg/src/cfg_expr.rs index 39d71851c..85b100c6a 100644 --- a/crates/ra_cfg/src/cfg_expr.rs +++ b/crates/ra_cfg/src/cfg_expr.rs | |||
@@ -88,13 +88,17 @@ fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> { | |||
88 | mod tests { | 88 | mod tests { |
89 | use super::*; | 89 | use super::*; |
90 | 90 | ||
91 | use mbe::ast_to_token_tree; | 91 | use mbe::{ast_to_token_tree, TokenMap}; |
92 | use ra_syntax::ast::{self, AstNode}; | 92 | use ra_syntax::ast::{self, AstNode}; |
93 | 93 | ||
94 | fn assert_parse_result(input: &str, expected: CfgExpr) { | 94 | fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { |
95 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | 95 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); |
96 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | 96 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); |
97 | let (tt, _) = ast_to_token_tree(&tt).unwrap(); | 97 | ast_to_token_tree(&tt).unwrap() |
98 | } | ||
99 | |||
100 | fn assert_parse_result(input: &str, expected: CfgExpr) { | ||
101 | let (tt, _) = get_token_tree_generated(input); | ||
98 | assert_eq!(parse_cfg(&tt), expected); | 102 | assert_eq!(parse_cfg(&tt), expected); |
99 | } | 103 | } |
100 | 104 | ||
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index f8f767091..482a2f3e6 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs | |||
@@ -63,7 +63,7 @@ use std::sync::Arc; | |||
63 | 63 | ||
64 | use ra_cfg::CfgOptions; | 64 | use ra_cfg::CfgOptions; |
65 | use rustc_hash::FxHashMap; | 65 | use rustc_hash::FxHashMap; |
66 | use test_utils::{extract_offset, parse_fixture, parse_single_fixture, CURSOR_MARKER}; | 66 | use test_utils::{extract_offset, parse_fixture, parse_single_fixture, FixtureMeta, CURSOR_MARKER}; |
67 | 67 | ||
68 | use crate::{ | 68 | use crate::{ |
69 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, | 69 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, |
@@ -113,7 +113,7 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId | |||
113 | let fixture = parse_single_fixture(ra_fixture); | 113 | let fixture = parse_single_fixture(ra_fixture); |
114 | 114 | ||
115 | let crate_graph = if let Some(entry) = fixture { | 115 | let crate_graph = if let Some(entry) = fixture { |
116 | let meta = match parse_meta(&entry.meta) { | 116 | let meta = match ParsedMeta::from(&entry.meta) { |
117 | ParsedMeta::File(it) => it, | 117 | ParsedMeta::File(it) => it, |
118 | _ => panic!("with_single_file only support file meta"), | 118 | _ => panic!("with_single_file only support file meta"), |
119 | }; | 119 | }; |
@@ -170,7 +170,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
170 | let mut file_position = None; | 170 | let mut file_position = None; |
171 | 171 | ||
172 | for entry in fixture.iter() { | 172 | for entry in fixture.iter() { |
173 | let meta = match parse_meta(&entry.meta) { | 173 | let meta = match ParsedMeta::from(&entry.meta) { |
174 | ParsedMeta::Root { path } => { | 174 | ParsedMeta::Root { path } => { |
175 | let source_root = std::mem::replace(&mut source_root, SourceRoot::new_local()); | 175 | let source_root = std::mem::replace(&mut source_root, SourceRoot::new_local()); |
176 | db.set_source_root(source_root_id, Arc::new(source_root)); | 176 | db.set_source_root(source_root_id, Arc::new(source_root)); |
@@ -258,53 +258,25 @@ struct FileMeta { | |||
258 | env: Env, | 258 | env: Env, |
259 | } | 259 | } |
260 | 260 | ||
261 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo) | 261 | impl From<&FixtureMeta> for ParsedMeta { |
262 | fn parse_meta(meta: &str) -> ParsedMeta { | 262 | fn from(meta: &FixtureMeta) -> Self { |
263 | let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); | 263 | match meta { |
264 | 264 | FixtureMeta::Root { path } => { | |
265 | if components[0] == "root" { | 265 | // `Self::Root` causes a false warning: 'variant is never constructed: `Root` ' |
266 | let path: RelativePathBuf = components[1].into(); | 266 | // see https://github.com/rust-lang/rust/issues/69018 |
267 | assert!(path.starts_with("/") && path.ends_with("/")); | 267 | ParsedMeta::Root { path: path.to_owned() } |
268 | return ParsedMeta::Root { path }; | ||
269 | } | ||
270 | |||
271 | let path: RelativePathBuf = components[0].into(); | ||
272 | assert!(path.starts_with("/")); | ||
273 | |||
274 | let mut krate = None; | ||
275 | let mut deps = Vec::new(); | ||
276 | let mut edition = Edition::Edition2018; | ||
277 | let mut cfg = CfgOptions::default(); | ||
278 | let mut env = Env::default(); | ||
279 | for component in components[1..].iter() { | ||
280 | let (key, value) = split1(component, ':').unwrap(); | ||
281 | match key { | ||
282 | "crate" => krate = Some(value.to_string()), | ||
283 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), | ||
284 | "edition" => edition = Edition::from_str(&value).unwrap(), | ||
285 | "cfg" => { | ||
286 | for key in value.split(',') { | ||
287 | match split1(key, '=') { | ||
288 | None => cfg.insert_atom(key.into()), | ||
289 | Some((k, v)) => cfg.insert_key_value(k.into(), v.into()), | ||
290 | } | ||
291 | } | ||
292 | } | ||
293 | "env" => { | ||
294 | for key in value.split(',') { | ||
295 | if let Some((k, v)) = split1(key, '=') { | ||
296 | env.set(k, v.into()); | ||
297 | } | ||
298 | } | ||
299 | } | 268 | } |
300 | _ => panic!("bad component: {:?}", component), | 269 | FixtureMeta::File(f) => Self::File(FileMeta { |
270 | path: f.path.to_owned(), | ||
271 | krate: f.crate_name.to_owned(), | ||
272 | deps: f.deps.to_owned(), | ||
273 | cfg: f.cfg.to_owned(), | ||
274 | edition: f | ||
275 | .edition | ||
276 | .as_ref() | ||
277 | .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), | ||
278 | env: Env::from(f.env.iter()), | ||
279 | }), | ||
301 | } | 280 | } |
302 | } | 281 | } |
303 | |||
304 | ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg, env }) | ||
305 | } | ||
306 | |||
307 | fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
308 | let idx = haystack.find(delim)?; | ||
309 | Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) | ||
310 | } | 282 | } |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index ab14e2d5e..4d2d3b48a 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -311,6 +311,21 @@ impl fmt::Display for Edition { | |||
311 | } | 311 | } |
312 | } | 312 | } |
313 | 313 | ||
314 | impl<'a, T> From<T> for Env | ||
315 | where | ||
316 | T: Iterator<Item = (&'a String, &'a String)>, | ||
317 | { | ||
318 | fn from(iter: T) -> Self { | ||
319 | let mut result = Self::default(); | ||
320 | |||
321 | for (k, v) in iter { | ||
322 | result.entries.insert(k.to_owned(), v.to_owned()); | ||
323 | } | ||
324 | |||
325 | result | ||
326 | } | ||
327 | } | ||
328 | |||
314 | impl Env { | 329 | impl Env { |
315 | pub fn set(&mut self, env: &str, value: String) { | 330 | pub fn set(&mut self, env: &str, value: String) { |
316 | self.entries.insert(env.to_owned(), value); | 331 | self.entries.insert(env.to_owned(), value); |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index c5df4ac24..3364a822f 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -62,6 +62,7 @@ pub use crate::{ | |||
62 | 62 | ||
63 | pub use hir_def::{ | 63 | pub use hir_def::{ |
64 | adt::StructKind, | 64 | adt::StructKind, |
65 | attr::Attrs, | ||
65 | body::scope::ExprScopes, | 66 | body::scope::ExprScopes, |
66 | builtin_type::BuiltinType, | 67 | builtin_type::BuiltinType, |
67 | docs::Documentation, | 68 | docs::Documentation, |
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 576cd0c65..8b6c0bede 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -81,7 +81,7 @@ impl Attrs { | |||
81 | } | 81 | } |
82 | } | 82 | } |
83 | 83 | ||
84 | fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs { | 84 | pub fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs { |
85 | let hygiene = Hygiene::new(db.upcast(), owner.file_id); | 85 | let hygiene = Hygiene::new(db.upcast(), owner.file_id); |
86 | Attrs::new(owner.value, &hygiene) | 86 | Attrs::new(owner.value, &hygiene) |
87 | } | 87 | } |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index f5a7305dc..273036cee 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -29,7 +29,7 @@ use crate::{ | |||
29 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, | 29 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, |
30 | }; | 30 | }; |
31 | 31 | ||
32 | /// A subset of Exander that only deals with cfg attributes. We only need it to | 32 | /// A subset of Expander that only deals with cfg attributes. We only need it to |
33 | /// avoid cyclic queries in crate def map during enum processing. | 33 | /// avoid cyclic queries in crate def map during enum processing. |
34 | pub(crate) struct CfgExpander { | 34 | pub(crate) struct CfgExpander { |
35 | cfg_options: CfgOptions, | 35 | cfg_options: CfgOptions, |
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 2f71511ba..945a0025e 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -17,6 +17,7 @@ use crate::{ | |||
17 | item_scope::ItemInNs, | 17 | item_scope::ItemInNs, |
18 | lang_item::{LangItemTarget, LangItems}, | 18 | lang_item::{LangItemTarget, LangItems}, |
19 | nameres::{raw::RawItems, CrateDefMap}, | 19 | nameres::{raw::RawItems, CrateDefMap}, |
20 | path::ModPath, | ||
20 | visibility::Visibility, | 21 | visibility::Visibility, |
21 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, | 22 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, |
22 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, | 23 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, |
@@ -118,6 +119,9 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
118 | item: ItemInNs, | 119 | item: ItemInNs, |
119 | krate: CrateId, | 120 | krate: CrateId, |
120 | ) -> Arc<[(ModuleId, Name, Visibility)]>; | 121 | ) -> Arc<[(ModuleId, Name, Visibility)]>; |
122 | |||
123 | #[salsa::invoke(find_path::find_path_inner_query)] | ||
124 | fn find_path_inner(&self, item: ItemInNs, from: ModuleId, max_len: usize) -> Option<ModPath>; | ||
121 | } | 125 | } |
122 | 126 | ||
123 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { | 127 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { |
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index 68d3cde08..4db798473 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs | |||
@@ -20,7 +20,7 @@ use crate::{ | |||
20 | /// *from where* you're referring to the item, hence the `from` parameter. | 20 | /// *from where* you're referring to the item, hence the `from` parameter. |
21 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | 21 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { |
22 | let _p = profile("find_path"); | 22 | let _p = profile("find_path"); |
23 | find_path_inner(db, item, from, MAX_PATH_LEN) | 23 | db.find_path_inner(item, from, MAX_PATH_LEN) |
24 | } | 24 | } |
25 | 25 | ||
26 | const MAX_PATH_LEN: usize = 15; | 26 | const MAX_PATH_LEN: usize = 15; |
@@ -49,7 +49,7 @@ impl ModPath { | |||
49 | } | 49 | } |
50 | } | 50 | } |
51 | 51 | ||
52 | fn find_path_inner( | 52 | pub(crate) fn find_path_inner_query( |
53 | db: &dyn DefDatabase, | 53 | db: &dyn DefDatabase, |
54 | item: ItemInNs, | 54 | item: ItemInNs, |
55 | from: ModuleId, | 55 | from: ModuleId, |
@@ -140,8 +140,7 @@ fn find_path_inner( | |||
140 | let mut best_path = None; | 140 | let mut best_path = None; |
141 | let mut best_path_len = max_len; | 141 | let mut best_path_len = max_len; |
142 | for (module_id, name) in importable_locations { | 142 | for (module_id, name) in importable_locations { |
143 | let mut path = match find_path_inner( | 143 | let mut path = match db.find_path_inner( |
144 | db, | ||
145 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), | 144 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), |
146 | from, | 145 | from, |
147 | best_path_len - 1, | 146 | best_path_len - 1, |
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs index d96ac8c0a..3516784b8 100644 --- a/crates/ra_hir_def/src/lang_item.rs +++ b/crates/ra_hir_def/src/lang_item.rs | |||
@@ -73,8 +73,8 @@ pub struct LangItems { | |||
73 | } | 73 | } |
74 | 74 | ||
75 | impl LangItems { | 75 | impl LangItems { |
76 | pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> { | 76 | pub fn target(&self, item: &str) -> Option<LangItemTarget> { |
77 | self.items.get(item) | 77 | self.items.get(item).copied() |
78 | } | 78 | } |
79 | 79 | ||
80 | /// Salsa query. This will look for lang items in a specific crate. | 80 | /// Salsa query. This will look for lang items in a specific crate. |
@@ -163,9 +163,13 @@ impl LangItems { | |||
163 | ) where | 163 | ) where |
164 | T: Into<AttrDefId> + Copy, | 164 | T: Into<AttrDefId> + Copy, |
165 | { | 165 | { |
166 | let attrs = db.attrs(item.into()); | 166 | if let Some(lang_item_name) = lang_attr(db, item) { |
167 | if let Some(lang_item_name) = attrs.by_key("lang").string_value() { | 167 | self.items.entry(lang_item_name).or_insert_with(|| constructor(item)); |
168 | self.items.entry(lang_item_name.clone()).or_insert_with(|| constructor(item)); | ||
169 | } | 168 | } |
170 | } | 169 | } |
171 | } | 170 | } |
171 | |||
172 | pub fn lang_attr(db: &dyn DefDatabase, item: impl Into<AttrDefId> + Copy) -> Option<SmolStr> { | ||
173 | let attrs = db.attrs(item.into()); | ||
174 | attrs.by_key("lang").string_value().cloned() | ||
175 | } | ||
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index 5fc0ec5e3..b2de7fa34 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml | |||
@@ -27,9 +27,9 @@ test_utils = { path = "../test_utils" } | |||
27 | 27 | ||
28 | scoped-tls = "1" | 28 | scoped-tls = "1" |
29 | 29 | ||
30 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" } | 30 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } |
31 | chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" } | 31 | chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } |
32 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "3e9c2503ae9c5277c2acb74624dc267876dd89b3" } | 32 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } |
33 | 33 | ||
34 | [dev-dependencies] | 34 | [dev-dependencies] |
35 | insta = "0.16.0" | 35 | insta = "0.16.0" |
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index fdb49560b..0a8bb24ac 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs | |||
@@ -76,6 +76,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
76 | #[salsa::interned] | 76 | #[salsa::interned] |
77 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; | 77 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; |
78 | #[salsa::interned] | 78 | #[salsa::interned] |
79 | fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId; | ||
80 | #[salsa::interned] | ||
79 | fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; | 81 | fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; |
80 | #[salsa::interned] | 82 | #[salsa::interned] |
81 | fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; | 83 | fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; |
@@ -89,11 +91,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
89 | fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>; | 91 | fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>; |
90 | 92 | ||
91 | #[salsa::invoke(chalk::struct_datum_query)] | 93 | #[salsa::invoke(chalk::struct_datum_query)] |
92 | fn struct_datum(&self, krate: CrateId, struct_id: chalk::StructId) -> Arc<chalk::StructDatum>; | 94 | fn struct_datum(&self, krate: CrateId, struct_id: chalk::AdtId) -> Arc<chalk::StructDatum>; |
93 | 95 | ||
94 | #[salsa::invoke(crate::traits::chalk::impl_datum_query)] | 96 | #[salsa::invoke(crate::traits::chalk::impl_datum_query)] |
95 | fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>; | 97 | fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>; |
96 | 98 | ||
99 | #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)] | ||
100 | fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>; | ||
101 | |||
97 | #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] | 102 | #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] |
98 | fn associated_ty_value( | 103 | fn associated_ty_value( |
99 | &self, | 104 | &self, |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index c87ee06ce..93cb45a64 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -155,10 +155,16 @@ pub enum TypeCtor { | |||
155 | /// This exists just for Chalk, because Chalk just has a single `StructId` where | 155 | /// This exists just for Chalk, because Chalk just has a single `StructId` where |
156 | /// we have different kinds of ADTs, primitive types and special type | 156 | /// we have different kinds of ADTs, primitive types and special type |
157 | /// constructors like tuples and function pointers. | 157 | /// constructors like tuples and function pointers. |
158 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 158 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] |
159 | pub struct TypeCtorId(salsa::InternId); | 159 | pub struct TypeCtorId(salsa::InternId); |
160 | impl_intern_key!(TypeCtorId); | 160 | impl_intern_key!(TypeCtorId); |
161 | 161 | ||
162 | /// This exists just for Chalk, because Chalk just has a single `FnDefId` where | ||
163 | /// we have different IDs for struct and enum variant constructors. | ||
164 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] | ||
165 | pub struct CallableDefId(salsa::InternId); | ||
166 | impl_intern_key!(CallableDefId); | ||
167 | |||
162 | impl TypeCtor { | 168 | impl TypeCtor { |
163 | pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { | 169 | pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { |
164 | match self { | 170 | match self { |
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 34f4b9039..0419bc751 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -2602,3 +2602,155 @@ fn test(x: &dyn Foo) { | |||
2602 | "### | 2602 | "### |
2603 | ); | 2603 | ); |
2604 | } | 2604 | } |
2605 | |||
2606 | #[test] | ||
2607 | fn builtin_copy() { | ||
2608 | assert_snapshot!( | ||
2609 | infer_with_mismatches(r#" | ||
2610 | #[lang = "copy"] | ||
2611 | trait Copy {} | ||
2612 | |||
2613 | struct IsCopy; | ||
2614 | impl Copy for IsCopy {} | ||
2615 | struct NotCopy; | ||
2616 | |||
2617 | trait Test { fn test(&self) -> bool; } | ||
2618 | impl<T: Copy> Test for T {} | ||
2619 | |||
2620 | fn test() { | ||
2621 | IsCopy.test(); | ||
2622 | NotCopy.test(); | ||
2623 | (IsCopy, IsCopy).test(); | ||
2624 | (IsCopy, NotCopy).test(); | ||
2625 | } | ||
2626 | "#, true), | ||
2627 | @r###" | ||
2628 | 111..115 'self': &Self | ||
2629 | 167..268 '{ ...t(); }': () | ||
2630 | 173..179 'IsCopy': IsCopy | ||
2631 | 173..186 'IsCopy.test()': bool | ||
2632 | 192..199 'NotCopy': NotCopy | ||
2633 | 192..206 'NotCopy.test()': {unknown} | ||
2634 | 212..228 '(IsCop...sCopy)': (IsCopy, IsCopy) | ||
2635 | 212..235 '(IsCop...test()': bool | ||
2636 | 213..219 'IsCopy': IsCopy | ||
2637 | 221..227 'IsCopy': IsCopy | ||
2638 | 241..258 '(IsCop...tCopy)': (IsCopy, NotCopy) | ||
2639 | 241..265 '(IsCop...test()': {unknown} | ||
2640 | 242..248 'IsCopy': IsCopy | ||
2641 | 250..257 'NotCopy': NotCopy | ||
2642 | "### | ||
2643 | ); | ||
2644 | } | ||
2645 | |||
2646 | #[test] | ||
2647 | fn builtin_fn_def_copy() { | ||
2648 | assert_snapshot!( | ||
2649 | infer_with_mismatches(r#" | ||
2650 | #[lang = "copy"] | ||
2651 | trait Copy {} | ||
2652 | |||
2653 | fn foo() {} | ||
2654 | fn bar<T: Copy>(T) -> T {} | ||
2655 | struct Struct(usize); | ||
2656 | enum Enum { Variant(usize) } | ||
2657 | |||
2658 | trait Test { fn test(&self) -> bool; } | ||
2659 | impl<T: Copy> Test for T {} | ||
2660 | |||
2661 | fn test() { | ||
2662 | foo.test(); | ||
2663 | bar.test(); | ||
2664 | Struct.test(); | ||
2665 | Enum::Variant.test(); | ||
2666 | } | ||
2667 | "#, true), | ||
2668 | // wrong result, because the built-in Copy impl for fn defs doesn't exist in Chalk yet | ||
2669 | @r###" | ||
2670 | 42..44 '{}': () | ||
2671 | 61..62 'T': {unknown} | ||
2672 | 69..71 '{}': () | ||
2673 | 69..71: expected T, got () | ||
2674 | 146..150 'self': &Self | ||
2675 | 202..282 '{ ...t(); }': () | ||
2676 | 208..211 'foo': fn foo() | ||
2677 | 208..218 'foo.test()': {unknown} | ||
2678 | 224..227 'bar': fn bar<{unknown}>({unknown}) -> {unknown} | ||
2679 | 224..234 'bar.test()': {unknown} | ||
2680 | 240..246 'Struct': Struct(usize) -> Struct | ||
2681 | 240..253 'Struct.test()': {unknown} | ||
2682 | 259..272 'Enum::Variant': Variant(usize) -> Enum | ||
2683 | 259..279 'Enum::...test()': {unknown} | ||
2684 | "### | ||
2685 | ); | ||
2686 | } | ||
2687 | |||
2688 | #[test] | ||
2689 | fn builtin_fn_ptr_copy() { | ||
2690 | assert_snapshot!( | ||
2691 | infer_with_mismatches(r#" | ||
2692 | #[lang = "copy"] | ||
2693 | trait Copy {} | ||
2694 | |||
2695 | trait Test { fn test(&self) -> bool; } | ||
2696 | impl<T: Copy> Test for T {} | ||
2697 | |||
2698 | fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { | ||
2699 | f1.test(); | ||
2700 | f2.test(); | ||
2701 | f3.test(); | ||
2702 | } | ||
2703 | "#, true), | ||
2704 | @r###" | ||
2705 | 55..59 'self': &Self | ||
2706 | 109..111 'f1': fn() | ||
2707 | 119..121 'f2': fn(usize) -> u8 | ||
2708 | 140..142 'f3': fn(u8, u8) -> &u8 | ||
2709 | 163..211 '{ ...t(); }': () | ||
2710 | 169..171 'f1': fn() | ||
2711 | 169..178 'f1.test()': bool | ||
2712 | 184..186 'f2': fn(usize) -> u8 | ||
2713 | 184..193 'f2.test()': bool | ||
2714 | 199..201 'f3': fn(u8, u8) -> &u8 | ||
2715 | 199..208 'f3.test()': bool | ||
2716 | "### | ||
2717 | ); | ||
2718 | } | ||
2719 | |||
2720 | #[test] | ||
2721 | fn builtin_sized() { | ||
2722 | assert_snapshot!( | ||
2723 | infer_with_mismatches(r#" | ||
2724 | #[lang = "sized"] | ||
2725 | trait Sized {} | ||
2726 | |||
2727 | trait Test { fn test(&self) -> bool; } | ||
2728 | impl<T: Sized> Test for T {} | ||
2729 | |||
2730 | fn test() { | ||
2731 | 1u8.test(); | ||
2732 | (*"foo").test(); // not Sized | ||
2733 | (1u8, 1u8).test(); | ||
2734 | (1u8, *"foo").test(); // not Sized | ||
2735 | } | ||
2736 | "#, true), | ||
2737 | @r###" | ||
2738 | 57..61 'self': &Self | ||
2739 | 114..229 '{ ...ized }': () | ||
2740 | 120..123 '1u8': u8 | ||
2741 | 120..130 '1u8.test()': bool | ||
2742 | 136..151 '(*"foo").test()': {unknown} | ||
2743 | 137..143 '*"foo"': str | ||
2744 | 138..143 '"foo"': &str | ||
2745 | 170..180 '(1u8, 1u8)': (u8, u8) | ||
2746 | 170..187 '(1u8, ...test()': bool | ||
2747 | 171..174 '1u8': u8 | ||
2748 | 176..179 '1u8': u8 | ||
2749 | 193..206 '(1u8, *"foo")': (u8, str) | ||
2750 | 193..213 '(1u8, ...test()': {unknown} | ||
2751 | 194..197 '1u8': u8 | ||
2752 | 199..205 '*"foo"': str | ||
2753 | 200..205 '"foo"': &str | ||
2754 | "### | ||
2755 | ); | ||
2756 | } | ||
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index ccab246bf..88a422d2c 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs | |||
@@ -290,8 +290,7 @@ fn trait_object_unsize_impl_datum( | |||
290 | let self_trait_ref = TraitRef { trait_, substs: self_substs }; | 290 | let self_trait_ref = TraitRef { trait_, substs: self_substs }; |
291 | let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)]; | 291 | let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)]; |
292 | 292 | ||
293 | let impl_substs = | 293 | let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.into())).build(); |
294 | Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.clone().into())).build(); | ||
295 | 294 | ||
296 | let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs }; | 295 | let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs }; |
297 | 296 | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 5870618a0..5b0f12a3c 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -1,301 +1,29 @@ | |||
1 | //! Conversion code from/to Chalk. | 1 | //! Conversion code from/to Chalk. |
2 | use std::{fmt, sync::Arc}; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use log::debug; | 4 | use log::debug; |
5 | 5 | ||
6 | use chalk_ir::{ | 6 | use chalk_ir::{fold::shift::Shift, GenericArg, TypeName}; |
7 | cast::Cast, fold::shift::Shift, interner::HasInterner, Goal, GoalData, Parameter, | ||
8 | PlaceholderIndex, TypeName, UniverseIndex, | ||
9 | }; | ||
10 | 7 | ||
11 | use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId}; | 8 | use hir_def::{ |
12 | use ra_db::{ | 9 | lang_item::{lang_attr, LangItemTarget}, |
13 | salsa::{InternId, InternKey}, | 10 | AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId, |
14 | CrateId, | ||
15 | }; | 11 | }; |
12 | use ra_db::{salsa::InternKey, CrateId}; | ||
16 | 13 | ||
17 | use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; | 14 | use super::{builtin, AssocTyValue, ChalkContext, Impl}; |
18 | use crate::{ | 15 | use crate::{ |
19 | db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, | 16 | db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, |
20 | ApplicationTy, DebruijnIndex, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | 17 | CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor, |
21 | }; | 18 | }; |
19 | use chalk_rust_ir::WellKnownTrait; | ||
20 | use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders}; | ||
22 | 21 | ||
23 | pub(super) mod tls; | 22 | pub use self::interner::*; |
24 | |||
25 | #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] | ||
26 | pub struct Interner; | ||
27 | |||
28 | impl chalk_ir::interner::Interner for Interner { | ||
29 | type InternedType = Box<chalk_ir::TyData<Self>>; | ||
30 | type InternedLifetime = chalk_ir::LifetimeData<Self>; | ||
31 | type InternedParameter = chalk_ir::ParameterData<Self>; | ||
32 | type InternedGoal = Arc<GoalData<Self>>; | ||
33 | type InternedGoals = Vec<Goal<Self>>; | ||
34 | type InternedSubstitution = Vec<Parameter<Self>>; | ||
35 | type InternedProgramClause = chalk_ir::ProgramClauseData<Self>; | ||
36 | type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>; | ||
37 | type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; | ||
38 | type InternedParameterKinds = Vec<chalk_ir::ParameterKind<()>>; | ||
39 | type InternedCanonicalVarKinds = Vec<chalk_ir::ParameterKind<UniverseIndex>>; | ||
40 | type Identifier = TypeAliasId; | ||
41 | type DefId = InternId; | ||
42 | |||
43 | fn debug_struct_id( | ||
44 | type_kind_id: StructId, | ||
45 | fmt: &mut fmt::Formatter<'_>, | ||
46 | ) -> Option<fmt::Result> { | ||
47 | tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) | ||
48 | } | ||
49 | |||
50 | fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
51 | tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) | ||
52 | } | ||
53 | |||
54 | fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
55 | tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) | ||
56 | } | ||
57 | |||
58 | fn debug_alias( | ||
59 | alias: &chalk_ir::AliasTy<Interner>, | ||
60 | fmt: &mut fmt::Formatter<'_>, | ||
61 | ) -> Option<fmt::Result> { | ||
62 | tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt))) | ||
63 | } | ||
64 | |||
65 | fn debug_projection_ty( | ||
66 | proj: &chalk_ir::ProjectionTy<Interner>, | ||
67 | fmt: &mut fmt::Formatter<'_>, | ||
68 | ) -> Option<fmt::Result> { | ||
69 | tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt))) | ||
70 | } | ||
71 | |||
72 | fn debug_opaque_ty( | ||
73 | opaque_ty: &chalk_ir::OpaqueTy<Interner>, | ||
74 | fmt: &mut fmt::Formatter<'_>, | ||
75 | ) -> Option<fmt::Result> { | ||
76 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty(opaque_ty, fmt))) | ||
77 | } | ||
78 | |||
79 | fn debug_opaque_ty_id( | ||
80 | opaque_ty_id: chalk_ir::OpaqueTyId<Self>, | ||
81 | fmt: &mut fmt::Formatter<'_>, | ||
82 | ) -> Option<fmt::Result> { | ||
83 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty_id(opaque_ty_id, fmt))) | ||
84 | } | ||
85 | |||
86 | fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
87 | tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt))) | ||
88 | } | ||
89 | |||
90 | fn debug_lifetime( | ||
91 | lifetime: &chalk_ir::Lifetime<Interner>, | ||
92 | fmt: &mut fmt::Formatter<'_>, | ||
93 | ) -> Option<fmt::Result> { | ||
94 | tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt))) | ||
95 | } | ||
96 | |||
97 | fn debug_parameter( | ||
98 | parameter: &Parameter<Interner>, | ||
99 | fmt: &mut fmt::Formatter<'_>, | ||
100 | ) -> Option<fmt::Result> { | ||
101 | tls::with_current_program(|prog| Some(prog?.debug_parameter(parameter, fmt))) | ||
102 | } | ||
103 | |||
104 | fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
105 | tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt))) | ||
106 | } | ||
107 | |||
108 | fn debug_goals( | ||
109 | goals: &chalk_ir::Goals<Interner>, | ||
110 | fmt: &mut fmt::Formatter<'_>, | ||
111 | ) -> Option<fmt::Result> { | ||
112 | tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt))) | ||
113 | } | ||
114 | |||
115 | fn debug_program_clause_implication( | ||
116 | pci: &chalk_ir::ProgramClauseImplication<Interner>, | ||
117 | fmt: &mut fmt::Formatter<'_>, | ||
118 | ) -> Option<fmt::Result> { | ||
119 | tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt))) | ||
120 | } | ||
121 | |||
122 | fn debug_application_ty( | ||
123 | application_ty: &chalk_ir::ApplicationTy<Interner>, | ||
124 | fmt: &mut fmt::Formatter<'_>, | ||
125 | ) -> Option<fmt::Result> { | ||
126 | tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt))) | ||
127 | } | ||
128 | |||
129 | fn debug_substitution( | ||
130 | substitution: &chalk_ir::Substitution<Interner>, | ||
131 | fmt: &mut fmt::Formatter<'_>, | ||
132 | ) -> Option<fmt::Result> { | ||
133 | tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt))) | ||
134 | } | ||
135 | |||
136 | fn debug_separator_trait_ref( | ||
137 | separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>, | ||
138 | fmt: &mut fmt::Formatter<'_>, | ||
139 | ) -> Option<fmt::Result> { | ||
140 | tls::with_current_program(|prog| { | ||
141 | Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt)) | ||
142 | }) | ||
143 | } | ||
144 | |||
145 | fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> { | ||
146 | Box::new(ty) | ||
147 | } | ||
148 | |||
149 | fn ty_data<'a>(&self, ty: &'a Box<chalk_ir::TyData<Self>>) -> &'a chalk_ir::TyData<Self> { | ||
150 | ty | ||
151 | } | ||
152 | |||
153 | fn intern_lifetime( | ||
154 | &self, | ||
155 | lifetime: chalk_ir::LifetimeData<Self>, | ||
156 | ) -> chalk_ir::LifetimeData<Self> { | ||
157 | lifetime | ||
158 | } | ||
159 | |||
160 | fn lifetime_data<'a>( | ||
161 | &self, | ||
162 | lifetime: &'a chalk_ir::LifetimeData<Self>, | ||
163 | ) -> &'a chalk_ir::LifetimeData<Self> { | ||
164 | lifetime | ||
165 | } | ||
166 | |||
167 | fn intern_parameter( | ||
168 | &self, | ||
169 | parameter: chalk_ir::ParameterData<Self>, | ||
170 | ) -> chalk_ir::ParameterData<Self> { | ||
171 | parameter | ||
172 | } | ||
173 | |||
174 | fn parameter_data<'a>( | ||
175 | &self, | ||
176 | parameter: &'a chalk_ir::ParameterData<Self>, | ||
177 | ) -> &'a chalk_ir::ParameterData<Self> { | ||
178 | parameter | ||
179 | } | ||
180 | |||
181 | fn intern_goal(&self, goal: GoalData<Self>) -> Arc<GoalData<Self>> { | ||
182 | Arc::new(goal) | ||
183 | } | ||
184 | |||
185 | fn intern_goals<E>( | ||
186 | &self, | ||
187 | data: impl IntoIterator<Item = Result<Goal<Self>, E>>, | ||
188 | ) -> Result<Self::InternedGoals, E> { | ||
189 | data.into_iter().collect() | ||
190 | } | ||
191 | |||
192 | fn goal_data<'a>(&self, goal: &'a Arc<GoalData<Self>>) -> &'a GoalData<Self> { | ||
193 | goal | ||
194 | } | ||
195 | |||
196 | fn goals_data<'a>(&self, goals: &'a Vec<Goal<Interner>>) -> &'a [Goal<Interner>] { | ||
197 | goals | ||
198 | } | ||
199 | |||
200 | fn intern_substitution<E>( | ||
201 | &self, | ||
202 | data: impl IntoIterator<Item = Result<Parameter<Self>, E>>, | ||
203 | ) -> Result<Vec<Parameter<Self>>, E> { | ||
204 | data.into_iter().collect() | ||
205 | } | ||
206 | |||
207 | fn substitution_data<'a>( | ||
208 | &self, | ||
209 | substitution: &'a Vec<Parameter<Self>>, | ||
210 | ) -> &'a [Parameter<Self>] { | ||
211 | substitution | ||
212 | } | ||
213 | |||
214 | fn intern_program_clause( | ||
215 | &self, | ||
216 | data: chalk_ir::ProgramClauseData<Self>, | ||
217 | ) -> chalk_ir::ProgramClauseData<Self> { | ||
218 | data | ||
219 | } | ||
220 | |||
221 | fn program_clause_data<'a>( | ||
222 | &self, | ||
223 | clause: &'a chalk_ir::ProgramClauseData<Self>, | ||
224 | ) -> &'a chalk_ir::ProgramClauseData<Self> { | ||
225 | clause | ||
226 | } | ||
227 | |||
228 | fn intern_program_clauses<E>( | ||
229 | &self, | ||
230 | data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>, | ||
231 | ) -> Result<Arc<[chalk_ir::ProgramClause<Self>]>, E> { | ||
232 | data.into_iter().collect() | ||
233 | } | ||
234 | |||
235 | fn program_clauses_data<'a>( | ||
236 | &self, | ||
237 | clauses: &'a Arc<[chalk_ir::ProgramClause<Self>]>, | ||
238 | ) -> &'a [chalk_ir::ProgramClause<Self>] { | ||
239 | &clauses | ||
240 | } | ||
241 | |||
242 | fn intern_quantified_where_clauses<E>( | ||
243 | &self, | ||
244 | data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>, | ||
245 | ) -> Result<Self::InternedQuantifiedWhereClauses, E> { | ||
246 | data.into_iter().collect() | ||
247 | } | ||
248 | |||
249 | fn quantified_where_clauses_data<'a>( | ||
250 | &self, | ||
251 | clauses: &'a Self::InternedQuantifiedWhereClauses, | ||
252 | ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] { | ||
253 | clauses | ||
254 | } | ||
255 | |||
256 | fn intern_parameter_kinds<E>( | ||
257 | &self, | ||
258 | data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<()>, E>>, | ||
259 | ) -> Result<Self::InternedParameterKinds, E> { | ||
260 | data.into_iter().collect() | ||
261 | } | ||
262 | 23 | ||
263 | fn parameter_kinds_data<'a>( | 24 | pub(super) mod tls; |
264 | &self, | 25 | mod interner; |
265 | parameter_kinds: &'a Self::InternedParameterKinds, | 26 | mod mapping; |
266 | ) -> &'a [chalk_ir::ParameterKind<()>] { | ||
267 | ¶meter_kinds | ||
268 | } | ||
269 | |||
270 | fn intern_canonical_var_kinds<E>( | ||
271 | &self, | ||
272 | data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<UniverseIndex>, E>>, | ||
273 | ) -> Result<Self::InternedCanonicalVarKinds, E> { | ||
274 | data.into_iter().collect() | ||
275 | } | ||
276 | |||
277 | fn canonical_var_kinds_data<'a>( | ||
278 | &self, | ||
279 | canonical_var_kinds: &'a Self::InternedCanonicalVarKinds, | ||
280 | ) -> &'a [chalk_ir::ParameterKind<UniverseIndex>] { | ||
281 | &canonical_var_kinds | ||
282 | } | ||
283 | } | ||
284 | |||
285 | impl chalk_ir::interner::HasInterner for Interner { | ||
286 | type Interner = Self; | ||
287 | } | ||
288 | |||
289 | pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; | ||
290 | pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum<Interner>; | ||
291 | pub type TraitId = chalk_ir::TraitId<Interner>; | ||
292 | pub type TraitDatum = chalk_rust_ir::TraitDatum<Interner>; | ||
293 | pub type StructId = chalk_ir::StructId<Interner>; | ||
294 | pub type StructDatum = chalk_rust_ir::StructDatum<Interner>; | ||
295 | pub type ImplId = chalk_ir::ImplId<Interner>; | ||
296 | pub type ImplDatum = chalk_rust_ir::ImplDatum<Interner>; | ||
297 | pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId<Interner>; | ||
298 | pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<Interner>; | ||
299 | 27 | ||
300 | pub(super) trait ToChalk { | 28 | pub(super) trait ToChalk { |
301 | type Chalk; | 29 | type Chalk; |
@@ -310,508 +38,6 @@ where | |||
310 | T::from_chalk(db, chalk) | 38 | T::from_chalk(db, chalk) |
311 | } | 39 | } |
312 | 40 | ||
313 | impl ToChalk for Ty { | ||
314 | type Chalk = chalk_ir::Ty<Interner>; | ||
315 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { | ||
316 | match self { | ||
317 | Ty::Apply(apply_ty) => { | ||
318 | let name = apply_ty.ctor.to_chalk(db); | ||
319 | let substitution = apply_ty.parameters.to_chalk(db); | ||
320 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
321 | } | ||
322 | Ty::Projection(proj_ty) => { | ||
323 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); | ||
324 | let substitution = proj_ty.parameters.to_chalk(db); | ||
325 | chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { | ||
326 | associated_ty_id, | ||
327 | substitution, | ||
328 | }) | ||
329 | .cast(&Interner) | ||
330 | .intern(&Interner) | ||
331 | } | ||
332 | Ty::Placeholder(id) => { | ||
333 | let interned_id = db.intern_type_param_id(id); | ||
334 | PlaceholderIndex { | ||
335 | ui: UniverseIndex::ROOT, | ||
336 | idx: interned_id.as_intern_id().as_usize(), | ||
337 | } | ||
338 | .to_ty::<Interner>(&Interner) | ||
339 | } | ||
340 | Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner), | ||
341 | Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), | ||
342 | Ty::Dyn(predicates) => { | ||
343 | let where_clauses = chalk_ir::QuantifiedWhereClauses::from( | ||
344 | &Interner, | ||
345 | predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)), | ||
346 | ); | ||
347 | let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) }; | ||
348 | chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) | ||
349 | } | ||
350 | Ty::Opaque(_) | Ty::Unknown => { | ||
351 | let substitution = chalk_ir::Substitution::empty(&Interner); | ||
352 | let name = TypeName::Error; | ||
353 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self { | ||
358 | match chalk.data(&Interner).clone() { | ||
359 | chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name { | ||
360 | TypeName::Error => Ty::Unknown, | ||
361 | _ => { | ||
362 | let ctor = from_chalk(db, apply_ty.name); | ||
363 | let parameters = from_chalk(db, apply_ty.substitution); | ||
364 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
365 | } | ||
366 | }, | ||
367 | chalk_ir::TyData::Placeholder(idx) => { | ||
368 | assert_eq!(idx.ui, UniverseIndex::ROOT); | ||
369 | let interned_id = crate::db::GlobalTypeParamId::from_intern_id( | ||
370 | crate::salsa::InternId::from(idx.idx), | ||
371 | ); | ||
372 | Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) | ||
373 | } | ||
374 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Projection(proj)) => { | ||
375 | let associated_ty = from_chalk(db, proj.associated_ty_id); | ||
376 | let parameters = from_chalk(db, proj.substitution); | ||
377 | Ty::Projection(ProjectionTy { associated_ty, parameters }) | ||
378 | } | ||
379 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(), | ||
380 | chalk_ir::TyData::Function(_) => unimplemented!(), | ||
381 | chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx), | ||
382 | chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, | ||
383 | chalk_ir::TyData::Dyn(where_clauses) => { | ||
384 | assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); | ||
385 | let predicates = where_clauses | ||
386 | .bounds | ||
387 | .skip_binders() | ||
388 | .iter(&Interner) | ||
389 | .map(|c| from_chalk(db, c.clone())) | ||
390 | .collect(); | ||
391 | Ty::Dyn(predicates) | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | } | ||
396 | |||
397 | impl ToChalk for Substs { | ||
398 | type Chalk = chalk_ir::Substitution<Interner>; | ||
399 | |||
400 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> { | ||
401 | chalk_ir::Substitution::from(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db))) | ||
402 | } | ||
403 | |||
404 | fn from_chalk(db: &dyn HirDatabase, parameters: chalk_ir::Substitution<Interner>) -> Substs { | ||
405 | let tys = parameters | ||
406 | .iter(&Interner) | ||
407 | .map(|p| match p.ty(&Interner) { | ||
408 | Some(ty) => from_chalk(db, ty.clone()), | ||
409 | None => unimplemented!(), | ||
410 | }) | ||
411 | .collect(); | ||
412 | Substs(tys) | ||
413 | } | ||
414 | } | ||
415 | |||
416 | impl ToChalk for TraitRef { | ||
417 | type Chalk = chalk_ir::TraitRef<Interner>; | ||
418 | |||
419 | fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> { | ||
420 | let trait_id = self.trait_.to_chalk(db); | ||
421 | let substitution = self.substs.to_chalk(db); | ||
422 | chalk_ir::TraitRef { trait_id, substitution } | ||
423 | } | ||
424 | |||
425 | fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self { | ||
426 | let trait_ = from_chalk(db, trait_ref.trait_id); | ||
427 | let substs = from_chalk(db, trait_ref.substitution); | ||
428 | TraitRef { trait_, substs } | ||
429 | } | ||
430 | } | ||
431 | |||
432 | impl ToChalk for hir_def::TraitId { | ||
433 | type Chalk = TraitId; | ||
434 | |||
435 | fn to_chalk(self, _db: &dyn HirDatabase) -> TraitId { | ||
436 | chalk_ir::TraitId(self.as_intern_id()) | ||
437 | } | ||
438 | |||
439 | fn from_chalk(_db: &dyn HirDatabase, trait_id: TraitId) -> hir_def::TraitId { | ||
440 | InternKey::from_intern_id(trait_id.0) | ||
441 | } | ||
442 | } | ||
443 | |||
444 | impl ToChalk for TypeCtor { | ||
445 | type Chalk = TypeName<Interner>; | ||
446 | |||
447 | fn to_chalk(self, db: &dyn HirDatabase) -> TypeName<Interner> { | ||
448 | match self { | ||
449 | TypeCtor::AssociatedType(type_alias) => { | ||
450 | let type_id = type_alias.to_chalk(db); | ||
451 | TypeName::AssociatedType(type_id) | ||
452 | } | ||
453 | _ => { | ||
454 | // other TypeCtors get interned and turned into a chalk StructId | ||
455 | let struct_id = db.intern_type_ctor(self).into(); | ||
456 | TypeName::Struct(struct_id) | ||
457 | } | ||
458 | } | ||
459 | } | ||
460 | |||
461 | fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor { | ||
462 | match type_name { | ||
463 | TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), | ||
464 | TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), | ||
465 | TypeName::OpaqueType(_) => unreachable!(), | ||
466 | |||
467 | TypeName::Scalar(_) => unreachable!(), | ||
468 | TypeName::Tuple(_) => unreachable!(), | ||
469 | TypeName::Raw(_) => unreachable!(), | ||
470 | TypeName::Slice => unreachable!(), | ||
471 | TypeName::Ref(_) => unreachable!(), | ||
472 | TypeName::Str => unreachable!(), | ||
473 | |||
474 | TypeName::Error => { | ||
475 | // this should not be reached, since we don't represent TypeName::Error with TypeCtor | ||
476 | unreachable!() | ||
477 | } | ||
478 | } | ||
479 | } | ||
480 | } | ||
481 | |||
482 | impl ToChalk for Impl { | ||
483 | type Chalk = ImplId; | ||
484 | |||
485 | fn to_chalk(self, db: &dyn HirDatabase) -> ImplId { | ||
486 | db.intern_chalk_impl(self).into() | ||
487 | } | ||
488 | |||
489 | fn from_chalk(db: &dyn HirDatabase, impl_id: ImplId) -> Impl { | ||
490 | db.lookup_intern_chalk_impl(impl_id.into()) | ||
491 | } | ||
492 | } | ||
493 | |||
494 | impl ToChalk for TypeAliasId { | ||
495 | type Chalk = AssocTypeId; | ||
496 | |||
497 | fn to_chalk(self, _db: &dyn HirDatabase) -> AssocTypeId { | ||
498 | chalk_ir::AssocTypeId(self.as_intern_id()) | ||
499 | } | ||
500 | |||
501 | fn from_chalk(_db: &dyn HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId { | ||
502 | InternKey::from_intern_id(type_alias_id.0) | ||
503 | } | ||
504 | } | ||
505 | |||
506 | impl ToChalk for AssocTyValue { | ||
507 | type Chalk = AssociatedTyValueId; | ||
508 | |||
509 | fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValueId { | ||
510 | db.intern_assoc_ty_value(self).into() | ||
511 | } | ||
512 | |||
513 | fn from_chalk(db: &dyn HirDatabase, assoc_ty_value_id: AssociatedTyValueId) -> AssocTyValue { | ||
514 | db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into()) | ||
515 | } | ||
516 | } | ||
517 | |||
518 | impl ToChalk for GenericPredicate { | ||
519 | type Chalk = chalk_ir::QuantifiedWhereClause<Interner>; | ||
520 | |||
521 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> { | ||
522 | match self { | ||
523 | GenericPredicate::Implemented(trait_ref) => { | ||
524 | let chalk_trait_ref = trait_ref.to_chalk(db); | ||
525 | let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner); | ||
526 | make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0) | ||
527 | } | ||
528 | GenericPredicate::Projection(projection_pred) => { | ||
529 | let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner); | ||
530 | let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner); | ||
531 | let alias = chalk_ir::AliasTy::Projection(projection); | ||
532 | make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0) | ||
533 | } | ||
534 | GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), | ||
535 | } | ||
536 | } | ||
537 | |||
538 | fn from_chalk( | ||
539 | db: &dyn HirDatabase, | ||
540 | where_clause: chalk_ir::QuantifiedWhereClause<Interner>, | ||
541 | ) -> GenericPredicate { | ||
542 | // we don't produce any where clauses with binders and can't currently deal with them | ||
543 | match where_clause | ||
544 | .skip_binders() | ||
545 | .shifted_out(&Interner) | ||
546 | .expect("unexpected bound vars in where clause") | ||
547 | { | ||
548 | chalk_ir::WhereClause::Implemented(tr) => { | ||
549 | GenericPredicate::Implemented(from_chalk(db, tr)) | ||
550 | } | ||
551 | chalk_ir::WhereClause::AliasEq(projection_eq) => { | ||
552 | let projection_ty = from_chalk( | ||
553 | db, | ||
554 | match projection_eq.alias { | ||
555 | chalk_ir::AliasTy::Projection(p) => p, | ||
556 | _ => unimplemented!(), | ||
557 | }, | ||
558 | ); | ||
559 | let ty = from_chalk(db, projection_eq.ty); | ||
560 | GenericPredicate::Projection(super::ProjectionPredicate { projection_ty, ty }) | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | } | ||
565 | |||
566 | impl ToChalk for ProjectionTy { | ||
567 | type Chalk = chalk_ir::ProjectionTy<Interner>; | ||
568 | |||
569 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> { | ||
570 | chalk_ir::ProjectionTy { | ||
571 | associated_ty_id: self.associated_ty.to_chalk(db), | ||
572 | substitution: self.parameters.to_chalk(db), | ||
573 | } | ||
574 | } | ||
575 | |||
576 | fn from_chalk( | ||
577 | db: &dyn HirDatabase, | ||
578 | projection_ty: chalk_ir::ProjectionTy<Interner>, | ||
579 | ) -> ProjectionTy { | ||
580 | ProjectionTy { | ||
581 | associated_ty: from_chalk(db, projection_ty.associated_ty_id), | ||
582 | parameters: from_chalk(db, projection_ty.substitution), | ||
583 | } | ||
584 | } | ||
585 | } | ||
586 | |||
587 | impl ToChalk for super::ProjectionPredicate { | ||
588 | type Chalk = chalk_ir::AliasEq<Interner>; | ||
589 | |||
590 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> { | ||
591 | chalk_ir::AliasEq { | ||
592 | alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)), | ||
593 | ty: self.ty.to_chalk(db), | ||
594 | } | ||
595 | } | ||
596 | |||
597 | fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self { | ||
598 | unimplemented!() | ||
599 | } | ||
600 | } | ||
601 | |||
602 | impl ToChalk for Obligation { | ||
603 | type Chalk = chalk_ir::DomainGoal<Interner>; | ||
604 | |||
605 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> { | ||
606 | match self { | ||
607 | Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner), | ||
608 | Obligation::Projection(pr) => pr.to_chalk(db).cast(&Interner), | ||
609 | } | ||
610 | } | ||
611 | |||
612 | fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self { | ||
613 | unimplemented!() | ||
614 | } | ||
615 | } | ||
616 | |||
617 | impl<T> ToChalk for Canonical<T> | ||
618 | where | ||
619 | T: ToChalk, | ||
620 | T::Chalk: HasInterner<Interner = Interner>, | ||
621 | { | ||
622 | type Chalk = chalk_ir::Canonical<T::Chalk>; | ||
623 | |||
624 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { | ||
625 | let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT); | ||
626 | let value = self.value.to_chalk(db); | ||
627 | chalk_ir::Canonical { | ||
628 | value, | ||
629 | binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]), | ||
630 | } | ||
631 | } | ||
632 | |||
633 | fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { | ||
634 | Canonical { | ||
635 | num_vars: canonical.binders.len(&Interner), | ||
636 | value: from_chalk(db, canonical.value), | ||
637 | } | ||
638 | } | ||
639 | } | ||
640 | |||
641 | impl ToChalk for Arc<super::TraitEnvironment> { | ||
642 | type Chalk = chalk_ir::Environment<Interner>; | ||
643 | |||
644 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Environment<Interner> { | ||
645 | let mut clauses = Vec::new(); | ||
646 | for pred in &self.predicates { | ||
647 | if pred.is_error() { | ||
648 | // for env, we just ignore errors | ||
649 | continue; | ||
650 | } | ||
651 | let program_clause: chalk_ir::ProgramClause<Interner> = | ||
652 | pred.clone().to_chalk(db).cast(&Interner); | ||
653 | clauses.push(program_clause.into_from_env_clause(&Interner)); | ||
654 | } | ||
655 | chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses) | ||
656 | } | ||
657 | |||
658 | fn from_chalk( | ||
659 | _db: &dyn HirDatabase, | ||
660 | _env: chalk_ir::Environment<Interner>, | ||
661 | ) -> Arc<super::TraitEnvironment> { | ||
662 | unimplemented!() | ||
663 | } | ||
664 | } | ||
665 | |||
666 | impl<T: ToChalk> ToChalk for super::InEnvironment<T> | ||
667 | where | ||
668 | T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>, | ||
669 | { | ||
670 | type Chalk = chalk_ir::InEnvironment<T::Chalk>; | ||
671 | |||
672 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { | ||
673 | chalk_ir::InEnvironment { | ||
674 | environment: self.environment.to_chalk(db), | ||
675 | goal: self.value.to_chalk(db), | ||
676 | } | ||
677 | } | ||
678 | |||
679 | fn from_chalk( | ||
680 | db: &dyn HirDatabase, | ||
681 | in_env: chalk_ir::InEnvironment<T::Chalk>, | ||
682 | ) -> super::InEnvironment<T> { | ||
683 | super::InEnvironment { | ||
684 | environment: from_chalk(db, in_env.environment), | ||
685 | value: from_chalk(db, in_env.goal), | ||
686 | } | ||
687 | } | ||
688 | } | ||
689 | |||
690 | impl ToChalk for builtin::BuiltinImplData { | ||
691 | type Chalk = ImplDatum; | ||
692 | |||
693 | fn to_chalk(self, db: &dyn HirDatabase) -> ImplDatum { | ||
694 | let impl_type = chalk_rust_ir::ImplType::External; | ||
695 | let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect(); | ||
696 | |||
697 | let impl_datum_bound = | ||
698 | chalk_rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses }; | ||
699 | let associated_ty_value_ids = | ||
700 | self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect(); | ||
701 | chalk_rust_ir::ImplDatum { | ||
702 | binders: make_binders(impl_datum_bound, self.num_vars), | ||
703 | impl_type, | ||
704 | polarity: chalk_rust_ir::Polarity::Positive, | ||
705 | associated_ty_value_ids, | ||
706 | } | ||
707 | } | ||
708 | |||
709 | fn from_chalk(_db: &dyn HirDatabase, _data: ImplDatum) -> Self { | ||
710 | unimplemented!() | ||
711 | } | ||
712 | } | ||
713 | |||
714 | impl ToChalk for builtin::BuiltinImplAssocTyValueData { | ||
715 | type Chalk = AssociatedTyValue; | ||
716 | |||
717 | fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue { | ||
718 | let ty = self.value.to_chalk(db); | ||
719 | let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty }; | ||
720 | |||
721 | chalk_rust_ir::AssociatedTyValue { | ||
722 | associated_ty_id: self.assoc_ty_id.to_chalk(db), | ||
723 | impl_id: self.impl_.to_chalk(db), | ||
724 | value: make_binders(value_bound, self.num_vars), | ||
725 | } | ||
726 | } | ||
727 | |||
728 | fn from_chalk( | ||
729 | _db: &dyn HirDatabase, | ||
730 | _data: AssociatedTyValue, | ||
731 | ) -> builtin::BuiltinImplAssocTyValueData { | ||
732 | unimplemented!() | ||
733 | } | ||
734 | } | ||
735 | |||
736 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> | ||
737 | where | ||
738 | T: HasInterner<Interner = Interner>, | ||
739 | { | ||
740 | chalk_ir::Binders::new( | ||
741 | chalk_ir::ParameterKinds::from( | ||
742 | &Interner, | ||
743 | std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars), | ||
744 | ), | ||
745 | value, | ||
746 | ) | ||
747 | } | ||
748 | |||
749 | fn convert_where_clauses( | ||
750 | db: &dyn HirDatabase, | ||
751 | def: GenericDefId, | ||
752 | substs: &Substs, | ||
753 | ) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> { | ||
754 | let generic_predicates = db.generic_predicates(def); | ||
755 | let mut result = Vec::with_capacity(generic_predicates.len()); | ||
756 | for pred in generic_predicates.iter() { | ||
757 | if pred.value.is_error() { | ||
758 | // skip errored predicates completely | ||
759 | continue; | ||
760 | } | ||
761 | result.push(pred.clone().subst(substs).to_chalk(db)); | ||
762 | } | ||
763 | result | ||
764 | } | ||
765 | |||
766 | fn generic_predicate_to_inline_bound( | ||
767 | db: &dyn HirDatabase, | ||
768 | pred: &GenericPredicate, | ||
769 | self_ty: &Ty, | ||
770 | ) -> Option<chalk_rust_ir::InlineBound<Interner>> { | ||
771 | // An InlineBound is like a GenericPredicate, except the self type is left out. | ||
772 | // We don't have a special type for this, but Chalk does. | ||
773 | match pred { | ||
774 | GenericPredicate::Implemented(trait_ref) => { | ||
775 | if &trait_ref.substs[0] != self_ty { | ||
776 | // we can only convert predicates back to type bounds if they | ||
777 | // have the expected self type | ||
778 | return None; | ||
779 | } | ||
780 | let args_no_self = trait_ref.substs[1..] | ||
781 | .iter() | ||
782 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
783 | .collect(); | ||
784 | let trait_bound = | ||
785 | chalk_rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; | ||
786 | Some(chalk_rust_ir::InlineBound::TraitBound(trait_bound)) | ||
787 | } | ||
788 | GenericPredicate::Projection(proj) => { | ||
789 | if &proj.projection_ty.parameters[0] != self_ty { | ||
790 | return None; | ||
791 | } | ||
792 | let trait_ = match proj.projection_ty.associated_ty.lookup(db.upcast()).container { | ||
793 | AssocContainerId::TraitId(t) => t, | ||
794 | _ => panic!("associated type not in trait"), | ||
795 | }; | ||
796 | let args_no_self = proj.projection_ty.parameters[1..] | ||
797 | .iter() | ||
798 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
799 | .collect(); | ||
800 | let alias_eq_bound = chalk_rust_ir::AliasEqBound { | ||
801 | value: proj.ty.clone().to_chalk(db), | ||
802 | trait_bound: chalk_rust_ir::TraitBound { | ||
803 | trait_id: trait_.to_chalk(db), | ||
804 | args_no_self, | ||
805 | }, | ||
806 | associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db), | ||
807 | parameters: Vec::new(), // FIXME we don't support generic associated types yet | ||
808 | }; | ||
809 | Some(chalk_rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) | ||
810 | } | ||
811 | GenericPredicate::Error => None, | ||
812 | } | ||
813 | } | ||
814 | |||
815 | impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | 41 | impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { |
816 | fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { | 42 | fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { |
817 | self.db.associated_ty_data(id) | 43 | self.db.associated_ty_data(id) |
@@ -819,16 +45,24 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
819 | fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> { | 45 | fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> { |
820 | self.db.trait_datum(self.krate, trait_id) | 46 | self.db.trait_datum(self.krate, trait_id) |
821 | } | 47 | } |
822 | fn struct_datum(&self, struct_id: StructId) -> Arc<StructDatum> { | 48 | fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> { |
823 | self.db.struct_datum(self.krate, struct_id) | 49 | self.db.struct_datum(self.krate, struct_id) |
824 | } | 50 | } |
825 | fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { | 51 | fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { |
826 | self.db.impl_datum(self.krate, impl_id) | 52 | self.db.impl_datum(self.krate, impl_id) |
827 | } | 53 | } |
54 | |||
55 | fn fn_def_datum( | ||
56 | &self, | ||
57 | fn_def_id: chalk_ir::FnDefId<Interner>, | ||
58 | ) -> Arc<chalk_rust_ir::FnDefDatum<Interner>> { | ||
59 | self.db.fn_def_datum(self.krate, fn_def_id) | ||
60 | } | ||
61 | |||
828 | fn impls_for_trait( | 62 | fn impls_for_trait( |
829 | &self, | 63 | &self, |
830 | trait_id: TraitId, | 64 | trait_id: TraitId, |
831 | parameters: &[Parameter<Interner>], | 65 | parameters: &[GenericArg<Interner>], |
832 | ) -> Vec<ImplId> { | 66 | ) -> Vec<ImplId> { |
833 | debug!("impls_for_trait {:?}", trait_id); | 67 | debug!("impls_for_trait {:?}", trait_id); |
834 | let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); | 68 | let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); |
@@ -859,7 +93,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
859 | debug!("impls_for_trait returned {} impls", result.len()); | 93 | debug!("impls_for_trait returned {} impls", result.len()); |
860 | result | 94 | result |
861 | } | 95 | } |
862 | fn impl_provided_for(&self, auto_trait_id: TraitId, struct_id: StructId) -> bool { | 96 | fn impl_provided_for(&self, auto_trait_id: TraitId, struct_id: AdtId) -> bool { |
863 | debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); | 97 | debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); |
864 | false // FIXME | 98 | false // FIXME |
865 | } | 99 | } |
@@ -878,10 +112,15 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
878 | } | 112 | } |
879 | fn well_known_trait_id( | 113 | fn well_known_trait_id( |
880 | &self, | 114 | &self, |
881 | _well_known_trait: chalk_rust_ir::WellKnownTrait, | 115 | well_known_trait: chalk_rust_ir::WellKnownTrait, |
882 | ) -> Option<chalk_ir::TraitId<Interner>> { | 116 | ) -> Option<chalk_ir::TraitId<Interner>> { |
883 | // FIXME tell Chalk about well-known traits (here and in trait_datum) | 117 | let lang_attr = lang_attr_from_well_known_trait(well_known_trait); |
884 | None | 118 | let lang_items = self.db.crate_lang_items(self.krate); |
119 | let trait_ = match lang_items.target(lang_attr) { | ||
120 | Some(LangItemTarget::TraitId(trait_)) => trait_, | ||
121 | _ => return None, | ||
122 | }; | ||
123 | Some(trait_.to_chalk(self.db)) | ||
885 | } | 124 | } |
886 | 125 | ||
887 | fn program_clauses_for_env( | 126 | fn program_clauses_for_env( |
@@ -983,7 +222,8 @@ pub(crate) fn trait_datum_query( | |||
983 | let associated_ty_ids = | 222 | let associated_ty_ids = |
984 | trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); | 223 | trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); |
985 | let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses }; | 224 | let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses }; |
986 | let well_known = None; // FIXME set this (depending on lang items) | 225 | let well_known = |
226 | lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); | ||
987 | let trait_datum = TraitDatum { | 227 | let trait_datum = TraitDatum { |
988 | id: trait_id, | 228 | id: trait_id, |
989 | binders: make_binders(trait_datum_bound, bound_vars.len()), | 229 | binders: make_binders(trait_datum_bound, bound_vars.len()), |
@@ -994,13 +234,32 @@ pub(crate) fn trait_datum_query( | |||
994 | Arc::new(trait_datum) | 234 | Arc::new(trait_datum) |
995 | } | 235 | } |
996 | 236 | ||
237 | fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> { | ||
238 | Some(match name { | ||
239 | "sized" => WellKnownTrait::SizedTrait, | ||
240 | "copy" => WellKnownTrait::CopyTrait, | ||
241 | "clone" => WellKnownTrait::CloneTrait, | ||
242 | "drop" => WellKnownTrait::DropTrait, | ||
243 | _ => return None, | ||
244 | }) | ||
245 | } | ||
246 | |||
247 | fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str { | ||
248 | match attr { | ||
249 | WellKnownTrait::SizedTrait => "sized", | ||
250 | WellKnownTrait::CopyTrait => "copy", | ||
251 | WellKnownTrait::CloneTrait => "clone", | ||
252 | WellKnownTrait::DropTrait => "drop", | ||
253 | } | ||
254 | } | ||
255 | |||
997 | pub(crate) fn struct_datum_query( | 256 | pub(crate) fn struct_datum_query( |
998 | db: &dyn HirDatabase, | 257 | db: &dyn HirDatabase, |
999 | krate: CrateId, | 258 | krate: CrateId, |
1000 | struct_id: StructId, | 259 | struct_id: AdtId, |
1001 | ) -> Arc<StructDatum> { | 260 | ) -> Arc<StructDatum> { |
1002 | debug!("struct_datum {:?}", struct_id); | 261 | debug!("struct_datum {:?}", struct_id); |
1003 | let type_ctor: TypeCtor = from_chalk(db, TypeName::Struct(struct_id)); | 262 | let type_ctor: TypeCtor = from_chalk(db, TypeName::Adt(struct_id)); |
1004 | debug!("struct {:?} = {:?}", struct_id, type_ctor); | 263 | debug!("struct {:?} = {:?}", struct_id, type_ctor); |
1005 | let num_params = type_ctor.num_ty_params(db); | 264 | let num_params = type_ctor.num_ty_params(db); |
1006 | let upstream = type_ctor.krate(db) != Some(krate); | 265 | let upstream = type_ctor.krate(db) != Some(krate); |
@@ -1012,12 +271,12 @@ pub(crate) fn struct_datum_query( | |||
1012 | convert_where_clauses(db, generic_def, &bound_vars) | 271 | convert_where_clauses(db, generic_def, &bound_vars) |
1013 | }) | 272 | }) |
1014 | .unwrap_or_else(Vec::new); | 273 | .unwrap_or_else(Vec::new); |
1015 | let flags = chalk_rust_ir::StructFlags { | 274 | let flags = chalk_rust_ir::AdtFlags { |
1016 | upstream, | 275 | upstream, |
1017 | // FIXME set fundamental flag correctly | 276 | // FIXME set fundamental flag correctly |
1018 | fundamental: false, | 277 | fundamental: false, |
1019 | }; | 278 | }; |
1020 | let struct_datum_bound = chalk_rust_ir::StructDatumBound { | 279 | let struct_datum_bound = chalk_rust_ir::AdtDatumBound { |
1021 | fields: Vec::new(), // FIXME add fields (only relevant for auto traits) | 280 | fields: Vec::new(), // FIXME add fields (only relevant for auto traits) |
1022 | where_clauses, | 281 | where_clauses, |
1023 | }; | 282 | }; |
@@ -1145,15 +404,47 @@ fn type_alias_associated_ty_value( | |||
1145 | Arc::new(value) | 404 | Arc::new(value) |
1146 | } | 405 | } |
1147 | 406 | ||
1148 | impl From<StructId> for crate::TypeCtorId { | 407 | pub(crate) fn fn_def_datum_query( |
1149 | fn from(struct_id: StructId) -> Self { | 408 | db: &dyn HirDatabase, |
1150 | InternKey::from_intern_id(struct_id.0) | 409 | _krate: CrateId, |
410 | fn_def_id: FnDefId, | ||
411 | ) -> Arc<FnDefDatum> { | ||
412 | let callable_def: CallableDef = from_chalk(db, fn_def_id); | ||
413 | let generic_params = generics(db.upcast(), callable_def.into()); | ||
414 | let sig = db.callable_item_signature(callable_def); | ||
415 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
416 | let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); | ||
417 | let bound = chalk_rust_ir::FnDefDatumBound { | ||
418 | // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway | ||
419 | argument_types: sig.value.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(), | ||
420 | return_type: sig.value.ret().clone().to_chalk(db), | ||
421 | where_clauses, | ||
422 | }; | ||
423 | let datum = FnDefDatum { id: fn_def_id, binders: make_binders(bound, sig.num_binders) }; | ||
424 | Arc::new(datum) | ||
425 | } | ||
426 | |||
427 | impl From<AdtId> for crate::TypeCtorId { | ||
428 | fn from(struct_id: AdtId) -> Self { | ||
429 | struct_id.0 | ||
1151 | } | 430 | } |
1152 | } | 431 | } |
1153 | 432 | ||
1154 | impl From<crate::TypeCtorId> for StructId { | 433 | impl From<crate::TypeCtorId> for AdtId { |
1155 | fn from(type_ctor_id: crate::TypeCtorId) -> Self { | 434 | fn from(type_ctor_id: crate::TypeCtorId) -> Self { |
1156 | chalk_ir::StructId(type_ctor_id.as_intern_id()) | 435 | chalk_ir::AdtId(type_ctor_id) |
436 | } | ||
437 | } | ||
438 | |||
439 | impl From<FnDefId> for crate::CallableDefId { | ||
440 | fn from(fn_def_id: FnDefId) -> Self { | ||
441 | InternKey::from_intern_id(fn_def_id.0) | ||
442 | } | ||
443 | } | ||
444 | |||
445 | impl From<crate::CallableDefId> for FnDefId { | ||
446 | fn from(callable_def_id: crate::CallableDefId) -> Self { | ||
447 | chalk_ir::FnDefId(callable_def_id.as_intern_id()) | ||
1157 | } | 448 | } |
1158 | } | 449 | } |
1159 | 450 | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk/interner.rs b/crates/ra_hir_ty/src/traits/chalk/interner.rs new file mode 100644 index 000000000..2a27f8ed8 --- /dev/null +++ b/crates/ra_hir_ty/src/traits/chalk/interner.rs | |||
@@ -0,0 +1,353 @@ | |||
1 | //! Implementation of the Chalk `Interner` trait, which allows customizing the | ||
2 | //! representation of the various objects Chalk deals with (types, goals etc.). | ||
3 | |||
4 | use super::tls; | ||
5 | use chalk_ir::{GenericArg, Goal, GoalData}; | ||
6 | use hir_def::TypeAliasId; | ||
7 | use ra_db::salsa::InternId; | ||
8 | use std::{fmt, sync::Arc}; | ||
9 | |||
10 | #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] | ||
11 | pub struct Interner; | ||
12 | |||
13 | pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; | ||
14 | pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum<Interner>; | ||
15 | pub type TraitId = chalk_ir::TraitId<Interner>; | ||
16 | pub type TraitDatum = chalk_rust_ir::TraitDatum<Interner>; | ||
17 | pub type AdtId = chalk_ir::AdtId<Interner>; | ||
18 | pub type StructDatum = chalk_rust_ir::AdtDatum<Interner>; | ||
19 | pub type ImplId = chalk_ir::ImplId<Interner>; | ||
20 | pub type ImplDatum = chalk_rust_ir::ImplDatum<Interner>; | ||
21 | pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId<Interner>; | ||
22 | pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<Interner>; | ||
23 | pub type FnDefId = chalk_ir::FnDefId<Interner>; | ||
24 | pub type FnDefDatum = chalk_rust_ir::FnDefDatum<Interner>; | ||
25 | |||
26 | impl chalk_ir::interner::Interner for Interner { | ||
27 | type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc? | ||
28 | type InternedLifetime = chalk_ir::LifetimeData<Self>; | ||
29 | type InternedConst = Arc<chalk_ir::ConstData<Self>>; | ||
30 | type InternedConcreteConst = (); | ||
31 | type InternedGenericArg = chalk_ir::GenericArgData<Self>; | ||
32 | type InternedGoal = Arc<GoalData<Self>>; | ||
33 | type InternedGoals = Vec<Goal<Self>>; | ||
34 | type InternedSubstitution = Vec<GenericArg<Self>>; | ||
35 | type InternedProgramClause = chalk_ir::ProgramClauseData<Self>; | ||
36 | type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>; | ||
37 | type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; | ||
38 | type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>; | ||
39 | type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>; | ||
40 | type DefId = InternId; | ||
41 | type InternedAdtId = crate::TypeCtorId; | ||
42 | type Identifier = TypeAliasId; | ||
43 | |||
44 | fn debug_adt_id(type_kind_id: AdtId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
45 | tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) | ||
46 | } | ||
47 | |||
48 | fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
49 | tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) | ||
50 | } | ||
51 | |||
52 | fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
53 | tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) | ||
54 | } | ||
55 | |||
56 | fn debug_alias( | ||
57 | alias: &chalk_ir::AliasTy<Interner>, | ||
58 | fmt: &mut fmt::Formatter<'_>, | ||
59 | ) -> Option<fmt::Result> { | ||
60 | tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt))) | ||
61 | } | ||
62 | |||
63 | fn debug_projection_ty( | ||
64 | proj: &chalk_ir::ProjectionTy<Interner>, | ||
65 | fmt: &mut fmt::Formatter<'_>, | ||
66 | ) -> Option<fmt::Result> { | ||
67 | tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt))) | ||
68 | } | ||
69 | |||
70 | fn debug_opaque_ty( | ||
71 | opaque_ty: &chalk_ir::OpaqueTy<Interner>, | ||
72 | fmt: &mut fmt::Formatter<'_>, | ||
73 | ) -> Option<fmt::Result> { | ||
74 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty(opaque_ty, fmt))) | ||
75 | } | ||
76 | |||
77 | fn debug_opaque_ty_id( | ||
78 | opaque_ty_id: chalk_ir::OpaqueTyId<Self>, | ||
79 | fmt: &mut fmt::Formatter<'_>, | ||
80 | ) -> Option<fmt::Result> { | ||
81 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty_id(opaque_ty_id, fmt))) | ||
82 | } | ||
83 | |||
84 | fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
85 | tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt))) | ||
86 | } | ||
87 | |||
88 | fn debug_lifetime( | ||
89 | lifetime: &chalk_ir::Lifetime<Interner>, | ||
90 | fmt: &mut fmt::Formatter<'_>, | ||
91 | ) -> Option<fmt::Result> { | ||
92 | tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt))) | ||
93 | } | ||
94 | |||
95 | fn debug_generic_arg( | ||
96 | parameter: &GenericArg<Interner>, | ||
97 | fmt: &mut fmt::Formatter<'_>, | ||
98 | ) -> Option<fmt::Result> { | ||
99 | tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt))) | ||
100 | } | ||
101 | |||
102 | fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
103 | tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt))) | ||
104 | } | ||
105 | |||
106 | fn debug_goals( | ||
107 | goals: &chalk_ir::Goals<Interner>, | ||
108 | fmt: &mut fmt::Formatter<'_>, | ||
109 | ) -> Option<fmt::Result> { | ||
110 | tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt))) | ||
111 | } | ||
112 | |||
113 | fn debug_program_clause_implication( | ||
114 | pci: &chalk_ir::ProgramClauseImplication<Interner>, | ||
115 | fmt: &mut fmt::Formatter<'_>, | ||
116 | ) -> Option<fmt::Result> { | ||
117 | tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt))) | ||
118 | } | ||
119 | |||
120 | fn debug_application_ty( | ||
121 | application_ty: &chalk_ir::ApplicationTy<Interner>, | ||
122 | fmt: &mut fmt::Formatter<'_>, | ||
123 | ) -> Option<fmt::Result> { | ||
124 | tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt))) | ||
125 | } | ||
126 | |||
127 | fn debug_substitution( | ||
128 | substitution: &chalk_ir::Substitution<Interner>, | ||
129 | fmt: &mut fmt::Formatter<'_>, | ||
130 | ) -> Option<fmt::Result> { | ||
131 | tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt))) | ||
132 | } | ||
133 | |||
134 | fn debug_separator_trait_ref( | ||
135 | separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>, | ||
136 | fmt: &mut fmt::Formatter<'_>, | ||
137 | ) -> Option<fmt::Result> { | ||
138 | tls::with_current_program(|prog| { | ||
139 | Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt)) | ||
140 | }) | ||
141 | } | ||
142 | |||
143 | fn debug_fn_def_id( | ||
144 | fn_def_id: chalk_ir::FnDefId<Self>, | ||
145 | fmt: &mut fmt::Formatter<'_>, | ||
146 | ) -> Option<fmt::Result> { | ||
147 | tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt))) | ||
148 | } | ||
149 | fn debug_const( | ||
150 | constant: &chalk_ir::Const<Self>, | ||
151 | fmt: &mut fmt::Formatter<'_>, | ||
152 | ) -> Option<fmt::Result> { | ||
153 | tls::with_current_program(|prog| Some(prog?.debug_const(constant, fmt))) | ||
154 | } | ||
155 | fn debug_variable_kinds( | ||
156 | variable_kinds: &chalk_ir::VariableKinds<Self>, | ||
157 | fmt: &mut fmt::Formatter<'_>, | ||
158 | ) -> Option<fmt::Result> { | ||
159 | tls::with_current_program(|prog| Some(prog?.debug_variable_kinds(variable_kinds, fmt))) | ||
160 | } | ||
161 | fn debug_variable_kinds_with_angles( | ||
162 | variable_kinds: &chalk_ir::VariableKinds<Self>, | ||
163 | fmt: &mut fmt::Formatter<'_>, | ||
164 | ) -> Option<fmt::Result> { | ||
165 | tls::with_current_program(|prog| { | ||
166 | Some(prog?.debug_variable_kinds_with_angles(variable_kinds, fmt)) | ||
167 | }) | ||
168 | } | ||
169 | fn debug_canonical_var_kinds( | ||
170 | canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Self>, | ||
171 | fmt: &mut fmt::Formatter<'_>, | ||
172 | ) -> Option<fmt::Result> { | ||
173 | tls::with_current_program(|prog| { | ||
174 | Some(prog?.debug_canonical_var_kinds(canonical_var_kinds, fmt)) | ||
175 | }) | ||
176 | } | ||
177 | fn debug_program_clause( | ||
178 | clause: &chalk_ir::ProgramClause<Self>, | ||
179 | fmt: &mut fmt::Formatter<'_>, | ||
180 | ) -> Option<fmt::Result> { | ||
181 | tls::with_current_program(|prog| Some(prog?.debug_program_clause(clause, fmt))) | ||
182 | } | ||
183 | fn debug_program_clauses( | ||
184 | clauses: &chalk_ir::ProgramClauses<Self>, | ||
185 | fmt: &mut fmt::Formatter<'_>, | ||
186 | ) -> Option<fmt::Result> { | ||
187 | tls::with_current_program(|prog| Some(prog?.debug_program_clauses(clauses, fmt))) | ||
188 | } | ||
189 | fn debug_quantified_where_clauses( | ||
190 | clauses: &chalk_ir::QuantifiedWhereClauses<Self>, | ||
191 | fmt: &mut fmt::Formatter<'_>, | ||
192 | ) -> Option<fmt::Result> { | ||
193 | tls::with_current_program(|prog| Some(prog?.debug_quantified_where_clauses(clauses, fmt))) | ||
194 | } | ||
195 | |||
196 | fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> { | ||
197 | Box::new(ty) | ||
198 | } | ||
199 | |||
200 | fn ty_data<'a>(&self, ty: &'a Box<chalk_ir::TyData<Self>>) -> &'a chalk_ir::TyData<Self> { | ||
201 | ty | ||
202 | } | ||
203 | |||
204 | fn intern_lifetime( | ||
205 | &self, | ||
206 | lifetime: chalk_ir::LifetimeData<Self>, | ||
207 | ) -> chalk_ir::LifetimeData<Self> { | ||
208 | lifetime | ||
209 | } | ||
210 | |||
211 | fn lifetime_data<'a>( | ||
212 | &self, | ||
213 | lifetime: &'a chalk_ir::LifetimeData<Self>, | ||
214 | ) -> &'a chalk_ir::LifetimeData<Self> { | ||
215 | lifetime | ||
216 | } | ||
217 | |||
218 | fn intern_const(&self, constant: chalk_ir::ConstData<Self>) -> Arc<chalk_ir::ConstData<Self>> { | ||
219 | Arc::new(constant) | ||
220 | } | ||
221 | |||
222 | fn const_data<'a>( | ||
223 | &self, | ||
224 | constant: &'a Arc<chalk_ir::ConstData<Self>>, | ||
225 | ) -> &'a chalk_ir::ConstData<Self> { | ||
226 | constant | ||
227 | } | ||
228 | |||
229 | fn const_eq(&self, _ty: &Box<chalk_ir::TyData<Self>>, _c1: &(), _c2: &()) -> bool { | ||
230 | true | ||
231 | } | ||
232 | |||
233 | fn intern_generic_arg( | ||
234 | &self, | ||
235 | parameter: chalk_ir::GenericArgData<Self>, | ||
236 | ) -> chalk_ir::GenericArgData<Self> { | ||
237 | parameter | ||
238 | } | ||
239 | |||
240 | fn generic_arg_data<'a>( | ||
241 | &self, | ||
242 | parameter: &'a chalk_ir::GenericArgData<Self>, | ||
243 | ) -> &'a chalk_ir::GenericArgData<Self> { | ||
244 | parameter | ||
245 | } | ||
246 | |||
247 | fn intern_goal(&self, goal: GoalData<Self>) -> Arc<GoalData<Self>> { | ||
248 | Arc::new(goal) | ||
249 | } | ||
250 | |||
251 | fn intern_goals<E>( | ||
252 | &self, | ||
253 | data: impl IntoIterator<Item = Result<Goal<Self>, E>>, | ||
254 | ) -> Result<Self::InternedGoals, E> { | ||
255 | data.into_iter().collect() | ||
256 | } | ||
257 | |||
258 | fn goal_data<'a>(&self, goal: &'a Arc<GoalData<Self>>) -> &'a GoalData<Self> { | ||
259 | goal | ||
260 | } | ||
261 | |||
262 | fn goals_data<'a>(&self, goals: &'a Vec<Goal<Interner>>) -> &'a [Goal<Interner>] { | ||
263 | goals | ||
264 | } | ||
265 | |||
266 | fn intern_substitution<E>( | ||
267 | &self, | ||
268 | data: impl IntoIterator<Item = Result<GenericArg<Self>, E>>, | ||
269 | ) -> Result<Vec<GenericArg<Self>>, E> { | ||
270 | data.into_iter().collect() | ||
271 | } | ||
272 | |||
273 | fn substitution_data<'a>( | ||
274 | &self, | ||
275 | substitution: &'a Vec<GenericArg<Self>>, | ||
276 | ) -> &'a [GenericArg<Self>] { | ||
277 | substitution | ||
278 | } | ||
279 | |||
280 | fn intern_program_clause( | ||
281 | &self, | ||
282 | data: chalk_ir::ProgramClauseData<Self>, | ||
283 | ) -> chalk_ir::ProgramClauseData<Self> { | ||
284 | data | ||
285 | } | ||
286 | |||
287 | fn program_clause_data<'a>( | ||
288 | &self, | ||
289 | clause: &'a chalk_ir::ProgramClauseData<Self>, | ||
290 | ) -> &'a chalk_ir::ProgramClauseData<Self> { | ||
291 | clause | ||
292 | } | ||
293 | |||
294 | fn intern_program_clauses<E>( | ||
295 | &self, | ||
296 | data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>, | ||
297 | ) -> Result<Arc<[chalk_ir::ProgramClause<Self>]>, E> { | ||
298 | data.into_iter().collect() | ||
299 | } | ||
300 | |||
301 | fn program_clauses_data<'a>( | ||
302 | &self, | ||
303 | clauses: &'a Arc<[chalk_ir::ProgramClause<Self>]>, | ||
304 | ) -> &'a [chalk_ir::ProgramClause<Self>] { | ||
305 | &clauses | ||
306 | } | ||
307 | |||
308 | fn intern_quantified_where_clauses<E>( | ||
309 | &self, | ||
310 | data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>, | ||
311 | ) -> Result<Self::InternedQuantifiedWhereClauses, E> { | ||
312 | data.into_iter().collect() | ||
313 | } | ||
314 | |||
315 | fn quantified_where_clauses_data<'a>( | ||
316 | &self, | ||
317 | clauses: &'a Self::InternedQuantifiedWhereClauses, | ||
318 | ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] { | ||
319 | clauses | ||
320 | } | ||
321 | |||
322 | fn intern_generic_arg_kinds<E>( | ||
323 | &self, | ||
324 | data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>, | ||
325 | ) -> Result<Self::InternedVariableKinds, E> { | ||
326 | data.into_iter().collect() | ||
327 | } | ||
328 | |||
329 | fn variable_kinds_data<'a>( | ||
330 | &self, | ||
331 | parameter_kinds: &'a Self::InternedVariableKinds, | ||
332 | ) -> &'a [chalk_ir::VariableKind<Self>] { | ||
333 | ¶meter_kinds | ||
334 | } | ||
335 | |||
336 | fn intern_canonical_var_kinds<E>( | ||
337 | &self, | ||
338 | data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>, | ||
339 | ) -> Result<Self::InternedCanonicalVarKinds, E> { | ||
340 | data.into_iter().collect() | ||
341 | } | ||
342 | |||
343 | fn canonical_var_kinds_data<'a>( | ||
344 | &self, | ||
345 | canonical_var_kinds: &'a Self::InternedCanonicalVarKinds, | ||
346 | ) -> &'a [chalk_ir::CanonicalVarKind<Self>] { | ||
347 | &canonical_var_kinds | ||
348 | } | ||
349 | } | ||
350 | |||
351 | impl chalk_ir::interner::HasInterner for Interner { | ||
352 | type Interner = Self; | ||
353 | } | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs new file mode 100644 index 000000000..7082cb095 --- /dev/null +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs | |||
@@ -0,0 +1,701 @@ | |||
1 | //! This module contains the implementations of the `ToChalk` trait, which | ||
2 | //! handles conversion between our data types and their corresponding types in | ||
3 | //! Chalk (in both directions); plus some helper functions for more specialized | ||
4 | //! conversions. | ||
5 | |||
6 | use chalk_ir::{ | ||
7 | cast::Cast, fold::shift::Shift, interner::HasInterner, PlaceholderIndex, Scalar, TypeName, | ||
8 | UniverseIndex, | ||
9 | }; | ||
10 | |||
11 | use hir_def::{type_ref::Mutability, AssocContainerId, GenericDefId, Lookup, TypeAliasId}; | ||
12 | use ra_db::salsa::InternKey; | ||
13 | |||
14 | use crate::{ | ||
15 | db::HirDatabase, | ||
16 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, | ||
17 | traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, | ||
18 | ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, | ||
19 | Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, | ||
20 | }; | ||
21 | |||
22 | use super::interner::*; | ||
23 | use super::*; | ||
24 | |||
25 | impl ToChalk for Ty { | ||
26 | type Chalk = chalk_ir::Ty<Interner>; | ||
27 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { | ||
28 | match self { | ||
29 | Ty::Apply(apply_ty) => match apply_ty.ctor { | ||
30 | TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters), | ||
31 | TypeCtor::FnPtr { num_args: _ } => { | ||
32 | let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); | ||
33 | chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution }) | ||
34 | .intern(&Interner) | ||
35 | } | ||
36 | _ => { | ||
37 | let name = apply_ty.ctor.to_chalk(db); | ||
38 | let substitution = apply_ty.parameters.to_chalk(db); | ||
39 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
40 | } | ||
41 | }, | ||
42 | Ty::Projection(proj_ty) => { | ||
43 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); | ||
44 | let substitution = proj_ty.parameters.to_chalk(db); | ||
45 | chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { | ||
46 | associated_ty_id, | ||
47 | substitution, | ||
48 | }) | ||
49 | .cast(&Interner) | ||
50 | .intern(&Interner) | ||
51 | } | ||
52 | Ty::Placeholder(id) => { | ||
53 | let interned_id = db.intern_type_param_id(id); | ||
54 | PlaceholderIndex { | ||
55 | ui: UniverseIndex::ROOT, | ||
56 | idx: interned_id.as_intern_id().as_usize(), | ||
57 | } | ||
58 | .to_ty::<Interner>(&Interner) | ||
59 | } | ||
60 | Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner), | ||
61 | Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), | ||
62 | Ty::Dyn(predicates) => { | ||
63 | let where_clauses = chalk_ir::QuantifiedWhereClauses::from( | ||
64 | &Interner, | ||
65 | predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)), | ||
66 | ); | ||
67 | let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) }; | ||
68 | chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) | ||
69 | } | ||
70 | Ty::Opaque(_) | Ty::Unknown => { | ||
71 | let substitution = chalk_ir::Substitution::empty(&Interner); | ||
72 | let name = TypeName::Error; | ||
73 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self { | ||
78 | match chalk.data(&Interner).clone() { | ||
79 | chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name { | ||
80 | TypeName::Error => Ty::Unknown, | ||
81 | TypeName::Ref(m) => ref_from_chalk(db, m, apply_ty.substitution), | ||
82 | _ => { | ||
83 | let ctor = from_chalk(db, apply_ty.name); | ||
84 | let parameters = from_chalk(db, apply_ty.substitution); | ||
85 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
86 | } | ||
87 | }, | ||
88 | chalk_ir::TyData::Placeholder(idx) => { | ||
89 | assert_eq!(idx.ui, UniverseIndex::ROOT); | ||
90 | let interned_id = crate::db::GlobalTypeParamId::from_intern_id( | ||
91 | crate::salsa::InternId::from(idx.idx), | ||
92 | ); | ||
93 | Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) | ||
94 | } | ||
95 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Projection(proj)) => { | ||
96 | let associated_ty = from_chalk(db, proj.associated_ty_id); | ||
97 | let parameters = from_chalk(db, proj.substitution); | ||
98 | Ty::Projection(ProjectionTy { associated_ty, parameters }) | ||
99 | } | ||
100 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(), | ||
101 | chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => { | ||
102 | let parameters: Substs = from_chalk(db, substitution); | ||
103 | Ty::Apply(ApplicationTy { | ||
104 | ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16 }, | ||
105 | parameters, | ||
106 | }) | ||
107 | } | ||
108 | chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx), | ||
109 | chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, | ||
110 | chalk_ir::TyData::Dyn(where_clauses) => { | ||
111 | assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); | ||
112 | let predicates = where_clauses | ||
113 | .bounds | ||
114 | .skip_binders() | ||
115 | .iter(&Interner) | ||
116 | .map(|c| from_chalk(db, c.clone())) | ||
117 | .collect(); | ||
118 | Ty::Dyn(predicates) | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | const LIFETIME_PLACEHOLDER: PlaceholderIndex = | ||
125 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::MAX }; | ||
126 | |||
127 | /// We currently don't model lifetimes, but Chalk does. So, we have to insert a | ||
128 | /// fake lifetime here, because Chalks built-in logic may expect it to be there. | ||
129 | fn ref_to_chalk( | ||
130 | db: &dyn HirDatabase, | ||
131 | mutability: Mutability, | ||
132 | subst: Substs, | ||
133 | ) -> chalk_ir::Ty<Interner> { | ||
134 | let arg = subst[0].clone().to_chalk(db); | ||
135 | let lifetime = LIFETIME_PLACEHOLDER.to_lifetime(&Interner); | ||
136 | chalk_ir::ApplicationTy { | ||
137 | name: TypeName::Ref(mutability.to_chalk(db)), | ||
138 | substitution: chalk_ir::Substitution::from( | ||
139 | &Interner, | ||
140 | vec![lifetime.cast(&Interner), arg.cast(&Interner)], | ||
141 | ), | ||
142 | } | ||
143 | .intern(&Interner) | ||
144 | } | ||
145 | |||
146 | /// Here we remove the lifetime from the type we got from Chalk. | ||
147 | fn ref_from_chalk( | ||
148 | db: &dyn HirDatabase, | ||
149 | mutability: chalk_ir::Mutability, | ||
150 | subst: chalk_ir::Substitution<Interner>, | ||
151 | ) -> Ty { | ||
152 | let tys = subst | ||
153 | .iter(&Interner) | ||
154 | .filter_map(|p| Some(from_chalk(db, p.ty(&Interner)?.clone()))) | ||
155 | .collect(); | ||
156 | Ty::apply(TypeCtor::Ref(from_chalk(db, mutability)), Substs(tys)) | ||
157 | } | ||
158 | |||
159 | impl ToChalk for Substs { | ||
160 | type Chalk = chalk_ir::Substitution<Interner>; | ||
161 | |||
162 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> { | ||
163 | chalk_ir::Substitution::from(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db))) | ||
164 | } | ||
165 | |||
166 | fn from_chalk(db: &dyn HirDatabase, parameters: chalk_ir::Substitution<Interner>) -> Substs { | ||
167 | let tys = parameters | ||
168 | .iter(&Interner) | ||
169 | .map(|p| match p.ty(&Interner) { | ||
170 | Some(ty) => from_chalk(db, ty.clone()), | ||
171 | None => unimplemented!(), | ||
172 | }) | ||
173 | .collect(); | ||
174 | Substs(tys) | ||
175 | } | ||
176 | } | ||
177 | |||
178 | impl ToChalk for TraitRef { | ||
179 | type Chalk = chalk_ir::TraitRef<Interner>; | ||
180 | |||
181 | fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> { | ||
182 | let trait_id = self.trait_.to_chalk(db); | ||
183 | let substitution = self.substs.to_chalk(db); | ||
184 | chalk_ir::TraitRef { trait_id, substitution } | ||
185 | } | ||
186 | |||
187 | fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self { | ||
188 | let trait_ = from_chalk(db, trait_ref.trait_id); | ||
189 | let substs = from_chalk(db, trait_ref.substitution); | ||
190 | TraitRef { trait_, substs } | ||
191 | } | ||
192 | } | ||
193 | |||
194 | impl ToChalk for hir_def::TraitId { | ||
195 | type Chalk = TraitId; | ||
196 | |||
197 | fn to_chalk(self, _db: &dyn HirDatabase) -> TraitId { | ||
198 | chalk_ir::TraitId(self.as_intern_id()) | ||
199 | } | ||
200 | |||
201 | fn from_chalk(_db: &dyn HirDatabase, trait_id: TraitId) -> hir_def::TraitId { | ||
202 | InternKey::from_intern_id(trait_id.0) | ||
203 | } | ||
204 | } | ||
205 | |||
206 | impl ToChalk for TypeCtor { | ||
207 | type Chalk = TypeName<Interner>; | ||
208 | |||
209 | fn to_chalk(self, db: &dyn HirDatabase) -> TypeName<Interner> { | ||
210 | match self { | ||
211 | TypeCtor::AssociatedType(type_alias) => { | ||
212 | let type_id = type_alias.to_chalk(db); | ||
213 | TypeName::AssociatedType(type_id) | ||
214 | } | ||
215 | |||
216 | TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), | ||
217 | TypeCtor::Char => TypeName::Scalar(Scalar::Char), | ||
218 | TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)), | ||
219 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) => { | ||
220 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) | ||
221 | } | ||
222 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) => { | ||
223 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) | ||
224 | } | ||
225 | |||
226 | TypeCtor::Tuple { cardinality } => TypeName::Tuple(cardinality.into()), | ||
227 | TypeCtor::RawPtr(mutability) => TypeName::Raw(mutability.to_chalk(db)), | ||
228 | TypeCtor::Slice => TypeName::Slice, | ||
229 | TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)), | ||
230 | TypeCtor::Str => TypeName::Str, | ||
231 | TypeCtor::FnDef(callable_def) => { | ||
232 | let id = callable_def.to_chalk(db); | ||
233 | TypeName::FnDef(id) | ||
234 | } | ||
235 | TypeCtor::Int(Uncertain::Unknown) | ||
236 | | TypeCtor::Float(Uncertain::Unknown) | ||
237 | | TypeCtor::Adt(_) | ||
238 | | TypeCtor::Array | ||
239 | | TypeCtor::FnPtr { .. } | ||
240 | | TypeCtor::Never | ||
241 | | TypeCtor::Closure { .. } => { | ||
242 | // other TypeCtors get interned and turned into a chalk StructId | ||
243 | let struct_id = db.intern_type_ctor(self).into(); | ||
244 | TypeName::Adt(struct_id) | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | |||
249 | fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor { | ||
250 | match type_name { | ||
251 | TypeName::Adt(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), | ||
252 | TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), | ||
253 | TypeName::OpaqueType(_) => unreachable!(), | ||
254 | |||
255 | TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool, | ||
256 | TypeName::Scalar(Scalar::Char) => TypeCtor::Char, | ||
257 | TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { | ||
258 | signedness: Signedness::Signed, | ||
259 | bitness: bitness_from_chalk_int(int_ty), | ||
260 | })), | ||
261 | TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { | ||
262 | signedness: Signedness::Unsigned, | ||
263 | bitness: bitness_from_chalk_uint(uint_ty), | ||
264 | })), | ||
265 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => { | ||
266 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) | ||
267 | } | ||
268 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => { | ||
269 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) | ||
270 | } | ||
271 | TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 }, | ||
272 | TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)), | ||
273 | TypeName::Slice => TypeCtor::Slice, | ||
274 | TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)), | ||
275 | TypeName::Str => TypeCtor::Str, | ||
276 | |||
277 | TypeName::FnDef(fn_def_id) => { | ||
278 | let callable_def = from_chalk(db, fn_def_id); | ||
279 | TypeCtor::FnDef(callable_def) | ||
280 | } | ||
281 | |||
282 | TypeName::Error => { | ||
283 | // this should not be reached, since we don't represent TypeName::Error with TypeCtor | ||
284 | unreachable!() | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | } | ||
289 | |||
290 | fn bitness_from_chalk_uint(uint_ty: chalk_ir::UintTy) -> IntBitness { | ||
291 | use chalk_ir::UintTy; | ||
292 | |||
293 | match uint_ty { | ||
294 | UintTy::Usize => IntBitness::Xsize, | ||
295 | UintTy::U8 => IntBitness::X8, | ||
296 | UintTy::U16 => IntBitness::X16, | ||
297 | UintTy::U32 => IntBitness::X32, | ||
298 | UintTy::U64 => IntBitness::X64, | ||
299 | UintTy::U128 => IntBitness::X128, | ||
300 | } | ||
301 | } | ||
302 | |||
303 | fn bitness_from_chalk_int(int_ty: chalk_ir::IntTy) -> IntBitness { | ||
304 | use chalk_ir::IntTy; | ||
305 | |||
306 | match int_ty { | ||
307 | IntTy::Isize => IntBitness::Xsize, | ||
308 | IntTy::I8 => IntBitness::X8, | ||
309 | IntTy::I16 => IntBitness::X16, | ||
310 | IntTy::I32 => IntBitness::X32, | ||
311 | IntTy::I64 => IntBitness::X64, | ||
312 | IntTy::I128 => IntBitness::X128, | ||
313 | } | ||
314 | } | ||
315 | |||
316 | fn int_ty_to_chalk(int_ty: IntTy) -> Scalar { | ||
317 | use chalk_ir::{IntTy, UintTy}; | ||
318 | |||
319 | match int_ty.signedness { | ||
320 | Signedness::Signed => Scalar::Int(match int_ty.bitness { | ||
321 | IntBitness::Xsize => IntTy::Isize, | ||
322 | IntBitness::X8 => IntTy::I8, | ||
323 | IntBitness::X16 => IntTy::I16, | ||
324 | IntBitness::X32 => IntTy::I32, | ||
325 | IntBitness::X64 => IntTy::I64, | ||
326 | IntBitness::X128 => IntTy::I128, | ||
327 | }), | ||
328 | Signedness::Unsigned => Scalar::Uint(match int_ty.bitness { | ||
329 | IntBitness::Xsize => UintTy::Usize, | ||
330 | IntBitness::X8 => UintTy::U8, | ||
331 | IntBitness::X16 => UintTy::U16, | ||
332 | IntBitness::X32 => UintTy::U32, | ||
333 | IntBitness::X64 => UintTy::U64, | ||
334 | IntBitness::X128 => UintTy::U128, | ||
335 | }), | ||
336 | } | ||
337 | } | ||
338 | |||
339 | impl ToChalk for Mutability { | ||
340 | type Chalk = chalk_ir::Mutability; | ||
341 | fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk { | ||
342 | match self { | ||
343 | Mutability::Shared => chalk_ir::Mutability::Not, | ||
344 | Mutability::Mut => chalk_ir::Mutability::Mut, | ||
345 | } | ||
346 | } | ||
347 | fn from_chalk(_db: &dyn HirDatabase, chalk: Self::Chalk) -> Self { | ||
348 | match chalk { | ||
349 | chalk_ir::Mutability::Mut => Mutability::Mut, | ||
350 | chalk_ir::Mutability::Not => Mutability::Shared, | ||
351 | } | ||
352 | } | ||
353 | } | ||
354 | |||
355 | impl ToChalk for Impl { | ||
356 | type Chalk = ImplId; | ||
357 | |||
358 | fn to_chalk(self, db: &dyn HirDatabase) -> ImplId { | ||
359 | db.intern_chalk_impl(self).into() | ||
360 | } | ||
361 | |||
362 | fn from_chalk(db: &dyn HirDatabase, impl_id: ImplId) -> Impl { | ||
363 | db.lookup_intern_chalk_impl(impl_id.into()) | ||
364 | } | ||
365 | } | ||
366 | |||
367 | impl ToChalk for CallableDef { | ||
368 | type Chalk = FnDefId; | ||
369 | |||
370 | fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId { | ||
371 | db.intern_callable_def(self).into() | ||
372 | } | ||
373 | |||
374 | fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDef { | ||
375 | db.lookup_intern_callable_def(fn_def_id.into()) | ||
376 | } | ||
377 | } | ||
378 | |||
379 | impl ToChalk for TypeAliasId { | ||
380 | type Chalk = AssocTypeId; | ||
381 | |||
382 | fn to_chalk(self, _db: &dyn HirDatabase) -> AssocTypeId { | ||
383 | chalk_ir::AssocTypeId(self.as_intern_id()) | ||
384 | } | ||
385 | |||
386 | fn from_chalk(_db: &dyn HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId { | ||
387 | InternKey::from_intern_id(type_alias_id.0) | ||
388 | } | ||
389 | } | ||
390 | |||
391 | impl ToChalk for AssocTyValue { | ||
392 | type Chalk = AssociatedTyValueId; | ||
393 | |||
394 | fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValueId { | ||
395 | db.intern_assoc_ty_value(self).into() | ||
396 | } | ||
397 | |||
398 | fn from_chalk(db: &dyn HirDatabase, assoc_ty_value_id: AssociatedTyValueId) -> AssocTyValue { | ||
399 | db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into()) | ||
400 | } | ||
401 | } | ||
402 | |||
403 | impl ToChalk for GenericPredicate { | ||
404 | type Chalk = chalk_ir::QuantifiedWhereClause<Interner>; | ||
405 | |||
406 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> { | ||
407 | match self { | ||
408 | GenericPredicate::Implemented(trait_ref) => { | ||
409 | let chalk_trait_ref = trait_ref.to_chalk(db); | ||
410 | let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner); | ||
411 | make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0) | ||
412 | } | ||
413 | GenericPredicate::Projection(projection_pred) => { | ||
414 | let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner); | ||
415 | let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner); | ||
416 | let alias = chalk_ir::AliasTy::Projection(projection); | ||
417 | make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0) | ||
418 | } | ||
419 | GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), | ||
420 | } | ||
421 | } | ||
422 | |||
423 | fn from_chalk( | ||
424 | db: &dyn HirDatabase, | ||
425 | where_clause: chalk_ir::QuantifiedWhereClause<Interner>, | ||
426 | ) -> GenericPredicate { | ||
427 | // we don't produce any where clauses with binders and can't currently deal with them | ||
428 | match where_clause | ||
429 | .skip_binders() | ||
430 | .shifted_out(&Interner) | ||
431 | .expect("unexpected bound vars in where clause") | ||
432 | { | ||
433 | chalk_ir::WhereClause::Implemented(tr) => { | ||
434 | GenericPredicate::Implemented(from_chalk(db, tr)) | ||
435 | } | ||
436 | chalk_ir::WhereClause::AliasEq(projection_eq) => { | ||
437 | let projection_ty = from_chalk( | ||
438 | db, | ||
439 | match projection_eq.alias { | ||
440 | chalk_ir::AliasTy::Projection(p) => p, | ||
441 | _ => unimplemented!(), | ||
442 | }, | ||
443 | ); | ||
444 | let ty = from_chalk(db, projection_eq.ty); | ||
445 | GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty }) | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | |||
451 | impl ToChalk for ProjectionTy { | ||
452 | type Chalk = chalk_ir::ProjectionTy<Interner>; | ||
453 | |||
454 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> { | ||
455 | chalk_ir::ProjectionTy { | ||
456 | associated_ty_id: self.associated_ty.to_chalk(db), | ||
457 | substitution: self.parameters.to_chalk(db), | ||
458 | } | ||
459 | } | ||
460 | |||
461 | fn from_chalk( | ||
462 | db: &dyn HirDatabase, | ||
463 | projection_ty: chalk_ir::ProjectionTy<Interner>, | ||
464 | ) -> ProjectionTy { | ||
465 | ProjectionTy { | ||
466 | associated_ty: from_chalk(db, projection_ty.associated_ty_id), | ||
467 | parameters: from_chalk(db, projection_ty.substitution), | ||
468 | } | ||
469 | } | ||
470 | } | ||
471 | |||
472 | impl ToChalk for ProjectionPredicate { | ||
473 | type Chalk = chalk_ir::AliasEq<Interner>; | ||
474 | |||
475 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> { | ||
476 | chalk_ir::AliasEq { | ||
477 | alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)), | ||
478 | ty: self.ty.to_chalk(db), | ||
479 | } | ||
480 | } | ||
481 | |||
482 | fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self { | ||
483 | unimplemented!() | ||
484 | } | ||
485 | } | ||
486 | |||
487 | impl ToChalk for Obligation { | ||
488 | type Chalk = chalk_ir::DomainGoal<Interner>; | ||
489 | |||
490 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> { | ||
491 | match self { | ||
492 | Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner), | ||
493 | Obligation::Projection(pr) => pr.to_chalk(db).cast(&Interner), | ||
494 | } | ||
495 | } | ||
496 | |||
497 | fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self { | ||
498 | unimplemented!() | ||
499 | } | ||
500 | } | ||
501 | |||
502 | impl<T> ToChalk for Canonical<T> | ||
503 | where | ||
504 | T: ToChalk, | ||
505 | T::Chalk: HasInterner<Interner = Interner>, | ||
506 | { | ||
507 | type Chalk = chalk_ir::Canonical<T::Chalk>; | ||
508 | |||
509 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { | ||
510 | let parameter = chalk_ir::CanonicalVarKind::new( | ||
511 | chalk_ir::VariableKind::Ty, | ||
512 | chalk_ir::UniverseIndex::ROOT, | ||
513 | ); | ||
514 | let value = self.value.to_chalk(db); | ||
515 | chalk_ir::Canonical { | ||
516 | value, | ||
517 | binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]), | ||
518 | } | ||
519 | } | ||
520 | |||
521 | fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { | ||
522 | Canonical { | ||
523 | num_vars: canonical.binders.len(&Interner), | ||
524 | value: from_chalk(db, canonical.value), | ||
525 | } | ||
526 | } | ||
527 | } | ||
528 | |||
529 | impl ToChalk for Arc<TraitEnvironment> { | ||
530 | type Chalk = chalk_ir::Environment<Interner>; | ||
531 | |||
532 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Environment<Interner> { | ||
533 | let mut clauses = Vec::new(); | ||
534 | for pred in &self.predicates { | ||
535 | if pred.is_error() { | ||
536 | // for env, we just ignore errors | ||
537 | continue; | ||
538 | } | ||
539 | let program_clause: chalk_ir::ProgramClause<Interner> = | ||
540 | pred.clone().to_chalk(db).cast(&Interner); | ||
541 | clauses.push(program_clause.into_from_env_clause(&Interner)); | ||
542 | } | ||
543 | chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses) | ||
544 | } | ||
545 | |||
546 | fn from_chalk( | ||
547 | _db: &dyn HirDatabase, | ||
548 | _env: chalk_ir::Environment<Interner>, | ||
549 | ) -> Arc<TraitEnvironment> { | ||
550 | unimplemented!() | ||
551 | } | ||
552 | } | ||
553 | |||
554 | impl<T: ToChalk> ToChalk for InEnvironment<T> | ||
555 | where | ||
556 | T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>, | ||
557 | { | ||
558 | type Chalk = chalk_ir::InEnvironment<T::Chalk>; | ||
559 | |||
560 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { | ||
561 | chalk_ir::InEnvironment { | ||
562 | environment: self.environment.to_chalk(db), | ||
563 | goal: self.value.to_chalk(db), | ||
564 | } | ||
565 | } | ||
566 | |||
567 | fn from_chalk( | ||
568 | db: &dyn HirDatabase, | ||
569 | in_env: chalk_ir::InEnvironment<T::Chalk>, | ||
570 | ) -> InEnvironment<T> { | ||
571 | InEnvironment { | ||
572 | environment: from_chalk(db, in_env.environment), | ||
573 | value: from_chalk(db, in_env.goal), | ||
574 | } | ||
575 | } | ||
576 | } | ||
577 | |||
578 | impl ToChalk for builtin::BuiltinImplData { | ||
579 | type Chalk = ImplDatum; | ||
580 | |||
581 | fn to_chalk(self, db: &dyn HirDatabase) -> ImplDatum { | ||
582 | let impl_type = chalk_rust_ir::ImplType::External; | ||
583 | let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect(); | ||
584 | |||
585 | let impl_datum_bound = | ||
586 | chalk_rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses }; | ||
587 | let associated_ty_value_ids = | ||
588 | self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect(); | ||
589 | chalk_rust_ir::ImplDatum { | ||
590 | binders: make_binders(impl_datum_bound, self.num_vars), | ||
591 | impl_type, | ||
592 | polarity: chalk_rust_ir::Polarity::Positive, | ||
593 | associated_ty_value_ids, | ||
594 | } | ||
595 | } | ||
596 | |||
597 | fn from_chalk(_db: &dyn HirDatabase, _data: ImplDatum) -> Self { | ||
598 | unimplemented!() | ||
599 | } | ||
600 | } | ||
601 | |||
602 | impl ToChalk for builtin::BuiltinImplAssocTyValueData { | ||
603 | type Chalk = AssociatedTyValue; | ||
604 | |||
605 | fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue { | ||
606 | let ty = self.value.to_chalk(db); | ||
607 | let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty }; | ||
608 | |||
609 | chalk_rust_ir::AssociatedTyValue { | ||
610 | associated_ty_id: self.assoc_ty_id.to_chalk(db), | ||
611 | impl_id: self.impl_.to_chalk(db), | ||
612 | value: make_binders(value_bound, self.num_vars), | ||
613 | } | ||
614 | } | ||
615 | |||
616 | fn from_chalk( | ||
617 | _db: &dyn HirDatabase, | ||
618 | _data: AssociatedTyValue, | ||
619 | ) -> builtin::BuiltinImplAssocTyValueData { | ||
620 | unimplemented!() | ||
621 | } | ||
622 | } | ||
623 | |||
624 | pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> | ||
625 | where | ||
626 | T: HasInterner<Interner = Interner>, | ||
627 | { | ||
628 | chalk_ir::Binders::new( | ||
629 | chalk_ir::VariableKinds::from( | ||
630 | &Interner, | ||
631 | std::iter::repeat(chalk_ir::VariableKind::Ty).take(num_vars), | ||
632 | ), | ||
633 | value, | ||
634 | ) | ||
635 | } | ||
636 | |||
637 | pub(super) fn convert_where_clauses( | ||
638 | db: &dyn HirDatabase, | ||
639 | def: GenericDefId, | ||
640 | substs: &Substs, | ||
641 | ) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> { | ||
642 | let generic_predicates = db.generic_predicates(def); | ||
643 | let mut result = Vec::with_capacity(generic_predicates.len()); | ||
644 | for pred in generic_predicates.iter() { | ||
645 | if pred.value.is_error() { | ||
646 | // skip errored predicates completely | ||
647 | continue; | ||
648 | } | ||
649 | result.push(pred.clone().subst(substs).to_chalk(db)); | ||
650 | } | ||
651 | result | ||
652 | } | ||
653 | |||
654 | pub(super) fn generic_predicate_to_inline_bound( | ||
655 | db: &dyn HirDatabase, | ||
656 | pred: &GenericPredicate, | ||
657 | self_ty: &Ty, | ||
658 | ) -> Option<chalk_rust_ir::InlineBound<Interner>> { | ||
659 | // An InlineBound is like a GenericPredicate, except the self type is left out. | ||
660 | // We don't have a special type for this, but Chalk does. | ||
661 | match pred { | ||
662 | GenericPredicate::Implemented(trait_ref) => { | ||
663 | if &trait_ref.substs[0] != self_ty { | ||
664 | // we can only convert predicates back to type bounds if they | ||
665 | // have the expected self type | ||
666 | return None; | ||
667 | } | ||
668 | let args_no_self = trait_ref.substs[1..] | ||
669 | .iter() | ||
670 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
671 | .collect(); | ||
672 | let trait_bound = | ||
673 | chalk_rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; | ||
674 | Some(chalk_rust_ir::InlineBound::TraitBound(trait_bound)) | ||
675 | } | ||
676 | GenericPredicate::Projection(proj) => { | ||
677 | if &proj.projection_ty.parameters[0] != self_ty { | ||
678 | return None; | ||
679 | } | ||
680 | let trait_ = match proj.projection_ty.associated_ty.lookup(db.upcast()).container { | ||
681 | AssocContainerId::TraitId(t) => t, | ||
682 | _ => panic!("associated type not in trait"), | ||
683 | }; | ||
684 | let args_no_self = proj.projection_ty.parameters[1..] | ||
685 | .iter() | ||
686 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
687 | .collect(); | ||
688 | let alias_eq_bound = chalk_rust_ir::AliasEqBound { | ||
689 | value: proj.ty.clone().to_chalk(db), | ||
690 | trait_bound: chalk_rust_ir::TraitBound { | ||
691 | trait_id: trait_.to_chalk(db), | ||
692 | args_no_self, | ||
693 | }, | ||
694 | associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db), | ||
695 | parameters: Vec::new(), // FIXME we don't support generic associated types yet | ||
696 | }; | ||
697 | Some(chalk_rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) | ||
698 | } | ||
699 | GenericPredicate::Error => None, | ||
700 | } | ||
701 | } | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs index 4867cb17e..d88828c7c 100644 --- a/crates/ra_hir_ty/src/traits/chalk/tls.rs +++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Implementation of Chalk debug helper functions using TLS. | 1 | //! Implementation of Chalk debug helper functions using TLS. |
2 | use std::fmt; | 2 | use std::fmt; |
3 | 3 | ||
4 | use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName}; | 4 | use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication, TypeName}; |
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | 6 | ||
7 | use super::{from_chalk, Interner}; | 7 | use super::{from_chalk, Interner}; |
@@ -15,10 +15,10 @@ pub struct DebugContext<'a>(&'a (dyn HirDatabase + 'a)); | |||
15 | impl DebugContext<'_> { | 15 | impl DebugContext<'_> { |
16 | pub fn debug_struct_id( | 16 | pub fn debug_struct_id( |
17 | &self, | 17 | &self, |
18 | id: super::StructId, | 18 | id: super::AdtId, |
19 | f: &mut fmt::Formatter<'_>, | 19 | f: &mut fmt::Formatter<'_>, |
20 | ) -> Result<(), fmt::Error> { | 20 | ) -> Result<(), fmt::Error> { |
21 | let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Struct(id)); | 21 | let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Adt(id)); |
22 | match type_ctor { | 22 | match type_ctor { |
23 | TypeCtor::Bool => write!(f, "bool")?, | 23 | TypeCtor::Bool => write!(f, "bool")?, |
24 | TypeCtor::Char => write!(f, "char")?, | 24 | TypeCtor::Char => write!(f, "char")?, |
@@ -188,9 +188,9 @@ impl DebugContext<'_> { | |||
188 | write!(fmt, "{:?}", lifetime.data(&Interner)) | 188 | write!(fmt, "{:?}", lifetime.data(&Interner)) |
189 | } | 189 | } |
190 | 190 | ||
191 | pub fn debug_parameter( | 191 | pub fn debug_generic_arg( |
192 | &self, | 192 | &self, |
193 | parameter: &Parameter<Interner>, | 193 | parameter: &GenericArg<Interner>, |
194 | fmt: &mut fmt::Formatter<'_>, | 194 | fmt: &mut fmt::Formatter<'_>, |
195 | ) -> Result<(), fmt::Error> { | 195 | ) -> Result<(), fmt::Error> { |
196 | write!(fmt, "{:?}", parameter.data(&Interner).inner_debug()) | 196 | write!(fmt, "{:?}", parameter.data(&Interner).inner_debug()) |
@@ -244,6 +244,79 @@ impl DebugContext<'_> { | |||
244 | ) -> Result<(), fmt::Error> { | 244 | ) -> Result<(), fmt::Error> { |
245 | write!(fmt, "{:?}", separator_trait_ref.debug(&Interner)) | 245 | write!(fmt, "{:?}", separator_trait_ref.debug(&Interner)) |
246 | } | 246 | } |
247 | |||
248 | pub fn debug_fn_def_id( | ||
249 | &self, | ||
250 | fn_def_id: chalk_ir::FnDefId<Interner>, | ||
251 | fmt: &mut fmt::Formatter<'_>, | ||
252 | ) -> Result<(), fmt::Error> { | ||
253 | let def: CallableDef = from_chalk(self.0, fn_def_id); | ||
254 | let name = match def { | ||
255 | CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(), | ||
256 | CallableDef::StructId(s) => self.0.struct_data(s).name.clone(), | ||
257 | CallableDef::EnumVariantId(e) => { | ||
258 | let enum_data = self.0.enum_data(e.parent); | ||
259 | enum_data.variants[e.local_id].name.clone() | ||
260 | } | ||
261 | }; | ||
262 | match def { | ||
263 | CallableDef::FunctionId(_) => write!(fmt, "{{fn {}}}", name), | ||
264 | CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { | ||
265 | write!(fmt, "{{ctor {}}}", name) | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | |||
270 | pub fn debug_const( | ||
271 | &self, | ||
272 | _constant: &chalk_ir::Const<Interner>, | ||
273 | fmt: &mut fmt::Formatter<'_>, | ||
274 | ) -> fmt::Result { | ||
275 | write!(fmt, "const") | ||
276 | } | ||
277 | |||
278 | pub fn debug_variable_kinds( | ||
279 | &self, | ||
280 | variable_kinds: &chalk_ir::VariableKinds<Interner>, | ||
281 | fmt: &mut fmt::Formatter<'_>, | ||
282 | ) -> fmt::Result { | ||
283 | write!(fmt, "{:?}", variable_kinds.as_slice(&Interner)) | ||
284 | } | ||
285 | pub fn debug_variable_kinds_with_angles( | ||
286 | &self, | ||
287 | variable_kinds: &chalk_ir::VariableKinds<Interner>, | ||
288 | fmt: &mut fmt::Formatter<'_>, | ||
289 | ) -> fmt::Result { | ||
290 | write!(fmt, "{:?}", variable_kinds.inner_debug(&Interner)) | ||
291 | } | ||
292 | pub fn debug_canonical_var_kinds( | ||
293 | &self, | ||
294 | canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Interner>, | ||
295 | fmt: &mut fmt::Formatter<'_>, | ||
296 | ) -> fmt::Result { | ||
297 | write!(fmt, "{:?}", canonical_var_kinds.as_slice(&Interner)) | ||
298 | } | ||
299 | pub fn debug_program_clause( | ||
300 | &self, | ||
301 | clause: &chalk_ir::ProgramClause<Interner>, | ||
302 | fmt: &mut fmt::Formatter<'_>, | ||
303 | ) -> fmt::Result { | ||
304 | write!(fmt, "{:?}", clause.data(&Interner)) | ||
305 | } | ||
306 | pub fn debug_program_clauses( | ||
307 | &self, | ||
308 | clauses: &chalk_ir::ProgramClauses<Interner>, | ||
309 | fmt: &mut fmt::Formatter<'_>, | ||
310 | ) -> fmt::Result { | ||
311 | write!(fmt, "{:?}", clauses.as_slice(&Interner)) | ||
312 | } | ||
313 | pub fn debug_quantified_where_clauses( | ||
314 | &self, | ||
315 | clauses: &chalk_ir::QuantifiedWhereClauses<Interner>, | ||
316 | fmt: &mut fmt::Formatter<'_>, | ||
317 | ) -> fmt::Result { | ||
318 | write!(fmt, "{:?}", clauses.as_slice(&Interner)) | ||
319 | } | ||
247 | } | 320 | } |
248 | 321 | ||
249 | mod unsafe_tls { | 322 | mod unsafe_tls { |
diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs index 85d1f0cb1..defd8176f 100644 --- a/crates/ra_ide/src/call_hierarchy.rs +++ b/crates/ra_ide/src/call_hierarchy.rs | |||
@@ -246,6 +246,35 @@ mod tests { | |||
246 | } | 246 | } |
247 | 247 | ||
248 | #[test] | 248 | #[test] |
249 | fn test_call_hierarchy_in_tests_mod() { | ||
250 | check_hierarchy( | ||
251 | r#" | ||
252 | //- /lib.rs cfg:test | ||
253 | fn callee() {} | ||
254 | fn caller1() { | ||
255 | call<|>ee(); | ||
256 | } | ||
257 | |||
258 | #[cfg(test)] | ||
259 | mod tests { | ||
260 | use super::*; | ||
261 | |||
262 | #[test] | ||
263 | fn test_caller() { | ||
264 | callee(); | ||
265 | } | ||
266 | } | ||
267 | "#, | ||
268 | "callee FN_DEF FileId(1) 0..14 3..9", | ||
269 | &[ | ||
270 | "caller1 FN_DEF FileId(1) 15..45 18..25 : [34..40]", | ||
271 | "test_caller FN_DEF FileId(1) 93..147 108..119 : [132..138]", | ||
272 | ], | ||
273 | &[], | ||
274 | ); | ||
275 | } | ||
276 | |||
277 | #[test] | ||
249 | fn test_call_hierarchy_in_different_files() { | 278 | fn test_call_hierarchy_in_different_files() { |
250 | check_hierarchy( | 279 | check_hierarchy( |
251 | r#" | 280 | r#" |
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 6021f7279..cfb7c1e38 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs | |||
@@ -63,8 +63,8 @@ impl fmt::Debug for CompletionItem { | |||
63 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 63 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
64 | let mut s = f.debug_struct("CompletionItem"); | 64 | let mut s = f.debug_struct("CompletionItem"); |
65 | s.field("label", &self.label()).field("source_range", &self.source_range()); | 65 | s.field("label", &self.label()).field("source_range", &self.source_range()); |
66 | if self.text_edit().as_indels().len() == 1 { | 66 | if self.text_edit().len() == 1 { |
67 | let atom = &self.text_edit().as_indels()[0]; | 67 | let atom = &self.text_edit().iter().next().unwrap(); |
68 | s.field("delete", &atom.delete); | 68 | s.field("delete", &atom.delete); |
69 | s.field("insert", &atom.insert); | 69 | s.field("insert", &atom.insert); |
70 | } else { | 70 | } else { |
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 54c2bcc09..3d83c0f71 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -21,7 +21,7 @@ use ra_syntax::{ | |||
21 | }; | 21 | }; |
22 | use ra_text_edit::{TextEdit, TextEditBuilder}; | 22 | use ra_text_edit::{TextEdit, TextEditBuilder}; |
23 | 23 | ||
24 | use crate::{Diagnostic, FileId, FileSystemEdit, SourceChange, SourceFileEdit}; | 24 | use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceChange, SourceFileEdit}; |
25 | 25 | ||
26 | #[derive(Debug, Copy, Clone)] | 26 | #[derive(Debug, Copy, Clone)] |
27 | pub enum Severity { | 27 | pub enum Severity { |
@@ -63,8 +63,8 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
63 | .parent() | 63 | .parent() |
64 | .unwrap_or_else(|| RelativePath::new("")) | 64 | .unwrap_or_else(|| RelativePath::new("")) |
65 | .join(&d.candidate); | 65 | .join(&d.candidate); |
66 | let create_file = FileSystemEdit::CreateFile { source_root, path }; | 66 | let fix = |
67 | let fix = SourceChange::file_system_edit("Create module", create_file); | 67 | Fix::new("Create module", FileSystemEdit::CreateFile { source_root, path }.into()); |
68 | res.borrow_mut().push(Diagnostic { | 68 | res.borrow_mut().push(Diagnostic { |
69 | range: sema.diagnostics_range(d).range, | 69 | range: sema.diagnostics_range(d).range, |
70 | message: d.message(), | 70 | message: d.message(), |
@@ -88,14 +88,12 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
88 | field_list = field_list.append_field(&field); | 88 | field_list = field_list.append_field(&field); |
89 | } | 89 | } |
90 | 90 | ||
91 | let mut builder = TextEditBuilder::default(); | 91 | let edit = { |
92 | algo::diff(&d.ast(db).syntax(), &field_list.syntax()).into_text_edit(&mut builder); | 92 | let mut builder = TextEditBuilder::default(); |
93 | 93 | algo::diff(&d.ast(db).syntax(), &field_list.syntax()).into_text_edit(&mut builder); | |
94 | Some(SourceChange::source_file_edit_from( | 94 | builder.finish() |
95 | "Fill struct fields", | 95 | }; |
96 | file_id, | 96 | Some(Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into())) |
97 | builder.finish(), | ||
98 | )) | ||
99 | }; | 97 | }; |
100 | 98 | ||
101 | res.borrow_mut().push(Diagnostic { | 99 | res.borrow_mut().push(Diagnostic { |
@@ -117,7 +115,8 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
117 | let node = d.ast(db); | 115 | let node = d.ast(db); |
118 | let replacement = format!("Ok({})", node.syntax()); | 116 | let replacement = format!("Ok({})", node.syntax()); |
119 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); | 117 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); |
120 | let fix = SourceChange::source_file_edit_from("Wrap with ok", file_id, edit); | 118 | let source_change = SourceChange::source_file_edit_from(file_id, edit); |
119 | let fix = Fix::new("Wrap with ok", source_change); | ||
121 | res.borrow_mut().push(Diagnostic { | 120 | res.borrow_mut().push(Diagnostic { |
122 | range: sema.diagnostics_range(d).range, | 121 | range: sema.diagnostics_range(d).range, |
123 | message: d.message(), | 122 | message: d.message(), |
@@ -154,9 +153,9 @@ fn check_unnecessary_braces_in_use_statement( | |||
154 | range, | 153 | range, |
155 | message: "Unnecessary braces in use statement".to_string(), | 154 | message: "Unnecessary braces in use statement".to_string(), |
156 | severity: Severity::WeakWarning, | 155 | severity: Severity::WeakWarning, |
157 | fix: Some(SourceChange::source_file_edit( | 156 | fix: Some(Fix::new( |
158 | "Remove unnecessary braces", | 157 | "Remove unnecessary braces", |
159 | SourceFileEdit { file_id, edit }, | 158 | SourceFileEdit { file_id, edit }.into(), |
160 | )), | 159 | )), |
161 | }); | 160 | }); |
162 | } | 161 | } |
@@ -198,9 +197,9 @@ fn check_struct_shorthand_initialization( | |||
198 | range: record_field.syntax().text_range(), | 197 | range: record_field.syntax().text_range(), |
199 | message: "Shorthand struct initialization".to_string(), | 198 | message: "Shorthand struct initialization".to_string(), |
200 | severity: Severity::WeakWarning, | 199 | severity: Severity::WeakWarning, |
201 | fix: Some(SourceChange::source_file_edit( | 200 | fix: Some(Fix::new( |
202 | "Use struct shorthand initialization", | 201 | "Use struct shorthand initialization", |
203 | SourceFileEdit { file_id, edit }, | 202 | SourceFileEdit { file_id, edit }.into(), |
204 | )), | 203 | )), |
205 | }); | 204 | }); |
206 | } | 205 | } |
@@ -240,7 +239,7 @@ mod tests { | |||
240 | let diagnostic = | 239 | let diagnostic = |
241 | diagnostics.pop().unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before)); | 240 | diagnostics.pop().unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before)); |
242 | let mut fix = diagnostic.fix.unwrap(); | 241 | let mut fix = diagnostic.fix.unwrap(); |
243 | let edit = fix.source_file_edits.pop().unwrap().edit; | 242 | let edit = fix.source_change.source_file_edits.pop().unwrap().edit; |
244 | let actual = { | 243 | let actual = { |
245 | let mut actual = before.to_string(); | 244 | let mut actual = before.to_string(); |
246 | edit.apply(&mut actual); | 245 | edit.apply(&mut actual); |
@@ -258,7 +257,7 @@ mod tests { | |||
258 | let (analysis, file_position) = analysis_and_position(fixture); | 257 | let (analysis, file_position) = analysis_and_position(fixture); |
259 | let diagnostic = analysis.diagnostics(file_position.file_id).unwrap().pop().unwrap(); | 258 | let diagnostic = analysis.diagnostics(file_position.file_id).unwrap().pop().unwrap(); |
260 | let mut fix = diagnostic.fix.unwrap(); | 259 | let mut fix = diagnostic.fix.unwrap(); |
261 | let edit = fix.source_file_edits.pop().unwrap().edit; | 260 | let edit = fix.source_change.source_file_edits.pop().unwrap().edit; |
262 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); | 261 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); |
263 | let actual = { | 262 | let actual = { |
264 | let mut actual = target_file_contents.to_string(); | 263 | let mut actual = target_file_contents.to_string(); |
@@ -295,7 +294,7 @@ mod tests { | |||
295 | let (analysis, file_id) = single_file(before); | 294 | let (analysis, file_id) = single_file(before); |
296 | let diagnostic = analysis.diagnostics(file_id).unwrap().pop().unwrap(); | 295 | let diagnostic = analysis.diagnostics(file_id).unwrap().pop().unwrap(); |
297 | let mut fix = diagnostic.fix.unwrap(); | 296 | let mut fix = diagnostic.fix.unwrap(); |
298 | let edit = fix.source_file_edits.pop().unwrap().edit; | 297 | let edit = fix.source_change.source_file_edits.pop().unwrap().edit; |
299 | let actual = { | 298 | let actual = { |
300 | let mut actual = before.to_string(); | 299 | let mut actual = before.to_string(); |
301 | edit.apply(&mut actual); | 300 | edit.apply(&mut actual); |
@@ -616,23 +615,24 @@ mod tests { | |||
616 | Diagnostic { | 615 | Diagnostic { |
617 | message: "unresolved module", | 616 | message: "unresolved module", |
618 | range: 0..8, | 617 | range: 0..8, |
618 | severity: Error, | ||
619 | fix: Some( | 619 | fix: Some( |
620 | SourceChange { | 620 | Fix { |
621 | label: "Create module", | 621 | label: "Create module", |
622 | source_file_edits: [], | 622 | source_change: SourceChange { |
623 | file_system_edits: [ | 623 | source_file_edits: [], |
624 | CreateFile { | 624 | file_system_edits: [ |
625 | source_root: SourceRootId( | 625 | CreateFile { |
626 | 0, | 626 | source_root: SourceRootId( |
627 | ), | 627 | 0, |
628 | path: "foo.rs", | 628 | ), |
629 | }, | 629 | path: "foo.rs", |
630 | ], | 630 | }, |
631 | cursor_position: None, | 631 | ], |
632 | is_snippet: false, | 632 | is_snippet: false, |
633 | }, | ||
633 | }, | 634 | }, |
634 | ), | 635 | ), |
635 | severity: Error, | ||
636 | }, | 636 | }, |
637 | ] | 637 | ] |
638 | "###); | 638 | "###); |
@@ -666,30 +666,31 @@ mod tests { | |||
666 | Diagnostic { | 666 | Diagnostic { |
667 | message: "Missing structure fields:\n- b", | 667 | message: "Missing structure fields:\n- b", |
668 | range: 224..233, | 668 | range: 224..233, |
669 | severity: Error, | ||
669 | fix: Some( | 670 | fix: Some( |
670 | SourceChange { | 671 | Fix { |
671 | label: "Fill struct fields", | 672 | label: "Fill struct fields", |
672 | source_file_edits: [ | 673 | source_change: SourceChange { |
673 | SourceFileEdit { | 674 | source_file_edits: [ |
674 | file_id: FileId( | 675 | SourceFileEdit { |
675 | 1, | 676 | file_id: FileId( |
676 | ), | 677 | 1, |
677 | edit: TextEdit { | 678 | ), |
678 | indels: [ | 679 | edit: TextEdit { |
679 | Indel { | 680 | indels: [ |
680 | insert: "{a:42, b: ()}", | 681 | Indel { |
681 | delete: 3..9, | 682 | insert: "{a:42, b: ()}", |
682 | }, | 683 | delete: 3..9, |
683 | ], | 684 | }, |
685 | ], | ||
686 | }, | ||
684 | }, | 687 | }, |
685 | }, | 688 | ], |
686 | ], | 689 | file_system_edits: [], |
687 | file_system_edits: [], | 690 | is_snippet: false, |
688 | cursor_position: None, | 691 | }, |
689 | is_snippet: false, | ||
690 | }, | 692 | }, |
691 | ), | 693 | ), |
692 | severity: Error, | ||
693 | }, | 694 | }, |
694 | ] | 695 | ] |
695 | "###); | 696 | "###); |
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs index 722092de9..827c094e7 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs | |||
@@ -79,16 +79,17 @@ pub(crate) fn rust_code_markup_with_doc( | |||
79 | doc: Option<&str>, | 79 | doc: Option<&str>, |
80 | mod_path: Option<&str>, | 80 | mod_path: Option<&str>, |
81 | ) -> String { | 81 | ) -> String { |
82 | let mut buf = "```rust\n".to_owned(); | 82 | let mut buf = String::new(); |
83 | 83 | ||
84 | if let Some(mod_path) = mod_path { | 84 | if let Some(mod_path) = mod_path { |
85 | if !mod_path.is_empty() { | 85 | if !mod_path.is_empty() { |
86 | format_to!(buf, "{}\n", mod_path); | 86 | format_to!(buf, "```rust\n{}\n```\n\n", mod_path); |
87 | } | 87 | } |
88 | } | 88 | } |
89 | format_to!(buf, "{}\n```", code); | 89 | format_to!(buf, "```rust\n{}\n```", code); |
90 | 90 | ||
91 | if let Some(doc) = doc { | 91 | if let Some(doc) = doc { |
92 | format_to!(buf, "\n___"); | ||
92 | format_to!(buf, "\n\n{}", doc); | 93 | format_to!(buf, "\n\n{}", doc); |
93 | } | 94 | } |
94 | 95 | ||
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index befa977c7..3e721dcca 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -405,7 +405,7 @@ mod tests { | |||
405 | }; | 405 | }; |
406 | } | 406 | } |
407 | "#, | 407 | "#, |
408 | &["Foo\nfield_a: u32"], | 408 | &["Foo\n```\n\n```rust\nfield_a: u32"], |
409 | ); | 409 | ); |
410 | 410 | ||
411 | // Hovering over the field in the definition | 411 | // Hovering over the field in the definition |
@@ -422,7 +422,7 @@ mod tests { | |||
422 | }; | 422 | }; |
423 | } | 423 | } |
424 | "#, | 424 | "#, |
425 | &["Foo\nfield_a: u32"], | 425 | &["Foo\n```\n\n```rust\nfield_a: u32"], |
426 | ); | 426 | ); |
427 | } | 427 | } |
428 | 428 | ||
@@ -475,7 +475,7 @@ fn main() { | |||
475 | ", | 475 | ", |
476 | ); | 476 | ); |
477 | let hover = analysis.hover(position).unwrap().unwrap(); | 477 | let hover = analysis.hover(position).unwrap().unwrap(); |
478 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\nSome")); | 478 | assert_eq!(trim_markup_opt(hover.info.first()), Some("Option\n```\n\n```rust\nSome")); |
479 | 479 | ||
480 | let (analysis, position) = single_file_with_position( | 480 | let (analysis, position) = single_file_with_position( |
481 | " | 481 | " |
@@ -503,8 +503,12 @@ fn main() { | |||
503 | "#, | 503 | "#, |
504 | &[" | 504 | &[" |
505 | Option | 505 | Option |
506 | ``` | ||
507 | |||
508 | ```rust | ||
506 | None | 509 | None |
507 | ``` | 510 | ``` |
511 | ___ | ||
508 | 512 | ||
509 | The None variant | 513 | The None variant |
510 | " | 514 | " |
@@ -524,8 +528,12 @@ The None variant | |||
524 | "#, | 528 | "#, |
525 | &[" | 529 | &[" |
526 | Option | 530 | Option |
531 | ``` | ||
532 | |||
533 | ```rust | ||
527 | Some | 534 | Some |
528 | ``` | 535 | ``` |
536 | ___ | ||
529 | 537 | ||
530 | The Some variant | 538 | The Some variant |
531 | " | 539 | " |
@@ -606,7 +614,10 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
606 | ", | 614 | ", |
607 | ); | 615 | ); |
608 | let hover = analysis.hover(position).unwrap().unwrap(); | 616 | let hover = analysis.hover(position).unwrap().unwrap(); |
609 | assert_eq!(trim_markup_opt(hover.info.first()), Some("wrapper::Thing\nfn new() -> Thing")); | 617 | assert_eq!( |
618 | trim_markup_opt(hover.info.first()), | ||
619 | Some("wrapper::Thing\n```\n\n```rust\nfn new() -> Thing") | ||
620 | ); | ||
610 | } | 621 | } |
611 | 622 | ||
612 | #[test] | 623 | #[test] |
@@ -882,7 +893,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
882 | fo<|>o(); | 893 | fo<|>o(); |
883 | } | 894 | } |
884 | ", | 895 | ", |
885 | &["fn foo()\n```\n\n<- `\u{3000}` here"], | 896 | &["fn foo()\n```\n___\n\n<- `\u{3000}` here"], |
886 | ); | 897 | ); |
887 | } | 898 | } |
888 | 899 | ||
diff --git a/crates/ra_ide/src/join_lines.rs b/crates/ra_ide/src/join_lines.rs index d3af780c4..af1ade8a1 100644 --- a/crates/ra_ide/src/join_lines.rs +++ b/crates/ra_ide/src/join_lines.rs | |||
@@ -166,16 +166,28 @@ fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { | |||
166 | 166 | ||
167 | #[cfg(test)] | 167 | #[cfg(test)] |
168 | mod tests { | 168 | mod tests { |
169 | use crate::test_utils::{assert_eq_text, check_action, extract_range}; | 169 | use ra_syntax::SourceFile; |
170 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; | ||
170 | 171 | ||
171 | use super::*; | 172 | use super::*; |
172 | 173 | ||
173 | fn check_join_lines(before: &str, after: &str) { | 174 | fn check_join_lines(before: &str, after: &str) { |
174 | check_action(before, after, |file, offset| { | 175 | let (before_cursor_pos, before) = extract_offset(before); |
175 | let range = TextRange::empty(offset); | 176 | let file = SourceFile::parse(&before).ok().unwrap(); |
176 | let res = join_lines(file, range); | 177 | |
177 | Some(res) | 178 | let range = TextRange::empty(before_cursor_pos); |
178 | }) | 179 | let result = join_lines(&file, range); |
180 | |||
181 | let actual = { | ||
182 | let mut actual = before.to_string(); | ||
183 | result.apply(&mut actual); | ||
184 | actual | ||
185 | }; | ||
186 | let actual_cursor_pos = result | ||
187 | .apply_to_offset(before_cursor_pos) | ||
188 | .expect("cursor position is affected by the edit"); | ||
189 | let actual = add_cursor(&actual, actual_cursor_pos); | ||
190 | assert_eq_text!(after, &actual); | ||
179 | } | 191 | } |
180 | 192 | ||
181 | #[test] | 193 | #[test] |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 83cb498f7..d983cd910 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -42,9 +42,6 @@ mod inlay_hints; | |||
42 | mod expand_macro; | 42 | mod expand_macro; |
43 | mod ssr; | 43 | mod ssr; |
44 | 44 | ||
45 | #[cfg(test)] | ||
46 | mod test_utils; | ||
47 | |||
48 | use std::sync::Arc; | 45 | use std::sync::Arc; |
49 | 46 | ||
50 | use ra_cfg::CfgOptions; | 47 | use ra_cfg::CfgOptions; |
@@ -87,12 +84,12 @@ pub use ra_db::{ | |||
87 | pub use ra_ide_db::{ | 84 | pub use ra_ide_db::{ |
88 | change::{AnalysisChange, LibraryData}, | 85 | change::{AnalysisChange, LibraryData}, |
89 | line_index::{LineCol, LineIndex}, | 86 | line_index::{LineCol, LineIndex}, |
90 | line_index_utils::translate_offset_with_edit, | ||
91 | search::SearchScope, | 87 | search::SearchScope, |
92 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, | 88 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, |
93 | symbol_index::Query, | 89 | symbol_index::Query, |
94 | RootDatabase, | 90 | RootDatabase, |
95 | }; | 91 | }; |
92 | pub use ra_text_edit::{Indel, TextEdit}; | ||
96 | 93 | ||
97 | pub type Cancelable<T> = Result<T, Canceled>; | 94 | pub type Cancelable<T> = Result<T, Canceled>; |
98 | 95 | ||
@@ -100,8 +97,22 @@ pub type Cancelable<T> = Result<T, Canceled>; | |||
100 | pub struct Diagnostic { | 97 | pub struct Diagnostic { |
101 | pub message: String, | 98 | pub message: String, |
102 | pub range: TextRange, | 99 | pub range: TextRange, |
103 | pub fix: Option<SourceChange>, | ||
104 | pub severity: Severity, | 100 | pub severity: Severity, |
101 | pub fix: Option<Fix>, | ||
102 | } | ||
103 | |||
104 | #[derive(Debug)] | ||
105 | pub struct Fix { | ||
106 | pub label: String, | ||
107 | pub source_change: SourceChange, | ||
108 | } | ||
109 | |||
110 | impl Fix { | ||
111 | pub fn new(label: impl Into<String>, source_change: SourceChange) -> Self { | ||
112 | let label = label.into(); | ||
113 | assert!(label.starts_with(char::is_uppercase) && !label.ends_with('.')); | ||
114 | Self { label, source_change } | ||
115 | } | ||
105 | } | 116 | } |
106 | 117 | ||
107 | /// Info associated with a text range. | 118 | /// Info associated with a text range. |
@@ -289,20 +300,17 @@ impl Analysis { | |||
289 | 300 | ||
290 | /// Returns an edit to remove all newlines in the range, cleaning up minor | 301 | /// Returns an edit to remove all newlines in the range, cleaning up minor |
291 | /// stuff like trailing commas. | 302 | /// stuff like trailing commas. |
292 | pub fn join_lines(&self, frange: FileRange) -> Cancelable<SourceChange> { | 303 | pub fn join_lines(&self, frange: FileRange) -> Cancelable<TextEdit> { |
293 | self.with_db(|db| { | 304 | self.with_db(|db| { |
294 | let parse = db.parse(frange.file_id); | 305 | let parse = db.parse(frange.file_id); |
295 | let file_edit = SourceFileEdit { | 306 | join_lines::join_lines(&parse.tree(), frange.range) |
296 | file_id: frange.file_id, | ||
297 | edit: join_lines::join_lines(&parse.tree(), frange.range), | ||
298 | }; | ||
299 | SourceChange::source_file_edit("Join lines", file_edit) | ||
300 | }) | 307 | }) |
301 | } | 308 | } |
302 | 309 | ||
303 | /// Returns an edit which should be applied when opening a new line, fixing | 310 | /// Returns an edit which should be applied when opening a new line, fixing |
304 | /// up minor stuff like continuing the comment. | 311 | /// up minor stuff like continuing the comment. |
305 | pub fn on_enter(&self, position: FilePosition) -> Cancelable<Option<SourceChange>> { | 312 | /// The edit will be a snippet (with `$0`). |
313 | pub fn on_enter(&self, position: FilePosition) -> Cancelable<Option<TextEdit>> { | ||
306 | self.with_db(|db| typing::on_enter(&db, position)) | 314 | self.with_db(|db| typing::on_enter(&db, position)) |
307 | } | 315 | } |
308 | 316 | ||
@@ -500,7 +508,7 @@ impl Analysis { | |||
500 | ) -> Cancelable<Result<SourceChange, SsrError>> { | 508 | ) -> Cancelable<Result<SourceChange, SsrError>> { |
501 | self.with_db(|db| { | 509 | self.with_db(|db| { |
502 | let edits = ssr::parse_search_replace(query, parse_only, db)?; | 510 | let edits = ssr::parse_search_replace(query, parse_only, db)?; |
503 | Ok(SourceChange::source_file_edits("Structural Search Replace", edits)) | 511 | Ok(SourceChange::source_file_edits(edits)) |
504 | }) | 512 | }) |
505 | } | 513 | } |
506 | 514 | ||
diff --git a/crates/ra_ide/src/mock_analysis.rs b/crates/ra_ide/src/mock_analysis.rs index 2c13f206a..ad78d2d93 100644 --- a/crates/ra_ide/src/mock_analysis.rs +++ b/crates/ra_ide/src/mock_analysis.rs | |||
@@ -1,21 +1,81 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::str::FromStr; | ||
3 | use std::sync::Arc; | 4 | use std::sync::Arc; |
4 | 5 | ||
5 | use ra_cfg::CfgOptions; | 6 | use ra_cfg::CfgOptions; |
6 | use ra_db::{CrateName, Env, RelativePathBuf}; | 7 | use ra_db::{CrateName, Env, RelativePathBuf}; |
7 | use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; | 8 | use test_utils::{extract_offset, extract_range, parse_fixture, FixtureEntry, CURSOR_MARKER}; |
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition::Edition2018, FileId, FilePosition, | 11 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, |
11 | FileRange, SourceRootId, | 12 | SourceRootId, |
12 | }; | 13 | }; |
13 | 14 | ||
15 | #[derive(Debug)] | ||
16 | enum MockFileData { | ||
17 | Plain { path: String, content: String }, | ||
18 | Fixture(FixtureEntry), | ||
19 | } | ||
20 | |||
21 | impl MockFileData { | ||
22 | fn new(path: String, content: String) -> Self { | ||
23 | // `Self::Plain` causes a false warning: 'variant is never constructed: `Plain` ' | ||
24 | // see https://github.com/rust-lang/rust/issues/69018 | ||
25 | MockFileData::Plain { path, content } | ||
26 | } | ||
27 | |||
28 | fn path(&self) -> &str { | ||
29 | match self { | ||
30 | MockFileData::Plain { path, .. } => path.as_str(), | ||
31 | MockFileData::Fixture(f) => f.meta.path().as_str(), | ||
32 | } | ||
33 | } | ||
34 | |||
35 | fn content(&self) -> &str { | ||
36 | match self { | ||
37 | MockFileData::Plain { content, .. } => content, | ||
38 | MockFileData::Fixture(f) => f.text.as_str(), | ||
39 | } | ||
40 | } | ||
41 | |||
42 | fn cfg_options(&self) -> CfgOptions { | ||
43 | match self { | ||
44 | MockFileData::Fixture(f) => { | ||
45 | f.meta.cfg_options().map_or_else(Default::default, |o| o.clone()) | ||
46 | } | ||
47 | _ => CfgOptions::default(), | ||
48 | } | ||
49 | } | ||
50 | |||
51 | fn edition(&self) -> Edition { | ||
52 | match self { | ||
53 | MockFileData::Fixture(f) => { | ||
54 | f.meta.edition().map_or(Edition::Edition2018, |v| Edition::from_str(v).unwrap()) | ||
55 | } | ||
56 | _ => Edition::Edition2018, | ||
57 | } | ||
58 | } | ||
59 | |||
60 | fn env(&self) -> Env { | ||
61 | match self { | ||
62 | MockFileData::Fixture(f) => Env::from(f.meta.env()), | ||
63 | _ => Env::default(), | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
68 | impl From<FixtureEntry> for MockFileData { | ||
69 | fn from(fixture: FixtureEntry) -> Self { | ||
70 | Self::Fixture(fixture) | ||
71 | } | ||
72 | } | ||
73 | |||
14 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis | 74 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis |
15 | /// from a set of in-memory files. | 75 | /// from a set of in-memory files. |
16 | #[derive(Debug, Default)] | 76 | #[derive(Debug, Default)] |
17 | pub struct MockAnalysis { | 77 | pub struct MockAnalysis { |
18 | files: Vec<(String, String)>, | 78 | files: Vec<MockFileData>, |
19 | } | 79 | } |
20 | 80 | ||
21 | impl MockAnalysis { | 81 | impl MockAnalysis { |
@@ -35,7 +95,7 @@ impl MockAnalysis { | |||
35 | pub fn with_files(fixture: &str) -> MockAnalysis { | 95 | pub fn with_files(fixture: &str) -> MockAnalysis { |
36 | let mut res = MockAnalysis::new(); | 96 | let mut res = MockAnalysis::new(); |
37 | for entry in parse_fixture(fixture) { | 97 | for entry in parse_fixture(fixture) { |
38 | res.add_file(&entry.meta, &entry.text); | 98 | res.add_file_fixture(entry); |
39 | } | 99 | } |
40 | res | 100 | res |
41 | } | 101 | } |
@@ -48,30 +108,44 @@ impl MockAnalysis { | |||
48 | for entry in parse_fixture(fixture) { | 108 | for entry in parse_fixture(fixture) { |
49 | if entry.text.contains(CURSOR_MARKER) { | 109 | if entry.text.contains(CURSOR_MARKER) { |
50 | assert!(position.is_none(), "only one marker (<|>) per fixture is allowed"); | 110 | assert!(position.is_none(), "only one marker (<|>) per fixture is allowed"); |
51 | position = Some(res.add_file_with_position(&entry.meta, &entry.text)); | 111 | position = Some(res.add_file_fixture_with_position(entry)); |
52 | } else { | 112 | } else { |
53 | res.add_file(&entry.meta, &entry.text); | 113 | res.add_file_fixture(entry); |
54 | } | 114 | } |
55 | } | 115 | } |
56 | let position = position.expect("expected a marker (<|>)"); | 116 | let position = position.expect("expected a marker (<|>)"); |
57 | (res, position) | 117 | (res, position) |
58 | } | 118 | } |
59 | 119 | ||
120 | pub fn add_file_fixture(&mut self, fixture: FixtureEntry) -> FileId { | ||
121 | let file_id = self.next_id(); | ||
122 | self.files.push(MockFileData::from(fixture)); | ||
123 | file_id | ||
124 | } | ||
125 | |||
126 | pub fn add_file_fixture_with_position(&mut self, mut fixture: FixtureEntry) -> FilePosition { | ||
127 | let (offset, text) = extract_offset(&fixture.text); | ||
128 | fixture.text = text; | ||
129 | let file_id = self.next_id(); | ||
130 | self.files.push(MockFileData::from(fixture)); | ||
131 | FilePosition { file_id, offset } | ||
132 | } | ||
133 | |||
60 | pub fn add_file(&mut self, path: &str, text: &str) -> FileId { | 134 | pub fn add_file(&mut self, path: &str, text: &str) -> FileId { |
61 | let file_id = FileId((self.files.len() + 1) as u32); | 135 | let file_id = self.next_id(); |
62 | self.files.push((path.to_string(), text.to_string())); | 136 | self.files.push(MockFileData::new(path.to_string(), text.to_string())); |
63 | file_id | 137 | file_id |
64 | } | 138 | } |
65 | pub fn add_file_with_position(&mut self, path: &str, text: &str) -> FilePosition { | 139 | pub fn add_file_with_position(&mut self, path: &str, text: &str) -> FilePosition { |
66 | let (offset, text) = extract_offset(text); | 140 | let (offset, text) = extract_offset(text); |
67 | let file_id = FileId((self.files.len() + 1) as u32); | 141 | let file_id = self.next_id(); |
68 | self.files.push((path.to_string(), text)); | 142 | self.files.push(MockFileData::new(path.to_string(), text)); |
69 | FilePosition { file_id, offset } | 143 | FilePosition { file_id, offset } |
70 | } | 144 | } |
71 | pub fn add_file_with_range(&mut self, path: &str, text: &str) -> FileRange { | 145 | pub fn add_file_with_range(&mut self, path: &str, text: &str) -> FileRange { |
72 | let (range, text) = extract_range(text); | 146 | let (range, text) = extract_range(text); |
73 | let file_id = FileId((self.files.len() + 1) as u32); | 147 | let file_id = self.next_id(); |
74 | self.files.push((path.to_string(), text)); | 148 | self.files.push(MockFileData::new(path.to_string(), text)); |
75 | FileRange { file_id, range } | 149 | FileRange { file_id, range } |
76 | } | 150 | } |
77 | pub fn id_of(&self, path: &str) -> FileId { | 151 | pub fn id_of(&self, path: &str) -> FileId { |
@@ -79,7 +153,7 @@ impl MockAnalysis { | |||
79 | .files | 153 | .files |
80 | .iter() | 154 | .iter() |
81 | .enumerate() | 155 | .enumerate() |
82 | .find(|(_, (p, _text))| path == p) | 156 | .find(|(_, data)| path == data.path()) |
83 | .expect("no file in this mock"); | 157 | .expect("no file in this mock"); |
84 | FileId(idx as u32 + 1) | 158 | FileId(idx as u32 + 1) |
85 | } | 159 | } |
@@ -90,18 +164,21 @@ impl MockAnalysis { | |||
90 | change.add_root(source_root, true); | 164 | change.add_root(source_root, true); |
91 | let mut crate_graph = CrateGraph::default(); | 165 | let mut crate_graph = CrateGraph::default(); |
92 | let mut root_crate = None; | 166 | let mut root_crate = None; |
93 | for (i, (path, contents)) in self.files.into_iter().enumerate() { | 167 | for (i, data) in self.files.into_iter().enumerate() { |
168 | let path = data.path(); | ||
94 | assert!(path.starts_with('/')); | 169 | assert!(path.starts_with('/')); |
95 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); | 170 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); |
171 | let cfg_options = data.cfg_options(); | ||
96 | let file_id = FileId(i as u32 + 1); | 172 | let file_id = FileId(i as u32 + 1); |
97 | let cfg_options = CfgOptions::default(); | 173 | let edition = data.edition(); |
174 | let env = data.env(); | ||
98 | if path == "/lib.rs" || path == "/main.rs" { | 175 | if path == "/lib.rs" || path == "/main.rs" { |
99 | root_crate = Some(crate_graph.add_crate_root( | 176 | root_crate = Some(crate_graph.add_crate_root( |
100 | file_id, | 177 | file_id, |
101 | Edition2018, | 178 | edition, |
102 | None, | 179 | None, |
103 | cfg_options, | 180 | cfg_options, |
104 | Env::default(), | 181 | env, |
105 | Default::default(), | 182 | Default::default(), |
106 | Default::default(), | 183 | Default::default(), |
107 | )); | 184 | )); |
@@ -109,10 +186,10 @@ impl MockAnalysis { | |||
109 | let crate_name = path.parent().unwrap().file_name().unwrap(); | 186 | let crate_name = path.parent().unwrap().file_name().unwrap(); |
110 | let other_crate = crate_graph.add_crate_root( | 187 | let other_crate = crate_graph.add_crate_root( |
111 | file_id, | 188 | file_id, |
112 | Edition2018, | 189 | edition, |
113 | Some(CrateName::new(crate_name).unwrap()), | 190 | Some(CrateName::new(crate_name).unwrap()), |
114 | cfg_options, | 191 | cfg_options, |
115 | Env::default(), | 192 | env, |
116 | Default::default(), | 193 | Default::default(), |
117 | Default::default(), | 194 | Default::default(), |
118 | ); | 195 | ); |
@@ -122,7 +199,7 @@ impl MockAnalysis { | |||
122 | .unwrap(); | 199 | .unwrap(); |
123 | } | 200 | } |
124 | } | 201 | } |
125 | change.add_file(source_root, file_id, path, Arc::new(contents)); | 202 | change.add_file(source_root, file_id, path, Arc::new(data.content().to_owned())); |
126 | } | 203 | } |
127 | change.set_crate_graph(crate_graph); | 204 | change.set_crate_graph(crate_graph); |
128 | host.apply_change(change); | 205 | host.apply_change(change); |
@@ -131,6 +208,10 @@ impl MockAnalysis { | |||
131 | pub fn analysis(self) -> Analysis { | 208 | pub fn analysis(self) -> Analysis { |
132 | self.analysis_host().analysis() | 209 | self.analysis_host().analysis() |
133 | } | 210 | } |
211 | |||
212 | fn next_id(&self) -> FileId { | ||
213 | FileId((self.files.len() + 1) as u32) | ||
214 | } | ||
134 | } | 215 | } |
135 | 216 | ||
136 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. | 217 | /// Creates analysis from a multi-file fixture, returns positions marked with <|>. |
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs index 62ec8d85d..28c6349b1 100644 --- a/crates/ra_ide/src/references/rename.rs +++ b/crates/ra_ide/src/references/rename.rs | |||
@@ -128,7 +128,7 @@ fn rename_mod( | |||
128 | source_file_edits.extend(ref_edits); | 128 | source_file_edits.extend(ref_edits); |
129 | } | 129 | } |
130 | 130 | ||
131 | Some(SourceChange::from_edits("Rename", source_file_edits, file_system_edits)) | 131 | Some(SourceChange::from_edits(source_file_edits, file_system_edits)) |
132 | } | 132 | } |
133 | 133 | ||
134 | fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<SourceChange>> { | 134 | fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<SourceChange>> { |
@@ -171,7 +171,7 @@ fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo | |||
171 | ), | 171 | ), |
172 | }); | 172 | }); |
173 | 173 | ||
174 | Some(RangeInfo::new(range, SourceChange::source_file_edits("Rename", edits))) | 174 | Some(RangeInfo::new(range, SourceChange::source_file_edits(edits))) |
175 | } | 175 | } |
176 | 176 | ||
177 | fn text_edit_from_self_param( | 177 | fn text_edit_from_self_param( |
@@ -234,7 +234,7 @@ fn rename_self_to_param( | |||
234 | let range = ast::SelfParam::cast(self_token.parent()) | 234 | let range = ast::SelfParam::cast(self_token.parent()) |
235 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); | 235 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); |
236 | 236 | ||
237 | Some(RangeInfo::new(range, SourceChange::source_file_edits("Rename", edits))) | 237 | Some(RangeInfo::new(range, SourceChange::source_file_edits(edits))) |
238 | } | 238 | } |
239 | 239 | ||
240 | fn rename_reference( | 240 | fn rename_reference( |
@@ -253,7 +253,7 @@ fn rename_reference( | |||
253 | return None; | 253 | return None; |
254 | } | 254 | } |
255 | 255 | ||
256 | Some(RangeInfo::new(range, SourceChange::source_file_edits("Rename", edit))) | 256 | Some(RangeInfo::new(range, SourceChange::source_file_edits(edit))) |
257 | } | 257 | } |
258 | 258 | ||
259 | #[cfg(test)] | 259 | #[cfg(test)] |
@@ -642,7 +642,6 @@ mod tests { | |||
642 | RangeInfo { | 642 | RangeInfo { |
643 | range: 4..7, | 643 | range: 4..7, |
644 | info: SourceChange { | 644 | info: SourceChange { |
645 | label: "Rename", | ||
646 | source_file_edits: [ | 645 | source_file_edits: [ |
647 | SourceFileEdit { | 646 | SourceFileEdit { |
648 | file_id: FileId( | 647 | file_id: FileId( |
@@ -669,7 +668,6 @@ mod tests { | |||
669 | dst_path: "bar/foo2.rs", | 668 | dst_path: "bar/foo2.rs", |
670 | }, | 669 | }, |
671 | ], | 670 | ], |
672 | cursor_position: None, | ||
673 | is_snippet: false, | 671 | is_snippet: false, |
674 | }, | 672 | }, |
675 | }, | 673 | }, |
@@ -695,7 +693,6 @@ mod tests { | |||
695 | RangeInfo { | 693 | RangeInfo { |
696 | range: 4..7, | 694 | range: 4..7, |
697 | info: SourceChange { | 695 | info: SourceChange { |
698 | label: "Rename", | ||
699 | source_file_edits: [ | 696 | source_file_edits: [ |
700 | SourceFileEdit { | 697 | SourceFileEdit { |
701 | file_id: FileId( | 698 | file_id: FileId( |
@@ -722,7 +719,6 @@ mod tests { | |||
722 | dst_path: "foo2/mod.rs", | 719 | dst_path: "foo2/mod.rs", |
723 | }, | 720 | }, |
724 | ], | 721 | ], |
725 | cursor_position: None, | ||
726 | is_snippet: false, | 722 | is_snippet: false, |
727 | }, | 723 | }, |
728 | }, | 724 | }, |
@@ -779,7 +775,6 @@ mod tests { | |||
779 | RangeInfo { | 775 | RangeInfo { |
780 | range: 8..11, | 776 | range: 8..11, |
781 | info: SourceChange { | 777 | info: SourceChange { |
782 | label: "Rename", | ||
783 | source_file_edits: [ | 778 | source_file_edits: [ |
784 | SourceFileEdit { | 779 | SourceFileEdit { |
785 | file_id: FileId( | 780 | file_id: FileId( |
@@ -819,7 +814,6 @@ mod tests { | |||
819 | dst_path: "bar/foo2.rs", | 814 | dst_path: "bar/foo2.rs", |
820 | }, | 815 | }, |
821 | ], | 816 | ], |
822 | cursor_position: None, | ||
823 | is_snippet: false, | 817 | is_snippet: false, |
824 | }, | 818 | }, |
825 | }, | 819 | }, |
@@ -986,8 +980,8 @@ mod tests { | |||
986 | if let Some(change) = source_change { | 980 | if let Some(change) = source_change { |
987 | for edit in change.info.source_file_edits { | 981 | for edit in change.info.source_file_edits { |
988 | file_id = Some(edit.file_id); | 982 | file_id = Some(edit.file_id); |
989 | for indel in edit.edit.as_indels() { | 983 | for indel in edit.edit.into_iter() { |
990 | text_edit_builder.replace(indel.delete, indel.insert.clone()); | 984 | text_edit_builder.replace(indel.delete, indel.insert); |
991 | } | 985 | } |
992 | } | 986 | } |
993 | } | 987 | } |
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index 131b8f307..6e7e47199 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{AsAssocItem, Semantics}; | 3 | use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; |
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
@@ -10,12 +10,14 @@ use ra_syntax::{ | |||
10 | 10 | ||
11 | use crate::FileId; | 11 | use crate::FileId; |
12 | use ast::DocCommentsOwner; | 12 | use ast::DocCommentsOwner; |
13 | use ra_cfg::CfgExpr; | ||
13 | use std::fmt::Display; | 14 | use std::fmt::Display; |
14 | 15 | ||
15 | #[derive(Debug)] | 16 | #[derive(Debug)] |
16 | pub struct Runnable { | 17 | pub struct Runnable { |
17 | pub range: TextRange, | 18 | pub range: TextRange, |
18 | pub kind: RunnableKind, | 19 | pub kind: RunnableKind, |
20 | pub cfg_exprs: Vec<CfgExpr>, | ||
19 | } | 21 | } |
20 | 22 | ||
21 | #[derive(Debug)] | 23 | #[derive(Debug)] |
@@ -45,29 +47,33 @@ pub enum RunnableKind { | |||
45 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 47 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
46 | let sema = Semantics::new(db); | 48 | let sema = Semantics::new(db); |
47 | let source_file = sema.parse(file_id); | 49 | let source_file = sema.parse(file_id); |
48 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i)).collect() | 50 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i, file_id)).collect() |
49 | } | 51 | } |
50 | 52 | ||
51 | fn runnable(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { | 53 | fn runnable(sema: &Semantics<RootDatabase>, item: SyntaxNode, file_id: FileId) -> Option<Runnable> { |
52 | match_ast! { | 54 | match_ast! { |
53 | match item { | 55 | match item { |
54 | ast::FnDef(it) => runnable_fn(sema, it), | 56 | ast::FnDef(it) => runnable_fn(sema, it, file_id), |
55 | ast::Module(it) => runnable_mod(sema, it), | 57 | ast::Module(it) => runnable_mod(sema, it, file_id), |
56 | _ => None, | 58 | _ => None, |
57 | } | 59 | } |
58 | } | 60 | } |
59 | } | 61 | } |
60 | 62 | ||
61 | fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Runnable> { | 63 | fn runnable_fn( |
64 | sema: &Semantics<RootDatabase>, | ||
65 | fn_def: ast::FnDef, | ||
66 | file_id: FileId, | ||
67 | ) -> Option<Runnable> { | ||
62 | let name_string = fn_def.name()?.text().to_string(); | 68 | let name_string = fn_def.name()?.text().to_string(); |
63 | 69 | ||
64 | let kind = if name_string == "main" { | 70 | let kind = if name_string == "main" { |
65 | RunnableKind::Bin | 71 | RunnableKind::Bin |
66 | } else { | 72 | } else { |
67 | let test_id = if let Some(module) = sema.to_def(&fn_def).map(|def| def.module(sema.db)) { | 73 | let test_id = match sema.to_def(&fn_def).map(|def| def.module(sema.db)) { |
68 | let def = sema.to_def(&fn_def)?; | 74 | Some(module) => { |
69 | let impl_trait_name = | 75 | let def = sema.to_def(&fn_def)?; |
70 | def.as_assoc_item(sema.db).and_then(|assoc_item| { | 76 | let impl_trait_name = def.as_assoc_item(sema.db).and_then(|assoc_item| { |
71 | match assoc_item.container(sema.db) { | 77 | match assoc_item.container(sema.db) { |
72 | hir::AssocItemContainer::Trait(trait_item) => { | 78 | hir::AssocItemContainer::Trait(trait_item) => { |
73 | Some(trait_item.name(sema.db).to_string()) | 79 | Some(trait_item.name(sema.db).to_string()) |
@@ -79,25 +85,25 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run | |||
79 | } | 85 | } |
80 | }); | 86 | }); |
81 | 87 | ||
82 | let path_iter = module | 88 | let path_iter = module |
83 | .path_to_root(sema.db) | 89 | .path_to_root(sema.db) |
84 | .into_iter() | 90 | .into_iter() |
85 | .rev() | 91 | .rev() |
86 | .filter_map(|it| it.name(sema.db)) | 92 | .filter_map(|it| it.name(sema.db)) |
87 | .map(|name| name.to_string()); | 93 | .map(|name| name.to_string()); |
88 | 94 | ||
89 | let path = if let Some(impl_trait_name) = impl_trait_name { | 95 | let path = if let Some(impl_trait_name) = impl_trait_name { |
90 | path_iter | 96 | path_iter |
91 | .chain(std::iter::once(impl_trait_name)) | 97 | .chain(std::iter::once(impl_trait_name)) |
92 | .chain(std::iter::once(name_string)) | 98 | .chain(std::iter::once(name_string)) |
93 | .join("::") | 99 | .join("::") |
94 | } else { | 100 | } else { |
95 | path_iter.chain(std::iter::once(name_string)).join("::") | 101 | path_iter.chain(std::iter::once(name_string)).join("::") |
96 | }; | 102 | }; |
97 | 103 | ||
98 | TestId::Path(path) | 104 | TestId::Path(path) |
99 | } else { | 105 | } |
100 | TestId::Name(name_string) | 106 | None => TestId::Name(name_string), |
101 | }; | 107 | }; |
102 | 108 | ||
103 | if has_test_related_attribute(&fn_def) { | 109 | if has_test_related_attribute(&fn_def) { |
@@ -111,7 +117,12 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, fn_def: ast::FnDef) -> Option<Run | |||
111 | return None; | 117 | return None; |
112 | } | 118 | } |
113 | }; | 119 | }; |
114 | Some(Runnable { range: fn_def.syntax().text_range(), kind }) | 120 | |
121 | let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &fn_def)); | ||
122 | let cfg_exprs = | ||
123 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); | ||
124 | |||
125 | Some(Runnable { range: fn_def.syntax().text_range(), kind, cfg_exprs }) | ||
115 | } | 126 | } |
116 | 127 | ||
117 | #[derive(Debug)] | 128 | #[derive(Debug)] |
@@ -147,7 +158,11 @@ fn has_doc_test(fn_def: &ast::FnDef) -> bool { | |||
147 | fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```")) | 158 | fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```")) |
148 | } | 159 | } |
149 | 160 | ||
150 | fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<Runnable> { | 161 | fn runnable_mod( |
162 | sema: &Semantics<RootDatabase>, | ||
163 | module: ast::Module, | ||
164 | file_id: FileId, | ||
165 | ) -> Option<Runnable> { | ||
151 | let has_test_function = module | 166 | let has_test_function = module |
152 | .item_list()? | 167 | .item_list()? |
153 | .items() | 168 | .items() |
@@ -160,11 +175,20 @@ fn runnable_mod(sema: &Semantics<RootDatabase>, module: ast::Module) -> Option<R | |||
160 | return None; | 175 | return None; |
161 | } | 176 | } |
162 | let range = module.syntax().text_range(); | 177 | let range = module.syntax().text_range(); |
163 | let module = sema.to_def(&module)?; | 178 | let module_def = sema.to_def(&module)?; |
164 | 179 | ||
165 | let path = | 180 | let path = module_def |
166 | module.path_to_root(sema.db).into_iter().rev().filter_map(|it| it.name(sema.db)).join("::"); | 181 | .path_to_root(sema.db) |
167 | Some(Runnable { range, kind: RunnableKind::TestMod { path } }) | 182 | .into_iter() |
183 | .rev() | ||
184 | .filter_map(|it| it.name(sema.db)) | ||
185 | .join("::"); | ||
186 | |||
187 | let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &module)); | ||
188 | let cfg_exprs = | ||
189 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); | ||
190 | |||
191 | Some(Runnable { range, kind: RunnableKind::TestMod { path }, cfg_exprs }) | ||
168 | } | 192 | } |
169 | 193 | ||
170 | #[cfg(test)] | 194 | #[cfg(test)] |
@@ -196,6 +220,7 @@ mod tests { | |||
196 | Runnable { | 220 | Runnable { |
197 | range: 1..21, | 221 | range: 1..21, |
198 | kind: Bin, | 222 | kind: Bin, |
223 | cfg_exprs: [], | ||
199 | }, | 224 | }, |
200 | Runnable { | 225 | Runnable { |
201 | range: 22..46, | 226 | range: 22..46, |
@@ -207,6 +232,7 @@ mod tests { | |||
207 | ignore: false, | 232 | ignore: false, |
208 | }, | 233 | }, |
209 | }, | 234 | }, |
235 | cfg_exprs: [], | ||
210 | }, | 236 | }, |
211 | Runnable { | 237 | Runnable { |
212 | range: 47..81, | 238 | range: 47..81, |
@@ -218,6 +244,7 @@ mod tests { | |||
218 | ignore: true, | 244 | ignore: true, |
219 | }, | 245 | }, |
220 | }, | 246 | }, |
247 | cfg_exprs: [], | ||
221 | }, | 248 | }, |
222 | ] | 249 | ] |
223 | "### | 250 | "### |
@@ -245,6 +272,7 @@ mod tests { | |||
245 | Runnable { | 272 | Runnable { |
246 | range: 1..21, | 273 | range: 1..21, |
247 | kind: Bin, | 274 | kind: Bin, |
275 | cfg_exprs: [], | ||
248 | }, | 276 | }, |
249 | Runnable { | 277 | Runnable { |
250 | range: 22..64, | 278 | range: 22..64, |
@@ -253,6 +281,7 @@ mod tests { | |||
253 | "foo", | 281 | "foo", |
254 | ), | 282 | ), |
255 | }, | 283 | }, |
284 | cfg_exprs: [], | ||
256 | }, | 285 | }, |
257 | ] | 286 | ] |
258 | "### | 287 | "### |
@@ -283,6 +312,7 @@ mod tests { | |||
283 | Runnable { | 312 | Runnable { |
284 | range: 1..21, | 313 | range: 1..21, |
285 | kind: Bin, | 314 | kind: Bin, |
315 | cfg_exprs: [], | ||
286 | }, | 316 | }, |
287 | Runnable { | 317 | Runnable { |
288 | range: 51..105, | 318 | range: 51..105, |
@@ -291,6 +321,7 @@ mod tests { | |||
291 | "Data::foo", | 321 | "Data::foo", |
292 | ), | 322 | ), |
293 | }, | 323 | }, |
324 | cfg_exprs: [], | ||
294 | }, | 325 | }, |
295 | ] | 326 | ] |
296 | "### | 327 | "### |
@@ -318,6 +349,7 @@ mod tests { | |||
318 | kind: TestMod { | 349 | kind: TestMod { |
319 | path: "test_mod", | 350 | path: "test_mod", |
320 | }, | 351 | }, |
352 | cfg_exprs: [], | ||
321 | }, | 353 | }, |
322 | Runnable { | 354 | Runnable { |
323 | range: 28..57, | 355 | range: 28..57, |
@@ -329,6 +361,7 @@ mod tests { | |||
329 | ignore: false, | 361 | ignore: false, |
330 | }, | 362 | }, |
331 | }, | 363 | }, |
364 | cfg_exprs: [], | ||
332 | }, | 365 | }, |
333 | ] | 366 | ] |
334 | "### | 367 | "### |
@@ -358,6 +391,7 @@ mod tests { | |||
358 | kind: TestMod { | 391 | kind: TestMod { |
359 | path: "foo::test_mod", | 392 | path: "foo::test_mod", |
360 | }, | 393 | }, |
394 | cfg_exprs: [], | ||
361 | }, | 395 | }, |
362 | Runnable { | 396 | Runnable { |
363 | range: 46..79, | 397 | range: 46..79, |
@@ -369,6 +403,7 @@ mod tests { | |||
369 | ignore: false, | 403 | ignore: false, |
370 | }, | 404 | }, |
371 | }, | 405 | }, |
406 | cfg_exprs: [], | ||
372 | }, | 407 | }, |
373 | ] | 408 | ] |
374 | "### | 409 | "### |
@@ -400,6 +435,7 @@ mod tests { | |||
400 | kind: TestMod { | 435 | kind: TestMod { |
401 | path: "foo::bar::test_mod", | 436 | path: "foo::bar::test_mod", |
402 | }, | 437 | }, |
438 | cfg_exprs: [], | ||
403 | }, | 439 | }, |
404 | Runnable { | 440 | Runnable { |
405 | range: 68..105, | 441 | range: 68..105, |
@@ -411,6 +447,89 @@ mod tests { | |||
411 | ignore: false, | 447 | ignore: false, |
412 | }, | 448 | }, |
413 | }, | 449 | }, |
450 | cfg_exprs: [], | ||
451 | }, | ||
452 | ] | ||
453 | "### | ||
454 | ); | ||
455 | } | ||
456 | |||
457 | #[test] | ||
458 | fn test_runnables_with_feature() { | ||
459 | let (analysis, pos) = analysis_and_position( | ||
460 | r#" | ||
461 | //- /lib.rs crate:foo cfg:feature=foo | ||
462 | <|> //empty | ||
463 | #[test] | ||
464 | #[cfg(feature = "foo")] | ||
465 | fn test_foo1() {} | ||
466 | "#, | ||
467 | ); | ||
468 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
469 | assert_debug_snapshot!(&runnables, | ||
470 | @r###" | ||
471 | [ | ||
472 | Runnable { | ||
473 | range: 1..58, | ||
474 | kind: Test { | ||
475 | test_id: Path( | ||
476 | "test_foo1", | ||
477 | ), | ||
478 | attr: TestAttr { | ||
479 | ignore: false, | ||
480 | }, | ||
481 | }, | ||
482 | cfg_exprs: [ | ||
483 | KeyValue { | ||
484 | key: "feature", | ||
485 | value: "foo", | ||
486 | }, | ||
487 | ], | ||
488 | }, | ||
489 | ] | ||
490 | "### | ||
491 | ); | ||
492 | } | ||
493 | |||
494 | #[test] | ||
495 | fn test_runnables_with_features() { | ||
496 | let (analysis, pos) = analysis_and_position( | ||
497 | r#" | ||
498 | //- /lib.rs crate:foo cfg:feature=foo,feature=bar | ||
499 | <|> //empty | ||
500 | #[test] | ||
501 | #[cfg(all(feature = "foo", feature = "bar"))] | ||
502 | fn test_foo1() {} | ||
503 | "#, | ||
504 | ); | ||
505 | let runnables = analysis.runnables(pos.file_id).unwrap(); | ||
506 | assert_debug_snapshot!(&runnables, | ||
507 | @r###" | ||
508 | [ | ||
509 | Runnable { | ||
510 | range: 1..80, | ||
511 | kind: Test { | ||
512 | test_id: Path( | ||
513 | "test_foo1", | ||
514 | ), | ||
515 | attr: TestAttr { | ||
516 | ignore: false, | ||
517 | }, | ||
518 | }, | ||
519 | cfg_exprs: [ | ||
520 | All( | ||
521 | [ | ||
522 | KeyValue { | ||
523 | key: "feature", | ||
524 | value: "foo", | ||
525 | }, | ||
526 | KeyValue { | ||
527 | key: "feature", | ||
528 | value: "bar", | ||
529 | }, | ||
530 | ], | ||
531 | ), | ||
532 | ], | ||
414 | }, | 533 | }, |
415 | ] | 534 | ] |
416 | "### | 535 | "### |
diff --git a/crates/ra_ide/src/snapshots/highlight_injection.html b/crates/ra_ide/src/snapshots/highlight_injection.html index ea026d7a0..68fc589bc 100644 --- a/crates/ra_ide/src/snapshots/highlight_injection.html +++ b/crates/ra_ide/src/snapshots/highlight_injection.html | |||
@@ -17,6 +17,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
17 | .type_param { color: #DFAF8F; } | 17 | .type_param { color: #DFAF8F; } |
18 | .attribute { color: #94BFF3; } | 18 | .attribute { color: #94BFF3; } |
19 | .numeric_literal { color: #BFEBBF; } | 19 | .numeric_literal { color: #BFEBBF; } |
20 | .bool_literal { color: #BFE6EB; } | ||
20 | .macro { color: #94BFF3; } | 21 | .macro { color: #94BFF3; } |
21 | .module { color: #AFD8AF; } | 22 | .module { color: #AFD8AF; } |
22 | .variable { color: #DCDCCC; } | 23 | .variable { color: #DCDCCC; } |
diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html index 752b487e8..326744361 100644 --- a/crates/ra_ide/src/snapshots/highlight_strings.html +++ b/crates/ra_ide/src/snapshots/highlight_strings.html | |||
@@ -17,6 +17,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
17 | .type_param { color: #DFAF8F; } | 17 | .type_param { color: #DFAF8F; } |
18 | .attribute { color: #94BFF3; } | 18 | .attribute { color: #94BFF3; } |
19 | .numeric_literal { color: #BFEBBF; } | 19 | .numeric_literal { color: #BFEBBF; } |
20 | .bool_literal { color: #BFE6EB; } | ||
20 | .macro { color: #94BFF3; } | 21 | .macro { color: #94BFF3; } |
21 | .module { color: #AFD8AF; } | 22 | .module { color: #AFD8AF; } |
22 | .variable { color: #DCDCCC; } | 23 | .variable { color: #DCDCCC; } |
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index 635fe5cf9..352e35095 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html | |||
@@ -17,6 +17,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
17 | .type_param { color: #DFAF8F; } | 17 | .type_param { color: #DFAF8F; } |
18 | .attribute { color: #94BFF3; } | 18 | .attribute { color: #94BFF3; } |
19 | .numeric_literal { color: #BFEBBF; } | 19 | .numeric_literal { color: #BFEBBF; } |
20 | .bool_literal { color: #BFE6EB; } | ||
20 | .macro { color: #94BFF3; } | 21 | .macro { color: #94BFF3; } |
21 | .module { color: #AFD8AF; } | 22 | .module { color: #AFD8AF; } |
22 | .variable { color: #DCDCCC; } | 23 | .variable { color: #DCDCCC; } |
@@ -27,19 +28,19 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
27 | .keyword.unsafe { color: #BC8383; font-weight: bold; } | 28 | .keyword.unsafe { color: #BC8383; font-weight: bold; } |
28 | .control { font-style: italic; } | 29 | .control { font-style: italic; } |
29 | </style> | 30 | </style> |
30 | <pre><code><span class="attribute">#[derive(Clone, Debug)]</span> | 31 | <pre><code><span class="attribute">#[</span><span class="function attribute">derive</span><span class="attribute">(Clone, Debug)]</span> |
31 | <span class="keyword">struct</span> <span class="struct declaration">Foo</span> { | 32 | <span class="keyword">struct</span> <span class="struct declaration">Foo</span> { |
32 | <span class="keyword">pub</span> <span class="field declaration">x</span>: <span class="builtin_type">i32</span>, | 33 | <span class="keyword">pub</span> <span class="field declaration">x</span>: <span class="builtin_type">i32</span>, |
33 | <span class="keyword">pub</span> <span class="field declaration">y</span>: <span class="builtin_type">i32</span>, | 34 | <span class="keyword">pub</span> <span class="field declaration">y</span>: <span class="builtin_type">i32</span>, |
34 | } | 35 | } |
35 | 36 | ||
36 | <span class="keyword">trait</span> <span class="trait declaration">Bar</span> { | 37 | <span class="keyword">trait</span> <span class="trait declaration">Bar</span> { |
37 | <span class="keyword">fn</span> <span class="function declaration">bar</span>(&<span class="keyword">self</span>) -> <span class="builtin_type">i32</span>; | 38 | <span class="keyword">fn</span> <span class="function declaration">bar</span>(&<span class="self_keyword">self</span>) -> <span class="builtin_type">i32</span>; |
38 | } | 39 | } |
39 | 40 | ||
40 | <span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> { | 41 | <span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> { |
41 | <span class="keyword">fn</span> <span class="function declaration">bar</span>(&<span class="keyword">self</span>) -> <span class="builtin_type">i32</span> { | 42 | <span class="keyword">fn</span> <span class="function declaration">bar</span>(&<span class="self_keyword">self</span>) -> <span class="builtin_type">i32</span> { |
42 | <span class="keyword">self</span>.<span class="field">x</span> | 43 | <span class="self_keyword">self</span>.<span class="field">x</span> |
43 | } | 44 | } |
44 | } | 45 | } |
45 | 46 | ||
@@ -64,7 +65,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
64 | <span class="macro">println!</span>(<span class="string_literal">"Hello, {}!"</span>, <span class="numeric_literal">92</span>); | 65 | <span class="macro">println!</span>(<span class="string_literal">"Hello, {}!"</span>, <span class="numeric_literal">92</span>); |
65 | 66 | ||
66 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> = <span class="unresolved_reference">Vec</span>::<span class="unresolved_reference">new</span>(); | 67 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> = <span class="unresolved_reference">Vec</span>::<span class="unresolved_reference">new</span>(); |
67 | <span class="keyword control">if</span> <span class="keyword">true</span> { | 68 | <span class="keyword control">if</span> <span class="bool_literal">true</span> { |
68 | <span class="keyword">let</span> <span class="variable declaration">x</span> = <span class="numeric_literal">92</span>; | 69 | <span class="keyword">let</span> <span class="variable declaration">x</span> = <span class="numeric_literal">92</span>; |
69 | <span class="variable mutable">vec</span>.<span class="unresolved_reference">push</span>(<span class="struct">Foo</span> { <span class="field">x</span>, <span class="field">y</span>: <span class="numeric_literal">1</span> }); | 70 | <span class="variable mutable">vec</span>.<span class="unresolved_reference">push</span>(<span class="struct">Foo</span> { <span class="field">x</span>, <span class="field">y</span>: <span class="numeric_literal">1</span> }); |
70 | } | 71 | } |
@@ -91,7 +92,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
91 | <span class="keyword">use</span> <span class="enum">Option</span>::*; | 92 | <span class="keyword">use</span> <span class="enum">Option</span>::*; |
92 | 93 | ||
93 | <span class="keyword">impl</span><<span class="type_param declaration">T</span>> <span class="enum">Option</span><<span class="type_param">T</span>> { | 94 | <span class="keyword">impl</span><<span class="type_param declaration">T</span>> <span class="enum">Option</span><<span class="type_param">T</span>> { |
94 | <span class="keyword">fn</span> <span class="function declaration">and</span><<span class="type_param declaration">U</span>>(<span class="keyword">self</span>, <span class="variable declaration">other</span>: <span class="enum">Option</span><<span class="type_param">U</span>>) -> <span class="enum">Option</span><(<span class="type_param">T</span>, <span class="type_param">U</span>)> { | 95 | <span class="keyword">fn</span> <span class="function declaration">and</span><<span class="type_param declaration">U</span>>(<span class="self_keyword">self</span>, <span class="variable declaration">other</span>: <span class="enum">Option</span><<span class="type_param">U</span>>) -> <span class="enum">Option</span><(<span class="type_param">T</span>, <span class="type_param">U</span>)> { |
95 | <span class="keyword control">match</span> <span class="variable">other</span> { | 96 | <span class="keyword control">match</span> <span class="variable">other</span> { |
96 | <span class="enum_variant">None</span> => <span class="macro">unimplemented!</span>(), | 97 | <span class="enum_variant">None</span> => <span class="macro">unimplemented!</span>(), |
97 | <span class="variable declaration">Nope</span> => <span class="variable">Nope</span>, | 98 | <span class="variable declaration">Nope</span> => <span class="variable">Nope</span>, |
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html index 11e1f3e44..2a0294f71 100644 --- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html | |||
@@ -17,6 +17,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
17 | .type_param { color: #DFAF8F; } | 17 | .type_param { color: #DFAF8F; } |
18 | .attribute { color: #94BFF3; } | 18 | .attribute { color: #94BFF3; } |
19 | .numeric_literal { color: #BFEBBF; } | 19 | .numeric_literal { color: #BFEBBF; } |
20 | .bool_literal { color: #BFE6EB; } | ||
20 | .macro { color: #94BFF3; } | 21 | .macro { color: #94BFF3; } |
21 | .module { color: #AFD8AF; } | 22 | .module { color: #AFD8AF; } |
22 | .variable { color: #DCDCCC; } | 23 | .variable { color: #DCDCCC; } |
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs index 1873d1d0d..130d3b4c3 100644 --- a/crates/ra_ide/src/ssr.rs +++ b/crates/ra_ide/src/ssr.rs | |||
@@ -196,10 +196,10 @@ fn find(pattern: &SsrPattern, code: &SyntaxNode) -> SsrMatches { | |||
196 | ) -> Option<Match> { | 196 | ) -> Option<Match> { |
197 | let match_ = check_opt_nodes(pattern.path(), code.path(), placeholders, match_)?; | 197 | let match_ = check_opt_nodes(pattern.path(), code.path(), placeholders, match_)?; |
198 | 198 | ||
199 | let mut pattern_fields = | 199 | let mut pattern_fields: Vec<RecordField> = |
200 | pattern.record_field_list().map(|x| x.fields().collect()).unwrap_or(vec![]); | 200 | pattern.record_field_list().map(|x| x.fields().collect()).unwrap_or_default(); |
201 | let mut code_fields = | 201 | let mut code_fields: Vec<RecordField> = |
202 | code.record_field_list().map(|x| x.fields().collect()).unwrap_or(vec![]); | 202 | code.record_field_list().map(|x| x.fields().collect()).unwrap_or_default(); |
203 | 203 | ||
204 | if pattern_fields.len() != code_fields.len() { | 204 | if pattern_fields.len() != code_fields.len() { |
205 | return None; | 205 | return None; |
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index be57eeb0a..8a995d779 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -361,7 +361,9 @@ fn highlight_element( | |||
361 | } | 361 | } |
362 | 362 | ||
363 | // Highlight references like the definitions they resolve to | 363 | // Highlight references like the definitions they resolve to |
364 | NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => return None, | 364 | NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => { |
365 | Highlight::from(HighlightTag::Function) | HighlightModifier::Attribute | ||
366 | } | ||
365 | NAME_REF => { | 367 | NAME_REF => { |
366 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); | 368 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); |
367 | match classify_name_ref(sema, &name_ref) { | 369 | match classify_name_ref(sema, &name_ref) { |
@@ -411,6 +413,8 @@ fn highlight_element( | |||
411 | | T![in] => h | HighlightModifier::ControlFlow, | 413 | | T![in] => h | HighlightModifier::ControlFlow, |
412 | T![for] if !is_child_of_impl(element) => h | HighlightModifier::ControlFlow, | 414 | T![for] if !is_child_of_impl(element) => h | HighlightModifier::ControlFlow, |
413 | T![unsafe] => h | HighlightModifier::Unsafe, | 415 | T![unsafe] => h | HighlightModifier::Unsafe, |
416 | T![true] | T![false] => HighlightTag::BoolLiteral.into(), | ||
417 | T![self] => HighlightTag::SelfKeyword.into(), | ||
414 | _ => h, | 418 | _ => h, |
415 | } | 419 | } |
416 | } | 420 | } |
@@ -478,23 +482,31 @@ fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { | |||
478 | } | 482 | } |
479 | 483 | ||
480 | fn highlight_name_by_syntax(name: ast::Name) -> Highlight { | 484 | fn highlight_name_by_syntax(name: ast::Name) -> Highlight { |
481 | let default = HighlightTag::Function.into(); | 485 | let default = HighlightTag::UnresolvedReference; |
482 | 486 | ||
483 | let parent = match name.syntax().parent() { | 487 | let parent = match name.syntax().parent() { |
484 | Some(it) => it, | 488 | Some(it) => it, |
485 | _ => return default, | 489 | _ => return default.into(), |
486 | }; | 490 | }; |
487 | 491 | ||
488 | match parent.kind() { | 492 | let tag = match parent.kind() { |
489 | STRUCT_DEF => HighlightTag::Struct.into(), | 493 | STRUCT_DEF => HighlightTag::Struct, |
490 | ENUM_DEF => HighlightTag::Enum.into(), | 494 | ENUM_DEF => HighlightTag::Enum, |
491 | UNION_DEF => HighlightTag::Union.into(), | 495 | UNION_DEF => HighlightTag::Union, |
492 | TRAIT_DEF => HighlightTag::Trait.into(), | 496 | TRAIT_DEF => HighlightTag::Trait, |
493 | TYPE_ALIAS_DEF => HighlightTag::TypeAlias.into(), | 497 | TYPE_ALIAS_DEF => HighlightTag::TypeAlias, |
494 | TYPE_PARAM => HighlightTag::TypeParam.into(), | 498 | TYPE_PARAM => HighlightTag::TypeParam, |
495 | RECORD_FIELD_DEF => HighlightTag::Field.into(), | 499 | RECORD_FIELD_DEF => HighlightTag::Field, |
500 | MODULE => HighlightTag::Module, | ||
501 | FN_DEF => HighlightTag::Function, | ||
502 | CONST_DEF => HighlightTag::Constant, | ||
503 | STATIC_DEF => HighlightTag::Static, | ||
504 | ENUM_VARIANT => HighlightTag::EnumVariant, | ||
505 | BIND_PAT => HighlightTag::Local, | ||
496 | _ => default, | 506 | _ => default, |
497 | } | 507 | }; |
508 | |||
509 | tag.into() | ||
498 | } | 510 | } |
499 | 511 | ||
500 | fn highlight_injection( | 512 | fn highlight_injection( |
diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs index ff0eeeb52..edfe61f39 100644 --- a/crates/ra_ide/src/syntax_highlighting/html.rs +++ b/crates/ra_ide/src/syntax_highlighting/html.rs | |||
@@ -76,6 +76,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
76 | .type_param { color: #DFAF8F; } | 76 | .type_param { color: #DFAF8F; } |
77 | .attribute { color: #94BFF3; } | 77 | .attribute { color: #94BFF3; } |
78 | .numeric_literal { color: #BFEBBF; } | 78 | .numeric_literal { color: #BFEBBF; } |
79 | .bool_literal { color: #BFE6EB; } | ||
79 | .macro { color: #94BFF3; } | 80 | .macro { color: #94BFF3; } |
80 | .module { color: #AFD8AF; } | 81 | .module { color: #AFD8AF; } |
81 | .variable { color: #DCDCCC; } | 82 | .variable { color: #DCDCCC; } |
diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs index be1a0f12b..46c718c91 100644 --- a/crates/ra_ide/src/syntax_highlighting/tags.rs +++ b/crates/ra_ide/src/syntax_highlighting/tags.rs | |||
@@ -15,6 +15,7 @@ pub struct HighlightModifiers(u32); | |||
15 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 15 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
16 | pub enum HighlightTag { | 16 | pub enum HighlightTag { |
17 | Attribute, | 17 | Attribute, |
18 | BoolLiteral, | ||
18 | BuiltinType, | 19 | BuiltinType, |
19 | ByteLiteral, | 20 | ByteLiteral, |
20 | CharLiteral, | 21 | CharLiteral, |
@@ -29,6 +30,7 @@ pub enum HighlightTag { | |||
29 | Macro, | 30 | Macro, |
30 | Module, | 31 | Module, |
31 | NumericLiteral, | 32 | NumericLiteral, |
33 | SelfKeyword, | ||
32 | SelfType, | 34 | SelfType, |
33 | Static, | 35 | Static, |
34 | StringLiteral, | 36 | StringLiteral, |
@@ -45,8 +47,10 @@ pub enum HighlightTag { | |||
45 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 47 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
46 | #[repr(u8)] | 48 | #[repr(u8)] |
47 | pub enum HighlightModifier { | 49 | pub enum HighlightModifier { |
50 | /// Used to differentiate individual elements within attributes. | ||
51 | Attribute = 0, | ||
48 | /// Used with keywords like `if` and `break`. | 52 | /// Used with keywords like `if` and `break`. |
49 | ControlFlow = 0, | 53 | ControlFlow, |
50 | /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is | 54 | /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is |
51 | /// not. | 55 | /// not. |
52 | Definition, | 56 | Definition, |
@@ -58,6 +62,7 @@ impl HighlightTag { | |||
58 | fn as_str(self) -> &'static str { | 62 | fn as_str(self) -> &'static str { |
59 | match self { | 63 | match self { |
60 | HighlightTag::Attribute => "attribute", | 64 | HighlightTag::Attribute => "attribute", |
65 | HighlightTag::BoolLiteral => "bool_literal", | ||
61 | HighlightTag::BuiltinType => "builtin_type", | 66 | HighlightTag::BuiltinType => "builtin_type", |
62 | HighlightTag::ByteLiteral => "byte_literal", | 67 | HighlightTag::ByteLiteral => "byte_literal", |
63 | HighlightTag::CharLiteral => "char_literal", | 68 | HighlightTag::CharLiteral => "char_literal", |
@@ -72,6 +77,7 @@ impl HighlightTag { | |||
72 | HighlightTag::Macro => "macro", | 77 | HighlightTag::Macro => "macro", |
73 | HighlightTag::Module => "module", | 78 | HighlightTag::Module => "module", |
74 | HighlightTag::NumericLiteral => "numeric_literal", | 79 | HighlightTag::NumericLiteral => "numeric_literal", |
80 | HighlightTag::SelfKeyword => "self_keyword", | ||
75 | HighlightTag::SelfType => "self_type", | 81 | HighlightTag::SelfType => "self_type", |
76 | HighlightTag::Static => "static", | 82 | HighlightTag::Static => "static", |
77 | HighlightTag::StringLiteral => "string_literal", | 83 | HighlightTag::StringLiteral => "string_literal", |
@@ -95,6 +101,7 @@ impl fmt::Display for HighlightTag { | |||
95 | 101 | ||
96 | impl HighlightModifier { | 102 | impl HighlightModifier { |
97 | const ALL: &'static [HighlightModifier] = &[ | 103 | const ALL: &'static [HighlightModifier] = &[ |
104 | HighlightModifier::Attribute, | ||
98 | HighlightModifier::ControlFlow, | 105 | HighlightModifier::ControlFlow, |
99 | HighlightModifier::Definition, | 106 | HighlightModifier::Definition, |
100 | HighlightModifier::Mutable, | 107 | HighlightModifier::Mutable, |
@@ -103,6 +110,7 @@ impl HighlightModifier { | |||
103 | 110 | ||
104 | fn as_str(self) -> &'static str { | 111 | fn as_str(self) -> &'static str { |
105 | match self { | 112 | match self { |
113 | HighlightModifier::Attribute => "attribute", | ||
106 | HighlightModifier::ControlFlow => "control", | 114 | HighlightModifier::ControlFlow => "control", |
107 | HighlightModifier::Definition => "declaration", | 115 | HighlightModifier::Definition => "declaration", |
108 | HighlightModifier::Mutable => "mutable", | 116 | HighlightModifier::Mutable => "mutable", |
diff --git a/crates/ra_ide/src/test_utils.rs b/crates/ra_ide/src/test_utils.rs deleted file mode 100644 index 48c8fd1f4..000000000 --- a/crates/ra_ide/src/test_utils.rs +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use ra_syntax::{SourceFile, TextSize}; | ||
4 | use ra_text_edit::TextEdit; | ||
5 | |||
6 | pub use test_utils::*; | ||
7 | |||
8 | pub fn check_action<F: Fn(&SourceFile, TextSize) -> Option<TextEdit>>( | ||
9 | before: &str, | ||
10 | after: &str, | ||
11 | f: F, | ||
12 | ) { | ||
13 | let (before_cursor_pos, before) = extract_offset(before); | ||
14 | let file = SourceFile::parse(&before).ok().unwrap(); | ||
15 | let result = f(&file, before_cursor_pos).expect("code action is not applicable"); | ||
16 | let actual = { | ||
17 | let mut actual = before.to_string(); | ||
18 | result.apply(&mut actual); | ||
19 | actual | ||
20 | }; | ||
21 | let actual_cursor_pos = | ||
22 | result.apply_to_offset(before_cursor_pos).expect("cursor position is affected by the edit"); | ||
23 | let actual = add_cursor(&actual, actual_cursor_pos); | ||
24 | assert_eq_text!(after, &actual); | ||
25 | } | ||
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs index 6f04f0be4..39bb3b357 100644 --- a/crates/ra_ide/src/typing.rs +++ b/crates/ra_ide/src/typing.rs | |||
@@ -17,7 +17,7 @@ mod on_enter; | |||
17 | 17 | ||
18 | use ra_db::{FilePosition, SourceDatabase}; | 18 | use ra_db::{FilePosition, SourceDatabase}; |
19 | use ra_fmt::leading_indent; | 19 | use ra_fmt::leading_indent; |
20 | use ra_ide_db::{source_change::SingleFileChange, RootDatabase}; | 20 | use ra_ide_db::RootDatabase; |
21 | use ra_syntax::{ | 21 | use ra_syntax::{ |
22 | algo::find_node_at_offset, | 22 | algo::find_node_at_offset, |
23 | ast::{self, AstToken}, | 23 | ast::{self, AstToken}, |
@@ -40,15 +40,11 @@ pub(crate) fn on_char_typed( | |||
40 | assert!(TRIGGER_CHARS.contains(char_typed)); | 40 | assert!(TRIGGER_CHARS.contains(char_typed)); |
41 | let file = &db.parse(position.file_id).tree(); | 41 | let file = &db.parse(position.file_id).tree(); |
42 | assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); | 42 | assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); |
43 | let single_file_change = on_char_typed_inner(file, position.offset, char_typed)?; | 43 | let text_edit = on_char_typed_inner(file, position.offset, char_typed)?; |
44 | Some(single_file_change.into_source_change(position.file_id)) | 44 | Some(SourceChange::source_file_edit_from(position.file_id, text_edit)) |
45 | } | 45 | } |
46 | 46 | ||
47 | fn on_char_typed_inner( | 47 | fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> { |
48 | file: &SourceFile, | ||
49 | offset: TextSize, | ||
50 | char_typed: char, | ||
51 | ) -> Option<SingleFileChange> { | ||
52 | assert!(TRIGGER_CHARS.contains(char_typed)); | 48 | assert!(TRIGGER_CHARS.contains(char_typed)); |
53 | match char_typed { | 49 | match char_typed { |
54 | '.' => on_dot_typed(file, offset), | 50 | '.' => on_dot_typed(file, offset), |
@@ -61,7 +57,7 @@ fn on_char_typed_inner( | |||
61 | /// Returns an edit which should be applied after `=` was typed. Primarily, | 57 | /// Returns an edit which should be applied after `=` was typed. Primarily, |
62 | /// this works when adding `let =`. | 58 | /// this works when adding `let =`. |
63 | // FIXME: use a snippet completion instead of this hack here. | 59 | // FIXME: use a snippet completion instead of this hack here. |
64 | fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> { | 60 | fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { |
65 | assert_eq!(file.syntax().text().char_at(offset), Some('=')); | 61 | assert_eq!(file.syntax().text().char_at(offset), Some('=')); |
66 | let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; | 62 | let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; |
67 | if let_stmt.semicolon_token().is_some() { | 63 | if let_stmt.semicolon_token().is_some() { |
@@ -79,15 +75,11 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> | |||
79 | return None; | 75 | return None; |
80 | } | 76 | } |
81 | let offset = let_stmt.syntax().text_range().end(); | 77 | let offset = let_stmt.syntax().text_range().end(); |
82 | Some(SingleFileChange { | 78 | Some(TextEdit::insert(offset, ";".to_string())) |
83 | label: "add semicolon".to_string(), | ||
84 | edit: TextEdit::insert(offset, ";".to_string()), | ||
85 | cursor_position: None, | ||
86 | }) | ||
87 | } | 79 | } |
88 | 80 | ||
89 | /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. | 81 | /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. |
90 | fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> { | 82 | fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { |
91 | assert_eq!(file.syntax().text().char_at(offset), Some('.')); | 83 | assert_eq!(file.syntax().text().char_at(offset), Some('.')); |
92 | let whitespace = | 84 | let whitespace = |
93 | file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; | 85 | file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; |
@@ -108,15 +100,11 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> | |||
108 | return None; | 100 | return None; |
109 | } | 101 | } |
110 | 102 | ||
111 | Some(SingleFileChange { | 103 | Some(TextEdit::replace(TextRange::new(offset - current_indent_len, offset), target_indent)) |
112 | label: "reindent dot".to_string(), | ||
113 | edit: TextEdit::replace(TextRange::new(offset - current_indent_len, offset), target_indent), | ||
114 | cursor_position: Some(offset + target_indent_len - current_indent_len + TextSize::of('.')), | ||
115 | }) | ||
116 | } | 104 | } |
117 | 105 | ||
118 | /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` | 106 | /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` |
119 | fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChange> { | 107 | fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { |
120 | let file_text = file.syntax().text(); | 108 | let file_text = file.syntax().text(); |
121 | assert_eq!(file_text.char_at(offset), Some('>')); | 109 | assert_eq!(file_text.char_at(offset), Some('>')); |
122 | let after_arrow = offset + TextSize::of('>'); | 110 | let after_arrow = offset + TextSize::of('>'); |
@@ -127,11 +115,7 @@ fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<SingleFileChang | |||
127 | return None; | 115 | return None; |
128 | } | 116 | } |
129 | 117 | ||
130 | Some(SingleFileChange { | 118 | Some(TextEdit::insert(after_arrow, " ".to_string())) |
131 | label: "add space after return type".to_string(), | ||
132 | edit: TextEdit::insert(after_arrow, " ".to_string()), | ||
133 | cursor_position: Some(after_arrow), | ||
134 | }) | ||
135 | } | 119 | } |
136 | 120 | ||
137 | #[cfg(test)] | 121 | #[cfg(test)] |
@@ -140,29 +124,23 @@ mod tests { | |||
140 | 124 | ||
141 | use super::*; | 125 | use super::*; |
142 | 126 | ||
143 | fn do_type_char(char_typed: char, before: &str) -> Option<(String, SingleFileChange)> { | 127 | fn do_type_char(char_typed: char, before: &str) -> Option<String> { |
144 | let (offset, before) = extract_offset(before); | 128 | let (offset, before) = extract_offset(before); |
145 | let edit = TextEdit::insert(offset, char_typed.to_string()); | 129 | let edit = TextEdit::insert(offset, char_typed.to_string()); |
146 | let mut before = before.to_string(); | 130 | let mut before = before.to_string(); |
147 | edit.apply(&mut before); | 131 | edit.apply(&mut before); |
148 | let parse = SourceFile::parse(&before); | 132 | let parse = SourceFile::parse(&before); |
149 | on_char_typed_inner(&parse.tree(), offset, char_typed).map(|it| { | 133 | on_char_typed_inner(&parse.tree(), offset, char_typed).map(|it| { |
150 | it.edit.apply(&mut before); | 134 | it.apply(&mut before); |
151 | (before.to_string(), it) | 135 | before.to_string() |
152 | }) | 136 | }) |
153 | } | 137 | } |
154 | 138 | ||
155 | fn type_char(char_typed: char, before: &str, after: &str) { | 139 | fn type_char(char_typed: char, before: &str, after: &str) { |
156 | let (actual, file_change) = do_type_char(char_typed, before) | 140 | let actual = do_type_char(char_typed, before) |
157 | .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed)); | 141 | .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed)); |
158 | 142 | ||
159 | if after.contains("<|>") { | 143 | assert_eq_text!(after, &actual); |
160 | let (offset, after) = extract_offset(after); | ||
161 | assert_eq_text!(&after, &actual); | ||
162 | assert_eq!(file_change.cursor_position, Some(offset)) | ||
163 | } else { | ||
164 | assert_eq_text!(after, &actual); | ||
165 | } | ||
166 | } | 144 | } |
167 | 145 | ||
168 | fn type_char_noop(char_typed: char, before: &str) { | 146 | fn type_char_noop(char_typed: char, before: &str) { |
@@ -350,6 +328,6 @@ fn foo() { | |||
350 | 328 | ||
351 | #[test] | 329 | #[test] |
352 | fn adds_space_after_return_type() { | 330 | fn adds_space_after_return_type() { |
353 | type_char('>', "fn foo() -<|>{ 92 }", "fn foo() -><|> { 92 }") | 331 | type_char('>', "fn foo() -<|>{ 92 }", "fn foo() -> { 92 }") |
354 | } | 332 | } |
355 | } | 333 | } |
diff --git a/crates/ra_ide/src/typing/on_enter.rs b/crates/ra_ide/src/typing/on_enter.rs index 78a40cc94..a40d8af9c 100644 --- a/crates/ra_ide/src/typing/on_enter.rs +++ b/crates/ra_ide/src/typing/on_enter.rs | |||
@@ -11,9 +11,7 @@ use ra_syntax::{ | |||
11 | }; | 11 | }; |
12 | use ra_text_edit::TextEdit; | 12 | use ra_text_edit::TextEdit; |
13 | 13 | ||
14 | use crate::{SourceChange, SourceFileEdit}; | 14 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { |
15 | |||
16 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<SourceChange> { | ||
17 | let parse = db.parse(position.file_id); | 15 | let parse = db.parse(position.file_id); |
18 | let file = parse.tree(); | 16 | let file = parse.tree(); |
19 | let comment = file | 17 | let comment = file |
@@ -38,17 +36,10 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Sour | |||
38 | } | 36 | } |
39 | 37 | ||
40 | let indent = node_indent(&file, comment.syntax())?; | 38 | let indent = node_indent(&file, comment.syntax())?; |
41 | let inserted = format!("\n{}{} ", indent, prefix); | 39 | let inserted = format!("\n{}{} $0", indent, prefix); |
42 | let cursor_position = position.offset + TextSize::of(&inserted); | ||
43 | let edit = TextEdit::insert(position.offset, inserted); | 40 | let edit = TextEdit::insert(position.offset, inserted); |
44 | 41 | ||
45 | Some( | 42 | Some(edit) |
46 | SourceChange::source_file_edit( | ||
47 | "On enter", | ||
48 | SourceFileEdit { edit, file_id: position.file_id }, | ||
49 | ) | ||
50 | .with_cursor(FilePosition { offset: cursor_position, file_id: position.file_id }), | ||
51 | ) | ||
52 | } | 43 | } |
53 | 44 | ||
54 | fn followed_by_comment(comment: &ast::Comment) -> bool { | 45 | fn followed_by_comment(comment: &ast::Comment) -> bool { |
@@ -84,7 +75,7 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option<SmolStr> { | |||
84 | 75 | ||
85 | #[cfg(test)] | 76 | #[cfg(test)] |
86 | mod tests { | 77 | mod tests { |
87 | use test_utils::{add_cursor, assert_eq_text, extract_offset}; | 78 | use test_utils::{assert_eq_text, extract_offset}; |
88 | 79 | ||
89 | use crate::mock_analysis::single_file; | 80 | use crate::mock_analysis::single_file; |
90 | 81 | ||
@@ -95,10 +86,8 @@ mod tests { | |||
95 | let (analysis, file_id) = single_file(&before); | 86 | let (analysis, file_id) = single_file(&before); |
96 | let result = analysis.on_enter(FilePosition { offset, file_id }).unwrap()?; | 87 | let result = analysis.on_enter(FilePosition { offset, file_id }).unwrap()?; |
97 | 88 | ||
98 | assert_eq!(result.source_file_edits.len(), 1); | ||
99 | let mut actual = before.to_string(); | 89 | let mut actual = before.to_string(); |
100 | result.source_file_edits[0].edit.apply(&mut actual); | 90 | result.apply(&mut actual); |
101 | let actual = add_cursor(&actual, result.cursor_position.unwrap().offset); | ||
102 | Some(actual) | 91 | Some(actual) |
103 | } | 92 | } |
104 | 93 | ||
@@ -121,7 +110,7 @@ fn foo() { | |||
121 | ", | 110 | ", |
122 | r" | 111 | r" |
123 | /// Some docs | 112 | /// Some docs |
124 | /// <|> | 113 | /// $0 |
125 | fn foo() { | 114 | fn foo() { |
126 | } | 115 | } |
127 | ", | 116 | ", |
@@ -137,7 +126,7 @@ impl S { | |||
137 | r" | 126 | r" |
138 | impl S { | 127 | impl S { |
139 | /// Some | 128 | /// Some |
140 | /// <|> docs. | 129 | /// $0 docs. |
141 | fn foo() {} | 130 | fn foo() {} |
142 | } | 131 | } |
143 | ", | 132 | ", |
@@ -151,7 +140,7 @@ fn foo() { | |||
151 | ", | 140 | ", |
152 | r" | 141 | r" |
153 | /// | 142 | /// |
154 | /// <|> Some docs | 143 | /// $0 Some docs |
155 | fn foo() { | 144 | fn foo() { |
156 | } | 145 | } |
157 | ", | 146 | ", |
@@ -175,7 +164,7 @@ fn main() { | |||
175 | r" | 164 | r" |
176 | fn main() { | 165 | fn main() { |
177 | // Fix | 166 | // Fix |
178 | // <|> me | 167 | // $0 me |
179 | let x = 1 + 1; | 168 | let x = 1 + 1; |
180 | } | 169 | } |
181 | ", | 170 | ", |
@@ -195,7 +184,7 @@ fn main() { | |||
195 | r" | 184 | r" |
196 | fn main() { | 185 | fn main() { |
197 | // Fix | 186 | // Fix |
198 | // <|> | 187 | // $0 |
199 | // me | 188 | // me |
200 | let x = 1 + 1; | 189 | let x = 1 + 1; |
201 | } | 190 | } |
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 4f37954bf..1b74e6558 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs | |||
@@ -3,7 +3,6 @@ | |||
3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. | 3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. |
4 | 4 | ||
5 | pub mod line_index; | 5 | pub mod line_index; |
6 | pub mod line_index_utils; | ||
7 | pub mod symbol_index; | 6 | pub mod symbol_index; |
8 | pub mod change; | 7 | pub mod change; |
9 | pub mod defs; | 8 | pub mod defs; |
diff --git a/crates/ra_ide_db/src/line_index_utils.rs b/crates/ra_ide_db/src/line_index_utils.rs deleted file mode 100644 index 7fa6fc448..000000000 --- a/crates/ra_ide_db/src/line_index_utils.rs +++ /dev/null | |||
@@ -1,302 +0,0 @@ | |||
1 | //! Code actions can specify desirable final position of the cursor. | ||
2 | //! | ||
3 | //! The position is specified as a `TextSize` in the final file. We need to send | ||
4 | //! it in `(Line, Column)` coordinate though. However, we only have a LineIndex | ||
5 | //! for a file pre-edit! | ||
6 | //! | ||
7 | //! Code in this module applies this "to (Line, Column) after edit" | ||
8 | //! transformation. | ||
9 | |||
10 | use std::convert::TryInto; | ||
11 | |||
12 | use ra_syntax::{TextRange, TextSize}; | ||
13 | use ra_text_edit::{Indel, TextEdit}; | ||
14 | |||
15 | use crate::line_index::{LineCol, LineIndex, Utf16Char}; | ||
16 | |||
17 | pub fn translate_offset_with_edit( | ||
18 | line_index: &LineIndex, | ||
19 | offset: TextSize, | ||
20 | text_edit: &TextEdit, | ||
21 | ) -> LineCol { | ||
22 | let mut state = Edits::from_text_edit(&text_edit); | ||
23 | |||
24 | let mut res = RunningLineCol::new(); | ||
25 | |||
26 | macro_rules! test_step { | ||
27 | ($x:ident) => { | ||
28 | match &$x { | ||
29 | Step::Newline(n) => { | ||
30 | if offset < *n { | ||
31 | return res.to_line_col(offset); | ||
32 | } else { | ||
33 | res.add_line(*n); | ||
34 | } | ||
35 | } | ||
36 | Step::Utf16Char(x) => { | ||
37 | if offset < x.end() { | ||
38 | // if the offset is inside a multibyte char it's invalid | ||
39 | // clamp it to the start of the char | ||
40 | let clamp = offset.min(x.start()); | ||
41 | return res.to_line_col(clamp); | ||
42 | } else { | ||
43 | res.adjust_col(*x); | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | }; | ||
48 | } | ||
49 | |||
50 | for orig_step in LineIndexStepIter::from(line_index) { | ||
51 | loop { | ||
52 | let translated_step = state.translate_step(&orig_step); | ||
53 | match state.next_steps(&translated_step) { | ||
54 | NextSteps::Use => { | ||
55 | test_step!(translated_step); | ||
56 | break; | ||
57 | } | ||
58 | NextSteps::ReplaceMany(ns) => { | ||
59 | for n in ns { | ||
60 | test_step!(n); | ||
61 | } | ||
62 | break; | ||
63 | } | ||
64 | NextSteps::AddMany(ns) => { | ||
65 | for n in ns { | ||
66 | test_step!(n); | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | loop { | ||
74 | match state.next_inserted_steps() { | ||
75 | None => break, | ||
76 | Some(ns) => { | ||
77 | for n in ns { | ||
78 | test_step!(n); | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | res.to_line_col(offset) | ||
85 | } | ||
86 | |||
87 | #[derive(Debug, Clone)] | ||
88 | enum Step { | ||
89 | Newline(TextSize), | ||
90 | Utf16Char(TextRange), | ||
91 | } | ||
92 | |||
93 | #[derive(Debug)] | ||
94 | struct LineIndexStepIter<'a> { | ||
95 | line_index: &'a LineIndex, | ||
96 | next_newline_idx: usize, | ||
97 | utf16_chars: Option<(TextSize, std::slice::Iter<'a, Utf16Char>)>, | ||
98 | } | ||
99 | |||
100 | impl LineIndexStepIter<'_> { | ||
101 | fn from(line_index: &LineIndex) -> LineIndexStepIter { | ||
102 | let mut x = LineIndexStepIter { line_index, next_newline_idx: 0, utf16_chars: None }; | ||
103 | // skip first newline since it's not real | ||
104 | x.next(); | ||
105 | x | ||
106 | } | ||
107 | } | ||
108 | |||
109 | impl Iterator for LineIndexStepIter<'_> { | ||
110 | type Item = Step; | ||
111 | fn next(&mut self) -> Option<Step> { | ||
112 | self.utf16_chars | ||
113 | .as_mut() | ||
114 | .and_then(|(newline, x)| { | ||
115 | let x = x.next()?; | ||
116 | Some(Step::Utf16Char(TextRange::new(*newline + x.start, *newline + x.end))) | ||
117 | }) | ||
118 | .or_else(|| { | ||
119 | let next_newline = *self.line_index.newlines.get(self.next_newline_idx)?; | ||
120 | self.utf16_chars = self | ||
121 | .line_index | ||
122 | .utf16_lines | ||
123 | .get(&(self.next_newline_idx as u32)) | ||
124 | .map(|x| (next_newline, x.iter())); | ||
125 | self.next_newline_idx += 1; | ||
126 | Some(Step::Newline(next_newline)) | ||
127 | }) | ||
128 | } | ||
129 | } | ||
130 | |||
131 | #[derive(Debug)] | ||
132 | struct OffsetStepIter<'a> { | ||
133 | text: &'a str, | ||
134 | offset: TextSize, | ||
135 | } | ||
136 | |||
137 | impl Iterator for OffsetStepIter<'_> { | ||
138 | type Item = Step; | ||
139 | fn next(&mut self) -> Option<Step> { | ||
140 | let (next, next_offset) = self | ||
141 | .text | ||
142 | .char_indices() | ||
143 | .filter_map(|(i, c)| { | ||
144 | let i: TextSize = i.try_into().unwrap(); | ||
145 | let char_len = TextSize::of(c); | ||
146 | if c == '\n' { | ||
147 | let next_offset = self.offset + i + char_len; | ||
148 | let next = Step::Newline(next_offset); | ||
149 | Some((next, next_offset)) | ||
150 | } else { | ||
151 | if !c.is_ascii() { | ||
152 | let start = self.offset + i; | ||
153 | let end = start + char_len; | ||
154 | let next = Step::Utf16Char(TextRange::new(start, end)); | ||
155 | let next_offset = end; | ||
156 | Some((next, next_offset)) | ||
157 | } else { | ||
158 | None | ||
159 | } | ||
160 | } | ||
161 | }) | ||
162 | .next()?; | ||
163 | let next_idx: usize = (next_offset - self.offset).into(); | ||
164 | self.text = &self.text[next_idx..]; | ||
165 | self.offset = next_offset; | ||
166 | Some(next) | ||
167 | } | ||
168 | } | ||
169 | |||
170 | #[derive(Debug)] | ||
171 | enum NextSteps<'a> { | ||
172 | Use, | ||
173 | ReplaceMany(OffsetStepIter<'a>), | ||
174 | AddMany(OffsetStepIter<'a>), | ||
175 | } | ||
176 | |||
177 | #[derive(Debug)] | ||
178 | struct TranslatedEdit<'a> { | ||
179 | delete: TextRange, | ||
180 | insert: &'a str, | ||
181 | diff: i64, | ||
182 | } | ||
183 | |||
184 | struct Edits<'a> { | ||
185 | edits: &'a [Indel], | ||
186 | current: Option<TranslatedEdit<'a>>, | ||
187 | acc_diff: i64, | ||
188 | } | ||
189 | |||
190 | impl<'a> Edits<'a> { | ||
191 | fn from_text_edit(text_edit: &'a TextEdit) -> Edits<'a> { | ||
192 | let mut x = Edits { edits: text_edit.as_indels(), current: None, acc_diff: 0 }; | ||
193 | x.advance_edit(); | ||
194 | x | ||
195 | } | ||
196 | fn advance_edit(&mut self) { | ||
197 | self.acc_diff += self.current.as_ref().map_or(0, |x| x.diff); | ||
198 | match self.edits.split_first() { | ||
199 | Some((next, rest)) => { | ||
200 | let delete = self.translate_range(next.delete); | ||
201 | let diff = next.insert.len() as i64 - usize::from(next.delete.len()) as i64; | ||
202 | self.current = Some(TranslatedEdit { delete, insert: &next.insert, diff }); | ||
203 | self.edits = rest; | ||
204 | } | ||
205 | None => { | ||
206 | self.current = None; | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | fn next_inserted_steps(&mut self) -> Option<OffsetStepIter<'a>> { | ||
212 | let cur = self.current.as_ref()?; | ||
213 | let res = Some(OffsetStepIter { offset: cur.delete.start(), text: &cur.insert }); | ||
214 | self.advance_edit(); | ||
215 | res | ||
216 | } | ||
217 | |||
218 | fn next_steps(&mut self, step: &Step) -> NextSteps { | ||
219 | let step_pos = match *step { | ||
220 | Step::Newline(n) => n, | ||
221 | Step::Utf16Char(r) => r.end(), | ||
222 | }; | ||
223 | match &mut self.current { | ||
224 | Some(edit) => { | ||
225 | if step_pos <= edit.delete.start() { | ||
226 | NextSteps::Use | ||
227 | } else if step_pos <= edit.delete.end() { | ||
228 | let iter = OffsetStepIter { offset: edit.delete.start(), text: &edit.insert }; | ||
229 | // empty slice to avoid returning steps again | ||
230 | edit.insert = &edit.insert[edit.insert.len()..]; | ||
231 | NextSteps::ReplaceMany(iter) | ||
232 | } else { | ||
233 | let iter = OffsetStepIter { offset: edit.delete.start(), text: &edit.insert }; | ||
234 | // empty slice to avoid returning steps again | ||
235 | edit.insert = &edit.insert[edit.insert.len()..]; | ||
236 | self.advance_edit(); | ||
237 | NextSteps::AddMany(iter) | ||
238 | } | ||
239 | } | ||
240 | None => NextSteps::Use, | ||
241 | } | ||
242 | } | ||
243 | |||
244 | fn translate_range(&self, range: TextRange) -> TextRange { | ||
245 | if self.acc_diff == 0 { | ||
246 | range | ||
247 | } else { | ||
248 | let start = self.translate(range.start()); | ||
249 | let end = self.translate(range.end()); | ||
250 | TextRange::new(start, end) | ||
251 | } | ||
252 | } | ||
253 | |||
254 | fn translate(&self, x: TextSize) -> TextSize { | ||
255 | if self.acc_diff == 0 { | ||
256 | x | ||
257 | } else { | ||
258 | TextSize::from((usize::from(x) as i64 + self.acc_diff) as u32) | ||
259 | } | ||
260 | } | ||
261 | |||
262 | fn translate_step(&self, x: &Step) -> Step { | ||
263 | if self.acc_diff == 0 { | ||
264 | x.clone() | ||
265 | } else { | ||
266 | match *x { | ||
267 | Step::Newline(n) => Step::Newline(self.translate(n)), | ||
268 | Step::Utf16Char(r) => Step::Utf16Char(self.translate_range(r)), | ||
269 | } | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | |||
274 | #[derive(Debug)] | ||
275 | struct RunningLineCol { | ||
276 | line: u32, | ||
277 | last_newline: TextSize, | ||
278 | col_adjust: TextSize, | ||
279 | } | ||
280 | |||
281 | impl RunningLineCol { | ||
282 | fn new() -> RunningLineCol { | ||
283 | RunningLineCol { line: 0, last_newline: TextSize::from(0), col_adjust: TextSize::from(0) } | ||
284 | } | ||
285 | |||
286 | fn to_line_col(&self, offset: TextSize) -> LineCol { | ||
287 | LineCol { | ||
288 | line: self.line, | ||
289 | col_utf16: ((offset - self.last_newline) - self.col_adjust).into(), | ||
290 | } | ||
291 | } | ||
292 | |||
293 | fn add_line(&mut self, newline: TextSize) { | ||
294 | self.line += 1; | ||
295 | self.last_newline = newline; | ||
296 | self.col_adjust = TextSize::from(0); | ||
297 | } | ||
298 | |||
299 | fn adjust_col(&mut self, range: TextRange) { | ||
300 | self.col_adjust += range.len() - TextSize::from(1); | ||
301 | } | ||
302 | } | ||
diff --git a/crates/ra_ide_db/src/source_change.rs b/crates/ra_ide_db/src/source_change.rs index c64165f3a..e713f4b7e 100644 --- a/crates/ra_ide_db/src/source_change.rs +++ b/crates/ra_ide_db/src/source_change.rs | |||
@@ -3,94 +3,35 @@ | |||
3 | //! | 3 | //! |
4 | //! It can be viewed as a dual for `AnalysisChange`. | 4 | //! It can be viewed as a dual for `AnalysisChange`. |
5 | 5 | ||
6 | use ra_db::{FileId, FilePosition, RelativePathBuf, SourceRootId}; | 6 | use ra_db::{FileId, RelativePathBuf, SourceRootId}; |
7 | use ra_text_edit::{TextEdit, TextSize}; | 7 | use ra_text_edit::TextEdit; |
8 | 8 | ||
9 | #[derive(Debug, Clone)] | 9 | #[derive(Debug, Clone)] |
10 | pub struct SourceChange { | 10 | pub struct SourceChange { |
11 | /// For display in the undo log in the editor | ||
12 | pub label: String, | ||
13 | pub source_file_edits: Vec<SourceFileEdit>, | 11 | pub source_file_edits: Vec<SourceFileEdit>, |
14 | pub file_system_edits: Vec<FileSystemEdit>, | 12 | pub file_system_edits: Vec<FileSystemEdit>, |
15 | pub cursor_position: Option<FilePosition>, | ||
16 | pub is_snippet: bool, | 13 | pub is_snippet: bool, |
17 | } | 14 | } |
18 | 15 | ||
19 | impl SourceChange { | 16 | impl SourceChange { |
20 | /// Creates a new SourceChange with the given label | 17 | /// Creates a new SourceChange with the given label |
21 | /// from the edits. | 18 | /// from the edits. |
22 | pub fn from_edits<L: Into<String>>( | 19 | pub fn from_edits( |
23 | label: L, | ||
24 | source_file_edits: Vec<SourceFileEdit>, | 20 | source_file_edits: Vec<SourceFileEdit>, |
25 | file_system_edits: Vec<FileSystemEdit>, | 21 | file_system_edits: Vec<FileSystemEdit>, |
26 | ) -> Self { | 22 | ) -> Self { |
27 | SourceChange { | 23 | SourceChange { source_file_edits, file_system_edits, is_snippet: false } |
28 | label: label.into(), | ||
29 | source_file_edits, | ||
30 | file_system_edits, | ||
31 | cursor_position: None, | ||
32 | is_snippet: false, | ||
33 | } | ||
34 | } | 24 | } |
35 | 25 | ||
36 | /// Creates a new SourceChange with the given label, | 26 | /// Creates a new SourceChange with the given label, |
37 | /// containing only the given `SourceFileEdits`. | 27 | /// containing only the given `SourceFileEdits`. |
38 | pub fn source_file_edits<L: Into<String>>(label: L, edits: Vec<SourceFileEdit>) -> Self { | 28 | pub fn source_file_edits(edits: Vec<SourceFileEdit>) -> Self { |
39 | let label = label.into(); | 29 | SourceChange { source_file_edits: edits, file_system_edits: vec![], is_snippet: false } |
40 | assert!(label.starts_with(char::is_uppercase)); | ||
41 | SourceChange { | ||
42 | label: label, | ||
43 | source_file_edits: edits, | ||
44 | file_system_edits: vec![], | ||
45 | cursor_position: None, | ||
46 | is_snippet: false, | ||
47 | } | ||
48 | } | ||
49 | |||
50 | /// Creates a new SourceChange with the given label, | ||
51 | /// containing only the given `FileSystemEdits`. | ||
52 | pub(crate) fn file_system_edits<L: Into<String>>(label: L, edits: Vec<FileSystemEdit>) -> Self { | ||
53 | SourceChange { | ||
54 | label: label.into(), | ||
55 | source_file_edits: vec![], | ||
56 | file_system_edits: edits, | ||
57 | cursor_position: None, | ||
58 | is_snippet: false, | ||
59 | } | ||
60 | } | ||
61 | |||
62 | /// Creates a new SourceChange with the given label, | ||
63 | /// containing only a single `SourceFileEdit`. | ||
64 | pub fn source_file_edit<L: Into<String>>(label: L, edit: SourceFileEdit) -> Self { | ||
65 | SourceChange::source_file_edits(label, vec![edit]) | ||
66 | } | ||
67 | |||
68 | /// Creates a new SourceChange with the given label | ||
69 | /// from the given `FileId` and `TextEdit` | ||
70 | pub fn source_file_edit_from<L: Into<String>>( | ||
71 | label: L, | ||
72 | file_id: FileId, | ||
73 | edit: TextEdit, | ||
74 | ) -> Self { | ||
75 | SourceChange::source_file_edit(label, SourceFileEdit { file_id, edit }) | ||
76 | } | 30 | } |
77 | |||
78 | /// Creates a new SourceChange with the given label | 31 | /// Creates a new SourceChange with the given label |
79 | /// from the given `FileId` and `TextEdit` | 32 | /// from the given `FileId` and `TextEdit` |
80 | pub fn file_system_edit<L: Into<String>>(label: L, edit: FileSystemEdit) -> Self { | 33 | pub fn source_file_edit_from(file_id: FileId, edit: TextEdit) -> Self { |
81 | SourceChange::file_system_edits(label, vec![edit]) | 34 | SourceFileEdit { file_id, edit }.into() |
82 | } | ||
83 | |||
84 | /// Sets the cursor position to the given `FilePosition` | ||
85 | pub fn with_cursor(mut self, cursor_position: FilePosition) -> Self { | ||
86 | self.cursor_position = Some(cursor_position); | ||
87 | self | ||
88 | } | ||
89 | |||
90 | /// Sets the cursor position to the given `FilePosition` | ||
91 | pub fn with_cursor_opt(mut self, cursor_position: Option<FilePosition>) -> Self { | ||
92 | self.cursor_position = cursor_position; | ||
93 | self | ||
94 | } | 35 | } |
95 | } | 36 | } |
96 | 37 | ||
@@ -100,25 +41,27 @@ pub struct SourceFileEdit { | |||
100 | pub edit: TextEdit, | 41 | pub edit: TextEdit, |
101 | } | 42 | } |
102 | 43 | ||
44 | impl From<SourceFileEdit> for SourceChange { | ||
45 | fn from(edit: SourceFileEdit) -> SourceChange { | ||
46 | SourceChange { | ||
47 | source_file_edits: vec![edit], | ||
48 | file_system_edits: Vec::new(), | ||
49 | is_snippet: false, | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
103 | #[derive(Debug, Clone)] | 54 | #[derive(Debug, Clone)] |
104 | pub enum FileSystemEdit { | 55 | pub enum FileSystemEdit { |
105 | CreateFile { source_root: SourceRootId, path: RelativePathBuf }, | 56 | CreateFile { source_root: SourceRootId, path: RelativePathBuf }, |
106 | MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf }, | 57 | MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf }, |
107 | } | 58 | } |
108 | 59 | ||
109 | pub struct SingleFileChange { | 60 | impl From<FileSystemEdit> for SourceChange { |
110 | pub label: String, | 61 | fn from(edit: FileSystemEdit) -> SourceChange { |
111 | pub edit: TextEdit, | ||
112 | pub cursor_position: Option<TextSize>, | ||
113 | } | ||
114 | |||
115 | impl SingleFileChange { | ||
116 | pub fn into_source_change(self, file_id: FileId) -> SourceChange { | ||
117 | SourceChange { | 62 | SourceChange { |
118 | label: self.label, | 63 | source_file_edits: Vec::new(), |
119 | source_file_edits: vec![SourceFileEdit { file_id, edit: self.edit }], | 64 | file_system_edits: vec![edit], |
120 | file_system_edits: Vec::new(), | ||
121 | cursor_position: self.cursor_position.map(|offset| FilePosition { file_id, offset }), | ||
122 | is_snippet: false, | 65 | is_snippet: false, |
123 | } | 66 | } |
124 | } | 67 | } |
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index c07ff488e..a9a5cc7bc 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.9.0" | 14 | itertools = "0.9.0" |
15 | rowan = "0.10.0" | 15 | rowan = "0.10.0" |
16 | rustc_lexer = { version = "656.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "660.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index 74906d8a6..3cd6d99c3 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs | |||
@@ -6,6 +6,7 @@ use crate::{ | |||
6 | ast::{AstToken, Comment, RawString, String, Whitespace}, | 6 | ast::{AstToken, Comment, RawString, String, Whitespace}, |
7 | TextRange, TextSize, | 7 | TextRange, TextSize, |
8 | }; | 8 | }; |
9 | use rustc_lexer::unescape::{unescape_literal, Mode}; | ||
9 | 10 | ||
10 | impl Comment { | 11 | impl Comment { |
11 | pub fn kind(&self) -> CommentKind { | 12 | pub fn kind(&self) -> CommentKind { |
@@ -147,7 +148,7 @@ impl HasStringValue for String { | |||
147 | 148 | ||
148 | let mut buf = std::string::String::with_capacity(text.len()); | 149 | let mut buf = std::string::String::with_capacity(text.len()); |
149 | let mut has_error = false; | 150 | let mut has_error = false; |
150 | rustc_lexer::unescape::unescape_str(text, &mut |_, unescaped_char| match unescaped_char { | 151 | unescape_literal(text, Mode::Str, &mut |_, unescaped_char| match unescaped_char { |
151 | Ok(c) => buf.push(c), | 152 | Ok(c) => buf.push(c), |
152 | Err(_) => has_error = true, | 153 | Err(_) => has_error = true, |
153 | }); | 154 | }); |
@@ -498,7 +499,7 @@ impl HasFormatSpecifier for String { | |||
498 | let offset = self.text_range_between_quotes()?.start() - self.syntax().text_range().start(); | 499 | let offset = self.text_range_between_quotes()?.start() - self.syntax().text_range().start(); |
499 | 500 | ||
500 | let mut res = Vec::with_capacity(text.len()); | 501 | let mut res = Vec::with_capacity(text.len()); |
501 | rustc_lexer::unescape::unescape_str(text, &mut |range, unescaped_char| { | 502 | unescape_literal(text, Mode::Str, &mut |range, unescaped_char| { |
502 | res.push(( | 503 | res.push(( |
503 | TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap()) | 504 | TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap()) |
504 | + offset, | 505 | + offset, |
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index d68cf0a82..fdec48fb0 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -2,15 +2,15 @@ | |||
2 | 2 | ||
3 | mod block; | 3 | mod block; |
4 | 4 | ||
5 | use std::convert::TryFrom; | ||
6 | |||
7 | use rustc_lexer::unescape; | ||
8 | |||
9 | use crate::{ | 5 | use crate::{ |
10 | ast, match_ast, AstNode, SyntaxError, | 6 | ast, match_ast, AstNode, SyntaxError, |
11 | SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF}, | 7 | SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF}, |
12 | SyntaxNode, SyntaxToken, TextSize, T, | 8 | SyntaxNode, SyntaxToken, TextSize, T, |
13 | }; | 9 | }; |
10 | use rustc_lexer::unescape::{ | ||
11 | self, unescape_byte, unescape_byte_literal, unescape_char, unescape_literal, Mode, | ||
12 | }; | ||
13 | use std::convert::TryFrom; | ||
14 | 14 | ||
15 | fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> &'static str { | 15 | fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> &'static str { |
16 | use unescape::EscapeError as EE; | 16 | use unescape::EscapeError as EE; |
@@ -81,10 +81,8 @@ fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> &'static str { | |||
81 | 81 | ||
82 | pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { | 82 | pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { |
83 | // FIXME: | 83 | // FIXME: |
84 | // * Add validation of character literal containing only a single char | 84 | // * Add unescape validation of raw string literals and raw byte string literals |
85 | // * Add validation of `crate` keyword not appearing in the middle of the symbol path | ||
86 | // * Add validation of doc comments are being attached to nodes | 85 | // * Add validation of doc comments are being attached to nodes |
87 | // * Remove validation of unterminated literals (it is already implemented in `tokenize()`) | ||
88 | 86 | ||
89 | let mut errors = Vec::new(); | 87 | let mut errors = Vec::new(); |
90 | for node in root.descendants() { | 88 | for node in root.descendants() { |
@@ -121,18 +119,18 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { | |||
121 | 119 | ||
122 | match token.kind() { | 120 | match token.kind() { |
123 | BYTE => { | 121 | BYTE => { |
124 | if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape::unescape_byte) { | 122 | if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) { |
125 | push_err(2, e); | 123 | push_err(2, e); |
126 | } | 124 | } |
127 | } | 125 | } |
128 | CHAR => { | 126 | CHAR => { |
129 | if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape::unescape_char) { | 127 | if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape_char) { |
130 | push_err(1, e); | 128 | push_err(1, e); |
131 | } | 129 | } |
132 | } | 130 | } |
133 | BYTE_STRING => { | 131 | BYTE_STRING => { |
134 | if let Some(without_quotes) = unquote(text, 2, '"') { | 132 | if let Some(without_quotes) = unquote(text, 2, '"') { |
135 | unescape::unescape_byte_str(without_quotes, &mut |range, char| { | 133 | unescape_byte_literal(without_quotes, Mode::ByteStr, &mut |range, char| { |
136 | if let Err(err) = char { | 134 | if let Err(err) = char { |
137 | push_err(2, (range.start, err)); | 135 | push_err(2, (range.start, err)); |
138 | } | 136 | } |
@@ -141,7 +139,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { | |||
141 | } | 139 | } |
142 | STRING => { | 140 | STRING => { |
143 | if let Some(without_quotes) = unquote(text, 1, '"') { | 141 | if let Some(without_quotes) = unquote(text, 1, '"') { |
144 | unescape::unescape_str(without_quotes, &mut |range, char| { | 142 | unescape_literal(without_quotes, Mode::Str, &mut |range, char| { |
145 | if let Err(err) = char { | 143 | if let Err(err) = char { |
146 | push_err(1, (range.start, err)); | 144 | push_err(1, (range.start, err)); |
147 | } | 145 | } |
diff --git a/crates/ra_text_edit/src/lib.rs b/crates/ra_text_edit/src/lib.rs index c4f945101..25554f583 100644 --- a/crates/ra_text_edit/src/lib.rs +++ b/crates/ra_text_edit/src/lib.rs | |||
@@ -3,6 +3,7 @@ | |||
3 | //! `rust-analyzer` never mutates text itself and only sends diffs to clients, | 3 | //! `rust-analyzer` never mutates text itself and only sends diffs to clients, |
4 | //! so `TextEdit` is the ultimate representation of the work done by | 4 | //! so `TextEdit` is the ultimate representation of the work done by |
5 | //! rust-analyzer. | 5 | //! rust-analyzer. |
6 | use std::{slice, vec}; | ||
6 | 7 | ||
7 | pub use text_size::{TextRange, TextSize}; | 8 | pub use text_size::{TextRange, TextSize}; |
8 | 9 | ||
@@ -16,7 +17,7 @@ pub struct Indel { | |||
16 | pub delete: TextRange, | 17 | pub delete: TextRange, |
17 | } | 18 | } |
18 | 19 | ||
19 | #[derive(Debug, Clone)] | 20 | #[derive(Default, Debug, Clone)] |
20 | pub struct TextEdit { | 21 | pub struct TextEdit { |
21 | indels: Vec<Indel>, | 22 | indels: Vec<Indel>, |
22 | } | 23 | } |
@@ -63,25 +64,24 @@ impl TextEdit { | |||
63 | builder.finish() | 64 | builder.finish() |
64 | } | 65 | } |
65 | 66 | ||
66 | pub(crate) fn from_indels(mut indels: Vec<Indel>) -> TextEdit { | 67 | pub fn len(&self) -> usize { |
67 | indels.sort_by_key(|a| (a.delete.start(), a.delete.end())); | 68 | self.indels.len() |
68 | for (a1, a2) in indels.iter().zip(indels.iter().skip(1)) { | ||
69 | assert!(a1.delete.end() <= a2.delete.start()) | ||
70 | } | ||
71 | TextEdit { indels } | ||
72 | } | 69 | } |
73 | 70 | ||
74 | pub fn is_empty(&self) -> bool { | 71 | pub fn is_empty(&self) -> bool { |
75 | self.indels.is_empty() | 72 | self.indels.is_empty() |
76 | } | 73 | } |
77 | 74 | ||
78 | // FXME: impl IntoIter instead | 75 | pub fn iter(&self) -> slice::Iter<'_, Indel> { |
79 | pub fn as_indels(&self) -> &[Indel] { | 76 | self.indels.iter() |
80 | &self.indels | 77 | } |
78 | |||
79 | pub fn into_iter(self) -> vec::IntoIter<Indel> { | ||
80 | self.indels.into_iter() | ||
81 | } | 81 | } |
82 | 82 | ||
83 | pub fn apply(&self, text: &mut String) { | 83 | pub fn apply(&self, text: &mut String) { |
84 | match self.indels.len() { | 84 | match self.len() { |
85 | 0 => return, | 85 | 0 => return, |
86 | 1 => { | 86 | 1 => { |
87 | self.indels[0].apply(text); | 87 | self.indels[0].apply(text); |
@@ -114,6 +114,17 @@ impl TextEdit { | |||
114 | *text = buf | 114 | *text = buf |
115 | } | 115 | } |
116 | 116 | ||
117 | pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> { | ||
118 | // FIXME: can be done without allocating intermediate vector | ||
119 | let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>(); | ||
120 | if !check_disjoint(&mut all) { | ||
121 | return Err(other); | ||
122 | } | ||
123 | self.indels.extend(other.indels); | ||
124 | assert!(check_disjoint(&mut self.indels)); | ||
125 | Ok(()) | ||
126 | } | ||
127 | |||
117 | pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> { | 128 | pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> { |
118 | let mut res = offset; | 129 | let mut res = offset; |
119 | for indel in self.indels.iter() { | 130 | for indel in self.indels.iter() { |
@@ -141,9 +152,19 @@ impl TextEditBuilder { | |||
141 | self.indels.push(Indel::insert(offset, text)) | 152 | self.indels.push(Indel::insert(offset, text)) |
142 | } | 153 | } |
143 | pub fn finish(self) -> TextEdit { | 154 | pub fn finish(self) -> TextEdit { |
144 | TextEdit::from_indels(self.indels) | 155 | let mut indels = self.indels; |
156 | assert!(check_disjoint(&mut indels)); | ||
157 | TextEdit { indels } | ||
145 | } | 158 | } |
146 | pub fn invalidates_offset(&self, offset: TextSize) -> bool { | 159 | pub fn invalidates_offset(&self, offset: TextSize) -> bool { |
147 | self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset)) | 160 | self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset)) |
148 | } | 161 | } |
149 | } | 162 | } |
163 | |||
164 | fn check_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool { | ||
165 | indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end())); | ||
166 | indels | ||
167 | .iter() | ||
168 | .zip(indels.iter().skip(1)) | ||
169 | .all(|(l, r)| l.borrow().delete.end() <= r.borrow().delete.start()) | ||
170 | } | ||
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 9b2d29b1d..65b487db3 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -40,6 +40,7 @@ ra_project_model = { path = "../ra_project_model" } | |||
40 | ra_syntax = { path = "../ra_syntax" } | 40 | ra_syntax = { path = "../ra_syntax" } |
41 | ra_text_edit = { path = "../ra_text_edit" } | 41 | ra_text_edit = { path = "../ra_text_edit" } |
42 | ra_vfs = "0.6.0" | 42 | ra_vfs = "0.6.0" |
43 | ra_cfg = { path = "../ra_cfg"} | ||
43 | 44 | ||
44 | # This should only be used in CLI | 45 | # This should only be used in CLI |
45 | ra_db = { path = "../ra_db" } | 46 | ra_db = { path = "../ra_db" } |
@@ -55,6 +56,8 @@ winapi = "0.3.8" | |||
55 | tempfile = "3.1.0" | 56 | tempfile = "3.1.0" |
56 | insta = "0.16.0" | 57 | insta = "0.16.0" |
57 | test_utils = { path = "../test_utils" } | 58 | test_utils = { path = "../test_utils" } |
59 | mbe = { path = "../ra_mbe", package = "ra_mbe" } | ||
60 | tt = { path = "../ra_tt", package = "ra_tt" } | ||
58 | 61 | ||
59 | [features] | 62 | [features] |
60 | jemalloc = [ "ra_prof/jemalloc" ] | 63 | jemalloc = [ "ra_prof/jemalloc" ] |
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 09908458d..e82fd57de 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -74,12 +74,25 @@ fn run_server() -> Result<()> { | |||
74 | log::info!("lifecycle: server started"); | 74 | log::info!("lifecycle: server started"); |
75 | 75 | ||
76 | let (connection, io_threads) = Connection::stdio(); | 76 | let (connection, io_threads) = Connection::stdio(); |
77 | let server_capabilities = serde_json::to_value(rust_analyzer::server_capabilities()).unwrap(); | ||
78 | 77 | ||
79 | let initialize_params = connection.initialize(server_capabilities)?; | 78 | let (initialize_id, initialize_params) = connection.initialize_start()?; |
80 | let initialize_params = | 79 | let initialize_params = |
81 | from_json::<lsp_types::InitializeParams>("InitializeParams", initialize_params)?; | 80 | from_json::<lsp_types::InitializeParams>("InitializeParams", initialize_params)?; |
82 | 81 | ||
82 | let server_capabilities = rust_analyzer::server_capabilities(&initialize_params.capabilities); | ||
83 | |||
84 | let initialize_result = lsp_types::InitializeResult { | ||
85 | capabilities: server_capabilities, | ||
86 | server_info: Some(lsp_types::ServerInfo { | ||
87 | name: String::from("rust-analyzer"), | ||
88 | version: Some(String::from(env!("REV"))), | ||
89 | }), | ||
90 | }; | ||
91 | |||
92 | let initialize_result = serde_json::to_value(initialize_result).unwrap(); | ||
93 | |||
94 | connection.initialize_finish(initialize_id, initialize_result)?; | ||
95 | |||
83 | if let Some(client_info) = initialize_params.client_info { | 96 | if let Some(client_info) = initialize_params.client_info { |
84 | log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); | 97 | log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); |
85 | } | 98 | } |
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 110c9a442..345693524 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -1,19 +1,23 @@ | |||
1 | //! Advertizes the capabilities of the LSP Server. | 1 | //! Advertizes the capabilities of the LSP Server. |
2 | use std::env; | 2 | use std::env; |
3 | 3 | ||
4 | use crate::semantic_tokens; | ||
5 | |||
6 | use lsp_types::{ | 4 | use lsp_types::{ |
7 | CallHierarchyServerCapability, CodeActionOptions, CodeActionProviderCapability, | 5 | CallHierarchyServerCapability, ClientCapabilities, CodeActionOptions, |
8 | CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, | 6 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, |
9 | FoldingRangeProviderCapability, ImplementationProviderCapability, RenameOptions, | 7 | DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, |
10 | RenameProviderCapability, SaveOptions, SelectionRangeProviderCapability, | 8 | ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions, |
11 | SemanticTokensDocumentProvider, SemanticTokensLegend, SemanticTokensOptions, | 9 | SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend, |
12 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, | 10 | SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, |
13 | TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, | 11 | TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability, |
12 | WorkDoneProgressOptions, | ||
14 | }; | 13 | }; |
14 | use serde_json::json; | ||
15 | |||
16 | use crate::semantic_tokens; | ||
17 | |||
18 | pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities { | ||
19 | let code_action_provider = code_action_capabilities(client_caps); | ||
15 | 20 | ||
16 | pub fn server_capabilities() -> ServerCapabilities { | ||
17 | ServerCapabilities { | 21 | ServerCapabilities { |
18 | text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { | 22 | text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { |
19 | open_close: Some(true), | 23 | open_close: Some(true), |
@@ -45,20 +49,7 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
45 | document_highlight_provider: Some(true), | 49 | document_highlight_provider: Some(true), |
46 | document_symbol_provider: Some(true), | 50 | document_symbol_provider: Some(true), |
47 | workspace_symbol_provider: Some(true), | 51 | workspace_symbol_provider: Some(true), |
48 | code_action_provider: Some(CodeActionProviderCapability::Options(CodeActionOptions { | 52 | code_action_provider: Some(code_action_provider), |
49 | // Advertise support for all built-in CodeActionKinds | ||
50 | code_action_kinds: Some(vec![ | ||
51 | lsp_types::code_action_kind::EMPTY.to_string(), | ||
52 | lsp_types::code_action_kind::QUICKFIX.to_string(), | ||
53 | lsp_types::code_action_kind::REFACTOR.to_string(), | ||
54 | lsp_types::code_action_kind::REFACTOR_EXTRACT.to_string(), | ||
55 | lsp_types::code_action_kind::REFACTOR_INLINE.to_string(), | ||
56 | lsp_types::code_action_kind::REFACTOR_REWRITE.to_string(), | ||
57 | lsp_types::code_action_kind::SOURCE.to_string(), | ||
58 | lsp_types::code_action_kind::SOURCE_ORGANIZE_IMPORTS.to_string(), | ||
59 | ]), | ||
60 | work_done_progress_options: Default::default(), | ||
61 | })), | ||
62 | code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), | 53 | code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), |
63 | document_formatting_provider: Some(true), | 54 | document_formatting_provider: Some(true), |
64 | document_range_formatting_provider: None, | 55 | document_range_formatting_provider: None, |
@@ -91,6 +82,37 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
91 | } | 82 | } |
92 | .into(), | 83 | .into(), |
93 | ), | 84 | ), |
94 | experimental: Default::default(), | 85 | experimental: Some(json!({ |
86 | "joinLines": true, | ||
87 | "ssr": true, | ||
88 | "onEnter": true, | ||
89 | "parentModule": true, | ||
90 | })), | ||
95 | } | 91 | } |
96 | } | 92 | } |
93 | |||
94 | fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability { | ||
95 | client_caps | ||
96 | .text_document | ||
97 | .as_ref() | ||
98 | .and_then(|it| it.code_action.as_ref()) | ||
99 | .and_then(|it| it.code_action_literal_support.as_ref()) | ||
100 | .map_or(CodeActionProviderCapability::Simple(true), |_| { | ||
101 | CodeActionProviderCapability::Options(CodeActionOptions { | ||
102 | // Advertise support for all built-in CodeActionKinds. | ||
103 | // Ideally we would base this off of the client capabilities | ||
104 | // but the client is supposed to fall back gracefully for unknown values. | ||
105 | code_action_kinds: Some(vec![ | ||
106 | lsp_types::code_action_kind::EMPTY.to_string(), | ||
107 | lsp_types::code_action_kind::QUICKFIX.to_string(), | ||
108 | lsp_types::code_action_kind::REFACTOR.to_string(), | ||
109 | lsp_types::code_action_kind::REFACTOR_EXTRACT.to_string(), | ||
110 | lsp_types::code_action_kind::REFACTOR_INLINE.to_string(), | ||
111 | lsp_types::code_action_kind::REFACTOR_REWRITE.to_string(), | ||
112 | lsp_types::code_action_kind::SOURCE.to_string(), | ||
113 | lsp_types::code_action_kind::SOURCE_ORGANIZE_IMPORTS.to_string(), | ||
114 | ]), | ||
115 | work_done_progress_options: Default::default(), | ||
116 | }) | ||
117 | }) | ||
118 | } | ||
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 5e5a17943..441fb61df 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs | |||
@@ -4,6 +4,7 @@ use ra_ide::{FileId, RunnableKind, TestId}; | |||
4 | use ra_project_model::{self, ProjectWorkspace, TargetKind}; | 4 | use ra_project_model::{self, ProjectWorkspace, TargetKind}; |
5 | 5 | ||
6 | use crate::{world::WorldSnapshot, Result}; | 6 | use crate::{world::WorldSnapshot, Result}; |
7 | use ra_syntax::SmolStr; | ||
7 | 8 | ||
8 | /// Abstract representation of Cargo target. | 9 | /// Abstract representation of Cargo target. |
9 | /// | 10 | /// |
@@ -20,6 +21,7 @@ impl CargoTargetSpec { | |||
20 | pub(crate) fn runnable_args( | 21 | pub(crate) fn runnable_args( |
21 | spec: Option<CargoTargetSpec>, | 22 | spec: Option<CargoTargetSpec>, |
22 | kind: &RunnableKind, | 23 | kind: &RunnableKind, |
24 | features_needed: &Vec<SmolStr>, | ||
23 | ) -> Result<(Vec<String>, Vec<String>)> { | 25 | ) -> Result<(Vec<String>, Vec<String>)> { |
24 | let mut args = Vec::new(); | 26 | let mut args = Vec::new(); |
25 | let mut extra_args = Vec::new(); | 27 | let mut extra_args = Vec::new(); |
@@ -73,6 +75,12 @@ impl CargoTargetSpec { | |||
73 | } | 75 | } |
74 | } | 76 | } |
75 | } | 77 | } |
78 | |||
79 | features_needed.iter().for_each(|feature| { | ||
80 | args.push("--features".to_string()); | ||
81 | args.push(feature.to_string()); | ||
82 | }); | ||
83 | |||
76 | Ok((args, extra_args)) | 84 | Ok((args, extra_args)) |
77 | } | 85 | } |
78 | 86 | ||
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index d75c48597..c0f7c2c0c 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -102,6 +102,7 @@ pub struct ClientCapsConfig { | |||
102 | pub hierarchical_symbols: bool, | 102 | pub hierarchical_symbols: bool, |
103 | pub code_action_literals: bool, | 103 | pub code_action_literals: bool, |
104 | pub work_done_progress: bool, | 104 | pub work_done_progress: bool, |
105 | pub code_action_group: bool, | ||
105 | } | 106 | } |
106 | 107 | ||
107 | impl Default for Config { | 108 | impl Default for Config { |
@@ -268,10 +269,8 @@ impl Config { | |||
268 | { | 269 | { |
269 | self.client_caps.hierarchical_symbols = value | 270 | self.client_caps.hierarchical_symbols = value |
270 | } | 271 | } |
271 | if let Some(value) = doc_caps | 272 | if let Some(value) = |
272 | .code_action | 273 | doc_caps.code_action.as_ref().map(|it| it.code_action_literal_support.is_some()) |
273 | .as_ref() | ||
274 | .and_then(|it| Some(it.code_action_literal_support.is_some())) | ||
275 | { | 274 | { |
276 | self.client_caps.code_action_literals = value; | 275 | self.client_caps.code_action_literals = value; |
277 | } | 276 | } |
@@ -294,9 +293,13 @@ impl Config { | |||
294 | 293 | ||
295 | self.assist.allow_snippets(false); | 294 | self.assist.allow_snippets(false); |
296 | if let Some(experimental) = &caps.experimental { | 295 | if let Some(experimental) = &caps.experimental { |
297 | let enable = | 296 | let snippet_text_edit = |
298 | experimental.get("snippetTextEdit").and_then(|it| it.as_bool()) == Some(true); | 297 | experimental.get("snippetTextEdit").and_then(|it| it.as_bool()) == Some(true); |
299 | self.assist.allow_snippets(enable); | 298 | self.assist.allow_snippets(snippet_text_edit); |
299 | |||
300 | let code_action_group = | ||
301 | experimental.get("codeActionGroup").and_then(|it| it.as_bool()) == Some(true); | ||
302 | self.client_caps.code_action_group = code_action_group | ||
300 | } | 303 | } |
301 | } | 304 | } |
302 | } | 305 | } |
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap index 96466b5c9..c40cfdcdc 100644 --- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap +++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap | |||
@@ -65,6 +65,7 @@ expression: diag | |||
65 | fixes: [ | 65 | fixes: [ |
66 | CodeAction { | 66 | CodeAction { |
67 | title: "return the expression directly", | 67 | title: "return the expression directly", |
68 | group: None, | ||
68 | kind: Some( | 69 | kind: Some( |
69 | "quickfix", | 70 | "quickfix", |
70 | ), | 71 | ), |
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap index 8f962277f..6dd3fcb2e 100644 --- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap +++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap | |||
@@ -50,6 +50,7 @@ expression: diag | |||
50 | fixes: [ | 50 | fixes: [ |
51 | CodeAction { | 51 | CodeAction { |
52 | title: "consider prefixing with an underscore", | 52 | title: "consider prefixing with an underscore", |
53 | group: None, | ||
53 | kind: Some( | 54 | kind: Some( |
54 | "quickfix", | 55 | "quickfix", |
55 | ), | 56 | ), |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index afea59525..a500d670a 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -145,6 +145,7 @@ fn map_rust_child_diagnostic( | |||
145 | } else { | 145 | } else { |
146 | MappedRustChildDiagnostic::SuggestedFix(lsp_ext::CodeAction { | 146 | MappedRustChildDiagnostic::SuggestedFix(lsp_ext::CodeAction { |
147 | title: rd.message.clone(), | 147 | title: rd.message.clone(), |
148 | group: None, | ||
148 | kind: Some("quickfix".to_string()), | 149 | kind: Some("quickfix".to_string()), |
149 | edit: Some(lsp_ext::SnippetWorkspaceEdit { | 150 | edit: Some(lsp_ext::SnippetWorkspaceEdit { |
150 | // FIXME: there's no good reason to use edit_map here.... | 151 | // FIXME: there's no good reason to use edit_map here.... |
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index f75a26eb7..acb1dacb6 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use std::{collections::HashMap, path::PathBuf}; | 3 | use std::{collections::HashMap, path::PathBuf}; |
4 | 4 | ||
5 | use lsp_types::request::Request; | 5 | use lsp_types::request::Request; |
6 | use lsp_types::{Location, Position, Range, TextDocumentIdentifier}; | 6 | use lsp_types::{Position, Range, TextDocumentIdentifier}; |
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
8 | use serde::{Deserialize, Serialize}; | 8 | use serde::{Deserialize, Serialize}; |
9 | 9 | ||
@@ -38,13 +38,6 @@ pub struct SyntaxTreeParams { | |||
38 | pub range: Option<Range>, | 38 | pub range: Option<Range>, |
39 | } | 39 | } |
40 | 40 | ||
41 | #[derive(Deserialize, Serialize, Debug)] | ||
42 | #[serde(rename_all = "camelCase")] | ||
43 | pub struct ExpandedMacro { | ||
44 | pub name: String, | ||
45 | pub expansion: String, | ||
46 | } | ||
47 | |||
48 | pub enum ExpandMacro {} | 41 | pub enum ExpandMacro {} |
49 | 42 | ||
50 | impl Request for ExpandMacro { | 43 | impl Request for ExpandMacro { |
@@ -57,53 +50,60 @@ impl Request for ExpandMacro { | |||
57 | #[serde(rename_all = "camelCase")] | 50 | #[serde(rename_all = "camelCase")] |
58 | pub struct ExpandMacroParams { | 51 | pub struct ExpandMacroParams { |
59 | pub text_document: TextDocumentIdentifier, | 52 | pub text_document: TextDocumentIdentifier, |
60 | pub position: Option<Position>, | 53 | pub position: Position, |
54 | } | ||
55 | |||
56 | #[derive(Deserialize, Serialize, Debug)] | ||
57 | #[serde(rename_all = "camelCase")] | ||
58 | pub struct ExpandedMacro { | ||
59 | pub name: String, | ||
60 | pub expansion: String, | ||
61 | } | 61 | } |
62 | 62 | ||
63 | pub enum FindMatchingBrace {} | 63 | pub enum MatchingBrace {} |
64 | 64 | ||
65 | impl Request for FindMatchingBrace { | 65 | impl Request for MatchingBrace { |
66 | type Params = FindMatchingBraceParams; | 66 | type Params = MatchingBraceParams; |
67 | type Result = Vec<Position>; | 67 | type Result = Vec<Position>; |
68 | const METHOD: &'static str = "rust-analyzer/findMatchingBrace"; | 68 | const METHOD: &'static str = "experimental/matchingBrace"; |
69 | } | 69 | } |
70 | 70 | ||
71 | #[derive(Deserialize, Serialize, Debug)] | 71 | #[derive(Deserialize, Serialize, Debug)] |
72 | #[serde(rename_all = "camelCase")] | 72 | #[serde(rename_all = "camelCase")] |
73 | pub struct FindMatchingBraceParams { | 73 | pub struct MatchingBraceParams { |
74 | pub text_document: TextDocumentIdentifier, | 74 | pub text_document: TextDocumentIdentifier, |
75 | pub offsets: Vec<Position>, | 75 | pub positions: Vec<Position>, |
76 | } | 76 | } |
77 | 77 | ||
78 | pub enum ParentModule {} | 78 | pub enum ParentModule {} |
79 | 79 | ||
80 | impl Request for ParentModule { | 80 | impl Request for ParentModule { |
81 | type Params = lsp_types::TextDocumentPositionParams; | 81 | type Params = lsp_types::TextDocumentPositionParams; |
82 | type Result = Vec<Location>; | 82 | type Result = Option<lsp_types::GotoDefinitionResponse>; |
83 | const METHOD: &'static str = "rust-analyzer/parentModule"; | 83 | const METHOD: &'static str = "experimental/parentModule"; |
84 | } | 84 | } |
85 | 85 | ||
86 | pub enum JoinLines {} | 86 | pub enum JoinLines {} |
87 | 87 | ||
88 | impl Request for JoinLines { | 88 | impl Request for JoinLines { |
89 | type Params = JoinLinesParams; | 89 | type Params = JoinLinesParams; |
90 | type Result = SourceChange; | 90 | type Result = Vec<lsp_types::TextEdit>; |
91 | const METHOD: &'static str = "rust-analyzer/joinLines"; | 91 | const METHOD: &'static str = "experimental/joinLines"; |
92 | } | 92 | } |
93 | 93 | ||
94 | #[derive(Deserialize, Serialize, Debug)] | 94 | #[derive(Deserialize, Serialize, Debug)] |
95 | #[serde(rename_all = "camelCase")] | 95 | #[serde(rename_all = "camelCase")] |
96 | pub struct JoinLinesParams { | 96 | pub struct JoinLinesParams { |
97 | pub text_document: TextDocumentIdentifier, | 97 | pub text_document: TextDocumentIdentifier, |
98 | pub range: Range, | 98 | pub ranges: Vec<Range>, |
99 | } | 99 | } |
100 | 100 | ||
101 | pub enum OnEnter {} | 101 | pub enum OnEnter {} |
102 | 102 | ||
103 | impl Request for OnEnter { | 103 | impl Request for OnEnter { |
104 | type Params = lsp_types::TextDocumentPositionParams; | 104 | type Params = lsp_types::TextDocumentPositionParams; |
105 | type Result = Option<SourceChange>; | 105 | type Result = Option<Vec<SnippetTextEdit>>; |
106 | const METHOD: &'static str = "rust-analyzer/onEnter"; | 106 | const METHOD: &'static str = "experimental/onEnter"; |
107 | } | 107 | } |
108 | 108 | ||
109 | pub enum Runnables {} | 109 | pub enum Runnables {} |
@@ -133,14 +133,6 @@ pub struct Runnable { | |||
133 | pub cwd: Option<PathBuf>, | 133 | pub cwd: Option<PathBuf>, |
134 | } | 134 | } |
135 | 135 | ||
136 | #[derive(Deserialize, Serialize, Debug)] | ||
137 | #[serde(rename_all = "camelCase")] | ||
138 | pub struct SourceChange { | ||
139 | pub label: String, | ||
140 | pub workspace_edit: SnippetWorkspaceEdit, | ||
141 | pub cursor_position: Option<lsp_types::TextDocumentPositionParams>, | ||
142 | } | ||
143 | |||
144 | pub enum InlayHints {} | 136 | pub enum InlayHints {} |
145 | 137 | ||
146 | impl Request for InlayHints { | 138 | impl Request for InlayHints { |
@@ -173,8 +165,8 @@ pub enum Ssr {} | |||
173 | 165 | ||
174 | impl Request for Ssr { | 166 | impl Request for Ssr { |
175 | type Params = SsrParams; | 167 | type Params = SsrParams; |
176 | type Result = SourceChange; | 168 | type Result = lsp_types::WorkspaceEdit; |
177 | const METHOD: &'static str = "rust-analyzer/ssr"; | 169 | const METHOD: &'static str = "experimental/ssr"; |
178 | } | 170 | } |
179 | 171 | ||
180 | #[derive(Debug, Deserialize, Serialize)] | 172 | #[derive(Debug, Deserialize, Serialize)] |
@@ -196,6 +188,8 @@ impl Request for CodeActionRequest { | |||
196 | pub struct CodeAction { | 188 | pub struct CodeAction { |
197 | pub title: String, | 189 | pub title: String, |
198 | #[serde(skip_serializing_if = "Option::is_none")] | 190 | #[serde(skip_serializing_if = "Option::is_none")] |
191 | pub group: Option<String>, | ||
192 | #[serde(skip_serializing_if = "Option::is_none")] | ||
199 | pub kind: Option<String>, | 193 | pub kind: Option<String>, |
200 | #[serde(skip_serializing_if = "Option::is_none")] | 194 | #[serde(skip_serializing_if = "Option::is_none")] |
201 | pub command: Option<lsp_types::Command>, | 195 | pub command: Option<lsp_types::Command>, |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 87795fffb..f1287d52c 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -509,9 +509,7 @@ fn on_request( | |||
509 | .on_sync::<lsp_types::request::SelectionRangeRequest>(|s, p| { | 509 | .on_sync::<lsp_types::request::SelectionRangeRequest>(|s, p| { |
510 | handlers::handle_selection_range(s.snapshot(), p) | 510 | handlers::handle_selection_range(s.snapshot(), p) |
511 | })? | 511 | })? |
512 | .on_sync::<lsp_ext::FindMatchingBrace>(|s, p| { | 512 | .on_sync::<lsp_ext::MatchingBrace>(|s, p| handlers::handle_matching_brace(s.snapshot(), p))? |
513 | handlers::handle_find_matching_brace(s.snapshot(), p) | ||
514 | })? | ||
515 | .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)? | 513 | .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)? |
516 | .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)? | 514 | .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)? |
517 | .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)? | 515 | .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)? |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 4ff8fa69e..1f910ff82 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -15,14 +15,16 @@ use lsp_types::{ | |||
15 | DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location, | 15 | DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location, |
16 | MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, | 16 | MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, |
17 | SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, | 17 | SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, |
18 | SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, TextEdit, Url, WorkspaceEdit, | 18 | SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit, |
19 | }; | 19 | }; |
20 | use ra_cfg::CfgExpr; | ||
20 | use ra_ide::{ | 21 | use ra_ide::{ |
21 | Assist, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, | 22 | FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, |
23 | TextEdit, | ||
22 | }; | 24 | }; |
23 | use ra_prof::profile; | 25 | use ra_prof::profile; |
24 | use ra_project_model::TargetKind; | 26 | use ra_project_model::TargetKind; |
25 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; | 27 | use ra_syntax::{AstNode, SmolStr, SyntaxKind, TextRange, TextSize}; |
26 | use rustc_hash::FxHashMap; | 28 | use rustc_hash::FxHashMap; |
27 | use serde::{Deserialize, Serialize}; | 29 | use serde::{Deserialize, Serialize}; |
28 | use serde_json::to_value; | 30 | use serde_json::to_value; |
@@ -70,15 +72,10 @@ pub fn handle_expand_macro( | |||
70 | let _p = profile("handle_expand_macro"); | 72 | let _p = profile("handle_expand_macro"); |
71 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 73 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; |
72 | let line_index = world.analysis().file_line_index(file_id)?; | 74 | let line_index = world.analysis().file_line_index(file_id)?; |
73 | let offset = params.position.map(|p| from_proto::offset(&line_index, p)); | 75 | let offset = from_proto::offset(&line_index, params.position); |
74 | 76 | ||
75 | match offset { | 77 | let res = world.analysis().expand_macro(FilePosition { file_id, offset })?; |
76 | None => Ok(None), | 78 | Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion })) |
77 | Some(offset) => { | ||
78 | let res = world.analysis().expand_macro(FilePosition { file_id, offset })?; | ||
79 | Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion })) | ||
80 | } | ||
81 | } | ||
82 | } | 79 | } |
83 | 80 | ||
84 | pub fn handle_selection_range( | 81 | pub fn handle_selection_range( |
@@ -124,15 +121,15 @@ pub fn handle_selection_range( | |||
124 | Ok(Some(res?)) | 121 | Ok(Some(res?)) |
125 | } | 122 | } |
126 | 123 | ||
127 | pub fn handle_find_matching_brace( | 124 | pub fn handle_matching_brace( |
128 | world: WorldSnapshot, | 125 | world: WorldSnapshot, |
129 | params: lsp_ext::FindMatchingBraceParams, | 126 | params: lsp_ext::MatchingBraceParams, |
130 | ) -> Result<Vec<Position>> { | 127 | ) -> Result<Vec<Position>> { |
131 | let _p = profile("handle_find_matching_brace"); | 128 | let _p = profile("handle_matching_brace"); |
132 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 129 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; |
133 | let line_index = world.analysis().file_line_index(file_id)?; | 130 | let line_index = world.analysis().file_line_index(file_id)?; |
134 | let res = params | 131 | let res = params |
135 | .offsets | 132 | .positions |
136 | .into_iter() | 133 | .into_iter() |
137 | .map(|position| { | 134 | .map(|position| { |
138 | let offset = from_proto::offset(&line_index, position); | 135 | let offset = from_proto::offset(&line_index, position); |
@@ -149,30 +146,47 @@ pub fn handle_find_matching_brace( | |||
149 | pub fn handle_join_lines( | 146 | pub fn handle_join_lines( |
150 | world: WorldSnapshot, | 147 | world: WorldSnapshot, |
151 | params: lsp_ext::JoinLinesParams, | 148 | params: lsp_ext::JoinLinesParams, |
152 | ) -> Result<lsp_ext::SourceChange> { | 149 | ) -> Result<Vec<lsp_types::TextEdit>> { |
153 | let _p = profile("handle_join_lines"); | 150 | let _p = profile("handle_join_lines"); |
154 | let frange = from_proto::file_range(&world, params.text_document, params.range)?; | 151 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; |
155 | let source_change = world.analysis().join_lines(frange)?; | 152 | let line_index = world.analysis().file_line_index(file_id)?; |
156 | to_proto::source_change(&world, source_change) | 153 | let line_endings = world.file_line_endings(file_id); |
154 | let mut res = TextEdit::default(); | ||
155 | for range in params.ranges { | ||
156 | let range = from_proto::text_range(&line_index, range); | ||
157 | let edit = world.analysis().join_lines(FileRange { file_id, range })?; | ||
158 | match res.union(edit) { | ||
159 | Ok(()) => (), | ||
160 | Err(_edit) => { | ||
161 | // just ignore overlapping edits | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | let res = to_proto::text_edit_vec(&line_index, line_endings, res); | ||
166 | Ok(res) | ||
157 | } | 167 | } |
158 | 168 | ||
159 | pub fn handle_on_enter( | 169 | pub fn handle_on_enter( |
160 | world: WorldSnapshot, | 170 | world: WorldSnapshot, |
161 | params: lsp_types::TextDocumentPositionParams, | 171 | params: lsp_types::TextDocumentPositionParams, |
162 | ) -> Result<Option<lsp_ext::SourceChange>> { | 172 | ) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> { |
163 | let _p = profile("handle_on_enter"); | 173 | let _p = profile("handle_on_enter"); |
164 | let position = from_proto::file_position(&world, params)?; | 174 | let position = from_proto::file_position(&world, params)?; |
165 | match world.analysis().on_enter(position)? { | 175 | let edit = match world.analysis().on_enter(position)? { |
166 | None => Ok(None), | 176 | None => return Ok(None), |
167 | Some(source_change) => to_proto::source_change(&world, source_change).map(Some), | 177 | Some(it) => it, |
168 | } | 178 | }; |
179 | let line_index = world.analysis().file_line_index(position.file_id)?; | ||
180 | let line_endings = world.file_line_endings(position.file_id); | ||
181 | let edit = to_proto::snippet_text_edit_vec(&line_index, line_endings, true, edit); | ||
182 | Ok(Some(edit)) | ||
169 | } | 183 | } |
170 | 184 | ||
171 | // Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`. | 185 | // Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`. |
172 | pub fn handle_on_type_formatting( | 186 | pub fn handle_on_type_formatting( |
173 | world: WorldSnapshot, | 187 | world: WorldSnapshot, |
174 | params: lsp_types::DocumentOnTypeFormattingParams, | 188 | params: lsp_types::DocumentOnTypeFormattingParams, |
175 | ) -> Result<Option<Vec<TextEdit>>> { | 189 | ) -> Result<Option<Vec<lsp_types::TextEdit>>> { |
176 | let _p = profile("handle_on_type_formatting"); | 190 | let _p = profile("handle_on_type_formatting"); |
177 | let mut position = from_proto::file_position(&world, params.text_document_position)?; | 191 | let mut position = from_proto::file_position(&world, params.text_document_position)?; |
178 | let line_index = world.analysis().file_line_index(position.file_id)?; | 192 | let line_index = world.analysis().file_line_index(position.file_id)?; |
@@ -267,7 +281,7 @@ pub fn handle_document_symbol( | |||
267 | kind: symbol.kind, | 281 | kind: symbol.kind, |
268 | deprecated: symbol.deprecated, | 282 | deprecated: symbol.deprecated, |
269 | location: Location::new(url.clone(), symbol.range), | 283 | location: Location::new(url.clone(), symbol.range), |
270 | container_name: container_name, | 284 | container_name, |
271 | }); | 285 | }); |
272 | 286 | ||
273 | for child in symbol.children.iter().flatten() { | 287 | for child in symbol.children.iter().flatten() { |
@@ -330,11 +344,8 @@ pub fn handle_goto_definition( | |||
330 | None => return Ok(None), | 344 | None => return Ok(None), |
331 | Some(it) => it, | 345 | Some(it) => it, |
332 | }; | 346 | }; |
333 | let res = to_proto::goto_definition_response( | 347 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; |
334 | &world, | 348 | let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; |
335 | FileRange { file_id: position.file_id, range: nav_info.range }, | ||
336 | nav_info.info, | ||
337 | )?; | ||
338 | Ok(Some(res)) | 349 | Ok(Some(res)) |
339 | } | 350 | } |
340 | 351 | ||
@@ -348,11 +359,8 @@ pub fn handle_goto_implementation( | |||
348 | None => return Ok(None), | 359 | None => return Ok(None), |
349 | Some(it) => it, | 360 | Some(it) => it, |
350 | }; | 361 | }; |
351 | let res = to_proto::goto_definition_response( | 362 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; |
352 | &world, | 363 | let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; |
353 | FileRange { file_id: position.file_id, range: nav_info.range }, | ||
354 | nav_info.info, | ||
355 | )?; | ||
356 | Ok(Some(res)) | 364 | Ok(Some(res)) |
357 | } | 365 | } |
358 | 366 | ||
@@ -366,26 +374,20 @@ pub fn handle_goto_type_definition( | |||
366 | None => return Ok(None), | 374 | None => return Ok(None), |
367 | Some(it) => it, | 375 | Some(it) => it, |
368 | }; | 376 | }; |
369 | let res = to_proto::goto_definition_response( | 377 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; |
370 | &world, | 378 | let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; |
371 | FileRange { file_id: position.file_id, range: nav_info.range }, | ||
372 | nav_info.info, | ||
373 | )?; | ||
374 | Ok(Some(res)) | 379 | Ok(Some(res)) |
375 | } | 380 | } |
376 | 381 | ||
377 | pub fn handle_parent_module( | 382 | pub fn handle_parent_module( |
378 | world: WorldSnapshot, | 383 | world: WorldSnapshot, |
379 | params: lsp_types::TextDocumentPositionParams, | 384 | params: lsp_types::TextDocumentPositionParams, |
380 | ) -> Result<Vec<Location>> { | 385 | ) -> Result<Option<lsp_types::GotoDefinitionResponse>> { |
381 | let _p = profile("handle_parent_module"); | 386 | let _p = profile("handle_parent_module"); |
382 | let position = from_proto::file_position(&world, params)?; | 387 | let position = from_proto::file_position(&world, params)?; |
383 | world | 388 | let navs = world.analysis().parent_module(position)?; |
384 | .analysis() | 389 | let res = to_proto::goto_definition_response(&world, None, navs)?; |
385 | .parent_module(position)? | 390 | Ok(Some(res)) |
386 | .into_iter() | ||
387 | .map(|it| to_proto::location(&world, it.file_range())) | ||
388 | .collect::<Result<Vec<_>>>() | ||
389 | } | 391 | } |
390 | 392 | ||
391 | pub fn handle_runnables( | 393 | pub fn handle_runnables( |
@@ -618,7 +620,7 @@ pub fn handle_references( | |||
618 | pub fn handle_formatting( | 620 | pub fn handle_formatting( |
619 | world: WorldSnapshot, | 621 | world: WorldSnapshot, |
620 | params: DocumentFormattingParams, | 622 | params: DocumentFormattingParams, |
621 | ) -> Result<Option<Vec<TextEdit>>> { | 623 | ) -> Result<Option<Vec<lsp_types::TextEdit>>> { |
622 | let _p = profile("handle_formatting"); | 624 | let _p = profile("handle_formatting"); |
623 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 625 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; |
624 | let file = world.analysis().file_text(file_id)?; | 626 | let file = world.analysis().file_text(file_id)?; |
@@ -685,7 +687,7 @@ pub fn handle_formatting( | |||
685 | } | 687 | } |
686 | } | 688 | } |
687 | 689 | ||
688 | Ok(Some(vec![TextEdit { | 690 | Ok(Some(vec![lsp_types::TextEdit { |
689 | range: Range::new(Position::new(0, 0), end_position), | 691 | range: Range::new(Position::new(0, 0), end_position), |
690 | new_text: captured_stdout, | 692 | new_text: captured_stdout, |
691 | }])) | 693 | }])) |
@@ -706,6 +708,7 @@ pub fn handle_code_action( | |||
706 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 708 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; |
707 | let line_index = world.analysis().file_line_index(file_id)?; | 709 | let line_index = world.analysis().file_line_index(file_id)?; |
708 | let range = from_proto::text_range(&line_index, params.range); | 710 | let range = from_proto::text_range(&line_index, params.range); |
711 | let frange = FileRange { file_id, range }; | ||
709 | 712 | ||
710 | let diagnostics = world.analysis().diagnostics(file_id)?; | 713 | let diagnostics = world.analysis().diagnostics(file_id)?; |
711 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); | 714 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); |
@@ -716,10 +719,11 @@ pub fn handle_code_action( | |||
716 | .filter(|(diag_range, _fix)| diag_range.intersect(range).is_some()) | 719 | .filter(|(diag_range, _fix)| diag_range.intersect(range).is_some()) |
717 | .map(|(_range, fix)| fix); | 720 | .map(|(_range, fix)| fix); |
718 | 721 | ||
719 | for source_edit in fixes_from_diagnostics { | 722 | for fix in fixes_from_diagnostics { |
720 | let title = source_edit.label.clone(); | 723 | let title = fix.label; |
721 | let edit = to_proto::snippet_workspace_edit(&world, source_edit)?; | 724 | let edit = to_proto::snippet_workspace_edit(&world, fix.source_change)?; |
722 | let action = lsp_ext::CodeAction { title, kind: None, edit: Some(edit), command: None }; | 725 | let action = |
726 | lsp_ext::CodeAction { title, group: None, kind: None, edit: Some(edit), command: None }; | ||
723 | res.push(action); | 727 | res.push(action); |
724 | } | 728 | } |
725 | 729 | ||
@@ -731,53 +735,9 @@ pub fn handle_code_action( | |||
731 | res.push(fix.action.clone()); | 735 | res.push(fix.action.clone()); |
732 | } | 736 | } |
733 | 737 | ||
734 | let mut grouped_assists: FxHashMap<String, (usize, Vec<Assist>)> = FxHashMap::default(); | 738 | for assist in world.analysis().assists(&world.config.assist, frange)?.into_iter() { |
735 | for assist in | 739 | res.push(to_proto::code_action(&world, assist)?.into()); |
736 | world.analysis().assists(&world.config.assist, FileRange { file_id, range })?.into_iter() | ||
737 | { | ||
738 | match &assist.group_label { | ||
739 | Some(label) => grouped_assists | ||
740 | .entry(label.to_owned()) | ||
741 | .or_insert_with(|| { | ||
742 | let idx = res.len(); | ||
743 | let dummy = lsp_ext::CodeAction { | ||
744 | title: String::new(), | ||
745 | kind: None, | ||
746 | command: None, | ||
747 | edit: None, | ||
748 | }; | ||
749 | res.push(dummy); | ||
750 | (idx, Vec::new()) | ||
751 | }) | ||
752 | .1 | ||
753 | .push(assist), | ||
754 | None => { | ||
755 | res.push(to_proto::code_action(&world, assist)?.into()); | ||
756 | } | ||
757 | } | ||
758 | } | 740 | } |
759 | |||
760 | for (group_label, (idx, assists)) in grouped_assists { | ||
761 | if assists.len() == 1 { | ||
762 | res[idx] = to_proto::code_action(&world, assists.into_iter().next().unwrap())?.into(); | ||
763 | } else { | ||
764 | let title = group_label; | ||
765 | |||
766 | let mut arguments = Vec::with_capacity(assists.len()); | ||
767 | for assist in assists { | ||
768 | let source_change = to_proto::source_change(&world, assist.source_change)?; | ||
769 | arguments.push(to_value(source_change)?); | ||
770 | } | ||
771 | |||
772 | let command = Some(Command { | ||
773 | title: title.clone(), | ||
774 | command: "rust-analyzer.selectAndApplySourceChange".to_string(), | ||
775 | arguments: Some(vec![serde_json::Value::Array(arguments)]), | ||
776 | }); | ||
777 | res[idx] = lsp_ext::CodeAction { title, kind: None, edit: None, command }; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | Ok(Some(res)) | 741 | Ok(Some(res)) |
782 | } | 742 | } |
783 | 743 | ||
@@ -802,11 +762,11 @@ pub fn handle_code_lens( | |||
802 | for runnable in world.analysis().runnables(file_id)? { | 762 | for runnable in world.analysis().runnables(file_id)? { |
803 | let (run_title, debugee) = match &runnable.kind { | 763 | let (run_title, debugee) = match &runnable.kind { |
804 | RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => { | 764 | RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => { |
805 | ("▶️\u{fe0e}Run Test", true) | 765 | ("▶\u{fe0e} Run Test", true) |
806 | } | 766 | } |
807 | RunnableKind::DocTest { .. } => { | 767 | RunnableKind::DocTest { .. } => { |
808 | // cargo does not support -no-run for doctests | 768 | // cargo does not support -no-run for doctests |
809 | ("▶️\u{fe0e}Run Doctest", false) | 769 | ("▶\u{fe0e} Run Doctest", false) |
810 | } | 770 | } |
811 | RunnableKind::Bench { .. } => { | 771 | RunnableKind::Bench { .. } => { |
812 | // Nothing wrong with bench debugging | 772 | // Nothing wrong with bench debugging |
@@ -972,11 +932,11 @@ pub fn handle_document_highlight( | |||
972 | pub fn handle_ssr( | 932 | pub fn handle_ssr( |
973 | world: WorldSnapshot, | 933 | world: WorldSnapshot, |
974 | params: lsp_ext::SsrParams, | 934 | params: lsp_ext::SsrParams, |
975 | ) -> Result<lsp_ext::SourceChange> { | 935 | ) -> Result<lsp_types::WorkspaceEdit> { |
976 | let _p = profile("handle_ssr"); | 936 | let _p = profile("handle_ssr"); |
977 | let source_change = | 937 | let source_change = |
978 | world.analysis().structural_search_replace(¶ms.query, params.parse_only)??; | 938 | world.analysis().structural_search_replace(¶ms.query, params.parse_only)??; |
979 | to_proto::source_change(&world, source_change) | 939 | to_proto::workspace_edit(&world, source_change) |
980 | } | 940 | } |
981 | 941 | ||
982 | pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<DiagnosticTask> { | 942 | pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<DiagnosticTask> { |
@@ -1006,7 +966,12 @@ fn to_lsp_runnable( | |||
1006 | ) -> Result<lsp_ext::Runnable> { | 966 | ) -> Result<lsp_ext::Runnable> { |
1007 | let spec = CargoTargetSpec::for_file(world, file_id)?; | 967 | let spec = CargoTargetSpec::for_file(world, file_id)?; |
1008 | let target = spec.as_ref().map(|s| s.target.clone()); | 968 | let target = spec.as_ref().map(|s| s.target.clone()); |
1009 | let (args, extra_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind)?; | 969 | let mut features_needed = vec![]; |
970 | for cfg_expr in &runnable.cfg_exprs { | ||
971 | collect_minimal_features_needed(cfg_expr, &mut features_needed); | ||
972 | } | ||
973 | let (args, extra_args) = | ||
974 | CargoTargetSpec::runnable_args(spec, &runnable.kind, &features_needed)?; | ||
1010 | let line_index = world.analysis().file_line_index(file_id)?; | 975 | let line_index = world.analysis().file_line_index(file_id)?; |
1011 | let label = match &runnable.kind { | 976 | let label = match &runnable.kind { |
1012 | RunnableKind::Test { test_id, .. } => format!("test {}", test_id), | 977 | RunnableKind::Test { test_id, .. } => format!("test {}", test_id), |
@@ -1032,6 +997,26 @@ fn to_lsp_runnable( | |||
1032 | }) | 997 | }) |
1033 | } | 998 | } |
1034 | 999 | ||
1000 | /// Fill minimal features needed | ||
1001 | fn collect_minimal_features_needed(cfg_expr: &CfgExpr, features: &mut Vec<SmolStr>) { | ||
1002 | match cfg_expr { | ||
1003 | CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.clone()), | ||
1004 | CfgExpr::All(preds) => { | ||
1005 | preds.iter().for_each(|cfg| collect_minimal_features_needed(cfg, features)); | ||
1006 | } | ||
1007 | CfgExpr::Any(preds) => { | ||
1008 | for cfg in preds { | ||
1009 | let len_features = features.len(); | ||
1010 | collect_minimal_features_needed(cfg, features); | ||
1011 | if len_features != features.len() { | ||
1012 | break; | ||
1013 | } | ||
1014 | } | ||
1015 | } | ||
1016 | _ => {} | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1035 | pub fn handle_inlay_hints( | 1020 | pub fn handle_inlay_hints( |
1036 | world: WorldSnapshot, | 1021 | world: WorldSnapshot, |
1037 | params: InlayHintsParams, | 1022 | params: InlayHintsParams, |
@@ -1168,3 +1153,54 @@ pub fn handle_semantic_tokens_range( | |||
1168 | let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); | 1153 | let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); |
1169 | Ok(Some(semantic_tokens.into())) | 1154 | Ok(Some(semantic_tokens.into())) |
1170 | } | 1155 | } |
1156 | |||
1157 | #[cfg(test)] | ||
1158 | mod tests { | ||
1159 | use super::*; | ||
1160 | |||
1161 | use mbe::{ast_to_token_tree, TokenMap}; | ||
1162 | use ra_cfg::parse_cfg; | ||
1163 | use ra_syntax::{ | ||
1164 | ast::{self, AstNode}, | ||
1165 | SmolStr, | ||
1166 | }; | ||
1167 | |||
1168 | fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { | ||
1169 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | ||
1170 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
1171 | ast_to_token_tree(&tt).unwrap() | ||
1172 | } | ||
1173 | |||
1174 | #[test] | ||
1175 | fn test_cfg_expr_minimal_features_needed() { | ||
1176 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#); | ||
1177 | let cfg_expr = parse_cfg(&subtree); | ||
1178 | let mut min_features = vec![]; | ||
1179 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1180 | |||
1181 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
1182 | |||
1183 | let (subtree, _) = | ||
1184 | get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#); | ||
1185 | let cfg_expr = parse_cfg(&subtree); | ||
1186 | |||
1187 | let mut min_features = vec![]; | ||
1188 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1189 | assert_eq!(min_features, vec![SmolStr::new("baz"), SmolStr::new("foo")]); | ||
1190 | |||
1191 | let (subtree, _) = | ||
1192 | get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); | ||
1193 | let cfg_expr = parse_cfg(&subtree); | ||
1194 | |||
1195 | let mut min_features = vec![]; | ||
1196 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1197 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
1198 | |||
1199 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); | ||
1200 | let cfg_expr = parse_cfg(&subtree); | ||
1201 | |||
1202 | let mut min_features = vec![]; | ||
1203 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | ||
1204 | assert!(min_features.is_empty()); | ||
1205 | } | ||
1206 | } | ||
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index 2dc5cb119..6f125c37c 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -36,9 +36,11 @@ macro_rules! define_semantic_token_types { | |||
36 | 36 | ||
37 | define_semantic_token_types![ | 37 | define_semantic_token_types![ |
38 | (ATTRIBUTE, "attribute"), | 38 | (ATTRIBUTE, "attribute"), |
39 | (BOOLEAN, "boolean"), | ||
39 | (BUILTIN_TYPE, "builtinType"), | 40 | (BUILTIN_TYPE, "builtinType"), |
40 | (ENUM_MEMBER, "enumMember"), | 41 | (ENUM_MEMBER, "enumMember"), |
41 | (LIFETIME, "lifetime"), | 42 | (LIFETIME, "lifetime"), |
43 | (SELF_KEYWORD, "selfKeyword"), | ||
42 | (TYPE_ALIAS, "typeAlias"), | 44 | (TYPE_ALIAS, "typeAlias"), |
43 | (UNION, "union"), | 45 | (UNION, "union"), |
44 | (UNRESOLVED_REFERENCE, "unresolvedReference"), | 46 | (UNRESOLVED_REFERENCE, "unresolvedReference"), |
@@ -67,6 +69,7 @@ define_semantic_token_modifiers![ | |||
67 | (CONTROL_FLOW, "controlFlow"), | 69 | (CONTROL_FLOW, "controlFlow"), |
68 | (MUTABLE, "mutable"), | 70 | (MUTABLE, "mutable"), |
69 | (UNSAFE, "unsafe"), | 71 | (UNSAFE, "unsafe"), |
72 | (ATTRIBUTE_MODIFIER, "attribute"), | ||
70 | ]; | 73 | ]; |
71 | 74 | ||
72 | #[derive(Default)] | 75 | #[derive(Default)] |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index af54f81b7..8e8e7033d 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -1,13 +1,12 @@ | |||
1 | //! Conversion of rust-analyzer specific types to lsp_types equivalents. | 1 | //! Conversion of rust-analyzer specific types to lsp_types equivalents. |
2 | use ra_db::{FileId, FileRange}; | 2 | use ra_db::{FileId, FileRange}; |
3 | use ra_ide::{ | 3 | use ra_ide::{ |
4 | translate_offset_with_edit, Assist, CompletionItem, CompletionItemKind, Documentation, | 4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, |
5 | FileSystemEdit, Fold, FoldKind, FunctionSignature, Highlight, HighlightModifier, HighlightTag, | 5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, |
6 | HighlightedRange, InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, | 6 | InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Severity, |
7 | ReferenceAccess, Severity, SourceChange, SourceFileEdit, | 7 | SourceChange, SourceFileEdit, TextEdit, |
8 | }; | 8 | }; |
9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; | 9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; |
10 | use ra_text_edit::{Indel, TextEdit}; | ||
11 | use ra_vfs::LineEndings; | 10 | use ra_vfs::LineEndings; |
12 | 11 | ||
13 | use crate::{lsp_ext, semantic_tokens, world::WorldSnapshot, Result}; | 12 | use crate::{lsp_ext, semantic_tokens, world::WorldSnapshot, Result}; |
@@ -133,10 +132,18 @@ pub(crate) fn text_edit_vec( | |||
133 | line_endings: LineEndings, | 132 | line_endings: LineEndings, |
134 | text_edit: TextEdit, | 133 | text_edit: TextEdit, |
135 | ) -> Vec<lsp_types::TextEdit> { | 134 | ) -> Vec<lsp_types::TextEdit> { |
135 | text_edit.into_iter().map(|indel| self::text_edit(line_index, line_endings, indel)).collect() | ||
136 | } | ||
137 | |||
138 | pub(crate) fn snippet_text_edit_vec( | ||
139 | line_index: &LineIndex, | ||
140 | line_endings: LineEndings, | ||
141 | is_snippet: bool, | ||
142 | text_edit: TextEdit, | ||
143 | ) -> Vec<lsp_ext::SnippetTextEdit> { | ||
136 | text_edit | 144 | text_edit |
137 | .as_indels() | 145 | .into_iter() |
138 | .iter() | 146 | .map(|indel| self::snippet_text_edit(line_index, line_endings, is_snippet, indel)) |
139 | .map(|it| self::text_edit(line_index, line_endings, it.clone())) | ||
140 | .collect() | 147 | .collect() |
141 | } | 148 | } |
142 | 149 | ||
@@ -150,7 +157,7 @@ pub(crate) fn completion_item( | |||
150 | // LSP does not allow arbitrary edits in completion, so we have to do a | 157 | // LSP does not allow arbitrary edits in completion, so we have to do a |
151 | // non-trivial mapping here. | 158 | // non-trivial mapping here. |
152 | let source_range = completion_item.source_range(); | 159 | let source_range = completion_item.source_range(); |
153 | for indel in completion_item.text_edit().as_indels() { | 160 | for indel in completion_item.text_edit().iter() { |
154 | if indel.delete.contains_range(source_range) { | 161 | if indel.delete.contains_range(source_range) { |
155 | text_edit = Some(if indel.delete == source_range { | 162 | text_edit = Some(if indel.delete == source_range { |
156 | self::text_edit(line_index, line_endings, indel.clone()) | 163 | self::text_edit(line_index, line_endings, indel.clone()) |
@@ -279,6 +286,7 @@ fn semantic_token_type_and_modifiers( | |||
279 | HighlightTag::TypeAlias => semantic_tokens::TYPE_ALIAS, | 286 | HighlightTag::TypeAlias => semantic_tokens::TYPE_ALIAS, |
280 | HighlightTag::Trait => lsp_types::SemanticTokenType::INTERFACE, | 287 | HighlightTag::Trait => lsp_types::SemanticTokenType::INTERFACE, |
281 | HighlightTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, | 288 | HighlightTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, |
289 | HighlightTag::SelfKeyword => semantic_tokens::SELF_KEYWORD, | ||
282 | HighlightTag::SelfType => lsp_types::SemanticTokenType::TYPE, | 290 | HighlightTag::SelfType => lsp_types::SemanticTokenType::TYPE, |
283 | HighlightTag::Field => lsp_types::SemanticTokenType::PROPERTY, | 291 | HighlightTag::Field => lsp_types::SemanticTokenType::PROPERTY, |
284 | HighlightTag::Function => lsp_types::SemanticTokenType::FUNCTION, | 292 | HighlightTag::Function => lsp_types::SemanticTokenType::FUNCTION, |
@@ -300,6 +308,7 @@ fn semantic_token_type_and_modifiers( | |||
300 | HighlightTag::ByteLiteral | HighlightTag::NumericLiteral => { | 308 | HighlightTag::ByteLiteral | HighlightTag::NumericLiteral => { |
301 | lsp_types::SemanticTokenType::NUMBER | 309 | lsp_types::SemanticTokenType::NUMBER |
302 | } | 310 | } |
311 | HighlightTag::BoolLiteral => semantic_tokens::BOOLEAN, | ||
303 | HighlightTag::CharLiteral | HighlightTag::StringLiteral => { | 312 | HighlightTag::CharLiteral | HighlightTag::StringLiteral => { |
304 | lsp_types::SemanticTokenType::STRING | 313 | lsp_types::SemanticTokenType::STRING |
305 | } | 314 | } |
@@ -312,6 +321,7 @@ fn semantic_token_type_and_modifiers( | |||
312 | 321 | ||
313 | for modifier in highlight.modifiers.iter() { | 322 | for modifier in highlight.modifiers.iter() { |
314 | let modifier = match modifier { | 323 | let modifier = match modifier { |
324 | HighlightModifier::Attribute => semantic_tokens::ATTRIBUTE_MODIFIER, | ||
315 | HighlightModifier::Definition => lsp_types::SemanticTokenModifier::DECLARATION, | 325 | HighlightModifier::Definition => lsp_types::SemanticTokenModifier::DECLARATION, |
316 | HighlightModifier::ControlFlow => semantic_tokens::CONTROL_FLOW, | 326 | HighlightModifier::ControlFlow => semantic_tokens::CONTROL_FLOW, |
317 | HighlightModifier::Mutable => semantic_tokens::MUTABLE, | 327 | HighlightModifier::Mutable => semantic_tokens::MUTABLE, |
@@ -375,14 +385,6 @@ pub(crate) fn url(world: &WorldSnapshot, file_id: FileId) -> Result<lsp_types::U | |||
375 | world.file_id_to_uri(file_id) | 385 | world.file_id_to_uri(file_id) |
376 | } | 386 | } |
377 | 387 | ||
378 | pub(crate) fn text_document_identifier( | ||
379 | world: &WorldSnapshot, | ||
380 | file_id: FileId, | ||
381 | ) -> Result<lsp_types::TextDocumentIdentifier> { | ||
382 | let res = lsp_types::TextDocumentIdentifier { uri: url(world, file_id)? }; | ||
383 | Ok(res) | ||
384 | } | ||
385 | |||
386 | pub(crate) fn versioned_text_document_identifier( | 388 | pub(crate) fn versioned_text_document_identifier( |
387 | world: &WorldSnapshot, | 389 | world: &WorldSnapshot, |
388 | file_id: FileId, | 390 | file_id: FileId, |
@@ -402,13 +404,20 @@ pub(crate) fn location(world: &WorldSnapshot, frange: FileRange) -> Result<lsp_t | |||
402 | 404 | ||
403 | pub(crate) fn location_link( | 405 | pub(crate) fn location_link( |
404 | world: &WorldSnapshot, | 406 | world: &WorldSnapshot, |
405 | src: FileRange, | 407 | src: Option<FileRange>, |
406 | target: NavigationTarget, | 408 | target: NavigationTarget, |
407 | ) -> Result<lsp_types::LocationLink> { | 409 | ) -> Result<lsp_types::LocationLink> { |
408 | let src_location = location(world, src)?; | 410 | let origin_selection_range = match src { |
411 | Some(src) => { | ||
412 | let line_index = world.analysis().file_line_index(src.file_id)?; | ||
413 | let range = range(&line_index, src.range); | ||
414 | Some(range) | ||
415 | } | ||
416 | None => None, | ||
417 | }; | ||
409 | let (target_uri, target_range, target_selection_range) = location_info(world, target)?; | 418 | let (target_uri, target_range, target_selection_range) = location_info(world, target)?; |
410 | let res = lsp_types::LocationLink { | 419 | let res = lsp_types::LocationLink { |
411 | origin_selection_range: Some(src_location.range), | 420 | origin_selection_range, |
412 | target_uri, | 421 | target_uri, |
413 | target_range, | 422 | target_range, |
414 | target_selection_range, | 423 | target_selection_range, |
@@ -431,7 +440,7 @@ fn location_info( | |||
431 | 440 | ||
432 | pub(crate) fn goto_definition_response( | 441 | pub(crate) fn goto_definition_response( |
433 | world: &WorldSnapshot, | 442 | world: &WorldSnapshot, |
434 | src: FileRange, | 443 | src: Option<FileRange>, |
435 | targets: Vec<NavigationTarget>, | 444 | targets: Vec<NavigationTarget>, |
436 | ) -> Result<lsp_types::GotoDefinitionResponse> { | 445 | ) -> Result<lsp_types::GotoDefinitionResponse> { |
437 | if world.config.client_caps.location_link { | 446 | if world.config.client_caps.location_link { |
@@ -467,9 +476,8 @@ pub(crate) fn snippet_text_document_edit( | |||
467 | let line_endings = world.file_line_endings(source_file_edit.file_id); | 476 | let line_endings = world.file_line_endings(source_file_edit.file_id); |
468 | let edits = source_file_edit | 477 | let edits = source_file_edit |
469 | .edit | 478 | .edit |
470 | .as_indels() | 479 | .into_iter() |
471 | .iter() | 480 | .map(|it| snippet_text_edit(&line_index, line_endings, is_snippet, it)) |
472 | .map(|it| snippet_text_edit(&line_index, line_endings, is_snippet, it.clone())) | ||
473 | .collect(); | 481 | .collect(); |
474 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) | 482 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) |
475 | } | 483 | } |
@@ -492,36 +500,6 @@ pub(crate) fn resource_op( | |||
492 | Ok(res) | 500 | Ok(res) |
493 | } | 501 | } |
494 | 502 | ||
495 | pub(crate) fn source_change( | ||
496 | world: &WorldSnapshot, | ||
497 | source_change: SourceChange, | ||
498 | ) -> Result<lsp_ext::SourceChange> { | ||
499 | let cursor_position = match source_change.cursor_position { | ||
500 | None => None, | ||
501 | Some(pos) => { | ||
502 | let line_index = world.analysis().file_line_index(pos.file_id)?; | ||
503 | let edit = source_change | ||
504 | .source_file_edits | ||
505 | .iter() | ||
506 | .find(|it| it.file_id == pos.file_id) | ||
507 | .map(|it| &it.edit); | ||
508 | let line_col = match edit { | ||
509 | Some(edit) => translate_offset_with_edit(&*line_index, pos.offset, edit), | ||
510 | None => line_index.line_col(pos.offset), | ||
511 | }; | ||
512 | let position = | ||
513 | lsp_types::Position::new(u64::from(line_col.line), u64::from(line_col.col_utf16)); | ||
514 | Some(lsp_types::TextDocumentPositionParams { | ||
515 | text_document: text_document_identifier(world, pos.file_id)?, | ||
516 | position, | ||
517 | }) | ||
518 | } | ||
519 | }; | ||
520 | let label = source_change.label.clone(); | ||
521 | let workspace_edit = self::snippet_workspace_edit(world, source_change)?; | ||
522 | Ok(lsp_ext::SourceChange { label, workspace_edit, cursor_position }) | ||
523 | } | ||
524 | |||
525 | pub(crate) fn snippet_workspace_edit( | 503 | pub(crate) fn snippet_workspace_edit( |
526 | world: &WorldSnapshot, | 504 | world: &WorldSnapshot, |
527 | source_change: SourceChange, | 505 | source_change: SourceChange, |
@@ -639,25 +617,12 @@ fn main() <fold>{ | |||
639 | } | 617 | } |
640 | 618 | ||
641 | pub(crate) fn code_action(world: &WorldSnapshot, assist: Assist) -> Result<lsp_ext::CodeAction> { | 619 | pub(crate) fn code_action(world: &WorldSnapshot, assist: Assist) -> Result<lsp_ext::CodeAction> { |
642 | let res = if assist.source_change.cursor_position.is_none() { | 620 | let res = lsp_ext::CodeAction { |
643 | lsp_ext::CodeAction { | 621 | title: assist.label, |
644 | title: assist.label, | 622 | group: if world.config.client_caps.code_action_group { assist.group_label } else { None }, |
645 | kind: Some(String::new()), | 623 | kind: Some(String::new()), |
646 | edit: Some(snippet_workspace_edit(world, assist.source_change)?), | 624 | edit: Some(snippet_workspace_edit(world, assist.source_change)?), |
647 | command: None, | 625 | command: None, |
648 | } | ||
649 | } else { | ||
650 | assert!(!assist.source_change.is_snippet); | ||
651 | let source_change = source_change(&world, assist.source_change)?; | ||
652 | let arg = serde_json::to_value(source_change)?; | ||
653 | let title = assist.label; | ||
654 | let command = lsp_types::Command { | ||
655 | title: title.clone(), | ||
656 | command: "rust-analyzer.applySourceChange".to_string(), | ||
657 | arguments: Some(vec![arg]), | ||
658 | }; | ||
659 | |||
660 | lsp_ext::CodeAction { title, kind: Some(String::new()), edit: None, command: Some(command) } | ||
661 | }; | 626 | }; |
662 | Ok(res) | 627 | Ok(res) |
663 | } | 628 | } |
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 74676b3ee..405ddb362 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs | |||
@@ -473,29 +473,14 @@ fn main() {{}} | |||
473 | text_document: server.doc_id("src/m0.rs"), | 473 | text_document: server.doc_id("src/m0.rs"), |
474 | position: Position { line: 0, character: 5 }, | 474 | position: Position { line: 0, character: 5 }, |
475 | }, | 475 | }, |
476 | json!({ | 476 | json!([{ |
477 | "cursorPosition": { | 477 | "insertTextFormat": 2, |
478 | "position": { "character": 4, "line": 1 }, | 478 | "newText": "\n/// $0", |
479 | "textDocument": { "uri": "file:///[..]src/m0.rs" } | 479 | "range": { |
480 | }, | 480 | "end": { "character": 5, "line": 0 }, |
481 | "label": "On enter", | 481 | "start": { "character": 5, "line": 0 } |
482 | "workspaceEdit": { | 482 | } |
483 | "documentChanges": [ | 483 | }]), |
484 | { | ||
485 | "edits": [ | ||
486 | { | ||
487 | "newText": "\n/// ", | ||
488 | "range": { | ||
489 | "end": { "character": 5, "line": 0 }, | ||
490 | "start": { "character": 5, "line": 0 } | ||
491 | } | ||
492 | } | ||
493 | ], | ||
494 | "textDocument": { "uri": "file:///[..]src/m0.rs", "version": null } | ||
495 | } | ||
496 | ] | ||
497 | } | ||
498 | }), | ||
499 | ); | 484 | ); |
500 | let elapsed = start.elapsed(); | 485 | let elapsed = start.elapsed(); |
501 | assert!(elapsed.as_millis() < 2000, "typing enter took {:?}", elapsed); | 486 | assert!(elapsed.as_millis() < 2000, "typing enter took {:?}", elapsed); |
@@ -525,29 +510,14 @@ version = \"0.0.0\" | |||
525 | text_document: server.doc_id("src/main.rs"), | 510 | text_document: server.doc_id("src/main.rs"), |
526 | position: Position { line: 0, character: 8 }, | 511 | position: Position { line: 0, character: 8 }, |
527 | }, | 512 | }, |
528 | json!({ | 513 | json!([{ |
529 | "cursorPosition": { | 514 | "insertTextFormat": 2, |
530 | "position": { "line": 1, "character": 4 }, | 515 | "newText": "\r\n/// $0", |
531 | "textDocument": { "uri": "file:///[..]src/main.rs" } | 516 | "range": { |
532 | }, | 517 | "end": { "line": 0, "character": 8 }, |
533 | "label": "On enter", | 518 | "start": { "line": 0, "character": 8 } |
534 | "workspaceEdit": { | 519 | } |
535 | "documentChanges": [ | 520 | }]), |
536 | { | ||
537 | "edits": [ | ||
538 | { | ||
539 | "newText": "\r\n/// ", | ||
540 | "range": { | ||
541 | "end": { "line": 0, "character": 8 }, | ||
542 | "start": { "line": 0, "character": 8 } | ||
543 | } | ||
544 | } | ||
545 | ], | ||
546 | "textDocument": { "uri": "file:///[..]src/main.rs", "version": null } | ||
547 | } | ||
548 | ] | ||
549 | } | ||
550 | }), | ||
551 | ); | 521 | ); |
552 | } | 522 | } |
553 | 523 | ||
@@ -786,5 +756,5 @@ pub fn foo(_input: TokenStream) -> TokenStream { | |||
786 | }); | 756 | }); |
787 | 757 | ||
788 | let value = res.get("contents").unwrap().get("value").unwrap().to_string(); | 758 | let value = res.get("contents").unwrap().get("value").unwrap().to_string(); |
789 | assert_eq!(value, r#""```rust\nfoo::Bar\nfn bar()\n```""#) | 759 | assert_eq!(value, r#""```rust\nfoo::Bar\n```\n\n```rust\nfn bar()\n```""#) |
790 | } | 760 | } |
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index 9acbae066..66a6f4d54 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs | |||
@@ -68,7 +68,7 @@ impl<'a> Project<'a> { | |||
68 | let mut paths = vec![]; | 68 | let mut paths = vec![]; |
69 | 69 | ||
70 | for entry in parse_fixture(self.fixture) { | 70 | for entry in parse_fixture(self.fixture) { |
71 | let path = tmp_dir.path().join(entry.meta); | 71 | let path = tmp_dir.path().join(entry.meta.path().as_str()); |
72 | fs::create_dir_all(path.parent().unwrap()).unwrap(); | 72 | fs::create_dir_all(path.parent().unwrap()).unwrap(); |
73 | fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); | 73 | fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); |
74 | paths.push((path, entry.text)); | 74 | paths.push((path, entry.text)); |
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml index 8ec986bcb..4d185b01c 100644 --- a/crates/test_utils/Cargo.toml +++ b/crates/test_utils/Cargo.toml | |||
@@ -11,3 +11,7 @@ doctest = false | |||
11 | difference = "2.0.0" | 11 | difference = "2.0.0" |
12 | text-size = "1.0.0" | 12 | text-size = "1.0.0" |
13 | serde_json = "1.0.48" | 13 | serde_json = "1.0.48" |
14 | relative-path = "1.0.0" | ||
15 | rustc-hash = "1.1.0" | ||
16 | |||
17 | ra_cfg = { path = "../ra_cfg" } \ No newline at end of file | ||
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index be2cfbaa2..1bd97215c 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -14,6 +14,10 @@ use std::{ | |||
14 | path::{Path, PathBuf}, | 14 | path::{Path, PathBuf}, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | pub use ra_cfg::CfgOptions; | ||
18 | |||
19 | pub use relative_path::{RelativePath, RelativePathBuf}; | ||
20 | pub use rustc_hash::FxHashMap; | ||
17 | use serde_json::Value; | 21 | use serde_json::Value; |
18 | use text_size::{TextRange, TextSize}; | 22 | use text_size::{TextRange, TextSize}; |
19 | 23 | ||
@@ -157,10 +161,82 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String { | |||
157 | 161 | ||
158 | #[derive(Debug, Eq, PartialEq)] | 162 | #[derive(Debug, Eq, PartialEq)] |
159 | pub struct FixtureEntry { | 163 | pub struct FixtureEntry { |
160 | pub meta: String, | 164 | pub meta: FixtureMeta, |
161 | pub text: String, | 165 | pub text: String, |
162 | } | 166 | } |
163 | 167 | ||
168 | #[derive(Debug, Eq, PartialEq)] | ||
169 | pub enum FixtureMeta { | ||
170 | Root { path: RelativePathBuf }, | ||
171 | File(FileMeta), | ||
172 | } | ||
173 | |||
174 | #[derive(Debug, Eq, PartialEq)] | ||
175 | pub struct FileMeta { | ||
176 | pub path: RelativePathBuf, | ||
177 | pub crate_name: Option<String>, | ||
178 | pub deps: Vec<String>, | ||
179 | pub cfg: CfgOptions, | ||
180 | pub edition: Option<String>, | ||
181 | pub env: FxHashMap<String, String>, | ||
182 | } | ||
183 | |||
184 | impl FixtureMeta { | ||
185 | pub fn path(&self) -> &RelativePath { | ||
186 | match self { | ||
187 | FixtureMeta::Root { path } => &path, | ||
188 | FixtureMeta::File(f) => &f.path, | ||
189 | } | ||
190 | } | ||
191 | |||
192 | pub fn crate_name(&self) -> Option<&String> { | ||
193 | match self { | ||
194 | FixtureMeta::File(f) => f.crate_name.as_ref(), | ||
195 | _ => None, | ||
196 | } | ||
197 | } | ||
198 | |||
199 | pub fn cfg_options(&self) -> Option<&CfgOptions> { | ||
200 | match self { | ||
201 | FixtureMeta::File(f) => Some(&f.cfg), | ||
202 | _ => None, | ||
203 | } | ||
204 | } | ||
205 | |||
206 | pub fn edition(&self) -> Option<&String> { | ||
207 | match self { | ||
208 | FixtureMeta::File(f) => f.edition.as_ref(), | ||
209 | _ => None, | ||
210 | } | ||
211 | } | ||
212 | |||
213 | pub fn env(&self) -> impl Iterator<Item = (&String, &String)> { | ||
214 | struct EnvIter<'a> { | ||
215 | iter: Option<std::collections::hash_map::Iter<'a, String, String>>, | ||
216 | } | ||
217 | |||
218 | impl<'a> EnvIter<'a> { | ||
219 | fn new(meta: &'a FixtureMeta) -> Self { | ||
220 | Self { | ||
221 | iter: match meta { | ||
222 | FixtureMeta::File(f) => Some(f.env.iter()), | ||
223 | _ => None, | ||
224 | }, | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | |||
229 | impl<'a> Iterator for EnvIter<'a> { | ||
230 | type Item = (&'a String, &'a String); | ||
231 | fn next(&mut self) -> Option<Self::Item> { | ||
232 | self.iter.as_mut().and_then(|i| i.next()) | ||
233 | } | ||
234 | } | ||
235 | |||
236 | EnvIter::new(self) | ||
237 | } | ||
238 | } | ||
239 | |||
164 | /// Parses text which looks like this: | 240 | /// Parses text which looks like this: |
165 | /// | 241 | /// |
166 | /// ```not_rust | 242 | /// ```not_rust |
@@ -169,8 +245,8 @@ pub struct FixtureEntry { | |||
169 | /// line 2 | 245 | /// line 2 |
170 | /// // - other meta | 246 | /// // - other meta |
171 | /// ``` | 247 | /// ``` |
172 | pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> { | 248 | pub fn parse_fixture(ra_fixture: &str) -> Vec<FixtureEntry> { |
173 | let fixture = indent_first_line(fixture); | 249 | let fixture = indent_first_line(ra_fixture); |
174 | let margin = fixture_margin(&fixture); | 250 | let margin = fixture_margin(&fixture); |
175 | 251 | ||
176 | let mut lines = fixture | 252 | let mut lines = fixture |
@@ -200,6 +276,7 @@ The offending line: {:?}"#, | |||
200 | for line in lines.by_ref() { | 276 | for line in lines.by_ref() { |
201 | if line.starts_with("//-") { | 277 | if line.starts_with("//-") { |
202 | let meta = line["//-".len()..].trim().to_string(); | 278 | let meta = line["//-".len()..].trim().to_string(); |
279 | let meta = parse_meta(&meta); | ||
203 | res.push(FixtureEntry { meta, text: String::new() }) | 280 | res.push(FixtureEntry { meta, text: String::new() }) |
204 | } else if let Some(entry) = res.last_mut() { | 281 | } else if let Some(entry) = res.last_mut() { |
205 | entry.text.push_str(line); | 282 | entry.text.push_str(line); |
@@ -209,6 +286,57 @@ The offending line: {:?}"#, | |||
209 | res | 286 | res |
210 | } | 287 | } |
211 | 288 | ||
289 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo | ||
290 | fn parse_meta(meta: &str) -> FixtureMeta { | ||
291 | let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); | ||
292 | |||
293 | if components[0] == "root" { | ||
294 | let path: RelativePathBuf = components[1].into(); | ||
295 | assert!(path.starts_with("/") && path.ends_with("/")); | ||
296 | return FixtureMeta::Root { path }; | ||
297 | } | ||
298 | |||
299 | let path: RelativePathBuf = components[0].into(); | ||
300 | assert!(path.starts_with("/")); | ||
301 | |||
302 | let mut krate = None; | ||
303 | let mut deps = Vec::new(); | ||
304 | let mut edition = None; | ||
305 | let mut cfg = CfgOptions::default(); | ||
306 | let mut env = FxHashMap::default(); | ||
307 | for component in components[1..].iter() { | ||
308 | let (key, value) = split1(component, ':').unwrap(); | ||
309 | match key { | ||
310 | "crate" => krate = Some(value.to_string()), | ||
311 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), | ||
312 | "edition" => edition = Some(value.to_string()), | ||
313 | "cfg" => { | ||
314 | for key in value.split(',') { | ||
315 | match split1(key, '=') { | ||
316 | None => cfg.insert_atom(key.into()), | ||
317 | Some((k, v)) => cfg.insert_key_value(k.into(), v.into()), | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | "env" => { | ||
322 | for key in value.split(',') { | ||
323 | if let Some((k, v)) = split1(key, '=') { | ||
324 | env.insert(k.into(), v.into()); | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | _ => panic!("bad component: {:?}", component), | ||
329 | } | ||
330 | } | ||
331 | |||
332 | FixtureMeta::File(FileMeta { path, crate_name: krate, deps, edition, cfg, env }) | ||
333 | } | ||
334 | |||
335 | fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
336 | let idx = haystack.find(delim)?; | ||
337 | Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) | ||
338 | } | ||
339 | |||
212 | /// Adjusts the indentation of the first line to the minimum indentation of the rest of the lines. | 340 | /// Adjusts the indentation of the first line to the minimum indentation of the rest of the lines. |
213 | /// This allows fixtures to start off in a different indentation, e.g. to align the first line with | 341 | /// This allows fixtures to start off in a different indentation, e.g. to align the first line with |
214 | /// the other lines visually: | 342 | /// the other lines visually: |
@@ -288,13 +416,33 @@ struct Bar; | |||
288 | ) | 416 | ) |
289 | } | 417 | } |
290 | 418 | ||
419 | #[test] | ||
420 | fn parse_fixture_gets_full_meta() { | ||
421 | let parsed = parse_fixture( | ||
422 | r" | ||
423 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo | ||
424 | mod m; | ||
425 | ", | ||
426 | ); | ||
427 | assert_eq!(1, parsed.len()); | ||
428 | |||
429 | let parsed = &parsed[0]; | ||
430 | assert_eq!("mod m;\n\n", parsed.text); | ||
431 | |||
432 | let meta = &parsed.meta; | ||
433 | assert_eq!("foo", meta.crate_name().unwrap()); | ||
434 | assert_eq!("/lib.rs", meta.path()); | ||
435 | assert!(meta.cfg_options().is_some()); | ||
436 | assert_eq!(2, meta.env().count()); | ||
437 | } | ||
438 | |||
291 | /// Same as `parse_fixture`, except it allow empty fixture | 439 | /// Same as `parse_fixture`, except it allow empty fixture |
292 | pub fn parse_single_fixture(fixture: &str) -> Option<FixtureEntry> { | 440 | pub fn parse_single_fixture(ra_fixture: &str) -> Option<FixtureEntry> { |
293 | if !fixture.lines().any(|it| it.trim_start().starts_with("//-")) { | 441 | if !ra_fixture.lines().any(|it| it.trim_start().starts_with("//-")) { |
294 | return None; | 442 | return None; |
295 | } | 443 | } |
296 | 444 | ||
297 | let fixtures = parse_fixture(fixture); | 445 | let fixtures = parse_fixture(ra_fixture); |
298 | if fixtures.len() > 1 { | 446 | if fixtures.len() > 1 { |
299 | panic!("too many fixtures"); | 447 | panic!("too many fixtures"); |
300 | } | 448 | } |
diff --git a/docs/dev/README.md b/docs/dev/README.md index a20ead0b6..65cc9fc12 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -74,7 +74,7 @@ relevant test and execute it (VS Code includes an action for running a single | |||
74 | test). | 74 | test). |
75 | 75 | ||
76 | However, launching a VS Code instance with locally build language server is | 76 | However, launching a VS Code instance with locally build language server is |
77 | possible. There's **"Run Extension (Dev Server)"** launch configuration for this. | 77 | possible. There's **"Run Extension (Debug Build)"** launch configuration for this. |
78 | 78 | ||
79 | In general, I use one of the following workflows for fixing bugs and | 79 | In general, I use one of the following workflows for fixing bugs and |
80 | implementing features. | 80 | implementing features. |
@@ -86,7 +86,7 @@ then just do printf-driven development/debugging. As a sanity check after I'm | |||
86 | done, I use `cargo xtask install --server` and **Reload Window** action in VS | 86 | done, I use `cargo xtask install --server` and **Reload Window** action in VS |
87 | Code to sanity check that the thing works as I expect. | 87 | Code to sanity check that the thing works as I expect. |
88 | 88 | ||
89 | If the problem concerns only the VS Code extension, I use **Run Extension** | 89 | If the problem concerns only the VS Code extension, I use **Run Installed Extension** |
90 | launch configuration from `launch.json`. Notably, this uses the usual | 90 | launch configuration from `launch.json`. Notably, this uses the usual |
91 | `rust-analyzer` binary from `PATH`. For this it is important to have the following | 91 | `rust-analyzer` binary from `PATH`. For this it is important to have the following |
92 | in `setting.json` file: | 92 | in `setting.json` file: |
diff --git a/docs/dev/debugging.md b/docs/dev/debugging.md index 1aa392935..59a83f7d7 100644 --- a/docs/dev/debugging.md +++ b/docs/dev/debugging.md | |||
@@ -22,8 +22,8 @@ where **only** the `rust-analyzer` extension being debugged is enabled. | |||
22 | 22 | ||
23 | ## Debug TypeScript VSCode extension | 23 | ## Debug TypeScript VSCode extension |
24 | 24 | ||
25 | - `Run Extension` - runs the extension with the globally installed `rust-analyzer` binary. | 25 | - `Run Installed Extension` - runs the extension with the globally installed `rust-analyzer` binary. |
26 | - `Run Extension (Dev Server)` - runs extension with the locally built LSP server (`target/debug/rust-analyzer`). | 26 | - `Run Extension (Debug Build)` - runs extension with the locally built LSP server (`target/debug/rust-analyzer`). |
27 | 27 | ||
28 | TypeScript debugging is configured to watch your source edits and recompile. | 28 | TypeScript debugging is configured to watch your source edits and recompile. |
29 | To apply changes to an already running debug process, press <kbd>Ctrl+Shift+P</kbd> and run the following command in your `[Extension Development Host]` | 29 | To apply changes to an already running debug process, press <kbd>Ctrl+Shift+P</kbd> and run the following command in your `[Extension Development Host]` |
@@ -47,7 +47,7 @@ To apply changes to an already running debug process, press <kbd>Ctrl+Shift+P</k | |||
47 | debug = 2 | 47 | debug = 2 |
48 | ``` | 48 | ``` |
49 | 49 | ||
50 | - Select `Run Extension (Dev Server)` to run your locally built `target/debug/rust-analyzer`. | 50 | - Select `Run Extension (Debug Build)` to run your locally built `target/debug/rust-analyzer`. |
51 | 51 | ||
52 | - In the original VSCode window once again select the `Attach To Server` debug configuration. | 52 | - In the original VSCode window once again select the `Attach To Server` debug configuration. |
53 | 53 | ||
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index d2ec6c021..209f470eb 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -3,17 +3,15 @@ | |||
3 | This document describes LSP extensions used by rust-analyzer. | 3 | This document describes LSP extensions used by rust-analyzer. |
4 | It's a best effort document, when in doubt, consult the source (and send a PR with clarification ;-) ). | 4 | It's a best effort document, when in doubt, consult the source (and send a PR with clarification ;-) ). |
5 | We aim to upstream all non Rust-specific extensions to the protocol, but this is not a top priority. | 5 | We aim to upstream all non Rust-specific extensions to the protocol, but this is not a top priority. |
6 | All capabilities are enabled via `experimental` field of `ClientCapabilities`. | 6 | All capabilities are enabled via `experimental` field of `ClientCapabilities` or `ServerCapabilities`. |
7 | Requests which we hope to upstream live under `experimental/` namespace. | ||
8 | Requests, which are likely to always remain specific to `rust-analyzer` are under `rust-analyzer/` namespace. | ||
7 | 9 | ||
8 | ## `SnippetTextEdit` | 10 | ## Snippet `TextEdit` |
9 | 11 | ||
10 | **Capability** | 12 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/724 |
11 | 13 | ||
12 | ```typescript | 14 | **Client Capability:** `{ "snippetTextEdit": boolean }` |
13 | { | ||
14 | "snippetTextEdit": boolean | ||
15 | } | ||
16 | ``` | ||
17 | 15 | ||
18 | If this capability is set, `WorkspaceEdit`s returned from `codeAction` requests might contain `SnippetTextEdit`s instead of usual `TextEdit`s: | 16 | If this capability is set, `WorkspaceEdit`s returned from `codeAction` requests might contain `SnippetTextEdit`s instead of usual `TextEdit`s: |
19 | 17 | ||
@@ -32,3 +30,335 @@ export interface TextDocumentEdit { | |||
32 | 30 | ||
33 | When applying such code action, the editor should insert snippet, with tab stops and placeholder. | 31 | When applying such code action, the editor should insert snippet, with tab stops and placeholder. |
34 | At the moment, rust-analyzer guarantees that only a single edit will have `InsertTextFormat.Snippet`. | 32 | At the moment, rust-analyzer guarantees that only a single edit will have `InsertTextFormat.Snippet`. |
33 | |||
34 | ### Example | ||
35 | |||
36 | "Add `derive`" code action transforms `struct S;` into `#[derive($0)] struct S;` | ||
37 | |||
38 | ### Unresolved Questions | ||
39 | |||
40 | * Where exactly are `SnippetTextEdit`s allowed (only in code actions at the moment)? | ||
41 | * Can snippets span multiple files (so far, no)? | ||
42 | |||
43 | ## `CodeAction` Groups | ||
44 | |||
45 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/994 | ||
46 | |||
47 | **Client Capability:** `{ "codeActionGroup": boolean }` | ||
48 | |||
49 | If this capability is set, `CodeAction` returned from the server contain an additional field, `group`: | ||
50 | |||
51 | ```typescript | ||
52 | interface CodeAction { | ||
53 | title: string; | ||
54 | group?: string; | ||
55 | ... | ||
56 | } | ||
57 | ``` | ||
58 | |||
59 | All code-actions with the same `group` should be grouped under single (extendable) entry in lightbulb menu. | ||
60 | The set of actions `[ { title: "foo" }, { group: "frobnicate", title: "bar" }, { group: "frobnicate", title: "baz" }]` should be rendered as | ||
61 | |||
62 | ``` | ||
63 | 💡 | ||
64 | +-------------+ | ||
65 | | foo | | ||
66 | +-------------+-----+ | ||
67 | | frobnicate >| bar | | ||
68 | +-------------+-----+ | ||
69 | | baz | | ||
70 | +-----+ | ||
71 | ``` | ||
72 | |||
73 | Alternatively, selecting `frobnicate` could present a user with an additional menu to choose between `bar` and `baz`. | ||
74 | |||
75 | ### Example | ||
76 | |||
77 | ```rust | ||
78 | fn main() { | ||
79 | let x: Entry/*cursor here*/ = todo!(); | ||
80 | } | ||
81 | ``` | ||
82 | |||
83 | Invoking code action at this position will yield two code actions for importing `Entry` from either `collections::HashMap` or `collection::BTreeMap`, grouped under a single "import" group. | ||
84 | |||
85 | ### Unresolved Questions | ||
86 | |||
87 | * Is a fixed two-level structure enough? | ||
88 | * Should we devise a general way to encode custom interaction protocols for GUI refactorings? | ||
89 | |||
90 | ## Parent Module | ||
91 | |||
92 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/1002 | ||
93 | |||
94 | **Server Capability:** `{ "parentModule": boolean }` | ||
95 | |||
96 | This request is send from client to server to handle "Goto Parent Module" editor action. | ||
97 | |||
98 | **Method:** `experimental/parentModule` | ||
99 | |||
100 | **Request:** `TextDocumentPositionParams` | ||
101 | |||
102 | **Response:** `Location | Location[] | LocationLink[] | null` | ||
103 | |||
104 | |||
105 | ### Example | ||
106 | |||
107 | ```rust | ||
108 | // src/main.rs | ||
109 | mod foo; | ||
110 | // src/foo.rs | ||
111 | |||
112 | /* cursor here*/ | ||
113 | ``` | ||
114 | |||
115 | `experimental/parentModule` returns a single `Link` to the `mod foo;` declaration. | ||
116 | |||
117 | ### Unresolved Question | ||
118 | |||
119 | * An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules. | ||
120 | This is the approach IntelliJ Rust is takeing. | ||
121 | However, experience shows that super module (which generally has a feeling of navigation between files) should be separate. | ||
122 | If you want super module, but the cursor happens to be inside an overriden function, the behavior with single "gotoSuper" request is surprising. | ||
123 | |||
124 | ## Join Lines | ||
125 | |||
126 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/992 | ||
127 | |||
128 | **Server Capability:** `{ "joinLines": boolean }` | ||
129 | |||
130 | This request is send from client to server to handle "Join Lines" editor action. | ||
131 | |||
132 | **Method:** `experimental/joinLines` | ||
133 | |||
134 | **Request:** | ||
135 | |||
136 | ```typescript | ||
137 | interface JoinLinesParams { | ||
138 | textDocument: TextDocumentIdentifier, | ||
139 | /// Currently active selections/cursor offsets. | ||
140 | /// This is an array to support multiple cursors. | ||
141 | ranges: Range[], | ||
142 | } | ||
143 | ``` | ||
144 | |||
145 | **Response:** `TextEdit[]` | ||
146 | |||
147 | ### Example | ||
148 | |||
149 | ```rust | ||
150 | fn main() { | ||
151 | /*cursor here*/let x = { | ||
152 | 92 | ||
153 | }; | ||
154 | } | ||
155 | ``` | ||
156 | |||
157 | `experimental/joinLines` yields (curly braces are automagiacally removed) | ||
158 | |||
159 | ```rust | ||
160 | fn main() { | ||
161 | let x = 92; | ||
162 | } | ||
163 | ``` | ||
164 | |||
165 | ### Unresolved Question | ||
166 | |||
167 | * What is the position of the cursor after `joinLines`? | ||
168 | Currently this is left to editor's discretion, but it might be useful to specify on the server via snippets. | ||
169 | However, it then becomes unclear how it works with multi cursor. | ||
170 | |||
171 | ## On Enter | ||
172 | |||
173 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/1001 | ||
174 | |||
175 | **Server Capability:** `{ "onEnter": boolean }` | ||
176 | |||
177 | This request is send from client to server to handle <kbd>Enter</kbd> keypress. | ||
178 | |||
179 | **Method:** `experimental/onEnter` | ||
180 | |||
181 | **Request:**: `TextDocumentPositionParams` | ||
182 | |||
183 | **Response:** | ||
184 | |||
185 | ```typescript | ||
186 | SnippetTextEdit[] | ||
187 | ``` | ||
188 | |||
189 | ### Example | ||
190 | |||
191 | ```rust | ||
192 | fn main() { | ||
193 | // Some /*cursor here*/ docs | ||
194 | let x = 92; | ||
195 | } | ||
196 | ``` | ||
197 | |||
198 | `experimental/onEnter` returns the following snippet | ||
199 | |||
200 | ```rust | ||
201 | fn main() { | ||
202 | // Some | ||
203 | // $0 docs | ||
204 | let x = 92; | ||
205 | } | ||
206 | ``` | ||
207 | |||
208 | The primary goal of `onEnter` is to handle automatic indentation when opening a new line. | ||
209 | This is not yet implemented. | ||
210 | The secondary goal is to handle fixing up syntax, like continuing doc strings and comments, and escaping `\n` in string literals. | ||
211 | |||
212 | As proper cursor positioning is raison-d'etat for `onEnter`, it uses `SnippetTextEdit`. | ||
213 | |||
214 | ### Unresolved Question | ||
215 | |||
216 | * How to deal with synchronicity of the request? | ||
217 | One option is to require the client to block until the server returns the response. | ||
218 | Another option is to do a OT-style merging of edits from client and server. | ||
219 | A third option is to do a record-replay: client applies heuristic on enter immediatelly, then applies all user's keypresses. | ||
220 | When the server is ready with the response, the client rollbacks all the changes and applies the recorded actions on top of the correct response. | ||
221 | * How to deal with multiple carets? | ||
222 | * Should we extend this to arbitrary typed events and not just `onEnter`? | ||
223 | |||
224 | ## Structural Search Replace (SSR) | ||
225 | |||
226 | **Server Capability:** `{ "ssr": boolean }` | ||
227 | |||
228 | This request is send from client to server to handle structural search replace -- automated syntax tree based transformation of the source. | ||
229 | |||
230 | **Method:** `experimental/ssr` | ||
231 | |||
232 | **Request:** | ||
233 | |||
234 | ```typescript | ||
235 | interface SsrParams { | ||
236 | /// Search query. | ||
237 | /// The specific syntax is specified outside of the protocol. | ||
238 | query: string, | ||
239 | /// If true, only check the syntax of the query and don't compute the actual edit. | ||
240 | parseOnly: bool, | ||
241 | } | ||
242 | ``` | ||
243 | |||
244 | **Response:** | ||
245 | |||
246 | ```typescript | ||
247 | WorkspaceEdit | ||
248 | ``` | ||
249 | |||
250 | ### Example | ||
251 | |||
252 | SSR with query `foo($a:expr, $b:expr) ==>> ($a).foo($b)` will transform, eg `foo(y + 5, z)` into `(y + 5).foo(z)`. | ||
253 | |||
254 | ### Unresolved Question | ||
255 | |||
256 | * Probably needs search without replace mode | ||
257 | * Needs a way to limit the scope to certain files. | ||
258 | |||
259 | ## Matching Brace | ||
260 | |||
261 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/999 | ||
262 | |||
263 | **Server Capability:** `{ "matchingBrace": boolean }` | ||
264 | |||
265 | This request is send from client to server to handle "Matching Brace" editor action. | ||
266 | |||
267 | **Method:** `experimental/matchingBrace` | ||
268 | |||
269 | **Request:** | ||
270 | |||
271 | ```typescript | ||
272 | interface MatchingBraceParams { | ||
273 | textDocument: TextDocumentIdentifier, | ||
274 | /// Position for each cursor | ||
275 | positions: Position[], | ||
276 | } | ||
277 | ``` | ||
278 | |||
279 | **Response:** | ||
280 | |||
281 | ```typescript | ||
282 | Position[] | ||
283 | ``` | ||
284 | |||
285 | ### Example | ||
286 | |||
287 | ```rust | ||
288 | fn main() { | ||
289 | let x: Vec<()>/*cursor here*/ = vec![] | ||
290 | } | ||
291 | ``` | ||
292 | |||
293 | `experimental/matchingBrace` yields the position of `<`. | ||
294 | In many cases, matching braces can be handled by the editor. | ||
295 | However, some cases (like disambiguating between generics and comparison operations) need a real parser. | ||
296 | Moreover, it would be cool if editors didn't need to implement even basic language parsing | ||
297 | |||
298 | ### Unresolved Question | ||
299 | |||
300 | * Should we return a a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair? | ||
301 | This is how `SelectionRange` request works. | ||
302 | * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? | ||
303 | |||
304 | ## Analyzer Status | ||
305 | |||
306 | **Method:** `rust-analyzer/analyzerStatus` | ||
307 | |||
308 | **Request:** `null` | ||
309 | |||
310 | **Response:** `string` | ||
311 | |||
312 | Returns internal status message, mostly for debugging purposes. | ||
313 | |||
314 | ## Collect Garbage | ||
315 | |||
316 | **Method:** `rust-analyzer/collectGarbage` | ||
317 | |||
318 | **Request:** `null` | ||
319 | |||
320 | **Response:** `null` | ||
321 | |||
322 | Frees some caches. For internal use, and is mostly broken at the moment. | ||
323 | |||
324 | ## Syntax Tree | ||
325 | |||
326 | **Method:** `rust-analyzer/syntaxTree` | ||
327 | |||
328 | **Request:** | ||
329 | |||
330 | ```typescript | ||
331 | interface SyntaxTeeParams { | ||
332 | textDocument: TextDocumentIdentifier, | ||
333 | range?: Range, | ||
334 | } | ||
335 | ``` | ||
336 | |||
337 | **Response:** `string` | ||
338 | |||
339 | Returns textual representation of a parse tree for the file/selected region. | ||
340 | Primarily for debugging, but very useful for all people working on rust-analyzer itself. | ||
341 | |||
342 | ## Expand Macro | ||
343 | |||
344 | **Method:** `rust-analyzer/expandMacro` | ||
345 | |||
346 | **Request:** | ||
347 | |||
348 | ```typescript | ||
349 | interface ExpandMacroParams { | ||
350 | textDocument: TextDocumentIdentifier, | ||
351 | position: Position, | ||
352 | } | ||
353 | ``` | ||
354 | |||
355 | **Response:** | ||
356 | |||
357 | ```typescript | ||
358 | interface ExpandedMacro { | ||
359 | name: string, | ||
360 | expansion: string, | ||
361 | } | ||
362 | ``` | ||
363 | |||
364 | Expands macro call at a given position. | ||
diff --git a/docs/user/assists.md b/docs/user/assists.md index 51807ffda..4ad7ea59d 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md | |||
@@ -426,7 +426,7 @@ fn main() { | |||
426 | 426 | ||
427 | // AFTER | 427 | // AFTER |
428 | fn main() { | 428 | fn main() { |
429 | let var_name = (1 + 2); | 429 | let $0var_name = (1 + 2); |
430 | var_name * 4; | 430 | var_name * 4; |
431 | } | 431 | } |
432 | ``` | 432 | ``` |
@@ -733,7 +733,7 @@ fn main() { | |||
733 | let x: Result<i32, i32> = Result::Ok(92); | 733 | let x: Result<i32, i32> = Result::Ok(92); |
734 | let y = match x { | 734 | let y = match x { |
735 | Ok(a) => a, | 735 | Ok(a) => a, |
736 | _ => unreachable!(), | 736 | $0_ => unreachable!(), |
737 | }; | 737 | }; |
738 | } | 738 | } |
739 | ``` | 739 | ``` |
diff --git a/docs/user/features.md b/docs/user/features.md index 340bce835..12ecdec13 100644 --- a/docs/user/features.md +++ b/docs/user/features.md | |||
@@ -93,6 +93,12 @@ Shows internal statistic about memory usage of rust-analyzer. | |||
93 | 93 | ||
94 | Show current rust-analyzer version. | 94 | Show current rust-analyzer version. |
95 | 95 | ||
96 | #### Toggle inlay hints | ||
97 | |||
98 | Toggle inlay hints view for the current workspace. | ||
99 | It is recommended to assign a shortcut for this command to quickly turn off | ||
100 | inlay hints when they prevent you from reading/writing the code. | ||
101 | |||
96 | #### Run Garbage Collection | 102 | #### Run Garbage Collection |
97 | 103 | ||
98 | Manually triggers GC. | 104 | Manually triggers GC. |
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc index 03836e6e2..40ed54809 100644 --- a/docs/user/readme.adoc +++ b/docs/user/readme.adoc | |||
@@ -249,7 +249,7 @@ If it worked, you should see "rust-analyzer, Line X, Column Y" on the left side | |||
249 | 249 | ||
250 | If you get an error saying `No such file or directory: 'rust-analyzer'`, see the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>> section on installing the language server binary. | 250 | If you get an error saying `No such file or directory: 'rust-analyzer'`, see the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>> section on installing the language server binary. |
251 | 251 | ||
252 | === Gnome Builder | 252 | === GNOME Builder |
253 | 253 | ||
254 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. | 254 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. |
255 | 255 | ||
diff --git a/editors/code/.vscodeignore b/editors/code/.vscodeignore index 257b744bf..7149ab799 100644 --- a/editors/code/.vscodeignore +++ b/editors/code/.vscodeignore | |||
@@ -1,5 +1,5 @@ | |||
1 | ** | 1 | ** |
2 | !out/main.js | 2 | !out/src/main.js |
3 | !package.json | 3 | !package.json |
4 | !package-lock.json | 4 | !package-lock.json |
5 | !ra_syntax_tree.tmGrammar.json | 5 | !ra_syntax_tree.tmGrammar.json |
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 06178990f..3b4a31682 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json | |||
@@ -13,21 +13,27 @@ | |||
13 | "@babel/highlight": "^7.8.3" | 13 | "@babel/highlight": "^7.8.3" |
14 | } | 14 | } |
15 | }, | 15 | }, |
16 | "@babel/helper-validator-identifier": { | ||
17 | "version": "7.9.5", | ||
18 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", | ||
19 | "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", | ||
20 | "dev": true | ||
21 | }, | ||
16 | "@babel/highlight": { | 22 | "@babel/highlight": { |
17 | "version": "7.8.3", | 23 | "version": "7.9.0", |
18 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", | 24 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", |
19 | "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", | 25 | "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", |
20 | "dev": true, | 26 | "dev": true, |
21 | "requires": { | 27 | "requires": { |
28 | "@babel/helper-validator-identifier": "^7.9.0", | ||
22 | "chalk": "^2.0.0", | 29 | "chalk": "^2.0.0", |
23 | "esutils": "^2.0.2", | ||
24 | "js-tokens": "^4.0.0" | 30 | "js-tokens": "^4.0.0" |
25 | } | 31 | } |
26 | }, | 32 | }, |
27 | "@rollup/plugin-commonjs": { | 33 | "@rollup/plugin-commonjs": { |
28 | "version": "11.1.0", | 34 | "version": "12.0.0", |
29 | "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-11.1.0.tgz", | 35 | "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-12.0.0.tgz", |
30 | "integrity": "sha512-Ycr12N3ZPN96Fw2STurD21jMqzKwL9QuFhms3SD7KKRK7oaXUsBU9Zt0jL/rOPHiPYisI21/rXGO3jr9BnLHUA==", | 36 | "integrity": "sha512-8+mDQt1QUmN+4Y9D3yCG8AJNewuTSLYPJVzKKUZ+lGeQrI+bV12Tc5HCyt2WdlnG6ihIL/DPbKRJlB40DX40mw==", |
31 | "dev": true, | 37 | "dev": true, |
32 | "requires": { | 38 | "requires": { |
33 | "@rollup/pluginutils": "^3.0.8", | 39 | "@rollup/pluginutils": "^3.0.8", |
@@ -40,27 +46,29 @@ | |||
40 | } | 46 | } |
41 | }, | 47 | }, |
42 | "@rollup/plugin-node-resolve": { | 48 | "@rollup/plugin-node-resolve": { |
43 | "version": "7.1.3", | 49 | "version": "8.0.0", |
44 | "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", | 50 | "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.0.0.tgz", |
45 | "integrity": "sha512-RxtSL3XmdTAE2byxekYLnx+98kEUOrPHF/KRVjLH+DEIHy6kjIw7YINQzn+NXiH/NTrQLAwYs0GWB+csWygA9Q==", | 51 | "integrity": "sha512-5poJCChrkVggXXND/sQ7yNqwjUNT4fP31gpRWCnSNnlXuUXTCMHT33xZrTGxgjm5Rl18MHj7iEzlCT8rYWwQSA==", |
46 | "dev": true, | 52 | "dev": true, |
47 | "requires": { | 53 | "requires": { |
48 | "@rollup/pluginutils": "^3.0.8", | 54 | "@rollup/pluginutils": "^3.0.8", |
49 | "@types/resolve": "0.0.8", | 55 | "@types/resolve": "0.0.8", |
50 | "builtin-modules": "^3.1.0", | 56 | "builtin-modules": "^3.1.0", |
57 | "deep-freeze": "^0.0.1", | ||
58 | "deepmerge": "^4.2.2", | ||
51 | "is-module": "^1.0.0", | 59 | "is-module": "^1.0.0", |
52 | "resolve": "^1.14.2" | 60 | "resolve": "^1.14.2" |
53 | } | 61 | } |
54 | }, | 62 | }, |
55 | "@rollup/pluginutils": { | 63 | "@rollup/pluginutils": { |
56 | "version": "3.0.9", | 64 | "version": "3.0.10", |
57 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.9.tgz", | 65 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.10.tgz", |
58 | "integrity": "sha512-TLZavlfPAZYI7v33wQh4mTP6zojne14yok3DNSLcjoG/Hirxfkonn6icP5rrNWRn8nZsirJBFFpijVOJzkUHDg==", | 66 | "integrity": "sha512-d44M7t+PjmMrASHbhgpSbVgtL6EFyX7J4mYxwQ/c5eoaE6N2VgCgEcWVzNnwycIloti+/MpwFr8qfw+nRw00sw==", |
59 | "dev": true, | 67 | "dev": true, |
60 | "requires": { | 68 | "requires": { |
61 | "@types/estree": "0.0.39", | 69 | "@types/estree": "0.0.39", |
62 | "estree-walker": "^1.0.1", | 70 | "estree-walker": "^1.0.1", |
63 | "micromatch": "^4.0.2" | 71 | "picomatch": "^2.2.2" |
64 | } | 72 | } |
65 | }, | 73 | }, |
66 | "@types/color-name": { | 74 | "@types/color-name": { |
@@ -81,16 +89,45 @@ | |||
81 | "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", | 89 | "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", |
82 | "dev": true | 90 | "dev": true |
83 | }, | 91 | }, |
92 | "@types/events": { | ||
93 | "version": "3.0.0", | ||
94 | "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", | ||
95 | "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", | ||
96 | "dev": true | ||
97 | }, | ||
98 | "@types/glob": { | ||
99 | "version": "7.1.1", | ||
100 | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", | ||
101 | "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", | ||
102 | "dev": true, | ||
103 | "requires": { | ||
104 | "@types/events": "*", | ||
105 | "@types/minimatch": "*", | ||
106 | "@types/node": "*" | ||
107 | } | ||
108 | }, | ||
84 | "@types/json-schema": { | 109 | "@types/json-schema": { |
85 | "version": "7.0.4", | 110 | "version": "7.0.4", |
86 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", | 111 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", |
87 | "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==", | 112 | "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==", |
88 | "dev": true | 113 | "dev": true |
89 | }, | 114 | }, |
115 | "@types/minimatch": { | ||
116 | "version": "3.0.3", | ||
117 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", | ||
118 | "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", | ||
119 | "dev": true | ||
120 | }, | ||
121 | "@types/mocha": { | ||
122 | "version": "7.0.2", | ||
123 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", | ||
124 | "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", | ||
125 | "dev": true | ||
126 | }, | ||
90 | "@types/node": { | 127 | "@types/node": { |
91 | "version": "12.12.39", | 128 | "version": "14.0.5", |
92 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.39.tgz", | 129 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.5.tgz", |
93 | "integrity": "sha512-pADGfwnDkr6zagDwEiCVE4yQrv7XDkoeVa4OfA9Ju/zRTk6YNDLGtQbkdL4/56mCQQCs4AhNrBIag6jrp7ZuOg==", | 130 | "integrity": "sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==", |
94 | "dev": true | 131 | "dev": true |
95 | }, | 132 | }, |
96 | "@types/node-fetch": { | 133 | "@types/node-fetch": { |
@@ -119,56 +156,54 @@ | |||
119 | "dev": true | 156 | "dev": true |
120 | }, | 157 | }, |
121 | "@typescript-eslint/eslint-plugin": { | 158 | "@typescript-eslint/eslint-plugin": { |
122 | "version": "2.33.0", | 159 | "version": "3.0.0", |
123 | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.33.0.tgz", | 160 | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.0.0.tgz", |
124 | "integrity": "sha512-QV6P32Btu1sCI/kTqjTNI/8OpCYyvlGjW5vD8MpTIg+HGE5S88HtT1G+880M4bXlvXj/NjsJJG0aGcVh0DdbeQ==", | 161 | "integrity": "sha512-lcZ0M6jD4cqGccYOERKdMtg+VWpoq3NSnWVxpc/AwAy0zhkUYVioOUZmfNqiNH8/eBNGhCn6HXd6mKIGRgNc1Q==", |
125 | "dev": true, | 162 | "dev": true, |
126 | "requires": { | 163 | "requires": { |
127 | "@typescript-eslint/experimental-utils": "2.33.0", | 164 | "@typescript-eslint/experimental-utils": "3.0.0", |
128 | "functional-red-black-tree": "^1.0.1", | 165 | "functional-red-black-tree": "^1.0.1", |
129 | "regexpp": "^3.0.0", | 166 | "regexpp": "^3.0.0", |
167 | "semver": "^7.3.2", | ||
130 | "tsutils": "^3.17.1" | 168 | "tsutils": "^3.17.1" |
169 | }, | ||
170 | "dependencies": { | ||
171 | "semver": { | ||
172 | "version": "7.3.2", | ||
173 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", | ||
174 | "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", | ||
175 | "dev": true | ||
176 | } | ||
131 | } | 177 | } |
132 | }, | 178 | }, |
133 | "@typescript-eslint/experimental-utils": { | 179 | "@typescript-eslint/experimental-utils": { |
134 | "version": "2.33.0", | 180 | "version": "3.0.0", |
135 | "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.33.0.tgz", | 181 | "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.0.0.tgz", |
136 | "integrity": "sha512-qzPM2AuxtMrRq78LwyZa8Qn6gcY8obkIrBs1ehqmQADwkYzTE1Pb4y2W+U3rE/iFkSWcWHG2LS6MJfj6SmHApg==", | 182 | "integrity": "sha512-BN0vmr9N79M9s2ctITtChRuP1+Dls0x/wlg0RXW1yQ7WJKPurg6X3Xirv61J2sjPif4F8SLsFMs5Nzte0WYoTQ==", |
137 | "dev": true, | 183 | "dev": true, |
138 | "requires": { | 184 | "requires": { |
139 | "@types/json-schema": "^7.0.3", | 185 | "@types/json-schema": "^7.0.3", |
140 | "@typescript-eslint/typescript-estree": "2.33.0", | 186 | "@typescript-eslint/typescript-estree": "3.0.0", |
141 | "eslint-scope": "^5.0.0", | 187 | "eslint-scope": "^5.0.0", |
142 | "eslint-utils": "^2.0.0" | 188 | "eslint-utils": "^2.0.0" |
143 | }, | ||
144 | "dependencies": { | ||
145 | "eslint-utils": { | ||
146 | "version": "2.0.0", | ||
147 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", | ||
148 | "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", | ||
149 | "dev": true, | ||
150 | "requires": { | ||
151 | "eslint-visitor-keys": "^1.1.0" | ||
152 | } | ||
153 | } | ||
154 | } | 189 | } |
155 | }, | 190 | }, |
156 | "@typescript-eslint/parser": { | 191 | "@typescript-eslint/parser": { |
157 | "version": "2.33.0", | 192 | "version": "3.0.0", |
158 | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.33.0.tgz", | 193 | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.0.0.tgz", |
159 | "integrity": "sha512-AUtmwUUhJoH6yrtxZMHbRUEMsC2G6z5NSxg9KsROOGqNXasM71I8P2NihtumlWTUCRld70vqIZ6Pm4E5PAziEA==", | 194 | "integrity": "sha512-8RRCA9KLxoFNO0mQlrLZA0reGPd/MsobxZS/yPFj+0/XgMdS8+mO8mF3BDj2ZYQj03rkayhSJtF1HAohQ3iylw==", |
160 | "dev": true, | 195 | "dev": true, |
161 | "requires": { | 196 | "requires": { |
162 | "@types/eslint-visitor-keys": "^1.0.0", | 197 | "@types/eslint-visitor-keys": "^1.0.0", |
163 | "@typescript-eslint/experimental-utils": "2.33.0", | 198 | "@typescript-eslint/experimental-utils": "3.0.0", |
164 | "@typescript-eslint/typescript-estree": "2.33.0", | 199 | "@typescript-eslint/typescript-estree": "3.0.0", |
165 | "eslint-visitor-keys": "^1.1.0" | 200 | "eslint-visitor-keys": "^1.1.0" |
166 | } | 201 | } |
167 | }, | 202 | }, |
168 | "@typescript-eslint/typescript-estree": { | 203 | "@typescript-eslint/typescript-estree": { |
169 | "version": "2.33.0", | 204 | "version": "3.0.0", |
170 | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.33.0.tgz", | 205 | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.0.0.tgz", |
171 | "integrity": "sha512-d8rY6/yUxb0+mEwTShCQF2zYQdLlqihukNfG9IUlLYz5y1CH6G/9XYbrxQLq3Z14RNvkCC6oe+OcFlyUpwUbkg==", | 206 | "integrity": "sha512-nevQvHyNghsfLrrByzVIH4ZG3NROgJ8LZlfh3ddwPPH4CH7W4GAiSx5qu+xHuX5pWsq6q/eqMc1io840ZhAnUg==", |
172 | "dev": true, | 207 | "dev": true, |
173 | "requires": { | 208 | "requires": { |
174 | "debug": "^4.1.1", | 209 | "debug": "^4.1.1", |
@@ -189,9 +224,9 @@ | |||
189 | } | 224 | } |
190 | }, | 225 | }, |
191 | "acorn": { | 226 | "acorn": { |
192 | "version": "7.1.1", | 227 | "version": "7.2.0", |
193 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", | 228 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz", |
194 | "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", | 229 | "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==", |
195 | "dev": true | 230 | "dev": true |
196 | }, | 231 | }, |
197 | "acorn-jsx": { | 232 | "acorn-jsx": { |
@@ -200,10 +235,19 @@ | |||
200 | "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", | 235 | "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", |
201 | "dev": true | 236 | "dev": true |
202 | }, | 237 | }, |
238 | "agent-base": { | ||
239 | "version": "4.3.0", | ||
240 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", | ||
241 | "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", | ||
242 | "dev": true, | ||
243 | "requires": { | ||
244 | "es6-promisify": "^5.0.0" | ||
245 | } | ||
246 | }, | ||
203 | "ajv": { | 247 | "ajv": { |
204 | "version": "6.12.0", | 248 | "version": "6.12.2", |
205 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", | 249 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", |
206 | "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", | 250 | "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", |
207 | "dev": true, | 251 | "dev": true, |
208 | "requires": { | 252 | "requires": { |
209 | "fast-deep-equal": "^3.1.1", | 253 | "fast-deep-equal": "^3.1.1", |
@@ -212,6 +256,12 @@ | |||
212 | "uri-js": "^4.2.2" | 256 | "uri-js": "^4.2.2" |
213 | } | 257 | } |
214 | }, | 258 | }, |
259 | "ansi-colors": { | ||
260 | "version": "3.2.3", | ||
261 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", | ||
262 | "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", | ||
263 | "dev": true | ||
264 | }, | ||
215 | "ansi-escapes": { | 265 | "ansi-escapes": { |
216 | "version": "4.3.1", | 266 | "version": "4.3.1", |
217 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", | 267 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", |
@@ -244,6 +294,16 @@ | |||
244 | "color-convert": "^1.9.0" | 294 | "color-convert": "^1.9.0" |
245 | } | 295 | } |
246 | }, | 296 | }, |
297 | "anymatch": { | ||
298 | "version": "3.1.1", | ||
299 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", | ||
300 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", | ||
301 | "dev": true, | ||
302 | "requires": { | ||
303 | "normalize-path": "^3.0.0", | ||
304 | "picomatch": "^2.0.4" | ||
305 | } | ||
306 | }, | ||
247 | "argparse": { | 307 | "argparse": { |
248 | "version": "1.0.10", | 308 | "version": "1.0.10", |
249 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", | 309 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", |
@@ -283,6 +343,12 @@ | |||
283 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", | 343 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", |
284 | "dev": true | 344 | "dev": true |
285 | }, | 345 | }, |
346 | "binary-extensions": { | ||
347 | "version": "2.0.0", | ||
348 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", | ||
349 | "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", | ||
350 | "dev": true | ||
351 | }, | ||
286 | "boolbase": { | 352 | "boolbase": { |
287 | "version": "1.0.0", | 353 | "version": "1.0.0", |
288 | "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", | 354 | "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", |
@@ -308,6 +374,12 @@ | |||
308 | "fill-range": "^7.0.1" | 374 | "fill-range": "^7.0.1" |
309 | } | 375 | } |
310 | }, | 376 | }, |
377 | "browser-stdout": { | ||
378 | "version": "1.3.1", | ||
379 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", | ||
380 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", | ||
381 | "dev": true | ||
382 | }, | ||
311 | "buffer-crc32": { | 383 | "buffer-crc32": { |
312 | "version": "0.2.13", | 384 | "version": "0.2.13", |
313 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", | 385 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", |
@@ -326,6 +398,12 @@ | |||
326 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", | 398 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", |
327 | "dev": true | 399 | "dev": true |
328 | }, | 400 | }, |
401 | "camelcase": { | ||
402 | "version": "5.3.1", | ||
403 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", | ||
404 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", | ||
405 | "dev": true | ||
406 | }, | ||
329 | "chalk": { | 407 | "chalk": { |
330 | "version": "2.4.2", | 408 | "version": "2.4.2", |
331 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", | 409 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", |
@@ -357,6 +435,22 @@ | |||
357 | "parse5": "^3.0.1" | 435 | "parse5": "^3.0.1" |
358 | } | 436 | } |
359 | }, | 437 | }, |
438 | "chokidar": { | ||
439 | "version": "3.3.0", | ||
440 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", | ||
441 | "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", | ||
442 | "dev": true, | ||
443 | "requires": { | ||
444 | "anymatch": "~3.1.1", | ||
445 | "braces": "~3.0.2", | ||
446 | "fsevents": "~2.1.1", | ||
447 | "glob-parent": "~5.1.0", | ||
448 | "is-binary-path": "~2.1.0", | ||
449 | "is-glob": "~4.0.1", | ||
450 | "normalize-path": "~3.0.0", | ||
451 | "readdirp": "~3.2.0" | ||
452 | } | ||
453 | }, | ||
360 | "cli-cursor": { | 454 | "cli-cursor": { |
361 | "version": "3.1.0", | 455 | "version": "3.1.0", |
362 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", | 456 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", |
@@ -367,11 +461,62 @@ | |||
367 | } | 461 | } |
368 | }, | 462 | }, |
369 | "cli-width": { | 463 | "cli-width": { |
370 | "version": "2.2.0", | 464 | "version": "2.2.1", |
371 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", | 465 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", |
372 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", | 466 | "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", |
373 | "dev": true | 467 | "dev": true |
374 | }, | 468 | }, |
469 | "cliui": { | ||
470 | "version": "5.0.0", | ||
471 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", | ||
472 | "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", | ||
473 | "dev": true, | ||
474 | "requires": { | ||
475 | "string-width": "^3.1.0", | ||
476 | "strip-ansi": "^5.2.0", | ||
477 | "wrap-ansi": "^5.1.0" | ||
478 | }, | ||
479 | "dependencies": { | ||
480 | "ansi-regex": { | ||
481 | "version": "4.1.0", | ||
482 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", | ||
483 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", | ||
484 | "dev": true | ||
485 | }, | ||
486 | "emoji-regex": { | ||
487 | "version": "7.0.3", | ||
488 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", | ||
489 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", | ||
490 | "dev": true | ||
491 | }, | ||
492 | "is-fullwidth-code-point": { | ||
493 | "version": "2.0.0", | ||
494 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", | ||
495 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", | ||
496 | "dev": true | ||
497 | }, | ||
498 | "string-width": { | ||
499 | "version": "3.1.0", | ||
500 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", | ||
501 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", | ||
502 | "dev": true, | ||
503 | "requires": { | ||
504 | "emoji-regex": "^7.0.1", | ||
505 | "is-fullwidth-code-point": "^2.0.0", | ||
506 | "strip-ansi": "^5.1.0" | ||
507 | } | ||
508 | }, | ||
509 | "strip-ansi": { | ||
510 | "version": "5.2.0", | ||
511 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", | ||
512 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", | ||
513 | "dev": true, | ||
514 | "requires": { | ||
515 | "ansi-regex": "^4.1.0" | ||
516 | } | ||
517 | } | ||
518 | } | ||
519 | }, | ||
375 | "color-convert": { | 520 | "color-convert": { |
376 | "version": "1.9.3", | 521 | "version": "1.9.3", |
377 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", | 522 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", |
@@ -421,24 +566,14 @@ | |||
421 | "dev": true | 566 | "dev": true |
422 | }, | 567 | }, |
423 | "cross-spawn": { | 568 | "cross-spawn": { |
424 | "version": "6.0.5", | 569 | "version": "7.0.2", |
425 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", | 570 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", |
426 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", | 571 | "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", |
427 | "dev": true, | 572 | "dev": true, |
428 | "requires": { | 573 | "requires": { |
429 | "nice-try": "^1.0.4", | 574 | "path-key": "^3.1.0", |
430 | "path-key": "^2.0.1", | 575 | "shebang-command": "^2.0.0", |
431 | "semver": "^5.5.0", | 576 | "which": "^2.0.1" |
432 | "shebang-command": "^1.2.0", | ||
433 | "which": "^1.2.9" | ||
434 | }, | ||
435 | "dependencies": { | ||
436 | "semver": { | ||
437 | "version": "5.7.1", | ||
438 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", | ||
439 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", | ||
440 | "dev": true | ||
441 | } | ||
442 | } | 577 | } |
443 | }, | 578 | }, |
444 | "css-select": { | 579 | "css-select": { |
@@ -468,12 +603,39 @@ | |||
468 | "ms": "^2.1.1" | 603 | "ms": "^2.1.1" |
469 | } | 604 | } |
470 | }, | 605 | }, |
606 | "decamelize": { | ||
607 | "version": "1.2.0", | ||
608 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", | ||
609 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", | ||
610 | "dev": true | ||
611 | }, | ||
612 | "deep-freeze": { | ||
613 | "version": "0.0.1", | ||
614 | "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz", | ||
615 | "integrity": "sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=", | ||
616 | "dev": true | ||
617 | }, | ||
471 | "deep-is": { | 618 | "deep-is": { |
472 | "version": "0.1.3", | 619 | "version": "0.1.3", |
473 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", | 620 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", |
474 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", | 621 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", |
475 | "dev": true | 622 | "dev": true |
476 | }, | 623 | }, |
624 | "deepmerge": { | ||
625 | "version": "4.2.2", | ||
626 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", | ||
627 | "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", | ||
628 | "dev": true | ||
629 | }, | ||
630 | "define-properties": { | ||
631 | "version": "1.1.3", | ||
632 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", | ||
633 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", | ||
634 | "dev": true, | ||
635 | "requires": { | ||
636 | "object-keys": "^1.0.12" | ||
637 | } | ||
638 | }, | ||
477 | "delayed-stream": { | 639 | "delayed-stream": { |
478 | "version": "1.0.0", | 640 | "version": "1.0.0", |
479 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", | 641 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", |
@@ -486,6 +648,12 @@ | |||
486 | "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=", | 648 | "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=", |
487 | "dev": true | 649 | "dev": true |
488 | }, | 650 | }, |
651 | "diff": { | ||
652 | "version": "3.5.0", | ||
653 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", | ||
654 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", | ||
655 | "dev": true | ||
656 | }, | ||
489 | "doctrine": { | 657 | "doctrine": { |
490 | "version": "3.0.0", | 658 | "version": "3.0.0", |
491 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", | 659 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", |
@@ -562,6 +730,51 @@ | |||
562 | "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", | 730 | "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", |
563 | "dev": true | 731 | "dev": true |
564 | }, | 732 | }, |
733 | "es-abstract": { | ||
734 | "version": "1.17.5", | ||
735 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", | ||
736 | "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", | ||
737 | "dev": true, | ||
738 | "requires": { | ||
739 | "es-to-primitive": "^1.2.1", | ||
740 | "function-bind": "^1.1.1", | ||
741 | "has": "^1.0.3", | ||
742 | "has-symbols": "^1.0.1", | ||
743 | "is-callable": "^1.1.5", | ||
744 | "is-regex": "^1.0.5", | ||
745 | "object-inspect": "^1.7.0", | ||
746 | "object-keys": "^1.1.1", | ||
747 | "object.assign": "^4.1.0", | ||
748 | "string.prototype.trimleft": "^2.1.1", | ||
749 | "string.prototype.trimright": "^2.1.1" | ||
750 | } | ||
751 | }, | ||
752 | "es-to-primitive": { | ||
753 | "version": "1.2.1", | ||
754 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", | ||
755 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", | ||
756 | "dev": true, | ||
757 | "requires": { | ||
758 | "is-callable": "^1.1.4", | ||
759 | "is-date-object": "^1.0.1", | ||
760 | "is-symbol": "^1.0.2" | ||
761 | } | ||
762 | }, | ||
763 | "es6-promise": { | ||
764 | "version": "4.2.8", | ||
765 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", | ||
766 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", | ||
767 | "dev": true | ||
768 | }, | ||
769 | "es6-promisify": { | ||
770 | "version": "5.0.0", | ||
771 | "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", | ||
772 | "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", | ||
773 | "dev": true, | ||
774 | "requires": { | ||
775 | "es6-promise": "^4.0.3" | ||
776 | } | ||
777 | }, | ||
565 | "escape-string-regexp": { | 778 | "escape-string-regexp": { |
566 | "version": "1.0.5", | 779 | "version": "1.0.5", |
567 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", | 780 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", |
@@ -569,22 +782,22 @@ | |||
569 | "dev": true | 782 | "dev": true |
570 | }, | 783 | }, |
571 | "eslint": { | 784 | "eslint": { |
572 | "version": "6.8.0", | 785 | "version": "7.1.0", |
573 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", | 786 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.1.0.tgz", |
574 | "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", | 787 | "integrity": "sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA==", |
575 | "dev": true, | 788 | "dev": true, |
576 | "requires": { | 789 | "requires": { |
577 | "@babel/code-frame": "^7.0.0", | 790 | "@babel/code-frame": "^7.0.0", |
578 | "ajv": "^6.10.0", | 791 | "ajv": "^6.10.0", |
579 | "chalk": "^2.1.0", | 792 | "chalk": "^4.0.0", |
580 | "cross-spawn": "^6.0.5", | 793 | "cross-spawn": "^7.0.2", |
581 | "debug": "^4.0.1", | 794 | "debug": "^4.0.1", |
582 | "doctrine": "^3.0.0", | 795 | "doctrine": "^3.0.0", |
583 | "eslint-scope": "^5.0.0", | 796 | "eslint-scope": "^5.0.0", |
584 | "eslint-utils": "^1.4.3", | 797 | "eslint-utils": "^2.0.0", |
585 | "eslint-visitor-keys": "^1.1.0", | 798 | "eslint-visitor-keys": "^1.1.0", |
586 | "espree": "^6.1.2", | 799 | "espree": "^7.0.0", |
587 | "esquery": "^1.0.1", | 800 | "esquery": "^1.2.0", |
588 | "esutils": "^2.0.2", | 801 | "esutils": "^2.0.2", |
589 | "file-entry-cache": "^5.0.1", | 802 | "file-entry-cache": "^5.0.1", |
590 | "functional-red-black-tree": "^1.0.1", | 803 | "functional-red-black-tree": "^1.0.1", |
@@ -597,27 +810,76 @@ | |||
597 | "is-glob": "^4.0.0", | 810 | "is-glob": "^4.0.0", |
598 | "js-yaml": "^3.13.1", | 811 | "js-yaml": "^3.13.1", |
599 | "json-stable-stringify-without-jsonify": "^1.0.1", | 812 | "json-stable-stringify-without-jsonify": "^1.0.1", |
600 | "levn": "^0.3.0", | 813 | "levn": "^0.4.1", |
601 | "lodash": "^4.17.14", | 814 | "lodash": "^4.17.14", |
602 | "minimatch": "^3.0.4", | 815 | "minimatch": "^3.0.4", |
603 | "mkdirp": "^0.5.1", | ||
604 | "natural-compare": "^1.4.0", | 816 | "natural-compare": "^1.4.0", |
605 | "optionator": "^0.8.3", | 817 | "optionator": "^0.9.1", |
606 | "progress": "^2.0.0", | 818 | "progress": "^2.0.0", |
607 | "regexpp": "^2.0.1", | 819 | "regexpp": "^3.1.0", |
608 | "semver": "^6.1.2", | 820 | "semver": "^7.2.1", |
609 | "strip-ansi": "^5.2.0", | 821 | "strip-ansi": "^6.0.0", |
610 | "strip-json-comments": "^3.0.1", | 822 | "strip-json-comments": "^3.1.0", |
611 | "table": "^5.2.3", | 823 | "table": "^5.2.3", |
612 | "text-table": "^0.2.0", | 824 | "text-table": "^0.2.0", |
613 | "v8-compile-cache": "^2.0.3" | 825 | "v8-compile-cache": "^2.0.3" |
614 | }, | 826 | }, |
615 | "dependencies": { | 827 | "dependencies": { |
616 | "regexpp": { | 828 | "ansi-styles": { |
829 | "version": "4.2.1", | ||
830 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", | ||
831 | "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", | ||
832 | "dev": true, | ||
833 | "requires": { | ||
834 | "@types/color-name": "^1.1.1", | ||
835 | "color-convert": "^2.0.1" | ||
836 | } | ||
837 | }, | ||
838 | "chalk": { | ||
839 | "version": "4.0.0", | ||
840 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", | ||
841 | "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", | ||
842 | "dev": true, | ||
843 | "requires": { | ||
844 | "ansi-styles": "^4.1.0", | ||
845 | "supports-color": "^7.1.0" | ||
846 | } | ||
847 | }, | ||
848 | "color-convert": { | ||
617 | "version": "2.0.1", | 849 | "version": "2.0.1", |
618 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", | 850 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", |
619 | "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", | 851 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", |
852 | "dev": true, | ||
853 | "requires": { | ||
854 | "color-name": "~1.1.4" | ||
855 | } | ||
856 | }, | ||
857 | "color-name": { | ||
858 | "version": "1.1.4", | ||
859 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", | ||
860 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", | ||
861 | "dev": true | ||
862 | }, | ||
863 | "has-flag": { | ||
864 | "version": "4.0.0", | ||
865 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", | ||
866 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", | ||
867 | "dev": true | ||
868 | }, | ||
869 | "semver": { | ||
870 | "version": "7.3.2", | ||
871 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", | ||
872 | "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", | ||
620 | "dev": true | 873 | "dev": true |
874 | }, | ||
875 | "supports-color": { | ||
876 | "version": "7.1.0", | ||
877 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", | ||
878 | "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", | ||
879 | "dev": true, | ||
880 | "requires": { | ||
881 | "has-flag": "^4.0.0" | ||
882 | } | ||
621 | } | 883 | } |
622 | } | 884 | } |
623 | }, | 885 | }, |
@@ -632,9 +894,9 @@ | |||
632 | } | 894 | } |
633 | }, | 895 | }, |
634 | "eslint-utils": { | 896 | "eslint-utils": { |
635 | "version": "1.4.3", | 897 | "version": "2.0.0", |
636 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", | 898 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", |
637 | "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", | 899 | "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", |
638 | "dev": true, | 900 | "dev": true, |
639 | "requires": { | 901 | "requires": { |
640 | "eslint-visitor-keys": "^1.1.0" | 902 | "eslint-visitor-keys": "^1.1.0" |
@@ -647,9 +909,9 @@ | |||
647 | "dev": true | 909 | "dev": true |
648 | }, | 910 | }, |
649 | "espree": { | 911 | "espree": { |
650 | "version": "6.2.1", | 912 | "version": "7.0.0", |
651 | "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", | 913 | "resolved": "https://registry.npmjs.org/espree/-/espree-7.0.0.tgz", |
652 | "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", | 914 | "integrity": "sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw==", |
653 | "dev": true, | 915 | "dev": true, |
654 | "requires": { | 916 | "requires": { |
655 | "acorn": "^7.1.1", | 917 | "acorn": "^7.1.1", |
@@ -664,12 +926,20 @@ | |||
664 | "dev": true | 926 | "dev": true |
665 | }, | 927 | }, |
666 | "esquery": { | 928 | "esquery": { |
667 | "version": "1.1.0", | 929 | "version": "1.3.1", |
668 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.1.0.tgz", | 930 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", |
669 | "integrity": "sha512-MxYW9xKmROWF672KqjO75sszsA8Mxhw06YFeS5VHlB98KDHbOSurm3ArsjO60Eaf3QmGMCP1yn+0JQkNLo/97Q==", | 931 | "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", |
670 | "dev": true, | 932 | "dev": true, |
671 | "requires": { | 933 | "requires": { |
672 | "estraverse": "^4.0.0" | 934 | "estraverse": "^5.1.0" |
935 | }, | ||
936 | "dependencies": { | ||
937 | "estraverse": { | ||
938 | "version": "5.1.0", | ||
939 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", | ||
940 | "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", | ||
941 | "dev": true | ||
942 | } | ||
673 | } | 943 | } |
674 | }, | 944 | }, |
675 | "esrecurse": { | 945 | "esrecurse": { |
@@ -764,6 +1034,24 @@ | |||
764 | "to-regex-range": "^5.0.1" | 1034 | "to-regex-range": "^5.0.1" |
765 | } | 1035 | } |
766 | }, | 1036 | }, |
1037 | "find-up": { | ||
1038 | "version": "3.0.0", | ||
1039 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", | ||
1040 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", | ||
1041 | "dev": true, | ||
1042 | "requires": { | ||
1043 | "locate-path": "^3.0.0" | ||
1044 | } | ||
1045 | }, | ||
1046 | "flat": { | ||
1047 | "version": "4.1.0", | ||
1048 | "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", | ||
1049 | "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", | ||
1050 | "dev": true, | ||
1051 | "requires": { | ||
1052 | "is-buffer": "~2.0.3" | ||
1053 | } | ||
1054 | }, | ||
767 | "flat-cache": { | 1055 | "flat-cache": { |
768 | "version": "2.0.1", | 1056 | "version": "2.0.1", |
769 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", | 1057 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", |
@@ -776,9 +1064,9 @@ | |||
776 | } | 1064 | } |
777 | }, | 1065 | }, |
778 | "flatted": { | 1066 | "flatted": { |
779 | "version": "2.0.1", | 1067 | "version": "2.0.2", |
780 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", | 1068 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", |
781 | "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", | 1069 | "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", |
782 | "dev": true | 1070 | "dev": true |
783 | }, | 1071 | }, |
784 | "form-data": { | 1072 | "form-data": { |
@@ -805,12 +1093,24 @@ | |||
805 | "dev": true, | 1093 | "dev": true, |
806 | "optional": true | 1094 | "optional": true |
807 | }, | 1095 | }, |
1096 | "function-bind": { | ||
1097 | "version": "1.1.1", | ||
1098 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", | ||
1099 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", | ||
1100 | "dev": true | ||
1101 | }, | ||
808 | "functional-red-black-tree": { | 1102 | "functional-red-black-tree": { |
809 | "version": "1.0.1", | 1103 | "version": "1.0.1", |
810 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", | 1104 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", |
811 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", | 1105 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", |
812 | "dev": true | 1106 | "dev": true |
813 | }, | 1107 | }, |
1108 | "get-caller-file": { | ||
1109 | "version": "2.0.5", | ||
1110 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", | ||
1111 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", | ||
1112 | "dev": true | ||
1113 | }, | ||
814 | "glob": { | 1114 | "glob": { |
815 | "version": "7.1.6", | 1115 | "version": "7.1.6", |
816 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", | 1116 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", |
@@ -826,9 +1126,9 @@ | |||
826 | } | 1126 | } |
827 | }, | 1127 | }, |
828 | "glob-parent": { | 1128 | "glob-parent": { |
829 | "version": "5.1.0", | 1129 | "version": "5.1.1", |
830 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", | 1130 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", |
831 | "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", | 1131 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", |
832 | "dev": true, | 1132 | "dev": true, |
833 | "requires": { | 1133 | "requires": { |
834 | "is-glob": "^4.0.1" | 1134 | "is-glob": "^4.0.1" |
@@ -843,12 +1143,39 @@ | |||
843 | "type-fest": "^0.8.1" | 1143 | "type-fest": "^0.8.1" |
844 | } | 1144 | } |
845 | }, | 1145 | }, |
1146 | "growl": { | ||
1147 | "version": "1.10.5", | ||
1148 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", | ||
1149 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", | ||
1150 | "dev": true | ||
1151 | }, | ||
1152 | "has": { | ||
1153 | "version": "1.0.3", | ||
1154 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", | ||
1155 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", | ||
1156 | "dev": true, | ||
1157 | "requires": { | ||
1158 | "function-bind": "^1.1.1" | ||
1159 | } | ||
1160 | }, | ||
846 | "has-flag": { | 1161 | "has-flag": { |
847 | "version": "3.0.0", | 1162 | "version": "3.0.0", |
848 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", | 1163 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", |
849 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", | 1164 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", |
850 | "dev": true | 1165 | "dev": true |
851 | }, | 1166 | }, |
1167 | "has-symbols": { | ||
1168 | "version": "1.0.1", | ||
1169 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", | ||
1170 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", | ||
1171 | "dev": true | ||
1172 | }, | ||
1173 | "he": { | ||
1174 | "version": "1.2.0", | ||
1175 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", | ||
1176 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", | ||
1177 | "dev": true | ||
1178 | }, | ||
852 | "htmlparser2": { | 1179 | "htmlparser2": { |
853 | "version": "3.10.1", | 1180 | "version": "3.10.1", |
854 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", | 1181 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", |
@@ -863,6 +1190,54 @@ | |||
863 | "readable-stream": "^3.1.1" | 1190 | "readable-stream": "^3.1.1" |
864 | } | 1191 | } |
865 | }, | 1192 | }, |
1193 | "http-proxy-agent": { | ||
1194 | "version": "2.1.0", | ||
1195 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", | ||
1196 | "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", | ||
1197 | "dev": true, | ||
1198 | "requires": { | ||
1199 | "agent-base": "4", | ||
1200 | "debug": "3.1.0" | ||
1201 | }, | ||
1202 | "dependencies": { | ||
1203 | "debug": { | ||
1204 | "version": "3.1.0", | ||
1205 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", | ||
1206 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", | ||
1207 | "dev": true, | ||
1208 | "requires": { | ||
1209 | "ms": "2.0.0" | ||
1210 | } | ||
1211 | }, | ||
1212 | "ms": { | ||
1213 | "version": "2.0.0", | ||
1214 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | ||
1215 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", | ||
1216 | "dev": true | ||
1217 | } | ||
1218 | } | ||
1219 | }, | ||
1220 | "https-proxy-agent": { | ||
1221 | "version": "2.2.4", | ||
1222 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", | ||
1223 | "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", | ||
1224 | "dev": true, | ||
1225 | "requires": { | ||
1226 | "agent-base": "^4.3.0", | ||
1227 | "debug": "^3.1.0" | ||
1228 | }, | ||
1229 | "dependencies": { | ||
1230 | "debug": { | ||
1231 | "version": "3.2.6", | ||
1232 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", | ||
1233 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", | ||
1234 | "dev": true, | ||
1235 | "requires": { | ||
1236 | "ms": "^2.1.1" | ||
1237 | } | ||
1238 | } | ||
1239 | } | ||
1240 | }, | ||
866 | "iconv-lite": { | 1241 | "iconv-lite": { |
867 | "version": "0.4.24", | 1242 | "version": "0.4.24", |
868 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", | 1243 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", |
@@ -972,15 +1347,6 @@ | |||
972 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", | 1347 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", |
973 | "dev": true | 1348 | "dev": true |
974 | }, | 1349 | }, |
975 | "strip-ansi": { | ||
976 | "version": "6.0.0", | ||
977 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", | ||
978 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", | ||
979 | "dev": true, | ||
980 | "requires": { | ||
981 | "ansi-regex": "^5.0.0" | ||
982 | } | ||
983 | }, | ||
984 | "supports-color": { | 1350 | "supports-color": { |
985 | "version": "7.1.0", | 1351 | "version": "7.1.0", |
986 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", | 1352 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", |
@@ -992,6 +1358,33 @@ | |||
992 | } | 1358 | } |
993 | } | 1359 | } |
994 | }, | 1360 | }, |
1361 | "is-binary-path": { | ||
1362 | "version": "2.1.0", | ||
1363 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", | ||
1364 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", | ||
1365 | "dev": true, | ||
1366 | "requires": { | ||
1367 | "binary-extensions": "^2.0.0" | ||
1368 | } | ||
1369 | }, | ||
1370 | "is-buffer": { | ||
1371 | "version": "2.0.4", | ||
1372 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", | ||
1373 | "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", | ||
1374 | "dev": true | ||
1375 | }, | ||
1376 | "is-callable": { | ||
1377 | "version": "1.1.5", | ||
1378 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", | ||
1379 | "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", | ||
1380 | "dev": true | ||
1381 | }, | ||
1382 | "is-date-object": { | ||
1383 | "version": "1.0.2", | ||
1384 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", | ||
1385 | "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", | ||
1386 | "dev": true | ||
1387 | }, | ||
995 | "is-extglob": { | 1388 | "is-extglob": { |
996 | "version": "2.1.1", | 1389 | "version": "2.1.1", |
997 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", | 1390 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", |
@@ -1025,12 +1418,6 @@ | |||
1025 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", | 1418 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", |
1026 | "dev": true | 1419 | "dev": true |
1027 | }, | 1420 | }, |
1028 | "is-promise": { | ||
1029 | "version": "2.1.0", | ||
1030 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", | ||
1031 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", | ||
1032 | "dev": true | ||
1033 | }, | ||
1034 | "is-reference": { | 1421 | "is-reference": { |
1035 | "version": "1.1.4", | 1422 | "version": "1.1.4", |
1036 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", | 1423 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", |
@@ -1040,6 +1427,24 @@ | |||
1040 | "@types/estree": "0.0.39" | 1427 | "@types/estree": "0.0.39" |
1041 | } | 1428 | } |
1042 | }, | 1429 | }, |
1430 | "is-regex": { | ||
1431 | "version": "1.0.5", | ||
1432 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", | ||
1433 | "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", | ||
1434 | "dev": true, | ||
1435 | "requires": { | ||
1436 | "has": "^1.0.3" | ||
1437 | } | ||
1438 | }, | ||
1439 | "is-symbol": { | ||
1440 | "version": "1.0.3", | ||
1441 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", | ||
1442 | "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", | ||
1443 | "dev": true, | ||
1444 | "requires": { | ||
1445 | "has-symbols": "^1.0.1" | ||
1446 | } | ||
1447 | }, | ||
1043 | "isexe": { | 1448 | "isexe": { |
1044 | "version": "2.0.0", | 1449 | "version": "2.0.0", |
1045 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", | 1450 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", |
@@ -1053,9 +1458,9 @@ | |||
1053 | "dev": true | 1458 | "dev": true |
1054 | }, | 1459 | }, |
1055 | "js-yaml": { | 1460 | "js-yaml": { |
1056 | "version": "3.13.1", | 1461 | "version": "3.14.0", |
1057 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", | 1462 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", |
1058 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", | 1463 | "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", |
1059 | "dev": true, | 1464 | "dev": true, |
1060 | "requires": { | 1465 | "requires": { |
1061 | "argparse": "^1.0.7", | 1466 | "argparse": "^1.0.7", |
@@ -1081,13 +1486,13 @@ | |||
1081 | "dev": true | 1486 | "dev": true |
1082 | }, | 1487 | }, |
1083 | "levn": { | 1488 | "levn": { |
1084 | "version": "0.3.0", | 1489 | "version": "0.4.1", |
1085 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", | 1490 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", |
1086 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", | 1491 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", |
1087 | "dev": true, | 1492 | "dev": true, |
1088 | "requires": { | 1493 | "requires": { |
1089 | "prelude-ls": "~1.1.2", | 1494 | "prelude-ls": "^1.2.1", |
1090 | "type-check": "~0.3.2" | 1495 | "type-check": "~0.4.0" |
1091 | } | 1496 | } |
1092 | }, | 1497 | }, |
1093 | "linkify-it": { | 1498 | "linkify-it": { |
@@ -1099,12 +1504,31 @@ | |||
1099 | "uc.micro": "^1.0.1" | 1504 | "uc.micro": "^1.0.1" |
1100 | } | 1505 | } |
1101 | }, | 1506 | }, |
1507 | "locate-path": { | ||
1508 | "version": "3.0.0", | ||
1509 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", | ||
1510 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", | ||
1511 | "dev": true, | ||
1512 | "requires": { | ||
1513 | "p-locate": "^3.0.0", | ||
1514 | "path-exists": "^3.0.0" | ||
1515 | } | ||
1516 | }, | ||
1102 | "lodash": { | 1517 | "lodash": { |
1103 | "version": "4.17.15", | 1518 | "version": "4.17.15", |
1104 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", | 1519 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", |
1105 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", | 1520 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", |
1106 | "dev": true | 1521 | "dev": true |
1107 | }, | 1522 | }, |
1523 | "log-symbols": { | ||
1524 | "version": "3.0.0", | ||
1525 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", | ||
1526 | "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", | ||
1527 | "dev": true, | ||
1528 | "requires": { | ||
1529 | "chalk": "^2.4.2" | ||
1530 | } | ||
1531 | }, | ||
1108 | "lru-cache": { | 1532 | "lru-cache": { |
1109 | "version": "4.1.5", | 1533 | "version": "4.1.5", |
1110 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", | 1534 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", |
@@ -1151,16 +1575,6 @@ | |||
1151 | "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", | 1575 | "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", |
1152 | "dev": true | 1576 | "dev": true |
1153 | }, | 1577 | }, |
1154 | "micromatch": { | ||
1155 | "version": "4.0.2", | ||
1156 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", | ||
1157 | "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", | ||
1158 | "dev": true, | ||
1159 | "requires": { | ||
1160 | "braces": "^3.0.1", | ||
1161 | "picomatch": "^2.0.5" | ||
1162 | } | ||
1163 | }, | ||
1164 | "mime": { | 1578 | "mime": { |
1165 | "version": "1.6.0", | 1579 | "version": "1.6.0", |
1166 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", | 1580 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", |
@@ -1204,14 +1618,111 @@ | |||
1204 | "dev": true | 1618 | "dev": true |
1205 | }, | 1619 | }, |
1206 | "mkdirp": { | 1620 | "mkdirp": { |
1207 | "version": "0.5.3", | 1621 | "version": "0.5.5", |
1208 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", | 1622 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", |
1209 | "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", | 1623 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", |
1210 | "dev": true, | 1624 | "dev": true, |
1211 | "requires": { | 1625 | "requires": { |
1212 | "minimist": "^1.2.5" | 1626 | "minimist": "^1.2.5" |
1213 | } | 1627 | } |
1214 | }, | 1628 | }, |
1629 | "mocha": { | ||
1630 | "version": "7.2.0", | ||
1631 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", | ||
1632 | "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", | ||
1633 | "dev": true, | ||
1634 | "requires": { | ||
1635 | "ansi-colors": "3.2.3", | ||
1636 | "browser-stdout": "1.3.1", | ||
1637 | "chokidar": "3.3.0", | ||
1638 | "debug": "3.2.6", | ||
1639 | "diff": "3.5.0", | ||
1640 | "escape-string-regexp": "1.0.5", | ||
1641 | "find-up": "3.0.0", | ||
1642 | "glob": "7.1.3", | ||
1643 | "growl": "1.10.5", | ||
1644 | "he": "1.2.0", | ||
1645 | "js-yaml": "3.13.1", | ||
1646 | "log-symbols": "3.0.0", | ||
1647 | "minimatch": "3.0.4", | ||
1648 | "mkdirp": "0.5.5", | ||
1649 | "ms": "2.1.1", | ||
1650 | "node-environment-flags": "1.0.6", | ||
1651 | "object.assign": "4.1.0", | ||
1652 | "strip-json-comments": "2.0.1", | ||
1653 | "supports-color": "6.0.0", | ||
1654 | "which": "1.3.1", | ||
1655 | "wide-align": "1.1.3", | ||
1656 | "yargs": "13.3.2", | ||
1657 | "yargs-parser": "13.1.2", | ||
1658 | "yargs-unparser": "1.6.0" | ||
1659 | }, | ||
1660 | "dependencies": { | ||
1661 | "debug": { | ||
1662 | "version": "3.2.6", | ||
1663 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", | ||
1664 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", | ||
1665 | "dev": true, | ||
1666 | "requires": { | ||
1667 | "ms": "^2.1.1" | ||
1668 | } | ||
1669 | }, | ||
1670 | "glob": { | ||
1671 | "version": "7.1.3", | ||
1672 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", | ||
1673 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", | ||
1674 | "dev": true, | ||
1675 | "requires": { | ||
1676 | "fs.realpath": "^1.0.0", | ||
1677 | "inflight": "^1.0.4", | ||
1678 | "inherits": "2", | ||
1679 | "minimatch": "^3.0.4", | ||
1680 | "once": "^1.3.0", | ||
1681 | "path-is-absolute": "^1.0.0" | ||
1682 | } | ||
1683 | }, | ||
1684 | "js-yaml": { | ||
1685 | "version": "3.13.1", | ||
1686 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", | ||
1687 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", | ||
1688 | "dev": true, | ||
1689 | "requires": { | ||
1690 | "argparse": "^1.0.7", | ||
1691 | "esprima": "^4.0.0" | ||
1692 | } | ||
1693 | }, | ||
1694 | "ms": { | ||
1695 | "version": "2.1.1", | ||
1696 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", | ||
1697 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", | ||
1698 | "dev": true | ||
1699 | }, | ||
1700 | "strip-json-comments": { | ||
1701 | "version": "2.0.1", | ||
1702 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", | ||
1703 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", | ||
1704 | "dev": true | ||
1705 | }, | ||
1706 | "supports-color": { | ||
1707 | "version": "6.0.0", | ||
1708 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", | ||
1709 | "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", | ||
1710 | "dev": true, | ||
1711 | "requires": { | ||
1712 | "has-flag": "^3.0.0" | ||
1713 | } | ||
1714 | }, | ||
1715 | "which": { | ||
1716 | "version": "1.3.1", | ||
1717 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", | ||
1718 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", | ||
1719 | "dev": true, | ||
1720 | "requires": { | ||
1721 | "isexe": "^2.0.0" | ||
1722 | } | ||
1723 | } | ||
1724 | } | ||
1725 | }, | ||
1215 | "ms": { | 1726 | "ms": { |
1216 | "version": "2.1.2", | 1727 | "version": "2.1.2", |
1217 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | 1728 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", |
@@ -1230,17 +1741,35 @@ | |||
1230 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", | 1741 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", |
1231 | "dev": true | 1742 | "dev": true |
1232 | }, | 1743 | }, |
1233 | "nice-try": { | 1744 | "node-environment-flags": { |
1234 | "version": "1.0.5", | 1745 | "version": "1.0.6", |
1235 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", | 1746 | "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", |
1236 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", | 1747 | "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", |
1237 | "dev": true | 1748 | "dev": true, |
1749 | "requires": { | ||
1750 | "object.getownpropertydescriptors": "^2.0.3", | ||
1751 | "semver": "^5.7.0" | ||
1752 | }, | ||
1753 | "dependencies": { | ||
1754 | "semver": { | ||
1755 | "version": "5.7.1", | ||
1756 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", | ||
1757 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", | ||
1758 | "dev": true | ||
1759 | } | ||
1760 | } | ||
1238 | }, | 1761 | }, |
1239 | "node-fetch": { | 1762 | "node-fetch": { |
1240 | "version": "2.6.0", | 1763 | "version": "2.6.0", |
1241 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", | 1764 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", |
1242 | "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" | 1765 | "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" |
1243 | }, | 1766 | }, |
1767 | "normalize-path": { | ||
1768 | "version": "3.0.0", | ||
1769 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", | ||
1770 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", | ||
1771 | "dev": true | ||
1772 | }, | ||
1244 | "nth-check": { | 1773 | "nth-check": { |
1245 | "version": "1.0.2", | 1774 | "version": "1.0.2", |
1246 | "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", | 1775 | "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", |
@@ -1250,6 +1779,40 @@ | |||
1250 | "boolbase": "~1.0.0" | 1779 | "boolbase": "~1.0.0" |
1251 | } | 1780 | } |
1252 | }, | 1781 | }, |
1782 | "object-inspect": { | ||
1783 | "version": "1.7.0", | ||
1784 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", | ||
1785 | "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", | ||
1786 | "dev": true | ||
1787 | }, | ||
1788 | "object-keys": { | ||
1789 | "version": "1.1.1", | ||
1790 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", | ||
1791 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", | ||
1792 | "dev": true | ||
1793 | }, | ||
1794 | "object.assign": { | ||
1795 | "version": "4.1.0", | ||
1796 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", | ||
1797 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", | ||
1798 | "dev": true, | ||
1799 | "requires": { | ||
1800 | "define-properties": "^1.1.2", | ||
1801 | "function-bind": "^1.1.1", | ||
1802 | "has-symbols": "^1.0.0", | ||
1803 | "object-keys": "^1.0.11" | ||
1804 | } | ||
1805 | }, | ||
1806 | "object.getownpropertydescriptors": { | ||
1807 | "version": "2.1.0", | ||
1808 | "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", | ||
1809 | "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", | ||
1810 | "dev": true, | ||
1811 | "requires": { | ||
1812 | "define-properties": "^1.1.3", | ||
1813 | "es-abstract": "^1.17.0-next.1" | ||
1814 | } | ||
1815 | }, | ||
1253 | "once": { | 1816 | "once": { |
1254 | "version": "1.4.0", | 1817 | "version": "1.4.0", |
1255 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", | 1818 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", |
@@ -1269,17 +1832,17 @@ | |||
1269 | } | 1832 | } |
1270 | }, | 1833 | }, |
1271 | "optionator": { | 1834 | "optionator": { |
1272 | "version": "0.8.3", | 1835 | "version": "0.9.1", |
1273 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", | 1836 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", |
1274 | "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", | 1837 | "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", |
1275 | "dev": true, | 1838 | "dev": true, |
1276 | "requires": { | 1839 | "requires": { |
1277 | "deep-is": "~0.1.3", | 1840 | "deep-is": "^0.1.3", |
1278 | "fast-levenshtein": "~2.0.6", | 1841 | "fast-levenshtein": "^2.0.6", |
1279 | "levn": "~0.3.0", | 1842 | "levn": "^0.4.1", |
1280 | "prelude-ls": "~1.1.2", | 1843 | "prelude-ls": "^1.2.1", |
1281 | "type-check": "~0.3.2", | 1844 | "type-check": "^0.4.0", |
1282 | "word-wrap": "~1.2.3" | 1845 | "word-wrap": "^1.2.3" |
1283 | } | 1846 | } |
1284 | }, | 1847 | }, |
1285 | "os": { | 1848 | "os": { |
@@ -1310,6 +1873,30 @@ | |||
1310 | "os-tmpdir": "^1.0.0" | 1873 | "os-tmpdir": "^1.0.0" |
1311 | } | 1874 | } |
1312 | }, | 1875 | }, |
1876 | "p-limit": { | ||
1877 | "version": "2.3.0", | ||
1878 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", | ||
1879 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", | ||
1880 | "dev": true, | ||
1881 | "requires": { | ||
1882 | "p-try": "^2.0.0" | ||
1883 | } | ||
1884 | }, | ||
1885 | "p-locate": { | ||
1886 | "version": "3.0.0", | ||
1887 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", | ||
1888 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", | ||
1889 | "dev": true, | ||
1890 | "requires": { | ||
1891 | "p-limit": "^2.0.0" | ||
1892 | } | ||
1893 | }, | ||
1894 | "p-try": { | ||
1895 | "version": "2.2.0", | ||
1896 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", | ||
1897 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", | ||
1898 | "dev": true | ||
1899 | }, | ||
1313 | "parent-module": { | 1900 | "parent-module": { |
1314 | "version": "1.0.1", | 1901 | "version": "1.0.1", |
1315 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", | 1902 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", |
@@ -1345,6 +1932,12 @@ | |||
1345 | "@types/node": "*" | 1932 | "@types/node": "*" |
1346 | } | 1933 | } |
1347 | }, | 1934 | }, |
1935 | "path-exists": { | ||
1936 | "version": "3.0.0", | ||
1937 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", | ||
1938 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", | ||
1939 | "dev": true | ||
1940 | }, | ||
1348 | "path-is-absolute": { | 1941 | "path-is-absolute": { |
1349 | "version": "1.0.1", | 1942 | "version": "1.0.1", |
1350 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", | 1943 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", |
@@ -1352,9 +1945,9 @@ | |||
1352 | "dev": true | 1945 | "dev": true |
1353 | }, | 1946 | }, |
1354 | "path-key": { | 1947 | "path-key": { |
1355 | "version": "2.0.1", | 1948 | "version": "3.1.1", |
1356 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", | 1949 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", |
1357 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", | 1950 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", |
1358 | "dev": true | 1951 | "dev": true |
1359 | }, | 1952 | }, |
1360 | "path-parse": { | 1953 | "path-parse": { |
@@ -1376,9 +1969,9 @@ | |||
1376 | "dev": true | 1969 | "dev": true |
1377 | }, | 1970 | }, |
1378 | "prelude-ls": { | 1971 | "prelude-ls": { |
1379 | "version": "1.1.2", | 1972 | "version": "1.2.1", |
1380 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", | 1973 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", |
1381 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", | 1974 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", |
1382 | "dev": true | 1975 | "dev": true |
1383 | }, | 1976 | }, |
1384 | "progress": { | 1977 | "progress": { |
@@ -1419,16 +2012,37 @@ | |||
1419 | "util-deprecate": "^1.0.1" | 2012 | "util-deprecate": "^1.0.1" |
1420 | } | 2013 | } |
1421 | }, | 2014 | }, |
2015 | "readdirp": { | ||
2016 | "version": "3.2.0", | ||
2017 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", | ||
2018 | "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", | ||
2019 | "dev": true, | ||
2020 | "requires": { | ||
2021 | "picomatch": "^2.0.4" | ||
2022 | } | ||
2023 | }, | ||
1422 | "regexpp": { | 2024 | "regexpp": { |
1423 | "version": "3.1.0", | 2025 | "version": "3.1.0", |
1424 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", | 2026 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", |
1425 | "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", | 2027 | "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", |
1426 | "dev": true | 2028 | "dev": true |
1427 | }, | 2029 | }, |
2030 | "require-directory": { | ||
2031 | "version": "2.1.1", | ||
2032 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", | ||
2033 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", | ||
2034 | "dev": true | ||
2035 | }, | ||
2036 | "require-main-filename": { | ||
2037 | "version": "2.0.0", | ||
2038 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", | ||
2039 | "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", | ||
2040 | "dev": true | ||
2041 | }, | ||
1428 | "resolve": { | 2042 | "resolve": { |
1429 | "version": "1.16.1", | 2043 | "version": "1.17.0", |
1430 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.1.tgz", | 2044 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", |
1431 | "integrity": "sha512-rmAglCSqWWMrrBv/XM6sW0NuRFiKViw/W4d9EbC4pt+49H8JwHy+mcGmALTEg504AUDcLTvb1T2q3E9AnmY+ig==", | 2045 | "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", |
1432 | "dev": true, | 2046 | "dev": true, |
1433 | "requires": { | 2047 | "requires": { |
1434 | "path-parse": "^1.0.6" | 2048 | "path-parse": "^1.0.6" |
@@ -1460,30 +2074,35 @@ | |||
1460 | } | 2074 | } |
1461 | }, | 2075 | }, |
1462 | "rollup": { | 2076 | "rollup": { |
1463 | "version": "2.10.0", | 2077 | "version": "2.10.9", |
1464 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.10.0.tgz", | 2078 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.10.9.tgz", |
1465 | "integrity": "sha512-7BmpEfUN9P6esJzWIn3DmR//90mW6YwYB1t3y48LpF8ITpYtL8s1kEirMKqUu44dVH/6a/rs0EuwYVL3FuRDoA==", | 2079 | "integrity": "sha512-dY/EbjiWC17ZCUSyk14hkxATAMAShkMsD43XmZGWjLrgFj15M3Dw2kEkA9ns64BiLFm9PKN6vTQw8neHwK74eg==", |
1466 | "dev": true, | 2080 | "dev": true, |
1467 | "requires": { | 2081 | "requires": { |
1468 | "fsevents": "~2.1.2" | 2082 | "fsevents": "~2.1.2" |
1469 | } | 2083 | } |
1470 | }, | 2084 | }, |
1471 | "run-async": { | 2085 | "run-async": { |
1472 | "version": "2.4.0", | 2086 | "version": "2.4.1", |
1473 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz", | 2087 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", |
1474 | "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==", | 2088 | "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", |
1475 | "dev": true, | 2089 | "dev": true |
1476 | "requires": { | ||
1477 | "is-promise": "^2.1.0" | ||
1478 | } | ||
1479 | }, | 2090 | }, |
1480 | "rxjs": { | 2091 | "rxjs": { |
1481 | "version": "6.5.4", | 2092 | "version": "6.5.5", |
1482 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", | 2093 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", |
1483 | "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", | 2094 | "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", |
1484 | "dev": true, | 2095 | "dev": true, |
1485 | "requires": { | 2096 | "requires": { |
1486 | "tslib": "^1.9.0" | 2097 | "tslib": "^1.9.0" |
2098 | }, | ||
2099 | "dependencies": { | ||
2100 | "tslib": { | ||
2101 | "version": "1.13.0", | ||
2102 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", | ||
2103 | "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", | ||
2104 | "dev": true | ||
2105 | } | ||
1487 | } | 2106 | } |
1488 | }, | 2107 | }, |
1489 | "safe-buffer": { | 2108 | "safe-buffer": { |
@@ -1503,19 +2122,25 @@ | |||
1503 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", | 2122 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", |
1504 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" | 2123 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" |
1505 | }, | 2124 | }, |
2125 | "set-blocking": { | ||
2126 | "version": "2.0.0", | ||
2127 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", | ||
2128 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", | ||
2129 | "dev": true | ||
2130 | }, | ||
1506 | "shebang-command": { | 2131 | "shebang-command": { |
1507 | "version": "1.2.0", | 2132 | "version": "2.0.0", |
1508 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", | 2133 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", |
1509 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", | 2134 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", |
1510 | "dev": true, | 2135 | "dev": true, |
1511 | "requires": { | 2136 | "requires": { |
1512 | "shebang-regex": "^1.0.0" | 2137 | "shebang-regex": "^3.0.0" |
1513 | } | 2138 | } |
1514 | }, | 2139 | }, |
1515 | "shebang-regex": { | 2140 | "shebang-regex": { |
1516 | "version": "1.0.0", | 2141 | "version": "3.0.0", |
1517 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", | 2142 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", |
1518 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", | 2143 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", |
1519 | "dev": true | 2144 | "dev": true |
1520 | }, | 2145 | }, |
1521 | "sigmund": { | 2146 | "sigmund": { |
@@ -1525,9 +2150,9 @@ | |||
1525 | "dev": true | 2150 | "dev": true |
1526 | }, | 2151 | }, |
1527 | "signal-exit": { | 2152 | "signal-exit": { |
1528 | "version": "3.0.2", | 2153 | "version": "3.0.3", |
1529 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", | 2154 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", |
1530 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", | 2155 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", |
1531 | "dev": true | 2156 | "dev": true |
1532 | }, | 2157 | }, |
1533 | "slice-ansi": { | 2158 | "slice-ansi": { |
@@ -1570,17 +2195,48 @@ | |||
1570 | "emoji-regex": "^8.0.0", | 2195 | "emoji-regex": "^8.0.0", |
1571 | "is-fullwidth-code-point": "^3.0.0", | 2196 | "is-fullwidth-code-point": "^3.0.0", |
1572 | "strip-ansi": "^6.0.0" | 2197 | "strip-ansi": "^6.0.0" |
1573 | }, | 2198 | } |
1574 | "dependencies": { | 2199 | }, |
1575 | "strip-ansi": { | 2200 | "string.prototype.trimend": { |
1576 | "version": "6.0.0", | 2201 | "version": "1.0.1", |
1577 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", | 2202 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", |
1578 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", | 2203 | "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", |
1579 | "dev": true, | 2204 | "dev": true, |
1580 | "requires": { | 2205 | "requires": { |
1581 | "ansi-regex": "^5.0.0" | 2206 | "define-properties": "^1.1.3", |
1582 | } | 2207 | "es-abstract": "^1.17.5" |
1583 | } | 2208 | } |
2209 | }, | ||
2210 | "string.prototype.trimleft": { | ||
2211 | "version": "2.1.2", | ||
2212 | "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", | ||
2213 | "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", | ||
2214 | "dev": true, | ||
2215 | "requires": { | ||
2216 | "define-properties": "^1.1.3", | ||
2217 | "es-abstract": "^1.17.5", | ||
2218 | "string.prototype.trimstart": "^1.0.0" | ||
2219 | } | ||
2220 | }, | ||
2221 | "string.prototype.trimright": { | ||
2222 | "version": "2.1.2", | ||
2223 | "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", | ||
2224 | "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", | ||
2225 | "dev": true, | ||
2226 | "requires": { | ||
2227 | "define-properties": "^1.1.3", | ||
2228 | "es-abstract": "^1.17.5", | ||
2229 | "string.prototype.trimend": "^1.0.0" | ||
2230 | } | ||
2231 | }, | ||
2232 | "string.prototype.trimstart": { | ||
2233 | "version": "1.0.1", | ||
2234 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", | ||
2235 | "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", | ||
2236 | "dev": true, | ||
2237 | "requires": { | ||
2238 | "define-properties": "^1.1.3", | ||
2239 | "es-abstract": "^1.17.5" | ||
1584 | } | 2240 | } |
1585 | }, | 2241 | }, |
1586 | "string_decoder": { | 2242 | "string_decoder": { |
@@ -1593,26 +2249,18 @@ | |||
1593 | } | 2249 | } |
1594 | }, | 2250 | }, |
1595 | "strip-ansi": { | 2251 | "strip-ansi": { |
1596 | "version": "5.2.0", | 2252 | "version": "6.0.0", |
1597 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", | 2253 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", |
1598 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", | 2254 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", |
1599 | "dev": true, | 2255 | "dev": true, |
1600 | "requires": { | 2256 | "requires": { |
1601 | "ansi-regex": "^4.1.0" | 2257 | "ansi-regex": "^5.0.0" |
1602 | }, | ||
1603 | "dependencies": { | ||
1604 | "ansi-regex": { | ||
1605 | "version": "4.1.0", | ||
1606 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", | ||
1607 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", | ||
1608 | "dev": true | ||
1609 | } | ||
1610 | } | 2258 | } |
1611 | }, | 2259 | }, |
1612 | "strip-json-comments": { | 2260 | "strip-json-comments": { |
1613 | "version": "3.0.1", | 2261 | "version": "3.1.0", |
1614 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", | 2262 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", |
1615 | "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", | 2263 | "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", |
1616 | "dev": true | 2264 | "dev": true |
1617 | }, | 2265 | }, |
1618 | "supports-color": { | 2266 | "supports-color": { |
@@ -1636,6 +2284,12 @@ | |||
1636 | "string-width": "^3.0.0" | 2284 | "string-width": "^3.0.0" |
1637 | }, | 2285 | }, |
1638 | "dependencies": { | 2286 | "dependencies": { |
2287 | "ansi-regex": { | ||
2288 | "version": "4.1.0", | ||
2289 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", | ||
2290 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", | ||
2291 | "dev": true | ||
2292 | }, | ||
1639 | "emoji-regex": { | 2293 | "emoji-regex": { |
1640 | "version": "7.0.3", | 2294 | "version": "7.0.3", |
1641 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", | 2295 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", |
@@ -1658,6 +2312,15 @@ | |||
1658 | "is-fullwidth-code-point": "^2.0.0", | 2312 | "is-fullwidth-code-point": "^2.0.0", |
1659 | "strip-ansi": "^5.1.0" | 2313 | "strip-ansi": "^5.1.0" |
1660 | } | 2314 | } |
2315 | }, | ||
2316 | "strip-ansi": { | ||
2317 | "version": "5.2.0", | ||
2318 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", | ||
2319 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", | ||
2320 | "dev": true, | ||
2321 | "requires": { | ||
2322 | "ansi-regex": "^4.1.0" | ||
2323 | } | ||
1661 | } | 2324 | } |
1662 | } | 2325 | } |
1663 | }, | 2326 | }, |
@@ -1692,9 +2355,9 @@ | |||
1692 | } | 2355 | } |
1693 | }, | 2356 | }, |
1694 | "tslib": { | 2357 | "tslib": { |
1695 | "version": "1.12.0", | 2358 | "version": "2.0.0", |
1696 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.12.0.tgz", | 2359 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.0.tgz", |
1697 | "integrity": "sha512-5rxCQkP0kytf4H1T4xz1imjxaUUPMvc5aWp0rJ/VMIN7ClRiH1FwFvBt8wOeMasp/epeUnmSW6CixSIePtiLqA==", | 2360 | "integrity": "sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==", |
1698 | "dev": true | 2361 | "dev": true |
1699 | }, | 2362 | }, |
1700 | "tsutils": { | 2363 | "tsutils": { |
@@ -1704,6 +2367,14 @@ | |||
1704 | "dev": true, | 2367 | "dev": true, |
1705 | "requires": { | 2368 | "requires": { |
1706 | "tslib": "^1.8.1" | 2369 | "tslib": "^1.8.1" |
2370 | }, | ||
2371 | "dependencies": { | ||
2372 | "tslib": { | ||
2373 | "version": "1.13.0", | ||
2374 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", | ||
2375 | "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", | ||
2376 | "dev": true | ||
2377 | } | ||
1707 | } | 2378 | } |
1708 | }, | 2379 | }, |
1709 | "tunnel": { | 2380 | "tunnel": { |
@@ -1713,12 +2384,12 @@ | |||
1713 | "dev": true | 2384 | "dev": true |
1714 | }, | 2385 | }, |
1715 | "type-check": { | 2386 | "type-check": { |
1716 | "version": "0.3.2", | 2387 | "version": "0.4.0", |
1717 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", | 2388 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", |
1718 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", | 2389 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", |
1719 | "dev": true, | 2390 | "dev": true, |
1720 | "requires": { | 2391 | "requires": { |
1721 | "prelude-ls": "~1.1.2" | 2392 | "prelude-ls": "^1.2.1" |
1722 | } | 2393 | } |
1723 | }, | 2394 | }, |
1724 | "type-fest": { | 2395 | "type-fest": { |
@@ -1738,9 +2409,9 @@ | |||
1738 | } | 2409 | } |
1739 | }, | 2410 | }, |
1740 | "typescript": { | 2411 | "typescript": { |
1741 | "version": "3.9.2", | 2412 | "version": "3.9.3", |
1742 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.2.tgz", | 2413 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz", |
1743 | "integrity": "sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw==", | 2414 | "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==", |
1744 | "dev": true | 2415 | "dev": true |
1745 | }, | 2416 | }, |
1746 | "typescript-formatter": { | 2417 | "typescript-formatter": { |
@@ -1865,21 +2536,131 @@ | |||
1865 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0-next.1.tgz", | 2536 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0-next.1.tgz", |
1866 | "integrity": "sha512-tZFUSbyjUcrh+qQf13ALX4QDdOfDX0cVaBFgy7ktJ0VwS7AW/yRKgGPSxVqqP9OCMNPdqP57O5q47w2pEwfaUg==" | 2537 | "integrity": "sha512-tZFUSbyjUcrh+qQf13ALX4QDdOfDX0cVaBFgy7ktJ0VwS7AW/yRKgGPSxVqqP9OCMNPdqP57O5q47w2pEwfaUg==" |
1867 | }, | 2538 | }, |
2539 | "vscode-test": { | ||
2540 | "version": "1.3.0", | ||
2541 | "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.3.0.tgz", | ||
2542 | "integrity": "sha512-LddukcBiSU2FVTDr3c1D8lwkiOvwlJdDL2hqVbn6gIz+rpTqUCkMZSKYm94Y1v0WXlHSDQBsXyY+tchWQgGVsw==", | ||
2543 | "dev": true, | ||
2544 | "requires": { | ||
2545 | "http-proxy-agent": "^2.1.0", | ||
2546 | "https-proxy-agent": "^2.2.4", | ||
2547 | "rimraf": "^2.6.3" | ||
2548 | } | ||
2549 | }, | ||
1868 | "which": { | 2550 | "which": { |
1869 | "version": "1.3.1", | 2551 | "version": "2.0.2", |
1870 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", | 2552 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", |
1871 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", | 2553 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", |
1872 | "dev": true, | 2554 | "dev": true, |
1873 | "requires": { | 2555 | "requires": { |
1874 | "isexe": "^2.0.0" | 2556 | "isexe": "^2.0.0" |
1875 | } | 2557 | } |
1876 | }, | 2558 | }, |
2559 | "which-module": { | ||
2560 | "version": "2.0.0", | ||
2561 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", | ||
2562 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", | ||
2563 | "dev": true | ||
2564 | }, | ||
2565 | "wide-align": { | ||
2566 | "version": "1.1.3", | ||
2567 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", | ||
2568 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", | ||
2569 | "dev": true, | ||
2570 | "requires": { | ||
2571 | "string-width": "^1.0.2 || 2" | ||
2572 | }, | ||
2573 | "dependencies": { | ||
2574 | "ansi-regex": { | ||
2575 | "version": "3.0.0", | ||
2576 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", | ||
2577 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", | ||
2578 | "dev": true | ||
2579 | }, | ||
2580 | "is-fullwidth-code-point": { | ||
2581 | "version": "2.0.0", | ||
2582 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", | ||
2583 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", | ||
2584 | "dev": true | ||
2585 | }, | ||
2586 | "string-width": { | ||
2587 | "version": "2.1.1", | ||
2588 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", | ||
2589 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", | ||
2590 | "dev": true, | ||
2591 | "requires": { | ||
2592 | "is-fullwidth-code-point": "^2.0.0", | ||
2593 | "strip-ansi": "^4.0.0" | ||
2594 | } | ||
2595 | }, | ||
2596 | "strip-ansi": { | ||
2597 | "version": "4.0.0", | ||
2598 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", | ||
2599 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", | ||
2600 | "dev": true, | ||
2601 | "requires": { | ||
2602 | "ansi-regex": "^3.0.0" | ||
2603 | } | ||
2604 | } | ||
2605 | } | ||
2606 | }, | ||
1877 | "word-wrap": { | 2607 | "word-wrap": { |
1878 | "version": "1.2.3", | 2608 | "version": "1.2.3", |
1879 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", | 2609 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", |
1880 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", | 2610 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", |
1881 | "dev": true | 2611 | "dev": true |
1882 | }, | 2612 | }, |
2613 | "wrap-ansi": { | ||
2614 | "version": "5.1.0", | ||
2615 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", | ||
2616 | "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", | ||
2617 | "dev": true, | ||
2618 | "requires": { | ||
2619 | "ansi-styles": "^3.2.0", | ||
2620 | "string-width": "^3.0.0", | ||
2621 | "strip-ansi": "^5.0.0" | ||
2622 | }, | ||
2623 | "dependencies": { | ||
2624 | "ansi-regex": { | ||
2625 | "version": "4.1.0", | ||
2626 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", | ||
2627 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", | ||
2628 | "dev": true | ||
2629 | }, | ||
2630 | "emoji-regex": { | ||
2631 | "version": "7.0.3", | ||
2632 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", | ||
2633 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", | ||
2634 | "dev": true | ||
2635 | }, | ||
2636 | "is-fullwidth-code-point": { | ||
2637 | "version": "2.0.0", | ||
2638 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", | ||
2639 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", | ||
2640 | "dev": true | ||
2641 | }, | ||
2642 | "string-width": { | ||
2643 | "version": "3.1.0", | ||
2644 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", | ||
2645 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", | ||
2646 | "dev": true, | ||
2647 | "requires": { | ||
2648 | "emoji-regex": "^7.0.1", | ||
2649 | "is-fullwidth-code-point": "^2.0.0", | ||
2650 | "strip-ansi": "^5.1.0" | ||
2651 | } | ||
2652 | }, | ||
2653 | "strip-ansi": { | ||
2654 | "version": "5.2.0", | ||
2655 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", | ||
2656 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", | ||
2657 | "dev": true, | ||
2658 | "requires": { | ||
2659 | "ansi-regex": "^4.1.0" | ||
2660 | } | ||
2661 | } | ||
2662 | } | ||
2663 | }, | ||
1883 | "wrappy": { | 2664 | "wrappy": { |
1884 | "version": "1.0.2", | 2665 | "version": "1.0.2", |
1885 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", | 2666 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", |
@@ -1895,12 +2676,97 @@ | |||
1895 | "mkdirp": "^0.5.1" | 2676 | "mkdirp": "^0.5.1" |
1896 | } | 2677 | } |
1897 | }, | 2678 | }, |
2679 | "y18n": { | ||
2680 | "version": "4.0.0", | ||
2681 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", | ||
2682 | "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", | ||
2683 | "dev": true | ||
2684 | }, | ||
1898 | "yallist": { | 2685 | "yallist": { |
1899 | "version": "2.1.2", | 2686 | "version": "2.1.2", |
1900 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", | 2687 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", |
1901 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", | 2688 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", |
1902 | "dev": true | 2689 | "dev": true |
1903 | }, | 2690 | }, |
2691 | "yargs": { | ||
2692 | "version": "13.3.2", | ||
2693 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", | ||
2694 | "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", | ||
2695 | "dev": true, | ||
2696 | "requires": { | ||
2697 | "cliui": "^5.0.0", | ||
2698 | "find-up": "^3.0.0", | ||
2699 | "get-caller-file": "^2.0.1", | ||
2700 | "require-directory": "^2.1.1", | ||
2701 | "require-main-filename": "^2.0.0", | ||
2702 | "set-blocking": "^2.0.0", | ||
2703 | "string-width": "^3.0.0", | ||
2704 | "which-module": "^2.0.0", | ||
2705 | "y18n": "^4.0.0", | ||
2706 | "yargs-parser": "^13.1.2" | ||
2707 | }, | ||
2708 | "dependencies": { | ||
2709 | "ansi-regex": { | ||
2710 | "version": "4.1.0", | ||
2711 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", | ||
2712 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", | ||
2713 | "dev": true | ||
2714 | }, | ||
2715 | "emoji-regex": { | ||
2716 | "version": "7.0.3", | ||
2717 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", | ||
2718 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", | ||
2719 | "dev": true | ||
2720 | }, | ||
2721 | "is-fullwidth-code-point": { | ||
2722 | "version": "2.0.0", | ||
2723 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", | ||
2724 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", | ||
2725 | "dev": true | ||
2726 | }, | ||
2727 | "string-width": { | ||
2728 | "version": "3.1.0", | ||
2729 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", | ||
2730 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", | ||
2731 | "dev": true, | ||
2732 | "requires": { | ||
2733 | "emoji-regex": "^7.0.1", | ||
2734 | "is-fullwidth-code-point": "^2.0.0", | ||
2735 | "strip-ansi": "^5.1.0" | ||
2736 | } | ||
2737 | }, | ||
2738 | "strip-ansi": { | ||
2739 | "version": "5.2.0", | ||
2740 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", | ||
2741 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", | ||
2742 | "dev": true, | ||
2743 | "requires": { | ||
2744 | "ansi-regex": "^4.1.0" | ||
2745 | } | ||
2746 | } | ||
2747 | } | ||
2748 | }, | ||
2749 | "yargs-parser": { | ||
2750 | "version": "13.1.2", | ||
2751 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", | ||
2752 | "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", | ||
2753 | "dev": true, | ||
2754 | "requires": { | ||
2755 | "camelcase": "^5.0.0", | ||
2756 | "decamelize": "^1.2.0" | ||
2757 | } | ||
2758 | }, | ||
2759 | "yargs-unparser": { | ||
2760 | "version": "1.6.0", | ||
2761 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", | ||
2762 | "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", | ||
2763 | "dev": true, | ||
2764 | "requires": { | ||
2765 | "flat": "^4.1.0", | ||
2766 | "lodash": "^4.17.15", | ||
2767 | "yargs": "^13.3.0" | ||
2768 | } | ||
2769 | }, | ||
1904 | "yauzl": { | 2770 | "yauzl": { |
1905 | "version": "2.10.0", | 2771 | "version": "2.10.0", |
1906 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", | 2772 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", |
diff --git a/editors/code/package.json b/editors/code/package.json index d899f60e3..acf3ca4b5 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -21,7 +21,7 @@ | |||
21 | "Programming Languages" | 21 | "Programming Languages" |
22 | ], | 22 | ], |
23 | "engines": { | 23 | "engines": { |
24 | "vscode": "^1.44.0" | 24 | "vscode": "^1.44.1" |
25 | }, | 25 | }, |
26 | "enableProposedApi": true, | 26 | "enableProposedApi": true, |
27 | "scripts": { | 27 | "scripts": { |
@@ -29,27 +29,34 @@ | |||
29 | "package": "vsce package -o rust-analyzer.vsix", | 29 | "package": "vsce package -o rust-analyzer.vsix", |
30 | "build": "tsc", | 30 | "build": "tsc", |
31 | "watch": "tsc --watch", | 31 | "watch": "tsc --watch", |
32 | "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src", | 32 | "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src ./tests", |
33 | "fix": " tsfmt -r && eslint -c .eslintrc.js --ext ts ./src --fix" | 33 | "fix": " tsfmt -r && eslint -c .eslintrc.js --ext ts ./src ./tests --fix", |
34 | "pretest": "npm run build", | ||
35 | "test": "node ./out/tests/runTests.js" | ||
34 | }, | 36 | }, |
35 | "dependencies": { | 37 | "dependencies": { |
36 | "node-fetch": "^2.6.0", | 38 | "node-fetch": "^2.6.0", |
37 | "vscode-languageclient": "7.0.0-next.1" | 39 | "vscode-languageclient": "7.0.0-next.1" |
38 | }, | 40 | }, |
39 | "devDependencies": { | 41 | "devDependencies": { |
40 | "@rollup/plugin-commonjs": "^11.1.0", | 42 | "@rollup/plugin-commonjs": "^12.0.0", |
41 | "@rollup/plugin-node-resolve": "^7.1.3", | 43 | "@rollup/plugin-node-resolve": "^8.0.0", |
42 | "@types/node": "^12.12.39", | 44 | "@types/glob": "^7.1.1", |
45 | "@types/mocha": "^7.0.2", | ||
46 | "@types/node": "^14.0.5", | ||
43 | "@types/node-fetch": "^2.5.7", | 47 | "@types/node-fetch": "^2.5.7", |
44 | "@types/vscode": "^1.44.0", | 48 | "@types/vscode": "^1.44.1", |
45 | "@typescript-eslint/eslint-plugin": "^2.33.0", | 49 | "@typescript-eslint/eslint-plugin": "^3.0.0", |
46 | "@typescript-eslint/parser": "^2.33.0", | 50 | "@typescript-eslint/parser": "^3.0.0", |
47 | "eslint": "^6.8.0", | 51 | "eslint": "^7.0.0", |
48 | "rollup": "^2.10.0", | 52 | "glob": "^7.1.6", |
49 | "tslib": "^1.12.0", | 53 | "mocha": "^7.1.2", |
50 | "typescript": "^3.9.2", | 54 | "rollup": "^2.10.7", |
55 | "tslib": "^2.0.0", | ||
56 | "typescript": "^3.9.3", | ||
51 | "typescript-formatter": "^7.2.2", | 57 | "typescript-formatter": "^7.2.2", |
52 | "vsce": "^1.75.0" | 58 | "vsce": "^1.75.0", |
59 | "vscode-test": "^1.3.0" | ||
53 | }, | 60 | }, |
54 | "activationEvents": [ | 61 | "activationEvents": [ |
55 | "onLanguage:rust", | 62 | "onLanguage:rust", |
@@ -57,7 +64,7 @@ | |||
57 | "onCommand:rust-analyzer.collectGarbage", | 64 | "onCommand:rust-analyzer.collectGarbage", |
58 | "workspaceContains:**/Cargo.toml" | 65 | "workspaceContains:**/Cargo.toml" |
59 | ], | 66 | ], |
60 | "main": "./out/main", | 67 | "main": "./out/src/main", |
61 | "contributes": { | 68 | "contributes": { |
62 | "taskDefinitions": [ | 69 | "taskDefinitions": [ |
63 | { | 70 | { |
@@ -159,6 +166,11 @@ | |||
159 | "command": "rust-analyzer.serverVersion", | 166 | "command": "rust-analyzer.serverVersion", |
160 | "title": "Show RA Version", | 167 | "title": "Show RA Version", |
161 | "category": "Rust Analyzer" | 168 | "category": "Rust Analyzer" |
169 | }, | ||
170 | { | ||
171 | "command": "rust-analyzer.toggleInlayHints", | ||
172 | "title": "Toggle inlay hints", | ||
173 | "category": "Rust Analyzer" | ||
162 | } | 174 | } |
163 | ], | 175 | ], |
164 | "keybindings": [ | 176 | "keybindings": [ |
@@ -313,22 +325,22 @@ | |||
313 | "rust-analyzer.inlayHints.enable": { | 325 | "rust-analyzer.inlayHints.enable": { |
314 | "type": "boolean", | 326 | "type": "boolean", |
315 | "default": true, | 327 | "default": true, |
316 | "description": "Disable all inlay hints" | 328 | "description": "Whether to show inlay hints" |
317 | }, | 329 | }, |
318 | "rust-analyzer.inlayHints.typeHints": { | 330 | "rust-analyzer.inlayHints.typeHints": { |
319 | "type": "boolean", | 331 | "type": "boolean", |
320 | "default": true, | 332 | "default": true, |
321 | "description": "Whether to show inlay type hints" | 333 | "description": "Whether to show inlay type hints for variables." |
322 | }, | 334 | }, |
323 | "rust-analyzer.inlayHints.chainingHints": { | 335 | "rust-analyzer.inlayHints.chainingHints": { |
324 | "type": "boolean", | 336 | "type": "boolean", |
325 | "default": true, | 337 | "default": true, |
326 | "description": "Whether to show inlay type hints for method chains" | 338 | "description": "Whether to show inlay type hints for method chains." |
327 | }, | 339 | }, |
328 | "rust-analyzer.inlayHints.parameterHints": { | 340 | "rust-analyzer.inlayHints.parameterHints": { |
329 | "type": "boolean", | 341 | "type": "boolean", |
330 | "default": true, | 342 | "default": true, |
331 | "description": "Whether to show function parameter name inlay hints at the call site" | 343 | "description": "Whether to show function parameter name inlay hints at the call site." |
332 | }, | 344 | }, |
333 | "rust-analyzer.inlayHints.maxLength": { | 345 | "rust-analyzer.inlayHints.maxLength": { |
334 | "type": [ | 346 | "type": [ |
@@ -575,6 +587,11 @@ | |||
575 | "description": "Style for attributes" | 587 | "description": "Style for attributes" |
576 | }, | 588 | }, |
577 | { | 589 | { |
590 | "id": "boolean", | ||
591 | "description": "Style for boolean literals", | ||
592 | "superType": "keyword" | ||
593 | }, | ||
594 | { | ||
578 | "id": "builtinType", | 595 | "id": "builtinType", |
579 | "description": "Style for builtin types", | 596 | "description": "Style for builtin types", |
580 | "superType": "type" | 597 | "superType": "type" |
@@ -584,6 +601,11 @@ | |||
584 | "description": "Style for lifetimes" | 601 | "description": "Style for lifetimes" |
585 | }, | 602 | }, |
586 | { | 603 | { |
604 | "id": "selfKeyword", | ||
605 | "description": "Style for the self keyword", | ||
606 | "superType": "keyword" | ||
607 | }, | ||
608 | { | ||
587 | "id": "typeAlias", | 609 | "id": "typeAlias", |
588 | "description": "Style for type aliases", | 610 | "description": "Style for type aliases", |
589 | "superType": "type" | 611 | "superType": "type" |
@@ -604,6 +626,10 @@ | |||
604 | ], | 626 | ], |
605 | "semanticTokenModifiers": [ | 627 | "semanticTokenModifiers": [ |
606 | { | 628 | { |
629 | "id": "attribute", | ||
630 | "description": "Style for elements within attributes" | ||
631 | }, | ||
632 | { | ||
607 | "id": "constant", | 633 | "id": "constant", |
608 | "description": "Style for compile-time constants" | 634 | "description": "Style for compile-time constants" |
609 | }, | 635 | }, |
@@ -630,6 +656,12 @@ | |||
630 | "attribute": [ | 656 | "attribute": [ |
631 | "meta.attribute.rust" | 657 | "meta.attribute.rust" |
632 | ], | 658 | ], |
659 | "function.attribute": [ | ||
660 | "entity.name.function.attribute.rust" | ||
661 | ], | ||
662 | "boolean": [ | ||
663 | "constant.language.boolean.rust" | ||
664 | ], | ||
633 | "builtinType": [ | 665 | "builtinType": [ |
634 | "support.type.primitive.rust" | 666 | "support.type.primitive.rust" |
635 | ], | 667 | ], |
diff --git a/editors/code/rollup.config.js b/editors/code/rollup.config.js index 2ca27694d..58360eabb 100644 --- a/editors/code/rollup.config.js +++ b/editors/code/rollup.config.js | |||
@@ -6,7 +6,7 @@ import nodeBuiltins from 'builtin-modules'; | |||
6 | 6 | ||
7 | /** @type { import('rollup').RollupOptions } */ | 7 | /** @type { import('rollup').RollupOptions } */ |
8 | export default { | 8 | export default { |
9 | input: 'out/main.js', | 9 | input: 'out/src/main.js', |
10 | plugins: [ | 10 | plugins: [ |
11 | resolve({ | 11 | resolve({ |
12 | preferBuiltins: true | 12 | preferBuiltins: true |
@@ -20,7 +20,7 @@ export default { | |||
20 | ], | 20 | ], |
21 | external: [...nodeBuiltins, 'vscode'], | 21 | external: [...nodeBuiltins, 'vscode'], |
22 | output: { | 22 | output: { |
23 | file: './out/main.js', | 23 | file: './out/src/main.js', |
24 | format: 'cjs', | 24 | format: 'cjs', |
25 | exports: 'named' | 25 | exports: 'named' |
26 | } | 26 | } |
diff --git a/editors/code/rust.tmGrammar.json b/editors/code/rust.tmGrammar.json index aa0811326..cdcd557dc 100644 --- a/editors/code/rust.tmGrammar.json +++ b/editors/code/rust.tmGrammar.json | |||
@@ -75,8 +75,13 @@ | |||
75 | { | 75 | { |
76 | "comment": "Attribute", | 76 | "comment": "Attribute", |
77 | "name": "meta.attribute.rust", | 77 | "name": "meta.attribute.rust", |
78 | "begin": "#\\!?\\[", | 78 | "begin": "#\\!?\\[(\\w*)", |
79 | "end": "\\]", | 79 | "end": "\\]", |
80 | "captures": { | ||
81 | "1": { | ||
82 | "name": "entity.name.function.attribute.rust" | ||
83 | } | ||
84 | }, | ||
80 | "patterns": [ | 85 | "patterns": [ |
81 | { | 86 | { |
82 | "include": "#string_literal" | 87 | "include": "#string_literal" |
diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/ast_inspector.ts index a5446c327..4fdd167bd 100644 --- a/editors/code/src/commands/syntax_tree.ts +++ b/editors/code/src/ast_inspector.ts | |||
@@ -1,93 +1,15 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as ra from '../rust-analyzer-api'; | ||
3 | |||
4 | import { Ctx, Cmd, Disposable } from '../ctx'; | ||
5 | import { isRustDocument, RustEditor, isRustEditor, sleep } from '../util'; | ||
6 | |||
7 | const AST_FILE_SCHEME = "rust-analyzer"; | ||
8 | |||
9 | // Opens the virtual file that will show the syntax tree | ||
10 | // | ||
11 | // The contents of the file come from the `TextDocumentContentProvider` | ||
12 | export function syntaxTree(ctx: Ctx): Cmd { | ||
13 | const tdcp = new TextDocumentContentProvider(ctx); | ||
14 | |||
15 | void new AstInspector(ctx); | ||
16 | |||
17 | ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider(AST_FILE_SCHEME, tdcp)); | ||
18 | ctx.pushCleanup(vscode.languages.setLanguageConfiguration("ra_syntax_tree", { | ||
19 | brackets: [["[", ")"]], | ||
20 | })); | ||
21 | |||
22 | return async () => { | ||
23 | const editor = vscode.window.activeTextEditor; | ||
24 | const rangeEnabled = !!editor && !editor.selection.isEmpty; | ||
25 | |||
26 | const uri = rangeEnabled | ||
27 | ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) | ||
28 | : tdcp.uri; | ||
29 | |||
30 | const document = await vscode.workspace.openTextDocument(uri); | ||
31 | |||
32 | tdcp.eventEmitter.fire(uri); | ||
33 | |||
34 | void await vscode.window.showTextDocument(document, { | ||
35 | viewColumn: vscode.ViewColumn.Two, | ||
36 | preserveFocus: true | ||
37 | }); | ||
38 | }; | ||
39 | } | ||
40 | |||
41 | class TextDocumentContentProvider implements vscode.TextDocumentContentProvider { | ||
42 | readonly uri = vscode.Uri.parse('rust-analyzer://syntaxtree/tree.rast'); | ||
43 | readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); | ||
44 | |||
45 | |||
46 | constructor(private readonly ctx: Ctx) { | ||
47 | vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); | ||
48 | vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions); | ||
49 | } | ||
50 | |||
51 | private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { | ||
52 | if (isRustDocument(event.document)) { | ||
53 | // We need to order this after language server updates, but there's no API for that. | ||
54 | // Hence, good old sleep(). | ||
55 | void sleep(10).then(() => this.eventEmitter.fire(this.uri)); | ||
56 | } | ||
57 | } | ||
58 | private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { | ||
59 | if (editor && isRustEditor(editor)) { | ||
60 | this.eventEmitter.fire(this.uri); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | provideTextDocumentContent(uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult<string> { | ||
65 | const rustEditor = this.ctx.activeRustEditor; | ||
66 | if (!rustEditor) return ''; | ||
67 | |||
68 | // When the range based query is enabled we take the range of the selection | ||
69 | const range = uri.query === 'range=true' && !rustEditor.selection.isEmpty | ||
70 | ? this.ctx.client.code2ProtocolConverter.asRange(rustEditor.selection) | ||
71 | : null; | ||
72 | |||
73 | const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range, }; | ||
74 | return this.ctx.client.sendRequest(ra.syntaxTree, params, ct); | ||
75 | } | ||
76 | |||
77 | get onDidChange(): vscode.Event<vscode.Uri> { | ||
78 | return this.eventEmitter.event; | ||
79 | } | ||
80 | } | ||
81 | 2 | ||
3 | import { Ctx, Disposable } from './ctx'; | ||
4 | import { RustEditor, isRustEditor } from './util'; | ||
82 | 5 | ||
83 | // FIXME: consider implementing this via the Tree View API? | 6 | // FIXME: consider implementing this via the Tree View API? |
84 | // https://code.visualstudio.com/api/extension-guides/tree-view | 7 | // https://code.visualstudio.com/api/extension-guides/tree-view |
85 | class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable { | 8 | export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable { |
86 | private readonly astDecorationType = vscode.window.createTextEditorDecorationType({ | 9 | private readonly astDecorationType = vscode.window.createTextEditorDecorationType({ |
87 | borderColor: new vscode.ThemeColor('rust_analyzer.syntaxTreeBorder'), | 10 | borderColor: new vscode.ThemeColor('rust_analyzer.syntaxTreeBorder'), |
88 | borderStyle: "solid", | 11 | borderStyle: "solid", |
89 | borderWidth: "2px", | 12 | borderWidth: "2px", |
90 | |||
91 | }); | 13 | }); |
92 | private rustEditor: undefined | RustEditor; | 14 | private rustEditor: undefined | RustEditor; |
93 | 15 | ||
@@ -113,7 +35,7 @@ class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, D | |||
113 | }); | 35 | }); |
114 | 36 | ||
115 | constructor(ctx: Ctx) { | 37 | constructor(ctx: Ctx) { |
116 | ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: AST_FILE_SCHEME }, this)); | 38 | ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: 'rust-analyzer' }, this)); |
117 | ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this)); | 39 | ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this)); |
118 | vscode.workspace.onDidCloseTextDocument(this.onDidCloseTextDocument, this, ctx.subscriptions); | 40 | vscode.workspace.onDidCloseTextDocument(this.onDidCloseTextDocument, this, ctx.subscriptions); |
119 | vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); | 41 | vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); |
@@ -146,7 +68,7 @@ class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, D | |||
146 | } | 68 | } |
147 | 69 | ||
148 | private findAstTextEditor(): undefined | vscode.TextEditor { | 70 | private findAstTextEditor(): undefined | vscode.TextEditor { |
149 | return vscode.window.visibleTextEditors.find(it => it.document.uri.scheme === AST_FILE_SCHEME); | 71 | return vscode.window.visibleTextEditors.find(it => it.document.uri.scheme === 'rust-analyzer'); |
150 | } | 72 | } |
151 | 73 | ||
152 | private setRustEditor(newRustEditor: undefined | RustEditor) { | 74 | private setRustEditor(newRustEditor: undefined | RustEditor) { |
diff --git a/editors/code/src/cargo.ts b/editors/code/src/cargo.ts index 6a41873d0..a55b2f860 100644 --- a/editors/code/src/cargo.ts +++ b/editors/code/src/cargo.ts | |||
@@ -12,14 +12,44 @@ interface CompilationArtifact { | |||
12 | isTest: boolean; | 12 | isTest: boolean; |
13 | } | 13 | } |
14 | 14 | ||
15 | export interface ArtifactSpec { | ||
16 | cargoArgs: string[]; | ||
17 | filter?: (artifacts: CompilationArtifact[]) => CompilationArtifact[]; | ||
18 | } | ||
19 | |||
20 | export function artifactSpec(args: readonly string[]): ArtifactSpec { | ||
21 | const cargoArgs = [...args, "--message-format=json"]; | ||
22 | |||
23 | // arguments for a runnable from the quick pick should be updated. | ||
24 | // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens | ||
25 | switch (cargoArgs[0]) { | ||
26 | case "run": cargoArgs[0] = "build"; break; | ||
27 | case "test": { | ||
28 | if (!cargoArgs.includes("--no-run")) { | ||
29 | cargoArgs.push("--no-run"); | ||
30 | } | ||
31 | break; | ||
32 | } | ||
33 | } | ||
34 | |||
35 | const result: ArtifactSpec = { cargoArgs: cargoArgs }; | ||
36 | if (cargoArgs[0] === "test") { | ||
37 | // for instance, `crates\rust-analyzer\tests\heavy_tests\main.rs` tests | ||
38 | // produce 2 artifacts: {"kind": "bin"} and {"kind": "test"} | ||
39 | result.filter = (artifacts) => artifacts.filter(it => it.isTest); | ||
40 | } | ||
41 | |||
42 | return result; | ||
43 | } | ||
44 | |||
15 | export class Cargo { | 45 | export class Cargo { |
16 | constructor(readonly rootFolder: string, readonly output: OutputChannel) { } | 46 | constructor(readonly rootFolder: string, readonly output: OutputChannel) { } |
17 | 47 | ||
18 | private async artifactsFromArgs(cargoArgs: string[]): Promise<CompilationArtifact[]> { | 48 | private async getArtifacts(spec: ArtifactSpec): Promise<CompilationArtifact[]> { |
19 | const artifacts: CompilationArtifact[] = []; | 49 | const artifacts: CompilationArtifact[] = []; |
20 | 50 | ||
21 | try { | 51 | try { |
22 | await this.runCargo(cargoArgs, | 52 | await this.runCargo(spec.cargoArgs, |
23 | message => { | 53 | message => { |
24 | if (message.reason === 'compiler-artifact' && message.executable) { | 54 | if (message.reason === 'compiler-artifact' && message.executable) { |
25 | const isBinary = message.target.crate_types.includes('bin'); | 55 | const isBinary = message.target.crate_types.includes('bin'); |
@@ -43,30 +73,11 @@ export class Cargo { | |||
43 | throw new Error(`Cargo invocation has failed: ${err}`); | 73 | throw new Error(`Cargo invocation has failed: ${err}`); |
44 | } | 74 | } |
45 | 75 | ||
46 | return artifacts; | 76 | return spec.filter?.(artifacts) ?? artifacts; |
47 | } | 77 | } |
48 | 78 | ||
49 | async executableFromArgs(args: readonly string[]): Promise<string> { | 79 | async executableFromArgs(args: readonly string[]): Promise<string> { |
50 | const cargoArgs = [...args, "--message-format=json"]; | 80 | const artifacts = await this.getArtifacts(artifactSpec(args)); |
51 | |||
52 | // arguments for a runnable from the quick pick should be updated. | ||
53 | // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens | ||
54 | switch (cargoArgs[0]) { | ||
55 | case "run": cargoArgs[0] = "build"; break; | ||
56 | case "test": { | ||
57 | if (cargoArgs.indexOf("--no-run") === -1) { | ||
58 | cargoArgs.push("--no-run"); | ||
59 | } | ||
60 | break; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | let artifacts = await this.artifactsFromArgs(cargoArgs); | ||
65 | if (cargoArgs[0] === "test") { | ||
66 | // for instance, `crates\rust-analyzer\tests\heavy_tests\main.rs` tests | ||
67 | // produce 2 artifacts: {"kind": "bin"} and {"kind": "test"} | ||
68 | artifacts = artifacts.filter(a => a.isTest); | ||
69 | } | ||
70 | 81 | ||
71 | if (artifacts.length === 0) { | 82 | if (artifacts.length === 0) { |
72 | throw new Error('No compilation artifacts'); | 83 | throw new Error('No compilation artifacts'); |
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index fac1a0be3..d64f9a3f9 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -41,10 +41,12 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
41 | return client.sendRequest(lc.CodeActionRequest.type, params, token).then((values) => { | 41 | return client.sendRequest(lc.CodeActionRequest.type, params, token).then((values) => { |
42 | if (values === null) return undefined; | 42 | if (values === null) return undefined; |
43 | const result: (vscode.CodeAction | vscode.Command)[] = []; | 43 | const result: (vscode.CodeAction | vscode.Command)[] = []; |
44 | const groups = new Map<string, { index: number; items: vscode.CodeAction[] }>(); | ||
44 | for (const item of values) { | 45 | for (const item of values) { |
45 | if (lc.CodeAction.is(item)) { | 46 | if (lc.CodeAction.is(item)) { |
46 | const action = client.protocol2CodeConverter.asCodeAction(item); | 47 | const action = client.protocol2CodeConverter.asCodeAction(item); |
47 | if (isSnippetEdit(item)) { | 48 | const group = actionGroup(item); |
49 | if (isSnippetEdit(item) || group) { | ||
48 | action.command = { | 50 | action.command = { |
49 | command: "rust-analyzer.applySnippetWorkspaceEdit", | 51 | command: "rust-analyzer.applySnippetWorkspaceEdit", |
50 | title: "", | 52 | title: "", |
@@ -52,12 +54,38 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
52 | }; | 54 | }; |
53 | action.edit = undefined; | 55 | action.edit = undefined; |
54 | } | 56 | } |
55 | result.push(action); | 57 | |
58 | if (group) { | ||
59 | let entry = groups.get(group); | ||
60 | if (!entry) { | ||
61 | entry = { index: result.length, items: [] }; | ||
62 | groups.set(group, entry); | ||
63 | result.push(action); | ||
64 | } | ||
65 | entry.items.push(action); | ||
66 | } else { | ||
67 | result.push(action); | ||
68 | } | ||
56 | } else { | 69 | } else { |
57 | const command = client.protocol2CodeConverter.asCommand(item); | 70 | const command = client.protocol2CodeConverter.asCommand(item); |
58 | result.push(command); | 71 | result.push(command); |
59 | } | 72 | } |
60 | } | 73 | } |
74 | for (const [group, { index, items }] of groups) { | ||
75 | if (items.length === 1) { | ||
76 | result[index] = items[0]; | ||
77 | } else { | ||
78 | const action = new vscode.CodeAction(group); | ||
79 | action.command = { | ||
80 | command: "rust-analyzer.applyActionGroup", | ||
81 | title: "", | ||
82 | arguments: [items.map((item) => { | ||
83 | return { label: item.title, edit: item.command!!.arguments!![0] }; | ||
84 | })], | ||
85 | }; | ||
86 | result[index] = action; | ||
87 | } | ||
88 | } | ||
61 | return result; | 89 | return result; |
62 | }, | 90 | }, |
63 | (_error) => undefined | 91 | (_error) => undefined |
@@ -81,15 +109,16 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
81 | // implementations are still in the "proposed" category for 3.16. | 109 | // implementations are still in the "proposed" category for 3.16. |
82 | client.registerFeature(new CallHierarchyFeature(client)); | 110 | client.registerFeature(new CallHierarchyFeature(client)); |
83 | client.registerFeature(new SemanticTokensFeature(client)); | 111 | client.registerFeature(new SemanticTokensFeature(client)); |
84 | client.registerFeature(new SnippetTextEditFeature()); | 112 | client.registerFeature(new ExperimentalFeatures()); |
85 | 113 | ||
86 | return client; | 114 | return client; |
87 | } | 115 | } |
88 | 116 | ||
89 | class SnippetTextEditFeature implements lc.StaticFeature { | 117 | class ExperimentalFeatures implements lc.StaticFeature { |
90 | fillClientCapabilities(capabilities: lc.ClientCapabilities): void { | 118 | fillClientCapabilities(capabilities: lc.ClientCapabilities): void { |
91 | const caps: any = capabilities.experimental ?? {}; | 119 | const caps: any = capabilities.experimental ?? {}; |
92 | caps.snippetTextEdit = true; | 120 | caps.snippetTextEdit = true; |
121 | caps.codeActionGroup = true; | ||
93 | capabilities.experimental = caps; | 122 | capabilities.experimental = caps; |
94 | } | 123 | } |
95 | initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void { | 124 | initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void { |
@@ -107,3 +136,7 @@ function isSnippetEdit(action: lc.CodeAction): boolean { | |||
107 | } | 136 | } |
108 | return false; | 137 | return false; |
109 | } | 138 | } |
139 | |||
140 | function actionGroup(action: lc.CodeAction): string | undefined { | ||
141 | return (action as any).group; | ||
142 | } | ||
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts new file mode 100644 index 000000000..86302db37 --- /dev/null +++ b/editors/code/src/commands.ts | |||
@@ -0,0 +1,370 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import * as lc from 'vscode-languageclient'; | ||
3 | import * as ra from './lsp_ext'; | ||
4 | |||
5 | import { Ctx, Cmd } from './ctx'; | ||
6 | import { applySnippetWorkspaceEdit, applySnippetTextEdits } from './snippets'; | ||
7 | import { spawnSync } from 'child_process'; | ||
8 | import { RunnableQuickPick, selectRunnable, createTask } from './run'; | ||
9 | import { AstInspector } from './ast_inspector'; | ||
10 | import { isRustDocument, sleep, isRustEditor } from './util'; | ||
11 | |||
12 | export * from './ast_inspector'; | ||
13 | export * from './run'; | ||
14 | |||
15 | export function analyzerStatus(ctx: Ctx): Cmd { | ||
16 | const tdcp = new class implements vscode.TextDocumentContentProvider { | ||
17 | readonly uri = vscode.Uri.parse('rust-analyzer-status://status'); | ||
18 | readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); | ||
19 | |||
20 | provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> { | ||
21 | if (!vscode.window.activeTextEditor) return ''; | ||
22 | |||
23 | return ctx.client.sendRequest(ra.analyzerStatus, null); | ||
24 | } | ||
25 | |||
26 | get onDidChange(): vscode.Event<vscode.Uri> { | ||
27 | return this.eventEmitter.event; | ||
28 | } | ||
29 | }(); | ||
30 | |||
31 | let poller: NodeJS.Timer | undefined = undefined; | ||
32 | |||
33 | ctx.pushCleanup( | ||
34 | vscode.workspace.registerTextDocumentContentProvider( | ||
35 | 'rust-analyzer-status', | ||
36 | tdcp, | ||
37 | ), | ||
38 | ); | ||
39 | |||
40 | ctx.pushCleanup({ | ||
41 | dispose() { | ||
42 | if (poller !== undefined) { | ||
43 | clearInterval(poller); | ||
44 | } | ||
45 | }, | ||
46 | }); | ||
47 | |||
48 | return async () => { | ||
49 | if (poller === undefined) { | ||
50 | poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000); | ||
51 | } | ||
52 | const document = await vscode.workspace.openTextDocument(tdcp.uri); | ||
53 | return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true); | ||
54 | }; | ||
55 | } | ||
56 | |||
57 | export function matchingBrace(ctx: Ctx): Cmd { | ||
58 | return async () => { | ||
59 | const editor = ctx.activeRustEditor; | ||
60 | const client = ctx.client; | ||
61 | if (!editor || !client) return; | ||
62 | |||
63 | const response = await client.sendRequest(ra.matchingBrace, { | ||
64 | textDocument: { uri: editor.document.uri.toString() }, | ||
65 | positions: editor.selections.map(s => | ||
66 | client.code2ProtocolConverter.asPosition(s.active), | ||
67 | ), | ||
68 | }); | ||
69 | editor.selections = editor.selections.map((sel, idx) => { | ||
70 | const active = client.protocol2CodeConverter.asPosition( | ||
71 | response[idx], | ||
72 | ); | ||
73 | const anchor = sel.isEmpty ? active : sel.anchor; | ||
74 | return new vscode.Selection(anchor, active); | ||
75 | }); | ||
76 | editor.revealRange(editor.selection); | ||
77 | }; | ||
78 | } | ||
79 | |||
80 | export function joinLines(ctx: Ctx): Cmd { | ||
81 | return async () => { | ||
82 | const editor = ctx.activeRustEditor; | ||
83 | const client = ctx.client; | ||
84 | if (!editor || !client) return; | ||
85 | |||
86 | const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, { | ||
87 | ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)), | ||
88 | textDocument: { uri: editor.document.uri.toString() }, | ||
89 | }); | ||
90 | editor.edit((builder) => { | ||
91 | client.protocol2CodeConverter.asTextEdits(items).forEach((edit) => { | ||
92 | builder.replace(edit.range, edit.newText); | ||
93 | }); | ||
94 | }); | ||
95 | }; | ||
96 | } | ||
97 | |||
98 | export function onEnter(ctx: Ctx): Cmd { | ||
99 | async function handleKeypress() { | ||
100 | const editor = ctx.activeRustEditor; | ||
101 | const client = ctx.client; | ||
102 | |||
103 | if (!editor || !client) return false; | ||
104 | |||
105 | const lcEdits = await client.sendRequest(ra.onEnter, { | ||
106 | textDocument: { uri: editor.document.uri.toString() }, | ||
107 | position: client.code2ProtocolConverter.asPosition( | ||
108 | editor.selection.active, | ||
109 | ), | ||
110 | }).catch(_error => { | ||
111 | // client.logFailedRequest(OnEnterRequest.type, error); | ||
112 | return null; | ||
113 | }); | ||
114 | if (!lcEdits) return false; | ||
115 | |||
116 | const edits = client.protocol2CodeConverter.asTextEdits(lcEdits); | ||
117 | await applySnippetTextEdits(editor, edits); | ||
118 | return true; | ||
119 | } | ||
120 | |||
121 | return async () => { | ||
122 | if (await handleKeypress()) return; | ||
123 | |||
124 | await vscode.commands.executeCommand('default:type', { text: '\n' }); | ||
125 | }; | ||
126 | } | ||
127 | |||
128 | export function parentModule(ctx: Ctx): Cmd { | ||
129 | return async () => { | ||
130 | const editor = ctx.activeRustEditor; | ||
131 | const client = ctx.client; | ||
132 | if (!editor || !client) return; | ||
133 | |||
134 | const response = await client.sendRequest(ra.parentModule, { | ||
135 | textDocument: { uri: editor.document.uri.toString() }, | ||
136 | position: client.code2ProtocolConverter.asPosition( | ||
137 | editor.selection.active, | ||
138 | ), | ||
139 | }); | ||
140 | const loc = response[0]; | ||
141 | if (!loc) return; | ||
142 | |||
143 | const uri = client.protocol2CodeConverter.asUri(loc.targetUri); | ||
144 | const range = client.protocol2CodeConverter.asRange(loc.targetRange); | ||
145 | |||
146 | const doc = await vscode.workspace.openTextDocument(uri); | ||
147 | const e = await vscode.window.showTextDocument(doc); | ||
148 | e.selection = new vscode.Selection(range.start, range.start); | ||
149 | e.revealRange(range, vscode.TextEditorRevealType.InCenter); | ||
150 | }; | ||
151 | } | ||
152 | |||
153 | export function ssr(ctx: Ctx): Cmd { | ||
154 | return async () => { | ||
155 | const client = ctx.client; | ||
156 | if (!client) return; | ||
157 | |||
158 | const options: vscode.InputBoxOptions = { | ||
159 | value: "() ==>> ()", | ||
160 | prompt: "Enter request, for example 'Foo($a:expr) ==> Foo::new($a)' ", | ||
161 | validateInput: async (x: string) => { | ||
162 | try { | ||
163 | await client.sendRequest(ra.ssr, { query: x, parseOnly: true }); | ||
164 | } catch (e) { | ||
165 | return e.toString(); | ||
166 | } | ||
167 | return null; | ||
168 | } | ||
169 | }; | ||
170 | const request = await vscode.window.showInputBox(options); | ||
171 | if (!request) return; | ||
172 | |||
173 | const edit = await client.sendRequest(ra.ssr, { query: request, parseOnly: false }); | ||
174 | |||
175 | await vscode.workspace.applyEdit(client.protocol2CodeConverter.asWorkspaceEdit(edit)); | ||
176 | }; | ||
177 | } | ||
178 | |||
179 | export function serverVersion(ctx: Ctx): Cmd { | ||
180 | return async () => { | ||
181 | const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" }); | ||
182 | const commitHash = stdout.slice(`rust-analyzer `.length).trim(); | ||
183 | const { releaseTag } = ctx.config.package; | ||
184 | |||
185 | void vscode.window.showInformationMessage( | ||
186 | `rust-analyzer version: ${releaseTag ?? "unreleased"} (${commitHash})` | ||
187 | ); | ||
188 | }; | ||
189 | } | ||
190 | |||
191 | export function toggleInlayHints(ctx: Ctx): Cmd { | ||
192 | return async () => { | ||
193 | await vscode | ||
194 | .workspace | ||
195 | .getConfiguration(`${ctx.config.rootSection}.inlayHints`) | ||
196 | .update('enable', !ctx.config.inlayHints.enable, vscode.ConfigurationTarget.Workspace); | ||
197 | }; | ||
198 | } | ||
199 | |||
200 | export function run(ctx: Ctx): Cmd { | ||
201 | let prevRunnable: RunnableQuickPick | undefined; | ||
202 | |||
203 | return async () => { | ||
204 | const item = await selectRunnable(ctx, prevRunnable); | ||
205 | if (!item) return; | ||
206 | |||
207 | item.detail = 'rerun'; | ||
208 | prevRunnable = item; | ||
209 | const task = createTask(item.runnable); | ||
210 | return await vscode.tasks.executeTask(task); | ||
211 | }; | ||
212 | } | ||
213 | |||
214 | // Opens the virtual file that will show the syntax tree | ||
215 | // | ||
216 | // The contents of the file come from the `TextDocumentContentProvider` | ||
217 | export function syntaxTree(ctx: Ctx): Cmd { | ||
218 | const tdcp = new class implements vscode.TextDocumentContentProvider { | ||
219 | readonly uri = vscode.Uri.parse('rust-analyzer://syntaxtree/tree.rast'); | ||
220 | readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); | ||
221 | constructor() { | ||
222 | vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); | ||
223 | vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions); | ||
224 | } | ||
225 | |||
226 | private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { | ||
227 | if (isRustDocument(event.document)) { | ||
228 | // We need to order this after language server updates, but there's no API for that. | ||
229 | // Hence, good old sleep(). | ||
230 | void sleep(10).then(() => this.eventEmitter.fire(this.uri)); | ||
231 | } | ||
232 | } | ||
233 | private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { | ||
234 | if (editor && isRustEditor(editor)) { | ||
235 | this.eventEmitter.fire(this.uri); | ||
236 | } | ||
237 | } | ||
238 | |||
239 | provideTextDocumentContent(uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult<string> { | ||
240 | const rustEditor = ctx.activeRustEditor; | ||
241 | if (!rustEditor) return ''; | ||
242 | |||
243 | // When the range based query is enabled we take the range of the selection | ||
244 | const range = uri.query === 'range=true' && !rustEditor.selection.isEmpty | ||
245 | ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection) | ||
246 | : null; | ||
247 | |||
248 | const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range, }; | ||
249 | return ctx.client.sendRequest(ra.syntaxTree, params, ct); | ||
250 | } | ||
251 | |||
252 | get onDidChange(): vscode.Event<vscode.Uri> { | ||
253 | return this.eventEmitter.event; | ||
254 | } | ||
255 | }; | ||
256 | |||
257 | void new AstInspector(ctx); | ||
258 | |||
259 | ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); | ||
260 | ctx.pushCleanup(vscode.languages.setLanguageConfiguration("ra_syntax_tree", { | ||
261 | brackets: [["[", ")"]], | ||
262 | })); | ||
263 | |||
264 | return async () => { | ||
265 | const editor = vscode.window.activeTextEditor; | ||
266 | const rangeEnabled = !!editor && !editor.selection.isEmpty; | ||
267 | |||
268 | const uri = rangeEnabled | ||
269 | ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) | ||
270 | : tdcp.uri; | ||
271 | |||
272 | const document = await vscode.workspace.openTextDocument(uri); | ||
273 | |||
274 | tdcp.eventEmitter.fire(uri); | ||
275 | |||
276 | void await vscode.window.showTextDocument(document, { | ||
277 | viewColumn: vscode.ViewColumn.Two, | ||
278 | preserveFocus: true | ||
279 | }); | ||
280 | }; | ||
281 | } | ||
282 | |||
283 | |||
284 | // Opens the virtual file that will show the syntax tree | ||
285 | // | ||
286 | // The contents of the file come from the `TextDocumentContentProvider` | ||
287 | export function expandMacro(ctx: Ctx): Cmd { | ||
288 | function codeFormat(expanded: ra.ExpandedMacro): string { | ||
289 | let result = `// Recursive expansion of ${expanded.name}! macro\n`; | ||
290 | result += '// ' + '='.repeat(result.length - 3); | ||
291 | result += '\n\n'; | ||
292 | result += expanded.expansion; | ||
293 | |||
294 | return result; | ||
295 | } | ||
296 | |||
297 | const tdcp = new class implements vscode.TextDocumentContentProvider { | ||
298 | uri = vscode.Uri.parse('rust-analyzer://expandMacro/[EXPANSION].rs'); | ||
299 | eventEmitter = new vscode.EventEmitter<vscode.Uri>(); | ||
300 | async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> { | ||
301 | const editor = vscode.window.activeTextEditor; | ||
302 | const client = ctx.client; | ||
303 | if (!editor || !client) return ''; | ||
304 | |||
305 | const position = editor.selection.active; | ||
306 | |||
307 | const expanded = await client.sendRequest(ra.expandMacro, { | ||
308 | textDocument: { uri: editor.document.uri.toString() }, | ||
309 | position, | ||
310 | }); | ||
311 | |||
312 | if (expanded == null) return 'Not available'; | ||
313 | |||
314 | return codeFormat(expanded); | ||
315 | } | ||
316 | |||
317 | get onDidChange(): vscode.Event<vscode.Uri> { | ||
318 | return this.eventEmitter.event; | ||
319 | } | ||
320 | }(); | ||
321 | |||
322 | ctx.pushCleanup( | ||
323 | vscode.workspace.registerTextDocumentContentProvider( | ||
324 | 'rust-analyzer', | ||
325 | tdcp, | ||
326 | ), | ||
327 | ); | ||
328 | |||
329 | return async () => { | ||
330 | const document = await vscode.workspace.openTextDocument(tdcp.uri); | ||
331 | tdcp.eventEmitter.fire(tdcp.uri); | ||
332 | return vscode.window.showTextDocument( | ||
333 | document, | ||
334 | vscode.ViewColumn.Two, | ||
335 | true, | ||
336 | ); | ||
337 | }; | ||
338 | } | ||
339 | |||
340 | export function collectGarbage(ctx: Ctx): Cmd { | ||
341 | return async () => ctx.client.sendRequest(ra.collectGarbage, null); | ||
342 | } | ||
343 | |||
344 | export function showReferences(ctx: Ctx): Cmd { | ||
345 | return (uri: string, position: lc.Position, locations: lc.Location[]) => { | ||
346 | const client = ctx.client; | ||
347 | if (client) { | ||
348 | vscode.commands.executeCommand( | ||
349 | 'editor.action.showReferences', | ||
350 | vscode.Uri.parse(uri), | ||
351 | client.protocol2CodeConverter.asPosition(position), | ||
352 | locations.map(client.protocol2CodeConverter.asLocation), | ||
353 | ); | ||
354 | } | ||
355 | }; | ||
356 | } | ||
357 | |||
358 | export function applyActionGroup(_ctx: Ctx): Cmd { | ||
359 | return async (actions: { label: string; edit: vscode.WorkspaceEdit }[]) => { | ||
360 | const selectedAction = await vscode.window.showQuickPick(actions); | ||
361 | if (!selectedAction) return; | ||
362 | await applySnippetWorkspaceEdit(selectedAction.edit); | ||
363 | }; | ||
364 | } | ||
365 | |||
366 | export function applySnippetWorkspaceEditCommand(_ctx: Ctx): Cmd { | ||
367 | return async (edit: vscode.WorkspaceEdit) => { | ||
368 | await applySnippetWorkspaceEdit(edit); | ||
369 | }; | ||
370 | } | ||
diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts deleted file mode 100644 index 09daa3402..000000000 --- a/editors/code/src/commands/analyzer_status.ts +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | |||
3 | import * as ra from '../rust-analyzer-api'; | ||
4 | import { Ctx, Cmd } from '../ctx'; | ||
5 | |||
6 | // Shows status of rust-analyzer (for debugging) | ||
7 | export function analyzerStatus(ctx: Ctx): Cmd { | ||
8 | let poller: NodeJS.Timer | undefined = undefined; | ||
9 | const tdcp = new TextDocumentContentProvider(ctx); | ||
10 | |||
11 | ctx.pushCleanup( | ||
12 | vscode.workspace.registerTextDocumentContentProvider( | ||
13 | 'rust-analyzer-status', | ||
14 | tdcp, | ||
15 | ), | ||
16 | ); | ||
17 | |||
18 | ctx.pushCleanup({ | ||
19 | dispose() { | ||
20 | if (poller !== undefined) { | ||
21 | clearInterval(poller); | ||
22 | } | ||
23 | }, | ||
24 | }); | ||
25 | |||
26 | return async () => { | ||
27 | if (poller === undefined) { | ||
28 | poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000); | ||
29 | } | ||
30 | const document = await vscode.workspace.openTextDocument(tdcp.uri); | ||
31 | return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true); | ||
32 | }; | ||
33 | } | ||
34 | |||
35 | class TextDocumentContentProvider implements vscode.TextDocumentContentProvider { | ||
36 | readonly uri = vscode.Uri.parse('rust-analyzer-status://status'); | ||
37 | readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); | ||
38 | |||
39 | constructor(private readonly ctx: Ctx) { | ||
40 | } | ||
41 | |||
42 | provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> { | ||
43 | if (!vscode.window.activeTextEditor) return ''; | ||
44 | |||
45 | return this.ctx.client.sendRequest(ra.analyzerStatus, null); | ||
46 | } | ||
47 | |||
48 | get onDidChange(): vscode.Event<vscode.Uri> { | ||
49 | return this.eventEmitter.event; | ||
50 | } | ||
51 | } | ||
diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts deleted file mode 100644 index 23f2ef1d5..000000000 --- a/editors/code/src/commands/expand_macro.ts +++ /dev/null | |||
@@ -1,66 +0,0 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import * as ra from '../rust-analyzer-api'; | ||
3 | |||
4 | import { Ctx, Cmd } from '../ctx'; | ||
5 | |||
6 | // Opens the virtual file that will show the syntax tree | ||
7 | // | ||
8 | // The contents of the file come from the `TextDocumentContentProvider` | ||
9 | export function expandMacro(ctx: Ctx): Cmd { | ||
10 | const tdcp = new TextDocumentContentProvider(ctx); | ||
11 | ctx.pushCleanup( | ||
12 | vscode.workspace.registerTextDocumentContentProvider( | ||
13 | 'rust-analyzer', | ||
14 | tdcp, | ||
15 | ), | ||
16 | ); | ||
17 | |||
18 | return async () => { | ||
19 | const document = await vscode.workspace.openTextDocument(tdcp.uri); | ||
20 | tdcp.eventEmitter.fire(tdcp.uri); | ||
21 | return vscode.window.showTextDocument( | ||
22 | document, | ||
23 | vscode.ViewColumn.Two, | ||
24 | true, | ||
25 | ); | ||
26 | }; | ||
27 | } | ||
28 | |||
29 | function codeFormat(expanded: ra.ExpandedMacro): string { | ||
30 | let result = `// Recursive expansion of ${expanded.name}! macro\n`; | ||
31 | result += '// ' + '='.repeat(result.length - 3); | ||
32 | result += '\n\n'; | ||
33 | result += expanded.expansion; | ||
34 | |||
35 | return result; | ||
36 | } | ||
37 | |||
38 | class TextDocumentContentProvider | ||
39 | implements vscode.TextDocumentContentProvider { | ||
40 | uri = vscode.Uri.parse('rust-analyzer://expandMacro/[EXPANSION].rs'); | ||
41 | eventEmitter = new vscode.EventEmitter<vscode.Uri>(); | ||
42 | |||
43 | constructor(private readonly ctx: Ctx) { | ||
44 | } | ||
45 | |||
46 | async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> { | ||
47 | const editor = vscode.window.activeTextEditor; | ||
48 | const client = this.ctx.client; | ||
49 | if (!editor || !client) return ''; | ||
50 | |||
51 | const position = editor.selection.active; | ||
52 | |||
53 | const expanded = await client.sendRequest(ra.expandMacro, { | ||
54 | textDocument: { uri: editor.document.uri.toString() }, | ||
55 | position, | ||
56 | }); | ||
57 | |||
58 | if (expanded == null) return 'Not available'; | ||
59 | |||
60 | return codeFormat(expanded); | ||
61 | } | ||
62 | |||
63 | get onDidChange(): vscode.Event<vscode.Uri> { | ||
64 | return this.eventEmitter.event; | ||
65 | } | ||
66 | } | ||
diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands/index.ts deleted file mode 100644 index 0937b495c..000000000 --- a/editors/code/src/commands/index.ts +++ /dev/null | |||
@@ -1,88 +0,0 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import * as lc from 'vscode-languageclient'; | ||
3 | import * as ra from '../rust-analyzer-api'; | ||
4 | |||
5 | import { Ctx, Cmd } from '../ctx'; | ||
6 | import * as sourceChange from '../source_change'; | ||
7 | import { assert } from '../util'; | ||
8 | |||
9 | export * from './analyzer_status'; | ||
10 | export * from './matching_brace'; | ||
11 | export * from './join_lines'; | ||
12 | export * from './on_enter'; | ||
13 | export * from './parent_module'; | ||
14 | export * from './syntax_tree'; | ||
15 | export * from './expand_macro'; | ||
16 | export * from './runnables'; | ||
17 | export * from './ssr'; | ||
18 | export * from './server_version'; | ||
19 | |||
20 | export function collectGarbage(ctx: Ctx): Cmd { | ||
21 | return async () => ctx.client.sendRequest(ra.collectGarbage, null); | ||
22 | } | ||
23 | |||
24 | export function showReferences(ctx: Ctx): Cmd { | ||
25 | return (uri: string, position: lc.Position, locations: lc.Location[]) => { | ||
26 | const client = ctx.client; | ||
27 | if (client) { | ||
28 | vscode.commands.executeCommand( | ||
29 | 'editor.action.showReferences', | ||
30 | vscode.Uri.parse(uri), | ||
31 | client.protocol2CodeConverter.asPosition(position), | ||
32 | locations.map(client.protocol2CodeConverter.asLocation), | ||
33 | ); | ||
34 | } | ||
35 | }; | ||
36 | } | ||
37 | |||
38 | export function applySourceChange(ctx: Ctx): Cmd { | ||
39 | return async (change: ra.SourceChange) => { | ||
40 | await sourceChange.applySourceChange(ctx, change); | ||
41 | }; | ||
42 | } | ||
43 | |||
44 | export function selectAndApplySourceChange(ctx: Ctx): Cmd { | ||
45 | return async (changes: ra.SourceChange[]) => { | ||
46 | if (changes.length === 1) { | ||
47 | await sourceChange.applySourceChange(ctx, changes[0]); | ||
48 | } else if (changes.length > 0) { | ||
49 | const selectedChange = await vscode.window.showQuickPick(changes); | ||
50 | if (!selectedChange) return; | ||
51 | await sourceChange.applySourceChange(ctx, selectedChange); | ||
52 | } | ||
53 | }; | ||
54 | } | ||
55 | |||
56 | export function applySnippetWorkspaceEdit(_ctx: Ctx): Cmd { | ||
57 | return async (edit: vscode.WorkspaceEdit) => { | ||
58 | assert(edit.entries().length === 1, `bad ws edit: ${JSON.stringify(edit)}`); | ||
59 | const [uri, edits] = edit.entries()[0]; | ||
60 | |||
61 | const editor = vscode.window.visibleTextEditors.find((it) => it.document.uri.toString() === uri.toString()); | ||
62 | if (!editor) return; | ||
63 | |||
64 | let editWithSnippet: vscode.TextEdit | undefined = undefined; | ||
65 | let lineDelta = 0; | ||
66 | await editor.edit((builder) => { | ||
67 | for (const indel of edits) { | ||
68 | const isSnippet = indel.newText.indexOf('$0') !== -1 || indel.newText.indexOf('${') !== -1; | ||
69 | if (isSnippet) { | ||
70 | editWithSnippet = indel; | ||
71 | } else { | ||
72 | if (!editWithSnippet) { | ||
73 | lineDelta = (indel.newText.match(/\n/g) || []).length - (indel.range.end.line - indel.range.start.line); | ||
74 | } | ||
75 | builder.replace(indel.range, indel.newText); | ||
76 | } | ||
77 | } | ||
78 | }); | ||
79 | if (editWithSnippet) { | ||
80 | const snip = editWithSnippet as vscode.TextEdit; | ||
81 | const range = snip.range.with( | ||
82 | snip.range.start.with(snip.range.start.line + lineDelta), | ||
83 | snip.range.end.with(snip.range.end.line + lineDelta), | ||
84 | ); | ||
85 | await editor.insertSnippet(new vscode.SnippetString(snip.newText), range); | ||
86 | } | ||
87 | }; | ||
88 | } | ||
diff --git a/editors/code/src/commands/join_lines.ts b/editors/code/src/commands/join_lines.ts deleted file mode 100644 index de0614653..000000000 --- a/editors/code/src/commands/join_lines.ts +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | import * as ra from '../rust-analyzer-api'; | ||
2 | |||
3 | import { Ctx, Cmd } from '../ctx'; | ||
4 | import { applySourceChange } from '../source_change'; | ||
5 | |||
6 | export function joinLines(ctx: Ctx): Cmd { | ||
7 | return async () => { | ||
8 | const editor = ctx.activeRustEditor; | ||
9 | const client = ctx.client; | ||
10 | if (!editor || !client) return; | ||
11 | |||
12 | const change = await client.sendRequest(ra.joinLines, { | ||
13 | range: client.code2ProtocolConverter.asRange(editor.selection), | ||
14 | textDocument: { uri: editor.document.uri.toString() }, | ||
15 | }); | ||
16 | await applySourceChange(ctx, change); | ||
17 | }; | ||
18 | } | ||
diff --git a/editors/code/src/commands/matching_brace.ts b/editors/code/src/commands/matching_brace.ts deleted file mode 100644 index a60776e2d..000000000 --- a/editors/code/src/commands/matching_brace.ts +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import * as ra from '../rust-analyzer-api'; | ||
3 | |||
4 | import { Ctx, Cmd } from '../ctx'; | ||
5 | |||
6 | export function matchingBrace(ctx: Ctx): Cmd { | ||
7 | return async () => { | ||
8 | const editor = ctx.activeRustEditor; | ||
9 | const client = ctx.client; | ||
10 | if (!editor || !client) return; | ||
11 | |||
12 | const response = await client.sendRequest(ra.findMatchingBrace, { | ||
13 | textDocument: { uri: editor.document.uri.toString() }, | ||
14 | offsets: editor.selections.map(s => | ||
15 | client.code2ProtocolConverter.asPosition(s.active), | ||
16 | ), | ||
17 | }); | ||
18 | editor.selections = editor.selections.map((sel, idx) => { | ||
19 | const active = client.protocol2CodeConverter.asPosition( | ||
20 | response[idx], | ||
21 | ); | ||
22 | const anchor = sel.isEmpty ? active : sel.anchor; | ||
23 | return new vscode.Selection(anchor, active); | ||
24 | }); | ||
25 | editor.revealRange(editor.selection); | ||
26 | }; | ||
27 | } | ||
diff --git a/editors/code/src/commands/on_enter.ts b/editors/code/src/commands/on_enter.ts deleted file mode 100644 index 285849db7..000000000 --- a/editors/code/src/commands/on_enter.ts +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import * as ra from '../rust-analyzer-api'; | ||
3 | |||
4 | import { applySourceChange } from '../source_change'; | ||
5 | import { Cmd, Ctx } from '../ctx'; | ||
6 | |||
7 | async function handleKeypress(ctx: Ctx) { | ||
8 | const editor = ctx.activeRustEditor; | ||
9 | const client = ctx.client; | ||
10 | |||
11 | if (!editor || !client) return false; | ||
12 | |||
13 | const change = await client.sendRequest(ra.onEnter, { | ||
14 | textDocument: { uri: editor.document.uri.toString() }, | ||
15 | position: client.code2ProtocolConverter.asPosition( | ||
16 | editor.selection.active, | ||
17 | ), | ||
18 | }).catch(_error => { | ||
19 | // client.logFailedRequest(OnEnterRequest.type, error); | ||
20 | return null; | ||
21 | }); | ||
22 | if (!change) return false; | ||
23 | |||
24 | await applySourceChange(ctx, change); | ||
25 | return true; | ||
26 | } | ||
27 | |||
28 | export function onEnter(ctx: Ctx): Cmd { | ||
29 | return async () => { | ||
30 | if (await handleKeypress(ctx)) return; | ||
31 | |||
32 | await vscode.commands.executeCommand('default:type', { text: '\n' }); | ||
33 | }; | ||
34 | } | ||
diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts deleted file mode 100644 index 8f78ddd71..000000000 --- a/editors/code/src/commands/parent_module.ts +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import * as ra from '../rust-analyzer-api'; | ||
3 | |||
4 | import { Ctx, Cmd } from '../ctx'; | ||
5 | |||
6 | export function parentModule(ctx: Ctx): Cmd { | ||
7 | return async () => { | ||
8 | const editor = ctx.activeRustEditor; | ||
9 | const client = ctx.client; | ||
10 | if (!editor || !client) return; | ||
11 | |||
12 | const response = await client.sendRequest(ra.parentModule, { | ||
13 | textDocument: { uri: editor.document.uri.toString() }, | ||
14 | position: client.code2ProtocolConverter.asPosition( | ||
15 | editor.selection.active, | ||
16 | ), | ||
17 | }); | ||
18 | const loc = response[0]; | ||
19 | if (loc == null) return; | ||
20 | |||
21 | const uri = client.protocol2CodeConverter.asUri(loc.uri); | ||
22 | const range = client.protocol2CodeConverter.asRange(loc.range); | ||
23 | |||
24 | const doc = await vscode.workspace.openTextDocument(uri); | ||
25 | const e = await vscode.window.showTextDocument(doc); | ||
26 | e.selection = new vscode.Selection(range.start, range.start); | ||
27 | e.revealRange(range, vscode.TextEditorRevealType.InCenter); | ||
28 | }; | ||
29 | } | ||
diff --git a/editors/code/src/commands/server_version.ts b/editors/code/src/commands/server_version.ts deleted file mode 100644 index d64ac726e..000000000 --- a/editors/code/src/commands/server_version.ts +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | import * as vscode from "vscode"; | ||
2 | import { spawnSync } from "child_process"; | ||
3 | import { Ctx, Cmd } from '../ctx'; | ||
4 | |||
5 | export function serverVersion(ctx: Ctx): Cmd { | ||
6 | return async () => { | ||
7 | const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" }); | ||
8 | const commitHash = stdout.slice(`rust-analyzer `.length).trim(); | ||
9 | const { releaseTag } = ctx.config.package; | ||
10 | |||
11 | void vscode.window.showInformationMessage( | ||
12 | `rust-analyzer version: ${releaseTag ?? "unreleased"} (${commitHash})` | ||
13 | ); | ||
14 | }; | ||
15 | } | ||
diff --git a/editors/code/src/commands/ssr.ts b/editors/code/src/commands/ssr.ts deleted file mode 100644 index 4ef8cdf04..000000000 --- a/editors/code/src/commands/ssr.ts +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import * as ra from "../rust-analyzer-api"; | ||
3 | |||
4 | import { Ctx, Cmd } from '../ctx'; | ||
5 | import { applySourceChange } from '../source_change'; | ||
6 | |||
7 | export function ssr(ctx: Ctx): Cmd { | ||
8 | return async () => { | ||
9 | const client = ctx.client; | ||
10 | if (!client) return; | ||
11 | |||
12 | const options: vscode.InputBoxOptions = { | ||
13 | value: "() ==>> ()", | ||
14 | prompt: "Enter request, for example 'Foo($a:expr) ==> Foo::new($a)' ", | ||
15 | validateInput: async (x: string) => { | ||
16 | try { | ||
17 | await client.sendRequest(ra.ssr, { query: x, parseOnly: true }); | ||
18 | } catch (e) { | ||
19 | return e.toString(); | ||
20 | } | ||
21 | return null; | ||
22 | } | ||
23 | }; | ||
24 | const request = await vscode.window.showInputBox(options); | ||
25 | |||
26 | if (!request) return; | ||
27 | |||
28 | const change = await client.sendRequest(ra.ssr, { query: request, parseOnly: false }); | ||
29 | |||
30 | await applySourceChange(ctx, change); | ||
31 | }; | ||
32 | } | ||
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index ee294fbe3..e8abf8284 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -8,7 +8,7 @@ export const NIGHTLY_TAG = "nightly"; | |||
8 | export class Config { | 8 | export class Config { |
9 | readonly extensionId = "matklad.rust-analyzer"; | 9 | readonly extensionId = "matklad.rust-analyzer"; |
10 | 10 | ||
11 | private readonly rootSection = "rust-analyzer"; | 11 | readonly rootSection = "rust-analyzer"; |
12 | private readonly requiresReloadOpts = [ | 12 | private readonly requiresReloadOpts = [ |
13 | "serverPath", | 13 | "serverPath", |
14 | "cargo", | 14 | "cargo", |
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index d3fe588e8..027504ecd 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import * as os from "os"; | 1 | import * as os from "os"; |
2 | import * as vscode from 'vscode'; | 2 | import * as vscode from 'vscode'; |
3 | import * as path from 'path'; | 3 | import * as path from 'path'; |
4 | import * as ra from './rust-analyzer-api'; | 4 | import * as ra from './lsp_ext'; |
5 | 5 | ||
6 | import { Cargo } from './cargo'; | 6 | import { Cargo } from './cargo'; |
7 | import { Ctx } from "./ctx"; | 7 | import { Ctx } from "./ctx"; |
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index a2b07d003..9e6d6045f 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import * as lc from "vscode-languageclient"; | 1 | import * as lc from "vscode-languageclient"; |
2 | import * as vscode from 'vscode'; | 2 | import * as vscode from 'vscode'; |
3 | import * as ra from './rust-analyzer-api'; | 3 | import * as ra from './lsp_ext'; |
4 | 4 | ||
5 | import { Ctx, Disposable } from './ctx'; | 5 | import { Ctx, Disposable } from './ctx'; |
6 | import { sendRequestWithRetry, isRustDocument, RustDocument, RustEditor, sleep } from './util'; | 6 | import { sendRequestWithRetry, isRustDocument, RustDocument, RustEditor, sleep } from './util'; |
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts new file mode 100644 index 000000000..4da12eb30 --- /dev/null +++ b/editors/code/src/lsp_ext.ts | |||
@@ -0,0 +1,84 @@ | |||
1 | /** | ||
2 | * This file mirrors `crates/rust-analyzer/src/req.rs` declarations. | ||
3 | */ | ||
4 | |||
5 | import * as lc from "vscode-languageclient"; | ||
6 | |||
7 | export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus"); | ||
8 | |||
9 | export const collectGarbage = new lc.RequestType<null, null, void>("rust-analyzer/collectGarbage"); | ||
10 | |||
11 | export interface SyntaxTreeParams { | ||
12 | textDocument: lc.TextDocumentIdentifier; | ||
13 | range: lc.Range | null; | ||
14 | } | ||
15 | export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>("rust-analyzer/syntaxTree"); | ||
16 | |||
17 | |||
18 | export interface ExpandMacroParams { | ||
19 | textDocument: lc.TextDocumentIdentifier; | ||
20 | position: lc.Position; | ||
21 | } | ||
22 | export interface ExpandedMacro { | ||
23 | name: string; | ||
24 | expansion: string; | ||
25 | } | ||
26 | export const expandMacro = new lc.RequestType<ExpandMacroParams, ExpandedMacro | null, void>("rust-analyzer/expandMacro"); | ||
27 | |||
28 | export interface MatchingBraceParams { | ||
29 | textDocument: lc.TextDocumentIdentifier; | ||
30 | positions: lc.Position[]; | ||
31 | } | ||
32 | export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position[], void>("experimental/matchingBrace"); | ||
33 | |||
34 | export const parentModule = new lc.RequestType<lc.TextDocumentPositionParams, lc.LocationLink[], void>("experimental/parentModule"); | ||
35 | |||
36 | export interface JoinLinesParams { | ||
37 | textDocument: lc.TextDocumentIdentifier; | ||
38 | ranges: lc.Range[]; | ||
39 | } | ||
40 | export const joinLines = new lc.RequestType<JoinLinesParams, lc.TextEdit[], void>("experimental/joinLines"); | ||
41 | |||
42 | export const onEnter = new lc.RequestType<lc.TextDocumentPositionParams, lc.TextEdit[], void>("experimental/onEnter"); | ||
43 | |||
44 | export interface RunnablesParams { | ||
45 | textDocument: lc.TextDocumentIdentifier; | ||
46 | position: lc.Position | null; | ||
47 | } | ||
48 | export interface Runnable { | ||
49 | range: lc.Range; | ||
50 | label: string; | ||
51 | bin: string; | ||
52 | args: string[]; | ||
53 | extraArgs: string[]; | ||
54 | env: { [key: string]: string }; | ||
55 | cwd: string | null; | ||
56 | } | ||
57 | export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>("rust-analyzer/runnables"); | ||
58 | |||
59 | export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint | InlayHint.ChainingHint; | ||
60 | |||
61 | export namespace InlayHint { | ||
62 | export const enum Kind { | ||
63 | TypeHint = "TypeHint", | ||
64 | ParamHint = "ParameterHint", | ||
65 | ChainingHint = "ChainingHint", | ||
66 | } | ||
67 | interface Common { | ||
68 | range: lc.Range; | ||
69 | label: string; | ||
70 | } | ||
71 | export type TypeHint = Common & { kind: Kind.TypeHint }; | ||
72 | export type ParamHint = Common & { kind: Kind.ParamHint }; | ||
73 | export type ChainingHint = Common & { kind: Kind.ChainingHint }; | ||
74 | } | ||
75 | export interface InlayHintsParams { | ||
76 | textDocument: lc.TextDocumentIdentifier; | ||
77 | } | ||
78 | export const inlayHints = new lc.RequestType<InlayHintsParams, InlayHint[], void>("rust-analyzer/inlayHints"); | ||
79 | |||
80 | export interface SsrParams { | ||
81 | query: string; | ||
82 | parseOnly: boolean; | ||
83 | } | ||
84 | export const ssr = new lc.RequestType<SsrParams, lc.WorkspaceEdit, void>('experimental/ssr'); | ||
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index ac3bb365e..31ac81ee8 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as path from "path"; | 2 | import * as path from "path"; |
3 | import * as os from "os"; | 3 | import * as os from "os"; |
4 | import { promises as fs } from "fs"; | 4 | import { promises as fs, PathLike } from "fs"; |
5 | 5 | ||
6 | import * as commands from './commands'; | 6 | import * as commands from './commands'; |
7 | import { activateInlayHints } from './inlay_hints'; | 7 | import { activateInlayHints } from './inlay_hints'; |
@@ -12,6 +12,7 @@ import { log, assert, isValidExecutable } from './util'; | |||
12 | import { PersistentState } from './persistent_state'; | 12 | import { PersistentState } from './persistent_state'; |
13 | import { fetchRelease, download } from './net'; | 13 | import { fetchRelease, download } from './net'; |
14 | import { activateTaskProvider } from './tasks'; | 14 | import { activateTaskProvider } from './tasks'; |
15 | import { exec } from 'child_process'; | ||
15 | 16 | ||
16 | let ctx: Ctx | undefined; | 17 | let ctx: Ctx | undefined; |
17 | 18 | ||
@@ -85,14 +86,14 @@ export async function activate(context: vscode.ExtensionContext) { | |||
85 | 86 | ||
86 | ctx.registerCommand('ssr', commands.ssr); | 87 | ctx.registerCommand('ssr', commands.ssr); |
87 | ctx.registerCommand('serverVersion', commands.serverVersion); | 88 | ctx.registerCommand('serverVersion', commands.serverVersion); |
89 | ctx.registerCommand('toggleInlayHints', commands.toggleInlayHints); | ||
88 | 90 | ||
89 | // Internal commands which are invoked by the server. | 91 | // Internal commands which are invoked by the server. |
90 | ctx.registerCommand('runSingle', commands.runSingle); | 92 | ctx.registerCommand('runSingle', commands.runSingle); |
91 | ctx.registerCommand('debugSingle', commands.debugSingle); | 93 | ctx.registerCommand('debugSingle', commands.debugSingle); |
92 | ctx.registerCommand('showReferences', commands.showReferences); | 94 | ctx.registerCommand('showReferences', commands.showReferences); |
93 | ctx.registerCommand('applySourceChange', commands.applySourceChange); | 95 | ctx.registerCommand('applySnippetWorkspaceEdit', commands.applySnippetWorkspaceEditCommand); |
94 | ctx.registerCommand('applySnippetWorkspaceEdit', commands.applySnippetWorkspaceEdit); | 96 | ctx.registerCommand('applyActionGroup', commands.applyActionGroup); |
95 | ctx.registerCommand('selectAndApplySourceChange', commands.selectAndApplySourceChange); | ||
96 | 97 | ||
97 | ctx.pushCleanup(activateTaskProvider(workspaceFolder)); | 98 | ctx.pushCleanup(activateTaskProvider(workspaceFolder)); |
98 | 99 | ||
@@ -188,6 +189,46 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise< | |||
188 | return path; | 189 | return path; |
189 | } | 190 | } |
190 | 191 | ||
192 | async function patchelf(dest: PathLike): Promise<void> { | ||
193 | await vscode.window.withProgress( | ||
194 | { | ||
195 | location: vscode.ProgressLocation.Notification, | ||
196 | title: "Patching rust-analyzer for NixOS" | ||
197 | }, | ||
198 | async (progress, _) => { | ||
199 | const expression = ` | ||
200 | {src, pkgs ? import <nixpkgs> {}}: | ||
201 | pkgs.stdenv.mkDerivation { | ||
202 | name = "rust-analyzer"; | ||
203 | inherit src; | ||
204 | phases = [ "installPhase" "fixupPhase" ]; | ||
205 | installPhase = "cp $src $out"; | ||
206 | fixupPhase = '' | ||
207 | chmod 755 $out | ||
208 | patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out | ||
209 | ''; | ||
210 | } | ||
211 | `; | ||
212 | const origFile = dest + "-orig"; | ||
213 | await fs.rename(dest, origFile); | ||
214 | progress.report({ message: "Patching executable", increment: 20 }); | ||
215 | await new Promise((resolve, reject) => { | ||
216 | const handle = exec(`nix-build -E - --arg src '${origFile}' -o ${dest}`, | ||
217 | (err, stdout, stderr) => { | ||
218 | if (err != null) { | ||
219 | reject(Error(stderr)); | ||
220 | } else { | ||
221 | resolve(stdout); | ||
222 | } | ||
223 | }); | ||
224 | handle.stdin?.write(expression); | ||
225 | handle.stdin?.end(); | ||
226 | }); | ||
227 | await fs.unlink(origFile); | ||
228 | } | ||
229 | ); | ||
230 | } | ||
231 | |||
191 | async function getServer(config: Config, state: PersistentState): Promise<string | undefined> { | 232 | async function getServer(config: Config, state: PersistentState): Promise<string | undefined> { |
192 | const explicitPath = process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath; | 233 | const explicitPath = process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath; |
193 | if (explicitPath) { | 234 | if (explicitPath) { |
@@ -237,6 +278,12 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
237 | assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); | 278 | assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); |
238 | 279 | ||
239 | await download(artifact.browser_download_url, dest, "Downloading rust-analyzer server", { mode: 0o755 }); | 280 | await download(artifact.browser_download_url, dest, "Downloading rust-analyzer server", { mode: 0o755 }); |
281 | |||
282 | // Patching executable if that's NixOS. | ||
283 | if (await fs.stat("/etc/nixos").then(_ => true).catch(_ => false)) { | ||
284 | await patchelf(dest); | ||
285 | } | ||
286 | |||
240 | await state.updateServerVersion(config.package.version); | 287 | await state.updateServerVersion(config.package.version); |
241 | return dest; | 288 | return dest; |
242 | } | 289 | } |
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/run.ts index 0bd30fb07..2a7a429cf 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/run.ts | |||
@@ -1,13 +1,13 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as lc from 'vscode-languageclient'; |
3 | import * as ra from '../rust-analyzer-api'; | 3 | import * as ra from './lsp_ext'; |
4 | 4 | ||
5 | import { Ctx, Cmd } from '../ctx'; | 5 | import { Ctx, Cmd } from './ctx'; |
6 | import { startDebugSession, getDebugConfiguration } from '../debug'; | 6 | import { startDebugSession, getDebugConfiguration } from './debug'; |
7 | 7 | ||
8 | const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; | 8 | const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; |
9 | 9 | ||
10 | async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> { | 10 | export async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> { |
11 | const editor = ctx.activeRustEditor; | 11 | const editor = ctx.activeRustEditor; |
12 | const client = ctx.client; | 12 | const client = ctx.client; |
13 | if (!editor || !client) return; | 13 | if (!editor || !client) return; |
@@ -83,20 +83,6 @@ async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debugg | |||
83 | }); | 83 | }); |
84 | } | 84 | } |
85 | 85 | ||
86 | export function run(ctx: Ctx): Cmd { | ||
87 | let prevRunnable: RunnableQuickPick | undefined; | ||
88 | |||
89 | return async () => { | ||
90 | const item = await selectRunnable(ctx, prevRunnable); | ||
91 | if (!item) return; | ||
92 | |||
93 | item.detail = 'rerun'; | ||
94 | prevRunnable = item; | ||
95 | const task = createTask(item.runnable); | ||
96 | return await vscode.tasks.executeTask(task); | ||
97 | }; | ||
98 | } | ||
99 | |||
100 | export function runSingle(ctx: Ctx): Cmd { | 86 | export function runSingle(ctx: Ctx): Cmd { |
101 | return async (runnable: ra.Runnable) => { | 87 | return async (runnable: ra.Runnable) => { |
102 | const editor = ctx.activeRustEditor; | 88 | const editor = ctx.activeRustEditor; |
@@ -165,7 +151,7 @@ export function newDebugConfig(ctx: Ctx): Cmd { | |||
165 | }; | 151 | }; |
166 | } | 152 | } |
167 | 153 | ||
168 | class RunnableQuickPick implements vscode.QuickPickItem { | 154 | export class RunnableQuickPick implements vscode.QuickPickItem { |
169 | public label: string; | 155 | public label: string; |
170 | public description?: string | undefined; | 156 | public description?: string | undefined; |
171 | public detail?: string | undefined; | 157 | public detail?: string | undefined; |
@@ -184,7 +170,7 @@ interface CargoTaskDefinition extends vscode.TaskDefinition { | |||
184 | env?: { [key: string]: string }; | 170 | env?: { [key: string]: string }; |
185 | } | 171 | } |
186 | 172 | ||
187 | function createTask(spec: ra.Runnable): vscode.Task { | 173 | export function createTask(spec: ra.Runnable): vscode.Task { |
188 | const TASK_SOURCE = 'Rust'; | 174 | const TASK_SOURCE = 'Rust'; |
189 | const definition: CargoTaskDefinition = { | 175 | const definition: CargoTaskDefinition = { |
190 | type: 'cargo', | 176 | type: 'cargo', |
diff --git a/editors/code/src/rust-analyzer-api.ts b/editors/code/src/rust-analyzer-api.ts deleted file mode 100644 index 400ac3714..000000000 --- a/editors/code/src/rust-analyzer-api.ts +++ /dev/null | |||
@@ -1,125 +0,0 @@ | |||
1 | /** | ||
2 | * This file mirrors `crates/rust-analyzer/src/req.rs` declarations. | ||
3 | */ | ||
4 | |||
5 | import * as lc from "vscode-languageclient"; | ||
6 | |||
7 | type Option<T> = null | T; | ||
8 | type Vec<T> = T[]; | ||
9 | type FxHashMap<K extends PropertyKey, V> = Record<K, V>; | ||
10 | |||
11 | function request<TParams, TResult>(method: string) { | ||
12 | return new lc.RequestType<TParams, TResult, unknown>(`rust-analyzer/${method}`); | ||
13 | } | ||
14 | function notification<TParam>(method: string) { | ||
15 | return new lc.NotificationType<TParam>(method); | ||
16 | } | ||
17 | |||
18 | |||
19 | export const analyzerStatus = request<null, string>("analyzerStatus"); | ||
20 | |||
21 | |||
22 | export const collectGarbage = request<null, null>("collectGarbage"); | ||
23 | |||
24 | |||
25 | export interface SyntaxTreeParams { | ||
26 | textDocument: lc.TextDocumentIdentifier; | ||
27 | range: Option<lc.Range>; | ||
28 | } | ||
29 | export const syntaxTree = request<SyntaxTreeParams, string>("syntaxTree"); | ||
30 | |||
31 | |||
32 | export interface ExpandMacroParams { | ||
33 | textDocument: lc.TextDocumentIdentifier; | ||
34 | position: Option<lc.Position>; | ||
35 | } | ||
36 | export interface ExpandedMacro { | ||
37 | name: string; | ||
38 | expansion: string; | ||
39 | } | ||
40 | export const expandMacro = request<ExpandMacroParams, Option<ExpandedMacro>>("expandMacro"); | ||
41 | |||
42 | |||
43 | export interface FindMatchingBraceParams { | ||
44 | textDocument: lc.TextDocumentIdentifier; | ||
45 | offsets: Vec<lc.Position>; | ||
46 | } | ||
47 | export const findMatchingBrace = request<FindMatchingBraceParams, Vec<lc.Position>>("findMatchingBrace"); | ||
48 | |||
49 | |||
50 | export interface PublishDecorationsParams { | ||
51 | uri: string; | ||
52 | decorations: Vec<Decoration>; | ||
53 | } | ||
54 | export interface Decoration { | ||
55 | range: lc.Range; | ||
56 | tag: string; | ||
57 | bindingHash: Option<string>; | ||
58 | } | ||
59 | export const decorationsRequest = request<lc.TextDocumentIdentifier, Vec<Decoration>>("decorationsRequest"); | ||
60 | |||
61 | |||
62 | export const parentModule = request<lc.TextDocumentPositionParams, Vec<lc.Location>>("parentModule"); | ||
63 | |||
64 | |||
65 | export interface JoinLinesParams { | ||
66 | textDocument: lc.TextDocumentIdentifier; | ||
67 | range: lc.Range; | ||
68 | } | ||
69 | export const joinLines = request<JoinLinesParams, SourceChange>("joinLines"); | ||
70 | |||
71 | |||
72 | export const onEnter = request<lc.TextDocumentPositionParams, Option<SourceChange>>("onEnter"); | ||
73 | |||
74 | export interface RunnablesParams { | ||
75 | textDocument: lc.TextDocumentIdentifier; | ||
76 | position: Option<lc.Position>; | ||
77 | } | ||
78 | export interface Runnable { | ||
79 | range: lc.Range; | ||
80 | label: string; | ||
81 | bin: string; | ||
82 | args: Vec<string>; | ||
83 | extraArgs: Vec<string>; | ||
84 | env: FxHashMap<string, string>; | ||
85 | cwd: Option<string>; | ||
86 | } | ||
87 | export const runnables = request<RunnablesParams, Vec<Runnable>>("runnables"); | ||
88 | |||
89 | export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint | InlayHint.ChainingHint; | ||
90 | |||
91 | export namespace InlayHint { | ||
92 | export const enum Kind { | ||
93 | TypeHint = "TypeHint", | ||
94 | ParamHint = "ParameterHint", | ||
95 | ChainingHint = "ChainingHint", | ||
96 | } | ||
97 | interface Common { | ||
98 | range: lc.Range; | ||
99 | label: string; | ||
100 | } | ||
101 | export type TypeHint = Common & { kind: Kind.TypeHint }; | ||
102 | export type ParamHint = Common & { kind: Kind.ParamHint }; | ||
103 | export type ChainingHint = Common & { kind: Kind.ChainingHint }; | ||
104 | } | ||
105 | export interface InlayHintsParams { | ||
106 | textDocument: lc.TextDocumentIdentifier; | ||
107 | } | ||
108 | export const inlayHints = request<InlayHintsParams, Vec<InlayHint>>("inlayHints"); | ||
109 | |||
110 | |||
111 | export interface SsrParams { | ||
112 | query: string; | ||
113 | parseOnly: boolean; | ||
114 | } | ||
115 | export const ssr = request<SsrParams, SourceChange>("ssr"); | ||
116 | |||
117 | |||
118 | export const publishDecorations = notification<PublishDecorationsParams>("publishDecorations"); | ||
119 | |||
120 | |||
121 | export interface SourceChange { | ||
122 | label: string; | ||
123 | workspaceEdit: lc.WorkspaceEdit; | ||
124 | cursorPosition: Option<lc.TextDocumentPositionParams>; | ||
125 | } | ||
diff --git a/editors/code/src/snippets.ts b/editors/code/src/snippets.ts new file mode 100644 index 000000000..bcb3f2cc7 --- /dev/null +++ b/editors/code/src/snippets.ts | |||
@@ -0,0 +1,55 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | |||
3 | import { assert } from './util'; | ||
4 | |||
5 | export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { | ||
6 | assert(edit.entries().length === 1, `bad ws edit: ${JSON.stringify(edit)}`); | ||
7 | const [uri, edits] = edit.entries()[0]; | ||
8 | |||
9 | const editor = vscode.window.visibleTextEditors.find((it) => it.document.uri.toString() === uri.toString()); | ||
10 | if (!editor) return; | ||
11 | await applySnippetTextEdits(editor, edits); | ||
12 | } | ||
13 | |||
14 | export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) { | ||
15 | let selection: vscode.Selection | undefined = undefined; | ||
16 | let lineDelta = 0; | ||
17 | await editor.edit((builder) => { | ||
18 | for (const indel of edits) { | ||
19 | const parsed = parseSnippet(indel.newText); | ||
20 | if (parsed) { | ||
21 | const [newText, [placeholderStart, placeholderLength]] = parsed; | ||
22 | const prefix = newText.substr(0, placeholderStart); | ||
23 | const lastNewline = prefix.lastIndexOf('\n'); | ||
24 | |||
25 | const startLine = indel.range.start.line + lineDelta + countLines(prefix); | ||
26 | const startColumn = lastNewline === -1 ? | ||
27 | indel.range.start.character + placeholderStart | ||
28 | : prefix.length - lastNewline - 1; | ||
29 | const endColumn = startColumn + placeholderLength; | ||
30 | selection = new vscode.Selection( | ||
31 | new vscode.Position(startLine, startColumn), | ||
32 | new vscode.Position(startLine, endColumn), | ||
33 | ); | ||
34 | builder.replace(indel.range, newText); | ||
35 | } else { | ||
36 | lineDelta = countLines(indel.newText) - (indel.range.end.line - indel.range.start.line); | ||
37 | builder.replace(indel.range, indel.newText); | ||
38 | } | ||
39 | } | ||
40 | }); | ||
41 | if (selection) editor.selection = selection; | ||
42 | } | ||
43 | |||
44 | function parseSnippet(snip: string): [string, [number, number]] | undefined { | ||
45 | const m = snip.match(/\$(0|\{0:([^}]*)\})/); | ||
46 | if (!m) return undefined; | ||
47 | const placeholder = m[2] ?? ""; | ||
48 | const range: [number, number] = [m.index!!, placeholder.length]; | ||
49 | const insert = snip.replace(m[0], placeholder); | ||
50 | return [insert, range]; | ||
51 | } | ||
52 | |||
53 | function countLines(text: string): number { | ||
54 | return (text.match(/\n/g) || []).length; | ||
55 | } | ||
diff --git a/editors/code/src/source_change.ts b/editors/code/src/source_change.ts deleted file mode 100644 index af8f1df51..000000000 --- a/editors/code/src/source_change.ts +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import * as lc from 'vscode-languageclient'; | ||
3 | import * as ra from './rust-analyzer-api'; | ||
4 | |||
5 | import { Ctx } from './ctx'; | ||
6 | |||
7 | export async function applySourceChange(ctx: Ctx, change: ra.SourceChange) { | ||
8 | const client = ctx.client; | ||
9 | if (!client) return; | ||
10 | |||
11 | const wsEdit = client.protocol2CodeConverter.asWorkspaceEdit( | ||
12 | change.workspaceEdit, | ||
13 | ); | ||
14 | let created; | ||
15 | let moved; | ||
16 | if (change.workspaceEdit.documentChanges) { | ||
17 | for (const docChange of change.workspaceEdit.documentChanges) { | ||
18 | if (lc.CreateFile.is(docChange)) { | ||
19 | created = docChange.uri; | ||
20 | } else if (lc.RenameFile.is(docChange)) { | ||
21 | moved = docChange.newUri; | ||
22 | } | ||
23 | } | ||
24 | } | ||
25 | const toOpen = created || moved; | ||
26 | const toReveal = change.cursorPosition; | ||
27 | await vscode.workspace.applyEdit(wsEdit); | ||
28 | if (toOpen) { | ||
29 | const toOpenUri = vscode.Uri.parse(toOpen); | ||
30 | const doc = await vscode.workspace.openTextDocument(toOpenUri); | ||
31 | await vscode.window.showTextDocument(doc); | ||
32 | } else if (toReveal) { | ||
33 | const uri = client.protocol2CodeConverter.asUri( | ||
34 | toReveal.textDocument.uri, | ||
35 | ); | ||
36 | const position = client.protocol2CodeConverter.asPosition( | ||
37 | toReveal.position, | ||
38 | ); | ||
39 | const editor = vscode.window.activeTextEditor; | ||
40 | if (!editor || !editor.selection.isEmpty) { | ||
41 | return; | ||
42 | } | ||
43 | |||
44 | if (editor.document.uri !== uri) { | ||
45 | const doc = await vscode.workspace.openTextDocument(uri); | ||
46 | await vscode.window.showTextDocument(doc); | ||
47 | } | ||
48 | editor.selection = new vscode.Selection(position, position); | ||
49 | editor.revealRange( | ||
50 | new vscode.Range(position, position), | ||
51 | vscode.TextEditorRevealType.Default, | ||
52 | ); | ||
53 | } | ||
54 | } | ||
diff --git a/editors/code/tests/runTests.ts b/editors/code/tests/runTests.ts new file mode 100644 index 000000000..22df80ad3 --- /dev/null +++ b/editors/code/tests/runTests.ts | |||
@@ -0,0 +1,43 @@ | |||
1 | import * as path from 'path'; | ||
2 | import * as fs from 'fs'; | ||
3 | |||
4 | import { runTests } from 'vscode-test'; | ||
5 | |||
6 | async function main() { | ||
7 | // The folder containing the Extension Manifest package.json | ||
8 | // Passed to `--extensionDevelopmentPath` | ||
9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); | ||
10 | |||
11 | // Minimum supported version. | ||
12 | const jsonData = fs.readFileSync(path.join(extensionDevelopmentPath, 'package.json')); | ||
13 | const json = JSON.parse(jsonData.toString()); | ||
14 | let minimalVersion: string = json.engines.vscode; | ||
15 | if (minimalVersion.startsWith('^')) minimalVersion = minimalVersion.slice(1); | ||
16 | |||
17 | const launchArgs = ["--disable-extensions"]; | ||
18 | |||
19 | // All test suites (either unit tests or integration tests) should be in subfolders. | ||
20 | const extensionTestsPath = path.resolve(__dirname, './unit/index'); | ||
21 | |||
22 | // Run tests using the minimal supported version. | ||
23 | await runTests({ | ||
24 | version: minimalVersion, | ||
25 | launchArgs, | ||
26 | extensionDevelopmentPath, | ||
27 | extensionTestsPath | ||
28 | }); | ||
29 | |||
30 | // and the latest one | ||
31 | await runTests({ | ||
32 | version: 'stable', | ||
33 | launchArgs, | ||
34 | extensionDevelopmentPath, | ||
35 | extensionTestsPath | ||
36 | }); | ||
37 | } | ||
38 | |||
39 | main().catch(err => { | ||
40 | // eslint-disable-next-line no-console | ||
41 | console.error('Failed to run tests', err); | ||
42 | process.exit(1); | ||
43 | }); | ||
diff --git a/editors/code/tests/unit/index.ts b/editors/code/tests/unit/index.ts new file mode 100644 index 000000000..5165720b4 --- /dev/null +++ b/editors/code/tests/unit/index.ts | |||
@@ -0,0 +1,38 @@ | |||
1 | import * as path from 'path'; | ||
2 | import Mocha from 'mocha'; | ||
3 | import glob from 'glob'; | ||
4 | |||
5 | export function run(): Promise<void> { | ||
6 | // Create the mocha test | ||
7 | const mocha = new Mocha({ | ||
8 | ui: 'tdd', | ||
9 | color: true | ||
10 | }); | ||
11 | |||
12 | const testsRoot = __dirname; | ||
13 | |||
14 | return new Promise((resolve, reject) => { | ||
15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { | ||
16 | if (err) { | ||
17 | return reject(err); | ||
18 | } | ||
19 | |||
20 | // Add files to the test suite | ||
21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); | ||
22 | |||
23 | try { | ||
24 | // Run the mocha test | ||
25 | mocha.timeout(100000); | ||
26 | mocha.run(failures => { | ||
27 | if (failures > 0) { | ||
28 | reject(new Error(`${failures} tests failed.`)); | ||
29 | } else { | ||
30 | resolve(); | ||
31 | } | ||
32 | }); | ||
33 | } catch (err) { | ||
34 | reject(err); | ||
35 | } | ||
36 | }); | ||
37 | }); | ||
38 | } | ||
diff --git a/editors/code/tests/unit/launch_config.test.ts b/editors/code/tests/unit/launch_config.test.ts new file mode 100644 index 000000000..d5cf1b74e --- /dev/null +++ b/editors/code/tests/unit/launch_config.test.ts | |||
@@ -0,0 +1,52 @@ | |||
1 | import * as assert from 'assert'; | ||
2 | import * as cargo from '../../src/cargo'; | ||
3 | |||
4 | suite('Launch configuration', () => { | ||
5 | |||
6 | suite('Lens', () => { | ||
7 | test('A binary', async () => { | ||
8 | const args = cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "pkg_name"]); | ||
9 | |||
10 | assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]); | ||
11 | assert.deepEqual(args.filter, undefined); | ||
12 | }); | ||
13 | |||
14 | test('One of Multiple Binaries', async () => { | ||
15 | const args = cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "bin1"]); | ||
16 | |||
17 | assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin1", "--message-format=json"]); | ||
18 | assert.deepEqual(args.filter, undefined); | ||
19 | }); | ||
20 | |||
21 | test('A test', async () => { | ||
22 | const args = cargo.artifactSpec(["test", "--package", "pkg_name", "--lib", "--no-run"]); | ||
23 | |||
24 | assert.deepEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--no-run", "--message-format=json"]); | ||
25 | assert.notDeepEqual(args.filter, undefined); | ||
26 | }); | ||
27 | }); | ||
28 | |||
29 | suite('QuickPick', () => { | ||
30 | test('A binary', async () => { | ||
31 | const args = cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "pkg_name"]); | ||
32 | |||
33 | assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]); | ||
34 | assert.deepEqual(args.filter, undefined); | ||
35 | }); | ||
36 | |||
37 | |||
38 | test('One of Multiple Binaries', async () => { | ||
39 | const args = cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "bin2"]); | ||
40 | |||
41 | assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin2", "--message-format=json"]); | ||
42 | assert.deepEqual(args.filter, undefined); | ||
43 | }); | ||
44 | |||
45 | test('A test', async () => { | ||
46 | const args = cargo.artifactSpec(["test", "--package", "pkg_name", "--lib"]); | ||
47 | |||
48 | assert.deepEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--message-format=json", "--no-run"]); | ||
49 | assert.notDeepEqual(args.filter, undefined); | ||
50 | }); | ||
51 | }); | ||
52 | }); | ||
diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json index ad134865a..32d1a865f 100644 --- a/editors/code/tsconfig.json +++ b/editors/code/tsconfig.json | |||
@@ -9,7 +9,7 @@ | |||
9 | "esModuleInterop": true, | 9 | "esModuleInterop": true, |
10 | "allowSyntheticDefaultImports": true, | 10 | "allowSyntheticDefaultImports": true, |
11 | "sourceMap": true, | 11 | "sourceMap": true, |
12 | "rootDir": "src", | 12 | "rootDir": ".", |
13 | "strict": true, | 13 | "strict": true, |
14 | "noUnusedLocals": true, | 14 | "noUnusedLocals": true, |
15 | "noUnusedParameters": true, | 15 | "noUnusedParameters": true, |
@@ -18,6 +18,11 @@ | |||
18 | "newLine": "LF" | 18 | "newLine": "LF" |
19 | }, | 19 | }, |
20 | "exclude": [ | 20 | "exclude": [ |
21 | "node_modules" | 21 | "node_modules", |
22 | ".vscode-test" | ||
23 | ], | ||
24 | "include": [ | ||
25 | "src", | ||
26 | "tests" | ||
22 | ] | 27 | ] |
23 | } | 28 | } |