parent
6a204e619e
commit
061c3589ac
11 changed files with 636 additions and 48 deletions
@ -0,0 +1,58 @@ |
|||||||
|
// Copyright (C) 2022 Tassilo Horn <tsdh@gnu.org>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the Free
|
||||||
|
// Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
// more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! `swayrbar` lib.
|
||||||
|
|
||||||
|
use crate::bar::module::BarModuleFn; |
||||||
|
use env_logger::Env; |
||||||
|
use serde_json; |
||||||
|
use std::thread; |
||||||
|
|
||||||
|
pub mod module; |
||||||
|
|
||||||
|
pub fn start() { |
||||||
|
env_logger::Builder::from_env(Env::default().default_filter_or("warn")) |
||||||
|
.init(); |
||||||
|
|
||||||
|
thread::spawn(handle_input); |
||||||
|
let mods: Vec<Box<dyn BarModuleFn>> = vec![ |
||||||
|
crate::bar::module::window::BarModuleWindow::init(), |
||||||
|
crate::bar::module::sysinfo::BarModuleSysInfo::init(), |
||||||
|
crate::bar::module::date::BarModuleDate::init(), |
||||||
|
]; |
||||||
|
generate_status(&mods); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn handle_input() { |
||||||
|
// TODO: Read stdin and react to click events.
|
||||||
|
} |
||||||
|
|
||||||
|
pub fn generate_status(mods: &[Box<dyn BarModuleFn>]) { |
||||||
|
println!("{{\"version\": 1}}"); |
||||||
|
// status_command should output an infinite array meaning we emit an
|
||||||
|
// opening [ and never the closing bracket.
|
||||||
|
println!("["); |
||||||
|
|
||||||
|
loop { |
||||||
|
let mut blocks = vec![]; |
||||||
|
for m in mods { |
||||||
|
blocks.push(m.build()); |
||||||
|
} |
||||||
|
let json = serde_json::to_string_pretty(&blocks) |
||||||
|
.unwrap_or_else(|_| "".to_string()); |
||||||
|
println!("{},", json); |
||||||
|
thread::sleep(std::time::Duration::from_secs(1)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
// Copyright (C) 2022 Tassilo Horn <tsdh@gnu.org>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the Free
|
||||||
|
// Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
// more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use swaybar_types as s; |
||||||
|
|
||||||
|
pub mod date; |
||||||
|
pub mod sysinfo; |
||||||
|
pub mod window; |
||||||
|
|
||||||
|
pub trait BarModuleFn { |
||||||
|
fn init() -> Box<dyn BarModuleFn> |
||||||
|
where |
||||||
|
Self: Sized; |
||||||
|
fn name() -> String |
||||||
|
where |
||||||
|
Self: Sized; |
||||||
|
fn instance(&self) -> String; |
||||||
|
fn build(&self) -> s::Block; |
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
// Copyright (C) 2022 Tassilo Horn <tsdh@gnu.org>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the Free
|
||||||
|
// Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
// more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! The date `swayrbar` module.
|
||||||
|
|
||||||
|
use crate::bar::module::BarModuleFn; |
||||||
|
use swaybar_types as s; |
||||||
|
|
||||||
|
pub struct BarModuleDate { |
||||||
|
pub instance: String, |
||||||
|
} |
||||||
|
|
||||||
|
impl BarModuleFn for BarModuleDate { |
||||||
|
fn init() -> Box<dyn BarModuleFn> { |
||||||
|
Box::new(BarModuleDate { |
||||||
|
instance: "0".to_string(), |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn name() -> String { |
||||||
|
String::from("date") |
||||||
|
} |
||||||
|
|
||||||
|
fn instance(&self) -> String { |
||||||
|
self.instance.clone() |
||||||
|
} |
||||||
|
|
||||||
|
fn build(&self) -> s::Block { |
||||||
|
let d = chrono::Local::now().format("%F %X").to_string(); |
||||||
|
s::Block { |
||||||
|
name: Some(Self::name()), |
||||||
|
instance: Some(self.instance.clone()), |
||||||
|
full_text: d, |
||||||
|
align: Some(s::Align::Right), |
||||||
|
markup: Some(s::Markup::Pango), |
||||||
|
short_text: None, |
||||||
|
color: None, |
||||||
|
background: None, |
||||||
|
border: None, |
||||||
|
border_top: None, |
||||||
|
border_bottom: None, |
||||||
|
border_left: None, |
||||||
|
border_right: None, |
||||||
|
min_width: None, |
||||||
|
urgent: None, |
||||||
|
separator: None, |
||||||
|
separator_block_width: None, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,71 @@ |
|||||||
|
// Copyright (C) 2022 Tassilo Horn <tsdh@gnu.org>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the Free
|
||||||
|
// Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
// more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! The date `swayrbar` module.
|
||||||
|
|
||||||
|
use crate::bar::module::BarModuleFn; |
||||||
|
use std::cell::RefCell; |
||||||
|
use swaybar_types as s; |
||||||
|
use sysinfo; |
||||||
|
use sysinfo::SystemExt; |
||||||
|
|
||||||
|
pub struct BarModuleSysInfo { |
||||||
|
pub instance: String, |
||||||
|
system: RefCell<sysinfo::System>, |
||||||
|
} |
||||||
|
|
||||||
|
impl BarModuleFn for BarModuleSysInfo { |
||||||
|
fn init() -> Box<dyn BarModuleFn> { |
||||||
|
Box::new(BarModuleSysInfo { |
||||||
|
instance: "0".to_string(), |
||||||
|
system: RefCell::new(sysinfo::System::new_all()), |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn name() -> String { |
||||||
|
String::from("sysinfo") |
||||||
|
} |
||||||
|
|
||||||
|
fn instance(&self) -> String { |
||||||
|
self.instance.clone() |
||||||
|
} |
||||||
|
|
||||||
|
fn build(&self) -> s::Block { |
||||||
|
let x = String::from("{cpu_usage_avg}"); |
||||||
|
self.system.borrow_mut().refresh_specifics( |
||||||
|
sysinfo::RefreshKind::new().with_cpu().with_memory(), |
||||||
|
); |
||||||
|
|
||||||
|
s::Block { |
||||||
|
name: Some(Self::name()), |
||||||
|
instance: Some(self.instance.clone()), |
||||||
|
full_text: x, |
||||||
|
align: Some(s::Align::Right), |
||||||
|
markup: Some(s::Markup::Pango), |
||||||
|
short_text: None, |
||||||
|
color: None, |
||||||
|
background: None, |
||||||
|
border: None, |
||||||
|
border_top: None, |
||||||
|
border_bottom: None, |
||||||
|
border_left: None, |
||||||
|
border_right: None, |
||||||
|
min_width: None, |
||||||
|
urgent: None, |
||||||
|
separator: None, |
||||||
|
separator_block_width: None, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,105 @@ |
|||||||
|
// Copyright (C) 2022 Tassilo Horn <tsdh@gnu.org>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the Free
|
||||||
|
// Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
// more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! The window `swayrbar` module.
|
||||||
|
|
||||||
|
use crate::bar::module::BarModuleFn; |
||||||
|
use std::cell::RefCell; |
||||||
|
use swaybar_types as s; |
||||||
|
use swayipc as ipc; |
||||||
|
|
||||||
|
pub struct NodeIter<'a> { |
||||||
|
stack: Vec<&'a ipc::Node>, |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a> NodeIter<'a> { |
||||||
|
fn new(node: &'a ipc::Node) -> NodeIter { |
||||||
|
NodeIter { stack: vec![node] } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a> Iterator for NodeIter<'a> { |
||||||
|
type Item = &'a ipc::Node; |
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> { |
||||||
|
if let Some(node) = self.stack.pop() { |
||||||
|
for n in &node.floating_nodes { |
||||||
|
self.stack.push(n); |
||||||
|
} |
||||||
|
for n in &node.nodes { |
||||||
|
self.stack.push(n); |
||||||
|
} |
||||||
|
Some(node) |
||||||
|
} else { |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct BarModuleWindow { |
||||||
|
pub instance: String, |
||||||
|
connection: RefCell<swayipc::Connection>, |
||||||
|
} |
||||||
|
|
||||||
|
impl BarModuleFn for BarModuleWindow { |
||||||
|
fn init() -> Box<dyn BarModuleFn> { |
||||||
|
Box::new(BarModuleWindow { |
||||||
|
instance: "0".to_string(), |
||||||
|
connection: RefCell::new( |
||||||
|
ipc::Connection::new() |
||||||
|
.expect("Couldn't get a sway IPC connection"), |
||||||
|
), |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn name() -> String { |
||||||
|
String::from("window") |
||||||
|
} |
||||||
|
|
||||||
|
fn instance(&self) -> String { |
||||||
|
self.instance.clone() |
||||||
|
} |
||||||
|
|
||||||
|
fn build(&self) -> s::Block { |
||||||
|
let x: String = match self.connection.borrow_mut().get_tree() { |
||||||
|
Ok(root) => { |
||||||
|
let o: Option<&ipc::Node> = |
||||||
|
NodeIter::new(&root).find(|n| n.focused); |
||||||
|
o.map(|w| w.name.clone().unwrap_or_default()) |
||||||
|
.unwrap_or_else(String::new) |
||||||
|
} |
||||||
|
Err(err) => format!("{}", err), |
||||||
|
}; |
||||||
|
s::Block { |
||||||
|
name: Some(Self::name()), |
||||||
|
instance: Some(self.instance.clone()), |
||||||
|
full_text: x, |
||||||
|
align: Some(s::Align::Right), |
||||||
|
markup: Some(s::Markup::Pango), |
||||||
|
short_text: None, |
||||||
|
color: None, |
||||||
|
background: None, |
||||||
|
border: None, |
||||||
|
border_top: None, |
||||||
|
border_bottom: None, |
||||||
|
border_left: None, |
||||||
|
border_right: None, |
||||||
|
min_width: None, |
||||||
|
urgent: None, |
||||||
|
separator: None, |
||||||
|
separator_block_width: None, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
// Copyright (C) 2022 Tassilo Horn <tsdh@gnu.org>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the Free
|
||||||
|
// Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
// more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! The `swayrbar` binary.
|
||||||
|
|
||||||
|
fn main() { |
||||||
|
// TODO: We need a config file cmd line option so that each bar can have
|
||||||
|
// its own config.
|
||||||
|
swayr::bar::start(); |
||||||
|
} |
@ -0,0 +1,71 @@ |
|||||||
|
// Copyright (C) 2022 Tassilo Horn <tsdh@gnu.org>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the Free
|
||||||
|
// Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
// more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use lazy_static::lazy_static; |
||||||
|
|
||||||
|
lazy_static! { |
||||||
|
pub static ref PLACEHOLDER_RX: regex::Regex = regex::Regex::new( |
||||||
|
r"\{(?P<name>[^}:]+)(?::(?P<fmtstr>\{[^}]*\})(?P<clipstr>[^}]*))?\}" |
||||||
|
) |
||||||
|
.unwrap(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn maybe_html_escape(do_it: bool, text: String) -> String { |
||||||
|
if do_it { |
||||||
|
text.replace('<', "<") |
||||||
|
.replace('>', ">") |
||||||
|
.replace('&', "&") |
||||||
|
} else { |
||||||
|
text |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
macro_rules! fmt_replace { |
||||||
|
( $fmt_str:expr, $html_escape:ident, |
||||||
|
{ $( $($pat:pat)|+ => $exp:expr, )+ } |
||||||
|
) => { |
||||||
|
$crate::fmt_replace::PLACEHOLDER_RX |
||||||
|
.replace_all($fmt_str, |caps: ®ex::Captures| { |
||||||
|
let value: String = match &caps["name"] { |
||||||
|
$( |
||||||
|
$( | $pat )+ => { |
||||||
|
let val = $exp; |
||||||
|
let fmt_str = caps.name("fmtstr") |
||||||
|
.map_or("{}", |m| m.as_str()); |
||||||
|
let clipped_str = caps.name("clipstr") |
||||||
|
.map_or("", |m| m.as_str()); |
||||||
|
$crate::fmt_replace::maybe_html_escape( |
||||||
|
$html_escape, |
||||||
|
crate::rtfmt::format(fmt_str, &val, clipped_str), |
||||||
|
) |
||||||
|
} |
||||||
|
)+ |
||||||
|
_ => caps[0].to_string(), |
||||||
|
}; |
||||||
|
value |
||||||
|
}).into() |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn foo() { |
||||||
|
let foo = "{a}, {b}"; |
||||||
|
let html_escape = true; |
||||||
|
let x: String = fmt_replace!(foo, html_escape, { |
||||||
|
"a" => "1".to_string(), |
||||||
|
"b" => "2".to_string(), |
||||||
|
"c" => "3".to_owned(), |
||||||
|
}); |
||||||
|
} |
Loading…
Reference in new issue