feat: inline code, resource links
fixes Text::is_empty() and allows formatted text in the context section of quotes (so you can link to /ref) slight changes to the css of the html generator, this should fix document preview on link hovering and might improve nesting if you edit the generated html in weird ways (should be more robust now).
This commit is contained in:
19
src/doc.rs
19
src/doc.rs
@@ -11,7 +11,8 @@ pub enum Section<'a> {
|
||||
Paragraph(Text<'a>),
|
||||
List(Vec<Text<'a>>),
|
||||
Code(&'a str, Text<'a>),
|
||||
Quote(&'a str, &'a str, Text<'a>),
|
||||
Quote(&'a str, Text<'a>, Text<'a>),
|
||||
Link(&'a str, &'a str, Text<'a>),
|
||||
Ext(&'a str, &'a str),
|
||||
Document(Document<'a>),
|
||||
}
|
||||
@@ -25,34 +26,32 @@ pub enum Component<'a> {
|
||||
Text(&'a str),
|
||||
Note(Text<'a>),
|
||||
Wrong(Text<'a>),
|
||||
Name(Text<'a>),
|
||||
Code(Text<'a>),
|
||||
Special(Text<'a>),
|
||||
Emphasis(Text<'a>),
|
||||
Important(Text<'a>),
|
||||
Name(Text<'a>),
|
||||
Code(Text<'a>),
|
||||
Link(&'a str, Text<'a>),
|
||||
Ext(&'a str, &'a str),
|
||||
}
|
||||
|
||||
impl<'a> Text<'a> {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.iter().any(|c| c.is_empty())
|
||||
self.0.iter().all(|c| c.is_empty())
|
||||
}
|
||||
}
|
||||
impl<'a> Component<'a> {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
Component::Char(_) => false,
|
||||
Component::Char(_) | Component::Link(_, _) | Component::Ext(_, _) => false,
|
||||
Component::Text(t) => t.is_empty(),
|
||||
Component::Note(t)
|
||||
| Component::Wrong(t)
|
||||
| Component::Name(t)
|
||||
| Component::Code(t)
|
||||
| Component::Special(t)
|
||||
| Component::Emphasis(t)
|
||||
| Component::Important(t)
|
||||
| Component::Name(t)
|
||||
| Component::Code(t) => t.is_empty(),
|
||||
Component::Link(target, t) => target.is_empty() && t.is_empty(),
|
||||
Component::Ext(_, _) => false,
|
||||
| Component::Important(t) => t.is_empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
44
src/parse.rs
44
src/parse.rs
@@ -225,6 +225,12 @@ pub fn parse_text_impl<'a>(
|
||||
'~' if opt.is_empty() => {
|
||||
inner = Ok(text(inner, Component::Wrong));
|
||||
}
|
||||
'@' if opt.is_empty() => {
|
||||
inner = Ok(text(inner, Component::Name));
|
||||
}
|
||||
'!' if opt.is_empty() => {
|
||||
inner = Ok(text(inner, Component::Code));
|
||||
}
|
||||
'_' if opt.is_empty() => {
|
||||
inner = Ok(text(inner, Component::Special));
|
||||
}
|
||||
@@ -234,12 +240,6 @@ pub fn parse_text_impl<'a>(
|
||||
'*' if opt.is_empty() => {
|
||||
inner = Ok(text(inner, Component::Important));
|
||||
}
|
||||
'@' if opt.is_empty() => {
|
||||
inner = Ok(text(inner, Component::Name));
|
||||
}
|
||||
'!' if opt.is_empty() => {
|
||||
inner = Ok(text(inner, Component::Code));
|
||||
}
|
||||
'/' if !opt.is_empty() => {
|
||||
inner = Ok(text(inner, |v| Component::Link(opt, v)));
|
||||
}
|
||||
@@ -254,11 +254,11 @@ pub fn parse_text_impl<'a>(
|
||||
Component::Link(_, text)
|
||||
| Component::Note(text)
|
||||
| Component::Wrong(text)
|
||||
| Component::Name(text)
|
||||
| Component::Code(text)
|
||||
| Component::Special(text)
|
||||
| Component::Emphasis(text)
|
||||
| Component::Important(text)
|
||||
| Component::Name(text)
|
||||
| Component::Code(text) => inner = &mut text.0[0],
|
||||
| Component::Important(text) => inner = &mut text.0[0],
|
||||
Component::Char(_) | Component::Ext(_, _) => {
|
||||
unreachable!()
|
||||
}
|
||||
@@ -426,7 +426,31 @@ fn parse_sections<'a>(
|
||||
attributed.rsplit_once('@').unwrap_or((attributed, ""));
|
||||
sections.push(Section::Quote(
|
||||
attributed.strip_suffix(' ').unwrap_or(attributed),
|
||||
context.strip_prefix(' ').unwrap_or(context),
|
||||
parse_text(&mut context.strip_prefix(' ').unwrap_or(context), |o| {
|
||||
o.remove_linebreaks()
|
||||
})
|
||||
.map_err(|ParseError(e, i)| ParseError(e, i + pos))?,
|
||||
parse_text(&mut inner, |o| o.remove_linebreaks())
|
||||
.map_err(|ParseError(e, i)| ParseError(e, i + pos))?,
|
||||
));
|
||||
}
|
||||
Some(_)
|
||||
if posthash
|
||||
.trim_start_matches(|c: char| !(c == ':' || c.is_whitespace()))
|
||||
.starts_with(":") =>
|
||||
{
|
||||
let i = posthash.find(':').unwrap();
|
||||
let (mut link, mut inner) = if let Some(j) = posthash.find('\n') {
|
||||
(&posthash[0..j], &posthash[j + 1..])
|
||||
} else {
|
||||
(posthash, "")
|
||||
};
|
||||
if i == 0 {
|
||||
link = &link[1..];
|
||||
}
|
||||
sections.push(Section::Link(
|
||||
&posthash[0..i],
|
||||
link,
|
||||
parse_text(&mut inner, |o| o.remove_linebreaks())
|
||||
.map_err(|ParseError(e, i)| ParseError(e, i + pos))?,
|
||||
));
|
||||
|
||||
@@ -40,7 +40,7 @@ pub fn page_to<'a>(
|
||||
<style>
|
||||
@media (prefers-color-scheme: light) {{ :root {{ --bg: #FFF; --bg2: #FFF4F4; --fg: #000; }} }}
|
||||
@media (prefers-color-scheme: dark) {{ :root {{ --bg: #070002; --bg2: #070010; --fg: #E0B8A0; }} }}
|
||||
:root {{ color: var(--fg); background: var(--bg); font-family: sans-serif;
|
||||
:root {{ background: var(--bg);
|
||||
--fgl: color-mix(var(--fg), var(--bg) 50%); --fgd: color-mix(var(--fg), var(--bg) 65%); --fgt: color-mix(var(--fg), var(--bg) 80%);
|
||||
--fsmall: 66%; --fless: 77%; --fmore: 110%; --ftitle: 132%; }}
|
||||
/*
|
||||
@@ -54,6 +54,11 @@ pub fn page_to<'a>(
|
||||
max-width: 90%;
|
||||
width: fit-content;
|
||||
}}
|
||||
.doc {{
|
||||
color: var(--fg); font-family: sans-serif;
|
||||
text-align: left; text-decoration: none;
|
||||
}}
|
||||
a {{ color: inherit; text-decoration: none; }}
|
||||
.z {{
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
@@ -108,64 +113,67 @@ pub fn page_to<'a>(
|
||||
padding-left: 1em;
|
||||
}}
|
||||
|
||||
.y.code .head {{
|
||||
.y.code > .head {{
|
||||
color: var(--fgl);
|
||||
font-size: var(--fsmall);
|
||||
}}
|
||||
.y.code .head::before {{
|
||||
.y.code > .head::before {{
|
||||
content: "#! ";
|
||||
font-size: var(--fless);
|
||||
}}
|
||||
|
||||
.y.quote .head {{
|
||||
.y.quote > .head {{
|
||||
color: var(--fgl);
|
||||
font-size: var(--fless);
|
||||
}}
|
||||
.y.quote .tail {{
|
||||
.y.quote > .tail {{
|
||||
color: var(--fgl);
|
||||
font-size: var(--fsmall);
|
||||
text-align: right;
|
||||
}}
|
||||
.y.quote .head::before {{
|
||||
.y.quote > .head::before {{
|
||||
content: "@ ";
|
||||
font-size: var(--fless);
|
||||
}}
|
||||
.y.quote:not(.c-) .tail::before {{
|
||||
.y.quote > .tail::before {{
|
||||
content: " (";
|
||||
font-size: var(--fless);
|
||||
}}
|
||||
.y.quote:not(.c-) .tail::after {{
|
||||
.y.quote > .tail::after {{
|
||||
content: ") ";
|
||||
font-size: var(--fless);
|
||||
}}
|
||||
.y.quote.c- .x::after {{
|
||||
color: var(--fgl);
|
||||
|
||||
.y.rlink > .head {{
|
||||
font-size: var(--fsmall);
|
||||
content: "”";
|
||||
> * {{ text-decoration: underline var(--fgl); }}
|
||||
}}
|
||||
.y.rlink > .head::before {{
|
||||
content: "➤ ";
|
||||
color: var(--fgl);
|
||||
}}
|
||||
|
||||
.y.ext.spec .head {{
|
||||
.y.ext.spec > .head {{
|
||||
color: var(--fgl);
|
||||
}}
|
||||
.y.ext.nospec .head {{
|
||||
.y.ext.nospec > .head {{
|
||||
color: red;
|
||||
}}
|
||||
.y.ext .head {{
|
||||
.y.ext > .head {{
|
||||
font-size: var(--fsmall);
|
||||
}}
|
||||
.y.ext .head::before {{
|
||||
.y.ext > .head::before {{
|
||||
content: "#/ ";
|
||||
font-size: var(--fless);
|
||||
}}
|
||||
.y.ext.spec.e-html .head {{
|
||||
.y.ext.spec.e-html > .head {{
|
||||
display: none;
|
||||
}}
|
||||
.y.ext.spec.e-texm .head {{
|
||||
.y.ext.spec.e-texm > .head {{
|
||||
display: none;
|
||||
}}
|
||||
|
||||
.link {{
|
||||
color: var(--fg);
|
||||
text-decoration: underline var(--fgl);
|
||||
position: relative;
|
||||
}}
|
||||
@@ -303,6 +311,8 @@ fn doc_to_impl<'a>(
|
||||
Section::List(..) => "y list",
|
||||
Section::Code(..) => "y code",
|
||||
Section::Quote(..) => "y quote",
|
||||
Section::Link("", ..) => "y rlink path",
|
||||
Section::Link(..) => "y rlink uri",
|
||||
Section::Ext(..) => "y ext",
|
||||
Section::Document(..) => "sub",
|
||||
},
|
||||
@@ -333,16 +343,27 @@ fn doc_to_impl<'a>(
|
||||
}
|
||||
Section::Quote(attributed, context, text) => {
|
||||
out.push_str(&format!(
|
||||
r#" a-{} c-{}"><div class="head">{}</div><div class="x">"#,
|
||||
r#" a-{}"><div class="head">{}</div><div class="x">"#,
|
||||
escape_quot(&attributed.replace(char::is_whitespace, "-")),
|
||||
escape_quot(&context.replace(char::is_whitespace, "-")),
|
||||
escape(attributed),
|
||||
));
|
||||
text_to(text, specs, out, doc_args);
|
||||
out.push_str("</div>");
|
||||
if !context.is_empty() {
|
||||
out.push_str(r#"<div class="x tail">"#);
|
||||
text_to(context, specs, out, doc_args);
|
||||
out.push_str("</div>");
|
||||
}
|
||||
}
|
||||
Section::Link(scheme, link, text) => {
|
||||
out.push_str(&format!(
|
||||
r#"</div><div class="tail">{}</div>"#,
|
||||
escape(context),
|
||||
r#" ls-{}"><div class="head"><a href="{}">{}</a></div><div class="x">"#,
|
||||
escape_quot(scheme),
|
||||
escape_quot(link),
|
||||
escape(link),
|
||||
));
|
||||
text_to(text, specs, out, doc_args);
|
||||
out.push_str("</div>");
|
||||
}
|
||||
Section::Ext(spec @ "html", source) if specs.has(spec) => {
|
||||
out.push_str(&format!(
|
||||
@@ -417,6 +438,16 @@ fn text_to<'a: 'b, 'b>(
|
||||
text_to(text, specs, out, args);
|
||||
out.push_str("</del>");
|
||||
}
|
||||
Component::Name(text) => {
|
||||
out.push_str(r#"<span class="tname">"#);
|
||||
text_to(text, specs, out, args);
|
||||
out.push_str("</span>");
|
||||
}
|
||||
Component::Code(text) => {
|
||||
out.push_str(r#"<pre class="tcode">"#);
|
||||
text_to(text, specs, out, args);
|
||||
out.push_str("</pre>");
|
||||
}
|
||||
Component::Special(text) => {
|
||||
out.push_str(r#"<u class="special">"#);
|
||||
text_to(text, specs, out, args);
|
||||
@@ -432,16 +463,6 @@ fn text_to<'a: 'b, 'b>(
|
||||
text_to(text, specs, out, args);
|
||||
out.push_str("</strong>");
|
||||
}
|
||||
Component::Name(text) => {
|
||||
out.push_str(r#"<span class="tname">"#);
|
||||
text_to(text, specs, out, args);
|
||||
out.push_str("</span>");
|
||||
}
|
||||
Component::Code(text) => {
|
||||
out.push_str(r#"<pre class="tcode">"#);
|
||||
text_to(text, specs, out, args);
|
||||
out.push_str("</pre>");
|
||||
}
|
||||
Component::Link(target, text) => {
|
||||
let link_target: Option<&'a Document<'a>> = args
|
||||
.max_len
|
||||
|
||||
@@ -35,6 +35,18 @@ fn text_to(text: &Text<'_>, complete: bool, specs: &[impl Spec], out: &mut Strin
|
||||
out.push('~');
|
||||
}
|
||||
}
|
||||
Component::Name(text) => {
|
||||
text_to(text, complete, specs, out);
|
||||
}
|
||||
Component::Code(text) => {
|
||||
if complete {
|
||||
out.push('`');
|
||||
}
|
||||
text_to(text, complete, specs, out);
|
||||
if complete {
|
||||
out.push('`');
|
||||
}
|
||||
}
|
||||
Component::Special(text) => {
|
||||
if complete {
|
||||
out.push('_');
|
||||
@@ -66,18 +78,6 @@ fn text_to(text: &Text<'_>, complete: bool, specs: &[impl Spec], out: &mut Strin
|
||||
out.push('*');
|
||||
}
|
||||
}
|
||||
Component::Name(text) => {
|
||||
text_to(text, complete, specs, out);
|
||||
}
|
||||
Component::Code(text) => {
|
||||
if complete {
|
||||
out.push('`');
|
||||
}
|
||||
text_to(text, complete, specs, out);
|
||||
if complete {
|
||||
out.push('`');
|
||||
}
|
||||
}
|
||||
Component::Link(target, text) => {
|
||||
if complete {
|
||||
out.push('_');
|
||||
|
||||
Reference in New Issue
Block a user