aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Jankowski <daniel.jankowski@rub.de>2025-01-18 09:32:18 +0100
committerDaniel Jankowski <daniel.jankowski@rub.de>2025-01-18 09:34:07 +0100
commitf73635159598119a67533fda394e49830506cd85 (patch)
tree78f3c2b0052af68d4bdcd8b31e548af613d34814 /src
parentchore: update cargo deps (diff)
downloadsl0pstatus-f73635159598119a67533fda394e49830506cd85.tar.gz
sl0pstatus-f73635159598119a67533fda394e49830506cd85.tar.xz
sl0pstatus-f73635159598119a67533fda394e49830506cd85.zip
feat: add pipe widget
Diffstat (limited to 'src')
-rw-r--r--src/bin/zjstatus.rs3
-rw-r--r--src/config.rs6
-rw-r--r--src/pipe.rs16
-rw-r--r--src/render.rs13
-rw-r--r--src/widgets/mod.rs1
-rw-r--r--src/widgets/pipe.rs97
6 files changed, 132 insertions, 4 deletions
diff --git a/src/bin/zjstatus.rs b/src/bin/zjstatus.rs
index 30a40b0..c4d5267 100644
--- a/src/bin/zjstatus.rs
+++ b/src/bin/zjstatus.rs
@@ -12,6 +12,7 @@ use zjstatus::{
datetime::DateTimeWidget,
mode::ModeWidget,
notification::NotificationWidget,
+ pipe::PipeWidget,
session::SessionWidget,
swap_layout::SwapLayoutWidget,
tabs::TabsWidget,
@@ -90,6 +91,7 @@ impl ZellijPlugin for State {
self.state = ZellijState {
cols: 0,
command_results: BTreeMap::new(),
+ pipe_results: BTreeMap::new(),
mode: ModeInfo::default(),
panes: PaneManifest::default(),
plugin_uuid: uid.to_string(),
@@ -307,6 +309,7 @@ fn register_widgets(configuration: &BTreeMap<String, String>) -> BTreeMap<String
"datetime".to_owned(),
Arc::new(DateTimeWidget::new(configuration)),
);
+ widget_map.insert("pipe".to_owned(), Arc::new(PipeWidget::new(configuration)));
widget_map.insert(
"swap_layout".to_owned(),
Arc::new(SwapLayoutWidget::new(configuration)),
diff --git a/src/config.rs b/src/config.rs
index f0befbb..0bb260d 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -15,6 +15,7 @@ use chrono::{DateTime, Local};
pub struct ZellijState {
pub cols: usize,
pub command_results: BTreeMap<String, CommandResult>,
+ pub pipe_results: BTreeMap<String, String>,
pub mode: ModeInfo,
pub panes: PaneManifest,
pub plugin_uuid: String,
@@ -63,6 +64,7 @@ pub fn event_mask_from_widget_name(name: &str) -> u8 {
"session" => UpdateEventMask::Mode as u8,
"swap_layout" => UpdateEventMask::Tab as u8,
"tabs" => UpdateEventMask::Tab as u8,
+ "pipe" => UpdateEventMask::Always as u8,
_ => UpdateEventMask::None as u8,
}
}
@@ -278,6 +280,10 @@ impl ModuleConfig {
widget_key_name = "command";
}
+ if widget_key.starts_with("pipe_") {
+ widget_key_name = "pipe";
+ }
+
if !tokens.contains(&widget_key_name.to_owned()) {
continue;
}
diff --git a/src/pipe.rs b/src/pipe.rs
index f88db89..38fea5d 100644
--- a/src/pipe.rs
+++ b/src/pipe.rs
@@ -67,12 +67,28 @@ fn process_line(state: &mut ZellijState, line: &str) -> bool {
should_render = true;
}
+ "pipe" => {
+ if parts.len() < 4 {
+ return false;
+ }
+
+ pipe(state, parts[2], parts[3]);
+
+ should_render = true;
+ }
_ => {}
}
should_render
}
+fn pipe(state: &mut ZellijState, name: &str, content: &str) {
+ tracing::debug!("saving pipe result {name} {content}");
+ state
+ .pipe_results
+ .insert(name.to_owned(), content.to_owned());
+}
+
fn notify(state: &mut ZellijState, message: &str) {
state.incoming_notification = Some(notification::Message {
body: message.to_string(),
diff --git a/src/render.rs b/src/render.rs
index a9f55ef..6ef0005 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -205,6 +205,10 @@ impl FormattedPart {
widget_key_name = "command";
}
+ if widget_key.starts_with("pipe_") {
+ widget_key_name = "pipe";
+ }
+
let widget_mask = event_mask_from_widget_name(widget_key_name);
let skip_widget_cache = widget_mask & UpdateEventMask::Always as u8 != 0;
if !skip_widget_cache && widget_mask & state.cache_mask == 0 {
@@ -278,6 +282,10 @@ fn cache_mask_from_content(content: &str) -> u8 {
widget_key_name = "command";
}
+ if widget_key.starts_with("pipe_") {
+ widget_key_name = "pipe";
+ }
+
output |= event_mask_from_widget_name(widget_key_name);
}
output
@@ -304,10 +312,7 @@ fn parse_color(color: &str, config: &BTreeMap<String, String>) -> Option<Color>
if color.starts_with('$') {
let alias_name = color.strip_prefix('$').unwrap();
- color = match config.get(&format!("color_{alias_name}")) {
- Some(color_str) => color_str,
- None => return None,
- };
+ color = config.get(&format!("color_{alias_name}"))?;
}
if color.starts_with('#') {
diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs
index edbf868..aa60cc3 100644
--- a/src/widgets/mod.rs
+++ b/src/widgets/mod.rs
@@ -2,6 +2,7 @@ pub mod command;
pub mod datetime;
pub mod mode;
pub mod notification;
+pub mod pipe;
pub mod session;
pub mod swap_layout;
pub mod tabs;
diff --git a/src/widgets/pipe.rs b/src/widgets/pipe.rs
new file mode 100644
index 0000000..f6acf1a
--- /dev/null
+++ b/src/widgets/pipe.rs
@@ -0,0 +1,97 @@
+use lazy_static::lazy_static;
+use regex::Regex;
+use std::collections::BTreeMap;
+
+use crate::render::FormattedPart;
+
+use super::widget::Widget;
+
+lazy_static! {
+ static ref PIPE_REGEX: Regex = Regex::new("_[a-zA-Z0-9]+$").unwrap();
+}
+
+pub struct PipeWidget {
+ config: BTreeMap<String, PipeConfig>,
+}
+
+#[derive(Clone)]
+struct PipeConfig {
+ format: Vec<FormattedPart>,
+}
+
+impl PipeWidget {
+ pub fn new(config: &BTreeMap<String, String>) -> Self {
+ Self {
+ config: parse_config(config),
+ }
+ }
+}
+
+impl Widget for PipeWidget {
+ fn process(&self, name: &str, state: &crate::config::ZellijState) -> String {
+ let pipe_config = match self.config.get(name) {
+ Some(pc) => pc,
+ None => {
+ tracing::debug!("pipe no name {name}");
+ return "".to_owned();
+ }
+ };
+
+ let pipe_result = match state.pipe_results.get(name) {
+ Some(pr) => pr,
+ None => {
+ tracing::debug!("pipe no content {name}");
+ return "".to_owned();
+ }
+ };
+
+ pipe_config
+ .format
+ .iter()
+ .map(|f| {
+ let mut content = f.content.clone();
+
+ if content.contains("{output}") {
+ content = content.replace(
+ "{output}",
+ pipe_result.strip_suffix('\n').unwrap_or(pipe_result),
+ )
+ }
+
+ (f, content)
+ })
+ .fold("".to_owned(), |acc, (f, content)| {
+ format!("{acc}{}", f.format_string(&content))
+ })
+ }
+
+ fn process_click(&self, _name: &str, _state: &crate::config::ZellijState, _pos: usize) {}
+}
+
+fn parse_config(zj_conf: &BTreeMap<String, String>) -> BTreeMap<String, PipeConfig> {
+ let mut keys: Vec<String> = zj_conf
+ .keys()
+ .filter(|k| k.starts_with("pipe_"))
+ .cloned()
+ .collect();
+ keys.sort();
+
+ let mut config: BTreeMap<String, PipeConfig> = BTreeMap::new();
+
+ for key in keys {
+ let pipe_name = PIPE_REGEX.replace(&key, "").to_string();
+ let mut pipe_conf = PipeConfig { format: vec![] };
+
+ if let Some(existing_conf) = config.get(pipe_name.as_str()) {
+ pipe_conf = existing_conf.clone();
+ }
+
+ if key.ends_with("format") {
+ pipe_conf.format =
+ FormattedPart::multiple_from_format_string(zj_conf.get(&key).unwrap(), zj_conf);
+ }
+
+ config.insert(pipe_name, pipe_conf);
+ }
+ config
+}