summaryrefslogtreecommitdiff
path: root/support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs')
-rw-r--r--support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs199
1 files changed, 12 insertions, 187 deletions
diff --git a/support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs b/support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs
index 2b16939f43..0070765b4b 100644
--- a/support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs
+++ b/support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs
@@ -1,7 +1,6 @@
-use base_db::{util::LineIndex, Document, Workspace};
+use base_db::{Document, Workspace};
use lsp_types::{FormattingOptions, TextEdit};
-use rowan::{ast::AstNode, NodeOrToken};
-use syntax::bibtex::{self, HasName, HasType, HasValue};
+use rowan::{TextLen, TextRange};
use crate::util::line_index_ext::LineIndexExt;
@@ -10,189 +9,15 @@ pub fn format_bibtex_internal(
document: &Document,
options: &FormattingOptions,
) -> Option<Vec<TextEdit>> {
- let mut indent = String::new();
-
- if options.insert_spaces {
- for _ in 0..options.tab_size {
- indent.push(' ');
- }
- } else {
- indent.push('\t');
- }
-
- let line_length = workspace.config().formatting.line_length;
-
- let line_index = &document.line_index;
-
let data = document.data.as_bib()?;
- let mut edits = Vec::new();
-
- for node in data.root_node().children().filter(|node| {
- matches!(
- node.kind(),
- bibtex::PREAMBLE | bibtex::STRING | bibtex::ENTRY
- )
- }) {
- let range = node.text_range();
-
- let mut formatter =
- Formatter::new(indent.clone(), options.tab_size, line_length, line_index);
-
- formatter.visit_node(node);
- edits.push(TextEdit {
- range: line_index.line_col_lsp_range(range),
- new_text: formatter.output,
- });
- }
-
- Some(edits)
-}
-
-struct Formatter<'a> {
- indent: String,
- tab_size: u32,
- line_length: usize,
- output: String,
- align: Vec<usize>,
- line_index: &'a LineIndex,
-}
-
-impl<'a> Formatter<'a> {
- fn new(indent: String, tab_size: u32, line_length: usize, line_index: &'a LineIndex) -> Self {
- Self {
- indent,
- tab_size,
- line_length,
- output: String::new(),
- align: Vec::new(),
- line_index,
- }
- }
-
- fn visit_token_lowercase(&mut self, token: &bibtex::SyntaxToken) {
- self.output.push_str(&token.text().to_lowercase());
- }
-
- fn should_insert_space(
- &self,
- previous: &bibtex::SyntaxToken,
- current: &bibtex::SyntaxToken,
- ) -> bool {
- let previous_range = self.line_index.line_col_lsp_range(previous.text_range());
- let current_range = self.line_index.line_col_lsp_range(current.text_range());
- previous_range.start.line != current_range.start.line
- || previous_range.end.character < current_range.start.character
- }
-
- fn base_align(&self) -> usize {
- self.output[self.output.rfind('\n').unwrap_or(0)..]
- .chars()
- .count()
- }
-
- fn visit_node(&mut self, parent: bibtex::SyntaxNode) {
- match parent.kind() {
- bibtex::PREAMBLE => {
- let preamble = bibtex::Preamble::cast(parent).unwrap();
- self.visit_token_lowercase(&preamble.type_token().unwrap());
- self.output.push('{');
- if preamble.syntax().children().next().is_some() {
- self.align.push(self.base_align());
- for node in preamble.syntax().children() {
- self.visit_node(node);
- }
- self.output.push('}');
- }
- }
- bibtex::STRING => {
- let string = bibtex::StringDef::cast(parent).unwrap();
- self.visit_token_lowercase(&string.type_token().unwrap());
- self.output.push('{');
- if let Some(name) = string.name_token() {
- self.output.push_str(name.text());
- self.output.push_str(" = ");
- if let Some(value) = string.value() {
- self.align.push(self.base_align());
- self.visit_node(value.syntax().clone());
- self.output.push('}');
- }
- }
- }
- bibtex::ENTRY => {
- let entry = bibtex::Entry::cast(parent).unwrap();
- self.visit_token_lowercase(&entry.type_token().unwrap());
- self.output.push('{');
- if let Some(key) = entry.name_token() {
- self.output.push_str(&key.to_string());
- self.output.push(',');
- self.output.push('\n');
- for field in entry.fields() {
- self.visit_node(field.syntax().clone());
- }
- self.output.push('}');
- }
- }
- bibtex::FIELD => {
- let field = bibtex::Field::cast(parent).unwrap();
- self.output.push_str(&self.indent);
- let name = field.name_token().unwrap();
- self.output.push_str(name.text());
- self.output.push_str(" = ");
- if let Some(value) = field.value() {
- let count = name.text().chars().count();
- self.align.push(self.tab_size as usize + count + 3);
- self.visit_node(value.syntax().clone());
- self.output.push(',');
- self.output.push('\n');
- }
- }
- kind if bibtex::Value::can_cast(kind) => {
- let tokens: Vec<_> = parent
- .descendants_with_tokens()
- .filter_map(|element| element.into_token())
- .filter(|token| token.kind() != bibtex::WHITESPACE)
- .collect();
-
- self.output.push_str(tokens[0].text());
-
- let align = self.align.pop().unwrap_or_default();
- let mut length = align + tokens[0].text().chars().count();
- for i in 1..tokens.len() {
- let previous = &tokens[i - 1];
- let current = &tokens[i];
- let current_length = current.text().chars().count();
-
- let insert_space = self.should_insert_space(previous, current);
- let space_length = if insert_space { 1 } else { 0 };
-
- if length + current_length + space_length > self.line_length {
- self.output.push('\n');
- self.output.push_str(self.indent.as_ref());
- for _ in 0..=align - self.tab_size as usize {
- self.output.push(' ');
- }
- length = align;
- } else if insert_space {
- self.output.push(' ');
- length += 1;
- }
- self.output.push_str(current.text());
- length += current_length;
- }
- }
- bibtex::ROOT | bibtex::JUNK => {
- for element in parent.children_with_tokens() {
- match element {
- NodeOrToken::Token(token) => {
- self.output.push_str(token.text());
- }
- NodeOrToken::Node(node) => {
- self.visit_node(node);
- }
- }
- }
- }
- _ => unreachable!(),
- }
- }
+ let options = bibfmt::Options {
+ insert_spaces: options.insert_spaces,
+ line_length: workspace.config().formatting.line_length,
+ tab_size: options.tab_size as usize,
+ };
+
+ let output = bibfmt::format(&data.root_node(), &document.line_index, &options);
+ let range = TextRange::new(0.into(), document.text.text_len());
+ let range = document.line_index.line_col_lsp_range(range)?;
+ Some(vec![lsp_types::TextEdit::new(range, output)])
}