90 lines
2.3 KiB
Nim
90 lines
2.3 KiB
Nim
import std/[
|
|
collections/sequtils,
|
|
strformat,
|
|
sugar,
|
|
]
|
|
import fp/[
|
|
option,
|
|
resultM,
|
|
]
|
|
import ./org_types
|
|
import ./org_builder_api
|
|
import ../parser/parser
|
|
import ../utils/fp
|
|
|
|
import fusion/matching
|
|
{.experimental: "caseStmtMacros".}
|
|
|
|
# -- Parsers
|
|
|
|
let linkStartParser* = following(@[
|
|
ignore(str("[[")),
|
|
anyUntil(choice(@[str("]["), str("]]")])),
|
|
optional(ignore(str("][")))
|
|
])
|
|
let linkEndParser* = following(@[
|
|
anyUntil(str("]]")),
|
|
ignore(str("]]")),
|
|
])
|
|
|
|
let linkParser* = proc(parser: Parser): ParserResult {.closure.} =
|
|
# Parse an an org link in the `parser` state.
|
|
# Return two tokens for a link with description: [[url][description]]
|
|
# Return one token for a link without description : [[url]]
|
|
let linkUrl = linkStartParser(parser)
|
|
.map(flattenTokens)
|
|
|
|
let linkValue = linkUrl
|
|
.map(emptyTokens)
|
|
.flatMap(linkEndParser)
|
|
.map(flattenTokens)
|
|
|
|
case (linkUrl, linkValue):
|
|
of (Some(@key), Some(@value)):
|
|
ParserResult.ok(
|
|
Parser(
|
|
state: value.state,
|
|
tokens: @[
|
|
key.tokens[0],
|
|
value.tokens[0],
|
|
],
|
|
)
|
|
)
|
|
else:
|
|
linkValue
|
|
|
|
# -- Tokenizers
|
|
|
|
func linkStringifier*(linkUrl: string, linkDescription: Option[string]): string =
|
|
case (linkUrl, linkDescription):
|
|
of (@linkUrl, Some(@linkDescription)):
|
|
return &"[[{linkUrl}][{linkDescription}]]"
|
|
of (@linkUrl, None()):
|
|
return &"[[{linkUrl}]]"
|
|
|
|
let linkTokenizer* = func(parserTokens: seq[ParserToken]): seq[OrgInlineBuilderT] {.closure.} =
|
|
[@linkUrl, @linkDescription] := parserTokens.map(toString)
|
|
let linkDescriptionOption = linkDescription.some().notEmpty()
|
|
return @[
|
|
OrgInlineBuilderT(
|
|
kind: orgLink,
|
|
content: linkStringifier(linkUrl, linkDescriptionOption),
|
|
linkUrl: linkUrl,
|
|
linkDescription: linkDescriptionOption,
|
|
)
|
|
]
|
|
|
|
when isMainModule:
|
|
block testParsers:
|
|
proc testParser(str: string, parser: parserFnT): string =
|
|
initParserResult(str).flatMap(parser).tokensToString()
|
|
|
|
assert testParser("[[placeholder.com]]", linkParser) == "placeholder.com"
|
|
assert testParser("[[placeholder.com][ - title]]", linkParser) == "placeholder.com - title"
|
|
|
|
# .linkParser()
|
|
# .foldTokens(
|
|
# onError = xs => newSeq[OrgInlineBuilderT](),
|
|
# onSuccess = linkTokenizer,
|
|
# )
|