Generate features docs from source

This commit is contained in:
Aleksey Kladov 2020-05-31 01:54:54 +02:00
parent 383247a9ae
commit c8f27a4a88
15 changed files with 258 additions and 58 deletions

View file

@ -18,6 +18,19 @@ pub struct StructureNode {
pub deprecated: bool, pub deprecated: bool,
} }
// Feature: File Structure
//
// 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]
// |===
pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> { pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
let mut res = Vec::new(); let mut res = Vec::new();
let mut stack = Vec::new(); let mut stack = Vec::new();

View file

@ -14,6 +14,16 @@ use ra_syntax::{
use crate::FileRange; use crate::FileRange;
// Feature: Extend Selection
//
// 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+→]
// |===
pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange {
let sema = Semantics::new(db); let sema = Semantics::new(db);
let src = sema.parse(frange.file_id); let src = sema.parse(frange.file_id);

View file

@ -17,6 +17,15 @@ use crate::{
FilePosition, NavigationTarget, RangeInfo, FilePosition, NavigationTarget, RangeInfo,
}; };
// Feature: Go To Definition
//
// Navigates to the definition of an identifier.
//
// |===
// | Editor | Shortcut
//
// | VS Code | kbd:[F12]
// |===
pub(crate) fn goto_definition( pub(crate) fn goto_definition(
db: &RootDatabase, db: &RootDatabase,
position: FilePosition, position: FilePosition,

View file

@ -6,6 +6,15 @@ use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo};
// Feature: Go To Implementation
//
// Navigates to the impl block of structs, enums or traits. Also implemented as a code lens.
//
// |===
// | Editor | Shortcut
//
// | VS Code | kbd:[Ctrl+F12]
// |===
pub(crate) fn goto_implementation( pub(crate) fn goto_implementation(
db: &RootDatabase, db: &RootDatabase,
position: FilePosition, position: FilePosition,

View file

@ -5,6 +5,9 @@ use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffs
use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo};
// Feature: Go To Type Definition
//
// Navigates to the type of an identifier.
pub(crate) fn goto_type_definition( pub(crate) fn goto_type_definition(
db: &RootDatabase, db: &RootDatabase,
position: FilePosition, position: FilePosition,

View file

@ -23,6 +23,7 @@ mod completion;
mod runnables; mod runnables;
mod goto_definition; mod goto_definition;
mod goto_type_definition; mod goto_type_definition;
mod goto_implementation;
mod extend_selection; mod extend_selection;
mod hover; mod hover;
mod call_hierarchy; mod call_hierarchy;
@ -30,7 +31,6 @@ mod call_info;
mod syntax_highlighting; mod syntax_highlighting;
mod parent_module; mod parent_module;
mod references; mod references;
mod impls;
mod diagnostics; mod diagnostics;
mod syntax_tree; mod syntax_tree;
mod folding_ranges; mod folding_ranges;
@ -373,7 +373,7 @@ impl Analysis {
&self, &self,
position: FilePosition, position: FilePosition,
) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> { ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
self.with_db(|db| impls::goto_implementation(db, position)) self.with_db(|db| goto_implementation::goto_implementation(db, position))
} }
/// Returns the type definitions for the symbol at `position`. /// Returns the type definitions for the symbol at `position`.

View file

@ -32,6 +32,13 @@ pub(crate) use on_enter::on_enter;
pub(crate) const TRIGGER_CHARS: &str = ".=>"; pub(crate) const TRIGGER_CHARS: &str = ".=>";
// Feature: 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
pub(crate) fn on_char_typed( pub(crate) fn on_char_typed(
db: &RootDatabase, db: &RootDatabase,
position: FilePosition, position: FilePosition,

View file

@ -110,6 +110,27 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex>
Arc::new(SymbolIndex::new(symbols)) Arc::new(SymbolIndex::new(symbols))
} }
// Feature: Workspace Symbol
//
// 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]
// |===
pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
/// Need to wrap Snapshot to provide `Clone` impl for `map_with` /// Need to wrap Snapshot to provide `Clone` impl for `map_with`
struct Snap(salsa::Snapshot<RootDatabase>); struct Snap(salsa::Snapshot<RootDatabase>);

View file

@ -2,58 +2,6 @@ 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, 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. 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> ### Commands <kbd>ctrl+shift+p</kbd>
#### Run #### Run

View file

@ -0,0 +1,98 @@
=== 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.
=== 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
=== 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]
|===

View file

@ -8,6 +8,7 @@
:important-caption: :heavy_exclamation_mark: :important-caption: :heavy_exclamation_mark:
:caution-caption: :fire: :caution-caption: :fire:
:warning-caption: :warning: :warning-caption: :warning:
:experimental:
// Master copy of this document lives in the https://github.com/rust-analyzer/rust-analyzer repository // Master copy of this document lives in the https://github.com/rust-analyzer/rust-analyzer repository
@ -268,6 +269,6 @@ 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`). 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. 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[]

View file

@ -8,14 +8,15 @@
mod gen_syntax; mod gen_syntax;
mod gen_parser_tests; mod gen_parser_tests;
mod gen_assists_docs; mod gen_assists_docs;
mod gen_feature_docs;
use std::{mem, path::Path}; use std::{mem, path::Path};
use crate::{not_bash::fs2, Result}; use crate::{not_bash::fs2, Result};
pub use self::{ pub use self::{
gen_assists_docs::generate_assists_docs, gen_parser_tests::generate_parser_tests, gen_assists_docs::generate_assists_docs, gen_feature_docs::generate_feature_docs,
gen_syntax::generate_syntax, gen_parser_tests::generate_parser_tests, gen_syntax::generate_syntax,
}; };
const GRAMMAR_DIR: &str = "crates/ra_parser/src/grammar"; const GRAMMAR_DIR: &str = "crates/ra_parser/src/grammar";

View file

@ -0,0 +1,72 @@
//! Generates `assists.md` documentation.
use std::{fmt, fs, path::PathBuf};
use crate::{
codegen::{self, extract_comment_blocks_with_empty_lines, Mode},
project_root, rust_files, Result,
};
pub fn generate_feature_docs(mode: Mode) -> Result<()> {
let features = Feature::collect()?;
let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
let dst = project_root().join("docs/user/generated_features.adoc");
codegen::update(&dst, &contents, mode)?;
Ok(())
}
#[derive(Debug)]
struct Feature {
id: String,
path: PathBuf,
doc: String,
}
impl Feature {
fn collect() -> Result<Vec<Feature>> {
let mut res = Vec::new();
for path in rust_files(&project_root()) {
collect_file(&mut res, path)?;
}
res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id));
return Ok(res);
fn collect_file(acc: &mut Vec<Feature>, path: PathBuf) -> Result<()> {
let text = fs::read_to_string(&path)?;
let comment_blocks = extract_comment_blocks_with_empty_lines("Feature", &text);
for block in comment_blocks {
let id = block.id;
assert!(
id.split_ascii_whitespace().all(|it| it.starts_with(char::is_uppercase)),
"bad feature: {}",
id
);
let doc = block.contents.join("\n");
acc.push(Feature { id, path: path.clone(), doc })
}
Ok(())
}
}
}
impl fmt::Display for Feature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "=== {}", self.id)?;
let path = self.path.strip_prefix(&project_root()).unwrap();
let name = self.path.file_name().unwrap();
//FIXME: generate line number as well
writeln!(
f,
"**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/{}[{}]",
path.display(),
name.to_str().unwrap(),
)?;
writeln!(f, "\n{}", self.doc)?;
Ok(())
}
}

View file

@ -75,6 +75,7 @@ FLAGS:
codegen::generate_syntax(Mode::Overwrite)?; codegen::generate_syntax(Mode::Overwrite)?;
codegen::generate_parser_tests(Mode::Overwrite)?; codegen::generate_parser_tests(Mode::Overwrite)?;
codegen::generate_assists_docs(Mode::Overwrite)?; codegen::generate_assists_docs(Mode::Overwrite)?;
codegen::generate_feature_docs(Mode::Overwrite)?;
Ok(()) Ok(())
} }
"format" => { "format" => {

View file

@ -30,6 +30,13 @@ fn generated_assists_are_fresh() {
} }
} }
#[test]
fn generated_features_are_fresh() {
if let Err(error) = codegen::generate_feature_docs(Mode::Verify) {
panic!("{}. Please update features by running `cargo xtask codegen`", error);
}
}
#[test] #[test]
fn check_code_formatting() { fn check_code_formatting() {
if let Err(error) = run_rustfmt(Mode::Verify) { if let Err(error) = run_rustfmt(Mode::Verify) {