repl.rs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. use rustyline::{
  2. completion::Completer, highlight::Highlighter, hint::Hinter, validate::Validator, Helper,
  3. };
  4. use std::cell::RefCell;
  5. use std::rc::Rc;
  6. pub struct Repl {
  7. state: Rc<RefCell<crate::interp::State>>,
  8. }
  9. impl Repl {
  10. pub fn new(state: Rc<RefCell<crate::interp::State>>) -> Repl {
  11. Repl { state }
  12. }
  13. }
  14. impl Completer for Repl {
  15. type Candidate = String;
  16. fn complete(
  17. &self,
  18. line: &str,
  19. pos: usize,
  20. _ctx: &rustyline::Context<'_>,
  21. ) -> rustyline::Result<(usize, Vec<String>)> {
  22. if pos == 0 {
  23. return Ok((pos, Vec::new()));
  24. }
  25. if let Some(c) = line.chars().nth(pos - 1) {
  26. if c.is_alphabetic() {
  27. // this means we're looking at maybe something
  28. // alphabetic; let's see what the current typed thing
  29. // is
  30. let mut str_start = 0;
  31. for (idx, ch) in line.chars().enumerate() {
  32. if ch.is_whitespace() {
  33. str_start = idx + 1;
  34. }
  35. if idx == pos {
  36. break;
  37. }
  38. }
  39. // we've now found the current fragment
  40. let so_far = &line[str_start..pos];
  41. return Ok((
  42. str_start,
  43. self.state.borrow().autocomplete(so_far, str_start == 0),
  44. ));
  45. }
  46. }
  47. Ok((pos, Vec::new()))
  48. }
  49. }
  50. impl Hinter for Repl {
  51. type Hint = String;
  52. fn hint(&self, line: &str, pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String> {
  53. if pos == 0 {
  54. return None;
  55. }
  56. if let Some(c) = line.chars().nth(pos - 1) {
  57. if c.is_alphabetic() {
  58. // this means we're looking at maybe something
  59. // alphabetic; let's see what the current typed thing
  60. // is
  61. let mut str_start = 0;
  62. for (idx, ch) in line.chars().enumerate() {
  63. if ch.is_whitespace() {
  64. str_start = idx + 1;
  65. }
  66. if idx == pos {
  67. break;
  68. }
  69. }
  70. // don't suggest for stuff that's too short
  71. if pos - str_start < 2 {
  72. return None;
  73. }
  74. // we've now found the current fragment
  75. let so_far = &line[str_start..pos];
  76. let autocompletes = self.state.borrow().autocomplete(so_far, str_start == 0);
  77. if autocompletes.len() == 1 {
  78. let known = autocompletes.first().unwrap();
  79. return known
  80. .strip_prefix(so_far)
  81. .map(|s| ansi_term::Colour::Blue.dimmed().paint(s).to_string());
  82. } else {
  83. return None;
  84. }
  85. }
  86. }
  87. None
  88. }
  89. }
  90. impl Highlighter for Repl {}
  91. impl Validator for Repl {}
  92. impl Helper for Repl {}