change formatting config
This commit is contained in:
parent
5cf18bfc43
commit
f544d0e19a
26 changed files with 156 additions and 439 deletions
|
@ -11,3 +11,4 @@ condense_wildcard_suffixes = true
|
|||
format_code_in_doc_comments = true
|
||||
format_macro_matchers = true
|
||||
format_strings = true
|
||||
use_small_heuristics = "Max"
|
||||
|
|
94
src/app.rs
94
src/app.rs
|
@ -149,20 +149,10 @@ impl App {
|
|||
}
|
||||
}
|
||||
DaemonCommand::OpenMany { windows, sender } => {
|
||||
let result = windows
|
||||
.iter()
|
||||
.map(|w| self.open_window(w, None, None, None, None))
|
||||
.collect::<Result<()>>();
|
||||
let result = windows.iter().map(|w| self.open_window(w, None, None, None, None)).collect::<Result<()>>();
|
||||
respond_with_error(sender, result)?;
|
||||
}
|
||||
DaemonCommand::OpenWindow {
|
||||
window_name,
|
||||
pos,
|
||||
size,
|
||||
anchor,
|
||||
monitor,
|
||||
sender,
|
||||
} => {
|
||||
DaemonCommand::OpenWindow { window_name, pos, size, anchor, monitor, sender } => {
|
||||
let result = self.open_window(&window_name, pos, size, monitor, anchor);
|
||||
respond_with_error(sender, result)?;
|
||||
}
|
||||
|
@ -171,15 +161,9 @@ impl App {
|
|||
respond_with_error(sender, result)?;
|
||||
}
|
||||
DaemonCommand::PrintState(sender) => {
|
||||
let output = self
|
||||
.eww_state
|
||||
.get_variables()
|
||||
.iter()
|
||||
.map(|(key, value)| format!("{}: {}", key, value))
|
||||
.join("\n");
|
||||
sender
|
||||
.send(DaemonResponse::Success(output))
|
||||
.context("sending response from main thread")?
|
||||
let output =
|
||||
self.eww_state.get_variables().iter().map(|(key, value)| format!("{}: {}", key, value)).join("\n");
|
||||
sender.send(DaemonResponse::Success(output)).context("sending response from main thread")?
|
||||
}
|
||||
DaemonCommand::PrintWindows(sender) => {
|
||||
let output = self
|
||||
|
@ -191,15 +175,11 @@ impl App {
|
|||
format!("{}{}", if is_open { "*" } else { "" }, window_name)
|
||||
})
|
||||
.join("\n");
|
||||
sender
|
||||
.send(DaemonResponse::Success(output))
|
||||
.context("sending response from main thread")?
|
||||
sender.send(DaemonResponse::Success(output)).context("sending response from main thread")?
|
||||
}
|
||||
DaemonCommand::PrintDebug(sender) => {
|
||||
let output = format!("state: {:#?}\n\nconfig: {:#?}", &self.eww_state, &self.eww_config);
|
||||
sender
|
||||
.send(DaemonResponse::Success(output))
|
||||
.context("sending response from main thread")?
|
||||
sender.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());
|
||||
}
|
||||
|
||||
let window = self
|
||||
.open_windows
|
||||
.remove(window_name)
|
||||
.context(format!("No window with name '{}' is running.", window_name))?;
|
||||
let window =
|
||||
self.open_windows.remove(window_name).context(format!("No window with name '{}' is running.", window_name))?;
|
||||
|
||||
window.close();
|
||||
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);
|
||||
|
||||
let root_widget =
|
||||
window_def
|
||||
.widget
|
||||
.render(&mut self.eww_state, window_name, &self.eww_config.get_widget_definitions())?;
|
||||
window_def.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());
|
||||
|
||||
let monitor_geometry =
|
||||
|
@ -264,9 +240,8 @@ impl App {
|
|||
|
||||
// initialize script var handlers for variables that where not used before opening this window.
|
||||
// TODO somehow make this less shit
|
||||
for newly_used_var in self
|
||||
.variables_only_used_in(&window_name)
|
||||
.filter_map(|var| self.eww_config.get_script_var(&var).ok())
|
||||
for newly_used_var in
|
||||
self.variables_only_used_in(&window_name).filter_map(|var| self.eww_config.get_script_var(&var).ok())
|
||||
{
|
||||
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.
|
||||
pub fn get_currently_used_variables(&self) -> impl Iterator<Item = &VarName> {
|
||||
self.open_windows
|
||||
.keys()
|
||||
.flat_map(move |window_name| self.eww_state.vars_referenced_in(window_name))
|
||||
self.open_windows.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.
|
||||
|
@ -308,9 +281,7 @@ impl App {
|
|||
let mut vars: HashMap<&'a VarName, Vec<_>> = HashMap::new();
|
||||
for window_name in self.open_windows.keys() {
|
||||
for var in self.eww_state.vars_referenced_in(window_name) {
|
||||
vars.entry(var)
|
||||
.and_modify(|l| l.push(window_name))
|
||||
.or_insert_with(|| vec![window_name]);
|
||||
vars.entry(var).and_modify(|l| l.push(window_name)).or_insert_with(|| vec![window_name]);
|
||||
}
|
||||
}
|
||||
vars
|
||||
|
@ -332,11 +303,8 @@ fn initialize_window(
|
|||
) -> Result<EwwWindow> {
|
||||
let actual_window_rect = window_def.geometry.get_window_rectangle(monitor_geometry);
|
||||
|
||||
let window = if window_def.focusable {
|
||||
gtk::Window::new(gtk::WindowType::Toplevel)
|
||||
} else {
|
||||
gtk::Window::new(gtk::WindowType::Popup)
|
||||
};
|
||||
let window =
|
||||
if window_def.focusable { gtk::Window::new(gtk::WindowType::Toplevel) } else { gtk::Window::new(gtk::WindowType::Popup) };
|
||||
|
||||
window.set_title(&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.
|
||||
// This is necessary to handle different anchors correctly in case the size was wrong.
|
||||
let (gtk_window_width, gtk_window_height) = window.get_size();
|
||||
window_def.geometry.size = Coords {
|
||||
x: NumWithUnit::Pixels(gtk_window_width),
|
||||
y: NumWithUnit::Pixels(gtk_window_height),
|
||||
};
|
||||
window_def.geometry.size = Coords { x: NumWithUnit::Pixels(gtk_window_width), y: NumWithUnit::Pixels(gtk_window_height) };
|
||||
let actual_window_rect = window_def.geometry.get_window_rectangle(monitor_geometry);
|
||||
|
||||
window.show_all();
|
||||
|
@ -382,37 +347,24 @@ fn initialize_window(
|
|||
|
||||
display_backend::reserve_space_for(&window, monitor_geometry, window_def.struts)?;
|
||||
|
||||
Ok(EwwWindow {
|
||||
name: window_def.name.clone(),
|
||||
definition: window_def,
|
||||
gtk_window: window,
|
||||
})
|
||||
Ok(EwwWindow { name: window_def.name.clone(), definition: window_def, gtk_window: window })
|
||||
}
|
||||
|
||||
fn on_screen_changed(window: >k::Window, _old_screen: Option<&gdk::Screen>) {
|
||||
let visual = window.get_screen().and_then(|screen| {
|
||||
screen
|
||||
.get_rgba_visual()
|
||||
.filter(|_| screen.is_composited())
|
||||
.or_else(|| screen.get_system_visual())
|
||||
});
|
||||
let visual = window
|
||||
.get_screen()
|
||||
.and_then(|screen| screen.get_rgba_visual().filter(|_| screen.is_composited()).or_else(|| screen.get_system_visual()));
|
||||
window.set_visual(visual.as_ref());
|
||||
}
|
||||
|
||||
/// get the index of the default monitor
|
||||
fn get_default_monitor_index() -> i32 {
|
||||
gdk::Display::get_default()
|
||||
.expect("could not get default display")
|
||||
.get_default_screen()
|
||||
.get_primary_monitor()
|
||||
gdk::Display::get_default().expect("could not get default display").get_default_screen().get_primary_monitor()
|
||||
}
|
||||
|
||||
/// Get the monitor geometry of a given monitor number
|
||||
fn get_monitor_geometry(n: i32) -> gdk::Rectangle {
|
||||
gdk::Display::get_default()
|
||||
.expect("could not get default display")
|
||||
.get_default_screen()
|
||||
.get_monitor_geometry(n)
|
||||
gdk::Display::get_default().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.
|
||||
|
|
|
@ -11,20 +11,14 @@ lazy_static::lazy_static! {
|
|||
|
||||
/// Notify all listening tasks of the termination of the eww application process.
|
||||
pub fn send_exit() -> Result<()> {
|
||||
(&*APPLICATION_EXIT_SENDER)
|
||||
.send(())
|
||||
.context("Failed to send exit lifecycle event")?;
|
||||
(&*APPLICATION_EXIT_SENDER).send(()).context("Failed to send exit lifecycle event")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Yields Ok(()) on application termination. Await on this in all long-running tasks
|
||||
/// and perform any cleanup if necessary.
|
||||
pub async fn recv_exit() -> Result<()> {
|
||||
(&*APPLICATION_EXIT_SENDER)
|
||||
.subscribe()
|
||||
.recv()
|
||||
.await
|
||||
.context("Failed to receive lifecycle event")
|
||||
(&*APPLICATION_EXIT_SENDER).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.
|
||||
|
|
|
@ -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>> {
|
||||
log::info!("Forwarding options to server");
|
||||
stream
|
||||
.set_nonblocking(false)
|
||||
.context("Failed to set stream to non-blocking")?;
|
||||
stream.set_nonblocking(false).context("Failed to set stream to non-blocking")?;
|
||||
|
||||
let message_bytes = bincode::serialize(&action)?;
|
||||
|
||||
stream
|
||||
.write(&(message_bytes.len() as u32).to_be_bytes())
|
||||
.context("Failed to send command size header to IPC stream")?;
|
||||
stream.write(&(message_bytes.len() as u32).to_be_bytes()).context("Failed to send command size header to IPC stream")?;
|
||||
|
||||
stream
|
||||
.write_all(&message_bytes)
|
||||
.context("Failed to write command to IPC stream")?;
|
||||
stream.write_all(&message_bytes).context("Failed to write command to IPC stream")?;
|
||||
|
||||
let mut buf = Vec::new();
|
||||
stream
|
||||
.set_read_timeout(Some(std::time::Duration::from_millis(100)))
|
||||
.context("Failed to set read timeout")?;
|
||||
stream.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")?;
|
||||
|
||||
Ok(if buf.is_empty() {
|
||||
|
|
|
@ -58,12 +58,7 @@ impl PartialEq for WidgetUse {
|
|||
|
||||
impl WidgetUse {
|
||||
pub fn new(name: String, children: Vec<WidgetUse>) -> Self {
|
||||
WidgetUse {
|
||||
name,
|
||||
children,
|
||||
attrs: HashMap::new(),
|
||||
..WidgetUse::default()
|
||||
}
|
||||
WidgetUse { name, children, attrs: HashMap::new(), ..WidgetUse::default() }
|
||||
}
|
||||
|
||||
pub fn from_xml_node(xml: XmlNode) -> Result<Self> {
|
||||
|
@ -171,9 +166,6 @@ mod test {
|
|||
},
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
expected,
|
||||
WidgetDefinition::from_xml_element(xml.as_element().unwrap()).unwrap()
|
||||
);
|
||||
assert_eq!(expected, WidgetDefinition::from_xml_element(xml.as_element().unwrap()).unwrap());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,21 +28,12 @@ impl EwwConfig {
|
|||
}
|
||||
|
||||
pub fn generate(conf: RawEwwConfig) -> Result<Self> {
|
||||
let RawEwwConfig {
|
||||
windows,
|
||||
initial_variables,
|
||||
script_vars,
|
||||
filepath,
|
||||
widgets,
|
||||
} = conf;
|
||||
let RawEwwConfig { windows, initial_variables, script_vars, filepath, widgets } = conf;
|
||||
Ok(EwwConfig {
|
||||
windows: windows
|
||||
.into_iter()
|
||||
.map(|(name, window)| {
|
||||
Ok((
|
||||
name,
|
||||
EwwWindowDefinition::generate(&widgets, window).context("Failed expand window definition")?,
|
||||
))
|
||||
Ok((name, EwwWindowDefinition::generate(&widgets, window).context("Failed expand window definition")?))
|
||||
})
|
||||
.collect::<Result<HashMap<_, _>>>()?,
|
||||
widgets,
|
||||
|
@ -54,11 +45,8 @@ impl EwwConfig {
|
|||
|
||||
// TODO this is kinda ugly
|
||||
pub fn generate_initial_state(&self) -> Result<HashMap<VarName, PrimitiveValue>> {
|
||||
let mut vars = self
|
||||
.script_vars
|
||||
.iter()
|
||||
.map(|var| Ok((var.0.clone(), var.1.initial_value()?)))
|
||||
.collect::<Result<HashMap<_, _>>>()?;
|
||||
let mut vars =
|
||||
self.script_vars.iter().map(|var| Ok((var.0.clone(), var.1.initial_value()?))).collect::<Result<HashMap<_, _>>>()?;
|
||||
vars.extend(self.initial_variables.clone());
|
||||
Ok(vars)
|
||||
}
|
||||
|
@ -68,15 +56,11 @@ impl EwwConfig {
|
|||
}
|
||||
|
||||
pub fn get_window(&self, name: &WindowName) -> Result<&EwwWindowDefinition> {
|
||||
self.windows
|
||||
.get(name)
|
||||
.with_context(|| format!("No window named '{}' exists", name))
|
||||
self.windows.get(name).with_context(|| format!("No window named '{}' exists", name))
|
||||
}
|
||||
|
||||
pub fn get_script_var(&self, name: &VarName) -> Result<&ScriptVar> {
|
||||
self.script_vars
|
||||
.get(name)
|
||||
.with_context(|| format!("No script var named '{}' exists", name))
|
||||
self.script_vars.get(name).with_context(|| format!("No script var named '{}' exists", name))
|
||||
}
|
||||
|
||||
pub fn get_widget_definitions(&self) -> &HashMap<String, WidgetDefinition> {
|
||||
|
@ -192,13 +176,7 @@ impl RawEwwConfig {
|
|||
None => Default::default(),
|
||||
};
|
||||
|
||||
let config = RawEwwConfig {
|
||||
widgets: definitions,
|
||||
windows,
|
||||
initial_variables,
|
||||
script_vars,
|
||||
filepath: path.to_path_buf(),
|
||||
};
|
||||
let config = RawEwwConfig { widgets: definitions, windows, initial_variables, script_vars, filepath: path.to_path_buf() };
|
||||
Ok((config, included_paths))
|
||||
}
|
||||
}
|
||||
|
@ -209,10 +187,7 @@ fn parse_variables_block(xml: XmlElement) -> Result<(HashMap<VarName, PrimitiveV
|
|||
for node in xml.child_elements() {
|
||||
match node.tag_name() {
|
||||
"var" => {
|
||||
let value = node
|
||||
.only_child()
|
||||
.map(|c| c.as_text_or_sourcecode())
|
||||
.unwrap_or_else(|_| String::new());
|
||||
let value = node.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));
|
||||
}
|
||||
"script-var" => {
|
||||
|
@ -282,12 +257,10 @@ mod test {
|
|||
|
||||
let document1 = roxmltree::Document::parse(&input1).unwrap();
|
||||
let document2 = roxmltree::Document::parse(input2).unwrap();
|
||||
let config1 = RawEwwConfig::from_xml_element(XmlNode::from(document1.root_element()).as_element().unwrap().clone(), "")
|
||||
.unwrap()
|
||||
.0;
|
||||
let config2 = RawEwwConfig::from_xml_element(XmlNode::from(document2.root_element()).as_element().unwrap().clone(), "")
|
||||
.unwrap()
|
||||
.0;
|
||||
let config1 =
|
||||
RawEwwConfig::from_xml_element(XmlNode::from(document1.root_element()).as_element().unwrap().clone(), "").unwrap().0;
|
||||
let config2 =
|
||||
RawEwwConfig::from_xml_element(XmlNode::from(document2.root_element()).as_element().unwrap().clone(), "").unwrap().0;
|
||||
let base_config = RawEwwConfig {
|
||||
widgets: HashMap::new(),
|
||||
windows: HashMap::new(),
|
||||
|
|
|
@ -24,12 +24,7 @@ macro_rules! ensure_xml_tag_is {
|
|||
($element:ident, $name:literal) => {
|
||||
ensure!(
|
||||
$element.tag_name() == $name,
|
||||
anyhow!(
|
||||
"{} | Tag needed to be of type '{}', but was: {}",
|
||||
$element.text_pos(),
|
||||
$name,
|
||||
$element.as_tag_string()
|
||||
)
|
||||
anyhow!("{} | Tag needed to be of type '{}', but was: {}", $element.text_pos(), $name, $element.as_tag_string())
|
||||
)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -55,12 +55,8 @@ impl RawEwwWindowDefinition {
|
|||
let focusable = xml.parse_optional_attr("focusable")?;
|
||||
let screen_number = xml.parse_optional_attr("screen")?;
|
||||
|
||||
let struts: Option<StrutDefinition> = xml
|
||||
.child("reserve")
|
||||
.ok()
|
||||
.map(StrutDefinition::from_xml_element)
|
||||
.transpose()
|
||||
.context("Failed to parse <reserve>")?;
|
||||
let struts: Option<StrutDefinition> =
|
||||
xml.child("reserve").ok().map(StrutDefinition::from_xml_element).transpose().context("Failed to parse <reserve>")?;
|
||||
|
||||
Ok(RawEwwWindowDefinition {
|
||||
name: WindowName(xml.attr("name")?.to_owned()),
|
||||
|
@ -94,10 +90,7 @@ impl std::str::FromStr for Side {
|
|||
"r" | "right" => Ok(Side::Right),
|
||||
"t" | "top" => Ok(Side::Top),
|
||||
"b" | "bottom" => Ok(Side::Bottom),
|
||||
_ => Err(anyhow!(
|
||||
"Failed to parse {} as valid side. Must be one of \"left\", \"right\", \"top\", \"bottom\"",
|
||||
s
|
||||
)),
|
||||
_ => Err(anyhow!("Failed to parse {} as valid side. Must be one of \"left\", \"right\", \"top\", \"bottom\"", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,10 +103,7 @@ pub struct StrutDefinition {
|
|||
|
||||
impl StrutDefinition {
|
||||
pub fn from_xml_element(xml: XmlElement) -> Result<Self> {
|
||||
Ok(StrutDefinition {
|
||||
side: xml.attr("side")?.parse()?,
|
||||
dist: xml.attr("distance")?.parse()?,
|
||||
})
|
||||
Ok(StrutDefinition { side: xml.attr("side")?.parse()?, dist: xml.attr("distance")?.parse()? })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,10 +122,7 @@ impl std::str::FromStr for WindowStacking {
|
|||
match s.as_str() {
|
||||
"foreground" | "fg" | "f" => Ok(WindowStacking::Foreground),
|
||||
"background" | "bg" | "b" => Ok(WindowStacking::Background),
|
||||
_ => Err(anyhow!(
|
||||
"Couldn't parse '{}' as window stacking, must be either foreground, fg, background or bg",
|
||||
s
|
||||
)),
|
||||
_ => Err(anyhow!("Couldn't parse '{}' as window stacking, must be either foreground, fg, background or bg", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,10 +24,7 @@ impl AnchorAlignment {
|
|||
"l" | "left" => Ok(AnchorAlignment::START),
|
||||
"c" | "center" => Ok(AnchorAlignment::CENTER),
|
||||
"r" | "right" => Ok(AnchorAlignment::END),
|
||||
_ => bail!(
|
||||
r#"couldn't parse '{}' as x-alignment. Must be one of "left", "center", "right""#,
|
||||
s
|
||||
),
|
||||
_ => bail!(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),
|
||||
"c" | "center" => Ok(AnchorAlignment::CENTER),
|
||||
"b" | "bottom" => Ok(AnchorAlignment::END),
|
||||
_ => bail!(
|
||||
r#"couldn't parse '{}' as y-alignment. Must be one of "top", "center", "bottom""#,
|
||||
s
|
||||
),
|
||||
_ => bail!(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> {
|
||||
if s == "center" {
|
||||
Ok(AnchorPoint {
|
||||
x: AnchorAlignment::CENTER,
|
||||
y: AnchorAlignment::CENTER,
|
||||
})
|
||||
Ok(AnchorPoint { x: AnchorAlignment::CENTER, y: AnchorAlignment::CENTER })
|
||||
} else {
|
||||
let (first, second) = s
|
||||
.split_once(' ')
|
||||
.context("Failed to parse anchor: Must either be \"center\" or be formatted like \"top left\"")?;
|
||||
let x_y_result: Result<_> = try {
|
||||
AnchorPoint {
|
||||
x: AnchorAlignment::from_x_alignment(first)?,
|
||||
y: AnchorAlignment::from_y_alignment(second)?,
|
||||
}
|
||||
AnchorPoint { x: AnchorAlignment::from_x_alignment(first)?, y: AnchorAlignment::from_y_alignment(second)? }
|
||||
};
|
||||
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)? })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
/// 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 {
|
||||
let mut code_text = s
|
||||
.lines()
|
||||
.dropping(start_pos.row as usize - 1)
|
||||
.take(end_pos.row as usize - (start_pos.row as usize - 1))
|
||||
.collect_vec();
|
||||
let mut code_text =
|
||||
s.lines().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() {
|
||||
*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> {
|
||||
pub fn as_tag_string(&self) -> String {
|
||||
let attrs = self
|
||||
.attributes()
|
||||
.iter()
|
||||
.map(|attr| format!("{}=\"{}\"", attr.name(), attr.value()))
|
||||
.join(" ");
|
||||
let attrs = self.attributes().iter().map(|attr| format!("{}=\"{}\"", attr.name(), attr.value())).join(" ");
|
||||
|
||||
format!("<{} {}>", self.tag_name(), attrs)
|
||||
}
|
||||
|
@ -255,10 +248,7 @@ mod test {
|
|||
let input = "<something>whatever</something>";
|
||||
let document = roxmltree::Document::parse(&input).unwrap();
|
||||
let root_node = XmlNode::from(document.root_element());
|
||||
assert_eq!(
|
||||
root_node.as_element().unwrap().only_child().unwrap().as_text_or_sourcecode(),
|
||||
"whatever".to_string()
|
||||
);
|
||||
assert_eq!(root_node.as_element().unwrap().only_child().unwrap().as_text_or_sourcecode(), "whatever".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -41,11 +41,7 @@ mod platform {
|
|||
let (conn, screen_num) = RustConnection::connect(None)?;
|
||||
let screen = conn.setup().roots[screen_num].clone();
|
||||
let atoms = AtomCollection::new(&conn)?.reply()?;
|
||||
Ok(X11Backend {
|
||||
conn,
|
||||
root_window: screen.root,
|
||||
atoms,
|
||||
})
|
||||
Ok(X11Backend { conn, root_window: screen.root, atoms })
|
||||
}
|
||||
|
||||
fn reserve_space_for(
|
||||
|
|
|
@ -51,10 +51,7 @@ impl EwwWindowState {
|
|||
fn put_handler(&mut self, handler: StateChangeHandler) {
|
||||
let handler = Arc::new(handler);
|
||||
for var_name in handler.used_variables() {
|
||||
self.state_change_handlers
|
||||
.entry(var_name.clone())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(handler.clone());
|
||||
self.state_change_handlers.entry(var_name.clone()).or_insert_with(Vec::new).push(handler.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,10 +72,7 @@ impl std::fmt::Debug for EwwState {
|
|||
|
||||
impl EwwState {
|
||||
pub fn from_default_vars(defaults: HashMap<VarName, PrimitiveValue>) -> Self {
|
||||
EwwState {
|
||||
variables_state: defaults,
|
||||
..EwwState::default()
|
||||
}
|
||||
EwwState { variables_state: defaults, ..EwwState::default() }
|
||||
}
|
||||
|
||||
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.
|
||||
pub fn lookup(&self, var_name: &VarName) -> Result<&PrimitiveValue> {
|
||||
self.variables_state
|
||||
.get(var_name)
|
||||
.with_context(|| format!("Unknown variable '{}' referenced", var_name))
|
||||
self.variables_state.get(var_name).with_context(|| format!("Unknown variable '{}' referenced", var_name))
|
||||
}
|
||||
|
||||
/// resolves a value if possible, using the current eww_state.
|
||||
|
@ -134,19 +126,13 @@ impl EwwState {
|
|||
required_attributes: HashMap<AttrName, AttrValue>,
|
||||
set_value: F,
|
||||
) {
|
||||
let handler = StateChangeHandler {
|
||||
func: Box::new(set_value),
|
||||
unresolved_values: required_attributes,
|
||||
};
|
||||
let handler = StateChangeHandler { func: Box::new(set_value), unresolved_values: required_attributes };
|
||||
|
||||
handler.run_with_state(&self.variables_state);
|
||||
|
||||
// only store the handler if at least one variable is being used
|
||||
if handler.used_variables().next().is_some() {
|
||||
self.windows
|
||||
.entry(window_name.clone())
|
||||
.or_insert_with(EwwWindowState::default)
|
||||
.put_handler(handler);
|
||||
self.windows.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> {
|
||||
self.windows
|
||||
.get(window_name)
|
||||
.map(|window| window.state_change_handlers.keys().collect())
|
||||
.unwrap_or_default()
|
||||
self.windows.get(window_name).map(|window| window.state_change_handlers.keys().collect()).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,11 +26,6 @@ impl Rectangular for Rect {
|
|||
|
||||
impl Rectangular for gdk::Rectangle {
|
||||
fn get_rect(&self) -> Rect {
|
||||
Rect {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
}
|
||||
Rect { x: self.x, y: self.y, width: self.width, height: self.height }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
async fn read_action_from_stream(stream_read: &'_ mut tokio::net::unix::ReadHalf<'_>) -> Result<opts::ActionWithServer> {
|
||||
let mut message_byte_length = [0u8; 4];
|
||||
stream_read
|
||||
.read_exact(&mut message_byte_length)
|
||||
.await
|
||||
.context("Failed to read message size header in IPC message")?;
|
||||
stream_read.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 mut raw_message = Vec::<u8>::with_capacity(message_byte_length as usize);
|
||||
while raw_message.len() < message_byte_length as usize {
|
||||
stream_read
|
||||
.read_buf(&mut raw_message)
|
||||
.await
|
||||
.context("Failed to read actual IPC message")?;
|
||||
stream_read.read_buf(&mut raw_message).await.context("Failed to read actual IPC message")?;
|
||||
}
|
||||
|
||||
bincode::deserialize(&raw_message).context("Failed to parse client message")
|
||||
|
|
26
src/main.rs
26
src/main.rs
|
@ -35,32 +35,20 @@ pub mod widgets;
|
|||
fn main() {
|
||||
let opts: opts::Opt = opts::Opt::from_env();
|
||||
|
||||
let log_level_filter = if opts.log_debug {
|
||||
log::LevelFilter::Debug
|
||||
} else {
|
||||
log::LevelFilter::Off
|
||||
};
|
||||
let log_level_filter = if opts.log_debug { log::LevelFilter::Debug } else { log::LevelFilter::Off };
|
||||
|
||||
pretty_env_logger::formatted_builder()
|
||||
.filter(Some("eww"), log_level_filter)
|
||||
.init();
|
||||
pretty_env_logger::formatted_builder().filter(Some("eww"), log_level_filter).init();
|
||||
|
||||
let result: Result<_> = try {
|
||||
let paths = opts
|
||||
.config_path
|
||||
.map(EwwPaths::from_config_dir)
|
||||
.unwrap_or_else(EwwPaths::default)
|
||||
.context("Failed set paths")?;
|
||||
let paths =
|
||||
opts.config_path.map(EwwPaths::from_config_dir).unwrap_or_else(EwwPaths::default).context("Failed set paths")?;
|
||||
|
||||
match opts.action {
|
||||
opts::Action::ClientOnly(action) => {
|
||||
client::handle_client_only_action(&paths, action)?;
|
||||
}
|
||||
opts::Action::WithServer(action) => {
|
||||
log::info!(
|
||||
"Trying to find server process at socket {}",
|
||||
paths.get_ipc_socket_file().display()
|
||||
);
|
||||
log::info!("Trying to find server process at socket {}", paths.get_ipc_socket_file().display());
|
||||
match net::UnixStream::connect(&paths.get_ipc_socket_file()) {
|
||||
Ok(stream) => {
|
||||
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> {
|
||||
let config_dir = config_dir.as_ref();
|
||||
let config_dir = if config_dir.is_file() {
|
||||
config_dir
|
||||
.parent()
|
||||
.context("Given config file did not have a parent directory")?
|
||||
config_dir.parent().context("Given config file did not have a parent directory")?
|
||||
} else {
|
||||
config_dir
|
||||
};
|
||||
|
|
20
src/opts.rs
20
src/opts.rs
|
@ -133,16 +133,8 @@ impl Opt {
|
|||
|
||||
impl From<RawOpt> for Opt {
|
||||
fn from(other: RawOpt) -> Self {
|
||||
let RawOpt {
|
||||
action,
|
||||
log_debug,
|
||||
config,
|
||||
} = other;
|
||||
Opt {
|
||||
action,
|
||||
log_debug,
|
||||
config_path: config,
|
||||
}
|
||||
let RawOpt { action, log_debug, config } = other;
|
||||
Opt { action, log_debug, config_path: config }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,13 +160,7 @@ impl ActionWithServer {
|
|||
ActionWithServer::OpenMany { windows } => {
|
||||
return with_response_channel(|sender| app::DaemonCommand::OpenMany { windows, sender });
|
||||
}
|
||||
ActionWithServer::OpenWindow {
|
||||
window_name,
|
||||
pos,
|
||||
size,
|
||||
monitor,
|
||||
anchor,
|
||||
} => {
|
||||
ActionWithServer::OpenWindow { window_name, pos, size, monitor, anchor } => {
|
||||
return with_response_channel(|sender| app::DaemonCommand::OpenWindow {
|
||||
window_name,
|
||||
pos,
|
||||
|
|
|
@ -122,10 +122,7 @@ struct PollVarHandler {
|
|||
|
||||
impl PollVarHandler {
|
||||
fn new(evt_send: UnboundedSender<DaemonCommand>) -> Result<Self> {
|
||||
let handler = PollVarHandler {
|
||||
evt_send,
|
||||
poll_handles: HashMap::new(),
|
||||
};
|
||||
let handler = PollVarHandler { evt_send, poll_handles: HashMap::new() };
|
||||
Ok(handler)
|
||||
}
|
||||
|
||||
|
@ -177,10 +174,7 @@ struct TailVarHandler {
|
|||
|
||||
impl TailVarHandler {
|
||||
fn new(evt_send: UnboundedSender<DaemonCommand>) -> Result<Self> {
|
||||
let handler = TailVarHandler {
|
||||
evt_send,
|
||||
tail_process_handles: HashMap::new(),
|
||||
};
|
||||
let handler = TailVarHandler { evt_send, tail_process_handles: HashMap::new() };
|
||||
Ok(handler)
|
||||
}
|
||||
|
||||
|
|
|
@ -70,10 +70,7 @@ pub fn initialize_server(paths: EwwPaths) -> Result<()> {
|
|||
|
||||
fn init_async_part(paths: EwwPaths, ui_send: UnboundedSender<app::DaemonCommand>) {
|
||||
std::thread::spawn(move || {
|
||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Failed to initialize tokio runtime");
|
||||
let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build().expect("Failed to initialize tokio runtime");
|
||||
rt.block_on(async {
|
||||
let filewatch_join_handle = {
|
||||
let ui_send = ui_send.clone();
|
||||
|
@ -168,10 +165,7 @@ fn do_detach(log_file_path: impl AsRef<Path>) -> Result<()> {
|
|||
.create(true)
|
||||
.append(true)
|
||||
.open(&log_file_path)
|
||||
.expect(&format!(
|
||||
"Error opening log file ({}), for writing",
|
||||
log_file_path.as_ref().to_string_lossy()
|
||||
));
|
||||
.expect(&format!("Error opening log file ({}), for writing", log_file_path.as_ref().to_string_lossy()));
|
||||
let fd = file.as_raw_fd();
|
||||
|
||||
if nix::unistd::isatty(1)? {
|
||||
|
|
|
@ -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>,
|
||||
b: T,
|
||||
) -> Vec<K> {
|
||||
b.into_iter()
|
||||
.filter_map(|(k, v)| a.insert(k.clone(), v).map(|_| k.clone()))
|
||||
.collect()
|
||||
b.into_iter().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
|
||||
|
@ -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();
|
||||
}
|
||||
ENV_VAR_PATTERN
|
||||
.replace_all(&input, |var_name: ®ex::Captures| {
|
||||
std::env::var(var_name.get(1).unwrap().as_str()).unwrap_or_default()
|
||||
})
|
||||
.replace_all(&input, |var_name: ®ex::Captures| std::env::var(var_name.get(1).unwrap().as_str()).unwrap_or_default())
|
||||
.into_owned()
|
||||
}
|
||||
|
||||
|
|
|
@ -94,18 +94,13 @@ impl AttrValueExpr {
|
|||
match self {
|
||||
Literal(x) => Ok(AttrValueExpr::Literal(x)),
|
||||
VarRef(ref name) => Ok(Literal(AttrValue::from_primitive(
|
||||
variables
|
||||
.get(name)
|
||||
.with_context(|| format!("Unknown variable {} referenced in {:?}", &name, &self))?
|
||||
.clone(),
|
||||
variables.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)?)),
|
||||
UnaryOp(op, box x) => Ok(UnaryOp(op, box x.resolve_refs(variables)?)),
|
||||
IfElse(box a, box b, box c) => Ok(IfElse(
|
||||
box a.resolve_refs(variables)?,
|
||||
box b.resolve_refs(variables)?,
|
||||
box c.resolve_refs(variables)?,
|
||||
)),
|
||||
IfElse(box a, box b, box c) => {
|
||||
Ok(IfElse(box a.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> {
|
||||
match self {
|
||||
AttrValueExpr::Literal(x) => x.resolve_fully(&values),
|
||||
AttrValueExpr::VarRef(ref name) => values.get(name).cloned().context(format!(
|
||||
"Got unresolved variable {} while trying to evaluate expression {:?}",
|
||||
&name, &self
|
||||
)),
|
||||
AttrValueExpr::VarRef(ref name) => values
|
||||
.get(name)
|
||||
.cloned()
|
||||
.context(format!("Got unresolved variable {} while trying to evaluate expression {:?}", &name, &self)),
|
||||
AttrValueExpr::BinOp(a, op, b) => {
|
||||
let a = a.eval(values)?;
|
||||
let b = b.eval(values)?;
|
||||
|
|
|
@ -28,10 +28,7 @@ fn parse_num(i: &str) -> IResult<&str, i32, VerboseError<&str>> {
|
|||
}
|
||||
|
||||
fn parse_stringlit(i: &str) -> IResult<&str, &str, VerboseError<&str>> {
|
||||
alt((
|
||||
delimited(tag("'"), take_while(|c| c != '\''), tag("'")),
|
||||
delimited(tag("\""), take_while(|c| c != '"'), tag("\"")),
|
||||
))(i)
|
||||
alt((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>> {
|
||||
|
@ -43,13 +40,9 @@ fn parse_literal(i: &str) -> IResult<&str, &str, VerboseError<&str>> {
|
|||
}
|
||||
|
||||
fn parse_identifier(i: &str) -> IResult<&str, &str, VerboseError<&str>> {
|
||||
verify(
|
||||
recognize(pair(
|
||||
alt((alpha1, tag("_"), tag("-"))),
|
||||
many0(alt((alphanumeric1, tag("_"), tag("-")))),
|
||||
)),
|
||||
|x| !["if", "then", "else"].contains(x),
|
||||
)(i)
|
||||
verify(recognize(pair(alt((alpha1, tag("_"), tag("-"))), many0(alt((alphanumeric1, tag("_"), tag("-")))))), |x| {
|
||||
!["if", "then", "else"].contains(x)
|
||||
})(i)
|
||||
}
|
||||
|
||||
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((
|
||||
context("expression", ws(delimited(tag("("), parse_expr, tag(")")))),
|
||||
context("if-expression", ws(parse_ifelse)),
|
||||
context(
|
||||
"literal",
|
||||
map(ws(parse_literal), |x| AttrValueExpr::Literal(AttrValue::parse_string(x))),
|
||||
),
|
||||
context(
|
||||
"identifier",
|
||||
map(ws(parse_identifier), |x| AttrValueExpr::VarRef(VarName(x.to_string()))),
|
||||
),
|
||||
context("literal", 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)?;
|
||||
Ok((
|
||||
i,
|
||||
|
@ -91,9 +78,7 @@ fn parse_term3(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
|||
map(preceded(tag("%"), parse_factor), |x| (BinOp::Mod, x)),
|
||||
)))(i)?;
|
||||
|
||||
let exprs = remainder
|
||||
.into_iter()
|
||||
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
|
||||
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)),
|
||||
)))(i)?;
|
||||
|
||||
let exprs = remainder
|
||||
.into_iter()
|
||||
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
|
||||
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)),
|
||||
)))(i)?;
|
||||
|
||||
let exprs = remainder
|
||||
.into_iter()
|
||||
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
|
||||
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)),
|
||||
)))(i)?;
|
||||
|
||||
let exprs = remainder
|
||||
.into_iter()
|
||||
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
|
||||
Ok((i, exprs))
|
||||
}
|
||||
|
@ -161,10 +140,7 @@ mod test {
|
|||
use pretty_assertions::assert_eq;
|
||||
#[test]
|
||||
fn test_parser() {
|
||||
assert_eq!(
|
||||
AttrValueExpr::Literal(AttrValue::from_primitive("12")),
|
||||
AttrValueExpr::parse("12").unwrap()
|
||||
);
|
||||
assert_eq!(AttrValueExpr::Literal(AttrValue::from_primitive("12")), AttrValueExpr::parse("12").unwrap());
|
||||
assert_eq!(
|
||||
AttrValueExpr::UnaryOp(UnaryOp::Not, box AttrValueExpr::Literal(AttrValue::from_primitive("false"))),
|
||||
AttrValueExpr::parse("!false").unwrap()
|
||||
|
|
|
@ -69,10 +69,7 @@ impl fmt::Debug for Coords {
|
|||
|
||||
impl Coords {
|
||||
pub fn from_pixels(x: i32, y: i32) -> Self {
|
||||
Coords {
|
||||
x: NumWithUnit::Pixels(x),
|
||||
y: NumWithUnit::Pixels(y),
|
||||
}
|
||||
Coords { x: NumWithUnit::Pixels(x), y: NumWithUnit::Pixels(y) }
|
||||
}
|
||||
|
||||
/// parse a string for x and a string for y into a [`Coords`] object.
|
||||
|
@ -104,13 +101,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_parse_coords() {
|
||||
assert_eq!(
|
||||
Coords {
|
||||
x: NumWithUnit::Pixels(50),
|
||||
y: NumWithUnit::Pixels(60)
|
||||
},
|
||||
Coords::from_str("50x60").unwrap()
|
||||
);
|
||||
assert_eq!(Coords { x: NumWithUnit::Pixels(50), y: NumWithUnit::Pixels(60) }, Coords::from_str("50x60").unwrap());
|
||||
assert!(Coords::from_str("5060").is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,21 +92,15 @@ impl PrimitiveValue {
|
|||
}
|
||||
|
||||
pub fn as_f64(&self) -> Result<f64> {
|
||||
self.0
|
||||
.parse()
|
||||
.map_err(|e| anyhow!("couldn't convert {:?} to f64: {}", &self, e))
|
||||
self.0.parse().map_err(|e| anyhow!("couldn't convert {:?} to f64: {}", &self, e))
|
||||
}
|
||||
|
||||
pub fn as_i32(&self) -> Result<i32> {
|
||||
self.0
|
||||
.parse()
|
||||
.map_err(|e| anyhow!("couldn't convert {:?} to i32: {}", &self, e))
|
||||
self.0.parse().map_err(|e| anyhow!("couldn't convert {:?} to i32: {}", &self, e))
|
||||
}
|
||||
|
||||
pub fn as_bool(&self) -> Result<bool> {
|
||||
self.0
|
||||
.parse()
|
||||
.map_err(|e| anyhow!("couldn't convert {:?} to bool: {}", &self, e))
|
||||
self.0.parse().map_err(|e| anyhow!("couldn't convert {:?} to bool: {}", &self, e))
|
||||
}
|
||||
|
||||
pub fn as_vec(&self) -> Result<Vec<String>> {
|
||||
|
@ -141,36 +135,21 @@ mod test {
|
|||
use pretty_assertions::assert_eq;
|
||||
#[test]
|
||||
fn test_parse_vec() {
|
||||
assert_eq!(
|
||||
vec![""],
|
||||
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!(vec![""], 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!(
|
||||
vec!["hi", "ho", "hu"],
|
||||
parse_vec("[hi,ho,hu]".to_string()).unwrap(),
|
||||
"should be able to parse three element list"
|
||||
);
|
||||
assert_eq!(
|
||||
vec!["hi,ho"],
|
||||
parse_vec("[hi\\,ho]".to_string()).unwrap(),
|
||||
"should be able to parse list with escaped comma"
|
||||
);
|
||||
assert_eq!(vec!["hi,ho"], parse_vec("[hi\\,ho]".to_string()).unwrap(), "should be able to parse list with escaped comma");
|
||||
assert_eq!(
|
||||
vec!["hi,ho", "hu"],
|
||||
parse_vec("[hi\\,ho,hu]".to_string()).unwrap(),
|
||||
"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("[a,b".to_string()).is_err(),
|
||||
"Should fail when parsing unclosed list"
|
||||
);
|
||||
assert!(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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,18 +64,13 @@ fn build_builtin_gtk_widget(
|
|||
widget_definitions: &HashMap<String, WidgetDefinition>,
|
||||
widget: &widget_node::Generic,
|
||||
) -> Result<Option<gtk::Widget>> {
|
||||
let mut bargs = BuilderArgs {
|
||||
eww_state,
|
||||
widget,
|
||||
window_name,
|
||||
unhandled_attrs: widget.attrs.keys().collect(),
|
||||
widget_definitions,
|
||||
};
|
||||
let mut bargs =
|
||||
BuilderArgs { eww_state, widget, window_name, unhandled_attrs: widget.attrs.keys().collect(), widget_definitions };
|
||||
let gtk_widget = match widget_to_gtk_widget(&mut bargs) {
|
||||
Ok(Some(gtk_widget)) => gtk_widget,
|
||||
result => {
|
||||
return result.with_context(|| {
|
||||
anyhow!(
|
||||
format!(
|
||||
"{}Error building widget {}",
|
||||
bargs.widget.text_pos.map(|x| format!("{} |", x)).unwrap_or_default(),
|
||||
bargs.widget.name,
|
||||
|
@ -89,9 +84,7 @@ fn build_builtin_gtk_widget(
|
|||
if let Some(gtk_widget) = gtk_widget.dynamic_cast_ref::<gtk::Container>() {
|
||||
resolve_container_attrs(&mut bargs, >k_widget);
|
||||
for child in &widget.children {
|
||||
let child_widget = child
|
||||
.render(bargs.eww_state, window_name, widget_definitions)
|
||||
.with_context(|| {
|
||||
let child_widget = child.render(bargs.eww_state, window_name, widget_definitions).with_context(|| {
|
||||
format!(
|
||||
"{}error while building child '{:#?}' of '{}'",
|
||||
widget.text_pos.map(|x| format!("{} |", x)).unwrap_or_default(),
|
||||
|
|
|
@ -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(),
|
||||
"combo-box-text" => build_gtk_combo_box_text(bargs)?.upcast(),
|
||||
"checkbox" => build_gtk_checkbox(bargs)?.upcast(),
|
||||
|
||||
"if-else" => build_if_else(bargs)?.upcast(),
|
||||
_ => return Ok(None),
|
||||
};
|
||||
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: >k::Widget) {
|
||||
let css_provider = gtk::CssProvider::new();
|
||||
|
||||
if let Ok(visible) = bargs
|
||||
.widget
|
||||
.get_attr("visible")
|
||||
.and_then(|v| bargs.eww_state.resolve_once(v)?.as_bool())
|
||||
{
|
||||
if let Ok(visible) = bargs.widget.get_attr("visible").and_then(|v| bargs.eww_state.resolve_once(v)?.as_bool()) {
|
||||
connect_first_map(gtk_widget, move |w| {
|
||||
if visible {
|
||||
w.show();
|
||||
|
@ -161,6 +157,29 @@ pub(super) fn resolve_orientable_attrs(bargs: &mut BuilderArgs, gtk_widget: >k
|
|||
|
||||
// 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
|
||||
/// @desc A combo box allowing the user to choose between several items.
|
||||
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
|
||||
/// @desc A slider.
|
||||
fn build_gtk_scale(bargs: &mut BuilderArgs) -> Result<gtk::Scale> {
|
||||
let gtk_widget = gtk::Scale::new(
|
||||
gtk::Orientation::Horizontal,
|
||||
Some(>k::Adjustment::new(0.0, 0.0, 100.0, 1.0, 1.0, 1.0)),
|
||||
);
|
||||
let gtk_widget = gtk::Scale::new(gtk::Orientation::Horizontal, Some(>k::Adjustment::new(0.0, 0.0, 100.0, 1.0, 1.0, 1.0)));
|
||||
resolve_block!(bargs, gtk_widget, {
|
||||
// @prop flipped - flip the direction
|
||||
prop(flipped: as_bool) { gtk_widget.set_inverted(flipped) },
|
||||
|
@ -472,10 +488,7 @@ fn parse_orientation(o: &str) -> Result<gtk::Orientation> {
|
|||
Ok(match o {
|
||||
"vertical" | "v" => gtk::Orientation::Vertical,
|
||||
"horizontal" | "h" => gtk::Orientation::Horizontal,
|
||||
_ => bail!(
|
||||
r#"Couldn't parse orientation: '{}'. Possible values are "vertical", "v", "horizontal", "h""#,
|
||||
o
|
||||
),
|
||||
_ => bail!(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,
|
||||
"start" => gtk::Align::Start,
|
||||
"end" => gtk::Align::End,
|
||||
_ => bail!(
|
||||
r#"Couldn't parse alignment: '{}'. Possible values are "fill", "baseline", "center", "start", "end""#,
|
||||
o
|
||||
),
|
||||
_ => bail!(r#"Couldn't parse alignment: '{}'. Possible values are "fill", "baseline", "center", "start", "end""#, o),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -66,9 +66,7 @@ pub struct Generic {
|
|||
|
||||
impl Generic {
|
||||
pub fn get_attr(&self, key: &str) -> Result<&AttrValue> {
|
||||
self.attrs
|
||||
.get(key)
|
||||
.context(format!("attribute '{}' missing from use of '{}'", key, &self.name))
|
||||
self.attrs.get(key).context(format!("attribute '{}' missing from use of '{}'", key, &self.name))
|
||||
}
|
||||
|
||||
/// returns all the variables that are referenced in this widget
|
||||
|
@ -92,10 +90,8 @@ impl WidgetNode for Generic {
|
|||
window_name: &WindowName,
|
||||
widget_definitions: &HashMap<String, WidgetDefinition>,
|
||||
) -> Result<gtk::Widget> {
|
||||
Ok(
|
||||
crate::widgets::build_builtin_gtk_widget(eww_state, window_name, widget_definitions, &self)?
|
||||
.with_context(|| format!("Unknown widget '{}'", self.get_name()))?,
|
||||
)
|
||||
Ok(crate::widgets::build_builtin_gtk_widget(eww_state, window_name, widget_definitions, &self)?
|
||||
.with_context(|| format!("Unknown widget '{}'", self.get_name()))?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,20 +110,12 @@ pub fn generate_generic_widget_node(
|
|||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let content = generate_generic_widget_node(defs, &new_local_env, def.structure.clone())?;
|
||||
Ok(Box::new(UserDefined {
|
||||
name: w.name,
|
||||
text_pos: w.text_pos,
|
||||
content,
|
||||
}))
|
||||
Ok(Box::new(UserDefined { name: w.name, text_pos: w.text_pos, content }))
|
||||
} else {
|
||||
Ok(Box::new(Generic {
|
||||
name: w.name,
|
||||
text_pos: w.text_pos,
|
||||
attrs: w
|
||||
.attrs
|
||||
.into_iter()
|
||||
.map(|(name, value)| (name, value.resolve_one_level(local_env)))
|
||||
.collect(),
|
||||
attrs: w.attrs.into_iter().map(|(name, value)| (name, value.resolve_one_level(local_env))).collect(),
|
||||
children: w
|
||||
.children
|
||||
.into_iter()
|
||||
|
|
Loading…
Add table
Reference in a new issue