error.rs
1 /* This file is part of DarkFi (https://dark.fi) 2 * 3 * Copyright (C) 2020-2025 Dyne.org foundation 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Affero General Public License as 7 * published by the Free Software Foundation, either version 3 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Affero General Public License for more details. 14 * 15 * You should have received a copy of the GNU Affero General Public License 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 */ 18 19 use std::io::{self, Error, Write}; 20 21 pub(super) struct ErrorEmitter { 22 namespace: String, 23 file: String, 24 lines: Vec<String>, 25 } 26 27 impl ErrorEmitter { 28 pub fn new(namespace: &str, file: &str, lines: Vec<String>) -> Self { 29 Self { namespace: namespace.to_string(), file: file.to_string(), lines } 30 } 31 32 fn fmt(&self, msg: String, ln: usize, col: usize) -> String { 33 let (err_msg, dbg_msg, caret) = match ln { 34 0 => (msg, "".to_string(), "".to_string()), 35 _ => { 36 let err_msg = format!("{msg} (line {ln}, column {col})"); 37 let dbg_msg = format!("{}:{ln}:{col}: {}", self.file, self.lines[ln - 1]); 38 let pad = dbg_msg.split(": ").next().unwrap().len() + col + 1; 39 let caret = format!("{:width$}^", "", width = pad); 40 (err_msg, dbg_msg, caret) 41 } 42 }; 43 format!("{err_msg}\n{dbg_msg}\n{caret}\n") 44 } 45 46 pub fn abort(&self, msg: &str, ln: usize, col: usize) -> Error { 47 let m = self.fmt(msg.to_string(), ln, col); 48 self.emit("error", &m); 49 Error::other(m) 50 } 51 52 pub fn warn(&self, msg: &str, ln: usize, col: usize) { 53 let m = self.fmt(msg.to_string(), ln, col); 54 self.emit("warning", &m); 55 } 56 57 pub fn emit(&self, typ: &str, msg: &str) { 58 if std::env::var("ZKAS_SILENT").is_ok() { 59 return 60 } 61 62 let stderr = io::stderr(); 63 let mut handle = stderr.lock(); 64 65 match typ { 66 "error" => write!(handle, "\x1b[31;1m{} error:\x1b[0m {msg}", self.namespace).unwrap(), 67 68 "warning" => { 69 write!(handle, "\x1b[33;1m{} warning:\x1b[0m {msg}", self.namespace).unwrap() 70 } 71 72 _ => unreachable!(), 73 }; 74 75 handle.flush().unwrap(); 76 } 77 }