-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Do not fold the entire structure but the contents inside. See #915.
- Loading branch information
Showing
5 changed files
with
137 additions
and
54 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "folding" | ||
version = "0.0.0" | ||
license.workspace = true | ||
authors.workspace = true | ||
edition.workspace = true | ||
rust-version.workspace = true | ||
|
||
[dependencies] | ||
base-db = { path = "../base-db" } | ||
rowan = "0.15.11" | ||
syntax = { path = "../syntax" } | ||
|
||
[dev-dependencies] | ||
expect-test = "1.4.1" | ||
test-utils = { path = "../test-utils" } | ||
|
||
[lib] | ||
doctest = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
use base_db::{Document, DocumentData}; | ||
use rowan::{ast::AstNode, TextRange}; | ||
use syntax::{ | ||
bibtex::{self, HasDelims, HasName}, | ||
latex, | ||
}; | ||
|
||
#[derive(Debug)] | ||
pub struct FoldingRange { | ||
pub range: TextRange, | ||
} | ||
|
||
pub fn find_all(document: &Document) -> Vec<FoldingRange> { | ||
let mut builder = FoldingBuilder::default(); | ||
|
||
if let DocumentData::Tex(data) = &document.data { | ||
for node in data.root_node().descendants() { | ||
if let Some(section) = latex::Section::cast(node.clone()) { | ||
builder.fold_section(§ion); | ||
} else if let Some(item) = latex::EnumItem::cast(node.clone()) { | ||
builder.fold_enum_item(&item); | ||
} else if let Some(env) = latex::Environment::cast(node) { | ||
builder.fold_environment(env); | ||
} | ||
} | ||
} else if let DocumentData::Bib(data) = &document.data { | ||
for node in data.root_node().descendants() { | ||
if let Some(entry) = bibtex::Entry::cast(node.clone()) { | ||
builder.fold_entry(&entry); | ||
} else if let Some(string) = bibtex::StringDef::cast(node) { | ||
builder.fold_entry(&string); | ||
} | ||
} | ||
} | ||
|
||
builder.ranges | ||
} | ||
|
||
#[derive(Debug, Default)] | ||
struct FoldingBuilder { | ||
ranges: Vec<FoldingRange>, | ||
} | ||
|
||
impl FoldingBuilder { | ||
fn fold_section(&mut self, section: &latex::Section) -> Option<()> { | ||
let start = section | ||
.name() | ||
.map(|name| latex::small_range(&name).end()) | ||
.or_else(|| section.command().map(|cmd| cmd.text_range().end()))?; | ||
let end = section.syntax().text_range().end(); | ||
|
||
self.ranges.push(FoldingRange { | ||
range: TextRange::new(start, end), | ||
}); | ||
|
||
Some(()) | ||
} | ||
|
||
fn fold_enum_item(&mut self, item: &latex::EnumItem) -> Option<()> { | ||
let start = item | ||
.label() | ||
.map(|label| latex::small_range(&label).end()) | ||
.or_else(|| item.command().map(|cmd| cmd.text_range().end()))?; | ||
|
||
let end = item.syntax().text_range().end(); | ||
self.ranges.push(FoldingRange { | ||
range: TextRange::new(start, end), | ||
}); | ||
|
||
Some(()) | ||
} | ||
|
||
fn fold_environment(&mut self, env: latex::Environment) -> Option<()> { | ||
let start = latex::small_range(&env.begin()?).end(); | ||
let end = latex::small_range(&env.end()?).start(); | ||
self.ranges.push(FoldingRange { | ||
range: TextRange::new(start, end), | ||
}); | ||
|
||
Some(()) | ||
} | ||
|
||
fn fold_entry(&mut self, entry: &(impl HasName + HasDelims)) -> Option<()> { | ||
let start = entry.name_token()?.text_range().end(); | ||
let end = entry.right_delim_token()?.text_range().start(); | ||
self.ranges.push(FoldingRange { | ||
range: TextRange::new(start, end), | ||
}); | ||
|
||
Some(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,62 +1,21 @@ | ||
use base_db::{DocumentData, Workspace}; | ||
use lsp_types::{FoldingRange, FoldingRangeKind, Range, Url}; | ||
use rowan::ast::AstNode; | ||
use syntax::{bibtex, latex}; | ||
use base_db::Workspace; | ||
use lsp_types::{FoldingRange, Url}; | ||
|
||
use crate::util::line_index_ext::LineIndexExt; | ||
|
||
pub fn find_all(workspace: &Workspace, uri: &Url) -> Option<Vec<FoldingRange>> { | ||
let document = workspace.lookup(uri)?; | ||
let line_index = &document.line_index; | ||
let foldings = match &document.data { | ||
DocumentData::Tex(data) => { | ||
let mut results = Vec::new(); | ||
for node in data.root_node().descendants() { | ||
if let Some(folding) = latex::Environment::cast(node.clone()) | ||
.map(|node| latex::small_range(&node)) | ||
.or_else(|| { | ||
latex::Section::cast(node.clone()).map(|node| latex::small_range(&node)) | ||
}) | ||
.or_else(|| latex::EnumItem::cast(node).map(|node| latex::small_range(&node))) | ||
.map(|node| line_index.line_col_lsp_range(node)) | ||
.map(create_range) | ||
{ | ||
results.push(folding); | ||
} | ||
} | ||
|
||
results | ||
} | ||
DocumentData::Bib(data) => { | ||
let root = data.root_node(); | ||
root.descendants() | ||
.filter(|node| { | ||
matches!( | ||
node.kind(), | ||
bibtex::PREAMBLE | bibtex::STRING | bibtex::ENTRY | ||
) | ||
}) | ||
.map(|node| create_range(line_index.line_col_lsp_range(node.text_range()))) | ||
.collect() | ||
} | ||
DocumentData::Aux(_) | ||
| DocumentData::Log(_) | ||
| DocumentData::Root | ||
| DocumentData::Tectonic => { | ||
return None; | ||
let foldings = folding::find_all(document).into_iter().map(|folding| { | ||
let range = document.line_index.line_col_lsp_range(folding.range); | ||
FoldingRange { | ||
start_line: range.start.line, | ||
start_character: Some(range.start.character), | ||
end_line: range.end.line, | ||
end_character: Some(range.end.character), | ||
collapsed_text: None, | ||
kind: None, | ||
} | ||
}; | ||
|
||
Some(foldings) | ||
} | ||
}); | ||
|
||
fn create_range(range: Range) -> FoldingRange { | ||
FoldingRange { | ||
start_line: range.start.line, | ||
start_character: Some(range.start.character), | ||
end_line: range.end.line, | ||
end_character: Some(range.end.character), | ||
collapsed_text: None, | ||
kind: Some(FoldingRangeKind::Region), | ||
} | ||
Some(foldings.collect()) | ||
} |