8382: Make Fixture docs more accessible and fix small doc issues r=SomeoneToIgnore a=SomeoneToIgnore

Follow up of https://github.com/rust-analyzer/rust-analyzer/pull/8302#discussion_r607054896

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
This commit is contained in:
bors[bot] 2021-04-06 22:23:41 +00:00 committed by GitHub
commit a35f7cb635
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 88 additions and 85 deletions

View file

@ -14,4 +14,4 @@ Any other editor plugins that integrate with `rust-analyzer` are not under the c
## Others ## Others
If `cargo check` is enabled (the default), any build scripts or procedural macros used by the project or its dependencies will be executed. This is also the case when `cargo check` is disabled, but build script or procedural macro support is enabled in `rust-analyzer` (off by default). If `cargo check` is enabled (the default), any build scripts or procedural macros used by the project or its dependencies will be executed. This is also the case when `cargo check` is disabled, but build script or procedural macro support is enabled in `rust-analyzer` (on by default).

View file

@ -33,9 +33,9 @@ For usage and troubleshooting requests, please use "IDEs and Editors" category o
https://users.rust-lang.org/c/ide/14 https://users.rust-lang.org/c/ide/14
For questions about development and implementation, join rls-2.0 working group on Zulip: For questions about development and implementation, join rust-analyzer working group on Zulip:
https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0 https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
## Quick Links ## Quick Links

View file

@ -1,62 +1,4 @@
//! Fixtures are strings containing rust source code with optional metadata. //! A set of high-level utility fixture methods to use in tests.
//! A fixture without metadata is parsed into a single source file.
//! Use this to test functionality local to one file.
//!
//! Simple Example:
//! ```
//! r#"
//! fn main() {
//! println!("Hello World")
//! }
//! "#
//! ```
//!
//! Metadata can be added to a fixture after a `//-` comment.
//! The basic form is specifying filenames,
//! which is also how to define multiple files in a single test fixture
//!
//! Example using two files in the same crate:
//! ```
//! "
//! //- /main.rs
//! mod foo;
//! fn main() {
//! foo::bar();
//! }
//!
//! //- /foo.rs
//! pub fn bar() {}
//! "
//! ```
//!
//! Example using two crates with one file each, with one crate depending on the other:
//! ```
//! r#"
//! //- /main.rs crate:a deps:b
//! fn main() {
//! b::foo();
//! }
//! //- /lib.rs crate:b
//! pub fn b() {
//! println!("Hello World")
//! }
//! "#
//! ```
//!
//! Metadata allows specifying all settings and variables
//! that are available in a real rust project:
//! - crate names via `crate:cratename`
//! - dependencies via `deps:dep1,dep2`
//! - configuration settings via `cfg:dbg=false,opt_level=2`
//! - environment variables via `env:PATH=/bin,RUST_LOG=debug`
//!
//! Example using all available metadata:
//! ```
//! "
//! //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
//! fn insert_source_code_here() {}
//! "
//! ```
use std::{mem, str::FromStr, sync::Arc}; use std::{mem, str::FromStr, sync::Arc};
use cfg::CfgOptions; use cfg::CfgOptions;

View file

@ -1,5 +1,65 @@
//! Defines `Fixture` -- a convenient way to describe the initial state of //! Defines `Fixture` -- a convenient way to describe the initial state of
//! rust-analyzer database from a single string. //! rust-analyzer database from a single string.
//!
//! Fixtures are strings containing rust source code with optional metadata.
//! A fixture without metadata is parsed into a single source file.
//! Use this to test functionality local to one file.
//!
//! Simple Example:
//! ```
//! r#"
//! fn main() {
//! println!("Hello World")
//! }
//! "#
//! ```
//!
//! Metadata can be added to a fixture after a `//-` comment.
//! The basic form is specifying filenames,
//! which is also how to define multiple files in a single test fixture
//!
//! Example using two files in the same crate:
//! ```
//! "
//! //- /main.rs
//! mod foo;
//! fn main() {
//! foo::bar();
//! }
//!
//! //- /foo.rs
//! pub fn bar() {}
//! "
//! ```
//!
//! Example using two crates with one file each, with one crate depending on the other:
//! ```
//! r#"
//! //- /main.rs crate:a deps:b
//! fn main() {
//! b::foo();
//! }
//! //- /lib.rs crate:b
//! pub fn b() {
//! println!("Hello World")
//! }
//! "#
//! ```
//!
//! Metadata allows specifying all settings and variables
//! that are available in a real rust project:
//! - crate names via `crate:cratename`
//! - dependencies via `deps:dep1,dep2`
//! - configuration settings via `cfg:dbg=false,opt_level=2`
//! - environment variables via `env:PATH=/bin,RUST_LOG=debug`
//!
//! Example using all available metadata:
//! ```
//! "
//! //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
//! fn insert_source_code_here() {}
//! "
//! ```
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use stdx::{lines_with_ends, split_once, trim_indent}; use stdx::{lines_with_ends, split_once, trim_indent};
@ -24,7 +84,7 @@ impl Fixture {
/// //- some meta /// //- some meta
/// line 1 /// line 1
/// line 2 /// line 2
/// // - other meta /// //- other meta
/// ``` /// ```
pub fn parse(ra_fixture: &str) -> Vec<Fixture> { pub fn parse(ra_fixture: &str) -> Vec<Fixture> {
let fixture = trim_indent(ra_fixture); let fixture = trim_indent(ra_fixture);

View file

@ -42,7 +42,7 @@ The underlying engine makes sure that model is computed lazily (on-demand) and c
## Entry Points ## Entry Points
`crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP. `crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP.
This is *the* entry point, but it front-loads a lot of complexity, so its fine to just skim through it. This is *the* entry point, but it front-loads a lot of complexity, so it's fine to just skim through it.
`crates/rust-analyzer/src/handlers.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP. `crates/rust-analyzer/src/handlers.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP.
@ -67,7 +67,7 @@ They are handled by Rust code in the xtask directory.
VS Code plugin. VS Code plugin.
### `libs/` ### `lib/`
rust-analyzer independent libraries which we publish to crates.io. rust-analyzer independent libraries which we publish to crates.io.
It's not heavily utilized at the moment. 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
### `crates/base_db` ### `crates/base_db`
We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation. We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation.
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. 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.
Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer. Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer.
Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs. Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs.
@ -221,7 +222,7 @@ Internally, `ide` is split across several crates. `ide_assists`, `ide_completion
The `ide` contains a public API/façade, as well as implementation for a plethora of smaller features. The `ide` contains a public API/façade, as well as implementation for a plethora of smaller features.
**Architecture Invariant:** `ide` crate strives to provide a _perfect_ API. **Architecture Invariant:** `ide` crate strives to provide a _perfect_ API.
Although at the moment it has only one consumer, the LSP server, LSP *does not* influence it's API design. Although at the moment it has only one consumer, the LSP server, LSP *does not* influence its API design.
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. 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.
### `crates/rust-analyzer` ### `crates/rust-analyzer`
@ -307,7 +308,7 @@ This sections talks about the things which are everywhere and nowhere in particu
### Code generation ### Code generation
Some of the components of this repository are generated through automatic processes. Some ]components in this repository are generated through automatic processes.
Generated code is updated automatically on `cargo test`. Generated code is updated automatically on `cargo test`.
Generated code is generally committed to the git repository. Generated code is generally committed to the git repository.
@ -389,7 +390,7 @@ fn spam() {
``` ```
To specify input data, we use a single string literal in a special format, which can describe a set of rust files. To specify input data, we use a single string literal in a special format, which can describe a set of rust files.
See the `Fixture` type. See the `Fixture` its module for fixture examples and documentation.
**Architecture Invariant:** all code invariants are tested by `#[test]` tests. **Architecture Invariant:** all code invariants are tested by `#[test]` tests.
There's no additional checks in CI, formatting and tidy tests are run with `cargo test`. There's no additional checks in CI, formatting and tidy tests are run with `cargo test`.

View file

@ -51,8 +51,8 @@ interface SnippetTextEdit extends TextEdit {
```typescript ```typescript
export interface TextDocumentEdit { export interface TextDocumentEdit {
textDocument: OptionalVersionedTextDocumentIdentifier; textDocument: OptionalVersionedTextDocumentIdentifier;
edits: (TextEdit | SnippetTextEdit)[]; edits: (TextEdit | SnippetTextEdit)[];
} }
``` ```
@ -145,9 +145,9 @@ mod foo;
### Unresolved Question ### Unresolved Question
* An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules. * An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules.
This is the approach IntelliJ Rust is takeing. This is the approach IntelliJ Rust is taking.
However, experience shows that super module (which generally has a feeling of navigation between files) should be separate. However, experience shows that super module (which generally has a feeling of navigation between files) should be separate.
If you want super module, but the cursor happens to be inside an overriden function, the behavior with single "gotoSuper" request is surprising. If you want super module, but the cursor happens to be inside an overridden function, the behavior with single "gotoSuper" request is surprising.
## Join Lines ## Join Lines
@ -193,7 +193,7 @@ fn main() {
### Unresolved Question ### Unresolved Question
* What is the position of the cursor after `joinLines`? * What is the position of the cursor after `joinLines`?
Currently this is left to editor's discretion, but it might be useful to specify on the server via snippets. Currently, this is left to editor's discretion, but it might be useful to specify on the server via snippets.
However, it then becomes unclear how it works with multi cursor. However, it then becomes unclear how it works with multi cursor.
## On Enter ## On Enter
@ -330,7 +330,7 @@ Moreover, it would be cool if editors didn't need to implement even basic langua
### Unresolved Question ### Unresolved Question
* Should we return a a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair? * Should we return a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair?
This is how `SelectionRange` request works. This is how `SelectionRange` request works.
* Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs?
@ -511,7 +511,7 @@ Expands macro call at a given position.
This request is sent from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types. This request is sent from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types.
Generally, the client should re-query inlay hints after every modification. Generally, the client should re-query inlay hints after every modification.
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. 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.
Upstream issue: https://github.com/microsoft/language-server-protocol/issues/956 Upstream issues: https://github.com/microsoft/language-server-protocol/issues/956 , https://github.com/rust-analyzer/rust-analyzer/issues/2797
**Request:** **Request:**

View file

@ -53,9 +53,9 @@ https://www.tedinski.com/2018/02/06/system-boundaries.html
## Crates.io Dependencies ## Crates.io Dependencies
We try to be very conservative with usage of crates.io dependencies. We try to be very conservative with usage of crates.io dependencies.
Don't use small "helper" crates (exception: `itertools` is allowed). Don't use small "helper" crates (exception: `itertools` and `either` are allowed).
If there's some general reusable bit of code you need, consider adding it to the `stdx` crate. If there's some general reusable bit of code you need, consider adding it to the `stdx` crate.
A useful exercise is to read Cargo.lock and see if some of the *transitive* dependencies do not make sense for rust-analyzer. A useful exercise is to read Cargo.lock and see if some *transitive* dependencies do not make sense for rust-analyzer.
**Rationale:** keep compile times low, create ecosystem pressure for faster compiles, reduce the number of things which might break. **Rationale:** keep compile times low, create ecosystem pressure for faster compiles, reduce the number of things which might break.
@ -330,7 +330,7 @@ When implementing `do_thing`, it might be very useful to create a context object
```rust ```rust
pub fn do_thing(arg1: Arg1, arg2: Arg2) -> Res { pub fn do_thing(arg1: Arg1, arg2: Arg2) -> Res {
let mut ctx = Ctx { arg1, arg2 } let mut ctx = Ctx { arg1, arg2 };
ctx.run() ctx.run()
} }
@ -586,7 +586,7 @@ use super::{}
**Rationale:** consistency. **Rationale:** consistency.
Reading order is important for new contributors. Reading order is important for new contributors.
Grouping by crate allows to spot unwanted dependencies easier. Grouping by crate allows spotting unwanted dependencies easier.
## Import Style ## Import Style
@ -779,7 +779,7 @@ assert!(x < y);
assert!(x > 0); assert!(x > 0);
// BAD // BAD
assert!(x >= lo && x <= hi>); assert!(x >= lo && x <= hi);
assert!(r1 < l2 || l1 > r2); assert!(r1 < l2 || l1 > r2);
assert!(y > x); assert!(y > x);
assert!(0 > x); assert!(0 > x);

View file

@ -145,7 +145,7 @@ Another alternative (used by swift and roslyn) is to explicitly divide the set o
```rust ```rust
struct Token { struct Token {
kind: NonTriviaTokenKind kind: NonTriviaTokenKind,
text: String, text: String,
leading_trivia: Vec<TriviaToken>, leading_trivia: Vec<TriviaToken>,
trailing_trivia: Vec<TriviaToken>, trailing_trivia: Vec<TriviaToken>,
@ -240,7 +240,7 @@ impl SyntaxNode {
let child_offset = offset; let child_offset = offset;
offset += green_child.text_len; offset += green_child.text_len;
Arc::new(SyntaxData { Arc::new(SyntaxData {
offset: child_offset; offset: child_offset,
parent: Some(Arc::clone(self)), parent: Some(Arc::clone(self)),
green: Arc::clone(green_child), green: Arc::clone(green_child),
}) })
@ -249,7 +249,7 @@ impl SyntaxNode {
} }
impl PartialEq for SyntaxNode { impl PartialEq for SyntaxNode {
fn eq(&self, other: &SyntaxNode) { fn eq(&self, other: &SyntaxNode) -> bool {
self.offset == other.offset self.offset == other.offset
&& Arc::ptr_eq(&self.green, &other.green) && Arc::ptr_eq(&self.green, &other.green)
} }
@ -273,7 +273,7 @@ This is OK because trees traversals mostly (always, in case of rust-analyzer) ru
The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range. The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range.
You can also use the similar trick to store a `SyntaxNode`. You can also use the similar trick to store a `SyntaxNode`.
That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`. That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`.
However rust-analyzer goes even further. However, rust-analyzer goes even further.
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>)`. 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>)`.
The `SyntaxNode` is the restored by reparsing the file and traversing it from root. The `SyntaxNode` is the restored by reparsing the file and traversing it from root.
With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage. With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage.