Struct ratatui::Terminal

source ·
pub struct Terminal<B>
where B: Backend,
{ /* private fields */ }
Expand description

An interface to interact and draw Frames on the user’s terminal.

This is the main entry point for Ratatui. It is responsible for drawing and maintaining the state of the buffers, cursor and viewport.

The Terminal is generic over a Backend implementation which is used to interface with the underlying terminal library. The Backend trait is implemented for three popular Rust terminal libraries: Crossterm, Termion and Termwiz. See the backend module for more information.

The Terminal struct maintains two buffers: the current and the previous. When the widgets are drawn, the changes are accumulated in the current buffer. At the end of each draw pass, the two buffers are compared, and only the changes between these buffers are written to the terminal, avoiding any redundant operations. After flushing these changes, the buffers are swapped to prepare for the next draw cycle.

The terminal also has a viewport which is the area of the terminal that is currently visible to the user. It can be either fullscreen, inline or fixed. See Viewport for more information.

Applications should detect terminal resizes and call Terminal::draw to redraw the application with the new size. This will automatically resize the internal buffers to match the new size for inline and fullscreen viewports. Fixed viewports are not resized automatically.

§Examples

use std::io::stdout;

use ratatui::{prelude::*, widgets::Paragraph};

let backend = CrosstermBackend::new(stdout());
let mut terminal = Terminal::new(backend)?;
terminal.draw(|frame| {
    let area = frame.size();
    frame.render_widget(Paragraph::new("Hello World!"), area);
    frame.set_cursor(0, 0);
})?;

Implementations§

source§

impl<B> Terminal<B>
where B: Backend,

source

pub fn new(backend: B) -> Result<Terminal<B>>

Creates a new Terminal with the given Backend with a full screen viewport.

§Example
let backend = CrosstermBackend::new(stdout());
let terminal = Terminal::new(backend)?;
Examples found in repository?
examples/canvas.rs (line 202)
199
200
201
202
203
fn init_terminal() -> io::Result<Terminal<CrosstermBackend<Stdout>>> {
    enable_raw_mode()?;
    stdout().execute(EnterAlternateScreen)?;
    Terminal::new(CrosstermBackend::new(stdout()))
}
More examples
Hide additional examples
examples/constraint-explorer.rs (line 638)
634
635
636
637
638
639
640
fn init_terminal() -> Result<Terminal<impl Backend>> {
    enable_raw_mode()?;
    stdout().execute(EnterAlternateScreen)?;
    let backend = CrosstermBackend::new(stdout());
    let terminal = Terminal::new(backend)?;
    Ok(terminal)
}
examples/flex.rs (line 544)
540
541
542
543
544
545
546
fn init_terminal() -> Result<Terminal<impl Backend>> {
    enable_raw_mode()?;
    stdout().execute(EnterAlternateScreen)?;
    let backend = CrosstermBackend::new(stdout());
    let terminal = Terminal::new(backend)?;
    Ok(terminal)
}
examples/gauge.rs (line 232)
228
229
230
231
232
233
234
fn init_terminal() -> color_eyre::Result<Terminal<impl Backend>> {
    enable_raw_mode()?;
    stdout().execute(EnterAlternateScreen)?;
    let backend = CrosstermBackend::new(stdout());
    let terminal = Terminal::new(backend)?;
    Ok(terminal)
}
examples/list.rs (line 93)
89
90
91
92
93
94
95
fn init_terminal() -> color_eyre::Result<Terminal<impl Backend>> {
    enable_raw_mode()?;
    stdout().execute(EnterAlternateScreen)?;
    let backend = CrosstermBackend::new(stdout());
    let terminal = Terminal::new(backend)?;
    Ok(terminal)
}
examples/tabs.rs (line 242)
238
239
240
241
242
243
244
fn init_terminal() -> color_eyre::Result<Terminal<impl Backend>> {
    enable_raw_mode()?;
    stdout().execute(EnterAlternateScreen)?;
    let backend = CrosstermBackend::new(stdout());
    let terminal = Terminal::new(backend)?;
    Ok(terminal)
}
source

pub fn with_options(backend: B, options: TerminalOptions) -> Result<Terminal<B>>

Creates a new Terminal with the given Backend and TerminalOptions.

§Example
let backend = CrosstermBackend::new(stdout());
let viewport = Viewport::Fixed(Rect::new(0, 0, 10, 10));
let terminal = Terminal::with_options(backend, TerminalOptions { viewport })?;
Examples found in repository?
examples/ratatui-logo.rs (line 80)
75
76
77
78
79
80
81
pub fn init() -> io::Result<Terminal<impl Backend>> {
    enable_raw_mode()?;
    let options = TerminalOptions {
        viewport: Viewport::Inline(3),
    };
    Terminal::with_options(CrosstermBackend::new(stdout()), options)
}
More examples
Hide additional examples
examples/demo2/term.rs (line 20)
14
15
16
17
18
19
20
21
22
23
24
25
26
pub fn init() -> Result<Terminal<impl Backend>> {
    // this size is to match the size of the terminal when running the demo
    // using vhs in a 1280x640 sized window (github social preview size)
    let options = TerminalOptions {
        viewport: Viewport::Fixed(Rect::new(0, 0, 81, 18)),
    };
    let terminal = Terminal::with_options(CrosstermBackend::new(io::stdout()), options)?;
    enable_raw_mode().context("enable raw mode")?;
    stdout()
        .execute(EnterAlternateScreen)
        .wrap_err("enter alternate screen")?;
    Ok(terminal)
}
examples/inline.rs (lines 85-90)
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
fn main() -> Result<(), Box<dyn Error>> {
    crossterm::terminal::enable_raw_mode()?;
    let stdout = io::stdout();
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::with_options(
        backend,
        TerminalOptions {
            viewport: Viewport::Inline(8),
        },
    )?;

    let (tx, rx) = mpsc::channel();
    input_handling(tx.clone());
    let workers = workers(tx);
    let mut downloads = downloads();

    for w in &workers {
        let d = downloads.next(w.id).unwrap();
        w.tx.send(d).unwrap();
    }

    run_app(&mut terminal, workers, downloads, rx)?;

    crossterm::terminal::disable_raw_mode()?;
    terminal.clear()?;

    Ok(())
}
source

pub fn get_frame(&mut self) -> Frame<'_>

Get a Frame object which provides a consistent view into the terminal state for rendering.

source

pub fn current_buffer_mut(&mut self) -> &mut Buffer

Gets the current buffer as a mutable reference.

source

pub fn backend(&self) -> &B

Gets the backend

source

pub fn backend_mut(&mut self) -> &mut B

Gets the backend as a mutable reference

Examples found in repository?
examples/block.rs (line 64)
62
63
64
65
66
fn restore_terminal(mut terminal: Terminal) -> Result<()> {
    disable_raw_mode()?;
    execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
    Ok(())
}
More examples
Hide additional examples
examples/hello_world.rs (line 58)
56
57
58
59
60
61
fn restore_terminal(terminal: &mut Terminal<CrosstermBackend<Stdout>>) -> Result<()> {
    disable_raw_mode().context("failed to disable raw mode")?;
    execute!(terminal.backend_mut(), LeaveAlternateScreen)
        .context("unable to switch to main screen")?;
    terminal.show_cursor().context("unable to show cursor")
}
examples/custom_widget.rs (line 151)
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
fn main() -> Result<(), Box<dyn Error>> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // create app and run it
    let res = run_app(&mut terminal);

    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{err:?}");
    }

    Ok(())
}
examples/layout.rs (line 40)
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
fn main() -> Result<(), Box<dyn Error>> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // create app and run it
    let res = run_app(&mut terminal);

    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{err:?}");
    }

    Ok(())
}
examples/popup.rs (line 52)
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
fn main() -> Result<(), Box<dyn Error>> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // create app and run it
    let app = App::new();
    let res = run_app(&mut terminal, app);

    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{err:?}");
    }

    Ok(())
}
examples/table.rs (line 194)
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
fn main() -> Result<(), Box<dyn Error>> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // create app and run it
    let app = App::new();
    let res = run_app(&mut terminal, app);

    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{err:?}");
    }

    Ok(())
}
source

