From 316c35f918403750415f5b679d95619de51a954b Mon Sep 17 00:00:00 2001 From: metagn Date: Fri, 11 Oct 2024 16:44:29 +0300 Subject: [PATCH] give tag enum proper names --- margrave.nimble | 2 +- src/margrave/common.nim | 5 ++- src/margrave/element.nim | 25 ++++++----- src/margrave/parser.nim | 84 +++++++++++++++++------------------ src/margrave/parser/utils.nim | 18 ++++---- 5 files changed, 69 insertions(+), 65 deletions(-) diff --git a/margrave.nimble b/margrave.nimble index 02a00aa..2ac8630 100644 --- a/margrave.nimble +++ b/margrave.nimble @@ -1,4 +1,4 @@ -version = "0.4.0" +version = "0.4.1" author = "metagn" description = "markdown dialect" license = "MIT" diff --git a/src/margrave/common.nim b/src/margrave/common.nim index 8a02a47..1746f2e 100644 --- a/src/margrave/common.nim +++ b/src/margrave/common.nim @@ -69,5 +69,8 @@ func toCstring*[T: enum](x: T): cstring = for i in 1 ..< impl.len: let e = impl[i] let z = if e.kind in {nnkIdent, nnkSym}: e else: e[0] - result.add(newTree(nnkOfBranch, z, newAssignment(ident"result", newCall(bindSym"cstring", newLit($e))))) + result.add(newTree(nnkOfBranch, z, + newAssignment(ident"result", + newCall(bindSym"cstring", + newCall(bindSym"$", e))))) gen(x) diff --git a/src/margrave/element.nim b/src/margrave/element.nim index 6c2cea0..6452753 100644 --- a/src/margrave/element.nim +++ b/src/margrave/element.nim @@ -3,14 +3,15 @@ import ./common, tables type KnownTags* = enum ## Enum of tags used in this library. - noTag, - p, br, - h1, h2, h3, h4, h5, h6, - ul, ol, li, blockquote, - sup, sub, em, strong, pre, code, u, s, - img, input, a, - picture, video, audio, source, - otherTag + tagNone = "", + tagParagraph = "p", tagLineBreak = "br", + tagHeader1 = "h1", tagHeader2 = "h2", tagHeader3 = "h3", tagHeader4 = "h4", tagHeader5 = "h5", tagHeader6 = "h6", + tagUnorderedList = "ul", tagOrderedList = "ol", tagListItem = "li", tagBlockquote = "blockquote", + tagSuperscript = "sup", tagSubscript = "sub", tagItalic = "em", tagBold = "strong", + tagPreformatted = "pre", tagCode = "code", tagUnderline = "u", tagStrikethrough = "s", + tagImage = "img", tagInput = "input", tagLinked = "a", + tagPicture = "picture", tagVideo = "video", tagAudio = "audio", tagSource = "source", + tagOther = "unknownTag" #text MargraveElement* {.acyclic.} = ref object @@ -38,7 +39,7 @@ type content*: seq[MargraveElement] ## Inner HTML elements of an HTML element. -const EmptyTags* = {noTag, br, img, input, source, otherTag} +const EmptyTags* = {tagNone, tagLineBreak, tagImage, tagInput, tagSource, tagOther} when defined(js): func isEmpty*(tag: KnownTags): bool {.inline.} = @@ -63,7 +64,7 @@ func paragraphIfText*(elem: MargraveElement): MargraveElement = ## If `elem` is a text node, turns it into a

