diff options
206 files changed, 12350 insertions, 4978 deletions
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 3f52f31f8..29ac89549 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -20,7 +20,7 @@ jobs: | |||
20 | runs-on: ${{ matrix.os }} | 20 | runs-on: ${{ matrix.os }} |
21 | strategy: | 21 | strategy: |
22 | matrix: | 22 | matrix: |
23 | os: [ubuntu-latest, windows-latest, macos-latest] | 23 | os: [ubuntu-16.04, windows-latest, macos-latest] |
24 | 24 | ||
25 | steps: | 25 | steps: |
26 | - name: Checkout repository | 26 | - name: Checkout repository |
@@ -42,25 +42,25 @@ jobs: | |||
42 | override: true | 42 | override: true |
43 | 43 | ||
44 | - name: Install Nodejs | 44 | - name: Install Nodejs |
45 | if: matrix.os == 'ubuntu-latest' | 45 | if: matrix.os == 'ubuntu-16.04' |
46 | uses: actions/setup-node@v1 | 46 | uses: actions/setup-node@v1 |
47 | with: | 47 | with: |
48 | node-version: 12.x | 48 | node-version: 12.x |
49 | 49 | ||
50 | - name: Dist | 50 | - name: Dist |
51 | if: matrix.os == 'ubuntu-latest' && github.ref == 'refs/heads/release' | 51 | if: matrix.os == 'ubuntu-16.04' && github.ref == 'refs/heads/release' |
52 | run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER | 52 | run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER |
53 | 53 | ||
54 | - name: Dist | 54 | - name: Dist |
55 | if: matrix.os == 'ubuntu-latest' && github.ref != 'refs/heads/release' | 55 | if: matrix.os == 'ubuntu-16.04' && github.ref != 'refs/heads/release' |
56 | run: cargo xtask dist --nightly --client 0.3.$GITHUB_RUN_NUMBER-nightly | 56 | run: cargo xtask dist --nightly --client 0.3.$GITHUB_RUN_NUMBER-nightly |
57 | 57 | ||
58 | - name: Dist | 58 | - name: Dist |
59 | if: matrix.os != 'ubuntu-latest' | 59 | if: matrix.os != 'ubuntu-16.04' |
60 | run: cargo xtask dist | 60 | run: cargo xtask dist |
61 | 61 | ||
62 | - name: Nightly analysis-stats check | 62 | - name: Nightly analysis-stats check |
63 | if: matrix.os == 'ubuntu-latest' && github.ref != 'refs/heads/release' | 63 | if: matrix.os == 'ubuntu-16.04' && github.ref != 'refs/heads/release' |
64 | run: ./dist/rust-analyzer-linux analysis-stats . | 64 | run: ./dist/rust-analyzer-linux analysis-stats . |
65 | 65 | ||
66 | - name: Upload artifacts | 66 | - name: Upload artifacts |
@@ -71,7 +71,7 @@ jobs: | |||
71 | 71 | ||
72 | publish: | 72 | publish: |
73 | name: publish | 73 | name: publish |
74 | runs-on: ubuntu-latest | 74 | runs-on: ubuntu-16.04 |
75 | needs: ['dist'] | 75 | needs: ['dist'] |
76 | steps: | 76 | steps: |
77 | - name: Install Nodejs | 77 | - name: Install Nodejs |
@@ -94,7 +94,7 @@ jobs: | |||
94 | path: dist | 94 | path: dist |
95 | - uses: actions/download-artifact@v1 | 95 | - uses: actions/download-artifact@v1 |
96 | with: | 96 | with: |
97 | name: dist-ubuntu-latest | 97 | name: dist-ubuntu-16.04 |
98 | path: dist | 98 | path: dist |
99 | - uses: actions/download-artifact@v1 | 99 | - uses: actions/download-artifact@v1 |
100 | with: | 100 | with: |
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 5a319a040..a511e0d28 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1,6 +1,15 @@ | |||
1 | # This file is automatically @generated by Cargo. | 1 | # This file is automatically @generated by Cargo. |
2 | # It is not intended for manual editing. | 2 | # It is not intended for manual editing. |
3 | [[package]] | 3 | [[package]] |
4 | name = "addr2line" | ||
5 | version = "0.12.1" | ||
6 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
7 | checksum = "a49806b9dadc843c61e7c97e72490ad7f7220ae249012fbda9ad0609457c0543" | ||
8 | dependencies = [ | ||
9 | "gimli", | ||
10 | ] | ||
11 | |||
12 | [[package]] | ||
4 | name = "aho-corasick" | 13 | name = "aho-corasick" |
5 | version = "0.7.10" | 14 | version = "0.7.10" |
6 | source = "registry+https://github.com/rust-lang/crates.io-index" | 15 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -11,9 +20,9 @@ dependencies = [ | |||
11 | 20 | ||
12 | [[package]] | 21 | [[package]] |
13 | name = "anyhow" | 22 | name = "anyhow" |
14 | version = "1.0.28" | 23 | version = "1.0.31" |
15 | source = "registry+https://github.com/rust-lang/crates.io-index" | 24 | source = "registry+https://github.com/rust-lang/crates.io-index" |
16 | checksum = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff" | 25 | checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" |
17 | 26 | ||
18 | [[package]] | 27 | [[package]] |
19 | name = "anymap" | 28 | name = "anymap" |
@@ -46,27 +55,18 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" | |||
46 | 55 | ||
47 | [[package]] | 56 | [[package]] |
48 | name = "backtrace" | 57 | name = "backtrace" |
49 | version = "0.3.46" | 58 | version = "0.3.48" |
50 | source = "registry+https://github.com/rust-lang/crates.io-index" | 59 | source = "registry+https://github.com/rust-lang/crates.io-index" |
51 | checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e" | 60 | checksum = "0df2f85c8a2abbe3b7d7e748052fdd9b76a0458fdeb16ad4223f5eca78c7c130" |
52 | dependencies = [ | 61 | dependencies = [ |
53 | "backtrace-sys", | 62 | "addr2line", |
54 | "cfg-if", | 63 | "cfg-if", |
55 | "libc", | 64 | "libc", |
65 | "object", | ||
56 | "rustc-demangle", | 66 | "rustc-demangle", |
57 | ] | 67 | ] |
58 | 68 | ||
59 | [[package]] | 69 | [[package]] |
60 | name = "backtrace-sys" | ||
61 | version = "0.1.37" | ||
62 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
63 | checksum = "18fbebbe1c9d1f383a9cc7e8ccdb471b91c8d024ee9c2ca5b5346121fe8b4399" | ||
64 | dependencies = [ | ||
65 | "cc", | ||
66 | "libc", | ||
67 | ] | ||
68 | |||
69 | [[package]] | ||
70 | name = "base64" | 70 | name = "base64" |
71 | version = "0.12.1" | 71 | version = "0.12.1" |
72 | source = "registry+https://github.com/rust-lang/crates.io-index" | 72 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -80,9 +80,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" | |||
80 | 80 | ||
81 | [[package]] | 81 | [[package]] |
82 | name = "bstr" | 82 | name = "bstr" |
83 | version = "0.2.12" | 83 | version = "0.2.13" |
84 | source = "registry+https://github.com/rust-lang/crates.io-index" | 84 | source = "registry+https://github.com/rust-lang/crates.io-index" |
85 | checksum = "2889e6d50f394968c8bf4240dc3f2a7eb4680844d27308f798229ac9d4725f41" | 85 | checksum = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931" |
86 | dependencies = [ | 86 | dependencies = [ |
87 | "memchr", | 87 | "memchr", |
88 | ] | 88 | ] |
@@ -101,9 +101,9 @@ dependencies = [ | |||
101 | 101 | ||
102 | [[package]] | 102 | [[package]] |
103 | name = "cc" | 103 | name = "cc" |
104 | version = "1.0.52" | 104 | version = "1.0.53" |
105 | source = "registry+https://github.com/rust-lang/crates.io-index" | 105 | source = "registry+https://github.com/rust-lang/crates.io-index" |
106 | checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d" | 106 | checksum = "404b1fe4f65288577753b17e3b36a04596ee784493ec249bf81c7f2d2acd751c" |
107 | 107 | ||
108 | [[package]] | 108 | [[package]] |
109 | name = "cfg-if" | 109 | name = "cfg-if" |
@@ -113,8 +113,8 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" | |||
113 | 113 | ||
114 | [[package]] | 114 | [[package]] |
115 | name = "chalk-derive" | 115 | name = "chalk-derive" |
116 | version = "0.1.0" | 116 | version = "0.10.1-dev" |
117 | source = "git+https://github.com/rust-lang/chalk.git?rev=2c072cc830d04af5f10b390e6643327f85108282#2c072cc830d04af5f10b390e6643327f85108282" | 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", |
@@ -124,8 +124,8 @@ dependencies = [ | |||
124 | 124 | ||
125 | [[package]] | 125 | [[package]] |
126 | name = "chalk-engine" | 126 | name = "chalk-engine" |
127 | version = "0.9.0" | 127 | version = "0.10.1-dev" |
128 | source = "git+https://github.com/rust-lang/chalk.git?rev=2c072cc830d04af5f10b390e6643327f85108282#2c072cc830d04af5f10b390e6643327f85108282" | 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", |
@@ -133,8 +133,8 @@ dependencies = [ | |||
133 | 133 | ||
134 | [[package]] | 134 | [[package]] |
135 | name = "chalk-ir" | 135 | name = "chalk-ir" |
136 | version = "0.1.0" | 136 | version = "0.10.1-dev" |
137 | source = "git+https://github.com/rust-lang/chalk.git?rev=2c072cc830d04af5f10b390e6643327f85108282#2c072cc830d04af5f10b390e6643327f85108282" | 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", |
@@ -143,16 +143,16 @@ dependencies = [ | |||
143 | 143 | ||
144 | [[package]] | 144 | [[package]] |
145 | name = "chalk-macros" | 145 | name = "chalk-macros" |
146 | version = "0.1.1" | 146 | version = "0.10.1-dev" |
147 | source = "git+https://github.com/rust-lang/chalk.git?rev=2c072cc830d04af5f10b390e6643327f85108282#2c072cc830d04af5f10b390e6643327f85108282" | 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 | ] |
151 | 151 | ||
152 | [[package]] | 152 | [[package]] |
153 | name = "chalk-rust-ir" | 153 | name = "chalk-rust-ir" |
154 | version = "0.1.0" | 154 | version = "0.10.1-dev" |
155 | source = "git+https://github.com/rust-lang/chalk.git?rev=2c072cc830d04af5f10b390e6643327f85108282#2c072cc830d04af5f10b390e6643327f85108282" | 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", |
@@ -162,15 +162,15 @@ dependencies = [ | |||
162 | 162 | ||
163 | [[package]] | 163 | [[package]] |
164 | name = "chalk-solve" | 164 | name = "chalk-solve" |
165 | version = "0.1.0" | 165 | version = "0.10.1-dev" |
166 | source = "git+https://github.com/rust-lang/chalk.git?rev=2c072cc830d04af5f10b390e6643327f85108282#2c072cc830d04af5f10b390e6643327f85108282" | 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,15 +345,15 @@ 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" |
363 | version = "1.0.6" | 354 | version = "1.0.7" |
364 | source = "registry+https://github.com/rust-lang/crates.io-index" | 355 | source = "registry+https://github.com/rust-lang/crates.io-index" |
365 | checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" | 356 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" |
366 | 357 | ||
367 | [[package]] | 358 | [[package]] |
368 | name = "fs_extra" | 359 | name = "fs_extra" |
@@ -423,6 +414,12 @@ dependencies = [ | |||
423 | ] | 414 | ] |
424 | 415 | ||
425 | [[package]] | 416 | [[package]] |
417 | name = "gimli" | ||
418 | version = "0.21.0" | ||
419 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
420 | checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" | ||
421 | |||
422 | [[package]] | ||
426 | name = "globset" | 423 | name = "globset" |
427 | version = "0.4.5" | 424 | version = "0.4.5" |
428 | source = "registry+https://github.com/rust-lang/crates.io-index" | 425 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -437,9 +434,9 @@ dependencies = [ | |||
437 | 434 | ||
438 | [[package]] | 435 | [[package]] |
439 | name = "goblin" | 436 | name = "goblin" |
440 | version = "0.2.1" | 437 | version = "0.2.3" |
441 | source = "registry+https://github.com/rust-lang/crates.io-index" | 438 | source = "registry+https://github.com/rust-lang/crates.io-index" |
442 | checksum = "ddd5e3132801a1ac34ac53b97acde50c4685414dd2f291b9ea52afa6f07468c8" | 439 | checksum = "d20fd25aa456527ce4f544271ae4fea65d2eda4a6561ea56f39fb3ee4f7e3884" |
443 | dependencies = [ | 440 | dependencies = [ |
444 | "log", | 441 | "log", |
445 | "plain", | 442 | "plain", |
@@ -457,9 +454,9 @@ dependencies = [ | |||
457 | 454 | ||
458 | [[package]] | 455 | [[package]] |
459 | name = "hermit-abi" | 456 | name = "hermit-abi" |
460 | version = "0.1.12" | 457 | version = "0.1.13" |
461 | source = "registry+https://github.com/rust-lang/crates.io-index" | 458 | source = "registry+https://github.com/rust-lang/crates.io-index" |
462 | checksum = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4" | 459 | checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" |
463 | dependencies = [ | 460 | dependencies = [ |
464 | "libc", | 461 | "libc", |
465 | ] | 462 | ] |
@@ -613,9 +610,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" | |||
613 | 610 | ||
614 | [[package]] | 611 | [[package]] |
615 | name = "libc" | 612 | name = "libc" |
616 | version = "0.2.69" | 613 | version = "0.2.70" |
617 | source = "registry+https://github.com/rust-lang/crates.io-index" | 614 | source = "registry+https://github.com/rust-lang/crates.io-index" |
618 | checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" | 615 | checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" |
619 | 616 | ||
620 | [[package]] | 617 | [[package]] |
621 | name = "libloading" | 618 | name = "libloading" |
@@ -652,9 +649,9 @@ dependencies = [ | |||
652 | 649 | ||
653 | [[package]] | 650 | [[package]] |
654 | name = "lsp-server" | 651 | name = "lsp-server" |
655 | version = "0.3.1" | 652 | version = "0.3.2" |
656 | source = "registry+https://github.com/rust-lang/crates.io-index" | 653 | source = "registry+https://github.com/rust-lang/crates.io-index" |
657 | checksum = "5383e043329615624bbf45e1ba27bd75c176762b2592855c659bc28ac580a06b" | 654 | checksum = "dccec31bfd027ac0dd288a78e19005fd89624d9099456e284b5241316a6c3072" |
658 | dependencies = [ | 655 | dependencies = [ |
659 | "crossbeam-channel", | 656 | "crossbeam-channel", |
660 | "log", | 657 | "log", |
@@ -796,16 +793,16 @@ dependencies = [ | |||
796 | ] | 793 | ] |
797 | 794 | ||
798 | [[package]] | 795 | [[package]] |
799 | name = "once_cell" | 796 | name = "object" |
800 | version = "1.3.1" | 797 | version = "0.19.0" |
801 | source = "registry+https://github.com/rust-lang/crates.io-index" | 798 | source = "registry+https://github.com/rust-lang/crates.io-index" |
802 | checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" | 799 | checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2" |
803 | 800 | ||
804 | [[package]] | 801 | [[package]] |
805 | name = "ordermap" | 802 | name = "once_cell" |
806 | version = "0.3.5" | 803 | version = "1.4.0" |
807 | source = "registry+https://github.com/rust-lang/crates.io-index" | 804 | source = "registry+https://github.com/rust-lang/crates.io-index" |
808 | checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" | 805 | checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" |
809 | 806 | ||
810 | [[package]] | 807 | [[package]] |
811 | name = "parking_lot" | 808 | name = "parking_lot" |
@@ -861,12 +858,12 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" | |||
861 | 858 | ||
862 | [[package]] | 859 | [[package]] |
863 | name = "petgraph" | 860 | name = "petgraph" |
864 | version = "0.4.13" | 861 | version = "0.5.0" |
865 | source = "registry+https://github.com/rust-lang/crates.io-index" | 862 | source = "registry+https://github.com/rust-lang/crates.io-index" |
866 | checksum = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" | 863 | checksum = "29c127eea4a29ec6c85d153c59dc1213f33ec74cead30fe4730aecc88cc1fd92" |
867 | dependencies = [ | 864 | dependencies = [ |
868 | "fixedbitset", | 865 | "fixedbitset", |
869 | "ordermap", | 866 | "indexmap", |
870 | ] | 867 | ] |
871 | 868 | ||
872 | [[package]] | 869 | [[package]] |
@@ -883,9 +880,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" | |||
883 | 880 | ||
884 | [[package]] | 881 | [[package]] |
885 | name = "ppv-lite86" | 882 | name = "ppv-lite86" |
886 | version = "0.2.6" | 883 | version = "0.2.8" |
887 | source = "registry+https://github.com/rust-lang/crates.io-index" | 884 | source = "registry+https://github.com/rust-lang/crates.io-index" |
888 | checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" | 885 | checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" |
889 | 886 | ||
890 | [[package]] | 887 | [[package]] |
891 | name = "proc-macro-hack" | 888 | name = "proc-macro-hack" |
@@ -895,18 +892,18 @@ checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" | |||
895 | 892 | ||
896 | [[package]] | 893 | [[package]] |
897 | name = "proc-macro2" | 894 | name = "proc-macro2" |
898 | version = "1.0.12" | 895 | version = "1.0.13" |
899 | source = "registry+https://github.com/rust-lang/crates.io-index" | 896 | source = "registry+https://github.com/rust-lang/crates.io-index" |
900 | checksum = "8872cf6f48eee44265156c111456a700ab3483686b3f96df4cf5481c89157319" | 897 | checksum = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639" |
901 | dependencies = [ | 898 | dependencies = [ |
902 | "unicode-xid", | 899 | "unicode-xid", |
903 | ] | 900 | ] |
904 | 901 | ||
905 | [[package]] | 902 | [[package]] |
906 | name = "quote" | 903 | name = "quote" |
907 | version = "1.0.4" | 904 | version = "1.0.6" |
908 | source = "registry+https://github.com/rust-lang/crates.io-index" | 905 | source = "registry+https://github.com/rust-lang/crates.io-index" |
909 | checksum = "4c1f4b0efa5fc5e8ceb705136bfee52cfdb6a4e3509f770b478cd6ed434232a7" | 906 | checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" |
910 | dependencies = [ | 907 | dependencies = [ |
911 | "proc-macro2", | 908 | "proc-macro2", |
912 | ] | 909 | ] |
@@ -963,10 +960,8 @@ version = "0.1.0" | |||
963 | dependencies = [ | 960 | dependencies = [ |
964 | "cargo_metadata", | 961 | "cargo_metadata", |
965 | "crossbeam-channel", | 962 | "crossbeam-channel", |
966 | "insta", | ||
967 | "jod-thread", | 963 | "jod-thread", |
968 | "log", | 964 | "log", |
969 | "lsp-types", | ||
970 | "ra_toolchain", | 965 | "ra_toolchain", |
971 | "serde_json", | 966 | "serde_json", |
972 | ] | 967 | ] |
@@ -1043,7 +1038,7 @@ dependencies = [ | |||
1043 | "chalk-ir", | 1038 | "chalk-ir", |
1044 | "chalk-rust-ir", | 1039 | "chalk-rust-ir", |
1045 | "chalk-solve", | 1040 | "chalk-solve", |
1046 | "ena 0.14.0", | 1041 | "ena", |
1047 | "insta", | 1042 | "insta", |
1048 | "itertools", | 1043 | "itertools", |
1049 | "log", | 1044 | "log", |
@@ -1369,6 +1364,7 @@ dependencies = [ | |||
1369 | "crossbeam-channel", | 1364 | "crossbeam-channel", |
1370 | "env_logger", | 1365 | "env_logger", |
1371 | "globset", | 1366 | "globset", |
1367 | "insta", | ||
1372 | "itertools", | 1368 | "itertools", |
1373 | "jod-thread", | 1369 | "jod-thread", |
1374 | "log", | 1370 | "log", |
@@ -1402,9 +1398,9 @@ dependencies = [ | |||
1402 | 1398 | ||
1403 | [[package]] | 1399 | [[package]] |
1404 | name = "rustc-ap-rustc_lexer" | 1400 | name = "rustc-ap-rustc_lexer" |
1405 | version = "656.0.0" | 1401 | version = "660.0.0" |
1406 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1407 | checksum = "9cbba98ec46e96a4663197dfa8c0378752de2006e314e5400c0ca74929d6692f" | 1403 | checksum = "30760dbcc7667c9e0da561e980e24867ca7f4526ce060a3d7e6d9dcfeaae88d1" |
1408 | dependencies = [ | 1404 | dependencies = [ |
1409 | "unicode-xid", | 1405 | "unicode-xid", |
1410 | ] | 1406 | ] |
@@ -1487,9 +1483,9 @@ dependencies = [ | |||
1487 | 1483 | ||
1488 | [[package]] | 1484 | [[package]] |
1489 | name = "scroll_derive" | 1485 | name = "scroll_derive" |
1490 | version = "0.10.1" | 1486 | version = "0.10.2" |
1491 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1487 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1492 | checksum = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28" | 1488 | checksum = "e367622f934864ffa1c704ba2b82280aab856e3d8213c84c5720257eb34b15b9" |
1493 | dependencies = [ | 1489 | dependencies = [ |
1494 | "proc-macro2", | 1490 | "proc-macro2", |
1495 | "quote", | 1491 | "quote", |
@@ -1514,18 +1510,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" | |||
1514 | 1510 | ||
1515 | [[package]] | 1511 | [[package]] |
1516 | name = "serde" | 1512 | name = "serde" |
1517 | version = "1.0.107" | 1513 | version = "1.0.110" |
1518 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1514 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1519 | checksum = "eba7550f2cdf88ffc23ab0f1607133486c390a8c0f89b57e589b9654ee15e04d" | 1515 | checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" |
1520 | dependencies = [ | 1516 | dependencies = [ |
1521 | "serde_derive", | 1517 | "serde_derive", |
1522 | ] | 1518 | ] |
1523 | 1519 | ||
1524 | [[package]] | 1520 | [[package]] |
1525 | name = "serde_derive" | 1521 | name = "serde_derive" |
1526 | version = "1.0.107" | 1522 | version = "1.0.110" |
1527 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1523 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1528 | checksum = "10be45e22e5597d4b88afcc71f9d7bfadcd604bf0c78a3ab4582b8d2b37f39f3" | 1524 | checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" |
1529 | dependencies = [ | 1525 | dependencies = [ |
1530 | "proc-macro2", | 1526 | "proc-macro2", |
1531 | "quote", | 1527 | "quote", |
@@ -1534,9 +1530,9 @@ dependencies = [ | |||
1534 | 1530 | ||
1535 | [[package]] | 1531 | [[package]] |
1536 | name = "serde_json" | 1532 | name = "serde_json" |
1537 | version = "1.0.52" | 1533 | version = "1.0.53" |
1538 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1534 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1539 | checksum = "a7894c8ed05b7a3a279aeb79025fdec1d3158080b75b98a08faf2806bb799edd" | 1535 | checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" |
1540 | dependencies = [ | 1536 | dependencies = [ |
1541 | "itoa", | 1537 | "itoa", |
1542 | "ryu", | 1538 | "ryu", |
@@ -1556,9 +1552,9 @@ dependencies = [ | |||
1556 | 1552 | ||
1557 | [[package]] | 1553 | [[package]] |
1558 | name = "serde_yaml" | 1554 | name = "serde_yaml" |
1559 | version = "0.8.11" | 1555 | version = "0.8.12" |
1560 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1556 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1561 | checksum = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" | 1557 | checksum = "16c7a592a1ec97c9c1c68d75b6e537dcbf60c7618e038e7841e00af1d9ccf0c4" |
1562 | dependencies = [ | 1558 | dependencies = [ |
1563 | "dtoa", | 1559 | "dtoa", |
1564 | "linked-hash-map", | 1560 | "linked-hash-map", |
@@ -1599,9 +1595,9 @@ checksum = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" | |||
1599 | 1595 | ||
1600 | [[package]] | 1596 | [[package]] |
1601 | name = "syn" | 1597 | name = "syn" |
1602 | version = "1.0.19" | 1598 | version = "1.0.22" |
1603 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1599 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1604 | checksum = "e8e5aa70697bb26ee62214ae3288465ecec0000f05182f039b477001f08f5ae7" | 1600 | checksum = "1425de3c33b0941002740a420b1a906a350b88d08b82b2c8a01035a3f9447bac" |
1605 | dependencies = [ | 1601 | dependencies = [ |
1606 | "proc-macro2", | 1602 | "proc-macro2", |
1607 | "quote", | 1603 | "quote", |
@@ -1685,9 +1681,9 @@ dependencies = [ | |||
1685 | 1681 | ||
1686 | [[package]] | 1682 | [[package]] |
1687 | name = "threadpool" | 1683 | name = "threadpool" |
1688 | version = "1.8.0" | 1684 | version = "1.8.1" |
1689 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1685 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1690 | checksum = "e8dae184447c15d5a6916d973c642aec485105a13cd238192a6927ae3e077d66" | 1686 | checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" |
1691 | dependencies = [ | 1687 | dependencies = [ |
1692 | "num_cpus", | 1688 | "num_cpus", |
1693 | ] | 1689 | ] |
diff --git a/crates/ra_assists/src/assist_config.rs b/crates/ra_assists/src/assist_config.rs new file mode 100644 index 000000000..c0a0226fb --- /dev/null +++ b/crates/ra_assists/src/assist_config.rs | |||
@@ -0,0 +1,27 @@ | |||
1 | //! Settings for tweaking assists. | ||
2 | //! | ||
3 | //! The fun thing here is `SnippetCap` -- this type can only be created in this | ||
4 | //! module, and we use to statically check that we only produce snippet | ||
5 | //! assists if we are allowed to. | ||
6 | |||
7 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
8 | pub struct AssistConfig { | ||
9 | pub snippet_cap: Option<SnippetCap>, | ||
10 | } | ||
11 | |||
12 | impl AssistConfig { | ||
13 | pub fn allow_snippets(&mut self, yes: bool) { | ||
14 | self.snippet_cap = if yes { Some(SnippetCap { _private: () }) } else { None } | ||
15 | } | ||
16 | } | ||
17 | |||
18 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
19 | pub struct SnippetCap { | ||
20 | _private: (), | ||
21 | } | ||
22 | |||
23 | impl Default for AssistConfig { | ||
24 | fn default() -> Self { | ||
25 | AssistConfig { snippet_cap: Some(SnippetCap { _private: () }) } | ||
26 | } | ||
27 | } | ||
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index a680f752b..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::{ |
@@ -15,7 +15,10 @@ use ra_syntax::{ | |||
15 | }; | 15 | }; |
16 | use ra_text_edit::TextEditBuilder; | 16 | use ra_text_edit::TextEditBuilder; |
17 | 17 | ||
18 | use crate::{Assist, AssistId, GroupLabel, ResolvedAssist}; | 18 | use crate::{ |
19 | assist_config::{AssistConfig, SnippetCap}, | ||
20 | Assist, AssistId, GroupLabel, ResolvedAssist, | ||
21 | }; | ||
19 | 22 | ||
20 | /// `AssistContext` allows to apply an assist or check if it could be applied. | 23 | /// `AssistContext` allows to apply an assist or check if it could be applied. |
21 | /// | 24 | /// |
@@ -48,6 +51,7 @@ use crate::{Assist, AssistId, GroupLabel, ResolvedAssist}; | |||
48 | /// moment, because the LSP API is pretty awkward in this place, and it's much | 51 | /// moment, because the LSP API is pretty awkward in this place, and it's much |
49 | /// easier to just compute the edit eagerly :-) | 52 | /// easier to just compute the edit eagerly :-) |
50 | pub(crate) struct AssistContext<'a> { | 53 | pub(crate) struct AssistContext<'a> { |
54 | pub(crate) config: &'a AssistConfig, | ||
51 | pub(crate) sema: Semantics<'a, RootDatabase>, | 55 | pub(crate) sema: Semantics<'a, RootDatabase>, |
52 | pub(crate) db: &'a RootDatabase, | 56 | pub(crate) db: &'a RootDatabase, |
53 | pub(crate) frange: FileRange, | 57 | pub(crate) frange: FileRange, |
@@ -55,10 +59,14 @@ pub(crate) struct AssistContext<'a> { | |||
55 | } | 59 | } |
56 | 60 | ||
57 | impl<'a> AssistContext<'a> { | 61 | impl<'a> AssistContext<'a> { |
58 | pub fn new(sema: Semantics<'a, RootDatabase>, frange: FileRange) -> AssistContext<'a> { | 62 | pub(crate) fn new( |
63 | sema: Semantics<'a, RootDatabase>, | ||
64 | config: &'a AssistConfig, | ||
65 | frange: FileRange, | ||
66 | ) -> AssistContext<'a> { | ||
59 | let source_file = sema.parse(frange.file_id); | 67 | let source_file = sema.parse(frange.file_id); |
60 | let db = sema.db; | 68 | let db = sema.db; |
61 | AssistContext { sema, db, frange, source_file } | 69 | AssistContext { config, sema, db, frange, source_file } |
62 | } | 70 | } |
63 | 71 | ||
64 | // NB, this ignores active selection. | 72 | // NB, this ignores active selection. |
@@ -142,11 +150,10 @@ impl Assists { | |||
142 | self.add_impl(label, f) | 150 | self.add_impl(label, f) |
143 | } | 151 | } |
144 | 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<()> { |
145 | let change_label = label.label.clone(); | ||
146 | let source_change = if self.resolve { | 153 | let source_change = if self.resolve { |
147 | let mut builder = AssistBuilder::new(self.file); | 154 | let mut builder = AssistBuilder::new(self.file); |
148 | f(&mut builder); | 155 | f(&mut builder); |
149 | Some(builder.finish(change_label)) | 156 | Some(builder.finish()) |
150 | } else { | 157 | } else { |
151 | None | 158 | None |
152 | }; | 159 | }; |
@@ -163,13 +170,13 @@ impl Assists { | |||
163 | 170 | ||
164 | pub(crate) struct AssistBuilder { | 171 | pub(crate) struct AssistBuilder { |
165 | edit: TextEditBuilder, | 172 | edit: TextEditBuilder, |
166 | cursor_position: Option<TextSize>, | ||
167 | file: FileId, | 173 | file: FileId, |
174 | is_snippet: bool, | ||
168 | } | 175 | } |
169 | 176 | ||
170 | impl AssistBuilder { | 177 | impl AssistBuilder { |
171 | pub(crate) fn new(file: FileId) -> AssistBuilder { | 178 | pub(crate) fn new(file: FileId) -> AssistBuilder { |
172 | AssistBuilder { edit: TextEditBuilder::default(), cursor_position: None, file } | 179 | AssistBuilder { edit: TextEditBuilder::default(), file, is_snippet: false } |
173 | } | 180 | } |
174 | 181 | ||
175 | /// Remove specified `range` of text. | 182 | /// Remove specified `range` of text. |
@@ -180,10 +187,30 @@ impl AssistBuilder { | |||
180 | pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) { | 187 | pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) { |
181 | self.edit.insert(offset, text.into()) | 188 | self.edit.insert(offset, text.into()) |
182 | } | 189 | } |
190 | /// Append specified `snippet` at the given `offset` | ||
191 | pub(crate) fn insert_snippet( | ||
192 | &mut self, | ||
193 | _cap: SnippetCap, | ||
194 | offset: TextSize, | ||
195 | snippet: impl Into<String>, | ||
196 | ) { | ||
197 | self.is_snippet = true; | ||
198 | self.insert(offset, snippet); | ||
199 | } | ||
183 | /// Replaces specified `range` of text with a given string. | 200 | /// Replaces specified `range` of text with a given string. |
184 | pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { | 201 | pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { |
185 | self.edit.replace(range, replace_with.into()) | 202 | self.edit.replace(range, replace_with.into()) |
186 | } | 203 | } |
204 | /// Replaces specified `range` of text with a given `snippet`. | ||
205 | pub(crate) fn replace_snippet( | ||
206 | &mut self, | ||
207 | _cap: SnippetCap, | ||
208 | range: TextRange, | ||
209 | snippet: impl Into<String>, | ||
210 | ) { | ||
211 | self.is_snippet = true; | ||
212 | self.replace(range, snippet); | ||
213 | } | ||
187 | pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { | 214 | pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { |
188 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) | 215 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) |
189 | } | 216 | } |
@@ -207,10 +234,6 @@ impl AssistBuilder { | |||
207 | algo::diff(&node, &new).into_text_edit(&mut self.edit) | 234 | algo::diff(&node, &new).into_text_edit(&mut self.edit) |
208 | } | 235 | } |
209 | 236 | ||
210 | /// Specify desired position of the cursor after the assist is applied. | ||
211 | pub(crate) fn set_cursor(&mut self, offset: TextSize) { | ||
212 | self.cursor_position = Some(offset) | ||
213 | } | ||
214 | // FIXME: better API | 237 | // FIXME: better API |
215 | pub(crate) fn set_file(&mut self, assist_file: FileId) { | 238 | pub(crate) fn set_file(&mut self, assist_file: FileId) { |
216 | self.file = assist_file; | 239 | self.file = assist_file; |
@@ -222,12 +245,13 @@ impl AssistBuilder { | |||
222 | &mut self.edit | 245 | &mut self.edit |
223 | } | 246 | } |
224 | 247 | ||
225 | fn finish(self, change_label: String) -> SourceChange { | 248 | fn finish(self) -> SourceChange { |
226 | let edit = self.edit.finish(); | 249 | let edit = self.edit.finish(); |
227 | if edit.is_empty() && self.cursor_position.is_none() { | 250 | let source_file_edit = SourceFileEdit { file_id: self.file, edit }; |
228 | panic!("Only call `add_assist` if the assist can be applied") | 251 | let mut res: SourceChange = source_file_edit.into(); |
252 | if self.is_snippet { | ||
253 | res.is_snippet = true; | ||
229 | } | 254 | } |
230 | SingleFileChange { label: change_label, edit, cursor_position: self.cursor_position } | 255 | res |
231 | .into_source_change(self.file) | ||
232 | } | 256 | } |
233 | } | 257 | } |
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 9ac65ab39..3079a02a2 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined. | 1 | //! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined. |
2 | use rustc_hash::FxHashMap; | 2 | use rustc_hash::FxHashMap; |
3 | 3 | ||
4 | use hir::{PathResolution, SemanticsScope}; | 4 | use hir::{HirDisplay, PathResolution, SemanticsScope}; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
7 | algo::SyntaxRewriter, | 7 | algo::SyntaxRewriter, |
@@ -51,7 +51,27 @@ impl<'a> SubstituteTypeParams<'a> { | |||
51 | .into_iter() | 51 | .into_iter() |
52 | // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky | 52 | // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky |
53 | .skip(1) | 53 | .skip(1) |
54 | .zip(substs.into_iter()) | 54 | // The actual list of trait type parameters may be longer than the one |
55 | // used in the `impl` block due to trailing default type parametrs. | ||
56 | // For that case we extend the `substs` with an empty iterator so we | ||
57 | // can still hit those trailing values and check if they actually have | ||
58 | // a default type. If they do, go for that type from `hir` to `ast` so | ||
59 | // the resulting change can be applied correctly. | ||
60 | .zip(substs.into_iter().map(Some).chain(std::iter::repeat(None))) | ||
61 | .filter_map(|(k, v)| match v { | ||
62 | Some(v) => Some((k, v)), | ||
63 | None => { | ||
64 | let default = k.default(source_scope.db)?; | ||
65 | Some(( | ||
66 | k, | ||
67 | ast::make::type_ref( | ||
68 | &default | ||
69 | .display_source_code(source_scope.db, source_scope.module()?.into()) | ||
70 | .ok()?, | ||
71 | ), | ||
72 | )) | ||
73 | } | ||
74 | }) | ||
55 | .collect(); | 75 | .collect(); |
56 | return SubstituteTypeParams { | 76 | return SubstituteTypeParams { |
57 | source_scope, | 77 | source_scope, |
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs index 795a225a4..fa70c8496 100644 --- a/crates/ra_assists/src/handlers/add_custom_impl.rs +++ b/crates/ra_assists/src/handlers/add_custom_impl.rs | |||
@@ -25,7 +25,7 @@ use crate::{ | |||
25 | // struct S; | 25 | // struct S; |
26 | // | 26 | // |
27 | // impl Debug for S { | 27 | // impl Debug for S { |
28 | // | 28 | // $0 |
29 | // } | 29 | // } |
30 | // ``` | 30 | // ``` |
31 | pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 31 | pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
@@ -49,10 +49,10 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
49 | let start_offset = annotated.syntax().parent()?.text_range().end(); | 49 | let start_offset = annotated.syntax().parent()?.text_range().end(); |
50 | 50 | ||
51 | let label = | 51 | let label = |
52 | format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name); | 52 | format!("Add custom impl `{}` for `{}`", trait_token.text().as_str(), annotated_name); |
53 | 53 | ||
54 | let target = attr.syntax().text_range(); | 54 | let target = attr.syntax().text_range(); |
55 | acc.add(AssistId("add_custom_impl"), label, target, |edit| { | 55 | acc.add(AssistId("add_custom_impl"), label, target, |builder| { |
56 | let new_attr_input = input | 56 | let new_attr_input = input |
57 | .syntax() | 57 | .syntax() |
58 | .descendants_with_tokens() | 58 | .descendants_with_tokens() |
@@ -63,20 +63,11 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
63 | let has_more_derives = !new_attr_input.is_empty(); | 63 | let has_more_derives = !new_attr_input.is_empty(); |
64 | let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string(); | 64 | let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string(); |
65 | 65 | ||
66 | let mut buf = String::new(); | 66 | if has_more_derives { |
67 | buf.push_str("\n\nimpl "); | 67 | builder.replace(input.syntax().text_range(), new_attr_input); |
68 | buf.push_str(trait_token.text().as_str()); | ||
69 | buf.push_str(" for "); | ||
70 | buf.push_str(annotated_name.as_str()); | ||
71 | buf.push_str(" {\n"); | ||
72 | |||
73 | let cursor_delta = if has_more_derives { | ||
74 | let delta = input.syntax().text_range().len() - TextSize::of(&new_attr_input); | ||
75 | edit.replace(input.syntax().text_range(), new_attr_input); | ||
76 | delta | ||
77 | } else { | 68 | } else { |
78 | let attr_range = attr.syntax().text_range(); | 69 | let attr_range = attr.syntax().text_range(); |
79 | edit.delete(attr_range); | 70 | builder.delete(attr_range); |
80 | 71 | ||
81 | let line_break_range = attr | 72 | let line_break_range = attr |
82 | .syntax() | 73 | .syntax() |
@@ -84,14 +75,24 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
84 | .filter(|t| t.kind() == WHITESPACE) | 75 | .filter(|t| t.kind() == WHITESPACE) |
85 | .map(|t| t.text_range()) | 76 | .map(|t| t.text_range()) |
86 | .unwrap_or_else(|| TextRange::new(TextSize::from(0), TextSize::from(0))); | 77 | .unwrap_or_else(|| TextRange::new(TextSize::from(0), TextSize::from(0))); |
87 | edit.delete(line_break_range); | 78 | builder.delete(line_break_range); |
88 | 79 | } | |
89 | attr_range.len() + line_break_range.len() | 80 | |
90 | }; | 81 | match ctx.config.snippet_cap { |
91 | 82 | Some(cap) => { | |
92 | edit.set_cursor(start_offset + TextSize::of(&buf) - cursor_delta); | 83 | builder.insert_snippet( |
93 | buf.push_str("\n}"); | 84 | cap, |
94 | edit.insert(start_offset, buf); | 85 | start_offset, |
86 | format!("\n\nimpl {} for {} {{\n $0\n}}", trait_token, annotated_name), | ||
87 | ); | ||
88 | } | ||
89 | None => { | ||
90 | builder.insert( | ||
91 | start_offset, | ||
92 | format!("\n\nimpl {} for {} {{\n\n}}", trait_token, annotated_name), | ||
93 | ); | ||
94 | } | ||
95 | } | ||
95 | }) | 96 | }) |
96 | } | 97 | } |
97 | 98 | ||
@@ -117,7 +118,7 @@ struct Foo { | |||
117 | } | 118 | } |
118 | 119 | ||
119 | impl Debug for Foo { | 120 | impl Debug for Foo { |
120 | <|> | 121 | $0 |
121 | } | 122 | } |
122 | ", | 123 | ", |
123 | ) | 124 | ) |
@@ -139,7 +140,7 @@ pub struct Foo { | |||
139 | } | 140 | } |
140 | 141 | ||
141 | impl Debug for Foo { | 142 | impl Debug for Foo { |
142 | <|> | 143 | $0 |
143 | } | 144 | } |
144 | ", | 145 | ", |
145 | ) | 146 | ) |
@@ -158,7 +159,7 @@ struct Foo {} | |||
158 | struct Foo {} | 159 | struct Foo {} |
159 | 160 | ||
160 | impl Debug for Foo { | 161 | impl Debug for Foo { |
161 | <|> | 162 | $0 |
162 | } | 163 | } |
163 | ", | 164 | ", |
164 | ) | 165 | ) |
diff --git a/crates/ra_assists/src/handlers/add_derive.rs b/crates/ra_assists/src/handlers/add_derive.rs index fb08c19e9..b123b8498 100644 --- a/crates/ra_assists/src/handlers/add_derive.rs +++ b/crates/ra_assists/src/handlers/add_derive.rs | |||
@@ -18,31 +18,37 @@ use crate::{AssistContext, AssistId, Assists}; | |||
18 | // ``` | 18 | // ``` |
19 | // -> | 19 | // -> |
20 | // ``` | 20 | // ``` |
21 | // #[derive()] | 21 | // #[derive($0)] |
22 | // struct Point { | 22 | // struct Point { |
23 | // x: u32, | 23 | // x: u32, |
24 | // y: u32, | 24 | // y: u32, |
25 | // } | 25 | // } |
26 | // ``` | 26 | // ``` |
27 | pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 27 | pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
28 | let cap = ctx.config.snippet_cap?; | ||
28 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; | 29 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; |
29 | let node_start = derive_insertion_offset(&nominal)?; | 30 | let node_start = derive_insertion_offset(&nominal)?; |
30 | let target = nominal.syntax().text_range(); | 31 | let target = nominal.syntax().text_range(); |
31 | acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |edit| { | 32 | acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |builder| { |
32 | let derive_attr = nominal | 33 | let derive_attr = nominal |
33 | .attrs() | 34 | .attrs() |
34 | .filter_map(|x| x.as_simple_call()) | 35 | .filter_map(|x| x.as_simple_call()) |
35 | .filter(|(name, _arg)| name == "derive") | 36 | .filter(|(name, _arg)| name == "derive") |
36 | .map(|(_name, arg)| arg) | 37 | .map(|(_name, arg)| arg) |
37 | .next(); | 38 | .next(); |
38 | let offset = match derive_attr { | 39 | match derive_attr { |
39 | None => { | 40 | None => { |
40 | edit.insert(node_start, "#[derive()]\n"); | 41 | builder.insert_snippet(cap, node_start, "#[derive($0)]\n"); |
41 | node_start + TextSize::of("#[derive(") | 42 | } |
43 | Some(tt) => { | ||
44 | // Just move the cursor. | ||
45 | builder.insert_snippet( | ||
46 | cap, | ||
47 | tt.syntax().text_range().end() - TextSize::of(')'), | ||
48 | "$0", | ||
49 | ) | ||
42 | } | 50 | } |
43 | Some(tt) => tt.syntax().text_range().end() - TextSize::of(')'), | ||
44 | }; | 51 | }; |
45 | edit.set_cursor(offset) | ||
46 | }) | 52 | }) |
47 | } | 53 | } |
48 | 54 | ||
@@ -66,12 +72,12 @@ mod tests { | |||
66 | check_assist( | 72 | check_assist( |
67 | add_derive, | 73 | add_derive, |
68 | "struct Foo { a: i32, <|>}", | 74 | "struct Foo { a: i32, <|>}", |
69 | "#[derive(<|>)]\nstruct Foo { a: i32, }", | 75 | "#[derive($0)]\nstruct Foo { a: i32, }", |
70 | ); | 76 | ); |
71 | check_assist( | 77 | check_assist( |
72 | add_derive, | 78 | add_derive, |
73 | "struct Foo { <|> a: i32, }", | 79 | "struct Foo { <|> a: i32, }", |
74 | "#[derive(<|>)]\nstruct Foo { a: i32, }", | 80 | "#[derive($0)]\nstruct Foo { a: i32, }", |
75 | ); | 81 | ); |
76 | } | 82 | } |
77 | 83 | ||
@@ -80,7 +86,7 @@ mod tests { | |||
80 | check_assist( | 86 | check_assist( |
81 | add_derive, | 87 | add_derive, |
82 | "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", | 88 | "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", |
83 | "#[derive(Clone<|>)]\nstruct Foo { a: i32, }", | 89 | "#[derive(Clone$0)]\nstruct Foo { a: i32, }", |
84 | ); | 90 | ); |
85 | } | 91 | } |
86 | 92 | ||
@@ -96,7 +102,7 @@ struct Foo { a: i32<|>, } | |||
96 | " | 102 | " |
97 | /// `Foo` is a pretty important struct. | 103 | /// `Foo` is a pretty important struct. |
98 | /// It does stuff. | 104 | /// It does stuff. |
99 | #[derive(<|>)] | 105 | #[derive($0)] |
100 | struct Foo { a: i32, } | 106 | struct Foo { a: i32, } |
101 | ", | 107 | ", |
102 | ); | 108 | ); |
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index 7ced00626..ab20c6649 100644 --- a/crates/ra_assists/src/handlers/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs | |||
@@ -25,9 +25,8 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
25 | let stmt = ctx.find_node_at_offset::<LetStmt>()?; | 25 | let stmt = ctx.find_node_at_offset::<LetStmt>()?; |
26 | let module = ctx.sema.scope(stmt.syntax()).module()?; | 26 | let module = ctx.sema.scope(stmt.syntax()).module()?; |
27 | let expr = stmt.initializer()?; | 27 | let expr = stmt.initializer()?; |
28 | let pat = stmt.pat()?; | ||
29 | // Must be a binding | 28 | // Must be a binding |
30 | let pat = match pat { | 29 | let pat = match stmt.pat()? { |
31 | ast::Pat::BindPat(bind_pat) => bind_pat, | 30 | ast::Pat::BindPat(bind_pat) => bind_pat, |
32 | _ => return None, | 31 | _ => return None, |
33 | }; | 32 | }; |
@@ -46,7 +45,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
46 | // Assist not applicable if the type has already been specified | 45 | // Assist not applicable if the type has already been specified |
47 | // and it has no placeholders | 46 | // and it has no placeholders |
48 | let ascribed_ty = stmt.ascribed_type(); | 47 | let ascribed_ty = stmt.ascribed_type(); |
49 | if let Some(ref ty) = ascribed_ty { | 48 | if let Some(ty) = &ascribed_ty { |
50 | if ty.syntax().descendants().find_map(ast::PlaceholderType::cast).is_none() { | 49 | if ty.syntax().descendants().find_map(ast::PlaceholderType::cast).is_none() { |
51 | return None; | 50 | return None; |
52 | } | 51 | } |
@@ -61,7 +60,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
61 | let inferred_type = ty.display_source_code(ctx.db, module.into()).ok()?; | 60 | let inferred_type = ty.display_source_code(ctx.db, module.into()).ok()?; |
62 | acc.add( | 61 | acc.add( |
63 | AssistId("add_explicit_type"), | 62 | AssistId("add_explicit_type"), |
64 | format!("Insert explicit type '{}'", inferred_type), | 63 | format!("Insert explicit type `{}`", inferred_type), |
65 | pat_range, | 64 | pat_range, |
66 | |builder| match ascribed_ty { | 65 | |builder| match ascribed_ty { |
67 | Some(ascribed_ty) => { | 66 | Some(ascribed_ty) => { |
@@ -87,11 +86,7 @@ mod tests { | |||
87 | 86 | ||
88 | #[test] | 87 | #[test] |
89 | fn add_explicit_type_works_for_simple_expr() { | 88 | fn add_explicit_type_works_for_simple_expr() { |
90 | check_assist( | 89 | check_assist(add_explicit_type, "fn f() { let a<|> = 1; }", "fn f() { let a: i32 = 1; }"); |
91 | add_explicit_type, | ||
92 | "fn f() { let a<|> = 1; }", | ||
93 | "fn f() { let a<|>: i32 = 1; }", | ||
94 | ); | ||
95 | } | 90 | } |
96 | 91 | ||
97 | #[test] | 92 | #[test] |
@@ -99,7 +94,7 @@ mod tests { | |||
99 | check_assist( | 94 | check_assist( |
100 | add_explicit_type, | 95 | add_explicit_type, |
101 | "fn f() { let a<|>: _ = 1; }", | 96 | "fn f() { let a<|>: _ = 1; }", |
102 | "fn f() { let a<|>: i32 = 1; }", | 97 | "fn f() { let a: i32 = 1; }", |
103 | ); | 98 | ); |
104 | } | 99 | } |
105 | 100 | ||
@@ -123,7 +118,7 @@ mod tests { | |||
123 | } | 118 | } |
124 | 119 | ||
125 | fn f() { | 120 | fn f() { |
126 | let a<|>: Option<i32> = Option::Some(1); | 121 | let a: Option<i32> = Option::Some(1); |
127 | }"#, | 122 | }"#, |
128 | ); | 123 | ); |
129 | } | 124 | } |
@@ -133,7 +128,7 @@ mod tests { | |||
133 | check_assist( | 128 | check_assist( |
134 | add_explicit_type, | 129 | add_explicit_type, |
135 | r"macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }", | 130 | r"macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }", |
136 | r"macro_rules! v { () => {0u64} } fn f() { let a<|>: u64 = v!(); }", | 131 | r"macro_rules! v { () => {0u64} } fn f() { let a: u64 = v!(); }", |
137 | ); | 132 | ); |
138 | } | 133 | } |
139 | 134 | ||
@@ -141,8 +136,8 @@ mod tests { | |||
141 | fn add_explicit_type_works_for_macro_call_recursive() { | 136 | fn add_explicit_type_works_for_macro_call_recursive() { |
142 | check_assist( | 137 | check_assist( |
143 | add_explicit_type, | 138 | add_explicit_type, |
144 | "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!(); }"#, |
145 | "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!(); }"#, |
146 | ); | 141 | ); |
147 | } | 142 | } |
148 | 143 | ||
@@ -209,7 +204,7 @@ struct Test<K, T = u8> { | |||
209 | } | 204 | } |
210 | 205 | ||
211 | fn main() { | 206 | fn main() { |
212 | let test<|>: Test<i32> = Test { t: 23, k: 33 }; | 207 | let test: Test<i32> = Test { t: 23, k: 33 }; |
213 | }"#, | 208 | }"#, |
214 | ); | 209 | ); |
215 | } | 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 6a49b7dbd..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 | |||
@@ -1,7 +1,6 @@ | |||
1 | use ra_ide_db::RootDatabase; | 1 | use ra_ide_db::RootDatabase; |
2 | use ra_syntax::ast::{self, AstNode, NameOwner}; | 2 | use ra_syntax::ast::{self, AstNode, NameOwner}; |
3 | use stdx::format_to; | 3 | use test_utils::mark; |
4 | use test_utils::tested_by; | ||
5 | 4 | ||
6 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; | 5 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; |
7 | 6 | ||
@@ -35,12 +34,12 @@ pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> | |||
35 | } | 34 | } |
36 | let field_type = field_list.fields().next()?.type_ref()?; | 35 | let field_type = field_list.fields().next()?.type_ref()?; |
37 | let path = match field_type { | 36 | let path = match field_type { |
38 | ast::TypeRef::PathType(p) => p, | 37 | ast::TypeRef::PathType(it) => it, |
39 | _ => return None, | 38 | _ => return None, |
40 | }; | 39 | }; |
41 | 40 | ||
42 | if existing_from_impl(&ctx.sema, &variant).is_some() { | 41 | if existing_from_impl(&ctx.sema, &variant).is_some() { |
43 | tested_by!(test_add_from_impl_already_exists); | 42 | mark::hit!(test_add_from_impl_already_exists); |
44 | return None; | 43 | return None; |
45 | } | 44 | } |
46 | 45 | ||
@@ -51,9 +50,7 @@ pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> | |||
51 | target, | 50 | target, |
52 | |edit| { | 51 | |edit| { |
53 | let start_offset = variant.parent_enum().syntax().text_range().end(); | 52 | let start_offset = variant.parent_enum().syntax().text_range().end(); |
54 | let mut buf = String::new(); | 53 | let buf = format!( |
55 | format_to!( | ||
56 | buf, | ||
57 | r#" | 54 | r#" |
58 | 55 | ||
59 | impl From<{0}> for {1} {{ | 56 | impl From<{0}> for {1} {{ |
@@ -93,7 +90,7 @@ fn existing_from_impl( | |||
93 | 90 | ||
94 | #[cfg(test)] | 91 | #[cfg(test)] |
95 | mod tests { | 92 | mod tests { |
96 | use test_utils::covers; | 93 | use test_utils::mark; |
97 | 94 | ||
98 | use crate::tests::{check_assist, check_assist_not_applicable}; | 95 | use crate::tests::{check_assist, check_assist_not_applicable}; |
99 | 96 | ||
@@ -104,7 +101,7 @@ mod tests { | |||
104 | check_assist( | 101 | check_assist( |
105 | add_from_impl_for_enum, | 102 | add_from_impl_for_enum, |
106 | "enum A { <|>One(u32) }", | 103 | "enum A { <|>One(u32) }", |
107 | r#"enum A { <|>One(u32) } | 104 | r#"enum A { One(u32) } |
108 | 105 | ||
109 | impl From<u32> for A { | 106 | impl From<u32> for A { |
110 | fn from(v: u32) -> Self { | 107 | fn from(v: u32) -> Self { |
@@ -119,7 +116,7 @@ impl From<u32> for A { | |||
119 | check_assist( | 116 | check_assist( |
120 | add_from_impl_for_enum, | 117 | add_from_impl_for_enum, |
121 | r#"enum A { <|>One(foo::bar::baz::Boo) }"#, | 118 | r#"enum A { <|>One(foo::bar::baz::Boo) }"#, |
122 | r#"enum A { <|>One(foo::bar::baz::Boo) } | 119 | r#"enum A { One(foo::bar::baz::Boo) } |
123 | 120 | ||
124 | impl From<foo::bar::baz::Boo> for A { | 121 | impl From<foo::bar::baz::Boo> for A { |
125 | fn from(v: foo::bar::baz::Boo) -> Self { | 122 | fn from(v: foo::bar::baz::Boo) -> Self { |
@@ -152,7 +149,7 @@ impl From<foo::bar::baz::Boo> for A { | |||
152 | 149 | ||
153 | #[test] | 150 | #[test] |
154 | fn test_add_from_impl_already_exists() { | 151 | fn test_add_from_impl_already_exists() { |
155 | covers!(test_add_from_impl_already_exists); | 152 | mark::check!(test_add_from_impl_already_exists); |
156 | check_not_applicable( | 153 | check_not_applicable( |
157 | r#" | 154 | r#" |
158 | enum A { <|>One(u32), } | 155 | enum A { <|>One(u32), } |
@@ -181,7 +178,7 @@ impl From<String> for A { | |||
181 | pub trait From<T> { | 178 | pub trait From<T> { |
182 | fn from(T) -> Self; | 179 | fn from(T) -> Self; |
183 | }"#, | 180 | }"#, |
184 | r#"enum A { <|>One(u32), Two(String), } | 181 | r#"enum A { One(u32), Two(String), } |
185 | 182 | ||
186 | impl From<u32> for A { | 183 | impl From<u32> for A { |
187 | fn from(v: u32) -> Self { | 184 | fn from(v: u32) -> Self { |
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs index de016ae4e..24f931a85 100644 --- a/crates/ra_assists/src/handlers/add_function.rs +++ b/crates/ra_assists/src/handlers/add_function.rs | |||
@@ -4,13 +4,17 @@ use ra_syntax::{ | |||
4 | ast::{ | 4 | ast::{ |
5 | self, | 5 | self, |
6 | edit::{AstNodeEdit, IndentLevel}, | 6 | edit::{AstNodeEdit, IndentLevel}, |
7 | ArgListOwner, AstNode, ModuleItemOwner, | 7 | make, ArgListOwner, AstNode, ModuleItemOwner, |
8 | }, | 8 | }, |
9 | SyntaxKind, SyntaxNode, TextSize, | 9 | SyntaxKind, SyntaxNode, TextSize, |
10 | }; | 10 | }; |
11 | use rustc_hash::{FxHashMap, FxHashSet}; | 11 | use rustc_hash::{FxHashMap, FxHashSet}; |
12 | 12 | ||
13 | use crate::{AssistContext, AssistId, Assists}; | 13 | use crate::{ |
14 | assist_config::SnippetCap, | ||
15 | utils::{render_snippet, Cursor}, | ||
16 | AssistContext, AssistId, Assists, | ||
17 | }; | ||
14 | 18 | ||
15 | // Assist: add_function | 19 | // Assist: add_function |
16 | // | 20 | // |
@@ -33,7 +37,7 @@ use crate::{AssistContext, AssistId, Assists}; | |||
33 | // } | 37 | // } |
34 | // | 38 | // |
35 | // fn bar(arg: &str, baz: Baz) { | 39 | // fn bar(arg: &str, baz: Baz) { |
36 | // todo!() | 40 | // ${0:todo!()} |
37 | // } | 41 | // } |
38 | // | 42 | // |
39 | // ``` | 43 | // ``` |
@@ -58,21 +62,40 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
58 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; | 62 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; |
59 | 63 | ||
60 | let target = call.syntax().text_range(); | 64 | let target = call.syntax().text_range(); |
61 | acc.add(AssistId("add_function"), "Add function", target, |edit| { | 65 | acc.add(AssistId("add_function"), "Add function", target, |builder| { |
62 | let function_template = function_builder.render(); | 66 | let function_template = function_builder.render(); |
63 | edit.set_file(function_template.file); | 67 | builder.set_file(function_template.file); |
64 | edit.set_cursor(function_template.cursor_offset); | 68 | let new_fn = function_template.to_string(ctx.config.snippet_cap); |
65 | edit.insert(function_template.insert_offset, function_template.fn_def.to_string()); | 69 | match ctx.config.snippet_cap { |
70 | Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn), | ||
71 | None => builder.insert(function_template.insert_offset, new_fn), | ||
72 | } | ||
66 | }) | 73 | }) |
67 | } | 74 | } |
68 | 75 | ||
69 | struct FunctionTemplate { | 76 | struct FunctionTemplate { |
70 | insert_offset: TextSize, | 77 | insert_offset: TextSize, |
71 | cursor_offset: TextSize, | 78 | placeholder_expr: ast::MacroCall, |
72 | fn_def: ast::SourceFile, | 79 | leading_ws: String, |
80 | fn_def: ast::FnDef, | ||
81 | trailing_ws: String, | ||
73 | file: FileId, | 82 | file: FileId, |
74 | } | 83 | } |
75 | 84 | ||
85 | impl FunctionTemplate { | ||
86 | fn to_string(&self, cap: Option<SnippetCap>) -> String { | ||
87 | let f = match cap { | ||
88 | Some(cap) => render_snippet( | ||
89 | cap, | ||
90 | self.fn_def.syntax(), | ||
91 | Cursor::Replace(self.placeholder_expr.syntax()), | ||
92 | ), | ||
93 | None => self.fn_def.to_string(), | ||
94 | }; | ||
95 | format!("{}{}{}", self.leading_ws, f, self.trailing_ws) | ||
96 | } | ||
97 | } | ||
98 | |||
76 | struct FunctionBuilder { | 99 | struct FunctionBuilder { |
77 | target: GeneratedFunctionTarget, | 100 | target: GeneratedFunctionTarget, |
78 | fn_name: ast::Name, | 101 | fn_name: ast::Name, |
@@ -110,35 +133,41 @@ impl FunctionBuilder { | |||
110 | } | 133 | } |
111 | 134 | ||
112 | fn render(self) -> FunctionTemplate { | 135 | fn render(self) -> FunctionTemplate { |
113 | let placeholder_expr = ast::make::expr_todo(); | 136 | let placeholder_expr = make::expr_todo(); |
114 | let fn_body = ast::make::block_expr(vec![], Some(placeholder_expr)); | 137 | let fn_body = make::block_expr(vec![], Some(placeholder_expr)); |
115 | let mut fn_def = ast::make::fn_def(self.fn_name, self.type_params, self.params, fn_body); | 138 | let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None }; |
116 | if self.needs_pub { | 139 | let mut fn_def = |
117 | fn_def = ast::make::add_pub_crate_modifier(fn_def); | 140 | make::fn_def(visibility, self.fn_name, self.type_params, self.params, fn_body); |
118 | } | 141 | let leading_ws; |
119 | 142 | let trailing_ws; | |
120 | let (fn_def, insert_offset) = match self.target { | 143 | |
144 | let insert_offset = match self.target { | ||
121 | GeneratedFunctionTarget::BehindItem(it) => { | 145 | GeneratedFunctionTarget::BehindItem(it) => { |
122 | let with_leading_blank_line = ast::make::add_leading_newlines(2, fn_def); | 146 | let indent = IndentLevel::from_node(&it); |
123 | let indented = with_leading_blank_line.indent(IndentLevel::from_node(&it)); | 147 | leading_ws = format!("\n\n{}", indent); |
124 | (indented, it.text_range().end()) | 148 | fn_def = fn_def.indent(indent); |
149 | trailing_ws = String::new(); | ||
150 | it.text_range().end() | ||
125 | } | 151 | } |
126 | GeneratedFunctionTarget::InEmptyItemList(it) => { | 152 | GeneratedFunctionTarget::InEmptyItemList(it) => { |
127 | let indent_once = IndentLevel(1); | ||
128 | let indent = IndentLevel::from_node(it.syntax()); | 153 | let indent = IndentLevel::from_node(it.syntax()); |
129 | let fn_def = ast::make::add_leading_newlines(1, fn_def); | 154 | leading_ws = format!("\n{}", indent + 1); |
130 | let fn_def = fn_def.indent(indent_once); | 155 | fn_def = fn_def.indent(indent + 1); |
131 | let fn_def = ast::make::add_trailing_newlines(1, fn_def); | 156 | trailing_ws = format!("\n{}", indent); |
132 | let fn_def = fn_def.indent(indent); | 157 | it.syntax().text_range().start() + TextSize::of('{') |
133 | (fn_def, it.syntax().text_range().start() + TextSize::of('{')) | ||
134 | } | 158 | } |
135 | }; | 159 | }; |
136 | 160 | ||
137 | let placeholder_expr = | 161 | let placeholder_expr = |
138 | fn_def.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | 162 | fn_def.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); |
139 | let cursor_offset_from_fn_start = placeholder_expr.syntax().text_range().start(); | 163 | FunctionTemplate { |
140 | let cursor_offset = insert_offset + cursor_offset_from_fn_start; | 164 | insert_offset, |
141 | FunctionTemplate { insert_offset, cursor_offset, fn_def, file: self.file } | 165 | placeholder_expr, |
166 | leading_ws, | ||
167 | fn_def, | ||
168 | trailing_ws, | ||
169 | file: self.file, | ||
170 | } | ||
142 | } | 171 | } |
143 | } | 172 | } |
144 | 173 | ||
@@ -158,7 +187,7 @@ impl GeneratedFunctionTarget { | |||
158 | 187 | ||
159 | fn fn_name(call: &ast::Path) -> Option<ast::Name> { | 188 | fn fn_name(call: &ast::Path) -> Option<ast::Name> { |
160 | let name = call.segment()?.syntax().to_string(); | 189 | let name = call.segment()?.syntax().to_string(); |
161 | Some(ast::make::name(&name)) | 190 | Some(make::name(&name)) |
162 | } | 191 | } |
163 | 192 | ||
164 | /// Computes the type variables and arguments required for the generated function | 193 | /// Computes the type variables and arguments required for the generated function |
@@ -180,8 +209,8 @@ fn fn_args( | |||
180 | }); | 209 | }); |
181 | } | 210 | } |
182 | deduplicate_arg_names(&mut arg_names); | 211 | deduplicate_arg_names(&mut arg_names); |
183 | let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| ast::make::param(name, ty)); | 212 | let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| make::param(name, ty)); |
184 | Some((None, ast::make::param_list(params))) | 213 | Some((None, make::param_list(params))) |
185 | } | 214 | } |
186 | 215 | ||
187 | /// Makes duplicate argument names unique by appending incrementing numbers. | 216 | /// Makes duplicate argument names unique by appending incrementing numbers. |
@@ -316,7 +345,7 @@ fn foo() { | |||
316 | } | 345 | } |
317 | 346 | ||
318 | fn bar() { | 347 | fn bar() { |
319 | <|>todo!() | 348 | ${0:todo!()} |
320 | } | 349 | } |
321 | ", | 350 | ", |
322 | ) | 351 | ) |
@@ -343,7 +372,7 @@ impl Foo { | |||
343 | } | 372 | } |
344 | 373 | ||
345 | fn bar() { | 374 | fn bar() { |
346 | <|>todo!() | 375 | ${0:todo!()} |
347 | } | 376 | } |
348 | ", | 377 | ", |
349 | ) | 378 | ) |
@@ -367,7 +396,7 @@ fn foo1() { | |||
367 | } | 396 | } |
368 | 397 | ||
369 | fn bar() { | 398 | fn bar() { |
370 | <|>todo!() | 399 | ${0:todo!()} |
371 | } | 400 | } |
372 | 401 | ||
373 | fn foo2() {} | 402 | fn foo2() {} |
@@ -393,7 +422,7 @@ mod baz { | |||
393 | } | 422 | } |
394 | 423 | ||
395 | fn bar() { | 424 | fn bar() { |
396 | <|>todo!() | 425 | ${0:todo!()} |
397 | } | 426 | } |
398 | } | 427 | } |
399 | ", | 428 | ", |
@@ -419,7 +448,7 @@ fn foo() { | |||
419 | } | 448 | } |
420 | 449 | ||
421 | fn bar(baz: Baz) { | 450 | fn bar(baz: Baz) { |
422 | <|>todo!() | 451 | ${0:todo!()} |
423 | } | 452 | } |
424 | ", | 453 | ", |
425 | ); | 454 | ); |
@@ -452,7 +481,7 @@ impl Baz { | |||
452 | } | 481 | } |
453 | 482 | ||
454 | fn bar(baz: Baz) { | 483 | fn bar(baz: Baz) { |
455 | <|>todo!() | 484 | ${0:todo!()} |
456 | } | 485 | } |
457 | ", | 486 | ", |
458 | ) | 487 | ) |
@@ -473,7 +502,7 @@ fn foo() { | |||
473 | } | 502 | } |
474 | 503 | ||
475 | fn bar(arg: &str) { | 504 | fn bar(arg: &str) { |
476 | <|>todo!() | 505 | ${0:todo!()} |
477 | } | 506 | } |
478 | "#, | 507 | "#, |
479 | ) | 508 | ) |
@@ -494,7 +523,7 @@ fn foo() { | |||
494 | } | 523 | } |
495 | 524 | ||
496 | fn bar(arg: char) { | 525 | fn bar(arg: char) { |
497 | <|>todo!() | 526 | ${0:todo!()} |
498 | } | 527 | } |
499 | "#, | 528 | "#, |
500 | ) | 529 | ) |
@@ -515,7 +544,7 @@ fn foo() { | |||
515 | } | 544 | } |
516 | 545 | ||
517 | fn bar(arg: i32) { | 546 | fn bar(arg: i32) { |
518 | <|>todo!() | 547 | ${0:todo!()} |
519 | } | 548 | } |
520 | ", | 549 | ", |
521 | ) | 550 | ) |
@@ -536,7 +565,7 @@ fn foo() { | |||
536 | } | 565 | } |
537 | 566 | ||
538 | fn bar(arg: u8) { | 567 | fn bar(arg: u8) { |
539 | <|>todo!() | 568 | ${0:todo!()} |
540 | } | 569 | } |
541 | ", | 570 | ", |
542 | ) | 571 | ) |
@@ -561,7 +590,7 @@ fn foo() { | |||
561 | } | 590 | } |
562 | 591 | ||
563 | fn bar(x: u8) { | 592 | fn bar(x: u8) { |
564 | <|>todo!() | 593 | ${0:todo!()} |
565 | } | 594 | } |
566 | ", | 595 | ", |
567 | ) | 596 | ) |
@@ -584,7 +613,7 @@ fn foo() { | |||
584 | } | 613 | } |
585 | 614 | ||
586 | fn bar(worble: ()) { | 615 | fn bar(worble: ()) { |
587 | <|>todo!() | 616 | ${0:todo!()} |
588 | } | 617 | } |
589 | ", | 618 | ", |
590 | ) | 619 | ) |
@@ -613,7 +642,7 @@ fn baz() { | |||
613 | } | 642 | } |
614 | 643 | ||
615 | fn bar(foo: impl Foo) { | 644 | fn bar(foo: impl Foo) { |
616 | <|>todo!() | 645 | ${0:todo!()} |
617 | } | 646 | } |
618 | ", | 647 | ", |
619 | ) | 648 | ) |
@@ -640,7 +669,7 @@ fn foo() { | |||
640 | } | 669 | } |
641 | 670 | ||
642 | fn bar(baz: &Baz) { | 671 | fn bar(baz: &Baz) { |
643 | <|>todo!() | 672 | ${0:todo!()} |
644 | } | 673 | } |
645 | ", | 674 | ", |
646 | ) | 675 | ) |
@@ -669,7 +698,7 @@ fn foo() { | |||
669 | } | 698 | } |
670 | 699 | ||
671 | fn bar(baz: Baz::Bof) { | 700 | fn bar(baz: Baz::Bof) { |
672 | <|>todo!() | 701 | ${0:todo!()} |
673 | } | 702 | } |
674 | ", | 703 | ", |
675 | ) | 704 | ) |
@@ -692,7 +721,7 @@ fn foo<T>(t: T) { | |||
692 | } | 721 | } |
693 | 722 | ||
694 | fn bar<T>(t: T) { | 723 | fn bar<T>(t: T) { |
695 | <|>todo!() | 724 | ${0:todo!()} |
696 | } | 725 | } |
697 | ", | 726 | ", |
698 | ) | 727 | ) |
@@ -723,7 +752,7 @@ fn foo() { | |||
723 | } | 752 | } |
724 | 753 | ||
725 | fn bar(arg: fn() -> Baz) { | 754 | fn bar(arg: fn() -> Baz) { |
726 | <|>todo!() | 755 | ${0:todo!()} |
727 | } | 756 | } |
728 | ", | 757 | ", |
729 | ) | 758 | ) |
@@ -748,7 +777,7 @@ fn foo() { | |||
748 | } | 777 | } |
749 | 778 | ||
750 | fn bar(closure: impl Fn(i64) -> i64) { | 779 | fn bar(closure: impl Fn(i64) -> i64) { |
751 | <|>todo!() | 780 | ${0:todo!()} |
752 | } | 781 | } |
753 | ", | 782 | ", |
754 | ) | 783 | ) |
@@ -769,7 +798,7 @@ fn foo() { | |||
769 | } | 798 | } |
770 | 799 | ||
771 | fn bar(baz: ()) { | 800 | fn bar(baz: ()) { |
772 | <|>todo!() | 801 | ${0:todo!()} |
773 | } | 802 | } |
774 | ", | 803 | ", |
775 | ) | 804 | ) |
@@ -794,7 +823,7 @@ fn foo() { | |||
794 | } | 823 | } |
795 | 824 | ||
796 | fn bar(baz_1: Baz, baz_2: Baz) { | 825 | fn bar(baz_1: Baz, baz_2: Baz) { |
797 | <|>todo!() | 826 | ${0:todo!()} |
798 | } | 827 | } |
799 | ", | 828 | ", |
800 | ) | 829 | ) |
@@ -819,7 +848,7 @@ fn foo() { | |||
819 | } | 848 | } |
820 | 849 | ||
821 | fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) { | 850 | fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) { |
822 | <|>todo!() | 851 | ${0:todo!()} |
823 | } | 852 | } |
824 | "#, | 853 | "#, |
825 | ) | 854 | ) |
@@ -839,7 +868,7 @@ fn foo() { | |||
839 | r" | 868 | r" |
840 | mod bar { | 869 | mod bar { |
841 | pub(crate) fn my_fn() { | 870 | pub(crate) fn my_fn() { |
842 | <|>todo!() | 871 | ${0:todo!()} |
843 | } | 872 | } |
844 | } | 873 | } |
845 | 874 | ||
@@ -878,7 +907,7 @@ fn bar() { | |||
878 | } | 907 | } |
879 | 908 | ||
880 | fn baz(foo: foo::Foo) { | 909 | fn baz(foo: foo::Foo) { |
881 | <|>todo!() | 910 | ${0:todo!()} |
882 | } | 911 | } |
883 | ", | 912 | ", |
884 | ) | 913 | ) |
@@ -902,7 +931,7 @@ mod bar { | |||
902 | fn something_else() {} | 931 | fn something_else() {} |
903 | 932 | ||
904 | pub(crate) fn my_fn() { | 933 | pub(crate) fn my_fn() { |
905 | <|>todo!() | 934 | ${0:todo!()} |
906 | } | 935 | } |
907 | } | 936 | } |
908 | 937 | ||
@@ -930,7 +959,7 @@ fn foo() { | |||
930 | mod bar { | 959 | mod bar { |
931 | mod baz { | 960 | mod baz { |
932 | pub(crate) fn my_fn() { | 961 | pub(crate) fn my_fn() { |
933 | <|>todo!() | 962 | ${0:todo!()} |
934 | } | 963 | } |
935 | } | 964 | } |
936 | } | 965 | } |
@@ -959,7 +988,7 @@ fn main() { | |||
959 | 988 | ||
960 | 989 | ||
961 | pub(crate) fn bar() { | 990 | pub(crate) fn bar() { |
962 | <|>todo!() | 991 | ${0:todo!()} |
963 | }", | 992 | }", |
964 | ) | 993 | ) |
965 | } | 994 | } |
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs index df114a0d8..eceba7d0a 100644 --- a/crates/ra_assists/src/handlers/add_impl.rs +++ b/crates/ra_assists/src/handlers/add_impl.rs | |||
@@ -1,7 +1,4 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::ast::{self, AstNode, NameOwner, TypeParamsOwner}; |
2 | ast::{self, AstNode, NameOwner, TypeParamsOwner}, | ||
3 | TextSize, | ||
4 | }; | ||
5 | use stdx::{format_to, SepBy}; | 2 | use stdx::{format_to, SepBy}; |
6 | 3 | ||
7 | use crate::{AssistContext, AssistId, Assists}; | 4 | use crate::{AssistContext, AssistId, Assists}; |
@@ -12,17 +9,17 @@ use crate::{AssistContext, AssistId, Assists}; | |||
12 | // | 9 | // |
13 | // ``` | 10 | // ``` |
14 | // struct Ctx<T: Clone> { | 11 | // struct Ctx<T: Clone> { |
15 | // data: T,<|> | 12 | // data: T,<|> |
16 | // } | 13 | // } |
17 | // ``` | 14 | // ``` |
18 | // -> | 15 | // -> |
19 | // ``` | 16 | // ``` |
20 | // struct Ctx<T: Clone> { | 17 | // struct Ctx<T: Clone> { |
21 | // data: T, | 18 | // data: T, |
22 | // } | 19 | // } |
23 | // | 20 | // |
24 | // impl<T: Clone> Ctx<T> { | 21 | // impl<T: Clone> Ctx<T> { |
25 | // | 22 | // $0 |
26 | // } | 23 | // } |
27 | // ``` | 24 | // ``` |
28 | pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 25 | pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
@@ -50,30 +47,37 @@ pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
50 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); | 47 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); |
51 | format_to!(buf, "<{}>", generic_params) | 48 | format_to!(buf, "<{}>", generic_params) |
52 | } | 49 | } |
53 | buf.push_str(" {\n"); | 50 | match ctx.config.snippet_cap { |
54 | edit.set_cursor(start_offset + TextSize::of(&buf)); | 51 | Some(cap) => { |
55 | buf.push_str("\n}"); | 52 | buf.push_str(" {\n $0\n}"); |
56 | edit.insert(start_offset, buf); | 53 | edit.insert_snippet(cap, start_offset, buf); |
54 | } | ||
55 | None => { | ||
56 | buf.push_str(" {\n}"); | ||
57 | edit.insert(start_offset, buf); | ||
58 | } | ||
59 | } | ||
57 | }) | 60 | }) |
58 | } | 61 | } |
59 | 62 | ||
60 | #[cfg(test)] | 63 | #[cfg(test)] |
61 | mod tests { | 64 | mod tests { |
62 | use super::*; | ||
63 | use crate::tests::{check_assist, check_assist_target}; | 65 | use crate::tests::{check_assist, check_assist_target}; |
64 | 66 | ||
67 | use super::*; | ||
68 | |||
65 | #[test] | 69 | #[test] |
66 | fn test_add_impl() { | 70 | fn test_add_impl() { |
67 | check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n<|>\n}\n"); | 71 | check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n $0\n}\n"); |
68 | check_assist( | 72 | check_assist( |
69 | add_impl, | 73 | add_impl, |
70 | "struct Foo<T: Clone> {<|>}", | 74 | "struct Foo<T: Clone> {<|>}", |
71 | "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}", | 75 | "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n $0\n}", |
72 | ); | 76 | ); |
73 | check_assist( | 77 | check_assist( |
74 | add_impl, | 78 | add_impl, |
75 | "struct Foo<'a, T: Foo<'a>> {<|>}", | 79 | "struct Foo<'a, T: Foo<'a>> {<|>}", |
76 | "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n<|>\n}", | 80 | "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}", |
77 | ); | 81 | ); |
78 | } | 82 | } |
79 | 83 | ||
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index c1ce87914..abacd4065 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | use crate::{ | 11 | use crate::{ |
12 | assist_context::{AssistContext, Assists}, | 12 | assist_context::{AssistContext, Assists}, |
13 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, | 13 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, |
14 | utils::{get_missing_assoc_items, resolve_target_trait}, | 14 | utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor}, |
15 | AssistId, | 15 | AssistId, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -46,7 +46,7 @@ enum AddMissingImplMembersMode { | |||
46 | // | 46 | // |
47 | // impl Trait<u32> for () { | 47 | // impl Trait<u32> for () { |
48 | // fn foo(&self) -> u32 { | 48 | // fn foo(&self) -> u32 { |
49 | // todo!() | 49 | // ${0:todo!()} |
50 | // } | 50 | // } |
51 | // | 51 | // |
52 | // } | 52 | // } |
@@ -89,7 +89,7 @@ pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) - | |||
89 | // impl Trait for () { | 89 | // impl Trait for () { |
90 | // Type X = (); | 90 | // Type X = (); |
91 | // fn foo(&self) {} | 91 | // fn foo(&self) {} |
92 | // fn bar(&self) {} | 92 | // $0fn bar(&self) {} |
93 | // | 93 | // |
94 | // } | 94 | // } |
95 | // ``` | 95 | // ``` |
@@ -147,7 +147,7 @@ fn add_missing_impl_members_inner( | |||
147 | } | 147 | } |
148 | 148 | ||
149 | let target = impl_def.syntax().text_range(); | 149 | let target = impl_def.syntax().text_range(); |
150 | acc.add(AssistId(assist_id), label, target, |edit| { | 150 | acc.add(AssistId(assist_id), label, target, |builder| { |
151 | let n_existing_items = impl_item_list.assoc_items().count(); | 151 | let n_existing_items = impl_item_list.assoc_items().count(); |
152 | let source_scope = ctx.sema.scope_for_def(trait_); | 152 | let source_scope = ctx.sema.scope_for_def(trait_); |
153 | let target_scope = ctx.sema.scope(impl_item_list.syntax()); | 153 | let target_scope = ctx.sema.scope(impl_item_list.syntax()); |
@@ -162,13 +162,29 @@ fn add_missing_impl_members_inner( | |||
162 | }) | 162 | }) |
163 | .map(|it| edit::remove_attrs_and_docs(&it)); | 163 | .map(|it| edit::remove_attrs_and_docs(&it)); |
164 | let new_impl_item_list = impl_item_list.append_items(items); | 164 | let new_impl_item_list = impl_item_list.append_items(items); |
165 | let cursor_position = { | 165 | let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap(); |
166 | let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap(); | 166 | |
167 | first_new_item.syntax().text_range().start() | 167 | let original_range = impl_item_list.syntax().text_range(); |
168 | match ctx.config.snippet_cap { | ||
169 | None => builder.replace(original_range, new_impl_item_list.to_string()), | ||
170 | Some(cap) => { | ||
171 | let mut cursor = Cursor::Before(first_new_item.syntax()); | ||
172 | let placeholder; | ||
173 | if let ast::AssocItem::FnDef(func) = &first_new_item { | ||
174 | if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) { | ||
175 | if m.syntax().text() == "todo!()" { | ||
176 | placeholder = m; | ||
177 | cursor = Cursor::Replace(placeholder.syntax()); | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | builder.replace_snippet( | ||
182 | cap, | ||
183 | original_range, | ||
184 | render_snippet(cap, new_impl_item_list.syntax(), cursor), | ||
185 | ) | ||
186 | } | ||
168 | }; | 187 | }; |
169 | |||
170 | edit.replace_ast(impl_item_list, new_impl_item_list); | ||
171 | edit.set_cursor(cursor_position); | ||
172 | }) | 188 | }) |
173 | } | 189 | } |
174 | 190 | ||
@@ -222,7 +238,7 @@ struct S; | |||
222 | 238 | ||
223 | impl Foo for S { | 239 | impl Foo for S { |
224 | fn bar(&self) {} | 240 | fn bar(&self) {} |
225 | <|>type Output; | 241 | $0type Output; |
226 | const CONST: usize = 42; | 242 | const CONST: usize = 42; |
227 | fn foo(&self) { | 243 | fn foo(&self) { |
228 | todo!() | 244 | todo!() |
@@ -263,8 +279,8 @@ struct S; | |||
263 | 279 | ||
264 | impl Foo for S { | 280 | impl Foo for S { |
265 | fn bar(&self) {} | 281 | fn bar(&self) {} |
266 | <|>fn foo(&self) { | 282 | fn foo(&self) { |
267 | todo!() | 283 | ${0:todo!()} |
268 | } | 284 | } |
269 | 285 | ||
270 | }"#, | 286 | }"#, |
@@ -283,8 +299,8 @@ impl Foo for S { <|> }"#, | |||
283 | trait Foo { fn foo(&self); } | 299 | trait Foo { fn foo(&self); } |
284 | struct S; | 300 | struct S; |
285 | impl Foo for S { | 301 | impl Foo for S { |
286 | <|>fn foo(&self) { | 302 | fn foo(&self) { |
287 | todo!() | 303 | ${0:todo!()} |
288 | } | 304 | } |
289 | }"#, | 305 | }"#, |
290 | ); | 306 | ); |
@@ -302,8 +318,8 @@ impl Foo<u32> for S { <|> }"#, | |||
302 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 318 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
303 | struct S; | 319 | struct S; |
304 | impl Foo<u32> for S { | 320 | impl Foo<u32> for S { |
305 | <|>fn foo(&self, t: u32) -> &u32 { | 321 | fn foo(&self, t: u32) -> &u32 { |
306 | todo!() | 322 | ${0:todo!()} |
307 | } | 323 | } |
308 | }"#, | 324 | }"#, |
309 | ); | 325 | ); |
@@ -321,8 +337,8 @@ impl<U> Foo<U> for S { <|> }"#, | |||
321 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 337 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
322 | struct S; | 338 | struct S; |
323 | impl<U> Foo<U> for S { | 339 | impl<U> Foo<U> for S { |
324 | <|>fn foo(&self, t: U) -> &U { | 340 | fn foo(&self, t: U) -> &U { |
325 | todo!() | 341 | ${0:todo!()} |
326 | } | 342 | } |
327 | }"#, | 343 | }"#, |
328 | ); | 344 | ); |
@@ -340,8 +356,8 @@ impl Foo for S {}<|>"#, | |||
340 | trait Foo { fn foo(&self); } | 356 | trait Foo { fn foo(&self); } |
341 | struct S; | 357 | struct S; |
342 | impl Foo for S { | 358 | impl Foo for S { |
343 | <|>fn foo(&self) { | 359 | fn foo(&self) { |
344 | todo!() | 360 | ${0:todo!()} |
345 | } | 361 | } |
346 | }"#, | 362 | }"#, |
347 | ) | 363 | ) |
@@ -365,8 +381,8 @@ mod foo { | |||
365 | } | 381 | } |
366 | struct S; | 382 | struct S; |
367 | impl foo::Foo for S { | 383 | impl foo::Foo for S { |
368 | <|>fn foo(&self, bar: foo::Bar) { | 384 | fn foo(&self, bar: foo::Bar) { |
369 | todo!() | 385 | ${0:todo!()} |
370 | } | 386 | } |
371 | }"#, | 387 | }"#, |
372 | ); | 388 | ); |
@@ -390,8 +406,8 @@ mod foo { | |||
390 | } | 406 | } |
391 | struct S; | 407 | struct S; |
392 | impl foo::Foo for S { | 408 | impl foo::Foo for S { |
393 | <|>fn foo(&self, bar: foo::Bar<u32>) { | 409 | fn foo(&self, bar: foo::Bar<u32>) { |
394 | todo!() | 410 | ${0:todo!()} |
395 | } | 411 | } |
396 | }"#, | 412 | }"#, |
397 | ); | 413 | ); |
@@ -415,8 +431,8 @@ mod foo { | |||
415 | } | 431 | } |
416 | struct S; | 432 | struct S; |
417 | impl foo::Foo<u32> for S { | 433 | impl foo::Foo<u32> for S { |
418 | <|>fn foo(&self, bar: foo::Bar<u32>) { | 434 | fn foo(&self, bar: foo::Bar<u32>) { |
419 | todo!() | 435 | ${0:todo!()} |
420 | } | 436 | } |
421 | }"#, | 437 | }"#, |
422 | ); | 438 | ); |
@@ -443,8 +459,8 @@ mod foo { | |||
443 | struct Param; | 459 | struct Param; |
444 | struct S; | 460 | struct S; |
445 | impl foo::Foo<Param> for S { | 461 | impl foo::Foo<Param> for S { |
446 | <|>fn foo(&self, bar: Param) { | 462 | fn foo(&self, bar: Param) { |
447 | todo!() | 463 | ${0:todo!()} |
448 | } | 464 | } |
449 | }"#, | 465 | }"#, |
450 | ); | 466 | ); |
@@ -470,8 +486,8 @@ mod foo { | |||
470 | } | 486 | } |
471 | struct S; | 487 | struct S; |
472 | impl foo::Foo for S { | 488 | impl foo::Foo for S { |
473 | <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { | 489 | fn foo(&self, bar: foo::Bar<u32>::Assoc) { |
474 | todo!() | 490 | ${0:todo!()} |
475 | } | 491 | } |
476 | }"#, | 492 | }"#, |
477 | ); | 493 | ); |
@@ -497,8 +513,8 @@ mod foo { | |||
497 | } | 513 | } |
498 | struct S; | 514 | struct S; |
499 | impl foo::Foo for S { | 515 | impl foo::Foo for S { |
500 | <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { | 516 | fn foo(&self, bar: foo::Bar<foo::Baz>) { |
501 | todo!() | 517 | ${0:todo!()} |
502 | } | 518 | } |
503 | }"#, | 519 | }"#, |
504 | ); | 520 | ); |
@@ -522,8 +538,8 @@ mod foo { | |||
522 | } | 538 | } |
523 | struct S; | 539 | struct S; |
524 | impl foo::Foo for S { | 540 | impl foo::Foo for S { |
525 | <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { | 541 | fn foo(&self, bar: dyn Fn(u32) -> i32) { |
526 | todo!() | 542 | ${0:todo!()} |
527 | } | 543 | } |
528 | }"#, | 544 | }"#, |
529 | ); | 545 | ); |
@@ -580,7 +596,7 @@ trait Foo { | |||
580 | } | 596 | } |
581 | struct S; | 597 | struct S; |
582 | impl Foo for S { | 598 | impl Foo for S { |
583 | <|>type Output; | 599 | $0type Output; |
584 | fn foo(&self) { | 600 | fn foo(&self) { |
585 | todo!() | 601 | todo!() |
586 | } | 602 | } |
@@ -614,7 +630,57 @@ trait Foo { | |||
614 | } | 630 | } |
615 | struct S; | 631 | struct S; |
616 | impl Foo for S { | 632 | impl Foo for S { |
617 | <|>fn valid(some: u32) -> bool { false } | 633 | $0fn valid(some: u32) -> bool { false } |
634 | }"#, | ||
635 | ) | ||
636 | } | ||
637 | |||
638 | #[test] | ||
639 | fn test_generic_single_default_parameter() { | ||
640 | check_assist( | ||
641 | add_missing_impl_members, | ||
642 | r#" | ||
643 | trait Foo<T = Self> { | ||
644 | fn bar(&self, other: &T); | ||
645 | } | ||
646 | |||
647 | struct S; | ||
648 | impl Foo for S { <|> }"#, | ||
649 | r#" | ||
650 | trait Foo<T = Self> { | ||
651 | fn bar(&self, other: &T); | ||
652 | } | ||
653 | |||
654 | struct S; | ||
655 | impl Foo for S { | ||
656 | fn bar(&self, other: &Self) { | ||
657 | ${0:todo!()} | ||
658 | } | ||
659 | }"#, | ||
660 | ) | ||
661 | } | ||
662 | |||
663 | #[test] | ||
664 | fn test_generic_default_parameter_is_second() { | ||
665 | check_assist( | ||
666 | add_missing_impl_members, | ||
667 | r#" | ||
668 | trait Foo<T1, T2 = Self> { | ||
669 | fn bar(&self, this: &T1, that: &T2); | ||
670 | } | ||
671 | |||
672 | struct S<T>; | ||
673 | impl Foo<T> for S<T> { <|> }"#, | ||
674 | r#" | ||
675 | trait Foo<T1, T2 = Self> { | ||
676 | fn bar(&self, this: &T1, that: &T2); | ||
677 | } | ||
678 | |||
679 | struct S<T>; | ||
680 | impl Foo<T> for S<T> { | ||
681 | fn bar(&self, this: &T, that: &Self) { | ||
682 | ${0:todo!()} | ||
683 | } | ||
618 | }"#, | 684 | }"#, |
619 | ) | 685 | ) |
620 | } | 686 | } |
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index fe7451dcf..837aa8377 100644 --- a/crates/ra_assists/src/handlers/add_new.rs +++ b/crates/ra_assists/src/handlers/add_new.rs | |||
@@ -3,7 +3,7 @@ use ra_syntax::{ | |||
3 | ast::{ | 3 | ast::{ |
4 | self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, | 4 | self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, |
5 | }, | 5 | }, |
6 | TextSize, T, | 6 | T, |
7 | }; | 7 | }; |
8 | use stdx::{format_to, SepBy}; | 8 | use stdx::{format_to, SepBy}; |
9 | 9 | ||
@@ -25,7 +25,7 @@ use crate::{AssistContext, AssistId, Assists}; | |||
25 | // } | 25 | // } |
26 | // | 26 | // |
27 | // impl<T: Clone> Ctx<T> { | 27 | // impl<T: Clone> Ctx<T> { |
28 | // fn new(data: T) -> Self { Self { data } } | 28 | // fn $0new(data: T) -> Self { Self { data } } |
29 | // } | 29 | // } |
30 | // | 30 | // |
31 | // ``` | 31 | // ``` |
@@ -42,31 +42,26 @@ pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
42 | let impl_def = find_struct_impl(&ctx, &strukt)?; | 42 | let impl_def = find_struct_impl(&ctx, &strukt)?; |
43 | 43 | ||
44 | let target = strukt.syntax().text_range(); | 44 | let target = strukt.syntax().text_range(); |
45 | acc.add(AssistId("add_new"), "Add default constructor", target, |edit| { | 45 | acc.add(AssistId("add_new"), "Add default constructor", target, |builder| { |
46 | let mut buf = String::with_capacity(512); | 46 | let mut buf = String::with_capacity(512); |
47 | 47 | ||
48 | if impl_def.is_some() { | 48 | if impl_def.is_some() { |
49 | buf.push('\n'); | 49 | buf.push('\n'); |
50 | } | 50 | } |
51 | 51 | ||
52 | let vis = strukt.visibility().map(|v| format!("{} ", v)); | 52 | let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); |
53 | let vis = vis.as_deref().unwrap_or(""); | ||
54 | 53 | ||
55 | let params = field_list | 54 | let params = field_list |
56 | .fields() | 55 | .fields() |
57 | .filter_map(|f| { | 56 | .filter_map(|f| { |
58 | Some(format!( | 57 | Some(format!("{}: {}", f.name()?.syntax(), f.ascribed_type()?.syntax())) |
59 | "{}: {}", | ||
60 | f.name()?.syntax().text(), | ||
61 | f.ascribed_type()?.syntax().text() | ||
62 | )) | ||
63 | }) | 58 | }) |
64 | .sep_by(", "); | 59 | .sep_by(", "); |
65 | let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", "); | 60 | let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", "); |
66 | 61 | ||
67 | format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); | 62 | format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); |
68 | 63 | ||
69 | let (start_offset, end_offset) = impl_def | 64 | let start_offset = impl_def |
70 | .and_then(|impl_def| { | 65 | .and_then(|impl_def| { |
71 | buf.push('\n'); | 66 | buf.push('\n'); |
72 | let start = impl_def | 67 | let start = impl_def |
@@ -76,17 +71,20 @@ pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
76 | .text_range() | 71 | .text_range() |
77 | .end(); | 72 | .end(); |
78 | 73 | ||
79 | Some((start, TextSize::of("\n"))) | 74 | Some(start) |
80 | }) | 75 | }) |
81 | .unwrap_or_else(|| { | 76 | .unwrap_or_else(|| { |
82 | buf = generate_impl_text(&strukt, &buf); | 77 | buf = generate_impl_text(&strukt, &buf); |
83 | let start = strukt.syntax().text_range().end(); | 78 | strukt.syntax().text_range().end() |
84 | |||
85 | (start, TextSize::of("\n}\n")) | ||
86 | }); | 79 | }); |
87 | 80 | ||
88 | edit.set_cursor(start_offset + TextSize::of(&buf) - end_offset); | 81 | match ctx.config.snippet_cap { |
89 | edit.insert(start_offset, buf); | 82 | None => builder.insert(start_offset, buf), |
83 | Some(cap) => { | ||
84 | buf = buf.replace("fn new", "fn $0new"); | ||
85 | builder.insert_snippet(cap, start_offset, buf); | ||
86 | } | ||
87 | } | ||
90 | }) | 88 | }) |
91 | } | 89 | } |
92 | 90 | ||
@@ -191,7 +189,7 @@ mod tests { | |||
191 | "struct Foo {} | 189 | "struct Foo {} |
192 | 190 | ||
193 | impl Foo { | 191 | impl Foo { |
194 | fn new() -> Self { Self { } }<|> | 192 | fn $0new() -> Self { Self { } } |
195 | } | 193 | } |
196 | ", | 194 | ", |
197 | ); | 195 | ); |
@@ -201,7 +199,7 @@ impl Foo { | |||
201 | "struct Foo<T: Clone> {} | 199 | "struct Foo<T: Clone> {} |
202 | 200 | ||
203 | impl<T: Clone> Foo<T> { | 201 | impl<T: Clone> Foo<T> { |
204 | fn new() -> Self { Self { } }<|> | 202 | fn $0new() -> Self { Self { } } |
205 | } | 203 | } |
206 | ", | 204 | ", |
207 | ); | 205 | ); |
@@ -211,7 +209,7 @@ impl<T: Clone> Foo<T> { | |||
211 | "struct Foo<'a, T: Foo<'a>> {} | 209 | "struct Foo<'a, T: Foo<'a>> {} |
212 | 210 | ||
213 | impl<'a, T: Foo<'a>> Foo<'a, T> { | 211 | impl<'a, T: Foo<'a>> Foo<'a, T> { |
214 | fn new() -> Self { Self { } }<|> | 212 | fn $0new() -> Self { Self { } } |
215 | } | 213 | } |
216 | ", | 214 | ", |
217 | ); | 215 | ); |
@@ -221,7 +219,7 @@ impl<'a, T: Foo<'a>> Foo<'a, T> { | |||
221 | "struct Foo { baz: String } | 219 | "struct Foo { baz: String } |
222 | 220 | ||
223 | impl Foo { | 221 | impl Foo { |
224 | fn new(baz: String) -> Self { Self { baz } }<|> | 222 | fn $0new(baz: String) -> Self { Self { baz } } |
225 | } | 223 | } |
226 | ", | 224 | ", |
227 | ); | 225 | ); |
@@ -231,7 +229,7 @@ impl Foo { | |||
231 | "struct Foo { baz: String, qux: Vec<i32> } | 229 | "struct Foo { baz: String, qux: Vec<i32> } |
232 | 230 | ||
233 | impl Foo { | 231 | impl Foo { |
234 | fn new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }<|> | 232 | fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } } |
235 | } | 233 | } |
236 | ", | 234 | ", |
237 | ); | 235 | ); |
@@ -243,7 +241,7 @@ impl Foo { | |||
243 | "struct Foo { pub baz: String, pub qux: Vec<i32> } | 241 | "struct Foo { pub baz: String, pub qux: Vec<i32> } |
244 | 242 | ||
245 | impl Foo { | 243 | impl Foo { |
246 | fn new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }<|> | 244 | fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } } |
247 | } | 245 | } |
248 | ", | 246 | ", |
249 | ); | 247 | ); |
@@ -258,7 +256,7 @@ impl Foo {} | |||
258 | "struct Foo {} | 256 | "struct Foo {} |
259 | 257 | ||
260 | impl Foo { | 258 | impl Foo { |
261 | fn new() -> Self { Self { } }<|> | 259 | fn $0new() -> Self { Self { } } |
262 | } | 260 | } |
263 | ", | 261 | ", |
264 | ); | 262 | ); |
@@ -273,7 +271,7 @@ impl Foo { | |||
273 | "struct Foo {} | 271 | "struct Foo {} |
274 | 272 | ||
275 | impl Foo { | 273 | impl Foo { |
276 | fn new() -> Self { Self { } }<|> | 274 | fn $0new() -> Self { Self { } } |
277 | 275 | ||
278 | fn qux(&self) {} | 276 | fn qux(&self) {} |
279 | } | 277 | } |
@@ -294,7 +292,7 @@ impl Foo { | |||
294 | "struct Foo {} | 292 | "struct Foo {} |
295 | 293 | ||
296 | impl Foo { | 294 | impl Foo { |
297 | fn new() -> Self { Self { } }<|> | 295 | fn $0new() -> Self { Self { } } |
298 | 296 | ||
299 | fn qux(&self) {} | 297 | fn qux(&self) {} |
300 | fn baz() -> i32 { | 298 | fn baz() -> i32 { |
@@ -311,7 +309,7 @@ impl Foo { | |||
311 | "pub struct Foo {} | 309 | "pub struct Foo {} |
312 | 310 | ||
313 | impl Foo { | 311 | impl Foo { |
314 | pub fn new() -> Self { Self { } }<|> | 312 | pub fn $0new() -> Self { Self { } } |
315 | } | 313 | } |
316 | ", | 314 | ", |
317 | ); | 315 | ); |
@@ -321,7 +319,7 @@ impl Foo { | |||
321 | "pub(crate) struct Foo {} | 319 | "pub(crate) struct Foo {} |
322 | 320 | ||
323 | impl Foo { | 321 | impl Foo { |
324 | pub(crate) fn new() -> Self { Self { } }<|> | 322 | pub(crate) fn $0new() -> Self { Self { } } |
325 | } | 323 | } |
326 | ", | 324 | ", |
327 | ); | 325 | ); |
@@ -414,7 +412,7 @@ pub struct Source<T> { | |||
414 | } | 412 | } |
415 | 413 | ||
416 | impl<T> Source<T> { | 414 | impl<T> Source<T> { |
417 | pub fn new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }<|> | 415 | pub fn $0new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } } |
418 | 416 | ||
419 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | 417 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { |
420 | Source { file_id: self.file_id, ast: f(self.ast) } | 418 | Source { file_id: self.file_id, ast: f(self.ast) } |
diff --git a/crates/ra_assists/src/handlers/add_turbo_fish.rs b/crates/ra_assists/src/handlers/add_turbo_fish.rs new file mode 100644 index 000000000..26acf81f2 --- /dev/null +++ b/crates/ra_assists/src/handlers/add_turbo_fish.rs | |||
@@ -0,0 +1,134 @@ | |||
1 | use ra_ide_db::defs::{classify_name_ref, Definition, NameRefClass}; | ||
2 | use ra_syntax::{ast, AstNode, SyntaxKind, T}; | ||
3 | use test_utils::mark; | ||
4 | |||
5 | use crate::{ | ||
6 | assist_context::{AssistContext, Assists}, | ||
7 | AssistId, | ||
8 | }; | ||
9 | |||
10 | // Assist: add_turbo_fish | ||
11 | // | ||
12 | // Adds `::<_>` to a call of a generic method or function. | ||
13 | // | ||
14 | // ``` | ||
15 | // fn make<T>() -> T { todo!() } | ||
16 | // fn main() { | ||
17 | // let x = make<|>(); | ||
18 | // } | ||
19 | // ``` | ||
20 | // -> | ||
21 | // ``` | ||
22 | // fn make<T>() -> T { todo!() } | ||
23 | // fn main() { | ||
24 | // let x = make::<${0:_}>(); | ||
25 | // } | ||
26 | // ``` | ||
27 | pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
28 | let ident = ctx.find_token_at_offset(SyntaxKind::IDENT)?; | ||
29 | let next_token = ident.next_token()?; | ||
30 | if next_token.kind() == T![::] { | ||
31 | mark::hit!(add_turbo_fish_one_fish_is_enough); | ||
32 | return None; | ||
33 | } | ||
34 | let name_ref = ast::NameRef::cast(ident.parent())?; | ||
35 | let def = match classify_name_ref(&ctx.sema, &name_ref)? { | ||
36 | NameRefClass::Definition(def) => def, | ||
37 | NameRefClass::FieldShorthand { .. } => return None, | ||
38 | }; | ||
39 | let fun = match def { | ||
40 | Definition::ModuleDef(hir::ModuleDef::Function(it)) => it, | ||
41 | _ => return None, | ||
42 | }; | ||
43 | let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); | ||
44 | if generics.is_empty() { | ||
45 | mark::hit!(add_turbo_fish_non_generic); | ||
46 | return None; | ||
47 | } | ||
48 | acc.add(AssistId("add_turbo_fish"), "Add `::<>`", ident.text_range(), |builder| { | ||
49 | match ctx.config.snippet_cap { | ||
50 | Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"), | ||
51 | None => builder.insert(ident.text_range().end(), "::<_>"), | ||
52 | } | ||
53 | }) | ||
54 | } | ||
55 | |||
56 | #[cfg(test)] | ||
57 | mod tests { | ||
58 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
59 | |||
60 | use super::*; | ||
61 | use test_utils::mark; | ||
62 | |||
63 | #[test] | ||
64 | fn add_turbo_fish_function() { | ||
65 | check_assist( | ||
66 | add_turbo_fish, | ||
67 | r#" | ||
68 | fn make<T>() -> T {} | ||
69 | fn main() { | ||
70 | make<|>(); | ||
71 | } | ||
72 | "#, | ||
73 | r#" | ||
74 | fn make<T>() -> T {} | ||
75 | fn main() { | ||
76 | make::<${0:_}>(); | ||
77 | } | ||
78 | "#, | ||
79 | ); | ||
80 | } | ||
81 | |||
82 | #[test] | ||
83 | fn add_turbo_fish_method() { | ||
84 | check_assist( | ||
85 | add_turbo_fish, | ||
86 | r#" | ||
87 | struct S; | ||
88 | impl S { | ||
89 | fn make<T>(&self) -> T {} | ||
90 | } | ||
91 | fn main() { | ||
92 | S.make<|>(); | ||
93 | } | ||
94 | "#, | ||
95 | r#" | ||
96 | struct S; | ||
97 | impl S { | ||
98 | fn make<T>(&self) -> T {} | ||
99 | } | ||
100 | fn main() { | ||
101 | S.make::<${0:_}>(); | ||
102 | } | ||
103 | "#, | ||
104 | ); | ||
105 | } | ||
106 | |||
107 | #[test] | ||
108 | fn add_turbo_fish_one_fish_is_enough() { | ||
109 | mark::check!(add_turbo_fish_one_fish_is_enough); | ||
110 | check_assist_not_applicable( | ||
111 | add_turbo_fish, | ||
112 | r#" | ||
113 | fn make<T>() -> T {} | ||
114 | fn main() { | ||
115 | make<|>::<()>(); | ||
116 | } | ||
117 | "#, | ||
118 | ); | ||
119 | } | ||
120 | |||
121 | #[test] | ||
122 | fn add_turbo_fish_non_generic() { | ||
123 | mark::check!(add_turbo_fish_non_generic); | ||
124 | check_assist_not_applicable( | ||
125 | add_turbo_fish, | ||
126 | r#" | ||
127 | fn make() -> () {} | ||
128 | fn main() { | ||
129 | make<|>(); | ||
130 | } | ||
131 | "#, | ||
132 | ); | ||
133 | } | ||
134 | } | ||
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 78d23150d..edf96d50e 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -50,7 +50,12 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
50 | format!("Import `{}`", &import), | 50 | format!("Import `{}`", &import), |
51 | range, | 51 | range, |
52 | |builder| { | 52 | |builder| { |
53 | insert_use_statement(&auto_import_assets.syntax_under_caret, &import, ctx, builder); | 53 | insert_use_statement( |
54 | &auto_import_assets.syntax_under_caret, | ||
55 | &import, | ||
56 | ctx, | ||
57 | builder.text_edit_builder(), | ||
58 | ); | ||
54 | }, | 59 | }, |
55 | ); | 60 | ); |
56 | } | 61 | } |
@@ -293,7 +298,7 @@ mod tests { | |||
293 | } | 298 | } |
294 | ", | 299 | ", |
295 | r" | 300 | r" |
296 | <|>use PubMod::PubStruct; | 301 | use PubMod::PubStruct; |
297 | 302 | ||
298 | PubStruct | 303 | PubStruct |
299 | 304 | ||
@@ -324,7 +329,7 @@ mod tests { | |||
324 | macro_rules! foo { | 329 | macro_rules! foo { |
325 | ($i:ident) => { fn foo(a: $i) {} } | 330 | ($i:ident) => { fn foo(a: $i) {} } |
326 | } | 331 | } |
327 | foo!(Pub<|>Struct); | 332 | foo!(PubStruct); |
328 | 333 | ||
329 | pub mod PubMod { | 334 | pub mod PubMod { |
330 | pub struct PubStruct; | 335 | pub struct PubStruct; |
@@ -355,7 +360,7 @@ mod tests { | |||
355 | use PubMod::{PubStruct2, PubStruct1}; | 360 | use PubMod::{PubStruct2, PubStruct1}; |
356 | 361 | ||
357 | struct Test { | 362 | struct Test { |
358 | test: Pub<|>Struct2<u8>, | 363 | test: PubStruct2<u8>, |
359 | } | 364 | } |
360 | 365 | ||
361 | pub mod PubMod { | 366 | pub mod PubMod { |
@@ -388,7 +393,7 @@ mod tests { | |||
388 | r" | 393 | r" |
389 | use PubMod3::PubStruct; | 394 | use PubMod3::PubStruct; |
390 | 395 | ||
391 | PubSt<|>ruct | 396 | PubStruct |
392 | 397 | ||
393 | pub mod PubMod1 { | 398 | pub mod PubMod1 { |
394 | pub struct PubStruct; | 399 | pub struct PubStruct; |
@@ -469,7 +474,7 @@ mod tests { | |||
469 | r" | 474 | r" |
470 | use PubMod::test_function; | 475 | use PubMod::test_function; |
471 | 476 | ||
472 | test_function<|> | 477 | test_function |
473 | 478 | ||
474 | pub mod PubMod { | 479 | pub mod PubMod { |
475 | pub fn test_function() {}; | 480 | pub fn test_function() {}; |
@@ -496,7 +501,7 @@ mod tests { | |||
496 | r"use crate_with_macro::foo; | 501 | r"use crate_with_macro::foo; |
497 | 502 | ||
498 | fn main() { | 503 | fn main() { |
499 | foo<|> | 504 | foo |
500 | } | 505 | } |
501 | ", | 506 | ", |
502 | ); | 507 | ); |
@@ -582,7 +587,7 @@ fn main() { | |||
582 | } | 587 | } |
583 | 588 | ||
584 | fn main() { | 589 | fn main() { |
585 | TestStruct::test_function<|> | 590 | TestStruct::test_function |
586 | } | 591 | } |
587 | ", | 592 | ", |
588 | ); | 593 | ); |
@@ -615,7 +620,7 @@ fn main() { | |||
615 | } | 620 | } |
616 | 621 | ||
617 | fn main() { | 622 | fn main() { |
618 | TestStruct::TEST_CONST<|> | 623 | TestStruct::TEST_CONST |
619 | } | 624 | } |
620 | ", | 625 | ", |
621 | ); | 626 | ); |
@@ -654,7 +659,7 @@ fn main() { | |||
654 | } | 659 | } |
655 | 660 | ||
656 | fn main() { | 661 | fn main() { |
657 | test_mod::TestStruct::test_function<|> | 662 | test_mod::TestStruct::test_function |
658 | } | 663 | } |
659 | ", | 664 | ", |
660 | ); | 665 | ); |
@@ -725,7 +730,7 @@ fn main() { | |||
725 | } | 730 | } |
726 | 731 | ||
727 | fn main() { | 732 | fn main() { |
728 | test_mod::TestStruct::TEST_CONST<|> | 733 | test_mod::TestStruct::TEST_CONST |
729 | } | 734 | } |
730 | ", | 735 | ", |
731 | ); | 736 | ); |
@@ -798,7 +803,7 @@ fn main() { | |||
798 | 803 | ||
799 | fn main() { | 804 | fn main() { |
800 | let test_struct = test_mod::TestStruct {}; | 805 | let test_struct = test_mod::TestStruct {}; |
801 | test_struct.test_meth<|>od() | 806 | test_struct.test_method() |
802 | } | 807 | } |
803 | ", | 808 | ", |
804 | ); | 809 | ); |
diff --git a/crates/ra_assists/src/handlers/change_return_type_to_result.rs b/crates/ra_assists/src/handlers/change_return_type_to_result.rs index 5c907097e..c6baa0a57 100644 --- a/crates/ra_assists/src/handlers/change_return_type_to_result.rs +++ b/crates/ra_assists/src/handlers/change_return_type_to_result.rs | |||
@@ -1,8 +1,6 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | ast::{self, BlockExpr, Expr, LoopBodyOwner}, | 2 | ast::{self, BlockExpr, Expr, LoopBodyOwner}, |
3 | AstNode, | 3 | AstNode, SyntaxNode, |
4 | SyntaxKind::{COMMENT, WHITESPACE}, | ||
5 | SyntaxNode, TextSize, | ||
6 | }; | 4 | }; |
7 | 5 | ||
8 | use crate::{AssistContext, AssistId, Assists}; | 6 | use crate::{AssistContext, AssistId, Assists}; |
@@ -16,39 +14,40 @@ use crate::{AssistContext, AssistId, Assists}; | |||
16 | // ``` | 14 | // ``` |
17 | // -> | 15 | // -> |
18 | // ``` | 16 | // ``` |
19 | // fn foo() -> Result<i32, > { Ok(42i32) } | 17 | // fn foo() -> Result<i32, ${0:_}> { Ok(42i32) } |
20 | // ``` | 18 | // ``` |
21 | pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 19 | pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
22 | let fn_def = ctx.find_node_at_offset::<ast::FnDef>(); | 20 | let ret_type = ctx.find_node_at_offset::<ast::RetType>()?; |
23 | let fn_def = &mut fn_def?; | 21 | // FIXME: extend to lambdas as well |
24 | let ret_type = &fn_def.ret_type()?.type_ref()?; | 22 | let fn_def = ret_type.syntax().parent().and_then(ast::FnDef::cast)?; |
25 | if ret_type.syntax().text().to_string().starts_with("Result<") { | 23 | |
24 | let type_ref = &ret_type.type_ref()?; | ||
25 | if type_ref.syntax().text().to_string().starts_with("Result<") { | ||
26 | return None; | 26 | return None; |
27 | } | 27 | } |
28 | 28 | ||
29 | let block_expr = &fn_def.body()?; | 29 | let block_expr = &fn_def.body()?; |
30 | let cursor_in_ret_type = | ||
31 | fn_def.ret_type()?.syntax().text_range().contains_range(ctx.frange.range); | ||
32 | if !cursor_in_ret_type { | ||
33 | return None; | ||
34 | } | ||
35 | 30 | ||
36 | acc.add( | 31 | acc.add( |
37 | AssistId("change_return_type_to_result"), | 32 | AssistId("change_return_type_to_result"), |
38 | "Change return type to Result", | 33 | "Change return type to Result", |
39 | ret_type.syntax().text_range(), | 34 | type_ref.syntax().text_range(), |
40 | |edit| { | 35 | |builder| { |
41 | let mut tail_return_expr_collector = TailReturnCollector::new(); | 36 | let mut tail_return_expr_collector = TailReturnCollector::new(); |
42 | tail_return_expr_collector.collect_jump_exprs(block_expr, false); | 37 | tail_return_expr_collector.collect_jump_exprs(block_expr, false); |
43 | tail_return_expr_collector.collect_tail_exprs(block_expr); | 38 | tail_return_expr_collector.collect_tail_exprs(block_expr); |
44 | 39 | ||
45 | for ret_expr_arg in tail_return_expr_collector.exprs_to_wrap { | 40 | for ret_expr_arg in tail_return_expr_collector.exprs_to_wrap { |
46 | edit.replace_node_and_indent(&ret_expr_arg, format!("Ok({})", ret_expr_arg)); | 41 | builder.replace_node_and_indent(&ret_expr_arg, format!("Ok({})", ret_expr_arg)); |
47 | } | 42 | } |
48 | edit.replace_node_and_indent(ret_type.syntax(), format!("Result<{}, >", ret_type)); | ||
49 | 43 | ||
50 | if let Some(node_start) = result_insertion_offset(&ret_type) { | 44 | match ctx.config.snippet_cap { |
51 | edit.set_cursor(node_start + TextSize::of(&format!("Result<{}, ", ret_type))); | 45 | Some(cap) => { |
46 | let snippet = format!("Result<{}, ${{0:_}}>", type_ref); | ||
47 | builder.replace_snippet(cap, type_ref.syntax().text_range(), snippet) | ||
48 | } | ||
49 | None => builder | ||
50 | .replace(type_ref.syntax().text_range(), format!("Result<{}, _>", type_ref)), | ||
52 | } | 51 | } |
53 | }, | 52 | }, |
54 | ) | 53 | ) |
@@ -250,17 +249,8 @@ fn get_tail_expr_from_block(expr: &Expr) -> Option<Vec<NodeType>> { | |||
250 | } | 249 | } |
251 | } | 250 | } |
252 | 251 | ||
253 | fn result_insertion_offset(ret_type: &ast::TypeRef) -> Option<TextSize> { | ||
254 | let non_ws_child = ret_type | ||
255 | .syntax() | ||
256 | .children_with_tokens() | ||
257 | .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?; | ||
258 | Some(non_ws_child.text_range().start()) | ||
259 | } | ||
260 | |||
261 | #[cfg(test)] | 252 | #[cfg(test)] |
262 | mod tests { | 253 | mod tests { |
263 | |||
264 | use crate::tests::{check_assist, check_assist_not_applicable}; | 254 | use crate::tests::{check_assist, check_assist_not_applicable}; |
265 | 255 | ||
266 | use super::*; | 256 | use super::*; |
@@ -273,7 +263,7 @@ mod tests { | |||
273 | let test = "test"; | 263 | let test = "test"; |
274 | return 42i32; | 264 | return 42i32; |
275 | }"#, | 265 | }"#, |
276 | r#"fn foo() -> Result<i32, <|>> { | 266 | r#"fn foo() -> Result<i32, ${0:_}> { |
277 | let test = "test"; | 267 | let test = "test"; |
278 | return Ok(42i32); | 268 | return Ok(42i32); |
279 | }"#, | 269 | }"#, |
@@ -288,7 +278,7 @@ mod tests { | |||
288 | let test = "test"; | 278 | let test = "test"; |
289 | return 42i32; | 279 | return 42i32; |
290 | }"#, | 280 | }"#, |
291 | r#"fn foo() -> Result<i32, <|>> { | 281 | r#"fn foo() -> Result<i32, ${0:_}> { |
292 | let test = "test"; | 282 | let test = "test"; |
293 | return Ok(42i32); | 283 | return Ok(42i32); |
294 | }"#, | 284 | }"#, |
@@ -314,7 +304,7 @@ mod tests { | |||
314 | let test = "test"; | 304 | let test = "test"; |
315 | return 42i32; | 305 | return 42i32; |
316 | }"#, | 306 | }"#, |
317 | r#"fn foo() -> Result<i32, <|>> { | 307 | r#"fn foo() -> Result<i32, ${0:_}> { |
318 | let test = "test"; | 308 | let test = "test"; |
319 | return Ok(42i32); | 309 | return Ok(42i32); |
320 | }"#, | 310 | }"#, |
@@ -329,7 +319,7 @@ mod tests { | |||
329 | let test = "test"; | 319 | let test = "test"; |
330 | 42i32 | 320 | 42i32 |
331 | }"#, | 321 | }"#, |
332 | r#"fn foo() -> Result<i32, <|>> { | 322 | r#"fn foo() -> Result<i32, ${0:_}> { |
333 | let test = "test"; | 323 | let test = "test"; |
334 | Ok(42i32) | 324 | Ok(42i32) |
335 | }"#, | 325 | }"#, |
@@ -343,7 +333,7 @@ mod tests { | |||
343 | r#"fn foo() -> i32<|> { | 333 | r#"fn foo() -> i32<|> { |
344 | 42i32 | 334 | 42i32 |
345 | }"#, | 335 | }"#, |
346 | r#"fn foo() -> Result<i32, <|>> { | 336 | r#"fn foo() -> Result<i32, ${0:_}> { |
347 | Ok(42i32) | 337 | Ok(42i32) |
348 | }"#, | 338 | }"#, |
349 | ); | 339 | ); |
@@ -359,7 +349,7 @@ mod tests { | |||
359 | 24i32 | 349 | 24i32 |
360 | } | 350 | } |
361 | }"#, | 351 | }"#, |
362 | r#"fn foo() -> Result<i32, <|>> { | 352 | r#"fn foo() -> Result<i32, ${0:_}> { |
363 | if true { | 353 | if true { |
364 | Ok(42i32) | 354 | Ok(42i32) |
365 | } else { | 355 | } else { |
@@ -384,7 +374,7 @@ mod tests { | |||
384 | 24i32 | 374 | 24i32 |
385 | } | 375 | } |
386 | }"#, | 376 | }"#, |
387 | r#"fn foo() -> Result<i32, <|>> { | 377 | r#"fn foo() -> Result<i32, ${0:_}> { |
388 | if true { | 378 | if true { |
389 | if false { | 379 | if false { |
390 | Ok(1) | 380 | Ok(1) |
@@ -413,7 +403,7 @@ mod tests { | |||
413 | 24i32.await | 403 | 24i32.await |
414 | } | 404 | } |
415 | }"#, | 405 | }"#, |
416 | r#"async fn foo() -> Result<i32, <|>> { | 406 | r#"async fn foo() -> Result<i32, ${0:_}> { |
417 | if true { | 407 | if true { |
418 | if false { | 408 | if false { |
419 | Ok(1.await) | 409 | Ok(1.await) |
@@ -434,7 +424,7 @@ mod tests { | |||
434 | r#"fn foo() -> [i32;<|> 3] { | 424 | r#"fn foo() -> [i32;<|> 3] { |
435 | [1, 2, 3] | 425 | [1, 2, 3] |
436 | }"#, | 426 | }"#, |
437 | r#"fn foo() -> Result<[i32; 3], <|>> { | 427 | r#"fn foo() -> Result<[i32; 3], ${0:_}> { |
438 | Ok([1, 2, 3]) | 428 | Ok([1, 2, 3]) |
439 | }"#, | 429 | }"#, |
440 | ); | 430 | ); |
@@ -455,7 +445,7 @@ mod tests { | |||
455 | 24 as i32 | 445 | 24 as i32 |
456 | } | 446 | } |
457 | }"#, | 447 | }"#, |
458 | r#"fn foo() -> Result<i32, <|>> { | 448 | r#"fn foo() -> Result<i32, ${0:_}> { |
459 | if true { | 449 | if true { |
460 | if false { | 450 | if false { |
461 | Ok(1 as i32) | 451 | Ok(1 as i32) |
@@ -480,7 +470,7 @@ mod tests { | |||
480 | _ => 24i32, | 470 | _ => 24i32, |
481 | } | 471 | } |
482 | }"#, | 472 | }"#, |
483 | r#"fn foo() -> Result<i32, <|>> { | 473 | r#"fn foo() -> Result<i32, ${0:_}> { |
484 | let my_var = 5; | 474 | let my_var = 5; |
485 | match my_var { | 475 | match my_var { |
486 | 5 => Ok(42i32), | 476 | 5 => Ok(42i32), |
@@ -503,7 +493,7 @@ mod tests { | |||
503 | 493 | ||
504 | my_var | 494 | my_var |
505 | }"#, | 495 | }"#, |
506 | r#"fn foo() -> Result<i32, <|>> { | 496 | r#"fn foo() -> Result<i32, ${0:_}> { |
507 | let my_var = 5; | 497 | let my_var = 5; |
508 | loop { | 498 | loop { |
509 | println!("test"); | 499 | println!("test"); |
@@ -526,7 +516,7 @@ mod tests { | |||
526 | 516 | ||
527 | my_var | 517 | my_var |
528 | }"#, | 518 | }"#, |
529 | r#"fn foo() -> Result<i32, <|>> { | 519 | r#"fn foo() -> Result<i32, ${0:_}> { |
530 | let my_var = let x = loop { | 520 | let my_var = let x = loop { |
531 | break 1; | 521 | break 1; |
532 | }; | 522 | }; |
@@ -549,7 +539,7 @@ mod tests { | |||
549 | 539 | ||
550 | res | 540 | res |
551 | }"#, | 541 | }"#, |
552 | r#"fn foo() -> Result<i32, <|>> { | 542 | r#"fn foo() -> Result<i32, ${0:_}> { |
553 | let my_var = 5; | 543 | let my_var = 5; |
554 | let res = match my_var { | 544 | let res = match my_var { |
555 | 5 => 42i32, | 545 | 5 => 42i32, |
@@ -572,7 +562,7 @@ mod tests { | |||
572 | 562 | ||
573 | res | 563 | res |
574 | }"#, | 564 | }"#, |
575 | r#"fn foo() -> Result<i32, <|>> { | 565 | r#"fn foo() -> Result<i32, ${0:_}> { |
576 | let my_var = 5; | 566 | let my_var = 5; |
577 | let res = if my_var == 5 { | 567 | let res = if my_var == 5 { |
578 | 42i32 | 568 | 42i32 |
@@ -608,7 +598,7 @@ mod tests { | |||
608 | }, | 598 | }, |
609 | } | 599 | } |
610 | }"#, | 600 | }"#, |
611 | r#"fn foo() -> Result<i32, <|>> { | 601 | r#"fn foo() -> Result<i32, ${0:_}> { |
612 | let my_var = 5; | 602 | let my_var = 5; |
613 | match my_var { | 603 | match my_var { |
614 | 5 => { | 604 | 5 => { |
@@ -641,7 +631,7 @@ mod tests { | |||
641 | } | 631 | } |
642 | 53i32 | 632 | 53i32 |
643 | }"#, | 633 | }"#, |
644 | r#"fn foo() -> Result<i32, <|>> { | 634 | r#"fn foo() -> Result<i32, ${0:_}> { |
645 | let test = "test"; | 635 | let test = "test"; |
646 | if test == "test" { | 636 | if test == "test" { |
647 | return Ok(24i32); | 637 | return Ok(24i32); |
@@ -672,7 +662,7 @@ mod tests { | |||
672 |