rantlr-core 0.2.0

Rantlr core: .gr lexer, parser, linter, and in-process runtime
Documentation
//! Structured auto-fix payloads for the linter / playground / LSP.

use serde::Serialize;

use crate::span::Span;

/// A concrete rewrite the UI can preview and apply via Monaco `executeEdits`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FixHint {
    pub title: String,
    /// Human explanation in plain “dev-speak”.
    pub explanation: String,
    /// Current source slice that will be replaced.
    pub before: String,
    /// Suggested replacement source (same as [`Self::suggestion`]).
    pub after: String,
    /// Exact string to splice over `[start, end)` — preferred by Smart Fix Pro.
    pub suggestion: String,
    /// Inclusive-exclusive UTF-8 byte range into the grammar source.
    pub start: u32,
    pub end: u32,
    /// 1-based line/column range covering the same bytes (for Monaco).
    pub start_line: u32,
    pub start_col: u32,
    pub end_line: u32,
    pub end_col: u32,
}

impl FixHint {
    pub fn new(
        title: impl Into<String>,
        explanation: impl Into<String>,
        before: impl Into<String>,
        after: impl Into<String>,
        span: Span,
        source: &str,
    ) -> Self {
        let after = after.into();
        let (start_line, start_col) = span.line_col(source);
        let end_off = span.end.as_usize().min(source.len());
        let (end_line, end_col) = Span::from_offsets(end_off, end_off).line_col(source);
        Self {
            title: title.into(),
            explanation: explanation.into(),
            before: before.into(),
            suggestion: after.clone(),
            after,
            start: span.start.0,
            end: span.end.0,
            start_line: start_line as u32,
            start_col: start_col as u32,
            end_line: end_line as u32,
            end_col: end_col.max(1) as u32,
        }
    }
}