Unnamed repository; edit this file 'description' to name the repository.
Restore original terminal background color (#15527)
We were previously emitting OSC111 to reset the terminal background color when restoring. This breaks setups where you customize the terminal background with OSC11 outside of Helix. We can use OSC111 when there is no detected background color or when restoring during a panic, but otherwise we should first query with `OSC 11 ; ? ST` and set that color when restoring.
Michael Davis 3 months ago
parent 59f3231 · commit 253e619
-rw-r--r--Cargo.lock4
-rw-r--r--Cargo.toml2
-rw-r--r--helix-term/src/application.rs2
-rw-r--r--helix-tui/src/backend/termina.rs148
4 files changed, 87 insertions, 69 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d0fdf561..c0fe3d28 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2796,9 +2796,9 @@ dependencies = [
[[package]]
name = "termina"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9747435fb6e4b6db463ce5a7ec39354e60b555a1083211d976421384beb5b8db"
+checksum = "9a49b3d294d994319c4cd8c30f2172aab3217db673bb057912dc383677372830"
dependencies = [
"bitflags",
"futures-core",
diff --git a/Cargo.toml b/Cargo.toml
index b5a2565c..bf546efd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -52,7 +52,7 @@ futures-executor = "0.3"
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
tokio-stream = "0.1.18"
toml = "1.1"
-termina = "0.2"
+termina = "0.3"
sonic-rs = "0.5"
globset = "0.4"
etcetera = "0.11"
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index ed03edfc..c4e0bc3e 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -751,6 +751,8 @@ impl Application {
kind: crossterm::event::KeyEventKind::Release,
..
}) => false,
+ #[cfg(not(windows))]
+ event if event.is_escape() => false,
event => self.compositor.handle_event(&event.into(), &mut cx),
};
diff --git a/helix-tui/src/backend/termina.rs b/helix-tui/src/backend/termina.rs
index 30f67a3e..a5850edd 100644
--- a/helix-tui/src/backend/termina.rs
+++ b/helix-tui/src/backend/termina.rs
@@ -79,64 +79,26 @@ pub struct TerminaBackend {
capabilities: Capabilities,
reset_cursor_command: String,
is_synchronized_output_set: bool,
+ /// The requested terminal background color, set in `Self::set_background_color`.
background_color: Option<RgbColor>,
+ /// The terminal emulator's background color. This is queried when claiming the terminal so
+ /// that custom colors set outside of Helix with OSC11 are restored when Helix exits.
+ original_background_color: Option<RgbColor>,
}
impl TerminaBackend {
pub fn new(config: Config) -> io::Result<Self> {
- let mut terminal = PlatformTerminal::new()?;
- let (capabilities, reset_cursor_command) =
- Self::detect_capabilities(&mut terminal, &config)?;
-
- // In the case of a panic, reset the terminal eagerly. If we didn't do this and instead
- // relied on `Drop`, the backtrace would be lost because it is printed before we would
- // clear and exit the alternate screen.
- let hook_reset_cursor_command = reset_cursor_command.clone();
- terminal.set_panic_hook(move |term| {
- let _ = write!(
- term,
- "{}{}{}{}{}{}{}{}{}{}{}{}",
- Csi::Keyboard(csi::Keyboard::PopFlags(1)),
- decreset!(MouseTracking),
- decreset!(ButtonEventMouse),
- decreset!(AnyEventMouse),
- decreset!(RXVTMouse),
- decreset!(SGRMouse),
- &hook_reset_cursor_command,
- decreset!(BracketedPaste),
- decreset!(FocusTracking),
- Osc::ResetDynamicColor(osc::DynamicColorNumber::TextBackgroundColor),
- Csi::Edit(csi::Edit::EraseInDisplay(csi::EraseInDisplay::EraseDisplay)),
- decreset!(ClearAndEnableAlternateScreen),
- );
- });
-
- Ok(Self {
- terminal,
- config,
- capabilities,
- reset_cursor_command,
- is_synchronized_output_set: false,
- background_color: None,
- })
- }
-
- pub fn terminal(&self) -> &PlatformTerminal {
- &self.terminal
- }
-
- fn detect_capabilities(
- terminal: &mut PlatformTerminal,
- config: &Config,
- ) -> io::Result<(Capabilities, String)> {
use std::time::{Duration, Instant};
+ let mut terminal = PlatformTerminal::new()?;
+
// Colibri "midnight"
const TEST_COLOR: RgbColor = RgbColor::new(59, 34, 76);
terminal.enter_raw_mode()?;
let mut capabilities = Capabilities::default();
+ let mut original_background_color = None;
let start = Instant::now();
// HACK: emitting OSC11 / OSC111 seems to break SGR and cause flickering in tmux.
@@ -158,7 +120,7 @@ impl TerminaBackend {
// If we only receive the device attributes then we know it is not.
write!(
terminal,
- "{}{}{}{}{}{}{}",
+ "{}{}{}{}{}{}{}{}",
// Synchronized output
Csi::Mode(csi::Mode::QueryDecPrivateMode(csi::DecPrivateMode::Code(
csi::DecPrivateModeCode::SynchronizedOutput
@@ -171,6 +133,10 @@ impl TerminaBackend {
Csi::Sgr(csi::Sgr::UnderlineColor(TEST_COLOR.into())),
Dcs::Request(dcs::DcsRequest::GraphicRendition),
Csi::Sgr(csi::Sgr::Reset),
+ Osc::ChangeDynamicColors(
+ osc::DynamicColorNumber::TextBackgroundColor,
+ vec![osc::ColorOrQuery::Query]
+ ),
// Finally request the primary device attributes
Csi::Device(csi::Device::RequestPrimaryDeviceAttributes),
)?;
@@ -199,6 +165,14 @@ impl TerminaBackend {
Event::Csi(Csi::Mode(csi::Mode::ReportTheme(mode))) => {
capabilities.theme_mode = Some(mode.into());
}
+ Event::Osc(Osc::ChangeDynamicColors(
+ osc::DynamicColorNumber::TextBackgroundColor,
+ colors,
+ )) => {
+ if let Some(osc::ColorOrQuery::Color(color)) = colors.first() {
+ original_background_color = Some(*color);
+ }
+ }
Event::Dcs(dcs::Dcs::Response {
value: dcs::DcsResponse::GraphicRendition(sgrs),
..
@@ -250,7 +224,42 @@ impl TerminaBackend {
terminal.enter_cooked_mode()?;
- Ok((capabilities, reset_cursor_command))
+ // In the case of a panic, reset the terminal eagerly. If we didn't do this and instead
+ // relied on `Drop`, the backtrace would be lost because it is printed before we would
+ // clear and exit the alternate screen.
+ let hook_reset_cursor_command = reset_cursor_command.clone();
+ terminal.set_panic_hook(move |term| {
+ let _ = write!(
+ term,
+ "{}{}{}{}{}{}{}{}{}{}{}{}",
+ Csi::Keyboard(csi::Keyboard::PopFlags(1)),
+ decreset!(MouseTracking),
+ decreset!(ButtonEventMouse),
+ decreset!(AnyEventMouse),
+ decreset!(RXVTMouse),
+ decreset!(SGRMouse),
+ &hook_reset_cursor_command,
+ decreset!(BracketedPaste),
+ decreset!(FocusTracking),
+ Osc::ResetDynamicColor(osc::DynamicColorNumber::TextBackgroundColor),
+ Csi::Edit(csi::Edit::EraseInDisplay(csi::EraseInDisplay::EraseDisplay)),
+ decreset!(ClearAndEnableAlternateScreen),
+ );
+ });
+
+ Ok(Self {
+ terminal,
+ config,
+ capabilities,
+ reset_cursor_command,
+ is_synchronized_output_set: false,
+ background_color: None,
+ original_background_color,
+ })
+ }
+
+ pub fn terminal(&self) -> &PlatformTerminal {
+ &self.terminal
}
fn enable_mouse_capture(&mut self) -> io::Result<()> {
@@ -283,6 +292,20 @@ impl TerminaBackend {
Ok(())
}
+ fn reset_background_color(&mut self) -> io::Result<()> {
+ write!(
+ self.terminal,
+ "{}",
+ match self.original_background_color {
+ Some(color) => Osc::ChangeDynamicColors(
+ osc::DynamicColorNumber::TextBackgroundColor,
+ vec![color.into()]
+ ),
+ None => Osc::ResetDynamicColor(osc::DynamicColorNumber::TextBackgroundColor),
+ }
+ )
+ }
+
fn enable_extensions(&mut self) -> io::Result<()> {
const KEYBOARD_FLAGS: csi::KittyKeyboardFlags =
csi::KittyKeyboardFlags::DISAMBIGUATE_ESCAPE_CODES
@@ -440,11 +463,7 @@ impl Backend for TerminaBackend {
decreset!(ClearAndEnableAlternateScreen),
)?;
if self.background_color.is_some() {
- write!(
- self.terminal,
- "{}",
- Osc::ResetDynamicColor(osc::DynamicColorNumber::TextBackgroundColor)
- )?;
+ self.reset_background_color()?;
}
self.terminal.flush()?;
self.terminal.enter_cooked_mode()?;
@@ -606,17 +625,18 @@ impl Backend for TerminaBackend {
Some(Color::Rgb(r, g, b)) => Some(RgbColor::new(r, g, b)),
_ => None,
};
- write!(
- self.terminal,
- "{}",
- match self.background_color {
- Some(color) => Osc::ChangeDynamicColors(
+ if let Some(color) = self.background_color {
+ write!(
+ self.terminal,
+ "{}",
+ Osc::ChangeDynamicColors(
osc::DynamicColorNumber::TextBackgroundColor,
vec![color.into()]
- ),
- _ => Osc::ResetDynamicColor(osc::DynamicColorNumber::TextBackgroundColor),
- }
- )
+ )
+ )
+ } else {
+ self.reset_background_color()
+ }
}
}
@@ -636,11 +656,7 @@ impl Drop for TerminaBackend {
decreset!(ClearAndEnableAlternateScreen),
);
if self.background_color.is_some() {
- let _ = write!(
- self.terminal,
- "{}",
- Osc::ResetDynamicColor(osc::DynamicColorNumber::TextBackgroundColor)
- );
+ let _ = self.reset_background_color();
}
// NOTE: Drop for Platform terminal resets the mode and flushes the buffer when not
// panicking.