diff --git a/src_v2/org/org_builder.nim b/src_v2/org/org_builder.nim new file mode 100644 index 0000000..e4b4275 --- /dev/null +++ b/src_v2/org/org_builder.nim @@ -0,0 +1,61 @@ +import std/[ + collections/sequtils, + sugar, +] +import fp/[ + resultM, +] +import ./org_types +import ../parser/parser + +# -- OrgInlineBlock.Builder.Type + +type OrgInlineBuilderT* = OrgInlineBlock +type OrgInlineBuilder* = Builder[OrgInlineBuilderT] +type OrgInlineBuilderResult* = BuilderResult[OrgInlineBuilderT] + +# -- OrgInlineBlock.Builder.Initializers + +func initOrgInlineBuilder*(content: string): OrgInlineBuilderResult = + return OrgInlineBuilderResult.ok(OrgInlineBuilder(( + parser: initParser(content), + tree: newSeq[OrgInlineBuilderT](), + ))) + +func convertTokens*(kind: orgInlineBlockKind): seq[ParserToken] -> seq[OrgInlineBuilderT] = + return func(tokens: seq[ParserToken]): seq[OrgInlineBuilderT] = + return @[ + OrgInlineBuilderT( + kind: kind, + content: tokens.tokensToString(), + ) + ] + +# func rawTextTokenizer*(kind: orgInlineBlockKind): string -> OrgInlineBuilderT = +# return func(content: string): OrgInlineBuilderT = +# return OrgInlineBuilderT( +# kind: kind, +# content: content, +# ) + +# ## Blocks +# type OrgBuilderT* = OrgBlock +# type OrgBuilder* = Builder[OrgBuilderT] +# type OrgBuilderResult* = BuilderResult[OrgBuilderT] + +# func initOrgBuilder*(content: string): OrgBuilderResult = +# return OrgBuilderResult.ok(OrgBuilder(( +# parser: initParser(content), +# tree: newSeq[OrgBuilderT](), +# ))) + +# # proc orgBuilderConcat*(typeInfo: OrgBuilderT, concatFn: (ParserToken, OrgBuilderT) -> OrgBuilderT): +# # (seq[ParserToken], OrgBuilderT) -> OrgBuilderT = +# # return proc(xs: seq[ParserToken], builder: OrgBuilderT): OrgBuilderT = +# # return xs.foldl(concatFn(b, a), typeInfo) + + +# proc orgBuilderApply*(concatFn: (ParserToken, OrgBuilderT) -> OrgBuilderT): +# (seq[ParserToken], OrgBuilderT) -> OrgBuilderT = +# return proc(tokens: seq[ParserToken], builder: OrgBuilderT): OrgBuilderT = +# tokens.foldl(concatFn(b, a), builder) diff --git a/src_v2/org/org_text_delimiter.nim b/src_v2/org/org_text_delimiter.nim new file mode 100644 index 0000000..0f01fb1 --- /dev/null +++ b/src_v2/org/org_text_delimiter.nim @@ -0,0 +1,80 @@ +import std/[ + collections/sequtils, + strformat, + strutils, + sugar, +] +import fp/[ + resultM, +] +import ./org_types +import ./org_builder +import ../parser/parser +# import ./org_text_link +# import ../utils/fp +# import ../parser/parser_internals +# import ../parser/parser_types +# import ../parser/builder_api + +# -- Parsers + +let boldParser* = anyBetweenPair(ch('*')) +let italicParser* = anyBetweenPair(ch('/')) +let underlineParser* = anyBetweenPair(ch('_')) +let verbatimParser* = anyBetweenPair(ch('=')) +let codeParser* = anyBetweenPair(ch('~')) +let strikeThroughParser* = anyBetweenPair(ch('+')) + +# let rawTokenizer* = rawTextTokenizer(orgRawText) +# let boldTokenizer* = textTokenizer(orgBoldText) +# let italicTokenizer* = textTokenizer(orgItalicText) +# let underlineTokenizer* = textTokenizer(orgUnderlineText) +# let verbatimTokenizer* = textTokenizer(orgVerbatimText) +# let codeTokenizer* = textTokenizer(orgCodeText) +# let strikeThroughTokenizer* = textTokenizer(orgStrikeThroughText) + +# let tok = linkTokenizerSeq + +# let orgStyledTextBuilders = @[ +# (boldParser, boldTokenizer), +# (italicParser, italicTokenizer), +# (underlineParser, underlineTokenizer), +# (verbatimParser, verbatimTokenizer), +# (codeParser, codeTokenizer), +# (strikeThroughParser, strikeThroughTokenizer), +# (linkParser, linkTokenizerSeq), +# ] + +# proc makeRawTokenOrEmpty(tokens: seq[ParserToken]): seq[OrgInlineBuilderT] = +# ## Merge all parser `tokens` into a string to tokenize for the builder. +# ## Unless the string is empty, in this case return an empty list. +# let str = tokens.foldl(a & b.tokenStringValue(), "") +# if str.len == 0: @[] +# else: @[rawTokenizer(str)] + +# proc tryBuildInline*(content: string): OrgInlineBuilderResult = +# initOrgInlineBuilder(content) +# .flatMap((builder: OrgInlineBuilder) => tryParseBuild( +# builder = builder, +# builderFns = orgStyledTextBuilders, +# defaultBuilderFn = makeRawTokenOrEmpty, +# )) + +# when isMainModule: +# let test = tryBuildInline( +# "Regular *bold* [[placeholder.com]] /italic/ _underline_ =verbatim= ~code~ +strikethrough+ [[https://placeholder.com][title]]" +# ) + +# echo test + +when isMainModule: + block testParsers: + proc testParser(str: string, parser: parserFnT): string = + initParserResult(str).flatMap(parser).tokensToString() + + assert testParser("*bold*", boldParser) == "bold" + assert testParser("/italic/", italicParser) == "italic" + assert testParser("_underline_", underlineParser) == "underline" + assert testParser("=verbatim=", verbatimParser) == "verbatim" + assert testParser("~code~", codeParser) == "code" + assert testParser("+strikeThrough+", strikeThroughParser) == "strikeThrough" diff --git a/src_v2/org/org_types.nim b/src_v2/org/org_types.nim new file mode 100644 index 0000000..4f8cc53 --- /dev/null +++ b/src_v2/org/org_types.nim @@ -0,0 +1,209 @@ +import std/[ + sequtils, + strutils, + sugar, +] +import fp/[ + option, +] +import ../utils/printers + +# -- OrgInlineBlock.Type + +type + orgInlineBlockKind* = enum + orgRawText, + orgText, + + # Formating + orgBoldText, + orgItalicText, + orgUnderlineText, + orgVerbatimText, + orgCodeText, + orgStrikeThroughText, + + # Links + orgLink, + + OrgInlineBlock* = ref object + children*: seq[OrgInlineBlock] + content*: string + + case kind*: orgInlineBlockKind + of orgRawText: discard + of orgText: discard + + # Formating + of orgBoldText: discard + of orgItalicText: discard + of orgUnderlineText: discard + of orgVerbatimText: discard + of orgCodeText: discard + of orgStrikeThroughText: discard + + # Links + of orgLink: + linkUrl*: string + linkDescription*: Option[string] + +# -- OrgInlineBlock.PrettyPrinters + +proc `$`*(x: orgInlineBlockKind): string = + case x: + of orgRawText: "Text (Raw)" + of orgText: "Text" + + # Formating + of orgBoldText: "Text (Bold)" + of orgItalicText: "Text (Italic)" + of orgUnderlineText: "Text (Underline)" + of orgVerbatimText: "Text (Verbatim)" + of orgCodeText: "Text (Code)" + of orgStrikeThroughText: "Text (StrikeThrough)" + + # Links + of orgLink: "Link" + +const PPRINT_INDENT_SIZE* = 2 + +func pprint*(x: OrgInlineBlock, indent = 0): string = + let specialFields = case x.kind: + of orgLink: + @[ + ("linkUrl", $x.linkUrl, true), + ("linkDescription", x.linkDescription.getOrElse(""), x.linkDescription.isSome()), + ] + else: @[] + + let fields = @[ + ("kind", $x.kind, true), + ("content", $x.content, x.content.len != 0), + ] + .concat(specialFields) + .stringifyFields() + + stringifyBlock( + "OrgInlineBlock", + indent, + fields, + ) + +func `$`*(x: OrgInlineBlock): string = pprint(x) + +func pprint*(xs: seq[OrgInlineBlock], indent = 0): string = + stringifySeq(xs, (x: OrgInlineBlock) => pprint(x, indent), indent) + +func `$`*(xs: seq[OrgInlineBlock]): string = pprint(xs) + +## -- OrgBlock.Type + +type + orgBlockKind* = enum + orgHeading + orgParagraph + orgNewline + OrgBlock* = ref object + children*: seq[OrgInlineBlock] + + case kind*: orgBlockKind + of orgHeading: + level*: int + todo*: Option[string] + headlineContent*: seq[OrgInlineBlock] + content*: seq[OrgBlock] + of orgParagraph: + paragraphContent: seq[OrgInlineBlock] + of orgNewline: discard + +## -- OrgBlock.PrettyPrinters + +func pprint*(x: OrgBlock, indent = 0): string = + let fields = case x.kind: + of orgHeading: + @[ + ("kind", $x.kind, true), + ("level", $x.level, true), + ("todo", $x.todo, x.todo.isSome()), + ("headlineContent", $x.headlineContent, x.headlineContent.len != 0), + ("children", $x.children, x.children.len != 0), + ( + "content", + ("@[\n" & + x.content.map((x) => pprint(x)).join(",\n").indent(PPRINT_INDENT_SIZE) & + ",\n]," + ).indent(indent), + x.content.len != 0 + ), + ] + of orgParagraph: + @[ + ("kind", $x.kind, true), + ("paragraphContent", $x.paragraphContent, x.paragraphContent.len != 0), + ] + else: + @[ + ("kind", $x.kind, true), + ] + + stringifyBlock( + "OrgBlock", + indent, + fields.stringifyFields(), + ) + +func `$`*(x: OrgBlock): string = pprint(x) + +func pprint*(xs: seq[OrgBlock], indent = 0): string = + stringifySeq(xs, (x: OrgBlock) => pprint(x, indent), indent) + +func `$`*(xs: seq[OrgBlock]): string = pprint(xs) + +# -- OrgDocument.Type + +type + OrgDocument* = ref object + children*: seq[OrgBlock] + +# -- OrgDocument.PrettyPrinters + +func pprint*(x: OrgDocument, indent = 0): string = + let fields = @[ + ("children", $x.children, true), + ] + .stringifyFields() + + stringifyBlock( + "OrgDocument", + indent, + fields, + ) + +func `$`*(xs: OrgDocument): string = pprint(xs) + +when isMainModule: + let doc = OrgDocument( + children: @[ + OrgBlock( + kind: orgHeading, + children: @[ + OrgInlineBlock( + kind: orgLink, + linkUrl: "https://placeholder.com", + linkDescription: "Placeholder".some(), + ), + ], + content: @[ + OrgBlock( + kind: orgNewline, + ), + OrgBlock( + kind: orgNewline, + ) + ], + ), + OrgBlock(kind: orgHeading, level: 1), + OrgBlock(kind: orgHeading), + ] + ) + echo doc diff --git a/src_v2/parser/parser_types.nim b/src_v2/parser/parser_types.nim index d879b3b..2fbe00b 100644 --- a/src_v2/parser/parser_types.nim +++ b/src_v2/parser/parser_types.nim @@ -143,6 +143,9 @@ func tokensToString*(parserResult: ParserResult, fallback = ""): string = xs => xs.toString(), ) +func tokensToString*(tokens: seq[ParserToken]): string = + tokens.foldl(a & b.toString(), "") + func setErrorExpectedField*(err: ParserError, expected: string): ParserError = ParserError( kind: err.kind, @@ -329,3 +332,4 @@ when isMainModule: # tokensToString assert testTokensSeqParserResult.tokensToString() == testExpectedStr + assert testTokensSeq.tokensToString() == testExpectedStr