feat: Add support IPC socket control over menu.
This commit is contained in:
@@ -39,6 +39,7 @@ pub fn restore_terminal() {
|
||||
pub async fn run(
|
||||
action_tx: mpsc::Sender<Action>,
|
||||
mut event_rx: broadcast::Receiver<MenuEvent>,
|
||||
filter_history: Option<Vec<String>>,
|
||||
) -> std::io::Result<()> {
|
||||
crossterm::terminal::enable_raw_mode()?;
|
||||
crossterm::execute!(std::io::stderr(), crossterm::terminal::EnterAlternateScreen,)?;
|
||||
@@ -53,7 +54,7 @@ pub async fn run(
|
||||
let _ = crossterm::event::read()?;
|
||||
}
|
||||
|
||||
let result = run_inner(&action_tx, &mut event_rx, &mut terminal).await;
|
||||
let result = run_inner(&action_tx, &mut event_rx, &mut terminal, filter_history).await;
|
||||
|
||||
// Always clean up terminal, even on error
|
||||
restore_terminal();
|
||||
@@ -67,6 +68,7 @@ async fn run_inner(
|
||||
action_tx: &mpsc::Sender<Action>,
|
||||
event_rx: &mut broadcast::Receiver<MenuEvent>,
|
||||
terminal: &mut Terminal<CrosstermBackend<std::io::Stderr>>,
|
||||
filter_history: Option<Vec<String>>,
|
||||
) -> std::io::Result<()> {
|
||||
// Send initial resize
|
||||
let size = terminal.size()?;
|
||||
@@ -95,6 +97,11 @@ async fn run_inner(
|
||||
let mut multi_enabled = false;
|
||||
let mut visual_anchor: Option<usize> = None;
|
||||
|
||||
// Session filter history cycling state
|
||||
let history = filter_history.unwrap_or_default();
|
||||
let mut history_cursor: Option<usize> = None;
|
||||
let mut pre_history_text: Option<String> = None;
|
||||
|
||||
loop {
|
||||
if let Some(ref vs) = view_state {
|
||||
let ft = filter_text.clone();
|
||||
@@ -112,6 +119,62 @@ async fn run_inner(
|
||||
let event = event_result?;
|
||||
match event {
|
||||
Event::Key(key) => {
|
||||
// History cycling: Ctrl+P/Ctrl+N in insert mode
|
||||
// with a non-empty history list.
|
||||
if mode == Mode::Insert && !history.is_empty() {
|
||||
let history_handled = match (key.code, key.modifiers) {
|
||||
(KeyCode::Char('p'), KeyModifiers::CONTROL) | (KeyCode::Up, _) => {
|
||||
if pre_history_text.is_none() {
|
||||
pre_history_text = Some(filter_text.clone());
|
||||
}
|
||||
let new_cursor = match history_cursor {
|
||||
Some(c) if c > 0 => c - 1,
|
||||
Some(_) => 0,
|
||||
None => history.len() - 1,
|
||||
};
|
||||
history_cursor = Some(new_cursor);
|
||||
filter_text.clone_from(&history[new_cursor]);
|
||||
let _ = action_tx
|
||||
.send(Action::UpdateFilter(filter_text.clone()))
|
||||
.await;
|
||||
true
|
||||
}
|
||||
(KeyCode::Char('n'), KeyModifiers::CONTROL) => {
|
||||
if let Some(c) = history_cursor {
|
||||
if c + 1 < history.len() {
|
||||
history_cursor = Some(c + 1);
|
||||
filter_text.clone_from(&history[c + 1]);
|
||||
} else {
|
||||
// Past the end: restore original text
|
||||
history_cursor = None;
|
||||
if let Some(ref saved) = pre_history_text {
|
||||
filter_text.clone_from(saved);
|
||||
}
|
||||
pre_history_text = None;
|
||||
}
|
||||
let _ = action_tx
|
||||
.send(Action::UpdateFilter(filter_text.clone()))
|
||||
.await;
|
||||
true
|
||||
} else {
|
||||
// Not cycling, fall through to normal Ctrl+N
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Any other key resets history cycling
|
||||
if history_cursor.is_some() {
|
||||
history_cursor = None;
|
||||
pre_history_text = None;
|
||||
}
|
||||
false
|
||||
}
|
||||
};
|
||||
if history_handled {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle multi-action keys (Tab, Space in normal/visual)
|
||||
// before the single-action map_key_event path.
|
||||
let handled = handle_multi_action_key(
|
||||
|
||||
Reference in New Issue
Block a user