Flag absolute anchors
This commit is contained in:
parent
1d801dce06
commit
88fdd3084e
6 changed files with 100 additions and 26 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
|
@ -139,9 +139,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
|||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.44"
|
||||
version = "0.4.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
||||
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
|
|
@ -531,9 +531,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
|||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.31"
|
||||
version = "0.4.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f"
|
||||
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
|
|
|
|||
|
|
@ -396,7 +396,7 @@ impl Graph {
|
|||
);
|
||||
} else {
|
||||
if let Some(destination) = anchor.destination()
|
||||
&& !anchor.external()
|
||||
&& !anchor.absolute()
|
||||
{
|
||||
let trimmed_destination = destination
|
||||
.trim_start_matches("/node/")
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ pub fn parse(
|
|||
log!(VERBOSE, "End: Next lexeme is a pipe");
|
||||
buffer.text.push_str(&lexeme.text());
|
||||
candidate.set_text(&buffer.text.clone());
|
||||
if buffer.text.starts_with('/') {
|
||||
candidate.set_absolute(true);
|
||||
}
|
||||
} else {
|
||||
log!(
|
||||
VERBOSE,
|
||||
|
|
@ -84,6 +87,13 @@ pub fn parse(
|
|||
"State: Found a pipe, but no boundary: destination follows"
|
||||
);
|
||||
candidate.set_balanced(true);
|
||||
if lexeme.match_next_first_char('/') {
|
||||
log!(
|
||||
VERBOSE,
|
||||
"State: Destination starts with a dash, marking as absolute"
|
||||
);
|
||||
candidate.set_absolute(true);
|
||||
}
|
||||
return true;
|
||||
} else if lexeme.match_char(':') {
|
||||
log!(VERBOSE, "State: Found a colon, marking anchor as external");
|
||||
|
|
@ -205,8 +215,10 @@ mod tests {
|
|||
fn needless_three_pipe_anchor() {
|
||||
assert_eq!(
|
||||
read("|Node|Destination|"),
|
||||
concat!(r#"<p><a class="detached" title="" "#,
|
||||
r#"href="/node/Destination">Node</a></p>"#)
|
||||
concat!(
|
||||
r#"<p><a class="detached" title="" "#,
|
||||
r#"href="/node/Destination">Node</a></p>"#
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -225,9 +237,11 @@ mod tests {
|
|||
fn anchor_to_node_s() {
|
||||
assert_eq!(
|
||||
read("The |letter s|s|'s node: |s|!"),
|
||||
concat!(r#"<p>The <a class="detached" title="" "#,
|
||||
concat!(
|
||||
r#"<p>The <a class="detached" title="" "#,
|
||||
r#"href="/node/s">letter s</a>'s node: "#,
|
||||
r#"<a class="detached" title="" href="/node/s">s</a>!</p>"#)
|
||||
r#"<a class="detached" title="" href="/node/s">s</a>!</p>"#
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -246,9 +260,11 @@ mod tests {
|
|||
fn leading_plural_anchor() {
|
||||
assert_eq!(
|
||||
read("Interfaces are |element|s of |system|s."),
|
||||
concat!(r#"<p>Interfaces are <a class="detached" title="" "#,
|
||||
concat!(
|
||||
r#"<p>Interfaces are <a class="detached" title="" "#,
|
||||
r#"href="/node/element">elements</a> of <a class="detached" "#,
|
||||
r#"title="" href="/node/system">systems</a>.</p>"#)
|
||||
r#"title="" href="/node/system">systems</a>.</p>"#
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -268,9 +284,11 @@ mod tests {
|
|||
fn explicit_end_of_destination() {
|
||||
assert_eq!(
|
||||
read("interactions are |basic elements|BasicElements| of systems"),
|
||||
concat!(r#"<p>interactions are <a class="detached" title="" "#,
|
||||
concat!(
|
||||
r#"<p>interactions are <a class="detached" title="" "#,
|
||||
r#"href="/node/BasicElements">basic elements</a> of "#,
|
||||
r#"systems</p>"#)
|
||||
r#"systems</p>"#
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -327,6 +345,21 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn absolute_anchor() {
|
||||
let parse_result =
|
||||
parser::rich_read("see the |raw endpoints|/data|.", &Graph::load());
|
||||
println!("Parsed tokens: {:#?}", parse_result.tokens);
|
||||
assert_eq!(
|
||||
parse_result.text.unwrap(),
|
||||
concat!(
|
||||
r#"<p>see the <a class="absolute" title="" "#,
|
||||
r#"href="/data">"#,
|
||||
r#"raw endpoints</a>.</p>"#,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn http_external_anchor() {
|
||||
assert_eq!(
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ pub struct Anchor {
|
|||
node: Option<Node>,
|
||||
leading: bool,
|
||||
balanced: bool,
|
||||
absolute: bool,
|
||||
external: bool,
|
||||
}
|
||||
|
||||
|
|
@ -34,10 +35,17 @@ impl Anchor {
|
|||
self.balanced = balanced;
|
||||
}
|
||||
|
||||
pub const fn absolute(&self) -> bool { self.absolute }
|
||||
|
||||
pub const fn set_absolute(&mut self, absolute: bool) {
|
||||
self.absolute = absolute;
|
||||
}
|
||||
|
||||
pub const fn external(&self) -> bool { self.external }
|
||||
|
||||
pub const fn set_external(&mut self, external: bool) {
|
||||
self.external = external;
|
||||
self.absolute = true;
|
||||
}
|
||||
|
||||
pub const fn set_leading(&mut self, leading: bool) {
|
||||
|
|
@ -58,21 +66,28 @@ impl Anchor {
|
|||
|
||||
fn route(&mut self) {
|
||||
self.destination = if let Some(destination) = self.destination.clone() {
|
||||
if destination.contains(':') || destination.contains('/') {
|
||||
if destination.contains(':') || destination.starts_with('/') {
|
||||
Some(destination)
|
||||
} else if destination.is_empty() && self.text.is_empty() {
|
||||
None
|
||||
} else if destination.is_empty() {
|
||||
self.node_id = Some(self.text.clone());
|
||||
self.node_id = Some(Self::strip_fragment(&self.text));
|
||||
Some(format!("/node/{}", self.text))
|
||||
} else {
|
||||
self.node_id = self.destination.clone();
|
||||
self.node_id = self
|
||||
.destination
|
||||
.clone()
|
||||
.map(|d| Anchor::strip_fragment(&d));
|
||||
Some(format!("/node/{destination}"))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn strip_fragment(target: &str) -> String {
|
||||
target.split('#').next().unwrap_or(target).to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Parseable for Anchor {
|
||||
|
|
@ -100,19 +115,31 @@ impl Parseable for Anchor {
|
|||
String::default()
|
||||
};
|
||||
|
||||
let classes = if self.node.is_some() {
|
||||
String::from(r#"class="attached""#)
|
||||
} else if !self.external {
|
||||
String::from(r#"class="detached""#)
|
||||
} else if self.external {
|
||||
let classes = if self.external {
|
||||
String::from(r#"class="external""#)
|
||||
} else if self.absolute {
|
||||
String::from(r#"class="absolute""#)
|
||||
} else if self.node.is_some() {
|
||||
String::from(r#"class="attached""#)
|
||||
} else {
|
||||
String::default()
|
||||
String::from(r#"class="detached""#)
|
||||
};
|
||||
|
||||
let text = if destination.contains('#')
|
||||
&& !self.absolute
|
||||
&& destination == &format!("/node/{}", self.text)
|
||||
{
|
||||
self.text
|
||||
.split('#')
|
||||
.next()
|
||||
.unwrap_or(&self.text)
|
||||
.to_string()
|
||||
} else {
|
||||
self.text.clone()
|
||||
};
|
||||
|
||||
format!(
|
||||
r#"<a {classes} title="{summary}" href="{}">{}</a>"#,
|
||||
destination, self.text,
|
||||
r#"<a {classes} title="{summary}" href="{destination}">{text}</a>"#
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,19 @@ a.external:hover {
|
|||
transition: 1500ms;
|
||||
}
|
||||
|
||||
a.absolute {
|
||||
color: light-dark(#196719, #2fe471);
|
||||
text-decoration-color: light-dark(#196719, #2fe471);
|
||||
text-decoration-style: solid;
|
||||
text-decoration-thickness: 1.5px;
|
||||
transition: 1500ms;
|
||||
}
|
||||
|
||||
a.absolute:hover {
|
||||
filter: brightness(1.25);
|
||||
transition: 1500ms;
|
||||
}
|
||||
|
||||
a:visited,
|
||||
a.detached:visited,
|
||||
a.external:visited
|
||||
|
|
|
|||
|
|
@ -9,15 +9,16 @@
|
|||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="#detached-edges">Detached edges</a>
|
||||
<a href="#detached-connections">Detached connections</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#detached-edges:~:text=Anchors">{{ detached_count }}</a>
|
||||
<a href="#detached-connections:~:text=Anchors">{{ detached_count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3 id="detached-edges">Detached edges</h3>
|
||||
<h3 id="detached-connections">Detached connections</h3>
|
||||
<p>These are the destinations to which connections exist, but the target node doesn't.</p>
|
||||
|
||||
<details>
|
||||
<summary>Expand to see all detached edges.</summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue