diff options
Diffstat (limited to 'docs/dev')
-rw-r--r-- | docs/dev/README.md | 37 | ||||
-rw-r--r-- | docs/dev/architecture.md | 13 | ||||
-rw-r--r-- | docs/dev/lsp-extensions.md | 57 | ||||
-rw-r--r-- | docs/dev/style.md | 52 | ||||
-rw-r--r-- | docs/dev/syntax.md | 8 |
5 files changed, 122 insertions, 45 deletions
diff --git a/docs/dev/README.md b/docs/dev/README.md index eab21a765..16b23adc6 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -24,7 +24,7 @@ Rust Analyzer is a part of [RLS-2.0 working | |||
24 | group](https://github.com/rust-lang/compiler-team/tree/6a769c13656c0a6959ebc09e7b1f7c09b86fb9c0/working-groups/rls-2.0). | 24 | group](https://github.com/rust-lang/compiler-team/tree/6a769c13656c0a6959ebc09e7b1f7c09b86fb9c0/working-groups/rls-2.0). |
25 | Discussion happens in this Zulip stream: | 25 | Discussion happens in this Zulip stream: |
26 | 26 | ||
27 | https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0 | 27 | https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer |
28 | 28 | ||
29 | # Issue Labels | 29 | # Issue Labels |
30 | 30 | ||
@@ -32,6 +32,8 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0 | |||
32 | are good issues to get into the project. | 32 | are good issues to get into the project. |
33 | * [E-has-instructions](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-has-instructions) | 33 | * [E-has-instructions](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-has-instructions) |
34 | issues have links to the code in question and tests. | 34 | issues have links to the code in question and tests. |
35 | * [Broken Window](https://github.com/rust-analyzer/rust-analyzer/issues?q=is:issue+is:open+label:%22Broken+Window%22) | ||
36 | are issues which are not critical by themselves, but which should be fixed ASAP regardless, to avoid accumulation of technical debt. | ||
35 | * [E-easy](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy), | 37 | * [E-easy](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy), |
36 | [E-medium](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-medium), | 38 | [E-medium](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-medium), |
37 | [E-hard](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-hard), | 39 | [E-hard](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-hard), |
@@ -206,20 +208,26 @@ Release process is handled by `release`, `dist` and `promote` xtasks, `release` | |||
206 | 208 | ||
207 | Additionally, it assumes that remote for `rust-analyzer` is called `upstream` (I use `origin` to point to my fork). | 209 | Additionally, it assumes that remote for `rust-analyzer` is called `upstream` (I use `origin` to point to my fork). |
208 | 210 | ||
211 | `release` calls the GitHub API calls to scrape pull request comments and categorize them in the changelog. | ||
212 | This step uses the `curl` and `jq` applications, which need to be available in `PATH`. | ||
213 | Finally, you need to obtain a GitHub personal access token and set the `GITHUB_TOKEN` environment variable. | ||
214 | |||
209 | Release steps: | 215 | Release steps: |
210 | 216 | ||
211 | 1. Inside rust-analyzer, run `cargo xtask release`. This will: | 217 | 1. Set the `GITHUB_TOKEN` environment variable. |
218 | 2. Inside rust-analyzer, run `cargo xtask release`. This will: | ||
212 | * checkout the `release` branch | 219 | * checkout the `release` branch |
213 | * reset it to `upstream/nightly` | 220 | * reset it to `upstream/nightly` |
214 | * push it to `upstream`. This triggers GitHub Actions which: | 221 | * push it to `upstream`. This triggers GitHub Actions which: |
215 | * runs `cargo xtask dist` to package binaries and VS Code extension | 222 | * runs `cargo xtask dist` to package binaries and VS Code extension |
216 | * makes a GitHub release | 223 | * makes a GitHub release |
217 | * pushes VS Code extension to the marketplace | 224 | * pushes VS Code extension to the marketplace |
218 | * create new changelog in `rust-analyzer.github.io` | 225 | * call the GitHub API for PR details |
219 | 2. While the release is in progress, fill in the changelog | 226 | * create a new changelog in `rust-analyzer.github.io` |
220 | 3. Commit & push the changelog | 227 | 3. While the release is in progress, fill in the changelog |
221 | 4. Tweet | 228 | 4. Commit & push the changelog |
222 | 5. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's submodule. | 229 | 5. Tweet |
230 | 6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's submodule. | ||
223 | Self-approve the PR. | 231 | Self-approve the PR. |
224 | 232 | ||
225 | If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console. | 233 | If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console. |
@@ -227,18 +235,27 @@ If it fails because of something that needs to be fixed, remove the release tag | |||
227 | Make sure to remove the new changelog post created when running `cargo xtask release` a second time. | 235 | Make sure to remove the new changelog post created when running `cargo xtask release` a second time. |
228 | 236 | ||
229 | We release "nightly" every night automatically and promote the latest nightly to "stable" manually, every week. | 237 | We release "nightly" every night automatically and promote the latest nightly to "stable" manually, every week. |
238 | |||
230 | We don't do "patch" releases, unless something truly egregious comes up. | 239 | We don't do "patch" releases, unless something truly egregious comes up. |
240 | To do a patch release, cherry-pick the fix on top of the current `release` branch and push the branch. | ||
241 | There's no need to write a changelog for a patch release, it's OK to include the notes about the fix into the next weekly one. | ||
242 | Note: we tag releases by dates, releasing a patch release on the same day should work (by overwriting a tag), but I am not 100% sure. | ||
231 | 243 | ||
232 | ## Permissions | 244 | ## Permissions |
233 | 245 | ||
234 | There are three sets of people with extra permissions: | 246 | There are three sets of people with extra permissions: |
235 | 247 | ||
236 | * rust-analyzer GitHub organization **admins** (which include current t-compiler leads). | 248 | * rust-analyzer GitHub organization [**admins**](https://github.com/orgs/rust-analyzer/people?query=role:owner) (which include current t-compiler leads). |
237 | Admins have full access to the org. | 249 | Admins have full access to the org. |
238 | * **review** team in the organization. | 250 | * [**review**](https://github.com/orgs/rust-analyzer/teams/review) team in the organization. |
239 | Reviewers have `r+` access to all of organization's repositories and publish rights on crates.io. | 251 | Reviewers have `r+` access to all of organization's repositories and publish rights on crates.io. |
240 | They also have direct commit access, but all changes should via bors queue. | 252 | They also have direct commit access, but all changes should via bors queue. |
241 | It's ok to self-approve if you think you know what you are doing! | 253 | It's ok to self-approve if you think you know what you are doing! |
242 | bors should automatically sync the permissions. | 254 | bors should automatically sync the permissions. |
243 | * **triage** team in the organization. | 255 | Feel free to request a review or assign any PR to a reviewer with the relevant expertise to bring the work to their attention. |
256 | Don't feel pressured to review assigned PRs though. | ||
257 | If you don't feel like reviewing for whatever reason, someone else will pick the review up! | ||
258 | * [**triage**](https://github.com/orgs/rust-analyzer/teams/triage) team in the organization. | ||
244 | This team can label and close issues. | 259 | This team can label and close issues. |
260 | |||
261 | Note that at the time being you need to be a member of the org yourself to view the links. | ||
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index fb991133a..39edf9e19 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md | |||
@@ -42,7 +42,7 @@ The underlying engine makes sure that model is computed lazily (on-demand) and c | |||
42 | ## Entry Points | 42 | ## Entry Points |
43 | 43 | ||
44 | `crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP. | 44 | `crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP. |
45 | This is *the* entry point, but it front-loads a lot of complexity, so its fine to just skim through it. | 45 | This is *the* entry point, but it front-loads a lot of complexity, so it's fine to just skim through it. |
46 | 46 | ||
47 | `crates/rust-analyzer/src/handlers.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP. | 47 | `crates/rust-analyzer/src/handlers.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP. |
48 | 48 | ||
@@ -67,7 +67,7 @@ They are handled by Rust code in the xtask directory. | |||
67 | 67 | ||
68 | VS Code plugin. | 68 | VS Code plugin. |
69 | 69 | ||
70 | ### `libs/` | 70 | ### `lib/` |
71 | 71 | ||
72 | rust-analyzer independent libraries which we publish to crates.io. | 72 | rust-analyzer independent libraries which we publish to crates.io. |
73 | It's not heavily utilized at the moment. | 73 | It's not heavily utilized at the moment. |
@@ -139,7 +139,8 @@ If an AST method returns an `Option`, it *can* be `None` at runtime, even if thi | |||
139 | ### `crates/base_db` | 139 | ### `crates/base_db` |
140 | 140 | ||
141 | We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation. | 141 | We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation. |
142 | Roughly, you can think of salsa as a key-value store, but it can also compute derived values using specified functions. The `base_db` crate provides basic infrastructure for interacting with salsa. | 142 | Roughly, you can think of salsa as a key-value store, but it can also compute derived values using specified functions. |
143 | The `base_db` crate provides basic infrastructure for interacting with salsa. | ||
143 | Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer. | 144 | Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer. |
144 | Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs. | 145 | Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs. |
145 | 146 | ||
@@ -221,7 +222,7 @@ Internally, `ide` is split across several crates. `ide_assists`, `ide_completion | |||
221 | The `ide` contains a public API/façade, as well as implementation for a plethora of smaller features. | 222 | The `ide` contains a public API/façade, as well as implementation for a plethora of smaller features. |
222 | 223 | ||
223 | **Architecture Invariant:** `ide` crate strives to provide a _perfect_ API. | 224 | **Architecture Invariant:** `ide` crate strives to provide a _perfect_ API. |
224 | Although at the moment it has only one consumer, the LSP server, LSP *does not* influence it's API design. | 225 | Although at the moment it has only one consumer, the LSP server, LSP *does not* influence its API design. |
225 | Instead, we keep in mind a hypothetical _ideal_ client -- an IDE tailored specifically for rust, every nook and cranny of which is packed with Rust-specific goodies. | 226 | Instead, we keep in mind a hypothetical _ideal_ client -- an IDE tailored specifically for rust, every nook and cranny of which is packed with Rust-specific goodies. |
226 | 227 | ||
227 | ### `crates/rust-analyzer` | 228 | ### `crates/rust-analyzer` |
@@ -307,7 +308,7 @@ This sections talks about the things which are everywhere and nowhere in particu | |||
307 | 308 | ||
308 | ### Code generation | 309 | ### Code generation |
309 | 310 | ||
310 | Some of the components of this repository are generated through automatic processes. | 311 | Some components in this repository are generated through automatic processes. |
311 | Generated code is updated automatically on `cargo test`. | 312 | Generated code is updated automatically on `cargo test`. |
312 | Generated code is generally committed to the git repository. | 313 | Generated code is generally committed to the git repository. |
313 | 314 | ||
@@ -389,7 +390,7 @@ fn spam() { | |||
389 | ``` | 390 | ``` |
390 | 391 | ||
391 | To specify input data, we use a single string literal in a special format, which can describe a set of rust files. | 392 | To specify input data, we use a single string literal in a special format, which can describe a set of rust files. |
392 | See the `Fixture` type. | 393 | See the `Fixture` its module for fixture examples and documentation. |
393 | 394 | ||
394 | **Architecture Invariant:** all code invariants are tested by `#[test]` tests. | 395 | **Architecture Invariant:** all code invariants are tested by `#[test]` tests. |
395 | There's no additional checks in CI, formatting and tidy tests are run with `cargo test`. | 396 | There's no additional checks in CI, formatting and tidy tests are run with `cargo test`. |
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 8a6f9f06e..f0f981802 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -1,8 +1,8 @@ | |||
1 | <!--- | 1 | <!--- |
2 | lsp_ext.rs hash: e8a7502bd2b2c2f5 | 2 | lsp_ext.rs hash: 28a9d5a24b7ca396 |
3 | 3 | ||
4 | If you need to change the above hash to make the test pass, please check if you | 4 | If you need to change the above hash to make the test pass, please check if you |
5 | need to adjust this doc as well and ping this issue: | 5 | need to adjust this doc as well and ping this issue: |
6 | 6 | ||
7 | https://github.com/rust-analyzer/rust-analyzer/issues/4604 | 7 | https://github.com/rust-analyzer/rust-analyzer/issues/4604 |
8 | 8 | ||
@@ -46,13 +46,14 @@ If this capability is set, `WorkspaceEdit`s returned from `codeAction` requests | |||
46 | ```typescript | 46 | ```typescript |
47 | interface SnippetTextEdit extends TextEdit { | 47 | interface SnippetTextEdit extends TextEdit { |
48 | insertTextFormat?: InsertTextFormat; | 48 | insertTextFormat?: InsertTextFormat; |
49 | annotationId?: ChangeAnnotationIdentifier; | ||
49 | } | 50 | } |
50 | ``` | 51 | ``` |
51 | 52 | ||
52 | ```typescript | 53 | ```typescript |
53 | export interface TextDocumentEdit { | 54 | export interface TextDocumentEdit { |
54 | textDocument: OptionalVersionedTextDocumentIdentifier; | 55 | textDocument: OptionalVersionedTextDocumentIdentifier; |
55 | edits: (TextEdit | SnippetTextEdit)[]; | 56 | edits: (TextEdit | SnippetTextEdit)[]; |
56 | } | 57 | } |
57 | ``` | 58 | ``` |
58 | 59 | ||
@@ -145,9 +146,9 @@ mod foo; | |||
145 | ### Unresolved Question | 146 | ### Unresolved Question |
146 | 147 | ||
147 | * An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules. | 148 | * An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules. |
148 | This is the approach IntelliJ Rust is takeing. | 149 | This is the approach IntelliJ Rust is taking. |
149 | However, experience shows that super module (which generally has a feeling of navigation between files) should be separate. | 150 | However, experience shows that super module (which generally has a feeling of navigation between files) should be separate. |
150 | If you want super module, but the cursor happens to be inside an overriden function, the behavior with single "gotoSuper" request is surprising. | 151 | If you want super module, but the cursor happens to be inside an overridden function, the behavior with single "gotoSuper" request is surprising. |
151 | 152 | ||
152 | ## Join Lines | 153 | ## Join Lines |
153 | 154 | ||
@@ -193,7 +194,7 @@ fn main() { | |||
193 | ### Unresolved Question | 194 | ### Unresolved Question |
194 | 195 | ||
195 | * What is the position of the cursor after `joinLines`? | 196 | * What is the position of the cursor after `joinLines`? |
196 | Currently this is left to editor's discretion, but it might be useful to specify on the server via snippets. | 197 | Currently, this is left to editor's discretion, but it might be useful to specify on the server via snippets. |
197 | However, it then becomes unclear how it works with multi cursor. | 198 | However, it then becomes unclear how it works with multi cursor. |
198 | 199 | ||
199 | ## On Enter | 200 | ## On Enter |
@@ -330,7 +331,7 @@ Moreover, it would be cool if editors didn't need to implement even basic langua | |||
330 | 331 | ||
331 | ### Unresolved Question | 332 | ### Unresolved Question |
332 | 333 | ||
333 | * Should we return a a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair? | 334 | * Should we return a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair? |
334 | This is how `SelectionRange` request works. | 335 | This is how `SelectionRange` request works. |
335 | * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? | 336 | * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? |
336 | 337 | ||
@@ -419,23 +420,42 @@ Returns internal status message, mostly for debugging purposes. | |||
419 | 420 | ||
420 | Reloads project information (that is, re-executes `cargo metadata`). | 421 | Reloads project information (that is, re-executes `cargo metadata`). |
421 | 422 | ||
422 | ## Status Notification | 423 | ## Server Status |
423 | 424 | ||
424 | **Experimental Client Capability:** `{ "statusNotification": boolean }` | 425 | **Experimental Client Capability:** `{ "serverStatusNotification": boolean }` |
425 | 426 | ||
426 | **Method:** `rust-analyzer/status` | 427 | **Method:** `experimental/serverStatus` |
427 | 428 | ||
428 | **Notification:** | 429 | **Notification:** |
429 | 430 | ||
430 | ```typescript | 431 | ```typescript |
431 | interface StatusParams { | 432 | interface ServerStatusParams { |
432 | status: "loading" | "readyPartial" | "ready" | "invalid" | "needsReload", | 433 | /// `ok` means that the server is completely functional. |
434 | /// | ||
435 | /// `warning` means that the server is partially functional. | ||
436 | /// It can answer correctly to most requests, but some results | ||
437 | /// might be wrong due to, for example, some missing dependencies. | ||
438 | /// | ||
439 | /// `error` means that the server is not functional. For example, | ||
440 | /// there's a fatal build configuration problem. The server might | ||
441 | /// still give correct answers to simple requests, but most results | ||
442 | /// will be incomplete or wrong. | ||
443 | health: "ok" | "warning" | "error", | ||
444 | /// Is there any pending background work which might change the status? | ||
445 | /// For example, are dependencies being downloaded? | ||
446 | quiescent: bool, | ||
447 | /// Explanatory message to show on hover. | ||
448 | message?: string, | ||
433 | } | 449 | } |
434 | ``` | 450 | ``` |
435 | 451 | ||
436 | This notification is sent from server to client. | 452 | This notification is sent from server to client. |
437 | The client can use it to display persistent status to the user (in modline). | 453 | The client can use it to display *persistent* status to the user (in modline). |
438 | For `needsReload` state, the client can provide a context-menu action to run `rust-analyzer/reloadWorkspace` request. | 454 | It is similar to the `showMessage`, but is intended for stares rather than point-in-time events. |
455 | |||
456 | Note that this functionality is intended primarily to inform the end user about the state of the server. | ||
457 | In particular, it's valid for the client to completely ignore this extension. | ||
458 | Clients are discouraged from but are allowed to use the `health` status to decide if it's worth sending a request to the server. | ||
439 | 459 | ||
440 | ## Syntax Tree | 460 | ## Syntax Tree |
441 | 461 | ||
@@ -497,7 +517,7 @@ Expands macro call at a given position. | |||
497 | This request is sent from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types. | 517 | This request is sent from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types. |
498 | Generally, the client should re-query inlay hints after every modification. | 518 | Generally, the client should re-query inlay hints after every modification. |
499 | Note that we plan to move this request to `experimental/inlayHints`, as it is not really Rust-specific, but the current API is not necessary the right one. | 519 | Note that we plan to move this request to `experimental/inlayHints`, as it is not really Rust-specific, but the current API is not necessary the right one. |
500 | Upstream issue: https://github.com/microsoft/language-server-protocol/issues/956 | 520 | Upstream issues: https://github.com/microsoft/language-server-protocol/issues/956 , https://github.com/rust-analyzer/rust-analyzer/issues/2797 |
501 | 521 | ||
502 | **Request:** | 522 | **Request:** |
503 | 523 | ||
@@ -602,12 +622,11 @@ interface TestInfo { | |||
602 | 622 | ||
603 | This request is sent from client to server to move item under cursor or selection in some direction. | 623 | This request is sent from client to server to move item under cursor or selection in some direction. |
604 | 624 | ||
605 | **Method:** `experimental/moveItemUp` | 625 | **Method:** `experimental/moveItem` |
606 | **Method:** `experimental/moveItemDown` | ||
607 | 626 | ||
608 | **Request:** `MoveItemParams` | 627 | **Request:** `MoveItemParams` |
609 | 628 | ||
610 | **Response:** `TextDocumentEdit | null` | 629 | **Response:** `SnippetTextEdit[]` |
611 | 630 | ||
612 | ```typescript | 631 | ```typescript |
613 | export interface MoveItemParams { | 632 | export interface MoveItemParams { |
diff --git a/docs/dev/style.md b/docs/dev/style.md index c594946be..6ab60b50e 100644 --- a/docs/dev/style.md +++ b/docs/dev/style.md | |||
@@ -53,9 +53,9 @@ https://www.tedinski.com/2018/02/06/system-boundaries.html | |||
53 | ## Crates.io Dependencies | 53 | ## Crates.io Dependencies |
54 | 54 | ||
55 | We try to be very conservative with usage of crates.io dependencies. | 55 | We try to be very conservative with usage of crates.io dependencies. |
56 | Don't use small "helper" crates (exception: `itertools` is allowed). | 56 | Don't use small "helper" crates (exception: `itertools` and `either` are allowed). |
57 | If there's some general reusable bit of code you need, consider adding it to the `stdx` crate. | 57 | If there's some general reusable bit of code you need, consider adding it to the `stdx` crate. |
58 | A useful exercise is to read Cargo.lock and see if some of the *transitive* dependencies do not make sense for rust-analyzer. | 58 | A useful exercise is to read Cargo.lock and see if some *transitive* dependencies do not make sense for rust-analyzer. |
59 | 59 | ||
60 | **Rationale:** keep compile times low, create ecosystem pressure for faster compiles, reduce the number of things which might break. | 60 | **Rationale:** keep compile times low, create ecosystem pressure for faster compiles, reduce the number of things which might break. |
61 | 61 | ||
@@ -83,8 +83,19 @@ This makes it easier to prepare a changelog. | |||
83 | 83 | ||
84 | If the change adds a new user-visible functionality, consider recording a GIF with [peek](https://github.com/phw/peek) and pasting it into the PR description. | 84 | If the change adds a new user-visible functionality, consider recording a GIF with [peek](https://github.com/phw/peek) and pasting it into the PR description. |
85 | 85 | ||
86 | To make writing the release notes easier, you can mark a pull request as a feature, fix, internal change, or minor. | ||
87 | Minor changes are excluded from the release notes, while the other types are distributed in their corresponding sections. | ||
88 | There are two ways to mark this: | ||
89 | |||
90 | * use a `feat: `, `feature: `, `fix: `, `internal: ` or `minor: ` prefix in the PR title | ||
91 | * write `changelog [feature|fix|internal|skip] [description]` in a comment or in the PR description; the description is optional, and will replace the title if included. | ||
92 | |||
93 | These comments don't have to be added by the PR author. | ||
94 | Editing a comment or the PR description or title is also fine, as long as it happens before the release. | ||
95 | |||
86 | **Rationale:** clean history is potentially useful, but rarely used. | 96 | **Rationale:** clean history is potentially useful, but rarely used. |
87 | But many users read changelogs. | 97 | But many users read changelogs. |
98 | Including a description and GIF suitable for the changelog means less work for the maintainers on the release day. | ||
88 | 99 | ||
89 | ## Clippy | 100 | ## Clippy |
90 | 101 | ||
@@ -152,6 +163,16 @@ Do not reuse marks between several tests. | |||
152 | 163 | ||
153 | **Rationale:** marks provide an easy way to find the canonical test for each bit of code. | 164 | **Rationale:** marks provide an easy way to find the canonical test for each bit of code. |
154 | This makes it much easier to understand. | 165 | This makes it much easier to understand. |
166 | More than one mark per test / code branch doesn't add significantly to understanding. | ||
167 | |||
168 | ## `#[should_panic]` | ||
169 | |||
170 | Do not use `#[should_panic]` tests. | ||
171 | Instead, explicitly check for `None`, `Err`, etc. | ||
172 | |||
173 | **Rationale:** `#[should_panic]` is a tool for library authors, to makes sure that API does not fail silently, when misused. | ||
174 | `rust-analyzer` is not a library, we don't need to test for API misuse, and we have to handle any user input without panics. | ||
175 | Panic messages in the logs from the `#[should_panic]` tests are confusing. | ||
155 | 176 | ||
156 | ## Function Preconditions | 177 | ## Function Preconditions |
157 | 178 | ||
@@ -330,7 +351,7 @@ When implementing `do_thing`, it might be very useful to create a context object | |||
330 | 351 | ||
331 | ```rust | 352 | ```rust |
332 | pub fn do_thing(arg1: Arg1, arg2: Arg2) -> Res { | 353 | pub fn do_thing(arg1: Arg1, arg2: Arg2) -> Res { |
333 | let mut ctx = Ctx { arg1, arg2 } | 354 | let mut ctx = Ctx { arg1, arg2 }; |
334 | ctx.run() | 355 | ctx.run() |
335 | } | 356 | } |
336 | 357 | ||
@@ -586,7 +607,7 @@ use super::{} | |||
586 | 607 | ||
587 | **Rationale:** consistency. | 608 | **Rationale:** consistency. |
588 | Reading order is important for new contributors. | 609 | Reading order is important for new contributors. |
589 | Grouping by crate allows to spot unwanted dependencies easier. | 610 | Grouping by crate allows spotting unwanted dependencies easier. |
590 | 611 | ||
591 | ## Import Style | 612 | ## Import Style |
592 | 613 | ||
@@ -779,7 +800,7 @@ assert!(x < y); | |||
779 | assert!(x > 0); | 800 | assert!(x > 0); |
780 | 801 | ||
781 | // BAD | 802 | // BAD |
782 | assert!(x >= lo && x <= hi>); | 803 | assert!(x >= lo && x <= hi); |
783 | assert!(r1 < l2 || l1 > r2); | 804 | assert!(r1 < l2 || l1 > r2); |
784 | assert!(y > x); | 805 | assert!(y > x); |
785 | assert!(0 > x); | 806 | assert!(0 > x); |
@@ -842,7 +863,26 @@ Re-using originally single-purpose function often leads to bad coupling. | |||
842 | 863 | ||
843 | ## Helper Variables | 864 | ## Helper Variables |
844 | 865 | ||
845 | Introduce helper variables freely, especially for multiline conditions. | 866 | Introduce helper variables freely, especially for multiline conditions: |
867 | |||
868 | ```rust | ||
869 | // GOOD | ||
870 | let rustfmt_not_installed = | ||
871 | captured_stderr.contains("not installed") || captured_stderr.contains("not available"); | ||
872 | |||
873 | match output.status.code() { | ||
874 | Some(1) if !rustfmt_not_installed => Ok(None), | ||
875 | _ => Err(format_err!("rustfmt failed:\n{}", captured_stderr)), | ||
876 | }; | ||
877 | |||
878 | // BAD | ||
879 | match output.status.code() { | ||
880 | Some(1) | ||
881 | if !captured_stderr.contains("not installed") | ||
882 | && !captured_stderr.contains("not available") => Ok(None), | ||
883 | _ => Err(format_err!("rustfmt failed:\n{}", captured_stderr)), | ||
884 | }; | ||
885 | ``` | ||
846 | 886 | ||
847 | **Rationale:** like blocks, single-use variables are a cognitively cheap abstraction, as they have access to all the context. | 887 | **Rationale:** like blocks, single-use variables are a cognitively cheap abstraction, as they have access to all the context. |
848 | Extra variables help during debugging, they make it easy to print/view important intermediate results. | 888 | Extra variables help during debugging, they make it easy to print/view important intermediate results. |
diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md index 737cc7a72..f7a0c09fc 100644 --- a/docs/dev/syntax.md +++ b/docs/dev/syntax.md | |||
@@ -145,7 +145,7 @@ Another alternative (used by swift and roslyn) is to explicitly divide the set o | |||
145 | 145 | ||
146 | ```rust | 146 | ```rust |
147 | struct Token { | 147 | struct Token { |
148 | kind: NonTriviaTokenKind | 148 | kind: NonTriviaTokenKind, |
149 | text: String, | 149 | text: String, |
150 | leading_trivia: Vec<TriviaToken>, | 150 | leading_trivia: Vec<TriviaToken>, |
151 | trailing_trivia: Vec<TriviaToken>, | 151 | trailing_trivia: Vec<TriviaToken>, |
@@ -240,7 +240,7 @@ impl SyntaxNode { | |||
240 | let child_offset = offset; | 240 | let child_offset = offset; |
241 | offset += green_child.text_len; | 241 | offset += green_child.text_len; |
242 | Arc::new(SyntaxData { | 242 | Arc::new(SyntaxData { |
243 | offset: child_offset; | 243 | offset: child_offset, |
244 | parent: Some(Arc::clone(self)), | 244 | parent: Some(Arc::clone(self)), |
245 | green: Arc::clone(green_child), | 245 | green: Arc::clone(green_child), |
246 | }) | 246 | }) |
@@ -249,7 +249,7 @@ impl SyntaxNode { | |||
249 | } | 249 | } |
250 | 250 | ||
251 | impl PartialEq for SyntaxNode { | 251 | impl PartialEq for SyntaxNode { |
252 | fn eq(&self, other: &SyntaxNode) { | 252 | fn eq(&self, other: &SyntaxNode) -> bool { |
253 | self.offset == other.offset | 253 | self.offset == other.offset |
254 | && Arc::ptr_eq(&self.green, &other.green) | 254 | && Arc::ptr_eq(&self.green, &other.green) |
255 | } | 255 | } |
@@ -273,7 +273,7 @@ This is OK because trees traversals mostly (always, in case of rust-analyzer) ru | |||
273 | The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range. | 273 | The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range. |
274 | You can also use the similar trick to store a `SyntaxNode`. | 274 | You can also use the similar trick to store a `SyntaxNode`. |
275 | That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`. | 275 | That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`. |
276 | However rust-analyzer goes even further. | 276 | However, rust-analyzer goes even further. |
277 | It treats trees as semi-transient and instead of storing a `GreenNode`, it generally stores just the id of the file from which the tree originated: `(FileId, Range<usize>)`. | 277 | It treats trees as semi-transient and instead of storing a `GreenNode`, it generally stores just the id of the file from which the tree originated: `(FileId, Range<usize>)`. |
278 | The `SyntaxNode` is the restored by reparsing the file and traversing it from root. | 278 | The `SyntaxNode` is the restored by reparsing the file and traversing it from root. |
279 | With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage. | 279 | With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage. |