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