luaur_repl_cli/functions/complete_repl.rs
1use alloc::vec::Vec;
2
3use rustyline::completion::Pair;
4
5use luaur_vm::type_aliases::lua_state::lua_State;
6
7use crate::functions::ic_get_completions::ic_get_completions;
8use crate::functions::is_method_or_function_char::is_method_or_function_char;
9
10// Faithful rustyline analog of Repl.cpp's `completeRepl`.
11//
12// In C++ this was:
13// ic_complete_word(cenv, editBuffer, icGetCompletions, isMethodOrFunctionChar);
14// `ic_complete_word` walks backwards from the cursor over characters for which
15// the `is_word_char` predicate (`isMethodOrFunctionChar`) returns true to find
16// the start of the word being completed, hands that word to the completer
17// (`icGetCompletions`), and reports completions relative to that word start.
18//
19// rustyline's `Completer::complete(line, pos, ctx)` gives us the full line and
20// cursor position and expects `(start, candidates)`, so we reproduce isocline's
21// word-boundary scan here and return the matches gathered by `ic_get_completions`.
22pub unsafe fn complete_repl(l: *mut lua_State, line: &str, pos: usize) -> (usize, Vec<Pair>) {
23 let bytes = line.as_bytes();
24
25 // Walk backwards from the cursor over method/function characters
26 // (alphanumeric, '.', ':', '_') to locate the start of the word, exactly
27 // as isocline's word-boundary detection (`isMethodOrFunctionChar`) does.
28 let mut start = pos;
29 while start > 0 {
30 let c = bytes[start - 1] as core::ffi::c_char;
31 if is_method_or_function_char(&c as *const core::ffi::c_char, 1) {
32 start -= 1;
33 } else {
34 break;
35 }
36 }
37
38 let edit_buffer = &line[start..pos];
39 let completions = ic_get_completions(l, edit_buffer);
40
41 (start, completions)
42}