mirror of
https://github.com/LordMZTE/mcstat.git
synced 2024-05-02 13:11:09 +02:00
output overhaul
This commit is contained in:
parent
71a3ea55b4
commit
5353975725
40
src/lib.rs
40
src/lib.rs
|
@ -1,45 +1,7 @@
|
||||||
use asciify::AsciiBuilder;
|
use asciify::AsciiBuilder;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
/// prints a table with the entries supplied
|
pub mod output;
|
||||||
/// the identifier at the start of each entry sets the type
|
|
||||||
///
|
|
||||||
/// l = list entry
|
|
||||||
/// b = block
|
|
||||||
/// lo = list entry option
|
|
||||||
/// bo = block option
|
|
||||||
///
|
|
||||||
/// options are checked if they are `Some` and won't be printed if they aren't
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! print_table {
|
|
||||||
//list entry
|
|
||||||
($width:expr; l $l:expr => $k:expr) => {
|
|
||||||
println!("{: <width$} | {}", $l, $k, width = $width);
|
|
||||||
};
|
|
||||||
|
|
||||||
//block
|
|
||||||
($width:expr; b $l:expr => $k:expr) => {
|
|
||||||
println!("{:=^width$}\n{}\n{:=<width$}", $l, $k, "", width = $width);
|
|
||||||
};
|
|
||||||
|
|
||||||
//list entry option
|
|
||||||
($width:expr; lo $l:expr => $k:expr) => {
|
|
||||||
if let Some(txt) = $k {
|
|
||||||
println!("{: <width$} | {}", $l, txt, width = $width);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//block option
|
|
||||||
($width:expr; bo $l:expr => $k:expr) => {
|
|
||||||
if let Some(txt) = $k {
|
|
||||||
println!("{:=^width$}\n{}\n{:=<width$}", $l, txt, "", width = $width);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
($width:expr; $($t:tt $l:expr => $k:expr),+ $(,)?) => {
|
|
||||||
$(print_table!($width; $t $l => $k);)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns an `Option` of the expression passed in
|
/// returns an `Option` of the expression passed in
|
||||||
/// `None` if the `is_empty` on the expression returns true, `Some(x)` otherwise
|
/// `None` if the `is_empty` on the expression returns true, `Some(x)` otherwise
|
||||||
|
|
86
src/main.rs
86
src/main.rs
|
@ -8,7 +8,7 @@ use async_minecraft_ping::{ConnectionConfig, ServerDescription, StatusResponse};
|
||||||
use clap::{load_yaml, App};
|
use clap::{load_yaml, App};
|
||||||
use image::ImageFormat;
|
use image::ImageFormat;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use mcstat::{get_table, none_if_empty, print_table, remove_formatting, AsciiConfig};
|
use mcstat::{get_table, none_if_empty, output::Table, remove_formatting, AsciiConfig};
|
||||||
use termcolor::{Buffer, BufferWriter, ColorChoice, WriteColor};
|
use termcolor::{Buffer, BufferWriter, ColorChoice, WriteColor};
|
||||||
|
|
||||||
/// this message is used if getting a value from the arguments fails
|
/// this message is used if getting a value from the arguments fails
|
||||||
|
@ -103,49 +103,69 @@ async fn main() -> Result<()> {
|
||||||
.intersperse("\n")
|
.intersperse("\n")
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
|
|
||||||
print_table! {
|
let mut table = Table::new();
|
||||||
40;
|
|
||||||
bo "Description" => none_if_empty!(remove_formatting(&response.description.get_text())),
|
table.opt_big_entry(
|
||||||
bo "Extra Description" => {
|
"Description",
|
||||||
if let ServerDescription::Big(big_desc) = &response.description {
|
none_if_empty!(remove_formatting(&response.description.get_text())),
|
||||||
let desc = &big_desc.extra;
|
);
|
||||||
if desc.is_empty() {
|
|
||||||
None
|
table.opt_big_entry("Extra Description", {
|
||||||
} else {
|
if let ServerDescription::Big(big_desc) = &response.description {
|
||||||
Some(desc.into_iter().map(|p| p.text.clone()).collect::<String>())
|
let desc = &big_desc.extra;
|
||||||
}
|
if desc.is_empty() {
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
Some(desc.into_iter().map(|p| p.text.clone()).collect::<String>())
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
table.opt_big_entry(
|
||||||
|
"Player Sample",
|
||||||
|
none_if_empty!(remove_formatting(&player_sample)),
|
||||||
|
);
|
||||||
|
|
||||||
|
table.opt_small_entry(
|
||||||
|
"Server Version",
|
||||||
|
none_if_empty!(remove_formatting(&response.version.name)),
|
||||||
|
);
|
||||||
|
table.small_entry("Online Players", &response.players.online);
|
||||||
|
table.small_entry("Max Players", &response.players.max);
|
||||||
|
|
||||||
|
table.opt_big_entry(
|
||||||
|
"Mods",
|
||||||
|
if let (Some(mod_list), true) = (response.forge_mod_info(), matches.is_present("mods")) {
|
||||||
|
Some(get_table(
|
||||||
|
mod_list
|
||||||
|
.iter()
|
||||||
|
.sorted_by(|a, b| a.modid.cmp(&b.modid))
|
||||||
|
.map(|m| (&*m.modid, &*m.version)),
|
||||||
|
matches.is_present("modversions"),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
},
|
},
|
||||||
bo "Player Sample" => none_if_empty!(remove_formatting(&player_sample)),
|
);
|
||||||
lo "Server Version" => none_if_empty!(remove_formatting(&response.version.name)),
|
|
||||||
l "Online Players" => &response.players.online,
|
table.opt_big_entry(
|
||||||
l "Max Players" => &response.players.max,
|
"Forge Channels",
|
||||||
bo "Mods" => if let (Some(mod_list), true) = (response.forge_mod_info(), matches.is_present("mods")) {
|
if let (true, Some(fd)) = (matches.is_present("channels"), response.forge_data) {
|
||||||
Some(get_table(
|
|
||||||
mod_list
|
|
||||||
.iter()
|
|
||||||
.sorted_by(|a, b| a.modid.cmp(&b.modid))
|
|
||||||
.map(|m| (&*m.modid, &*m.version)),
|
|
||||||
matches.is_present("modversions")
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
l "Server Protocol" => &response.version.protocol,
|
|
||||||
bo "Forge Channels" => if let (true, Some(fd)) = (matches.is_present("channels"), response.forge_data) {
|
|
||||||
Some(get_table(
|
Some(get_table(
|
||||||
fd.channels
|
fd.channels
|
||||||
.iter()
|
.iter()
|
||||||
.sorted_by(|a, b| a.res.cmp(&b.res))
|
.sorted_by(|a, b| a.res.cmp(&b.res))
|
||||||
.map(|c| (&*c.res, &*c.version)),
|
.map(|c| (&*c.res, &*c.version)),
|
||||||
true
|
true,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
},
|
||||||
};
|
);
|
||||||
|
|
||||||
|
table.stdout()?;
|
||||||
|
|
||||||
if let Some(img) = image {
|
if let Some(img) = image {
|
||||||
println!("\n{}", img.await??);
|
println!("\n{}", img.await??);
|
||||||
|
|
137
src/output.rs
Normal file
137
src/output.rs
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
use std::{
|
||||||
|
cmp::max,
|
||||||
|
io::{self, Write},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Table {
|
||||||
|
pub entries: Vec<Box<dyn TableEntry>>,
|
||||||
|
pub small_entry_width: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Table {
|
||||||
|
pub fn stdout(&self) -> io::Result<()> {
|
||||||
|
self.print(&mut io::stdout())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print(&self, out: &mut dyn Write) -> io::Result<()> {
|
||||||
|
for e in &self.entries {
|
||||||
|
e.print(out, self)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn small_entry(&mut self, name: impl ToString, val: impl ToString) {
|
||||||
|
let name = name.to_string();
|
||||||
|
self.set_small_width(name.len());
|
||||||
|
|
||||||
|
self.entries
|
||||||
|
.push(Box::new(SmallTableEntry(name, val.to_string())));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn big_entry(&mut self, name: impl ToString, val: impl ToString) {
|
||||||
|
self.entries.push(Box::new(BigTableEntry::new(
|
||||||
|
name.to_string(),
|
||||||
|
val.to_string(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn opt_small_entry(&mut self, name: impl ToString, val: Option<impl ToString>) {
|
||||||
|
let name = name.to_string();
|
||||||
|
self.set_small_width(name.len());
|
||||||
|
|
||||||
|
self.entries.push(Box::new(OptSmallTableEntry(
|
||||||
|
val.map(|t| SmallTableEntry(name, t.to_string())),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn opt_big_entry(&mut self, name: impl ToString, val: Option<impl ToString>) {
|
||||||
|
self.entries.push(Box::new(OptBigTableEntry(
|
||||||
|
val.map(|t| BigTableEntry::new(name.to_string(), t.to_string())),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_small_width(&mut self, width: usize) {
|
||||||
|
if width > self.small_entry_width {
|
||||||
|
self.small_entry_width = width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TableEntry {
|
||||||
|
fn print(&self, out: &mut dyn Write, table: &Table) -> io::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SmallTableEntry(String, String);
|
||||||
|
|
||||||
|
impl TableEntry for SmallTableEntry {
|
||||||
|
fn print(&self, out: &mut dyn Write, table: &Table) -> io::Result<()> {
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
"{: <width$} | {}",
|
||||||
|
self.0,
|
||||||
|
self.1,
|
||||||
|
width = table.small_entry_width
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BigTableEntry {
|
||||||
|
name: String,
|
||||||
|
val: String,
|
||||||
|
width: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TableEntry for BigTableEntry {
|
||||||
|
fn print(&self, out: &mut dyn Write, _table: &Table) -> io::Result<()> {
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
"{:=^width$}\n{}\n{:=<width$}",
|
||||||
|
self.name,
|
||||||
|
self.val,
|
||||||
|
"",
|
||||||
|
width = self.width,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BigTableEntry {
|
||||||
|
pub fn new(name: String, val: String) -> Self {
|
||||||
|
let val_width = val.splitn(2, '\n').next().unwrap_or(&val).len();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
width: max(name.len(), val_width),
|
||||||
|
name,
|
||||||
|
val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OptSmallTableEntry(Option<SmallTableEntry>);
|
||||||
|
|
||||||
|
impl TableEntry for OptSmallTableEntry {
|
||||||
|
fn print(&self, out: &mut dyn Write, table: &Table) -> io::Result<()> {
|
||||||
|
if let Some(entry) = &self.0 {
|
||||||
|
entry.print(out, table)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OptBigTableEntry(Option<BigTableEntry>);
|
||||||
|
|
||||||
|
impl TableEntry for OptBigTableEntry {
|
||||||
|
fn print(&self, out: &mut dyn Write, table: &Table) -> io::Result<()> {
|
||||||
|
if let Some(entry) = &self.0 {
|
||||||
|
entry.print(out, table)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue