asciitables.nim 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #[
  2. move to std/asciitables.nim once stable, or to a nimble paackage
  3. once compiler can depend on nimble
  4. ]#
  5. type Cell* = object
  6. text*: string
  7. width*, row*, col*, ncols*, nrows*: int
  8. iterator parseTableCells*(s: string, delim = '\t'): Cell =
  9. ## iterates over all cells in a `delim`-delimited `s`, after a 1st
  10. ## pass that computes number of rows, columns, and width of each column.
  11. var widths: seq[int]
  12. var cell: Cell
  13. template update() =
  14. if widths.len<=cell.col:
  15. widths.setLen cell.col+1
  16. widths[cell.col] = cell.width
  17. else:
  18. widths[cell.col] = max(widths[cell.col], cell.width)
  19. cell.width = 0
  20. for a in s:
  21. case a
  22. of '\n':
  23. update()
  24. cell.col = 0
  25. cell.row.inc
  26. elif a == delim:
  27. update()
  28. cell.col.inc
  29. else:
  30. # todo: consider multi-width chars when porting to non-ascii implementation
  31. cell.width.inc
  32. if s.len > 0 and s[^1] != '\n':
  33. update()
  34. cell.ncols = widths.len
  35. cell.nrows = cell.row + 1
  36. cell.row = 0
  37. cell.col = 0
  38. cell.width = 0
  39. template update2() =
  40. cell.width = widths[cell.col]
  41. yield cell
  42. cell.text = ""
  43. cell.width = 0
  44. cell.col.inc
  45. template finishRow() =
  46. for col in cell.col..<cell.ncols:
  47. cell.col = col
  48. update2()
  49. cell.col = 0
  50. for a in s:
  51. case a
  52. of '\n':
  53. finishRow()
  54. cell.row.inc
  55. elif a == delim:
  56. update2()
  57. else:
  58. cell.width.inc
  59. cell.text.add a
  60. if s.len > 0 and s[^1] != '\n':
  61. finishRow()
  62. proc alignTable*(s: string, delim = '\t', fill = ' ', sep = " "): string =
  63. ## formats a `delim`-delimited `s` representing a table; each cell is aligned
  64. ## to a width that's computed for each column; consecutive columns are
  65. ## delimited by `sep`, and alignment space is filled using `fill`.
  66. ## More customized formatting can be done by calling `parseTableCells` directly.
  67. for cell in parseTableCells(s, delim):
  68. result.add cell.text
  69. for i in cell.text.len..<cell.width:
  70. result.add fill
  71. if cell.col < cell.ncols-1:
  72. result.add sep
  73. if cell.col == cell.ncols-1 and cell.row < cell.nrows - 1:
  74. result.add '\n'