mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Split folding ranges into editor and lsp parts
This commit is contained in:
parent
bd2b2f1b48
commit
ff0a706a30
4 changed files with 114 additions and 77 deletions
|
@ -34,6 +34,7 @@ use imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp};
|
|||
pub use ra_editor::{
|
||||
StructureNode, LineIndex, FileSymbol,
|
||||
Runnable, RunnableKind, HighlightedRange, CompletionItem,
|
||||
Fold, FoldKind
|
||||
};
|
||||
pub use job::{JobToken, JobHandle};
|
||||
|
||||
|
@ -224,6 +225,10 @@ impl Analysis {
|
|||
pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
|
||||
self.imp.diagnostics(file_id)
|
||||
}
|
||||
pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> {
|
||||
let file = self.imp.file_syntax(file_id);
|
||||
ra_editor::folding_ranges(&file)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
86
crates/ra_editor/src/folding_ranges.rs
Normal file
86
crates/ra_editor/src/folding_ranges.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use ra_syntax::{
|
||||
File, TextRange, SyntaxNodeRef,
|
||||
SyntaxKind,
|
||||
algo::{walk, Direction, siblings},
|
||||
};
|
||||
|
||||
pub enum FoldKind {
|
||||
Comment,
|
||||
Imports,
|
||||
}
|
||||
|
||||
pub struct Fold {
|
||||
pub range: TextRange,
|
||||
pub kind: FoldKind,
|
||||
}
|
||||
|
||||
pub fn folding_ranges(file: &File) -> Vec<Fold> {
|
||||
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(FoldKind::Comment),
|
||||
),
|
||||
SyntaxKind::USE_ITEM => (
|
||||
contiguous_range_for(SyntaxKind::USE_ITEM, node, &mut visited),
|
||||
Some(FoldKind::Imports),
|
||||
),
|
||||
_ => (None, None),
|
||||
};
|
||||
|
||||
match range_and_kind {
|
||||
(Some(range), Some(kind)) => {
|
||||
res.push(Fold {
|
||||
range: range,
|
||||
kind: kind
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ mod extend_selection;
|
|||
mod symbols;
|
||||
mod line_index;
|
||||
mod edit;
|
||||
mod folding_ranges;
|
||||
mod code_actions;
|
||||
mod typing;
|
||||
mod completion;
|
||||
|
@ -36,6 +37,7 @@ pub use self::{
|
|||
},
|
||||
typing::{join_lines, on_eq_typed},
|
||||
completion::{scope_completion, CompletionItem},
|
||||
folding_ranges::{Fold, FoldKind, folding_ranges}
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::{HashMap};
|
||||
|
||||
use languageserver_types::{
|
||||
Diagnostic, DiagnosticSeverity, DocumentSymbol,
|
||||
|
@ -8,11 +8,9 @@ use languageserver_types::{
|
|||
FoldingRange, FoldingRangeParams, FoldingRangeKind
|
||||
};
|
||||
use serde_json::to_value;
|
||||
use ra_analysis::{Query, FileId, RunnableKind, JobToken};
|
||||
use ra_analysis::{Query, FileId, RunnableKind, JobToken, FoldKind};
|
||||
use ra_syntax::{
|
||||
algo::{siblings, walk, Direction},
|
||||
text_utils::contains_offset_nonstrict,
|
||||
SyntaxKind, SyntaxNodeRef, TextRange
|
||||
text_utils::contains_offset_nonstrict
|
||||
};
|
||||
|
||||
use ::{
|
||||
|
@ -375,82 +373,28 @@ pub fn handle_folding_range(
|
|||
_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),
|
||||
let res = Some(world.analysis()
|
||||
.folding_ranges(file_id)
|
||||
.into_iter()
|
||||
.map(|fold| {
|
||||
let kind = match fold.kind {
|
||||
FoldKind::Comment => FoldingRangeKind::Comment,
|
||||
FoldKind::Imports => FoldingRangeKind::Imports
|
||||
};
|
||||
|
||||
match range_and_kind {
|
||||
(Some(range), Some(kind)) => {
|
||||
let range = range.conv_with(&line_index);
|
||||
res.push(FoldingRange {
|
||||
let range = fold.range.conv_with(&line_index);
|
||||
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),
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
kind: Some(kind)
|
||||
}
|
||||
})
|
||||
.collect());
|
||||
|
||||
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
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn handle_code_action(
|
||||
|
|
Loading…
Reference in a new issue