Yeet try_blocks 😢

This commit is contained in:
elkowar 2024-02-17 12:59:41 +01:00 committed by ElKowar
parent 0eed19332b
commit 60ab81ac13
14 changed files with 211 additions and 205 deletions

View file

@ -146,152 +146,150 @@ impl<B> std::fmt::Debug for App<B> {
} }
impl<B: DisplayBackend> App<B> { impl<B: DisplayBackend> App<B> {
/// Handle a [`DaemonCommand`] event. /// Handle a [`DaemonCommand`] event, logging any errors that occur.
pub fn handle_command(&mut self, event: DaemonCommand) { pub fn handle_command(&mut self, event: DaemonCommand) {
log::debug!("Handling event: {:?}", &event); if let Err(err) = self.try_handle_command(event) {
let result: Result<_> = try {
match event {
DaemonCommand::NoOp => {}
DaemonCommand::OpenInspector => {
gtk::Window::set_interactive_debugging(true);
}
DaemonCommand::UpdateVars(mappings) => {
for (var_name, new_value) in mappings {
self.update_global_variable(var_name, new_value);
}
}
DaemonCommand::ReloadConfigAndCss(sender) => {
let mut errors = Vec::new();
let config_result = config::read_from_eww_paths(&self.paths);
if let Err(e) = config_result.and_then(|new_config| self.load_config(new_config)) {
errors.push(e)
}
match crate::config::scss::parse_scss_from_config(self.paths.get_config_dir()) {
Ok((file_id, css)) => {
if let Err(e) = self.load_css(file_id, &css) {
errors.push(anyhow!(e));
}
}
Err(e) => {
errors.push(e);
}
}
sender.respond_with_error_list(errors)?;
}
DaemonCommand::KillServer => {
log::info!("Received kill command, stopping server!");
self.stop_application();
}
DaemonCommand::CloseAll => {
log::info!("Received close command, closing all windows");
for window_name in self.open_windows.keys().cloned().collect::<Vec<String>>() {
self.close_window(&window_name)?;
}
}
DaemonCommand::OpenMany { windows, args, should_toggle, sender } => {
let errors = windows
.iter()
.map(|w| {
let (config_name, id) = w;
if should_toggle && self.open_windows.contains_key(id) {
self.close_window(id)
} else {
log::debug!("Config: {}, id: {}", config_name, id);
let window_args = args
.iter()
.filter(|(win_id, ..)| win_id.is_empty() || win_id == id)
.map(|(_, n, v)| (n.clone(), v.clone()))
.collect();
self.open_window(&WindowArguments::new_from_args(
id.to_string(),
config_name.clone(),
window_args,
)?)
}
})
.filter_map(Result::err);
sender.respond_with_error_list(errors)?;
}
DaemonCommand::OpenWindow {
window_name,
instance_id,
pos,
size,
anchor,
screen: monitor,
should_toggle,
duration,
sender,
args,
} => {
let instance_id = instance_id.unwrap_or_else(|| window_name.clone());
let is_open = self.open_windows.contains_key(&instance_id);
let result = if should_toggle && is_open {
self.close_window(&instance_id)
} else {
self.open_window(&WindowArguments {
instance_id,
window_name,
pos,
size,
monitor,
anchor,
duration,
args: args.unwrap_or_default().into_iter().collect(),
})
};
sender.respond_with_result(result)?;
}
DaemonCommand::CloseWindows { windows, sender } => {
let errors = windows.iter().map(|window| self.close_window(window)).filter_map(Result::err);
sender.respond_with_error_list(errors)?;
}
DaemonCommand::PrintState { all, sender } => {
let scope_graph = self.scope_graph.borrow();
let used_globals_names = scope_graph.currently_used_globals();
let output = scope_graph
.global_scope()
.data
.iter()
.filter(|(key, _)| all || used_globals_names.contains(*key))
.map(|(key, value)| format!("{}: {}", key, value))
.join("\n");
sender.send_success(output)?
}
DaemonCommand::GetVar { name, sender } => {
let scope_graph = &*self.scope_graph.borrow();
let vars = &scope_graph.global_scope().data;
match vars.get(name.as_str()) {
Some(x) => sender.send_success(x.to_string())?,
None => sender.send_failure(format!("Variable not found \"{}\"", name))?,
}
}
DaemonCommand::ListWindows(sender) => {
let output = self.eww_config.get_windows().keys().join("\n");
sender.send_success(output)?
}
DaemonCommand::ListActiveWindows(sender) => {
let output = self.open_windows.iter().map(|(id, window)| format!("{id}: {}", window.name)).join("\n");
sender.send_success(output)?
}
DaemonCommand::PrintDebug(sender) => {
let output = format!("{:#?}", &self);
sender.send_success(output)?
}
DaemonCommand::PrintGraph(sender) => sender.send_success(self.scope_graph.borrow().visualize())?,
}
};
if let Err(err) = result {
error_handling_ctx::print_error(err); error_handling_ctx::print_error(err);
} }
} }
/// Try to handle a [`DaemonCommand`] event.
fn try_handle_command(&mut self, event: DaemonCommand) -> Result<()> {
log::debug!("Handling event: {:?}", &event);
match event {
DaemonCommand::NoOp => {}
DaemonCommand::OpenInspector => {
gtk::Window::set_interactive_debugging(true);
}
DaemonCommand::UpdateVars(mappings) => {
for (var_name, new_value) in mappings {
self.update_global_variable(var_name, new_value);
}
}
DaemonCommand::ReloadConfigAndCss(sender) => {
let mut errors = Vec::new();
let config_result = config::read_from_eww_paths(&self.paths);
if let Err(e) = config_result.and_then(|new_config| self.load_config(new_config)) {
errors.push(e)
}
match crate::config::scss::parse_scss_from_config(self.paths.get_config_dir()) {
Ok((file_id, css)) => {
if let Err(e) = self.load_css(file_id, &css) {
errors.push(anyhow!(e));
}
}
Err(e) => {
errors.push(e);
}
}
sender.respond_with_error_list(errors)?;
}
DaemonCommand::KillServer => {
log::info!("Received kill command, stopping server!");
self.stop_application();
}
DaemonCommand::CloseAll => {
log::info!("Received close command, closing all windows");
for window_name in self.open_windows.keys().cloned().collect::<Vec<String>>() {
self.close_window(&window_name)?;
}
}
DaemonCommand::OpenMany { windows, args, should_toggle, sender } => {
let errors = windows
.iter()
.map(|w| {
let (config_name, id) = w;
if should_toggle && self.open_windows.contains_key(id) {
self.close_window(id)
} else {
log::debug!("Config: {}, id: {}", config_name, id);
let window_args = args
.iter()
.filter(|(win_id, ..)| win_id.is_empty() || win_id == id)
.map(|(_, n, v)| (n.clone(), v.clone()))
.collect();
self.open_window(&WindowArguments::new_from_args(id.to_string(), config_name.clone(), window_args)?)
}
})
.filter_map(Result::err);
sender.respond_with_error_list(errors)?;
}
DaemonCommand::OpenWindow {
window_name,
instance_id,
pos,
size,
anchor,
screen: monitor,
should_toggle,
duration,
sender,
args,
} => {
let instance_id = instance_id.unwrap_or_else(|| window_name.clone());
let is_open = self.open_windows.contains_key(&instance_id);
let result = if should_toggle && is_open {
self.close_window(&instance_id)
} else {
self.open_window(&WindowArguments {
instance_id,
window_name,
pos,
size,
monitor,
anchor,
duration,
args: args.unwrap_or_default().into_iter().collect(),
})
};
sender.respond_with_result(result)?;
}
DaemonCommand::CloseWindows { windows, sender } => {
let errors = windows.iter().map(|window| self.close_window(window)).filter_map(Result::err);
sender.respond_with_error_list(errors)?;
}
DaemonCommand::PrintState { all, sender } => {
let scope_graph = self.scope_graph.borrow();
let used_globals_names = scope_graph.currently_used_globals();
let output = scope_graph
.global_scope()
.data
.iter()
.filter(|(key, _)| all || used_globals_names.contains(*key))
.map(|(key, value)| format!("{}: {}", key, value))
.join("\n");
sender.send_success(output)?
}
DaemonCommand::GetVar { name, sender } => {
let scope_graph = &*self.scope_graph.borrow();
let vars = &scope_graph.global_scope().data;
match vars.get(name.as_str()) {
Some(x) => sender.send_success(x.to_string())?,
None => sender.send_failure(format!("Variable not found \"{}\"", name))?,
}
}
DaemonCommand::ListWindows(sender) => {
let output = self.eww_config.get_windows().keys().join("\n");
sender.send_success(output)?
}
DaemonCommand::ListActiveWindows(sender) => {
let output = self.open_windows.iter().map(|(id, window)| format!("{id}: {}", window.name)).join("\n");
sender.send_success(output)?
}
DaemonCommand::PrintDebug(sender) => {
let output = format!("{:#?}", &self);
sender.send_success(output)?
}
DaemonCommand::PrintGraph(sender) => sender.send_success(self.scope_graph.borrow().visualize())?,
}
Ok(())
}
/// Fully stop eww: /// Fully stop eww:
/// close all windows, stop the script_var_handler, quit the gtk appliaction and send the exit instruction to the lifecycle manager /// close all windows, stop the script_var_handler, quit the gtk appliaction and send the exit instruction to the lifecycle manager
fn stop_application(&mut self) { fn stop_application(&mut self) {
@ -375,7 +373,7 @@ impl<B: DisplayBackend> App<B> {
self.instance_id_to_args.insert(instance_id.to_string(), window_args.clone()); self.instance_id_to_args.insert(instance_id.to_string(), window_args.clone());
let open_result: Result<_> = try { let open_result: Result<_> = (|| {
let window_name: &str = &window_args.window_name; let window_name: &str = &window_args.window_name;
let window_def = self.eww_config.get_window(window_name)?.clone(); let window_def = self.eww_config.get_window(window_name)?.clone();
@ -461,7 +459,8 @@ impl<B: DisplayBackend> App<B> {
} }
self.open_windows.insert(instance_id.to_string(), eww_window); self.open_windows.insert(instance_id.to_string(), eww_window);
}; Ok(())
})();
if let Err(err) = open_result { if let Err(err) = open_result {
self.failed_windows.insert(instance_id.to_string()); self.failed_windows.insert(instance_id.to_string());
@ -499,15 +498,15 @@ impl<B: DisplayBackend> App<B> {
pub fn load_css(&mut self, file_id: usize, css: &str) -> Result<()> { pub fn load_css(&mut self, file_id: usize, css: &str) -> Result<()> {
if let Err(err) = self.css_provider.load_from_data(css.as_bytes()) { if let Err(err) = self.css_provider.load_from_data(css.as_bytes()) {
static PATTERN: Lazy<regex::Regex> = Lazy::new(|| regex::Regex::new(r"[^:]*:(\d+):(\d+)(.*)$").unwrap()); static PATTERN: Lazy<regex::Regex> = Lazy::new(|| regex::Regex::new(r"[^:]*:(\d+):(\d+)(.*)$").unwrap());
let nice_error_option: Option<_> = try { let nice_error_option: Option<_> = (|| {
let captures = PATTERN.captures(err.message())?; let captures = PATTERN.captures(err.message())?;
let line = captures.get(1).unwrap().as_str().parse::<usize>().ok()?; let line = captures.get(1).unwrap().as_str().parse::<usize>().ok()?;
let msg = captures.get(3).unwrap().as_str(); let msg = captures.get(3).unwrap().as_str();
let db = error_handling_ctx::FILE_DATABASE.read().ok()?; let db = error_handling_ctx::FILE_DATABASE.read().ok()?;
let line_range = db.line_range(file_id, line - 1).ok()?; let line_range = db.line_range(file_id, line - 1).ok()?;
let span = Span(line_range.start, line_range.end - 1, file_id); let span = Span(line_range.start, line_range.end - 1, file_id);
DiagError(gen_diagnostic!(msg, span)) Some(DiagError(gen_diagnostic!(msg, span)))
}; })();
match nice_error_option { match nice_error_option {
Some(error) => Err(anyhow!(error)), Some(error) => Err(anyhow!(error)),
None => Err(anyhow!("CSS error: {}", err.message())), None => Err(anyhow!("CSS error: {}", err.message())),

View file

@ -1,4 +1,3 @@
#![feature(try_blocks)]
#![allow(rustdoc::private_intra_doc_links)] #![allow(rustdoc::private_intra_doc_links)]
extern crate gtk; extern crate gtk;

View file

@ -33,7 +33,7 @@ pub fn init(evt_send: UnboundedSender<DaemonCommand>) -> ScriptVarHandlerHandle
.build() .build()
.expect("Failed to initialize tokio runtime for script var handlers"); .expect("Failed to initialize tokio runtime for script var handlers");
rt.block_on(async { rt.block_on(async {
let _: Result<_> = try { let _: Result<_> = async {
let mut handler = ScriptVarHandler { let mut handler = ScriptVarHandler {
listen_handler: ListenVarHandler::new(evt_send.clone())?, listen_handler: ListenVarHandler::new(evt_send.clone())?,
poll_handler: PollVarHandler::new(evt_send)?, poll_handler: PollVarHandler::new(evt_send)?,
@ -53,7 +53,9 @@ pub fn init(evt_send: UnboundedSender<DaemonCommand>) -> ScriptVarHandlerHandle
}, },
else => break, else => break,
}; };
}; Ok(())
}
.await;
}) })
}) })
.expect("Failed to start script-var-handler thread"); .expect("Failed to start script-var-handler thread");
@ -158,9 +160,10 @@ impl PollVarHandler {
self.poll_handles.insert(var.name.clone(), cancellation_token.clone()); self.poll_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 {
let result: Result<_> = try { let result: Result<_> = (|| {
evt_send.send(app::DaemonCommand::UpdateVars(vec![(var.name.clone(), run_poll_once(&var)?)]))?; evt_send.send(app::DaemonCommand::UpdateVars(vec![(var.name.clone(), run_poll_once(&var)?)]))?;
}; Ok(())
})();
if let Err(err) = result { if let Err(err) = result {
crate::error_handling_ctx::print_error(err); crate::error_handling_ctx::print_error(err);
} }
@ -168,9 +171,10 @@ impl PollVarHandler {
crate::loop_select_exiting! { crate::loop_select_exiting! {
_ = cancellation_token.cancelled() => break, _ = cancellation_token.cancelled() => break,
_ = tokio::time::sleep(var.interval) => { _ = tokio::time::sleep(var.interval) => {
let result: Result<_> = try { let result: Result<_> = (|| {
evt_send.send(app::DaemonCommand::UpdateVars(vec![(var.name.clone(), run_poll_once(&var)?)]))?; evt_send.send(app::DaemonCommand::UpdateVars(vec![(var.name.clone(), run_poll_once(&var)?)]))?;
}; Ok(())
})();
if let Err(err) = result { if let Err(err) = result {
crate::error_handling_ctx::print_error(err); crate::error_handling_ctx::print_error(err);
@ -233,17 +237,18 @@ impl ListenVarHandler {
let evt_send = self.evt_send.clone(); let evt_send = self.evt_send.clone();
tokio::spawn(async move { tokio::spawn(async move {
crate::try_logging_errors!(format!("Executing listen var-command {}", &var.command) => { let result: Result<_> = async {
let mut handle = unsafe { let mut handle = unsafe {
tokio::process::Command::new("sh") tokio::process::Command::new("sh")
.args(["-c", &var.command]) .args(["-c", &var.command])
.stdout(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped())
.stdin(std::process::Stdio::null()) .stdin(std::process::Stdio::null())
.pre_exec(|| { .pre_exec(|| {
let _ = setpgid(Pid::from_raw(0), Pid::from_raw(0)); let _ = setpgid(Pid::from_raw(0), Pid::from_raw(0));
Ok(()) Ok(())
}).spawn()? })
.spawn()?
}; };
let mut stdout_lines = BufReader::new(handle.stdout.take().unwrap()).lines(); let mut stdout_lines = BufReader::new(handle.stdout.take().unwrap()).lines();
let mut stderr_lines = BufReader::new(handle.stderr.take().unwrap()).lines(); let mut stderr_lines = BufReader::new(handle.stderr.take().unwrap()).lines();
@ -268,7 +273,19 @@ impl ListenVarHandler {
if let Some(completion_notify) = completion_notify { if let Some(completion_notify) = completion_notify {
completion_notify.completed().await; completion_notify.completed().await;
} }
}); Ok(())
}
.await;
if let Err(err) = result {
log::error!(
"[{}:{}] Error while executing listen-var command {}: {:?}",
::std::file!(),
::std::line!(),
&var.command,
err
);
}
}); });
} }

View file

@ -2,16 +2,6 @@ use extend::ext;
use itertools::Itertools; use itertools::Itertools;
use std::fmt::Write; use std::fmt::Write;
#[macro_export]
macro_rules! try_logging_errors {
($context:expr => $code:block) => {{
let result: Result<_> = try { $code };
if let Err(err) = result {
log::error!("[{}:{}] Error while {}: {:?}", ::std::file!(), ::std::line!(), $context, err);
}
}};
}
#[macro_export] #[macro_export]
macro_rules! print_result_err { macro_rules! print_result_err {
($context:expr, $result:expr $(,)?) => {{ ($context:expr, $result:expr $(,)?) => {{

View file

@ -116,6 +116,7 @@ fn calc_widget_lowest_preferred_dimension(widget: &gtk::Widget) -> (i32, i32) {
} }
impl BinImpl for CircProgPriv {} impl BinImpl for CircProgPriv {}
impl WidgetImpl for CircProgPriv { impl WidgetImpl for CircProgPriv {
// We overwrite preferred_* so that overflowing content from the children gets cropped // We overwrite preferred_* so that overflowing content from the children gets cropped
// We return min(child_width, child_height) // We return min(child_width, child_height)
@ -154,7 +155,7 @@ impl WidgetImpl for CircProgPriv {
} }
fn draw(&self, cr: &cairo::Context) -> Inhibit { fn draw(&self, cr: &cairo::Context) -> Inhibit {
let res: Result<()> = try { let res: Result<()> = (|| {
let value = *self.value.borrow(); let value = *self.value.borrow();
let start_at = *self.start_at.borrow(); let start_at = *self.start_at.borrow();
let thickness = *self.thickness.borrow(); let thickness = *self.thickness.borrow();
@ -218,7 +219,8 @@ impl WidgetImpl for CircProgPriv {
cr.reset_clip(); cr.reset_clip();
cr.restore()?; cr.restore()?;
} }
}; Ok(())
})();
if let Err(error) = res { if let Err(error) = res {
error_handling_ctx::print_error(error) error_handling_ctx::print_error(error)

View file

@ -19,14 +19,14 @@ macro_rules! def_widget {
// If an attribute is explicitly marked as optional (? appended to type) // If an attribute is explicitly marked as optional (? appended to type)
// the attribute will still show up here, as a `None` value. Otherwise, all values in this map // the attribute will still show up here, as a `None` value. Otherwise, all values in this map
// will be `Some`. // will be `Some`.
let attr_map: Result<HashMap<eww_shared_util::AttrName, Option<simplexpr::SimplExpr>>> = try { let attr_map: Result<HashMap<eww_shared_util::AttrName, Option<simplexpr::SimplExpr>>> = (|| {
::maplit::hashmap! { Ok(::maplit::hashmap! {
$( $(
eww_shared_util::AttrName(::std::stringify!($attr_name).to_owned()) => eww_shared_util::AttrName(::std::stringify!($attr_name).to_owned()) =>
def_widget!(@get_value $args, &::std::stringify!($attr_name).replace('_', "-"), $(? $($optional)?)? $(= $default)?) def_widget!(@get_value $args, &::std::stringify!($attr_name).replace('_', "-"), $(? $($optional)?)? $(= $default)?)
),* ),*
} })
}; })();
// Only proceed if any attributes from this `prop` where actually provided // Only proceed if any attributes from this `prop` where actually provided
if let Ok(attr_map) = attr_map { if let Ok(attr_map) = attr_map {

View file

@ -171,7 +171,7 @@ impl WidgetImpl for GraphPriv {
} }
fn draw(&self, cr: &cairo::Context) -> Inhibit { fn draw(&self, cr: &cairo::Context) -> Inhibit {
let res: Result<()> = try { let res: Result<()> = (|| {
let history = &*self.history.borrow(); let history = &*self.history.borrow();
let extra_point = *self.extra_point.borrow(); let extra_point = *self.extra_point.borrow();
@ -269,7 +269,8 @@ impl WidgetImpl for GraphPriv {
cr.reset_clip(); cr.reset_clip();
cr.restore()?; cr.restore()?;
}; Ok(())
})();
if let Err(error) = res { if let Err(error) = res {
error_handling_ctx::print_error(error) error_handling_ctx::print_error(error)

View file

@ -122,7 +122,7 @@ impl ContainerImpl for TransformPriv {
impl BinImpl for TransformPriv {} impl BinImpl for TransformPriv {}
impl WidgetImpl for TransformPriv { impl WidgetImpl for TransformPriv {
fn draw(&self, cr: &cairo::Context) -> Inhibit { fn draw(&self, cr: &cairo::Context) -> Inhibit {
let res: Result<()> = try { let res: Result<()> = (|| {
let rotate = *self.rotate.borrow(); let rotate = *self.rotate.borrow();
let total_width = self.obj().allocated_width() as f64; let total_width = self.obj().allocated_width() as f64;
let total_height = self.obj().allocated_height() as f64; let total_height = self.obj().allocated_height() as f64;
@ -159,7 +159,8 @@ impl WidgetImpl for TransformPriv {
} }
cr.restore()?; cr.restore()?;
}; Ok(())
})();
if let Err(error) = res { if let Err(error) = res {
error_handling_ctx::print_error(error) error_handling_ctx::print_error(error)

View file

@ -145,7 +145,7 @@ pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::Wi
let css_provider = gtk::CssProvider::new(); let css_provider = gtk::CssProvider::new();
let css_provider2 = css_provider.clone(); let css_provider2 = css_provider.clone();
let visible_result: Result<_> = try { let visible_result: Result<_> = (|| {
let visible_expr = bargs.widget_use.attrs.attrs.get("visible").map(|x| x.value.as_simplexpr()).transpose()?; let visible_expr = bargs.widget_use.attrs.attrs.get("visible").map(|x| x.value.as_simplexpr()).transpose()?;
if let Some(visible_expr) = visible_expr { if let Some(visible_expr) = visible_expr {
let visible = bargs.scope_graph.evaluate_simplexpr_in_scope(bargs.calling_scope, &visible_expr)?.as_bool()?; let visible = bargs.scope_graph.evaluate_simplexpr_in_scope(bargs.calling_scope, &visible_expr)?.as_bool()?;
@ -157,7 +157,8 @@ pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::Wi
} }
}); });
} }
}; Ok(())
})();
if let Err(err) = visible_result { if let Err(err) = visible_result {
error_handling_ctx::print_error(err); error_handling_ctx::print_error(err);
} }
@ -898,7 +899,7 @@ fn build_gtk_literal(bargs: &mut BuilderArgs) -> Result<gtk::Box> {
prop(content: as_string) { prop(content: as_string) {
gtk_widget.children().iter().for_each(|w| gtk_widget.remove(w)); gtk_widget.children().iter().for_each(|w| gtk_widget.remove(w));
if !content.is_empty() { if !content.is_empty() {
let content_widget_use: DiagResult<_> = try { let content_widget_use: DiagResult<_> = (||{
let ast = { let ast = {
let mut yuck_files = error_handling_ctx::FILE_DATABASE.write().unwrap(); let mut yuck_files = error_handling_ctx::FILE_DATABASE.write().unwrap();
let (span, asts) = yuck_files.load_yuck_str("<literal-content>".to_string(), content)?; let (span, asts) = yuck_files.load_yuck_str("<literal-content>".to_string(), content)?;
@ -908,8 +909,8 @@ fn build_gtk_literal(bargs: &mut BuilderArgs) -> Result<gtk::Box> {
yuck::parser::require_single_toplevel(span, asts)? yuck::parser::require_single_toplevel(span, asts)?
}; };
yuck::config::widget_use::WidgetUse::from_ast(ast)? yuck::config::widget_use::WidgetUse::from_ast(ast)
}; })();
let content_widget_use = content_widget_use?; let content_widget_use = content_widget_use?;
// TODO a literal should create a new scope, that I'm not even sure should inherit from root // TODO a literal should create a new scope, that I'm not even sure should inherit from root

View file

@ -1,6 +1,3 @@
#![feature(try_blocks)]
#![feature(unwrap_infallible)]
pub mod ast; pub mod ast;
pub mod dynval; pub mod dynval;
pub mod error; pub mod error;

View file

@ -61,7 +61,7 @@ impl FromAstElementContent for PollScriptVar {
const ELEMENT_NAME: &'static str = "defpoll"; const ELEMENT_NAME: &'static str = "defpoll";
fn from_tail<I: Iterator<Item = Ast>>(_span: Span, mut iter: AstIterator<I>) -> DiagResult<Self> { fn from_tail<I: Iterator<Item = Ast>>(_span: Span, mut iter: AstIterator<I>) -> DiagResult<Self> {
let result: DiagResult<_> = try { let result: DiagResult<_> = (move || {
let (name_span, name) = iter.expect_symbol()?; let (name_span, name) = iter.expect_symbol()?;
let mut attrs = iter.expect_key_values()?; let mut attrs = iter.expect_key_values()?;
let initial_value = Some(attrs.primitive_optional("initial")?.unwrap_or_else(|| DynVal::from_string(String::new()))); let initial_value = Some(attrs.primitive_optional("initial")?.unwrap_or_else(|| DynVal::from_string(String::new())));
@ -73,15 +73,15 @@ impl FromAstElementContent for PollScriptVar {
attrs.ast_optional::<SimplExpr>("run-while")?.unwrap_or_else(|| SimplExpr::Literal(DynVal::from(true))); attrs.ast_optional::<SimplExpr>("run-while")?.unwrap_or_else(|| SimplExpr::Literal(DynVal::from(true)));
iter.expect_done()?; iter.expect_done()?;
Self { Ok(Self {
name_span, name_span,
name: VarName(name), name: VarName(name),
run_while_expr, run_while_expr,
command: VarSource::Shell(script_span, script.to_string()), command: VarSource::Shell(script_span, script.to_string()),
initial_value, initial_value,
interval, interval,
} })
}; })();
result.note(r#"Expected format: `(defpoll name :interval "10s" "echo 'a shell script'")`"#) result.note(r#"Expected format: `(defpoll name :interval "10s" "echo 'a shell script'")`"#)
} }
} }
@ -98,14 +98,14 @@ impl FromAstElementContent for ListenScriptVar {
const ELEMENT_NAME: &'static str = "deflisten"; const ELEMENT_NAME: &'static str = "deflisten";
fn from_tail<I: Iterator<Item = Ast>>(_span: Span, mut iter: AstIterator<I>) -> DiagResult<Self> { fn from_tail<I: Iterator<Item = Ast>>(_span: Span, mut iter: AstIterator<I>) -> DiagResult<Self> {
let result: DiagResult<_> = try { let result: DiagResult<_> = (move || {
let (name_span, name) = iter.expect_symbol()?; let (name_span, name) = iter.expect_symbol()?;
let mut attrs = iter.expect_key_values()?; let mut attrs = iter.expect_key_values()?;
let initial_value = attrs.primitive_optional("initial")?.unwrap_or_else(|| DynVal::from_string(String::new())); let initial_value = attrs.primitive_optional("initial")?.unwrap_or_else(|| DynVal::from_string(String::new()));
let (command_span, script) = iter.expect_literal()?; let (command_span, script) = iter.expect_literal()?;
iter.expect_done()?; iter.expect_done()?;
Self { name_span, name: VarName(name), command: script.to_string(), initial_value, command_span } Ok(Self { name_span, name: VarName(name), command: script.to_string(), initial_value, command_span })
}; })();
result.note(r#"Expected format: `(deflisten name :initial "0" "tail -f /tmp/example")`"#) result.note(r#"Expected format: `(deflisten name :initial "0" "tail -f /tmp/example")`"#)
} }
} }

View file

@ -17,12 +17,12 @@ impl FromAstElementContent for VarDefinition {
const ELEMENT_NAME: &'static str = "defvar"; const ELEMENT_NAME: &'static str = "defvar";
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> DiagResult<Self> { fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> DiagResult<Self> {
let result: DiagResult<_> = try { let result = (move || {
let (_, name) = iter.expect_symbol()?; let (_, name) = iter.expect_symbol()?;
let (_, initial_value) = iter.expect_literal()?; let (_, initial_value) = iter.expect_literal()?;
iter.expect_done()?; iter.expect_done()?;
Self { name: VarName(name), initial_value, span } Ok(Self { name: VarName(name), initial_value, span })
}; })();
result.note(r#"Expected format: `(defvar name "initial-value")`"#) result.note(r#"Expected format: `(defvar name "initial-value")`"#)
} }
} }

View file

@ -99,9 +99,9 @@ impl std::str::FromStr for AnchorPoint {
Ok(AnchorPoint { x: AnchorAlignment::CENTER, y: AnchorAlignment::CENTER }) Ok(AnchorPoint { x: AnchorAlignment::CENTER, y: AnchorAlignment::CENTER })
} else { } else {
let (first, second) = s.split_once(' ').ok_or_else(|| AnchorPointParseError::WrongFormat(s.to_string()))?; let (first, second) = s.split_once(' ').ok_or_else(|| AnchorPointParseError::WrongFormat(s.to_string()))?;
let x_y_result: Result<_, EnumParseError> = try { let x_y_result: Result<_, EnumParseError> = (move || {
AnchorPoint { x: AnchorAlignment::from_x_alignment(first)?, y: AnchorAlignment::from_y_alignment(second)? } Ok(AnchorPoint { x: AnchorAlignment::from_x_alignment(first)?, y: AnchorAlignment::from_y_alignment(second)? })
}; })();
x_y_result.or_else(|_| { x_y_result.or_else(|_| {
Ok(AnchorPoint { x: AnchorAlignment::from_x_alignment(second)?, y: AnchorAlignment::from_y_alignment(first)? }) Ok(AnchorPoint { x: AnchorAlignment::from_x_alignment(second)?, y: AnchorAlignment::from_y_alignment(first)? })
}) })

View file

@ -1,5 +1,4 @@
#![allow(clippy::comparison_chain)] #![allow(clippy::comparison_chain)]
#![feature(try_blocks)]
pub mod ast_error; pub mod ast_error;
pub mod config; pub mod config;