diff --git a/docs/dev/guide.md b/docs/dev/guide.md index 098f5dccb22..650fbfc89f3 100644 --- a/docs/dev/guide.md +++ b/docs/dev/guide.md @@ -79,7 +79,7 @@ group of files which are assumed to rarely change. It's mostly an optimization and does not change the fundamental picture. The `set_crate_graph` method allows us to control how the input files are partitioned -into compilation unites -- crates. It also controls (in theory, not implemented +into compilation units -- crates. It also controls (in theory, not implemented yet) `cfg` flags. `CrateGraph` is a directed acyclic graph of crates. Each crate has a root `FileId`, a set of active `cfg` flags and a set of dependencies. Each dependency is a pair of a crate and a name. It is possible to have two crates @@ -95,7 +95,6 @@ function, and will be inserted into the crate graph just like dependencies. Soon we'll talk how we build an LSP server on top of `Analysis`, but first, let's deal with that paths issue. - ## Source roots (a.k.a. "Filesystems are horrible") This is a non-essential section, feel free to skip. @@ -104,18 +103,18 @@ The previous section said that the filesystem path is an attribute of a file, but this is not the whole truth. Making it an absolute `PathBuf` will be bad for several reasons. First, filesystems are full of (platform-dependent) edge cases: -* it's hard (requires a syscall) to decide if two paths are equivalent -* some filesystems are case-sensitive (e.g. on macOS) -* paths are not necessary UTF-8 -* symlinks can form cycles +* It's hard (requires a syscall) to decide if two paths are equivalent. +* Some filesystems are case-sensitive (e.g. macOS). +* Paths are not necessarily UTF-8. +* Symlinks can form cycles. -Second, this might hurt reproducibility and hermeticity of builds. In theory, +Second, this might hurt the reproducibility and hermeticity of builds. In theory, moving a project from `/foo/bar/my-project` to `/spam/eggs/my-project` should not change a bit in the output. However, if the absolute path is a part of the input, it is at least in theory observable, and *could* affect the output. Yet another problem is that we really *really* want to avoid doing I/O, but with -Rust the set of "input" files is not necessary known up-front. In theory, you +Rust the set of "input" files is not necessarily known up-front. In theory, you can have `#[path="/dev/random"] mod foo;`. To solve (or explicitly refuse to solve) these problems rust-analyzer uses the @@ -205,7 +204,7 @@ fact that most of the changes are small, and that analysis results are unlikely to change significantly between invocations. To do this we use [salsa]: a framework for incremental on-demand computation. -You can skip the rest of the section if you are familiar with rustc's red-green +You can skip the rest of the section if you are familiar with `rustc`'s red-green algorithm (which is used for incremental compilation). [salsa]: https://github.com/salsa-rs/salsa @@ -220,12 +219,11 @@ of type `V`. Queries come in two basic varieties: like. * **Functions**: pure functions (no side effects) that transform your inputs - into other values. The results of queries is memoized to avoid recomputing + into other values. The results of queries are memoized to avoid recomputing them a lot. When you make changes to the inputs, we'll figure out (fairly intelligently) when we can re-use these memoized values and when we have to recompute them. - For further discussion, its important to understand one bit of "fairly intelligently". Suppose we have two functions, `f1` and `f2`, and one input, `z`. We call `f1(X)` which in turn calls `f2(Y)` which inspects `i(Z)`. `i(Z)` @@ -267,13 +265,13 @@ The bulk of the rust-analyzer is transforming input text into a semantic model o Rust code: a web of entities like modules, structs, functions and traits. An important fact to realize is that (unlike most other languages like C# or -Java) there isn't a one-to-one mapping between source code and the semantic model. A +Java) there is not a one-to-one mapping between the source code and the semantic model. A single function definition in the source code might result in several semantic -functions: for example, the same source file might be included as a module into -several crate, or a single "crate" might be present in the compilation DAG +functions: for example, the same source file might get included as a module in +several crates or a single crate might be present in the compilation DAG several times, with different sets of `cfg`s enabled. The IDE-specific task of -mapping source code position into a semantic model is inherently imprecise for -this reason, and is handled by the [`source_binder`]. +mapping source code into a semantic model is inherently imprecise for +this reason and gets handled by the [`source_binder`]. [`source_binder`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/hir/src/source_binder.rs @@ -533,18 +531,18 @@ To conclude the overview of the rust-analyzer, let's trace the request for We start by [receiving a message] from the language client. We decode the message as a request for completion and [schedule it on the threadpool]. This is -the also place where we [catch] canceled errors if, immediately after completion, the +the place where we [catch] canceled errors if, immediately after completion, the client sends some modification. -In [the handler] we a deserialize LSP request into the rust-analyzer specific data +In [the handler], we deserialize LSP requests into rust-analyzer specific data types (by converting a file url into a numeric `FileId`), [ask analysis for -completion] and serializer results to LSP. +completion] and serialize results into the LSP. The [completion implementation] is finally the place where we start doing the actual work. The first step is to collect the `CompletionContext` -- a struct which describes the cursor position in terms of Rust syntax and semantics. For example, `function_syntax: Option<&'a ast::FnDef>` stores a reference to -enclosing function *syntax*, while `function: Option` is the +the enclosing function *syntax*, while `function: Option` is the `Def` for this function. To construct the context, we first do an ["IntelliJ Trick"]: we insert a dummy diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 78e14b01e45..b73a7487637 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -656,7 +656,7 @@ interface TestInfo { } ``` -## Hover Actions +## Move Item **Issue:** https://github.com/rust-analyzer/rust-analyzer/issues/6823 diff --git a/docs/dev/style.md b/docs/dev/style.md index 01daf948cea..6309fd02ce4 100644 --- a/docs/dev/style.md +++ b/docs/dev/style.md @@ -170,7 +170,7 @@ More than one mark per test / code branch doesn't add significantly to understan Do not use `#[should_panic]` tests. Instead, explicitly check for `None`, `Err`, etc. -**Rationale:** `#[should_panic]` is a tool for library authors, to makes sure that API does not fail silently, when misused. +**Rationale:** `#[should_panic]` is a tool for library authors to make sure that the API does not fail silently when misused. `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. Panic messages in the logs from the `#[should_panic]` tests are confusing. @@ -333,7 +333,7 @@ impl Foo { } ``` -Prefer `Default` even it has to be implemented manually. +Prefer `Default` even if it has to be implemented manually. **Rationale:** less typing in the common case, uniformity. @@ -343,7 +343,7 @@ Use `Vec::new` rather than `vec![]`. Avoid using "dummy" states to implement a `Default`. If a type doesn't have a sensible default, empty value, don't hide it. -Let the caller explicitly decide what's the right initial state is. +Let the caller explicitly decide what the right initial state is. ## Functions Over Objects @@ -526,7 +526,7 @@ if words.len() != 2 { } ``` -**Rationale:** not allocating is almost often faster. +**Rationale:** not allocating is almost always faster. ## Push Allocations to the Call Site @@ -998,9 +998,9 @@ match output.status.code() { }; ``` -**Rationale:** like blocks, single-use variables are a cognitively cheap abstraction, as they have access to all the context. +**Rationale:** Like blocks, single-use variables are a cognitively cheap abstraction, as they have access to all the context. Extra variables help during debugging, they make it easy to print/view important intermediate results. -Giving a name to a condition in `if` expression often improves clarity and leads to a nicer formatted code. +Giving a name to a condition inside an `if` expression often improves clarity and leads to nicely formatted code. ## Token names diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md index f7a0c09fc1e..5a065e00ef6 100644 --- a/docs/dev/syntax.md +++ b/docs/dev/syntax.md @@ -6,7 +6,7 @@ This guide describes the current state of syntax trees and parsing in rust-analy ## Source Code -The things described are implemented in two places +The things described are implemented in three places * [rowan](https://github.com/rust-analyzer/rowan/tree/v0.9.0) -- a generic library for rowan syntax trees. * [ra_syntax](https://github.com/rust-analyzer/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/ra_syntax) crate inside rust-analyzer which wraps `rowan` into rust-analyzer specific API. @@ -15,9 +15,9 @@ The things described are implemented in two places ## Design Goals -* Syntax trees are lossless, or full fidelity. All comments and whitespace are preserved. +* Syntax trees are lossless, or full fidelity. All comments and whitespace get preserved. * Syntax trees are semantic-less. They describe *strictly* the structure of a sequence of characters, they don't have hygiene, name resolution or type information attached. -* Syntax trees are simple value type. It is possible to create trees for a syntax without any external context. +* Syntax trees are simple value types. It is possible to create trees for a syntax without any external context. * Syntax trees have intuitive traversal API (parent, children, siblings, etc). * Parsing is lossless (even if the input is invalid, the tree produced by the parser represents it exactly). * Parsing is resilient (even if the input is invalid, parser tries to see as much syntax tree fragments in the input as it can).