self.b0 = self.b;
}
+ pub fn read_term_from_user_input(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
+ let atoms: Vec<_> = self.atom_tbl.table.iter().map(|a| a.as_str().to_string()).collect();
+
+ if let Stream::Readline(ptr) = stream {
+ unsafe {
+ let readline = ptr.as_ptr().as_mut().unwrap();
+ readline.set_atoms_for_completion(atoms);
+ let ret = self.read_term(stream, indices);
+ return ret
+ }
+ }
+
+ unreachable!("Stream must be a Stream::Readline(_)")
+ }
+
pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
fn push_var_eq_functors<'a>(
heap: &mut Heap,
use crate::machine::machine_state::MachineState;
use crate::machine::streams::*;
use crate::parser::char_reader::*;
+use crate::repl_helper::Helper;
use crate::types::*;
use fxhash::FxBuildHasher;
use rustyline::error::ReadlineError;
-use rustyline::{Cmd, Config, Editor, KeyEvent};
+use rustyline::{Config, Editor};
use std::collections::VecDeque;
use std::io::{Cursor, Error, ErrorKind, Read};
#[derive(Debug)]
pub struct ReadlineStream {
- rl: Editor<()>,
+ rl: Editor<Helper>,
pending_input: Cursor<String>,
add_history: bool,
}
#[inline]
pub fn new(pending_input: &str, add_history: bool) -> Self {
let config = Config::builder().check_cursor_position(true).build();
- let mut rl = Editor::<()>::with_config(config);
+ let helper = Helper::new();
+
+ let mut rl = Editor::with_config(config);
+ rl.set_helper(Some(helper));
if let Some(mut path) = dirs_next::home_dir() {
path.push(HISTORY_FILE);
}
}
- rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
+ // rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
ReadlineStream {
rl,
}
}
+ pub fn set_atoms_for_completion(&mut self, atoms: Vec<String>) {
+ let helper = self.rl.helper_mut().unwrap();
+ helper.atoms = atoms;
+ }
+
#[inline]
pub fn reset(&mut self) {
self.pending_input.get_mut().clear();
--- /dev/null
+use rustyline::completion::Completer;
+use rustyline::hint::Hinter;
+use rustyline::validate::Validator;
+use rustyline::highlight::{MatchingBracketHighlighter, Highlighter};
+use rustyline::{Helper as RlHelper, Result, Context};
+
+// pub struct Atoms {
+// atoms: *const *const str,
+// len: usize,
+// }
+
+// impl Atoms {
+// pub fn new() -> Self {
+// Self {
+// atoms: std::ptr::null(),
+// len: 0,
+// }
+// }
+// }
+
+// pub struct AtomsIterator<'a> {
+// atoms: &'a Atoms,
+// idx: usize,
+// }
+
+// impl<'a> Iterator for AtomsIterator<'a> {
+// type Item = &'a str;
+
+// fn next(&mut self) -> Option<Self::Item> {
+// self.idx += 1;
+
+// if self.idx == self.atoms.len {
+// None
+// } else {
+// unsafe {
+// let next = self.atoms.atoms.offset(self.idx as isize);
+// (*next).as_ref()
+// }
+// }
+// }
+// }
+
+// impl<'a> IntoIterator for &'a Atoms {
+// type Item = &'a str;
+// type IntoIter = AtomsIterator<'a>;
+
+// fn into_iter(self) -> Self::IntoIter {
+// Self::IntoIter {
+// atoms: self,
+// idx: 0,
+// }
+// }
+// }
+
+// TODO: Maybe add validation to the helper
+pub struct Helper {
+ highligher: MatchingBracketHighlighter,
+ pub atoms: Vec<String>,
+}
+
+impl Helper {
+ pub fn new() -> Self {
+ Self {
+ highligher: MatchingBracketHighlighter::new(),
+ atoms: vec![],
+ }
+ }
+
+ // pub fn set_atoms(&mut self, atoms_ptr: *const *const str, len: usize) {
+ // self.atoms.atoms = atoms_ptr;
+ // self.atoms.len = len;
+ // }
+}
+
+impl RlHelper for Helper {}
+
+fn get_prefix(line: &str, pos: usize) -> Option<usize> {
+ let mut start_of_atom = None;
+ let mut first_letter = true;
+
+ for (i, char) in line.chars().enumerate() {
+ if first_letter {
+ if char.is_alphabetic() && char.is_lowercase() {
+ start_of_atom = Some(i);
+ }
+
+ first_letter = false;
+ }
+
+ if !char.is_alphanumeric() && char != '_' {
+ first_letter = true;
+ start_of_atom = None;
+ }
+
+ if i == pos {
+ break
+ }
+ }
+
+ if first_letter || pos == 0 {
+ start_of_atom = Some(pos)
+ }
+
+ start_of_atom
+}
+
+impl Completer for Helper {
+ type Candidate = String;
+
+ fn complete(&self, line: &str, pos: usize, _ctx: &Context<'_>) -> Result<(usize, Vec<Self::Candidate>)> {
+ let start_of_prefix = get_prefix(line, pos);
+ if let Some(idx) = start_of_prefix {
+ let sub_str = line.get(idx..pos).unwrap();
+ let matching = self.atoms.iter().filter(|a| a.starts_with(sub_str)).map(|s| s.to_string()).collect();
+ Ok((idx, matching))
+ } else {
+ Ok((0, vec![]))
+ }
+ }
+}
+
+impl Highlighter for Helper {
+ fn highlight<'l>(&self, line: &'l str, pos: usize) -> std::borrow::Cow<'l, str> {
+ self.highligher.highlight(line, pos)
+ }
+
+ fn highlight_char(&self, line: &str, pos: usize) -> bool {
+ self.highligher.highlight_char(line, pos)
+ }
+}
+
+impl Validator for Helper {}
+
+impl Hinter for Helper {
+ type Hint = String;
+}