1use std::{cell::RefCell, rc::Rc};
2
3use rustyline::{
4 Helper, Result,
5 completion::{Completer, FilenameCompleter, Pair},
6 highlight::Highlighter,
7 hint::Hinter,
8 validate::Validator,
9};
10
11use crate::{Repl, commands::Edge};
12
13pub struct ReplHelper {
14 filename_completer: FilenameCompleter,
15 repl: Rc<RefCell<Repl>>,
16}
17
18impl ReplHelper {
19 pub fn new(repl: Rc<RefCell<Repl>>) -> Self {
20 Self {
21 filename_completer: FilenameCompleter::new(),
22 repl,
23 }
24 }
25
26 fn complete_command(&self, line: &str, pos: usize) -> Result<(usize, Vec<Pair>)> {
27 let repl = self.repl.borrow();
28
29 let line = &line[..pos];
30 let mut args = line.split_whitespace().collect::<Vec<_>>();
31 if char::is_whitespace(line.chars().last().unwrap()) {
33 args.push("");
35 }
36
37 let Some(node) = repl.commands.traverse(&args[..args.len() - 1]) else {
39 return Ok((pos, Vec::new()));
40 };
41
42 let last_part = args.last().unwrap();
43 let last_part_start = line.rfind(last_part).unwrap_or(0);
44 let mut suggestions = Vec::new();
45
46 let keywords = node.next_keywords_by_prefix(last_part).map(|k| Pair {
47 display: k.to_owned(),
48 replacement: k.to_owned(),
49 });
50 suggestions.extend(keywords);
51
52 if node.edges.contains_key(&Edge::Filename) {
53 let (start, filenames) = self.filename_completer.complete_path_unsorted(line, pos)?;
54 debug_assert_eq!(start, last_part_start);
55 suggestions.extend(filenames);
56 }
57
58 if node.edges.contains_key(&Edge::Variable) {
59 }
61
62 suggestions.sort_by(|a, b| a.display.cmp(&b.display));
63 Ok((last_part_start, suggestions))
64 }
65}
66
67impl Completer for ReplHelper {
68 type Candidate = Pair;
69
70 fn complete(
71 &self,
72 line: &str,
73 pos: usize,
74 _ctx: &rustyline::Context,
75 ) -> Result<(usize, Vec<Self::Candidate>)> {
76 if line.starts_with('.') {
77 self.complete_command(line, pos)
78 } else {
79 Ok((0, Vec::new()))
81 }
82 }
83}
84
85impl Hinter for ReplHelper {
86 type Hint = String;
87}
88
89impl Highlighter for ReplHelper {}
90
91impl Validator for ReplHelper {}
92
93impl Helper for ReplHelper {}