pub fn flush(&mut self) -> Result<()>

Obtains a difference between the previous and the current buffer and passes it to the current backend for drawing.

Examples found in repository?
examples/demo/termwiz.rs (line 21)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
pub fn run(tick_rate: Duration, enhanced_graphics: bool) -> Result<(), Box<dyn Error>> {
    let backend = TermwizBackend::new()?;
    let mut terminal = Terminal::new(backend)?;
    terminal.hide_cursor()?;

    // create app and run it
    let app = App::new("Termwiz Demo", enhanced_graphics);
    let res = run_app(&mut terminal, app, tick_rate);

    terminal.show_cursor()?;
    terminal.flush()?;

    if let Err(err) = res {
        println!("{err:?}");
    }

    Ok(())
}
source

pub fn resize(&mut self, size: Rect) -> Result<()>

Updates the Terminal so that internal buffers match the requested size.

Requested size will be saved so the size can remain consistent when rendering. This leads to a full clear of the screen.

source

pub fn autoresize(&mut self) -> Result<()>

Queries the backend for size and resizes if it doesn’t match the previous size.

Examples found in repository?
examples/inline.rs (line 191)
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
fn run_app<B: Backend>(
    terminal: &mut Terminal<B>,
    workers: Vec<Worker>,
    mut downloads: Downloads,
    rx: mpsc::Receiver<Event>,
) -> Result<(), Box<dyn Error>> {
    let mut redraw = true;
    loop {
        if redraw {
            terminal.draw(|f| ui(f, &downloads))?;
        }
        redraw = true;

        match rx.recv()? {
            Event::Input(event) => {
                if event.code == crossterm::event::KeyCode::Char('q') {
                    break;
                }
            }
            Event::Resize => {
                terminal.autoresize()?;
            }
            Event::Tick => {}
            Event::DownloadUpdate(worker_id, _download_id, progress) => {
                let download = downloads.in_progress.get_mut(&worker_id).unwrap();
                download.progress = progress;
                redraw = false
            }
            Event::DownloadDone(worker_id, download_id) => {
                let download = downloads.in_progress.remove(&worker_id).unwrap();
                terminal.insert_before(1, |buf| {
                    Paragraph::new(Line::from(vec![
                        Span::from("Finished "),
                        Span::styled(
                            format!("download {download_id}"),
                            Style::default().add_modifier(Modifier::BOLD),
                        ),
                        Span::from(format!(
                            " in {}ms",
                            download.started_at.elapsed().as_millis()
                        )),
                    ]))
                    .render(buf.area, buf);
                })?;
                match downloads.next(worker_id) {
                    Some(d) => workers[worker_id].tx.send(d).unwrap(),
                    None => {
                        if downloads.in_progress.is_empty() {
                            terminal.insert_before(1, |buf| {
                                Paragraph::new("Done !").render(buf.area, buf);
                            })?;
                            break;
                        }
                    }
                };
            }
        };
    }
    Ok(())
}
source

