luaur_analysis/records/
autocomplete_node_finder.rs1use alloc::vec::Vec;
2use luaur_ast::records::ast_node::AstNode;
3use luaur_ast::records::ast_visitor::AstVisitor;
4use luaur_ast::records::position::Position;
5
6#[derive(Debug, Clone)]
7pub struct AutocompleteNodeFinder {
8 pub(crate) pos: Position,
9 pub(crate) ancestry: Vec<*mut AstNode>,
10}
11
12impl AutocompleteNodeFinder {
13 pub fn new(pos: Position) -> Self {
14 Self {
15 pos,
16 ancestry: Vec::new(),
17 }
18 }
19}
20
21impl AstVisitor for AutocompleteNodeFinder {
22 fn visit_node(&mut self, _node: *mut core::ffi::c_void) -> bool {
23 true
24 }
25
26 fn visit_expr(&mut self, node: *mut core::ffi::c_void) -> bool {
27 let expr = node as *mut luaur_ast::records::ast_expr::AstExpr;
28 unsafe {
29 let loc = (*expr).base.location;
30 if loc.begin <= self.pos && self.pos <= loc.end && loc.begin != loc.end {
31 self.ancestry.push(expr as *mut AstNode);
32 return true;
33 }
34 }
35 false
36 }
37
38 fn visit_stat(&mut self, node: *mut core::ffi::c_void) -> bool {
39 let stat = node as *mut luaur_ast::records::ast_stat::AstStat;
40 unsafe {
41 let loc = (*stat).base.location;
42 let has_semicolon = (*stat).has_semicolon;
43 if loc.begin < self.pos
44 && (if has_semicolon {
45 self.pos < loc.end
46 } else {
47 self.pos <= loc.end
48 })
49 {
50 self.ancestry.push(stat as *mut AstNode);
51 return true;
52 }
53 }
54 false
55 }
56
57 fn visit_type(&mut self, node: *mut core::ffi::c_void) -> bool {
58 let ty = node as *mut luaur_ast::records::ast_type::AstType;
59 unsafe {
60 let loc = (*ty).base.location;
61 if loc.begin < self.pos && self.pos <= loc.end {
62 self.ancestry.push(ty as *mut AstNode);
63 return true;
64 }
65 }
66 false
67 }
68
69 fn visit_type_error(&mut self, node: *mut core::ffi::c_void) -> bool {
70 let ty = node as *mut luaur_ast::records::ast_type_error::AstTypeError;
71 unsafe {
72 if (*ty).is_missing && (*ty).base.base.location.containsClosed(self.pos) {
73 self.ancestry.push(ty as *mut AstNode);
74 return true;
75 }
76 }
77 false
78 }
79
80 fn visit_type_pack(&mut self, _node: *mut core::ffi::c_void) -> bool {
81 true
82 }
83
84 fn visit_stat_block(&mut self, node: *mut core::ffi::c_void) -> bool {
85 let block = node as *mut luaur_ast::records::ast_stat_block::AstStatBlock;
86 if self.ancestry.is_empty() {
87 self.ancestry.push(block as *mut AstNode);
88 return true;
89 }
90
91 unsafe {
92 let last = *self.ancestry.last().unwrap();
93 if (*last).is::<luaur_ast::records::ast_expr_index_name::AstExprIndexName>() {
94 return false;
95 }
96 if (*last).is::<luaur_ast::records::ast_type_error::AstTypeError>() {
97 return false;
98 }
99
100 let loc = (*block).base.base.location;
101 if loc.begin == self.pos {
102 if let Some(expr) = (*last).as_expr_const().as_ref() {
103 if !(*last).is::<luaur_ast::records::ast_expr_function::AstExprFunction>() {
104 return false;
105 }
106 }
107 if (*last).as_type().as_ref().is_some() {
108 return false;
109 }
110 }
111
112 if loc.begin <= self.pos && self.pos <= loc.end {
113 self.ancestry.push(block as *mut AstNode);
114 return true;
115 }
116 }
117 false
118 }
119}