@@ -48,6 +48,9 @@ use modalkit::crossterm::{
48
48
EnableFocusChange ,
49
49
Event ,
50
50
KeyEventKind ,
51
+ KeyboardEnhancementFlags ,
52
+ PopKeyboardEnhancementFlags ,
53
+ PushKeyboardEnhancementFlags ,
51
54
} ,
52
55
execute,
53
56
terminal:: { EnterAlternateScreen , LeaveAlternateScreen , SetTitle } ,
@@ -250,16 +253,7 @@ impl Application {
250
253
settings : ApplicationSettings ,
251
254
store : AsyncProgramStore ,
252
255
) -> 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 ( ) ) ;
263
257
let terminal = Terminal :: new ( backend) ?;
264
258
265
259
let mut bindings = crate :: keybindings:: setup_keybindings ( ) ;
@@ -905,6 +899,70 @@ async fn login_normal(
905
899
Ok ( ( ) )
906
900
}
907
901
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
+
908
966
async fn run ( settings : ApplicationSettings ) -> IambResult < ( ) > {
909
967
// Get old keys the first time we run w/ the upgraded SDK.
910
968
let import_keys = check_import_keys ( & settings) . await ?;
@@ -938,27 +996,30 @@ async fn run(settings: ApplicationSettings) -> IambResult<()> {
938
996
Ok ( ( ) ) => ( ) ,
939
997
}
940
998
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) ?;
948
1009
949
- // Make sure panics clean up the terminal properly.
950
1010
let orig_hook = std:: panic:: take_hook ( ) ;
951
1011
std:: panic:: set_hook ( Box :: new ( move |panic_info| {
952
- restore_tty ( ) ;
1012
+ restore_tty ( enable_enhanced_keys ) ;
953
1013
orig_hook ( panic_info) ;
954
1014
process:: exit ( 1 ) ;
955
1015
} ) ) ;
956
1016
1017
+ // And finally, start running the terminal UI.
957
1018
let mut application = Application :: new ( settings, store) . await ?;
958
-
959
- // We can now run the application.
960
1019
application. run ( ) . await ?;
961
- restore_tty ( ) ;
1020
+
1021
+ // Clean up the terminal on exit.
1022
+ restore_tty ( enable_enhanced_keys) ;
962
1023
963
1024
Ok ( ( ) )
964
1025
}
0 commit comments