Skip to content

Commit 02fda6e

Browse files
authored
Merge pull request #789 from multiplex55/tagandnote
Tagandnote
2 parents b8cfafd + c76da28 commit 02fda6e

6 files changed

Lines changed: 494 additions & 82 deletions

File tree

src/gui/mod.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ const SUBCOMMANDS: &[&str] = &[
120120

121121
/// Prefix used to search user saved applications.
122122
pub const APP_PREFIX: &str = "app";
123+
const NOTE_SEARCH_DEBOUNCE: Duration = Duration::from_secs(1);
123124

124125
fn scale_ui<R>(ui: &mut egui::Ui, scale: f32, add_contents: impl FnOnce(&mut egui::Ui) -> R) -> R {
125126
ui.scope(|ui| {
@@ -518,6 +519,7 @@ pub struct LauncherApp {
518519
last_results_valid: bool,
519520
last_timer_query: bool,
520521
last_stopwatch_query: bool,
522+
last_note_search_change: Option<Instant>,
521523
pending_query: Option<String>,
522524
confirm_modal: ConfirmationModal,
523525
pending_confirm: Option<PendingConfirmAction>,
@@ -714,6 +716,39 @@ impl LauncherApp {
714716
}
715717
}
716718

719+
fn is_note_search_query(query: &str) -> bool {
720+
query
721+
.trim_start()
722+
.to_lowercase()
723+
.starts_with("note search")
724+
}
725+
726+
fn note_search_debounce_ready(
727+
last_change: Option<Instant>,
728+
now: Instant,
729+
debounce: Duration,
730+
) -> bool {
731+
last_change
732+
.map(|changed_at| now.duration_since(changed_at) >= debounce)
733+
.unwrap_or(false)
734+
}
735+
736+
fn maybe_run_note_search_debounce(&mut self) {
737+
if !Self::is_note_search_query(&self.query) {
738+
self.last_note_search_change = None;
739+
return;
740+
}
741+
742+
if Self::note_search_debounce_ready(
743+
self.last_note_search_change,
744+
Instant::now(),
745+
NOTE_SEARCH_DEBOUNCE,
746+
) {
747+
self.search();
748+
self.last_note_search_change = None;
749+
}
750+
}
751+
717752
pub fn plugin_enabled(&self, name: &str) -> bool {
718753
match &self.enabled_plugins {
719754
Some(set) => set.contains(name),
@@ -1315,6 +1350,7 @@ impl LauncherApp {
13151350
last_results_valid: false,
13161351
last_timer_query: false,
13171352
last_stopwatch_query: false,
1353+
last_note_search_change: None,
13181354
pending_query: None,
13191355
confirm_modal: ConfirmationModal::default(),
13201356
pending_confirm: None,
@@ -3477,6 +3513,7 @@ impl eframe::App for LauncherApp {
34773513
self.search();
34783514
self.focus_input();
34793515
}
3516+
self.maybe_run_note_search_debounce();
34803517
if let (Some(t), Some(_)) = (self.error_time, self.error.as_ref()) {
34813518
if t.elapsed().as_secs_f32() >= 3.0 {
34823519
self.error = None;
@@ -3690,7 +3727,12 @@ impl eframe::App for LauncherApp {
36903727

36913728
if input.changed() {
36923729
self.autocomplete_index = 0;
3693-
self.search();
3730+
if Self::is_note_search_query(&self.query) {
3731+
self.last_note_search_change = Some(Instant::now());
3732+
} else {
3733+
self.last_note_search_change = None;
3734+
self.search();
3735+
}
36943736
}
36953737

36963738
if self.query_autocomplete && !use_dashboard && !self.suggestions.is_empty() {
@@ -4854,6 +4896,7 @@ mod tests {
48544896
Arc, Mutex,
48554897
};
48564898
use tempfile::tempdir;
4899+
use std::time::{Duration, Instant};
48574900

48584901
static TEST_MUTEX: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
48594902

@@ -5148,4 +5191,24 @@ mod tests {
51485191

51495192
std::env::set_current_dir(orig_dir).unwrap();
51505193
}
5194+
5195+
#[test]
5196+
fn note_search_debounce_respects_delay() {
5197+
let start = Instant::now();
5198+
assert!(!LauncherApp::note_search_debounce_ready(
5199+
Some(start),
5200+
start,
5201+
NOTE_SEARCH_DEBOUNCE,
5202+
));
5203+
assert!(!LauncherApp::note_search_debounce_ready(
5204+
Some(start),
5205+
start + Duration::from_millis(999),
5206+
NOTE_SEARCH_DEBOUNCE,
5207+
));
5208+
assert!(LauncherApp::note_search_debounce_ready(
5209+
Some(start),
5210+
start + NOTE_SEARCH_DEBOUNCE,
5211+
NOTE_SEARCH_DEBOUNCE,
5212+
));
5213+
}
51515214
}

src/gui/todo_view_dialog.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ impl TodoViewDialog {
8989
.sort_by(|a, b| self.entries[*b].priority.cmp(&self.entries[*a].priority));
9090
}
9191
let area_height = ui.available_height();
92+
// Keep horizontal overflow for long todo text without wrapping.
9293
egui::ScrollArea::both()
94+
.auto_shrink([false, false])
9395
.max_height(area_height)
9496
.show(ui, |ui| {
9597
for idx in indices {
@@ -134,13 +136,15 @@ impl TodoViewDialog {
134136
});
135137
} else {
136138
let entry = &mut self.entries[idx];
137-
ui.horizontal_wrapped(|ui| {
139+
ui.horizontal(|ui| {
138140
if ui.checkbox(&mut entry.done, "").changed() {
139141
save_now = true;
140142
}
141-
let resp = ui.label(entry.text.replace('\n', " "));
143+
let resp = ui.add(
144+
egui::Label::new(entry.text.replace('\n', " ")).wrap(false),
145+
);
142146
let idx_copy = idx;
143-
resp.clone().context_menu(|ui| {
147+
resp.clone().context_menu(|ui: &mut egui::Ui| {
144148
if ui.button("Edit Todo").clicked() {
145149
self.editing_idx = Some(idx_copy);
146150
self.editing_text = entry.text.clone();
@@ -149,15 +153,18 @@ impl TodoViewDialog {
149153
ui.close_menu();
150154
}
151155
});
152-
ui.label(format!("p{}", entry.priority));
156+
ui.add(
157+
egui::Label::new(format!("p{}", entry.priority))
158+
.wrap(false),
159+
);
153160
if !entry.tags.is_empty() {
154-
ui.label(format!("#{:?}", entry.tags.join(", ")));
155-
}
156-
if ui.button("Edit").clicked() {
157-
self.editing_idx = Some(idx);
158-
self.editing_text = entry.text.clone();
159-
self.editing_priority = entry.priority;
160-
self.editing_tags = entry.tags.join(", ");
161+
ui.add(
162+
egui::Label::new(format!(
163+
"#{:?}",
164+
entry.tags.join(", ")
165+
))
166+
.wrap(false),
167+
);
161168
}
162169
});
163170
}

0 commit comments

Comments
 (0)