import std/[ strutils, math, ] import fusion/matching {.experimental: "caseStmtMacros".} func prettyExpectedSet*(x: set[char]): string = ## Pretty print value for a set `x` of characters case x: of AllChars: "AllChars {'\x00'..'\xFF'}" of Digits: "Digits {'0'..'9'}" of HexDigits: "HexDigits {'0'..'9', 'A'..'F', 'a'..'f'}" of Letters: "Letters {'A'..'Z', 'a'..'z'}" of Newlines: "Newlines {'\r', '\n'}" of Whitespace: "Whitespace {' ', '\t', '\v', '\r', '\n', '\f'}" else: $x func indentAfterNewline*(str: string, count: int): string = ## Indent lines following the first line of `str` by `count`. ## Useful for indenting nested keys of stringify functions. var strDup = str.indent(count) strDup.delete(0..count - 1) strDup proc safeDelete*(str: string, slice: Slice[int]): string = ## Deletes the items `str[slice]`, ignoring elements out of range. if slice.a > str.len - 1: str else: let fromIndex = clamp(slice.a, 0..str.len) let toIndex = clamp(slice.b, 0..str.len - 1) var strDup = str strDup.delete(fromIndex..toIndex) strDup func findAndDelete*(str: string, chars: set[char], start = 0, last = str.len - 1): string = ## Find the next instance of `chars` from `start`. ## When found delete characters until `last`. # Prevent passing negative numbers (e.g.: initial parser) if start >= 0 and last >= 0: let startChar = str.find(chars, start, last) if startChar == -1: str else: str.safeDelete(startChar..last) else: str func deleteAfterNewline*(str: string, start = 0): string = ## Delete string after next Newline from `start`. findAndDelete(str, Newlines, start)