luaur_repl_cli/functions/
complete_partial_matches.rs1use alloc::string::String;
2use core::ffi::CStr;
3
4use luaur_common::functions::starts_with::startsWith;
5use luaur_vm::enums::lua_type::lua_Type;
6use luaur_vm::functions::lua_next::lua_next;
7use luaur_vm::functions::lua_pushnil::lua_pushnil;
8use luaur_vm::functions::lua_type::lua_type;
9use luaur_vm::macros::lua_istable::lua_istable;
10use luaur_vm::macros::lua_pop::lua_pop;
11use luaur_vm::macros::lua_tostring::lua_tostring;
12use luaur_vm::type_aliases::lua_state::lua_State;
13
14use crate::functions::try_replace_top_with_index::try_replace_top_with_index;
15
16const MAX_TRAVERSAL_LIMIT: i32 = 50;
18
19pub unsafe fn complete_partial_matches(
22 l: *mut lua_State,
23 complete_only_functions: bool,
24 edit_buffer: &str,
25 prefix: &str,
26 add_completion_callback: &dyn Fn(&str, &str),
27) {
28 let mut i = 0;
29 while i < MAX_TRAVERSAL_LIMIT && lua_istable!(l, -1) {
30 lua_pushnil(l);
32
33 while lua_next(l, -2) != 0 {
35 if lua_type(l, -2) == lua_Type::LUA_TSTRING as i32 {
36 let key_ptr = lua_tostring!(l, -2);
38 let key = CStr::from_ptr(key_ptr).to_string_lossy();
39 let value_type = lua_type(l, -1);
40
41 let required_value_type =
43 !complete_only_functions || value_type == lua_Type::LUA_TFUNCTION as i32;
44
45 if !key.is_empty() && required_value_type && startsWith(&key, prefix) {
46 let completed_component = &key[prefix.len()..];
47 let mut completion =
48 String::with_capacity(edit_buffer.len() + completed_component.len() + 1);
49 completion.push_str(edit_buffer);
50 completion.push_str(completed_component);
51 if value_type == lua_Type::LUA_TFUNCTION as i32 {
52 completion.push('(');
54 }
55 add_completion_callback(&completion, &key);
56 }
57 }
58 lua_pop(l, 1);
59 }
60
61 if !try_replace_top_with_index(l) {
63 break;
64 }
65
66 i += 1;
67 }
68}