Block.coffee 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. Layout = require '../../src/Layout'
  2. {object} = require 'utila'
  3. {open, get, conf} = do ->
  4. show = (layout) ->
  5. got = layout.get()
  6. got = got.replace /<[^>]+>/g, ''
  7. defaultBlockConfig =
  8. linePrependor: options: amount: 2
  9. c = (add = {}) ->
  10. object.append defaultBlockConfig, add
  11. ret = {}
  12. ret.open = (block, name, top = 0, bottom = 0) ->
  13. config = c
  14. blockPrependor: options: amount: top
  15. blockAppendor: options: amount: bottom
  16. b = block.openBlock config, name
  17. b.write name + ' | top ' + top + ' bottom ' + bottom
  18. b
  19. ret.get = (layout) ->
  20. layout.get().replace(/<[^>]+>/g, '')
  21. ret.conf = (props) ->
  22. config = {}
  23. if props.left?
  24. object.appendOnto config, linePrependor: options: amount: props.left
  25. if props.right?
  26. object.appendOnto config, lineAppendor: options: amount: props.right
  27. if props.top?
  28. object.appendOnto config, blockPrependor: options: amount: props.top
  29. if props.bottom?
  30. object.appendOnto config, blockAppendor: options: amount: props.bottom
  31. if props.width?
  32. object.appendOnto config, width: props.width
  33. if props.bullet is yes
  34. object.appendOnto config, linePrependor: options: bullet: {char: '-', alignment: 'left'}
  35. config
  36. ret
  37. describe "Layout", ->
  38. describe "inline inputs", ->
  39. it "should be merged", ->
  40. l = new Layout
  41. l.write 'a'
  42. l.write 'b'
  43. get(l).should.equal 'ab'
  44. it "should be correctly wrapped", ->
  45. l = new Layout
  46. block = l.openBlock conf width: 20
  47. block.write '123456789012345678901234567890'
  48. block.close()
  49. get(l).should.equal '12345678901234567890\n1234567890'
  50. it "should trim from left when wrapping to a new line", ->
  51. l = new Layout
  52. block = l.openBlock conf width: 20
  53. block.write '12345678901234567890 \t 123456789012345678901'
  54. block.close()
  55. get(l).should.equal '12345678901234567890\n12345678901234567890\n1'
  56. it "should handle line breaks correctly", ->
  57. l = new Layout
  58. block = l.openBlock conf width: 20
  59. block.write '\na\n\nb\n'
  60. block.close()
  61. get(l).should.equal '\na\n\nb\n'
  62. it "should not put extra line breaks when a line is already broken", ->
  63. l = new Layout
  64. block = l.openBlock conf width: 20
  65. block.write '01234567890123456789\n0123456789'
  66. block.close()
  67. get(l).should.equal '01234567890123456789\n0123456789'
  68. describe "horizontal margins", ->
  69. it "should account for left margins", ->
  70. l = new Layout
  71. block = l.openBlock conf width: 20, left: 2
  72. block.write '01'
  73. block.close()
  74. get(l).should.equal ' 01'
  75. it "should account for right margins", ->
  76. l = new Layout
  77. block = l.openBlock conf width: 20, right: 2
  78. block.write '01'
  79. block.close()
  80. get(l).should.equal '01 '
  81. it "should account for both margins", ->
  82. l = new Layout
  83. block = l.openBlock conf width: 20, right: 2, left: 1
  84. block.write '01'
  85. block.close()
  86. get(l).should.equal ' 01 '
  87. it "should break lines according to left margins", ->
  88. l = new Layout
  89. global.tick = yes
  90. block = l.openBlock conf width: 20, left: 2
  91. block.write '01234567890123456789'
  92. block.close()
  93. global.tick = no
  94. get(l).should.equal ' 01234567890123456789'
  95. it "should break lines according to right margins", ->
  96. l = new Layout
  97. block = l.openBlock conf width: 20, right: 2
  98. block.write '01234567890123456789'
  99. block.close()
  100. get(l).should.equal '01234567890123456789 '
  101. it "should break lines according to both margins", ->
  102. l = new Layout
  103. block = l.openBlock conf width: 20, right: 2, left: 1
  104. block.write '01234567890123456789'
  105. block.close()
  106. get(l).should.equal ' 01234567890123456789 '
  107. it "should break lines according to terminal width", ->
  108. l = new Layout terminalWidth: 20
  109. block = l.openBlock conf right: 2, left: 1
  110. block.write '01234567890123456789'
  111. block.close()
  112. # Note: We don't expect ' 01234567890123456 \n 789 ',
  113. # since the first line (' 01234567890123456 ') is a full line
  114. # according to layout.config.terminalWidth and doesn't need
  115. # a break line.
  116. get(l).should.equal ' 01234567890123456 789 '
  117. describe "lines and blocks", ->
  118. it "should put one break line between: line, block", ->
  119. l = new Layout
  120. l.write 'a'
  121. l.openBlock().write('b').close()
  122. get(l).should.equal 'a\nb'
  123. it "should put one break line between: block, line", ->
  124. l = new Layout
  125. l.openBlock().write('a').close()
  126. l.write 'b'
  127. get(l).should.equal 'a\nb'
  128. it "should put one break line between: line, block, line", ->
  129. l = new Layout
  130. l.write 'a'
  131. l.openBlock().write('b').close()
  132. l.write 'c'
  133. get(l).should.equal 'a\nb\nc'
  134. it "margin top should work for: line, block", ->
  135. l = new Layout
  136. l.write 'a'
  137. l.openBlock(conf top: 2).write('b').close()
  138. get(l).should.equal 'a\n\n\nb'
  139. it "margin top should work for: block, line", ->
  140. l = new Layout
  141. l.openBlock(conf top: 1).write('a').close()
  142. l.write 'b'
  143. get(l).should.equal '\na\nb'
  144. it "margin top should work for: block, line, when block starts with a break", ->
  145. l = new Layout
  146. l.openBlock(conf top: 1).write('\na').close()
  147. l.write 'b'
  148. get(l).should.equal '\n\na\nb'
  149. it "margin top should work for: line, block, when line ends with a break", ->
  150. l = new Layout
  151. l.write 'a\n'
  152. l.openBlock(conf top: 1).write('b').close()
  153. get(l).should.equal 'a\n\n\nb'
  154. it "margin top should work for: line, block, when there are two breaks in between", ->
  155. l = new Layout
  156. l.write 'a\n'
  157. l.openBlock(conf top: 1).write('\nb').close()
  158. get(l).should.equal 'a\n\n\n\nb'
  159. it "margin bottom should work for: line, block", ->
  160. l = new Layout
  161. l.write 'a'
  162. l.openBlock(conf bottom: 1).write('b').close()
  163. get(l).should.equal 'a\nb\n'
  164. it "margin bottom should work for: block, line", ->
  165. l = new Layout
  166. l.openBlock(conf bottom: 1).write('a').close()
  167. l.write 'b'
  168. get(l).should.equal 'a\n\nb'
  169. it "margin bottom should work for: block, line, when block ends with a break", ->
  170. l = new Layout
  171. l.openBlock(conf bottom: 1).write('a\n').close()
  172. l.write 'b'
  173. get(l).should.equal 'a\n\n\nb'
  174. it "margin bottom should work for: block, line, when line starts with a break", ->
  175. l = new Layout
  176. l.openBlock(conf bottom: 1).write('a').close()
  177. l.write '\nb'
  178. get(l).should.equal 'a\n\n\nb'
  179. it "margin bottom should work for: block, line, when there are two breaks in between", ->
  180. l = new Layout
  181. l.openBlock(conf bottom: 1).write('a\n').close()
  182. l.write '\nb'
  183. get(l).should.equal 'a\n\n\n\nb'
  184. describe "blocks and blocks", ->
  185. it "should not get extra break lines for full-width lines", ->
  186. l = new Layout
  187. l.openBlock(conf width: 20).write('01234567890123456789').close()
  188. l.openBlock().write('b').close()
  189. get(l).should.equal '01234567890123456789\nb'
  190. it "should not get extra break lines for full-width lines followed by a margin", ->
  191. l = new Layout
  192. l.openBlock(conf width: 20, bottom: 1).write('01234567890123456789').close()
  193. l.openBlock().write('b').close()
  194. get(l).should.equal '01234567890123456789\n\nb'
  195. it "a(top: 0, bottom: 0) b(top: 0, bottom: 0)", ->
  196. l = new Layout
  197. l.openBlock().write('a').close()
  198. l.openBlock().write('b').close()
  199. get(l).should.equal 'a\nb'
  200. it "a(top: 0, bottom: 0) b(top: 1, bottom: 0)", ->
  201. l = new Layout
  202. l.openBlock().write('a').close()
  203. l.openBlock(conf(top: 1)).write('b').close()
  204. get(l).should.equal 'a\n\nb'
  205. it "a(top: 0, bottom: 1) b(top: 0, bottom: 0)", ->
  206. l = new Layout
  207. l.openBlock(conf(bottom: 1)).write('a').close()
  208. l.openBlock().write('b').close()
  209. get(l).should.equal 'a\n\nb'
  210. it "a(top: 0, bottom: 1 ) b( top: 1, bottom: 0)", ->
  211. l = new Layout
  212. l.openBlock(conf(bottom: 1)).write('a').close()
  213. l.openBlock(conf(top: 1)).write('b').close()
  214. get(l).should.equal 'a\n\n\nb'
  215. it "a(top: 0, bottom: 1 br) b(br top: 1, bottom: 0)", ->
  216. l = new Layout
  217. l.openBlock(conf(bottom: 1)).write('a\n').close()
  218. l.openBlock(conf(top: 1)).write('\nb').close()
  219. get(l).should.equal 'a\n\n\n\n\nb'
  220. it "a(top: 2, bottom: 3 a1-br-a2) b(br-b1-br-br-b2-br top: 2, bottom: 3)", ->
  221. l = new Layout
  222. l.openBlock(conf(top: 2, bottom: 3)).write('a1\na2').close()
  223. l.openBlock(conf(top: 2, bottom: 3)).write('\nb1\n\nb2\n').close()
  224. get(l).should.equal '\n\na1\na2\n\n\n\n\n\n\nb1\n\nb2\n\n\n\n'
  225. describe "nesting", ->
  226. it "should break one line for nested blocks", ->
  227. l = new Layout
  228. l.write 'a'
  229. b = l.openBlock()
  230. c = b.openBlock().write('c').close()
  231. b.close()
  232. get(l).should.equal 'a\nc'
  233. it "a(left: 2) > b(top: 2)", ->
  234. l = new Layout
  235. a = l.openBlock(conf(left: 2))
  236. a.openBlock(conf(top: 2)).write('b').close()
  237. a.close()
  238. get(l).should.equal ' \n \n b'
  239. it "a(left: 2) > b(bottom: 2)", ->
  240. l = new Layout
  241. a = l.openBlock(conf(left: 2))
  242. a.openBlock(conf(bottom: 2)).write('b').close()
  243. a.close()
  244. get(l).should.equal ' b\n \n '
  245. describe "bullets", ->
  246. it "basic bullet", ->
  247. l = new Layout
  248. l.openBlock(conf(left: 3, bullet: yes)).write('a').close()
  249. get(l).should.equal '- a'
  250. it "a(left: 3, bullet) > b(top:1)", ->
  251. l = new Layout
  252. a = l.openBlock(conf(left: 3, bullet: yes))
  253. b = a.openBlock(conf(top: 1)).write('b').close()
  254. a.close()
  255. get(l).should.equal '- \n b'