pub fn draw<F>(&mut self, f: F) -> Result<CompletedFrame<'_>>
where F: FnOnce(&mut Frame<'_>),

Synchronizes terminal size, calls the rendering closure, flushes the current internal state and prepares for the next draw call.

This is the main entry point for drawing to the terminal.

The changes drawn to the frame are applied only to the current Buffer. After the closure returns, the current buffer is compared to the previous buffer and only the changes are applied to the terminal.

§Examples
let backend = CrosstermBackend::new(stdout());
let mut terminal = Terminal::new(backend)?;
terminal.draw(|frame| {
    let area = frame.size();
    frame.render_widget(Paragraph::new("Hello World!"), area);
    frame.set_cursor(0, 0);
})?;
Examples found in repository?
examples/gauge.rs (line 73)
72
73
74
75
    fn draw(&self, terminal: &mut Terminal<impl Backend>) -> Result<()> {
        terminal.draw(|f| f.render_widget(self, f.size()))?;
        Ok(())
    }
More examples
Hide additional examples
examples/list.rs (line 160)
159
160
161
162
    fn draw(&mut self, terminal: &mut Terminal<impl Backend>) -> io::Result<()> {
        terminal.draw(|f| f.render_widget(self, f.size()))?;
        Ok(())
    }
examples/tabs.rs (line 71)
70
71
72
73
    fn draw(&self, terminal: &mut Terminal<impl Backend>) -> Result<()> {
        terminal.draw(|frame| frame.render_widget(self, frame.size()))?;
        Ok(())
    }
examples/flex.rs (line 173)
172
173
174
175
    fn draw(self, terminal: &mut Terminal<impl Backend>) -> io::Result<()> {
        terminal.draw(|frame| frame.render_widget(self, frame.size()))?;
        Ok(())
    }
examples/constraint-explorer.rs (line 119)
118
119
120
121
    fn draw(&self, terminal: &mut Terminal<impl Backend>) -> io::Result<()> {
        terminal.draw(|frame| frame.render_widget(self, frame.size()))?;
        Ok(())
    }
examples/block.rs (line 70)
68
69
70
71
72
73
74
75
fn run(terminal: &mut Terminal) -> Result<()> {
    loop {
        terminal.draw(ui)?;
        if handle_events()?.is_break() {
            return Ok(());
        }
    }
}
source

pub fn hide_cursor(&mut self) -> Result<()>

Hides the cursor.

Examples found in repository?
examples/colors_rgb.rs (line 279)
274
275
276
277
278
279
280
281
fn init_terminal() -> Result<Terminal<impl Backend>> {
    enable_raw_mode()?;
    stdout().execute(EnterAlternateScreen)?;
    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
    terminal.clear()?;
    terminal.hide_cursor()?;
    Ok(terminal)
}
More examples
Hide additional examples
examples/panic.rs (line 83)
76
77
78
79
80
81
82
83
84
85
86
fn init_terminal() -> Result<Terminal<CrosstermBackend<io::Stdout>>> {
    crossterm::execute!(io::stdout(), EnterAlternateScreen)?;
    enable_raw_mode()?;

    let backend = CrosstermBackend::new(io::stdout());

    let mut terminal = Terminal::new(backend)?;
    terminal.hide_cursor()?;

    Ok(terminal)
}
examples/demo/termwiz.rs (line 14)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
pub fn run(tick_rate: Duration, enhanced_graphics: bool) -> Result<(), Box<dyn Error>> {
    let backend = TermwizBackend::new()?;
    let mut terminal = Terminal::new(backend)?;
    terminal.hide_cursor()?;

    // create app and run it
    let app = App::new("Termwiz Demo", enhanced_graphics);
    let res = run_app(&mut terminal, app, tick_rate);

    terminal.show_cursor()?;
    terminal.flush()?;

    if let Err(err) = res {
        println!("{err:?}");
    }

    Ok(())
}
source

pub fn show_cursor(&mut self) -> Result<()>

Shows the cursor.

Examples found in repository?
examples/hello_world.rs (line 60)
56
57
58
59
60
61
fn restore_terminal(terminal: &mut Terminal<CrosstermBackend<Stdout>>) -> Result<()> {
    disable_raw_mode().context("failed to disable raw mode")?;
    execute!(terminal.backend_mut(), LeaveAlternateScreen)
        .context("unable to switch to main screen")?;
    terminal.show_cursor().context("unable to show cursor")
}
More examples
Hide additional examples
examples/demo/termwiz.rs (line 20)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
pub fn run(tick_rate: Duration, enhanced_graphics: bool) -> Result<(), Box<dyn Error>> {
    let backend = TermwizBackend::new()?;
    let mut terminal = Terminal::new(backend)?;
    terminal.hide_cursor()?;

    // create app and run it
    let app = App::new("Termwiz Demo", enhanced_graphics);
    let res = run_app(&mut terminal, app, tick_rate);

    terminal.show_cursor()?;
    terminal.flush()?;

    if let Err(err) = res {
        println!("{err:?}");
    }

    Ok(())
}
examples/custom_widget.rs (line 155)
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
fn main() -> Result<(), Box<dyn Error>> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // create app and run it
    let res = run_app(&mut terminal);

    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{err:?}");
    }

    Ok(())
}
examples/layout.rs (line 44)
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
fn main() -> Result<(), Box<dyn Error>> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // create app and run it
    let res = run_app(&mut terminal);

    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{err:?}");
    }

    Ok(())
}
examples/popup.rs (line 56)
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
fn main() -> Result<(), Box<dyn Error>> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // create app and run it
    let app = App::new();
    let res = run_app(&mut terminal, app);

    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{err:?}");
    }

    Ok(())
}
examples/table.rs (line 198)
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
fn main() -> Result<(), Box<dyn Error>> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // create app and run it
    let app = App::new();
    let res = run_app(&mut terminal, app);

    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{err:?}");
    }

    Ok(())
}
source

