Add ad-hoc diagnostic errors
This commit is contained in:
parent
9f70a22cf0
commit
cff2f6beb8
8 changed files with 107 additions and 56 deletions
|
@ -1,8 +1,21 @@
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
|
use eww_shared_util::{Span, VarName};
|
||||||
use simplexpr::dynval::DynVal;
|
use simplexpr::dynval::DynVal;
|
||||||
use yuck::config::script_var_definition::{ScriptVarDefinition, VarSource};
|
use yuck::{
|
||||||
|
config::script_var_definition::{ScriptVarDefinition, VarSource},
|
||||||
|
gen_diagnostic,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::error::DiagError;
|
||||||
|
|
||||||
|
pub fn create_script_var_failed_error(span: Span, var_name: &VarName) -> DiagError {
|
||||||
|
DiagError::new(gen_diagnostic! {
|
||||||
|
msg = format!("Failed to compute value for `{}`", var_name),
|
||||||
|
label = span => "Defined here",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn initial_value(var: &ScriptVarDefinition) -> Result<DynVal> {
|
pub fn initial_value(var: &ScriptVarDefinition) -> Result<DynVal> {
|
||||||
match var {
|
match var {
|
||||||
|
@ -10,15 +23,20 @@ pub fn initial_value(var: &ScriptVarDefinition) -> Result<DynVal> {
|
||||||
VarSource::Function(f) => {
|
VarSource::Function(f) => {
|
||||||
f().map_err(|err| anyhow!(err)).with_context(|| format!("Failed to compute initial value for {}", &var.name()))
|
f().map_err(|err| anyhow!(err)).with_context(|| format!("Failed to compute initial value for {}", &var.name()))
|
||||||
}
|
}
|
||||||
VarSource::Shell(f) => run_command(f).with_context(|| format!("Failed to compute initial value for {}", &var.name())),
|
VarSource::Shell(span, f) => run_command(f).map_err(|_| anyhow!(create_script_var_failed_error(*span, var.name()))),
|
||||||
},
|
},
|
||||||
ScriptVarDefinition::Tail(_) => Ok(DynVal::from_string(String::new())),
|
ScriptVarDefinition::Listen(_) => Ok(DynVal::from_string(String::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run a command and get the output
|
/// Run a command and get the output
|
||||||
pub fn run_command(cmd: &str) -> Result<DynVal> {
|
pub fn run_command(cmd: &str) -> Result<DynVal> {
|
||||||
log::debug!("Running command: {}", cmd);
|
log::debug!("Running command: {}", cmd);
|
||||||
let output = String::from_utf8(Command::new("/bin/sh").arg("-c").arg(cmd).output()?.stdout)?;
|
let command = Command::new("/bin/sh").arg("-c").arg(cmd).output()?;
|
||||||
|
if !command.status.success() {
|
||||||
|
bail!("Execution of `{}` failed", cmd);
|
||||||
|
}
|
||||||
|
let output = String::from_utf8(command.stdout)?;
|
||||||
let output = output.trim_matches('\n');
|
let output = output.trim_matches('\n');
|
||||||
Ok(DynVal::from(output))
|
Ok(DynVal::from(output))
|
||||||
}
|
}
|
||||||
|
|
20
crates/eww/src/error.rs
Normal file
20
crates/eww/src/error.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
use codespan_reporting::diagnostic::Diagnostic;
|
||||||
|
|
||||||
|
/// An error that contains a [Diagnostic] for ad-hoc creation of diagnostics.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DiagError {
|
||||||
|
pub diag: Diagnostic<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagError {
|
||||||
|
pub fn new(diag: Diagnostic<usize>) -> Self {
|
||||||
|
Self { diag }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for DiagError {}
|
||||||
|
impl std::fmt::Display for DiagError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.diag.message)
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,8 @@ use yuck::{
|
||||||
format_diagnostic::{eval_error_to_diagnostic, ToDiagnostic},
|
format_diagnostic::{eval_error_to_diagnostic, ToDiagnostic},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::error::DiagError;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
pub static ref ERROR_HANDLING_CTX: Arc<Mutex<FsYuckFiles>> = Arc::new(Mutex::new(FsYuckFiles::new()));
|
pub static ref ERROR_HANDLING_CTX: Arc<Mutex<FsYuckFiles>> = Arc::new(Mutex::new(FsYuckFiles::new()));
|
||||||
}
|
}
|
||||||
|
@ -18,29 +20,25 @@ pub fn clear_files() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_error(err: &anyhow::Error) {
|
pub fn print_error(err: &anyhow::Error) {
|
||||||
match err.downcast_ref::<AstError>() {
|
if let Some(err) = err.downcast_ref::<DiagError>() {
|
||||||
Some(err) => {
|
eprintln!("{:?}\n{}", err, stringify_diagnostic(&err.diag));
|
||||||
eprintln!("{:?}\n{}", err, stringify_diagnostic(err.to_diagnostic()));
|
} else if let Some(err) = err.downcast_ref::<AstError>() {
|
||||||
}
|
eprintln!("{:?}\n{}", err, stringify_diagnostic(&err.to_diagnostic()));
|
||||||
None => match err.downcast_ref::<EvalError>() {
|
} else if let Some(err) = err.downcast_ref::<EvalError>() {
|
||||||
Some(err) => {
|
eprintln!("{:?}\n{}", err, stringify_diagnostic(&eval_error_to_diagnostic(err, err.span().unwrap_or(DUMMY_SPAN))));
|
||||||
eprintln!("{:?}\n{}", err, stringify_diagnostic(eval_error_to_diagnostic(err, err.span().unwrap_or(DUMMY_SPAN))));
|
} else {
|
||||||
}
|
|
||||||
None => {
|
|
||||||
log::error!("{:?}", err);
|
log::error!("{:?}", err);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_error(err: &anyhow::Error) -> String {
|
pub fn format_error(err: &anyhow::Error) -> String {
|
||||||
match err.downcast_ref::<AstError>() {
|
match err.downcast_ref::<AstError>() {
|
||||||
Some(err) => stringify_diagnostic(err.to_diagnostic()),
|
Some(err) => stringify_diagnostic(&err.to_diagnostic()),
|
||||||
None => format!("{:?}", err),
|
None => format!("{:?}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_diagnostic(diagnostic: Diagnostic<usize>) -> String {
|
pub fn stringify_diagnostic(diagnostic: &Diagnostic<usize>) -> String {
|
||||||
use codespan_reporting::term;
|
use codespan_reporting::term;
|
||||||
let config = term::Config::default();
|
let config = term::Config::default();
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
|
|
|
@ -32,6 +32,7 @@ pub mod script_var_handler;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod widgets;
|
pub mod widgets;
|
||||||
|
pub mod error;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let opts: opts::Opt = opts::Opt::from_env();
|
let opts: opts::Opt = opts::Opt::from_env();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::app;
|
use crate::{app, config::create_script_var_failed_error};
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use app::DaemonCommand;
|
use app::DaemonCommand;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ use tokio::{
|
||||||
sync::mpsc::UnboundedSender,
|
sync::mpsc::UnboundedSender,
|
||||||
};
|
};
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
use yuck::config::script_var_definition::{PollScriptVar, ScriptVarDefinition, TailScriptVar};
|
use yuck::config::script_var_definition::{ListenScriptVar, PollScriptVar, ScriptVarDefinition, VarSource};
|
||||||
|
|
||||||
/// Initialize the script var handler, and return a handle to that handler, which can be used to control
|
/// Initialize the script var handler, and return a handle to that handler, which can be used to control
|
||||||
/// the script var execution.
|
/// the script var execution.
|
||||||
|
@ -23,7 +23,7 @@ pub fn init(evt_send: UnboundedSender<DaemonCommand>) -> ScriptVarHandlerHandle
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
let _: Result<_> = try {
|
let _: Result<_> = try {
|
||||||
let mut handler = ScriptVarHandler {
|
let mut handler = ScriptVarHandler {
|
||||||
tail_handler: TailVarHandler::new(evt_send.clone())?,
|
listen_handler: ListenVarHandler::new(evt_send.clone())?,
|
||||||
poll_handler: PollVarHandler::new(evt_send)?,
|
poll_handler: PollVarHandler::new(evt_send)?,
|
||||||
};
|
};
|
||||||
crate::loop_select_exiting! {
|
crate::loop_select_exiting! {
|
||||||
|
@ -87,7 +87,7 @@ enum ScriptVarHandlerMsg {
|
||||||
|
|
||||||
/// Handler that manages running and updating [ScriptVarDefinition]s
|
/// Handler that manages running and updating [ScriptVarDefinition]s
|
||||||
struct ScriptVarHandler {
|
struct ScriptVarHandler {
|
||||||
tail_handler: TailVarHandler,
|
listen_handler: ListenVarHandler,
|
||||||
poll_handler: PollVarHandler,
|
poll_handler: PollVarHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,14 +95,14 @@ impl ScriptVarHandler {
|
||||||
async fn add(&mut self, script_var: ScriptVarDefinition) {
|
async fn add(&mut self, script_var: ScriptVarDefinition) {
|
||||||
match script_var {
|
match script_var {
|
||||||
ScriptVarDefinition::Poll(var) => self.poll_handler.start(var).await,
|
ScriptVarDefinition::Poll(var) => self.poll_handler.start(var).await,
|
||||||
ScriptVarDefinition::Tail(var) => self.tail_handler.start(var).await,
|
ScriptVarDefinition::Listen(var) => self.listen_handler.start(var).await,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stop the handler that is responsible for a given variable.
|
/// Stop the handler that is responsible for a given variable.
|
||||||
fn stop_for_variable(&mut self, name: &VarName) -> Result<()> {
|
fn stop_for_variable(&mut self, name: &VarName) -> Result<()> {
|
||||||
log::debug!("Stopping script var process for variable {}", name);
|
log::debug!("Stopping script var process for variable {}", name);
|
||||||
self.tail_handler.stop_for_variable(name);
|
self.listen_handler.stop_for_variable(name);
|
||||||
self.poll_handler.stop_for_variable(name);
|
self.poll_handler.stop_for_variable(name);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ impl ScriptVarHandler {
|
||||||
/// stop all running scripts and schedules
|
/// stop all running scripts and schedules
|
||||||
fn stop_all(&mut self) {
|
fn stop_all(&mut self) {
|
||||||
log::debug!("Stopping script-var-handlers");
|
log::debug!("Stopping script-var-handlers");
|
||||||
self.tail_handler.stop_all();
|
self.listen_handler.stop_all();
|
||||||
self.poll_handler.stop_all();
|
self.poll_handler.stop_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,8 +163,10 @@ impl PollVarHandler {
|
||||||
|
|
||||||
fn run_poll_once(var: &PollScriptVar) -> Result<DynVal> {
|
fn run_poll_once(var: &PollScriptVar) -> Result<DynVal> {
|
||||||
match &var.command {
|
match &var.command {
|
||||||
yuck::config::script_var_definition::VarSource::Shell(x) => crate::config::script_var::run_command(x),
|
VarSource::Shell(span, x) => crate::config::script_var::run_command(x).map_err(|_| {
|
||||||
yuck::config::script_var_definition::VarSource::Function(x) => x().map_err(|e| anyhow!(e)),
|
anyhow!(create_script_var_failed_error(*span, &var.name))
|
||||||
|
}),
|
||||||
|
VarSource::Function(x) => x().map_err(|e| anyhow!(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,21 +176,21 @@ impl Drop for PollVarHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TailVarHandler {
|
struct ListenVarHandler {
|
||||||
evt_send: UnboundedSender<DaemonCommand>,
|
evt_send: UnboundedSender<DaemonCommand>,
|
||||||
tail_process_handles: HashMap<VarName, CancellationToken>,
|
listen_process_handles: HashMap<VarName, CancellationToken>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TailVarHandler {
|
impl ListenVarHandler {
|
||||||
fn new(evt_send: UnboundedSender<DaemonCommand>) -> Result<Self> {
|
fn new(evt_send: UnboundedSender<DaemonCommand>) -> Result<Self> {
|
||||||
let handler = TailVarHandler { evt_send, tail_process_handles: HashMap::new() };
|
let handler = ListenVarHandler { evt_send, listen_process_handles: HashMap::new() };
|
||||||
Ok(handler)
|
Ok(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start(&mut self, var: TailScriptVar) {
|
async fn start(&mut self, var: ListenScriptVar) {
|
||||||
log::debug!("starting poll var {}", &var.name);
|
log::debug!("starting poll var {}", &var.name);
|
||||||
let cancellation_token = CancellationToken::new();
|
let cancellation_token = CancellationToken::new();
|
||||||
self.tail_process_handles.insert(var.name.clone(), cancellation_token.clone());
|
self.listen_process_handles.insert(var.name.clone(), cancellation_token.clone());
|
||||||
|
|
||||||
let evt_send = self.evt_send.clone();
|
let evt_send = self.evt_send.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
@ -215,18 +217,18 @@ impl TailVarHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop_for_variable(&mut self, name: &VarName) {
|
fn stop_for_variable(&mut self, name: &VarName) {
|
||||||
if let Some(token) = self.tail_process_handles.remove(name) {
|
if let Some(token) = self.listen_process_handles.remove(name) {
|
||||||
log::debug!("stopped tail var {}", name);
|
log::debug!("stopped listen-var {}", name);
|
||||||
token.cancel();
|
token.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop_all(&mut self) {
|
fn stop_all(&mut self) {
|
||||||
self.tail_process_handles.drain().for_each(|(_, token)| token.cancel());
|
self.listen_process_handles.drain().for_each(|(_, token)| token.cancel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TailVarHandler {
|
impl Drop for ListenVarHandler {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.stop_all();
|
self.stop_all();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use super::{
|
||||||
window_definition::WindowDefinition,
|
window_definition::WindowDefinition,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
config::script_var_definition::{PollScriptVar, TailScriptVar},
|
config::script_var_definition::{ListenScriptVar, PollScriptVar},
|
||||||
error::{AstError, AstResult, OptionAstErrorExt},
|
error::{AstError, AstResult, OptionAstErrorExt},
|
||||||
parser::{
|
parser::{
|
||||||
ast::Ast,
|
ast::Ast,
|
||||||
|
@ -59,8 +59,8 @@ impl FromAst for TopLevel {
|
||||||
x if x == PollScriptVar::get_element_name() => {
|
x if x == PollScriptVar::get_element_name() => {
|
||||||
Self::ScriptVarDefinition(ScriptVarDefinition::Poll(PollScriptVar::from_tail(span, iter)?))
|
Self::ScriptVarDefinition(ScriptVarDefinition::Poll(PollScriptVar::from_tail(span, iter)?))
|
||||||
}
|
}
|
||||||
x if x == TailScriptVar::get_element_name() => {
|
x if x == ListenScriptVar::get_element_name() => {
|
||||||
Self::ScriptVarDefinition(ScriptVarDefinition::Tail(TailScriptVar::from_tail(span, iter)?))
|
Self::ScriptVarDefinition(ScriptVarDefinition::Listen(ListenScriptVar::from_tail(span, iter)?))
|
||||||
}
|
}
|
||||||
x if x == WindowDefinition::get_element_name() => Self::WindowDefinition(WindowDefinition::from_tail(span, iter)?),
|
x if x == WindowDefinition::get_element_name() => Self::WindowDefinition(WindowDefinition::from_tail(span, iter)?),
|
||||||
x => return Err(AstError::UnknownToplevel(sym_span, x.to_string())),
|
x => return Err(AstError::UnknownToplevel(sym_span, x.to_string())),
|
||||||
|
|
|
@ -15,14 +15,24 @@ use eww_shared_util::{AttrName, Span, VarName};
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
|
||||||
pub enum ScriptVarDefinition {
|
pub enum ScriptVarDefinition {
|
||||||
Poll(PollScriptVar),
|
Poll(PollScriptVar),
|
||||||
Tail(TailScriptVar),
|
Listen(ListenScriptVar),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptVarDefinition {
|
impl ScriptVarDefinition {
|
||||||
pub fn name(&self) -> &VarName {
|
pub fn name(&self) -> &VarName {
|
||||||
match self {
|
match self {
|
||||||
ScriptVarDefinition::Poll(x) => &x.name,
|
ScriptVarDefinition::Poll(x) => &x.name,
|
||||||
ScriptVarDefinition::Tail(x) => &x.name,
|
ScriptVarDefinition::Listen(x) => &x.name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn command_span(&self) -> Option<Span> {
|
||||||
|
match self {
|
||||||
|
ScriptVarDefinition::Poll(x) => match x.command {
|
||||||
|
VarSource::Shell(span, _) => Some(span),
|
||||||
|
VarSource::Function(_) => None,
|
||||||
|
},
|
||||||
|
ScriptVarDefinition::Listen(x) => Some(x.command_span),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,10 +40,11 @@ impl ScriptVarDefinition {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
|
||||||
pub enum VarSource {
|
pub enum VarSource {
|
||||||
// TODO allow for other executors? (python, etc)
|
// TODO allow for other executors? (python, etc)
|
||||||
Shell(String),
|
Shell(Span, String),
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
Function(fn() -> Result<DynVal, Box<dyn std::error::Error + Sync + Send + 'static>>),
|
Function(fn() -> Result<DynVal, Box<dyn std::error::Error + Sync + Send + 'static>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
|
||||||
pub struct PollScriptVar {
|
pub struct PollScriptVar {
|
||||||
pub name: VarName,
|
pub name: VarName,
|
||||||
|
@ -43,32 +54,32 @@ pub struct PollScriptVar {
|
||||||
|
|
||||||
impl FromAstElementContent for PollScriptVar {
|
impl FromAstElementContent for PollScriptVar {
|
||||||
fn get_element_name() -> &'static str {
|
fn get_element_name() -> &'static str {
|
||||||
"defpollvar"
|
"defpoll"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> AstResult<Self> {
|
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> AstResult<Self> {
|
||||||
let (_, name) = iter.expect_symbol()?;
|
let (_, name) = iter.expect_symbol()?;
|
||||||
let mut attrs = iter.expect_key_values()?;
|
let mut attrs = iter.expect_key_values()?;
|
||||||
let interval = attrs.primitive_required::<DynVal, _>("interval")?.as_duration()?;
|
let interval = attrs.primitive_required::<DynVal, _>("interval")?.as_duration()?;
|
||||||
// let interval = interval.as_duration()?;
|
let (script_span, script) = iter.expect_literal()?;
|
||||||
let (_, script) = iter.expect_literal()?;
|
Ok(Self { name: VarName(name), command: VarSource::Shell(script_span, script.to_string()), interval })
|
||||||
Ok(Self { name: VarName(name), command: VarSource::Shell(script.to_string()), interval })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
|
||||||
pub struct TailScriptVar {
|
pub struct ListenScriptVar {
|
||||||
pub name: VarName,
|
pub name: VarName,
|
||||||
pub command: String,
|
pub command: String,
|
||||||
|
pub command_span: Span,
|
||||||
}
|
}
|
||||||
impl FromAstElementContent for TailScriptVar {
|
impl FromAstElementContent for ListenScriptVar {
|
||||||
fn get_element_name() -> &'static str {
|
fn get_element_name() -> &'static str {
|
||||||
"deftailvar"
|
"deflisten"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> AstResult<Self> {
|
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> AstResult<Self> {
|
||||||
let (_, name) = iter.expect_symbol()?;
|
let (_, name) = iter.expect_symbol()?;
|
||||||
let (_, script) = iter.expect_literal()?;
|
let (command_span, script) = iter.expect_literal()?;
|
||||||
Ok(Self { name: VarName(name), command: script.to_string() })
|
Ok(Self { name: VarName(name), command: script.to_string(), command_span })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,24 +12,25 @@ fn span_to_secondary_label(span: Span) -> Label<usize> {
|
||||||
Label::secondary(span.2, span.0..span.1)
|
Label::secondary(span.2, span.0..span.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
macro_rules! gen_diagnostic {
|
macro_rules! gen_diagnostic {
|
||||||
(
|
(
|
||||||
$(msg = $msg:expr)?
|
$(msg = $msg:expr)?
|
||||||
$(, label = $span:expr $(=> $label:expr)?)?
|
$(, label = $span:expr $(=> $label:expr)?)?
|
||||||
$(, note = $note:expr)? $(,)?
|
$(, note = $note:expr)? $(,)?
|
||||||
) => {
|
) => {
|
||||||
Diagnostic::error()
|
::codespan_reporting::diagnostic::Diagnostic::error()
|
||||||
$(.with_message($msg.to_string()))?
|
$(.with_message($msg.to_string()))?
|
||||||
$(.with_labels(vec![
|
$(.with_labels(vec![
|
||||||
Label::primary($span.2, $span.0..$span.1)
|
::codespan_reporting::diagnostic::Label::primary($span.2, $span.0..$span.1)
|
||||||
$(.with_message($label))?
|
$(.with_message($label))?
|
||||||
]))?
|
]))?
|
||||||
$(.with_notes(vec![$note]))?
|
$(.with_notes(vec![$note]))?
|
||||||
};
|
};
|
||||||
($msg:expr $(, $span:expr $(,)?)?) => {{
|
($msg:expr $(, $span:expr $(,)?)?) => {{
|
||||||
Diagnostic::error()
|
::codespan_reporting::diagnostic::Diagnostic::error()
|
||||||
.with_message($msg.to_string())
|
.with_message($msg.to_string())
|
||||||
$(.with_labels(vec![Label::primary($span.2, $span.0..$span.1)]))?
|
$(.with_labels(vec![::codespan_reporting::diagnostic::Label::primary($span.2, $span.0..$span.1)]))?
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue