use alloc::vec::Vec;
use luaur_ast::records::ast_node::AstNode;
use luaur_ast::records::ast_visitor::AstVisitor;
use luaur_ast::records::position::Position;
#[derive(Debug, Clone)]
pub struct AutocompleteNodeFinder {
pub(crate) pos: Position,
pub(crate) ancestry: Vec<*mut AstNode>,
}
impl AutocompleteNodeFinder {
pub fn new(pos: Position) -> Self {
Self {
pos,
ancestry: Vec::new(),
}
}
}
impl AstVisitor for AutocompleteNodeFinder {
fn visit_node(&mut self, _node: *mut core::ffi::c_void) -> bool {
true
}
fn visit_expr(&mut self, node: *mut core::ffi::c_void) -> bool {
let expr = node as *mut luaur_ast::records::ast_expr::AstExpr;
unsafe {
let loc = (*expr).base.location;
if loc.begin <= self.pos && self.pos <= loc.end && loc.begin != loc.end {
self.ancestry.push(expr as *mut AstNode);
return true;
}
}
false
}
fn visit_stat(&mut self, node: *mut core::ffi::c_void) -> bool {
let stat = node as *mut luaur_ast::records::ast_stat::AstStat;
unsafe {
let loc = (*stat).base.location;
let has_semicolon = (*stat).has_semicolon;
if loc.begin < self.pos
&& (if has_semicolon {
self.pos < loc.end
} else {
self.pos <= loc.end
})
{
self.ancestry.push(stat as *mut AstNode);
return true;
}
}
false
}
fn visit_type(&mut self, node: *mut core::ffi::c_void) -> bool {
let ty = node as *mut luaur_ast::records::ast_type::AstType;
unsafe {
let loc = (*ty).base.location;
if loc.begin < self.pos && self.pos <= loc.end {
self.ancestry.push(ty as *mut AstNode);
return true;
}
}
false
}
fn visit_type_error(&mut self, node: *mut core::ffi::c_void) -> bool {
let ty = node as *mut luaur_ast::records::ast_type_error::AstTypeError;
unsafe {
if (*ty).is_missing && (*ty).base.base.location.containsClosed(self.pos) {
self.ancestry.push(ty as *mut AstNode);
return true;
}
}
false
}
fn visit_type_pack(&mut self, _node: *mut core::ffi::c_void) -> bool {
true
}
fn visit_stat_block(&mut self, node: *mut core::ffi::c_void) -> bool {
let block = node as *mut luaur_ast::records::ast_stat_block::AstStatBlock;
if self.ancestry.is_empty() {
self.ancestry.push(block as *mut AstNode);
return true;
}
unsafe {
let last = *self.ancestry.last().unwrap();
if (*last).is::<luaur_ast::records::ast_expr_index_name::AstExprIndexName>() {
return false;
}
if (*last).is::<luaur_ast::records::ast_type_error::AstTypeError>() {
return false;
}
let loc = (*block).base.base.location;
if loc.begin == self.pos {
if let Some(expr) = (*last).as_expr_const().as_ref() {
if !(*last).is::<luaur_ast::records::ast_expr_function::AstExprFunction>() {
return false;
}
}
if (*last).as_type().as_ref().is_some() {
return false;
}
}
if loc.begin <= self.pos && self.pos <= loc.end {
self.ancestry.push(block as *mut AstNode);
return true;
}
}
false
}
}