Skip to content

Commit 5932cd8

Browse files
committed
Allow typing newline with <S-Enter> and enable keyboard enhancement protocol
1 parent 7bc34c8 commit 5932cd8

File tree

2 files changed

+97
-24
lines changed

2 files changed

+97
-24
lines changed

src/keybindings.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
//! The keybindings are set up here. We define some iamb-specific keybindings, but the default Vim
44
//! keys come from [modalkit::env::vim::keybindings].
55
use modalkit::{
6-
actions::{MacroAction, WindowAction},
6+
actions::{InsertTextAction, MacroAction, WindowAction},
77
env::vim::keybindings::{InputStep, VimBindings},
88
env::vim::VimMode,
99
env::CommonKeyClass,
1010
key::TerminalKey,
1111
keybindings::{EdgeEvent, EdgeRepeat, InputBindings},
12-
prelude::Count,
12+
prelude::*,
1313
};
1414

1515
use crate::base::{IambAction, IambInfo, Keybindings, MATRIX_ID_WORD};
@@ -36,6 +36,7 @@ pub fn setup_keybindings() -> Keybindings {
3636
let ctrl_z = "<C-Z>".parse::<TerminalKey>().unwrap();
3737
let key_m_lc = "m".parse::<TerminalKey>().unwrap();
3838
let key_z_lc = "z".parse::<TerminalKey>().unwrap();
39+
let shift_enter = "<S-Enter>".parse::<TerminalKey>().unwrap();
3940

4041
let cwz = vec![once(&ctrl_w), once(&key_z_lc)];
4142
let cwcz = vec![once(&ctrl_w), once(&ctrl_z)];
@@ -57,6 +58,17 @@ pub fn setup_keybindings() -> Keybindings {
5758
ism.add_mapping(VimMode::Visual, &cwm, &stoggle);
5859
ism.add_mapping(VimMode::Normal, &cwcm, &stoggle);
5960
ism.add_mapping(VimMode::Visual, &cwcm, &stoggle);
61+
62+
let shift_enter = vec![once(&shift_enter)];
63+
let newline = IambStep::new().actions(vec![InsertTextAction::Type(
64+
Char::Single('\n').into(),
65+
MoveDir1D::Previous,
66+
1.into(),
67+
)
68+
.into()]);
69+
ism.add_mapping(VimMode::Insert, &cwm, &newline);
70+
ism.add_mapping(VimMode::Insert, &shift_enter, &newline);
71+
6072
ism
6173
}
6274

src/main.rs

+83-22
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ use modalkit::crossterm::{
4848
EnableFocusChange,
4949
Event,
5050
KeyEventKind,
51+
KeyboardEnhancementFlags,
52+
PopKeyboardEnhancementFlags,
53+
PushKeyboardEnhancementFlags,
5154
},
5255
execute,
5356
terminal::{EnterAlternateScreen, LeaveAlternateScreen, SetTitle},
@@ -250,16 +253,7 @@ impl Application {
250253
settings: ApplicationSettings,
251254
store: AsyncProgramStore,
252255
) -> IambResult<Application> {
253-
let mut stdout = stdout();
254-
crossterm::terminal::enable_raw_mode()?;
255-
crossterm::execute!(stdout, EnterAlternateScreen)?;
256-
crossterm::execute!(stdout, EnableBracketedPaste)?;
257-
crossterm::execute!(stdout, EnableFocusChange)?;
258-
259-
let title = format!("iamb ({})", settings.profile.user_id);
260-
crossterm::execute!(stdout, SetTitle(title))?;
261-
262-
let backend = CrosstermBackend::new(stdout);
256+
let backend = CrosstermBackend::new(stdout());
263257
let terminal = Terminal::new(backend)?;
264258

265259
let mut bindings = crate::keybindings::setup_keybindings();
@@ -905,6 +899,70 @@ async fn login_normal(
905899
Ok(())
906900
}
907901

902+
struct EnableModifyOtherKeys;
903+
struct DisableModifyOtherKeys;
904+
905+
impl crossterm::Command for EnableModifyOtherKeys {
906+
fn write_ansi(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
907+
write!(f, "\x1B[>4;2m")
908+
}
909+
910+
#[cfg(windows)]
911+
fn execute_winapi(&self) -> std::io::Result<()> {
912+
Ok(())
913+
}
914+
}
915+
916+
impl crossterm::Command for DisableModifyOtherKeys {
917+
fn write_ansi(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
918+
write!(f, "\x1B[>4;0m")
919+
}
920+
921+
#[cfg(windows)]
922+
fn execute_winapi(&self) -> std::io::Result<()> {
923+
Ok(())
924+
}
925+
}
926+
927+
/// Set up the terminal for drawing the TUI, and getting additional info.
928+
fn setup_tty(title: &str, enable_enhanced_keys: bool) -> std::io::Result<()> {
929+
let title = format!("iamb ({})", title);
930+
931+
// Enable raw mode and enter the alternate screen.
932+
crossterm::terminal::enable_raw_mode()?;
933+
crossterm::execute!(stdout(), EnterAlternateScreen)?;
934+
935+
if enable_enhanced_keys {
936+
// Enable the Kitty keyboard enhancement protocol for improved keypresses.
937+
crossterm::queue!(
938+
stdout(),
939+
PushKeyboardEnhancementFlags(KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES)
940+
)?;
941+
} else {
942+
crossterm::queue!(stdout(), EnableModifyOtherKeys)?;
943+
}
944+
945+
crossterm::execute!(stdout(), EnableBracketedPaste, EnableFocusChange, SetTitle(title))
946+
}
947+
948+
// Do our best to reverse what we did in setup_tty() when we exit or crash.
949+
fn restore_tty(enable_enhanced_keys: bool) {
950+
if enable_enhanced_keys {
951+
let _ = crossterm::queue!(stdout(), PopKeyboardEnhancementFlags);
952+
}
953+
954+
let _ = crossterm::execute!(
955+
stdout(),
956+
DisableModifyOtherKeys,
957+
DisableBracketedPaste,
958+
DisableFocusChange,
959+
LeaveAlternateScreen,
960+
CursorShow,
961+
);
962+
963+
let _ = crossterm::terminal::disable_raw_mode();
964+
}
965+
908966
async fn run(settings: ApplicationSettings) -> IambResult<()> {
909967
// Get old keys the first time we run w/ the upgraded SDK.
910968
let import_keys = check_import_keys(&settings).await?;
@@ -938,27 +996,30 @@ async fn run(settings: ApplicationSettings) -> IambResult<()> {
938996
Ok(()) => (),
939997
}
940998

941-
fn restore_tty() {
942-
let _ = crossterm::terminal::disable_raw_mode();
943-
let _ = crossterm::execute!(stdout(), DisableBracketedPaste);
944-
let _ = crossterm::execute!(stdout(), DisableFocusChange);
945-
let _ = crossterm::execute!(stdout(), LeaveAlternateScreen);
946-
let _ = crossterm::execute!(stdout(), CursorShow);
947-
}
999+
// Set up the terminal for drawing, and cleanup properly on panics.
1000+
let enable_enhanced_keys = match crossterm::terminal::supports_keyboard_enhancement() {
1001+
Ok(supported) => supported,
1002+
Err(e) => {
1003+
tracing::warn!(err = %e,
1004+
"Failed to determine whether the terminal supports keyboard enhancements");
1005+
false
1006+
},
1007+
};
1008+
setup_tty(settings.profile.user_id.as_str(), enable_enhanced_keys)?;
9481009

949-
// Make sure panics clean up the terminal properly.
9501010
let orig_hook = std::panic::take_hook();
9511011
std::panic::set_hook(Box::new(move |panic_info| {
952-
restore_tty();
1012+
restore_tty(enable_enhanced_keys);
9531013
orig_hook(panic_info);
9541014
process::exit(1);
9551015
}));
9561016

1017+
// And finally, start running the terminal UI.
9571018
let mut application = Application::new(settings, store).await?;
958-
959-
// We can now run the application.
9601019
application.run().await?;
961-
restore_tty();
1020+
1021+
// Clean up the terminal on exit.
1022+
restore_tty(enable_enhanced_keys);
9621023

9631024
Ok(())
9641025
}

0 commit comments

Comments
 (0)