T08: Tab and F6 pass Ely's focus keys; each kitty flag reshapes only what it names; Cmd is Super; repeats and Command key-ups come from AppKit; IME commits stay UTF-8, as in kitty and Ghostty; key.zig out; the line rule reads every text file
This commit is contained in:
14 files changed
+505
-1147
No files matched your search
+53
-44
@@ -3,7 +3,7 @@ use std::ops::Range;
|
||||
use alacritty_terminal::{grid::Scroll, term::TermMode};
|
||||
use gpui::{
|
||||
App, Bounds, Context, EntityInputHandler, KeyBinding, KeyDownEvent, KeyUpEvent, Keystroke,
|
||||
Pixels, Point, UTF16Selection, Window, actions,
|
||||
NoAction, Pixels, Point, UTF16Selection, Window,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@@ -11,17 +11,15 @@ use super::{
|
||||
view::TerminalView,
|
||||
};
|
||||
|
||||
actions!(terminal, [SendTab, SendBackTab]);
|
||||
|
||||
/// The key context a terminal's root sets.
|
||||
pub const CONTEXT: &str = "Terminal";
|
||||
|
||||
/// Tab and Shift-Tab reach the terminal before Ely moves focus with them.
|
||||
/// Ely's focus keys go to the terminal's listeners instead.
|
||||
pub fn bind_keys(cx: &mut App) {
|
||||
cx.bind_keys([
|
||||
KeyBinding::new("tab", SendTab, Some(CONTEXT)),
|
||||
KeyBinding::new("shift-tab", SendBackTab, Some(CONTEXT)),
|
||||
]);
|
||||
cx.bind_keys(
|
||||
["tab", "shift-tab", "f6", "shift-f6"]
|
||||
.map(|key| KeyBinding::new(key, NoAction, Some(CONTEXT))),
|
||||
);
|
||||
}
|
||||
|
||||
impl TerminalView {
|
||||
@@ -41,41 +39,34 @@ impl TerminalView {
|
||||
if event.prefer_character_input {
|
||||
return;
|
||||
}
|
||||
let action = if event.is_held {
|
||||
let facts = self.facts();
|
||||
let action = if event.is_held || facts.repeat {
|
||||
Action::Repeat
|
||||
} else {
|
||||
Action::Press
|
||||
};
|
||||
if self.send(&event.keystroke, action, cx) {
|
||||
if self.send(&event.keystroke, action, facts, cx) {
|
||||
cx.stop_propagation();
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn key_up(&mut self, event: &KeyUpEvent, _: &mut Window, cx: &mut Context<Self>) {
|
||||
if self.send(&event.keystroke, Action::Release, cx) {
|
||||
let facts = self.facts();
|
||||
if self.send(&event.keystroke, Action::Release, facts, cx) {
|
||||
cx.stop_propagation();
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn tab(&mut self, shift: bool, cx: &mut Context<Self>) {
|
||||
let key = Key {
|
||||
name: "tab",
|
||||
text: if shift { "" } else { "\t" },
|
||||
shift,
|
||||
ctrl: false,
|
||||
alt: false,
|
||||
action: Action::Press,
|
||||
};
|
||||
self.encode(&key, cx);
|
||||
}
|
||||
|
||||
/// Sends what `keystroke` means to the program; false when it is text the input method types.
|
||||
fn send(&mut self, keystroke: &Keystroke, action: Action, cx: &mut Context<Self>) -> bool {
|
||||
fn send(
|
||||
&mut self,
|
||||
keystroke: &Keystroke,
|
||||
action: Action,
|
||||
facts: Facts,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
let modifiers = keystroke.modifiers;
|
||||
if modifiers.platform {
|
||||
return false;
|
||||
}
|
||||
let alt = modifiers.alt && self.alt_is_meta(cx);
|
||||
let alt = modifiers.alt && Self::alt_is_meta(facts, cx);
|
||||
let text = match &keystroke.key_char {
|
||||
Some(_) if alt && cfg!(target_os = "macos") => "",
|
||||
Some(text) => text.as_str(),
|
||||
@@ -87,12 +78,9 @@ impl TerminalView {
|
||||
shift: modifiers.shift,
|
||||
ctrl: modifiers.control,
|
||||
alt,
|
||||
platform: modifiers.platform,
|
||||
action,
|
||||
};
|
||||
self.encode(&key, cx)
|
||||
}
|
||||
|
||||
fn encode(&mut self, key: &Key, cx: &mut Context<Self>) -> bool {
|
||||
let mode = *self.pty.term.lock().mode();
|
||||
let kitty = Kitty {
|
||||
disambiguate: mode.contains(TermMode::DISAMBIGUATE_ESC_CODES),
|
||||
@@ -101,7 +89,7 @@ impl TerminalView {
|
||||
all: mode.contains(TermMode::REPORT_ALL_KEYS_AS_ESC),
|
||||
text: mode.contains(TermMode::REPORT_ASSOCIATED_TEXT),
|
||||
};
|
||||
let Some(bytes) = keys::encode(key, mode.contains(TermMode::APP_CURSOR), kitty) else {
|
||||
let Some(bytes) = keys::encode(&key, mode.contains(TermMode::APP_CURSOR), kitty) else {
|
||||
return false;
|
||||
};
|
||||
log::trace!("terminal {}: {key:?} sends {bytes:?}", self.pty.pid);
|
||||
@@ -109,31 +97,52 @@ impl TerminalView {
|
||||
true
|
||||
}
|
||||
|
||||
/// AppKit's facts of the key; logged and none when unreadable.
|
||||
#[cfg(target_os = "macos")]
|
||||
fn facts(&self) -> Facts {
|
||||
super::mac::key_facts().unwrap_or_else(|error| {
|
||||
log::error!("terminal {}: {error:#}", self.pty.pid);
|
||||
Facts {
|
||||
left_option: false,
|
||||
right_option: false,
|
||||
repeat: false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn facts(&self) -> Facts {
|
||||
Facts::default()
|
||||
}
|
||||
|
||||
/// Whether a held Alt is a modifier; on macOS only the Option keys the settings name.
|
||||
#[cfg(target_os = "macos")]
|
||||
fn alt_is_meta(&self, cx: &App) -> bool {
|
||||
fn alt_is_meta(facts: Facts, cx: &App) -> bool {
|
||||
use crate::settings::{OptionAsAlt, SettingsStore};
|
||||
let sides = || match super::mac::option_sides() {
|
||||
Ok(sides) => Some(sides),
|
||||
Err(error) => {
|
||||
log::error!("terminal {}: {error:#}; Option composes", self.pty.pid);
|
||||
None
|
||||
}
|
||||
};
|
||||
match SettingsStore::get(cx).option_as_alt {
|
||||
OptionAsAlt::Off => false,
|
||||
OptionAsAlt::Both => true,
|
||||
OptionAsAlt::Left => sides().is_some_and(|(left, _)| left),
|
||||
OptionAsAlt::Right => sides().is_some_and(|(_, right)| right),
|
||||
OptionAsAlt::Left => facts.left_option,
|
||||
OptionAsAlt::Right => facts.right_option,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn alt_is_meta(&self, _: &App) -> bool {
|
||||
fn alt_is_meta(_: Facts, _: &App) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
type Facts = super::mac::KeyFacts;
|
||||
|
||||
/// Other platforms tell gpui all it needs.
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
struct Facts {
|
||||
repeat: bool,
|
||||
}
|
||||
|
||||
impl EntityInputHandler for TerminalView {
|
||||
fn text_for_range(
|
||||
&mut self,
|
||||
|
||||
Reference in new issue
Block a user