sign_spec.lua 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. local helpers = require('test.functional.helpers')(after_each)
  2. local Screen = require('test.functional.ui.screen')
  3. local clear, feed, command = helpers.clear, helpers.feed, helpers.command
  4. local source = helpers.source
  5. local meths = helpers.meths
  6. describe('Signs', function()
  7. local screen
  8. before_each(function()
  9. clear()
  10. screen = Screen.new()
  11. screen:attach()
  12. screen:set_default_attr_ids( {
  13. [0] = {bold=true, foreground=255},
  14. [1] = {background = Screen.colors.Yellow},
  15. [2] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Grey},
  16. [3] = {background = Screen.colors.Gray90},
  17. [4] = {bold = true, reverse = true},
  18. [5] = {reverse = true},
  19. [6] = {foreground = Screen.colors.Brown},
  20. [7] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey},
  21. [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
  22. [9] = {bold = true, foreground = Screen.colors.Magenta},
  23. [10] = {foreground = Screen.colors.Blue1},
  24. [11] = {bold = true, foreground = Screen.colors.SeaGreen4},
  25. } )
  26. end)
  27. describe(':sign place', function()
  28. it('allows signs with combining characters', function()
  29. feed('ia<cr>b<cr><esc>')
  30. command('sign define piet1 text=𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄ texthl=Search')
  31. command('sign define piet2 text=𠜎̀́̂̃̄̅ texthl=Search')
  32. command('sign place 1 line=1 name=piet1 buffer=1')
  33. command('sign place 2 line=2 name=piet2 buffer=1')
  34. screen:expect([[
  35. {1:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}a |
  36. {1:𠜎̀́̂̃̄̅}b |
  37. {2: }^ |
  38. {0:~ }|
  39. {0:~ }|
  40. {0:~ }|
  41. {0:~ }|
  42. {0:~ }|
  43. {0:~ }|
  44. {0:~ }|
  45. {0:~ }|
  46. {0:~ }|
  47. {0:~ }|
  48. |
  49. ]])
  50. end)
  51. it('shadows previously placed signs', function()
  52. feed('ia<cr>b<cr>c<cr><esc>')
  53. command('sign define piet text=>> texthl=Search')
  54. command('sign define pietx text=>! texthl=Search')
  55. command('sign place 1 line=1 name=piet buffer=1')
  56. command('sign place 2 line=3 name=piet buffer=1')
  57. command('sign place 3 line=1 name=pietx buffer=1')
  58. screen:expect([[
  59. {1:>!}a |
  60. {2: }b |
  61. {1:>>}c |
  62. {2: }^ |
  63. {0:~ }|
  64. {0:~ }|
  65. {0:~ }|
  66. {0:~ }|
  67. {0:~ }|
  68. {0:~ }|
  69. {0:~ }|
  70. {0:~ }|
  71. {0:~ }|
  72. |
  73. ]])
  74. end)
  75. it('allows signs with no text', function()
  76. feed('ia<cr>b<cr><esc>')
  77. command('sign define piet1 text= texthl=Search')
  78. command('sign place 1 line=1 name=piet1 buffer=1')
  79. screen:expect([[
  80. a |
  81. b |
  82. ^ |
  83. {0:~ }|
  84. {0:~ }|
  85. {0:~ }|
  86. {0:~ }|
  87. {0:~ }|
  88. {0:~ }|
  89. {0:~ }|
  90. {0:~ }|
  91. {0:~ }|
  92. {0:~ }|
  93. |
  94. ]])
  95. end)
  96. it('can be called right after :split', function()
  97. feed('ia<cr>b<cr>c<cr><esc>gg')
  98. -- This used to cause a crash due to :sign using a special redraw
  99. -- (not updating nvim's specific highlight data structures)
  100. -- without proper redraw first, as split just flags for redraw later.
  101. source([[
  102. set cursorline
  103. sign define piet text=>> texthl=Search
  104. split
  105. sign place 3 line=2 name=piet buffer=1
  106. ]])
  107. screen:expect([[
  108. {2: }{3:^a }|
  109. {1:>>}b |
  110. {2: }c |
  111. {2: } |
  112. {0:~ }|
  113. {0:~ }|
  114. {4:[No Name] [+] }|
  115. {2: }{3:a }|
  116. {1:>>}b |
  117. {2: }c |
  118. {2: } |
  119. {0:~ }|
  120. {5:[No Name] [+] }|
  121. |
  122. ]])
  123. end)
  124. it('can combine text, linehl and numhl', function()
  125. feed('ia<cr>b<cr>c<cr><esc>')
  126. command('set number')
  127. command('sign define piet text=>> texthl=Search')
  128. command('sign define pietx linehl=ErrorMsg')
  129. command('sign define pietxx numhl=Folded')
  130. command('sign place 1 line=1 name=piet buffer=1')
  131. command('sign place 2 line=2 name=pietx buffer=1')
  132. command('sign place 3 line=3 name=pietxx buffer=1')
  133. command('sign place 4 line=4 name=piet buffer=1')
  134. command('sign place 5 line=4 name=pietx buffer=1')
  135. command('sign place 6 line=4 name=pietxx buffer=1')
  136. screen:expect([[
  137. {1:>>}{6: 1 }a |
  138. {2: }{6: 2 }{8:b }|
  139. {2: }{7: 3 }c |
  140. {1:>>}{7: 4 }{8:^ }|
  141. {0:~ }|
  142. {0:~ }|
  143. {0:~ }|
  144. {0:~ }|
  145. {0:~ }|
  146. {0:~ }|
  147. {0:~ }|
  148. {0:~ }|
  149. {0:~ }|
  150. |
  151. ]])
  152. -- Check that 'statuscolumn' correctly applies numhl
  153. command('set statuscolumn=%s%=%l\\ ')
  154. screen:expect_unchanged()
  155. end)
  156. it('highlights the cursorline sign with culhl', function()
  157. feed('ia<cr>b<cr>c<esc>')
  158. command('sign define piet text=>> texthl=Search culhl=ErrorMsg')
  159. command('sign place 1 line=1 name=piet buffer=1')
  160. command('sign place 2 line=2 name=piet buffer=1')
  161. command('sign place 3 line=3 name=piet buffer=1')
  162. command('set cursorline')
  163. screen:expect([[
  164. {1:>>}a |
  165. {1:>>}b |
  166. {8:>>}{3:^c }|
  167. {0:~ }|
  168. {0:~ }|
  169. {0:~ }|
  170. {0:~ }|
  171. {0:~ }|
  172. {0:~ }|
  173. {0:~ }|
  174. {0:~ }|
  175. {0:~ }|
  176. {0:~ }|
  177. |
  178. ]])
  179. feed('k')
  180. screen:expect([[
  181. {1:>>}a |
  182. {8:>>}{3:^b }|
  183. {1:>>}c |
  184. {0:~ }|
  185. {0:~ }|
  186. {0:~ }|
  187. {0:~ }|
  188. {0:~ }|
  189. {0:~ }|
  190. {0:~ }|
  191. {0:~ }|
  192. {0:~ }|
  193. {0:~ }|
  194. |
  195. ]])
  196. command('set nocursorline')
  197. screen:expect([[
  198. {1:>>}a |
  199. {1:>>}^b |
  200. {1:>>}c |
  201. {0:~ }|
  202. {0:~ }|
  203. {0:~ }|
  204. {0:~ }|
  205. {0:~ }|
  206. {0:~ }|
  207. {0:~ }|
  208. {0:~ }|
  209. {0:~ }|
  210. {0:~ }|
  211. |
  212. ]])
  213. command('set cursorline cursorlineopt=line')
  214. screen:expect([[
  215. {1:>>}a |
  216. {1:>>}{3:^b }|
  217. {1:>>}c |
  218. {0:~ }|
  219. {0:~ }|
  220. {0:~ }|
  221. {0:~ }|
  222. {0:~ }|
  223. {0:~ }|
  224. {0:~ }|
  225. {0:~ }|
  226. {0:~ }|
  227. {0:~ }|
  228. |
  229. ]])
  230. command('set cursorlineopt=number')
  231. command('hi! link SignColumn IncSearch')
  232. feed('Go<esc>2G')
  233. screen:expect([[
  234. {1:>>}a |
  235. {8:>>}^b |
  236. {1:>>}c |
  237. {5: } |
  238. {0:~ }|
  239. {0:~ }|
  240. {0:~ }|
  241. {0:~ }|
  242. {0:~ }|
  243. {0:~ }|
  244. {0:~ }|
  245. {0:~ }|
  246. {0:~ }|
  247. |
  248. ]])
  249. -- Check that 'statuscolumn' cursorline/signcolumn highlights are the same (#21726)
  250. command('set statuscolumn=%s')
  251. screen:expect_unchanged()
  252. end)
  253. it('multiple signs #9295', function()
  254. feed('ia<cr>b<cr>c<cr><esc>')
  255. command('set number')
  256. command('set signcolumn=yes:2')
  257. command('sign define pietSearch text=>> texthl=Search')
  258. command('sign define pietError text=XX texthl=Error')
  259. command('sign define pietWarn text=WW texthl=Warning')
  260. command('sign place 1 line=1 name=pietSearch buffer=1')
  261. command('sign place 2 line=1 name=pietError buffer=1')
  262. -- Line 2 helps checking that signs in the same line are ordered by Id.
  263. command('sign place 4 line=2 name=pietSearch buffer=1')
  264. command('sign place 3 line=2 name=pietError buffer=1')
  265. -- Line 3 checks that with a limit over the maximum number
  266. -- of signs, the ones with the highest Ids are being picked,
  267. -- and presented by their sorted Id order.
  268. command('sign place 4 line=3 name=pietSearch buffer=1')
  269. command('sign place 5 line=3 name=pietWarn buffer=1')
  270. command('sign place 3 line=3 name=pietError buffer=1')
  271. screen:expect([[
  272. {1:>>}{8:XX}{6: 1 }a |
  273. {8:XX}{1:>>}{6: 2 }b |
  274. {1:>>}WW{6: 3 }c |
  275. {2: }{6: 4 }^ |
  276. {0:~ }|
  277. {0:~ }|
  278. {0:~ }|
  279. {0:~ }|
  280. {0:~ }|
  281. {0:~ }|
  282. {0:~ }|
  283. {0:~ }|
  284. {0:~ }|
  285. |
  286. ]])
  287. -- With the default setting, we get the sign with the top id.
  288. command('set signcolumn=yes:1')
  289. screen:expect([[
  290. {8:XX}{6: 1 }a |
  291. {1:>>}{6: 2 }b |
  292. WW{6: 3 }c |
  293. {2: }{6: 4 }^ |
  294. {0:~ }|
  295. {0:~ }|
  296. {0:~ }|
  297. {0:~ }|
  298. {0:~ }|
  299. {0:~ }|
  300. {0:~ }|
  301. {0:~ }|
  302. {0:~ }|
  303. |
  304. ]])
  305. -- "auto:3" accommodates all the signs we defined so far.
  306. command('set signcolumn=auto:3')
  307. screen:expect([[
  308. {1:>>}{8:XX}{2: }{6: 1 }a |
  309. {8:XX}{1:>>}{2: }{6: 2 }b |
  310. {8:XX}{1:>>}WW{6: 3 }c |
  311. {2: }{6: 4 }^ |
  312. {0:~ }|
  313. {0:~ }|
  314. {0:~ }|
  315. {0:~ }|
  316. {0:~ }|
  317. {0:~ }|
  318. {0:~ }|
  319. {0:~ }|
  320. {0:~ }|
  321. |
  322. ]])
  323. -- Check "yes:9".
  324. command('set signcolumn=yes:9')
  325. screen:expect([[
  326. {1:>>}{8:XX}{2: }{6: 1 }a |
  327. {8:XX}{1:>>}{2: }{6: 2 }b |
  328. {8:XX}{1:>>}WW{2: }{6: 3 }c |
  329. {2: }{6: 4 }^ |
  330. {0:~ }|
  331. {0:~ }|
  332. {0:~ }|
  333. {0:~ }|
  334. {0:~ }|
  335. {0:~ }|
  336. {0:~ }|
  337. {0:~ }|
  338. {0:~ }|
  339. |
  340. ]])
  341. -- Check "auto:N" larger than the maximum number of signs defined in
  342. -- a single line (same result as "auto:3").
  343. command('set signcolumn=auto:4')
  344. screen:expect{grid=[[
  345. {1:>>}{8:XX}{2: }{6: 1 }a |
  346. {8:XX}{1:>>}{2: }{6: 2 }b |
  347. {8:XX}{1:>>}WW{6: 3 }c |
  348. {2: }{6: 4 }^ |
  349. {0:~ }|
  350. {0:~ }|
  351. {0:~ }|
  352. {0:~ }|
  353. {0:~ }|
  354. {0:~ }|
  355. {0:~ }|
  356. {0:~ }|
  357. {0:~ }|
  358. |
  359. ]]}
  360. -- line deletion deletes signs.
  361. command('2d')
  362. screen:expect([[
  363. {1:>>}{8:XX}{2: }{6: 1 }a |
  364. {8:XX}{1:>>}WW{6: 2 }^c |
  365. {2: }{6: 3 } |
  366. {0:~ }|
  367. {0:~ }|
  368. {0:~ }|
  369. {0:~ }|
  370. {0:~ }|
  371. {0:~ }|
  372. {0:~ }|
  373. {0:~ }|
  374. {0:~ }|
  375. {0:~ }|
  376. |
  377. ]])
  378. end)
  379. it('auto-resize sign column with minimum size (#13783)', function()
  380. feed('ia<cr>b<cr>c<cr><esc>')
  381. command('set number')
  382. -- sign column should always accommodate at the minimum size
  383. command('set signcolumn=auto:1-3')
  384. screen:expect([[
  385. {2: }{6: 1 }a |
  386. {2: }{6: 2 }b |
  387. {2: }{6: 3 }c |
  388. {2: }{6: 4 }^ |
  389. {0:~ }|
  390. {0:~ }|
  391. {0:~ }|
  392. {0:~ }|
  393. {0:~ }|
  394. {0:~ }|
  395. {0:~ }|
  396. {0:~ }|
  397. {0:~ }|
  398. |
  399. ]])
  400. -- should support up to 8 signs at minimum
  401. command('set signcolumn=auto:8-9')
  402. screen:expect([[
  403. {2: }{6: 1 }a |
  404. {2: }{6: 2 }b |
  405. {2: }{6: 3 }c |
  406. {2: }{6: 4 }^ |
  407. {0:~ }|
  408. {0:~ }|
  409. {0:~ }|
  410. {0:~ }|
  411. {0:~ }|
  412. {0:~ }|
  413. {0:~ }|
  414. {0:~ }|
  415. {0:~ }|
  416. |
  417. ]])
  418. -- should keep the same sign size when signs are not exceeding
  419. -- the minimum
  420. command('set signcolumn=auto:2-5')
  421. command('sign define pietSearch text=>> texthl=Search')
  422. command('sign place 1 line=1 name=pietSearch buffer=1')
  423. screen:expect([[
  424. {1:>>}{2: }{6: 1 }a |
  425. {2: }{6: 2 }b |
  426. {2: }{6: 3 }c |
  427. {2: }{6: 4 }^ |
  428. {0:~ }|
  429. {0:~ }|
  430. {0:~ }|
  431. {0:~ }|
  432. {0:~ }|
  433. {0:~ }|
  434. {0:~ }|
  435. {0:~ }|
  436. {0:~ }|
  437. |
  438. ]])
  439. -- should resize itself when signs are exceeding minimum but
  440. -- not over the maximum
  441. command('sign place 2 line=1 name=pietSearch buffer=1')
  442. command('sign place 3 line=1 name=pietSearch buffer=1')
  443. command('sign place 4 line=1 name=pietSearch buffer=1')
  444. screen:expect([[
  445. {1:>>>>>>>>}{6: 1 }a |
  446. {2: }{6: 2 }b |
  447. {2: }{6: 3 }c |
  448. {2: }{6: 4 }^ |
  449. {0:~ }|
  450. {0:~ }|
  451. {0:~ }|
  452. {0:~ }|
  453. {0:~ }|
  454. {0:~ }|
  455. {0:~ }|
  456. {0:~ }|
  457. {0:~ }|
  458. |
  459. ]])
  460. -- should keep the column at maximum size when signs are
  461. -- exceeding the maximum
  462. command('sign place 5 line=1 name=pietSearch buffer=1')
  463. command('sign place 6 line=1 name=pietSearch buffer=1')
  464. command('sign place 7 line=1 name=pietSearch buffer=1')
  465. command('sign place 8 line=1 name=pietSearch buffer=1')
  466. screen:expect([[
  467. {1:>>>>>>>>>>}{6: 1 }a |
  468. {2: }{6: 2 }b |
  469. {2: }{6: 3 }c |
  470. {2: }{6: 4 }^ |
  471. {0:~ }|
  472. {0:~ }|
  473. {0:~ }|
  474. {0:~ }|
  475. {0:~ }|
  476. {0:~ }|
  477. {0:~ }|
  478. {0:~ }|
  479. {0:~ }|
  480. |
  481. ]])
  482. end)
  483. it('ignores signs with no icon and text when calculating the signcolumn width', function()
  484. feed('ia<cr>b<cr>c<cr><esc>')
  485. command('set number')
  486. command('set signcolumn=auto:2')
  487. command('sign define pietSearch text=>> texthl=Search')
  488. command('sign define pietError text= texthl=Error')
  489. command('sign place 2 line=1 name=pietError buffer=1')
  490. -- no signcolumn with only empty sign
  491. screen:expect([[
  492. {6: 1 }a |
  493. {6: 2 }b |
  494. {6: 3 }c |
  495. {6: 4 }^ |
  496. {0:~ }|
  497. {0:~ }|
  498. {0:~ }|
  499. {0:~ }|
  500. {0:~ }|
  501. {0:~ }|
  502. {0:~ }|
  503. {0:~ }|
  504. {0:~ }|
  505. |
  506. ]])
  507. -- single column with 1 sign with text and one sign without
  508. command('sign place 1 line=1 name=pietSearch buffer=1')
  509. screen:expect([[
  510. {1:>>}{6: 1 }a |
  511. {2: }{6: 2 }b |
  512. {2: }{6: 3 }c |
  513. {2: }{6: 4 }^ |
  514. {0:~ }|
  515. {0:~ }|
  516. {0:~ }|
  517. {0:~ }|
  518. {0:~ }|
  519. {0:~ }|
  520. {0:~ }|
  521. {0:~ }|
  522. {0:~ }|
  523. |
  524. ]])
  525. end)
  526. it('shows the line number when signcolumn=number but no marks on a line have text', function()
  527. feed('ia<cr>b<cr>c<cr><esc>')
  528. command('set number signcolumn=number')
  529. command('sign define pietSearch text=>> texthl=Search numhl=Error')
  530. command('sign define pietError text= texthl=Search numhl=Error')
  531. command('sign place 1 line=1 name=pietSearch buffer=1')
  532. command('sign place 2 line=2 name=pietError buffer=1')
  533. -- no signcolumn, line number for "a" is Search, for "b" is Error, for "c" is LineNr
  534. screen:expect([[
  535. {1: >> }a |
  536. {8: 2 }b |
  537. {6: 3 }c |
  538. {6: 4 }^ |
  539. {0:~ }|
  540. {0:~ }|
  541. {0:~ }|
  542. {0:~ }|
  543. {0:~ }|
  544. {0:~ }|
  545. {0:~ }|
  546. {0:~ }|
  547. {0:~ }|
  548. |
  549. ]])
  550. end)
  551. it('can have 32bit sign IDs', function()
  552. command('sign define piet text=>> texthl=Search')
  553. command('sign place 100000 line=1 name=piet buffer=1')
  554. feed(':sign place<cr>')
  555. screen:expect([[
  556. {1:>>} |
  557. {0:~ }|
  558. {0:~ }|
  559. {0:~ }|
  560. {0:~ }|
  561. {0:~ }|
  562. {0:~ }|
  563. {4: }|
  564. :sign place |
  565. {9:--- Signs ---} |
  566. {10:Signs for [NULL]:} |
  567. line=1 id=100000 name=piet priority=10 |
  568. |
  569. {11:Press ENTER or type command to continue}^ |
  570. ]])
  571. feed('<cr>')
  572. screen:expect([[
  573. {1:>>}^ |
  574. {0:~ }|
  575. {0:~ }|
  576. {0:~ }|
  577. {0:~ }|
  578. {0:~ }|
  579. {0:~ }|
  580. {0:~ }|
  581. {0:~ }|
  582. {0:~ }|
  583. {0:~ }|
  584. {0:~ }|
  585. {0:~ }|
  586. |
  587. ]])
  588. end)
  589. end)
  590. it('signcolumn width is updated when removing all signs after deleting lines', function()
  591. meths.buf_set_lines(0, 0, 1, true, {'a', 'b', 'c', 'd', 'e'})
  592. command('sign define piet text=>>')
  593. command('sign place 10001 line=1 name=piet')
  594. command('sign place 10002 line=5 name=piet')
  595. command('2delete')
  596. command('sign unplace 10001')
  597. screen:expect([[
  598. {2: }a |
  599. {2: }^c |
  600. {2: }d |
  601. >>e |
  602. {0:~ }|
  603. {0:~ }|
  604. {0:~ }|
  605. {0:~ }|
  606. {0:~ }|
  607. {0:~ }|
  608. {0:~ }|
  609. {0:~ }|
  610. {0:~ }|
  611. |
  612. ]])
  613. command('sign unplace 10002')
  614. screen:expect([[
  615. a |
  616. ^c |
  617. d |
  618. e |
  619. {0:~ }|
  620. {0:~ }|
  621. {0:~ }|
  622. {0:~ }|
  623. {0:~ }|
  624. {0:~ }|
  625. {0:~ }|
  626. {0:~ }|
  627. {0:~ }|
  628. |
  629. ]])
  630. end)
  631. it('signcolumn width is updated when removing all signs after inserting lines', function()
  632. meths.buf_set_lines(0, 0, 1, true, {'a', 'b', 'c', 'd', 'e'})
  633. command('sign define piet text=>>')
  634. command('sign place 10001 line=1 name=piet')
  635. command('sign place 10002 line=5 name=piet')
  636. command('copy .')
  637. command('sign unplace 10001')
  638. screen:expect([[
  639. {2: }a |
  640. {2: }^a |
  641. {2: }b |
  642. {2: }c |
  643. {2: }d |
  644. >>e |
  645. {0:~ }|
  646. {0:~ }|
  647. {0:~ }|
  648. {0:~ }|
  649. {0:~ }|
  650. {0:~ }|
  651. {0:~ }|
  652. |
  653. ]])
  654. command('sign unplace 10002')
  655. screen:expect([[
  656. a |
  657. ^a |
  658. b |
  659. c |
  660. d |
  661. e |
  662. {0:~ }|
  663. {0:~ }|
  664. {0:~ }|
  665. {0:~ }|
  666. {0:~ }|
  667. {0:~ }|
  668. {0:~ }|
  669. |
  670. ]])
  671. end)
  672. end)