This commit is contained in:
2026-08-27 13:00:36 -04:00
parent a8938176be
commit 277d1d2a2d
4 changed files with 42 additions and 38 deletions
+21 -19
View File
@@ -1,5 +1,6 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::sync::LazyLock; use std::sync::LazyLock;
use oxigraph::model::NamedNode;
use url::Url; use url::Url;
const ONTOLOGY_PREFIX: &str = "https://graphofliberty.org/2026/04/ont/"; const ONTOLOGY_PREFIX: &str = "https://graphofliberty.org/2026/04/ont/";
@@ -61,37 +62,38 @@ impl CurieHelper {
Self { prefixes } Self { prefixes }
} }
pub fn abbreviate(&self, base: Option<&str>, iri: &str) -> Option<String> { pub fn abbreviate(&self, base: Option<&Url>, iri: &str) -> Option<String> {
if let Some(base) = base let relative_iri = base.and_then(|base| {
&& let Some(local_name) = iri.strip_prefix(base) let iri = Url::parse(iri).ok()?;
{ base.make_relative(&iri)
return Some(format!(":{local_name}")); });
}
for (name, base) in &self.prefixes { if relative_iri.is_some() {
if let Some(local_name) = iri.strip_prefix(base) { relative_iri
} else {
for (name, prefix) in &self.prefixes {
if let Some(local_name) = iri.strip_prefix(prefix) {
return Some(format!("{name}:{local_name}")); return Some(format!("{name}:{local_name}"));
} }
} }
None
if let Some(base) = base && }
let Some(parsed_iri) = Url::parse(iri).ok() &&
let Some(parsed_base) = Url::parse(base).ok() {
parsed_base.make_relative(&parsed_iri)
} else { None }
} }
pub fn expand(&self, base: Option<&str>, abbreviated_iri: &str) -> Option<String> { pub fn expand(&self, base: Option<&Url>, abbreviated_iri: &str) -> Option<String> {
let (prefix, name) = abbreviated_iri.split_once(':')?; let absolute_iri = base.and_then(|base| {
base.join(abbreviated_iri).ok().map(|absolute| absolute.as_str().to_string())
}).unwrap_or_else(|| abbreviated_iri.to_string());
if prefix == "" absolute_iri.split_once(':')
&& let Some(base) = base .and_then(|(prefix, name)| {
{ if prefix == "" && let Some(base) = base {
Some(format!("{base}{name}")) Some(format!("{base}{name}"))
} else { } else {
self.prefixes self.prefixes
.get(prefix) .get(prefix)
.map(|base| format!("{base}{name}")) .map(|base| format!("{base}{name}"))
} }
})
} }
} }
+1
View File
@@ -2,6 +2,7 @@ use rayon::iter::ParallelIterator;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use oxigraph::model::{Graph, NamedNode, TermRef, NamedOrBlankNodeRef, NamedNodeRef}; use oxigraph::model::{Graph, NamedNode, TermRef, NamedOrBlankNodeRef, NamedNodeRef};
use rayon::iter::IntoParallelRefIterator; use rayon::iter::IntoParallelRefIterator;
use url::Url;
use gl_search::{Field, OwnedValue, Schema}; use gl_search::{Field, OwnedValue, Schema};
use crate::class::Class; use crate::class::Class;
use crate::{helpers, vocab, CurieHelper}; use crate::{helpers, vocab, CurieHelper};
+6 -6
View File
@@ -676,14 +676,14 @@ impl Publisher {
container(space()).width(BUTTON_WIDTH) container(space()).width(BUTTON_WIDTH)
}; };
let base = self.document.origin().as_str(); let base = self.document.origin();
let subject = match &quad.subject { let subject = match &quad.subject {
NamedOrBlankNode::NamedNode(subject) => subject.as_str(), NamedOrBlankNode::NamedNode(subject) => subject.as_str(),
_ => "", _ => "",
}; };
let subject_input_base = iri_input(&self.curie_helper, "Subject", Some(&base), subject); let subject_input_base = iri_input(&self.curie_helper, "Subject", Some(base), subject);
let subject_input = if state.read_only { let subject_input = if state.read_only {
subject_input_base subject_input_base
} else { } else {
@@ -693,7 +693,7 @@ impl Publisher {
let predicate_input_base = iri_input( let predicate_input_base = iri_input(
&self.curie_helper, &self.curie_helper,
"Predicate", "Predicate",
Some(&base), Some(base),
quad.predicate.as_str(), quad.predicate.as_str(),
); );
let predicate_input = if state.read_only { let predicate_input = if state.read_only {
@@ -743,7 +743,7 @@ impl Publisher {
.into() .into()
} }
} else { } else {
let base = iri_input(&self.curie_helper, "Object", Some(&base), value.as_str()) let base = iri_input(&self.curie_helper, "Object", Some(base), value.as_str())
.on_shift_click(Message::NavigateToObject(key)); .on_shift_click(Message::NavigateToObject(key));
if state.read_only { if state.read_only {
base.into() base.into()
@@ -937,7 +937,7 @@ impl Publisher {
let subject_column = table::column("Subject", |triple: TripleRef| { let subject_column = table::column("Subject", |triple: TripleRef| {
let curie = if let NamedOrBlankNodeRef::NamedNode(subject) = triple.subject { let curie = if let NamedOrBlankNodeRef::NamedNode(subject) = triple.subject {
Some(self.curie_helper Some(self.curie_helper
.abbreviate(Some(self.document.origin().as_str()), subject.as_str()) .abbreviate(Some(self.document.origin()), subject.as_str())
.unwrap_or_else(|| subject.as_str().to_string())) .unwrap_or_else(|| subject.as_str().to_string()))
} else { } else {
None None
@@ -966,7 +966,7 @@ impl Publisher {
match triple.object { match triple.object {
TermRef::NamedNode(node) => { TermRef::NamedNode(node) => {
let curie = self.curie_helper let curie = self.curie_helper
.abbreviate(Some(self.document.origin().as_str()), node.as_str()) .abbreviate(Some(self.document.origin()), node.as_str())
.unwrap_or_else(|| node.as_str().to_string()); .unwrap_or_else(|| node.as_str().to_string());
let label = self.resource_descriptions let label = self.resource_descriptions
+7 -6
View File
@@ -7,6 +7,7 @@ use iced::clipboard::Content;
use iced::mouse::{Cursor, Interaction}; use iced::mouse::{Cursor, Interaction};
use iced::widget::text_input::{Catalog, Status, Style, StyleFn}; use iced::widget::text_input::{Catalog, Status, Style, StyleFn};
use iced::{Element, Event, Length, Rectangle, Size, keyboard, widget}; use iced::{Element, Event, Length, Rectangle, Size, keyboard, widget};
use url::Url;
pub struct State { pub struct State {
control: bool, control: bool,
@@ -19,7 +20,7 @@ where
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
curie_helper: &'a CurieHelper, curie_helper: &'a CurieHelper,
base: Option<String>, base: Option<&'a Url>,
on_control_click: Option<Message>, on_control_click: Option<Message>,
on_shift_click: Option<Message>, on_shift_click: Option<Message>,
text_input: widget::TextInput<'a, Message, Theme, Renderer>, text_input: widget::TextInput<'a, Message, Theme, Renderer>,
@@ -34,7 +35,7 @@ where
pub fn new( pub fn new(
curie_helper: &'a CurieHelper, curie_helper: &'a CurieHelper,
placeholder: &'a str, placeholder: &'a str,
base: Option<&str>, base: Option<&'a Url>,
iri: &str, iri: &str,
) -> Self { ) -> Self {
let display_value = curie_helper let display_value = curie_helper
@@ -43,7 +44,7 @@ where
let text_input = widget::TextInput::new(placeholder, display_value); let text_input = widget::TextInput::new(placeholder, display_value);
Self { Self {
curie_helper, curie_helper,
base: base.map(String::from), base,
on_control_click: None, on_control_click: None,
on_shift_click: None, on_shift_click: None,
text_input, text_input,
@@ -72,7 +73,7 @@ where
pub fn on_input(mut self, on_input: impl Fn(String) -> Message + 'a) -> Self { pub fn on_input(mut self, on_input: impl Fn(String) -> Message + 'a) -> Self {
let base_clone = self.base.clone(); let base_clone = self.base.clone();
let wrapped = move |value: String| { let wrapped = move |value: String| {
let expanded_value = self.curie_helper.expand(base_clone.as_deref(), &value); let expanded_value = self.curie_helper.expand(base_clone, &value);
on_input(expanded_value.unwrap_or_else(|| value)) on_input(expanded_value.unwrap_or_else(|| value))
}; };
@@ -117,7 +118,7 @@ where
pub fn iri_input<'a, Message, Theme, Renderer>( pub fn iri_input<'a, Message, Theme, Renderer>(
curie_helper: &'a CurieHelper, curie_helper: &'a CurieHelper,
placeholder: &'a str, placeholder: &'a str,
base: Option<&str>, base: Option<&'a Url>,
iri: &str, iri: &str,
) -> IriInput<'a, Message, Theme, Renderer> ) -> IriInput<'a, Message, Theme, Renderer>
where where
@@ -246,7 +247,7 @@ where
let clipboard = shell.clipboard_mut(); let clipboard = shell.clipboard_mut();
if let Some(Content::Text(content)) = &clipboard.write { if let Some(Content::Text(content)) = &clipboard.write {
if let Some(expanded) = self.curie_helper.expand(self.base.as_deref(), &content) { if let Some(expanded) = self.curie_helper.expand(self.base, &content) {
clipboard.write = Some(Content::Text(expanded)); clipboard.write = Some(Content::Text(expanded));
} }
} }