mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
Implement folding ranges
This commit is contained in:
parent
e293a16d6b
commit
bd2b2f1b48
2 changed files with 90 additions and 1 deletions
|
@ -1,15 +1,18 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use languageserver_types::{
|
||||
Diagnostic, DiagnosticSeverity, DocumentSymbol,
|
||||
CodeActionResponse, Command, TextDocumentIdentifier,
|
||||
SymbolInformation, Position, Location, TextEdit,
|
||||
CompletionItem, InsertTextFormat, CompletionItemKind,
|
||||
FoldingRange, FoldingRangeParams, FoldingRangeKind
|
||||
};
|
||||
use serde_json::to_value;
|
||||
use ra_analysis::{Query, FileId, RunnableKind, JobToken};
|
||||
use ra_syntax::{
|
||||
algo::{siblings, walk, Direction},
|
||||
text_utils::contains_offset_nonstrict,
|
||||
SyntaxKind, SyntaxNodeRef, TextRange
|
||||
};
|
||||
|
||||
use ::{
|
||||
|
@ -177,6 +180,7 @@ pub fn handle_workspace_symbol(
|
|||
world, &line_index
|
||||
)?,
|
||||
container_name: None,
|
||||
deprecated: None,
|
||||
};
|
||||
res.push(info);
|
||||
};
|
||||
|
@ -365,6 +369,90 @@ pub fn handle_completion(
|
|||
Ok(Some(req::CompletionResponse::Array(items)))
|
||||
}
|
||||
|
||||
pub fn handle_folding_range(
|
||||
world: ServerWorld,
|
||||
params: FoldingRangeParams,
|
||||
_token: JobToken,
|
||||
) -> Result<Option<Vec<FoldingRange>>> {
|
||||
let file_id = params.text_document.try_conv_with(&world)?;
|
||||
let file = world.analysis().file_syntax(file_id);
|
||||
let line_index = world.analysis().file_line_index(file_id);
|
||||
let syntax = file.syntax();
|
||||
|
||||
let mut res = vec![];
|
||||
let mut visited = HashSet::new();
|
||||
|
||||
for node in walk::preorder(syntax) {
|
||||
if visited.contains(&node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let range_and_kind = match node.kind() {
|
||||
SyntaxKind::COMMENT => (
|
||||
contiguous_range_for(SyntaxKind::COMMENT, node, &mut visited),
|
||||
Some(FoldingRangeKind::Comment),
|
||||
),
|
||||
SyntaxKind::USE_ITEM => (
|
||||
contiguous_range_for(SyntaxKind::USE_ITEM, node, &mut visited),
|
||||
Some(FoldingRangeKind::Imports),
|
||||
),
|
||||
_ => (None, None),
|
||||
};
|
||||
|
||||
match range_and_kind {
|
||||
(Some(range), Some(kind)) => {
|
||||
let range = range.conv_with(&line_index);
|
||||
res.push(FoldingRange {
|
||||
start_line: range.start.line,
|
||||
start_character: Some(range.start.character),
|
||||
end_line: range.end.line,
|
||||
end_character: Some(range.start.character),
|
||||
kind: Some(kind),
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if res.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(res))
|
||||
}
|
||||
}
|
||||
|
||||
fn contiguous_range_for<'a>(
|
||||
kind: SyntaxKind,
|
||||
node: SyntaxNodeRef<'a>,
|
||||
visited: &mut HashSet<SyntaxNodeRef<'a>>,
|
||||
) -> Option<TextRange> {
|
||||
visited.insert(node);
|
||||
|
||||
let left = node;
|
||||
let mut right = node;
|
||||
for node in siblings(node, Direction::Forward) {
|
||||
visited.insert(node);
|
||||
match node.kind() {
|
||||
SyntaxKind::WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (),
|
||||
k => {
|
||||
if k == kind {
|
||||
right = node
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if left != right {
|
||||
Some(TextRange::from_to(
|
||||
left.range().start(),
|
||||
right.range().end(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_code_action(
|
||||
world: ServerWorld,
|
||||
params: req::CodeActionParams,
|
||||
|
|
|
@ -253,6 +253,7 @@ fn on_request(
|
|||
.on::<req::DecorationsRequest>(handlers::handle_decorations)?
|
||||
.on::<req::Completion>(handlers::handle_completion)?
|
||||
.on::<req::CodeActionRequest>(handlers::handle_code_action)?
|
||||
.on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
|
||||
.finish();
|
||||
match req {
|
||||
Ok((id, handle)) => {
|
||||
|
|
Loading…
Reference in a new issue