diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/dev/README.md | 8 | ||||
-rw-r--r-- | docs/dev/architecture.md | 105 | ||||
-rw-r--r-- | docs/dev/lsp-extensions.md | 2 | ||||
-rw-r--r-- | docs/dev/style.md | 12 | ||||
-rw-r--r-- | docs/dev/syntax.md | 29 |
5 files changed, 104 insertions, 52 deletions
diff --git a/docs/dev/README.md b/docs/dev/README.md index 9c0af68e3..9b9b18102 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -114,6 +114,14 @@ npm run lint | |||
114 | 114 | ||
115 | Do see [./style.md](./style.md). | 115 | Do see [./style.md](./style.md). |
116 | 116 | ||
117 | # How to ... | ||
118 | |||
119 | * ... add an assist? [#7535](https://github.com/rust-analyzer/rust-analyzer/pull/7535) | ||
120 | * ... add a new protocol extension? [#4569](https://github.com/rust-analyzer/rust-analyzer/pull/4569) | ||
121 | * ... add a new configuration option? [#7451](https://github.com/rust-analyzer/rust-analyzer/pull/7451) | ||
122 | * ... add a new completion? [#6964](https://github.com/rust-analyzer/rust-analyzer/pull/6964) | ||
123 | * ... allow new syntax in the parser? [#7338](https://github.com/rust-analyzer/rust-analyzer/pull/7338) | ||
124 | |||
117 | # Logging | 125 | # Logging |
118 | 126 | ||
119 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to | 127 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to |
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index feda20dd7..56ebaa3df 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md | |||
@@ -9,9 +9,9 @@ Yet another resource is this playlist with videos about various parts of the ana | |||
9 | 9 | ||
10 | https://www.youtube.com/playlist?list=PL85XCvVPmGQho7MZkdW-wtPtuJcFpzycE | 10 | https://www.youtube.com/playlist?list=PL85XCvVPmGQho7MZkdW-wtPtuJcFpzycE |
11 | 11 | ||
12 | Note that the guide and videos are pretty dated, this document should be in generally fresher. | 12 | Note that the guide and videos are pretty dated, this document should be, in general, fresher. |
13 | 13 | ||
14 | See also this implementation-oriented blog posts: | 14 | See also these implementation-related blog posts: |
15 | 15 | ||
16 | * https://rust-analyzer.github.io/blog/2019/11/13/find-usages.html | 16 | * https://rust-analyzer.github.io/blog/2019/11/13/find-usages.html |
17 | * https://rust-analyzer.github.io/blog/2020/07/20/three-architectures-for-responsive-ide.html | 17 | * https://rust-analyzer.github.io/blog/2020/07/20/three-architectures-for-responsive-ide.html |
@@ -27,9 +27,9 @@ On the highest level, rust-analyzer is a thing which accepts input source code f | |||
27 | 27 | ||
28 | More specifically, input data consists of a set of test files (`(PathBuf, String)` pairs) and information about project structure, captured in the so called `CrateGraph`. | 28 | More specifically, input data consists of a set of test files (`(PathBuf, String)` pairs) and information about project structure, captured in the so called `CrateGraph`. |
29 | The crate graph specifies which files are crate roots, which cfg flags are specified for each crate and what dependencies exist between the crates. | 29 | The crate graph specifies which files are crate roots, which cfg flags are specified for each crate and what dependencies exist between the crates. |
30 | This the input (ground) state. | 30 | This is the input (ground) state. |
31 | The analyzer keeps all this input data in memory and never does any IO. | 31 | The analyzer keeps all this input data in memory and never does any IO. |
32 | Because the input data are source code, which typically measures in tens of megabytes at most, keeping everything in memory is OK. | 32 | Because the input data is source code, which typically measures in tens of megabytes at most, keeping everything in memory is OK. |
33 | 33 | ||
34 | A "structured semantic model" is basically an object-oriented representation of modules, functions and types which appear in the source code. | 34 | A "structured semantic model" is basically an object-oriented representation of modules, functions and types which appear in the source code. |
35 | This representation is fully "resolved": all expressions have types, all references are bound to declarations, etc. | 35 | This representation is fully "resolved": all expressions have types, all references are bound to declarations, etc. |
@@ -42,7 +42,7 @@ The underlying engine makes sure that model is computed lazily (on-demand) and c | |||
42 | 42 | ||
43 | ## Code Map | 43 | ## Code Map |
44 | 44 | ||
45 | This section talks briefly about various important directories an data structures. | 45 | This section talks briefly about various important directories and data structures. |
46 | Pay attention to the **Architecture Invariant** sections. | 46 | Pay attention to the **Architecture Invariant** sections. |
47 | They often talk about things which are deliberately absent in the source code. | 47 | They often talk about things which are deliberately absent in the source code. |
48 | 48 | ||
@@ -62,7 +62,7 @@ VS Code plugin. | |||
62 | ### `libs/` | 62 | ### `libs/` |
63 | 63 | ||
64 | rust-analyzer independent libraries which we publish to crates.io. | 64 | rust-analyzer independent libraries which we publish to crates.io. |
65 | It not heavily utilized at the moment. | 65 | It's not heavily utilized at the moment. |
66 | 66 | ||
67 | ### `crates/parser` | 67 | ### `crates/parser` |
68 | 68 | ||
@@ -110,19 +110,19 @@ in particular: it shows off various methods of working with syntax tree. | |||
110 | 110 | ||
111 | See [#93](https://github.com/rust-analyzer/rust-analyzer/pull/93) for an example PR which fixes a bug in the grammar. | 111 | See [#93](https://github.com/rust-analyzer/rust-analyzer/pull/93) for an example PR which fixes a bug in the grammar. |
112 | 112 | ||
113 | **Architecture Invariant:** `syntax` crate is completely independent from the rest of rust-analyzer, it knows nothing about salsa or LSP. | 113 | **Architecture Invariant:** `syntax` crate is completely independent from the rest of rust-analyzer. It knows nothing about salsa or LSP. |
114 | This is important because it is possible to useful tooling using only syntax tree. | 114 | This is important because it is possible to make useful tooling using only the syntax tree. |
115 | Without semantic information, you don't need to be able to _build_ code, which makes the tooling more robust. | 115 | Without semantic information, you don't need to be able to _build_ code, which makes the tooling more robust. |
116 | See also https://web.stanford.edu/~mlfbrown/paper.pdf. | 116 | See also https://web.stanford.edu/~mlfbrown/paper.pdf. |
117 | You can view the `syntax` crate as an entry point to rust-analyzer. | 117 | You can view the `syntax` crate as an entry point to rust-analyzer. |
118 | `sytax` crate is an **API Boundary**. | 118 | `syntax` crate is an **API Boundary**. |
119 | 119 | ||
120 | **Architecture Invariant:** syntax tree is a value type. | 120 | **Architecture Invariant:** syntax tree is a value type. |
121 | The tree is fully determined by the contents of its syntax nodes, it doesn't need global context (like an interner) and doesn't store semantic info. | 121 | The tree is fully determined by the contents of its syntax nodes, it doesn't need global context (like an interner) and doesn't store semantic info. |
122 | Using the tree as a store for semantic info is convenient in traditional compilers, but doesn't work nicely in the IDE. | 122 | Using the tree as a store for semantic info is convenient in traditional compilers, but doesn't work nicely in the IDE. |
123 | Specifically, assists and refactors require transforming syntax trees, and that becomes awkward if you need to do something with the semantic info. | 123 | Specifically, assists and refactors require transforming syntax trees, and that becomes awkward if you need to do something with the semantic info. |
124 | 124 | ||
125 | **Architecture Invariant:** syntax tree is build for a single file. | 125 | **Architecture Invariant:** syntax tree is built for a single file. |
126 | This is to enable parallel parsing of all files. | 126 | This is to enable parallel parsing of all files. |
127 | 127 | ||
128 | **Architecture Invariant:** Syntax trees are by design incomplete and do not enforce well-formedness. | 128 | **Architecture Invariant:** Syntax trees are by design incomplete and do not enforce well-formedness. |
@@ -131,7 +131,7 @@ If an AST method returns an `Option`, it *can* be `None` at runtime, even if thi | |||
131 | ### `crates/base_db` | 131 | ### `crates/base_db` |
132 | 132 | ||
133 | We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation. | 133 | We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation. |
134 | Roughly, you can think of salsa as a key-value store, but it also can compute derived values using specified functions. The `base_db` crate provides basic infrastructure for interacting with salsa. | 134 | 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. |
135 | Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer. | 135 | Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer. |
136 | Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs. | 136 | Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs. |
137 | 137 | ||
@@ -160,11 +160,11 @@ These crates also define various intermediate representations of the core. | |||
160 | 160 | ||
161 | `Body` stores information about expressions. | 161 | `Body` stores information about expressions. |
162 | 162 | ||
163 | **Architecture Invariant:** this crates are not, and will never be, an api boundary. | 163 | **Architecture Invariant:** these crates are not, and will never be, an api boundary. |
164 | 164 | ||
165 | **Architecture Invariant:** these creates explicitly care about being incremental. | 165 | **Architecture Invariant:** these crates explicitly care about being incremental. |
166 | The core invariant we maintain is "typing inside a function's body never invalidates global derived data". | 166 | The core invariant we maintain is "typing inside a function's body never invalidates global derived data". |
167 | Ie, if you change body of `foo`, all facts about `bar` should remain intact. | 167 | i.e., if you change the body of `foo`, all facts about `bar` should remain intact. |
168 | 168 | ||
169 | **Architecture Invariant:** hir exists only in context of particular crate instance with specific CFG flags. | 169 | **Architecture Invariant:** hir exists only in context of particular crate instance with specific CFG flags. |
170 | The same syntax may produce several instances of HIR if the crate participates in the crate graph more than once. | 170 | The same syntax may produce several instances of HIR if the crate participates in the crate graph more than once. |
@@ -188,24 +188,24 @@ We first resolve the parent _syntax_ node to the parent _hir_ element. | |||
188 | Then we ask the _hir_ parent what _syntax_ children does it have. | 188 | Then we ask the _hir_ parent what _syntax_ children does it have. |
189 | Then we look for our node in the set of children. | 189 | Then we look for our node in the set of children. |
190 | 190 | ||
191 | This is the heart of many IDE features, like goto definition, which start with figuring out a hir node at the cursor. | 191 | This is the heart of many IDE features, like goto definition, which start with figuring out the hir node at the cursor. |
192 | This is some kind of (yet unnamed) uber-IDE pattern, as it is present in Roslyn and Kotlin as well. | 192 | This is some kind of (yet unnamed) uber-IDE pattern, as it is present in Roslyn and Kotlin as well. |
193 | 193 | ||
194 | ### `crates/ide` | 194 | ### `crates/ide` |
195 | 195 | ||
196 | The `ide` crate build's on top of `hir` semantic model to provide high-level IDE features like completion or goto definition. | 196 | The `ide` crate builds on top of `hir` semantic model to provide high-level IDE features like completion or goto definition. |
197 | It is an **API Boundary**. | 197 | It is an **API Boundary**. |
198 | If you want to use IDE parts of rust-analyzer via LSP, custom flatbuffers-based protocol or just as a library in your text editor, this is the right API. | 198 | If you want to use IDE parts of rust-analyzer via LSP, custom flatbuffers-based protocol or just as a library in your text editor, this is the right API. |
199 | 199 | ||
200 | **Architecture Invariant:** `ide` crate's API is build out of POD types with public fields. | 200 | **Architecture Invariant:** `ide` crate's API is build out of POD types with public fields. |
201 | The API uses editor's terminology, it talks about offsets and string labels rathe than in terms of definitions or types. | 201 | The API uses editor's terminology, it talks about offsets and string labels rather than in terms of definitions or types. |
202 | It is effectively the view in MVC and viewmodel in [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel). | 202 | It is effectively the view in MVC and viewmodel in [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel). |
203 | All arguments and return types are conceptually serializable. | 203 | All arguments and return types are conceptually serializable. |
204 | In particular, syntax tress and and hir types are generally absent from the API (but are used heavily in the implementation). | 204 | In particular, syntax tress and and hir types are generally absent from the API (but are used heavily in the implementation). |
205 | Shout outs to LSP developers for popularizing the idea that "UI" is a good place to draw a boundary at. | 205 | Shout outs to LSP developers for popularizing the idea that "UI" is a good place to draw a boundary at. |
206 | 206 | ||
207 | `ide` is also the first crate which has the notion of change over time. | 207 | `ide` is also the first crate which has the notion of change over time. |
208 | `AnalysisHost` is a state to which you can transactonally `apply_change`. | 208 | `AnalysisHost` is a state to which you can transactionally `apply_change`. |
209 | `Analysis` is an immutable snapshot of the state. | 209 | `Analysis` is an immutable snapshot of the state. |
210 | 210 | ||
211 | Internally, `ide` is split across several crates. `ide_assists`, `ide_completion` and `ide_ssr` implement large isolated features. | 211 | Internally, `ide` is split across several crates. `ide_assists`, `ide_completion` and `ide_ssr` implement large isolated features. |
@@ -232,7 +232,7 @@ All other requests are processed in background. | |||
232 | 232 | ||
233 | **Architecture Invariant:** the server is stateless, a-la HTTP. | 233 | **Architecture Invariant:** the server is stateless, a-la HTTP. |
234 | Sometimes state needs to be preserved between requests. | 234 | Sometimes state needs to be preserved between requests. |
235 | For example, "what is the `edit` for the fifth's completion item of the last completion edit?". | 235 | For example, "what is the `edit` for the fifth completion item of the last completion edit?". |
236 | For this, the second request should include enough info to re-create the context from scratch. | 236 | For this, the second request should include enough info to re-create the context from scratch. |
237 | This generally means including all the parameters of the original request. | 237 | This generally means including all the parameters of the original request. |
238 | 238 | ||
@@ -249,23 +249,28 @@ These crates deal with invoking `cargo` to learn about project structure and get | |||
249 | They use `crates/path` heavily instead of `std::path`. | 249 | They use `crates/path` heavily instead of `std::path`. |
250 | A single `rust-analyzer` process can serve many projects, so it is important that server's current directory does not leak. | 250 | A single `rust-analyzer` process can serve many projects, so it is important that server's current directory does not leak. |
251 | 251 | ||
252 | ### `crates/mbe`, `crated/tt`, `crates/proc_macro_api`, `crates/proc_macro_srv` | 252 | ### `crates/mbe`, `crates/tt`, `crates/proc_macro_api`, `crates/proc_macro_srv` |
253 | 253 | ||
254 | These crates implement macros as token tree -> token tree transforms. | 254 | These crates implement macros as token tree -> token tree transforms. |
255 | They are independent from the rest of the code. | 255 | They are independent from the rest of the code. |
256 | 256 | ||
257 | ### `crates/cfg` | ||
258 | |||
259 | This crate is responsible for parsing, evaluation and general definition of `cfg` attributes. | ||
260 | |||
257 | ### `crates/vfs`, `crates/vfs-notify` | 261 | ### `crates/vfs`, `crates/vfs-notify` |
258 | 262 | ||
259 | These crates implement a virtual fils system. | 263 | These crates implement a virtual file system. |
260 | They provide consistent snapshots of the underlying file system and insulate messy OS paths. | 264 | They provide consistent snapshots of the underlying file system and insulate messy OS paths. |
261 | 265 | ||
262 | **Architecture Invariant:** vfs doesn't assume a single unified file system. | 266 | **Architecture Invariant:** vfs doesn't assume a single unified file system. |
263 | IE, a single rust-analyzer process can act as a remote server for two different machines, where the same `/tmp/foo.rs` path points to different files. | 267 | i.e., a single rust-analyzer process can act as a remote server for two different machines, where the same `/tmp/foo.rs` path points to different files. |
264 | For this reason, all path APIs generally take some existing path as a "file system witness". | 268 | For this reason, all path APIs generally take some existing path as a "file system witness". |
265 | 269 | ||
266 | ### `crates/stdx` | 270 | ### `crates/stdx` |
267 | 271 | ||
268 | This crate contains various non-rust-analyzer specific utils, which could have been in std. | 272 | This crate contains various non-rust-analyzer specific utils, which could have been in std, as well |
273 | as copies of unstable std items we would like to make use of already, like `std::str::split_once`. | ||
269 | 274 | ||
270 | ### `crates/profile` | 275 | ### `crates/profile` |
271 | 276 | ||
@@ -285,7 +290,7 @@ There are tests to check that the generated code is fresh. | |||
285 | 290 | ||
286 | In particular, we generate: | 291 | In particular, we generate: |
287 | 292 | ||
288 | * API for working with syntax trees (`syntax::ast`, the `ungrammar` crate). | 293 | * API for working with syntax trees (`syntax::ast`, the [`ungrammar`](https://github.com/rust-analyzer/ungrammar) crate). |
289 | * Various sections of the manual: | 294 | * Various sections of the manual: |
290 | 295 | ||
291 | * features | 296 | * features |
@@ -314,7 +319,7 @@ That is, rust-analyzer requires unwinding. | |||
314 | 319 | ||
315 | ### Testing | 320 | ### Testing |
316 | 321 | ||
317 | Rust Analyzer has three interesting [systems boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on. | 322 | Rust Analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on. |
318 | 323 | ||
319 | The outermost boundary is the `rust-analyzer` crate, which defines an LSP interface in terms of stdio. | 324 | The outermost boundary is the `rust-analyzer` crate, which defines an LSP interface in terms of stdio. |
320 | We do integration testing of this component, by feeding it with a stream of LSP requests and checking responses. | 325 | We do integration testing of this component, by feeding it with a stream of LSP requests and checking responses. |
@@ -323,8 +328,8 @@ For this reason, we try to avoid writing too many tests on this boundary: in a s | |||
323 | Heavy tests are only run when `RUN_SLOW_TESTS` env var is set. | 328 | Heavy tests are only run when `RUN_SLOW_TESTS` env var is set. |
324 | 329 | ||
325 | The middle, and most important, boundary is `ide`. | 330 | The middle, and most important, boundary is `ide`. |
326 | Unlike `rust-analyzer`, which exposes API, `ide` uses Rust API and is intended to use by various tools. | 331 | Unlike `rust-analyzer`, which exposes API, `ide` uses Rust API and is intended for use by various tools. |
327 | Typical test creates an `AnalysisHost`, calls some `Analysis` functions and compares the results against expectation. | 332 | A typical test creates an `AnalysisHost`, calls some `Analysis` functions and compares the results against expectation. |
328 | 333 | ||
329 | The innermost and most elaborate boundary is `hir`. | 334 | The innermost and most elaborate boundary is `hir`. |
330 | It has a much richer vocabulary of types than `ide`, but the basic testing setup is the same: we create a database, run some queries, assert result. | 335 | It has a much richer vocabulary of types than `ide`, but the basic testing setup is the same: we create a database, run some queries, assert result. |
@@ -338,7 +343,7 @@ See the `marks` module in the `test_utils` crate for more. | |||
338 | All required library code must be a part of the tests. | 343 | All required library code must be a part of the tests. |
339 | This ensures fast test execution. | 344 | This ensures fast test execution. |
340 | 345 | ||
341 | **Architecture Invariant:** tests are data driven and do not test API. | 346 | **Architecture Invariant:** tests are data driven and do not test the API. |
342 | Tests which directly call various API functions are a liability, because they make refactoring the API significantly more complicated. | 347 | Tests which directly call various API functions are a liability, because they make refactoring the API significantly more complicated. |
343 | So most of the tests look like this: | 348 | So most of the tests look like this: |
344 | 349 | ||
@@ -368,8 +373,48 @@ There's no additional checks in CI, formatting and tidy tests are run with `carg | |||
368 | 373 | ||
369 | **Architecture Invariant:** tests do not depend on any kind of external resources, they are perfectly reproducible. | 374 | **Architecture Invariant:** tests do not depend on any kind of external resources, they are perfectly reproducible. |
370 | 375 | ||
376 | ### Error Handling | ||
377 | |||
378 | **Architecture Invariant:** core parts of rust-analyzer (`ide`/`hir`) don't interact with the outside world and thus can't fail. | ||
379 | Only parts touching LSP are allowed to do IO. | ||
380 | |||
381 | Internals of rust-analyzer need to deal with broken code, but this is not an error condition. | ||
382 | rust-analyzer is robust: various analysis compute `(T, Vec<Error>)` rather than `Result<T, Error>`. | ||
383 | |||
384 | rust-analyzer is a complex long-running process. | ||
385 | It will always have bugs and panics. | ||
386 | But a panic in an isolated feature should not bring down the whole process. | ||
387 | Each LSP-request is protected by a `catch_unwind`. | ||
388 | We use `always` and `never` macros instead of `assert` to gracefully recover from impossible conditions. | ||
389 | |||
371 | ### Observability | 390 | ### Observability |
372 | 391 | ||
373 | I've run out of steam here :) | ||
374 | rust-analyzer is a long-running process, so its important to understand what's going on inside. | 392 | rust-analyzer is a long-running process, so its important to understand what's going on inside. |
375 | We have hierarchical profiler (`RA_PROFILER=1`) and object counting (`RA_COUNT=1`). | 393 | We have several instruments for that. |
394 | |||
395 | The event loop that runs rust-analyzer is very explicit. | ||
396 | Rather than spawning futures or scheduling callbacks (open), the event loop accepts an `enum` of possible events (closed). | ||
397 | It's easy to see all the things that trigger rust-analyzer processing, together with their performance | ||
398 | |||
399 | rust-analyzer includes a simple hierarchical profiler (`hprof`). | ||
400 | It is enabled with `RA_PROFILE='*>50` env var (log all (`*`) actions which take more than `50` ms) and produces output like: | ||
401 | |||
402 | ``` | ||
403 | 85ms - handle_completion | ||
404 | 68ms - import_on_the_fly | ||
405 | 67ms - import_assets::search_for_relative_paths | ||
406 | 0ms - crate_def_map:wait (804 calls) | ||
407 | 0ms - find_path (16 calls) | ||
408 | 2ms - find_similar_imports (1 calls) | ||
409 | 0ms - generic_params_query (334 calls) | ||
410 | 59ms - trait_solve_query (186 calls) | ||
411 | 0ms - Semantics::analyze_impl (1 calls) | ||
412 | 1ms - render_resolution (8 calls) | ||
413 | 0ms - Semantics::analyze_impl (5 calls) | ||
414 | ``` | ||
415 | |||
416 | This is cheap enough to enable in production. | ||
417 | |||
418 | |||
419 | Similarly, we save live object counting (`RA_COUNT=1`). | ||
420 | It is not cheap enough to enable in prod, and this is a bug which should be fixed. | ||
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index d7f287894..b2defa737 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -238,7 +238,7 @@ As proper cursor positioning is raison-d'etat for `onEnter`, it uses `SnippetTex | |||
238 | * How to deal with synchronicity of the request? | 238 | * How to deal with synchronicity of the request? |
239 | One option is to require the client to block until the server returns the response. | 239 | One option is to require the client to block until the server returns the response. |
240 | Another option is to do a OT-style merging of edits from client and server. | 240 | Another option is to do a OT-style merging of edits from client and server. |
241 | A third option is to do a record-replay: client applies heuristic on enter immediatelly, then applies all user's keypresses. | 241 | A third option is to do a record-replay: client applies heuristic on enter immediately, then applies all user's keypresses. |
242 | When the server is ready with the response, the client rollbacks all the changes and applies the recorded actions on top of the correct response. | 242 | When the server is ready with the response, the client rollbacks all the changes and applies the recorded actions on top of the correct response. |
243 | * How to deal with multiple carets? | 243 | * How to deal with multiple carets? |
244 | * Should we extend this to arbitrary typed events and not just `onEnter`? | 244 | * Should we extend this to arbitrary typed events and not just `onEnter`? |
diff --git a/docs/dev/style.md b/docs/dev/style.md index e2f1b6996..0482bc190 100644 --- a/docs/dev/style.md +++ b/docs/dev/style.md | |||
@@ -159,7 +159,7 @@ Express function preconditions in types and force the caller to provide them (ra | |||
159 | 159 | ||
160 | ```rust | 160 | ```rust |
161 | // GOOD | 161 | // GOOD |
162 | fn frbonicate(walrus: Walrus) { | 162 | fn frobnicate(walrus: Walrus) { |
163 | ... | 163 | ... |
164 | } | 164 | } |
165 | 165 | ||
@@ -374,7 +374,7 @@ Avoid making a lot of code type parametric, *especially* on the boundaries betwe | |||
374 | 374 | ||
375 | ```rust | 375 | ```rust |
376 | // GOOD | 376 | // GOOD |
377 | fn frbonicate(f: impl FnMut()) { | 377 | fn frobnicate(f: impl FnMut()) { |
378 | frobnicate_impl(&mut f) | 378 | frobnicate_impl(&mut f) |
379 | } | 379 | } |
380 | fn frobnicate_impl(f: &mut dyn FnMut()) { | 380 | fn frobnicate_impl(f: &mut dyn FnMut()) { |
@@ -382,7 +382,7 @@ fn frobnicate_impl(f: &mut dyn FnMut()) { | |||
382 | } | 382 | } |
383 | 383 | ||
384 | // BAD | 384 | // BAD |
385 | fn frbonicate(f: impl FnMut()) { | 385 | fn frobnicate(f: impl FnMut()) { |
386 | // lots of code | 386 | // lots of code |
387 | } | 387 | } |
388 | ``` | 388 | ``` |
@@ -391,11 +391,11 @@ Avoid `AsRef` polymorphism, it pays back only for widely used libraries: | |||
391 | 391 | ||
392 | ```rust | 392 | ```rust |
393 | // GOOD | 393 | // GOOD |
394 | fn frbonicate(f: &Path) { | 394 | fn frobnicate(f: &Path) { |
395 | } | 395 | } |
396 | 396 | ||
397 | // BAD | 397 | // BAD |
398 | fn frbonicate(f: impl AsRef<Path>) { | 398 | fn frobnicate(f: impl AsRef<Path>) { |
399 | } | 399 | } |
400 | ``` | 400 | ``` |
401 | 401 | ||
@@ -705,7 +705,7 @@ fn foo() -> Option<Bar> { | |||
705 | } | 705 | } |
706 | ``` | 706 | ``` |
707 | 707 | ||
708 | **Rationale:** reduce congnitive stack usage. | 708 | **Rationale:** reduce cognitive stack usage. |
709 | 709 | ||
710 | ## Comparisons | 710 | ## Comparisons |
711 | 711 | ||
diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md index 1edafab68..737cc7a72 100644 --- a/docs/dev/syntax.md +++ b/docs/dev/syntax.md | |||
@@ -92,19 +92,18 @@ [email protected] | |||
92 | [email protected] ")" | 92 | [email protected] ")" |
93 | [email protected] " " | 93 | [email protected] " " |
94 | [email protected] | 94 | [email protected] |
95 | [email protected] | 95 | [email protected] "{" |
96 | [email protected] "{" | 96 | [email protected] " " |
97 | [email protected] " " | 97 | [email protected] |
98 | [email protected] | 98 | [email protected] |
99 | [email protected] | 99 | [email protected] "90" |
100 | [email protected] "90" | 100 | [email protected] " " |
101 | [email protected] " " | 101 | [email protected] "+" |
102 | [email protected] "+" | 102 | [email protected] " " |
103 | [email protected] " " | 103 | [email protected] |
104 | [email protected] | 104 | [email protected] "2" |
105 | [email protected] "2" | 105 | [email protected] " " |
106 | [email protected] " " | 106 | [email protected] "}" |
107 | [email protected] "}" | ||
108 | ``` | 107 | ``` |
109 | 108 | ||
110 | #### Optimizations | 109 | #### Optimizations |
@@ -387,7 +386,7 @@ trait HasVisibility: AstNode { | |||
387 | fn visibility(&self) -> Option<Visibility>; | 386 | fn visibility(&self) -> Option<Visibility>; |
388 | } | 387 | } |
389 | 388 | ||
390 | impl HasVisbility for FnDef { | 389 | impl HasVisibility for FnDef { |
391 | fn visibility(&self) -> Option<Visibility> { | 390 | fn visibility(&self) -> Option<Visibility> { |
392 | self.syntax.children().find_map(Visibility::cast) | 391 | self.syntax.children().find_map(Visibility::cast) |
393 | } | 392 | } |
@@ -527,7 +526,7 @@ In practice, incremental reparsing doesn't actually matter much for IDE use-case | |||
527 | 526 | ||
528 | ### Parsing Algorithm | 527 | ### Parsing Algorithm |
529 | 528 | ||
530 | We use a boring hand-crafted recursive descent + pratt combination, with a special effort of continuting the parsing if an error is detected. | 529 | We use a boring hand-crafted recursive descent + pratt combination, with a special effort of continuing the parsing if an error is detected. |
531 | 530 | ||
532 | ### Parser Recap | 531 | ### Parser Recap |
533 | 532 | ||