spotify_cli/output/
pin.rs1use serde::Serialize;
3
4use crate::domain::pin::PinnedPlaylist;
5use crate::error::Result;
6use crate::output::human::truncate_cell;
7use crate::output::{DEFAULT_MAX_WIDTH, TableConfig};
8
9pub fn pin_list_human(pins: Vec<PinnedPlaylist>, table: TableConfig) -> Result<()> {
10 if pins.is_empty() {
11 return Ok(());
12 }
13
14 let max_width = table.max_width.unwrap_or(DEFAULT_MAX_WIDTH);
15 let mut names: Vec<String> = pins
16 .iter()
17 .map(|pin| {
18 if table.truncate {
19 truncate_cell(&pin.name, max_width)
20 } else {
21 pin.name.clone()
22 }
23 })
24 .collect();
25 let mut urls: Vec<String> = pins
26 .iter()
27 .map(|pin| {
28 if table.truncate {
29 truncate_cell(&pin.url, max_width)
30 } else {
31 pin.url.clone()
32 }
33 })
34 .collect();
35
36 let name_width = names
37 .iter()
38 .map(|name| name.len())
39 .max()
40 .unwrap_or(0)
41 .max("NAME".len());
42
43 println!("{:<width$} {}", "NAME", "URL", width = name_width);
44
45 for (name, url) in names.drain(..).zip(urls.drain(..)) {
46 println!("{:<width$} {}", name, url, width = name_width);
47 }
48 Ok(())
49}
50
51#[derive(Serialize)]
52struct PinPayload {
53 name: String,
54 url: String,
55}
56
57pub fn pin_list_json(pins: Vec<PinnedPlaylist>) -> Result<()> {
58 let payload = pin_list_payload(pins);
59 println!("{}", serde_json::to_string(&payload)?);
60 Ok(())
61}
62
63fn pin_list_payload(pins: Vec<PinnedPlaylist>) -> Vec<PinPayload> {
64 pins.into_iter()
65 .map(|pin| PinPayload {
66 name: pin.name,
67 url: pin.url,
68 })
69 .collect()
70}
71
72#[cfg(test)]
73mod tests {
74 use super::pin_list_payload;
75 use crate::domain::pin::PinnedPlaylist;
76
77 #[test]
78 fn pin_list_payload_shape() {
79 let payload = pin_list_payload(vec![PinnedPlaylist {
80 name: "Release Radar".to_string(),
81 url: "url".to_string(),
82 }]);
83 assert_eq!(payload.len(), 1);
84 assert_eq!(payload[0].name, "Release Radar");
85 }
86}