Claude optimisations
Rust / build (push) Canceled after 0s

This commit is contained in:
Martin Bley
2026-09-11 18:32:46 +02:00
parent 4d6ada502d
commit dfb2fee6ea
3 changed files with 158 additions and 133 deletions
Generated
+29 -4
View File
@@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "ansi_term"
version = "0.11.0"
@@ -83,15 +85,15 @@ name = "i3status-custom-pim"
version = "0.1.0"
dependencies = [
"chrono",
"json",
"serde_json",
"structopt",
]
[[package]]
name = "json"
version = "0.12.4"
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "lazy_static"
@@ -166,6 +168,29 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
name = "serde"
version = "1.0.185"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31"
[[package]]
name = "serde_json"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "strsim"
version = "0.8.0"
+1 -1
View File
@@ -10,4 +10,4 @@ edition = "2018"
[dependencies]
structopt = "0.3"
chrono = "0.4"
json = "0.12.4"
serde_json = "1.0"
+106 -106
View File
@@ -1,6 +1,6 @@
use chrono::{Local, NaiveDateTime, NaiveTime};
use serde_json::json;
use std::process;
use std::process::Command;
use structopt::StructOpt;
#[derive(Debug, StructOpt)]
@@ -42,150 +42,150 @@ enum Status {
Critical,
}
fn get_status(events: Vec<NaiveDateTime>, w: i64, c: i64) -> Result<Status, String> {
let now = Local::now();
let mut event_remaining: i64 = 365 * 24 * 60;
let mut state = Status::Idle;
impl Status {
fn as_str(&self) -> &str {
match self {
Status::Idle => "Idle",
Status::Warning => "Warning",
Status::Critical => "Critical",
}
}
}
for e in events.iter() {
let diff = *e - now.naive_local();
if (diff.num_minutes() < event_remaining) && (diff.num_minutes() >= 0) {
event_remaining = diff.num_minutes()
}
fn get_status(events: Vec<NaiveDateTime>, warn: i64, crit: i64) -> Status {
let now = Local::now().naive_local();
if event_remaining >= 0 {
if event_remaining <= w {
state = Status::Warning;
let nearest = events
.into_iter()
.filter_map(|e| {
let diff = e.signed_duration_since(now).num_minutes();
if diff >= 0 {
Some(diff)
} else {
None
}
if event_remaining <= c {
state = Status::Critical;
})
.min()
.unwrap_or(365 * 24 * 60);
if nearest <= crit {
Status::Critical
} else if nearest <= warn {
Status::Warning
} else {
Status::Idle
}
}
}
Ok(state)
}
fn run_command(cmd: &str, args: &[&str]) -> Result<String, String> {
std::process::Command::new(cmd)
.args(args)
.output()
.map_err(|e| format!("Error running {}: {}", cmd, e))
.and_then(|output| {
String::from_utf8(output.stdout)
.map_err(|e| format!("Converting output failed: {}", e))
})
}
fn output_json(icon: &str, state: &Status, count: usize) {
println!(
"{}",
json!({
"icon": icon,
"state": state.as_str(),
"text": count.to_string()
})
);
}
fn main() {
let args = Cli::from_args();
if (!args.khal && !args.todo) || (args.khal && args.todo) {
eprintln!("Please provide either khal or todo flag.");
let mode_count = (args.khal as i32) + (args.todo as i32);
if mode_count != 1 {
eprintln!("Please provide either --khal or --todo flag (not both, not none).");
Cli::clap().print_help().unwrap();
println!();
process::exit(1);
}
if args.khal {
handle_khal(&args);
} else {
handle_todo(&args);
}
}
fn handle_khal(args: &Cli) {
let now = Local::now().time();
let from = now.format("%H:%M").to_string();
if args.khal {
let cmd = Command::new("khal")
.arg("list")
.arg("-df")
.arg("{name}")
.arg("-f")
.arg("{start-time}")
.arg("--notstarted")
.arg(&from)
.arg("23:59")
.output();
let stdout = match cmd {
Ok(o) => o.stdout,
Err(e) => {
eprintln!("Error running khal: {}", e);
process::exit(1);
}
};
let output = match String::from_utf8(stdout) {
let output = match run_command(
"khal",
&["list", "-df", "{name}", "-f", "{start-time}", "--notstarted", &from, "23:59"],
) {
Ok(o) => o,
Err(e) => {
eprintln!("Converting output failed: {}", e);
process::exit(1);
}
};
let mut out_iter = output.lines();
let dayline = match out_iter.nth(0) {
Some(d) => d,
None => { "None" }
};
let today = Local::today();
let mut events: Vec<NaiveDateTime> = Vec::new();
if dayline.trim() == "Today" {
for e in out_iter {
let event_start = match NaiveTime::parse_from_str(e, "%H:%M") {
Ok(s) => s,
Err(_f) => {
continue;
}
};
events.push(today.and_time(event_start).unwrap().naive_local());
}
}
let count = events.len();
let state = match get_status(events, args.threshold_warn, args.threshold_crit) {
Ok(s) => s,
Err(e) => {
eprintln!("{}", e);
process::exit(1);
}
};
println!(
"{{ \"icon\": \"{}\", \"state\": \"{:?}\", \"text\": \"{}\" }}",
args.icon, state, count
);
} else if args.todo {
let cmd = Command::new("todo").arg("--porcelain").output();
let mut lines = output.lines();
let is_today = matches!(lines.next(), Some("Today"));
let stdout = match cmd {
Ok(o) => o.stdout,
Err(e) => {
eprintln!("Error running todo: {}", e);
process::exit(1);
if !is_today {
output_json(&args.icon, &Status::Idle, 0);
return;
}
};
let output = match String::from_utf8(stdout) {
let today = Local::today();
let events: Vec<NaiveDateTime> = lines
.filter_map(|line| {
NaiveTime::parse_from_str(line.trim(), "%H:%M")
.ok()
.and_then(|time| today.and_time(time))
.map(|dt| dt.naive_local())
})
.collect();
let count = events.len();
let state = get_status(events, args.threshold_warn, args.threshold_crit);
output_json(&args.icon, &state, count);
}
fn handle_todo(args: &Cli) {
let output = match run_command("todo", &["--porcelain"]) {
Ok(o) => o,
Err(e) => {
eprintln!("Converting output failed: {}", e);
eprintln!("{}", e);
process::exit(1);
}
};
let parsed = match json::parse(&output) {
let parsed = match serde_json::from_str::<Vec<serde_json::Value>>(&output) {
Ok(p) => p,
Err(e) => {
eprintln!("parsing JSON failed: {}", e);
eprintln!("Parsing JSON failed: {}", e);
process::exit(1);
}
};
let count = parsed.len();
//println!("{:#?}", count);
let mut tasks: Vec<NaiveDateTime> = Vec::new();
for due in parsed.members() {
tasks.push(NaiveDateTime::from_timestamp(
due["due"].as_i64().unwrap(),
0,
));
}
let state = match get_status(tasks, args.threshold_warn, args.threshold_crit) {
Ok(s) => s,
Err(e) => {
eprintln!("{}", e);
process::exit(1);
}
};
println!(
"{{ \"icon\": \"{}\", \"state\": \"{:?}\", \"text\": \"{}\" }}",
args.icon, state, count
);
}
let tasks: Vec<NaiveDateTime> = parsed
.iter()
.filter_map(|due| {
due.get("due")
.and_then(|v| v.as_i64())
.map(|ts| NaiveDateTime::from_timestamp(ts, 0))
})
.collect();
let state = get_status(tasks, args.threshold_warn, args.threshold_crit);
output_json(&args.icon, &state, count);
}