From 277d1d2a2dcff5a30bddf958fbec991cd6b369af83b85377e90bd79862ef95dd Mon Sep 17 00:00:00 2001 From: Alex Wied <2+alex@noreply.code.graphofliberty.org> Date: Thu, 27 Aug 2026 13:00:36 -0400 Subject: [PATCH] . --- graph/src/curie.rs | 54 +++++++++++++++++---------------- graph/src/indexer.rs | 1 + publish/src/app.rs | 12 ++++---- publish/src/widget/iri_input.rs | 13 ++++---- 4 files changed, 42 insertions(+), 38 deletions(-) diff --git a/graph/src/curie.rs b/graph/src/curie.rs index 1cf0e57..bb3a20d 100644 --- a/graph/src/curie.rs +++ b/graph/src/curie.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; use std::sync::LazyLock; +use oxigraph::model::NamedNode; use url::Url; const ONTOLOGY_PREFIX: &str = "https://graphofliberty.org/2026/04/ont/"; @@ -61,37 +62,38 @@ impl CurieHelper { Self { prefixes } } - pub fn abbreviate(&self, base: Option<&str>, iri: &str) -> Option { - if let Some(base) = base - && let Some(local_name) = iri.strip_prefix(base) - { - return Some(format!(":{local_name}")); - } + pub fn abbreviate(&self, base: Option<&Url>, iri: &str) -> Option { + let relative_iri = base.and_then(|base| { + let iri = Url::parse(iri).ok()?; + base.make_relative(&iri) + }); - for (name, base) in &self.prefixes { - if let Some(local_name) = iri.strip_prefix(base) { - return Some(format!("{name}:{local_name}")); + if relative_iri.is_some() { + relative_iri + } else { + for (name, prefix) in &self.prefixes { + if let Some(local_name) = iri.strip_prefix(prefix) { + 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 { - let (prefix, name) = abbreviated_iri.split_once(':')?; + pub fn expand(&self, base: Option<&Url>, abbreviated_iri: &str) -> Option { + 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 == "" - && let Some(base) = base - { - Some(format!("{base}{name}")) - } else { - self.prefixes - .get(prefix) - .map(|base| format!("{base}{name}")) - } + absolute_iri.split_once(':') + .and_then(|(prefix, name)| { + if prefix == "" && let Some(base) = base { + Some(format!("{base}{name}")) + } else { + self.prefixes + .get(prefix) + .map(|base| format!("{base}{name}")) + } + }) } } diff --git a/graph/src/indexer.rs b/graph/src/indexer.rs index 3965a9e..4ecce08 100644 --- a/graph/src/indexer.rs +++ b/graph/src/indexer.rs @@ -2,6 +2,7 @@ use rayon::iter::ParallelIterator; use std::collections::{HashMap, HashSet}; use oxigraph::model::{Graph, NamedNode, TermRef, NamedOrBlankNodeRef, NamedNodeRef}; use rayon::iter::IntoParallelRefIterator; +use url::Url; use gl_search::{Field, OwnedValue, Schema}; use crate::class::Class; use crate::{helpers, vocab, CurieHelper}; diff --git a/publish/src/app.rs b/publish/src/app.rs index 0358979..2ee018b 100644 --- a/publish/src/app.rs +++ b/publish/src/app.rs @@ -676,14 +676,14 @@ impl Publisher { container(space()).width(BUTTON_WIDTH) }; - let base = self.document.origin().as_str(); + let base = self.document.origin(); let subject = match &quad.subject { 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 { subject_input_base } else { @@ -693,7 +693,7 @@ impl Publisher { let predicate_input_base = iri_input( &self.curie_helper, "Predicate", - Some(&base), + Some(base), quad.predicate.as_str(), ); let predicate_input = if state.read_only { @@ -743,7 +743,7 @@ impl Publisher { .into() } } 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)); if state.read_only { base.into() @@ -937,7 +937,7 @@ impl Publisher { let subject_column = table::column("Subject", |triple: TripleRef| { let curie = if let NamedOrBlankNodeRef::NamedNode(subject) = triple.subject { 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())) } else { None @@ -966,7 +966,7 @@ impl Publisher { match triple.object { TermRef::NamedNode(node) => { 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()); let label = self.resource_descriptions diff --git a/publish/src/widget/iri_input.rs b/publish/src/widget/iri_input.rs index 12f2552..547ec33 100644 --- a/publish/src/widget/iri_input.rs +++ b/publish/src/widget/iri_input.rs @@ -7,6 +7,7 @@ use iced::clipboard::Content; use iced::mouse::{Cursor, Interaction}; use iced::widget::text_input::{Catalog, Status, Style, StyleFn}; use iced::{Element, Event, Length, Rectangle, Size, keyboard, widget}; +use url::Url; pub struct State { control: bool, @@ -19,7 +20,7 @@ where Renderer: text::Renderer, { curie_helper: &'a CurieHelper, - base: Option, + base: Option<&'a Url>, on_control_click: Option, on_shift_click: Option, text_input: widget::TextInput<'a, Message, Theme, Renderer>, @@ -34,7 +35,7 @@ where pub fn new( curie_helper: &'a CurieHelper, placeholder: &'a str, - base: Option<&str>, + base: Option<&'a Url>, iri: &str, ) -> Self { let display_value = curie_helper @@ -43,7 +44,7 @@ where let text_input = widget::TextInput::new(placeholder, display_value); Self { curie_helper, - base: base.map(String::from), + base, on_control_click: None, on_shift_click: None, text_input, @@ -72,7 +73,7 @@ where pub fn on_input(mut self, on_input: impl Fn(String) -> Message + 'a) -> Self { let base_clone = self.base.clone(); 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)) }; @@ -117,7 +118,7 @@ where pub fn iri_input<'a, Message, Theme, Renderer>( curie_helper: &'a CurieHelper, placeholder: &'a str, - base: Option<&str>, + base: Option<&'a Url>, iri: &str, ) -> IriInput<'a, Message, Theme, Renderer> where @@ -246,7 +247,7 @@ where let clipboard = shell.clipboard_mut(); 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)); } }