diff --git a/fs/html.go b/fs/html.go index f64059d..1b997d8 100644 --- a/fs/html.go +++ b/fs/html.go @@ -1,24 +1,16 @@ package fs import ( + "bytes" "fmt" "io/ioutil" "log" - "github.com/gomarkdown/markdown" - "github.com/gomarkdown/markdown/html" - "github.com/gomarkdown/markdown/parser" + "gopkg.in/russross/blackfriday.v2" ) -func markdownToHtml(md string) string { - extensions := parser.CommonExtensions | parser.AutoHeadingIDs - p := parser.NewWithExtensions(extensions) - - htmlFlags := html.CommonFlags | html.HrefTargetBlank - opts := html.RendererOptions{Flags: htmlFlags} - renderer := html.NewRenderer(opts) - - return string(markdown.ToHTML([]byte(md), p, renderer)) +func markdownToHtml(md []byte) string { + return string(blackfriday.Run(NormalizeEOL(md))) } func (h *Hypha) asHtml() (string, error) { @@ -41,7 +33,7 @@ func (h *Hypha) asHtml() (string, error) { // TODO: support mycorrhiza extensions like transclusion. switch rev.TextMime { case "text/markdown": - html := markdown.ToHTML(contents, nil, nil) + html := markdownToHtml(contents) ret += string(html) default: ret += fmt.Sprintf(`
%s`, contents) @@ -52,3 +44,43 @@ func (h *Hypha) asHtml() (string, error) { return ret, nil } + +// NormalizeEOL will convert Windows (CRLF) and Mac (CR) EOLs to UNIX (LF) +// Code taken from here: https://github.com/go-gitea/gitea/blob/dc8036dcc680abab52b342d18181a5ee42f40318/modules/util/util.go#L68-L102 +// Gitea has MIT License +// +// We use it because md parser does not handle CRLF correctly. I don't know why, but CRLF appears sometimes. +func NormalizeEOL(input []byte) []byte { + var right, left, pos int + if right = bytes.IndexByte(input, '\r'); right == -1 { + return input + } + length := len(input) + tmp := make([]byte, length) + + // We know that left < length because otherwise right would be -1 from IndexByte. + copy(tmp[pos:pos+right], input[left:left+right]) + pos += right + tmp[pos] = '\n' + left += right + 1 + pos++ + + for left < length { + if input[left] == '\n' { + left++ + } + + right = bytes.IndexByte(input[left:], '\r') + if right == -1 { + copy(tmp[pos:], input[left:]) + pos += length - left + break + } + copy(tmp[pos:pos+right], input[left:left+right]) + pos += right + tmp[pos] = '\n' + left += right + 1 + pos++ + } + return tmp[:pos] +} diff --git a/fs/hypha.go b/fs/hypha.go index 3ac7ed0..fb401d5 100644 --- a/fs/hypha.go +++ b/fs/hypha.go @@ -154,7 +154,7 @@ func (h *Hypha) ActionZen(w http.ResponseWriter) *Hypha { // ActionView is used with `?action=view` or no action at all. // It renders the page, the layout and everything else. -func (h *Hypha) ActionView(w http.ResponseWriter, renderExists, renderNotExists func(string, string) string) *Hypha { +func (h *Hypha) ActionView(w http.ResponseWriter, renderExists, renderNotExists func(string, string) []byte) *Hypha { var html string var err error if h.Exists { @@ -167,9 +167,9 @@ func (h *Hypha) ActionView(w http.ResponseWriter, renderExists, renderNotExists w.Header().Set("Content-Type", "text/html;charset=utf-8") w.WriteHeader(http.StatusOK) if h.Exists { - w.Write([]byte(renderExists(h.FullName, html))) + w.Write(renderExists(h.FullName, html)) } else { - w.Write([]byte(renderNotExists(h.FullName, ""))) + w.Write(renderNotExists(h.FullName, "")) } return h } diff --git a/go.mod b/go.mod index b33418b..9c28679 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,13 @@ module github.com/bouncepaw/mycorrhiza go 1.14 require ( - github.com/gomarkdown/markdown v0.0.0-20200609195525-3f9352745725 github.com/gorilla/mux v1.7.4 mvdan.cc/gogrep v0.0.0-20200420132841-24e8804e5b3c // indirect ) + +require ( + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + gopkg.in/russross/blackfriday.v2 v2.0.1 +) + +replace gopkg.in/russross/blackfriday.v2 => github.com/russross/blackfriday/v2 v2.0.1 diff --git a/go.sum b/go.sum index e2617dc..6aa9421 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,10 @@ github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= diff --git a/handlers.go b/handlers.go index 0f52411..1272121 100644 --- a/handlers.go +++ b/handlers.go @@ -44,7 +44,7 @@ func HandlerEdit(w http.ResponseWriter, rq *http.Request) { h := fs.Hs.Open(vars["hypha"]).OnRevision("0") w.Header().Set("Content-Type", "text/html;charset=utf-8") w.WriteHeader(http.StatusOK) - w.Write([]byte(render.HyphaEdit(h))) + w.Write(render.HyphaEdit(h)) } func HandlerUpdate(w http.ResponseWriter, rq *http.Request) { @@ -63,6 +63,6 @@ func HandlerUpdate(w http.ResponseWriter, rq *http.Request) { if !h.Invalid { w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "text/html; charset=utf-8") - w.Write([]byte(render.HyphaUpdateOk(h))) + w.Write(render.HyphaUpdateOk(h)) } } diff --git a/render/render.go b/render/render.go index 7ff6a05..44a6d4d 100644 --- a/render/render.go +++ b/render/render.go @@ -10,74 +10,52 @@ import ( "github.com/bouncepaw/mycorrhiza/fs" ) -// EditHyphaPage returns HTML page of hypha editor. -func EditHyphaPage(name, textMime, content, tags string) string { - page := map[string]string{ - "Text": content, - "TextMime": textMime, - "Name": name, - "Tags": tags, - } - keys := map[string]string{ - "Title": fmt.Sprintf(cfg.TitleEditTemplate, name), - "Header": renderFromString(name, "Hypha/edit/header.html"), - "Sidebar": renderFromMap(page, "Hypha/edit/sidebar.html"), - } - return renderBase(renderFromMap(page, "Hypha/edit/index.html"), keys) -} - -func HyphaEdit(h *fs.Hypha) string { - page := map[string]string{ +// HyphaEdit renders hypha editor. +func HyphaEdit(h *fs.Hypha) []byte { // + hyphaData := map[string]string{ "Name": h.FullName, "Tags": h.TagsJoined(), "TextMime": h.TextMime(), "Text": h.TextContent(), } - keys := map[string]string{ - "Title": fmt.Sprintf(cfg.TitleEditTemplate, h.FullName), - "Header": renderFromString(h.FullName, "Hypha/edit/header.html"), - "Sidebar": renderFromMap(page, "Hypha/edit/sidebar.html"), - } - return renderBase(renderFromMap(page, "Hypha/edit/index.html"), keys) + return layout("edit/index"). + withMap(hyphaData). + wrapInBase(map[string]string{ + "Title": fmt.Sprintf(cfg.TitleEditTemplate, h.FullName), + "Header": layout("edit/header").withString(h.FullName).String(), + "Sidebar": layout("edit/sidebar").withMap(hyphaData).String(), + }) } -// Hypha404 returns 404 page for nonexistent page. -func Hypha404(name, _ string) string { - return HyphaGeneric(name, name, "Hypha/view/404.html") +// HyphaUpdateOk is used to inform that update was successful. +func HyphaUpdateOk(h *fs.Hypha) []byte { // + return layout("updateOk"). + withMap(map[string]string{"Name": h.FullName}). + Bytes() } -// HyphaPage returns HTML page of hypha viewer. -func HyphaPage(name, content string) string { - return HyphaGeneric(name, content, "Hypha/view/index.html") +// Hypha404 renders 404 page for nonexistent page. +func Hypha404(name, _ string) []byte { + return hyphaGeneric(name, name, "view/404") } -// HyphaGeneric is used when building renderers for all types of hypha pages -func HyphaGeneric(name string, content, templatePath string) string { - var sidebar string - if aside := renderFromMap(map[string]string{ - "Tree": fs.Hs.GetTree(name, true).AsHtml(), - }, "Hypha/view/sidebar.html"); aside != "" { - sidebar = aside - } - keys := map[string]string{ - "Title": fmt.Sprintf(cfg.TitleTemplate, name), - "Sidebar": sidebar, - } - return renderBase(renderFromString(content, templatePath), keys) +// HyphaPage renders hypha viewer. +func HyphaPage(name, content string) []byte { + return hyphaGeneric(name, content, "view/index") } -func HyphaUpdateOk(h *fs.Hypha) string { - data := map[string]string{ - "Name": h.FullName, - } - return renderFromMap(data, "updateOk.html") +// hyphaGeneric is used when building renderers for all types of hypha pages +func hyphaGeneric(name, content, templateName string) []byte { + return layout(templateName). + withString(content). + wrapInBase(map[string]string{ + "Title": fmt.Sprintf(cfg.TitleTemplate, name), + "Sidebar": hyphaTree(name), + }) } -// renderBase collects and renders page from base template -// Args: -// content: string or pre-rendered template -// keys: map with replaced standart fields -func renderBase(content string, keys map[string]string) string { +// wrapInBase is used to wrap layouts in things that are present on all pages. +func (lyt *Layout) wrapInBase(keys map[string]string) []byte { page := map[string]string{ "Title": cfg.SiteTitle, "Main": "", @@ -86,36 +64,67 @@ func renderBase(content string, keys map[string]string) string { for key, val := range keys { page[key] = val } - page["Main"] = content - return renderFromMap(page, "base.html") + page["Main"] = lyt.String() + return layout("base").withMap(page).Bytes() } -// renderFromMap applies `data` map to template in `templatePath` and returns the result. -func renderFromMap(data map[string]string, templatePath string) string { - hyphPath := path.Join(cfg.TemplatesDir, cfg.Theme, templatePath) - h := fs.Hs.Open(hyphPath).OnRevision("0") - tmpl, err := template.ParseFiles(h.TextPath()) - if err != nil { - return err.Error() - } - buf := new(bytes.Buffer) - if err := tmpl.Execute(buf, data); err != nil { - return err.Error() - } - return buf.String() +func hyphaTree(name string) string { + return layout("view/sidebar"). + withMap(map[string]string{"Tree": fs.Hs.GetTree(name, true).AsHtml()}). + String() } -// renderFromMap applies `data` string to template in `templatePath` and returns the result. -func renderFromString(data string, templatePath string) string { - hyphPath := path.Join(cfg.TemplatesDir, cfg.Theme, templatePath) - h := fs.Hs.Open(hyphPath).OnRevision("0") +type Layout struct { + tmpl *template.Template + buf *bytes.Buffer + invalid bool + err error +} + +func layout(name string) *Layout { + h := fs.Hs.Open(path.Join(cfg.TemplatesDir, cfg.Theme, name+".html")).OnRevision("0") + if h.Invalid { + return &Layout{nil, nil, true, h.Err} + } tmpl, err := template.ParseFiles(h.TextPath()) if err != nil { - return err.Error() + return &Layout{nil, nil, true, err} } - buf := new(bytes.Buffer) - if err := tmpl.Execute(buf, data); err != nil { - return err.Error() - } - return buf.String() + return &Layout{tmpl, new(bytes.Buffer), false, nil} +} + +func (lyt *Layout) withString(data string) *Layout { + if lyt.invalid { + return lyt + } + if err := lyt.tmpl.Execute(lyt.buf, data); err != nil { + lyt.invalid = true + lyt.err = err + } + return lyt +} + +func (lyt *Layout) withMap(data map[string]string) *Layout { + if lyt.invalid { + return lyt + } + if err := lyt.tmpl.Execute(lyt.buf, data); err != nil { + lyt.invalid = true + lyt.err = err + } + return lyt +} + +func (lyt *Layout) Bytes() []byte { + if lyt.invalid { + return []byte(lyt.err.Error()) + } + return lyt.buf.Bytes() +} + +func (lyt *Layout) String() string { + if lyt.invalid { + return lyt.err.Error() + } + return lyt.buf.String() } diff --git a/w/m/Fruit/4.markdown b/w/m/Fruit/4.markdown new file mode 100644 index 0000000..3d7f71e --- /dev/null +++ b/w/m/Fruit/4.markdown @@ -0,0 +1,5 @@ +According to real *scientists*, fruit is a type of fetus. Most of them are tasty and cool, though some of them are really sour and depressing. Be careful when choosing fruit. Best ones are: + +* [Apple](./Apple) +* [Pear](/Pear) + \ No newline at end of file diff --git a/w/m/Fruit/5.markdown b/w/m/Fruit/5.markdown new file mode 100644 index 0000000..3ba13b4 --- /dev/null +++ b/w/m/Fruit/5.markdown @@ -0,0 +1,10 @@ +According to real *scientists*, fruit is a type of fetus. Most of them are tasty and cool, though some of them are really sour and depressing. Be careful when choosing fruit. Best ones are: + +- [Apple](Fruit/Apple) +- [Pear](Fruit/Pear) + +``` +фрукты полезны для здоровья!! +``` + + diff --git a/w/m/Fruit/meta.json b/w/m/Fruit/meta.json index b4d4797..46c5090 100644 --- a/w/m/Fruit/meta.json +++ b/w/m/Fruit/meta.json @@ -40,6 +40,32 @@ "binary_mime": "", "text_name": "3.markdown", "binary_name": "" + }, + "4": { + "tags": [ + "" + ], + "name": "Fruit", + "comment": "Update Fruit", + "author": "", + "time": 1593338963, + "text_mime": "text/markdown", + "binary_mime": "", + "text_name": "4.markdown", + "binary_name": "" + }, + "5": { + "tags": [ + "" + ], + "name": "Fruit", + "comment": "Update Fruit", + "author": "", + "time": 1593339050, + "text_mime": "text/markdown", + "binary_mime": "", + "text_name": "5.markdown", + "binary_name": "" } }, "Invalid": false, diff --git a/w/m/Templates/default-dark/Hypha/edit/header.html/meta.json b/w/m/Templates/default-dark/Hypha/edit/header.html/meta.json deleted file mode 100644 index cf72dcd..0000000 --- a/w/m/Templates/default-dark/Hypha/edit/header.html/meta.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "views": 0, - "deleted": false, - "revisions": { - "1": { - "tags": null, - "name": "header.html", - "comment": "Create Templates/default-dark/Hypha/edit/header.html", - "author": "", - "time": 1592996801, - "text_mime": "text/html", - "binary_mime": "", - "text_name": "1.html", - "binary_name": "" - } - } -} diff --git a/w/m/Templates/default-dark/Hypha/edit/index.html/1.html b/w/m/Templates/default-dark/Hypha/edit/index.html/1.html deleted file mode 100644 index a102c1e..0000000 --- a/w/m/Templates/default-dark/Hypha/edit/index.html/1.html +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/w/m/Templates/default-dark/Hypha/edit/index.html/meta.json b/w/m/Templates/default-dark/Hypha/edit/index.html/meta.json deleted file mode 100644 index 7534c5d..0000000 --- a/w/m/Templates/default-dark/Hypha/edit/index.html/meta.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "views": 0, - "deleted": false, - "revisions": { - "1": { - "tags": null, - "name": "index.html", - "comment": "Create Templates/default-dark/Hypha/edit/index.html", - "author": "", - "time": 1592996876, - "text_mime": "text/html", - "binary_mime": "", - "text_name": "1.html", - "binary_name": "" - } - } -} diff --git a/w/m/Templates/default-dark/Hypha/edit/sidebar.html/1.html b/w/m/Templates/default-dark/Hypha/edit/sidebar.html/1.html deleted file mode 100644 index 3f257cf..0000000 --- a/w/m/Templates/default-dark/Hypha/edit/sidebar.html/1.html +++ /dev/null @@ -1,19 +0,0 @@ -
Good types are text/markdown
and text/plain
Please make your comment helpful
- - -Tags are separated by commas, whitespace is ignored
- - -If this hypha has a file like that, the text above is meant to be a description of it
- - - - --The hypha you are trying to access does not exist yet. Why not create it? -
diff --git a/w/m/Templates/default-dark/base.html/1.html b/w/m/Templates/default-dark/base.html/1.html deleted file mode 100644 index b5dbe7a..0000000 --- a/w/m/Templates/default-dark/base.html/1.html +++ /dev/null @@ -1,30 +0,0 @@ - - -Saved successfully. Go back
- - diff --git a/w/m/Templates/default-dark/updateOk.html/meta.json b/w/m/Templates/default-dark/updateOk.html/meta.json deleted file mode 100644 index 4c7c3c3..0000000 --- a/w/m/Templates/default-dark/updateOk.html/meta.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "views": 0, - "deleted": false, - "revisions": { - "1": { - "tags": null, - "name": "updateOk.html", - "comment": "Create Templates/default-dark/updateOk.html", - "author": "", - "time": 1592996644, - "text_mime": "text/html", - "binary_mime": "", - "text_name": "1.html", - "binary_name": "" - } - } -} diff --git a/w/m/Templates/default-light/Hypha/edit/header.html/1.html b/w/m/Templates/default-light/Hypha/edit/header.html/1.html deleted file mode 100644 index 37a4b91..0000000 --- a/w/m/Templates/default-light/Hypha/edit/header.html/1.html +++ /dev/null @@ -1 +0,0 @@ -Good types are text/markdown
and text/plain
Please make your comment helpful
- - -Tags are separated by commas, whitespace is ignored
- - -If this hypha has a file like that, the text above is meant to be a description of it
- - - - -Good types are text/markdown
and text/plain
Please make your comment helpful
+ + +Tags are separated by commas, whitespace is ignored
+ + +If this hypha has a file like that, the text above is meant to be a description of it
+ + + + +-The hypha you are trying to access does not exist yet. Why not create it? -
++The hypha you are trying to access does not exist yet. Why not create it? +
diff --git a/w/m/Templates/default-dark/Hypha/view/404.html/meta.json b/w/m/Templates/default-light/view/404.html/meta.json similarity index 100% rename from w/m/Templates/default-dark/Hypha/view/404.html/meta.json rename to w/m/Templates/default-light/view/404.html/meta.json diff --git a/w/m/Templates/default-dark/Hypha/view/index.html/1.html b/w/m/Templates/default-light/view/index.html/1.html similarity index 88% rename from w/m/Templates/default-dark/Hypha/view/index.html/1.html rename to w/m/Templates/default-light/view/index.html/1.html index f75b53a..55a25b3 100644 --- a/w/m/Templates/default-dark/Hypha/view/index.html/1.html +++ b/w/m/Templates/default-light/view/index.html/1.html @@ -1 +1 @@ -{{ . }} +{{ . }} diff --git a/w/m/Templates/default-dark/Hypha/view/index.html/meta.json b/w/m/Templates/default-light/view/index.html/meta.json similarity index 100% rename from w/m/Templates/default-dark/Hypha/view/index.html/meta.json rename to w/m/Templates/default-light/view/index.html/meta.json diff --git a/w/m/Templates/default-dark/Hypha/view/sidebar.html/1.html b/w/m/Templates/default-light/view/sidebar.html/1.html similarity index 96% rename from w/m/Templates/default-dark/Hypha/view/sidebar.html/1.html rename to w/m/Templates/default-light/view/sidebar.html/1.html index 3f751f3..7e361d4 100644 --- a/w/m/Templates/default-dark/Hypha/view/sidebar.html/1.html +++ b/w/m/Templates/default-light/view/sidebar.html/1.html @@ -1,9 +1,9 @@ - -{{ .Tree }} + +{{ .Tree }} diff --git a/w/m/Templates/default-dark/Hypha/view/sidebar.html/meta.json b/w/m/Templates/default-light/view/sidebar.html/meta.json similarity index 100% rename from w/m/Templates/default-dark/Hypha/view/sidebar.html/meta.json rename to w/m/Templates/default-light/view/sidebar.html/meta.json diff --git a/w/m/TestMd/1.markdown b/w/m/TestMd/1.markdown new file mode 100644 index 0000000..c7ff99a --- /dev/null +++ b/w/m/TestMd/1.markdown @@ -0,0 +1,232 @@ + + +# h1 Heading 8-) +## h2 Heading +### h3 Heading +#### h4 Heading +##### h5 Heading +###### h6 Heading + + +## Horizontal Rules + +___ + +--- + +*** + + +## Typographic replacements + +Enable typographer option to see result. + +(c) (C) (r) (R) (tm) (TM) (p) (P) +- + +test.. test... test..... test?..... test!.... + +!!!!!! ???? ,, -- --- + +"Smartypants, double quotes" and 'single quotes' + + +## Emphasis + +**This is bold text** + +__This is bold text__ + +*This is italic text* + +_This is italic text_ + +~~Strikethrough~~ + + +## Blockquotes + + +> Blockquotes can also be nested... +>> ...by using additional greater-than signs right next to each other... +> > > ...or with spaces between arrows. + + +## Lists + +Unordered + ++ Create a list by starting a line with `+`, `-`, or `*` ++ Sub-lists are made by indenting 2 spaces: + - Marker character change forces new list start: + * Ac tristique libero volutpat at + + Facilisis in pretium nisl aliquet + - Nulla volutpat aliquam velit ++ Very easy! + +Ordered + +1. Lorem ipsum dolor sit amet +2. Consectetur adipiscing elit +3. Integer molestie lorem at massa + + +1. You can use sequential numbers... +1. ...or keep all the numbers as `1.` + +Start numbering with offset: + +57. foo +1. bar + + +## Code + +Inline `code` + +Indented code + + // Some comments + line 1 of code + line 2 of code + line 3 of code + + +Block code "fences" + +``` +Sample text here... +``` + +Syntax highlighting + +``` js +var foo = function (bar) { + return bar++; +}; + +console.log(foo(5)); +``` + +## Tables + +| Option | Description | +| ------ | ----------- | +| data | path to data files to supply the data that will be passed into templates. | +| engine | engine to be used for processing templates. Handlebars is the default. | +| ext | extension to be used for dest files. | + +Right aligned columns + +| Option | Description | +| ------:| -----------:| +| data | path to data files to supply the data that will be passed into templates. | +| engine | engine to be used for processing templates. Handlebars is the default. | +| ext | extension to be used for dest files. | + + +## Links + +[link text](http://dev.nodeca.com) + +[link with title](http://nodeca.github.io/pica/demo/ "title text!") + +Autoconverted link https://github.com/nodeca/pica (enable linkify to see) + + +## Images + +![Minion](https://octodex.github.com/images/minion.png) +![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat") + +Like links, Images also have a footnote style syntax + +![Alt text][id] + +With a reference later in the document defining the URL location: + +[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat" + + +## Plugins + +The killer feature of `markdown-it` is very effective support of +[syntax plugins](https://www.npmjs.org/browse/keyword/markdown-it-plugin). + + +### [Emojies](https://github.com/markdown-it/markdown-it-emoji) + +> Classic markup: :wink: :crush: :cry: :tear: :laughing: :yum: +> +> Shortcuts (emoticons): :-) :-( 8-) ;) + +see [how to change output](https://github.com/markdown-it/markdown-it-emoji#change-output) with twemoji. + + +### [Subscript](https://github.com/markdown-it/markdown-it-sub) / [Superscript](https://github.com/markdown-it/markdown-it-sup) + +- 19^th^ +- H~2~O + + +### [\](https://github.com/markdown-it/markdown-it-ins) + +++Inserted text++ + + +### [\](https://github.com/markdown-it/markdown-it-mark) + +==Marked text== + + +### [Footnotes](https://github.com/markdown-it/markdown-it-footnote) + +Footnote 1 link[^first]. + +Footnote 2 link[^second]. + +Inline footnote^[Text of inline footnote] definition. + +Duplicated footnote reference[^second]. + +[^first]: Footnote **can have markup** + + and multiple paragraphs. + +[^second]: Footnote text. + + +### [Definition lists](https://github.com/markdown-it/markdown-it-deflist) + +Term 1 + +: Definition 1 +with lazy continuation. + +Term 2 with *inline markup* + +: Definition 2 + + { some code, part of Definition 2 } + + Third paragraph of definition 2. + +_Compact style:_ + +Term 1 + ~ Definition 1 + +Term 2 + ~ Definition 2a + ~ Definition 2b + + +### [Abbreviations](https://github.com/markdown-it/markdown-it-abbr) + +This is HTML abbreviation example. + +It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on. + +*[HTML]: Hyper Text Markup Language + +### [Custom containers](https://github.com/markdown-it/markdown-it-container) + diff --git a/w/m/TestMd/meta.json b/w/m/TestMd/meta.json new file mode 100644 index 0000000..16f8db7 --- /dev/null +++ b/w/m/TestMd/meta.json @@ -0,0 +1,21 @@ +{ + "views": 0, + "deleted": false, + "revisions": { + "1": { + "tags": [ + "" + ], + "name": "TestMd", + "comment": "Update TestMd", + "author": "", + "time": 1593340713, + "text_mime": "text/markdown", + "binary_mime": "", + "text_name": "1.markdown", + "binary_name": "" + } + }, + "Invalid": false, + "Err": null +} \ No newline at end of file