swls_core/feature/
rename.rs1use bevy_ecs::{
2 prelude::*,
3 schedule::{IntoScheduleConfigs, ScheduleLabel},
4};
5use sophia_api::quad::Quad as _;
6use tracing::instrument;
7
8pub use crate::util::triple::get_current_triple;
9use crate::{lsp_types::TextEdit, prelude::*};
10
11#[derive(Component, Debug)]
13pub struct PrepareRenameRequest {
14 pub range: crate::lsp_types::Range,
15 pub placeholder: String,
16}
17
18#[derive(ScheduleLabel, Clone, Eq, PartialEq, Debug, Hash)]
20pub struct PrepareRename;
21
22#[derive(Component, Debug)]
24pub struct RenameEdits(
25 pub Vec<(crate::lsp_types::Url, crate::lsp_types::TextEdit)>,
26 pub String,
27);
28
29#[derive(ScheduleLabel, Clone, Eq, PartialEq, Debug, Hash)]
31pub struct Rename;
32
33pub fn setup_schedules(world: &mut World) {
34 let mut prepare_rename_schedule = Schedule::new(PrepareRename);
35 prepare_rename_schedule
36 .add_systems((get_current_triple, prepare_rename.after(get_current_triple)));
37 world.add_schedule(prepare_rename_schedule);
38
39 let mut rename_schedule = Schedule::new(Rename);
40 rename_schedule.add_systems((get_current_triple, rename.after(get_current_triple)));
41 world.add_schedule(rename_schedule);
42}
43
44#[instrument(skip(query, commands))]
45pub fn prepare_rename(
46 query: Query<(Entity, &RopeC, &DynLang, Option<&TripleComponent>)>,
47 mut commands: Commands,
48) {
49 for (e, rope, lang, m_triple) in &query {
50 if lang.0.model_based_rename() {
53 continue;
54 }
55 commands.entity(e).remove::<PrepareRenameRequest>();
56 if let Some(triple) = m_triple {
57 use sophia_api::term::TermKind;
58 let renameable = matches!(
59 triple.kind(),
60 TermKind::Iri | TermKind::BlankNode | TermKind::Variable
61 );
62 if renameable {
63 let span = match triple.target {
64 TripleTarget::Subject => &triple.triple.subject.span,
65 TripleTarget::Predicate => &triple.triple.predicate.span,
66 TripleTarget::Object => &triple.triple.object.span,
67 TripleTarget::Graph => continue,
68 };
69
70 let Some(raw) = rope.0.byte_slice(span.start..span.end) else {
71 continue;
72 };
73 let raw = raw.to_string();
74 let inner = lang.0.rename_placeholder(&raw);
75
76 if inner.is_empty() {
78 continue;
79 }
80
81 let prefix_offset = inner.as_ptr() as usize - raw.as_ptr() as usize;
86 let inner_start = span.start + prefix_offset;
87 let inner_end = inner_start + inner.len();
88
89 if inner_start >= inner_end || inner_end > span.end {
90 continue;
91 }
92
93 if let Some(range) = range_to_range(&(inner_start..inner_end), &rope.0) {
94 let placeholder = inner.to_string();
95 commands
96 .entity(e)
97 .insert(PrepareRenameRequest { range, placeholder });
98 continue;
99 }
100 }
101 }
102 tracing::debug!("Didn't find a renameable triple");
103 }
104}
105
106#[instrument(skip(query))]
107pub fn rename(mut query: Query<(&TripleComponent, &Triples, &RopeC, &Label, &DynLang, &mut RenameEdits)>) {
108 for (triple, triples, rope, label, lang, mut edits) in &mut query {
109 if lang.0.model_based_rename() {
111 continue;
112 }
113 let Some(target) = triple.term() else {
114 continue;
115 };
116 let new_text = lang.0.rename_wrap(&edits.1);
117
118 let mut seen_spans: std::collections::HashSet<(usize, usize)> = std::collections::HashSet::new();
121
122 for quad in triples.0.iter() {
123 for term in [quad.s(), quad.p(), quad.o()] {
124 if term == target {
125 let key = (term.span.start, term.span.end);
126 if seen_spans.insert(key) {
127 if let Some(range) = range_to_range(&term.span, &rope.0) {
128 edits.0.push((
129 label.0.clone(),
130 TextEdit {
131 range,
132 new_text: new_text.clone(),
133 },
134 ));
135 }
136 }
137 }
138 }
139 }
140 }
141}