From bba51c3ae6df6fc03b41fa95f85a38bf059cc19f Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 15 Aug 2022 18:05:07 -0700 Subject: [PATCH] Added cursor blink and settings --- assets/settings/default.json | 13 +++++++ crates/settings/src/settings.rs | 16 ++++++++ crates/terminal/src/connected_el.rs | 56 ++++++++++++++++++++------- crates/terminal/src/connected_view.rs | 14 +++++-- crates/terminal/src/terminal.rs | 22 ++++++++--- crates/terminal/src/terminal_view.rs | 9 ++++- 6 files changed, 104 insertions(+), 26 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 43b4be512f..c6f08f4e56 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -102,6 +102,19 @@ // // "working_directory": "current_project_directory", + //Set the cursor blinking behavior in the terminal. + //May take 4 values: + // 1. Never blink the cursor, ignoring the terminal mode + // "blinking": "never", + // 2. Default the cursor blink to off, but allow the terminal to + // turn blinking on + // "blinking": "off", + // 3. Default the cursor blink to on, but allow the terminal to + // turn blinking off + // "blinking": "on", + // 4. Always blink the cursor, ignoring the terminal mode + // "blinking": "always", + "blinking": "on", //Any key-value pairs added to this list will be added to the terminal's //enviroment. Use `:` to seperate multiple values. "env": { diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index ce1fa09d99..9c1a17a462 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -83,6 +83,22 @@ pub struct TerminalSettings { pub font_size: Option, pub font_family: Option, pub env: Option>, + pub blinking: Option, +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum TerminalBlink { + Never, + On, + Off, + Always, +} + +impl Default for TerminalBlink { + fn default() -> Self { + TerminalBlink::On + } } #[derive(Clone, Debug, Deserialize, PartialEq, Eq, JsonSchema)] diff --git a/crates/terminal/src/connected_el.rs b/crates/terminal/src/connected_el.rs index 392783f02d..eb9eb32b81 100644 --- a/crates/terminal/src/connected_el.rs +++ b/crates/terminal/src/connected_el.rs @@ -21,7 +21,7 @@ use gpui::{ }; use itertools::Itertools; use ordered_float::OrderedFloat; -use settings::Settings; +use settings::{Settings, TerminalBlink}; use theme::TerminalStyle; use util::ResultExt; @@ -201,6 +201,7 @@ pub struct TerminalEl { view: WeakViewHandle, modal: bool, focused: bool, + blink_state: bool, } impl TerminalEl { @@ -209,12 +210,14 @@ impl TerminalEl { terminal: WeakModelHandle, modal: bool, focused: bool, + blink_state: bool, ) -> TerminalEl { TerminalEl { view, terminal, modal, focused, + blink_state, } } @@ -568,6 +571,33 @@ impl TerminalEl { (point, side) } + + pub fn should_show_cursor( + settings: Option, + blinking_on: bool, + focused: bool, + blink_show: bool, + ) -> bool { + if !focused { + true + } else { + match settings { + Some(setting) => match setting { + TerminalBlink::Never => true, + TerminalBlink::On | TerminalBlink::Off if blinking_on => blink_show, + TerminalBlink::On | TerminalBlink::Off /*if !blinking_on */ => true, + TerminalBlink::Always => focused && blink_show, + }, + None => { + if blinking_on { + blink_show + } else { + false + } + } + } + } + } } impl Element for TerminalEl { @@ -580,6 +610,7 @@ impl Element for TerminalEl { cx: &mut gpui::LayoutContext, ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { let settings = cx.global::(); + let blink_settings = settings.terminal_overrides.blinking.clone(); let font_cache = cx.font_cache(); //Setup layout information @@ -598,13 +629,13 @@ impl Element for TerminalEl { terminal_theme.colors.background }; - let (cells, selection, cursor, display_offset, cursor_text) = self + let (cells, selection, cursor, display_offset, cursor_text, blink_mode) = self .terminal .upgrade(cx) .unwrap() .update(cx.app, |terminal, mcx| { terminal.set_size(dimensions); - terminal.render_lock(mcx, |content, cursor_text| { + terminal.render_lock(mcx, |content, cursor_text, style| { let mut cells = vec![]; cells.extend( content @@ -628,6 +659,7 @@ impl Element for TerminalEl { content.cursor, content.display_offset, cursor_text, + style, ) }) }); @@ -643,19 +675,13 @@ impl Element for TerminalEl { ); //Layout cursor - //TODO: This logic can be a lot better - let show_cursor = if let Some(view_handle) = self.view.upgrade(cx) { - if view_handle.read(cx).show_cursor() { - false - } else { - true - } - } else { - true - }; - let cursor = { - if show_cursor { + if !TerminalEl::should_show_cursor( + blink_settings, + blink_mode, + self.focused, + self.blink_state, + ) { None } else { let cursor_point = DisplayCursor::from(cursor.point, display_offset); diff --git a/crates/terminal/src/connected_view.rs b/crates/terminal/src/connected_view.rs index 924dece2c2..6f16ac9bcd 100644 --- a/crates/terminal/src/connected_view.rs +++ b/crates/terminal/src/connected_view.rs @@ -132,7 +132,7 @@ impl ConnectedView { } //Following code copied from editor cursor - pub fn show_cursor(&self) -> bool { + pub fn blink_show(&self) -> bool { self.blinking_paused || self.show_cursor } @@ -253,9 +253,15 @@ impl View for ConnectedView { Stack::new() .with_child( - TerminalEl::new(cx.handle(), terminal_handle, self.modal, focused) - .contained() - .boxed(), + TerminalEl::new( + cx.handle(), + terminal_handle, + self.modal, + focused, + self.blink_show(), + ) + .contained() + .boxed(), ) .with_child(ChildView::new(&self.context_menu).boxed()) .boxed() diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 0c1d29a248..0debf4fa91 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -25,7 +25,7 @@ use futures::{ }; use modal::deploy_modal; -use settings::{Settings, Shell}; +use settings::{Settings, Shell, TerminalBlink}; use std::{collections::HashMap, fmt::Display, path::PathBuf, sync::Arc, time::Duration}; use thiserror::Error; @@ -254,6 +254,7 @@ impl TerminalBuilder { shell: Option, env: Option>, initial_size: TerminalSize, + blink_settings: Option, ) -> Result { let pty_config = { let alac_shell = shell.clone().and_then(|shell| match shell { @@ -290,7 +291,18 @@ impl TerminalBuilder { //TODO: Remove with a bounded sender which can be dispatched on &self let (events_tx, events_rx) = unbounded(); //Set up the terminal... - let term = Term::new(&config, &initial_size, ZedListener(events_tx.clone())); + let mut term = Term::new(&config, &initial_size, ZedListener(events_tx.clone())); + + //Start off blinking if we need to + match blink_settings { + Some(setting) => match setting { + TerminalBlink::On | TerminalBlink::Always => { + term.set_mode(alacritty_terminal::ansi::Mode::BlinkingCursor) + } + _ => {} + }, + None => term.set_mode(alacritty_terminal::ansi::Mode::BlinkingCursor), + } let term = Arc::new(FairMutex::new(term)); //Setup the pty... @@ -322,7 +334,7 @@ impl TerminalBuilder { //And connect them together let event_loop = EventLoop::new( term.clone(), - ZedListener(events_tx), + ZedListener(events_tx.clone()), pty, pty_config.hold, false, @@ -583,7 +595,7 @@ impl Terminal { pub fn render_lock(&mut self, cx: &mut ModelContext, f: F) -> T where - F: FnOnce(RenderableContent, char) -> T, + F: FnOnce(RenderableContent, char, bool) -> T, { let m = self.term.clone(); //Arc clone let mut term = m.lock(); @@ -599,7 +611,7 @@ impl Terminal { let cursor_text = term.grid()[content.cursor.point].c; - f(content, cursor_text) + f(content, cursor_text, term.cursor_style().blinking) } ///Scroll the terminal diff --git a/crates/terminal/src/terminal_view.rs b/crates/terminal/src/terminal_view.rs index ed63217178..a997ebf631 100644 --- a/crates/terminal/src/terminal_view.rs +++ b/crates/terminal/src/terminal_view.rs @@ -94,8 +94,13 @@ impl TerminalView { let shell = settings.terminal_overrides.shell.clone(); let envs = settings.terminal_overrides.env.clone(); //Should be short and cheap. - let content = match TerminalBuilder::new(working_directory.clone(), shell, envs, size_info) - { + let content = match TerminalBuilder::new( + working_directory.clone(), + shell, + envs, + size_info, + settings.terminal_overrides.blinking.clone(), + ) { Ok(terminal) => { let terminal = cx.add_model(|cx| terminal.subscribe(cx)); let view = cx.add_view(|cx| ConnectedView::from_terminal(terminal, modal, cx));