Skip to main content

oxilean_std/show/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use oxilean_kernel::{BinderInfo, Declaration, Expr, Level, Literal, Name};
6
7use super::functions::*;
8use std::fmt;
9
10/// A diagnostic display wrapper for error messages.
11#[allow(dead_code)]
12pub struct DiagnosticDisplay {
13    /// The error message.
14    pub message: String,
15    /// Optional source location hint.
16    pub location: Option<String>,
17    /// Severity level: 0 = note, 1 = warning, 2 = error.
18    pub severity: u8,
19    /// Optional code snippet.
20    pub snippet: Option<String>,
21}
22impl DiagnosticDisplay {
23    /// Create a new diagnostic.
24    pub fn new(message: impl Into<String>, severity: u8) -> Self {
25        DiagnosticDisplay {
26            message: message.into(),
27            location: None,
28            severity,
29            snippet: None,
30        }
31    }
32    /// Add a source location.
33    pub fn with_location(mut self, loc: impl Into<String>) -> Self {
34        self.location = Some(loc.into());
35        self
36    }
37    /// Add a code snippet.
38    pub fn with_snippet(mut self, snip: impl Into<String>) -> Self {
39        self.snippet = Some(snip.into());
40        self
41    }
42    /// Render the diagnostic to a string.
43    pub fn render(&self) -> String {
44        let prefix = match self.severity {
45            0 => "note",
46            1 => "warning",
47            _ => "error",
48        };
49        let loc = self
50            .location
51            .as_deref()
52            .map(|l| format!(" [{}]", l))
53            .unwrap_or_default();
54        let snip = self
55            .snippet
56            .as_deref()
57            .map(|s| format!("\n  | {}", s))
58            .unwrap_or_default();
59        format!("{}{}: {}{}", prefix, loc, self.message, snip)
60    }
61}
62/// Selects a high-level display mode for show operations.
63#[derive(Clone, Copy, Debug, PartialEq, Eq)]
64pub enum ShowMode {
65    /// Short single-line output.
66    Short,
67    /// Full multi-line output.
68    Full,
69    /// Debug / internal representation.
70    Debug,
71}
72impl ShowMode {
73    /// Convert to a `ShowConfig`.
74    pub fn to_config(self) -> ShowConfig {
75        match self {
76            ShowMode::Short => ShowConfig::compact(),
77            ShowMode::Full => ShowConfig::wide(),
78            ShowMode::Debug => ShowConfig::default().with_implicit().with_levels(),
79        }
80    }
81}
82/// Registry of named show formatters.
83#[allow(clippy::type_complexity)]
84pub struct ShowRegistry {
85    formatters: Vec<(String, Box<dyn Fn(&Expr) -> String + Send + Sync>)>,
86}
87impl ShowRegistry {
88    /// Create an empty registry.
89    pub fn new() -> Self {
90        ShowRegistry {
91            formatters: Vec::new(),
92        }
93    }
94    /// Register a formatter under a name.
95    pub fn register<F>(&mut self, name: &str, f: F)
96    where
97        F: Fn(&Expr) -> String + Send + Sync + 'static,
98    {
99        self.formatters.push((name.to_string(), Box::new(f)));
100    }
101    /// Format an expression with all registered formatters, returning a map.
102    pub fn format_all(&self, expr: &Expr) -> Vec<(String, String)> {
103        self.formatters
104            .iter()
105            .map(|(n, f)| (n.clone(), f(expr)))
106            .collect()
107    }
108    /// Number of registered formatters.
109    pub fn len(&self) -> usize {
110        self.formatters.len()
111    }
112    /// Whether the registry is empty.
113    pub fn is_empty(&self) -> bool {
114        self.formatters.is_empty()
115    }
116}
117/// A formatted output value with metadata about how it was produced.
118#[allow(dead_code)]
119pub struct FormattedOutput {
120    /// The rendered string.
121    pub rendered: String,
122    /// The name of the formatter that produced it.
123    pub formatter: String,
124    /// Whether the output was truncated.
125    pub truncated: bool,
126    /// Character count.
127    pub char_count: usize,
128}
129impl FormattedOutput {
130    /// Create a new `FormattedOutput`.
131    pub fn new(rendered: impl Into<String>, formatter: impl Into<String>, truncated: bool) -> Self {
132        let r = rendered.into();
133        let cc = r.chars().count();
134        FormattedOutput {
135            rendered: r,
136            formatter: formatter.into(),
137            truncated,
138            char_count: cc,
139        }
140    }
141    /// Create from a show call.
142    pub fn from_show<T: Show>(
143        value: &T,
144        formatter: impl Into<String>,
145        max_len: Option<usize>,
146    ) -> Self {
147        let s = value.show();
148        let (rendered, truncated) = match max_len {
149            Some(n) if s.chars().count() > n => (truncate_show(&s, n), true),
150            _ => (s, false),
151        };
152        FormattedOutput::new(rendered, formatter, truncated)
153    }
154}
155/// A difference-string (ShowS) representation: a function `String → String`
156/// encoded as a closure stored with its description.
157#[allow(dead_code)]
158pub struct ShowS {
159    /// Human-readable label for this ShowS value.
160    pub label: String,
161    /// The accumulated prefix string.
162    pub prefix: String,
163}
164impl ShowS {
165    /// Create a new ShowS from a prefix string.
166    pub fn new(label: impl Into<String>, prefix: impl Into<String>) -> Self {
167        ShowS {
168            label: label.into(),
169            prefix: prefix.into(),
170        }
171    }
172    /// Apply this ShowS: prepend the prefix to `rest`.
173    pub fn apply(&self, rest: &str) -> String {
174        format!("{}{}", self.prefix, rest)
175    }
176    /// Compose two ShowS values: `self` then `other`.
177    pub fn compose(&self, other: &ShowS) -> ShowS {
178        ShowS {
179            label: format!("{}.{}", self.label, other.label),
180            prefix: format!("{}{}", self.prefix, other.prefix),
181        }
182    }
183    /// The identity ShowS (no prefix).
184    pub fn identity() -> ShowS {
185        ShowS {
186            label: "id".to_string(),
187            prefix: String::new(),
188        }
189    }
190}
191/// Configuration controlling how terms are shown.
192#[derive(Clone, Debug)]
193pub struct ShowConfig {
194    /// Use compact (single-line) output.
195    pub compact: bool,
196    /// Restrict output to ASCII characters.
197    pub ascii_only: bool,
198    /// Maximum display depth (None = unlimited).
199    pub max_depth: Option<usize>,
200    /// Whether to show implicit arguments.
201    pub show_implicit: bool,
202    /// Whether to show universe levels.
203    pub show_levels: bool,
204    /// Whether to show binder types.
205    pub show_binder_types: bool,
206    /// Indentation step in spaces.
207    pub indent_step: usize,
208}
209impl ShowConfig {
210    /// Create a compact (single-line) config.
211    pub fn compact() -> Self {
212        Self {
213            compact: true,
214            ..Self::default()
215        }
216    }
217    /// Create a wide (multi-line) config.
218    pub fn wide() -> Self {
219        Self {
220            compact: false,
221            ..Self::default()
222        }
223    }
224    /// Create an ASCII-only config.
225    pub fn ascii() -> Self {
226        Self {
227            ascii_only: true,
228            ..Self::default()
229        }
230    }
231    /// Set a depth limit.
232    pub fn with_depth(self, d: usize) -> Self {
233        Self {
234            max_depth: Some(d),
235            ..self
236        }
237    }
238    /// Remove the depth limit.
239    pub fn unlimited(self) -> Self {
240        Self {
241            max_depth: None,
242            ..self
243        }
244    }
245    /// Show implicit arguments.
246    pub fn with_implicit(self) -> Self {
247        Self {
248            show_implicit: true,
249            ..self
250        }
251    }
252    /// Show universe levels.
253    pub fn with_levels(self) -> Self {
254        Self {
255            show_levels: true,
256            ..self
257        }
258    }
259    /// Arrow character (Unicode or ASCII).
260    pub fn arrow(&self) -> &'static str {
261        if self.ascii_only {
262            "->"
263        } else {
264            "→"
265        }
266    }
267    /// Lambda character.
268    pub fn lambda(&self) -> &'static str {
269        "fun"
270    }
271    /// Pi/forall character.
272    pub fn forall_kw(&self) -> &'static str {
273        if self.ascii_only {
274            "forall"
275        } else {
276            "∀"
277        }
278    }
279}
280/// Statistics collected during show operations (for debugging).
281#[derive(Clone, Debug, Default)]
282pub struct ShowStats {
283    /// Number of expressions rendered.
284    pub exprs_shown: u64,
285    /// Number of depth-limit truncations.
286    pub depth_truncations: u64,
287    /// Total characters produced.
288    pub chars_produced: u64,
289}
290impl ShowStats {
291    /// Create zeroed stats.
292    pub fn new() -> Self {
293        Self::default()
294    }
295    /// Record a show operation.
296    pub fn record(&mut self, output_len: usize, truncated: bool) {
297        self.exprs_shown += 1;
298        self.chars_produced += output_len as u64;
299        if truncated {
300            self.depth_truncations += 1;
301        }
302    }
303}
304/// Wraps any `T: Show` to implement `std::fmt::Display`.
305pub struct Showable<T: Show>(pub T);
306/// A simple algebraic document type for pretty printing.
307#[allow(dead_code)]
308pub struct PrettyDoc {
309    /// The flattened text representation.
310    pub text: String,
311    /// The preferred line width.
312    pub width: usize,
313    /// The indentation level.
314    pub indent: usize,
315}
316impl PrettyDoc {
317    /// Create a text leaf document.
318    pub fn text(s: impl Into<String>) -> Self {
319        let t = s.into();
320        let w = t.len();
321        PrettyDoc {
322            text: t,
323            width: w,
324            indent: 0,
325        }
326    }
327    /// Concatenate two documents horizontally.
328    pub fn concat(a: &PrettyDoc, b: &PrettyDoc) -> PrettyDoc {
329        PrettyDoc {
330            text: format!("{}{}", a.text, b.text),
331            width: a.width + b.width,
332            indent: a.indent,
333        }
334    }
335    /// Nest a document by increasing its indent.
336    pub fn nest(d: &PrettyDoc, extra: usize) -> PrettyDoc {
337        PrettyDoc {
338            text: d.text.clone(),
339            width: d.width,
340            indent: d.indent + extra,
341        }
342    }
343    /// Render the document to a string.
344    pub fn render(&self) -> String {
345        self.text.clone()
346    }
347}
348/// Registry extension for Show instances over a type parameter.
349#[allow(dead_code)]
350pub struct ShowRegistryExt<T> {
351    /// Name of the type this registry extends.
352    pub type_name: String,
353    /// Phantom to hold `T`.
354    _phantom: std::marker::PhantomData<T>,
355    /// Registered formatter names.
356    pub formatter_names: Vec<String>,
357}
358impl<T> ShowRegistryExt<T> {
359    /// Create a new extension registry.
360    pub fn new(type_name: impl Into<String>) -> Self {
361        ShowRegistryExt {
362            type_name: type_name.into(),
363            _phantom: std::marker::PhantomData,
364            formatter_names: Vec::new(),
365        }
366    }
367    /// Register a named formatter.
368    pub fn register_name(&mut self, name: impl Into<String>) {
369        self.formatter_names.push(name.into());
370    }
371    /// Number of registered formatters.
372    pub fn count(&self) -> usize {
373        self.formatter_names.len()
374    }
375}
376/// A string buffer with indentation support.
377#[derive(Clone, Debug, Default)]
378pub struct ShowBuffer {
379    /// Accumulated output.
380    pub(super) buf: String,
381    /// Current indentation level.
382    pub(super) indent: usize,
383    /// Indentation step (spaces per level).
384    pub(super) step: usize,
385}
386impl ShowBuffer {
387    /// Create a new empty buffer.
388    pub fn new(step: usize) -> Self {
389        Self {
390            buf: String::new(),
391            indent: 0,
392            step,
393        }
394    }
395    /// Push a string directly.
396    pub fn push(&mut self, s: &str) {
397        self.buf.push_str(s);
398    }
399    /// Push a character.
400    pub fn push_char(&mut self, c: char) {
401        self.buf.push(c);
402    }
403    /// Push a newline followed by current indentation.
404    pub fn newline(&mut self) {
405        self.buf.push('\n');
406        for _ in 0..self.indent * self.step {
407            self.buf.push(' ');
408        }
409    }
410    /// Increase indentation.
411    pub fn indent(&mut self) {
412        self.indent += 1;
413    }
414    /// Decrease indentation (saturating).
415    pub fn dedent(&mut self) {
416        self.indent = self.indent.saturating_sub(1);
417    }
418    /// Consume the buffer and return the accumulated string.
419    pub fn finish(self) -> String {
420        self.buf
421    }
422    /// Current accumulated length in bytes.
423    pub fn len(&self) -> usize {
424        self.buf.len()
425    }
426    /// Whether the buffer is empty.
427    pub fn is_empty(&self) -> bool {
428        self.buf.is_empty()
429    }
430    /// Push an indented block: indent, run f, dedent.
431    pub fn with_indent<F: FnOnce(&mut ShowBuffer)>(&mut self, f: F) {
432        self.indent();
433        f(self);
434        self.dedent();
435    }
436}