fix: wire tui word navigation
This commit is contained in:
parent
d0bdad58c2
commit
cc98c0eb28
|
|
@ -47,10 +47,8 @@ fn merge_usage(acc: &mut UsageEvent, new: &UsageEvent) {
|
|||
pub trait ErasedHandler<K: Kind>: Send + Sync {
|
||||
/// イベントをディスパッチ
|
||||
fn dispatch(&mut self, event: &K::Event);
|
||||
/// スコープを開始(Block開始時)
|
||||
/// スコープを開始
|
||||
fn start_scope(&mut self);
|
||||
/// スコープを終了(Block終了時)
|
||||
fn end_scope(&mut self);
|
||||
}
|
||||
|
||||
/// `Handler<K>`を`ErasedHandler<K>`として扱うためのラッパー
|
||||
|
|
@ -94,10 +92,6 @@ where
|
|||
fn start_scope(&mut self) {
|
||||
self.scope = Some(H::Scope::default());
|
||||
}
|
||||
|
||||
fn end_scope(&mut self) {
|
||||
self.scope = None;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
|
|
|||
|
|
@ -586,10 +586,12 @@ impl App {
|
|||
self.queued_inputs.len()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn input_history_len(&self) -> usize {
|
||||
self.input_history.entries.len()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn input_history_is_browsing(&self) -> bool {
|
||||
self.input_history.is_browsing()
|
||||
}
|
||||
|
|
@ -1701,6 +1703,22 @@ impl App {
|
|||
pub fn move_cursor_right(&mut self) {
|
||||
self.active_input_mut().move_right();
|
||||
}
|
||||
pub fn move_cursor_word_left(&mut self) {
|
||||
self.active_input_mut().move_word_left();
|
||||
}
|
||||
pub fn move_cursor_word_right(&mut self) {
|
||||
self.active_input_mut().move_word_right();
|
||||
}
|
||||
pub fn delete_word_before_cursor(&mut self) {
|
||||
let command_mode = self.is_command_mode();
|
||||
if !command_mode {
|
||||
self.input_history.cancel_browse();
|
||||
}
|
||||
self.active_input_mut().delete_word_before();
|
||||
if command_mode {
|
||||
self.command_completion_selected = None;
|
||||
}
|
||||
}
|
||||
pub fn move_cursor_start(&mut self) {
|
||||
self.active_input_mut().move_start();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -573,6 +573,22 @@ fn handle_key(app: &mut App, key: KeyEvent) -> Option<Method> {
|
|||
app.move_cursor_start();
|
||||
Some(app.refresh_completion())
|
||||
}
|
||||
KeyCode::Left if ctrl || alt => {
|
||||
app.move_cursor_word_left();
|
||||
Some(app.refresh_completion())
|
||||
}
|
||||
KeyCode::Right if ctrl || alt => {
|
||||
app.move_cursor_word_right();
|
||||
Some(app.refresh_completion())
|
||||
}
|
||||
KeyCode::Backspace if ctrl || alt => {
|
||||
app.delete_word_before_cursor();
|
||||
Some(app.refresh_completion())
|
||||
}
|
||||
KeyCode::Char('w') if ctrl => {
|
||||
app.delete_word_before_cursor();
|
||||
Some(app.refresh_completion())
|
||||
}
|
||||
KeyCode::Char('u') if ctrl && app.is_command_mode() => {
|
||||
app.clear_command_input();
|
||||
Some(None)
|
||||
|
|
@ -1067,6 +1083,125 @@ mod tests {
|
|||
assert_eq!(app.queued_input_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn word_navigation_keys_edit_composer() {
|
||||
let mut app = App::new("agent".to_string());
|
||||
for c in "foo bar".chars() {
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Char(c), KeyModifiers::NONE)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Left, KeyModifiers::CONTROL)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Char('_'), KeyModifiers::NONE)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
assert_eq!(input_text(&app), "foo _bar");
|
||||
|
||||
assert!(handle_key(&mut app, KeyEvent::new(KeyCode::Right, KeyModifiers::ALT)).is_none());
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Char('!'), KeyModifiers::NONE)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
assert_eq!(input_text(&app), "foo _bar!");
|
||||
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Backspace, KeyModifiers::CONTROL)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
assert_eq!(input_text(&app), "foo ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ctrl_w_deletes_word_before_cursor() {
|
||||
let mut app = App::new("agent".to_string());
|
||||
for c in "foo bar baz".chars() {
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Char(c), KeyModifiers::NONE)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Char('w'), KeyModifiers::CONTROL)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
assert_eq!(input_text(&app), "foo bar ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn word_navigation_keys_edit_command_input() {
|
||||
let mut app = App::new("agent".to_string());
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Char(':'), KeyModifiers::NONE)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
for c in "peer alpha beta".chars() {
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Char(c), KeyModifiers::NONE)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Left, KeyModifiers::CONTROL)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Char('_'), KeyModifiers::NONE)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
assert_eq!(app.command_text(), "peer alpha _beta");
|
||||
|
||||
assert!(
|
||||
handle_key(
|
||||
&mut app,
|
||||
KeyEvent::new(KeyCode::Char('w'), KeyModifiers::CONTROL)
|
||||
)
|
||||
.is_none()
|
||||
);
|
||||
assert_eq!(app.command_text(), "peer alpha beta");
|
||||
assert_eq!(input_text(&app), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn command_mode_enters_with_colon_and_esc_restores_composer() {
|
||||
let mut app = App::new("agent".to_string());
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user