mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-12 21:28:51 +00:00
doc symbols
This commit is contained in:
parent
7afd84febc
commit
f2291d6a76
11 changed files with 2436 additions and 2413 deletions
6
code/.vscode/settings.json
vendored
6
code/.vscode/settings.json
vendored
|
@ -1,10 +1,10 @@
|
||||||
// Place your settings in this file to overwrite default and user settings.
|
// Place your settings in this file to overwrite default and user settings.
|
||||||
{
|
{
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
"out": true,
|
"out": true
|
||||||
"node_modules": true
|
// "node_modules": true
|
||||||
},
|
},
|
||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
"out": true // set this to false to include "out" folder in search results
|
"out": true // set this to false to include "out" folder in search results
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4721
code/package-lock.json
generated
4721
code/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -14,7 +14,7 @@
|
||||||
"postinstall": "node ./node_modules/vscode/bin/install"
|
"postinstall": "node ./node_modules/vscode/bin/install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vscode-languageclient": "^4.3.0"
|
"vscode-languageclient": "^4.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^7.0.56",
|
"@types/node": "^7.0.56",
|
||||||
|
|
|
@ -10,7 +10,7 @@ use std::{
|
||||||
};
|
};
|
||||||
use clap::{App, Arg, SubCommand};
|
use clap::{App, Arg, SubCommand};
|
||||||
use tools::collect_tests;
|
use tools::collect_tests;
|
||||||
use libeditor::{File, syntax_tree, symbols};
|
use libeditor::{File, syntax_tree, file_symbols};
|
||||||
|
|
||||||
type Result<T> = ::std::result::Result<T, failure::Error>;
|
type Result<T> = ::std::result::Result<T, failure::Error>;
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
("symbols", _) => {
|
("symbols", _) => {
|
||||||
let file = file()?;
|
let file = file()?;
|
||||||
for s in symbols(&file) {
|
for s in file_symbols(&file) {
|
||||||
println!("{:?}", s);
|
println!("{:?}", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ mod line_index;
|
||||||
|
|
||||||
use libsyntax2::{
|
use libsyntax2::{
|
||||||
ast::{self, NameOwner},
|
ast::{self, NameOwner},
|
||||||
SyntaxNodeRef, AstNode,
|
AstNode,
|
||||||
algo::walk,
|
algo::walk,
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
};
|
};
|
||||||
|
@ -100,19 +100,6 @@ pub fn syntax_tree(file: &ast::File) -> String {
|
||||||
::libsyntax2::utils::dump_tree(&file.syntax())
|
::libsyntax2::utils::dump_tree(&file.syntax())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn symbols(file: &ast::File) -> Vec<Symbol> {
|
|
||||||
let syntax = file.syntax();
|
|
||||||
let res: Vec<Symbol> = walk::preorder(syntax.as_ref())
|
|
||||||
.filter_map(Declaration::cast)
|
|
||||||
.filter_map(|decl| {
|
|
||||||
let name = decl.name()?;
|
|
||||||
let range = decl.range();
|
|
||||||
Some(Symbol { name, range })
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
res // NLL :-(
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn runnables(file: &ast::File) -> Vec<Runnable> {
|
pub fn runnables(file: &ast::File) -> Vec<Runnable> {
|
||||||
file
|
file
|
||||||
.functions()
|
.functions()
|
||||||
|
@ -134,27 +121,3 @@ pub fn runnables(file: &ast::File) -> Vec<Runnable> {
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Declaration<'f> (SyntaxNodeRef<'f>);
|
|
||||||
|
|
||||||
impl<'f> Declaration<'f> {
|
|
||||||
fn cast(node: SyntaxNodeRef<'f>) -> Option<Declaration<'f>> {
|
|
||||||
match node.kind() {
|
|
||||||
| STRUCT | ENUM | FUNCTION | TRAIT
|
|
||||||
| CONST_ITEM | STATIC_ITEM | MODULE | NAMED_FIELD
|
|
||||||
| TYPE_ITEM => Some(Declaration(node)),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> Option<String> {
|
|
||||||
let name = self.0.children()
|
|
||||||
.find(|child| child.kind() == NAME)?;
|
|
||||||
Some(name.text())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> TextRange {
|
|
||||||
self.0.range()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
failure = "0.1.2"
|
failure = "0.1.2"
|
||||||
languageserver-types = "0.48.0"
|
|
||||||
serde_json = "1.0.24"
|
serde_json = "1.0.24"
|
||||||
serde = "1.0.71"
|
serde = "1.0.71"
|
||||||
serde_derive = "1.0.71"
|
serde_derive = "1.0.71"
|
||||||
|
@ -14,8 +13,13 @@ crossbeam-channel = "0.2.4"
|
||||||
threadpool = "1.7.1"
|
threadpool = "1.7.1"
|
||||||
flexi_logger = "0.9.0"
|
flexi_logger = "0.9.0"
|
||||||
log = "0.4.3"
|
log = "0.4.3"
|
||||||
url = "1.1.0"
|
|
||||||
url_serde = "0.2.0"
|
url_serde = "0.2.0"
|
||||||
|
|
||||||
|
libsyntax2 = { path = "../libsyntax2" }
|
||||||
libeditor = { path = "../libeditor" }
|
libeditor = { path = "../libeditor" }
|
||||||
libanalysis = { path = "../libanalysis" }
|
libanalysis = { path = "../libanalysis" }
|
||||||
|
|
||||||
|
[dependencies.languageserver-types]
|
||||||
|
git = "https://github.com/matklad/languageserver-types"
|
||||||
|
rev = "70e6bf548b901f01dc249c20378d26dd4996c25f"
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub const SERVER_CAPABILITIES: ServerCapabilities = ServerCapabilities {
|
||||||
implementation_provider: None,
|
implementation_provider: None,
|
||||||
references_provider: None,
|
references_provider: None,
|
||||||
document_highlight_provider: None,
|
document_highlight_provider: None,
|
||||||
document_symbol_provider: None,
|
document_symbol_provider: Some(true),
|
||||||
workspace_symbol_provider: None,
|
workspace_symbol_provider: None,
|
||||||
code_action_provider: None,
|
code_action_provider: None,
|
||||||
code_lens_provider: None,
|
code_lens_provider: None,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use url::Url;
|
use languageserver_types::{Range, Position, Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, SymbolKind};
|
||||||
use languageserver_types::{Range, Position, Diagnostic, DiagnosticSeverity};
|
use libsyntax2::SyntaxKind;
|
||||||
use libanalysis::World;
|
use libanalysis::World;
|
||||||
use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit};
|
use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit};
|
||||||
|
|
||||||
|
@ -34,6 +34,50 @@ pub fn handle_extend_selection(
|
||||||
Ok(req::ExtendSelectionResult { selections })
|
Ok(req::ExtendSelectionResult { selections })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_document_symbol(
|
||||||
|
world: World,
|
||||||
|
params: req::DocumentSymbolParams,
|
||||||
|
) -> Result<Option<req::DocumentSymbolResponse>> {
|
||||||
|
let path = params.text_document.file_path()?;
|
||||||
|
let file = world.file_syntax(&path)?;
|
||||||
|
let line_index = world.file_line_index(&path)?;
|
||||||
|
|
||||||
|
let mut res: Vec<DocumentSymbol> = Vec::new();
|
||||||
|
|
||||||
|
for symbol in libeditor::file_symbols(&file) {
|
||||||
|
let doc_symbol = DocumentSymbol {
|
||||||
|
name: symbol.name.clone(),
|
||||||
|
detail: Some(symbol.name),
|
||||||
|
kind: to_symbol_kind(symbol.kind),
|
||||||
|
deprecated: None,
|
||||||
|
range: to_vs_range(&line_index, symbol.node_range),
|
||||||
|
selection_range: to_vs_range(&line_index, symbol.name_range),
|
||||||
|
children: None,
|
||||||
|
};
|
||||||
|
if let Some(idx) = symbol.parent {
|
||||||
|
let children = &mut res[idx].children;
|
||||||
|
if children.is_none() {
|
||||||
|
*children = Some(Vec::new());
|
||||||
|
}
|
||||||
|
children.as_mut().unwrap().push(doc_symbol);
|
||||||
|
} else {
|
||||||
|
res.push(doc_symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Some(req::DocumentSymbolResponse::Nested(res)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_symbol_kind(kind: SyntaxKind) -> SymbolKind {
|
||||||
|
match kind {
|
||||||
|
SyntaxKind::FUNCTION => SymbolKind::Function,
|
||||||
|
SyntaxKind::STRUCT => SymbolKind::Struct,
|
||||||
|
SyntaxKind::ENUM => SymbolKind::Enum,
|
||||||
|
SyntaxKind::TRAIT => SymbolKind::Interface,
|
||||||
|
SyntaxKind::MODULE => SymbolKind::Module,
|
||||||
|
_ => SymbolKind::Variable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn publish_diagnostics(world: World, uri: Url) -> Result<req::PublishDiagnosticsParams> {
|
pub fn publish_diagnostics(world: World, uri: Url) -> Result<req::PublishDiagnosticsParams> {
|
||||||
let path = uri.file_path()?;
|
let path = uri.file_path()?;
|
||||||
let file = world.file_syntax(&path)?;
|
let file = world.file_syntax(&path)?;
|
||||||
|
|
|
@ -11,11 +11,11 @@ extern crate crossbeam_channel;
|
||||||
extern crate threadpool;
|
extern crate threadpool;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate url;
|
|
||||||
extern crate url_serde;
|
extern crate url_serde;
|
||||||
extern crate flexi_logger;
|
extern crate flexi_logger;
|
||||||
extern crate libeditor;
|
extern crate libeditor;
|
||||||
extern crate libanalysis;
|
extern crate libanalysis;
|
||||||
|
extern crate libsyntax2;
|
||||||
|
|
||||||
mod io;
|
mod io;
|
||||||
mod caps;
|
mod caps;
|
||||||
|
@ -27,12 +27,13 @@ mod util;
|
||||||
use threadpool::ThreadPool;
|
use threadpool::ThreadPool;
|
||||||
use crossbeam_channel::{bounded, Sender, Receiver};
|
use crossbeam_channel::{bounded, Sender, Receiver};
|
||||||
use flexi_logger::Logger;
|
use flexi_logger::Logger;
|
||||||
use url::Url;
|
use languageserver_types::Url;
|
||||||
use libanalysis::{WorldState, World};
|
use libanalysis::{WorldState, World};
|
||||||
|
|
||||||
use ::{
|
use ::{
|
||||||
io::{Io, RawMsg, RawRequest},
|
io::{Io, RawMsg, RawRequest},
|
||||||
handlers::{handle_syntax_tree, handle_extend_selection, publish_diagnostics, publish_decorations},
|
handlers::{handle_syntax_tree, handle_extend_selection, publish_diagnostics, publish_decorations,
|
||||||
|
handle_document_symbol},
|
||||||
util::{FilePath, FnBox}
|
util::{FilePath, FnBox}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -178,6 +179,9 @@ fn main_loop(
|
||||||
handle_request_on_threadpool::<req::ExtendSelection>(
|
handle_request_on_threadpool::<req::ExtendSelection>(
|
||||||
&mut req, pool, world, &sender, handle_extend_selection
|
&mut req, pool, world, &sender, handle_extend_selection
|
||||||
)?;
|
)?;
|
||||||
|
handle_request_on_threadpool::<req::DocumentSymbolRequest>(
|
||||||
|
&mut req, pool, world, &sender, handle_document_symbol
|
||||||
|
)?;
|
||||||
let mut shutdown = false;
|
let mut shutdown = false;
|
||||||
dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| {
|
dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| {
|
||||||
resp.result(io, ())?;
|
resp.result(io, ())?;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use serde::{ser::Serialize, de::DeserializeOwned};
|
use serde::{ser::Serialize, de::DeserializeOwned};
|
||||||
use url::Url;
|
use languageserver_types::{TextDocumentIdentifier, Range, Url};
|
||||||
use languageserver_types::{TextDocumentIdentifier, Range};
|
|
||||||
use url_serde;
|
use url_serde;
|
||||||
|
|
||||||
pub use languageserver_types::{
|
pub use languageserver_types::{
|
||||||
request::*, notification::*,
|
request::*, notification::*,
|
||||||
InitializeResult, PublishDiagnosticsParams,
|
InitializeResult, PublishDiagnosticsParams,
|
||||||
|
DocumentSymbolParams, DocumentSymbolResponse
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use languageserver_types::{TextDocumentItem, VersionedTextDocumentIdentifier, TextDocumentIdentifier};
|
use languageserver_types::{TextDocumentItem, VersionedTextDocumentIdentifier,
|
||||||
|
TextDocumentIdentifier, Url};
|
||||||
use ::{Result};
|
use ::{Result};
|
||||||
|
|
||||||
pub trait FnBox<A, R>: Send {
|
pub trait FnBox<A, R>: Send {
|
||||||
|
@ -34,7 +35,7 @@ impl FilePath for TextDocumentIdentifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilePath for ::url::Url {
|
impl FilePath for Url {
|
||||||
fn file_path(&self) -> Result<PathBuf> {
|
fn file_path(&self) -> Result<PathBuf> {
|
||||||
self.to_file_path()
|
self.to_file_path()
|
||||||
.map_err(|()| format_err!("invalid uri: {}", self))
|
.map_err(|()| format_err!("invalid uri: {}", self))
|
||||||
|
|
Loading…
Reference in a new issue