texlang_stdlib/
errormode.rs1use std::cell::RefCell;
7use std::rc::Rc;
8use texlang::traits::*;
9use texlang::*;
10use texlang_common as common;
11
12#[derive(Default)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct Component {
15 mode: Mode,
16 #[cfg_attr(feature = "serde", serde(skip))]
17 default_terminal: DefaultTerminal,
18 errors: RefCell<Vec<error::TracedTexError>>,
19}
20
21impl Component {
22 pub fn set_default_terminal(&mut self, default_terminal: Rc<RefCell<dyn common::TerminalIn>>) {
24 self.default_terminal = DefaultTerminal(default_terminal);
25 }
26}
27
28struct DefaultTerminal(Rc<RefCell<dyn common::TerminalIn>>);
30
31impl Default for DefaultTerminal {
32 fn default() -> Self {
33 Self(Rc::new(RefCell::new(std::io::stdin())))
34 }
35}
36
37impl common::HasTerminalIn for Component {
38 fn terminal_in(&self) -> Rc<RefCell<dyn common::TerminalIn>> {
39 match self.mode {
40 Mode::ErrorStop | Mode::Scroll => self.default_terminal.0.clone(),
41 Mode::Batch | Mode::NonStop => Rc::new(RefCell::new(DisabledTerminalIn {})),
42 }
43 }
44}
45
46#[derive(Default, PartialEq, Eq, Debug)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48enum Mode {
49 #[default]
50 ErrorStop,
51 Scroll,
52 NonStop,
53 Batch,
54}
55
56pub fn get_errorstopmode<S: HasComponent<Component>>() -> command::BuiltIn<S> {
58 command::BuiltIn::new_execution(|_, input: &mut vm::ExecutionInput<S>| {
59 set_mode(input, Mode::ErrorStop);
60 Ok(())
61 })
62}
63
64pub fn get_scrollmode<S: HasComponent<Component>>() -> command::BuiltIn<S> {
66 command::BuiltIn::new_execution(|_, input: &mut vm::ExecutionInput<S>| {
67 set_mode(input, Mode::Scroll);
68 Ok(())
69 })
70}
71
72pub fn get_nonstopmode<S: HasComponent<Component>>() -> command::BuiltIn<S> {
74 command::BuiltIn::new_execution(|_, input: &mut vm::ExecutionInput<S>| {
75 set_mode(input, Mode::NonStop);
76 Ok(())
77 })
78}
79
80pub fn get_batchmode<S: HasComponent<Component>>() -> command::BuiltIn<S> {
82 command::BuiltIn::new_execution(|_, input: &mut vm::ExecutionInput<S>| {
83 set_mode(input, Mode::Batch);
84 Ok(())
85 })
86}
87
88pub fn recoverable_error_hook<S: HasComponent<Component> + common::HasLogging>(
89 state: &S,
90 recoverable_error: error::TracedTexError,
91) -> Result<(), Box<dyn error::TexError>> {
92 match &state.component().mode {
93 Mode::ErrorStop => {
94 return Err(recoverable_error.error);
95 }
96 Mode::Scroll | Mode::NonStop => {
97 writeln!(state.terminal_out().borrow_mut(), "{recoverable_error}").unwrap();
98 }
99 Mode::Batch => {}
100 }
101 writeln!(state.log_file().borrow_mut(), "{recoverable_error}").unwrap();
102 state
103 .component()
104 .errors
105 .borrow_mut()
106 .push(recoverable_error);
107 Ok(())
108}
109
110fn set_mode<S: HasComponent<Component>>(input: &mut vm::ExecutionInput<S>, mode: Mode) {
111 input.state_mut().component_mut().mode = mode;
112}
113
114struct DisabledTerminalIn;
115
116impl common::TerminalIn for DisabledTerminalIn {
117 fn read_line(&mut self, _: Option<&str>, _: &mut String) -> std::io::Result<()> {
118 todo!()
119 }
120}