1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use crate::vcs::common::{PullRequest, PullRequestState};
use colored::Colorize;

use super::utils::to_fixed_length;

pub enum FormatterType {
    Json,
    Normal,
    Short,
}

pub trait Formatter {
    fn show_json(&self) -> String;
    fn show_normal(&self) -> String;
    fn show_short(&self) -> String;
    fn show(&self, formatter_type: FormatterType) -> String {
        match formatter_type {
            FormatterType::Json => self.show_json(),
            FormatterType::Normal => self.show_normal(),
            FormatterType::Short => self.show_short(),
        }
    }
}

const FULL_SIZE: usize = 80;
const ID_SIZE: usize = 6;
const TITLE_SIZE: usize = FULL_SIZE - ID_SIZE - 1;
const SHORT_BRANCH_SIZE: usize = 20;
const SHORT_TITLE_SIZE: usize = FULL_SIZE - ID_SIZE - 1 - SHORT_BRANCH_SIZE - 1;

impl Formatter for PullRequest {
    fn show_json(&self) -> String {
        serde_json::to_string(&self).unwrap()
    }
    fn show_normal(&self) -> String {
        let title = to_fixed_length(&self.title, TITLE_SIZE, true);
        let title = match self.state {
            PullRequestState::Open => title.bold(),
            PullRequestState::Closed => title.bold().red(),
            PullRequestState::Merged => title.bold().green(),
            PullRequestState::Locked => title.bold().magenta(),
        };
        let colored_id = format!("#{}", self.id).dimmed();
        let title_line = format!("{} {:>width$}", title, colored_id, width = ID_SIZE);
        let details_line = format!(
            "{} {} {} {} {} {}",
            "opened by".dimmed(),
            self.author.username,
            "on".dimmed(),
            self.created_at.format("%Y-%m-%d"),
            "updated on".dimmed(),
            self.updated_at.format("%Y-%m-%d")
        );
        let branch_line = format!("{} -> {}", self.source.blue(), self.target.blue());
        let description = if self.description.len() > 0 {
            format!("\n{}\n---", self.description)
        } else {
            "".to_string()
        };
        let url_line = format!("{}", self.url.dimmed());

        format!(
            "{title_line}
{details_line}
{branch_line}
{description}
{url_line}
"
        )
    }
    fn show_short(&self) -> String {
        let title = to_fixed_length(&self.title, SHORT_TITLE_SIZE, true);
        let title = match self.state {
            PullRequestState::Open => title.bold(),
            PullRequestState::Closed => title.bold().red(),
            PullRequestState::Merged => title.bold().green(),
            PullRequestState::Locked => title.bold().magenta(),
        };
        let branch = to_fixed_length(&self.source, SHORT_BRANCH_SIZE, true).blue();
        let colored_id = format!("#{}", self.id).dimmed();
        format!("{} {} {:>6}\n", title, branch, colored_id)
    }
}