next.js/crates/next-code-frame/src/bin/code_frame.rs
code_frame.rs84 lines2.2 KB
use std::{fs, process::ExitCode};

use clap::Parser;
use next_code_frame::{CodeFrameLocation, CodeFrameOptions, Location, render_code_frame};

/// Render a code frame for the given file and position.
///
/// Lines and columns are 1-indexed.
#[derive(Parser)]
#[command(name = "code_frame")]
struct Args {
    /// Source file to render
    file: String,
    /// Start position (line:column, 1-indexed)
    start: String,
    /// End position (line:column, 1-indexed)
    end: Option<String>,
    /// Message to display with the error
    #[arg(short, long)]
    message: Option<String>,
    /// Maximum output width in columns
    #[arg(short = 'w', long, default_value_t = 100)]
    max_width: usize,
}

fn parse_position(s: &str) -> Option<Location> {
    let (line, col) = s.split_once(':')?;
    Some(Location {
        line: line.parse().ok()?,
        column: Some(col.parse().ok()?),
    })
}

fn main() -> ExitCode {
    let args = Args::parse();

    let source = match fs::read_to_string(&args.file) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Error reading {}: {e}", args.file);
            return ExitCode::FAILURE;
        }
    };

    let start = match parse_position(&args.start) {
        Some(loc) => loc,
        None => {
            eprintln!("Invalid start position: {}", args.start);
            return ExitCode::FAILURE;
        }
    };

    let end = match args.end.as_deref().map(parse_position) {
        Some(Some(loc)) => Some(loc),
        Some(None) => {
            eprintln!("Invalid end position: {}", args.end.unwrap());
            return ExitCode::FAILURE;
        }
        None => None,
    };

    let location = CodeFrameLocation { start, end };
    let options = CodeFrameOptions {
        message: args.message,
        max_width: args.max_width,
        ..Default::default()
    };

    match render_code_frame(&source, &location, &options) {
        Ok(Some(frame)) => {
            println!("{frame}");
            ExitCode::SUCCESS
        }
        Ok(None) => {
            // Location is out of range (e.g., empty file or line past EOF)
            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("Error rendering code frame: {e}");
            ExitCode::FAILURE
        }
    }
}
Quest for Codev2.0.0
/
SIGN IN