1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-30 05:19:57 +00:00

Revamp markdown plugin (#6528)

* Rename markdown to markdown-legacy

* Change how default renderWikiTextPragma value is displayed

To prevent out-of-sync, dynamically display the default value of
renderWikiTextPragma from the shadow tiddler instead of hard coding
the text in the "usage.tid".

* Repackage remarkable-based markdown plugin as markdown-legacy

- Rename plugin title to $:/plugins/tiddlywiki/markdown-legacy

- Add support for "text/markdown" MIME type and set that as the default
  when creating new markdown tiddlers

* Create new markdown plugin

* add support to text/markdown MIME type

* remove linkify and linkNewWindow config options

- linkify feature should be controlled by "extlink" TW parser rule;
  enabling markdown's linkify option will interfere with parsing

- remove the possibility to open external links in the same tab/window
  to match TW's behavior

* Ignore latex-parser wikirule in rednerWikiTextPragma

* Prevent camel-case link text from generating a link

* Update editions/markdowndemo

* Produce better parse tree

* Improve markdown/tiddlywiki integration

- widget block should not interrupt paragraph
- ignore tw-syntax links inside markdown-syntax links
- remove repeated renderWikiTextPragma parsing
- more efficient findNextMatch when examining tw rules

* Update user docs

* Replace includes() with indexOf() for legacy browsers
This commit is contained in:
cdruan 2023-01-14 01:49:04 -08:00 committed by GitHub
parent b5134951e5
commit 0c328a1696
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 2443 additions and 359 deletions

View File

@ -1,4 +1,7 @@
title: $:/DefaultTiddlers title: $:/DefaultTiddlers
[[HelloThere]] [[HelloThere]]
[[MarkdownExample]] $:/plugins/tiddlywiki/markdown
[[MarkdownTutorial]]
[[QuickDemo]]
[[QuickDemo Source]]

View File

@ -1,11 +1,9 @@
title: HelloThere title: HelloThere
This is a demo of TiddlyWiki5 incorporating a plugin for parsing tiddlers written in the Markdown language. The plugin uses the [[Remarkable|https://github.com/jonschlinkert/remarkable]] Markdown parser internally. The MarkdownExample tiddler below is written in Markdown. This is a demo of TiddlyWiki5 incorporating a plugin for parsing tiddlers written in the Markdown language. The plugin uses the [[markdown-it|https://github.com/markdown-it/markdown-it]] Markdown parser internally. The MarkdownTutorial tiddler below is written in Markdown.
! Installation ! Installation
To add the plugin to your own TiddlyWiki5, just drag this link to the browser window: To add the plugin to your own TiddlyWiki5, just drag this link to the browser window:
[[$:/plugins/tiddlywiki/markdown]] [[$:/plugins/tiddlywiki/markdown]]
{{$:/plugins/tiddlywiki/markdown/usage}}

View File

@ -1,4 +1,4 @@
title: MarkdownExample title: MarkdownTutorial
type: text/x-markdown type: text/x-markdown
Markdown: Basics Markdown: Basics

View File

@ -0,0 +1,220 @@
title: QuickDemo
type: text/markdown
<style>
.tc-image-loaded {
width: 35%;
}
</style>
# h1 Heading
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
____
---
****
## 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.
## Unordered List
+ 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 List
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));
```
## ~KaTeX
Equation $c = \pm\sqrt{a^2 + b^2}$ is typeset in inline mode.
Display style: $$c = \pm\sqrt{a^2 + b^2}$$
## Tables
| Attribute | Description |
| --------- | ----------- |
| multiple | select multiple files to download |
| param | parameter to be passed with the message |
| tooltip | optional tooltip text |
Aligning columns:
| Column A | Column B | Column C |
| :---- | :----: | ----: |
| is | is | is |
| left | nicely | right |
| aligned | centered | aligned |
## Links
[link text](http://google.com)
[link with title](http://nodeca.github.io/pica/demo/ "title text!")
link to tiddler [QuickDemo Source](#QuickDemo%20Source)
URL can contain spaces if enclosed in brackets `<>`: [QuickDemo Source](<#QuickDemo Source>)
## 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 reference style syntax
![Alt text][id]
with a link reference defined later in the document.
[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
## Subscript & Superscript
- 19^th^
- H~2~O
## \<ins\>
++Inserted text++
## \<mark\>
==Marked text==
## Footnotes
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
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

View File

@ -0,0 +1,5 @@
title: QuickDemo Source
<$let tiddler="QuickDemo">
<$codeblock code={{{ [<tiddler>get[text]] }}} language={{{ [<tiddler>get[type]else[text/vnd.tiddlywiki]] }}}/>
</$let>

View File

@ -1,7 +1,9 @@
{ {
"description": "Demo of the Markdown plugin", "description": "Demo of the Markdown plugin",
"plugins": [ "plugins": [
"tiddlywiki/markdown" "tiddlywiki/markdown",
"tiddlywiki/highlight",
"tiddlywiki/katex"
], ],
"themes": [ "themes": [
"tiddlywiki/vanilla", "tiddlywiki/vanilla",

View File

@ -8,4 +8,5 @@ text/html: codemirror
text/plain: codemirror text/plain: codemirror
text/vnd.tiddlywiki: codemirror text/vnd.tiddlywiki: codemirror
text/x-markdown: codemirror text/x-markdown: codemirror
text/markdown: codemirror
text/x-tiddlywiki: codemirror text/x-tiddlywiki: codemirror

View File

@ -1 +1 @@
!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../lib/codemirror")):"function"==typeof define&&define.amd?define(["../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.modeInfo=[{name:"CMake",mime:"text/x-cmake",mode:"cmake",ext:["cmake","cmake.in"],file:/^CMakeLists.txt$/},{name:"Cython",mime:"text/x-cython",mode:"python",ext:["pyx","pxd","pxi"]},{name:"CSS",mime:"text/css",mode:"css",ext:["css"]},{name:"diff",mime:"text/x-diff",mode:"diff",ext:["diff","patch"]},{name:"Embedded Javascript",mime:"application/x-ejs",mode:"htmlembedded",ext:["ejs"]},{name:"Embedded Ruby",mime:"application/x-erb",mode:"htmlembedded",ext:["erb"]},{name:"Erlang",mime:"text/x-erlang",mode:"erlang",ext:["erl"]},{name:"GitHub Flavored Markdown",mime:"text/x-gfm",mode:"gfm",file:/^(readme|contributing|history).md$/i},{name:"Go",mime:"text/x-go",mode:"go",ext:["go"]},{name:"ASP.NET",mime:"application/x-aspx",mode:"htmlembedded",ext:["aspx"],alias:["asp","aspx"]},{name:"HTML",mime:"text/html",mode:"htmlmixed",ext:["html","htm","handlebars","hbs"],alias:["xhtml"]},{name:"HTTP",mime:"message/http",mode:"http"},{name:"JavaScript",mimes:["text/javascript","text/ecmascript","application/javascript","application/x-javascript","application/ecmascript"],mode:"javascript",ext:["js"],alias:["ecmascript","js","node"]},{name:"JSON",mimes:["application/json","application/x-json"],mode:"javascript",ext:["json","map"],alias:["json5"]},{name:"JSON-LD",mime:"application/ld+json",mode:"javascript",ext:["jsonld"],alias:["jsonld"]},{name:"Lua",mime:"text/x-lua",mode:"lua",ext:["lua"]},{name:"Markdown",mime:"text/x-markdown",mode:"markdown",ext:["markdown","md","mkd"]},{name:"MySQL",mime:"text/x-mysql",mode:"sql"},{name:"Plain Text",mime:"text/plain",mode:"null",ext:["txt","text","conf","def","list","log"]},{name:"Python",mime:"text/x-python",mode:"python",ext:["BUILD","bzl","py","pyw"],file:/^(BUCK|BUILD)$/},{name:"SCSS",mime:"text/x-scss",mode:"css",ext:["scss"]},{name:"LaTeX",mime:"text/x-latex",mode:"stex",ext:["text","ltx","tex"],alias:["tex"]},{name:"TiddlyWiki ",mime:"text/x-tiddlywiki",mode:"tiddlywiki"}];for(var t=0;t<e.modeInfo.length;t++){var m=e.modeInfo[t];m.mimes&&(m.mime=m.mimes[0])}e.findModeByMIME=function(t){t=t.toLowerCase();for(var m=0;m<e.modeInfo.length;m++){var i=e.modeInfo[m];if(i.mime==t)return i;if(i.mimes)for(var a=0;a<i.mimes.length;a++)if(i.mimes[a]==t)return i}return/\+xml$/.test(t)?e.findModeByMIME("application/xml"):/\+json$/.test(t)?e.findModeByMIME("application/json"):void 0},e.findModeByExtension=function(t){for(var m=0;m<e.modeInfo.length;m++){var i=e.modeInfo[m];if(i.ext)for(var a=0;a<i.ext.length;a++)if(i.ext[a]==t)return i}},e.findModeByFileName=function(t){for(var m=0;m<e.modeInfo.length;m++){var i=e.modeInfo[m];if(i.file&&i.file.test(t))return i}var a=t.lastIndexOf("."),o=a>-1&&t.substring(a+1,t.length);if(o)return e.findModeByExtension(o)},e.findModeByName=function(t){t=t.toLowerCase();for(var m=0;m<e.modeInfo.length;m++){var i=e.modeInfo[m];if(i.name.toLowerCase()==t)return i;if(i.alias)for(var a=0;a<i.alias.length;a++)if(i.alias[a].toLowerCase()==t)return i}}}); !function(e){"object"==typeof exports&&"object"==typeof module?e(require("../lib/codemirror")):"function"==typeof define&&define.amd?define(["../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";e.modeInfo=[{name:"CMake",mime:"text/x-cmake",mode:"cmake",ext:["cmake","cmake.in"],file:/^CMakeLists.txt$/},{name:"Cython",mime:"text/x-cython",mode:"python",ext:["pyx","pxd","pxi"]},{name:"CSS",mime:"text/css",mode:"css",ext:["css"]},{name:"diff",mime:"text/x-diff",mode:"diff",ext:["diff","patch"]},{name:"Embedded Javascript",mime:"application/x-ejs",mode:"htmlembedded",ext:["ejs"]},{name:"Embedded Ruby",mime:"application/x-erb",mode:"htmlembedded",ext:["erb"]},{name:"Erlang",mime:"text/x-erlang",mode:"erlang",ext:["erl"]},{name:"GitHub Flavored Markdown",mime:"text/x-gfm",mode:"gfm",file:/^(readme|contributing|history).md$/i},{name:"Go",mime:"text/x-go",mode:"go",ext:["go"]},{name:"ASP.NET",mime:"application/x-aspx",mode:"htmlembedded",ext:["aspx"],alias:["asp","aspx"]},{name:"HTML",mime:"text/html",mode:"htmlmixed",ext:["html","htm","handlebars","hbs"],alias:["xhtml"]},{name:"HTTP",mime:"message/http",mode:"http"},{name:"JavaScript",mimes:["text/javascript","text/ecmascript","application/javascript","application/x-javascript","application/ecmascript"],mode:"javascript",ext:["js"],alias:["ecmascript","js","node"]},{name:"JSON",mimes:["application/json","application/x-json"],mode:"javascript",ext:["json","map"],alias:["json5"]},{name:"JSON-LD",mime:"application/ld+json",mode:"javascript",ext:["jsonld"],alias:["jsonld"]},{name:"Lua",mime:"text/x-lua",mode:"lua",ext:["lua"]},{name:"Markdown",mimes:["text/x-markdown","text/markdown"],mode:"markdown",ext:["markdown","md","mkd"]},{name:"MySQL",mime:"text/x-mysql",mode:"sql"},{name:"Plain Text",mime:"text/plain",mode:"null",ext:["txt","text","conf","def","list","log"]},{name:"Python",mime:"text/x-python",mode:"python",ext:["BUILD","bzl","py","pyw"],file:/^(BUCK|BUILD)$/},{name:"SCSS",mime:"text/x-scss",mode:"css",ext:["scss"]},{name:"LaTeX",mime:"text/x-latex",mode:"stex",ext:["text","ltx","tex"],alias:["tex"]},{name:"TiddlyWiki ",mime:"text/x-tiddlywiki",mode:"tiddlywiki"}];for(var t=0;t<e.modeInfo.length;t++){var m=e.modeInfo[t];m.mimes&&(m.mime=m.mimes[0])}e.findModeByMIME=function(t){t=t.toLowerCase();for(var m=0;m<e.modeInfo.length;m++){var i=e.modeInfo[m];if(i.mime==t)return i;if(i.mimes)for(var a=0;a<i.mimes.length;a++)if(i.mimes[a]==t)return i}return/\+xml$/.test(t)?e.findModeByMIME("application/xml"):/\+json$/.test(t)?e.findModeByMIME("application/json"):void 0},e.findModeByExtension=function(t){for(var m=0;m<e.modeInfo.length;m++){var i=e.modeInfo[m];if(i.ext)for(var a=0;a<i.ext.length;a++)if(i.ext[a]==t)return i}},e.findModeByFileName=function(t){for(var m=0;m<e.modeInfo.length;m++){var i=e.modeInfo[m];if(i.file&&i.file.test(t))return i}var a=t.lastIndexOf("."),o=a>-1&&t.substring(a+1,t.length);if(o)return e.findModeByExtension(o)},e.findModeByName=function(t){t=t.toLowerCase();for(var m=0;m<e.modeInfo.length;m++){var i=e.modeInfo[m];if(i.name.toLowerCase()==t)return i;if(i.alias)for(var a=0;a<i.alias.length;a++)if(i.alias[a].toLowerCase()==t)return i}}});

View File

@ -6,3 +6,4 @@ text/css: css
text/html: html text/html: html
image/svg+xml: xml image/svg+xml: xml
text/x-markdown: markdown text/x-markdown: markdown
text/markdown: markdown

View File

@ -6,3 +6,4 @@ text/css: css
text/html: html text/html: html
image/svg+xml: xml image/svg+xml: xml
text/x-markdown: markdown text/x-markdown: markdown
text/markdown: markdown

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/bold
list-after: $:/core/ui/EditorToolbar/bold
tags: $:/tags/EditorToolbar
icon: $:/core/images/bold
caption: {{$:/language/Buttons/Bold/Caption}} (Markdown)
description: {{$:/language/Buttons/Bold/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((bold))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="wrap-selection"
prefix="**"
suffix="**"
/>

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/heading-1
list-after: $:/core/ui/EditorToolbar/heading-1
tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-1
caption: {{$:/language/Buttons/Heading1/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading1/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-1))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="prefix-lines"
character="#"
count="1"
/>

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/heading-2
list-after: $:/core/ui/EditorToolbar/heading-2
tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-2
caption: {{$:/language/Buttons/Heading2/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading2/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-2))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="prefix-lines"
character="#"
count="2"
/>

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/heading-3
list-after: $:/core/ui/EditorToolbar/heading-3
tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-3
caption: {{$:/language/Buttons/Heading3/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading3/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-3))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="prefix-lines"
character="#"
count="3"
/>

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/heading-4
list-after: $:/core/ui/EditorToolbar/heading-4
tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-4
caption: {{$:/language/Buttons/Heading4/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading4/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-4))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="prefix-lines"
character="#"
count="4"
/>

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/heading-5
list-after: $:/core/ui/EditorToolbar/heading-5
tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-5
caption: {{$:/language/Buttons/Heading5/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading5/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-5))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="prefix-lines"
character="#"
count="5"
/>

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/heading-6
list-after: $:/core/ui/EditorToolbar/heading-6
tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-6
caption: {{$:/language/Buttons/Heading6/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading6/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-6))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="prefix-lines"
character="#"
count="6"
/>

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/italic
list-after: $:/core/ui/EditorToolbar/italic
tags: $:/tags/EditorToolbar
icon: $:/core/images/italic
caption: {{$:/language/Buttons/Italic/Caption}} (Markdown)
description: {{$:/language/Buttons/Italic/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((italic))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="wrap-selection"
prefix="*"
suffix="*"
/>

View File

@ -0,0 +1,73 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/link-dropdown
\define lingo-base() $:/language/Buttons/Link/
\define add-link-actions()
\whitespace trim
<$action-sendmessage $message="tm-edit-text-operation" $param="make-markdown-link" text={{$(linkTiddler)$}} />
<$action-deletetiddler $filter="[<dropdown-state>] [<searchTiddler>] [<linkTiddler>] [<storeTitle>] [<searchListState>]"/>
\end
\define get-focus-selector() [data-tiddler-title="$(cssEscapedTitle)$"] .tc-create-wikitext-link input
\define cancel-search-actions-inner()
<$set name="userInput" value={{{ [<storeTitle>get[text]] }}}><$list filter="[<searchTiddler>get[text]!match<userInput>]" emptyMessage="<$action-deletetiddler $filter='[<searchTiddler>] [<linkTiddler>] [<storeTitle>] [<searchListState>]'/>"><$action-setfield $tiddler=<<searchTiddler>> text=<<userInput>>/><$action-setfield $tiddler=<<refreshTitle>> text="yes"/></$list></$set>
\end
\define cancel-search-actions() <$list filter="[<storeTitle>!has[text]] +[<searchTiddler>!has[text]]" emptyMessage="<<cancel-search-actions-inner>>"><$action-sendmessage $message="tm-edit-text-operation" $param="focus-editor"/></$list>
\define external-link()
\whitespace trim
<$button class="tc-btn-invisible" style="width: auto; display: inline-block; background-colour: inherit;" actions=<<add-link-actions>>>
{{$:/core/images/chevron-right}}
</$button>
\end
\define set-next-input-tab(beforeafter:"after") <$macrocall $name="change-input-tab" stateTitle="$:/state/tab/search-results/sidebar" tag="$:/tags/SearchResults" beforeafter="$beforeafter$" defaultState={{$:/config/SearchResults/Default}} actions="<$action-setfield $tiddler='$:/state/search/currentTab' text=<<nextTab>>/>"/>
\define body(config-title)
\whitespace trim
''<<lingo Hint>>''
<$vars searchTiddler="""$config-title$/search""" linkTiddler="""$config-title$/link""" linktext="" searchListState=<<qualify "$:/temp/link-search/selected-item">> refreshTitle=<<qualify "$:/temp/link-search/refresh">> storeTitle=<<qualify "$:/temp/link-search/input">>>
<$vars linkTiddler=<<searchTiddler>>>
<$keyboard key="((input-tab-right))" actions=<<set-next-input-tab>>>
<$keyboard key="((input-tab-left))" actions=<<set-next-input-tab "before">> class="tc-create-wikitext-link">
<$macrocall $name="keyboard-driven-input" tiddler=<<searchTiddler>> storeTitle=<<storeTitle>>
selectionStateTitle=<<searchListState>> refreshTitle=<<refreshTitle>> type="search" filterMinLength="1"
tag="input" focus="true" class="tc-popup-handle" inputCancelActions=<<cancel-search-actions>>
inputAcceptActions=<<add-link-actions>> placeholder={{$:/language/Search/Search}} default=""
configTiddlerFilter="[[$:/state/search/currentTab]!is[missing]get[text]] ~[{$:/config/SearchResults/Default}]" />
</$keyboard>
</$keyboard>
&#32;
<$reveal tag="span" state=<<storeTitle>> type="nomatch" text="">
<<external-link>>
&#32;
<$button class="tc-btn-invisible" style="width: auto; display: inline-block; background-colour: inherit;">
<<cancel-search-actions>><$set name="cssEscapedTitle" value={{{ [<storyTiddler>escapecss[]] }}}><$action-sendmessage $message="tm-focus-selector" $param=<<get-focus-selector>>/></$set>
{{$:/core/images/close-button}}
</$button>
</$reveal>
</$vars>
<$reveal tag="div" state=<<storeTitle>> type="nomatch" text="">
<$linkcatcher actions=<<add-link-actions>> to=<<linkTiddler>>>
<$vars userInput={{{ [<storeTitle>get[text]] }}} configTiddler={{{ [[$:/state/search/currentTab]!is[missing]get[text]] ~[{$:/config/SearchResults/Default}] }}}>
{{$:/core/ui/SearchResults}}
</$vars>
</$linkcatcher>
</$reveal>
</$vars>
\end
<$macrocall $name="body" config-title=<<qualify "$:/state/Link/">>/>

View File

@ -0,0 +1,11 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/link
list-after: $:/core/ui/EditorToolbar/link
tags: $:/tags/EditorToolbar
icon: $:/core/images/link
caption: {{$:/language/Buttons/Link/Caption}}
description: {{$:/language/Buttons/Link/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
button-classes: tc-text-editor-toolbar-item-start-group
shortcuts: ((link))
dropdown: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/link-dropdown

View File

@ -0,0 +1,15 @@
caption: {{$:/language/Buttons/Linkify/Caption}} (Markdown)
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
description: {{$:/language/Buttons/Linkify/Hint}}
icon: $:/plugins/tiddlywiki/markdown-legacy/images/markdown-linkify
list-after: $:/core/ui/EditorToolbar/linkify
shortcuts: ((linkify))
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/linkify
tags: $:/tags/EditorToolbar
<$action-sendmessage
$message="tm-edit-text-operation"
$param="wrap-selection"
prefix="["
suffix="]()"
/>

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/list-bullet
list-after: $:/core/ui/EditorToolbar/list-bullet
tags: $:/tags/EditorToolbar
icon: $:/core/images/list-bullet
caption: {{$:/language/Buttons/ListBullet/Caption}} (Markdown)
description: {{$:/language/Buttons/ListBullet/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((list-bullet))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="prefix-lines"
character="*"
count="1"
/>

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/list-number
list-after: $:/core/ui/EditorToolbar/list-number
tags: $:/tags/EditorToolbar
icon: $:/core/images/list-number
caption: {{$:/language/Buttons/ListNumber/Caption}} (Markdown)
description: {{$:/language/Buttons/ListNumber/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((list-number))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="prefix-lines"
character="1."
count="1"
/>

View File

@ -0,0 +1,17 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/mono-block
list-after: $:/core/ui/EditorToolbar/mono-block
tags: $:/tags/EditorToolbar
icon: $:/core/images/mono-block
caption: {{$:/language/Buttons/MonoBlock/Caption}} (Markdown)
description: {{$:/language/Buttons/MonoBlock/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
button-classes: tc-text-editor-toolbar-item-start-group
shortcuts: ((mono-block))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="wrap-lines"
prefix="
```"
suffix="```"
/>

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/mono-line
list-after: $:/core/ui/EditorToolbar/mono-line
tags: $:/tags/EditorToolbar
icon: $:/core/images/mono-line
caption: {{$:/language/Buttons/MonoLine/Caption}} (Markdown)
description: {{$:/language/Buttons/MonoLine/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((mono-line))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="wrap-selection"
prefix="`"
suffix="`"
/>

View File

@ -0,0 +1,15 @@
title: $:/plugins/tiddlywiki/markdown-legacy/EditorToolbar/quote
list-after: $:/core/ui/EditorToolbar/quote
tags: $:/tags/EditorToolbar
icon: $:/core/images/quote
caption: {{$:/language/Buttons/Quote/Caption}} (Markdown)
description: {{$:/language/Buttons/Quote/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((quote))
<$action-sendmessage
$message="tm-edit-text-operation"
$param="prefix-lines"
character=">"
count="1"
/>

View File

@ -0,0 +1,8 @@
title: $:/plugins/tiddlywiki/markdown-legacy/KeyboardShortcuts/new-markdown-tiddler
tags: $:/tags/KeyboardShortcut
key: ((new-markdown-tiddler))
\whitespace trim
<$navigator story="$:/StoryList" history="$:/HistoryList" openLinkFromInsideRiver={{$:/config/Navigation/openLinkFromInsideRiver}} openLinkFromOutsideRiver={{$:/config/Navigation/openLinkFromOutsideRiver}} relinkOnRename={{$:/config/RelinkOnRename}}>
<$action-sendmessage $message="tm-new-tiddler" type="text/markdown"/>
</$navigator>

View File

@ -0,0 +1,5 @@
title: $:/config/
ShortcutInfo/new-markdown-tiddler: {{$:/language/Buttons/NewMarkdown/Hint}}
shortcuts-mac/new-markdown-tiddler: ctrl-M
shortcuts-not-mac/new-markdown-tiddler: alt-M

View File

@ -0,0 +1,4 @@
title: $:/language/Docs/Types/text/markdown
description: Markdown
name: text/markdown
group: Text

View File

@ -0,0 +1,37 @@
/*\
title: $:/plugins/tiddlywiki/markdown-legacy/editor-operations/make-markdown-link.js
type: application/javascript
module-type: texteditoroperation
Text editor operation to make a markdown link
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports["make-markdown-link"] = function(event,operation) {
if(operation.selection) {
if(event.paramObject.text.indexOf("://") !== -1) {
operation.replacement = "[" + operation.selection + "](" + event.paramObject.text + ")";
} else {
operation.replacement = "[" + operation.selection + "](#" + event.paramObject.text.replaceAll(" ", "%20") + ")";
}
operation.cutStart = operation.selStart;
operation.cutEnd = operation.selEnd;
} else {
if(event.paramObject.text.indexOf("://") !== -1) {
operation.replacement = "<" + event.paramObject.text + ">";
} else {
operation.replacement = "[](#" + event.paramObject.text.replaceAll(" ", "%20") + ")";
}
operation.cutStart = operation.selStart;
operation.cutEnd = operation.selEnd;
}
operation.newSelStart = operation.selStart + operation.replacement.length;
operation.newSelEnd = operation.newSelStart;
};
})();

View File

@ -0,0 +1,36 @@
{
"tiddlers": [
{
"file": "remarkable.js",
"fields": {
"type": "application/javascript",
"title": "$:/plugins/tiddlywiki/markdown-legacy/remarkable.js",
"module-type": "library"
}
},
{
"file": "remarkable-license.txt",
"fields": {
"type": "text/plain",
"title": "$:/plugins/tiddlywiki/markdown-legacy/remarkable-license"
}
},
{
"file": "remarkable-katex.min.js",
"fields": {
"type": "application/javascript",
"title": "$:/plugins/tiddlywiki/markdown-legacy/remarkable-katex.js",
"module-type": "library"
},
"prefix": "(function(realRequire) {var require = function(m) {if(m===\"katex\"){m = \"$:/plugins/tiddlywiki/katex/katex.min.js\"};return realRequire(m);};",
"suffix": "})(require);\n"
},
{
"file": "remarkable-katex-license.txt",
"fields": {
"type": "text/plain",
"title": "$:/plugins/tiddlywiki/markdown-legacy/remarkable-katex-license"
}
}
]
}

View File

@ -0,0 +1,6 @@
title: $:/plugins/tiddlywiki/markdown-legacy/images/markdown-linkify
tags: $:/tags/Image
<svg width="22pt" height="22pt" class="tc-markdown-linkify-button tc-image-button" viewBox="0 0 128 128">
<path d="M17.031185,32.1989189 L9.04781705,32.1989189 L9.04781705,97.1303119 L17.031185,97.1303119 L17.031185,104.049231 L0,104.049231 L0,25.28 L17.031185,25.28 L17.031185,32.1989189 Z M93.6716009,24.75 C90.4007675,30.8326023 88.0193713,37.1590826 86.5274123,43.7294408 C85.0354532,50.299799 84.2894737,56.9705775 84.2894737,63.7417763 C84.2894737,70.6277412 85.0211075,77.3702485 86.484375,83.9692982 C87.9476425,90.568348 90.314693,96.9952485 93.5855263,103.25 L93.5855263,103.25 L83.4287281,103.25 C79.8135965,97.3395468 77.0161732,91.1134868 75.0364583,84.5718202 C73.0567434,78.0301535 72.066886,71.3737208 72.066886,64.6025219 C72.066886,61.3890716 72.3107639,58.017818 72.7985197,54.488761 C73.2862756,50.9597039 74.0035636,47.4449927 74.9503838,43.9446272 C75.8972039,40.4442617 77.0735563,37.0586623 78.4794408,33.7878289 C79.8853253,30.5169956 81.5350877,27.504386 83.4287281,24.75 L83.4287281,24.75 Z M116.638158,24.75 C120.253289,30.6604532 123.050713,36.9152047 125.030428,43.5142544 C127.010143,50.1133041 128,56.7984284 128,63.5696272 C128,66.7830775 127.770468,70.1543311 127.311404,73.6833882 C126.852339,77.2124452 126.149397,80.7128107 125.202577,84.1844846 C124.255757,87.6561586 123.065058,91.0274123 121.630482,94.2982456 C120.195906,97.5690789 118.531798,100.552997 116.638158,103.25 L116.638158,103.25 L106.48136,103.25 C109.637427,97.1673977 111.975786,90.8696089 113.496436,84.3566338 C115.017087,77.8436586 115.777412,71.2015716 115.777412,64.4303728 C115.777412,57.5444079 115.031433,50.7732091 113.539474,44.1167763 C112.047515,37.4603436 109.723501,31.0047515 106.567434,24.75 L106.567434,24.75 Z M37.1101871,44.1061384 L37.1101871,56.702119 L49.0852391,52.799139 L51.3915454,59.8954661 L39.3277893,63.798446 L46.956341,74.1768244 L40.8357588,78.6120289 L33.2072072,68.1449464 L25.7560638,78.3459166 L19.8128898,73.8220081 L27.4414414,63.798446 L15.2889813,59.6293539 L17.5952876,52.5330268 L29.6590437,56.702119 L29.6590437,44.1061384 L37.1101871,44.1061384 Z M49.6493416,97.1303119 L57.6327096,97.1303119 L57.6327096,32.1989189 L49.6493416,32.1989189 L49.6493416,25.28 L66.6805267,25.28 L66.6805267,104.049231 L49.6493416,104.049231 L49.6493416,97.1303119 Z"></path>
</svg>

View File

@ -0,0 +1,10 @@
title: $:/plugins/tiddlywiki/markdown-legacy/images/new-markdown-button
tags: $:/tags/Image
<svg class="tc-image-new-markdown-button tc-image-button" viewBox="0 0 128 128" width="22pt" height="22pt">
<g fill-rule="evenodd">
<rect x="80" y="96" width="48" height="16" rx="8"></rect>
<rect x="96" y="80" width="16" height="48" rx="8"></rect>
<path d="M3.23876972,39.5396716 C3.23876972,35.9653274 6.13586353,33.0691646 9.7141757,33.0691646 L98.1283744,33.0691646 C101.706101,33.0691646 104.60378,35.9646626 104.60378,39.5396716 L104.60378,84.8296213 C104.60378,88.4039654 101.706687,91.3001282 98.1283744,91.3001282 L9.7141757,91.3001282 C6.13644944,91.3001282 3.23876972,88.4046302 3.23876972,84.8296213 L3.23876972,39.5396716 L3.23876972,39.5396716 Z M-2.15298617,39.5396716 L-2.15298617,84.8296213 C-2.15298617,91.3833243 3.15957363,96.6918841 9.7141757,96.6918841 L98.1283744,96.6918841 C104.684083,96.6918841 109.995536,91.382138 109.995536,84.8296213 L109.995536,39.5396716 C109.995536,32.9859686 104.682977,27.6774087 98.1283744,27.6774087 L9.7141757,27.6774087 C3.15846686,27.6774087 -2.15298617,32.9871549 -2.15298617,39.5396716 Z M14.0222815,80.5166164 L14.0222815,43.8526764 L24.8057933,43.8526764 L35.589305,57.3320661 L46.3728168,43.8526764 L57.1563286,43.8526764 L57.1563286,80.5166164 L46.3728168,80.5166164 L46.3728168,59.4887685 L35.589305,72.9681582 L24.8057933,59.4887685 L24.8057933,80.5166164 L14.0222815,80.5166164 Z M81.4192301,80.5166164 L65.2439624,62.723822 L76.0274742,62.723822 L76.0274742,43.8526764 L86.810986,43.8526764 L86.810986,62.723822 L97.5944978,62.723822 L81.4192301,80.5166164 Z"transform="translate(53.921275, 62.184646) rotate(-60.000000) translate(-53.921275, -62.184646) "></path>
</g>
</svg>

View File

@ -0,0 +1,16 @@
title: $:/plugins/tiddlywiki/markdown-legacy/new-markdown-button
tags: $:/tags/PageControls
caption: {{$:/plugins/tiddlywiki/markdown-legacy/images/new-markdown-button}} {{$:/language/Buttons/NewMarkdown/Caption}}
description: {{$:/language/Buttons/NewMarkdown/Hint}}
list-after: $:/core/ui/Buttons/new-tiddler
\whitespace trim
<$button tooltip={{$:/language/Buttons/NewMarkdown/Hint}} aria-label={{$:/language/Buttons/NewMarkdown/Caption}} class=<<tv-config-toolbar-class>>>
<$action-sendmessage $message="tm-new-tiddler" type="text/markdown"/>
<$list filter="[<tv-config-toolbar-icons>match[yes]]">
{{$:/plugins/tiddlywiki/markdown-legacy/images/new-markdown-button}}
</$list>
<$list filter="[<tv-config-toolbar-text>match[yes]]">
<span class="tc-btn-text"><$text text={{$:/language/Buttons/NewMarkdown/Caption}}/></span>
</$list>
</$button>

View File

@ -0,0 +1,6 @@
{
"title": "$:/plugins/tiddlywiki/markdown-legacy",
"name": "Markdown (Legacy)",
"description": "Markdown parser based on remarkable by Jon Schlinkert and remarkable-katex by Brad Howes",
"list": "readme usage remarkable-license remarkable-katex-license"
}

View File

@ -0,0 +1,7 @@
title: $:/plugins/tiddlywiki/markdown-legacy/readme
This is a TiddlyWiki plugin for parsing Markdown text, using the [[Remarkable|https://github.com/jonschlinkert/remarkable]] library. If the KaTeX TiddlyWiki plugin is installed, KaTeX support is enabled using the [[remarkable-katex|https://github.com/bradhowes/remarkable-katex]] Remarkable plugin.
It is completely self-contained, and doesn't need an Internet connection in order to work. It works both in the browser and under Node.js.
[[Source code|https://github.com/Jermolene/TiddlyWiki5/blob/master/plugins/tiddlywiki/markdown-legacy]]

View File

@ -1,4 +1,4 @@
title: $:/plugins/tiddlywiki/markdown/usage title: $:/plugins/tiddlywiki/markdown-legacy/usage
! Plugin Configuration ! Plugin Configuration
@ -8,7 +8,7 @@ title: $:/plugins/tiddlywiki/markdown/usage
| <code>[[linkNewWindow|$:/config/markdown/linkNewWindow]]</code>| ``true``|For external links, should clicking on them open a new window/tab automatically? | | <code>[[linkNewWindow|$:/config/markdown/linkNewWindow]]</code>| ``true``|For external links, should clicking on them open a new window/tab automatically? |
| <code>[[quotes|$:/config/markdown/quotes]]</code>| ``“”‘’``|Remarkable library config: Double + single quotes replacement pairs, when ``typographer`` enabled | | <code>[[quotes|$:/config/markdown/quotes]]</code>| ``“”‘’``|Remarkable library config: Double + single quotes replacement pairs, when ``typographer`` enabled |
| <code>[[renderWikiText|$:/config/markdown/renderWikiText]]</code>| ``true``|After Markdown is parsed, should any text elements be handed off to the ~WikiText parser for further processing? | | <code>[[renderWikiText|$:/config/markdown/renderWikiText]]</code>| ``true``|After Markdown is parsed, should any text elements be handed off to the ~WikiText parser for further processing? |
| <code>[[renderWikiTextPragma|$:/config/markdown/renderWikiTextPragma]]</code>| ``\rules only html image macrocallinline syslink transcludeinline wikilink filteredtranscludeblock macrocallblock transcludeblock``|When handing off to the ~WikiText parser, what pragma rules should it follow? | | <code>[[renderWikiTextPragma|$:/config/markdown/renderWikiTextPragma]]</code>|<code><$view tiddler="$:/plugins/tiddlywiki/markdown-legacy" subtiddler="$:/config/markdown/renderWikiTextPragma" mode="inline"/></code>|When handing off to the ~WikiText parser, what pragma rules should it follow? |
| <code>[[typographer|$:/config/markdown/typographer]]</code>| ``false``|Remarkable library config: Enable some language-neutral replacement + quotes beautification | | <code>[[typographer|$:/config/markdown/typographer]]</code>| ``false``|Remarkable library config: Enable some language-neutral replacement + quotes beautification |
! Creating ~WikiLinks ! Creating ~WikiLinks

View File

@ -0,0 +1,341 @@
/*\
title: $:/plugins/tiddlywiki/markdown-legacy/wrapper.js
type: application/javascript
module-type: parser
Wraps up the remarkable parser for use as a Parser in TiddlyWiki
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var r = require("$:/plugins/tiddlywiki/markdown-legacy/remarkable.js");
var Remarkable = r.Remarkable,
linkify = r.linkify,
utils = r.utils;
///// Set up configuration options /////
function parseAsBoolean(tiddlerName) {
return $tw.wiki.getTiddlerText(tiddlerName).toLowerCase() === "true";
}
var pluginOpts = {
linkNewWindow: parseAsBoolean("$:/config/markdown/linkNewWindow"),
renderWikiText: parseAsBoolean("$:/config/markdown/renderWikiText"),
renderWikiTextPragma: $tw.wiki.getTiddlerText("$:/config/markdown/renderWikiTextPragma").trim()
};
var remarkableOpts = {
breaks: parseAsBoolean("$:/config/markdown/breaks"),
quotes: $tw.wiki.getTiddlerText("$:/config/markdown/quotes"),
typographer: parseAsBoolean("$:/config/markdown/typographer")
};
var accumulatingTypes = {
"text": true,
"softbreak": true
};
// If rendering WikiText, we treat katex nodes as text.
if(pluginOpts.renderWikiText) {
accumulatingTypes["katex"] = true;
}
var md = new Remarkable(remarkableOpts);
// If tiddlywiki/katex plugin is present, use remarkable-katex to enable katex support.
if($tw.modules.titles["$:/plugins/tiddlywiki/katex/katex.min.js"]) {
var rk = require("$:/plugins/tiddlywiki/markdown-legacy/remarkable-katex.js");
md = md.use(rk);
}
if(parseAsBoolean("$:/config/markdown/linkify")) {
md = md.use(linkify);
}
function findTagWithType(nodes, startPoint, type, level) {
for (var i = startPoint; i < nodes.length; i++) {
if(nodes[i].type === type && nodes[i].level === level) {
return i;
}
}
return false;
}
/**
* Remarkable creates nodes that look like:
* [
* { type: 'paragraph_open'},
* { type: 'inline', content: 'Hello World', children:[{type: 'text', content: 'Hello World'}]},
* { type: 'paragraph_close'}
* ]
*
* But TiddlyWiki wants the Parser (https://tiddlywiki.com/dev/static/Parser.html) to emit nodes like:
*
* [
* { type: 'element', tag: 'p', children: [{type: 'text', text: 'Hello World'}]}
* ]
*/
function convertNodes(remarkableTree, isStartOfInline) {
let out = [];
var accumulatedText = '';
function withChildren(currentIndex, currentLevel, closingType, nodes, callback) {
var j = findTagWithType(nodes, currentIndex + 1, closingType, currentLevel);
if(j === false) {
console.error("Failed to find a " + closingType + " node after position " + currentIndex);
console.log(nodes);
return currentIndex + 1;
}
let children = convertNodes(nodes.slice(currentIndex + 1, j));
callback(children);
return j;
}
function wrappedElement(elementTag, currentIndex, currentLevel, closingType, nodes) {
return withChildren(currentIndex, currentLevel, closingType, nodes, function(children) {
out.push({
type: "element",
tag: elementTag,
children: children
});
});
}
for (var i = 0; i < remarkableTree.length; i++) {
var currentNode = remarkableTree[i];
switch (currentNode.type) {
case "paragraph_open":
// If the paragraph is a "tight" layout paragraph, don't wrap children in a <p> tag.
if(currentNode.tight) {
i = withChildren(i, currentNode.level, "paragraph_close", remarkableTree, function(children) {
Array.prototype.push.apply(out, children);
});
} else {
i = wrappedElement("p", i, currentNode.level, "paragraph_close", remarkableTree);
}
break;
case "heading_open":
i = wrappedElement("h" + currentNode.hLevel, i, currentNode.level, "heading_close", remarkableTree);
break;
case "bullet_list_open":
i = wrappedElement("ul", i, currentNode.level, "bullet_list_close", remarkableTree);
break;
case "ordered_list_open":
i = wrappedElement('ol', i, currentNode.level,'ordered_list_close', remarkableTree);
break;
case "list_item_open":
i = wrappedElement("li", i, currentNode.level, "list_item_close", remarkableTree);
break;
case "link_open":
i = withChildren(i, currentNode.level, "link_close", remarkableTree, function(children) {
if(currentNode.href[0] !== "#") {
// External link
var attributes = {
class: { type: "string", value: "tc-tiddlylink-external" },
href: { type: "string", value: currentNode.href },
rel: { type: "string", value: "noopener noreferrer" }
};
if(pluginOpts.linkNewWindow) {
attributes.target = { type: "string", value: "_blank" };
}
out.push({
type: "element",
tag: "a",
attributes: attributes,
children: children
});
} else {
// Internal link
out.push({
type: "link",
attributes: {
to: { type: "string", value: $tw.utils.decodeURISafe(currentNode.href.substr(1)) }
},
children: children
});
}
});
break;
case "code":
out.push({
type: "element",
tag: currentNode.block ? "pre" : "code",
children: [{ type: "text", text: currentNode.content }]
});
break;
case "fence":
out.push({
type: "codeblock",
attributes: {
language: { type: "string", value: currentNode.params },
code: { type: "string", value: currentNode.content }
}
});
break;
case "image":
out.push({
type: "image",
attributes: {
tooltip: { type: "string", value: currentNode.alt },
source: { type: "string", value: $tw.utils.decodeURIComponentSafe(currentNode.src) }
}
});
break;
case "softbreak":
if(remarkableOpts.breaks) {
out.push({
type: "element",
tag: "br",
});
} else {
accumulatedText = accumulatedText + '\n';
}
break;
case "hardbreak":
out.push({
type: "element",
tag: "br",
});
break;
case "th_open":
case "td_open":
var elementTag = currentNode.type.slice(0, 2);
i = withChildren(i, currentNode.level, elementTag + "_close", remarkableTree, function(children) {
var attributes = {};
if(currentNode.align) {
attributes.style = { type: "string", value: "text-align:" + currentNode.align };
}
out.push({
type: "element",
tag: elementTag,
attributes: attributes,
children: children
});
});
break;
case "hr":
out.push({
type: 'element',
tag: 'hr',
});
break;
case "inline":
out = out.concat(convertNodes(currentNode.children, true));
break;
case "text":
// We need to merge this text block with the upcoming text block and parse it all together.
accumulatedText = accumulatedText + currentNode.content;
break;
case "katex":
// If rendering WikiText, convert the katex node back to text for parsing by the WikiText LaTeX parser.
if(pluginOpts.renderWikiText) {
// If this is a block, add a newline to trigger the KaTeX plugins block detection.
var displayModeSuffix = currentNode.block ? "\n" : "";
accumulatedText = accumulatedText + "$$" + currentNode.content + displayModeSuffix + "$$";
} else {
out.push({
type: "latex",
attributes: {
text: { type: "text", value: currentNode.content },
displayMode: { type: "text", value: currentNode.block ? "true" : "false" }
}
});
}
break;
default:
if(currentNode.type.substr(currentNode.type.length - 5) === "_open") {
var tagName = currentNode.type.substr(0, currentNode.type.length - 5);
i = wrappedElement(tagName, i, currentNode.level, tagName + "_close", remarkableTree);
} else {
console.error("Unknown node type: " + currentNode.type, currentNode);
out.push({
type: "text",
text: currentNode.content
});
}
break;
}
// We test to see if we process the block now, or if there's
// more to accumulate first.
if(accumulatedText
&& (
remarkableOpts.breaks ||
(i+1) >= remarkableTree.length ||
!accumulatingTypes[remarkableTree[i+1].type]
)
) {
// The Markdown compiler thinks this is just text.
// Hand off to the WikiText parser to see if there's more to render
// But only if it's configured to, and we have more than whitespace
if(!pluginOpts.renderWikiText || accumulatedText.match(/^\s*$/)) {
out.push({
type: "text",
text: accumulatedText
});
} else {
// If we're inside a block element (div, p, td, h1), and this is the first child in the tree,
// handle as a block-level parse. Otherwise not.
var parseAsInline = !(isStartOfInline && i === 0);
var textToParse = accumulatedText;
if(pluginOpts.renderWikiTextPragma !== "") {
textToParse = pluginOpts.renderWikiTextPragma + "\n" + textToParse;
}
var wikiParser = $tw.wiki.parseText("text/vnd.tiddlywiki", textToParse, {
parseAsInline: parseAsInline
});
var rs = wikiParser.tree;
// If we parsed as a block, but the root element the WikiText parser gave is a paragraph,
// we should discard the paragraph, since the way Remarkable nests its nodes, this "inline"
// node is always inside something else that's a block-level element
if(!parseAsInline
&& rs.length === 1
&& rs[0].type === "element"
&& rs[0].tag === "p"
) {
rs = rs[0].children;
}
// If the original text element started with a space, add it back in
if(rs.length > 0
&& rs[0].type === "text"
&& (accumulatedText[0] === " " || accumulatedText[0] === "\n")
) {
rs[0].text = " " + rs[0].text;
}
out = out.concat(rs);
}
accumulatedText = '';
}
}
return out;
}
var MarkdownParser = function(type, text, options) {
var tree = md.parse(text, {});
//console.debug(tree);
tree = convertNodes(tree);
//console.debug(tree);
this.tree = tree;
};
exports["text/x-markdown"] = MarkdownParser;
exports["text/markdown"] = MarkdownParser;
})();

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/bold icon: $:/core/images/bold
caption: {{$:/language/Buttons/Bold/Caption}} (Markdown) caption: {{$:/language/Buttons/Bold/Caption}} (Markdown)
description: {{$:/language/Buttons/Bold/Hint}} description: {{$:/language/Buttons/Bold/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((bold)) shortcuts: ((bold))
<$action-sendmessage <$action-sendmessage

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-1 icon: $:/core/images/heading-1
caption: {{$:/language/Buttons/Heading1/Caption}} (Markdown) caption: {{$:/language/Buttons/Heading1/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading1/Hint}} description: {{$:/language/Buttons/Heading1/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-1)) shortcuts: ((heading-1))
<$action-sendmessage <$action-sendmessage

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-2 icon: $:/core/images/heading-2
caption: {{$:/language/Buttons/Heading2/Caption}} (Markdown) caption: {{$:/language/Buttons/Heading2/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading2/Hint}} description: {{$:/language/Buttons/Heading2/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-2)) shortcuts: ((heading-2))
<$action-sendmessage <$action-sendmessage

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-3 icon: $:/core/images/heading-3
caption: {{$:/language/Buttons/Heading3/Caption}} (Markdown) caption: {{$:/language/Buttons/Heading3/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading3/Hint}} description: {{$:/language/Buttons/Heading3/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-3)) shortcuts: ((heading-3))
<$action-sendmessage <$action-sendmessage

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-4 icon: $:/core/images/heading-4
caption: {{$:/language/Buttons/Heading4/Caption}} (Markdown) caption: {{$:/language/Buttons/Heading4/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading4/Hint}} description: {{$:/language/Buttons/Heading4/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-4)) shortcuts: ((heading-4))
<$action-sendmessage <$action-sendmessage

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-5 icon: $:/core/images/heading-5
caption: {{$:/language/Buttons/Heading5/Caption}} (Markdown) caption: {{$:/language/Buttons/Heading5/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading5/Hint}} description: {{$:/language/Buttons/Heading5/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-5)) shortcuts: ((heading-5))
<$action-sendmessage <$action-sendmessage

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/heading-6 icon: $:/core/images/heading-6
caption: {{$:/language/Buttons/Heading6/Caption}} (Markdown) caption: {{$:/language/Buttons/Heading6/Caption}} (Markdown)
description: {{$:/language/Buttons/Heading6/Hint}} description: {{$:/language/Buttons/Heading6/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((heading-6)) shortcuts: ((heading-6))
<$action-sendmessage <$action-sendmessage

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/italic icon: $:/core/images/italic
caption: {{$:/language/Buttons/Italic/Caption}} (Markdown) caption: {{$:/language/Buttons/Italic/Caption}} (Markdown)
description: {{$:/language/Buttons/Italic/Hint}} description: {{$:/language/Buttons/Italic/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((italic)) shortcuts: ((italic))
<$action-sendmessage <$action-sendmessage

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/list-bullet icon: $:/core/images/list-bullet
caption: {{$:/language/Buttons/ListBullet/Caption}} (Markdown) caption: {{$:/language/Buttons/ListBullet/Caption}} (Markdown)
description: {{$:/language/Buttons/ListBullet/Hint}} description: {{$:/language/Buttons/ListBullet/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((list-bullet)) shortcuts: ((list-bullet))
<$action-sendmessage <$action-sendmessage

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/list-number icon: $:/core/images/list-number
caption: {{$:/language/Buttons/ListNumber/Caption}} (Markdown) caption: {{$:/language/Buttons/ListNumber/Caption}} (Markdown)
description: {{$:/language/Buttons/ListNumber/Hint}} description: {{$:/language/Buttons/ListNumber/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((list-number)) shortcuts: ((list-number))
<$action-sendmessage <$action-sendmessage

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/mono-line icon: $:/core/images/mono-line
caption: {{$:/language/Buttons/MonoLine/Caption}} (Markdown) caption: {{$:/language/Buttons/MonoLine/Caption}} (Markdown)
description: {{$:/language/Buttons/MonoLine/Hint}} description: {{$:/language/Buttons/MonoLine/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((mono-line)) shortcuts: ((mono-line))
<$action-sendmessage <$action-sendmessage

View File

@ -4,7 +4,7 @@ tags: $:/tags/EditorToolbar
icon: $:/core/images/quote icon: $:/core/images/quote
caption: {{$:/language/Buttons/Quote/Caption}} (Markdown) caption: {{$:/language/Buttons/Quote/Caption}} (Markdown)
description: {{$:/language/Buttons/Quote/Hint}} description: {{$:/language/Buttons/Quote/Hint}}
condition: [<targetTiddler>type[text/x-markdown]] condition: [<targetTiddler>type[text/x-markdown]] [<targetTiddler>type[text/markdown]]
shortcuts: ((quote)) shortcuts: ((quote))
<$action-sendmessage <$action-sendmessage

View File

@ -4,5 +4,5 @@ key: ((new-markdown-tiddler))
\whitespace trim \whitespace trim
<$navigator story="$:/StoryList" history="$:/HistoryList" openLinkFromInsideRiver={{$:/config/Navigation/openLinkFromInsideRiver}} openLinkFromOutsideRiver={{$:/config/Navigation/openLinkFromOutsideRiver}} relinkOnRename={{$:/config/RelinkOnRename}}> <$navigator story="$:/StoryList" history="$:/HistoryList" openLinkFromInsideRiver={{$:/config/Navigation/openLinkFromInsideRiver}} openLinkFromOutsideRiver={{$:/config/Navigation/openLinkFromOutsideRiver}} relinkOnRename={{$:/config/RelinkOnRename}}>
<$action-sendmessage $message="tm-new-tiddler" type="text/x-markdown"/> <$action-sendmessage $message="tm-new-tiddler" type="text/markdown"/>
</$navigator> </$navigator>

View File

@ -3,3 +3,9 @@ title: $:/config/
ShortcutInfo/new-markdown-tiddler: {{$:/language/Buttons/NewMarkdown/Hint}} ShortcutInfo/new-markdown-tiddler: {{$:/language/Buttons/NewMarkdown/Hint}}
shortcuts-mac/new-markdown-tiddler: ctrl-M shortcuts-mac/new-markdown-tiddler: ctrl-M
shortcuts-not-mac/new-markdown-tiddler: alt-M shortcuts-not-mac/new-markdown-tiddler: alt-M
markdown/breaks: false
markdown/linkify: false
markdown/quotes: “”‘’
markdown/renderWikiText: true
markdown/renderWikiTextPragma: \rules only html entity syslink wikilink commentblock commentinline macrocallblock macrocallinline transcludeblock transcludeinline filteredtranscludeblock filteredtranscludeinline
markdown/typographer: false

View File

@ -0,0 +1,80 @@
title: $:/plugins/tiddlywiki/markdown/config
! Plugin Configuration
|!Config |!Default |!Description |
|[[breaks|$:/config/markdown/breaks]]|`false`|markdown-it library config: Convert '\n' in paragraphs into `<br>` |
|[[linkify|$:/config/markdown/linkify]]|`false`|markdown-it library config: Autoconvert URL-like text to links |
|[[renderWikiText|$:/config/markdown/renderWikiText]]|`true`|After Markdown is parsed, should any text elements be handed off to the ~WikiText parser for further processing? |
|[[renderWikiTextPragma|$:/config/markdown/renderWikiTextPragma]]|<code><$view tiddler="$:/plugins/tiddlywiki/markdown" subtiddler="$:/config/markdown/renderWikiTextPragma" mode="inline"/></code>|When handing off to the ~WikiText parser, what parser rules should it follow? |
|[[typographer|$:/config/markdown/typographer]]|`false`|markdown-it library config: Enable some language-neutral replacement + quotes beautification |
|[[quotes|$:/config/markdown/quotes]]|`“”‘’`|markdown-it library config: Double + single quotes replacement pairs, when `typographer` is enabled |
''IMPORTANT:'' You must reload your wiki for changes to take effect.
<h2 style="margin-top:1.5em">~WikiText Pragma</h2>
The value of [[renderWikiTextPragma|$:/config/markdown/renderWikiTextPragma]] has been carefully tuned to properly integrate markdown with ~TiddlyWiki. Changing this setting may produce unexpected results, but the inclusion of the following parser rules should be fine:
; image
: embed images using ~TiddlyWiki's image syntax:
<p style="margin-left:1em">
```
[img[An explanatory tooltip|TiddlerTitle]]
[img width=23 class="tc-image" [https://tiddlywiki.com/fractalveg.jpg]]
```
</p>
; prettylink
: create links the ~TiddlyWiki way:
<p style="margin-left:1em">
```
[[TiddlerTitle]]
[[Displayed Link Title|Tiddler Title]]
[[TW5|https://tiddlywiki.com/]]
```
</p>
; prettyextlink
: create external links using the following syntax:
<p style="margin-left:1em">
```
[ext[Open file|index.html]]
[ext[Open file|../README.md]]
```
</p>
; wikilink
: auto-link ~CamelCase titles
; syslink
: auto-link system tiddlers
<h2 style="margin-top:1.5em">Typographical Replacements</h2>
When [[typographer|$:/config/markdown/typographer]] is enabled, markdown-it will provide these typographical replacements:
```
(c) (C) → ©
(tm) (TM) → ™
(r) (R) → ®
+- → ±
... → …
?.... → ?..
!.... → !..
????? → ???
!!!!! → !!!
,, → ,
-- → &ndash;
--- → &mdash;
```

View File

@ -1,4 +1,4 @@
title: $:/language/Docs/Types/text/x-markdown title: $:/language/Docs/Types/text/markdown
description: Markdown description: Markdown
name: text/x-markdown name: text/markdown
group: Text group: Text

View File

@ -13,19 +13,25 @@ Text editor operation to make a markdown link
"use strict"; "use strict";
exports["make-markdown-link"] = function(event,operation) { exports["make-markdown-link"] = function(event,operation) {
var rx = /[()\\]/g, rs = '\\$&';
if(operation.selection) { if(operation.selection) {
if(event.paramObject.text.includes("://")) { var desc = operation.selection.replace(/[\[\]\\]/g, rs);
operation.replacement = "[" + operation.selection + "](" + event.paramObject.text + ")";
if(event.paramObject.text.indexOf("://") !== -1) {
operation.replacement = "[" + desc + "](" + event.paramObject.text.replace(rx, rs) + ")";
} else { } else {
operation.replacement = "[" + operation.selection + "](#" + event.paramObject.text.replaceAll(" ", "%20") + ")"; operation.replacement = "[" + desc + "](#" + encodeURIComponent(event.paramObject.text).replace(rx, rs) + ")";
} }
operation.cutStart = operation.selStart; operation.cutStart = operation.selStart;
operation.cutEnd = operation.selEnd; operation.cutEnd = operation.selEnd;
} else { } else {
if(event.paramObject.text.includes("://")) { if(event.paramObject.text.indexOf("://") !== -1) {
operation.replacement = "<" + event.paramObject.text + ">"; operation.replacement = "<" + event.paramObject.text.replace(/[<>]/g, function(m, offset, str) {
return encodeURI(m);
}) + ">";
} else { } else {
operation.replacement = "[](#" + event.paramObject.text.replaceAll(" ", "%20") + ")"; operation.replacement = "[](#" + encodeURIComponent(event.paramObject.text).replace(rx, rs) + ")";
} }
operation.cutStart = operation.selStart; operation.cutStart = operation.selStart;
operation.cutEnd = operation.selEnd; operation.cutEnd = operation.selEnd;

View File

@ -0,0 +1,22 @@
Copyright (c) 2014 Vitaly Puzrin, Alex Kocharin.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,7 @@
/*!
markdown-it-deflist
https://github.com/markdown-it/markdown-it-deflist
*/
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).markdownitDeflist=e()}}((function(){return function e(t,n,r){function i(f,d){if(!n[f]){if(!t[f]){var s="function"==typeof require&&require;if(!d&&s)return s(f,!0);if(o)return o(f,!0);var u=new Error("Cannot find module '"+f+"'");throw u.code="MODULE_NOT_FOUND",u}var a=n[f]={exports:{}};t[f][0].call(a.exports,(function(e){return i(t[f][1][e]||e)}),a,a.exports,e,t,n,r)}return n[f].exports}for(var o="function"==typeof require&&require,f=0;f<r.length;f++)i(r[f]);return i}({"/":[function(e,t,n){"use strict";t.exports=function(e){var t=e.utils.isSpace;function n(e,t){var n,r,i=e.bMarks[t]+e.tShift[t],o=e.eMarks[t];return i>=o||126!==(r=e.src.charCodeAt(i++))&&58!==r||i===(n=e.skipSpaces(i))||n>=o?-1:i}e.block.ruler.before("paragraph","deflist",(function(e,r,i,o){var f,d,s,u,a,l,p,k,c,h,b,y,m,g,C,I,v,_,w,x;if(o)return!(e.ddIndent<0)&&n(e,r)>=0;if((c=r+1)>=i)return!1;if(e.isEmpty(c)&&++c>=i)return!1;if(e.sCount[c]<e.blkIndent)return!1;if((d=n(e,c))<0)return!1;p=e.tokens.length,w=!0,(x=e.push("dl_open","dl",1)).map=l=[r,0],u=r,s=c;e:for(;;){for(_=!1,(x=e.push("dt_open","dt",1)).map=[u,u],(x=e.push("inline","",0)).map=[u,u],x.content=e.getLines(u,u+1,e.blkIndent,!1).trim(),x.children=[],x=e.push("dt_close","dt",-1);;){for((x=e.push("dd_open","dd",1)).map=a=[c,0],v=d,k=e.eMarks[s],h=e.sCount[s]+d-(e.bMarks[s]+e.tShift[s]);v<k&&(f=e.src.charCodeAt(v),t(f));)9===f?h+=4-h%4:h++,v++;if(d=v,I=e.tight,b=e.ddIndent,y=e.blkIndent,C=e.tShift[s],g=e.sCount[s],m=e.parentType,e.blkIndent=e.ddIndent=e.sCount[s]+2,e.tShift[s]=d-e.bMarks[s],e.sCount[s]=h,e.tight=!0,e.parentType="deflist",e.md.block.tokenize(e,s,i,!0),e.tight&&!_||(w=!1),_=e.line-s>1&&e.isEmpty(e.line-1),e.tShift[s]=C,e.sCount[s]=g,e.tight=I,e.parentType=m,e.blkIndent=y,e.ddIndent=b,x=e.push("dd_close","dd",-1),a[1]=c=e.line,c>=i)break e;if(e.sCount[c]<e.blkIndent)break e;if((d=n(e,c))<0)break;s=c}if(c>=i)break;if(u=c,e.isEmpty(u))break;if(e.sCount[u]<e.blkIndent)break;if((s=u+1)>=i)break;if(e.isEmpty(s)&&s++,s>=i)break;if(e.sCount[s]<e.blkIndent)break;if((d=n(e,s))<0)break}return x=e.push("dl_close","dl",-1),l[1]=c,e.line=c,w&&function(e,t){var n,r,i=e.level+2;for(n=t+2,r=e.tokens.length-2;n<r;n++)e.tokens[n].level===i&&"paragraph_open"===e.tokens[n].type&&(e.tokens[n+2].hidden=!0,e.tokens[n].hidden=!0,n+=2)}(e,p),!0}),{alt:["paragraph","reference","blockquote"]})}},{}]},{},[])("/")}));

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
/*! markdown-it-ins 3.0.1 https://github.com/markdown-it/markdown-it-mark @license MIT */
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self).markdownitIns=n()}(this,(function(){"use strict";return function(e){function n(e,n){var t,o,s,i,r,l=[],f=n.length;for(t=0;t<f;t++)43===(s=n[t]).marker&&-1!==s.end&&(i=n[s.end],(r=e.tokens[s.token]).type="ins_open",r.tag="ins",r.nesting=1,r.markup="++",r.content="",(r=e.tokens[i.token]).type="ins_close",r.tag="ins",r.nesting=-1,r.markup="++",r.content="","text"===e.tokens[i.token-1].type&&"+"===e.tokens[i.token-1].content&&l.push(i.token-1));for(;l.length;){for(o=(t=l.pop())+1;o<e.tokens.length&&"ins_close"===e.tokens[o].type;)o++;t!==--o&&(r=e.tokens[o],e.tokens[o]=e.tokens[t],e.tokens[t]=r)}}e.inline.ruler.before("emphasis","ins",(function(e,n){var t,o,s,i,r=e.pos,l=e.src.charCodeAt(r);if(n)return!1;if(43!==l)return!1;if(s=(o=e.scanDelims(e.pos,!0)).length,i=String.fromCharCode(l),s<2)return!1;for(s%2&&(e.push("text","",0).content=i,s--),t=0;t<s;t+=2)e.push("text","",0).content=i+i,(o.can_open||o.can_close)&&e.delimiters.push({marker:l,length:0,jump:t/2,token:e.tokens.length-1,end:-1,open:o.can_open,close:o.can_close});return e.pos+=o.length,!0})),e.inline.ruler2.before("emphasis","ins",(function(e){var t,o=e.tokens_meta,s=(e.tokens_meta||[]).length;for(n(e,e.delimiters),t=0;t<s;t++)o[t]&&o[t].delimiters&&n(e,o[t].delimiters)}))}}));

View File

@ -0,0 +1,2 @@
/*! markdown-it-mark 3.0.1 https://github.com/markdown-it/markdown-it-mark @license MIT */
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self).markdownitMark=n()}(this,(function(){"use strict";return function(e){function n(e,n){var t,o,r,s,i,a=[],k=n.length;for(t=0;t<k;t++)61===(r=n[t]).marker&&-1!==r.end&&(s=n[r.end],(i=e.tokens[r.token]).type="mark_open",i.tag="mark",i.nesting=1,i.markup="==",i.content="",(i=e.tokens[s.token]).type="mark_close",i.tag="mark",i.nesting=-1,i.markup="==",i.content="","text"===e.tokens[s.token-1].type&&"="===e.tokens[s.token-1].content&&a.push(s.token-1));for(;a.length;){for(o=(t=a.pop())+1;o<e.tokens.length&&"mark_close"===e.tokens[o].type;)o++;t!==--o&&(i=e.tokens[o],e.tokens[o]=e.tokens[t],e.tokens[t]=i)}}e.inline.ruler.before("emphasis","mark",(function(e,n){var t,o,r,s,i=e.pos,a=e.src.charCodeAt(i);if(n)return!1;if(61!==a)return!1;if(r=(o=e.scanDelims(e.pos,!0)).length,s=String.fromCharCode(a),r<2)return!1;for(r%2&&(e.push("text","",0).content=s,r--),t=0;t<r;t+=2)e.push("text","",0).content=s+s,(o.can_open||o.can_close)&&e.delimiters.push({marker:a,length:0,jump:t/2,token:e.tokens.length-1,end:-1,open:o.can_open,close:o.can_close});return e.pos+=o.length,!0})),e.inline.ruler2.before("emphasis","mark",(function(e){var t,o=e.tokens_meta,r=(e.tokens_meta||[]).length;for(n(e,e.delimiters),t=0;t<r;t++)o[t]&&o[t].delimiters&&n(e,o[t].delimiters)}))}}));

View File

@ -0,0 +1,2 @@
/*! markdown-it-sub 1.0.0 https://github.com//markdown-it/markdown-it-sub @license MIT */
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var r;r="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,r.markdownitSub=e()}}(function(){return function e(r,o,n){function t(i,u){if(!o[i]){if(!r[i]){var f="function"==typeof require&&require;if(!u&&f)return f(i,!0);if(s)return s(i,!0);var p=new Error("Cannot find module '"+i+"'");throw p.code="MODULE_NOT_FOUND",p}var a=o[i]={exports:{}};r[i][0].call(a.exports,function(e){var o=r[i][1][e];return t(o?o:e)},a,a.exports,e,r,o,n)}return o[i].exports}for(var s="function"==typeof require&&require,i=0;i<n.length;i++)t(n[i]);return t}({1:[function(e,r){"use strict";function o(e,r){var o,t,s,i=e.posMax,u=e.pos;if(126!==e.src.charCodeAt(u))return!1;if(r)return!1;if(u+2>=i)return!1;for(e.pos=u+1;e.pos<i;){if(126===e.src.charCodeAt(e.pos)){o=!0;break}e.md.inline.skipToken(e)}return o&&u+1!==e.pos?(t=e.src.slice(u+1,e.pos),t.match(/(^|[^\\])(\\\\)*\s/)?(e.pos=u,!1):(e.posMax=e.pos,e.pos=u+1,s=e.push("sub_open","sub",1),s.markup="~",s=e.push("text","",0),s.content=t.replace(n,"$1"),s=e.push("sub_close","sub",-1),s.markup="~",e.pos=e.posMax+1,e.posMax=i,!0)):(e.pos=u,!1)}var n=/\\([ \\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g;r.exports=function(e){e.inline.ruler.after("emphasis","sub",o)}},{}]},{},[1])(1)});

View File

@ -0,0 +1,2 @@
/*! markdown-it-sup 1.0.0 https://github.com//markdown-it/markdown-it-sup @license MIT */
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var r;r="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,r.markdownitSup=e()}}(function(){return function e(r,o,n){function t(i,p){if(!o[i]){if(!r[i]){var u="function"==typeof require&&require;if(!p&&u)return u(i,!0);if(s)return s(i,!0);var f=new Error("Cannot find module '"+i+"'");throw f.code="MODULE_NOT_FOUND",f}var a=o[i]={exports:{}};r[i][0].call(a.exports,function(e){var o=r[i][1][e];return t(o?o:e)},a,a.exports,e,r,o,n)}return o[i].exports}for(var s="function"==typeof require&&require,i=0;i<n.length;i++)t(n[i]);return t}({1:[function(e,r){"use strict";function o(e,r){var o,t,s,i=e.posMax,p=e.pos;if(94!==e.src.charCodeAt(p))return!1;if(r)return!1;if(p+2>=i)return!1;for(e.pos=p+1;e.pos<i;){if(94===e.src.charCodeAt(e.pos)){o=!0;break}e.md.inline.skipToken(e)}return o&&p+1!==e.pos?(t=e.src.slice(p+1,e.pos),t.match(/(^|[^\\])(\\\\)*\s/)?(e.pos=p,!1):(e.posMax=e.pos,e.pos=p+1,s=e.push("sup_open","sup",1),s.markup="^",s=e.push("text","",0),s.content=t.replace(n,"$1"),s=e.push("sup_close","sup",-1),s.markup="^",e.pos=e.posMax+1,e.posMax=i,!0)):(e.pos=p,!1)}var n=/\\([ \\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g;r.exports=function(e){e.inline.ruler.after("emphasis","sup",o)}},{}]},{},[1])(1)});

File diff suppressed because one or more lines are too long

View File

@ -1,35 +1,66 @@
{ {
"tiddlers": [ "tiddlers": [
{ {
"file": "remarkable.js", "file": "markdown-it.min.js",
"fields": { "fields": {
"type": "application/javascript", "type": "application/javascript",
"title": "$:/plugins/tiddlywiki/markdown/remarkable.js", "title": "$:/plugins/tiddlywiki/markdown/markdown-it.js",
"module-type": "library" "module-type": "library"
} }
}, },
{ {
"file": "remarkable-license.txt", "file": "markdown-it-deflist.min.js",
"fields": { "fields": {
"type": "text/plain", "type": "application/javascript",
"title": "$:/plugins/tiddlywiki/markdown/remarkable-license" "title": "$:/plugins/tiddlywiki/markdown/markdown-it-deflist.js",
"module-type": "library"
} }
}, },
{ {
"file": "remarkable-katex.min.js", "file": "markdown-it-footnote.min.js",
"fields": { "fields": {
"type": "application/javascript", "type": "application/javascript",
"title": "$:/plugins/tiddlywiki/markdown/remarkable-katex.js", "title": "$:/plugins/tiddlywiki/markdown/markdown-it-footnote.js",
"module-type": "library" "module-type": "library"
}, }
"prefix": "(function(realRequire) {var require = function(m) {if(m===\"katex\"){m = \"$:/plugins/tiddlywiki/katex/katex.min.js\"};return realRequire(m);};",
"suffix": "})(require);\n"
}, },
{ {
"file": "remarkable-katex-license.txt", "file": "markdown-it-ins.min.js",
"fields": {
"type": "application/javascript",
"title": "$:/plugins/tiddlywiki/markdown/markdown-it-ins.js",
"module-type": "library"
}
},
{
"file": "markdown-it-mark.min.js",
"fields": {
"type": "application/javascript",
"title": "$:/plugins/tiddlywiki/markdown/markdown-it-mark.js",
"module-type": "library"
}
},
{
"file": "markdown-it-sub.min.js",
"fields": {
"type": "application/javascript",
"title": "$:/plugins/tiddlywiki/markdown/markdown-it-sub.js",
"module-type": "library"
}
},
{
"file": "markdown-it-sup.min.js",
"fields": {
"type": "application/javascript",
"title": "$:/plugins/tiddlywiki/markdown/markdown-it-sup.js",
"module-type": "library"
}
},
{
"file": "LICENSE",
"fields": { "fields": {
"type": "text/plain", "type": "text/plain",
"title": "$:/plugins/tiddlywiki/markdown/remarkable-katex-license" "title": "$:/plugins/tiddlywiki/markdown/license"
} }
} }
] ]

View File

@ -0,0 +1,170 @@
/*\
title: $:/plugins/tiddlywiki/markdown/markdown-it-katex.js
type: application/javascript
module-type: library
Based on markdown-it-katex v2.0.0 by @waylonflinn https://github.com/waylonflinn/markdown-it-katex | MIT License
\*/
(function(){
/* Process inline math */
/*
Like markdown-it-simplemath, this is a stripped down, simplified version of:
https://github.com/runarberg/markdown-it-math
It differs in that it takes (a subset of) LaTeX as input and relies on KaTeX
for rendering output.
*/
/*jslint node: true */
'use strict';
// Test if potential opening or closing delimieter
// Assumes that there is a "$" at state.src[pos]
function isValidDelim(state, pos) {
var prevChar, nextChar,
max = state.posMax,
can_open = true,
can_close = true;
prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1;
nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1;
// Check non-whitespace conditions for opening and closing, and
// check that closing delimeter isn't followed by a number
if (prevChar === 0x20/* " " */ || prevChar === 0x09/* \t */ ||
prevChar === 0x0d/* "\r" */ || prevChar === 0x0a/* \n */ ||
(nextChar >= 0x30/* "0" */ && nextChar <= 0x39/* "9" */)) {
can_close = false;
}
if (nextChar === 0x20/* " " */ || nextChar === 0x09/* \t */ ||
nextChar === 0x0d/* "\r" */ || nextChar === 0x0a/* \ns */) {
can_open = false;
}
if (state.src.substring(pos,pos+3) === "$:/") {
can_open = false;
can_close = false;
}
return {
can_open: can_open,
can_close: can_close
};
}
function math_inline(state, silent) {
var start, match, token, res, pos, esc_count;
if (state.src[state.pos] !== "$") { return false; }
res = isValidDelim(state, state.pos);
if (!res.can_open) {
if (!silent) { state.pending += "$"; }
state.pos += 1;
return true;
}
// First check for and bypass all properly escaped delimieters
// This loop will assume that the first leading backtick can not
// be the first character in state.src, which is known since
// we have found an opening delimieter already.
start = state.pos + 1;
match = start;
while ( (match = state.src.indexOf("$", match)) !== -1) {
// Found potential $, look for escapes, pos will point to
// first non escape when complete
pos = match - 1;
while (state.src[pos] === "\\") { pos -= 1; }
// Even number of escapes, potential closing delimiter found
if ( ((match - pos) % 2) == 1 ) { break; }
match += 1;
}
// No closing delimter found. Consume $ and continue.
if (match === -1) {
if (!silent) { state.pending += "$"; }
state.pos = start;
return true;
}
// Check if we have empty content, ie: $$. Do not parse.
if (match - start === 0) {
if (!silent) { state.pending += "$$"; }
state.pos = start + 1;
return true;
}
// Check for valid closing delimiter
res = isValidDelim(state, match);
if (!res.can_close) {
if (!silent) { state.pending += "$"; }
state.pos = start;
return true;
}
if (!silent) {
token = state.push('math_inline', '$latex', 0);
token.markup = "$";
token.content = state.src.slice(start, match);
token.attrs = [["displayMode", "false"], ["text", token.content]];
}
state.pos = match + 1;
return true;
}
/*! https://github.com/iktakahiro/markdown-it-katex/pull/2 by @shinhermit */
function math_inline_block(state, silent) {
var start, match, token, res, pos, esc_count;
if(state.src.slice(state.pos, state.pos+2) !== "$$") { return false; }
// First check for and bypass all properly escaped delimieters
// This loop will assume that the first leading backtick can not
// be the first character in state.src, which is known since
// we have found an opening delimieter already.
start = state.pos + 2;
match = start;
while ( (match = state.src.indexOf("$$", match)) !== -1) {
// Found potential $$, look for escapes, pos will point to
// first non escape when complete
pos = match - 1;
while (state.src[pos] === "\\") { pos -= 1; }
// Even number of escapes, potential closing delimiter found
if ( ((match - pos) % 2) == 1 ) { break; }
match += 2;
}
// No closing delimter found. Consume $$ and continue.
if (match === -1) {
if (!silent) { state.pending += "$$"; }
state.pos = start;
return true;
}
// Check if we have empty content, ie: $$$$. Do not parse.
if (match - start === 0) {
if (!silent) { state.pending += "$$$$"; }
state.pos = start + 2;
return true;
}
if (!silent) {
token = state.push('math_inline_block', '$latex', 0);
token.block = true;
token.markup = "$$";
token.content = state.src.slice(start, match);
token.attrs = [["displayMode", "true"], ["text", token.content]];
}
state.pos = match + 2;
return true;
}
module.exports = function math_plugin(md, options) {
md.inline.ruler.after('escape', 'math_inline', math_inline);
md.inline.ruler.after('escape', 'math_inline_block', math_inline_block);
};
})();

View File

@ -0,0 +1,522 @@
/*\
title: $:/plugins/tiddlywiki/markdown/markdown-it-tiddlywiki.js
type: application/javascript
module-type: library
Wraps up the markdown-it parser for use as a Parser in TiddlyWiki
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var md;
var pluginOpts;
var TWMarkReplacements = {
"{" : "&#123;",
"[" : "&#91;",
"$" : "&#36;"
};
var TWMarkRegEx = /[{[$]/g;
function encodeTWMark(match) {
return TWMarkReplacements[match];
}
// escpae {, [ and $ in string s
function escapeTWMarks(s) {
s = String(s);
TWMarkRegEx.lastIndex = 0;
return s.replace(TWMarkRegEx,encodeTWMark);
}
// escape anything that could be interpreted as transclusion or syslink
function render_code_inline(tokens,idx,options,env,slf) {
tokens[idx].attrJoin('class','_codified_');
return '<code' + slf.renderAttrs(tokens[idx]) + '>'
+ escapeTWMarks(md.utils.escapeHtml(tokens[idx].content))
+ '</code>';
}
function render_code_block(tokens,idx) {
return '<$codeblock code=e"' + md.utils.escapeHtml(tokens[idx].content) + '" language=""/>\n';
}
function render_fence(tokens,idx) {
var info = tokens[idx].info ? md.utils.unescapeAll(tokens[idx].info).trim() : '';
return '<$codeblock code=e"' + md.utils.escapeHtml(tokens[idx].content) + '" language="' + info.split(/(\s+)/g)[0] + '"/>\n';
}
// add a blank line after opening tag to activate TW block parsing
function render_paragraph_open(tokens,idx) {
return tokens[idx].hidden ? '' : '<p>\n\n';
}
function render_paragraph_close(tokens,idx) {
return tokens[idx].hidden ? '' : '\n</p>\n';
}
// Replace footnote links with "qualified" internal links
function render_footnote_ref(tokens,idx,options,env,slf) {
var id = slf.rules.footnote_anchor_name(tokens,idx,options,env,slf);
var caption = slf.rules.footnote_caption(tokens,idx,options,env,slf);
var refid = id;
if(tokens[idx].meta.subId > 0) {
refid += ':' + tokens[idx].meta.subId;
}
return '<a class="footnote-ref" href=<<qualify "##fn' + id + '">> id=<<qualify "#fnref' + refid + '">>>' + caption + '</a>';
}
function render_footnote_open(tokens,idx,options,env,slf) {
var id = slf.rules.footnote_anchor_name(tokens,idx,options,env,slf);
if(tokens[idx].meta.subId > 0) {
id += ':' + tokens[idx].meta.subId;
}
return '<li id=<<qualify "#fn' + id + '">> class="footnote-item">';
}
function render_footnote_anchor(tokens,idx,options,env,slf) {
var id = slf.rules.footnote_anchor_name(tokens,idx,options,env,slf);
if(tokens[idx].meta.subId > 0) {
id += ':' + tokens[idx].meta.subId;
}
// append variation selector to prevent display as Apple Emoji on iOS
return '<a href=<<qualify "##fnref' + id + '">> class="footnote-backref">\u21A5\uFE0E</a>';
}
// do not un-escape html entities and escape characters
function render_text_special(tokens,idx) {
if(tokens[idx].info === 'entity') {
return tokens[idx].markup;
}
return escapeTWMarks(md.utils.escapeHtml(tokens[idx].content));
}
function render_tw_expr(tokens,idx) {
return tokens[idx].content;
}
// Overwrite default: render attribute strings in e"..." format instead,
// so HTML entities can be decoded. See parseStringLiteralExt() below.
function render_token_attrs(token) {
var i, l, result;
if(!token.attrs) { return ''; }
result = '';
for(i=0, l=token.attrs.length; i<l; i++) {
result += ' ' + md.utils.escapeHtml(token.attrs[i][0]) + '=e"' + md.utils.escapeHtml(token.attrs[i][1]) + '"';
}
return result;
}
// given tw parsing rule and starting pos, returns match index or undefined
// assumes pos >= 0
function findNextMatch(ruleinfo,pos) {
// ruleinfo.matchIndex needs to be -1 at the start of inline state
if(ruleinfo.matchIndex < pos) {
ruleinfo.matchIndex = ruleinfo.rule.findNextMatch(pos);
}
return ruleinfo.matchIndex;
}
// Add inline rule "macrocall" to parse <<macroname ...>>
var MacroCallRegEx = /<<([^\s>"'=]+)[^>]*>>/g;
function tw_macrocallinline(state,silent) {
var match, max, pos = state.pos;
// Check start
max = state.posMax;
if(state.src.charCodeAt(pos) !== 0x3C || state.src.charCodeAt(pos+1) !== 0x3C /* << */|| pos + 3 >= max) {
return false;
}
MacroCallRegEx.lastIndex = pos;
match = MacroCallRegEx.exec(state.src);
if(!match || match.index !== pos) { return false; }
if(!silent) {
var token = state.push('tw_expr','',0);
token.content = state.src.slice(pos,pos+match[0].length);
}
state.pos = MacroCallRegEx.lastIndex;
return true;
}
// parse transclusion elements
function tw_transcludeinline(state,silent) {
var ruleinfo = pluginOpts.inlineRules.transcludeinline;
var pos = state.pos;
var matchIndex = findNextMatch(ruleinfo,pos);
if(matchIndex === undefined || matchIndex !== pos) {
return false;
}
if(!silent) {
var token = state.push('tw_expr','',0);
token.content = state.src.slice(pos,pos+ruleinfo.rule.match[0].length);
}
state.pos += ruleinfo.rule.match[0].length;
return true;
}
// parse filtered transclusion elements
function tw_filteredtranscludeinline(state,silent) {
var ruleinfo = pluginOpts.inlineRules.filteredtranscludeinline;
var pos = state.pos;
var matchIndex = findNextMatch(ruleinfo,pos);
if(matchIndex === undefined || matchIndex !== pos) {
return false;
}
if(!silent) {
var token = state.push('tw_expr','',0);
if(state.linkLevel > 0) {
var filter = ruleinfo.rule.match[1];
token.content = '<$text text={{{' + filter + '}}}/>';
} else {
token.content = state.src.slice(pos,pos+ruleinfo.rule.match[0].length);
}
}
state.pos += ruleinfo.rule.match[0].length;
return true;
}
// based on markdown-it html_block()
var WidgetTagRegEx = [/^<\/?\$[a-zA-Z0-9\-\$]+(?=(\s|\/?>|$))/, /^$/];
function tw_block(state,startLine,endLine,silent) {
var i, nextLine, token, lineText,
pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine];
// if it's indented more than 3 spaces, it should be a code block
if(state.sCount[startLine] - state.blkIndent >= 4) { return false; }
if(!state.md.options.html) { return false; }
if(state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; }
lineText = state.src.slice(pos,max);
if(!WidgetTagRegEx[0].test(lineText)) { return false; }
if(silent) {
// don't let widgets interrupt a paragrpah
return false;
}
nextLine = startLine + 1;
// If we are here - we detected HTML block.
// Let's roll down till block end.
if(!WidgetTagRegEx[1].test(lineText)) {
for(; nextLine < endLine; nextLine++) {
if(state.sCount[nextLine] < state.blkIndent) { break; }
pos = state.bMarks[nextLine] + state.tShift[nextLine];
max = state.eMarks[nextLine];
lineText = state.src.slice(pos,max);
if(WidgetTagRegEx[1].test(lineText)) {
if(lineText.length !== 0) { nextLine++; }
break;
}
}
}
state.line = nextLine;
token = state.push('html_block','',0);
token.map = [ startLine, nextLine ];
token.content = state.getLines(startLine,nextLine,state.blkIndent,true);
return true;
}
// parse [img[...]] elements
function tw_image(state,silent) {
var ruleinfo = pluginOpts.inlineRules.image;
// ignore at parseLinkLabel stage; will be recognized in tokenize()
if(state.parsingLinkLabel > 0) {
return false;
}
var pos = state.pos;
var matchIndex = findNextMatch(ruleinfo,pos);
if(matchIndex === undefined || matchIndex !== pos) {
return false;
}
if(!silent) {
var twNode = ruleinfo.rule.parse()[0];
var token = state.push('$image','$image',0);
$tw.utils.each(twNode.attributes,function(attr,id) {
token.attrSet(id,attr.value);
});
token.markup = 'tw_image';
}
state.pos = ruleinfo.rule.parser.pos;
return true;
}
// parse [[link]] elements
function tw_prettylink(state,silent) {
var ruleinfo = pluginOpts.inlineRules.prettylink;
// skip if in link label
if(state.linkLevel > 0 || state.parsingLinkLabel > 0) {
return false;
}
var pos = state.pos;
var matchIndex = findNextMatch(ruleinfo,pos);
if(matchIndex === undefined || matchIndex !== pos) {
return false;
}
if(!silent) {
var twNode = ruleinfo.rule.parse()[0];
var tag = (twNode.type==='link' ? '$link' : 'a');
// push a link_open token so markdown's core.linkify will ignore
var token = state.push('link_open',tag,1);
$tw.utils.each(twNode.attributes,function(attr,id) {
token.attrSet(id,attr.value);
});
token.attrJoin('class','_codified_');
token.markup = 'tw_prettylink';
state.linkLevel++;
token = state.push('text','',0);
token.content = twNode.children[0].text;
state.linkLevel--;
token = state.push('link_close',tag,-1);
token.markup = 'tw_prettylink';
}
state.pos = ruleinfo.rule.parser.pos;
return true;
}
function tw_prettyextlink(state,silent) {
var ruleinfo = pluginOpts.inlineRules.prettyextlink;
// skip if in link label
if(state.linkLevel > 0 || state.parsingLinkLabel > 0) {
return false;
}
var pos = state.pos;
var matchIndex = findNextMatch(ruleinfo,pos);
if(matchIndex === undefined || matchIndex !== pos) {
return false;
}
if(!silent) {
var twNode = ruleinfo.rule.parse()[0];
var token = state.push('link_open','a',1);
$tw.utils.each(twNode.attributes,function(attr,id) {
token.attrSet(id,attr.value);
});
token.attrJoin('class','_codified_');
token.markup = 'tw_prettyextlink';
state.linkLevel++;
token = state.push('text','',0);
token.content = twNode.children[0].text;
state.linkLevel--;
token = state.push('link_close','a',-1);
token.markup = 'tw_prettyextlink';
}
state.pos = ruleinfo.rule.parser.pos;
return true;
}
var TWCloseTagRegEx = /<\/\$[A-Za-z0-9\-\$]+\s*>/gm;
function extendHtmlInline(origRule) {
return function(state,silent) {
if(origRule(state,silent)) {
return true;
}
var token, pos = state.pos;
var parseTag = $tw.Wiki.parsers['text/vnd.tiddlywiki'].prototype.inlineRuleClasses.html.prototype.parseTag;
var tag = parseTag(state.src,pos,{});
if(tag) {
if(!silent) {
token = state.push('html_inline','',0);
token.content = state.src.slice(pos,tag.end);
}
state.pos = tag.end;
return true;
}
TWCloseTagRegEx.lastIndex = pos;
var match = TWCloseTagRegEx.exec(state.src);
if(!match || match.index !== pos) {
return false;
}
if(!silent) {
token = state.push('html_inline','',0);
token.content = state.src.slice(pos,pos + match[0].length);
}
state.pos = TWCloseTagRegEx.lastIndex;
return true;
};
}
function extendParseLinkLabel(origFunc) {
return function(state,start,disableNested) {
if(state.parsingLinkLabel === undefined) {
state.parsingLinkLabel = 0;
}
state.parsingLinkLabel++;
var labelEnd = origFunc(state,start,disableNested);
state.parsingLinkLabel--;
return labelEnd;
};
}
// reset each tw inline rule to initial inline state
function extendInlineParse(thisArg,origFunc,twInlineRules) {
return function(str,md,env,outTokens) {
var i, ruleinfo, key;
for(key in twInlineRules) {
ruleinfo = twInlineRules[key];
ruleinfo.rule.parser.source = str;
ruleinfo.rule.parser.sourceLength = str.length;
ruleinfo.rule.parser.pos = 0; // not used
ruleinfo.matchIndex = -1;
}
origFunc.call(thisArg,str,md,env,outTokens);
}
}
/// post processing ///
function wikify(state) {
var href, title, src, alt;
var tagStack = [];
state.tokens.forEach(function(blockToken) {
if(blockToken.type === 'inline' && blockToken.children) {
blockToken.children.forEach(function(token) {
switch(token.type) {
case 'link_open':
if(token.markup === 'tw_prettylink' || token.markup === 'tw_prettyextlink') {
return;
}
href = token.attrGet('href');
if(href[0] === '#') {
token.tag = '$link';
href = $tw.utils.decodeURIComponentSafe(href.substring(1));
title = token.attrGet('title');
token.attrs = [['to', href], ['class', '_codified_']];
if(title) {
token.attrSet('tooltip',title);
}
} else {
token.attrSet('target','_blank');
token.attrJoin('class','tc-tiddlylink-external');
token.attrJoin('class','_codified_');
token.attrSet('rel','noopener noreferrer');
}
tagStack.push(token.tag);
break;
case 'link_close':
if(token.markup === 'tw_prettylink' || token.markup === 'tw_prettyextlink') {
return;
}
token.tag = tagStack.pop();
break;
case 'image':
token.tag = '$image';
src = token.attrGet('src');
alt = token.attrGet('alt');
title = token.attrGet('title');
token.attrs[token.attrIndex('src')][0] = 'source';
if(src[0] === '#') {
src = $tw.utils.decodeURIComponentSafe(src.substring(1));
token.attrSet('source',src);
}
if(title) {
token.attrs[token.attrIndex('title')][0] = 'tooltip';
}
break;
}
});
}
});
}
module.exports = function tiddlyWikiPlugin(markdown,options) {
var defaults = {
renderWikiText: false,
blockRules: {},
inlineRules: {}
};
md = markdown;
pluginOpts = md.utils.assign({},defaults,options||{});
md.renderer.rules.code_inline = render_code_inline;
md.renderer.rules.code_block = render_code_block;
md.renderer.rules.fence = render_fence;
md.renderer.rules.paragraph_open = render_paragraph_open;
md.renderer.rules.paragraph_close = render_paragraph_close;
md.renderer.rules.footnote_ref = render_footnote_ref;
md.renderer.rules.footnote_open = render_footnote_open;
md.renderer.rules.footnote_anchor = render_footnote_anchor;
md.renderer.rules.text_special = render_text_special;
md.renderer.rules.tw_expr = render_tw_expr;
md.renderer.renderAttrs = render_token_attrs;
if(pluginOpts.renderWikiText) {
md.helpers.parseLinkLabel = extendParseLinkLabel(md.helpers.parseLinkLabel);
if(pluginOpts.inlineRules.image) {
md.inline.ruler.after('link','tw_image',tw_image);
}
if(pluginOpts.inlineRules.prettyextlink) {
md.inline.ruler.after('link','tw_prettyextlink',tw_prettyextlink);
}
if(pluginOpts.inlineRules.prettylink) {
md.inline.ruler.after('link','tw_prettylink',tw_prettylink);
}
if(pluginOpts.inlineRules.filteredtranscludeinline) {
md.inline.ruler.before('html_inline','tw_filteredtranscludeinline',tw_filteredtranscludeinline);
}
if(pluginOpts.inlineRules.transcludeinline) {
md.inline.ruler.before('html_inline','tw_transcludeinline',tw_transcludeinline);
}
md.inline.ruler.before('html_inline','tw_macrocallinline',tw_macrocallinline);
md.inline.ruler.at('html_inline',extendHtmlInline(md.inline.ruler.__rules__[md.inline.ruler.__find__('html_inline')].fn));
md.block.ruler.after('html_block','tw_block',tw_block,{
alt: [ 'paragraph', 'reference', 'blockquote' ]
});
md.inline.parse = extendInlineParse(md.inline,md.inline.parse,options.inlineRules);
}
md.core.ruler.disable('text_join');
md.core.ruler.push('wikify',wikify);
};
})();

View File

@ -6,7 +6,7 @@ list-after: $:/core/ui/Buttons/new-tiddler
\whitespace trim \whitespace trim
<$button tooltip={{$:/language/Buttons/NewMarkdown/Hint}} aria-label={{$:/language/Buttons/NewMarkdown/Caption}} class=<<tv-config-toolbar-class>>> <$button tooltip={{$:/language/Buttons/NewMarkdown/Hint}} aria-label={{$:/language/Buttons/NewMarkdown/Caption}} class=<<tv-config-toolbar-class>>>
<$action-sendmessage $message="tm-new-tiddler" type="text/x-markdown"/> <$action-sendmessage $message="tm-new-tiddler" type="text/markdown"/>
<$list filter="[<tv-config-toolbar-icons>match[yes]]"> <$list filter="[<tv-config-toolbar-icons>match[yes]]">
{{$:/plugins/tiddlywiki/markdown/images/new-markdown-button}} {{$:/plugins/tiddlywiki/markdown/images/new-markdown-button}}
</$list> </$list>

View File

@ -1,6 +1,6 @@
{ {
"title": "$:/plugins/tiddlywiki/markdown", "title": "$:/plugins/tiddlywiki/markdown",
"name": "Markdown", "name": "Markdown",
"description": "Markdown parser based on remarkable by Jon Schlinkert and remarkable-katex by Brad Howes", "description": "Markdown parser based on markdown-it",
"list": "readme usage remarkable-license remarkable-katex-license" "list": "readme config syntax license"
} }

View File

@ -1,7 +1,32 @@
title: $:/plugins/tiddlywiki/markdown/readme title: $:/plugins/tiddlywiki/markdown/readme
This is a TiddlyWiki plugin for parsing Markdown text, using the [[Remarkable|https://github.com/jonschlinkert/remarkable]] library. If the KaTeX TiddlyWiki plugin is installed, KaTeX support is enabled using the [[remarkable-katex|https://github.com/bradhowes/remarkable-katex]] Remarkable plugin. This plugin provides Markdown support via the [[markdown-it|https://github.com/markdown-it/markdown-it]] parser and its associated plugins:
It is completely self-contained, and doesn't need an Internet connection in order to work. It works both in the browser and under Node.js. * markdown-it-deflist
* markdown-it-footnote
* markdown-it-ins
* markdown-it-mark
* markdown-it-sub
* markdown-it-sup
[[Source code|https://github.com/Jermolene/TiddlyWiki5/blob/master/plugins/tiddlywiki/markdown]] !! Compatibility Notes
* <p>A tab character in Markdown has a size of four spaces. Configure the tab size of your code editor accordingly. For example, if you use <$text text="CodeMirror"/>, it is recommended that you set $:/config/codemirror/indentUnit and $:/config/codemirror/tabSize to `4` to avoid inconsistent indentations.</p>
* <p>HTML blocks are ultimately parsed by the <$text text=WikiText/> parser: //an opening tag followed by a blank line will activate block-level parsing for its content//. When working with tags designed to contain literal content, such as `<pre>` and `<style>` tags, refrain from adding blank lines after the opening tags.</p>
* <p>You must terminate a table with either a blank line or another block-level structure.</p>
* <p>`latex-parser` in $:/config/markdown/renderWikiTextPragma is no longer required and will be ignored.</p>
* <p>Config option `linkNewWindow` is removed.</p>
!! Extending the Parser
You can extend the parser by loading additional markdown-it plugins this way:
```js
var plugin1 = require(...);
var plugin2 = require(...);
var md = $tw.Wiki.parsers["text/markdown"].prototype.md;
md.use(plugin1)
.use(plugin2, opts, ...);
```

View File

@ -0,0 +1,50 @@
title: $:/plugins/tiddlywiki/markdown/styles
tags: [[$:/tags/Stylesheet]]
code-body: yes
.markdown {
display: block;
margin: 0px;
}
.markdown hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid <<colour muted-foreground>>;
}
.markdown .footnotes {
font-size: 0.9em;
line-height: 1.32;
}
.markdown a.footnote-ref {
color: <<colour tiddler-link-foreground>>;
font-size: 0.75em;
text-decoration: none;
vertical-align: super;
padding:0px 1px;
}
.markdown ol.footnotes-list {
padding-left: 2em;
}
.markdown .footnote-item p {
margin: 0.7em 0px;
}
.markdown a.footnote-backref {
color: <<colour tiddler-link-foreground>>;
font-size: 0.8em;
text-decoration: none;
margin-left: 0.25em;
}
.markdown a.footnote-ref:target, .markdown .footnote-item:target {
background-color: <<colour message-background>>;
scroll-margin-top: {{{ [{$:/themes/tiddlywiki/vanilla/options/stickytitles}match[yes]then[120px]else[60px]] }}};
}
.markdown li > p:first-child {
margin-top: 0px;
}
.markdown li + li {
margin-top: 2px;
}
.markdown mark {
padding: 1px 3px;
}

View File

@ -0,0 +1,224 @@
title: $:/plugins/tiddlywiki/markdown/syntax
To review standard Markdown syntax, see: [ext[CommonMark quick reference|https://commonmark.org/help/]]. For formal specification, consult the [ext[CommonMark Spec|https://spec.commonmark.org/current/]].
! Linking to Tiddlers
Prepend `#` to tiddler titles to form link addresses. If a tiddler title contains spaces or other special characters, you must either (1) URI-encode the title, or (2) surround the #title with `<` `>` and backslash-escape any `<` or `>` in the title.
!! Links
<pre><code>[link text](<strong>#</strong><$text text="TiddlerTitle"/> "optional tooltip")
[link text](<strong>#</strong>New<strong>%20</strong>Tiddler)
[link text](<strong>&lt;#</strong>New Tiddler<strong>&gt;</strong>)
[](<strong>&lt;#</strong>How to use <strong>\</strong>&lt;$list<strong>\</strong>&gt; widget?<strong>&gt;</strong>)
</code></pre>
You can also use the `<$link>` widget to generate links to tiddlers:
```
<$link to="Tiddler Title">Displayed Link Title</$link>
```
!! Reference Style Links
```
[link text][1]
[link text][2]
[1]: #New%20Tiddler "optional tooltip"
[2]: <#Another Tiddler>
```
!! Images
```
![alt text](#Motovun%20Jack.jpg "optional tooltip")
![alt text](<#Motovun Jack.jpg>)
```
! Escaping Special Characters
Markdown allows you to escape ASCII punctuation characters with `\`.
! HTML Blocks
An [[HTML block|https://spec.commonmark.org/0.30/#html-blocks]] is a group of lines that starts with an HTML tag and is treated as raw HTML. Block-level tags such as `<div>` and `<p>` can interrupt a paragraph. Inline elements such as `<strong>` and `<em>` can start an HTML block if the //complete// tag begins on a new paragraph by itself. In most cases, an HTML block continues until a blank line is reached.
A widget tag that begins on a new paragraph will also be treated as an HTML block. Markdown elements are not recognized inside the HTML block. For example:
```
see
<$link to="New Tiddler">
_New_ Tiddler
</$link>
```
rendered as:
```
<p>see</p>
<$link to="New Tiddler">
_New_ Tiddler
</$link>
```
A widget tag not preceded by a blank line is an inline element.
```
see
<$link to="New Tiddler">
_New_ Tiddler
</$link>
```
rendered as:
```
<p>see <$link to="New Tiddler"><em>New</em> Tiddler</$link></p>
```
! Syntax Extensions
!! <$text text=KaTeX/>
You need to install the <$text text=KaTeX/> plugin to activate this syntax extension.
Surround your math expression with `$` for inline rendering. Whitespace characters cannot immediately follow the opening `$` or precede the closing `$`, and the closing delimiter must not immediately precede a digit. Furthermore, `$` followed by `:/` will not be recognized as a valid opening or closing delimiter either.
Here's an example of an inline math expression:
```
$c = \pm\sqrt{a^2 + b^2}$
```
Use `$$` to center the math in display mode:
```
$$c = \pm\sqrt{a^2 + b^2}$$
```
!! Superscript and Subscript
```
X^2^
```
x<sup>2</sup>
```
H~2~O
```
H<sub>2</sub>O
!! Marked Text
```
==marked text==
```
<mark>marked text</mark>
!! Strikethrough
```
~~striked through text~~
```
<s>striked through text</s>
!! Inserted Text
```
++inserted text++
```
<ins>inserted text</ins>
!! Tables
markdown-it supports <$text text="GitHub Flavored Markdown"/> (GFM) [ext[table syntax|https://github.github.com/gfm/#tables-extension-]].
```
|Left Aligned |Centered |Right Aligned |
|:--- | :---: | ---:|
|apple |bat |candle |
```
<table>
<thead>
<tr><th style="text-align:left">Left Aligned</th><th style="text-align:center">Centered</th><th style="text-align:right">Right Aligned</th></tr>
</thead>
<tbody>
<tr><td style="text-align:left">apple</td><td style="text-align:center">bat</td><td style="text-align:right">candle</td></tr>
</tbody>
</table>
!! Definition Lists
```
Term One
: Definition with
lazy continuation.
Term Two
: Here is the first defintion.
: Here is the second definition.
As you can see. A definition can have
more than one paragrpah. It can also have
And indended code block...
```
<dl>
<dt>Term One</dt>
<dd><p>Definition with
lazy continuation.
</p></dd>
<dt>Term Two</dt>
<dd><p>Here is the first defintion.
</p></dd>
<dd><p>Here is the second definition.</p><p>As you can see. A definition can have
more than one paragrpah. It can also have
<pre><code>And indended code block...
</code></pre>
</p></dd>
</dl>
!! Footnotes
For detailed explanation, see [[Creating Footnotes|https://www.markdownguide.org/extended-syntax/#footnotes]].
```
Here's a simple footnote,[^1] and here's a longer one.[^bignote]
[^1]: This is the first footnote.
[^bignote]: Here's one with multiple paragraphs and code.
Indent paragraphs to include them in the footnote.
`{ my code }`
Add as many paragraphs as you like.
```
<div class="markdown"><p>Heres a simple footnote,<a class="footnote-ref" href="##fn1--doc639182" id="#fnref1--doc639182">[1]</a> and heres a longer one.<a class="footnote-ref" href="##fn2--doc639182" id="#fnref2--doc639182">[2]</a>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="#fn1--doc639182" class="footnote-item"><p>This is the first footnote. <a href="##fnref1--doc639182" class="footnote-backref">↥︎</a>
</p></li>
<li id="#fn2--doc639182" class="footnote-item"><p>Heres one with multiple paragraphs and code.</p><p>Indent paragraphs to include them in the footnote.</p><p><code class="codified">{ my code }</code></p><p>Add as many paragraphs as you like. <a href="##fnref2--doc639182" class="footnote-backref">↥︎</a>
</p></li>
</ol>
</section>
</p></div>

View File

@ -3,338 +3,264 @@ title: $:/plugins/tiddlywiki/markdown/wrapper.js
type: application/javascript type: application/javascript
module-type: parser module-type: parser
Wraps up the remarkable parser for use as a Parser in TiddlyWiki Wraps up the markdown-it parser for use as a Parser in TiddlyWiki
\*/ \*/
(function(){ (function(realRequire){
/*jslint node: true, browser: true */ /*jslint node: true, browser: true */
/*global $tw: false */ /*global $tw: false */
"use strict"; "use strict";
var r = require("$:/plugins/tiddlywiki/markdown/remarkable.js"); var require = function(m) {
return realRequire("$:/plugins/tiddlywiki/markdown/" + m + ".js");
};
var Remarkable = r.Remarkable, var MarkdownIt = require("markdown-it");
linkify = r.linkify,
utils = r.utils;
///// Set up configuration options /////
function parseAsBoolean(tiddlerName) { function parseAsBoolean(tiddlerName) {
return $tw.wiki.getTiddlerText(tiddlerName).toLowerCase() === "true"; return $tw.wiki.getTiddlerText(tiddlerName,"false").trim().toLowerCase() === "true";
} }
var pluginOpts = { var pluginOpts = {
linkNewWindow: parseAsBoolean("$:/config/markdown/linkNewWindow"),
renderWikiText: parseAsBoolean("$:/config/markdown/renderWikiText"), renderWikiText: parseAsBoolean("$:/config/markdown/renderWikiText"),
renderWikiTextPragma: $tw.wiki.getTiddlerText("$:/config/markdown/renderWikiTextPragma").trim() renderWikiTextPragma: $tw.wiki.getTiddlerText("$:/config/markdown/renderWikiTextPragma").trim()
}; };
var remarkableOpts = {
var markdownOpts = {
html: true,
xhtmlOut: true,
breaks: parseAsBoolean("$:/config/markdown/breaks"), breaks: parseAsBoolean("$:/config/markdown/breaks"),
quotes: $tw.wiki.getTiddlerText("$:/config/markdown/quotes"), quotes: $tw.wiki.getTiddlerText("$:/config/markdown/quotes").trim(),
typographer: parseAsBoolean("$:/config/markdown/typographer") typographer: parseAsBoolean("$:/config/markdown/typographer"),
linkify: parseAsBoolean("$:/config/markdown/linkify")
}; };
var accumulatingTypes = {
"text": true, // Retrieve needed TW rule classes and instantiated rules
"softbreak": true function setupWikiRules(pluginOptions) {
var results = {};
function collectAllRules(classes,type) {
var rulesInfo = [], key,
self = wikiParser;
for(key in classes) {
// instantiate the rule
var RuleClass = classes[key];
var rule = new RuleClass(self);
rule.name = key;
rule.class = RuleClass;
rule.is = {};
rule.is[type] = true;
rule.init(self);
rulesInfo.push({
rule: rule,
matchIndex: -1
});
}; };
// If rendering WikiText, we treat katex nodes as text. return rulesInfo;
if(pluginOpts.renderWikiText) {
accumulatingTypes["katex"] = true;
} }
var md = new Remarkable(remarkableOpts); // first pass: get all rule classes
var wikiParser = new $tw.Wiki.parsers["text/vnd.tiddlywiki"](null, '', {parseAsInline: true, wiki: $tw.wiki});
// If tiddlywiki/katex plugin is present, use remarkable-katex to enable katex support. // restore all possible rules from each rule class
if($tw.modules.titles["$:/plugins/tiddlywiki/katex/katex.min.js"]) { wikiParser.pragmaRules = collectAllRules(wikiParser.pragmaRuleClasses,'pragma');
var rk = require("$:/plugins/tiddlywiki/markdown/remarkable-katex.js"); wikiParser.blockRules = collectAllRules(wikiParser.blockRuleClasses,'block');
md = md.use(rk); wikiParser.inlineRules = collectAllRules(wikiParser.inlineRuleClasses,'inline');
var pragma = pluginOptions.renderWikiText
? "\\rules except latex-parser extlink\n" + pluginOptions.renderWikiTextPragma
: "\\rules only html entity commentinline commentblock";
wikiParser.pos = 0;
wikiParser.source = pragma;
wikiParser.sourceLength = pragma.length;
// second pass: remove uninterested rules based on \rules pragma
wikiParser.parsePragmas();
results.blockRules = {};
results.inlineRules = {}
results.blockRuleClasses = {};
results.inlineRuleClasses = {};
// save the rule sets for future markdown parsing
wikiParser.blockRules.forEach(function(ruleinfo) {
results.blockRules[ruleinfo.rule.name] = ruleinfo;
results.blockRuleClasses[ruleinfo.rule.name] = ruleinfo.rule.class;
});
wikiParser.inlineRules.forEach(function(ruleinfo) {
results.inlineRules[ruleinfo.rule.name] = ruleinfo;
results.inlineRuleClasses[ruleinfo.rule.name] = ruleinfo.rule.class;
});
return results;
} }
if(parseAsBoolean("$:/config/markdown/linkify")) { // Creates markdown-it parser
md = md.use(linkify); function createMarkdownEngine(markdownItOptions, pluginOptions) {
var md = new MarkdownIt(markdownItOptions)
.use(require("markdown-it-sub"))
.use(require("markdown-it-sup"))
.use(require("markdown-it-ins"))
.use(require("markdown-it-mark"))
.use(require("markdown-it-footnote"))
.use(require("markdown-it-deflist"));
var results = setupWikiRules(pluginOptions);
MarkdownParser.prototype.blockRuleClasses = results.blockRuleClasses;
MarkdownParser.prototype.blockRules = results.blockRules;
MarkdownParser.prototype.inlineRuleClasses = results.inlineRuleClasses;
MarkdownParser.prototype.inlineRules = results.inlineRules;
if(pluginOptions.renderWikiText && $tw.modules.titles["$:/plugins/tiddlywiki/katex/katex.min.js"]) {
md.use(require("markdown-it-katex"));
} }
function findTagWithType(nodes, startPoint, type, level) { md.use(require("markdown-it-tiddlywiki"),{
for (var i = startPoint; i < nodes.length; i++) { renderWikiText: pluginOptions.renderWikiText,
if(nodes[i].type === type && nodes[i].level === level) { blockRules: results.blockRules,
return i; inlineRules: results.inlineRules
});
$tw.utils.each(['image','prettylink','prettyextlink'], function(rule) {
if(MarkdownParser.prototype.inlineRules[rule]) {
// delegate to md; ignore the rule class in WikiParser
delete MarkdownParser.prototype.inlineRuleClasses[rule];
}
});
return md;
}
/// Parse tree post processing ///
function deactivateLinks(tree) {
$tw.utils.each(tree,function(node) {
if(node.type === "link") {
node.type = "text";
node.text = node.children[0].text;
delete node.attributes;
delete node.children;
delete node.attributes;
} else {
deactivateLinks(node.children);
}
});
}
// true if the node contains "_codified_" class attribute
function isCodified(node) {
return node.attributes
&& node.attributes.class
&& node.attributes.class.type === "string"
&& (node.attributes.class.value.split(" ").indexOf("_codified_") !== -1);
}
function decodeEntities(s) {
return s.replace(/(&#?[a-zA-Z0-9]{2,8};)/g,$tw.utils.entityDecode);
}
// Add e"..." and e'....' syntax to enable decoding of HTML entities
// in string literals.
function parseStringLiteralExtended(source,pos) {
var node = {
type: "string",
start: pos
};
var reString = /(?:"""([\s\S]*?)"""|e?"([^"]*)")|(?:e?'([^']*)')/g;
reString.lastIndex = pos;
var match = reString.exec(source);
if(match && match.index === pos) {
node.value = match[1] !== undefined ? match[1] :
(match[2] !== undefined ? match[2] : match[3]);
node.end = pos + match[0].length;
if(match[0].charAt(0) === "e") {
node.value = decodeEntities(node.value);
}
return node;
} else {
return null;
} }
} }
function processWikiTree(tree,hasWikiLinkRule) {
var stack = [].concat(tree);
var mergeable = function(node) {
return node.type === "element" && node.tag === "p" && (!node.attributes || Object.keys(node.attributes).length === 0);
};
while(stack.length) {
var node = stack.pop();
if(node.type === "element" && node.tag === "p") {
// reduce nested <p> nodes
while(node.children && node.children.length === 1 && mergeable(node.children[0])) {
node.children = node.children[0].children;
}
} else if(hasWikiLinkRule && isCodified(node)) {
deactivateLinks(node.children);
continue;
}
if(node.children && node.children.length > 0) {
stack.push.apply(stack,node.children);
}
}
}
// to extend MarkdownIt outside of this module, do:
//
// md = $tw.Wiki.parsers["text/markdown"].prototype.md;
// md.use(plugin[, options]);
MarkdownParser.prototype.md = createMarkdownEngine(markdownOpts,pluginOpts);
function MarkdownParser(type,text,options) {
var env = {}
var md = this.md;
var mdTree = md.parse(text,env);
var textToParse = '<div class="markdown">\n' + md.renderer.render(mdTree,md.options,env) + '</div>';
//console.log(JSON.stringify(mdTree,null,2));
//console.log("\n----------------\n" + textToParse);
var wikiParser;
var origParseStringLiteral = $tw.utils.parseStringLiteral;
$tw.utils.parseStringLiteral = parseStringLiteralExtended;
try {
wikiParser = new $tw.Wiki.parsers["text/vnd.tiddlywiki"](null,textToParse,{
parseAsInline: true,
wiki: options.wiki,
rules: { pragma: {}, block: this.blockRuleClasses, inline: this.inlineRuleClasses }
});
}
catch (err) {
wikiParser = $tw.wiki.parseText("text/vnd.tiddlywiki",
"<strong>Error encountered while parsing the tiddler:</strong><p>" + err.message + "</p>",
{parseAsInline: false, wiki: options.wiki});
}
finally {
$tw.utils.parseStringLiteral = origParseStringLiteral;
}
if(wikiParser.tree.length > 0) {
var hasWikiLinkRule = false;
// see if wikilink rule has been invoked
$tw.utils.each(wikiParser.inlineRules,function(ruleInfo) {
if(ruleInfo.rule.name === "wikilink") {
hasWikiLinkRule = true;
return false; return false;
} }
/**
* Remarkable creates nodes that look like:
* [
* { type: 'paragraph_open'},
* { type: 'inline', content: 'Hello World', children:[{type: 'text', content: 'Hello World'}]},
* { type: 'paragraph_close'}
* ]
*
* But TiddlyWiki wants the Parser (https://tiddlywiki.com/dev/static/Parser.html) to emit nodes like:
*
* [
* { type: 'element', tag: 'p', children: [{type: 'text', text: 'Hello World'}]}
* ]
*/
function convertNodes(remarkableTree, isStartOfInline) {
let out = [];
var accumulatedText = '';
function withChildren(currentIndex, currentLevel, closingType, nodes, callback) {
var j = findTagWithType(nodes, currentIndex + 1, closingType, currentLevel);
if(j === false) {
console.error("Failed to find a " + closingType + " node after position " + currentIndex);
console.log(nodes);
return currentIndex + 1;
}
let children = convertNodes(nodes.slice(currentIndex + 1, j));
callback(children);
return j;
}
function wrappedElement(elementTag, currentIndex, currentLevel, closingType, nodes) {
return withChildren(currentIndex, currentLevel, closingType, nodes, function(children) {
out.push({
type: "element",
tag: elementTag,
children: children
});
}); });
processWikiTree(wikiParser.tree,hasWikiLinkRule);
}
this.tree = wikiParser.tree;
this.source = text;
this.type = type || "text/markdown";
this.wiki = options.wiki;
} }
for (var i = 0; i < remarkableTree.length; i++) { exports["text/markdown"] = MarkdownParser;
var currentNode = remarkableTree[i];
switch (currentNode.type) {
case "paragraph_open":
// If the paragraph is a "tight" layout paragraph, don't wrap children in a <p> tag.
if(currentNode.tight) {
i = withChildren(i, currentNode.level, "paragraph_close", remarkableTree, function(children) {
Array.prototype.push.apply(out, children);
});
} else {
i = wrappedElement("p", i, currentNode.level, "paragraph_close", remarkableTree);
}
break;
case "heading_open":
i = wrappedElement("h" + currentNode.hLevel, i, currentNode.level, "heading_close", remarkableTree);
break;
case "bullet_list_open":
i = wrappedElement("ul", i, currentNode.level, "bullet_list_close", remarkableTree);
break;
case "ordered_list_open":
i = wrappedElement('ol', i, currentNode.level,'ordered_list_close', remarkableTree);
break;
case "list_item_open":
i = wrappedElement("li", i, currentNode.level, "list_item_close", remarkableTree);
break;
case "link_open":
i = withChildren(i, currentNode.level, "link_close", remarkableTree, function(children) {
if(currentNode.href[0] !== "#") {
// External link
var attributes = {
class: { type: "string", value: "tc-tiddlylink-external" },
href: { type: "string", value: currentNode.href },
rel: { type: "string", value: "noopener noreferrer" }
};
if(pluginOpts.linkNewWindow) {
attributes.target = { type: "string", value: "_blank" };
}
out.push({
type: "element",
tag: "a",
attributes: attributes,
children: children
});
} else {
// Internal link
out.push({
type: "link",
attributes: {
to: { type: "string", value: $tw.utils.decodeURISafe(currentNode.href.substr(1)) }
},
children: children
});
}
});
break;
case "code":
out.push({
type: "element",
tag: currentNode.block ? "pre" : "code",
children: [{ type: "text", text: currentNode.content }]
});
break;
case "fence":
out.push({
type: "codeblock",
attributes: {
language: { type: "string", value: currentNode.params },
code: { type: "string", value: currentNode.content }
}
});
break;
case "image":
out.push({
type: "image",
attributes: {
tooltip: { type: "string", value: currentNode.alt },
source: { type: "string", value: $tw.utils.decodeURIComponentSafe(currentNode.src) }
}
});
break;
case "softbreak":
if(remarkableOpts.breaks) {
out.push({
type: "element",
tag: "br",
});
} else {
accumulatedText = accumulatedText + '\n';
}
break;
case "hardbreak":
out.push({
type: "element",
tag: "br",
});
break;
case "th_open":
case "td_open":
var elementTag = currentNode.type.slice(0, 2);
i = withChildren(i, currentNode.level, elementTag + "_close", remarkableTree, function(children) {
var attributes = {};
if(currentNode.align) {
attributes.style = { type: "string", value: "text-align:" + currentNode.align };
}
out.push({
type: "element",
tag: elementTag,
attributes: attributes,
children: children
});
});
break;
case "hr":
out.push({
type: 'element',
tag: 'hr',
});
break;
case "inline":
out = out.concat(convertNodes(currentNode.children, true));
break;
case "text":
// We need to merge this text block with the upcoming text block and parse it all together.
accumulatedText = accumulatedText + currentNode.content;
break;
case "katex":
// If rendering WikiText, convert the katex node back to text for parsing by the WikiText LaTeX parser.
if(pluginOpts.renderWikiText) {
// If this is a block, add a newline to trigger the KaTeX plugins block detection.
var displayModeSuffix = currentNode.block ? "\n" : "";
accumulatedText = accumulatedText + "$$" + currentNode.content + displayModeSuffix + "$$";
} else {
out.push({
type: "latex",
attributes: {
text: { type: "text", value: currentNode.content },
displayMode: { type: "text", value: currentNode.block ? "true" : "false" }
}
});
}
break;
default:
if(currentNode.type.substr(currentNode.type.length - 5) === "_open") {
var tagName = currentNode.type.substr(0, currentNode.type.length - 5);
i = wrappedElement(tagName, i, currentNode.level, tagName + "_close", remarkableTree);
} else {
console.error("Unknown node type: " + currentNode.type, currentNode);
out.push({
type: "text",
text: currentNode.content
});
}
break;
}
// We test to see if we process the block now, or if there's
// more to accumulate first.
if(accumulatedText
&& (
remarkableOpts.breaks ||
(i+1) >= remarkableTree.length ||
!accumulatingTypes[remarkableTree[i+1].type]
)
) {
// The Markdown compiler thinks this is just text.
// Hand off to the WikiText parser to see if there's more to render
// But only if it's configured to, and we have more than whitespace
if(!pluginOpts.renderWikiText || accumulatedText.match(/^\s*$/)) {
out.push({
type: "text",
text: accumulatedText
});
} else {
// If we're inside a block element (div, p, td, h1), and this is the first child in the tree,
// handle as a block-level parse. Otherwise not.
var parseAsInline = !(isStartOfInline && i === 0);
var textToParse = accumulatedText;
if(pluginOpts.renderWikiTextPragma !== "") {
textToParse = pluginOpts.renderWikiTextPragma + "\n" + textToParse;
}
var wikiParser = $tw.wiki.parseText("text/vnd.tiddlywiki", textToParse, {
parseAsInline: parseAsInline
});
var rs = wikiParser.tree;
// If we parsed as a block, but the root element the WikiText parser gave is a paragraph,
// we should discard the paragraph, since the way Remarkable nests its nodes, this "inline"
// node is always inside something else that's a block-level element
if(!parseAsInline
&& rs.length === 1
&& rs[0].type === "element"
&& rs[0].tag === "p"
) {
rs = rs[0].children;
}
// If the original text element started with a space, add it back in
if(rs.length > 0
&& rs[0].type === "text"
&& (accumulatedText[0] === " " || accumulatedText[0] === "\n")
) {
rs[0].text = " " + rs[0].text;
}
out = out.concat(rs);
}
accumulatedText = '';
}
}
return out;
}
var MarkdownParser = function(type, text, options) {
var tree = md.parse(text, {});
//console.debug(tree);
tree = convertNodes(tree);
//console.debug(tree);
this.tree = tree;
};
exports["text/x-markdown"] = MarkdownParser; exports["text/x-markdown"] = MarkdownParser;
})(require);
})();