davis 0.1.1

An CLI client for MPD.
use crate::ansi::{FormattedString, Style};
use crate::table::{Row, Table};
use crate::tags::Tags;
use mpdrs::Song;

pub fn bold<S: AsRef<str>>(s: S) -> String {
    FormattedString::new(s.as_ref())
        .style(Style::Bold)
        .to_string()
}

fn header(song: &Song) -> Option<String> {
    let tags = Tags::from_song(song);
    tags.joined(&["work", "composer"], " - ")
        .or_else(|| tags.joined(&["album", "albumartist"], " - "))
        .or_else(|| tags.joined(&["album", "artist"], " - "))
}

struct QueueRow {
    is_current: bool,
    fields: Vec<String>,
}

impl QueueRow {
    fn to_table_row(&self) -> Row {
        Row::new(
            self.fields
                .iter()
                .map(|s| {
                    FormattedString::new(&*s).style(if self.is_current {
                        Style::Bold
                    } else {
                        Style::Default
                    })
                })
                .collect(),
        )
    }
}

fn print_table(rows: &[QueueRow]) {
    let table_rows = rows
        .iter()
        .map(QueueRow::to_table_row)
        .collect::<Vec<Row>>();
    println!("{}", Table { rows: &*table_rows });
}

pub fn print(queue: Vec<Song>, current: &Option<Song>) {
    let mut cur_header = None;
    let mut rows: Vec<QueueRow> = Vec::new();
    for (pos, song) in queue.into_iter().enumerate() {
        let pos = pos + 1;
        if let Some(h) = header(&song).filter(|h| Some(h) != cur_header.as_ref()) {
            if !rows.is_empty() {
                print_table(&*rows);
                rows.clear();
            }
            println!("{}", bold(&h));
            cur_header = Some(h);
        }

        let tags = Tags::from_song(&song);
        let mut fields = ["movementnumber", "movement"]
            .iter()
            .map(|s| tags.get_option_joined(s))
            .collect::<Option<Vec<String>>>()
            .or_else(|| song.title.clone().map(|t| vec![t]))
            .unwrap_or_else(|| vec![song.file.clone()]);
        fields.insert(0, pos.to_string());
        rows.push(QueueRow {
            is_current: Some(&song) == current.as_ref(),
            fields,
        });
    }
    if !rows.is_empty() {
        print_table(&*rows);
    }
}