Files
org-parser/src_v2/org/org_builder_paragraph.nim
Florian Schroedl 6e50d9f013 Stuff
2023-10-04 15:02:49 +02:00

139 lines
3.3 KiB
Nim

import std/[
collections/sequtils,
sugar,
]
import fp/[
option,
resultM,
]
import ./org_types
import ./org_builder_api
import ./org_builder_link
import ./org_builder_inline_text
import ../parser/parser
import ../utils/fp
import fusion/matching
{.experimental: "caseStmtMacros".}
# let lineTokenizer = (builder: OrgInlineBuilder) => tryTokenize(
# builder = builder,
# builderFns = styledTextTokenizers,
# defaultTokenizerFn = tryTokenizeRawText,
# )
# OrgDocucment
# -> Seq [Builder -> Builder]
# One of OrgBlock
# @[
# OrgBuilderResult -> OrgBuilderResult
# ]
# with default OrgBuilder -> OrgBuilder
# until Eol
let lineParser = anyUntil(newlineOrEol)
let listTypesParser = choice(@[
ch('-'),
ch('+'),
choice(@[letter, digit]) + choice(@[ch('.'), ch(')')]),
])
let listStartParser = manyUntil(space, listTypesParser)
let listTypeParser = listTypesParser + ignore(space)
let listContentParser = anyUntil(newlineOrEol) + ignore(newlineOrEol)
let buildListItem = proc(builder: OrgBuilder): OrgBuilderResult {.closure.} =
let (parser, tree) = builder
let beforeSpaces = ParserResult.ok(parser)
.flatMap(listStartParser)
.map(flattenTokens)
let listType = beforeSpaces
.map(emptyTokens)
.flatMap(listTypeParser)
.map(flattenTokens)
let listContent = listType
.map(emptyTokens)
.flatMap(listContentParser)
.map(flattenTokens)
case (beforeSpaces, listType, listContent):
of (Some(@space), Some(@symbol), Some(@content)):
let treeResult = tree &
OrgBlock(
kind: orgList,
listIndentation: 1,
listBulletType: '-',
listContent: tryTokenizeInline(content.tokens.tokensToString()).unsafeGet().tree
)
OrgBuilderResult.ok(OrgBuilder((
parser: content,
tree: treeResult,
)))
else: OrgBuilderResult.err(OrgBuilderError(
kind: parserError,
parser: listContent,
tree: tree,
))
proc buildParagraph*(
builder: OrgBuilder,
builderFns: seq[proc (builder: OrgBuilder): OrgBuilderResult],
stopAtParserFn = endOfStream,
): OrgBuilderResult =
var builderAcc: OrgBuilderResult = OrgBuilderResult.ok(builder)
while builderAcc.isOk() and builderAcc.tryParserResult(stopAtParserFn).isErr():
var found = false
for builderFn in builderFns:
# let (builderFn) = fn
let builderResult: OrgBuilderResult = builderAcc.flatMap(builderFn)
if builderResult.isOk():
found = true
builderAcc = builderResult
break
if not found:
builderAcc
.flatMap((builder: OrgBuilder) => tryTokenize(
builder = builder,
builderFns = styledTextTokenizers,
defaultTokenizerFn = tryTokenizeRawText,
))
.fold(
OrgInlineBuilder
)
builderAcc = OrgBuilderResult.err(OrgBuilderError(
kind: builderError,
parser: builderAcc.fold(
(err: OrgBuilderError) => err.parser,
(builder: OrgBuilder) => ParserResult.ok(builder.parser),
),
tree: builder.tree,
))
break
builderAcc
let paragraphBuilders: seq[proc (builder: OrgBuilder): OrgBuilderResult] = @[buildListItem]
when isMainModule:
block testParsers:
let test = initOrgBuilder("""- List item
1. List item
random stuff""").flatMap((builder: OrgBuilder) => builder.buildParagraph(paragraphBuilders))
echo test