Implement shortcut search
This commit is contained in:
parent
1564a77e5f
commit
92d22621e4
4 changed files with 91 additions and 18 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1586,6 +1586,7 @@ dependencies = [
|
||||||
"open",
|
"open",
|
||||||
"palette",
|
"palette",
|
||||||
"paste",
|
"paste",
|
||||||
|
"regex",
|
||||||
"ron 0.11.0",
|
"ron 0.11.0",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"secret-service",
|
"secret-service",
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ log = "0.4"
|
||||||
open = "5.3.2"
|
open = "5.3.2"
|
||||||
palette = { version = "0.7", features = ["serde"] }
|
palette = { version = "0.7", features = ["serde"] }
|
||||||
paste = "1.0"
|
paste = "1.0"
|
||||||
|
regex = "1"
|
||||||
ron = "0.11"
|
ron = "0.11"
|
||||||
serde = { version = "1", features = ["serde_derive"] }
|
serde = { version = "1", features = ["serde_derive"] }
|
||||||
shlex = "1"
|
shlex = "1"
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ show-headerbar = Show header
|
||||||
show-header-description = Reveal the header from the right-click menu.
|
show-header-description = Reveal the header from the right-click menu.
|
||||||
|
|
||||||
### Keyboard shortcuts
|
### Keyboard shortcuts
|
||||||
|
type-to-search = Type to search...
|
||||||
keyboard-shortcuts = Keyboard shortcuts
|
keyboard-shortcuts = Keyboard shortcuts
|
||||||
customize-shortcuts = Customize shortcuts
|
customize-shortcuts = Customize shortcuts
|
||||||
shortcut-capture-hint = Press new shortcut, or Esc to cancel
|
shortcut-capture-hint = Press new shortcut, or Esc to cancel
|
||||||
|
|
|
||||||
106
src/main.rs
106
src/main.rs
|
|
@ -30,6 +30,7 @@ use cosmic_text::{Family, Stretch, Weight, fontdb::FaceInfo};
|
||||||
use localize::LANGUAGE_SORTER;
|
use localize::LANGUAGE_SORTER;
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
|
cell::Cell,
|
||||||
cmp,
|
cmp,
|
||||||
collections::{BTreeMap, BTreeSet, HashMap},
|
collections::{BTreeMap, BTreeSet, HashMap},
|
||||||
env,
|
env,
|
||||||
|
|
@ -379,6 +380,7 @@ pub enum Message {
|
||||||
ShortcutConflictCancel,
|
ShortcutConflictCancel,
|
||||||
ShortcutConflictReplace,
|
ShortcutConflictReplace,
|
||||||
ShortcutRemove(shortcuts::Binding, shortcuts::BindingSource),
|
ShortcutRemove(shortcuts::Binding, shortcuts::BindingSource),
|
||||||
|
ShortcutSearch(String),
|
||||||
MouseEnter(pane_grid::Pane),
|
MouseEnter(pane_grid::Pane),
|
||||||
Opacity(u8),
|
Opacity(u8),
|
||||||
PaneClicked(pane_grid::Pane),
|
PaneClicked(pane_grid::Pane),
|
||||||
|
|
@ -498,6 +500,10 @@ pub struct App {
|
||||||
shortcut_capture: Option<shortcuts::KeyBindAction>,
|
shortcut_capture: Option<shortcuts::KeyBindAction>,
|
||||||
shortcut_conflict: Option<ShortcutConflict>,
|
shortcut_conflict: Option<ShortcutConflict>,
|
||||||
shortcut_conflict_overlay_restore: Option<bool>,
|
shortcut_conflict_overlay_restore: Option<bool>,
|
||||||
|
shortcut_search_focus: Cell<bool>,
|
||||||
|
shortcut_search_id: widget::Id,
|
||||||
|
shortcut_search_regex: Option<regex::Regex>,
|
||||||
|
shortcut_search_value: String,
|
||||||
modifiers: Modifiers,
|
modifiers: Modifiers,
|
||||||
#[cfg(feature = "password_manager")]
|
#[cfg(feature = "password_manager")]
|
||||||
password_mgr: password_manager::PasswordManager,
|
password_mgr: password_manager::PasswordManager,
|
||||||
|
|
@ -617,6 +623,15 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn shortcut_page_toggle(&mut self) {
|
||||||
|
self.shortcut_capture = None;
|
||||||
|
self.clear_shortcut_conflict();
|
||||||
|
self.shortcut_search_focus
|
||||||
|
.set(self.core.window.show_context);
|
||||||
|
self.shortcut_search_regex = None;
|
||||||
|
self.shortcut_search_value.clear();
|
||||||
|
}
|
||||||
|
|
||||||
fn update_config(&mut self) -> Task<Message> {
|
fn update_config(&mut self) -> Task<Message> {
|
||||||
let theme = self.config.app_theme.theme();
|
let theme = self.config.app_theme.theme();
|
||||||
|
|
||||||
|
|
@ -712,7 +727,16 @@ impl App {
|
||||||
if self.find {
|
if self.find {
|
||||||
widget::text_input::focus(self.find_search_id.clone())
|
widget::text_input::focus(self.find_search_id.clone())
|
||||||
} else if self.core.window.show_context {
|
} else if self.core.window.show_context {
|
||||||
// TODO focus the context page?
|
match self.context_page {
|
||||||
|
ContextPage::KeyboardShortcuts => {
|
||||||
|
if self.shortcut_search_focus.get() {
|
||||||
|
self.shortcut_search_focus.set(false);
|
||||||
|
return widget::text_input::focus(self.shortcut_search_id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO focus for other context pages?
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
} else if let Some(terminal_id) = self.terminal_ids.get(&self.pane_model.focused()).cloned()
|
} else if let Some(terminal_id) = self.terminal_ids.get(&self.pane_model.focused()).cloned()
|
||||||
{
|
{
|
||||||
|
|
@ -946,10 +970,7 @@ impl App {
|
||||||
|
|
||||||
fn keyboard_shortcuts(&self) -> Element<'_, Message> {
|
fn keyboard_shortcuts(&self) -> Element<'_, Message> {
|
||||||
let cosmic_theme::Spacing {
|
let cosmic_theme::Spacing {
|
||||||
space_xxs,
|
space_xxs, space_m, ..
|
||||||
space_xs,
|
|
||||||
space_m,
|
|
||||||
..
|
|
||||||
} = self.core().system_theme().cosmic().spacing;
|
} = self.core().system_theme().cosmic().spacing;
|
||||||
|
|
||||||
let pad_m = [space_xxs, space_m];
|
let pad_m = [space_xxs, space_m];
|
||||||
|
|
@ -958,15 +979,33 @@ impl App {
|
||||||
let div_l = div_m + 32;
|
let div_l = div_m + 32;
|
||||||
|
|
||||||
let mut groups = Vec::new();
|
let mut groups = Vec::new();
|
||||||
|
//TODO: fix text input focus going outside bounds
|
||||||
|
groups.push(widget::horizontal_space().into());
|
||||||
|
groups.push(
|
||||||
|
widget::text_input::search_input(fl!("type-to-search"), &self.shortcut_search_value)
|
||||||
|
.id(self.shortcut_search_id.clone())
|
||||||
|
.on_input(Message::ShortcutSearch)
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
|
||||||
for group in shortcuts::shortcut_groups() {
|
for group in shortcuts::shortcut_groups() {
|
||||||
let mut list = widget::list::list_column();
|
let mut list = widget::list::list_column();
|
||||||
|
|
||||||
|
let mut found_actions = false;
|
||||||
for action in group.actions {
|
for action in group.actions {
|
||||||
|
let action_label = shortcuts::action_label(action);
|
||||||
|
if let Some(regex) = &self.shortcut_search_regex {
|
||||||
|
if regex.find(&action_label).is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
found_actions = true;
|
||||||
|
|
||||||
let bindings = self.shortcuts_config.bindings_for_action(action);
|
let bindings = self.shortcuts_config.bindings_for_action(action);
|
||||||
|
|
||||||
list = list.list_item_padding(pad_m);
|
list = list.list_item_padding(pad_m);
|
||||||
list = list.add(
|
list = list.add(
|
||||||
widget::settings::item::builder(shortcuts::action_label(action)).control(
|
widget::settings::item::builder(action_label).control(
|
||||||
widget::button::custom(icon_cache_get("list-add-symbolic", 16))
|
widget::button::custom(icon_cache_get("list-add-symbolic", 16))
|
||||||
.class(style::Button::Icon)
|
.class(style::Button::Icon)
|
||||||
.on_press(Message::ShortcutCaptureStart(action)),
|
.on_press(Message::ShortcutCaptureStart(action)),
|
||||||
|
|
@ -1014,16 +1053,16 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
groups.push(
|
if found_actions {
|
||||||
widget::settings::section::with_column(list)
|
groups.push(
|
||||||
.title(group.title)
|
widget::settings::section::with_column(list)
|
||||||
.into(),
|
.title(group.title)
|
||||||
);
|
.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
widget::column::with_children(groups)
|
widget::settings::view_column(groups).into()
|
||||||
.spacing(space_xs)
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn profiles(&self) -> Element<'_, Message> {
|
fn profiles(&self) -> Element<'_, Message> {
|
||||||
|
|
@ -1762,13 +1801,21 @@ impl Application for App {
|
||||||
shortcut_capture: None,
|
shortcut_capture: None,
|
||||||
shortcut_conflict: None,
|
shortcut_conflict: None,
|
||||||
shortcut_conflict_overlay_restore: None,
|
shortcut_conflict_overlay_restore: None,
|
||||||
|
shortcut_search_focus: Cell::new(true),
|
||||||
|
shortcut_search_id: widget::Id::unique(),
|
||||||
|
shortcut_search_regex: None,
|
||||||
|
shortcut_search_value: String::new(),
|
||||||
modifiers: Modifiers::empty(),
|
modifiers: Modifiers::empty(),
|
||||||
#[cfg(feature = "password_manager")]
|
#[cfg(feature = "password_manager")]
|
||||||
password_mgr: Default::default(),
|
password_mgr: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
app.set_curr_font_weights_and_stretches();
|
app.set_curr_font_weights_and_stretches();
|
||||||
let command = Task::batch([app.update_config(), app.update_title(None)]);
|
let command = Task::batch([
|
||||||
|
app.update_config(),
|
||||||
|
app.update_title(None),
|
||||||
|
app.update(Message::ToggleContextPage(ContextPage::KeyboardShortcuts)),
|
||||||
|
]);
|
||||||
|
|
||||||
(app, command)
|
(app, command)
|
||||||
}
|
}
|
||||||
|
|
@ -2397,6 +2444,26 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
self.save_shortcuts_custom();
|
self.save_shortcuts_custom();
|
||||||
}
|
}
|
||||||
|
Message::ShortcutSearch(search) => {
|
||||||
|
self.shortcut_search_focus.set(true);
|
||||||
|
self.shortcut_search_regex = None;
|
||||||
|
if !search.is_empty() {
|
||||||
|
let pattern = regex::escape(&search);
|
||||||
|
match regex::RegexBuilder::new(&pattern)
|
||||||
|
.case_insensitive(true)
|
||||||
|
.build()
|
||||||
|
{
|
||||||
|
Ok(regex) => {
|
||||||
|
self.shortcut_search_regex = Some(regex);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("failed to parse regex {:?}: {}", pattern, err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
self.shortcut_search_value = search;
|
||||||
|
return self.update_focus();
|
||||||
|
}
|
||||||
Message::Opacity(opacity) => {
|
Message::Opacity(opacity) => {
|
||||||
config_set!(opacity, cmp::min(100, opacity));
|
config_set!(opacity, cmp::min(100, opacity));
|
||||||
}
|
}
|
||||||
|
|
@ -2909,6 +2976,10 @@ impl Application for App {
|
||||||
self.core.window.show_context = !self.core.window.show_context;
|
self.core.window.show_context = !self.core.window.show_context;
|
||||||
self.pane_model.update_terminal_focus();
|
self.pane_model.update_terminal_focus();
|
||||||
|
|
||||||
|
if let ContextPage::KeyboardShortcuts = context_page {
|
||||||
|
self.shortcut_page_toggle();
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "password_manager")]
|
#[cfg(feature = "password_manager")]
|
||||||
if ContextPage::PasswordManager == context_page {
|
if ContextPage::PasswordManager == context_page {
|
||||||
if self.core.window.show_context {
|
if self.core.window.show_context {
|
||||||
|
|
@ -2951,9 +3022,8 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ContextPage::KeyboardShortcuts = context_page {
|
if let ContextPage::KeyboardShortcuts = context_page {
|
||||||
self.shortcut_capture = None;
|
self.shortcut_page_toggle();
|
||||||
self.shortcut_conflict = None;
|
return self.update_focus();
|
||||||
self.shortcut_conflict_overlay_restore = None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "password_manager")]
|
#[cfg(feature = "password_manager")]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue