1pub use ansi_colour::Colour as AnsiColour;
2use error::*;
3use prototty_grid::*;
4use prototty_input::*;
5use prototty_render::*;
6use std::time::Duration;
7use terminal::*;
8
9const DEFAULT_FG: AnsiColour = AnsiColour::from_rgb24(grey24(255));
10const DEFAULT_BG: AnsiColour = AnsiColour::from_rgb24(grey24(0));
11
12pub trait ColourConfig {
13 fn convert_foreground_rgb24(&mut self, rgb24: Rgb24) -> AnsiColour;
14 fn convert_background_rgb24(&mut self, rgb24: Rgb24) -> AnsiColour {
15 self.convert_foreground_rgb24(rgb24)
16 }
17 fn default_foreground(&mut self) -> AnsiColour {
18 DEFAULT_FG
19 }
20 fn default_background(&mut self) -> AnsiColour {
21 DEFAULT_BG
22 }
23}
24
25pub struct DefaultColourConfig;
26
27impl ColourConfig for DefaultColourConfig {
28 fn convert_foreground_rgb24(&mut self, rgb24: Rgb24) -> AnsiColour {
29 AnsiColour::from_rgb24(rgb24)
30 }
31}
32
33impl<F: FnMut(Rgb24) -> AnsiColour> ColourConfig for F {
34 fn convert_foreground_rgb24(&mut self, rgb24: Rgb24) -> AnsiColour {
35 (self)(rgb24)
36 }
37}
38
39struct UnixColourConversion<C>(C);
40
41impl<C: ColourConfig> ColourConversion for UnixColourConversion<C> {
42 type Colour = AnsiColour;
43 fn default_foreground(&mut self) -> Self::Colour {
44 self.0.default_foreground()
45 }
46 fn default_background(&mut self) -> Self::Colour {
47 self.0.default_background()
48 }
49 fn convert_foreground_rgb24(&mut self, rgb24: Rgb24) -> Self::Colour {
50 self.0.convert_foreground_rgb24(rgb24)
51 }
52 fn convert_background_rgb24(&mut self, rgb24: Rgb24) -> Self::Colour {
53 self.0.convert_background_rgb24(rgb24)
54 }
55}
56
57pub struct Context<C: ColourConfig = DefaultColourConfig> {
59 terminal: Terminal,
60 grid: Grid<UnixColourConversion<C>>,
61}
62
63impl Context<DefaultColourConfig> {
64 pub fn new() -> Result<Self> {
66 Self::with_colour_config(DefaultColourConfig)
67 }
68
69 pub fn from_terminal(terminal: Terminal) -> Result<Self> {
70 Self::from_terminal_with_colour_config(terminal, DefaultColourConfig)
71 }
72}
73
74impl<C: ColourConfig> Context<C> {
75 pub fn with_colour_config(mut colour_config: C) -> Result<Self> {
76 Terminal::new(
77 colour_config.default_foreground(),
78 colour_config.default_background(),
79 )
80 .and_then(|terminal| {
81 Self::from_terminal_with_colour_config(terminal, colour_config)
82 })
83 }
84
85 pub fn from_terminal_with_colour_config(
86 mut terminal: Terminal,
87 mut colour_config: C,
88 ) -> Result<Self> {
89 let size = terminal.resize_if_necessary(
90 colour_config.default_foreground(),
91 colour_config.default_background(),
92 )?;
93 let grid = Grid::new(size, UnixColourConversion(colour_config));
94 Ok(Self { terminal, grid })
95 }
96
97 fn resize_if_necessary(&mut self) -> Result<()> {
98 let size = self.terminal.resize_if_necessary(
99 self.grid.default_foreground(),
100 self.grid.default_background(),
101 )?;
102 if size != self.grid.size() {
103 self.grid.resize(size);
104 }
105 Ok(())
106 }
107
108 pub fn drain_input(&mut self) -> Result<DrainInput> {
109 self.terminal.drain_input()
110 }
111
112 pub fn poll_input(&mut self) -> Result<Option<Input>> {
115 self.terminal.poll_input()
116 }
117
118 pub fn wait_input(&mut self) -> Result<Input> {
121 self.terminal.wait_input()
122 }
123
124 pub fn wait_input_timeout(&mut self, timeout: Duration) -> Result<Option<Input>> {
128 self.terminal.wait_input_timeout(timeout)
129 }
130
131 pub fn render<V: View<T>, T>(&mut self, view: &mut V, data: T) -> Result<()> {
132 let size = self.size()?;
133 self.render_at(view, data, ViewContext::default_with_size(size))
134 }
135
136 pub fn render_at<V: View<T>, T, R: ViewTransformRgb24>(
137 &mut self,
138 view: &mut V,
139 data: T,
140 context: ViewContext<R>,
141 ) -> Result<()> {
142 self.resize_if_necessary()?;
143 self.grid.clear();
144 view.view(data, context, &mut self.grid);
145 self.terminal.draw_grid(&mut self.grid)
146 }
147
148 pub fn size(&self) -> Result<Size> {
149 self.terminal.size()
150 }
151}