terminal: Make CursorShape configurable (#18530)
This builds on top of @Yevgen's #15840 and combines it with the settings names introduced in #17572. Closes #4731. Release Notes: - Added a setting for the terminal's default cursor shape. The setting is `{"terminal": {"cursor_shape": "block"}}``. Possible values: `block`, `bar`, `hollow`, `underline`. Demo: https://github.com/user-attachments/assets/96ed28c2-c222-436b-80cb-7cd63eeb47dd
This commit is contained in:
parent
57ad5778fa
commit
533416c5a9
5 changed files with 88 additions and 4 deletions
|
@ -671,6 +671,18 @@
|
||||||
// 3. Always blink the cursor, ignoring the terminal mode
|
// 3. Always blink the cursor, ignoring the terminal mode
|
||||||
// "blinking": "on",
|
// "blinking": "on",
|
||||||
"blinking": "terminal_controlled",
|
"blinking": "terminal_controlled",
|
||||||
|
// Default cursor shape for the terminal.
|
||||||
|
// 1. A block that surrounds the following character
|
||||||
|
// "block"
|
||||||
|
// 2. A vertical bar
|
||||||
|
// "bar"
|
||||||
|
// 3. An underline that runs along the following character
|
||||||
|
// "underscore"
|
||||||
|
// 4. A box drawn around the following character
|
||||||
|
// "hollow"
|
||||||
|
//
|
||||||
|
// Default: not set, defaults to "block"
|
||||||
|
"cursor_shape": null,
|
||||||
// Set whether Alternate Scroll mode (code: ?1007) is active by default.
|
// Set whether Alternate Scroll mode (code: ?1007) is active by default.
|
||||||
// Alternate Scroll mode converts mouse scroll events into up / down key
|
// Alternate Scroll mode converts mouse scroll events into up / down key
|
||||||
// presses when in the alternate screen (e.g. when running applications
|
// presses when in the alternate screen (e.g. when running applications
|
||||||
|
|
|
@ -216,6 +216,7 @@ impl Project {
|
||||||
shell,
|
shell,
|
||||||
env,
|
env,
|
||||||
Some(settings.blinking),
|
Some(settings.blinking),
|
||||||
|
settings.cursor_shape.unwrap_or_default(),
|
||||||
settings.alternate_scroll,
|
settings.alternate_scroll,
|
||||||
settings.max_scroll_history_lines,
|
settings.max_scroll_history_lines,
|
||||||
window,
|
window,
|
||||||
|
|
|
@ -18,7 +18,9 @@ use alacritty_terminal::{
|
||||||
Config, RenderableCursor, TermMode,
|
Config, RenderableCursor, TermMode,
|
||||||
},
|
},
|
||||||
tty::{self},
|
tty::{self},
|
||||||
vte::ansi::{ClearMode, Handler, NamedPrivateMode, PrivateMode},
|
vte::ansi::{
|
||||||
|
ClearMode, CursorStyle as AlacCursorStyle, Handler, NamedPrivateMode, PrivateMode,
|
||||||
|
},
|
||||||
Term,
|
Term,
|
||||||
};
|
};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
@ -40,7 +42,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use smol::channel::{Receiver, Sender};
|
use smol::channel::{Receiver, Sender};
|
||||||
use task::{HideStrategy, Shell, TaskId};
|
use task::{HideStrategy, Shell, TaskId};
|
||||||
use terminal_settings::{AlternateScroll, TerminalBlink, TerminalSettings};
|
use terminal_settings::{AlternateScroll, CursorShape, TerminalBlink, TerminalSettings};
|
||||||
use theme::{ActiveTheme, Theme};
|
use theme::{ActiveTheme, Theme};
|
||||||
use util::truncate_and_trailoff;
|
use util::truncate_and_trailoff;
|
||||||
|
|
||||||
|
@ -314,6 +316,7 @@ impl TerminalBuilder {
|
||||||
shell: Shell,
|
shell: Shell,
|
||||||
mut env: HashMap<String, String>,
|
mut env: HashMap<String, String>,
|
||||||
blink_settings: Option<TerminalBlink>,
|
blink_settings: Option<TerminalBlink>,
|
||||||
|
cursor_shape: CursorShape,
|
||||||
alternate_scroll: AlternateScroll,
|
alternate_scroll: AlternateScroll,
|
||||||
max_scroll_history_lines: Option<usize>,
|
max_scroll_history_lines: Option<usize>,
|
||||||
window: AnyWindowHandle,
|
window: AnyWindowHandle,
|
||||||
|
@ -353,6 +356,7 @@ impl TerminalBuilder {
|
||||||
// Setup Alacritty's env, which modifies the current process's environment
|
// Setup Alacritty's env, which modifies the current process's environment
|
||||||
alacritty_terminal::tty::setup_env();
|
alacritty_terminal::tty::setup_env();
|
||||||
|
|
||||||
|
let default_cursor_style = AlacCursorStyle::from(cursor_shape);
|
||||||
let scrolling_history = if task.is_some() {
|
let scrolling_history = if task.is_some() {
|
||||||
// Tasks like `cargo build --all` may produce a lot of output, ergo allow maximum scrolling.
|
// Tasks like `cargo build --all` may produce a lot of output, ergo allow maximum scrolling.
|
||||||
// After the task finishes, we do not allow appending to that terminal, so small tasks output should not
|
// After the task finishes, we do not allow appending to that terminal, so small tasks output should not
|
||||||
|
@ -365,6 +369,7 @@ impl TerminalBuilder {
|
||||||
};
|
};
|
||||||
let config = Config {
|
let config = Config {
|
||||||
scrolling_history,
|
scrolling_history,
|
||||||
|
default_cursor_style,
|
||||||
..Config::default()
|
..Config::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -951,6 +956,10 @@ impl Terminal {
|
||||||
&self.last_content
|
&self.last_content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape) {
|
||||||
|
self.term.lock().set_cursor_style(Some(cursor_shape.into()));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn total_lines(&self) -> usize {
|
pub fn total_lines(&self) -> usize {
|
||||||
let term = self.term.clone();
|
let term = self.term.clone();
|
||||||
let terminal = term.lock_unfair();
|
let terminal = term.lock_unfair();
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use alacritty_terminal::vte::ansi::{
|
||||||
|
CursorShape as AlacCursorShape, CursorStyle as AlacCursorStyle,
|
||||||
|
};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
px, AbsoluteLength, AppContext, FontFallbacks, FontFeatures, FontWeight, Pixels, SharedString,
|
px, AbsoluteLength, AppContext, FontFallbacks, FontFeatures, FontWeight, Pixels, SharedString,
|
||||||
|
@ -32,6 +35,7 @@ pub struct TerminalSettings {
|
||||||
pub font_weight: Option<FontWeight>,
|
pub font_weight: Option<FontWeight>,
|
||||||
pub line_height: TerminalLineHeight,
|
pub line_height: TerminalLineHeight,
|
||||||
pub env: HashMap<String, String>,
|
pub env: HashMap<String, String>,
|
||||||
|
pub cursor_shape: Option<CursorShape>,
|
||||||
pub blinking: TerminalBlink,
|
pub blinking: TerminalBlink,
|
||||||
pub alternate_scroll: AlternateScroll,
|
pub alternate_scroll: AlternateScroll,
|
||||||
pub option_as_meta: bool,
|
pub option_as_meta: bool,
|
||||||
|
@ -129,6 +133,11 @@ pub struct TerminalSettingsContent {
|
||||||
///
|
///
|
||||||
/// Default: {}
|
/// Default: {}
|
||||||
pub env: Option<HashMap<String, String>>,
|
pub env: Option<HashMap<String, String>>,
|
||||||
|
/// Default cursor shape for the terminal.
|
||||||
|
/// Can be "bar", "block", "underscore", or "hollow".
|
||||||
|
///
|
||||||
|
/// Default: None
|
||||||
|
pub cursor_shape: Option<CursorShape>,
|
||||||
/// Sets the cursor blinking behavior in the terminal.
|
/// Sets the cursor blinking behavior in the terminal.
|
||||||
///
|
///
|
||||||
/// Default: terminal_controlled
|
/// Default: terminal_controlled
|
||||||
|
@ -282,3 +291,37 @@ pub struct ToolbarContent {
|
||||||
/// Default: true
|
/// Default: true
|
||||||
pub title: Option<bool>,
|
pub title: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum CursorShape {
|
||||||
|
/// Cursor is a block like `█`.
|
||||||
|
#[default]
|
||||||
|
Block,
|
||||||
|
/// Cursor is an underscore like `_`.
|
||||||
|
Underline,
|
||||||
|
/// Cursor is a vertical bar like `⎸`.
|
||||||
|
Bar,
|
||||||
|
/// Cursor is a hollow box like `▯`.
|
||||||
|
Hollow,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CursorShape> for AlacCursorShape {
|
||||||
|
fn from(value: CursorShape) -> Self {
|
||||||
|
match value {
|
||||||
|
CursorShape::Block => AlacCursorShape::Block,
|
||||||
|
CursorShape::Underline => AlacCursorShape::Underline,
|
||||||
|
CursorShape::Bar => AlacCursorShape::Beam,
|
||||||
|
CursorShape::Hollow => AlacCursorShape::HollowBlock,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CursorShape> for AlacCursorStyle {
|
||||||
|
fn from(value: CursorShape) -> Self {
|
||||||
|
AlacCursorStyle {
|
||||||
|
shape: value.into(),
|
||||||
|
blinking: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ use terminal::{
|
||||||
index::Point,
|
index::Point,
|
||||||
term::{search::RegexSearch, TermMode},
|
term::{search::RegexSearch, TermMode},
|
||||||
},
|
},
|
||||||
terminal_settings::{TerminalBlink, TerminalSettings, WorkingDirectory},
|
terminal_settings::{CursorShape, TerminalBlink, TerminalSettings, WorkingDirectory},
|
||||||
Clear, Copy, Event, MaybeNavigationTarget, Paste, ScrollLineDown, ScrollLineUp, ScrollPageDown,
|
Clear, Copy, Event, MaybeNavigationTarget, Paste, ScrollLineDown, ScrollLineUp, ScrollPageDown,
|
||||||
ScrollPageUp, ScrollToBottom, ScrollToTop, ShowCharacterPalette, TaskStatus, Terminal,
|
ScrollPageUp, ScrollToBottom, ScrollToTop, ShowCharacterPalette, TaskStatus, Terminal,
|
||||||
TerminalSize,
|
TerminalSize,
|
||||||
|
@ -102,6 +102,7 @@ pub struct TerminalView {
|
||||||
//Currently using iTerm bell, show bell emoji in tab until input is received
|
//Currently using iTerm bell, show bell emoji in tab until input is received
|
||||||
has_bell: bool,
|
has_bell: bool,
|
||||||
context_menu: Option<(View<ContextMenu>, gpui::Point<Pixels>, Subscription)>,
|
context_menu: Option<(View<ContextMenu>, gpui::Point<Pixels>, Subscription)>,
|
||||||
|
cursor_shape: CursorShape,
|
||||||
blink_state: bool,
|
blink_state: bool,
|
||||||
blinking_on: bool,
|
blinking_on: bool,
|
||||||
blinking_paused: bool,
|
blinking_paused: bool,
|
||||||
|
@ -171,6 +172,9 @@ impl TerminalView {
|
||||||
let focus_out = cx.on_focus_out(&focus_handle, |terminal_view, _event, cx| {
|
let focus_out = cx.on_focus_out(&focus_handle, |terminal_view, _event, cx| {
|
||||||
terminal_view.focus_out(cx);
|
terminal_view.focus_out(cx);
|
||||||
});
|
});
|
||||||
|
let cursor_shape = TerminalSettings::get_global(cx)
|
||||||
|
.cursor_shape
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
terminal,
|
terminal,
|
||||||
|
@ -178,6 +182,7 @@ impl TerminalView {
|
||||||
has_bell: false,
|
has_bell: false,
|
||||||
focus_handle,
|
focus_handle,
|
||||||
context_menu: None,
|
context_menu: None,
|
||||||
|
cursor_shape,
|
||||||
blink_state: true,
|
blink_state: true,
|
||||||
blinking_on: false,
|
blinking_on: false,
|
||||||
blinking_paused: false,
|
blinking_paused: false,
|
||||||
|
@ -255,6 +260,16 @@ impl TerminalView {
|
||||||
fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
|
fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
let settings = TerminalSettings::get_global(cx);
|
let settings = TerminalSettings::get_global(cx);
|
||||||
self.show_title = settings.toolbar.title;
|
self.show_title = settings.toolbar.title;
|
||||||
|
|
||||||
|
let new_cursor_shape = settings.cursor_shape.unwrap_or_default();
|
||||||
|
let old_cursor_shape = self.cursor_shape;
|
||||||
|
if old_cursor_shape != new_cursor_shape {
|
||||||
|
self.cursor_shape = new_cursor_shape;
|
||||||
|
self.terminal.update(cx, |term, _| {
|
||||||
|
term.set_cursor_shape(self.cursor_shape);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -903,7 +918,10 @@ impl TerminalView {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_in(&mut self, cx: &mut ViewContext<Self>) {
|
fn focus_in(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
self.terminal.read(cx).focus_in();
|
self.terminal.update(cx, |terminal, _| {
|
||||||
|
terminal.set_cursor_shape(self.cursor_shape);
|
||||||
|
terminal.focus_in();
|
||||||
|
});
|
||||||
self.blink_cursors(self.blink_epoch, cx);
|
self.blink_cursors(self.blink_epoch, cx);
|
||||||
cx.invalidate_character_coordinates();
|
cx.invalidate_character_coordinates();
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -912,6 +930,7 @@ impl TerminalView {
|
||||||
fn focus_out(&mut self, cx: &mut ViewContext<Self>) {
|
fn focus_out(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
self.terminal.update(cx, |terminal, _| {
|
self.terminal.update(cx, |terminal, _| {
|
||||||
terminal.focus_out();
|
terminal.focus_out();
|
||||||
|
terminal.set_cursor_shape(CursorShape::Hollow);
|
||||||
});
|
});
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue