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 {
|
pub trait ErasedHandler<K: Kind>: Send + Sync {
|
||||||
/// イベントをディスパッチ
|
/// イベントをディスパッチ
|
||||||
fn dispatch(&mut self, event: &K::Event);
|
fn dispatch(&mut self, event: &K::Event);
|
||||||
/// スコープを開始(Block開始時)
|
/// スコープを開始
|
||||||
fn start_scope(&mut self);
|
fn start_scope(&mut self);
|
||||||
/// スコープを終了(Block終了時)
|
|
||||||
fn end_scope(&mut self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `Handler<K>`を`ErasedHandler<K>`として扱うためのラッパー
|
/// `Handler<K>`を`ErasedHandler<K>`として扱うためのラッパー
|
||||||
|
|
@ -94,10 +92,6 @@ where
|
||||||
fn start_scope(&mut self) {
|
fn start_scope(&mut self) {
|
||||||
self.scope = Some(H::Scope::default());
|
self.scope = Some(H::Scope::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_scope(&mut self) {
|
|
||||||
self.scope = None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
|
||||||
|
|
@ -586,10 +586,12 @@ impl App {
|
||||||
self.queued_inputs.len()
|
self.queued_inputs.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
pub fn input_history_len(&self) -> usize {
|
pub fn input_history_len(&self) -> usize {
|
||||||
self.input_history.entries.len()
|
self.input_history.entries.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
pub fn input_history_is_browsing(&self) -> bool {
|
pub fn input_history_is_browsing(&self) -> bool {
|
||||||
self.input_history.is_browsing()
|
self.input_history.is_browsing()
|
||||||
}
|
}
|
||||||
|
|
@ -1701,6 +1703,22 @@ impl App {
|
||||||
pub fn move_cursor_right(&mut self) {
|
pub fn move_cursor_right(&mut self) {
|
||||||
self.active_input_mut().move_right();
|
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) {
|
pub fn move_cursor_start(&mut self) {
|
||||||
self.active_input_mut().move_start();
|
self.active_input_mut().move_start();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -573,6 +573,22 @@ fn handle_key(app: &mut App, key: KeyEvent) -> Option<Method> {
|
||||||
app.move_cursor_start();
|
app.move_cursor_start();
|
||||||
Some(app.refresh_completion())
|
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() => {
|
KeyCode::Char('u') if ctrl && app.is_command_mode() => {
|
||||||
app.clear_command_input();
|
app.clear_command_input();
|
||||||
Some(None)
|
Some(None)
|
||||||
|
|
@ -1067,6 +1083,125 @@ mod tests {
|
||||||
assert_eq!(app.queued_input_count(), 0);
|
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]
|
#[test]
|
||||||
fn command_mode_enters_with_colon_and_esc_restores_composer() {
|
fn command_mode_enters_with_colon_and_esc_restores_composer() {
|
||||||
let mut app = App::new("agent".to_string());
|
let mut app = App::new("agent".to_string());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user