Table of Contents generated with DocToc
ReMarkably
ReMarkably is a collection of MarkDown syntax extension to be used with the truly remarkable Remarkable MarkDown parser.
Install with
npm install --save remarkably
What is it for?
Finally, it's possible to easily extend your all-time favorite liteweight markup language, MarkDown.
Heretofore, it has been difficult to extend the syntax of markup languages because their parsers were not often written with extensibility in mind—as in programming languages, many markup designers are caught in a frame of thinking that makes them want to create the best language with the best syntax, the final one to rule them all.
LISPers were never interested in syntax, because, hey, what can surpass a homoiconic language (yes, they really call it that) with gazillions of brackets, right?
ReStructuredText (also once known as ReStructuredTextNG) used to be a strong contender to MarkDown, but IMHO it lost out because it's just too complicated—too many rules, and to setup a parser and just parse means jumping through too many Java-Enterprisy hoops (at least when i last checked five years ago). Is it extensible? Don't try at home.
In the Python community, extending syntax is seen as something dangerous, as an activity that can't be left to users but must be firmely policed by an inner circle of senior contributors. Given the fairly traditional Lex-YACC-Bison-ish tooling of the parser, that's even true because you'd have to make changes in like four or six files to add a trivial tidbit to the language, and then re-compile the entire thing, which makes development feel like you're back to mainframes and please come back tomorrow to pick up your printouts. Assuming you took that month-long upfront training class so you sorta know-what'cherdoing. Sort of. It's really difficult. And, having done that, anyone interested in your extension must download the entire source tree and compile that themselves, or else you must provide binary packages. It's not least this factor that has caused a lot of digital rot in the Python world, because compiling C sources tends to be much more fragile than relying on an 'interpreted' (i.e. low-level-compilation-free) idiom. In order to implement the tiniest of changes, you have to submit to a month-long or year-long period of intense scrutiny and deliberation, and your proposal will likely get downvoted.
Such strict procedures are necessary to uphold the quality of monolithic languages. After all, uncounted numbers of users will be confronted with your changes, and any addition to the language will likely be kept indefinitely because even correcting a mistake may break backward compatibility. JavaScript programmers know this very well: they have to live with lots of 'original sins' because their language was born under a very swiftly wandering star, and there was no time to correct oversights. Now those flaws are baked into the language, and any change for the better in JS core could potentially break many millions of websites.
As Douglas Crockford convincingly demonstrates in his 2013 MLOCJS Syntaxation talk, those times should be over. Languages should be extensible, and given the right tools, parsing can be much easier than it used to be.
Sadly, as of this writing (2014-11-09), there is very little documentation on how to extend remarkable
, so
the foremost purpose of ReMarkably is filling that gap. Anyone interested can fork the repo, develop their
own extensions, and issue pull requests to make more syntax extensions available to the masses.
Usage
It's quite simple (using CoffeeScript here):
log = consolelogRMY = require 'remarkably' enable = 'full'settings = html: yes# Enable HTML tags in source xhtmlOut: no# Use '/' to close single tags (<br />) breaks: no# Convert '\n' in paragraphs into <br> langPrefix: 'language-'# CSS language prefix for fenced blocks linkify: yes# Autoconvert URL-like text to links typographer: yes quotes: '“”‘’' RM = enablesettingsRMYuse RMvideo = RMYgetexamplesvideoRMYuse RMemphasis = RMYgetexamplesemphasisRMYuse RMemphasis2 = RMYgetexamplesemphasis2RMYuse RMbraces = RMYgetexamplesbrackets opener: '{'closer: '}'arity: 2name: 'braces'RMYuse RMangles = RMYgetexamplesbrackets opener: '<'closer: '>'arity: 2name: 'angles'RMYuse RMbrackets = RMYgetexamplesbrackets opener: '['closer: ']'arity: 3name: 'brackets-3'RMYuse RMsmh = RMYgetexamplesbrackets opener: '《'closer: '》'arity: 1name: 'book-title'source = """ =This= ==is== ===very=== _awesome_(c): %[example movie](http://example.com) *A* **B** ***C*** ****D**** Here are * <<double pointy brackets>>, * {{double braces}}, * [[[triple square brackets]]], * 也可以用 《中文書名号》 。 """trimlog RMrender source
You can run the above with
remarkably/build && node remarkably/lib/main.js
which should output
This is very awesome©: example movieA B C ****D****Here aredouble pointy brackets,double braces,triple square brackets,也可以用 中文書名号 。
Writing Your Own Extension
Paste and copy one of the existing sources. A dynamic extension (one that accepts parameters) should return
an object with a get
method. I'm in the middle of developing this, so details may change without notice;
you probably want to copy from the avaible sources.
Here is an example for a dynamic extension that accepts an opening and a closing bracket character,
an 'arity' (number of repetitions), and a rule name, and turns those into a rule to render
markup like [[[this]]]
as <span class='yournamehere'>this</span>
:
#=========================================================================================================== = #--------------------------------------------------------------------------------------------------------- rule = rule._opener = settings? 'opener' ? '<' rule._closer = settings? 'closer' ? '>' rule.terminators = rule_opener rule._arity = settings? 'arity' ? 2 rule._class_name = settings? 'name' ? 'angles' rule.name = 'REMARKABLY/examples/' + rule_class_name #--------------------------------------------------------------------------------------------------------- rule.about = """$name$ recognizes text stretches enclosed by multiple brackets.""" #--------------------------------------------------------------------------------------------------------- = opener = "(?:)" closer = "(?:)" anchor = if anchor then '^' else '' repeat_all = if arity is 1 then '' else "{}" repeat_some = if arity is 1 then '' else "{1,}" #....................................................................................................... return """ ((?!)) ((?: \\\\| [^]| (?!) )*) ()(?!) """replace /\n\s*/g'' #--------------------------------------------------------------------------------------------------------- rule._pattern = rule_get_multiple_bracket_pattern rule_openerrule_closerrule_arityno rule._re = rule_pattern'g' # need `g` for `lastIndex` #--------------------------------------------------------------------------------------------------------- = #....................................................................................................... state rule._re.lastIndex = pos return false if not match = rule_reexec src ? or match 'index' isnt pos match unless silent statepush type: rulename opener: opener closer: closer content: content block: false level: statelevel #....................................................................................................... state.pos += alllength return true #--------------------------------------------------------------------------------------------------------- = # options tokens idx return "<span class=''></span>" #--------------------------------------------------------------------------------------------------------- = selfinlinerulerbefore selfinlineruler 'rules' 0 'name' rulenameruleparse selfrendererrules rulename = rulerender return null #--------------------------------------------------------------------------------------------------------- return rule
remarkable
Compatibility
ReMarkably is comaptible with remarkable@1.4.0
.