diff options
Diffstat (limited to 'support/texlab/src/formatting/bibtex.rs')
-rw-r--r-- | support/texlab/src/formatting/bibtex.rs | 376 |
1 files changed, 0 insertions, 376 deletions
diff --git a/support/texlab/src/formatting/bibtex.rs b/support/texlab/src/formatting/bibtex.rs deleted file mode 100644 index aba3299468..0000000000 --- a/support/texlab/src/formatting/bibtex.rs +++ /dev/null @@ -1,376 +0,0 @@ -use crate::syntax::*; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct BibtexFormattingOptions { - pub line_length: Option<i32>, -} - -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct BibtexFormattingParams { - pub tab_size: usize, - pub insert_spaces: bool, - pub options: BibtexFormattingOptions, -} - -impl BibtexFormattingParams { - pub fn line_length(&self) -> i32 { - let line_length = self.options.line_length.unwrap_or(120); - if line_length <= 0 { - std::i32::MAX - } else { - line_length - } - } -} - -impl Default for BibtexFormattingParams { - fn default() -> Self { - BibtexFormattingParams { - tab_size: 4, - insert_spaces: true, - options: BibtexFormattingOptions::default(), - } - } -} - -struct BibtexFormatter<'a> { - params: &'a BibtexFormattingParams, - indent: String, - output: String, -} - -impl<'a> BibtexFormatter<'a> { - fn new(params: &'a BibtexFormattingParams) -> Self { - let indent = if params.insert_spaces { - let mut buffer = String::new(); - for _ in 0..params.tab_size { - buffer.push(' '); - } - buffer - } else { - "\t".into() - }; - - Self { - params, - indent, - output: String::new(), - } - } - - fn format_comment(&mut self, comment: &BibtexComment) { - self.output.push_str(comment.token.text()); - } - - fn format_preamble(&mut self, preamble: &BibtexPreamble) { - self.format_token(&preamble.ty); - self.output.push('{'); - if let Some(ref content) = preamble.content { - self.format_content(content, self.output.chars().count()); - self.output.push('}'); - } - } - - fn format_string(&mut self, string: &BibtexString) { - self.format_token(&string.ty); - self.output.push('{'); - if let Some(ref name) = string.name { - self.output.push_str(name.text()); - self.output.push_str(" = "); - if let Some(ref value) = string.value { - self.format_content(value, self.output.chars().count()); - self.output.push('}'); - } - } - } - - fn format_entry(&mut self, entry: &BibtexEntry) { - self.format_token(&entry.ty); - self.output.push('{'); - if let Some(ref key) = entry.key { - self.output.push_str(key.text()); - self.output.push(','); - self.output.push('\n'); - for field in &entry.fields { - self.format_field(field); - } - self.output.push('}'); - } - } - - fn format_field(&mut self, field: &BibtexField) { - self.output.push_str(self.indent.as_ref()); - self.format_token(&field.name); - self.output.push_str(" = "); - let count = field.name.text().chars().count(); - let align = self.params.tab_size as usize + count + 3; - if let Some(ref content) = field.content { - self.format_content(content, align); - self.output.push(','); - self.output.push('\n'); - } - } - - fn format_content(&mut self, content: &BibtexContent, align: usize) { - let mut analyzer = BibtexContentAnalyzer::new(); - content.accept(&mut analyzer); - let tokens = analyzer.tokens; - self.output.push_str(tokens[0].text()); - - 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.params.line_length() as usize { - self.output.push('\n'); - self.output.push_str(self.indent.as_ref()); - for _ in 0..=align - self.params.tab_size { - self.output.push(' '); - } - length = align; - } else if insert_space { - self.output.push(' '); - length += 1; - } - self.output.push_str(current.text()); - length += current_length; - } - } - - fn format_token(&mut self, token: &BibtexToken) { - self.output.push_str(token.text().to_lowercase().as_ref()); - } - - fn should_insert_space(previous: &BibtexToken, current: &BibtexToken) -> bool { - previous.start().line != current.start().line - || previous.end().character < current.start().character - } -} - -struct BibtexContentAnalyzer<'a> { - pub tokens: Vec<&'a BibtexToken>, -} - -impl<'a> BibtexContentAnalyzer<'a> { - pub fn new() -> Self { - BibtexContentAnalyzer { tokens: Vec::new() } - } -} - -impl<'a> BibtexVisitor<'a> for BibtexContentAnalyzer<'a> { - fn visit_root(&mut self, _root: &'a BibtexRoot) {} - - fn visit_comment(&mut self, _comment: &'a BibtexComment) {} - - fn visit_preamble(&mut self, _preamble: &'a BibtexPreamble) {} - - fn visit_string(&mut self, _string: &'a BibtexString) {} - - fn visit_entry(&mut self, _entry: &'a BibtexEntry) {} - - fn visit_field(&mut self, _field: &'a BibtexField) {} - - fn visit_word(&mut self, word: &'a BibtexWord) { - self.tokens.push(&word.token); - } - - fn visit_command(&mut self, command: &'a BibtexCommand) { - self.tokens.push(&command.token); - } - - fn visit_quoted_content(&mut self, content: &'a BibtexQuotedContent) { - self.tokens.push(&content.left); - BibtexWalker::walk_quoted_content(self, content); - if let Some(ref right) = content.right { - self.tokens.push(right); - } - } - - fn visit_braced_content(&mut self, content: &'a BibtexBracedContent) { - self.tokens.push(&content.left); - BibtexWalker::walk_braced_content(self, content); - if let Some(ref right) = content.right { - self.tokens.push(right); - } - } - - fn visit_concat(&mut self, concat: &'a BibtexConcat) { - concat.left.accept(self); - self.tokens.push(&concat.operator); - if let Some(ref right) = concat.right { - right.accept(self); - } - } -} - -pub fn format_declaration( - declaration: &BibtexDeclaration, - params: &BibtexFormattingParams, -) -> String { - match declaration { - BibtexDeclaration::Comment(comment) => format_comment(comment, params), - BibtexDeclaration::Preamble(preamble) => format_preamble(preamble, params), - BibtexDeclaration::String(string) => format_string(string, params), - BibtexDeclaration::Entry(entry) => format_entry(entry, params), - } -} - -pub fn format_comment(comment: &BibtexComment, params: &BibtexFormattingParams) -> String { - let mut formatter = BibtexFormatter::new(params); - formatter.format_comment(&comment); - formatter.output -} - -pub fn format_preamble(preamble: &BibtexPreamble, params: &BibtexFormattingParams) -> String { - let mut formatter = BibtexFormatter::new(params); - formatter.format_preamble(&preamble); - formatter.output -} - -pub fn format_string(string: &BibtexString, params: &BibtexFormattingParams) -> String { - let mut formatter = BibtexFormatter::new(params); - formatter.format_string(&string); - formatter.output -} - -pub fn format_entry(entry: &BibtexEntry, params: &BibtexFormattingParams) -> String { - let mut formatter = BibtexFormatter::new(params); - formatter.format_entry(&entry); - formatter.output -} - -pub fn format_content(content: &BibtexContent, params: &BibtexFormattingParams) -> String { - let mut formatter = BibtexFormatter::new(params); - formatter.format_content(content, 0); - formatter.output -} - -#[cfg(test)] -mod tests { - use super::*; - use indoc::indoc; - - fn verify(source: &str, expected: &str, line_length: i32) { - let tree = BibtexSyntaxTree::from(source); - let params = BibtexFormattingParams { - tab_size: 4, - insert_spaces: true, - options: BibtexFormattingOptions { - line_length: Some(line_length), - }, - }; - assert_eq!( - expected, - format_declaration(&tree.root.children[0], ¶ms) - ); - } - - #[test] - fn test_wrap_long_lines() { - let source = - "@article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}"; - let expected = indoc!( - " - @article{foo, - bar = {Lorem ipsum dolor - sit amet, - consectetur - adipiscing elit.}, - }" - ); - verify(source, expected, 30); - } - - #[test] - fn test_line_length_zero() { - let source = - "@article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}"; - let expected = indoc!( - " - @article{foo, - bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit.}, - }" - ); - verify(source, expected, 0); - } - - #[test] - fn test_trailing_commas() { - let source = "@article{foo, bar = baz}"; - let expected = indoc!( - " - @article{foo, - bar = baz, - }" - ); - verify(source, expected, 30); - } - - #[test] - fn test_insert_braces() { - let source = "@article{foo, bar = baz,"; - let expected = indoc!( - " - @article{foo, - bar = baz, - }" - ); - verify(source, expected, 30); - } - - #[test] - fn test_commands() { - let source = "@article{foo, bar = \"\\baz\",}"; - let expected = indoc!( - "@article{foo, - bar = \"\\baz\", - }" - ); - verify(source, expected, 30); - } - - #[test] - fn test_concatenation() { - let source = "@article{foo, bar = \"baz\" # \"qux\"}"; - let expected = indoc!( - " - @article{foo, - bar = \"baz\" # \"qux\", - }" - ); - verify(source, expected, 30); - } - - #[test] - fn test_parentheses() { - let source = "@article(foo,)"; - let expected = indoc!( - " - @article{foo, - }" - ); - verify(source, expected, 30); - } - - #[test] - fn test_string() { - let source = "@string{foo=\"bar\"}"; - let expected = "@string{foo = \"bar\"}"; - verify(source, expected, 30); - } - - #[test] - fn test_preamble() { - let source = "@preamble{\n\"foo bar baz\"}"; - let expected = "@preamble{\"foo bar baz\"}"; - verify(source, expected, 30); - } -} |