Skip to main content

swls_lang_trig/
lib.rs

1use bevy_ecs::{component::Component, resource::Resource, world::World};
2use swls_core::{
3    lang::{Lang, LangHelper},
4    lsp_types::SemanticTokenType,
5    prelude::*,
6};
7use swls_lang_rdf_base::register_rdf_lang;
8use swls_lang_turtle::lang::parser::TurtleParseError;
9
10pub mod ecs;
11use crate::ecs::{format_trig_system, setup_parsing};
12
13#[derive(Component, Default)]
14pub struct TriGLang;
15
16#[derive(Debug, Default)]
17pub struct TriGHelper;
18
19impl LangHelper for TriGHelper {
20    fn keyword(&self) -> &[&'static str] {
21        &["@prefix", "@base", "a", "GRAPH"]
22    }
23    fn model_based_rename(&self) -> bool {
24        true
25    }
26    fn blank_node_code_actions(&self) -> bool {
27        true
28    }
29}
30
31pub fn setup_world<C: Client + ClientSync + Resource + Clone>(world: &mut World) {
32    register_rdf_lang::<TriGLang, TriGHelper>(world, &["trig"], &[".trig"]);
33    setup_parsing(world);
34
35    world.schedule_scope(FormatLabel, |_, schedule| {
36        schedule.add_systems(format_trig_system);
37    });
38}
39
40impl Lang for TriGLang {
41    type ElementError = TurtleParseError;
42
43    const LANG: &'static str = "trig";
44    const TRIGGERS: &'static [&'static str] = &[":"];
45    const CODE_ACTION: bool = false;
46    const HOVER: bool = true;
47    const PATTERN: Option<&'static str> = None;
48
49    const LEGEND_TYPES: &'static [SemanticTokenType] = &[
50        semantic_token::BOOLEAN,
51        semantic_token::LANG_TAG,
52        SemanticTokenType::COMMENT,
53        SemanticTokenType::ENUM_MEMBER,
54        SemanticTokenType::KEYWORD,
55        SemanticTokenType::NAMESPACE,
56        SemanticTokenType::NUMBER,
57        SemanticTokenType::PROPERTY,
58        SemanticTokenType::STRING,
59    ];
60
61    fn semantic_token_type(kind: rowan::SyntaxKind) -> Option<SemanticTokenType> {
62        use rdf_parsers::trig::parser::SyntaxKind as SK;
63        match SK::from(kind) {
64            SK::Comment => Some(SemanticTokenType::COMMENT),
65            SK::Iriref => Some(SemanticTokenType::PROPERTY),
66            SK::Integer | SK::Decimal | SK::Double => Some(SemanticTokenType::NUMBER),
67            SK::StringLiteralQuote
68            | SK::StringLiteralSingleQuote
69            | SK::StringLiteralLongQuote
70            | SK::StringLiteralLongSingleQuote => Some(SemanticTokenType::STRING),
71            SK::Langtag => Some(semantic_token::LANG_TAG),
72            SK::TrueLit | SK::FalseLit => Some(semantic_token::BOOLEAN),
73            SK::BaseToken
74            | SK::PrefixToken
75            | SK::SparqlBaseToken
76            | SK::SparqlPrefixToken
77            | SK::GraphToken
78            | SK::Alit => Some(SemanticTokenType::KEYWORD),
79            _ => None,
80        }
81    }
82
83    fn semantic_token_spans(
84        kind: rowan::SyntaxKind,
85        span: std::ops::Range<usize>,
86        text: &str,
87    ) -> Vec<(SemanticTokenType, std::ops::Range<usize>)> {
88        use rdf_parsers::trig::parser::SyntaxKind as SK;
89        match SK::from(kind) {
90            SK::PnameLn => {
91                // "prefix:local" → NAMESPACE for "prefix:" and PROPERTY for "local"
92                if let Some((a, _)) = text.get(span.clone()).and_then(|s| s.split_once(':')) {
93                    let (start, end) = (span.start, span.end);
94                    vec![
95                        (SemanticTokenType::NAMESPACE, start..start + a.len() + 1),
96                        (SemanticTokenType::PROPERTY, start + a.len() + 1..end),
97                    ]
98                } else {
99                    vec![(SemanticTokenType::PROPERTY, span)]
100                }
101            }
102            SK::PnameNs => vec![(SemanticTokenType::NAMESPACE, span)],
103            SK::BlankNodeLabel => {
104                // "_:label" → "_:" as NAMESPACE, label as PROPERTY
105                if span.len() > 2 {
106                    vec![
107                        (SemanticTokenType::NAMESPACE, span.start..span.start + 2),
108                        (SemanticTokenType::PROPERTY, span.start + 2..span.end),
109                    ]
110                } else {
111                    vec![(SemanticTokenType::NAMESPACE, span)]
112                }
113            }
114            _ => Self::semantic_token_type(kind)
115                .map(|t| vec![(t, span)])
116                .unwrap_or_default(),
117        }
118    }
119}