pub fn get_cursor(&mut self) -> Result<(u16, u16)>

Gets the current cursor position.

This is the position of the cursor after the last draw call and is returned as a tuple of (x, y) coordinates.

source

pub fn set_cursor(&mut self, x: u16, y: u16) -> Result<()>

Sets the cursor position.

source

pub fn clear(&mut self) -> Result<()>

Clear the terminal and force a full redraw on the next draw call.

Examples found in repository?
examples/colors_rgb.rs (line 278)
274
275
276
277
278
279
280
281
fn init_terminal() -> Result<Terminal<impl Backend>> {
    enable_raw_mode()?;
    stdout().execute(EnterAlternateScreen)?;
    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
    terminal.clear()?;
    terminal.hide_cursor()?;
    Ok(terminal)
}
More examples
Hide additional examples
examples/inline.rs (line 105)
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
fn main() -> Result<(), Box<dyn Error>> {
    crossterm::terminal::enable_raw_mode()?;
    let stdout = io::stdout();
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::with_options(
        backend,
        TerminalOptions {
            viewport: Viewport::Inline(8),
        },
    )?;

    let (tx, rx) = mpsc::channel();
    input_handling(tx.clone());
    let workers = workers(tx);
    let mut downloads = downloads();

    for w in &workers {
        let d = downloads.next(w.id).unwrap();
        w.tx.send(d).unwrap();
    }

    run_app(&mut terminal, workers, downloads, rx)?;

    crossterm::terminal::disable_raw_mode()?;
    terminal.clear()?;

    Ok(())
}
source

pub fn swap_buffers(&mut self)

Clears the inactive buffer and swaps it with the current buffer

source

pub fn size(&self) -> Result<Rect>

Queries the real size of the backend.

Examples found in repository?
examples/gauge.rs (line 67)
63
64
65
66
67
68
69
70
    fn run(&mut self, mut terminal: Terminal<impl Backend>) -> Result<()> {
        while self.state != AppState::Quitting {
            self.draw(&mut terminal)?;
            self.handle_events()?;
            self.update(terminal.size()?.width);
        }
        Ok(())
    }
source

pub fn insert_before<F>(&mut self, height: u16, draw_fn: F) -> Result<()>
where F: FnOnce(&mut Buffer),

