Make verbose item print out configurable by field
This commit is contained in:
parent
507add66b8
commit
d0c7bcda58
3 changed files with 190 additions and 64 deletions
|
@ -53,6 +53,18 @@ impl TypePrimitive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pretty-print the type info, without the value
|
||||||
|
pub fn type_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::String(_) => "String",
|
||||||
|
Self::Int(_) => "Int",
|
||||||
|
Self::UInt(_) => "UInt",
|
||||||
|
Self::Float(_) => "Float",
|
||||||
|
Self::Bool(_) => "Bool",
|
||||||
|
Self::Empty => "Empty",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_u64(self) -> Option<u64> {
|
pub fn to_u64(self) -> Option<u64> {
|
||||||
match self {
|
match self {
|
||||||
Self::UInt(x) => Some(x),
|
Self::UInt(x) => Some(x),
|
||||||
|
|
|
@ -3,11 +3,15 @@ use muss_interpreter::Item;
|
||||||
use muss_player::EventTap;
|
use muss_player::EventTap;
|
||||||
use muss_player::{PlaybackAction, PlayerAction, ControlAction};
|
use muss_player::{PlaybackAction, PlayerAction, ControlAction};
|
||||||
|
|
||||||
|
use crate::repl::TERMINAL_WRITE_ERROR;
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct InterpreterDebugState {
|
pub struct InterpreterDebugState {
|
||||||
pub debug_flag: InterpreterDebugFlag,
|
pub debug_flag: InterpreterDebugFlag,
|
||||||
pub verbose: bool,
|
pub verbose: Verbosity,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -17,6 +21,134 @@ pub enum InterpreterDebugFlag {
|
||||||
Normal,
|
Normal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Verbosity {
|
||||||
|
field_handlers: Vec<VerboseField>,
|
||||||
|
debug: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum VerboseField {
|
||||||
|
ShowFieldValue(String),
|
||||||
|
ShowFieldType(String),
|
||||||
|
ShowFieldTypeValue(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VerboseField {
|
||||||
|
fn print_field(&self, item: &Item, terminal: &mut console::Term, args: &crate::cli::CliArgs) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::ShowFieldValue(f) => {
|
||||||
|
if let Some(field) = item.field(f) {
|
||||||
|
let field_str = field.as_str();
|
||||||
|
let max_len = terminal.size().1 as usize - (args.prompt.len() + f.len() + 6);
|
||||||
|
if field_str.len() >= max_len {
|
||||||
|
write!(
|
||||||
|
terminal,
|
||||||
|
" {}{}: `{}[...]`",
|
||||||
|
args.prompt,
|
||||||
|
f,
|
||||||
|
&field_str[..max_len - 5]
|
||||||
|
)
|
||||||
|
.expect(TERMINAL_WRITE_ERROR);
|
||||||
|
} else {
|
||||||
|
write!(terminal, " {}{}: `{}`", args.prompt, f, field_str).expect(TERMINAL_WRITE_ERROR);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Self::ShowFieldType(f) => {
|
||||||
|
if let Some(field) = item.field(f) {
|
||||||
|
let field_str = field.type_str();
|
||||||
|
write!(terminal, " {}{}: {}", args.prompt, f, field_str).expect(TERMINAL_WRITE_ERROR);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Self::ShowFieldTypeValue(f) => {
|
||||||
|
if let Some(field) = item.field(f) {
|
||||||
|
let field_str = format!("{}", field);
|
||||||
|
let max_len = terminal.size().1 as usize - (args.prompt.len() + f.len() + 4);
|
||||||
|
if field_str.len() >= max_len {
|
||||||
|
write!(
|
||||||
|
terminal,
|
||||||
|
" {}{}: {}[...]]",
|
||||||
|
args.prompt,
|
||||||
|
f,
|
||||||
|
&field_str[..max_len - 5]
|
||||||
|
)
|
||||||
|
.expect(TERMINAL_WRITE_ERROR);
|
||||||
|
} else {
|
||||||
|
write!(terminal, " {}{}: {}", args.prompt, f, field_str).expect(TERMINAL_WRITE_ERROR);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Verbosity {
|
||||||
|
pub fn print_item(&self, item: &Item, terminal: &mut console::Term, args: &crate::cli::CliArgs) {
|
||||||
|
Self::item_prompt(terminal, args);
|
||||||
|
if self.debug {
|
||||||
|
writeln!(terminal, "--\\/-- \\/ --\\/--").expect(TERMINAL_WRITE_ERROR);
|
||||||
|
if self.field_handlers.is_empty() {
|
||||||
|
let mut fields: Vec<_> = item.iter().collect();
|
||||||
|
fields.sort();
|
||||||
|
for field in fields {
|
||||||
|
VerboseField::ShowFieldValue(field.to_owned()).print_field(item, terminal, args);
|
||||||
|
writeln!(terminal, "").expect(TERMINAL_WRITE_ERROR);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for vf in &self.field_handlers {
|
||||||
|
let has_printed = vf.print_field(item, terminal, args);
|
||||||
|
if has_printed {
|
||||||
|
writeln!(terminal, "").expect(TERMINAL_WRITE_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writeln!(
|
||||||
|
terminal,
|
||||||
|
"`{}` by `{}`",
|
||||||
|
item.field("title")
|
||||||
|
.unwrap_or(&muss_interpreter::lang::TypePrimitive::Empty)
|
||||||
|
.as_str(),
|
||||||
|
item.field("artist")
|
||||||
|
.unwrap_or(&muss_interpreter::lang::TypePrimitive::Empty)
|
||||||
|
.as_str(),
|
||||||
|
)
|
||||||
|
.expect(TERMINAL_WRITE_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verbose_mut(&mut self) -> &'_ mut bool {
|
||||||
|
&mut self.debug
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verbose(&mut self) -> &'_ bool {
|
||||||
|
&self.debug
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handlers(&mut self, handlers: Vec<VerboseField>) {
|
||||||
|
self.field_handlers = handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_handlers(&mut self) {
|
||||||
|
self.field_handlers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn item_prompt(terminal: &mut console::Term, args: &crate::cli::CliArgs) {
|
||||||
|
write!(terminal, "I{}", args.prompt).expect(TERMINAL_WRITE_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DebugState {
|
pub struct DebugState {
|
||||||
pub now_playing: std::sync::Arc<std::sync::RwLock<Option<Item>>>,
|
pub now_playing: std::sync::Arc<std::sync::RwLock<Option<Item>>>,
|
||||||
|
@ -31,7 +163,10 @@ impl DebugState {
|
||||||
control_tx: std::sync::Arc::new(std::sync::Mutex::new(None)),
|
control_tx: std::sync::Arc::new(std::sync::Mutex::new(None)),
|
||||||
interpreter: std::sync::Arc::new(std::sync::RwLock::new(InterpreterDebugState {
|
interpreter: std::sync::Arc::new(std::sync::RwLock::new(InterpreterDebugState {
|
||||||
debug_flag: InterpreterDebugFlag::Normal,
|
debug_flag: InterpreterDebugFlag::Normal,
|
||||||
verbose: false,
|
verbose: Verbosity {
|
||||||
|
field_handlers: Vec::new(),
|
||||||
|
debug: false,
|
||||||
|
},
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
103
src/repl.rs
103
src/repl.rs
|
@ -5,7 +5,6 @@ use std::sync::mpsc::{self, Receiver};
|
||||||
|
|
||||||
use console::{Key, Term};
|
use console::{Key, Term};
|
||||||
|
|
||||||
use muss_interpreter::lang::TypePrimitive;
|
|
||||||
use muss_interpreter::{Debugger, Interpreter, InterpreterError, InterpreterEvent, Item};
|
use muss_interpreter::{Debugger, Interpreter, InterpreterError, InterpreterEvent, Item};
|
||||||
use muss_player::{Controller, Player};
|
use muss_player::{Controller, Player};
|
||||||
|
|
||||||
|
@ -75,57 +74,6 @@ fn interpreter_event_callback<'a, T: muss_interpreter::tokens::TokenReader>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn item_prompt(terminal: &mut Term, args: &CliArgs) {
|
|
||||||
write!(terminal, "*I{}", args.prompt).expect(TERMINAL_WRITE_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pretty_print_item(item: &Item, terminal: &mut Term, args: &CliArgs, verbose: bool) {
|
|
||||||
item_prompt(terminal, args);
|
|
||||||
if verbose {
|
|
||||||
writeln!(
|
|
||||||
terminal,
|
|
||||||
"--\\/-- `{}` --\\/--",
|
|
||||||
item.field("title")
|
|
||||||
.unwrap_or(&TypePrimitive::Empty)
|
|
||||||
.as_str()
|
|
||||||
)
|
|
||||||
.expect(TERMINAL_WRITE_ERROR);
|
|
||||||
let mut fields: Vec<&_> = item.iter().collect();
|
|
||||||
fields.sort();
|
|
||||||
for field in fields {
|
|
||||||
if field != "title" {
|
|
||||||
let field_str = item.field(field).unwrap_or(&TypePrimitive::Empty).as_str();
|
|
||||||
let max_len = terminal.size().1 as usize - (args.prompt.len() + field.len() + 8);
|
|
||||||
if field_str.len() >= max_len {
|
|
||||||
writeln!(
|
|
||||||
terminal,
|
|
||||||
" {}: `{}[...]`",
|
|
||||||
field,
|
|
||||||
&field_str[..max_len - 5]
|
|
||||||
)
|
|
||||||
.expect(TERMINAL_WRITE_ERROR);
|
|
||||||
} else {
|
|
||||||
writeln!(terminal, " {}: `{}`", field, field_str).expect(TERMINAL_WRITE_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
writeln!(
|
|
||||||
terminal,
|
|
||||||
"`{}` by `{}`",
|
|
||||||
item.field("title")
|
|
||||||
.unwrap_or(&TypePrimitive::Empty)
|
|
||||||
.as_str(),
|
|
||||||
item.field("artist")
|
|
||||||
.unwrap_or(&TypePrimitive::Empty)
|
|
||||||
.as_str(),
|
|
||||||
)
|
|
||||||
.expect(TERMINAL_WRITE_ERROR);
|
|
||||||
}
|
|
||||||
//writeln!(terminal, "I{}----", args.prompt).expect(TERMINAL_WRITE_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_list_rx(state: &mut ReplState, args: &CliArgs) {
|
fn handle_list_rx(state: &mut ReplState, args: &CliArgs) {
|
||||||
//let items = state.list_rx.try_iter().collect::<Vec<_>>();
|
//let items = state.list_rx.try_iter().collect::<Vec<_>>();
|
||||||
let d_state = state.controller_debug.interpreter
|
let d_state = state.controller_debug.interpreter
|
||||||
|
@ -134,7 +82,7 @@ fn handle_list_rx(state: &mut ReplState, args: &CliArgs) {
|
||||||
.clone();
|
.clone();
|
||||||
for item in state.list_rx.try_iter() {
|
for item in state.list_rx.try_iter() {
|
||||||
match item {
|
match item {
|
||||||
Ok(item) => pretty_print_item(&item, &mut state.terminal, args, d_state.verbose),
|
Ok(item) => d_state.verbose.print_item(&item, &mut state.terminal, args),
|
||||||
Err(e) => error_prompt(
|
Err(e) => error_prompt(
|
||||||
muss_player::PlayerError::Playback(muss_player::PlaybackError::from_err(e)),
|
muss_player::PlayerError::Playback(muss_player::PlaybackError::from_err(e)),
|
||||||
args,
|
args,
|
||||||
|
@ -148,8 +96,11 @@ fn handle_list_rx(state: &mut ReplState, args: &CliArgs) {
|
||||||
while let Ok(item) = state.list_rx.recv() {
|
while let Ok(item) = state.list_rx.recv() {
|
||||||
match item {
|
match item {
|
||||||
Ok(item) => {
|
Ok(item) => {
|
||||||
let verbose = state.controller_debug.interpreter.read().map(|x| x.verbose).unwrap_or(false);
|
state.controller_debug.interpreter
|
||||||
pretty_print_item(&item, &mut state.terminal, args, verbose)
|
.read()
|
||||||
|
.expect("Failed to get read lock for debug state info")
|
||||||
|
.verbose
|
||||||
|
.print_item(&item, &mut state.terminal, args)
|
||||||
}
|
}
|
||||||
Err(e) => error_prompt(
|
Err(e) => error_prompt(
|
||||||
muss_player::PlayerError::Playback(muss_player::PlaybackError::from_err(e)),
|
muss_player::PlayerError::Playback(muss_player::PlaybackError::from_err(e)),
|
||||||
|
@ -680,7 +631,7 @@ fn error_prompt(error: muss_player::PlayerError, args: &CliArgs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn repl_commands(command_str: &str, state: &mut ReplState, args: &CliArgs) {
|
fn repl_commands(command_str: &str, state: &mut ReplState, args: &CliArgs) {
|
||||||
let words: Vec<&str> = command_str.split(' ').map(|s| s.trim()).collect();
|
let mut words: Vec<&str> = command_str.split(' ').map(|s| s.trim()).collect();
|
||||||
match words[0] {
|
match words[0] {
|
||||||
"?help" => {
|
"?help" => {
|
||||||
writeln!(state.terminal, "{}", super::help::HELP_STRING).expect(TERMINAL_WRITE_ERROR)
|
writeln!(state.terminal, "{}", super::help::HELP_STRING).expect(TERMINAL_WRITE_ERROR)
|
||||||
|
@ -729,10 +680,38 @@ fn repl_commands(command_str: &str, state: &mut ReplState, args: &CliArgs) {
|
||||||
let mut debug_state = state.controller_debug.interpreter
|
let mut debug_state = state.controller_debug.interpreter
|
||||||
.write()
|
.write()
|
||||||
.expect("Failed to get write lock for debug state");
|
.expect("Failed to get write lock for debug state");
|
||||||
debug_state.verbose = !debug_state.verbose;
|
if *debug_state.verbose.verbose() && words.len() == 1 {
|
||||||
debug_state.verbose
|
*debug_state.verbose.verbose_mut() = false;
|
||||||
|
} else if !*debug_state.verbose.verbose() && words.len() == 1 {
|
||||||
|
*debug_state.verbose.verbose_mut() = true;
|
||||||
|
debug_state.verbose.clear_handlers();
|
||||||
|
} else {
|
||||||
|
*debug_state.verbose.verbose_mut() = true;
|
||||||
|
debug_state.verbose.handlers(
|
||||||
|
words.split_off(1)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|arg| {
|
||||||
|
const HANDLER_SPLIT_CHAR: char = ':';
|
||||||
|
if arg.contains(HANDLER_SPLIT_CHAR) {
|
||||||
|
let mut iter = arg.split(HANDLER_SPLIT_CHAR);
|
||||||
|
let handler = iter.next().unwrap();
|
||||||
|
let field = if let Some(f) = iter.next() { f } else { return None };
|
||||||
|
match handler {
|
||||||
|
"v" | "value" => Some(crate::debug_state::VerboseField::ShowFieldValue(field.to_owned())),
|
||||||
|
"t" | "type" => Some(crate::debug_state::VerboseField::ShowFieldType(field.to_owned())),
|
||||||
|
"vt" | "valuetype" => Some(crate::debug_state::VerboseField::ShowFieldTypeValue(field.to_owned())),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Some(crate::debug_state::VerboseField::ShowFieldValue(arg.to_owned()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
*debug_state.verbose.verbose()
|
||||||
};
|
};
|
||||||
writeln!(state.terminal, "Verbosed toggled to {}", verbose)
|
writeln!(state.terminal, "Verbose toggled to {}", verbose)
|
||||||
.expect(TERMINAL_WRITE_ERROR);
|
.expect(TERMINAL_WRITE_ERROR);
|
||||||
}
|
}
|
||||||
"?commands" => {
|
"?commands" => {
|
||||||
|
@ -740,11 +719,11 @@ fn repl_commands(command_str: &str, state: &mut ReplState, args: &CliArgs) {
|
||||||
}
|
}
|
||||||
"?now" => {
|
"?now" => {
|
||||||
if let Some(item) = crate::playlists::get_current_item(state) {
|
if let Some(item) = crate::playlists::get_current_item(state) {
|
||||||
let verbose = state.controller_debug.interpreter
|
state.controller_debug.interpreter
|
||||||
.read()
|
.read()
|
||||||
.expect("Failed to get read lock for debug state")
|
.expect("Failed to get read lock for debug state")
|
||||||
.verbose;
|
.verbose
|
||||||
pretty_print_item(&item, &mut state.terminal, args, verbose);
|
.print_item(&item, &mut state.terminal, args);
|
||||||
} else {
|
} else {
|
||||||
writeln!(state.terminal, "Nothing playing").expect(TERMINAL_WRITE_ERROR)
|
writeln!(state.terminal, "Nothing playing").expect(TERMINAL_WRITE_ERROR)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue