You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: commands_menu.rs
    path of file: ./repos/mprocs/src/modal
    
    the code of the file until where you have to start completion: use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
use tokio::sync::mpsc::UnboundedSender;
use tui::{
  prelude::{Margin, Rect},
  style::{Modifier, Style},
  text::{Line, Span},
  widgets::{HighlightSpacing, ListItem, ListState, Paragraph},
  Frame,
};
use tui_input::Input;

use crate::{
  app::LoopAction, error::ResultLogger, event::AppEvent,
  protocol::ProxyBackend, state::State, theme::Theme,
  widgets::text_input::TextInput,
};

use super::modal::Modal;

pub struct CommandsMenuModal {
  input: Input,
  list_state: ListState,
  items: Vec<CommandInfo>,
  app_sender: UnboundedSender<AppEvent>,
}

impl CommandsMenuModal {
  pub fn new(app_sender: UnboundedSender<AppEvent>) -> Self {
    CommandsMenuModal {
      input: Input::default(),
      list_state: ListState::default().with_selected(Some(0)),
      items: get_commands(""),
      app_sender,
    }
  }
}

impl Modal for CommandsMenuModal {
  fn boxed(self) -> Box<dyn Modal> {
    Box::new(self)
  }

  fn handle_input(
    &mut self,
    _state: &mut State,
    loop_action: &mut LoopAction,
    event: &Event,
  ) -> bool {
    match event {
      Event::Key(KeyEvent {
        code: KeyCode::Enter,
        modifiers,
        ..
      }) if modifiers.is_empty() => {
        self
          .app_sender
          .send(AppEvent::CloseCurrentModal)

    
fn get_commands(search: &str) -> Vec<CommandInfo> {
  let events = [
    ("quit-or-ask", AppEvent::QuitOrAsk),
    ("quit", AppEvent::Quit),
    ("force-quit", AppEvent::ForceQuit),
    ("toggle-focus", AppEvent::ToggleFocus),
    ("focus-term", AppEvent::FocusTerm),
    ("zoom", AppEvent::Zoom),
    ("show-commands-menu", AppEvent::ShowCommandsMenu),
    ("next-proc", AppEvent::NextProc),
    ("prev-proc", AppEvent::PrevProc),
    ("start-proc", AppEvent::StartProc),
    ("term-proc", AppEvent::TermProc),
    ("kill-proc", AppEvent::KillProc),
    ("restart-proc", AppEvent::RestartProc),
    ("force-restart-proc", AppEvent::ForceRestartProc),
    ("show-add-proc", AppEvent::ShowAddProc),
    ("show-rename-proc", AppEvent::ShowRenameProc),
    ("show-remove-proc", AppEvent::ShowRemoveProc),
    ("close-current-modal", AppEvent::CloseCurrentModal),
    ("scroll-down", AppEvent::ScrollDown),
    ("scroll-up", AppEvent::ScrollUp),
    ("copy-mode-enter", AppEvent::CopyModeEnter),
    ("copy-mode-leave", AppEvent::CopyModeLeave),
    ("copy-mode-end", AppEvent::CopyModeEnd),
    ("copy-mode-copy", AppEvent::CopyModeCopy),
  ];

  let mut result = Vec::new();
  for (cmd, event) in events {
    let desc = event.desc();
    if cmd.contains(search) || desc.contains(search) {
      result.push((cmd, desc, event));
    }
  }

  result
}