element. ## Otherwise returns `elem`. if elem.isText: - MargraveElement(isText: false, tag: p, content: @[elem]) + MargraveElement(isText: false, tag: tagParagraph, content: @[elem]) else: elem @@ -135,8 +136,8 @@ func toNativeString*(elem: MargraveElement): NativeString = var empty = elem.tag.isEmpty var tag: NativeString case elem.tag - of noTag: discard # tag stays empty - of otherTag: + of tagNone: discard # tag stays empty + of tagOther: if elem.hasAttr("tag"): tag = elem.attr("tag") empty = elem.hasAttr("emptyTag") diff --git a/src/margrave/parser.nim b/src/margrave/parser.nim index 22564ed..cab51d7 100644 --- a/src/margrave/parser.nim +++ b/src/margrave/parser.nim @@ -109,7 +109,7 @@ proc parseCodeBlockStr*(parser; options; delimChar: char): tuple[language, code: proc parseCodeBlock*(parser; options; delimChar: char): MargraveElement {.inline.} = let str = parseCodeBlockStr(parser, options, delimChar) - result = newElem(pre, @[newStr(str.code)]) + result = newElem(tagPreformatted, @[newStr(str.code)]) withOptions(parser, options, not options.codeBlockLanguageHandler.isNil): if str.language.len != 0: options.codeBlockLanguageHandler(result, str.language) @@ -179,7 +179,7 @@ proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool): proc bracket(image: bool, parser: var MargraveParser): DelimFinishReason = let elem = parseBracket(parser, options, image, singleLine) - if elem.tag == noTag: + if elem.tag == tagNone: add(if image: NativeString"![" else: NativeString"[") add(elem.content) #result = frFailed @@ -196,7 +196,7 @@ proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool): if parser.nextMatch("**"): let (finishReason, parsedElems) = parseDelimed(parser, options, "**", singleLine) if finishReason == frDone: - add(newElem(strong, parsedElems)) + add(newElem(tagBold, parsedElems)) #inc parser.pos continue else: @@ -215,7 +215,7 @@ proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool): if parser.nextMatch("__"): let (finishReason, parsedElems) = parseDelimed(parser, options, "__", singleLine) if finishReason == frDone: - add(newElem(u, parsedElems)) + add(newElem(tagUnderline, parsedElems)) #inc parser.pos continue else: @@ -254,20 +254,20 @@ proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool): elif not singleLine and (parser.nextMatch("\r\n") or parser.nextMatch("\n")): dec parser.pos withOptions(parser, options, options.insertLineBreaks): - add(newElem(br)) + add(newElem(tagLineBreak)) do: add(ch) of " \r\n", " \n": dec parser.pos - add(newElem(br)) + add(newElem(tagLineBreak)) of "```": add(parseCodeBlock(parser, options, '`')) of "~~~": add(parseCodeBlock(parser, options, '~')) - of "^(": parse(sup, ")") - of "**": parse(strong, "**") - of "__": parse(u, "__") - of "~~": parse(s, "~~") + of "^(": parse(tagSuperscript, ")") + of "**": parse(tagBold, "**") + of "__": parse(tagUnderline, "__") + of "~~": parse(tagStrikethrough, "~~") of "![": let reason = bracket(image = true, parser) if reason in {frFailed, frReachedEnd}: @@ -278,13 +278,13 @@ proc parseDelimed*(parser; options; delim: string, singleLine: SingleLineBool): let reason = bracket(image = false, parser) if reason in {frFailed, frReachedEnd}: return (reason, elems) - of '`': parse(code, "`") + of '`': parse(tagCode, "`") elif parser.noAdjacentWhitespace() and parser.nextMatch('^'): - parse(sup, " ", {frDone, frReachedEnd}) + parse(tagSuperscript, " ", {frDone, frReachedEnd}) elif not parser.surroundedWhitespace() and parser.nextMatch('*'): - parse(em, "*") + parse(tagItalic, "*") elif parser.onlyPrevWhitespace() and parser.nextMatch('_'): - parse(em, "_") + parse(tagItalic, "_") of '<': dec parser.pos var @@ -449,7 +449,7 @@ proc parseBracket*(parser; options; image: bool, singleLine: SingleLineBool): Ma inc parser.pos let secondPos = parser.pos - 2 if textWorked != frDone: - return newElem(noTag, textElems) + return newElem(tagNone, textElems) let checkMark = if not image and textElems.len == 1 and textElems[0].isText and textElems[0].str.len == 1: case textElems[0].str[0] @@ -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 = MargraveElement(isText: false, tag: img) + result = MargraveElement(isText: false, tag: tagImage) if secondPos - firstPos > 0: result.attrEscaped("alt", parser.str[firstPos..secondPos]) else: - result = MargraveElement(isText: false, tag: a) + result = MargraveElement(isText: false, tag: tagLinked) result.content = textElems if link.tip.len != 0: result.attrEscaped("title", link.tip) @@ -487,11 +487,11 @@ proc parseBracket*(parser; options; image: bool, singleLine: SingleLineBool): Ma if refName.len == 0: refName = parser.str[firstPos..secondPos] result = MargraveElement(isText: false) if image: - result.tag = img + result.tag = tagImage if secondPos - firstPos > 0: result.attrEscaped("alt", parser.str[firstPos..secondPos]) else: - result.tag = a + result.tag = tagLinked result.content = textElems parser.linkReferrers.mgetOrPut(refName, @[]).add(result) return @@ -499,11 +499,11 @@ proc parseBracket*(parser; options; image: bool, singleLine: SingleLineBool): Ma dec parser.pos if image: # this could be used like a directive tag - result = newElem(noTag, textElems) + result = newElem(tagNone, textElems) elif checkMark == 0: - result = newElem(if canBeSub: sub else: (dec parser.pos; noTag), textElems) + result = newElem(if canBeSub: tagSubscript else: (dec parser.pos; tagNone), textElems) else: - result = newElem(input) + result = newElem(tagInput) result.attr("type", "checkbox") result.attr("disabled", "") if checkMark == 2: @@ -521,7 +521,7 @@ template parseLine*(parser; options): seq[MargraveElement] = parseInline(parser, options, singleLine = false) const - SpecialLineTags* = {ul, ol, blockquote} + SpecialLineTags* = {tagUnorderedList, tagOrderedList, tagBlockquote} IdStarts* = {'(', '[', '{', ':'} LegalId* = {'a'..'z', 'A'..'Z', '0'..'9', '-', '_', ':', '.'} InlineWhitespace* = Whitespace - {'\r', '\n'} @@ -546,11 +546,11 @@ proc parseTopLevel*(parser; options): seq[MargraveElement] = while i < parser.contextStack.len: let c = parser.contextStack[i] case c.tag - of ul: + of tagUnorderedList: if parser.nextMatch({'*', '-', '+'}): while parser.nextMatch(InlineWhitespace): discard else: break - of ol: + of tagOrderedList: let originalPos = parser.pos while parser.nextMatch(Digits): discard if parser.nextMatch('.'): @@ -558,7 +558,7 @@ proc parseTopLevel*(parser; options): seq[MargraveElement] = else: parser.pos = originalPos break - of blockquote: + of tagBlockquote: if parser.nextMatch('>'): while parser.nextMatch(InlineWhitespace): discard else: break @@ -594,19 +594,19 @@ proc parseTopLevel*(parser; options): seq[MargraveElement] = newElem(t, els) if not context.isNil: case context.tag - of ol, ul: - context.add rawOrNot(li, parseSingleLine(parser, options)) - of blockquote: + of tagOrderedList, tagUnorderedList: + context.add rawOrNot(tagListItem, parseSingleLine(parser, options)) + of tagBlockquote: let c = parseSingleLine(parser, options) if not lastEmptyLine and context.content.len != 0 and - (let last = context[^1]; not last.isText and last.tag == p): + (let last = context[^1]; not last.isText and last.tag == tagParagraph): addNewline(parser, options, last) last.add(c) else: - context.add rawOrNot(p, c) + context.add rawOrNot(tagParagraph, c) else: discard # unreachable else: - result.add rawOrNot(p, parseLine(parser, options)) + result.add rawOrNot(tagParagraph, parseLine(parser, options)) template addLine(rawLine: static bool = false) = addLine(parser, options, context, result, lastEmptyLine, rawLine) @@ -632,8 +632,8 @@ proc parseTopLevel*(parser; options): seq[MargraveElement] = else: addLine() of '#': - if context.isNil or context.tag in {blockquote, p}: - while not context.isNil and context.tag == p: + if context.isNil or context.tag in {tagBlockquote, tagParagraph}: + while not context.isNil and context.tag == tagParagraph: let last = parser.contextStack.len - 1 context = parser.contextStack[last] parser.contextStack.setLen(last) @@ -641,7 +641,7 @@ proc parseTopLevel*(parser; options): seq[MargraveElement] = var level = 1 while level < 6 and parser.peekMatch('#', offset = level): inc level parser.pos += level - let header = newElem(KnownTags(static(h1.int - 1) + level)) + let header = newElem(KnownTags(static(tagHeader1.int - 1) + level)) parser.matchNext: of '|': style header, "text-align:center" of '<': style header, "text-align:left" @@ -654,11 +654,11 @@ proc parseTopLevel*(parser; options): seq[MargraveElement] = addLine() of '*', '-', '+': if parser.nextMatch(InlineWhitespace, offset = 1): - addContext newElem(ul) + addContext newElem(tagUnorderedList) addLine() elif parser.nextMatch(IdStarts, offset = 1): - let list = newElem(ul) - var item = newElem(li) + let list = newElem(tagUnorderedList) + var item = newElem(tagListItem) item.attr("id", parser.parseId(parser.get(-1))) item.content = parseSingleLine(parser, options) list.add(item) @@ -670,8 +670,8 @@ proc parseTopLevel*(parser; options): seq[MargraveElement] = inc parser.pos while parser.nextMatch(Digits): discard if parser.nextMatch('.'): - let list = newElem(ol) - var item = newElem(li) + let list = newElem(tagOrderedList) + var item = newElem(tagListItem) if (let ch = parser.get(); parser.nextMatch(IdStarts)): item.attr("id", parser.parseId(ch)) item.add(parseSingleLine(parser, options)) @@ -681,7 +681,7 @@ proc parseTopLevel*(parser; options): seq[MargraveElement] = parser.pos = originalPos addLine() of '>': - let quote = newElem(blockquote) + let quote = newElem(tagBlockquote) inc parser.pos if (let ch = parser.get(); parser.nextMatch(IdStarts)): quote.attr("id", parser.parseId(ch)) @@ -717,7 +717,7 @@ proc parseTopLevel*(parser; options): seq[MargraveElement] = of '<': align = "text-align:left" of '>': align = "text-align:right" else: align = "text-align:center" - let el = newElem(p, parseLine(parser, options)) + let el = newElem(tagParagraph, parseLine(parser, options)) style el, align result.add(el) elif parser.nextMatch("```"): diff --git a/src/margrave/parser/utils.nim b/src/margrave/parser/utils.nim index 3c58dbc..84f7386 100644 --- a/src/margrave/parser/utils.nim +++ b/src/margrave/parser/utils.nim @@ -32,17 +32,17 @@ proc setLinkDefault*(elem: MargraveElement, link: Link) = ## an audio element; then the `src` attribute will be set to `link`. ## Other tags for `elem` also set the `src` attribute to `link`. case elem.tag - of a: + of tagLinked: elem.attrEscaped("href", link.url) - of img: + of tagImage: let firstUrl = link.url if (firstUrl.len >= 4 and firstUrl[^4 .. ^1] in [NativeString".mp4", ".m4v", ".mov", ".ogv"]) or (firstUrl.len >= 5 and firstUrl[^5 .. ^1] == ".webm"): - elem.tag = video + elem.tag = tagVideo elif (firstUrl.len >= 4 and firstUrl[^4 .. ^1] in [NativeString".mp3", ".oga", ".ogg", ".wav"]) or (firstUrl.len >= 5 and firstUrl[^5 .. ^1] == ".flac"): - elem.tag = audio - if elem.tag != img: + elem.tag = tagAudio + if elem.tag != tagImage: elem.attr("controls", "") var altText: NativeString if elem.attrs.pop("alt", altText): @@ -51,14 +51,14 @@ proc setLinkDefault*(elem: MargraveElement, link: Link) = elem.attrEscaped("src", link.url) else: var sourceAttr: NativeString - if elem.tag == img: - elem.tag = picture + if elem.tag == tagImage: + elem.tag = tagPicture sourceAttr = "srcset" else: sourceAttr = "src" var i = 0 template addSource(u) = - let srcElem = newElem(source) + let srcElem = newElem(tagSource) srcElem.attr(sourceAttr, u) elem.content.insert(srcElem, i) inc i @@ -77,7 +77,7 @@ proc setLink*(parser: MargraveParser, options: static MargraveOptions, elem: Mar proc addNewline*(parser: MargraveParser, options: static MargraveOptions, elem: MargraveElement | seq[MargraveElement]) = withOptions(parser, options, options.insertLineBreaks): - elem.add(newElem(br)) + elem.add(newElem(tagLineBreak)) do: elem.add("\n")