devela/ui/back/crossterm/
service.rs

1// devela::ui::back::crossterm::service
2//
3//! Defines [`CrosstermService`].
4//
5// ISSUES
6// - WAIT: [add Event::Terminate](https://github.com/crossterm-rs/crossterm/issues/554)
7// - WAIT: [support ctrl+z + fg](https://github.com/crossterm-rs/crossterm/issues/494)
8//
9// TODO
10// - window refresh, render
11
12use ::crossterm::{event, execute, terminal};
13
14// use core::time::Duration;
15use std::io;
16
17use crate::{
18    IoError, UiCap, UiCapImage, /* Event, EventSource, */ UiCapInput,
19    /* Window, */ UiCapWindow, UiService,
20};
21
22/// `crossterm`'s UI backend service.
23//
24// https://docs.rs/crossterm/latest/crossterm/terminal/index.html
25pub struct CrosstermService;
26// { raw_mode: bool, }
27
28// TODO
29// impl Drop for CrosstermService {
30//     fn drop(&mut self)  {
31//         if self.raw_mode {
32//             self.set_raw_mode(false);
33//         }
34//     }
35// }
36
37impl CrosstermService {
38    /// Creates a new `CrosstermService`.
39    pub fn new() -> Result<Self, IoError> {
40        Ok(Self { /* raw_mode: false */ })
41    }
42
43    /// Tells whether the raw mode is enabled.
44    //
45    // https://docs.rs/crossterm/latest/crossterm/terminal/fn.is_raw_mode_enabled.html
46    #[inline]
47    pub fn is_raw_mode(&self) -> Result<bool, IoError> {
48        terminal::is_raw_mode_enabled()
49    }
50
51    /// Enables the raw mode.
52    //
53    // https://docs.rs/crossterm/latest/crossterm/terminal/fn.enable_raw_mode.html
54    #[inline]
55    pub fn enable_raw_mode(&self) -> Result<(), IoError> {
56        terminal::enable_raw_mode()
57    }
58
59    /// Disables the raw mode.
60    //
61    // https://docs.rs/crossterm/latest/crossterm/terminal/fn.disable_raw_mode.html
62    #[inline]
63    pub fn disable_raw_mode(&self) -> Result<(), IoError> {
64        terminal::disable_raw_mode()
65    }
66
67    /// Switches to the alternate screen.
68    //
69    // https://docs.rs/crossterm/latest/crossterm/terminal/struct.EnterAlternateScreen.html
70    pub fn enter_alternate_screen(&self) -> Result<(), IoError> {
71        Ok(execute!(io::stdout(), terminal::EnterAlternateScreen)?)
72    }
73
74    /// Switches back to the main screen.
75    //
76    // https://docs.rs/crossterm/latest/crossterm/terminal/struct.LeaveAlternateScreen.html
77    pub fn leave_alternate_screen(&self) -> Result<(), IoError> {
78        Ok(execute!(io::stdout(), terminal::EnterAlternateScreen)?)
79    }
80
81    /// Enables receiving mouse events.
82    //
83    // https://docs.rs/crossterm/latest/crossterm/event/struct.EnableMouseCapture.html
84    pub fn enable_mouse(&mut self) -> Result<(), IoError> {
85        Ok(execute!(io::stdout(), event::EnableMouseCapture)?)
86    }
87    /// Disables receiving mouse events.
88    //
89    // https://docs.rs/crossterm/latest/crossterm/event/struct.DisableMouseCapture.html
90    pub fn disable_mouse(&mut self) -> Result<(), IoError> {
91        Ok(execute!(io::stdout(), event::DisableMouseCapture)?)
92    }
93
94    // TODO
95    // /// Enables bracketed paste mode.
96    // //
97    // // https://docs.rs/crossterm/latest/crossterm/event/struct.EnableBracketedPaste.html
98    // pub fn enable_bracketed_paste(&self) -> Result<(), IoError> {
99    //     Ok(execute!(io::stdout(), event::EnableBracketedPaste)?)
100    // }
101    //
102    // /// Disables bracketed paste mode.
103    // //
104    // // https://docs.rs/crossterm/latest/crossterm/event/struct.DisableBracketedPaste.html
105    // pub fn disable_bracketed_paste(&self) -> Result<(), IoError> {
106    //     Ok(execute!(io::stdout(), event::DisableBracketedPaste)?)
107    // }
108
109    /// Enables focus change mode.
110    //
111    // https://docs.rs/crossterm/latest/crossterm/event/struct.EnableFocusChange.html
112    pub fn enable_focus_change(&self) -> Result<(), IoError> {
113        Ok(execute!(io::stdout(), event::EnableFocusChange)?)
114    }
115
116    /// Disables focus change mode.
117    //
118    // https://docs.rs/crossterm/latest/crossterm/event/struct.DisableFocusChange.html
119    pub fn disable_focus_change(&self) -> Result<(), IoError> {
120        Ok(execute!(io::stdout(), event::DisableFocusChange)?)
121    }
122}
123
124impl UiService for CrosstermService {
125    fn capabilities(&self) -> UiCap {
126        let image = Some(UiCapImage {
127            rgb: true,
128            // palette_change: false,
129            // palette_size: ::crossterm::style::available_color_count(),
130            ..Default::default()
131        });
132
133        let input = Some(UiCapInput { keyboard: true, mouse: true, ..Default::default() });
134
135        // let text_grid = Some(UiCapTextGridCap {
136        //     // we don't unknown
137        //     cell_size: None,
138        //     // https://github.com/crossterm-rs/crossterm/issues/166
139        //     // custom_cell_size: false,
140        //     // // https://github.com/crossterm-rs/crossterm/issues/677
141        //     // unicode: true,
142        //     // ..Default::default()
143        // });
144
145        let window = Some(UiCapWindow { multi: false });
146
147        UiCap {
148            image,
149            input,
150            // text_grid,
151            window,
152            ..Default::default()
153        }
154    }
155
156    fn version(&self) -> (u32, u32, u32) {
157        (0, 28, 1)
158    }
159}