import std/strutils import std/re import std/parseutils import std/strformat import std/sugar import fusion/matching import fp/maybe import fp/list import utils/fp {.experimental: "caseStmtMacros".} type contentT = string type headlingLevelT = int type lineNumberT = int type lineCharT = int type posT = (lineNumberT, lineCharT) type OrgBlockKind* = enum Document, Heading, NotImplemented OrgBlock* = ref object # position: posT case kind*: OrgBlockKind of Heading: content*: contentT level*: headlingLevelT else: str: string proc `$`*(x: OrgBlock): string = case x: of Document(): return &"""OrgBlock( kind: Document, )""" of Heading(content: @content, level: @level): return &"""OrgBlock( kind: Heading, content: {content}, level: {level}, )""" of NotImplemented(str: @str): return &"""OrgBlock( kind: NotImplemented, str: {str}, )""" proc parseHeadline(line: string): Maybe[OrgBlock] = if line.startsWith("*"): var token: string let idx = line.parseWhile(token, validChars = { '*' }) # Eat the first space character let content = line[idx + 1 .. ^1] Just(OrgBlock( kind: Heading, level: idx, content: content, )) else: Nothing[OrgBlock]() let parsers = @[ parseHeadline, ] proc parseLine(line: string): any = parsers .findMaybeFn(line) # .fold( # () => OrgBlock(kind: NotImplemented, str: line), # x => x.get(), # ) echo parseLine("**** foo :bar:")