Merge #4664
4664: Generate feature documentation from code r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
09df51dab8
33 changed files with 859 additions and 412 deletions
|
|
@ -56,6 +56,24 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
## `add_from_impl_for_enum`
|
||||
|
||||
Adds a From impl for an enum variant with one tuple field.
|
||||
|
||||
```rust
|
||||
// BEFORE
|
||||
enum A { ┃One(u32) }
|
||||
|
||||
// AFTER
|
||||
enum A { One(u32) }
|
||||
|
||||
impl From<u32> for A {
|
||||
fn from(v: u32) -> Self {
|
||||
A::One(v)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `add_function`
|
||||
|
||||
Adds a stub function with a signature matching the function under the cursor.
|
||||
|
|
|
|||
|
|
@ -1,218 +0,0 @@
|
|||
This document is an index of features that the rust-analyzer language server
|
||||
provides. Shortcuts are for the default VS Code layout. If there's no shortcut,
|
||||
you can use <kbd>Ctrl+Shift+P</kbd> to search for the corresponding action.
|
||||
|
||||
### Workspace Symbol <kbd>ctrl+t</kbd>
|
||||
|
||||
Uses fuzzy-search to find types, modules and functions by name across your
|
||||
project and dependencies. This is **the** most useful feature, which improves code
|
||||
navigation tremendously. It mostly works on top of the built-in LSP
|
||||
functionality, however `#` and `*` symbols can be used to narrow down the
|
||||
search. Specifically,
|
||||
|
||||
- `Foo` searches for `Foo` type in the current workspace
|
||||
- `foo#` searches for `foo` function in the current workspace
|
||||
- `Foo*` searches for `Foo` type among dependencies, including `stdlib`
|
||||
- `foo#*` searches for `foo` function among dependencies
|
||||
|
||||
That is, `#` switches from "types" to all symbols, `*` switches from the current
|
||||
workspace to dependencies.
|
||||
|
||||
### Document Symbol <kbd>ctrl+shift+o</kbd>
|
||||
|
||||
Provides a tree of the symbols defined in the file. Can be used to
|
||||
|
||||
* fuzzy search symbol in a file (super useful)
|
||||
* draw breadcrumbs to describe the context around the cursor
|
||||
* draw outline of the file
|
||||
|
||||
### On Typing Assists
|
||||
|
||||
Some features trigger on typing certain characters:
|
||||
|
||||
- typing `let =` tries to smartly add `;` if `=` is followed by an existing expression
|
||||
- Enter inside comments automatically inserts `///`
|
||||
- typing `.` in a chain method call auto-indents
|
||||
|
||||
### Extend Selection
|
||||
|
||||
Extends the current selection to the encompassing syntactic construct
|
||||
(expression, statement, item, module, etc). It works with multiple cursors. This
|
||||
is a relatively new feature of LSP:
|
||||
https://github.com/Microsoft/language-server-protocol/issues/613, check your
|
||||
editor's LSP library to see if this feature is supported.
|
||||
|
||||
### Go to Definition
|
||||
|
||||
Navigates to the definition of an identifier.
|
||||
|
||||
### Go to Implementation
|
||||
|
||||
Navigates to the impl block of structs, enums or traits. Also implemented as a code lens.
|
||||
|
||||
### Go to Type Defintion
|
||||
|
||||
Navigates to the type of an identifier.
|
||||
|
||||
### Commands <kbd>ctrl+shift+p</kbd>
|
||||
|
||||
#### Run
|
||||
|
||||
Shows a popup suggesting to run a test/benchmark/binary **at the current cursor
|
||||
location**. Super useful for repeatedly running just a single test. Do bind this
|
||||
to a shortcut!
|
||||
|
||||
#### Parent Module
|
||||
|
||||
Navigates to the parent module of the current module.
|
||||
|
||||
#### Matching Brace
|
||||
|
||||
If the cursor is on any brace (`<>(){}[]`) which is a part of a brace-pair,
|
||||
moves cursor to the matching brace. It uses the actual parser to determine
|
||||
braces, so it won't confuse generics with comparisons.
|
||||
|
||||
#### Join Lines
|
||||
|
||||
Join selected lines into one, smartly fixing up whitespace and trailing commas.
|
||||
|
||||
#### Show Syntax Tree
|
||||
|
||||
Shows the parse tree of the current file. It exists mostly for debugging
|
||||
rust-analyzer itself.
|
||||
|
||||
#### Expand Macro Recursively
|
||||
|
||||
Shows the full macro expansion of the macro at current cursor.
|
||||
|
||||
#### Status
|
||||
|
||||
Shows internal statistic about memory usage of rust-analyzer.
|
||||
|
||||
#### Show RA Version
|
||||
|
||||
Show current rust-analyzer version.
|
||||
|
||||
#### Toggle inlay hints
|
||||
|
||||
Toggle inlay hints view for the current workspace.
|
||||
It is recommended to assign a shortcut for this command to quickly turn off
|
||||
inlay hints when they prevent you from reading/writing the code.
|
||||
|
||||
#### Run Garbage Collection
|
||||
|
||||
Manually triggers GC.
|
||||
|
||||
#### Start Cargo Watch
|
||||
|
||||
Start `cargo watch` for live error highlighting. Will prompt to install if it's not already installed.
|
||||
|
||||
#### Stop Cargo Watch
|
||||
|
||||
Stop `cargo watch`.
|
||||
|
||||
#### Structural Seach and Replace
|
||||
|
||||
Search and replace with named wildcards that will match any expression.
|
||||
The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`. A `$<name>:expr` placeholder in the search pattern will match any expression and `$<name>` will reference it in the replacement. Available via the command `rust-analyzer.ssr`.
|
||||
|
||||
```rust
|
||||
// Using structural search replace command [foo($a:expr, $b:expr) ==>> ($a).foo($b)]
|
||||
|
||||
// BEFORE
|
||||
String::from(foo(y + 5, z))
|
||||
|
||||
// AFTER
|
||||
String::from((y + 5).foo(z))
|
||||
```
|
||||
|
||||
### Assists (Code Actions)
|
||||
|
||||
Assists, or code actions, are small local refactorings, available in a particular context.
|
||||
They are usually triggered by a shortcut or by clicking a light bulb icon in the editor.
|
||||
|
||||
See [assists.md](./assists.md) for the list of available assists.
|
||||
|
||||
### Magic Completions
|
||||
|
||||
In addition to usual reference completion, rust-analyzer provides some ✨magic✨
|
||||
completions as well:
|
||||
|
||||
Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor
|
||||
is placed at the appropriate position. Even though `if` is easy to type, you
|
||||
still want to complete it, to get ` { }` for free! `return` is inserted with a
|
||||
space or `;` depending on the return type of the function.
|
||||
|
||||
When completing a function call, `()` are automatically inserted. If a function
|
||||
takes arguments, the cursor is positioned inside the parenthesis.
|
||||
|
||||
There are postfix completions, which can be triggered by typing something like
|
||||
`foo().if`. The word after `.` determines postfix completion. Possible variants are:
|
||||
|
||||
- `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result`
|
||||
- `expr.match` -> `match expr {}`
|
||||
- `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result`
|
||||
- `expr.ref` -> `&expr`
|
||||
- `expr.refm` -> `&mut expr`
|
||||
- `expr.not` -> `!expr`
|
||||
- `expr.dbg` -> `dbg!(expr)`
|
||||
|
||||
There also snippet completions:
|
||||
|
||||
#### Inside Expressions
|
||||
|
||||
- `pd` -> `println!("{:?}")`
|
||||
- `ppd` -> `println!("{:#?}")`
|
||||
|
||||
#### Inside Modules
|
||||
|
||||
- `tfn` -> `#[test] fn f(){}`
|
||||
- `tmod` ->
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_fn() {}
|
||||
}
|
||||
```
|
||||
|
||||
### Code Highlighting
|
||||
|
||||
Experimental feature to let rust-analyzer highlight Rust code instead of using the
|
||||
default highlighter.
|
||||
|
||||
#### Rainbow Highlighting
|
||||
|
||||
Experimental feature that, given code highlighting using rust-analyzer is
|
||||
active, will pick unique colors for identifiers.
|
||||
|
||||
### Code hints
|
||||
|
||||
Rust-analyzer has two types of hints to show the information about the code:
|
||||
|
||||
* hover hints, appearing on hover on any element.
|
||||
|
||||
These contain extended information on the hovered language item.
|
||||
|
||||
* inlay hints, shown near the element hinted directly in the editor.
|
||||
|
||||
Two types of inlay hints are displayed currently:
|
||||
|
||||
* type hints, displaying the minimal information on the type of the expression (if the information is available)
|
||||
* method chaining hints, type information for multi-line method chains
|
||||
* parameter name hints, displaying the names of the parameters in the corresponding methods
|
||||
|
||||
#### VS Code
|
||||
|
||||
In VS Code, the following settings can be used to configure the inlay hints:
|
||||
|
||||
* `rust-analyzer.inlayHints.typeHints` - enable hints for inferred types.
|
||||
* `rust-analyzer.inlayHints.chainingHints` - enable hints for inferred types on method chains.
|
||||
* `rust-analyzer.inlayHints.parameterHints` - enable hints for function parameters.
|
||||
* `rust-analyzer.inlayHints.maxLength` — shortens the hints if their length exceeds the value specified. If no value is specified (`null`), no shortening is applied.
|
||||
|
||||
**Note:** VS Code does not have native support for inlay hints [yet](https://github.com/microsoft/vscode/issues/16221) and the hints are implemented using decorations.
|
||||
This approach has limitations, the caret movement and bracket highlighting near the edges of the hint may be weird:
|
||||
[1](https://github.com/rust-analyzer/rust-analyzer/issues/1623), [2](https://github.com/rust-analyzer/rust-analyzer/issues/3453).
|
||||
298
docs/user/generated_features.adoc
Normal file
298
docs/user/generated_features.adoc
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
=== Expand Macro Recursively
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/expand_macro.rs[expand_macro.rs]
|
||||
|
||||
Shows the full macro expansion of the macro at current cursor.
|
||||
|
||||
|===
|
||||
| Editor | Action Name
|
||||
|
||||
| VS Code | **Rust Analyzer: Expand macro recursively**
|
||||
|===
|
||||
|
||||
|
||||
=== Extend Selection
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/extend_selection.rs[extend_selection.rs]
|
||||
|
||||
Extends the current selection to the encompassing syntactic construct
|
||||
(expression, statement, item, module, etc). It works with multiple cursors.
|
||||
|
||||
|===
|
||||
| Editor | Shortcut
|
||||
|
||||
| VS Code | kbd:[Ctrl+Shift+→]
|
||||
|===
|
||||
|
||||
|
||||
=== File Structure
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/display/structure.rs[structure.rs]
|
||||
|
||||
Provides a tree of the symbols defined in the file. Can be used to
|
||||
|
||||
* fuzzy search symbol in a file (super useful)
|
||||
* draw breadcrumbs to describe the context around the cursor
|
||||
* draw outline of the file
|
||||
|
||||
|===
|
||||
| Editor | Shortcut
|
||||
|
||||
| VS Code | kbd:[Ctrl+Shift+O]
|
||||
|===
|
||||
|
||||
|
||||
=== Go to Definition
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/goto_definition.rs[goto_definition.rs]
|
||||
|
||||
Navigates to the definition of an identifier.
|
||||
|
||||
|===
|
||||
| Editor | Shortcut
|
||||
|
||||
| VS Code | kbd:[F12]
|
||||
|===
|
||||
|
||||
|
||||
=== Go to Implementation
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/goto_implementation.rs[goto_implementation.rs]
|
||||
|
||||
Navigates to the impl block of structs, enums or traits. Also implemented as a code lens.
|
||||
|
||||
|===
|
||||
| Editor | Shortcut
|
||||
|
||||
| VS Code | kbd:[Ctrl+F12]
|
||||
|===
|
||||
|
||||
|
||||
=== Go to Type Definition
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/goto_type_definition.rs[goto_type_definition.rs]
|
||||
|
||||
Navigates to the type of an identifier.
|
||||
|
||||
|===
|
||||
| Editor | Action Name
|
||||
|
||||
| VS Code | **Go to Type Definition*
|
||||
|===
|
||||
|
||||
|
||||
=== Hover
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/hover.rs[hover.rs]
|
||||
|
||||
Shows additional information, like type of an expression or documentation for definition when "focusing" code.
|
||||
Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
|
||||
|
||||
|
||||
=== Inlay Hints
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/inlay_hints.rs[inlay_hints.rs]
|
||||
|
||||
rust-analyzer shows additional information inline with the source code.
|
||||
Editors usually render this using read-only virtual text snippets interspersed with code.
|
||||
|
||||
rust-analyzer shows hits for
|
||||
|
||||
* types of local variables
|
||||
* names of function arguments
|
||||
* types of chained expressions
|
||||
|
||||
**Note:** VS Code does not have native support for inlay hints https://github.com/microsoft/vscode/issues/16221[yet] and the hints are implemented using decorations.
|
||||
This approach has limitations, the caret movement and bracket highlighting near the edges of the hint may be weird:
|
||||
https://github.com/rust-analyzer/rust-analyzer/issues/1623[1], https://github.com/rust-analyzer/rust-analyzer/issues/3453[2].
|
||||
|
||||
|===
|
||||
| Editor | Action Name
|
||||
|
||||
| VS Code | **Rust Analyzer: Toggle inlay hints*
|
||||
|===
|
||||
|
||||
|
||||
=== Join Lines
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/join_lines.rs[join_lines.rs]
|
||||
|
||||
Join selected lines into one, smartly fixing up whitespace, trailing commas, and braces.
|
||||
|
||||
|===
|
||||
| Editor | Action Name
|
||||
|
||||
| VS Code | **Rust Analyzer: Join lines**
|
||||
|===
|
||||
|
||||
|
||||
=== Magic Completions
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/completion.rs[completion.rs]
|
||||
|
||||
In addition to usual reference completion, rust-analyzer provides some ✨magic✨
|
||||
completions as well:
|
||||
|
||||
Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor
|
||||
is placed at the appropriate position. Even though `if` is easy to type, you
|
||||
still want to complete it, to get ` { }` for free! `return` is inserted with a
|
||||
space or `;` depending on the return type of the function.
|
||||
|
||||
When completing a function call, `()` are automatically inserted. If a function
|
||||
takes arguments, the cursor is positioned inside the parenthesis.
|
||||
|
||||
There are postfix completions, which can be triggered by typing something like
|
||||
`foo().if`. The word after `.` determines postfix completion. Possible variants are:
|
||||
|
||||
- `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result`
|
||||
- `expr.match` -> `match expr {}`
|
||||
- `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result`
|
||||
- `expr.ref` -> `&expr`
|
||||
- `expr.refm` -> `&mut expr`
|
||||
- `expr.not` -> `!expr`
|
||||
- `expr.dbg` -> `dbg!(expr)`
|
||||
|
||||
There also snippet completions:
|
||||
|
||||
.Expressions
|
||||
- `pd` -> `println!("{:?}")`
|
||||
- `ppd` -> `println!("{:#?}")`
|
||||
|
||||
.Items
|
||||
- `tfn` -> `#[test] fn f(){}`
|
||||
- `tmod` ->
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_fn() {}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== Matching Brace
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/matching_brace.rs[matching_brace.rs]
|
||||
|
||||
If the cursor is on any brace (`<>(){}[]`) which is a part of a brace-pair,
|
||||
moves cursor to the matching brace. It uses the actual parser to determine
|
||||
braces, so it won't confuse generics with comparisons.
|
||||
|
||||
|===
|
||||
| Editor | Action Name
|
||||
|
||||
| VS Code | **Rust Analyzer: Find matching brace**
|
||||
|===
|
||||
|
||||
|
||||
=== On Typing Assists
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/typing.rs[typing.rs]
|
||||
|
||||
Some features trigger on typing certain characters:
|
||||
|
||||
- typing `let =` tries to smartly add `;` if `=` is followed by an existing expression
|
||||
- Enter inside comments automatically inserts `///`
|
||||
- typing `.` in a chain method call auto-indents
|
||||
|
||||
|
||||
=== Parent Module
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/parent_module.rs[parent_module.rs]
|
||||
|
||||
Navigates to the parent module of the current module.
|
||||
|
||||
|===
|
||||
| Editor | Action Name
|
||||
|
||||
| VS Code | **Rust Analyzer: Locate parent module**
|
||||
|===
|
||||
|
||||
|
||||
=== Run
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/runnables.rs[runnables.rs]
|
||||
|
||||
Shows a popup suggesting to run a test/benchmark/binary **at the current cursor
|
||||
location**. Super useful for repeatedly running just a single test. Do bind this
|
||||
to a shortcut!
|
||||
|
||||
|===
|
||||
| Editor | Action Name
|
||||
|
||||
| VS Code | **Rust Analyzer: Run**
|
||||
|===
|
||||
|
||||
|
||||
=== Semantic Syntax Highlighting
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/syntax_highlighting.rs[syntax_highlighting.rs]
|
||||
|
||||
rust-analyzer highlights the code semantically.
|
||||
For example, `bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait.
|
||||
rust-analyzer does not specify colors directly, instead it assigns tag (like `struct`) and a set of modifiers (like `declaration`) to each token.
|
||||
It's up to the client to map those to specific colors.
|
||||
|
||||
The general rule is that a reference to an entity gets colored the same way as the entity itself.
|
||||
We also give special modifier for `mut` and `&mut` local variables.
|
||||
|
||||
|
||||
=== Show Syntax Tree
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/syntax_tree.rs[syntax_tree.rs]
|
||||
|
||||
Shows the parse tree of the current file. It exists mostly for debugging
|
||||
rust-analyzer itself.
|
||||
|
||||
|===
|
||||
| Editor | Action Name
|
||||
|
||||
| VS Code | **Rust Analyzer: Show Syntax Tree**
|
||||
|===
|
||||
|
||||
|
||||
=== Status
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/status.rs[status.rs]
|
||||
|
||||
Shows internal statistic about memory usage of rust-analyzer.
|
||||
|
||||
|===
|
||||
| Editor | Action Name
|
||||
|
||||
| VS Code | **Rust Analyzer: Status**
|
||||
|===
|
||||
|
||||
|
||||
=== Structural Seach and Replace
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/ssr.rs[ssr.rs]
|
||||
|
||||
Search and replace with named wildcards that will match any expression.
|
||||
The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`.
|
||||
A `$<name>:expr` placeholder in the search pattern will match any expression and `$<name>` will reference it in the replacement.
|
||||
Available via the command `rust-analyzer.ssr`.
|
||||
|
||||
```rust
|
||||
// Using structural search replace command [foo($a:expr, $b:expr) ==>> ($a).foo($b)]
|
||||
|
||||
// BEFORE
|
||||
String::from(foo(y + 5, z))
|
||||
|
||||
// AFTER
|
||||
String::from((y + 5).foo(z))
|
||||
```
|
||||
|
||||
|===
|
||||
| Editor | Action Name
|
||||
|
||||
| VS Code | **Rust Analyzer: Structural Search Replace**
|
||||
|===
|
||||
|
||||
|
||||
=== Workspace Symbol
|
||||
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide_db/src/symbol_index.rs[symbol_index.rs]
|
||||
|
||||
Uses fuzzy-search to find types, modules and functions by name across your
|
||||
project and dependencies. This is **the** most useful feature, which improves code
|
||||
navigation tremendously. It mostly works on top of the built-in LSP
|
||||
functionality, however `#` and `*` symbols can be used to narrow down the
|
||||
search. Specifically,
|
||||
|
||||
- `Foo` searches for `Foo` type in the current workspace
|
||||
- `foo#` searches for `foo` function in the current workspace
|
||||
- `Foo*` searches for `Foo` type among dependencies, including `stdlib`
|
||||
- `foo#*` searches for `foo` function among dependencies
|
||||
|
||||
That is, `#` switches from "types" to all symbols, `*` switches from the current
|
||||
workspace to dependencies.
|
||||
|
||||
|===
|
||||
| Editor | Shortcut
|
||||
|
||||
| VS Code | kbd:[Ctrl+T]
|
||||
|===
|
||||
|
|
@ -8,6 +8,8 @@
|
|||
:important-caption: :heavy_exclamation_mark:
|
||||
:caution-caption: :fire:
|
||||
:warning-caption: :warning:
|
||||
:source-highlighter: rouge
|
||||
:experimental:
|
||||
|
||||
// Master copy of this document lives in the https://github.com/rust-analyzer/rust-analyzer repository
|
||||
|
||||
|
|
@ -268,6 +270,13 @@ Gnome Builder currently has support for RLS, and there's no way to configure the
|
|||
1. Rename, symlink or copy the `rust-analyzer` binary to `rls` and place it somewhere Builder can find (in `PATH`, or under `~/.cargo/bin`).
|
||||
2. Enable the Rust Builder plugin.
|
||||
|
||||
== Usage
|
||||
== Features
|
||||
|
||||
See https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/features.md[features.md].
|
||||
include::./generated_features.adoc[]
|
||||
|
||||
== Assists (Code Actions)
|
||||
|
||||
Assists, or code actions, are small local refactorings, available in a particular context.
|
||||
They are usually triggered by a shortcut or by clicking a light bulb icon in the editor.
|
||||
|
||||
See [assists.md](./assists.md) for the list of available assists.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue