undo/history/
display.rs

1use crate::{At, Entry, Format, History};
2use core::fmt::{self, Write};
3#[cfg(feature = "std")]
4use std::time::SystemTime;
5
6/// Configurable display formatting for the [`History`].
7pub struct Display<'a, E, S> {
8    history: &'a History<E, S>,
9    format: Format,
10    #[cfg(feature = "std")]
11    st_fmt: &'a dyn Fn(SystemTime, SystemTime) -> String,
12}
13
14impl<'a, E, S> Display<'a, E, S> {
15    /// Show colored output (on by default).
16    ///
17    /// Requires the `colored` feature to be enabled.
18    #[cfg(feature = "colored")]
19    pub fn colored(&mut self, on: bool) -> &mut Self {
20        self.format.colored = on;
21        self
22    }
23
24    /// Show detailed output (on by default).
25    pub fn detailed(&mut self, on: bool) -> &mut Self {
26        self.format.detailed = on;
27        self
28    }
29
30    /// Show the current position in the output (on by default).
31    pub fn head(&mut self, on: bool) -> &mut Self {
32        self.format.head = on;
33        self
34    }
35
36    /// Show the saved edit (on by default).
37    pub fn saved(&mut self, on: bool) -> &mut Self {
38        self.format.saved = on;
39        self
40    }
41
42    /// Sets the format used to display [`SystemTime`]s.
43    ///
44    /// The first input parameter is the current system time.
45    /// The second input parameter is the system time of the event.
46    #[cfg(feature = "std")]
47    pub fn set_st_fmt(
48        &mut self,
49        st_fmt: &'a dyn Fn(SystemTime, SystemTime) -> String,
50    ) -> &mut Self {
51        self.st_fmt = st_fmt;
52        self
53    }
54}
55
56impl<E: fmt::Display, S> Display<'_, E, S> {
57    fn fmt_list(
58        &self,
59        f: &mut fmt::Formatter,
60        at: At,
61        entry: Option<&Entry<E>>,
62        level: usize,
63        #[cfg(feature = "std")] now: SystemTime,
64    ) -> fmt::Result {
65        self.format.mark(f, level)?;
66        self.format.at(f, at)?;
67
68        #[cfg(feature = "std")]
69        if let Some(entry) = entry {
70            if self.format.detailed {
71                let st_fmt = self.st_fmt;
72                let string = st_fmt(now, entry.st_of_latest());
73                self.format.elapsed(f, string)?;
74            }
75        }
76
77        self.format
78            .labels(f, at, self.history.head(), self.history.saved())?;
79
80        if let Some(entry) = entry {
81            if self.format.detailed {
82                writeln!(f)?;
83                self.format.message(f, entry, Some(level))?;
84            } else {
85                f.write_char(' ')?;
86                self.format.message(f, entry, Some(level))?;
87                writeln!(f)?;
88            }
89        }
90        Ok(())
91    }
92
93    fn fmt_graph(
94        &self,
95        f: &mut fmt::Formatter,
96        at: At,
97        entry: Option<&Entry<E>>,
98        level: usize,
99        #[cfg(feature = "std")] now: SystemTime,
100    ) -> fmt::Result {
101        for (i, branch) in self
102            .history
103            .branches()
104            .filter(|(_, branch)| branch.parent == at)
105        {
106            for (j, entry) in branch.entries.iter().enumerate().rev() {
107                let at = At::new(i, j + branch.parent.index + 1);
108                self.fmt_graph(
109                    f,
110                    at,
111                    Some(entry),
112                    level + 1,
113                    #[cfg(feature = "std")]
114                    now,
115                )?;
116            }
117
118            for j in 0..level {
119                self.format.edge(f, j)?;
120                f.write_char(' ')?;
121            }
122
123            self.format.split(f, level)?;
124            writeln!(f)?;
125        }
126
127        for i in 0..level {
128            self.format.edge(f, i)?;
129            f.write_char(' ')?;
130        }
131
132        self.fmt_list(
133            f,
134            at,
135            entry,
136            level,
137            #[cfg(feature = "std")]
138            now,
139        )
140    }
141}
142
143impl<'a, E, S> From<&'a History<E, S>> for Display<'a, E, S> {
144    fn from(history: &'a History<E, S>) -> Self {
145        Display {
146            history,
147            format: Format::default(),
148            #[cfg(feature = "std")]
149            st_fmt: &crate::format::default_st_fmt,
150        }
151    }
152}
153
154impl<E: fmt::Display, S> fmt::Display for Display<'_, E, S> {
155    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156        #[cfg(feature = "std")]
157        let now = SystemTime::now();
158        let root = self.history.root;
159        for (i, entry) in self.history.record.entries.iter().enumerate().rev() {
160            let at = At::new(root, i + 1);
161            self.fmt_graph(
162                f,
163                at,
164                Some(entry),
165                0,
166                #[cfg(feature = "std")]
167                now,
168            )?;
169        }
170        self.fmt_graph(
171            f,
172            At::new(root, 0),
173            None,
174            0,
175            #[cfg(feature = "std")]
176            now,
177        )
178    }
179}