Insert some content before the current inline viewport. This has no effect when the viewport is fullscreen.

This function scrolls down the current viewport by the given height. The newly freed space is then made available to the draw_fn closure through a writable Buffer.

Before:

+-------------------+
|                   |
|      viewport     |
|                   |
+-------------------+

After:

+-------------------+
|      buffer       |
+-------------------+
+-------------------+
|                   |
|      viewport     |
|                   |
+-------------------+
§Examples
§Insert a single line before the current viewport
terminal.insert_before(1, |buf| {
    Paragraph::new(Line::from(vec![
        Span::raw("This line will be added "),
        Span::styled("before", Style::default().fg(Color::Blue)),
        Span::raw(" the current viewport"),
    ]))
    .render(buf.area, buf);
});
Examples found in repository?
examples/inline.rs (lines 201-214)
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
fn run_app<B: Backend>(
    terminal: &mut Terminal<B>,
    workers: Vec<Worker>,
    mut downloads: Downloads,
    rx: mpsc::Receiver<Event>,
) -> Result<(), Box<dyn Error>> {
    let mut redraw = true;
    loop {
        if redraw {
            terminal.draw(|f| ui(f, &downloads))?;
        }
        redraw = true;

        match rx.recv()? {
            Event::Input(event) => {
                if event.code == crossterm::event::KeyCode::Char('q') {
                    break;
                }
            }
            Event::Resize => {
                terminal.autoresize()?;
            }
            Event::Tick => {}
            Event::DownloadUpdate(worker_id, _download_id, progress) => {
                let download = downloads.in_progress.get_mut(&worker_id).unwrap();
                download.progress = progress;
                redraw = false
            }
            Event::DownloadDone(worker_id, download_id) => {
                let download = downloads.in_progress.remove(&worker_id).unwrap();
                terminal.insert_before(1, |buf| {
                    Paragraph::new(Line::from(vec![
                        Span::from("Finished "),
                        Span::styled(
                            format!("download {download_id}"),
                            Style::default().add_modifier(Modifier::BOLD),
                        ),
                        Span::from(format!(
                            " in {}ms",
                            download.started_at.elapsed().as_millis()
                        )),
                    ]))
                    .render(buf.area, buf);
                })?;
                match downloads.next(worker_id) {
                    Some(d) => workers[worker_id].tx.send(d).unwrap(),
                    None => {
                        if downloads.in_progress.is_empty() {
                            terminal.insert_before(1, |buf| {
                                Paragraph::new("Done !").render(buf.area, buf);
                            })?;
                            break;
                        }
                    }
                };
            }
        };
    }
    Ok(())
}

Trait Implementations§

source§

impl<B> Clone for Terminal<B>
where B: Backend + Clone,

source§

fn clone(&self) -> Terminal<B>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<B> Debug for Terminal<B>
where B: Backend + Debug,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<B> Default for Terminal<B>
where B: Backend + Default,

source§

fn default() -> Terminal<B>

Returns the “default value” for a type. Read more
source§

impl<B> Drop for Terminal<B>
where B: Backend,

source§

fn drop(&mut self)

Executes the destructor for this type. Read more
source§

impl<B> Hash for Terminal<B>
where B: Backend + Hash,

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl<B> PartialEq for Terminal<B>
where B: Backend + PartialEq,

source§

fn eq(&self, other: &Terminal<B>) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl<B> Eq for Terminal<B>
where B: Backend + Eq,

source§

impl<B> StructuralPartialEq for Terminal<B>
where B: Backend,

Auto Trait Implementations§

§

impl<B> RefUnwindSafe for Terminal<B>
where B: RefUnwindSafe,

§

impl<B> Send for Terminal<B>
where B: Send,

§

impl<B> Sync for Terminal<B>
where B: Sync,

§

impl<B> Unpin for Terminal<B>
where B: Unpin,

§

impl<B> UnwindSafe for Terminal<B>
where B: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.