~xigoi/xidoc

13634f7e75760d512134031a5f0d2d0430db8f89 — Adam Blažek 1 year, 8 months ago 968a84f position
Incorrect implementation of position tracking
M src/xidoc.nim => src/xidoc.nim +2 -0
@@ 29,6 29,8 @@ proc renderXidoc*(body: string, path = "", target = tHtml, snippet = false, safe
    verbose: verbose,
    stack: @[Frame(
      cmdName: "[top]",
      cmdPos: body.low..body.high,
      cmdArgPos: body.low..body.high,
      path: some(path),
    )]
  )

M src/xidocpkg/error.nim => src/xidocpkg/error.nim +15 -1
@@ 15,6 15,18 @@ proc xidocWarning*(msge: string) =
  when not defined(js):
    stderr.writeLine("Warning: " & msge)

func posToCoords(body: string, pos: int): tuple[row, col: int] =
  var newlines = 0
  var lastNewline = -1
  for i in 0..<pos:
    if body[i] == '\n':
      newlines.inc
      lastNewline = i
  return (newlines + 1, pos - lastNewline)

func formatPos(pos: tuple[row, col: int]): string =
  &"{pos.row}:{pos.col}"

proc format*(err: XidocError, doc: Document, termColors: bool): FormattedXidocError =
  const
    red = "\e[91m"


@@ 35,7 47,9 @@ proc format*(err: XidocError, doc: Document, termColors: bool): FormattedXidocEr
      let numOpeningBrackets = truncatedArg.count('[')
      let numClosingBrackets = truncatedArg.count(']')
      truncatedArg.add "]…".repeat(numOpeningBrackets - numClosingBrackets)
    msg &= &"in [{frame.cmdName}{truncatedArg}]\n"
    let posA = posToCoords(doc.body, frame.cmdPos.a).formatPos
    let posB = posToCoords(doc.body, frame.cmdPos.b).formatPos
    msg &= &"[{posA}–{posB}] in [{frame.cmdName}{truncatedArg}]\n"
  if termColors:
    msg &= reset
  msg &= err.msg

M src/xidocpkg/expand.nim => src/xidocpkg/expand.nim +7 -1
@@ 6,6 6,9 @@ import std/options
import std/strformat
import std/strutils

proc `+`(s: Slice[int], n: int): Slice[int] =
  s.a + n .. s.b + n

proc escapeText*(text: string, target: Target): string =
  case target
  of tHtml:


@@ 58,7 61,10 @@ proc expand*(doc: Document, str: string, typ: XidocType): XidocValue =
        let name = node.name
        let command = doc.lookup(commands, name)
        ifSome command:
          var frame = Frame(cmdName: name, cmdArg: node.arg)
          let offset = doc.stack[^1].cmdArgPos.a
          var frame = Frame(cmdName: name, cmdArg: node.arg,
                            cmdPos: node.pos + offset,
                            cmdArgPos: node.argPos + offset)
          doc.stack.add frame
          let val = command(node.arg)
          discard doc.stack.pop

M src/xidocpkg/parser.nim => src/xidocpkg/parser.nim +12 -3
@@ 8,6 8,7 @@ type
    xnkWhitespace
    xnkCommand
  XidocNode* = object
    pos*: Slice[int]
    case kind*: XidocNodeKind
    of xnkString:
      str*: string


@@ 16,6 17,7 @@ type
    of xnkCommand:
      name*: string
      arg*: string
      argPos*: Slice[int]
  XidocNodes* = seq[XidocNode]

const nonTextChars = Whitespace + {'[', ']'}


@@ 62,17 64,20 @@ proc parseXidocString(body: string, i: var int): XidocNode =
  ## Finds a string of non-whitespace non-brackets characters in `body`,
  ## starting from position `i` and leaving `i` after the found substring.
  ## Returns a `XidocNode` with kind `xnkString`.
  XidocNode(kind: xnkString, str: parseXidocStringHelper(body, i))
  let start = i
  let str = parseXidocStringHelper(body, i)
  XidocNode(pos: start..<i, kind: xnkString, str: str)

proc parseXidocWhitespace(body: string, i: var int): XidocNode =
  ## Finds a string of whitespace characters in `body`,
  ## starting from position `i` and leaving `i` after the found substring.
  ## Returns a `XidocNode` with kind `xnkWhitespace`.
  let start = i
  var newline = false
  while i <= body.high and body[i] in Whitespace:
    newline = newline or body[i] == '\n'
    i.inc
  XidocNode(kind: xnkWhitespace, newline: newline)
  XidocNode(pos: start..<i, kind: xnkWhitespace, newline: newline)

proc parseXidocCommand(body: string, i: var int): XidocNode =
  ## Finds a xidoc command in `body`,


@@ 80,6 85,7 @@ proc parseXidocCommand(body: string, i: var int): XidocNode =
  ## `body[i]` must be '[' at the start.
  ## Returns a `XidocNode` with kind `xnkCommand`.
  assert body[i] == '['
  let start = i
  i.inc
  let name = parseXidocStringHelper(body, i)
  if i > body.high:


@@ 91,7 97,10 @@ proc parseXidocCommand(body: string, i: var int): XidocNode =
  skipBalancedText(body, i)
  if i > body.high:
    xidocError "Parse error: Unexpected end of file (did you forget to close a bracket?)"
  result = XidocNode(kind: xnkCommand, name: name, arg: body[argStart..<i])
  result = XidocNode(
    pos: start..<i+1,
    kind: xnkCommand, name: name, arg: body[argStart..<i], argPos: argStart..<i
  )
  i.inc

proc parseXidoc*(body: string, verbose = false): XidocNodes =

M src/xidocpkg/types.nim => src/xidocpkg/types.nim +2 -0
@@ 35,6 35,8 @@ type
    args*: Table[string, string]
    cmdArg*: string
    cmdName*: string
    cmdPos*: Slice[int]
    cmdArgPos*: Slice[int]
    commands*: Table[string, Command]
    lang*: Option[Language]
    path*: Option[string]