diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 966546f..542b87b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,4 +1,4 @@ -name: marggers +name: margrave on: push: diff --git a/README.md b/README.md index fdebf6c..c948dbc 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# marggers +# margrave Tweakable parser for a dialect of markdown that generates an HTML-like representation, which can be converted to HTML. Not stable. -[Try in browser](https://metagn.github.io/marggers/browser/converter.html). -[Docs](https://metagn.github.io/marggers/docs/marggers.html) +[Try in browser](https://metagn.github.io/margrave/browser/converter.html). +[Docs](https://metagn.github.io/margrave/docs/margrave.html) Tested for C, JS and NimScript (so also VM). diff --git a/browser/converter.html b/browser/converter.html index 271b32d..9f93af3 100644 --- a/browser/converter.html +++ b/browser/converter.html @@ -6,11 +6,11 @@ -
this page is a bit broken right now
diff --git a/marggers.nimble b/margrave.nimble similarity index 89% rename from marggers.nimble rename to margrave.nimble index 5f4e7e2..02a00aa 100644 --- a/marggers.nimble +++ b/margrave.nimble @@ -1,4 +1,4 @@ -version = "0.3.3" +version = "0.4.0" author = "metagn" description = "markdown dialect" license = "MIT" @@ -18,7 +18,7 @@ task tools, "builds tools, only browser converter for now": task docs, "build docs for all modules": when declared(buildDocs): - buildDocs(gitUrl = "https://github.com/metagn/marggers", extraOptions = "--path:src") + buildDocs(gitUrl = "https://github.com/metagn/margrave", extraOptions = "--path:src") else: echo "docs task not implemented, need nimbleutils" diff --git a/src/marggers.nim b/src/marggers.nim deleted file mode 100644 index 7e30a4a..0000000 --- a/src/marggers.nim +++ /dev/null @@ -1,67 +0,0 @@ -## Dialect of Markdown. -## -## Example -## ======= -## -## .. include:: ../examples/ref.mrg -## :literal: -## -## turns into HTML: -## -## .. include:: ../examples/ref.html -## :literal: -## -## Inline HTML note -## **************** -## -## **Note**: Nim's XML parser used for inline HTML uses `StringStream` from -## the `streams` module which does not work in JS for Nim version 1.2.x and -## earlier. To work around this, you can disable use of the XML parser, -## therefore disable inline HTML, by passing `-d:marggersNoInlineHtml`. -## This switch is available on all backends. You can still embed HTML inside -## curly braces. - -import marggers/[common, element, parser, parser/defs] - -export MarggersElement, element.`$`, defs - -proc parseMarggers*(parser: var MarggersParser, - staticOptions: static MarggersOptions = defaultParserOptions): seq[MarggersElement] = - ## Parses marggers with an already initialized parser. - result = parseTopLevel(parser, staticOptions) - -proc parseMarggers*(parser: ref MarggersParser, - staticOptions: static MarggersOptions = defaultParserOptions): seq[MarggersElement] = - ## Parses marggers with a reference to an already initialized parser. - result = parseTopLevel(parser[], staticOptions) - -proc parseMarggers*(text: sink NativeString, - options: MarggersOptions = defaultParserOptions, - staticOptions: static MarggersOptions = defaultParserOptions): seq[MarggersElement] = - ## Parses a string of text in marggers and translates it to HTML line by line. - ## Result is a sequence of MarggersElements, to simply generate HTML with no need for readability - ## turn these all into strings with ``$`` and join them with "". - var parser = initMarggersParser(text) - parser.options = options - result = parseMarggers(parser, staticOptions) - -proc parseMarggers*(text: sink (string | cstring), - options: MarggersOptions = defaultParserOptions, - staticOptions: static MarggersOptions = defaultParserOptions): seq[MarggersElement] = - ## Alias of parseMarggers that takes any string as the argument. - result = parseMarggers(NativeString(text), options, staticOptions) - -proc parseMarggers*(text: sink openarray[char], - options: MarggersOptions = defaultParserOptions, - staticOptions: static MarggersOptions = defaultParserOptions): seq[MarggersElement] = - ## Alias of parseMarggers that takes openarray[char] as the argument. - ## - ## Currently copies. - result = parseMarggers(NativeString($text), options, staticOptions) - -when isMainModule: - import os, strutils - case paramStr(1) - of "parse": echo parseMarggers(paramStr(2)).join("\n") - of "file": echo parseMarggers(readFile(paramStr(2))).join("\n") - else: echo "unknown command: ", paramStr(1) diff --git a/src/margrave.nim b/src/margrave.nim new file mode 100644 index 0000000..d6acc46 --- /dev/null +++ b/src/margrave.nim @@ -0,0 +1,67 @@ +## Dialect of Markdown. +## +## Example +## ======= +## +## .. include:: ../examples/ref.mrg +## :literal: +## +## turns into HTML: +## +## .. include:: ../examples/ref.html +## :literal: +## +## Inline HTML note +## **************** +## +## **Note**: Nim's XML parser used for inline HTML uses `StringStream` from +## the `streams` module which does not work in JS for Nim version 1.2.x and +## earlier. To work around this, you can disable use of the XML parser, +## therefore disable inline HTML, by passing `-d:margraveNoInlineHtml`. +## This switch is available on all backends. You can still embed HTML inside +## curly braces. + +import margrave/[common, element, parser, parser/defs] + +export MargraveElement, element.`$`, defs + +proc parseMargrave*(parser: var MargraveParser, + staticOptions: static MargraveOptions = defaultParserOptions): seq[MargraveElement] = + ## Parses margrave with an already initialized parser. + result = parseTopLevel(parser, staticOptions) + +proc parseMargrave*(parser: ref MargraveParser, + staticOptions: static MargraveOptions = defaultParserOptions): seq[MargraveElement] = + ## Parses margrave with a reference to an already initialized parser. + result = parseTopLevel(parser[], staticOptions) + +proc parseMargrave*(text: sink NativeString, + options: MargraveOptions = defaultParserOptions, + staticOptions: static MargraveOptions = defaultParserOptions): seq[MargraveElement] = + ## Parses a string of text in margrave and translates it to HTML line by line. + ## Result is a sequence of MargraveElements, to simply generate HTML with no need for readability + ## turn these all into strings with ``$`` and join them with "". + var parser = initMargraveParser(text) + parser.options = options + result = parseMargrave(parser, staticOptions) + +proc parseMargrave*(text: sink (string | cstring), + options: MargraveOptions = defaultParserOptions, + staticOptions: static MargraveOptions = defaultParserOptions): seq[MargraveElement] = + ## Alias of parseMargrave that takes any string as the argument. + result = parseMargrave(NativeString(text), options, staticOptions) + +proc parseMargrave*(text: sink openarray[char], + options: MargraveOptions = defaultParserOptions, + staticOptions: static MargraveOptions = defaultParserOptions): seq[MargraveElement] = + ## Alias of parseMargrave that takes openarray[char] as the argument. + ## + ## Currently copies. + result = parseMargrave(NativeString($text), options, staticOptions) + +when isMainModule: + import os, strutils + case paramStr(1) + of "parse": echo parseMargrave(paramStr(2)).join("\n") + of "file": echo parseMargrave(readFile(paramStr(2))).join("\n") + else: echo "unknown command: ", paramStr(1) diff --git a/src/marggers/common.nim b/src/margrave/common.nim similarity index 88% rename from src/marggers/common.nim rename to src/margrave/common.nim index 94d0eaf..8a02a47 100644 --- a/src/marggers/common.nim +++ b/src/margrave/common.nim @@ -1,13 +1,13 @@ const - marggersNoDefaultHtmlHandler* {.booldefine.} = false + margraveNoDefaultHtmlHandler* {.booldefine.} = false ## Define this to disable inline HTML at compile time completely, ## to circumvent the standard library XML parser dependency. - ## This is overriden by `MarggersParser.inlineHtmlHandler`. - marggersCurlyNoHtmlEscape* {.booldefine.} = false - ## The default compile time value of `MarggersOptions.curlyNoHtmlEscape`. - marggersSingleLineStaticBool* {.booldefine.} = false + ## This is overriden by `MargraveParser.inlineHtmlHandler`. + margraveCurlyNoHtmlEscape* {.booldefine.} = false + ## The default compile time value of `MargraveOptions.curlyNoHtmlEscape`. + margraveSingleLineStaticBool* {.booldefine.} = false ## Possible minor optimization. Not guaranteed to be faster. - marggersDelimedUseSubstrs* {.booldefine.} = false + margraveDelimedUseSubstrs* {.booldefine.} = false ## Possible minor optimization. Not guaranteed to be faster. when defined(js) and not defined(nimdoc): diff --git a/src/marggers/element.nim b/src/margrave/element.nim similarity index 72% rename from src/marggers/element.nim rename to src/margrave/element.nim index df1684c..6c2cea0 100644 --- a/src/marggers/element.nim +++ b/src/margrave/element.nim @@ -13,7 +13,7 @@ type otherTag #text - MarggersElement* {.acyclic.} = ref object + MargraveElement* {.acyclic.} = ref object ## An individual node. ## ## Can be text, or an HTML element. @@ -35,7 +35,7 @@ type ## with the `emptyTag` attribute. attrs*: OrderedTable[NativeString, NativeString] ## Attributes of an HTML element. - content*: seq[MarggersElement] + content*: seq[MargraveElement] ## Inner HTML elements of an HTML element. const EmptyTags* = {noTag, br, img, input, source, otherTag} @@ -51,31 +51,31 @@ else: ## Returns true if `tag` is an empty tag, i.e. it has no ending tag. tag in EmptyTags -func newStr*(s: NativeString): MarggersElement = +func newStr*(s: NativeString): MargraveElement = ## Creates a new text node with text `s`. - MarggersElement(isText: true, str: s) + MargraveElement(isText: true, str: s) -func newElem*(tag: KnownTags, content: seq[MarggersElement] = @[]): MarggersElement = +func newElem*(tag: KnownTags, content: seq[MargraveElement] = @[]): MargraveElement = ## Creates a new element node with tag `tag` and content nodes `content`. - MarggersElement(isText: false, tag: tag, content: content) + MargraveElement(isText: false, tag: tag, content: content) -func paragraphIfText*(elem: MarggersElement): MarggersElement = +func paragraphIfText*(elem: MargraveElement): MargraveElement = ## If `elem` is a text node, turns it into a element.
## Otherwise returns `elem`.
if elem.isText:
- MarggersElement(isText: false, tag: p, content: @[elem])
+ MargraveElement(isText: false, tag: p, content: @[elem])
else:
elem
-proc attr*(elem: MarggersElement, key: NativeString): NativeString =
+proc attr*(elem: MargraveElement, key: NativeString): NativeString =
## Gets attribute of element
elem.attrs[key]
-proc attr*(elem: MarggersElement, key, val: NativeString) =
+proc attr*(elem: MargraveElement, key, val: NativeString) =
## Adds attribute to element
elem.attrs[key] = val
-proc attrEscaped*(elem: MarggersElement, key, val: NativeString) =
+proc attrEscaped*(elem: MargraveElement, key, val: NativeString) =
## Adds attribute to element escaped
var esc =
when NativeString is string:
@@ -87,48 +87,48 @@ proc attrEscaped*(elem: MarggersElement, key, val: NativeString) =
else: esc.add v
elem.attr(key, esc)
-proc hasAttr*(elem: MarggersElement, key: NativeString): bool =
+proc hasAttr*(elem: MargraveElement, key: NativeString): bool =
## Checks if element has attribute
elem.attrs.hasKey(key)
-proc delAttr*(elem: MarggersElement, key: NativeString) =
+proc delAttr*(elem: MargraveElement, key: NativeString) =
## Deletes attribute of element
elem.attrs.del(key)
-proc style*(elem: MarggersElement, style: NativeString) =
+proc style*(elem: MargraveElement, style: NativeString) =
## Adds style to element
elem.attr("style", style)
-func `[]`*(elem: MarggersElement, i: int): MarggersElement =
+func `[]`*(elem: MargraveElement, i: int): MargraveElement =
## Indexes `elem.content`.
elem.content[i]
-func `[]`*(elem: MarggersElement, i: BackwardsIndex): MarggersElement =
+func `[]`*(elem: MargraveElement, i: BackwardsIndex): MargraveElement =
## Indexes `elem.content`.
elem.content[i]
-func `[]=`*(elem: MarggersElement, i: int, el: MarggersElement) =
+func `[]=`*(elem: MargraveElement, i: int, el: MargraveElement) =
## Indexes `elem.content`.
elem.content[i] = el
-func `[]=`*(elem: MarggersElement, i: BackwardsIndex, el: MarggersElement) =
+func `[]=`*(elem: MargraveElement, i: BackwardsIndex, el: MargraveElement) =
## Indexes `elem.content`.
elem.content[i] = el
-func add*(elem, cont: MarggersElement) =
+func add*(elem, cont: MargraveElement) =
## Adds to `elem.content`.
# was previously template, this broke vM
elem.content.add(cont)
-func add*(elem: MarggersElement, cont: seq[MarggersElement]) =
+func add*(elem: MargraveElement, cont: seq[MargraveElement]) =
## Appends nodes to `elem.content`.
elem.content.add(cont)
-func add*(elem: MarggersElement, str: NativeString) =
+func add*(elem: MargraveElement, str: NativeString) =
## Adds a text node to `elem.content`.
elem.content.add(newStr(str))
-func toNativeString*(elem: MarggersElement): NativeString =
+func toNativeString*(elem: MargraveElement): NativeString =
if elem.isText:
result = elem.str
else:
@@ -169,10 +169,10 @@ func toNativeString*(elem: MarggersElement): NativeString =
result.add(tag)
result.add('>')
-func `$`*(elem: MarggersElement): string =
- ## Outputs a marggers element as HTML.
+func `$`*(elem: MargraveElement): string =
+ ## Outputs a margrave element as HTML.
$toNativeString(elem)
-func toCstring*(elem: MarggersElement): cstring =
- ## Outputs a marggers element as HTML as a cstring, mostly for JS.
+func toCstring*(elem: MargraveElement): cstring =
+ ## Outputs a margrave element as HTML as a cstring, mostly for JS.
cstring(toNativeString(elem))
diff --git a/src/marggers/parser.nim b/src/margrave/parser.nim
similarity index 93%
rename from src/marggers/parser.nim
rename to src/margrave/parser.nim
index 4c55300..22564ed 100644
--- a/src/marggers/parser.nim
+++ b/src/margrave/parser.nim
@@ -1,24 +1,24 @@
import strutils, tables
import ./common, ./element, parser/[defs, utils]
-when not marggersNoDefaultHtmlHandler:
+when not margraveNoDefaultHtmlHandler:
import ./singlexml
-when marggersSingleLineStaticBool:
+when margraveSingleLineStaticBool:
type SingleLineBool = static bool
else:
type SingleLineBool = bool
using
- parser: var MarggersParser
- options: static MarggersOptions
+ parser: var MargraveParser
+ options: static MargraveOptions
-proc parseBracket*(parser; options; image: bool, singleLine: SingleLineBool): MarggersElement
+proc parseBracket*(parser; options; image: bool, singleLine: SingleLineBool): MargraveElement
proc parseCurly*(parser; options): NativeString =
## Parses a curly bracket element.
##
- ## If `-d:marggersCurlyNoHtmlEscape` is defined, initial `!` characters
+ ## If `-d:margraveCurlyNoHtmlEscape` is defined, initial `!` characters
## are ignored and no HTML chars are escaped.
result = ""
when options.curlyNoHtmlEscape:
@@ -107,7 +107,7 @@ proc parseCodeBlockStr*(parser; options; delimChar: char): tuple[language, code:
else: toNativeString ch
)
-proc parseCodeBlock*(parser; options; delimChar: char): MarggersElement {.inline.} =
+proc parseCodeBlock*(parser; options; delimChar: char): MargraveElement {.inline.} =
let str = parseCodeBlockStr(parser, options, delimChar)
result = newElem(pre, @[newStr(str.code)])
withOptions(parser, options, not options.codeBlockLanguageHandler.isNil):
@@ -120,7 +120,7 @@ type
frReachedEnd
frFailed
-proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool): (DelimFinishReason, seq[MarggersElement]) {.gcsafe.} =
+proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool): (DelimFinishReason, seq[MargraveElement]) {.gcsafe.} =
# DelimParser
var
escaped = false
@@ -134,11 +134,11 @@ proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool):
template add(s: string | cstring | char) =
lastStr.str.add(s)
- template add(elem: MarggersElement) =
+ template add(elem: MargraveElement) =
elems.add(elem)
refreshStr()
- template add(newElems: seq[MarggersElement]) =
+ template add(newElems: seq[MargraveElement]) =
elems.add(newElems)
refreshStr()
@@ -147,7 +147,7 @@ proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool):
if not escaped:
let initialPos = parser.pos
- when marggersDelimedUseSubstrs:
+ when margraveDelimedUseSubstrs:
var matchLen: int
let maxIndexAfter3 = min(parser.pos + 3, parser.str.len - 1)
var substrs: array[4, NativeString]
@@ -157,10 +157,10 @@ proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool):
template check(s: string): bool =
substrs[s.len - 1] == s and (matchLen = s.len; true)
- template nextMatch(parser: var MarggersParser, pat: string): bool =
+ template nextMatch(parser: var MargraveParser, pat: string): bool =
check(pat) and (parser.pos += matchLen; true)
- proc parseAux(tag: KnownTags, del: string, parser: var MarggersParser,
+ proc parseAux(tag: KnownTags, del: string, parser: var MargraveParser,
acceptedReasons = {frDone}): DelimFinishReason {.gcsafe.} =
let currentPos = parser.pos
let (finishReason, parsedElems) = parseDelimed(parser, options, del, singleLine)
@@ -177,7 +177,7 @@ proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool):
if reason in {frFailed, frReachedEnd}:
return (reason, elems)
- proc bracket(image: bool, parser: var MarggersParser): DelimFinishReason =
+ proc bracket(image: bool, parser: var MargraveParser): DelimFinishReason =
let elem = parseBracket(parser, options, image, singleLine)
if elem.tag == noTag:
add(if image: NativeString"![" else: NativeString"[")
@@ -239,7 +239,7 @@ proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool):
matchNext parser:
elif (
- when marggersSingleLineStaticBool:
+ when margraveSingleLineStaticBool:
when singleLine: parser.nextMatch("\r\n") or parser.nextMatch("\n")
else: parser.nextMatch("\r\n\r\n") or parser.nextMatch("\n\n")
else:
@@ -293,7 +293,7 @@ proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool):
withOptions(parser, options, not options.inlineHtmlHandler.isNil):
(change, pos) = options.inlineHtmlHandler(parser.str, parser.pos)
do:
- (change, pos) = when marggersNoDefaultHtmlHandler:
+ (change, pos) = when margraveNoDefaultHtmlHandler:
(false, 0)
else:
parseXml($parser.str, parser.pos)
@@ -442,7 +442,7 @@ proc parseReferenceName*(parser; options; failed: var bool): NativeString =
escaped = false
failed = true
-proc parseBracket*(parser; options; image: bool, singleLine: SingleLineBool): MarggersElement =
+proc parseBracket*(parser; options; image: bool, singleLine: SingleLineBool): MargraveElement =
let canBeSub = not image and not parser.prevWhitespace(offset = -1)
let firstPos = parser.pos
let (textWorked, textElems) = parseDelimed(parser, options, "]", singleLine)
@@ -466,11 +466,11 @@ proc parseBracket*(parser; options; image: bool, singleLine: SingleLineBool): Ma
if link.url.len == 0 and textElems.len == 1 and textElems[0].isText:
link.url = strip(textElems[0].str)
if image:
- result = MarggersElement(isText: false, tag: img)
+ result = MargraveElement(isText: false, tag: img)
if secondPos - firstPos > 0:
result.attrEscaped("alt", parser.str[firstPos..secondPos])
else:
- result = MarggersElement(isText: false, tag: a)
+ result = MargraveElement(isText: false, tag: a)
result.content = textElems
if link.tip.len != 0:
result.attrEscaped("title", link.tip)
@@ -485,7 +485,7 @@ proc parseBracket*(parser; options; image: bool, singleLine: SingleLineBool): Ma
parser.pos = initialPos
else:
if refName.len == 0: refName = parser.str[firstPos..secondPos]
- result = MarggersElement(isText: false)
+ result = MargraveElement(isText: false)
if image:
result.tag = img
if secondPos - firstPos > 0:
@@ -509,15 +509,15 @@ proc parseBracket*(parser; options; image: bool, singleLine: SingleLineBool): Ma
if checkMark == 2:
result.attr("checked", "")
-proc parseInline*(parser; options; singleLine: SingleLineBool): seq[MarggersElement] {.inline.} =
+proc parseInline*(parser; options; singleLine: SingleLineBool): seq[MargraveElement] {.inline.} =
let (finishReason, elems) = parseDelimed(parser, options, "", singleLine)
assert finishReason != frFailed
result = elems
-template parseSingleLine*(parser; options): seq[MarggersElement] =
+template parseSingleLine*(parser; options): seq[MargraveElement] =
parseInline(parser, options, singleLine = true)
-template parseLine*(parser; options): seq[MarggersElement] =
+template parseLine*(parser; options): seq[MargraveElement] =
parseInline(parser, options, singleLine = false)
const
@@ -537,10 +537,10 @@ proc parseId*(parser; startChar: char): NativeString =
while (let ch = parser.get(); parser.nextMatch(LegalId)): result.add(ch)
discard parser.nextMatch(idDelim)
-proc parseTopLevel*(parser; options): seq[MarggersElement] =
+proc parseTopLevel*(parser; options): seq[MargraveElement] =
var lastEmptyLine = false
for firstCh in parser.nextChars:
- var context: MarggersElement
+ var context: MargraveElement
block:
var i = 0
while i < parser.contextStack.len:
@@ -567,24 +567,24 @@ proc parseTopLevel*(parser; options): seq[MarggersElement] =
inc i
parser.contextStack.setLen(i)
- template addElement(elem: MarggersElement): untyped =
+ template addElement(elem: MargraveElement): untyped =
let el = elem
if not context.isNil:
context.add(el)
else:
result.add(el)
- template addContext(elem: MarggersElement): untyped =
+ template addContext(elem: MargraveElement): untyped =
let el = elem
addElement(el)
parser.contextStack.add(el)
context = el
proc addLine(
- parser: var MarggersParser;
- options: static MarggersOptions;
- context: MarggersElement;
- result: var seq[MarggersElement];
+ parser: var MargraveParser;
+ options: static MargraveOptions;
+ context: MargraveElement;
+ result: var seq[MargraveElement];
lastEmptyLine: bool;
rawLine: static bool = false) {.nimcall.} =
template rawOrNot(t, els): untyped =
@@ -732,5 +732,5 @@ proc parseTopLevel*(parser; options): seq[MarggersElement] =
lastEmptyLine = false
when isMainModule:
- import ../marggers
- discard parseMarggers("# hello")
+ import ../margrave
+ discard parseMargrave("# hello")
diff --git a/src/marggers/parser/defs.nim b/src/margrave/parser/defs.nim
similarity index 81%
rename from src/marggers/parser/defs.nim
rename to src/margrave/parser/defs.nim
index 16a7747..8319928 100644
--- a/src/marggers/parser/defs.nim
+++ b/src/margrave/parser/defs.nim
@@ -6,7 +6,7 @@ type
tip*: NativeString
altUrls*: seq[NativeString]
- MarggersOptions* {.byref.} = object
+ MargraveOptions* {.byref.} = object
curlyNoHtmlEscape*: bool
## Define this to disable HTML escaping inside curly brackets
## (normally only formatting is disabled).
@@ -25,14 +25,14 @@ type
## Not nil value at compile time overrides runtime value.
##
## See `singlexml.parseXml To escape use \\ < a\nb c\nd\ne f g a c f g a c f g
b
d
e
b
d
e