perl_lsp_completion/completion/
context.rs1use perl_semantic_analyzer::symbol::{ScopeId, ScopeKind, SymbolKind, SymbolTable};
4
5#[derive(Debug, Clone)]
7pub struct CompletionContext {
8 pub position: usize,
10 pub trigger_character: Option<char>,
12 pub in_string: bool,
14 pub in_regex: bool,
16 pub in_comment: bool,
18 pub in_use_statement: bool,
20 pub current_package: String,
22 pub prefix: String,
24 pub prefix_start: usize,
26 pub cursor_scope_id: ScopeId,
28}
29
30impl CompletionContext {
31 pub(crate) fn detect_current_package(symbol_table: &SymbolTable, position: usize) -> String {
32 let mut scope_start: Option<usize> = None;
34 for scope in symbol_table.scopes.values() {
35 if scope.kind == ScopeKind::Package
36 && scope.location.start <= position
37 && position <= scope.location.end
38 && scope_start.is_none_or(|s| scope.location.start >= s)
39 {
40 scope_start = Some(scope.location.start);
41 }
42 }
43
44 if let Some(start) = scope_start
45 && let Some(sym) = symbol_table
46 .symbols
47 .values()
48 .flat_map(|v| v.iter())
49 .find(|sym| sym.kind == SymbolKind::Package && sym.location.start == start)
50 {
51 return sym.name.clone();
52 }
53
54 let mut current = "main".to_string();
56 let mut packages: Vec<&perl_semantic_analyzer::symbol::Symbol> = symbol_table
57 .symbols
58 .values()
59 .flat_map(|v| v.iter())
60 .filter(|sym| sym.kind == SymbolKind::Package)
61 .collect();
62 packages.sort_by_key(|sym| sym.location.start);
63 for sym in packages {
64 if sym.location.start <= position {
65 let has_scope = symbol_table.scopes.values().any(|sc| {
66 sc.kind == ScopeKind::Package && sc.location.start == sym.location.start
67 });
68 if !has_scope {
69 current = sym.name.clone();
70 }
71 } else {
72 break;
73 }
74 }
75 current
76 }
77
78 pub(crate) fn new(
79 symbol_table: &SymbolTable,
80 position: usize,
81 trigger_character: Option<char>,
82 in_string: bool,
83 in_regex: bool,
84 in_comment: bool,
85 prefix: String,
86 prefix_start: usize,
87 ) -> Self {
88 let current_package = Self::detect_current_package(symbol_table, position);
89 CompletionContext {
90 position,
91 trigger_character,
92 in_string,
93 in_regex,
94 in_comment,
95 in_use_statement: false,
96 current_package,
97 prefix,
98 prefix_start,
99 cursor_scope_id: 0,
100 }
101 }
102}