1pub mod attr;
2pub mod ext;
3pub mod liteval;
4pub mod partial;
5pub mod pretty;
6
7mod config;
8mod utils;
9
10pub use attr::AttrStore;
11pub use config::Config;
12use pretty::{prelude::*, PrettyPrinter};
13use thiserror::Error;
14use typst_syntax::Source;
15
16#[derive(Error, Debug)]
17pub enum Error {
18 #[error("The document has syntax errors")]
19 SyntaxError,
20 #[error("An error occurred while rendering the document")]
21 RenderError,
22}
23
24#[derive(Debug, Clone, Default)]
26pub struct Typstyle {
27 config: Config,
28}
29
30impl Typstyle {
31 pub fn new(config: Config) -> Self {
33 Self { config }
34 }
35
36 pub fn format_text(&self, text: impl Into<String>) -> Formatter {
38 self.format_source(Source::detached(text.into()))
40 }
41
42 pub fn format_source(&self, source: Source) -> Formatter {
44 Formatter::new(self.config.clone(), source)
45 }
46}
47
48pub struct Formatter<'a> {
50 source: Source,
51 printer: PrettyPrinter<'a>,
52}
53
54impl<'a> Formatter<'a> {
55 fn new(config: Config, source: Source) -> Self {
56 let attr_store = AttrStore::new(source.root());
57 let printer = PrettyPrinter::new(config, attr_store);
58 Self { source, printer }
59 }
60
61 pub fn render_ir(&'a self) -> Result<String, Error> {
63 let doc = self.build_doc()?;
64 Ok(format!("{doc:#?}"))
65 }
66
67 pub fn render(&'a self) -> Result<String, Error> {
69 let doc = self.build_doc()?;
70 let mut buf = String::new();
71 doc.render_fmt(self.printer.config().max_width, &mut buf)
72 .map_err(|_| Error::RenderError)?;
73 let result = utils::strip_trailing_whitespace(&buf);
74 Ok(result)
75 }
76
77 fn build_doc(&'a self) -> Result<ArenaDoc<'a>, Error> {
78 let root = self.source.root();
79 if root.erroneous() {
80 return Err(Error::SyntaxError);
81 }
82 let markup = root.cast().unwrap();
83 let doc = self.printer.convert_markup(Default::default(), markup);
84 Ok(doc)
85 }
86}