main
1diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs
2index 926f33a3..f3124c63 100644
3--- a/helix-term/src/ui/prompt.rs
4+++ b/helix-term/src/ui/prompt.rs
5@@ -44,6 +44,8 @@ pub struct Prompt {
6 selection: Option<usize>,
7 history_register: Option<char>,
8 history_pos: Option<usize>,
9+ history_pattern: Option<String>,
10+ user_edited: bool,
11 completion_fn: CompletionFn,
12 callback_fn: CallbackFn,
13 pub doc_fn: DocFn,
14@@ -100,6 +102,8 @@ pub fn new(
15 selection: None,
16 history_register,
17 history_pos: None,
18+ history_pattern: None,
19+ user_edited: true,
20 completion_fn: Box::new(completion_fn),
21 callback_fn: Box::new(callback_fn),
22 doc_fn: Box::new(|_| None),
23@@ -346,27 +350,40 @@ pub fn change_history(
24 register: char,
25 direction: CompletionDirection,
26 ) {
27+ if self.line.is_empty() {
28+ self.history_pattern = None;
29+ self.history_pos = None;
30+ } else if self.user_edited {
31+ self.history_pattern = Some(self.line.clone());
32+ self.history_pos = None;
33+ }
34 (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
35- let mut values = match cx.editor.registers.read(register, cx.editor) {
36- Some(values) if values.len() > 0 => values.rev(),
37+
38+ let values: Vec<_> = match cx.editor.registers.read(register, cx.editor) {
39+ Some(values) if values.len() > 0 => {
40+ if let Some(pattern) = &self.history_pattern {
41+ values.filter(|the| the.contains(pattern)).rev().collect()
42+ } else {
43+ values.rev().collect()
44+ }
45+ }
46 _ => return,
47 };
48+ if values.is_empty() {
49+ return;
50+ }
51
52 let end = values.len().saturating_sub(1);
53
54 let index = match direction {
55 CompletionDirection::Forward => self.history_pos.map_or(0, |i| i + 1),
56- CompletionDirection::Backward => self
57- .history_pos
58- .unwrap_or_else(|| values.len())
59- .saturating_sub(1),
60+ CompletionDirection::Backward => {
61+ self.history_pos.unwrap_or(values.len()).saturating_sub(1)
62+ }
63 }
64 .min(end);
65
66- self.line = values.nth(index).unwrap().to_string();
67- // Appease the borrow checker.
68- drop(values);
69-
70+ self.line = values.into_iter().nth(index).unwrap().to_string();
71 self.history_pos = Some(index);
72
73 self.move_end();
74@@ -627,6 +644,7 @@ fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
75 compositor.remove(id);
76 })));
77
78+ let mut user_edited = true;
79 match event {
80 ctrl!('c') | key!(Esc) => {
81 (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
82@@ -713,11 +731,13 @@ fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
83 }
84 }
85 ctrl!('p') | key!(Up) => {
86+ user_edited = false;
87 if let Some(register) = self.history_register {
88 self.change_history(cx, register, CompletionDirection::Backward);
89 }
90 }
91 ctrl!('n') | key!(Down) => {
92+ user_edited = false;
93 if let Some(register) = self.history_register {
94 self.change_history(cx, register, CompletionDirection::Forward);
95 }
96@@ -765,6 +785,7 @@ fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
97 }
98 _ => (),
99 };
100+ self.user_edited = user_edited;
101
102 EventResult::Consumed(None)
103 }