Add reference anchors and update README

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/20/head
trivernis 4 years ago
parent e1e63cc35a
commit 1e46274003
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

2
Cargo.lock generated

@ -2315,7 +2315,7 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]] [[package]]
name = "snekdown" name = "snekdown"
version = "0.33.2" version = "0.33.3"
dependencies = [ dependencies = [
"asciimath-rs", "asciimath-rs",
"base64 0.12.3", "base64 0.12.3",

@ -1,9 +1,9 @@
[package] [package]
name = "snekdown" name = "snekdown"
version = "0.33.2" version = "0.33.3"
authors = ["trivernis <trivernis@protonmail.com>"] authors = ["trivernis <trivernis@protonmail.com>"]
edition = "2018" edition = "2018"
license-file = "LICENSE" license = "GPL-3.0"
readme = "README.md" readme = "README.md"
description = "A parser for the custom snekdown markdown syntax" description = "A parser for the custom snekdown markdown syntax"
repository = "https://github.com/Trivernis/snekdown" repository = "https://github.com/Trivernis/snekdown"

@ -1,465 +1,90 @@
# ![](https://i.imgur.com/FpdXqiT.png) Snekdown - More than just Markdown ![](https://img.shields.io/discord/729250668162056313) <p align="center">
<img src="https://i.imgur.com/FpdXqiT.png">
</p>
<h1 align="center">Snekdown</h1>
<p align="center">
<i>More than just Markdown</i>
</p>
<p align="center">
<img src="https://img.shields.io/github/workflow/status/trivernis/snekdown/Build%20and%20Test/main?style=for-the-badge">
<img src="https://img.shields.io/crates/v/snekdown?style=for-the-badge">
<img src="https://img.shields.io/aur/version/snekdown?style=for-the-badge">
<img src="https://img.shields.io/discord/729250668162056313?style=for-the-badge">
<br/>
<br/>
<a href="https://trivernis.net/snekdown/">Documentation</a> |
<a href="https://github.com/Trivernis/snekdown/releases">Releases</a>
</p>
- - -
## Description
This projects goal is to implement a fast markdown parser with an extended syntax fitted This projects goal is to implement a fast markdown parser with an extended syntax fitted
for my needs. for my needs.
## Installation ## Core Features
You need a working rust installation, for example by using [rustup](http://rustup.rs).
```sh
cargo install snekdown
```
With pdf rendering
```sh
cargo install snekdown --features pdf
```
## Usage
```
snekdown 0.30.5
USAGE:
snekdown <SUBCOMMAND>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
SUBCOMMANDS:
clear-cache Clears the cache directory
help Prints this message or the help of the given subcommand(s)
render Parse and render the document
watch Watch the document and its imports and render on change
```
### Rendering
```
Parse and render the document
USAGE:
snekdown render [OPTIONS] <input> <output>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-f, --format <format> the output format [default: html]
ARGS:
<input> Path to the input file
<output> Path for the output file
```
### Watching
```
Watch the document and its imports and render on change
USAGE:
snekdown watch [OPTIONS] <input> <output>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
--debounce <debounce> The amount of time in milliseconds to wait after changes before rendering [default:
500]
-f, --format <format> the output format [default: html]
ARGS:
<input> Path to the input file
<output> Path for the output file
```
## Syntax
### Images
```md
Simple Syntax
!(url)
Extended syntax with a description
![description](url)
Extended syntax with metadata to specify the size
![description](url)[metadata]
Extended syntax with metadata and no description
!(url)[metadata]
```
When generating the html file the images are base64 embedded. To turn off this behaviour
set the config parameter `embed-external` to `false`.
### Quotes
```md
Simple (default) Syntax
> This is a quote
Multiline
> This is a
> Multiline Quote
Quote with metadata (e.g. Author)
[author=Trivernis year=2020 display='{{author}} - {{year}}']> This is a quote with metadata
```
### Imports
Imports can be used to import a different document to be attached to the main document.
Imports are parsed via multithreading.
```md
<[path]
<[document.md]
<[style.css][type=stylesheet]
```
The parser differentiates four different types of imported files.
- `document` - The default import which is just another snekdown document
- `stylesheet` - CSS Stylesheets that are inclued when rendering
- `bibliography` - A file including bibliography
- `config`/`manifest` - A config file that contains metadata
If no type is provided the parser guesses the type of file from the extension.
### Tables
Tables MUST start with a pipe character `|`
```md
Standalone header:
| header | header | header
Header with rows
| header | header | header
|--------|--------|-------
| row | row | row
```
### Placeholders
Placeholders can be used to insert special elements in a specific place.
Placeholders are always case insensitive.
```md
Insert the table of contents
[[TOC]]
Insert the bibliography list
[[BIB]]
Insert the glossary
[[GLS]]
Insert the current date
[[date]]
Insert the current time
[[time]]
```
### Metadata
Additional metadata can be provided for some elements.
```md
String value
[key = value]
String value
[key = "String value"]
Integer value - Imports
[key = 123] - Bibliography & Glossary
- AsciiMath
- Placeholders
- Advanced Images
Float value
[key = 1.23]
Boolean ## Installation
[key]
Boolean
[key = false]
Placeholder
[key = [[placeholder]]]
```
Metadata can also be defined in a separate toml file with simple key-value pairs.
The file `Manifest.toml` will always be included by default.
Example:
```toml
# document metadata
[metadata]
# language setting of the document
language = 'en'
# author of the document
author = 'author'
# Title of the document
title = 'title'
# A short description for the document preview
description = '''
Description
'''
# Keywords to find the document
keywords = ['HTML', 'Snekdown']
# features used in the document
[features]
# if external sources (images, stylesheets, MathJax)
# should be embedded into the document (default: true)
embed_external = true
# If SmartArrows should be used (default: true)
smart_arrows = true
include_mathjax = true
[imports]
# those files won't get imported
ignored_imports = []
# stylesheets that should be included
included_stylesheets = ['style.css']
# bibliography that should be included
included_bibliography = ['Bibliography.toml']
# glossary that sould be included
included_glossaries = ['Glossary.toml']
# settings related to pdf rendering
[pdf]
# If the header and footer of the pdf should be displayed (default: true)
display_header_footer = true
# PDF header template of each page (default: '<div></div>')
header_template = '<div></div>'
# PDF footer template of each page (default: see chromium_pdf assets)
footer_template = '''
<div style="font-size: 10px; text-align: center; width: 100%;">
<span class="pageNumber"></span>/<span class="totalPages"></span>
</div>'''
# The scale at which the website is rendered into pdf.
page_scale = 1.0
# margin of the pdf document
[pdf.margin]
# Top margin of the pdf. Should be between 0 and 1. (default: 0.5)
top = 0.5
# Bottom margin of the pdf. Should be between 0 and 1. (default: 0.5)
bottom = 0.5
# Left margin of the pdf. Should be between 0 and 1.
left = 0
# Right margin of the pdf. Should be between 0 and 1.
right = 0
# image settings
[images]
# Force convert images to the specified format.
# Supported formats are png, jpeg, gif, bmp, (ico needs size <= 256), avif, pnm
# (default: keep original)
format = "png"
# the max width for the images.
# if an image is larger than that it get's resized.
# (default: none)
max_width = 700
# the max width for the images.
# if an image is larger than that it get's resized.
# (default: none)
max_height = 500
# Visual adjustments
[style]
# how bibliography references should be displayed
bib_ref_display = '{{number}}'
# the chosen theme for the document
# one of: GithubLight, SolarizedLight, OceanLight, SolarizedDark, OceanDark, MagicDark
theme = 'GithubLight'
# custom metadata
# String -> String Mappings
[custom_attributes]
custom_key1 = "Custom Value"
```
The `[Section]` keys are not relevant as the structure gets flattened before the values are read.
#### Usage
```
Hide a section (including subsections) in the TOC
#[toc-hidden] Section
Set the size of an image
!(url)[width = 42%, height=auto, brightness=10, contrast=1.2, huerotate=180, invert, grayscale]
Set the source of a quote
[author=Me date=[[date]] display="{{author}} - {{date}}"]> It's me
Set options for placeholders
[[toc]][ordered]
```
### Centered Text
```
|| These two lines
|| are centered
```
### Inline ### Binaries
```md
*Italic*
**Bold**
~~Striked~~
_Underlined_
^Superscript^
`Monospace`
:Emoji:
§[#0C0]Colored text§[] §[red] red §[]
```
## Bibliography You can download prebuilt binaries on the [Releases](https://github.com/Trivernis/snekdown/releases) Page.
Bibliography entries can be defined and referenced anywhere in the document.
Definition: ### Arch Linux
```md
[SD_BOOK]:[type=book, author=Snek, title = "Snekdown Book" date="20.08.2020", publisher=Snek]
[SD_GITHUB]: https://github.com/trivernis/snekdown
```
Usage: Snekdown is available in [the AUR](https://aur.archlinux.org/packages/snekdown).
```
There is a book about snekdown[^SD_BOOK] and a github repo[^SD_GITHUB].
```
Entries can also be defined in a separate toml file with the following data layout:
```toml ### Cargo
# snekdown.toml
[BIB_KEY]
key = "value"
[SD_BOOK] You need a working rust installation, for example by using [rustup](http://rustup.rs).
type = "book"
author = "Snek"
title = "Snekdown Book"
date = "20.08.2020"
publisher = "Snek"
[SD_GITHUB] ```sh
type = "website" cargo install snekdown
url = "https://github.com/trivernis/snekdown"
``` ```
The valid types for entries and required fields can be found on in the [bibliographix README](https://github.com/Trivernis/bibliographix#bibliography-types-and-fields). With pdf rendering
Bibliography entries are not rendered. To render a list of used bibliography insert the
`bib` placeholder at the place you want it to be rendered.
## Glossary
Glossary entries are to be defined in a `glossary.toml` file or any other toml file
that is imported as type `glossary`.
The definition of glossary entries has to follow the following structure
```toml
[SHORT]
long = "Long Form"
description = "The description of the entry"
# Example ```sh
[HTML] cargo install snekdown --features pdf
long = "Hypertext Markup Language"
description = "The markup language of the web"
``` ```
Those glossary entries can be referenced in the snekdown file as follows:
```md
~HTML is widely used for websites.
The format ~HTML is not considered a programming language by some definitions.
~~HTML ## Usage
```
The first occurence of the glossary entry (`~HTML`) always uses the long form. Use `snekdown help` and `snekdown <subcommand> --help` for more information.
The second will always be the short form. The long form can be enforced by using two
(`~~HTML`) tildes.
The glossary list can be inserted with the `[[GLS]]` placeholder.
## Math ### Rendering
Snekdown allows the embedding of [AsciiMath](http://asciimath.org/): `snekdown render <input> <output>`
The AsciiMath parser is provided in the [asciimath-rs](https://github.com/Trivernis/asciimath-rs) crate
``` ### Watching
inline math $$ a^2 + b^2 = c^2 $$
Block Math `snekdown watch <input> <output>`
$$$
A = [[1, 2],[3,4]]
$$$
```
The expression get's converted into MathML which is then converted by MathJax when loaded in
the browser.
## Smart Arrows ## Editors
Snekdown automatically renders the sequences `-->`, `==>`, `<--`, `<==`, `<-->`, `<==>` as I've created a [VisualStudio Code extension](https://marketplace.visualstudio.com/items?itemName=trivernis.snekdown) for Snekdown.
their respective unicode arrows (similar to [markdown-it-smartarrows](https://github.com/adam-p/markdown-it-smartarrows)). This extension provides a preview of snekdown files, exports and other commands similar to the
This behavior can be turned off by setting the config parameter `smart-arrows` to `false` cli. The source code can be found [here](https://github.com/Trivernis/snekdown-vscode-extension).
(the config needs to be imported before the arrows are used for that to work).
## Roadmap ## Roadmap
The end goal is to have a markup language with features similar to LaTeX. The end goal is to have a markup language with features similar to LaTeX.
### Short Term
- [x] Checkboxes - [x] Checkboxes
- [x] Emojis (\:emoji:) - [x] Emojis (\:emoji:)
- [x] Colors - [x] Colors
@ -471,9 +96,19 @@ The end goal is to have a markup language with features similar to LaTeX.
- [x] Chromium based pdf rendering - [x] Chromium based pdf rendering
- [x] Custom Stylesheets - [x] Custom Stylesheets
- [x] Smart arrows - [x] Smart arrows
- [ ] Custom Elements via templates (50%)
- [ ] Cross References - [ ] Cross References
- [ ] Figures - [ ] Figures
- [ ] EPUB Rendering - [ ] EPUB Rendering
- [ ] Text sizes - [ ] Text sizes
- [ ] Title pages - [ ] Title pages
### Long Term
- Rewrite of the whole parsing process
- Custom Elements via templates
## License
This project is licensed under GPL 3.0. See LICENSE for more information.

@ -188,6 +188,7 @@ pub enum Inline {
CharacterCode(CharacterCode), CharacterCode(CharacterCode),
LineBreak, LineBreak,
Arrow(Arrow), Arrow(Arrow),
Anchor(Anchor),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

@ -33,6 +33,7 @@ pub(crate) const L_BRACE: char = '}';
pub(crate) const PERCENT: char = '%'; pub(crate) const PERCENT: char = '%';
pub(crate) const COMMA: char = ','; pub(crate) const COMMA: char = ',';
pub(crate) const MATH: char = '$'; pub(crate) const MATH: char = '$';
pub(crate) const DOLLAR: char = '$';
pub(crate) const AMPERSAND: char = '&'; pub(crate) const AMPERSAND: char = '&';
pub(crate) const QUESTION_MARK: char = '?'; pub(crate) const QUESTION_MARK: char = '?';
@ -82,6 +83,18 @@ pub(crate) const CHARACTER_STOP: char = SEMICOLON;
pub(crate) const GLOSSARY_REF_START: char = TILDE; pub(crate) const GLOSSARY_REF_START: char = TILDE;
// Reference Anchors
pub(crate) const ANCHOR_START: &'static [char] = &[R_BRACKET, QUESTION_MARK];
pub(crate) const ANCHOR_STOP: char = L_BRACKET;
// References
pub(crate) const REF_START: &'static [char] = &[R_BRACKET, DOLLAR];
pub(crate) const REF_STOP: char = L_BRACKET;
pub(crate) const REF_DESC_START: char = R_PARENTH;
pub(crate) const REF_DESC_STOP: char = L_PARENTH;
// Arrows // Arrows
pub(crate) const A_RIGHT_ARROW: &'static [char] = &['-', '-', '>']; pub(crate) const A_RIGHT_ARROW: &'static [char] = &['-', '-', '>'];
@ -130,6 +143,8 @@ pub(crate) const INLINE_SPECIAL_SEQUENCES: &'static [&'static [char]] = &[
A_RIGHT_ARROW, A_RIGHT_ARROW,
A_LEFT_ARROW, A_LEFT_ARROW,
A_LEFT_RIGHT_ARROW, A_LEFT_RIGHT_ARROW,
ANCHOR_START,
REF_START,
]; ];
pub(crate) const LIST_SPECIAL_CHARS: [char; 14] = [ pub(crate) const LIST_SPECIAL_CHARS: [char; 14] = [

@ -62,6 +62,7 @@ impl ToHtml for Inline {
Inline::CharacterCode(code) => code.to_html(writer), Inline::CharacterCode(code) => code.to_html(writer),
Inline::GlossaryReference(gloss) => gloss.lock().to_html(writer), Inline::GlossaryReference(gloss) => gloss.lock().to_html(writer),
Inline::Arrow(a) => a.to_html(writer), Inline::Arrow(a) => a.to_html(writer),
Inline::Anchor(a) => a.to_html(writer),
} }
} }
} }

@ -39,6 +39,7 @@ pub(crate) trait ParseInline {
fn parse_template(&mut self) -> ParseResult<Template>; fn parse_template(&mut self) -> ParseResult<Template>;
fn parse_character_code(&mut self) -> ParseResult<CharacterCode>; fn parse_character_code(&mut self) -> ParseResult<CharacterCode>;
fn parse_arrow(&mut self) -> ParseResult<Arrow>; fn parse_arrow(&mut self) -> ParseResult<Arrow>;
fn parse_anchor(&mut self) -> ParseResult<Anchor>;
} }
impl ParseInline for Parser { impl ParseInline for Parser {
@ -127,6 +128,9 @@ impl ParseInline for Parser {
} else if let Ok(arrow) = self.parse_arrow() { } else if let Ok(arrow) = self.parse_arrow() {
log::trace!("Inline::Arrow {:?}", arrow); log::trace!("Inline::Arrow {:?}", arrow);
Ok(Inline::Arrow(arrow)) Ok(Inline::Arrow(arrow))
} else if let Ok(anchor) = self.parse_anchor() {
log::trace!("Inline::Anchor {:?}", anchor);
Ok(Inline::Anchor(anchor))
} else { } else {
let plain = self.parse_plain()?; let plain = self.parse_plain()?;
log::trace!("Inline::Plain {}", plain.value); log::trace!("Inline::Plain {}", plain.value);
@ -680,4 +684,22 @@ impl ParseInline for Parser {
Err(self.ctm.err().into()) Err(self.ctm.err().into())
} }
} }
/// Parses an anchor elements
fn parse_anchor(&mut self) -> ParseResult<Anchor> {
let start_index = self.ctm.get_index();
self.ctm.assert_sequence(&ANCHOR_START, Some(start_index))?;
self.ctm.seek_one()?;
let key = self.ctm.get_string_until_any_or_rewind(
&[ANCHOR_STOP],
&INLINE_WHITESPACE,
start_index,
)?;
self.ctm.try_seek();
Ok(Anchor {
inner: Box::new(Line::Text(TextLine::new())),
key,
})
}
} }

Loading…
Cancel
Save