aboutsummaryrefslogtreecommitdiff
path: root/helix-tui
diff options
context:
space:
mode:
authorMichael Davis2023-03-05 18:06:12 +0000
committerBlaž Hrastnik2023-03-08 01:49:32 +0000
commit3d850247177f61601296fe5b1cdada8819137783 (patch)
tree6c9639cea8fba74e0d8a61d34a49e5ee19d24cbe /helix-tui
parent48b6aa9a699df0680a6d31e9611ebd1ca9909de4 (diff)
Move terminal claim/restore code to helix-tui
This moves the `Application::claim_term` and `helix-term::application::restore_term` functions into the helix-tui crate. How the terminal should be claimed and restored is a TUI concern and is implemented differently through different TUI backends. This cleans out a lot of crossterm and TUI code in Application and makes it easier to modify claim/restore based on information we query from the terminal host. The child commit will take advantage of this to cache the check for whether the host terminal supports the keyboard enhancement protocol. Without this change, caching that information takes much more code which is not easily reusable for anything else. The code to restore the terminal is somewhat duplicated by this patch: we want to restore the terminal in cases of panics. Panic handler hooks must live for `'static` and the Application's terminal does not.
Diffstat (limited to 'helix-tui')
-rw-r--r--helix-tui/Cargo.toml1
-rw-r--r--helix-tui/src/backend/crossterm.rs70
-rw-r--r--helix-tui/src/backend/mod.rs5
-rw-r--r--helix-tui/src/backend/test.rs13
-rw-r--r--helix-tui/src/terminal.rs22
5 files changed, 109 insertions, 2 deletions
diff --git a/helix-tui/Cargo.toml b/helix-tui/Cargo.toml
index ccd016f5..3ca7e044 100644
--- a/helix-tui/Cargo.toml
+++ b/helix-tui/Cargo.toml
@@ -22,5 +22,6 @@ unicode-segmentation = "1.10"
crossterm = { version = "0.26", optional = true }
termini = "0.1"
serde = { version = "1", "optional" = true, features = ["derive"]}
+log = "~0.4"
helix-view = { version = "0.6", path = "../helix-view", features = ["term"] }
helix-core = { version = "0.6", path = "../helix-core" }
diff --git a/helix-tui/src/backend/crossterm.rs b/helix-tui/src/backend/crossterm.rs
index 5305640c..e81c1e00 100644
--- a/helix-tui/src/backend/crossterm.rs
+++ b/helix-tui/src/backend/crossterm.rs
@@ -1,6 +1,11 @@
-use crate::{backend::Backend, buffer::Cell};
+use crate::{backend::Backend, buffer::Cell, terminal::Config};
use crossterm::{
cursor::{Hide, MoveTo, SetCursorStyle, Show},
+ event::{
+ DisableBracketedPaste, DisableFocusChange, DisableMouseCapture, EnableBracketedPaste,
+ EnableFocusChange, EnableMouseCapture, KeyboardEnhancementFlags,
+ PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags,
+ },
execute, queue,
style::{
Attribute as CAttribute, Color as CColor, Print, SetAttribute, SetBackgroundColor,
@@ -83,6 +88,69 @@ impl<W> Backend for CrosstermBackend<W>
where
W: Write,
{
+ fn claim(&mut self, config: Config) -> io::Result<()> {
+ terminal::enable_raw_mode()?;
+ execute!(
+ self.buffer,
+ terminal::EnterAlternateScreen,
+ EnableBracketedPaste,
+ EnableFocusChange
+ )?;
+ execute!(self.buffer, terminal::Clear(terminal::ClearType::All))?;
+ if config.enable_mouse_capture {
+ execute!(self.buffer, EnableMouseCapture)?;
+ }
+ if matches!(terminal::supports_keyboard_enhancement(), Ok(true)) {
+ log::debug!("The enhanced keyboard protocol is supported on this terminal");
+ execute!(
+ self.buffer,
+ PushKeyboardEnhancementFlags(
+ KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
+ | KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS
+ )
+ )?;
+ } else {
+ log::debug!("The enhanced keyboard protocol is not supported on this terminal");
+ }
+ Ok(())
+ }
+
+ fn restore(&mut self, config: Config) -> io::Result<()> {
+ // reset cursor shape
+ write!(self.buffer, "\x1B[0 q")?;
+ if config.enable_mouse_capture {
+ execute!(self.buffer, DisableMouseCapture)?;
+ }
+ if matches!(terminal::supports_keyboard_enhancement(), Ok(true)) {
+ execute!(self.buffer, PopKeyboardEnhancementFlags)?;
+ }
+ execute!(
+ self.buffer,
+ DisableBracketedPaste,
+ DisableFocusChange,
+ terminal::LeaveAlternateScreen
+ )?;
+ terminal::disable_raw_mode()
+ }
+
+ fn force_restore() -> io::Result<()> {
+ let mut stdout = io::stdout();
+
+ // reset cursor shape
+ write!(stdout, "\x1B[0 q")?;
+ // Ignore errors on disabling, this might trigger on windows if we call
+ // disable without calling enable previously
+ let _ = execute!(stdout, DisableMouseCapture);
+ let _ = execute!(stdout, PopKeyboardEnhancementFlags);
+ execute!(
+ stdout,
+ DisableBracketedPaste,
+ DisableFocusChange,
+ terminal::LeaveAlternateScreen
+ )?;
+ terminal::disable_raw_mode()
+ }
+
fn draw<'a, I>(&mut self, content: I) -> io::Result<()>
where
I: Iterator<Item = (u16, u16, &'a Cell)>,
diff --git a/helix-tui/src/backend/mod.rs b/helix-tui/src/backend/mod.rs
index c6c11019..6d7c3894 100644
--- a/helix-tui/src/backend/mod.rs
+++ b/helix-tui/src/backend/mod.rs
@@ -1,6 +1,6 @@
use std::io;
-use crate::buffer::Cell;
+use crate::{buffer::Cell, terminal::Config};
use helix_view::graphics::{CursorKind, Rect};
@@ -13,6 +13,9 @@ mod test;
pub use self::test::TestBackend;
pub trait Backend {
+ fn claim(&mut self, config: Config) -> Result<(), io::Error>;
+ fn restore(&mut self, config: Config) -> Result<(), io::Error>;
+ fn force_restore() -> Result<(), io::Error>;
fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
where
I: Iterator<Item = (u16, u16, &'a Cell)>;
diff --git a/helix-tui/src/backend/test.rs b/helix-tui/src/backend/test.rs
index 52474148..ff133ff3 100644
--- a/helix-tui/src/backend/test.rs
+++ b/helix-tui/src/backend/test.rs
@@ -1,6 +1,7 @@
use crate::{
backend::Backend,
buffer::{Buffer, Cell},
+ terminal::Config,
};
use helix_core::unicode::width::UnicodeWidthStr;
use helix_view::graphics::{CursorKind, Rect};
@@ -106,6 +107,18 @@ impl TestBackend {
}
impl Backend for TestBackend {
+ fn claim(&mut self, _config: Config) -> Result<(), io::Error> {
+ Ok(())
+ }
+
+ fn restore(&mut self, _config: Config) -> Result<(), io::Error> {
+ Ok(())
+ }
+
+ fn force_restore() -> Result<(), io::Error> {
+ Ok(())
+ }
+
fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
where
I: Iterator<Item = (u16, u16, &'a Cell)>,
diff --git a/helix-tui/src/terminal.rs b/helix-tui/src/terminal.rs
index 22e9232f..802a8c1d 100644
--- a/helix-tui/src/terminal.rs
+++ b/helix-tui/src/terminal.rs
@@ -1,4 +1,5 @@
use crate::{backend::Backend, buffer::Buffer};
+use helix_view::editor::Config as EditorConfig;
use helix_view::graphics::{CursorKind, Rect};
use std::io;
@@ -16,6 +17,19 @@ pub struct Viewport {
resize_behavior: ResizeBehavior,
}
+#[derive(Debug)]
+pub struct Config {
+ pub enable_mouse_capture: bool,
+}
+
+impl From<EditorConfig> for Config {
+ fn from(config: EditorConfig) -> Self {
+ Self {
+ enable_mouse_capture: config.mouse,
+ }
+ }
+}
+
impl Viewport {
/// UNSTABLE
pub fn fixed(area: Rect) -> Viewport {
@@ -98,6 +112,14 @@ where
})
}
+ pub fn claim(&mut self, config: Config) -> io::Result<()> {
+ self.backend.claim(config)
+ }
+
+ pub fn restore(&mut self, config: Config) -> io::Result<()> {
+ self.backend.restore(config)
+ }
+
// /// Get a Frame object which provides a consistent view into the terminal state for rendering.
// pub fn get_frame(&mut self) -> Frame<B> {
// Frame {