Skip to main content

boringbib/
lib.rs

1//! A boring BibTeX formatter.
2//!
3//! `boringbib` is a small command-line tool for BibTeX `.bib` files with two
4//! jobs:
5//!
6//! * [`fmt`](printer): sort entries by citation key and pretty-print each
7//!   entry with the `=` signs aligned, exactly like LaTeX Workshop's "Align
8//!   and sort" action.
9//! * [`keys`]: rewrite citation keys into Google Scholar style
10//!   (`vaswani2017attention`), updating in-file references so nothing
11//!   dangles.
12//!
13//! The library is organized as a pipeline over a lossless concrete syntax
14//! tree:
15//!
16//! ```text
17//! text ──parse()──▶ Cst ──sort::group()/sort()──▶ printer::format() ──▶ text
18//!                    │
19//!                    └──keys::plan()──▶ Plan ──keys::apply()──▶ text
20//! ```
21//!
22//! The parser ([`parser`], built on [`lexer`]) keeps every byte of the input
23//! in the [`Cst`]; `Cst::to_source()` reproduces the input exactly. All
24//! formatting decisions live in [`printer`] and [`sort`]; `keys` edits are
25//! splices of the original text at recorded spans. This separation is what
26//! makes the tool boring: deterministic output, idempotent runs, and no loss
27//! of the user's data.
28//!
29//! The binary lives in [`cli`]; see `DESIGN.md` in the repository for the
30//! decisions behind the grammar and the output rules.
31
32pub mod cli;
33pub mod config;
34pub mod cst;
35pub mod keys;
36pub mod lexer;
37pub mod parser;
38pub mod printer;
39pub mod sort;
40
41pub use cst::Cst;
42pub use lexer::ParseError;
43pub use parser::parse;
44pub use printer::{FmtOptions, format, format_str};
45
46/// Errors reported by the library when working with files.
47///
48/// Each variant's message is complete on its own (the cause is part of the
49/// text rather than a chained source), so that it prints the same whether
50/// or not the caller walks the error chain. Parse errors render as
51/// `file:line:col: message`, the format editors know how to jump to.
52#[derive(Debug, thiserror::Error)]
53pub enum Error {
54    /// The file is not syntactically valid BibTeX.
55    #[error("{path}:{error}")]
56    Parse {
57        /// Display name of the file (`<stdin>` for standard input).
58        path: String,
59        /// The underlying syntax error.
60        error: ParseError,
61    },
62    /// Reading or writing the file failed.
63    #[error("{path}: {error}")]
64    Io {
65        /// Display name of the file.
66        path: String,
67        /// The underlying I/O error.
68        error: std::io::Error,
69    },
70    /// The file is not valid UTF-8.
71    #[error("{path}: not valid UTF-8 (invalid byte sequence at offset {offset})")]
72    Utf8 {
73        /// Display name of the file.
74        path: String,
75        /// Byte offset of the first invalid sequence.
76        offset: usize,
77    },
78    /// The configuration file could not be parsed.
79    #[error("{path}: {message}")]
80    Config {
81        /// Path of the configuration file.
82        path: String,
83        /// What is wrong with it.
84        message: String,
85    },
86}