pax_language_server/
lib.rs

1use completion::{
2    get_all_root_component_member_completions, get_block_declaration_completions,
3    get_class_completions, get_common_properties_setting_completions,
4    get_common_property_type_completion, get_id_completions, get_root_component_methods,
5    get_struct_property_setting_completions, get_struct_property_type_completion,
6    get_struct_static_member_completions,
7};
8use completion::{get_event_completions, get_struct_completion};
9use core::panic;
10use dashmap::DashMap;
11use lsp_types::request::Request;
12use pax_lang::{parse_pax_err, Rule};
13use pest::error::LineColLocation;
14use positional::is_inside_handlers_block;
15use positional::is_inside_selector_block;
16use positional::is_inside_settings_block;
17use positional::{
18    extract_positional_nodes, find_nodes_at_position, find_priority_node, find_relevant_ident,
19    find_relevant_tag, has_attribute_error, NodeType, PositionalNode,
20};
21use regex::Captures;
22use regex::Regex;
23use serde::*;
24use std::collections::HashSet;
25use std::path::PathBuf;
26
27use tower_lsp::jsonrpc::Error;
28use tower_lsp::jsonrpc::Result;
29use tower_lsp::lsp_types::*;
30use tower_lsp::{Client, LanguageServer, LspService, Server};
31
32mod index;
33use index::{
34    extract_import_positions, find_rust_file_with_macro, index_rust_file, IdentifierInfo,
35    IdentifierType, Info, InfoRequest,
36};
37
38mod positional;
39
40mod completion;
41
42use std::sync::{Arc, Mutex};
43
44use tokio::time::Duration;
45
46use ropey::Rope;
47
48#[derive(Debug, Deserialize, Serialize, Clone)]
49pub struct SymbolLocationParams {
50    symbol: SymbolData,
51}
52
53#[derive(Debug, Deserialize, Serialize, Clone)]
54struct SymbolData {
55    uri: String,
56    position: Position,
57}
58
59pub enum GetDefinitionRequest {}
60
61#[derive(Debug, Deserialize, Serialize, Clone)]
62pub struct GetDefinitionResult {
63    locations: Vec<LocationLink>,
64}
65
66impl Request for GetDefinitionRequest {
67    type Params = SymbolLocationParams;
68    type Result = GetDefinitionResult;
69    const METHOD: &'static str = "pax/getDefinition";
70}
71
72pub enum GetHoverRequest {}
73pub type GetHoverResult = String;
74
75impl Request for GetHoverRequest {
76    type Params = SymbolLocationParams;
77    type Result = GetHoverResult;
78    const METHOD: &'static str = "pax/getHover";
79}
80
81pub enum EnrichRequest {}
82
83#[allow(non_snake_case)]
84#[derive(Debug, Deserialize, Serialize, Clone)]
85pub struct EnrichParams {
86    symbol: SymbolData,
87    originatingPaxFile: String,
88}
89
90#[allow(non_snake_case)]
91#[derive(Debug, Deserialize, Serialize, Clone)]
92pub struct EnrichResult {
93    getDefinition: usize,
94    getHover: usize,
95}
96
97impl Request for EnrichRequest {
98    type Params = EnrichParams;
99    type Result = EnrichResult;
100    const METHOD: &'static str = "pax/enrich";
101}
102
103#[derive(Debug)]
104pub struct PaxComponent {
105    component_name: String,
106    identifier_map: DashMap<String, IdentifierInfo>,
107}
108
109#[derive(Debug)]
110pub struct SelectorData {
111    ids: HashSet<String>,
112    classes: HashSet<String>,
113}
114
115#[derive(Debug, Clone)]
116struct Backend {
117    client: Arc<Client>,
118    pax_map: Arc<DashMap<String, PaxComponent>>,
119    rs_to_pax_map: Arc<DashMap<String, String>>,
120    workspace_root: Arc<Mutex<Option<Url>>>,
121    pax_ast_cache: Arc<DashMap<String, Vec<PositionalNode>>>,
122    pax_selector_map: Arc<DashMap<String, SelectorData>>,
123    pending_changes: Arc<DashMap<String, DidChangeTextDocumentParams>>,
124    debounce_last_save: Arc<Mutex<std::time::Instant>>,
125    document_content: Arc<DashMap<String, Rope>>,
126}
127
128impl Backend {
129    pub async fn set_root(&self, url: Option<Url>) {
130        let mut root_guard = self.workspace_root.lock().unwrap();
131        *root_guard = url;
132    }
133
134    pub async fn handle_file(&self, pax_file: String, file_to_index: String) {
135        if let Some(component) = self.pax_map.get(&pax_file) {
136            let requests = match index_rust_file(&file_to_index, &component.identifier_map) {
137                Ok(reqs) => reqs,
138                Err(err) => {
139                    eprintln!("Error indexing file {}: {:?}", file_to_index, err);
140                    return;
141                }
142            };
143
144            for request in requests {
145                let backend_clone = self.clone();
146                let pax_file_clone = pax_file.clone();
147
148                tokio::spawn(async move {
149                    backend_clone
150                        .handle_info_request(pax_file_clone, request)
151                        .await;
152                });
153            }
154        }
155    }
156
157    pub async fn handle_info_request(&self, pax_file: String, info_request: InfoRequest) {
158        if let Some(component) = self.pax_map.get(&pax_file) {
159            let symbol_data = SymbolData {
160                uri: info_request.info.path.clone(),
161                position: info_request.info.position,
162            };
163
164            let params = EnrichParams {
165                symbol: symbol_data,
166                originatingPaxFile: pax_file.clone(),
167            };
168
169            let mut new_info = info_request.info.clone();
170
171            match self.client.send_request::<EnrichRequest>(params).await {
172                Ok(response) => {
173                    new_info.definition_id = Some(response.getDefinition);
174                    new_info.hover_id = Some(response.getHover);
175                }
176                Err(e) => {
177                    eprintln!("Error sending EnrichRequest: {:?}", e);
178                }
179            }
180
181            match &info_request.identifier_type {
182                IdentifierType::Component | IdentifierType::PaxType | IdentifierType::Enum => {
183                    if let Some(mut identifier_info) =
184                        component.identifier_map.remove(&info_request.identifier)
185                    {
186                        identifier_info.1.info = new_info;
187                        component
188                            .identifier_map
189                            .insert((&info_request).identifier.clone(), identifier_info.1);
190                    }
191                }
192                IdentifierType::Property => {
193                    if let Some(mut struct_info) = component
194                        .identifier_map
195                        .remove(&(&info_request).owner_identifier.clone().unwrap())
196                    {
197                        if let Some(property) = struct_info
198                            .1
199                            .properties
200                            .iter_mut()
201                            .find(|prop| prop.identifier == info_request.identifier)
202                        {
203                            property.info = new_info;
204                        }
205                        component.identifier_map.insert(
206                            (&info_request).owner_identifier.clone().unwrap().clone(),
207                            struct_info.1,
208                        );
209                    }
210                }
211                IdentifierType::Method => {
212                    if let Some(mut struct_info) = component
213                        .identifier_map
214                        .remove(&(&info_request).owner_identifier.clone().unwrap())
215                    {
216                        if let Some(method) = struct_info
217                            .1
218                            .methods
219                            .iter_mut()
220                            .find(|m| m.identifier == info_request.identifier)
221                        {
222                            method.info = new_info;
223                        }
224                        component.identifier_map.insert(
225                            (&info_request).owner_identifier.clone().unwrap().clone(),
226                            struct_info.1,
227                        );
228                    }
229                }
230                IdentifierType::EnumVariant => {
231                    if let Some(mut enum_info) = component
232                        .identifier_map
233                        .remove(&(&info_request).owner_identifier.clone().unwrap())
234                    {
235                        if let Some(variant) = enum_info
236                            .1
237                            .variants
238                            .iter_mut()
239                            .find(|prop| prop.identifier == info_request.identifier)
240                        {
241                            variant.info = new_info;
242                        }
243                        component.identifier_map.insert(
244                            (&info_request).owner_identifier.clone().unwrap().clone(),
245                            enum_info.1,
246                        );
247                    }
248                }
249            }
250        }
251    }
252
253    pub async fn index_file(
254        &self,
255        pax_file: &str,
256        rust_file_path: PathBuf,
257        component_name: String,
258    ) {
259        let identifier_map: DashMap<String, IdentifierInfo> = DashMap::new();
260
261        let rust_file_path_str = rust_file_path.to_string_lossy().to_string();
262        let info_requests = match index_rust_file(&rust_file_path_str, &identifier_map) {
263            Ok(reqs) => reqs,
264            Err(err) => {
265                eprintln!("Error indexing file {}: {:?}", rust_file_path_str, err);
266                return;
267            }
268        };
269
270        for info_request in info_requests.clone() {
271            let backend_clone = self.clone();
272            let pax_file_clone = pax_file.to_string();
273            tokio::spawn(async move {
274                backend_clone
275                    .handle_info_request(pax_file_clone, info_request)
276                    .await;
277            });
278        }
279
280        self.pax_map.insert(
281            pax_file.to_string(),
282            PaxComponent {
283                component_name,
284                identifier_map,
285            },
286        );
287
288        self.rs_to_pax_map
289            .insert(rust_file_path_str, pax_file.to_string());
290
291        let positions = extract_import_positions(&rust_file_path);
292        for position in positions {
293            let symbol_data = SymbolData {
294                uri: rust_file_path.to_string_lossy().to_string(),
295                position,
296            };
297
298            let params = SymbolLocationParams {
299                symbol: symbol_data,
300            };
301
302            match self
303                .client
304                .send_request::<GetDefinitionRequest>(params)
305                .await
306            {
307                Ok(response) => {
308                    for location_link in response.locations {
309                        let target_uri = location_link.target_uri;
310                        let _path = target_uri.clone().path().to_string();
311                        let target_file = target_uri
312                            .to_file_path()
313                            .expect("Failed to convert URI to path")
314                            .to_string_lossy()
315                            .to_string();
316
317                        let path = pax_file.to_string();
318                        let backend_clone = self.clone();
319                        tokio::spawn(async move {
320                            backend_clone.handle_file(path, target_file).await;
321                        });
322                    }
323                }
324                Err(e) => {
325                    self.client
326                        .log_message(MessageType::INFO, format!("Error couldnt look up imports"))
327                        .await;
328                    eprintln!("Error sending request: {:?}", e);
329                }
330            }
331        }
332    }
333
334    fn parse_and_cache_pax_file(&self, pax: &str, uri: Url) -> Vec<Diagnostic> {
335        let parse_result = parse_pax_err(Rule::pax_component_definition, pax);
336
337        let path_str = uri.path();
338
339        match parse_result {
340            Ok(pax_component_definition) => {
341                let mut nodes = Vec::new();
342                let mut ids = HashSet::new();
343                let mut classes = HashSet::new();
344
345                extract_positional_nodes(
346                    pax_component_definition.clone(),
347                    &mut nodes,
348                    &mut ids,
349                    &mut classes,
350                );
351                self.pax_ast_cache
352                    .insert(path_str.to_string(), nodes.clone());
353
354                self.pax_selector_map
355                    .insert(path_str.to_string(), SelectorData { ids, classes });
356                Vec::new()
357            }
358            Err(e) => {
359                let range = match e.line_col {
360                    LineColLocation::Pos((l, c)) => Range {
361                        start: Position {
362                            line: (l - 1) as u32,
363                            character: (c - 1) as u32,
364                        },
365                        end: Position {
366                            line: (l - 1) as u32,
367                            character: (c - 1) as u32,
368                        },
369                    },
370                    LineColLocation::Span((l_s, c_s), (l_e, c_e)) => Range {
371                        start: Position {
372                            line: (l_s - 1) as u32,
373                            character: (c_s - 1) as u32,
374                        },
375                        end: Position {
376                            line: (l_e - 1) as u32,
377                            character: (c_e - 1) as u32,
378                        },
379                    },
380                };
381                vec![Diagnostic {
382                    range: range,
383                    message: format!("{e}"),
384                    severity: Some(DiagnosticSeverity::ERROR),
385                    code: None,
386                    source: None,
387                    related_information: None,
388                    code_description: None,
389                    tags: None,
390                    data: None,
391                }]
392            }
393        }
394    }
395    async fn hover_id(&self, params: HoverParams) -> Result<Option<u32>> {
396        let uri_obj = &params.text_document_position_params.text_document.uri;
397        let uri_path = uri_obj.path();
398        let pos = &params.text_document_position_params.position;
399
400        if uri_path.ends_with(".pax") && !self.pax_map.contains_key(uri_path) {
401            self.process_pax_file(uri_obj).await;
402
403            let file_path = uri_obj
404                .to_file_path()
405                .map_err(|_| Error::invalid_params(format!("Invalid URI: {}", uri_obj)))?;
406            let file_content = std::fs::read_to_string(&file_path).map_err(|err| {
407                Error::invalid_params(format!("Failed to read {}: {}", file_path.display(), err))
408            })?;
409
410            let _ = self.parse_and_cache_pax_file(&file_content, uri_obj.clone());
411        }
412
413        if let Some(info) = self.get_info(uri_path, pos) {
414            if let Some(id) = info.hover_id {
415                return Ok(Some(id as u32));
416            }
417        }
418
419        Ok(None)
420    }
421
422    fn get_info(&self, uri: &str, pos: &Position) -> Option<Info> {
423        if let Some(component) = self.pax_map.get(uri) {
424            if let Some(cached_nodes) = self.pax_ast_cache.get(uri) {
425                let relevant_nodes = find_nodes_at_position(pos.clone(), &cached_nodes);
426                let priority_node = find_priority_node(&relevant_nodes);
427                let tag_node = find_relevant_tag(&relevant_nodes);
428                let relevant_ident = find_relevant_ident(&relevant_nodes);
429                if let Some(node) = priority_node {
430                    let struct_name = if let Some(tag) = tag_node {
431                        if let NodeType::Tag(tag_data) = &tag.node_type {
432                            Some(tag_data.pascal_identifier.clone())
433                        } else {
434                            panic!("Expected NodeType::Tag, found {:?}", tag.node_type);
435                        }
436                    } else {
437                        None
438                    };
439
440                    if let Some(ident) = relevant_ident {
441                        if let NodeType::Identifier(ident_data) = &ident.node_type {
442                            let ident_name = ident_data.identifier.clone();
443                            match &node.node_type {
444                                NodeType::Identifier(data) => {
445                                    let ident = data.identifier.clone();
446                                    if let Some(ident_info) =
447                                        component.identifier_map.get(ident.as_str())
448                                    {
449                                        return Some(ident_info.info.clone());
450                                    }
451                                }
452                                NodeType::LiteralFunction(data) => {
453                                    if let Some(ident_info) = component
454                                        .identifier_map
455                                        .get(component.component_name.clone().as_str())
456                                    {
457                                        if let Some(method) = ident_info
458                                            .methods
459                                            .iter()
460                                            .find(|m| m.identifier == data.function_name)
461                                        {
462                                            return Some(method.info.clone());
463                                        }
464                                    }
465                                }
466                                NodeType::LiteralEnumValue(data) => {
467                                    let mut struct_id = data.enum_name.clone();
468                                    if &struct_id == "Self" {
469                                        struct_id = component.component_name.clone();
470                                    }
471                                    if let Some(ident_info) =
472                                        component.identifier_map.get(struct_id.as_str())
473                                    {
474                                        if ident_name == data.enum_name {
475                                            return Some(ident_info.info.clone());
476                                        }
477                                        if let Some(variant) = ident_info
478                                            .variants
479                                            .iter()
480                                            .find(|p| p.identifier == data.property_name)
481                                        {
482                                            return Some(variant.info.clone());
483                                        }
484                                    }
485                                }
486                                NodeType::XoFunctionCall(data) => {
487                                    let mut struct_id = data.struct_name.clone();
488                                    if struct_id == "Self" {
489                                        struct_id = component.component_name.clone();
490                                    }
491                                    if let Some(ident_info) =
492                                        component.identifier_map.get(struct_id.as_str())
493                                    {
494                                        if ident_name == data.struct_name {
495                                            return Some(ident_info.info.clone());
496                                        }
497                                        if let Some(method) = ident_info
498                                            .methods
499                                            .iter()
500                                            .find(|m| m.identifier == data.function_name)
501                                        {
502                                            return Some(method.info.clone());
503                                        }
504                                    }
505                                }
506                                NodeType::AttributeKeyValuePair(data) => {
507                                    let property_names = vec![
508                                        "x",
509                                        "y",
510                                        "scale_x",
511                                        "scale_y",
512                                        "skew_x",
513                                        "skew_y",
514                                        "rotate",
515                                        "anchor_x",
516                                        "anchor_y",
517                                        "transform",
518                                        "width",
519                                        "height",
520                                    ];
521
522                                    if let Some(struct_ident) = struct_name {
523                                        let mut struct_id = struct_ident.clone();
524                                        if property_names.contains(&data.identifier.as_str()) {
525                                            struct_id = "CommonProperties".to_string();
526                                        }
527                                        if let Some(ident_info) =
528                                            component.identifier_map.get(struct_id.as_str())
529                                        {
530                                            if let Some(property) = ident_info
531                                                .properties
532                                                .iter()
533                                                .find(|p| p.identifier == data.identifier)
534                                            {
535                                                return Some(property.info.clone());
536                                            }
537                                        }
538                                    }
539                                }
540                                _ => {}
541                            };
542                        }
543                    }
544                }
545            }
546        }
547        return None;
548    }
549
550    async fn definition_id(&self, params: GotoDefinitionParams) -> Result<Option<u32>> {
551        let uri = params
552            .text_document_position_params
553            .text_document
554            .uri
555            .path();
556        let pos = &params.text_document_position_params.position;
557
558        if let Some(info) = self.get_info(uri, pos) {
559            if let Some(id) = info.definition_id {
560                return Ok(Some(id as u32));
561            }
562        }
563
564        Ok(None)
565    }
566
567    async fn process_pax_file(&self, uri: &Url) {
568        let file_path = uri.path();
569
570        if self.pax_map.contains_key(file_path) {
571            return;
572        }
573
574        let path = uri.clone().to_file_path().expect("Failed to get file path");
575        let directory = path.parent().expect("Failed to get parent directory");
576
577        if let Some((rust_file_path, component_name)) =
578            find_rust_file_with_macro(directory, &file_path)
579        {
580            let backend_clone = self.clone();
581            let path_str = file_path.to_string();
582            tokio::spawn(async move {
583                backend_clone
584                    .index_file(&path_str, rust_file_path, component_name)
585                    .await;
586            });
587        } else {
588            eprintln!("No matching Rust file found for {}", file_path);
589        }
590    }
591
592    async fn process_changes(&self, text: &str, uri: Url) {
593        let diagnostics = self.parse_and_cache_pax_file(text, uri.clone());
594
595        self.client
596            .publish_diagnostics(uri, diagnostics, None)
597            .await;
598    }
599
600    fn get_valid_setter(&self, uri: &str, pos: &Position) -> Option<String> {
601        if let Some(rope) = self.document_content.get(uri) {
602            let char_pos = rope.line_to_char(pos.line as usize) + pos.character as usize;
603
604            let start = if char_pos >= 50 { char_pos - 50 } else { 0 };
605            let text_before_pos = rope.slice(start..char_pos).to_string();
606
607            let pattern = r"(@?[A-Za-z_\d]+(=|::|:|\.| )*)";
608
609            let re = Regex::new(pattern).unwrap();
610
611            let mut largest_match: Option<String> = None;
612
613            let captures: Vec<Captures> = re.captures_iter(&text_before_pos).collect();
614
615            for captures in captures.into_iter().rev() {
616                if let Some(matched) = captures.get(0) {
617                    let matched_str = matched.as_str().to_string();
618                    if matched.end() == text_before_pos.len()
619                        && (largest_match.is_none()
620                            || matched_str.len() > largest_match.as_ref().unwrap().len())
621                    {
622                        largest_match = Some(matched_str.trim_end().to_string());
623                    }
624                }
625            }
626
627            return largest_match;
628        }
629
630        None
631    }
632}
633
634#[tower_lsp::async_trait]
635impl LanguageServer for Backend {
636    async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
637        self.set_root(params.root_uri).await;
638
639        let pending_changes_clone = self.pending_changes.clone();
640        let self_clone = self.clone();
641
642        tokio::spawn(async move {
643            loop {
644                tokio::time::sleep(Duration::from_millis(500)).await;
645
646                let mut processed_keys = Vec::new();
647
648                for entry in pending_changes_clone.iter() {
649                    let uri_path = entry.key().clone();
650                    let change_params = entry.value().clone();
651
652                    let uri = change_params.text_document.uri.clone();
653
654                    if uri_path.ends_with(".pax") {
655                        self_clone.process_pax_file(&uri).await;
656                        if !change_params.content_changes.is_empty() {
657                            self_clone
658                                .process_changes(
659                                    &change_params.content_changes[0].text,
660                                    change_params.text_document.uri.clone(),
661                                )
662                                .await;
663                        }
664                    }
665                    processed_keys.push(uri_path);
666                }
667
668                // Remove processed entries
669                for key in processed_keys {
670                    pending_changes_clone.remove(&key);
671                }
672            }
673        });
674
675        Ok(InitializeResult {
676            server_info: None,
677            capabilities: ServerCapabilities::default(),
678            offset_encoding: None,
679        })
680    }
681
682    async fn initialized(&self, _: tower_lsp::lsp_types::InitializedParams) {
683        self.client
684            .log_message(MessageType::INFO, "initialized!")
685            .await;
686    }
687
688    async fn shutdown(&self) -> Result<()> {
689        Ok(())
690    }
691
692    async fn did_open(&self, did_open_params: DidOpenTextDocumentParams) {
693        let uri = did_open_params.text_document.uri.clone();
694        let language_id = &did_open_params.text_document.language_id;
695        if language_id == "pax" {
696            self.process_pax_file(&uri).await;
697            let diagnostics = self
698                .parse_and_cache_pax_file(did_open_params.text_document.text.as_str(), uri.clone());
699            self.client
700                .publish_diagnostics(uri, diagnostics, None)
701                .await;
702        }
703    }
704
705    async fn did_change(&self, did_change_params: DidChangeTextDocumentParams) {
706        let uri = did_change_params.text_document.uri.clone();
707        let uri_path = uri.path().to_string();
708        let new_content = did_change_params.content_changes[0].text.clone();
709        if uri_path.ends_with(".pax") {
710            self.process_pax_file(&uri).await;
711            self.document_content
712                .insert(uri_path.clone(), Rope::from_str(&new_content));
713        }
714        self.pending_changes.insert(uri_path, did_change_params);
715    }
716
717    async fn did_save(&self, did_save_params: DidSaveTextDocumentParams) {
718        let uri_path = did_save_params.text_document.uri.path();
719
720        if uri_path.ends_with(".rs") {
721            if self.debounce_last_save.lock().unwrap().elapsed() < Duration::from_secs(10) {
722                return;
723            }
724            *self.debounce_last_save.lock().unwrap() = std::time::Instant::now();
725
726            if let Some(pax_file_path) = self.rs_to_pax_map.get(uri_path) {
727                self.pax_map.remove(pax_file_path.value());
728
729                let pax_uri = Url::from_file_path(pax_file_path.value()).unwrap();
730                self.process_pax_file(&pax_uri).await;
731            }
732        } else if uri_path.ends_with(".pax") {
733            self.pax_map.remove(uri_path);
734            self.process_pax_file(&did_save_params.text_document.uri)
735                .await;
736        }
737    }
738
739    async fn completion(
740        &self,
741        completion_params: CompletionParams,
742    ) -> Result<Option<CompletionResponse>> {
743        let uri = &completion_params.text_document_position.text_document.uri;
744        let pos = &completion_params.text_document_position.position;
745        let prior_identifier = self.get_valid_setter(uri.clone().path(), pos);
746        let selector_info = self.pax_selector_map.get(&uri.path().to_string());
747
748        let mut completions = Vec::new();
749        if let Some(cached_nodes) = self.pax_ast_cache.get(&uri.path().to_string()) {
750            let relevant_nodes = find_nodes_at_position(pos.clone(), &cached_nodes);
751            let tag_node = find_relevant_tag(&relevant_nodes);
752            let has_attribute_error = has_attribute_error(&relevant_nodes);
753            let is_inside_settings_block = is_inside_settings_block(&relevant_nodes);
754            let is_inside_handlers_block = is_inside_handlers_block(&relevant_nodes);
755            let is_inside_selector_block = is_inside_selector_block(&relevant_nodes);
756            if let Some(component) = self.pax_map.get(&uri.path().to_string()) {
757                if let Some(trigger_char) = &completion_params
758                    .context
759                    .and_then(|ctx| ctx.trigger_character)
760                {
761                    if trigger_char == "<" {
762                        for entry in component.identifier_map.iter() {
763                            if entry.ty == IdentifierType::Component
764                                && entry.identifier != component.component_name
765                            {
766                                let mut completion = CompletionItem::new_simple(
767                                    entry.identifier.clone(),
768                                    String::from(""),
769                                );
770                                completion.kind = Some(CompletionItemKind::CLASS);
771                                completion.insert_text =
772                                    Some(format!("{} $0 />", entry.identifier.clone()));
773                                completion.insert_text_format =
774                                    Some(lsp_types::InsertTextFormat::SNIPPET);
775                                if let Some(prepared_completion) =
776                                    get_struct_completion(&entry.identifier)
777                                {
778                                    completion = prepared_completion;
779                                }
780                                completions.push(completion);
781                            }
782                        }
783                        return Ok(Some(CompletionResponse::Array(completions)));
784                    } else if trigger_char == "@" {
785                        if let Some(_tag) = tag_node {
786                            completions.extend(get_event_completions("="));
787                            return Ok(Some(CompletionResponse::Array(completions)));
788                        } else if !is_inside_settings_block && !is_inside_handlers_block {
789                            completions.extend(get_block_declaration_completions());
790                            return Ok(Some(CompletionResponse::Array(completions)));
791                        }
792                    } else if trigger_char == "=" {
793                        if let Some(setter) = prior_identifier {
794                            if setter.contains("@") {
795                                completions.extend(get_root_component_methods(&component));
796                                return Ok(Some(CompletionResponse::Array(completions)));
797                            } else {
798                                let requested_property = setter.clone().replace("=", "");
799                                if let Some(tag) = tag_node {
800                                    if let NodeType::Tag(tag_data) = &tag.node_type {
801                                        if requested_property == "class" {
802                                            completions.extend(get_class_completions(
803                                                &selector_info,
804                                                false,
805                                                false,
806                                            ));
807                                            return Ok(Some(CompletionResponse::Array(
808                                                completions,
809                                            )));
810                                        } else if requested_property == "id" {
811                                            completions.extend(get_id_completions(
812                                                &selector_info,
813                                                false,
814                                                false,
815                                            ));
816                                            return Ok(Some(CompletionResponse::Array(
817                                                completions,
818                                            )));
819                                        } else {
820                                            completions.extend(
821                                                get_struct_property_type_completion(
822                                                    &component,
823                                                    tag_data.pascal_identifier.clone(),
824                                                    requested_property.clone(),
825                                                ),
826                                            );
827                                        }
828                                    }
829                                }
830                                completions.extend(get_common_property_type_completion(
831                                    &component,
832                                    requested_property.clone(),
833                                ));
834                                return Ok(Some(CompletionResponse::Array(completions)));
835                            }
836                        }
837                    } else if trigger_char == ":" {
838                        if let Some(word) = prior_identifier {
839                            if word.contains("::") {
840                                let requested_struct = word.clone().replace("::", "");
841                                completions.extend(get_struct_static_member_completions(
842                                    &component,
843                                    requested_struct,
844                                ));
845                                return Ok(Some(CompletionResponse::Array(completions)));
846                            } else {
847                                if is_inside_handlers_block {
848                                    completions.extend(get_root_component_methods(&component));
849                                    return Ok(Some(CompletionResponse::Array(completions)));
850                                } else {
851                                    let requested_property = word.clone().replace(":", "");
852                                    completions.extend(get_common_property_type_completion(
853                                        &component,
854                                        requested_property.clone(),
855                                    ));
856                                    return Ok(Some(CompletionResponse::Array(completions)));
857                                }
858                            }
859                        }
860                    } else if trigger_char == "." {
861                        if let Some(word) = prior_identifier {
862                            if word.contains("self") {
863                                completions
864                                    .extend(get_all_root_component_member_completions(&component));
865                                return Ok(Some(CompletionResponse::Array(completions)));
866                            }
867                        }
868                        if is_inside_settings_block {
869                            completions.extend(get_class_completions(&selector_info, true, false));
870                            return Ok(Some(CompletionResponse::Array(completions)));
871                        }
872                    } else if trigger_char == "#" {
873                        if is_inside_settings_block {
874                            completions.extend(get_id_completions(&selector_info, true, false));
875                            return Ok(Some(CompletionResponse::Array(completions)));
876                        }
877                    }
878                } else {
879                    if let Some(tag) = tag_node {
880                        if let NodeType::Tag(tag_data) = &tag.node_type {
881                            if let Some(word) = prior_identifier.clone() {
882                                if word.contains("@") {
883                                    completions.extend(get_root_component_methods(&component));
884                                    return Ok(Some(CompletionResponse::Array(completions)));
885                                } else if word.contains("=") {
886                                    let requested_property = word.clone().replace("=", "");
887                                    completions.extend(get_struct_property_type_completion(
888                                        &component,
889                                        tag_data.pascal_identifier.clone(),
890                                        requested_property.clone(),
891                                    ));
892                                    completions.extend(get_common_property_type_completion(
893                                        &component,
894                                        requested_property.clone(),
895                                    ));
896                                    return Ok(Some(CompletionResponse::Array(completions)));
897                                }
898                            }
899                            if !has_attribute_error {
900                                completions.extend(get_struct_property_setting_completions(
901                                    &component,
902                                    tag_data.clone().pascal_identifier,
903                                ));
904                                completions.extend(get_common_properties_setting_completions(
905                                    &component, "=",
906                                ));
907                                return Ok(Some(CompletionResponse::Array(completions)));
908                            }
909                        }
910                    }
911                    if is_inside_settings_block {
912                        if is_inside_selector_block {
913                            completions
914                                .extend(get_common_properties_setting_completions(&component, ":"));
915                            return Ok(Some(CompletionResponse::Array(completions)));
916                        }
917                        if let Some(word) = prior_identifier.clone() {
918                            let requested_property = word.clone().replace(":", "").replace("=", "");
919                            completions.extend(get_common_property_type_completion(
920                                &component,
921                                requested_property.clone(),
922                            ));
923                            return Ok(Some(CompletionResponse::Array(completions)));
924                        } else {
925                            completions.extend(get_class_completions(&selector_info, true, true));
926                            completions.extend(get_id_completions(&selector_info, true, true));
927                            return Ok(Some(CompletionResponse::Array(completions)));
928                        }
929                    }
930                    if is_inside_handlers_block {
931                        if let Some(_) = prior_identifier.clone() {
932                            completions.extend(get_root_component_methods(&component));
933                            return Ok(Some(CompletionResponse::Array(completions)));
934                        } else {
935                            completions.extend(get_event_completions(":"));
936                            return Ok(Some(CompletionResponse::Array(completions)));
937                        }
938                    }
939                }
940            }
941        }
942        return Ok(Some(CompletionResponse::Array(completions)));
943    }
944}
945
946pub async fn start_server() {
947    let stdin = tokio::io::stdin();
948    let stdout = tokio::io::stdout();
949
950    let (service, socket) = LspService::build(|client| Backend {
951        client: Arc::new(client),
952        pax_map: Arc::new(DashMap::new()),
953        rs_to_pax_map: Arc::new(DashMap::new()),
954        workspace_root: Arc::new(Mutex::new(None)),
955        pax_ast_cache: Arc::new(DashMap::new()),
956        pax_selector_map: Arc::new(DashMap::new()),
957        pending_changes: Arc::new(DashMap::new()),
958        debounce_last_save: Arc::new(Mutex::new(std::time::Instant::now())),
959        document_content: Arc::new(DashMap::new()),
960    })
961    .custom_method("pax/getHoverId", Backend::hover_id)
962    .custom_method("pax/getDefinitionId", Backend::definition_id)
963    .finish();
964
965    Server::new(stdin, stdout, socket).serve(service).await;
966}