lang_turtle/lang/
context.rs1use std::{
2 collections::{HashMap, HashSet},
3 ops::Index,
4};
5
6use bevy_ecs::component::Component;
7use lsp_core::{prelude::Token, util::Spanned};
8use similar::ChangeTag;
9
10pub struct TokenIdx<'a> {
11 pub tokens: &'a Vec<Spanned<Token>>,
12}
13impl<'a> Index<usize> for TokenIdx<'a> {
14 type Output = Token;
15
16 fn index(&self, index: usize) -> &Self::Output {
17 &self.tokens[index].value()
18 }
19}
20#[derive(Clone, Copy)]
21pub struct Ctx<'a> {
22 context: &'a Context,
23}
24
25impl<'a> Ctx<'a> {
26 pub fn find_was(&self, idx: usize) -> Option<ContextKind> {
27 if let Some(idx) = self.context.current_to_prev.get(&idx) {
28 if self.context.subjects.contains(idx) {
29 return Some(ContextKind::Subject);
30 }
31
32 if self.context.predicates.contains(idx) {
33 return Some(ContextKind::Predicate);
34 }
35
36 if self.context.objects.contains(idx) {
37 return Some(ContextKind::Object);
38 }
39 }
40 None
41 }
42 pub fn was(&self, idx: usize, kind: ContextKind) -> bool {
43 match kind {
44 ContextKind::Subject => self.was_subject(idx),
45 ContextKind::Predicate => self.was_predicate(idx),
46 ContextKind::Object => self.was_object(idx),
47 }
48 }
49
50 pub fn was_subject(&self, idx: usize) -> bool {
51 self.context
52 .current_to_prev
53 .get(&idx)
54 .map(|old| self.context.subjects.contains(old))
55 .unwrap_or_default()
56 }
57
58 pub fn was_object(&self, idx: usize) -> bool {
59 self.context
60 .current_to_prev
61 .get(&idx)
62 .map(|old| self.context.objects.contains(old))
63 .unwrap_or_default()
64 }
65
66 pub fn was_predicate(&self, idx: usize) -> bool {
67 self.context
68 .current_to_prev
69 .get(&idx)
70 .map(|old| self.context.predicates.contains(old))
71 .unwrap_or_default()
72 }
73}
74
75#[derive(Copy, Debug, Clone)]
76pub enum ContextKind {
77 Subject,
78 Predicate,
79 Object,
80}
81impl std::fmt::Display for ContextKind {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 match self {
84 ContextKind::Subject => write!(f, "subject"),
85 ContextKind::Predicate => write!(f, "predicate"),
86 ContextKind::Object => write!(f, "object"),
87 }
88 }
89}
90
91#[derive(Debug, Default, Component)]
92pub struct Context {
93 subjects: HashSet<usize>,
94 predicates: HashSet<usize>,
95 objects: HashSet<usize>,
96
97 current_to_prev: HashMap<usize, usize>,
99}
100
101impl Context {
102 pub fn new() -> Self {
103 Self {
104 ..Default::default()
105 }
106 }
107
108 pub fn add_subject(&mut self, idx: usize) {
109 self.subjects.insert(idx);
110 }
111
112 pub fn add_predicate(&mut self, idx: usize) {
113 self.predicates.insert(idx);
114 }
115
116 pub fn add_object(&mut self, idx: usize) {
117 self.objects.insert(idx);
118 }
119
120 pub fn add(&mut self, idx: usize, kind: ContextKind) {
121 match kind {
122 ContextKind::Subject => self.add_subject(idx),
123 ContextKind::Predicate => self.add_predicate(idx),
124 ContextKind::Object => self.add_object(idx),
125 }
126 }
127
128 pub fn clear(&mut self) {
129 self.subjects.clear();
130 self.predicates.clear();
131 self.objects.clear();
132 self.current_to_prev.clear();
133 }
134
135 pub fn setup_current_to_prev<Arr>(
136 &mut self,
137 current: Arr,
138 current_length: usize,
139 prev: Arr,
140 prev_length: usize,
141 ) where
142 Arr: Index<usize>,
143 Arr::Output: PartialEq<Arr::Output> + Ord + std::hash::Hash + Eq + Sized + Clone,
144 {
145 let diffs = similar::capture_diff(
146 similar::Algorithm::Myers,
147 &prev,
148 0..prev_length,
149 ¤t,
150 0..current_length,
151 );
152 for changes in diffs.iter() {
153 for change in changes.iter_changes(&prev, ¤t) {
154 if change.tag() == ChangeTag::Equal {
155 if let (Some(new), Some(old)) = (change.new_index(), change.old_index()) {
156 self.current_to_prev.insert(new, old);
157 }
158 }
159 }
160 }
161 }
162
163 pub fn ctx<'a>(&'a self) -> Ctx<'a> {
164 Ctx { context: self }
165 }
166}