diff --git a/example.mharkup b/example.mharkup index 49403d6..7d859e5 100644 --- a/example.mharkup +++ b/example.mharkup @@ -15,9 +15,9 @@ in most markdown flavors. as someone using mharkup, you ` can read and write it in your text editor -` can export and `/printable(print) it +` can export and `/printable[print] it ` can easily (re)organize your document -` probably won't apply formatting on accident `/backtick() +` probably won't apply formatting on accident `/backtick[] # the format @@ -46,9 +46,9 @@ for example, here are the sections you just read: each mharkup file starts with a title, the first line of the file, which doesn't have -any leading hashtags. a file `+(should) also have a small +any leading hashtags. a file `+[should] also have a small description of what it will contain, and the file's -actual content `+(should) be in subdocuments. +actual content `+[should] be in subdocuments. for example, here's how this file starts: [[ @@ -68,19 +68,20 @@ features of mharkup. in most cases, a section is just a few lines of text. you've probably already noticed that linebreaks are usually -ignored `-(or, more accurately, replaced with spaces). +ignored `-[or, more accurately, replaced with spaces]. -sections beginning with a hashtag (#) are special. +sections beginning with a hashtag (`![#]) are special. the first line specifies the type of section you want, and the other lines are the section's content. -you've already seen this with #!mharkup in the +you've already seen this with `![#!mharkup] in the first example. the types of sections you can create like this are: -` #@ quotes -` #! code blocks -` #\ various extensions +` `![#@] quotes +` `![#!] code blocks +` `![#:] resource links +` `![#\] various extensions ### backticks /here @@ -90,18 +91,18 @@ with a backtick followed by a space to create a list. here's a list of things the backtick can do: ` create a list -` represent itself ``: ```` -` add a `-(note): ``-(note) -` mark something that's `~(wrong): ``~(wrong) -` use monospace for `!(code): ``!(code) -` mark a non-word or name, like `@(mharkup): ``@(mharkup) -` highlight a `_(special) element: ``_(special) -` add emphasis to `+(something): ``+(something) -` highlight something `*(important): ``*(important) -` insert raw `{`text`}: `<`{`text`}>: `2{`<`{`text`}>}}: `2<`2{`<`{`text`}>}}>>: ... -` link `/here(somewhere): ``/here(somewhere) +` represent itself ``: `!{``} +` add a `-[note]: `!{`-[note]} +` mark something that's `~[wrong]: `!{`~[wrong]} +` include some `![code.f()]: `!{`![code.f()]} +` mark a non-word or name, like `@[mharkup]: ``@[mharkup] +` highlight a `_[special] element: `!{`_[special]} +` add emphasis to `+[something]: `!{`+[something]} +` highlight something `*[important]: `!{`*[important]} +` insert raw `{`text`}: `!<`{`text`}>: `2!{`<`{`text`}>}}: `2!<`2{`<`{`text`}>}}>>: ... +` link `/here[somewhere]: ``/here[somewhere] ` use an extension: ``\spec{...} or ``\spec<...> -` combine any of these: `*_+(whoah): ``*_+(whoah) +` combine any of these: `*_+[whoa`~(h)]: ``*_+[whoa``~(h)] ## @@ -155,21 +156,32 @@ to use the different section types in more detail. ### quotes -#@mark @21st century +#@mark @21st century `/ref[] i've solved many problems that noone's ever had. in this case, the first line -of the section was #@mark @21st century. +of the section was `!{#@mark @21st century `/ref[]}. -### code +### code blocks #!python def do_something_productive(): pass in this case, the first line -of the section was #!python. +of the section was `!{#!python}. + +### resource links /ref + +#:other_doc +A document you should read. + +#https://example.com/hello +Something external. + +The first lines of these sections were `!{#:other_doc} and `!{#https://example.com/hello}. +If the section starts with `!{#:}, the link is relative. ### extensions @@ -198,14 +210,14 @@ or inline: `\texm or `2\texm{ \frac{1}{2} }} i really don't want to think about how many special characters i can't use while writing my plaintext documents. -i know that writing `<`*(word)> instead of **word** is inconvenient, +i know that writing `{`*(word)} instead of **word** is inconvenient, but using *, _, and even \ without any escaping may `-[(?)] already be worth it. -Also, * and _ can't be nested, so if you took `+(this **cool** section) +Also, * and _ can't be nested, so if you took `+[this **cool** section] and copy-pasted it into an already bold section, you would get -`+(**this **cool** section**) which is just... ew. -Meanwhile `{`*(this `*(cool) section)} works just fine -and produces `*(this `*(cool) section). +`+[**this **cool** section**] which is just... ew. +Meanwhile `{`*[this `*(cool) section]} works just fine +and produces `*[this `*(cool) section]. ## why does it need to be printable? /printable @@ -237,7 +249,7 @@ and here's 10 layers of documents in mharkup: ########## whoah, that's a lot -but it's still perfectly readable +but it's still perfectly readable. ## why are there no nested lists? /listnesting diff --git a/src/doc.rs b/src/doc.rs index 952262a..1bfd9ed 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -11,7 +11,8 @@ pub enum Section<'a> { Paragraph(Text<'a>), List(Vec>), 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(), } } } diff --git a/src/parse.rs b/src/parse.rs index 0811209..c09ef93 100644 --- a/src/parse.rs +++ b/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))?, )); diff --git a/src/to/html.rs b/src/to/html.rs index 46acb1e..b86e854 100644 --- a/src/to/html.rs +++ b/src/to/html.rs @@ -40,7 +40,7 @@ pub fn page_to<'a>(