cursor_spec.lua (10644B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 local Screen = require('test.functional.ui.screen') 4 5 local clear, api = n.clear, n.api 6 local eq = t.eq 7 local command = n.command 8 9 describe('ui/cursor', function() 10 local screen 11 12 before_each(function() 13 clear() 14 screen = Screen.new(25, 5) 15 end) 16 17 it("'guicursor' is published as a UI event", function() 18 local expected_mode_info = { 19 [1] = { 20 blinkoff = 0, 21 blinkon = 0, 22 blinkwait = 0, 23 cell_percentage = 0, 24 cursor_shape = 'block', 25 name = 'normal', 26 hl_id = 0, 27 id_lm = 0, 28 attr = {}, 29 attr_lm = {}, 30 mouse_shape = 0, 31 short_name = 'n', 32 }, 33 [2] = { 34 blinkoff = 0, 35 blinkon = 0, 36 blinkwait = 0, 37 cell_percentage = 0, 38 cursor_shape = 'block', 39 name = 'visual', 40 hl_id = 0, 41 id_lm = 0, 42 attr = {}, 43 attr_lm = {}, 44 mouse_shape = 0, 45 short_name = 'v', 46 }, 47 [3] = { 48 blinkoff = 0, 49 blinkon = 0, 50 blinkwait = 0, 51 cell_percentage = 25, 52 cursor_shape = 'vertical', 53 name = 'insert', 54 hl_id = 0, 55 id_lm = 0, 56 attr = {}, 57 attr_lm = {}, 58 mouse_shape = 0, 59 short_name = 'i', 60 }, 61 [4] = { 62 blinkoff = 0, 63 blinkon = 0, 64 blinkwait = 0, 65 cell_percentage = 20, 66 cursor_shape = 'horizontal', 67 name = 'replace', 68 hl_id = 0, 69 id_lm = 0, 70 attr = {}, 71 attr_lm = {}, 72 mouse_shape = 0, 73 short_name = 'r', 74 }, 75 [5] = { 76 blinkoff = 0, 77 blinkon = 0, 78 blinkwait = 0, 79 cell_percentage = 0, 80 cursor_shape = 'block', 81 name = 'cmdline_normal', 82 hl_id = 0, 83 id_lm = 0, 84 attr = {}, 85 attr_lm = {}, 86 mouse_shape = 0, 87 short_name = 'c', 88 }, 89 [6] = { 90 blinkoff = 0, 91 blinkon = 0, 92 blinkwait = 0, 93 cell_percentage = 25, 94 cursor_shape = 'vertical', 95 name = 'cmdline_insert', 96 hl_id = 0, 97 id_lm = 0, 98 attr = {}, 99 attr_lm = {}, 100 mouse_shape = 0, 101 short_name = 'ci', 102 }, 103 [7] = { 104 blinkoff = 0, 105 blinkon = 0, 106 blinkwait = 0, 107 cell_percentage = 20, 108 cursor_shape = 'horizontal', 109 name = 'cmdline_replace', 110 hl_id = 0, 111 id_lm = 0, 112 attr = {}, 113 attr_lm = {}, 114 mouse_shape = 0, 115 short_name = 'cr', 116 }, 117 [8] = { 118 blinkoff = 0, 119 blinkon = 0, 120 blinkwait = 0, 121 cell_percentage = 20, 122 cursor_shape = 'horizontal', 123 name = 'operator', 124 hl_id = 0, 125 id_lm = 0, 126 attr = {}, 127 attr_lm = {}, 128 mouse_shape = 0, 129 short_name = 'o', 130 }, 131 [9] = { 132 blinkoff = 0, 133 blinkon = 0, 134 blinkwait = 0, 135 cell_percentage = 25, 136 cursor_shape = 'vertical', 137 name = 'visual_select', 138 hl_id = 0, 139 id_lm = 0, 140 attr = {}, 141 attr_lm = {}, 142 mouse_shape = 0, 143 short_name = 've', 144 }, 145 [10] = { 146 name = 'cmdline_hover', 147 mouse_shape = 0, 148 short_name = 'e', 149 }, 150 [11] = { 151 name = 'statusline_hover', 152 mouse_shape = 0, 153 short_name = 's', 154 }, 155 [12] = { 156 name = 'statusline_drag', 157 mouse_shape = 0, 158 short_name = 'sd', 159 }, 160 [13] = { 161 name = 'vsep_hover', 162 mouse_shape = 0, 163 short_name = 'vs', 164 }, 165 [14] = { 166 name = 'vsep_drag', 167 mouse_shape = 0, 168 short_name = 'vd', 169 }, 170 [15] = { 171 name = 'more', 172 mouse_shape = 0, 173 short_name = 'm', 174 }, 175 [16] = { 176 name = 'more_lastline', 177 mouse_shape = 0, 178 short_name = 'ml', 179 }, 180 [17] = { 181 blinkoff = 0, 182 blinkon = 0, 183 blinkwait = 0, 184 cell_percentage = 0, 185 cursor_shape = 'block', 186 name = 'showmatch', 187 hl_id = 0, 188 id_lm = 0, 189 attr = {}, 190 attr_lm = {}, 191 short_name = 'sm', 192 }, 193 [18] = { 194 blinkoff = 500, 195 blinkon = 500, 196 blinkwait = 0, 197 cell_percentage = 0, 198 cursor_shape = 'block', 199 name = 'terminal', 200 hl_id = 3, 201 id_lm = 3, 202 attr = { reverse = true }, 203 attr_lm = { reverse = true }, 204 short_name = 't', 205 }, 206 } 207 208 screen:expect(function() 209 -- Default 'guicursor', published on startup. 210 eq(expected_mode_info, screen._mode_info) 211 eq(true, screen._cursor_style_enabled) 212 eq('normal', screen.mode) 213 end) 214 215 -- Event is published ONLY if the cursor style changed. 216 screen._mode_info = nil 217 command("echo 'test'") 218 screen:expect { 219 grid = [[ 220 ^ | 221 {1:~ }|*3 222 test | 223 ]], 224 condition = function() 225 eq(nil, screen._mode_info) 226 end, 227 } 228 229 -- Change the cursor style. 230 n.command('hi Cursor guibg=DarkGray') 231 n.command( 232 'set guicursor=n-v-c:block,i-ci-ve:ver25,r-cr-o:hor20' 233 .. ',a:blinkwait700-blinkoff400-blinkon250-Cursor/lCursor' 234 .. ',sm:block-blinkwait175-blinkoff150-blinkon175' 235 ) 236 237 -- Update the expected values. 238 for _, m in ipairs(expected_mode_info) do 239 if m.name == 'showmatch' then 240 if m.blinkon then 241 m.blinkon = 175 242 end 243 if m.blinkoff then 244 m.blinkoff = 150 245 end 246 if m.blinkwait then 247 m.blinkwait = 175 248 end 249 else 250 if m.blinkon then 251 m.blinkon = 250 252 end 253 if m.blinkoff then 254 m.blinkoff = 400 255 end 256 if m.blinkwait then 257 m.blinkwait = 700 258 end 259 end 260 if m.hl_id then 261 m.hl_id = 67 262 m.attr = { background = Screen.colors.DarkGray } 263 end 264 if m.id_lm then 265 m.id_lm = 78 266 m.attr_lm = {} 267 end 268 end 269 270 -- Assert the new expectation. 271 screen:expect(function() 272 for i, v in ipairs(expected_mode_info) do 273 eq(v, screen._mode_info[i]) 274 end 275 eq(true, screen._cursor_style_enabled) 276 eq('normal', screen.mode) 277 end) 278 279 -- Change hl groups only, should update the styles 280 n.command('hi Cursor guibg=Red') 281 n.command('hi lCursor guibg=Green') 282 283 -- Update the expected values. 284 for _, m in ipairs(expected_mode_info) do 285 if m.hl_id then 286 m.attr = { background = Screen.colors.Red } 287 end 288 if m.id_lm then 289 m.attr_lm = { background = Screen.colors.Green } 290 end 291 end 292 -- Assert the new expectation. 293 screen:expect(function() 294 eq(expected_mode_info, screen._mode_info) 295 eq(true, screen._cursor_style_enabled) 296 eq('normal', screen.mode) 297 end) 298 299 -- update the highlight again to hide cursor 300 n.command('hi Cursor blend=100') 301 302 for _, m in ipairs(expected_mode_info) do 303 if m.hl_id then 304 m.attr = { background = Screen.colors.Red, blend = 100 } 305 end 306 end 307 screen:expect { 308 grid = [[ 309 ^ | 310 {1:~ }|*3 311 test | 312 ]], 313 condition = function() 314 eq(expected_mode_info, screen._mode_info) 315 end, 316 } 317 318 -- Another cursor style. 319 api.nvim_set_option_value( 320 'guicursor', 321 'n-v-c:ver35-blinkwait171-blinkoff172-blinkon173' 322 .. ',ve:hor35,o:ver50,i-ci:block,r-cr:hor90,sm:ver42', 323 {} 324 ) 325 screen:expect(function() 326 local named = {} 327 for _, m in ipairs(screen._mode_info) do 328 named[m.name] = m 329 end 330 eq('vertical', named.normal.cursor_shape) 331 eq(35, named.normal.cell_percentage) 332 eq('horizontal', named.visual_select.cursor_shape) 333 eq(35, named.visual_select.cell_percentage) 334 eq('vertical', named.operator.cursor_shape) 335 eq(50, named.operator.cell_percentage) 336 eq('block', named.insert.cursor_shape) 337 eq('vertical', named.showmatch.cursor_shape) 338 eq(90, named.cmdline_replace.cell_percentage) 339 eq(171, named.normal.blinkwait) 340 eq(172, named.normal.blinkoff) 341 eq(173, named.normal.blinkon) 342 eq(42, named.showmatch.cell_percentage) 343 end) 344 345 -- If there is no setting for guicursor, it becomes the default setting. 346 api.nvim_set_option_value( 347 'guicursor', 348 'n:ver35-blinkwait171-blinkoff172-blinkon173-Cursor/lCursor', 349 {} 350 ) 351 screen:expect(function() 352 for _, m in ipairs(screen._mode_info) do 353 if m.name ~= 'normal' then 354 eq('block', m.cursor_shape or 'block') 355 eq(0, m.blinkon or 0) 356 eq(0, m.blinkoff or 0) 357 eq(0, m.blinkwait or 0) 358 eq(0, m.hl_id or 0) 359 eq(0, m.id_lm or 0) 360 end 361 end 362 end) 363 end) 364 365 it("empty 'guicursor' sets cursor_shape=block in all modes", function() 366 api.nvim_set_option_value('guicursor', '', {}) 367 screen:expect(function() 368 -- Empty 'guicursor' sets enabled=false. 369 eq(false, screen._cursor_style_enabled) 370 for _, m in ipairs(screen._mode_info) do 371 if m['cursor_shape'] ~= nil then 372 eq('block', m.cursor_shape) 373 eq(0, m.blinkon) 374 eq(0, m.hl_id) 375 eq(0, m.id_lm) 376 end 377 end 378 end) 379 end) 380 381 it(':sleep does not hide cursor when sleeping', function() 382 n.feed(':sleep 300m | echo 42') 383 screen:expect([[ 384 | 385 {1:~ }|*3 386 :sleep 300m | echo 42^ | 387 ]]) 388 n.feed('\n') 389 screen:expect({ 390 grid = [[ 391 ^ | 392 {1:~ }|*3 393 :sleep 300m | echo 42 | 394 ]], 395 timeout = 100, 396 }) 397 screen:expect([[ 398 ^ | 399 {1:~ }|*3 400 42 | 401 ]]) 402 end) 403 404 it(':sleep! hides cursor when sleeping', function() 405 n.feed(':sleep! 300m | echo 42') 406 screen:expect([[ 407 | 408 {1:~ }|*3 409 :sleep! 300m | echo 42^ | 410 ]]) 411 n.feed('\n') 412 screen:expect({ 413 grid = [[ 414 | 415 {1:~ }|*3 416 :sleep! 300m | echo 42 | 417 ]], 418 timeout = 100, 419 }) 420 screen:expect([[ 421 ^ | 422 {1:~ }|*3 423 42 | 424 ]]) 425 end) 426 end)