Implement spaced anchor redirection

This commit is contained in:
Juno Takano 2026-01-05 23:12:10 -03:00
commit a98c87cdfc
3 changed files with 19 additions and 13 deletions

View file

@ -1,6 +1,6 @@
# Roadmap
- [x] Add tests
- [x] Setup tests
- [ ] Improve content syntax parser coverage
- [x] Redirects
- [ ] Strip/render some syntax in Tree text preview
@ -28,7 +28,7 @@
- [x] Ignore trailing punctuation
- [ ] Conjugation anchors (|will|ed -> will)
- [ ] Configurable suffixes
- [ ] Spaced node anchor (|red fox| -> redfox -> RedFox)
- [x] Spaced node anchor (|red fox| -> redfox -> RedFox)
- [ ] Automatic connections from anchors
- [ ] `#` syntax for header ID anchors
- [ ] Connection kinds

View file

@ -1,3 +1,4 @@
use crate::prelude::*;
use axum::response::IntoResponse as _;
use axum::{body::Body, extract::Path, http::Response, response::Redirect};
@ -8,7 +9,8 @@ use crate::{syntax::serial::populate_graph, router::handlers, types::Node};
pub async fn node(Path(id): Path<String>) -> Response<Body> {
let graph = populate_graph();
let empty_node = Node::new(Some(format!("Could not find node ID {id}.")));
let node = graph.find_node(&id).unwrap_or(empty_node.clone());
let (node_match, exact) = graph.find_node(&id);
let node = node_match.unwrap_or(empty_node.clone());
if !node.redirect.is_empty() {
return Redirect::permanent(
@ -17,9 +19,8 @@ pub async fn node(Path(id): Path<String>) -> Response<Body> {
.into_response();
}
if !graph.nodes.contains_key(&id)
&& graph.lowercase_keymap.contains_key(&id)
{
if !exact {
log!("Redirecting non-exact match to {}", node.id);
return Redirect::permanent(format!("/node/{}", node.id).as_str())
.into_response();
}

View file

@ -130,13 +130,18 @@ impl Graph {
}
}
pub fn find_node(&self, query: &str) -> Option<Node> {
self.nodes.get(query).cloned().or_else(|| {
self.lowercase_keymap
.get(query)
.and_then(|lower_key| self.nodes.get(lower_key))
.cloned()
})
pub fn find_node(&self, query: &str) -> (Option<Node>, bool) {
let collapsed_query = query.trim().replace(" ", "");
if let Some(exact_match) = self.nodes.get(query) {
(Some(exact_match.clone()), true)
} else if let Some(lower_key) =
self.lowercase_keymap.get(&collapsed_query)
{
(self.nodes.get(lower_key).cloned(), false)
} else {
(None, false)
}
}
pub fn get_root(&self) -> Option<Node> {