change formatting config

This commit is contained in:
elkowar 2021-03-08 22:28:29 +01:00
parent 5cf18bfc43
commit f544d0e19a
26 changed files with 156 additions and 439 deletions

View file

@ -11,3 +11,4 @@ condense_wildcard_suffixes = true
format_code_in_doc_comments = true format_code_in_doc_comments = true
format_macro_matchers = true format_macro_matchers = true
format_strings = true format_strings = true
use_small_heuristics = "Max"

View file

@ -149,20 +149,10 @@ impl App {
} }
} }
DaemonCommand::OpenMany { windows, sender } => { DaemonCommand::OpenMany { windows, sender } => {
let result = windows let result = windows.iter().map(|w| self.open_window(w, None, None, None, None)).collect::<Result<()>>();
.iter()
.map(|w| self.open_window(w, None, None, None, None))
.collect::<Result<()>>();
respond_with_error(sender, result)?; respond_with_error(sender, result)?;
} }
DaemonCommand::OpenWindow { DaemonCommand::OpenWindow { window_name, pos, size, anchor, monitor, sender } => {
window_name,
pos,
size,
anchor,
monitor,
sender,
} => {
let result = self.open_window(&window_name, pos, size, monitor, anchor); let result = self.open_window(&window_name, pos, size, monitor, anchor);
respond_with_error(sender, result)?; respond_with_error(sender, result)?;
} }
@ -171,15 +161,9 @@ impl App {
respond_with_error(sender, result)?; respond_with_error(sender, result)?;
} }
DaemonCommand::PrintState(sender) => { DaemonCommand::PrintState(sender) => {
let output = self let output =
.eww_state self.eww_state.get_variables().iter().map(|(key, value)| format!("{}: {}", key, value)).join("\n");
.get_variables() sender.send(DaemonResponse::Success(output)).context("sending response from main thread")?
.iter()
.map(|(key, value)| format!("{}: {}", key, value))
.join("\n");
sender
.send(DaemonResponse::Success(output))
.context("sending response from main thread")?
} }
DaemonCommand::PrintWindows(sender) => { DaemonCommand::PrintWindows(sender) => {
let output = self let output = self
@ -191,15 +175,11 @@ impl App {
format!("{}{}", if is_open { "*" } else { "" }, window_name) format!("{}{}", if is_open { "*" } else { "" }, window_name)
}) })
.join("\n"); .join("\n");
sender sender.send(DaemonResponse::Success(output)).context("sending response from main thread")?
.send(DaemonResponse::Success(output))
.context("sending response from main thread")?
} }
DaemonCommand::PrintDebug(sender) => { DaemonCommand::PrintDebug(sender) => {
let output = format!("state: {:#?}\n\nconfig: {:#?}", &self.eww_state, &self.eww_config); let output = format!("state: {:#?}\n\nconfig: {:#?}", &self.eww_state, &self.eww_config);
sender sender.send(DaemonResponse::Success(output)).context("sending response from main thread")?
.send(DaemonResponse::Success(output))
.context("sending response from main thread")?
} }
} }
}; };
@ -223,10 +203,8 @@ impl App {
self.script_var_handler.stop_for_variable(unused_var.clone()); self.script_var_handler.stop_for_variable(unused_var.clone());
} }
let window = self let window =
.open_windows self.open_windows.remove(window_name).context(format!("No window with name '{}' is running.", window_name))?;
.remove(window_name)
.context(format!("No window with name '{}' is running.", window_name))?;
window.close(); window.close();
self.eww_state.clear_window_state(window_name); self.eww_state.clear_window_state(window_name);
@ -251,9 +229,7 @@ impl App {
window_def.geometry = window_def.geometry.override_if_given(anchor, pos, size); window_def.geometry = window_def.geometry.override_if_given(anchor, pos, size);
let root_widget = let root_widget =
window_def window_def.widget.render(&mut self.eww_state, window_name, &self.eww_config.get_widget_definitions())?;
.widget
.render(&mut self.eww_state, window_name, &self.eww_config.get_widget_definitions())?;
root_widget.get_style_context().add_class(&window_name.to_string()); root_widget.get_style_context().add_class(&window_name.to_string());
let monitor_geometry = let monitor_geometry =
@ -264,9 +240,8 @@ impl App {
// initialize script var handlers for variables that where not used before opening this window. // initialize script var handlers for variables that where not used before opening this window.
// TODO somehow make this less shit // TODO somehow make this less shit
for newly_used_var in self for newly_used_var in
.variables_only_used_in(&window_name) self.variables_only_used_in(&window_name).filter_map(|var| self.eww_config.get_script_var(&var).ok())
.filter_map(|var| self.eww_config.get_script_var(&var).ok())
{ {
self.script_var_handler.add(newly_used_var.clone()); self.script_var_handler.add(newly_used_var.clone());
} }
@ -298,9 +273,7 @@ impl App {
/// Get all variable names that are currently referenced in any of the open windows. /// Get all variable names that are currently referenced in any of the open windows.
pub fn get_currently_used_variables(&self) -> impl Iterator<Item = &VarName> { pub fn get_currently_used_variables(&self) -> impl Iterator<Item = &VarName> {
self.open_windows self.open_windows.keys().flat_map(move |window_name| self.eww_state.vars_referenced_in(window_name))
.keys()
.flat_map(move |window_name| self.eww_state.vars_referenced_in(window_name))
} }
/// Get all variables mapped to a list of windows they are being used in. /// Get all variables mapped to a list of windows they are being used in.
@ -308,9 +281,7 @@ impl App {
let mut vars: HashMap<&'a VarName, Vec<_>> = HashMap::new(); let mut vars: HashMap<&'a VarName, Vec<_>> = HashMap::new();
for window_name in self.open_windows.keys() { for window_name in self.open_windows.keys() {
for var in self.eww_state.vars_referenced_in(window_name) { for var in self.eww_state.vars_referenced_in(window_name) {
vars.entry(var) vars.entry(var).and_modify(|l| l.push(window_name)).or_insert_with(|| vec![window_name]);
.and_modify(|l| l.push(window_name))
.or_insert_with(|| vec![window_name]);
} }
} }
vars vars
@ -332,11 +303,8 @@ fn initialize_window(
) -> Result<EwwWindow> { ) -> Result<EwwWindow> {
let actual_window_rect = window_def.geometry.get_window_rectangle(monitor_geometry); let actual_window_rect = window_def.geometry.get_window_rectangle(monitor_geometry);
let window = if window_def.focusable { let window =
gtk::Window::new(gtk::WindowType::Toplevel) if window_def.focusable { gtk::Window::new(gtk::WindowType::Toplevel) } else { gtk::Window::new(gtk::WindowType::Popup) };
} else {
gtk::Window::new(gtk::WindowType::Popup)
};
window.set_title(&format!("Eww - {}", window_def.name)); window.set_title(&format!("Eww - {}", window_def.name));
let wm_class_name = format!("eww-{}", window_def.name); let wm_class_name = format!("eww-{}", window_def.name);
@ -360,10 +328,7 @@ fn initialize_window(
// as it is sized according to how much space it's contents require. // as it is sized according to how much space it's contents require.
// This is necessary to handle different anchors correctly in case the size was wrong. // This is necessary to handle different anchors correctly in case the size was wrong.
let (gtk_window_width, gtk_window_height) = window.get_size(); let (gtk_window_width, gtk_window_height) = window.get_size();
window_def.geometry.size = Coords { window_def.geometry.size = Coords { x: NumWithUnit::Pixels(gtk_window_width), y: NumWithUnit::Pixels(gtk_window_height) };
x: NumWithUnit::Pixels(gtk_window_width),
y: NumWithUnit::Pixels(gtk_window_height),
};
let actual_window_rect = window_def.geometry.get_window_rectangle(monitor_geometry); let actual_window_rect = window_def.geometry.get_window_rectangle(monitor_geometry);
window.show_all(); window.show_all();
@ -382,37 +347,24 @@ fn initialize_window(
display_backend::reserve_space_for(&window, monitor_geometry, window_def.struts)?; display_backend::reserve_space_for(&window, monitor_geometry, window_def.struts)?;
Ok(EwwWindow { Ok(EwwWindow { name: window_def.name.clone(), definition: window_def, gtk_window: window })
name: window_def.name.clone(),
definition: window_def,
gtk_window: window,
})
} }
fn on_screen_changed(window: &gtk::Window, _old_screen: Option<&gdk::Screen>) { fn on_screen_changed(window: &gtk::Window, _old_screen: Option<&gdk::Screen>) {
let visual = window.get_screen().and_then(|screen| { let visual = window
screen .get_screen()
.get_rgba_visual() .and_then(|screen| screen.get_rgba_visual().filter(|_| screen.is_composited()).or_else(|| screen.get_system_visual()));
.filter(|_| screen.is_composited())
.or_else(|| screen.get_system_visual())
});
window.set_visual(visual.as_ref()); window.set_visual(visual.as_ref());
} }
/// get the index of the default monitor /// get the index of the default monitor
fn get_default_monitor_index() -> i32 { fn get_default_monitor_index() -> i32 {
gdk::Display::get_default() gdk::Display::get_default().expect("could not get default display").get_default_screen().get_primary_monitor()
.expect("could not get default display")
.get_default_screen()
.get_primary_monitor()
} }
/// Get the monitor geometry of a given monitor number /// Get the monitor geometry of a given monitor number
fn get_monitor_geometry(n: i32) -> gdk::Rectangle { fn get_monitor_geometry(n: i32) -> gdk::Rectangle {
gdk::Display::get_default() gdk::Display::get_default().expect("could not get default display").get_default_screen().get_monitor_geometry(n)
.expect("could not get default display")
.get_default_screen()
.get_monitor_geometry(n)
} }
/// In case of an Err, send the error message to a sender. /// In case of an Err, send the error message to a sender.

View file

@ -11,20 +11,14 @@ lazy_static::lazy_static! {
/// Notify all listening tasks of the termination of the eww application process. /// Notify all listening tasks of the termination of the eww application process.
pub fn send_exit() -> Result<()> { pub fn send_exit() -> Result<()> {
(&*APPLICATION_EXIT_SENDER) (&*APPLICATION_EXIT_SENDER).send(()).context("Failed to send exit lifecycle event")?;
.send(())
.context("Failed to send exit lifecycle event")?;
Ok(()) Ok(())
} }
/// Yields Ok(()) on application termination. Await on this in all long-running tasks /// Yields Ok(()) on application termination. Await on this in all long-running tasks
/// and perform any cleanup if necessary. /// and perform any cleanup if necessary.
pub async fn recv_exit() -> Result<()> { pub async fn recv_exit() -> Result<()> {
(&*APPLICATION_EXIT_SENDER) (&*APPLICATION_EXIT_SENDER).subscribe().recv().await.context("Failed to receive lifecycle event")
.subscribe()
.recv()
.await
.context("Failed to receive lifecycle event")
} }
/// Select in a loop, breaking once a application termination event (see `crate::application_lifecycle`) is received. /// Select in a loop, breaking once a application termination event (see `crate::application_lifecycle`) is received.

View file

@ -26,24 +26,16 @@ pub fn handle_client_only_action(paths: &EwwPaths, action: ActionClientOnly) ->
pub fn do_server_call(mut stream: UnixStream, action: opts::ActionWithServer) -> Result<Option<app::DaemonResponse>> { pub fn do_server_call(mut stream: UnixStream, action: opts::ActionWithServer) -> Result<Option<app::DaemonResponse>> {
log::info!("Forwarding options to server"); log::info!("Forwarding options to server");
stream stream.set_nonblocking(false).context("Failed to set stream to non-blocking")?;
.set_nonblocking(false)
.context("Failed to set stream to non-blocking")?;
let message_bytes = bincode::serialize(&action)?; let message_bytes = bincode::serialize(&action)?;
stream stream.write(&(message_bytes.len() as u32).to_be_bytes()).context("Failed to send command size header to IPC stream")?;
.write(&(message_bytes.len() as u32).to_be_bytes())
.context("Failed to send command size header to IPC stream")?;
stream stream.write_all(&message_bytes).context("Failed to write command to IPC stream")?;
.write_all(&message_bytes)
.context("Failed to write command to IPC stream")?;
let mut buf = Vec::new(); let mut buf = Vec::new();
stream stream.set_read_timeout(Some(std::time::Duration::from_millis(100))).context("Failed to set read timeout")?;
.set_read_timeout(Some(std::time::Duration::from_millis(100)))
.context("Failed to set read timeout")?;
stream.read_to_end(&mut buf).context("Error reading response from server")?; stream.read_to_end(&mut buf).context("Error reading response from server")?;
Ok(if buf.is_empty() { Ok(if buf.is_empty() {

View file

@ -58,12 +58,7 @@ impl PartialEq for WidgetUse {
impl WidgetUse { impl WidgetUse {
pub fn new(name: String, children: Vec<WidgetUse>) -> Self { pub fn new(name: String, children: Vec<WidgetUse>) -> Self {
WidgetUse { WidgetUse { name, children, attrs: HashMap::new(), ..WidgetUse::default() }
name,
children,
attrs: HashMap::new(),
..WidgetUse::default()
}
} }
pub fn from_xml_node(xml: XmlNode) -> Result<Self> { pub fn from_xml_node(xml: XmlNode) -> Result<Self> {
@ -171,9 +166,6 @@ mod test {
}, },
}; };
assert_eq!( assert_eq!(expected, WidgetDefinition::from_xml_element(xml.as_element().unwrap()).unwrap());
expected,
WidgetDefinition::from_xml_element(xml.as_element().unwrap()).unwrap()
);
} }
} }

View file

@ -28,21 +28,12 @@ impl EwwConfig {
} }
pub fn generate(conf: RawEwwConfig) -> Result<Self> { pub fn generate(conf: RawEwwConfig) -> Result<Self> {
let RawEwwConfig { let RawEwwConfig { windows, initial_variables, script_vars, filepath, widgets } = conf;
windows,
initial_variables,
script_vars,
filepath,
widgets,
} = conf;
Ok(EwwConfig { Ok(EwwConfig {
windows: windows windows: windows
.into_iter() .into_iter()
.map(|(name, window)| { .map(|(name, window)| {
Ok(( Ok((name, EwwWindowDefinition::generate(&widgets, window).context("Failed expand window definition")?))
name,
EwwWindowDefinition::generate(&widgets, window).context("Failed expand window definition")?,
))
}) })
.collect::<Result<HashMap<_, _>>>()?, .collect::<Result<HashMap<_, _>>>()?,
widgets, widgets,
@ -54,11 +45,8 @@ impl EwwConfig {
// TODO this is kinda ugly // TODO this is kinda ugly
pub fn generate_initial_state(&self) -> Result<HashMap<VarName, PrimitiveValue>> { pub fn generate_initial_state(&self) -> Result<HashMap<VarName, PrimitiveValue>> {
let mut vars = self let mut vars =
.script_vars self.script_vars.iter().map(|var| Ok((var.0.clone(), var.1.initial_value()?))).collect::<Result<HashMap<_, _>>>()?;
.iter()
.map(|var| Ok((var.0.clone(), var.1.initial_value()?)))
.collect::<Result<HashMap<_, _>>>()?;
vars.extend(self.initial_variables.clone()); vars.extend(self.initial_variables.clone());
Ok(vars) Ok(vars)
} }
@ -68,15 +56,11 @@ impl EwwConfig {
} }
pub fn get_window(&self, name: &WindowName) -> Result<&EwwWindowDefinition> { pub fn get_window(&self, name: &WindowName) -> Result<&EwwWindowDefinition> {
self.windows self.windows.get(name).with_context(|| format!("No window named '{}' exists", name))
.get(name)
.with_context(|| format!("No window named '{}' exists", name))
} }
pub fn get_script_var(&self, name: &VarName) -> Result<&ScriptVar> { pub fn get_script_var(&self, name: &VarName) -> Result<&ScriptVar> {
self.script_vars self.script_vars.get(name).with_context(|| format!("No script var named '{}' exists", name))
.get(name)
.with_context(|| format!("No script var named '{}' exists", name))
} }
pub fn get_widget_definitions(&self) -> &HashMap<String, WidgetDefinition> { pub fn get_widget_definitions(&self) -> &HashMap<String, WidgetDefinition> {
@ -192,13 +176,7 @@ impl RawEwwConfig {
None => Default::default(), None => Default::default(),
}; };
let config = RawEwwConfig { let config = RawEwwConfig { widgets: definitions, windows, initial_variables, script_vars, filepath: path.to_path_buf() };
widgets: definitions,
windows,
initial_variables,
script_vars,
filepath: path.to_path_buf(),
};
Ok((config, included_paths)) Ok((config, included_paths))
} }
} }
@ -209,10 +187,7 @@ fn parse_variables_block(xml: XmlElement) -> Result<(HashMap<VarName, PrimitiveV
for node in xml.child_elements() { for node in xml.child_elements() {
match node.tag_name() { match node.tag_name() {
"var" => { "var" => {
let value = node let value = node.only_child().map(|c| c.as_text_or_sourcecode()).unwrap_or_else(|_| String::new());
.only_child()
.map(|c| c.as_text_or_sourcecode())
.unwrap_or_else(|_| String::new());
normal_vars.insert(VarName(node.attr("name")?.to_owned()), PrimitiveValue::from_string(value)); normal_vars.insert(VarName(node.attr("name")?.to_owned()), PrimitiveValue::from_string(value));
} }
"script-var" => { "script-var" => {
@ -282,12 +257,10 @@ mod test {
let document1 = roxmltree::Document::parse(&input1).unwrap(); let document1 = roxmltree::Document::parse(&input1).unwrap();
let document2 = roxmltree::Document::parse(input2).unwrap(); let document2 = roxmltree::Document::parse(input2).unwrap();
let config1 = RawEwwConfig::from_xml_element(XmlNode::from(document1.root_element()).as_element().unwrap().clone(), "") let config1 =
.unwrap() RawEwwConfig::from_xml_element(XmlNode::from(document1.root_element()).as_element().unwrap().clone(), "").unwrap().0;
.0; let config2 =
let config2 = RawEwwConfig::from_xml_element(XmlNode::from(document2.root_element()).as_element().unwrap().clone(), "") RawEwwConfig::from_xml_element(XmlNode::from(document2.root_element()).as_element().unwrap().clone(), "").unwrap().0;
.unwrap()
.0;
let base_config = RawEwwConfig { let base_config = RawEwwConfig {
widgets: HashMap::new(), widgets: HashMap::new(),
windows: HashMap::new(), windows: HashMap::new(),

View file

@ -24,12 +24,7 @@ macro_rules! ensure_xml_tag_is {
($element:ident, $name:literal) => { ($element:ident, $name:literal) => {
ensure!( ensure!(
$element.tag_name() == $name, $element.tag_name() == $name,
anyhow!( anyhow!("{} | Tag needed to be of type '{}', but was: {}", $element.text_pos(), $name, $element.as_tag_string())
"{} | Tag needed to be of type '{}', but was: {}",
$element.text_pos(),
$name,
$element.as_tag_string()
)
) )
}; };
} }

View file

@ -55,12 +55,8 @@ impl RawEwwWindowDefinition {
let focusable = xml.parse_optional_attr("focusable")?; let focusable = xml.parse_optional_attr("focusable")?;
let screen_number = xml.parse_optional_attr("screen")?; let screen_number = xml.parse_optional_attr("screen")?;
let struts: Option<StrutDefinition> = xml let struts: Option<StrutDefinition> =
.child("reserve") xml.child("reserve").ok().map(StrutDefinition::from_xml_element).transpose().context("Failed to parse <reserve>")?;
.ok()
.map(StrutDefinition::from_xml_element)
.transpose()
.context("Failed to parse <reserve>")?;
Ok(RawEwwWindowDefinition { Ok(RawEwwWindowDefinition {
name: WindowName(xml.attr("name")?.to_owned()), name: WindowName(xml.attr("name")?.to_owned()),
@ -94,10 +90,7 @@ impl std::str::FromStr for Side {
"r" | "right" => Ok(Side::Right), "r" | "right" => Ok(Side::Right),
"t" | "top" => Ok(Side::Top), "t" | "top" => Ok(Side::Top),
"b" | "bottom" => Ok(Side::Bottom), "b" | "bottom" => Ok(Side::Bottom),
_ => Err(anyhow!( _ => Err(anyhow!("Failed to parse {} as valid side. Must be one of \"left\", \"right\", \"top\", \"bottom\"", s)),
"Failed to parse {} as valid side. Must be one of \"left\", \"right\", \"top\", \"bottom\"",
s
)),
} }
} }
} }
@ -110,10 +103,7 @@ pub struct StrutDefinition {
impl StrutDefinition { impl StrutDefinition {
pub fn from_xml_element(xml: XmlElement) -> Result<Self> { pub fn from_xml_element(xml: XmlElement) -> Result<Self> {
Ok(StrutDefinition { Ok(StrutDefinition { side: xml.attr("side")?.parse()?, dist: xml.attr("distance")?.parse()? })
side: xml.attr("side")?.parse()?,
dist: xml.attr("distance")?.parse()?,
})
} }
} }
@ -132,10 +122,7 @@ impl std::str::FromStr for WindowStacking {
match s.as_str() { match s.as_str() {
"foreground" | "fg" | "f" => Ok(WindowStacking::Foreground), "foreground" | "fg" | "f" => Ok(WindowStacking::Foreground),
"background" | "bg" | "b" => Ok(WindowStacking::Background), "background" | "bg" | "b" => Ok(WindowStacking::Background),
_ => Err(anyhow!( _ => Err(anyhow!("Couldn't parse '{}' as window stacking, must be either foreground, fg, background or bg", s)),
"Couldn't parse '{}' as window stacking, must be either foreground, fg, background or bg",
s
)),
} }
} }
} }

View file

@ -24,10 +24,7 @@ impl AnchorAlignment {
"l" | "left" => Ok(AnchorAlignment::START), "l" | "left" => Ok(AnchorAlignment::START),
"c" | "center" => Ok(AnchorAlignment::CENTER), "c" | "center" => Ok(AnchorAlignment::CENTER),
"r" | "right" => Ok(AnchorAlignment::END), "r" | "right" => Ok(AnchorAlignment::END),
_ => bail!( _ => bail!(r#"couldn't parse '{}' as x-alignment. Must be one of "left", "center", "right""#, s),
r#"couldn't parse '{}' as x-alignment. Must be one of "left", "center", "right""#,
s
),
} }
} }
@ -36,10 +33,7 @@ impl AnchorAlignment {
"t" | "top" => Ok(AnchorAlignment::START), "t" | "top" => Ok(AnchorAlignment::START),
"c" | "center" => Ok(AnchorAlignment::CENTER), "c" | "center" => Ok(AnchorAlignment::CENTER),
"b" | "bottom" => Ok(AnchorAlignment::END), "b" | "bottom" => Ok(AnchorAlignment::END),
_ => bail!( _ => bail!(r#"couldn't parse '{}' as y-alignment. Must be one of "top", "center", "bottom""#, s),
r#"couldn't parse '{}' as y-alignment. Must be one of "top", "center", "bottom""#,
s
),
} }
} }
@ -86,25 +80,16 @@ impl std::str::FromStr for AnchorPoint {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "center" { if s == "center" {
Ok(AnchorPoint { Ok(AnchorPoint { x: AnchorAlignment::CENTER, y: AnchorAlignment::CENTER })
x: AnchorAlignment::CENTER,
y: AnchorAlignment::CENTER,
})
} else { } else {
let (first, second) = s let (first, second) = s
.split_once(' ') .split_once(' ')
.context("Failed to parse anchor: Must either be \"center\" or be formatted like \"top left\"")?; .context("Failed to parse anchor: Must either be \"center\" or be formatted like \"top left\"")?;
let x_y_result: Result<_> = try { let x_y_result: Result<_> = try {
AnchorPoint { AnchorPoint { x: AnchorAlignment::from_x_alignment(first)?, y: AnchorAlignment::from_y_alignment(second)? }
x: AnchorAlignment::from_x_alignment(first)?,
y: AnchorAlignment::from_y_alignment(second)?,
}
}; };
x_y_result.or_else(|_| { x_y_result.or_else(|_| {
Ok(AnchorPoint { Ok(AnchorPoint { x: AnchorAlignment::from_x_alignment(second)?, y: AnchorAlignment::from_y_alignment(first)? })
x: AnchorAlignment::from_x_alignment(second)?,
y: AnchorAlignment::from_y_alignment(first)?,
})
}) })
} }
} }

View file

@ -31,11 +31,8 @@ impl<'a, 'b> fmt::Display for XmlNode<'a, 'b> {
/// Get the part of a string that is selected by the start and end TextPos. /// Get the part of a string that is selected by the start and end TextPos.
/// Will panic if the range is out of bounds in any way. /// Will panic if the range is out of bounds in any way.
fn get_text_from_text_range(s: &str, (start_pos, end_pos): (roxmltree::TextPos, roxmltree::TextPos)) -> String { fn get_text_from_text_range(s: &str, (start_pos, end_pos): (roxmltree::TextPos, roxmltree::TextPos)) -> String {
let mut code_text = s let mut code_text =
.lines() s.lines().dropping(start_pos.row as usize - 1).take(end_pos.row as usize - (start_pos.row as usize - 1)).collect_vec();
.dropping(start_pos.row as usize - 1)
.take(end_pos.row as usize - (start_pos.row as usize - 1))
.collect_vec();
if let Some(first_line) = code_text.first_mut() { if let Some(first_line) = code_text.first_mut() {
*first_line = first_line.split_at(start_pos.col as usize - 1).1; *first_line = first_line.split_at(start_pos.col as usize - 1).1;
} }
@ -133,11 +130,7 @@ impl<'a, 'b> fmt::Display for XmlElement<'a, 'b> {
impl<'a, 'b> XmlElement<'a, 'b> { impl<'a, 'b> XmlElement<'a, 'b> {
pub fn as_tag_string(&self) -> String { pub fn as_tag_string(&self) -> String {
let attrs = self let attrs = self.attributes().iter().map(|attr| format!("{}=\"{}\"", attr.name(), attr.value())).join(" ");
.attributes()
.iter()
.map(|attr| format!("{}=\"{}\"", attr.name(), attr.value()))
.join(" ");
format!("<{} {}>", self.tag_name(), attrs) format!("<{} {}>", self.tag_name(), attrs)
} }
@ -255,10 +248,7 @@ mod test {
let input = "<something>whatever</something>"; let input = "<something>whatever</something>";
let document = roxmltree::Document::parse(&input).unwrap(); let document = roxmltree::Document::parse(&input).unwrap();
let root_node = XmlNode::from(document.root_element()); let root_node = XmlNode::from(document.root_element());
assert_eq!( assert_eq!(root_node.as_element().unwrap().only_child().unwrap().as_text_or_sourcecode(), "whatever".to_string());
root_node.as_element().unwrap().only_child().unwrap().as_text_or_sourcecode(),
"whatever".to_string()
);
} }
#[test] #[test]

View file

@ -41,11 +41,7 @@ mod platform {
let (conn, screen_num) = RustConnection::connect(None)?; let (conn, screen_num) = RustConnection::connect(None)?;
let screen = conn.setup().roots[screen_num].clone(); let screen = conn.setup().roots[screen_num].clone();
let atoms = AtomCollection::new(&conn)?.reply()?; let atoms = AtomCollection::new(&conn)?.reply()?;
Ok(X11Backend { Ok(X11Backend { conn, root_window: screen.root, atoms })
conn,
root_window: screen.root,
atoms,
})
} }
fn reserve_space_for( fn reserve_space_for(

View file

@ -51,10 +51,7 @@ impl EwwWindowState {
fn put_handler(&mut self, handler: StateChangeHandler) { fn put_handler(&mut self, handler: StateChangeHandler) {
let handler = Arc::new(handler); let handler = Arc::new(handler);
for var_name in handler.used_variables() { for var_name in handler.used_variables() {
self.state_change_handlers self.state_change_handlers.entry(var_name.clone()).or_insert_with(Vec::new).push(handler.clone());
.entry(var_name.clone())
.or_insert_with(Vec::new)
.push(handler.clone());
} }
} }
} }
@ -75,10 +72,7 @@ impl std::fmt::Debug for EwwState {
impl EwwState { impl EwwState {
pub fn from_default_vars(defaults: HashMap<VarName, PrimitiveValue>) -> Self { pub fn from_default_vars(defaults: HashMap<VarName, PrimitiveValue>) -> Self {
EwwState { EwwState { variables_state: defaults, ..EwwState::default() }
variables_state: defaults,
..EwwState::default()
}
} }
pub fn get_variables(&self) -> &HashMap<VarName, PrimitiveValue> { pub fn get_variables(&self) -> &HashMap<VarName, PrimitiveValue> {
@ -110,9 +104,7 @@ impl EwwState {
/// Look up a single variable in the eww state, returning an `Err` when the value is not found. /// Look up a single variable in the eww state, returning an `Err` when the value is not found.
pub fn lookup(&self, var_name: &VarName) -> Result<&PrimitiveValue> { pub fn lookup(&self, var_name: &VarName) -> Result<&PrimitiveValue> {
self.variables_state self.variables_state.get(var_name).with_context(|| format!("Unknown variable '{}' referenced", var_name))
.get(var_name)
.with_context(|| format!("Unknown variable '{}' referenced", var_name))
} }
/// resolves a value if possible, using the current eww_state. /// resolves a value if possible, using the current eww_state.
@ -134,19 +126,13 @@ impl EwwState {
required_attributes: HashMap<AttrName, AttrValue>, required_attributes: HashMap<AttrName, AttrValue>,
set_value: F, set_value: F,
) { ) {
let handler = StateChangeHandler { let handler = StateChangeHandler { func: Box::new(set_value), unresolved_values: required_attributes };
func: Box::new(set_value),
unresolved_values: required_attributes,
};
handler.run_with_state(&self.variables_state); handler.run_with_state(&self.variables_state);
// only store the handler if at least one variable is being used // only store the handler if at least one variable is being used
if handler.used_variables().next().is_some() { if handler.used_variables().next().is_some() {
self.windows self.windows.entry(window_name.clone()).or_insert_with(EwwWindowState::default).put_handler(handler);
.entry(window_name.clone())
.or_insert_with(EwwWindowState::default)
.put_handler(handler);
} }
} }
@ -155,9 +141,6 @@ impl EwwState {
} }
pub fn vars_referenced_in(&self, window_name: &WindowName) -> std::collections::HashSet<&VarName> { pub fn vars_referenced_in(&self, window_name: &WindowName) -> std::collections::HashSet<&VarName> {
self.windows self.windows.get(window_name).map(|window| window.state_change_handlers.keys().collect()).unwrap_or_default()
.get(window_name)
.map(|window| window.state_change_handlers.keys().collect())
.unwrap_or_default()
} }
} }

View file

@ -26,11 +26,6 @@ impl Rectangular for Rect {
impl Rectangular for gdk::Rectangle { impl Rectangular for gdk::Rectangle {
fn get_rect(&self) -> Rect { fn get_rect(&self) -> Rect {
Rect { Rect { x: self.x, y: self.y, width: self.width, height: self.height }
x: self.x,
y: self.y,
width: self.width,
height: self.height,
}
} }
} }

View file

@ -53,17 +53,11 @@ async fn handle_connection(mut stream: tokio::net::UnixStream, evt_send: Unbound
/// The format here requires the first 4 bytes to be the size of the rest of the message (in big-endian), followed by the rest of the message. /// The format here requires the first 4 bytes to be the size of the rest of the message (in big-endian), followed by the rest of the message.
async fn read_action_from_stream(stream_read: &'_ mut tokio::net::unix::ReadHalf<'_>) -> Result<opts::ActionWithServer> { async fn read_action_from_stream(stream_read: &'_ mut tokio::net::unix::ReadHalf<'_>) -> Result<opts::ActionWithServer> {
let mut message_byte_length = [0u8; 4]; let mut message_byte_length = [0u8; 4];
stream_read stream_read.read_exact(&mut message_byte_length).await.context("Failed to read message size header in IPC message")?;
.read_exact(&mut message_byte_length)
.await
.context("Failed to read message size header in IPC message")?;
let message_byte_length = u32::from_be_bytes(message_byte_length); let message_byte_length = u32::from_be_bytes(message_byte_length);
let mut raw_message = Vec::<u8>::with_capacity(message_byte_length as usize); let mut raw_message = Vec::<u8>::with_capacity(message_byte_length as usize);
while raw_message.len() < message_byte_length as usize { while raw_message.len() < message_byte_length as usize {
stream_read stream_read.read_buf(&mut raw_message).await.context("Failed to read actual IPC message")?;
.read_buf(&mut raw_message)
.await
.context("Failed to read actual IPC message")?;
} }
bincode::deserialize(&raw_message).context("Failed to parse client message") bincode::deserialize(&raw_message).context("Failed to parse client message")

View file

@ -35,32 +35,20 @@ pub mod widgets;
fn main() { fn main() {
let opts: opts::Opt = opts::Opt::from_env(); let opts: opts::Opt = opts::Opt::from_env();
let log_level_filter = if opts.log_debug { let log_level_filter = if opts.log_debug { log::LevelFilter::Debug } else { log::LevelFilter::Off };
log::LevelFilter::Debug
} else {
log::LevelFilter::Off
};
pretty_env_logger::formatted_builder() pretty_env_logger::formatted_builder().filter(Some("eww"), log_level_filter).init();
.filter(Some("eww"), log_level_filter)
.init();
let result: Result<_> = try { let result: Result<_> = try {
let paths = opts let paths =
.config_path opts.config_path.map(EwwPaths::from_config_dir).unwrap_or_else(EwwPaths::default).context("Failed set paths")?;
.map(EwwPaths::from_config_dir)
.unwrap_or_else(EwwPaths::default)
.context("Failed set paths")?;
match opts.action { match opts.action {
opts::Action::ClientOnly(action) => { opts::Action::ClientOnly(action) => {
client::handle_client_only_action(&paths, action)?; client::handle_client_only_action(&paths, action)?;
} }
opts::Action::WithServer(action) => { opts::Action::WithServer(action) => {
log::info!( log::info!("Trying to find server process at socket {}", paths.get_ipc_socket_file().display());
"Trying to find server process at socket {}",
paths.get_ipc_socket_file().display()
);
match net::UnixStream::connect(&paths.get_ipc_socket_file()) { match net::UnixStream::connect(&paths.get_ipc_socket_file()) {
Ok(stream) => { Ok(stream) => {
log::info!("Connected to Eww server ({}).", &paths.get_ipc_socket_file().display()); log::info!("Connected to Eww server ({}).", &paths.get_ipc_socket_file().display());
@ -122,9 +110,7 @@ impl EwwPaths {
pub fn from_config_dir<P: AsRef<Path>>(config_dir: P) -> Result<Self> { pub fn from_config_dir<P: AsRef<Path>>(config_dir: P) -> Result<Self> {
let config_dir = config_dir.as_ref(); let config_dir = config_dir.as_ref();
let config_dir = if config_dir.is_file() { let config_dir = if config_dir.is_file() {
config_dir config_dir.parent().context("Given config file did not have a parent directory")?
.parent()
.context("Given config file did not have a parent directory")?
} else { } else {
config_dir config_dir
}; };

View file

@ -133,16 +133,8 @@ impl Opt {
impl From<RawOpt> for Opt { impl From<RawOpt> for Opt {
fn from(other: RawOpt) -> Self { fn from(other: RawOpt) -> Self {
let RawOpt { let RawOpt { action, log_debug, config } = other;
action, Opt { action, log_debug, config_path: config }
log_debug,
config,
} = other;
Opt {
action,
log_debug,
config_path: config,
}
} }
} }
@ -168,13 +160,7 @@ impl ActionWithServer {
ActionWithServer::OpenMany { windows } => { ActionWithServer::OpenMany { windows } => {
return with_response_channel(|sender| app::DaemonCommand::OpenMany { windows, sender }); return with_response_channel(|sender| app::DaemonCommand::OpenMany { windows, sender });
} }
ActionWithServer::OpenWindow { ActionWithServer::OpenWindow { window_name, pos, size, monitor, anchor } => {
window_name,
pos,
size,
monitor,
anchor,
} => {
return with_response_channel(|sender| app::DaemonCommand::OpenWindow { return with_response_channel(|sender| app::DaemonCommand::OpenWindow {
window_name, window_name,
pos, pos,

View file

@ -122,10 +122,7 @@ struct PollVarHandler {
impl PollVarHandler { impl PollVarHandler {
fn new(evt_send: UnboundedSender<DaemonCommand>) -> Result<Self> { fn new(evt_send: UnboundedSender<DaemonCommand>) -> Result<Self> {
let handler = PollVarHandler { let handler = PollVarHandler { evt_send, poll_handles: HashMap::new() };
evt_send,
poll_handles: HashMap::new(),
};
Ok(handler) Ok(handler)
} }
@ -177,10 +174,7 @@ struct TailVarHandler {
impl TailVarHandler { impl TailVarHandler {
fn new(evt_send: UnboundedSender<DaemonCommand>) -> Result<Self> { fn new(evt_send: UnboundedSender<DaemonCommand>) -> Result<Self> {
let handler = TailVarHandler { let handler = TailVarHandler { evt_send, tail_process_handles: HashMap::new() };
evt_send,
tail_process_handles: HashMap::new(),
};
Ok(handler) Ok(handler)
} }

View file

@ -70,10 +70,7 @@ pub fn initialize_server(paths: EwwPaths) -> Result<()> {
fn init_async_part(paths: EwwPaths, ui_send: UnboundedSender<app::DaemonCommand>) { fn init_async_part(paths: EwwPaths, ui_send: UnboundedSender<app::DaemonCommand>) {
std::thread::spawn(move || { std::thread::spawn(move || {
let rt = tokio::runtime::Builder::new_multi_thread() let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build().expect("Failed to initialize tokio runtime");
.enable_all()
.build()
.expect("Failed to initialize tokio runtime");
rt.block_on(async { rt.block_on(async {
let filewatch_join_handle = { let filewatch_join_handle = {
let ui_send = ui_send.clone(); let ui_send = ui_send.clone();
@ -168,10 +165,7 @@ fn do_detach(log_file_path: impl AsRef<Path>) -> Result<()> {
.create(true) .create(true)
.append(true) .append(true)
.open(&log_file_path) .open(&log_file_path)
.expect(&format!( .expect(&format!("Error opening log file ({}), for writing", log_file_path.as_ref().to_string_lossy()));
"Error opening log file ({}), for writing",
log_file_path.as_ref().to_string_lossy()
));
let fd = file.as_raw_fd(); let fd = file.as_raw_fd();
if nix::unistd::isatty(1)? { if nix::unistd::isatty(1)? {

View file

@ -69,9 +69,7 @@ pub fn extend_safe<K: std::cmp::Eq + std::hash::Hash + Clone, V, T: IntoIterator
a: &mut std::collections::HashMap<K, V>, a: &mut std::collections::HashMap<K, V>,
b: T, b: T,
) -> Vec<K> { ) -> Vec<K> {
b.into_iter() b.into_iter().filter_map(|(k, v)| a.insert(k.clone(), v).map(|_| k.clone())).collect()
.filter_map(|(k, v)| a.insert(k.clone(), v).map(|_| k.clone()))
.collect()
} }
/// read an scss file, replace all environment variable references within it and /// read an scss file, replace all environment variable references within it and
@ -122,9 +120,7 @@ pub fn replace_env_var_references(input: String) -> String {
static ref ENV_VAR_PATTERN: regex::Regex = regex::Regex::new(r"\$\{([^\s]*)\}").unwrap(); static ref ENV_VAR_PATTERN: regex::Regex = regex::Regex::new(r"\$\{([^\s]*)\}").unwrap();
} }
ENV_VAR_PATTERN ENV_VAR_PATTERN
.replace_all(&input, |var_name: &regex::Captures| { .replace_all(&input, |var_name: &regex::Captures| std::env::var(var_name.get(1).unwrap().as_str()).unwrap_or_default())
std::env::var(var_name.get(1).unwrap().as_str()).unwrap_or_default()
})
.into_owned() .into_owned()
} }

View file

@ -94,18 +94,13 @@ impl AttrValueExpr {
match self { match self {
Literal(x) => Ok(AttrValueExpr::Literal(x)), Literal(x) => Ok(AttrValueExpr::Literal(x)),
VarRef(ref name) => Ok(Literal(AttrValue::from_primitive( VarRef(ref name) => Ok(Literal(AttrValue::from_primitive(
variables variables.get(name).with_context(|| format!("Unknown variable {} referenced in {:?}", &name, &self))?.clone(),
.get(name)
.with_context(|| format!("Unknown variable {} referenced in {:?}", &name, &self))?
.clone(),
))), ))),
BinOp(box a, op, box b) => Ok(BinOp(box a.resolve_refs(variables)?, op, box b.resolve_refs(variables)?)), BinOp(box a, op, box b) => Ok(BinOp(box a.resolve_refs(variables)?, op, box b.resolve_refs(variables)?)),
UnaryOp(op, box x) => Ok(UnaryOp(op, box x.resolve_refs(variables)?)), UnaryOp(op, box x) => Ok(UnaryOp(op, box x.resolve_refs(variables)?)),
IfElse(box a, box b, box c) => Ok(IfElse( IfElse(box a, box b, box c) => {
box a.resolve_refs(variables)?, Ok(IfElse(box a.resolve_refs(variables)?, box b.resolve_refs(variables)?, box c.resolve_refs(variables)?))
box b.resolve_refs(variables)?, }
box c.resolve_refs(variables)?,
)),
} }
} }
@ -132,10 +127,10 @@ impl AttrValueExpr {
pub fn eval(self, values: &HashMap<VarName, PrimitiveValue>) -> Result<PrimitiveValue> { pub fn eval(self, values: &HashMap<VarName, PrimitiveValue>) -> Result<PrimitiveValue> {
match self { match self {
AttrValueExpr::Literal(x) => x.resolve_fully(&values), AttrValueExpr::Literal(x) => x.resolve_fully(&values),
AttrValueExpr::VarRef(ref name) => values.get(name).cloned().context(format!( AttrValueExpr::VarRef(ref name) => values
"Got unresolved variable {} while trying to evaluate expression {:?}", .get(name)
&name, &self .cloned()
)), .context(format!("Got unresolved variable {} while trying to evaluate expression {:?}", &name, &self)),
AttrValueExpr::BinOp(a, op, b) => { AttrValueExpr::BinOp(a, op, b) => {
let a = a.eval(values)?; let a = a.eval(values)?;
let b = b.eval(values)?; let b = b.eval(values)?;

View file

@ -28,10 +28,7 @@ fn parse_num(i: &str) -> IResult<&str, i32, VerboseError<&str>> {
} }
fn parse_stringlit(i: &str) -> IResult<&str, &str, VerboseError<&str>> { fn parse_stringlit(i: &str) -> IResult<&str, &str, VerboseError<&str>> {
alt(( alt((delimited(tag("'"), take_while(|c| c != '\''), tag("'")), delimited(tag("\""), take_while(|c| c != '"'), tag("\""))))(i)
delimited(tag("'"), take_while(|c| c != '\''), tag("'")),
delimited(tag("\""), take_while(|c| c != '"'), tag("\"")),
))(i)
} }
fn parse_bool(i: &str) -> IResult<&str, &str, VerboseError<&str>> { fn parse_bool(i: &str) -> IResult<&str, &str, VerboseError<&str>> {
@ -43,13 +40,9 @@ fn parse_literal(i: &str) -> IResult<&str, &str, VerboseError<&str>> {
} }
fn parse_identifier(i: &str) -> IResult<&str, &str, VerboseError<&str>> { fn parse_identifier(i: &str) -> IResult<&str, &str, VerboseError<&str>> {
verify( verify(recognize(pair(alt((alpha1, tag("_"), tag("-"))), many0(alt((alphanumeric1, tag("_"), tag("-")))))), |x| {
recognize(pair( !["if", "then", "else"].contains(x)
alt((alpha1, tag("_"), tag("-"))), })(i)
many0(alt((alphanumeric1, tag("_"), tag("-")))),
)),
|x| !["if", "then", "else"].contains(x),
)(i)
} }
fn parse_unary_op(i: &str) -> IResult<&str, UnaryOp, VerboseError<&str>> { fn parse_unary_op(i: &str) -> IResult<&str, UnaryOp, VerboseError<&str>> {
@ -65,14 +58,8 @@ fn parse_factor(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
let (i, factor) = alt(( let (i, factor) = alt((
context("expression", ws(delimited(tag("("), parse_expr, tag(")")))), context("expression", ws(delimited(tag("("), parse_expr, tag(")")))),
context("if-expression", ws(parse_ifelse)), context("if-expression", ws(parse_ifelse)),
context( context("literal", map(ws(parse_literal), |x| AttrValueExpr::Literal(AttrValue::parse_string(x)))),
"literal", context("identifier", map(ws(parse_identifier), |x| AttrValueExpr::VarRef(VarName(x.to_string())))),
map(ws(parse_literal), |x| AttrValueExpr::Literal(AttrValue::parse_string(x))),
),
context(
"identifier",
map(ws(parse_identifier), |x| AttrValueExpr::VarRef(VarName(x.to_string()))),
),
))(i)?; ))(i)?;
Ok(( Ok((
i, i,
@ -91,9 +78,7 @@ fn parse_term3(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
map(preceded(tag("%"), parse_factor), |x| (BinOp::Mod, x)), map(preceded(tag("%"), parse_factor), |x| (BinOp::Mod, x)),
)))(i)?; )))(i)?;
let exprs = remainder let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
.into_iter()
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
Ok((i, exprs)) Ok((i, exprs))
} }
@ -104,9 +89,7 @@ fn parse_term2(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
map(preceded(tag("-"), parse_term3), |x| (BinOp::Minus, x)), map(preceded(tag("-"), parse_term3), |x| (BinOp::Minus, x)),
)))(i)?; )))(i)?;
let exprs = remainder let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
.into_iter()
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
Ok((i, exprs)) Ok((i, exprs))
} }
@ -120,9 +103,7 @@ fn parse_term1(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
map(preceded(tag("<"), parse_term2), |x| (BinOp::LT, x)), map(preceded(tag("<"), parse_term2), |x| (BinOp::LT, x)),
)))(i)?; )))(i)?;
let exprs = remainder let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
.into_iter()
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
Ok((i, exprs)) Ok((i, exprs))
} }
@ -134,9 +115,7 @@ pub fn parse_expr(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
map(preceded(tag("?:"), parse_term1), |x| (BinOp::Elvis, x)), map(preceded(tag("?:"), parse_term1), |x| (BinOp::Elvis, x)),
)))(i)?; )))(i)?;
let exprs = remainder let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
.into_iter()
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
Ok((i, exprs)) Ok((i, exprs))
} }
@ -161,10 +140,7 @@ mod test {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
#[test] #[test]
fn test_parser() { fn test_parser() {
assert_eq!( assert_eq!(AttrValueExpr::Literal(AttrValue::from_primitive("12")), AttrValueExpr::parse("12").unwrap());
AttrValueExpr::Literal(AttrValue::from_primitive("12")),
AttrValueExpr::parse("12").unwrap()
);
assert_eq!( assert_eq!(
AttrValueExpr::UnaryOp(UnaryOp::Not, box AttrValueExpr::Literal(AttrValue::from_primitive("false"))), AttrValueExpr::UnaryOp(UnaryOp::Not, box AttrValueExpr::Literal(AttrValue::from_primitive("false"))),
AttrValueExpr::parse("!false").unwrap() AttrValueExpr::parse("!false").unwrap()

View file

@ -69,10 +69,7 @@ impl fmt::Debug for Coords {
impl Coords { impl Coords {
pub fn from_pixels(x: i32, y: i32) -> Self { pub fn from_pixels(x: i32, y: i32) -> Self {
Coords { Coords { x: NumWithUnit::Pixels(x), y: NumWithUnit::Pixels(y) }
x: NumWithUnit::Pixels(x),
y: NumWithUnit::Pixels(y),
}
} }
/// parse a string for x and a string for y into a [`Coords`] object. /// parse a string for x and a string for y into a [`Coords`] object.
@ -104,13 +101,7 @@ mod test {
#[test] #[test]
fn test_parse_coords() { fn test_parse_coords() {
assert_eq!( assert_eq!(Coords { x: NumWithUnit::Pixels(50), y: NumWithUnit::Pixels(60) }, Coords::from_str("50x60").unwrap());
Coords {
x: NumWithUnit::Pixels(50),
y: NumWithUnit::Pixels(60)
},
Coords::from_str("50x60").unwrap()
);
assert!(Coords::from_str("5060").is_err()); assert!(Coords::from_str("5060").is_err());
} }
} }

View file

@ -92,21 +92,15 @@ impl PrimitiveValue {
} }
pub fn as_f64(&self) -> Result<f64> { pub fn as_f64(&self) -> Result<f64> {
self.0 self.0.parse().map_err(|e| anyhow!("couldn't convert {:?} to f64: {}", &self, e))
.parse()
.map_err(|e| anyhow!("couldn't convert {:?} to f64: {}", &self, e))
} }
pub fn as_i32(&self) -> Result<i32> { pub fn as_i32(&self) -> Result<i32> {
self.0 self.0.parse().map_err(|e| anyhow!("couldn't convert {:?} to i32: {}", &self, e))
.parse()
.map_err(|e| anyhow!("couldn't convert {:?} to i32: {}", &self, e))
} }
pub fn as_bool(&self) -> Result<bool> { pub fn as_bool(&self) -> Result<bool> {
self.0 self.0.parse().map_err(|e| anyhow!("couldn't convert {:?} to bool: {}", &self, e))
.parse()
.map_err(|e| anyhow!("couldn't convert {:?} to bool: {}", &self, e))
} }
pub fn as_vec(&self) -> Result<Vec<String>> { pub fn as_vec(&self) -> Result<Vec<String>> {
@ -141,36 +135,21 @@ mod test {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
#[test] #[test]
fn test_parse_vec() { fn test_parse_vec() {
assert_eq!( assert_eq!(vec![""], parse_vec("[]".to_string()).unwrap(), "should be able to parse empty lists");
vec![""], assert_eq!(vec!["hi"], parse_vec("[hi]".to_string()).unwrap(), "should be able to parse single element list");
parse_vec("[]".to_string()).unwrap(),
"should be able to parse empty lists"
);
assert_eq!(
vec!["hi"],
parse_vec("[hi]".to_string()).unwrap(),
"should be able to parse single element list"
);
assert_eq!( assert_eq!(
vec!["hi", "ho", "hu"], vec!["hi", "ho", "hu"],
parse_vec("[hi,ho,hu]".to_string()).unwrap(), parse_vec("[hi,ho,hu]".to_string()).unwrap(),
"should be able to parse three element list" "should be able to parse three element list"
); );
assert_eq!( assert_eq!(vec!["hi,ho"], parse_vec("[hi\\,ho]".to_string()).unwrap(), "should be able to parse list with escaped comma");
vec!["hi,ho"],
parse_vec("[hi\\,ho]".to_string()).unwrap(),
"should be able to parse list with escaped comma"
);
assert_eq!( assert_eq!(
vec!["hi,ho", "hu"], vec!["hi,ho", "hu"],
parse_vec("[hi\\,ho,hu]".to_string()).unwrap(), parse_vec("[hi\\,ho,hu]".to_string()).unwrap(),
"should be able to parse two element list with escaped comma" "should be able to parse two element list with escaped comma"
); );
assert!(parse_vec("".to_string()).is_err(), "Should fail when parsing empty string"); assert!(parse_vec("".to_string()).is_err(), "Should fail when parsing empty string");
assert!( assert!(parse_vec("[a,b".to_string()).is_err(), "Should fail when parsing unclosed list");
parse_vec("[a,b".to_string()).is_err(),
"Should fail when parsing unclosed list"
);
assert!(parse_vec("a]".to_string()).is_err(), "Should fail when parsing unopened list"); assert!(parse_vec("a]".to_string()).is_err(), "Should fail when parsing unopened list");
} }
} }

View file

@ -64,18 +64,13 @@ fn build_builtin_gtk_widget(
widget_definitions: &HashMap<String, WidgetDefinition>, widget_definitions: &HashMap<String, WidgetDefinition>,
widget: &widget_node::Generic, widget: &widget_node::Generic,
) -> Result<Option<gtk::Widget>> { ) -> Result<Option<gtk::Widget>> {
let mut bargs = BuilderArgs { let mut bargs =
eww_state, BuilderArgs { eww_state, widget, window_name, unhandled_attrs: widget.attrs.keys().collect(), widget_definitions };
widget,
window_name,
unhandled_attrs: widget.attrs.keys().collect(),
widget_definitions,
};
let gtk_widget = match widget_to_gtk_widget(&mut bargs) { let gtk_widget = match widget_to_gtk_widget(&mut bargs) {
Ok(Some(gtk_widget)) => gtk_widget, Ok(Some(gtk_widget)) => gtk_widget,
result => { result => {
return result.with_context(|| { return result.with_context(|| {
anyhow!( format!(
"{}Error building widget {}", "{}Error building widget {}",
bargs.widget.text_pos.map(|x| format!("{} |", x)).unwrap_or_default(), bargs.widget.text_pos.map(|x| format!("{} |", x)).unwrap_or_default(),
bargs.widget.name, bargs.widget.name,
@ -89,16 +84,14 @@ fn build_builtin_gtk_widget(
if let Some(gtk_widget) = gtk_widget.dynamic_cast_ref::<gtk::Container>() { if let Some(gtk_widget) = gtk_widget.dynamic_cast_ref::<gtk::Container>() {
resolve_container_attrs(&mut bargs, &gtk_widget); resolve_container_attrs(&mut bargs, &gtk_widget);
for child in &widget.children { for child in &widget.children {
let child_widget = child let child_widget = child.render(bargs.eww_state, window_name, widget_definitions).with_context(|| {
.render(bargs.eww_state, window_name, widget_definitions) format!(
.with_context(|| { "{}error while building child '{:#?}' of '{}'",
format!( widget.text_pos.map(|x| format!("{} |", x)).unwrap_or_default(),
"{}error while building child '{:#?}' of '{}'", &child,
widget.text_pos.map(|x| format!("{} |", x)).unwrap_or_default(), &gtk_widget.get_widget_name()
&child, )
&gtk_widget.get_widget_name() })?;
)
})?;
gtk_widget.add(&child_widget); gtk_widget.add(&child_widget);
child_widget.show(); child_widget.show();
} }

View file

@ -25,7 +25,7 @@ pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result<Option<gtk
"color-chooser" => build_gtk_color_chooser(bargs)?.upcast(), "color-chooser" => build_gtk_color_chooser(bargs)?.upcast(),
"combo-box-text" => build_gtk_combo_box_text(bargs)?.upcast(), "combo-box-text" => build_gtk_combo_box_text(bargs)?.upcast(),
"checkbox" => build_gtk_checkbox(bargs)?.upcast(), "checkbox" => build_gtk_checkbox(bargs)?.upcast(),
"if-else" => build_if_else(bargs)?.upcast(),
_ => return Ok(None), _ => return Ok(None),
}; };
Ok(Some(gtk_widget)) Ok(Some(gtk_widget))
@ -37,11 +37,7 @@ pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result<Option<gtk
pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::Widget) { pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::Widget) {
let css_provider = gtk::CssProvider::new(); let css_provider = gtk::CssProvider::new();
if let Ok(visible) = bargs if let Ok(visible) = bargs.widget.get_attr("visible").and_then(|v| bargs.eww_state.resolve_once(v)?.as_bool()) {
.widget
.get_attr("visible")
.and_then(|v| bargs.eww_state.resolve_once(v)?.as_bool())
{
connect_first_map(gtk_widget, move |w| { connect_first_map(gtk_widget, move |w| {
if visible { if visible {
w.show(); w.show();
@ -161,6 +157,29 @@ pub(super) fn resolve_orientable_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk
// concrete widgets // concrete widgets
fn build_if_else(bargs: &mut BuilderArgs) -> Result<gtk::Box> {
if bargs.widget.children.len() != 2 {
bail!("if-widget needs to have exactly two children, but had {}", bargs.widget.children.len());
}
let gtk_widget = gtk::Box::new(gtk::Orientation::Vertical, 0);
let (yes_widget, no_widget) = (bargs.widget.children[0].clone(), bargs.widget.children[1].clone());
let yes_widget = yes_widget.render(bargs.eww_state, bargs.window_name, bargs.widget_definitions)?;
let no_widget = no_widget.render(bargs.eww_state, bargs.window_name, bargs.widget_definitions)?;
resolve_block!(bargs, gtk_widget, {
prop(cond: as_bool) {
gtk_widget.get_children().iter().for_each(|w| gtk_widget.remove(w));
if cond {
gtk_widget.add(&yes_widget)
} else {
gtk_widget.add(&no_widget)
}
}
});
Ok(gtk_widget)
}
/// @widget combo-box-text /// @widget combo-box-text
/// @desc A combo box allowing the user to choose between several items. /// @desc A combo box allowing the user to choose between several items.
fn build_gtk_combo_box_text(bargs: &mut BuilderArgs) -> Result<gtk::ComboBoxText> { fn build_gtk_combo_box_text(bargs: &mut BuilderArgs) -> Result<gtk::ComboBoxText> {
@ -272,10 +291,7 @@ fn build_gtk_color_chooser(bargs: &mut BuilderArgs) -> Result<gtk::ColorChooserW
/// @widget scale extends range /// @widget scale extends range
/// @desc A slider. /// @desc A slider.
fn build_gtk_scale(bargs: &mut BuilderArgs) -> Result<gtk::Scale> { fn build_gtk_scale(bargs: &mut BuilderArgs) -> Result<gtk::Scale> {
let gtk_widget = gtk::Scale::new( let gtk_widget = gtk::Scale::new(gtk::Orientation::Horizontal, Some(&gtk::Adjustment::new(0.0, 0.0, 100.0, 1.0, 1.0, 1.0)));
gtk::Orientation::Horizontal,
Some(&gtk::Adjustment::new(0.0, 0.0, 100.0, 1.0, 1.0, 1.0)),
);
resolve_block!(bargs, gtk_widget, { resolve_block!(bargs, gtk_widget, {
// @prop flipped - flip the direction // @prop flipped - flip the direction
prop(flipped: as_bool) { gtk_widget.set_inverted(flipped) }, prop(flipped: as_bool) { gtk_widget.set_inverted(flipped) },
@ -472,10 +488,7 @@ fn parse_orientation(o: &str) -> Result<gtk::Orientation> {
Ok(match o { Ok(match o {
"vertical" | "v" => gtk::Orientation::Vertical, "vertical" | "v" => gtk::Orientation::Vertical,
"horizontal" | "h" => gtk::Orientation::Horizontal, "horizontal" | "h" => gtk::Orientation::Horizontal,
_ => bail!( _ => bail!(r#"Couldn't parse orientation: '{}'. Possible values are "vertical", "v", "horizontal", "h""#, o),
r#"Couldn't parse orientation: '{}'. Possible values are "vertical", "v", "horizontal", "h""#,
o
),
}) })
} }
@ -487,10 +500,7 @@ fn parse_align(o: &str) -> Result<gtk::Align> {
"center" => gtk::Align::Center, "center" => gtk::Align::Center,
"start" => gtk::Align::Start, "start" => gtk::Align::Start,
"end" => gtk::Align::End, "end" => gtk::Align::End,
_ => bail!( _ => bail!(r#"Couldn't parse alignment: '{}'. Possible values are "fill", "baseline", "center", "start", "end""#, o),
r#"Couldn't parse alignment: '{}'. Possible values are "fill", "baseline", "center", "start", "end""#,
o
),
}) })
} }

View file

@ -66,9 +66,7 @@ pub struct Generic {
impl Generic { impl Generic {
pub fn get_attr(&self, key: &str) -> Result<&AttrValue> { pub fn get_attr(&self, key: &str) -> Result<&AttrValue> {
self.attrs self.attrs.get(key).context(format!("attribute '{}' missing from use of '{}'", key, &self.name))
.get(key)
.context(format!("attribute '{}' missing from use of '{}'", key, &self.name))
} }
/// returns all the variables that are referenced in this widget /// returns all the variables that are referenced in this widget
@ -92,10 +90,8 @@ impl WidgetNode for Generic {
window_name: &WindowName, window_name: &WindowName,
widget_definitions: &HashMap<String, WidgetDefinition>, widget_definitions: &HashMap<String, WidgetDefinition>,
) -> Result<gtk::Widget> { ) -> Result<gtk::Widget> {
Ok( Ok(crate::widgets::build_builtin_gtk_widget(eww_state, window_name, widget_definitions, &self)?
crate::widgets::build_builtin_gtk_widget(eww_state, window_name, widget_definitions, &self)? .with_context(|| format!("Unknown widget '{}'", self.get_name()))?)
.with_context(|| format!("Unknown widget '{}'", self.get_name()))?,
)
} }
} }
@ -114,20 +110,12 @@ pub fn generate_generic_widget_node(
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
let content = generate_generic_widget_node(defs, &new_local_env, def.structure.clone())?; let content = generate_generic_widget_node(defs, &new_local_env, def.structure.clone())?;
Ok(Box::new(UserDefined { Ok(Box::new(UserDefined { name: w.name, text_pos: w.text_pos, content }))
name: w.name,
text_pos: w.text_pos,
content,
}))
} else { } else {
Ok(Box::new(Generic { Ok(Box::new(Generic {
name: w.name, name: w.name,
text_pos: w.text_pos, text_pos: w.text_pos,
attrs: w attrs: w.attrs.into_iter().map(|(name, value)| (name, value.resolve_one_level(local_env))).collect(),
.attrs
.into_iter()
.map(|(name, value)| (name, value.resolve_one_level(local_env)))
.collect(),
children: w children: w
.children .children
.into_iter() .into_iter()