1use crate::{backend::Backend, buffer::Buffer};
2use helix_view::graphics::{CursorKind, Rect};
5#[derive(Debug, Clone, PartialEq)]
12#[derive(Debug, Clone, PartialEq)]
16 resize_behavior: ResizeBehavior,
21 pub fn fixed(area: Rect) -> Viewport {
24 resize_behavior: ResizeBehavior::Fixed,
29#[derive(Debug, Clone, PartialEq)]
30/// Options to pass to [`Terminal::with_options`]
31pub struct TerminalOptions {
32 /// Viewport used to draw to the terminal
33 pub viewport: Viewport,
36/// Interface to the terminal backed by Termion
43 /// Holds the results of the current and previous draw calls. The two are compared at the end
44 /// of each draw pass to output the necessary updates to the terminal
46 /// Index of the current buffer in the previous array
48 /// Kind of cursor (hidden or others)
49 cursor_kind: CursorKind,
54impl<B> Drop for Terminal<B>
59 // Attempt to restore the cursor state
60 if self.cursor_kind == CursorKind::Hidden {
61 if let Err(err) = self.show_cursor(CursorKind::Block) {
62 eprintln!("Failed to show the cursor: {}", err);
72 /// Wrapper around Terminal initialization. Each buffer is initialized with a blank string and
73 /// default colors for the foreground and the background
74 pub fn new(backend: B) -> io::Result<Terminal<B>> {
75 let size = backend.size()?;
76 Terminal::with_options(
81 resize_behavior: ResizeBehavior::Auto,
88 pub fn with_options(backend: B, options: TerminalOptions) -> io::Result<Terminal<B>> {
92 Buffer::empty(options.viewport.area),
93 Buffer::empty(options.viewport.area),
96 cursor_kind: CursorKind::Block,
97 viewport: options.viewport,
101 // /// Get a Frame object which provides a consistent view into the terminal state for rendering.
102 // pub fn get_frame(&mut self) -> Frame<B> {
105 // cursor_position: None,
109 pub fn current_buffer_mut(&mut self) -> &mut Buffer {
110 &mut self.buffers[self.current]
113 pub fn backend(&self) -> &B {
117 pub fn backend_mut(&mut self) -> &mut B {
121 /// Obtains a difference between the previous and the current buffer and passes it to the
122 /// current backend for drawing.
123 pub fn flush(&mut self) -> io::Result<()> {
124 let previous_buffer = &self.buffers[1 - self.current];
125 let current_buffer = &self.buffers[self.current];
126 let updates = previous_buffer.diff(current_buffer);
127 self.backend.draw(updates.into_iter())
130 /// Updates the Terminal so that internal buffers match the requested size. Requested size will
131 /// be saved so the size can remain consistent when rendering.
132 /// This leads to a full clear of the screen.
133 pub fn resize(&mut self, area: Rect) -> io::Result<()> {
134 self.buffers[self.current].resize(area);
135 self.buffers[1 - self.current].resize(area);
136 self.viewport.area = area;
140 /// Queries the backend for size and resizes if it doesn't match the previous size.
141 pub fn autoresize(&mut self) -> io::Result<Rect> {
142 let size = self.size()?;
143 if size != self.viewport.area {
149 /// Synchronizes terminal size, calls the rendering closure, flushes the current internal state
150 /// and prepares for the next draw call.
153 cursor_position: Option<(u16, u16)>,
154 cursor_kind: CursorKind,
155 ) -> io::Result<()> {
156 // // Autoresize - otherwise we get glitches if shrinking or potential desync between widgets
157 // // and the terminal (if growing), which may OOB.
158 // self.autoresize()?;
160 // let mut frame = self.get_frame();
162 // // We can't change the cursor position right away because we have to flush the frame to
163 // // stdout first. But we also can't keep the frame around, since it holds a &mut to
164 // // Terminal. Thus, we're taking the important data out of the Frame and dropping it.
165 // let cursor_position = frame.cursor_position;
170 if let Some((x, y)) = cursor_position {
171 self.set_cursor(x, y)?;
175 CursorKind::Hidden => self.hide_cursor()?,
176 kind => self.show_cursor(kind)?,
180 self.buffers[1 - self.current].reset();
181 self.current = 1 - self.current;
184 self.backend.flush()?;
189 pub fn cursor_kind(&self) -> CursorKind {
193 pub fn hide_cursor(&mut self) -> io::Result<()> {
194 self.backend.hide_cursor()?;
195 self.cursor_kind = CursorKind::Hidden;
199 pub fn show_cursor(&mut self, kind: CursorKind) -> io::Result<()> {
200 self.backend.show_cursor(kind)?;
201 self.cursor_kind = kind;
205 pub fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
206 self.backend.get_cursor()
209 pub fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
210 self.backend.set_cursor(x, y)
213 /// Clear the terminal and force a full redraw on the next draw call.
214 pub fn clear(&mut self) -> io::Result<()> {
215 self.backend.clear()?;
216 // Reset the back buffer to make sure the next update will redraw everything.
217 self.buffers[1 - self.current].reset();
221 /// Queries the real size of the backend.
222 pub fn size(&self) -> io::Result<Rect> {
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list