Skip to main content

glua_parser/syntax/traits/
description_trait.rs

1use crate::{LuaAstNode, LuaDocDescription, LuaKind, LuaSyntaxKind, LuaSyntaxNode, LuaTokenKind};
2
3#[allow(unused)]
4pub trait LuaDocDescriptionOwner: LuaAstNode {
5    fn get_description(&self) -> Option<LuaDocDescription> {
6        if let Some(inline_description) = find_inline_description(self.syntax()) {
7            return LuaDocDescription::cast(inline_description);
8        }
9
10        None
11    }
12
13    fn get_descriptions(&self) -> Vec<LuaDocDescription> {
14        let mut descriptions = vec![];
15        if let Some(attached_description) = find_attached_description(self.syntax()) {
16            descriptions.push(LuaDocDescription::cast(attached_description).unwrap());
17        }
18
19        if let Some(inline_description) = find_inline_description(self.syntax()) {
20            descriptions.push(LuaDocDescription::cast(inline_description).unwrap());
21        }
22
23        descriptions
24    }
25}
26
27fn find_attached_description(node: &LuaSyntaxNode) -> Option<LuaSyntaxNode> {
28    let mut prev_sibling = node.prev_sibling_or_token();
29    let mut meet_end_of_line = false;
30    for _ in 0..=5 {
31        prev_sibling.as_ref()?;
32
33        if let Some(sibling) = &prev_sibling {
34            match sibling.kind() {
35                LuaKind::Token(
36                    LuaTokenKind::TkWhitespace
37                    | LuaTokenKind::TkDocContinue
38                    | LuaTokenKind::TkDocStart,
39                ) => {}
40                LuaKind::Token(LuaTokenKind::TkEndOfLine) => {
41                    if meet_end_of_line {
42                        return None;
43                    }
44                    meet_end_of_line = true;
45                }
46                LuaKind::Syntax(LuaSyntaxKind::DocDescription) => {
47                    let description_node = sibling.clone().into_node()?;
48                    if !check_is_inline_description(&description_node).unwrap_or(false) {
49                        return Some(description_node);
50                    }
51                    return None;
52                }
53                _ => {
54                    return None;
55                }
56            }
57        }
58        prev_sibling = prev_sibling.unwrap().prev_sibling_or_token();
59    }
60
61    None
62}
63
64fn check_is_inline_description(node: &LuaSyntaxNode) -> Option<bool> {
65    let mut prev_sibling = node.prev_sibling_or_token();
66    for _ in 0..=3 {
67        prev_sibling.as_ref()?;
68
69        if let Some(sibling) = &prev_sibling {
70            match sibling.kind() {
71                LuaKind::Token(LuaTokenKind::TkWhitespace | LuaTokenKind::TkDocContinue) => {}
72                LuaKind::Token(LuaTokenKind::TkEndOfLine | LuaTokenKind::TkNormalStart) => {
73                    return Some(false);
74                }
75                _ => {
76                    return Some(true);
77                }
78            }
79        }
80        prev_sibling = prev_sibling.unwrap().prev_sibling_or_token();
81    }
82
83    Some(false)
84}
85
86fn find_inline_description(node: &LuaSyntaxNode) -> Option<LuaSyntaxNode> {
87    let mut next_sibling = node.next_sibling_or_token();
88    for _ in 0..=3 {
89        next_sibling.as_ref()?;
90
91        if let Some(sibling) = &next_sibling {
92            match sibling.kind() {
93                LuaKind::Token(LuaTokenKind::TkWhitespace) => {}
94                LuaKind::Syntax(LuaSyntaxKind::DocDescription) => {
95                    return sibling.clone().into_node();
96                }
97                _ => {
98                    return None;
99                }
100            }
101        }
102        next_sibling = next_sibling.unwrap().next_sibling_or_token();
103    }
104
105    None
106}