1use std::mem;
2use std::sync::Arc;
3
4use tuikit::prelude::*;
5use unicode_width::UnicodeWidthStr;
6
7use crate::event::{Event, EventHandler, UpdateScreen};
8use crate::options::SkimOptions;
9use crate::theme::{ColorTheme, DEFAULT_THEME};
10use crate::util::clear_canvas;
11
12#[derive(Clone, Copy, PartialEq)]
13enum QueryMode {
14 Cmd,
15 Query,
16}
17
18pub struct Query {
19 cmd_before: Vec<char>,
20 cmd_after: Vec<char>,
21 fz_query_before: Vec<char>,
22 fz_query_after: Vec<char>,
23 yank: Vec<char>,
24
25 mode: QueryMode,
26 base_cmd: String,
27 replstr: String,
28 query_prompt: String,
29 cmd_prompt: String,
30
31 cmd_history_before: Vec<String>,
32 cmd_history_after: Vec<String>,
33 fz_query_history_before: Vec<String>,
34 fz_query_history_after: Vec<String>,
35
36 pasted: Option<String>,
37
38 theme: Arc<ColorTheme>,
39}
40
41#[allow(dead_code)]
42impl Query {
43 pub fn builder() -> Self {
44 Query {
45 cmd_before: Vec::new(),
46 cmd_after: Vec::new(),
47 fz_query_before: Vec::new(),
48 fz_query_after: Vec::new(),
49 yank: Vec::new(),
50 mode: QueryMode::Query,
51 base_cmd: String::new(),
52 replstr: "{}".to_string(),
53 query_prompt: "> ".to_string(),
54 cmd_prompt: "c> ".to_string(),
55
56 cmd_history_before: Vec::new(),
57 cmd_history_after: Vec::new(),
58 fz_query_history_before: Vec::new(),
59 fz_query_history_after: Vec::new(),
60
61 pasted: None,
62
63 theme: Arc::new(*DEFAULT_THEME),
64 }
65 }
66
67 pub fn from_options(options: &SkimOptions) -> Self {
68 let mut query = Self::builder();
69 query.parse_options(options);
70 query
71 }
72
73 pub fn replace_base_cmd_if_not_set(mut self, base_cmd: &str) -> Self {
74 if self.base_cmd.is_empty() {
75 self.base_cmd = base_cmd.to_owned();
76 }
77 self
78 }
79
80 pub fn fz_query(mut self, query: &str) -> Self {
81 self.fz_query_before = query.chars().collect();
82 self
83 }
84
85 pub fn theme(mut self, theme: Arc<ColorTheme>) -> Self {
86 self.theme = theme;
87 self
88 }
89
90 pub fn cmd_history(mut self, mut history: Vec<String>) -> Self {
91 self.cmd_history_before.append(&mut history);
92 self
93 }
94
95 pub fn fz_query_history(mut self, mut history: Vec<String>) -> Self {
96 self.fz_query_history_before.append(&mut history);
97 self
98 }
99
100 pub fn build(self) -> Self {
101 self
102 }
103
104 fn parse_options(&mut self, options: &SkimOptions) {
105 if let Some(base_cmd) = options.cmd {
108 self.base_cmd = base_cmd.to_string();
109 }
110
111 if let Some(query) = options.query {
112 self.fz_query_before = query.chars().collect();
113 }
114
115 if let Some(cmd_query) = options.cmd_query {
116 self.cmd_before = cmd_query.chars().collect();
117 }
118
119 if let Some(replstr) = options.replstr {
120 self.replstr = replstr.to_string();
121 }
122
123 if options.interactive {
124 self.mode = QueryMode::Cmd;
125 }
126
127 if let Some(query_prompt) = options.prompt {
128 self.query_prompt = query_prompt.to_string();
129 }
130
131 if let Some(cmd_prompt) = options.cmd_prompt {
132 self.cmd_prompt = cmd_prompt.to_string();
133 }
134
135 self.fz_query_history_before = options.query_history.to_vec();
136 self.cmd_history_before = options.cmd_history.to_vec();
137 }
138
139 pub fn in_query_mode(&self) -> bool {
140 match self.mode {
141 QueryMode::Cmd => false,
142 QueryMode::Query => true,
143 }
144 }
145
146 pub fn get_fz_query(&self) -> String {
147 self.fz_query_before
148 .iter()
149 .cloned()
150 .chain(self.fz_query_after.iter().cloned().rev())
151 .collect()
152 }
153
154 pub fn get_cmd(&self) -> String {
155 let arg: String = self
156 .cmd_before
157 .iter()
158 .cloned()
159 .chain(self.cmd_after.iter().cloned().rev())
160 .collect();
161 self.base_cmd.replace(&self.replstr, &arg)
162 }
163
164 pub fn get_cmd_query(&self) -> String {
165 self.cmd_before
166 .iter()
167 .cloned()
168 .chain(self.cmd_after.iter().cloned().rev())
169 .collect()
170 }
171
172 fn get_query(&mut self) -> String {
173 match self.mode {
174 QueryMode::Query => self.get_fz_query(),
175 QueryMode::Cmd => self.get_cmd_query(),
176 }
177 }
178
179 fn get_before(&self) -> String {
180 match self.mode {
181 QueryMode::Cmd => self.cmd_before.iter().cloned().collect(),
182 QueryMode::Query => self.fz_query_before.iter().cloned().collect(),
183 }
184 }
185
186 fn get_after(&self) -> String {
187 match self.mode {
188 QueryMode::Cmd => self.cmd_after.iter().cloned().rev().collect(),
189 QueryMode::Query => self.fz_query_after.iter().cloned().rev().collect(),
190 }
191 }
192
193 fn get_prompt(&self) -> &str {
194 match self.mode {
195 QueryMode::Cmd => &self.cmd_prompt,
196 QueryMode::Query => &self.query_prompt,
197 }
198 }
199
200 fn get_query_ref(&mut self) -> (&mut Vec<char>, &mut Vec<char>) {
201 match self.mode {
202 QueryMode::Query => (&mut self.fz_query_before, &mut self.fz_query_after),
203 QueryMode::Cmd => (&mut self.cmd_before, &mut self.cmd_after),
204 }
205 }
206
207 fn get_history_ref(&mut self) -> (&mut Vec<String>, &mut Vec<String>) {
208 match self.mode {
209 QueryMode::Query => (&mut self.fz_query_history_before, &mut self.fz_query_history_after),
210 QueryMode::Cmd => (&mut self.cmd_history_before, &mut self.cmd_history_after),
211 }
212 }
213
214 fn save_yank(&mut self, mut yank: Vec<char>, reverse: bool) {
215 if yank.is_empty() {
216 return;
217 }
218
219 self.yank.clear();
220
221 if reverse {
222 self.yank.append(&mut yank.into_iter().rev().collect());
223 } else {
224 self.yank.append(&mut yank);
225 }
226 }
227
228 pub fn act_query_toggle_interactive(&mut self) {
232 self.mode = match self.mode {
233 QueryMode::Query => QueryMode::Cmd,
234 QueryMode::Cmd => QueryMode::Query,
235 }
236 }
237
238 pub fn act_add_char(&mut self, ch: char) {
239 let (before, _) = self.get_query_ref();
240 before.push(ch);
241 }
242
243 pub fn act_backward_delete_char(&mut self) {
244 let (before, _) = self.get_query_ref();
245 let _ = before.pop();
246 }
247
248 pub fn act_delete_char(&mut self) {
250 let (_, after) = self.get_query_ref();
251 let _ = after.pop();
252 }
253
254 pub fn act_backward_char(&mut self) {
255 let (before, after) = self.get_query_ref();
256 if let Some(ch) = before.pop() {
257 after.push(ch);
258 }
259 }
260
261 pub fn act_forward_char(&mut self) {
262 let (before, after) = self.get_query_ref();
263 if let Some(ch) = after.pop() {
264 before.push(ch);
265 }
266 }
267
268 pub fn act_unix_word_rubout(&mut self) {
269 let mut yank = Vec::new();
270
271 {
272 let (before, _) = self.get_query_ref();
273 while !before.is_empty() && before[before.len() - 1].is_whitespace() {
275 yank.push(before.pop().unwrap());
276 }
277
278 while !before.is_empty() && !before[before.len() - 1].is_whitespace() {
280 yank.push(before.pop().unwrap());
281 }
282 }
283
284 self.save_yank(yank, true);
285 }
286
287 pub fn act_backward_kill_word(&mut self) {
288 let mut yank = Vec::new();
289
290 {
291 let (before, _) = self.get_query_ref();
292 while !before.is_empty() && !before[before.len() - 1].is_alphanumeric() {
294 yank.push(before.pop().unwrap());
295 }
296
297 while !before.is_empty() && before[before.len() - 1].is_alphanumeric() {
299 yank.push(before.pop().unwrap());
300 }
301 }
302
303 self.save_yank(yank, true);
304 }
305
306 pub fn act_kill_word(&mut self) {
307 let mut yank = Vec::new();
308
309 {
310 let (_, after) = self.get_query_ref();
311
312 while !after.is_empty() && !after[after.len() - 1].is_alphanumeric() {
314 yank.push(after.pop().unwrap());
315 }
316 while !after.is_empty() && after[after.len() - 1].is_alphanumeric() {
318 yank.push(after.pop().unwrap());
319 }
320 }
321 self.save_yank(yank, false);
322 }
323
324 pub fn act_backward_word(&mut self) {
325 let (before, after) = self.get_query_ref();
326 while !before.is_empty() && !before[before.len() - 1].is_alphanumeric() {
328 if let Some(ch) = before.pop() {
329 after.push(ch);
330 }
331 }
332
333 while !before.is_empty() && before[before.len() - 1].is_alphanumeric() {
335 if let Some(ch) = before.pop() {
336 after.push(ch);
337 }
338 }
339 }
340
341 pub fn act_forward_word(&mut self) {
342 let (before, after) = self.get_query_ref();
343 while !after.is_empty() && after[after.len() - 1].is_whitespace() {
346 if let Some(ch) = after.pop() {
347 before.push(ch);
348 }
349 }
350
351 while !after.is_empty() && !after[after.len() - 1].is_whitespace() {
352 if let Some(ch) = after.pop() {
353 before.push(ch);
354 }
355 }
356 }
357
358 pub fn act_beginning_of_line(&mut self) {
359 let (before, after) = self.get_query_ref();
360 while !before.is_empty() {
361 if let Some(ch) = before.pop() {
362 after.push(ch);
363 }
364 }
365 }
366
367 pub fn act_end_of_line(&mut self) {
368 let (before, after) = self.get_query_ref();
369 while !after.is_empty() {
370 if let Some(ch) = after.pop() {
371 before.push(ch);
372 }
373 }
374 }
375
376 pub fn act_kill_line(&mut self) {
377 let (_, after) = self.get_query_ref();
378 let after = std::mem::take(after);
379 self.save_yank(after, false);
380 }
381
382 pub fn act_line_discard(&mut self) {
383 let (before, _) = self.get_query_ref();
384 let before = std::mem::take(before);
385 self.save_yank(before, false);
386 }
387
388 pub fn act_yank(&mut self) {
389 let yank = std::mem::take(&mut self.yank);
390 for &c in &yank {
391 self.act_add_char(c);
392 }
393 let _ = mem::replace(&mut self.yank, yank);
394 }
395
396 pub fn previous_history(&mut self) {
397 let current_query = self.get_query();
398 let (history_before, history_after) = self.get_history_ref();
399 if let Some(history) = history_before.pop() {
400 history_after.push(current_query);
401
402 let (query_before, _) = self.get_query_ref();
404 query_before.clear();
405 let mut new_query_chars = history.chars().collect();
406 query_before.append(&mut new_query_chars);
407 }
408 }
409
410 pub fn next_history(&mut self) {
411 let current_query = self.get_query();
412 let (history_before, history_after) = self.get_history_ref();
413 if let Some(history) = history_after.pop() {
414 history_before.push(current_query);
415
416 let (query_before, _) = self.get_query_ref();
418 query_before.clear();
419 let mut new_query_chars = history.chars().collect();
420 query_before.append(&mut new_query_chars);
421 }
422 }
423
424 fn query_changed(
425 &self,
426 mode: QueryMode,
427 query_before_len: usize,
428 query_after_len: usize,
429 cmd_before_len: usize,
430 cmd_after_len: usize,
431 ) -> bool {
432 self.mode != mode
433 || self.fz_query_before.len() != query_before_len
434 || self.fz_query_after.len() != query_after_len
435 || self.cmd_before.len() != cmd_before_len
436 || self.cmd_after.len() != cmd_after_len
437 }
438}
439
440impl EventHandler for Query {
441 fn handle(&mut self, event: &Event) -> UpdateScreen {
442 use crate::event::Event::*;
443
444 let mode = self.mode;
445 let query_before_len = self.fz_query_before.len();
446 let query_after_len = self.fz_query_after.len();
447 let cmd_before_len = self.cmd_before.len();
448 let cmd_after_len = self.cmd_after.len();
449
450 match event {
451 EvActAddChar(ch) => match self.pasted.as_mut() {
452 Some(pasted) => pasted.push(*ch),
453 None => self.act_add_char(*ch),
454 },
455
456 EvActDeleteChar | EvActDeleteCharEOF => {
457 self.act_delete_char();
458 }
459
460 EvActBackwardChar => {
461 self.act_backward_char();
462 }
463
464 EvActBackwardDeleteChar => {
465 self.act_backward_delete_char();
466 }
467
468 EvActBackwardKillWord => {
469 self.act_backward_kill_word();
470 }
471
472 EvActBackwardWord => {
473 self.act_backward_word();
474 }
475
476 EvActBeginningOfLine => {
477 self.act_beginning_of_line();
478 }
479
480 EvActEndOfLine => {
481 self.act_end_of_line();
482 }
483
484 EvActForwardChar => {
485 self.act_forward_char();
486 }
487
488 EvActForwardWord => {
489 self.act_forward_word();
490 }
491
492 EvActKillLine => {
493 self.act_kill_line();
494 }
495
496 EvActKillWord => {
497 self.act_kill_word();
498 }
499
500 EvActPreviousHistory => self.previous_history(),
501
502 EvActNextHistory => {
503 self.next_history();
504 }
505
506 EvActUnixLineDiscard => {
507 self.act_line_discard();
508 }
509
510 EvActUnixWordRubout => {
511 self.act_unix_word_rubout();
512 }
513
514 EvActYank => {
515 self.act_yank();
516 }
517
518 EvActToggleInteractive => {
519 self.act_query_toggle_interactive();
520 }
521
522 EvInputKey(Key::BracketedPasteStart) => {
523 self.pasted.replace(String::new());
524 }
525
526 EvInputKey(Key::BracketedPasteEnd) => {
527 let pasted = self.pasted.take().unwrap_or_default();
528 for ch in pasted.chars() {
529 self.act_add_char(ch);
530 }
531 }
532
533 _ => {}
534 }
535
536 if self.query_changed(mode, query_before_len, query_after_len, cmd_before_len, cmd_after_len) {
537 UpdateScreen::REDRAW
538 } else {
539 UpdateScreen::DONT_REDRAW
540 }
541 }
542}
543
544impl Draw for Query {
545 fn draw(&self, canvas: &mut dyn Canvas) -> DrawResult<()> {
546 canvas.clear()?;
547 let before = self.get_before();
548 let after = self.get_after();
549 let prompt = self.get_prompt();
550 clear_canvas(canvas)?;
551
552 let prompt_width = canvas.print_with_attr(0, 0, prompt, self.theme.prompt())?;
553 let before_width = canvas.print_with_attr(0, prompt_width, &before, self.theme.query())?;
554 let col = prompt_width + before_width;
555 canvas.print_with_attr(0, col, &after, self.theme.query())?;
556 canvas.set_cursor(0, col)?;
557 canvas.show_cursor(true)?;
558 Ok(())
559 }
560}
561
562impl Widget<Event> for Query {
563 fn size_hint(&self) -> (Option<usize>, Option<usize>) {
564 let before = self.get_before();
565 let after = self.get_after();
566 let prompt = self.get_prompt();
567 (Some(prompt.width() + before.width() + after.width() + 1), None)
568 }
569}
570
571#[cfg(test)]
572mod test {
573 use super::Query;
574
575 #[test]
576 fn test_new_query() {
577 let query1 = Query::builder().fz_query("").build();
578 assert_eq!(query1.get_fz_query(), "");
579
580 let query2 = Query::builder().fz_query("abc").build();
581 assert_eq!(query2.get_fz_query(), "abc");
582 }
583
584 #[test]
585 fn test_add_char() {
586 let mut query1 = Query::builder().fz_query("").build();
587 query1.act_add_char('a');
588 assert_eq!(query1.get_fz_query(), "a");
589 query1.act_add_char('b');
590 assert_eq!(query1.get_fz_query(), "ab");
591 query1.act_add_char('中');
592 assert_eq!(query1.get_fz_query(), "ab中");
593 }
594
595 #[test]
596 fn test_backward_delete_char() {
597 let mut query = Query::builder().fz_query("AB中c").build();
598 assert_eq!(query.get_fz_query(), "AB中c");
599
600 query.act_backward_delete_char();
601 assert_eq!(query.get_fz_query(), "AB中");
602
603 query.act_backward_delete_char();
604 assert_eq!(query.get_fz_query(), "AB");
605
606 query.act_backward_delete_char();
607 assert_eq!(query.get_fz_query(), "A");
608
609 query.act_backward_delete_char();
610 assert_eq!(query.get_fz_query(), "");
611
612 query.act_backward_delete_char();
613 assert_eq!(query.get_fz_query(), "");
614 }
615}