Skip to content

Commit

Permalink
feat: add notification widget
Browse files Browse the repository at this point in the history
  • Loading branch information
dj95 committed Mar 17, 2024
1 parent cd3700c commit 0633ef8
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 6 deletions.
11 changes: 7 additions & 4 deletions plugin-dev-workspace.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ layout {

pane size=2 borderless=true {
plugin location="file:target/wasm32-wasi/debug/zjstatus.wasm" {
format_left "{mode} #[fg=#89B4FA,bg=#181825,bold]{session} {tabs} "
format_left "{mode}#[fg=#89B4FA,bg=#181825,bold] {session} {tabs}"
format_center "{command_0} {command_1} {command_git_branch} {command_3}"
format_right "{tabs} {datetime}"
format_right "{notifications}{datetime}"
format_space "#[bg=#181825]"

// foo
notification_format_unread "#[fg=#89B4FA,bg=#181825,blink]  #[fg=#89B4FA,bg=#181825] {message} "
notification_format_no_notifications "#[fg=#89B4FA,bg=#181825,dim]  "
notification_show_interval "10"

border_enabled "true"
border_char "─"
border_format "#[fg=#6C7086]{char}"
Expand All @@ -36,7 +39,7 @@ layout {
command_0_interval "1"

command_1_command "date"
command_1_format "#[fg=blue,reverse,dashed-underscore,bg=default,us=red,blink,dim,strikethrough] {exit_code} {stdout} "
command_1_format "#[fg=blue,reverse,bg=default,us=red,blink,dim,strikethrough] {exit_code} {stdout} "
command_1_interval "1"

command_git_branch_command "git rev-parse --abbrev-ref HEAD"
Expand Down
7 changes: 7 additions & 0 deletions src/bin/zjstatus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ impl ZellijPlugin for State {
sessions: Vec::new(),
start_time: Local::now(),
cache_mask: 0,
incoming_notification: None,
};
}

Expand Down Expand Up @@ -286,6 +287,12 @@ fn register_widgets(configuration: &BTreeMap<String, String>) -> BTreeMap<String
Arc::new(SessionWidget::new(configuration)),
);
widget_map.insert("tabs".to_owned(), Arc::new(TabsWidget::new(configuration)));
widget_map.insert(
"notifications".to_owned(),
Arc::new(widgets::notification::NotificationWidget::new(
configuration,
)),
);

tracing::debug!("registered widgets: {:?}", widget_map.keys());

Expand Down
4 changes: 3 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use zellij_tile::prelude::*;
use crate::{
border::{parse_border_config, BorderConfig, BorderPosition},
render::FormattedPart,
widgets::{command::CommandResult, widget::Widget},
widgets::{command::CommandResult, notification, widget::Widget},
};
use chrono::{DateTime, Local};

Expand All @@ -20,6 +20,7 @@ pub struct ZellijState {
pub tabs: Vec<TabInfo>,
pub sessions: Vec<SessionInfo>,
pub start_time: DateTime<Local>,
pub incoming_notification: Option<notification::Message>,
pub cache_mask: u8,
}

Expand All @@ -37,6 +38,7 @@ pub fn event_mask_from_widget_name(name: &str) -> u8 {
"command" => UpdateEventMask::Always as u8,
"datetime" => UpdateEventMask::Always as u8,
"mode" => UpdateEventMask::Mode as u8,
"notifications" => UpdateEventMask::Always as u8,
"session" => UpdateEventMask::Session as u8,
"swap_layout" => UpdateEventMask::Tab as u8,
"tabs" => UpdateEventMask::Tab as u8,
Expand Down
22 changes: 21 additions & 1 deletion src/pipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use std::ops::Sub;

use chrono::{Duration, Local};

use crate::{config::ZellijState, widgets::command::TIMESTAMP_FORMAT};
use crate::{
config::ZellijState,
widgets::{command::TIMESTAMP_FORMAT, notification},
};

/// Parses the line protocol and updates the state accordingly
///
Expand All @@ -20,7 +23,9 @@ use crate::{config::ZellijState, widgets::command::TIMESTAMP_FORMAT};
///
/// The function returns a boolean indicating whether the state has been
/// changed and the UI should be re-rendered.
#[tracing::instrument(skip(state))]
pub fn parse_protocol(state: &mut ZellijState, input: &str) -> bool {
tracing::debug!("parsing protocol");
let lines = input.split('\n').collect::<Vec<&str>>();

let mut should_render = false;
Expand All @@ -35,6 +40,7 @@ pub fn parse_protocol(state: &mut ZellijState, input: &str) -> bool {
should_render
}

#[tracing::instrument(skip_all)]
fn process_line(state: &mut ZellijState, line: &str) -> bool {
let parts = line.split("::").collect::<Vec<&str>>();

Expand All @@ -46,6 +52,8 @@ fn process_line(state: &mut ZellijState, line: &str) -> bool {
return false;
}

tracing::debug!("command: {}", parts[1]);

let mut should_render = false;
#[allow(clippy::single_match)]
match parts[1] {
Expand All @@ -54,12 +62,24 @@ fn process_line(state: &mut ZellijState, line: &str) -> bool {

should_render = true;
}
"notify" => {
notify(state, parts[2]);

should_render = true;
}
_ => {}
}

should_render
}

fn notify(state: &mut ZellijState, message: &str) {
state.incoming_notification = Some(notification::Message {
body: message.to_string(),
received_at: Local::now(),
});
}

fn rerun_command(state: &mut ZellijState, command_name: &str) {
let command_result = state.command_results.get(command_name);

Expand Down
1 change: 1 addition & 0 deletions src/widgets/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod command;
pub mod datetime;
pub mod mode;
pub mod notification;
pub mod swap_layout;
pub mod session;
pub mod tabs;
Expand Down
78 changes: 78 additions & 0 deletions src/widgets/notification.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use std::collections::BTreeMap;

use chrono::{DateTime, Local};

use crate::render::FormattedPart;
use crate::{config::ZellijState, widgets::widget::Widget};

#[derive(Clone, Debug, Default)]
pub struct Message {
pub body: String,
pub received_at: DateTime<Local>,
}

pub struct NotificationWidget {
show_interval: i64,
format_unread: Vec<FormattedPart>,
format_no_notifications: Vec<FormattedPart>,
}

impl NotificationWidget {
pub fn new(config: &BTreeMap<String, String>) -> Self {
let format_unread = match config.get("notification_format_unread") {
Some(f) => FormattedPart::multiple_from_format_string(f),
None => FormattedPart::multiple_from_format_string(""),
};

let format_no_notifications = match config.get("notification_format_no_notifications") {
Some(f) => FormattedPart::multiple_from_format_string(f),
None => FormattedPart::multiple_from_format_string(""),
};

let show_interval = match config.get("notification_show_interval") {
Some(i) => i.parse::<i64>().unwrap_or(5),
None => 5,
};

Self {
show_interval,
format_unread,
format_no_notifications,
}
}
}

impl Widget for NotificationWidget {
fn process(&self, _name: &str, state: &ZellijState) -> String {
let message = match state.incoming_notification {
Some(ref message) => message.clone(),
None => Message::default(),
};

let no_new =
message.received_at.timestamp() + self.show_interval < Local::now().timestamp();

tracing::debug!("no_new: {}", no_new);

let format = match no_new {
true => self.format_no_notifications.clone(),
false => self.format_unread.clone(),
};

let mut output = "".to_owned();

for f in format.iter() {
let mut content = f.content.clone();

if content.contains("{message}") {
content = content.replace("{message}", message.body.as_str());
}

output = format!("{}{}", output, f.format_string(&content));
}

output.to_owned()
}

fn process_click(&self, _state: &ZellijState, _pos: usize) {}
}

0 comments on commit 0633ef8

Please sign in to comment.