mirror of
https://github.com/MalteT/mensa.git
synced 2024-10-22 21:59:17 +02:00
parent
fcf81a71db
commit
ab9bd9801c
46
src/main.rs
46
src/main.rs
|
@ -63,10 +63,9 @@
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
use directories_next::ProjectDirs;
|
use directories_next::ProjectDirs;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use serde::Serialize;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use strum::IntoEnumIterator;
|
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
use unicode_width::UnicodeWidthStr;
|
|
||||||
|
|
||||||
/// Colorizes the output.
|
/// Colorizes the output.
|
||||||
///
|
///
|
||||||
|
@ -170,7 +169,9 @@ fn real_main() -> Result<()> {
|
||||||
let canteens = Canteen::fetch(&state)?;
|
let canteens = Canteen::fetch(&state)?;
|
||||||
Canteen::print_all(&state, &canteens);
|
Canteen::print_all(&state, &canteens);
|
||||||
}
|
}
|
||||||
Some(Command::Tags) => print_tags(&state),
|
Some(Command::Tags) => {
|
||||||
|
Tag::print_all(&state)?;
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
let cmd = MealsCommand::default();
|
let cmd = MealsCommand::default();
|
||||||
let state = State::from(state, &cmd);
|
let state = State::from(state, &cmd);
|
||||||
|
@ -181,38 +182,6 @@ fn real_main() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_tags<Cmd>(state: &State<Cmd>) {
|
|
||||||
for tag in Tag::iter() {
|
|
||||||
println!();
|
|
||||||
const ID_WIDTH: usize = 4;
|
|
||||||
const TEXT_INDENT: &str = " ";
|
|
||||||
let emoji = if state.args.plain && tag.is_primary() {
|
|
||||||
format!("{:>width$}", "-", width = ID_WIDTH)
|
|
||||||
} else {
|
|
||||||
let emoji = tag.as_id(state);
|
|
||||||
let emoji_len = emoji.width();
|
|
||||||
format!(
|
|
||||||
"{}{}",
|
|
||||||
" ".repeat(ID_WIDTH.saturating_sub(emoji_len)),
|
|
||||||
emoji
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let description_width = get_sane_terminal_dimensions().0;
|
|
||||||
let description = textwrap::fill(
|
|
||||||
tag.describe(),
|
|
||||||
textwrap::Options::new(description_width)
|
|
||||||
.initial_indent(TEXT_INDENT)
|
|
||||||
.subsequent_indent(TEXT_INDENT),
|
|
||||||
);
|
|
||||||
println!(
|
|
||||||
"{} {}\n{}",
|
|
||||||
color!(state: emoji; bright_yellow, bold),
|
|
||||||
color!(state: tag; bold),
|
|
||||||
color!(state: description; bright_black),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_sane_terminal_dimensions() -> (usize, usize) {
|
fn get_sane_terminal_dimensions() -> (usize, usize) {
|
||||||
terminal_size::terminal_size()
|
terminal_size::terminal_size()
|
||||||
.map(|(w, h)| (w.0 as usize, h.0 as usize))
|
.map(|(w, h)| (w.0 as usize, h.0 as usize))
|
||||||
|
@ -221,3 +190,10 @@ fn get_sane_terminal_dimensions() -> (usize, usize) {
|
||||||
.log_warn()
|
.log_warn()
|
||||||
.unwrap_or((80, 80))
|
.unwrap_or((80, 80))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_json<T: Serialize>(value: &T) -> Result<()> {
|
||||||
|
let stdout = std::io::stdout();
|
||||||
|
let output = stdout.lock();
|
||||||
|
serde_json::to_writer_pretty(output, value)
|
||||||
|
.map_err(|why| Error::Serializing(why, "writing meals as json"))
|
||||||
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ use std::collections::HashSet;
|
||||||
use crate::{
|
use crate::{
|
||||||
cache::fetch_json,
|
cache::fetch_json,
|
||||||
config::{args::MealsCommand, MealsState, PriceTags},
|
config::{args::MealsCommand, MealsState, PriceTags},
|
||||||
error::{pass_info, Error, Result},
|
error::{pass_info, Result},
|
||||||
get_sane_terminal_dimensions,
|
get_sane_terminal_dimensions, print_json,
|
||||||
tag::Tag,
|
tag::Tag,
|
||||||
State, ENDPOINT,
|
State, ENDPOINT,
|
||||||
};
|
};
|
||||||
|
@ -128,10 +128,7 @@ impl Meal {
|
||||||
let favs = state.get_favs_rule();
|
let favs = state.get_favs_rule();
|
||||||
let meals = meals.iter().filter(|meal| filter.is_match(meal));
|
let meals = meals.iter().filter(|meal| filter.is_match(meal));
|
||||||
if state.args.json {
|
if state.args.json {
|
||||||
let stdout = std::io::stdout();
|
print_json(&meals.collect::<Vec<_>>())
|
||||||
let output = stdout.lock();
|
|
||||||
serde_json::to_writer_pretty(output, &meals.collect::<Vec<_>>())
|
|
||||||
.map_err(|why| Error::Serializing(why, "writing meals as json"))
|
|
||||||
} else {
|
} else {
|
||||||
for meal in meals {
|
for meal in meals {
|
||||||
let is_fav = favs.is_match(meal);
|
let is_fav = favs.is_match(meal);
|
||||||
|
|
75
src/tag.rs
75
src/tag.rs
|
@ -1,10 +1,16 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
use regex::RegexSet;
|
use regex::RegexSet;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use strum::{Display, EnumIter};
|
use strum::{Display, EnumIter, IntoEnumIterator};
|
||||||
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use crate::config::State;
|
use crate::{config::State, error::Result, get_sane_terminal_dimensions, print_json};
|
||||||
|
|
||||||
|
const ID_WIDTH: usize = 4;
|
||||||
|
const TEXT_INDENT: &str = " ";
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// These must have the same order as the variants in the [`Tag`] enum.
|
/// These must have the same order as the variants in the [`Tag`] enum.
|
||||||
|
@ -170,4 +176,69 @@ impl Tag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Print this tag.
|
||||||
|
///
|
||||||
|
/// Does **not** respect `--json`, use [`Self::print_all`].
|
||||||
|
pub fn print<Cmd>(&self, state: &State<Cmd>) {
|
||||||
|
let emoji = if state.args.plain && self.is_primary() {
|
||||||
|
format!("{:>width$}", "-", width = ID_WIDTH)
|
||||||
|
} else {
|
||||||
|
let emoji = self.as_id(state);
|
||||||
|
let emoji_len = emoji.width();
|
||||||
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
" ".repeat(ID_WIDTH.saturating_sub(emoji_len)),
|
||||||
|
emoji
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let description_width = get_sane_terminal_dimensions().0;
|
||||||
|
let description = textwrap::fill(
|
||||||
|
self.describe(),
|
||||||
|
textwrap::Options::new(description_width)
|
||||||
|
.initial_indent(TEXT_INDENT)
|
||||||
|
.subsequent_indent(TEXT_INDENT),
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"{} {}\n{}",
|
||||||
|
color!(state: emoji; bright_yellow, bold),
|
||||||
|
color!(state: self; bold),
|
||||||
|
color!(state: description; bright_black),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print all tags.
|
||||||
|
pub fn print_all<Cmd>(state: &State<Cmd>) -> Result<()> {
|
||||||
|
if state.args.json {
|
||||||
|
Self::print_all_json(state)
|
||||||
|
} else {
|
||||||
|
for tag in Tag::iter() {
|
||||||
|
println!();
|
||||||
|
tag.print(state);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print all tags as json.
|
||||||
|
///
|
||||||
|
/// This will result in a list of objects containing the following keys:
|
||||||
|
/// - id: An identifier, like 'Vegan' or '22'
|
||||||
|
/// - name: The name of the tag.
|
||||||
|
/// - desc: A simple description.
|
||||||
|
///
|
||||||
|
fn print_all_json<Cmd>(state: &State<Cmd>) -> Result<()> {
|
||||||
|
let tags: Vec<HashMap<&str, String>> = Tag::iter()
|
||||||
|
.map(|tag| {
|
||||||
|
vec![
|
||||||
|
("id", tag.as_id(state)),
|
||||||
|
("name", tag.to_string()),
|
||||||
|
("desc", tag.describe().to_owned()),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
print_json(&tags)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue