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::{
|
pub use ra_editor::{
|
||||||
StructureNode, LineIndex, FileSymbol,
|
StructureNode, LineIndex, FileSymbol,
|
||||||
Runnable, RunnableKind, HighlightedRange, CompletionItem,
|
Runnable, RunnableKind, HighlightedRange, CompletionItem,
|
||||||
|
Fold, FoldKind
|
||||||
};
|
};
|
||||||
pub use job::{JobToken, JobHandle};
|
pub use job::{JobToken, JobHandle};
|
||||||
|
|
||||||
|
@ -224,6 +225,10 @@ impl Analysis {
|
||||||
pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
|
pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
|
||||||
self.imp.diagnostics(file_id)
|
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)]
|
#[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 symbols;
|
||||||
mod line_index;
|
mod line_index;
|
||||||
mod edit;
|
mod edit;
|
||||||
|
mod folding_ranges;
|
||||||
mod code_actions;
|
mod code_actions;
|
||||||
mod typing;
|
mod typing;
|
||||||
mod completion;
|
mod completion;
|
||||||
|
@ -36,6 +37,7 @@ pub use self::{
|
||||||
},
|
},
|
||||||
typing::{join_lines, on_eq_typed},
|
typing::{join_lines, on_eq_typed},
|
||||||
completion::{scope_completion, CompletionItem},
|
completion::{scope_completion, CompletionItem},
|
||||||
|
folding_ranges::{Fold, FoldKind, folding_ranges}
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap};
|
||||||
|
|
||||||
use languageserver_types::{
|
use languageserver_types::{
|
||||||
Diagnostic, DiagnosticSeverity, DocumentSymbol,
|
Diagnostic, DiagnosticSeverity, DocumentSymbol,
|
||||||
|
@ -8,11 +8,9 @@ use languageserver_types::{
|
||||||
FoldingRange, FoldingRangeParams, FoldingRangeKind
|
FoldingRange, FoldingRangeParams, FoldingRangeKind
|
||||||
};
|
};
|
||||||
use serde_json::to_value;
|
use serde_json::to_value;
|
||||||
use ra_analysis::{Query, FileId, RunnableKind, JobToken};
|
use ra_analysis::{Query, FileId, RunnableKind, JobToken, FoldKind};
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
algo::{siblings, walk, Direction},
|
text_utils::contains_offset_nonstrict
|
||||||
text_utils::contains_offset_nonstrict,
|
|
||||||
SyntaxKind, SyntaxNodeRef, TextRange
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use ::{
|
use ::{
|
||||||
|
@ -375,82 +373,28 @@ pub fn handle_folding_range(
|
||||||
_token: JobToken,
|
_token: JobToken,
|
||||||
) -> Result<Option<Vec<FoldingRange>>> {
|
) -> Result<Option<Vec<FoldingRange>>> {
|
||||||
let file_id = params.text_document.try_conv_with(&world)?;
|
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 line_index = world.analysis().file_line_index(file_id);
|
||||||
let syntax = file.syntax();
|
|
||||||
|
|
||||||
let mut res = vec![];
|
let res = Some(world.analysis()
|
||||||
let mut visited = HashSet::new();
|
.folding_ranges(file_id)
|
||||||
|
.into_iter()
|
||||||
for node in walk::preorder(syntax) {
|
.map(|fold| {
|
||||||
if visited.contains(&node) {
|
let kind = match fold.kind {
|
||||||
continue;
|
FoldKind::Comment => FoldingRangeKind::Comment,
|
||||||
}
|
FoldKind::Imports => FoldingRangeKind::Imports
|
||||||
|
};
|
||||||
let range_and_kind = match node.kind() {
|
let range = fold.range.conv_with(&line_index);
|
||||||
SyntaxKind::COMMENT => (
|
FoldingRange {
|
||||||
contiguous_range_for(SyntaxKind::COMMENT, node, &mut visited),
|
start_line: range.start.line,
|
||||||
Some(FoldingRangeKind::Comment),
|
start_character: Some(range.start.character),
|
||||||
),
|
end_line: range.end.line,
|
||||||
SyntaxKind::USE_ITEM => (
|
end_character: Some(range.start.character),
|
||||||
contiguous_range_for(SyntaxKind::USE_ITEM, node, &mut visited),
|
kind: Some(kind)
|
||||||
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),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
_ => {}
|
})
|
||||||
}
|
.collect());
|
||||||
}
|
|
||||||
|
|
||||||
if res.is_empty() {
|
Ok(res)
|
||||||
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(
|
pub fn handle_code_action(
|
||||||
|
|
Loading…
Reference in a new issue