Skip to main content

cmakefmt/
error.rs

1// SPDX-FileCopyrightText: Copyright 2026 Puneet Matharu
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5use thiserror::Error;
6
7/// Structured config/spec deserialization failure metadata used for
8/// user-facing diagnostics.
9#[derive(Debug, Clone)]
10pub struct FileParseError {
11    /// Parser format name, such as `TOML` or `YAML`.
12    pub format: &'static str,
13    /// Human-readable parser message.
14    pub message: Box<str>,
15    /// Optional 1-based line number.
16    pub line: Option<usize>,
17    /// Optional 1-based column number.
18    pub column: Option<usize>,
19}
20
21/// Errors that can be returned by parsing, config loading, spec loading, or
22/// formatting operations.
23#[derive(Debug, Error)]
24pub enum Error {
25    /// A syntax error reported by the CMake parser.
26    #[error("parse error: {0}")]
27    Parse(#[from] Box<pest::error::Error<crate::parser::Rule>>),
28
29    /// A parser error annotated with source text and line-offset context.
30    #[error("parse error in {display_name}: {source}")]
31    ParseContext {
32        /// Human-facing source name, for example a path or `<stdin>`.
33        display_name: String,
34        /// The source text that failed to parse.
35        source_text: Box<str>,
36        /// The 1-based source line number where this parser chunk started.
37        start_line: usize,
38        /// Whether earlier barrier/fence handling affected how this chunk was parsed.
39        barrier_context: bool,
40        /// The underlying pest parser error.
41        source: Box<pest::error::Error<crate::parser::Rule>>,
42    },
43
44    /// A user config parse error.
45    #[error("config error in {path}: {source_message}")]
46    Config {
47        /// The config file that failed to deserialize.
48        path: std::path::PathBuf,
49        /// Structured parser details for the failure.
50        details: FileParseError,
51        /// Cached display string used by `thiserror`.
52        source_message: Box<str>,
53    },
54
55    /// A built-in or user override spec parse error.
56    #[error("spec error in {path}: {source_message}")]
57    Spec {
58        /// The spec file that failed to deserialize.
59        path: std::path::PathBuf,
60        /// Structured parser details for the failure.
61        details: FileParseError,
62        /// Cached display string used by `thiserror`.
63        source_message: Box<str>,
64    },
65
66    /// A filesystem or stream I/O failure.
67    #[error("I/O error: {0}")]
68    Io(#[from] std::io::Error),
69
70    /// A higher-level formatter or CLI error that does not fit another
71    /// structured variant.
72    #[error("formatter error: {0}")]
73    Formatter(String),
74}
75
76/// Convenience alias for crate-level results.
77pub type Result<T> = std::result::Result<T, Error>;
78
79impl Error {
80    /// Attach a human-facing source name to a contextual parser error.
81    pub fn with_display_name(self, display_name: impl Into<String>) -> Self {
82        match self {
83            Self::ParseContext {
84                source_text,
85                start_line,
86                barrier_context,
87                source,
88                ..
89            } => Self::ParseContext {
90                display_name: display_name.into(),
91                source_text,
92                start_line,
93                barrier_context,
94                source,
95            },
96            other => other,
97        }
98    }
99}