neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

decorations_spec.lua (320557B)


      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 = n.clear
      6 local feed = n.feed
      7 local insert = n.insert
      8 local exec_lua = n.exec_lua
      9 local exec = n.exec
     10 local expect_events = t.expect_events
     11 local api = n.api
     12 local fn = n.fn
     13 local command = n.command
     14 local eq = t.eq
     15 local assert_alive = n.assert_alive
     16 local pcall_err = t.pcall_err
     17 
     18 --- @return integer
     19 local function setup_provider(code)
     20  return exec_lua([[
     21    local api = vim.api
     22    _G.ns1 = api.nvim_create_namespace "ns1"
     23  ]] .. (code or [[
     24    beamtrace = {}
     25    local function on_do(kind, ...)
     26      table.insert(beamtrace, {kind, ...})
     27    end
     28  ]]) .. [[
     29    api.nvim_set_decoration_provider(_G.ns1, {
     30      on_start = on_do; on_buf = on_do;
     31      on_win = on_do; on_line = on_do; on_range = on_do;
     32      on_end = on_do; _on_spell_nav = on_do;
     33    })
     34    return _G.ns1
     35  ]])
     36 end
     37 
     38 local function setup_screen(screen)
     39  screen:set_default_attr_ids {
     40    [1] = { bold = true, foreground = Screen.colors.Blue },
     41    [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
     42    [3] = { foreground = Screen.colors.Brown },
     43    [4] = { foreground = Screen.colors.Blue1 },
     44    [5] = { foreground = Screen.colors.Magenta },
     45    [6] = { bold = true, foreground = Screen.colors.Brown },
     46    [7] = { background = Screen.colors.Gray90 },
     47    [8] = { bold = true, reverse = true },
     48    [9] = { reverse = true },
     49    [10] = { italic = true, background = Screen.colors.Magenta },
     50    [11] = { foreground = Screen.colors.Red, background = tonumber('0x005028') },
     51    [12] = { foreground = tonumber('0x990000') },
     52    [13] = { background = Screen.colors.LightBlue },
     53    [14] = { background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue },
     54    [15] = { special = Screen.colors.Blue, undercurl = true },
     55    [16] = { special = Screen.colors.Red, undercurl = true },
     56    [17] = { foreground = Screen.colors.Red },
     57    [18] = { bold = true, foreground = Screen.colors.SeaGreen },
     58    [19] = { bold = true },
     59  }
     60 end
     61 
     62 describe('decorations providers', function()
     63  local screen ---@type test.functional.ui.screen
     64  before_each(function()
     65    clear()
     66    screen = Screen.new(40, 8)
     67    setup_screen(screen)
     68  end)
     69 
     70  local mulholland = [[
     71    // just to see if there was an accident
     72    // on Mulholland Drive
     73    try_start();
     74    bufref_T save_buf;
     75    switch_buffer(&save_buf, buf);
     76    posp = getmark(mark, false);
     77    restore_buffer(&save_buf); ]]
     78 
     79  local function check_trace(expected)
     80    local actual = exec_lua [[ local b = beamtrace beamtrace = {} return b ]]
     81    expect_events(expected, actual, 'beam trace')
     82  end
     83 
     84  it('does not OOM when inserting, rather than appending, to the decoration provider vector', function()
     85    -- Add a dummy decoration provider with a larger ns id than what setup_provider() creates.
     86    -- This forces get_decor_provider() to insert into the providers vector,
     87    -- rather than append, which used to spin in an infinite loop allocating
     88    -- memory until nvim crashed/was killed.
     89    setup_provider([[
     90      local ns2 = api.nvim_create_namespace "ns2"
     91      api.nvim_set_decoration_provider(ns2, {})
     92    ]])
     93    assert_alive()
     94  end)
     95 
     96  it('leave a trace', function()
     97    insert(mulholland)
     98 
     99    setup_provider()
    100 
    101    screen:expect {
    102      grid = [[
    103      // just to see if there was an accident |
    104      // on Mulholland Drive                  |
    105      try_start();                            |
    106      bufref_T save_buf;                      |
    107      switch_buffer(&save_buf, buf);          |
    108      posp = getmark(mark, false);            |
    109      restore_buffer(&save_buf);^              |
    110                                              |
    111    ]],
    112    }
    113    check_trace {
    114      { 'start', 4 },
    115      { 'win', 1000, 1, 0, 6 },
    116      { 'line', 1000, 1, 0 },
    117      { 'range', 1000, 1, 0, 0, 1, 0 },
    118      { 'line', 1000, 1, 1 },
    119      { 'range', 1000, 1, 1, 0, 2, 0 },
    120      { 'line', 1000, 1, 2 },
    121      { 'range', 1000, 1, 2, 0, 3, 0 },
    122      { 'line', 1000, 1, 3 },
    123      { 'range', 1000, 1, 3, 0, 4, 0 },
    124      { 'line', 1000, 1, 4 },
    125      { 'range', 1000, 1, 4, 0, 5, 0 },
    126      { 'line', 1000, 1, 5 },
    127      { 'range', 1000, 1, 5, 0, 6, 0 },
    128      { 'line', 1000, 1, 6 },
    129      { 'range', 1000, 1, 6, 0, 7, 0 },
    130      { 'end', 4 },
    131    }
    132 
    133    feed 'iü<esc>'
    134    screen:expect {
    135      grid = [[
    136      // just to see if there was an accident |
    137      // on Mulholland Drive                  |
    138      try_start();                            |
    139      bufref_T save_buf;                      |
    140      switch_buffer(&save_buf, buf);          |
    141      posp = getmark(mark, false);            |
    142      restore_buffer(&save_buf);^ü             |
    143                                              |
    144    ]],
    145    }
    146    check_trace {
    147      { 'start', 5 },
    148      { 'buf', 1, 5 },
    149      { 'win', 1000, 1, 0, 6 },
    150      { 'line', 1000, 1, 6 },
    151      { 'range', 1000, 1, 6, 0, 7, 0 },
    152      { 'end', 5 },
    153    }
    154  end)
    155 
    156  it('can have single provider', function()
    157    insert(mulholland)
    158    setup_provider [[
    159      local hl = api.nvim_get_hl_id_by_name "ErrorMsg"
    160      local test_ns = api.nvim_create_namespace "mulholland"
    161      function on_do(event, ...)
    162        if event == "line" then
    163          local win, buf, line = ...
    164          api.nvim_buf_set_extmark(buf, test_ns, line, line,
    165                             { end_line = line, end_col = line+1,
    166                               hl_group = hl,
    167                               ephemeral = true
    168                              })
    169        end
    170      end
    171    ]]
    172 
    173    screen:expect {
    174      grid = [[
    175      {2:/}/ just to see if there was an accident |
    176      /{2:/} on Mulholland Drive                  |
    177      tr{2:y}_start();                            |
    178      buf{2:r}ef_T save_buf;                      |
    179      swit{2:c}h_buffer(&save_buf, buf);          |
    180      posp {2:=} getmark(mark, false);            |
    181      restor{2:e}_buffer(&save_buf);^              |
    182                                              |
    183    ]],
    184    }
    185  end)
    186 
    187  it('can indicate spellchecked points', function()
    188    exec [[
    189    set spell
    190    set spelloptions=noplainbuffer
    191    syntax off
    192    ]]
    193 
    194    insert [[
    195    I am well written text.
    196    i am not capitalized.
    197    I am a speling mistakke.
    198    ]]
    199 
    200    setup_provider [[
    201      local ns = api.nvim_create_namespace "spell"
    202      beamtrace = {}
    203      local function on_do(kind, ...)
    204        if kind == 'win' or kind == 'spell' then
    205          api.nvim_buf_set_extmark(0, ns, 0, 0, {
    206            end_row = 2,
    207            end_col = 23,
    208            spell = true,
    209            priority = 20,
    210            ephemeral = true
    211          })
    212        end
    213        table.insert(beamtrace, {kind, ...})
    214      end
    215    ]]
    216 
    217    check_trace {
    218      { 'start', 5 },
    219      { 'win', 1000, 1, 0, 3 },
    220      { 'line', 1000, 1, 0 },
    221      { 'range', 1000, 1, 0, 0, 1, 0 },
    222      { 'line', 1000, 1, 1 },
    223      { 'range', 1000, 1, 1, 0, 2, 0 },
    224      { 'line', 1000, 1, 2 },
    225      { 'range', 1000, 1, 2, 0, 3, 0 },
    226      { 'line', 1000, 1, 3 },
    227      { 'range', 1000, 1, 3, 0, 4, 0 },
    228      { 'end', 5 },
    229    }
    230 
    231    feed 'gg0'
    232 
    233    screen:expect {
    234      grid = [[
    235      ^I am well written text.                 |
    236      {15:i} am not capitalized.                   |
    237      I am a {16:speling} {16:mistakke}.                |
    238                                              |
    239      {1:~                                       }|*3
    240                                              |
    241    ]],
    242    }
    243 
    244    feed ']s'
    245    check_trace {
    246      { 'spell', 1000, 1, 1, 0, 1, -1 },
    247    }
    248    screen:expect {
    249      grid = [[
    250      I am well written text.                 |
    251      {15:^i} am not capitalized.                   |
    252      I am a {16:speling} {16:mistakke}.                |
    253                                              |
    254      {1:~                                       }|*3
    255                                              |
    256    ]],
    257    }
    258 
    259    feed ']s'
    260    check_trace {
    261      { 'spell', 1000, 1, 2, 7, 2, -1 },
    262    }
    263    screen:expect {
    264      grid = [[
    265      I am well written text.                 |
    266      {15:i} am not capitalized.                   |
    267      I am a {16:^speling} {16:mistakke}.                |
    268                                              |
    269      {1:~                                       }|*3
    270                                              |
    271    ]],
    272    }
    273 
    274    -- spell=false with higher priority does disable spell
    275    local ns = api.nvim_create_namespace 'spell'
    276    local id = api.nvim_buf_set_extmark(0, ns, 0, 0, { priority = 30, end_row = 2, end_col = 23, spell = false })
    277 
    278    screen:expect {
    279      grid = [[
    280      I am well written text.                 |
    281      i am not capitalized.                   |
    282      I am a ^speling mistakke.                |
    283                                              |
    284      {1:~                                       }|*3
    285                                              |
    286    ]],
    287    }
    288 
    289    feed ']s'
    290    screen:expect {
    291      grid = [[
    292      I am well written text.                 |
    293      i am not capitalized.                   |
    294      I am a ^speling mistakke.                |
    295                                              |
    296      {1:~                                       }|*3
    297      {17:search hit BOTTOM, continuing at TOP}    |
    298    ]],
    299    }
    300    command('echo ""')
    301 
    302    -- spell=false with lower priority doesn't disable spell
    303    api.nvim_buf_set_extmark(0, ns, 0, 0, { id = id, priority = 10, end_row = 2, end_col = 23, spell = false })
    304 
    305    screen:expect {
    306      grid = [[
    307      I am well written text.                 |
    308      {15:i} am not capitalized.                   |
    309      I am a {16:^speling} {16:mistakke}.                |
    310                                              |
    311      {1:~                                       }|*3
    312                                              |
    313    ]],
    314    }
    315 
    316    feed ']s'
    317    screen:expect {
    318      grid = [[
    319      I am well written text.                 |
    320      {15:i} am not capitalized.                   |
    321      I am a {16:speling} {16:^mistakke}.                |
    322                                              |
    323      {1:~                                       }|*3
    324                                              |
    325    ]],
    326    }
    327  end)
    328 
    329  it('can predefine highlights', function()
    330    screen:try_resize(40, 16)
    331    insert(mulholland)
    332    exec [[
    333      3
    334      set ft=c
    335      syntax on
    336      set number cursorline
    337      split
    338    ]]
    339    local ns1 = setup_provider()
    340 
    341    for k, v in pairs {
    342      LineNr = { italic = true, bg = 'Magenta' },
    343      Comment = { fg = '#FF0000', bg = 80 * 256 + 40 },
    344      CursorLine = { link = 'ErrorMsg' },
    345    } do
    346      api.nvim_set_hl(ns1, k, v)
    347    end
    348 
    349    screen:expect {
    350      grid = [[
    351      {3:  1 }{4:// just to see if there was an accid}|
    352      {3:    }{4:ent}                                 |
    353      {3:  2 }{4:// on Mulholland Drive}              |
    354      {6:  3 }{7:^try_start();                        }|
    355      {3:  4 }bufref_T save_buf;                  |
    356      {3:  5 }switch_buffer(&save_buf, buf);      |
    357      {3:  6 }posp = getmark(mark, {5:false});        |
    358      {8:[No Name] [+]                           }|
    359      {3:  2 }{4:// on Mulholland Drive}              |
    360      {6:  3 }{7:try_start();                        }|
    361      {3:  4 }bufref_T save_buf;                  |
    362      {3:  5 }switch_buffer(&save_buf, buf);      |
    363      {3:  6 }posp = getmark(mark, {5:false});        |
    364      {3:  7 }restore_buffer(&save_buf);          |
    365      {9:[No Name] [+]                           }|
    366                                              |
    367    ]],
    368    }
    369 
    370    api.nvim_set_hl_ns(ns1)
    371    screen:expect {
    372      grid = [[
    373      {10:  1 }{11:// just to see if there was an accid}|
    374      {10:    }{11:ent}                                 |
    375      {10:  2 }{11:// on Mulholland Drive}              |
    376      {6:  3 }{2:^try_start();                        }|
    377      {10:  4 }bufref_T save_buf;                  |
    378      {10:  5 }switch_buffer(&save_buf, buf);      |
    379      {10:  6 }posp = getmark(mark, {5:false});        |
    380      {8:[No Name] [+]                           }|
    381      {10:  2 }{11:// on Mulholland Drive}              |
    382      {6:  3 }{2:try_start();                        }|
    383      {10:  4 }bufref_T save_buf;                  |
    384      {10:  5 }switch_buffer(&save_buf, buf);      |
    385      {10:  6 }posp = getmark(mark, {5:false});        |
    386      {10:  7 }restore_buffer(&save_buf);          |
    387      {9:[No Name] [+]                           }|
    388                                              |
    389    ]],
    390    }
    391 
    392    exec_lua [[
    393      local api = vim.api
    394      local thewin = api.nvim_get_current_win()
    395      local ns2 = api.nvim_create_namespace 'ns2'
    396      api.nvim_set_decoration_provider (ns2, {
    397        on_win = function (_, win, buf)
    398          api.nvim_set_hl_ns_fast(win == thewin and _G.ns1 or ns2)
    399        end;
    400      })
    401    ]]
    402    screen:expect {
    403      grid = [[
    404      {10:  1 }{11:// just to see if there was an accid}|
    405      {10:    }{11:ent}                                 |
    406      {10:  2 }{11:// on Mulholland Drive}              |
    407      {6:  3 }{2:^try_start();                        }|
    408      {10:  4 }bufref_T save_buf;                  |
    409      {10:  5 }switch_buffer(&save_buf, buf);      |
    410      {10:  6 }posp = getmark(mark, {5:false});        |
    411      {8:[No Name] [+]                           }|
    412      {3:  2 }{4:// on Mulholland Drive}              |
    413      {6:  3 }{7:try_start();                        }|
    414      {3:  4 }bufref_T save_buf;                  |
    415      {3:  5 }switch_buffer(&save_buf, buf);      |
    416      {3:  6 }posp = getmark(mark, {5:false});        |
    417      {3:  7 }restore_buffer(&save_buf);          |
    418      {9:[No Name] [+]                           }|
    419                                              |
    420    ]],
    421    }
    422  end)
    423 
    424  it('can break an existing link', function()
    425    insert(mulholland)
    426    local ns1 = setup_provider()
    427 
    428    exec [[
    429      highlight OriginalGroup guifg='#990000'
    430      highlight link LinkGroup OriginalGroup
    431    ]]
    432 
    433    api.nvim_buf_set_virtual_text(0, 0, 2, { { '- not red', 'LinkGroup' } }, {})
    434    screen:expect {
    435      grid = [[
    436      // just to see if there was an accident |
    437      // on Mulholland Drive                  |
    438      try_start(); {12:- not red}                  |
    439      bufref_T save_buf;                      |
    440      switch_buffer(&save_buf, buf);          |
    441      posp = getmark(mark, false);            |
    442      restore_buffer(&save_buf);^              |
    443                                              |
    444    ]],
    445    }
    446 
    447    api.nvim_set_hl(ns1, 'LinkGroup', { fg = 'Blue' })
    448    api.nvim_set_hl_ns(ns1)
    449 
    450    screen:expect {
    451      grid = [[
    452      // just to see if there was an accident |
    453      // on Mulholland Drive                  |
    454      try_start(); {4:- not red}                  |
    455      bufref_T save_buf;                      |
    456      switch_buffer(&save_buf, buf);          |
    457      posp = getmark(mark, false);            |
    458      restore_buffer(&save_buf);^              |
    459                                              |
    460    ]],
    461    }
    462  end)
    463 
    464  it("with 'default': do not break an existing link", function()
    465    insert(mulholland)
    466    local ns1 = setup_provider()
    467 
    468    exec [[
    469      highlight OriginalGroup guifg='#990000'
    470      highlight link LinkGroup OriginalGroup
    471    ]]
    472 
    473    api.nvim_buf_set_virtual_text(0, 0, 2, { { '- not red', 'LinkGroup' } }, {})
    474    screen:expect {
    475      grid = [[
    476      // just to see if there was an accident |
    477      // on Mulholland Drive                  |
    478      try_start(); {12:- not red}                  |
    479      bufref_T save_buf;                      |
    480      switch_buffer(&save_buf, buf);          |
    481      posp = getmark(mark, false);            |
    482      restore_buffer(&save_buf);^              |
    483                                              |
    484    ]],
    485    }
    486 
    487    api.nvim_set_hl(ns1, 'LinkGroup', { fg = 'Blue', default = true })
    488    api.nvim_set_hl_ns(ns1)
    489    feed 'k'
    490 
    491    screen:expect {
    492      grid = [[
    493      // just to see if there was an accident |
    494      // on Mulholland Drive                  |
    495      try_start(); {12:- not red}                  |
    496      bufref_T save_buf;                      |
    497      switch_buffer(&save_buf, buf);          |
    498      posp = getmark(mark, false^);            |
    499      restore_buffer(&save_buf);              |
    500                                              |
    501    ]],
    502    }
    503  end)
    504 
    505  it('can have virtual text', function()
    506    insert(mulholland)
    507    setup_provider [[
    508      local hl = api.nvim_get_hl_id_by_name "ErrorMsg"
    509      local test_ns = api.nvim_create_namespace "mulholland"
    510      function on_do(event, ...)
    511        if event == "line" then
    512          local win, buf, line = ...
    513          api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
    514            virt_text = {{'+', 'ErrorMsg'}};
    515            virt_text_pos='overlay';
    516            ephemeral = true;
    517          })
    518        end
    519      end
    520    ]]
    521 
    522    screen:expect {
    523      grid = [[
    524      {2:+}/ just to see if there was an accident |
    525      {2:+}/ on Mulholland Drive                  |
    526      {2:+}ry_start();                            |
    527      {2:+}ufref_T save_buf;                      |
    528      {2:+}witch_buffer(&save_buf, buf);          |
    529      {2:+}osp = getmark(mark, false);            |
    530      {2:+}estore_buffer(&save_buf);^              |
    531                                              |
    532    ]],
    533    }
    534  end)
    535 
    536  it('can have virtual text of the style: right_align', function()
    537    insert(mulholland)
    538    setup_provider [[
    539      local hl = api.nvim_get_hl_id_by_name "ErrorMsg"
    540      local test_ns = api.nvim_create_namespace "mulholland"
    541      function on_do(event, ...)
    542        if event == "line" then
    543          local win, buf, line = ...
    544          api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
    545            virt_text = {{'+'}, {string.rep(' ', line+1), 'ErrorMsg'}};
    546            virt_text_pos='right_align';
    547            ephemeral = true;
    548          })
    549        end
    550      end
    551    ]]
    552 
    553    screen:expect {
    554      grid = [[
    555      // just to see if there was an acciden+{2: }|
    556      // on Mulholland Drive               +{2:  }|
    557      try_start();                        +{2:   }|
    558      bufref_T save_buf;                 +{2:    }|
    559      switch_buffer(&save_buf, buf);    +{2:     }|
    560      posp = getmark(mark, false);     +{2:      }|
    561      restore_buffer(&save_buf);^      +{2:       }|
    562                                              |
    563    ]],
    564    }
    565  end)
    566 
    567  it('can have virtual text of the style: eol_right_align', function()
    568    insert(mulholland)
    569    setup_provider [[
    570      local hl = api.nvim_get_hl_id_by_name "ErrorMsg"
    571      local test_ns = api.nvim_create_namespace "mulholland"
    572      function on_do(event, ...)
    573        if event == "line" then
    574          local win, buf, line = ...
    575          api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
    576            virt_text = {{'+'}, {'1234567890', 'ErrorMsg'}};
    577            virt_text_pos='eol_right_align';
    578            ephemeral = true;
    579          })
    580        end
    581      end
    582    ]]
    583 
    584    screen:expect {
    585      grid = [[
    586      // just to see if there was an accident |
    587      // on Mulholland Drive       +{2:1234567890}|
    588      try_start();                 +{2:1234567890}|
    589      bufref_T save_buf;           +{2:1234567890}|
    590      switch_buffer(&save_buf, buf); +{2:12345678}|
    591      posp = getmark(mark, false); +{2:1234567890}|
    592      restore_buffer(&save_buf);^   +{2:1234567890}|
    593                                              |
    594    ]],
    595    }
    596  end)
    597 
    598  it('multiple eol_right_align', function()
    599    insert(mulholland)
    600    setup_provider [[
    601      local hl = api.nvim_get_hl_id_by_name "ErrorMsg"
    602      local test_ns = api.nvim_create_namespace "mulholland"
    603      function on_do(event, ...)
    604        if event == "line" then
    605          local win, buf, line = ...
    606          api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
    607            virt_text = {{'11111'}};
    608            virt_text_pos='eol_right_align';
    609            ephemeral = true;
    610          })
    611          api.nvim_buf_set_extmark(0, test_ns, line, 0, {
    612            virt_text = {{'22222'}};
    613            virt_text_pos='eol_right_align';
    614            ephemeral = true;
    615          })
    616        end
    617      end
    618    ]]
    619 
    620    screen:expect {
    621      grid = [[
    622      // just to see if there was an accident |
    623      // on Mulholland Drive       11111 22222|
    624      try_start();                 11111 22222|
    625      bufref_T save_buf;           11111 22222|
    626      switch_buffer(&save_buf, buf); 11111 222|
    627      posp = getmark(mark, false); 11111 22222|
    628      restore_buffer(&save_buf);^   11111 22222|
    629                                              |
    630    ]],
    631    }
    632  end)
    633 
    634  it('eol_right_align: second text much longer than first', function()
    635    insert('short')
    636    setup_provider [[
    637      local test_ns = api.nvim_create_namespace "test_length_diff"
    638      function on_do(event, ...)
    639        if event == "line" then
    640          local win, buf, line = ...
    641 
    642          api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
    643            virt_text = {{'AA', 'Comment'}};
    644            virt_text_pos = 'eol_right_align';
    645            priority = 100;
    646            ephemeral = true;
    647          })
    648 
    649          api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
    650            virt_text = {{'BBBBBBBBBBBBBBBBBBBB', 'ErrorMsg'}};
    651            virt_text_pos = 'eol_right_align';
    652            priority = 200;
    653            ephemeral = true;
    654          })
    655        end
    656      end
    657    ]]
    658 
    659    screen:expect([[
    660      shor^t            {4:AA} {2:BBBBBBBBBBBBBBBBBBBB}|
    661      {1:~                                       }|*6
    662                                              |
    663    ]])
    664  end)
    665 
    666  it('virtual text works with wrapped lines', function()
    667    insert(mulholland)
    668    feed('ggJj3JjJ')
    669    setup_provider [[
    670      local hl = api.nvim_get_hl_id_by_name "ErrorMsg"
    671      local test_ns = api.nvim_create_namespace "mulholland"
    672      function on_do(event, ...)
    673        if event == "line" then
    674          local win, buf, line = ...
    675          api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
    676            virt_text = {{string.rep('/', line+1), 'ErrorMsg'}};
    677            virt_text_pos='eol';
    678            ephemeral = true;
    679          })
    680          api.nvim_buf_set_extmark(buf, test_ns, line, 6, {
    681            virt_text = {{string.rep('*', line+1), 'ErrorMsg'}};
    682            virt_text_pos='overlay';
    683            ephemeral = true;
    684          })
    685          api.nvim_buf_set_extmark(buf, test_ns, line, 39, {
    686            virt_text = {{string.rep('!', line+1), 'ErrorMsg'}};
    687            virt_text_win_col=20;
    688            ephemeral = true;
    689          })
    690          api.nvim_buf_set_extmark(buf, test_ns, line, 40, {
    691            virt_text = {{string.rep('?', line+1), 'ErrorMsg'}};
    692            virt_text_win_col=10;
    693            ephemeral = true;
    694          })
    695          api.nvim_buf_set_extmark(buf, test_ns, line, 40, {
    696            virt_text = {{string.rep(';', line+1), 'ErrorMsg'}};
    697            virt_text_pos='overlay';
    698            ephemeral = true;
    699          })
    700          api.nvim_buf_set_extmark(buf, test_ns, line, 40, {
    701            virt_text = {{'+'}, {string.rep(' ', line+1), 'ErrorMsg'}};
    702            virt_text_pos='right_align';
    703            ephemeral = true;
    704          })
    705        end
    706      end
    707    ]]
    708 
    709    screen:expect {
    710      grid = [[
    711      // jus{2:*} to see if th{2:!}re was an accident |
    712      {2:;}n Mulholl{2:?}nd Drive {2:/}                 +{2: }|
    713      try_st{2:**}t(); bufref_{2:!!}save_buf; switch_b|
    714      {2:;;}fer(&sav{2:??}buf, buf); {2://}            +{2:  }|
    715      posp ={2:***}tmark(mark,{2:!!!}lse);^ restore_buf|
    716      {2:;;;}(&save_{2:???});  {2:///}                +{2:   }|
    717      {1:~                                       }|
    718                                              |
    719    ]],
    720    }
    721    command('setlocal breakindent breakindentopt=shift:2')
    722    screen:expect {
    723      grid = [[
    724      // jus{2:*} to see if th{2:!}re was an accident |
    725        {2:;}n Mulho{2:?}land Drive {2:/}               +{2: }|
    726      try_st{2:**}t(); bufref_{2:!!}save_buf; switch_b|
    727        {2:;;}fer(&s{2:??}e_buf, buf); {2://}          +{2:  }|
    728      posp ={2:***}tmark(mark,{2:!!!}lse);^ restore_buf|
    729        {2:;;;}(&sav{2:???}uf);  {2:///}              +{2:   }|
    730      {1:~                                       }|
    731                                              |
    732    ]],
    733    }
    734  end)
    735 
    736  it('can highlight beyond EOL', function()
    737    insert(mulholland)
    738    setup_provider [[
    739      local test_ns = api.nvim_create_namespace "veberod"
    740      function on_do(event, ...)
    741        if event == "line" then
    742          local win, buf, line = ...
    743          if string.find(api.nvim_buf_get_lines(buf, line, line+1, true)[1], "buf") then
    744            api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
    745              end_line = line+1;
    746              hl_group = 'DiffAdd';
    747              hl_eol = true;
    748              ephemeral = true;
    749            })
    750          end
    751        end
    752      end
    753    ]]
    754 
    755    screen:expect {
    756      grid = [[
    757      // just to see if there was an accident |
    758      // on Mulholland Drive                  |
    759      try_start();                            |
    760      {13:bufref_T save_buf;                      }|
    761      {13:switch_buffer(&save_buf, buf);          }|
    762      posp = getmark(mark, false);            |
    763      {13:restore_buffer(&save_buf);^              }|
    764                                              |
    765    ]],
    766    }
    767  end)
    768 
    769  it('can create and remove signs when CursorMoved autocommand validates botline #18661', function()
    770    exec_lua([[
    771      local lines = {}
    772      for i = 1, 200 do
    773        lines[i] = 'hello' .. tostring(i)
    774      end
    775      vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
    776    ]])
    777    setup_provider([[
    778      local function on_do(kind, winid, bufnr, topline, botline)
    779        if kind == 'win' then
    780          if topline < 100 and botline > 100 then
    781            api.nvim_buf_set_extmark(bufnr, ns1, 99, -1, { sign_text = 'X' })
    782          else
    783            api.nvim_buf_clear_namespace(bufnr, ns1, 0, -1)
    784          end
    785        end
    786      end
    787    ]])
    788    command([[autocmd CursorMoved * call line('w$')]])
    789    api.nvim_win_set_cursor(0, { 100, 0 })
    790    screen:expect([[
    791      {14:  }hello97                               |
    792      {14:  }hello98                               |
    793      {14:  }hello99                               |
    794      {14:X }^hello100                              |
    795      {14:  }hello101                              |
    796      {14:  }hello102                              |
    797      {14:  }hello103                              |
    798                                              |
    799    ]])
    800    api.nvim_win_set_cursor(0, { 1, 0 })
    801    screen:expect([[
    802      ^hello1                                  |
    803      hello2                                  |
    804      hello3                                  |
    805      hello4                                  |
    806      hello5                                  |
    807      hello6                                  |
    808      hello7                                  |
    809                                              |
    810    ]])
    811  end)
    812 
    813  it('does allow removing extmarks during on_line callbacks', function()
    814    exec_lua([[
    815      eok = true
    816    ]])
    817    setup_provider([[
    818      local function on_do(kind, winid, bufnr, topline, botline)
    819        if kind == 'line' then
    820          api.nvim_buf_set_extmark(bufnr, ns1, 1, -1, { sign_text = 'X' })
    821          eok = pcall(api.nvim_buf_clear_namespace, bufnr, ns1, 0, -1)
    822        end
    823      end
    824    ]])
    825    exec_lua([[
    826      assert(eok == true)
    827    ]])
    828  end)
    829 
    830  it('on_line is invoked only for buffer lines', function()
    831    insert(mulholland)
    832    command('vnew')
    833    insert(mulholland)
    834    feed('dd')
    835    command('windo diffthis')
    836 
    837    exec_lua([[
    838      out_of_bound = false
    839    ]])
    840    setup_provider([[
    841      local function on_do(kind, _, bufnr, row)
    842        if kind == 'line' then
    843          if not api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1] then
    844            out_of_bound = true
    845          end
    846        end
    847      end
    848    ]])
    849 
    850    feed('<C-e>')
    851 
    852    exec_lua([[
    853      assert(out_of_bound == false)
    854    ]])
    855  end)
    856 
    857  it('on_range is invoked on all visible characters', function()
    858    clear()
    859    screen = Screen.new(20, 4)
    860    setup_screen(screen)
    861 
    862    local function record()
    863      exec_lua(function()
    864        _G.p_min = { math.huge, math.huge }
    865        _G.p_max = { -math.huge, -math.huge }
    866        function _G.pos_gt(a, b)
    867          return a[1] > b[1] or (a[1] == b[1] and a[2] > b[2])
    868        end
    869        function _G.pos_lt(a, b)
    870          return a[1] < b[1] or (a[1] == b[1] and a[2] < b[2])
    871        end
    872      end)
    873      setup_provider [[
    874        local function on_do(kind, _, bufnr, br, bc, er, ec)
    875          if kind == 'range' then
    876            local b = { br, bc }
    877            local e = { er, ec }
    878            if _G.pos_gt(_G.p_min, b) then
    879              _G.p_min = b
    880            end
    881            if _G.pos_lt(_G.p_max, e) then
    882              _G.p_max = e
    883            end
    884          end
    885        end
    886      ]]
    887    end
    888    local function check(min, max)
    889      local p_min = exec_lua('return _G.p_min')
    890      assert(
    891        p_min[1] < min[1] or (p_min[1] == min[1] and p_min[2] <= min[2]),
    892        'minimum position ' .. vim.inspect(p_min) .. ' should be before the first char'
    893      )
    894      local p_max = exec_lua('return _G.p_max')
    895      assert(
    896        p_max[1] > max[1] or (p_max[1] == max[1] and p_max[2] >= max[2]),
    897        'maximum position ' .. vim.inspect(p_max) .. ' should be on or after the last char'
    898      )
    899    end
    900 
    901    -- Multiple lines.
    902    exec_lua([[
    903      local lines = { ('a'):rep(40), ('b'):rep(40), ('c'):rep(40) }
    904      vim.api.nvim_buf_set_lines(0, 0, -1, true, lines)
    905      vim.api.nvim_win_set_cursor(0, { 2, 0 })
    906    ]])
    907    record()
    908    screen:expect([[
    909      ^bbbbbbbbbbbbbbbbbbbb|
    910      bbbbbbbbbbbbbbbbbbbb|
    911      ccccccccccccccccc{1:@@@}|
    912                          |
    913    ]])
    914    check({ 1, 0 }, { 2, 21 })
    915 
    916    -- One long line.
    917    exec_lua([[
    918      local lines = { ('a'):rep(100) }
    919      vim.api.nvim_buf_set_lines(0, 0, -1, true, lines)
    920      vim.api.nvim_win_set_cursor(0, { 1, 70 })
    921    ]])
    922    record()
    923    screen:expect([[
    924      {1:<<<}aaaaaaaaaaaaaaaaa|
    925      aaaaaaaaaaaaaaaaaaaa|
    926      aaaaaaaaaa^aaaaaaaaaa|
    927                          |
    928    ]])
    929    check({ 0, 20 }, { 0, 81 })
    930 
    931    -- Multibyte characters.
    932    exec_lua([[
    933      local lines = { ('\195\162'):rep(100) }
    934      vim.api.nvim_buf_set_lines(0, 0, -1, true, lines)
    935      vim.api.nvim_win_set_cursor(0, { 1, 70 * 2 })
    936    ]])
    937    record()
    938    screen:expect([[
    939      {1:<<<}âââââââââââââââââ|
    940      ââââââââââââââââââââ|
    941      ââââââââââ^ââââââââââ|
    942                          |
    943    ]])
    944    check({ 0, 20 * 2 }, { 0, 81 * 2 })
    945 
    946    -- Tabs.
    947    exec_lua([[
    948      local lines = { 'a' .. ('\t'):rep(100) }
    949      vim.api.nvim_buf_set_lines(0, 0, -1, true, lines)
    950      vim.api.nvim_win_set_cursor(0, { 1, 39 })
    951    ]])
    952    record()
    953    screen:expect([[
    954      {1:<<<}                 |
    955                          |
    956                 ^         |
    957                          |
    958    ]])
    959    check({ 0, 33 }, { 0, 94 })
    960 
    961    -- One long line without wrapping.
    962    command('set nowrap')
    963    exec_lua([[
    964      local lines = { ('a'):rep(50) .. ('b'):rep(50) }
    965      vim.api.nvim_buf_set_lines(0, 0, -1, true, lines)
    966      vim.api.nvim_win_set_cursor(0, { 1, 50 })
    967    ]])
    968    record()
    969    screen:expect([[
    970      aaaaaaaaaa^bbbbbbbbbb|
    971      {1:~                   }|*2
    972                          |
    973    ]])
    974    check({ 0, 40 }, { 0, 60 })
    975  end)
    976 
    977  it('can add new providers during redraw #26652', function()
    978    setup_provider [[
    979    local ns = api.nvim_create_namespace('test_no_add')
    980    function on_do(...)
    981      api.nvim_set_decoration_provider(ns, {})
    982    end
    983    ]]
    984 
    985    n.assert_alive()
    986  end)
    987 
    988  it('is not invoked repeatedly in Visual mode with vim.schedule() #20235', function()
    989    exec_lua([[_G.cnt = 0]])
    990    setup_provider([[
    991      function on_do(event, ...)
    992        if event == 'win' then
    993          vim.schedule(function() end)
    994          _G.cnt = _G.cnt + 1
    995        end
    996      end
    997    ]])
    998    feed('v')
    999    screen:expect([[
   1000      ^                                        |
   1001      {1:~                                       }|*6
   1002      {19:-- VISUAL --}                            |
   1003    ]])
   1004    eq(2, exec_lua([[return _G.cnt]]))
   1005  end)
   1006 
   1007  it('can do large changes to the marktree', function()
   1008    insert('line1 with a lot of text\nline2 with a lot of text')
   1009    setup_provider([[
   1010      function on_do(event, _, _, row)
   1011        if event == 'win' or (event == 'line' and row == 1) then
   1012          vim.api.nvim_buf_clear_namespace(0, ns1, 0, -1)
   1013          for i = 0,1 do
   1014            for j = 0,23 do
   1015              vim.api.nvim_buf_set_extmark(0, ns1, i, j, {hl_group='ErrorMsg', end_col = j+1})
   1016            end
   1017          end
   1018        end
   1019      end
   1020    ]])
   1021 
   1022    -- Doesn't crash when modifying the marktree between line1 and line2
   1023    screen:expect([[
   1024      {2:line1 with a lot of text}                |
   1025      {2:line2 with a lot of tex^t}                |
   1026      {1:~                                       }|*5
   1027                                              |
   1028    ]])
   1029  end)
   1030 
   1031  it('inline virt_text does not result in wrong cursor column #33153', function()
   1032    insert('line1 with a lot of text\nline2 with a lot of text')
   1033    setup_provider([[
   1034      _G.do_win = false
   1035      vim.keymap.set('n', 'f', function()
   1036        _G.do_win = true
   1037        vim.cmd('redraw!')
   1038      end)
   1039      vim.o.concealcursor = 'n'
   1040      function on_do(event)
   1041        if event == 'win' and _G.do_win then
   1042          vim.api.nvim_buf_set_extmark(0, ns1, 1, 0, {
   1043            virt_text = { { 'virt_text ' } },
   1044            virt_text_pos = 'inline'
   1045          })
   1046        end
   1047      end
   1048    ]])
   1049    feed('f')
   1050    screen:expect([[
   1051      line1 with a lot of text                |
   1052      virt_text line2 with a lot of tex^t      |
   1053      {1:~                                       }|*5
   1054                                              |
   1055    ]])
   1056  end)
   1057 
   1058  it('decor provider is enabled again for next redraw after on_win disabled it', function()
   1059    exec_lua(function()
   1060      vim.api.nvim_set_decoration_provider(vim.api.nvim_create_namespace(''), {
   1061        on_win = function()
   1062          return false
   1063        end,
   1064        on_buf = function()
   1065          _G.did_buf = (_G.did_buf or 0) + 1
   1066        end,
   1067      })
   1068    end)
   1069    api.nvim_buf_set_lines(0, 0, -1, false, { 'foo' })
   1070    screen:expect([[
   1071      ^foo                                     |
   1072      {1:~                                       }|*6
   1073                                              |
   1074    ]])
   1075    eq(1, exec_lua('return _G.did_buf'))
   1076  end)
   1077 end)
   1078 
   1079 describe('decoration_providers', function()
   1080  it('errors and logs gracefully', function()
   1081    local testlog = 'Xtest_decorations_log'
   1082    clear({ env = { NVIM_LOG_FILE = testlog } })
   1083    local screen = Screen.new(65, 7)
   1084    setup_provider([[
   1085      function on_do(...)
   1086        error "Foo"
   1087      end
   1088    ]])
   1089    screen:expect([[
   1090      {3:                                                                 }|
   1091      {9:Decoration provider "start" (ns=ns1):}                            |
   1092      {9:Lua: [string "<nvim>"]:4: Foo}                                    |
   1093      {9:stack traceback:}                                                 |
   1094      {9:        [C]: in function 'error'}                                 |
   1095      {9:        [string "<nvim>"]:4: in function <[string "<nvim>"]:3>}   |
   1096      {6:Press ENTER or type command to continue}^                          |
   1097    ]])
   1098    t.assert_log('Error in decoration provider "start" %(ns=ns1%):', testlog, 100)
   1099    t.assert_log('Lua: %[string "<nvim>"%]:4: Foo', testlog, 100)
   1100    n.check_close()
   1101    os.remove(testlog)
   1102  end)
   1103 end)
   1104 
   1105 local example_text = [[
   1106 for _,item in ipairs(items) do
   1107    local text, hl_id_cell, count = unpack(item)
   1108    if hl_id_cell ~= nil then
   1109        hl_id = hl_id_cell
   1110    end
   1111    for _ = 1, (count or 1) do
   1112        local cell = line[colpos]
   1113        cell.text = text
   1114        cell.hl_id = hl_id
   1115        colpos = colpos+1
   1116    end
   1117 end]]
   1118 
   1119 describe('extmark decorations', function()
   1120  local screen ---@type test.functional.ui.screen
   1121  local ns ---@type integer
   1122  before_each(function()
   1123    clear()
   1124    screen = Screen.new(50, 15)
   1125    screen:set_default_attr_ids {
   1126      [1] = { bold = true, foreground = Screen.colors.Blue },
   1127      [2] = { foreground = Screen.colors.Brown },
   1128      [3] = { bold = true, foreground = Screen.colors.SeaGreen },
   1129      [4] = { background = Screen.colors.Red1, foreground = Screen.colors.Gray100 },
   1130      [5] = { foreground = Screen.colors.Brown, bold = true },
   1131      [6] = { foreground = Screen.colors.DarkCyan },
   1132      [7] = { foreground = Screen.colors.Grey0, background = tonumber('0xff4c4c') },
   1133      [8] = { foreground = tonumber('0x180606'), background = tonumber('0xff4c4c') },
   1134      [9] = { foreground = tonumber('0xe40c0c'), background = tonumber('0xff4c4c'), bold = true },
   1135      [10] = { foreground = tonumber('0xb20000'), background = tonumber('0xff4c4c') },
   1136      [11] = { blend = 30, background = Screen.colors.Red1 },
   1137      [12] = { foreground = Screen.colors.Brown, blend = 30, background = Screen.colors.Red1, bold = true },
   1138      [13] = { foreground = Screen.colors.Fuchsia },
   1139      [14] = { background = Screen.colors.Red1, foreground = Screen.colors.Black },
   1140      [15] = { background = Screen.colors.Red1, foreground = tonumber('0xb20000') },
   1141      [16] = { blend = 30, background = Screen.colors.Red1, foreground = Screen.colors.Magenta1 },
   1142      [17] = { bold = true, foreground = Screen.colors.Brown, background = Screen.colors.LightGrey },
   1143      [18] = { background = Screen.colors.LightGrey },
   1144      [19] = { foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGrey },
   1145      [20] = { foreground = tonumber('0x180606'), background = tonumber('0xf13f3f') },
   1146      [21] = { foreground = Screen.colors.Gray0, background = tonumber('0xf13f3f') },
   1147      [22] = { foreground = tonumber('0xb20000'), background = tonumber('0xf13f3f') },
   1148      [23] = { foreground = Screen.colors.Magenta1, background = Screen.colors.LightGrey },
   1149      [24] = { bold = true },
   1150      [25] = { background = Screen.colors.LightRed },
   1151      [26] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey },
   1152      [27] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Black },
   1153      [28] = { underline = true, foreground = Screen.colors.SlateBlue },
   1154      [29] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.LightGrey, underline = true },
   1155      [30] = { foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGrey, underline = true },
   1156      [31] = { underline = true, foreground = Screen.colors.DarkCyan },
   1157      [32] = { underline = true },
   1158      [33] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey },
   1159      [34] = { background = Screen.colors.Yellow },
   1160      [35] = { background = Screen.colors.Yellow, bold = true, foreground = Screen.colors.Blue },
   1161      [36] = { foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.Red },
   1162      [37] = { background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue },
   1163      [38] = { background = Screen.colors.LightBlue },
   1164      [39] = { foreground = Screen.colors.Blue1, background = Screen.colors.LightCyan1, bold = true },
   1165      [40] = { reverse = true },
   1166      [41] = { bold = true, reverse = true },
   1167      [42] = { undercurl = true, special = Screen.colors.Red },
   1168      [43] = { background = Screen.colors.Yellow, undercurl = true, special = Screen.colors.Red },
   1169      [44] = { background = Screen.colors.LightMagenta },
   1170      [45] = { background = Screen.colors.Red, special = Screen.colors.Red, foreground = Screen.colors.Red },
   1171      [46] = { background = Screen.colors.Blue, foreground = Screen.colors.Blue, special = Screen.colors.Red },
   1172      [47] = { background = Screen.colors.Green, foreground = Screen.colors.Blue, special = Screen.colors.Red },
   1173    }
   1174 
   1175    ns = api.nvim_create_namespace 'test'
   1176  end)
   1177 
   1178  it('empty virtual text at eol should not break colorcolumn #17860', function()
   1179    insert(example_text)
   1180    feed('gg')
   1181    command('set colorcolumn=40')
   1182    screen:expect([[
   1183      ^for _,item in ipairs(items) do         {25: }          |
   1184          local text, hl_id_cell, count = unp{25:a}ck(item)  |
   1185          if hl_id_cell ~= nil then          {25: }          |
   1186              hl_id = hl_id_cell             {25: }          |
   1187          end                                {25: }          |
   1188          for _ = 1, (count or 1) do         {25: }          |
   1189              local cell = line[colpos]      {25: }          |
   1190              cell.text = text               {25: }          |
   1191              cell.hl_id = hl_id             {25: }          |
   1192              colpos = colpos+1              {25: }          |
   1193          end                                {25: }          |
   1194      end                                    {25: }          |
   1195      {1:~                                                 }|*2
   1196                                                        |
   1197    ]])
   1198    api.nvim_buf_set_extmark(0, ns, 4, 0, { virt_text = { { '' } }, virt_text_pos = 'eol' })
   1199    screen:expect_unchanged()
   1200  end)
   1201 
   1202  it('can have virtual text of overlay position', function()
   1203    insert(example_text)
   1204    feed 'gg'
   1205 
   1206    for i = 1, 9 do
   1207      api.nvim_buf_set_extmark(0, ns, i, 0, { virt_text = { { '|', 'LineNr' } }, virt_text_pos = 'overlay' })
   1208      if i == 3 or (i >= 6 and i <= 9) then
   1209        api.nvim_buf_set_extmark(0, ns, i, 4, { virt_text = { { '|', 'NonText' } }, virt_text_pos = 'overlay' })
   1210      end
   1211    end
   1212    api.nvim_buf_set_extmark(
   1213      0,
   1214      ns,
   1215      9,
   1216      10,
   1217      { virt_text = { { 'foo' }, { 'bar', 'MoreMsg' }, { '!!', 'ErrorMsg' } }, virt_text_pos = 'overlay' }
   1218    )
   1219 
   1220    -- can "float" beyond end of line
   1221    api.nvim_buf_set_extmark(0, ns, 5, 28, { virt_text = { { 'loopy', 'ErrorMsg' } }, virt_text_pos = 'overlay' })
   1222    -- bound check: right edge of window
   1223    api.nvim_buf_set_extmark(
   1224      0,
   1225      ns,
   1226      2,
   1227      26,
   1228      { virt_text = { { 'bork bork bork' }, { (' bork'):rep(10), 'ErrorMsg' } }, virt_text_pos = 'overlay' }
   1229    )
   1230    -- empty virt_text should not change anything
   1231    api.nvim_buf_set_extmark(0, ns, 6, 16, { virt_text = { { '' } }, virt_text_pos = 'overlay' })
   1232 
   1233    screen:expect {
   1234      grid = [[
   1235      ^for _,item in ipairs(items) do                    |
   1236      {2:|}   local text, hl_id_cell, count = unpack(item)  |
   1237      {2:|}   if hl_id_cell ~= nil tbork bork bork{4: bork bork}|
   1238      {2:|}   {1:|}   hl_id = hl_id_cell                        |
   1239      {2:|}   end                                           |
   1240      {2:|}   for _ = 1, (count or 1) {4:loopy}                 |
   1241      {2:|}   {1:|}   local cell = line[colpos]                 |
   1242      {2:|}   {1:|}   cell.text = text                          |
   1243      {2:|}   {1:|}   cell.hl_id = hl_id                        |
   1244      {2:|}   {1:|}   cofoo{3:bar}{4:!!}olpos+1                         |
   1245          end                                           |
   1246      end                                               |
   1247      {1:~                                                 }|*2
   1248                                                        |
   1249    ]],
   1250    }
   1251 
   1252    -- handles broken lines
   1253    screen:try_resize(22, 25)
   1254    screen:expect {
   1255      grid = [[
   1256      ^for _,item in ipairs(i|
   1257      tems) do              |
   1258      {2:|}   local text, hl_id_|
   1259      cell, count = unpack(i|
   1260      tem)                  |
   1261      {2:|}   if hl_id_cell ~= n|
   1262      il tbork bork bork{4: bor}|
   1263      {2:|}   {1:|}   hl_id = hl_id_|
   1264      cell                  |
   1265      {2:|}   end               |
   1266      {2:|}   for _ = 1, (count |
   1267      or 1) {4:loopy}           |
   1268      {2:|}   {1:|}   local cell = l|
   1269      ine[colpos]           |
   1270      {2:|}   {1:|}   cell.text = te|
   1271      xt                    |
   1272      {2:|}   {1:|}   cell.hl_id = h|
   1273      l_id                  |
   1274      {2:|}   {1:|}   cofoo{3:bar}{4:!!}olpo|
   1275      s+1                   |
   1276          end               |
   1277      end                   |
   1278      {1:~                     }|*2
   1279                            |
   1280    ]],
   1281    }
   1282 
   1283    -- truncating in the middle of a char leaves a space
   1284    api.nvim_buf_set_lines(0, 0, 1, true, { 'for _,item in ipairs(items) do  -- 古古古' })
   1285    api.nvim_buf_set_lines(0, 10, 12, true, { '    end  -- ??????????', 'end  -- ?古古古古?古古' })
   1286    api.nvim_buf_set_extmark(0, ns, 0, 35, { virt_text = { { 'A', 'ErrorMsg' }, { 'AA' } }, virt_text_pos = 'overlay' })
   1287    api.nvim_buf_set_extmark(0, ns, 10, 19, { virt_text = { { '口口口', 'ErrorMsg' } }, virt_text_pos = 'overlay' })
   1288    api.nvim_buf_set_extmark(0, ns, 11, 21, { virt_text = { { '口口口', 'ErrorMsg' } }, virt_text_pos = 'overlay' })
   1289    api.nvim_buf_set_extmark(0, ns, 11, 8, { virt_text = { { '口口', 'ErrorMsg' } }, virt_text_pos = 'overlay' })
   1290    screen:expect {
   1291      grid = [[
   1292      ^for _,item in ipairs(i|
   1293      tems) do  -- {4:A}AA 古   |
   1294      {2:|}   local text, hl_id_|
   1295      cell, count = unpack(i|
   1296      tem)                  |
   1297      {2:|}   if hl_id_cell ~= n|
   1298      il tbork bork bork{4: bor}|
   1299      {2:|}   {1:|}   hl_id = hl_id_|
   1300      cell                  |
   1301      {2:|}   end               |
   1302      {2:|}   for _ = 1, (count |
   1303      or 1) {4:loopy}           |
   1304      {2:|}   {1:|}   local cell = l|
   1305      ine[colpos]           |
   1306      {2:|}   {1:|}   cell.text = te|
   1307      xt                    |
   1308      {2:|}   {1:|}   cell.hl_id = h|
   1309      l_id                  |
   1310      {2:|}   {1:|}   cofoo{3:bar}{4:!!}olpo|
   1311      s+1                   |
   1312          end  -- ???????{4:口 }|
   1313      end  -- {4:口口} 古古{4:口口 }|
   1314      {1:~                     }|*2
   1315                            |
   1316    ]],
   1317    }
   1318 
   1319    screen:try_resize(82, 13)
   1320    screen:expect {
   1321      grid = [[
   1322      ^for _,item in ipairs(items) do  -- {4:A}AA 古                                         |
   1323      {2:|}   local text, hl_id_cell, count = unpack(item)                                  |
   1324      {2:|}   if hl_id_cell ~= nil tbork bork bork{4: bork bork bork bork bork bork bork bork b}|
   1325      {2:|}   {1:|}   hl_id = hl_id_cell                                                        |
   1326      {2:|}   end                                                                           |
   1327      {2:|}   for _ = 1, (count or 1) {4:loopy}                                                 |
   1328      {2:|}   {1:|}   local cell = line[colpos]                                                 |
   1329      {2:|}   {1:|}   cell.text = text                                                          |
   1330      {2:|}   {1:|}   cell.hl_id = hl_id                                                        |
   1331      {2:|}   {1:|}   cofoo{3:bar}{4:!!}olpos+1                                                         |
   1332          end  -- ???????{4:口口口}                                                         |
   1333      end  -- {4:口口} 古古{4:口口口}                                                           |
   1334                                                                                        |
   1335    ]],
   1336    }
   1337 
   1338    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   1339    screen:expect {
   1340      grid = [[
   1341      ^for _,item in ipairs(items) do  -- 古古古                                         |
   1342          local text, hl_id_cell, count = unpack(item)                                  |
   1343          if hl_id_cell ~= nil then                                                     |
   1344              hl_id = hl_id_cell                                                        |
   1345          end                                                                           |
   1346          for _ = 1, (count or 1) do                                                    |
   1347              local cell = line[colpos]                                                 |
   1348              cell.text = text                                                          |
   1349              cell.hl_id = hl_id                                                        |
   1350              colpos = colpos+1                                                         |
   1351          end  -- ??????????                                                            |
   1352      end  -- ?古古古古?古古                                                            |
   1353                                                                                        |
   1354    ]],
   1355    }
   1356  end)
   1357 
   1358  it('overlay virtual text works with wrapped lines #25158', function()
   1359    screen:try_resize(50, 6)
   1360    insert(('ab'):rep(100))
   1361    for i = 0, 9 do
   1362      api.nvim_buf_set_extmark(0, ns, 0, 42 + i, { virt_text = { { tostring(i), 'ErrorMsg' } }, virt_text_pos = 'overlay' })
   1363      api.nvim_buf_set_extmark(
   1364        0,
   1365        ns,
   1366        0,
   1367        91 + i,
   1368        { virt_text = { { tostring(i), 'ErrorMsg' } }, virt_text_pos = 'overlay', virt_text_hide = true }
   1369      )
   1370    end
   1371    screen:expect {
   1372      grid = [[
   1373      ababababababababababababababababababababab{4:01234567}|
   1374      {4:89}abababababababababababababababababababa{4:012345678}|
   1375      {4:9}babababababababababababababababababababababababab|
   1376      ababababababababababababababababababababababababa^b|
   1377      {1:~                                                 }|
   1378                                                        |
   1379    ]],
   1380    }
   1381 
   1382    command('set showbreak=++')
   1383    screen:expect {
   1384      grid = [[
   1385      ababababababababababababababababababababab{4:01234567}|
   1386      {1:++}{4:89}abababababababababababababababababababa{4:0123456}|
   1387      {1:++}{4:789}babababababababababababababababababababababab|
   1388      {1:++}abababababababababababababababababababababababab|
   1389      {1:++}ababa^b                                          |
   1390                                                        |
   1391    ]],
   1392    }
   1393 
   1394    feed('2gkvg0')
   1395    screen:expect {
   1396      grid = [[
   1397      ababababababababababababababababababababab{4:01234567}|
   1398      {1:++}{4:89}abababababababababababababababababababa{4:0123456}|
   1399      {1:++}^a{27:babab}ababababababababababababababababababababab|
   1400      {1:++}abababababababababababababababababababababababab|
   1401      {1:++}ababab                                          |
   1402      {24:-- VISUAL --}                                      |
   1403    ]],
   1404    }
   1405 
   1406    feed('o')
   1407    screen:expect {
   1408      grid = [[
   1409      ababababababababababababababababababababab{4:01234567}|
   1410      {1:++}{4:89}abababababababababababababababababababa{4:0123456}|
   1411      {1:++}{27:ababa}^bababababababababababababababababababababab|
   1412      {1:++}abababababababababababababababababababababababab|
   1413      {1:++}ababab                                          |
   1414      {24:-- VISUAL --}                                      |
   1415    ]],
   1416    }
   1417 
   1418    feed('gk')
   1419    screen:expect {
   1420      grid = [[
   1421      ababababababababababababababababababababab{4:01234567}|
   1422      {1:++}{4:89}aba^b{27:ababababababababababababababababababababab}|
   1423      {1:++}{27:a}{4:89}babababababababababababababababababababababab|
   1424      {1:++}abababababababababababababababababababababababab|
   1425      {1:++}ababab                                          |
   1426      {24:-- VISUAL --}                                      |
   1427    ]],
   1428    }
   1429 
   1430    feed('o')
   1431    screen:expect {
   1432      grid = [[
   1433      ababababababababababababababababababababab{4:01234567}|
   1434      {1:++}{4:89}aba{27:bababababababababababababababababababababab}|
   1435      {1:++}^a{4:89}babababababababababababababababababababababab|
   1436      {1:++}abababababababababababababababababababababababab|
   1437      {1:++}ababab                                          |
   1438      {24:-- VISUAL --}                                      |
   1439    ]],
   1440    }
   1441 
   1442    feed('<Esc>$')
   1443    command('set number showbreak=')
   1444    screen:expect {
   1445      grid = [[
   1446      {2:  1 }ababababababababababababababababababababab{4:0123}|
   1447      {2:    }{4:456789}abababababababababababababababababababa{4:0}|
   1448      {2:    }{4:123456789}babababababababababababababababababab|
   1449      {2:    }ababababababababababababababababababababababab|
   1450      {2:    }abababababababa^b                              |
   1451                                                        |
   1452    ]],
   1453    }
   1454 
   1455    command('set cpoptions+=n')
   1456    screen:expect {
   1457      grid = [[
   1458      {2:  1 }ababababababababababababababababababababab{4:0123}|
   1459      {4:456789}abababababababababababababababababababa{4:01234}|
   1460      {4:56789}babababababababababababababababababababababab|
   1461      ababababababababababababababababababababababababab|
   1462      aba^b                                              |
   1463                                                        |
   1464    ]],
   1465    }
   1466 
   1467    feed('0g$hi<Tab>')
   1468    screen:expect {
   1469      grid = [[
   1470      {2:  1 }ababababababababababababababababababababab{4:01}  |
   1471        {4:^23456789}abababababababababababababababababababa{4:0}|
   1472      {4:123456789}babababababababababababababababababababab|
   1473      ababababababababababababababababababababababababab|
   1474      abababab                                          |
   1475      {24:-- INSERT --}                                      |
   1476    ]],
   1477    }
   1478  end)
   1479 
   1480  it('virt_text_hide hides overlay virtual text when extmark is off-screen', function()
   1481    screen:try_resize(50, 3)
   1482    command('set nowrap')
   1483    api.nvim_buf_set_lines(0, 0, -1, true, { '-- ' .. ('…'):rep(57) })
   1484    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { '?????', 'ErrorMsg' } }, virt_text_pos = 'overlay', virt_text_hide = true })
   1485    api.nvim_buf_set_extmark(0, ns, 0, 123, { virt_text = { { '!!!!!', 'ErrorMsg' } }, virt_text_pos = 'overlay', virt_text_hide = true })
   1486    screen:expect {
   1487      grid = [[
   1488      {4:^?????}……………………………………………………………………………………………………{4:!!!!!}……|
   1489      {1:~                                                 }|
   1490                                                        |
   1491    ]],
   1492    }
   1493    feed('40zl')
   1494    screen:expect {
   1495      grid = [[
   1496      ^………{4:!!!!!}………………………………                              |
   1497      {1:~                                                 }|
   1498                                                        |
   1499    ]],
   1500    }
   1501    feed('3zl')
   1502    screen:expect {
   1503      grid = [[
   1504      {4:^!!!!!}………………………………                                 |
   1505      {1:~                                                 }|
   1506                                                        |
   1507    ]],
   1508    }
   1509    feed('7zl')
   1510    screen:expect {
   1511      grid = [[
   1512      ^…………………………                                        |
   1513      {1:~                                                 }|
   1514                                                        |
   1515    ]],
   1516    }
   1517 
   1518    command('set wrap smoothscroll')
   1519    screen:expect {
   1520      grid = [[
   1521      {4:?????}……………………………………………………………………………………………………{4:!!!!!}……|
   1522      ^…………………………                                        |
   1523                                                        |
   1524    ]],
   1525    }
   1526    feed('<C-E>')
   1527    screen:expect {
   1528      grid = [[
   1529      {1:<<<}………………^…                                        |
   1530      {1:~                                                 }|
   1531                                                        |
   1532    ]],
   1533    }
   1534    screen:try_resize(40, 3)
   1535    screen:expect {
   1536      grid = [[
   1537      {1:<<<}{4:!!!!!}……………………………^…                    |
   1538      {1:~                                       }|
   1539                                              |
   1540    ]],
   1541    }
   1542    feed('<C-Y>')
   1543    screen:expect {
   1544      grid = [[
   1545      {4:?????}……………………………………………………………………………………………|
   1546      ………{4:!!!!!}……………………………^…                    |
   1547                                              |
   1548    ]],
   1549    }
   1550  end)
   1551 
   1552  it('overlay virtual text works on and after a TAB #24022', function()
   1553    screen:try_resize(40, 3)
   1554    api.nvim_buf_set_lines(0, 0, -1, true, { '\t\tline 1' })
   1555    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'AA', 'Search' } }, virt_text_pos = 'overlay', hl_mode = 'combine' })
   1556    api.nvim_buf_set_extmark(0, ns, 0, 1, { virt_text = { { 'BB', 'Search' } }, virt_text_pos = 'overlay', hl_mode = 'combine' })
   1557    api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'CC', 'Search' } }, virt_text_pos = 'overlay', hl_mode = 'combine' })
   1558    screen:expect {
   1559      grid = [[
   1560      {34:AA}     ^ {34:BB}      {34:CC}ne 1                  |
   1561      {1:~                                       }|
   1562                                              |
   1563    ]],
   1564    }
   1565    command('setlocal list listchars=tab:<->')
   1566    screen:expect {
   1567      grid = [[
   1568      {35:^AA}{1:----->}{35:BB}{1:----->}{34:CC}ne 1                  |
   1569      {1:~                                       }|
   1570                                              |
   1571    ]],
   1572    }
   1573  end)
   1574 
   1575  it('can have virtual text of overlay position and styling', function()
   1576    insert(example_text)
   1577    feed 'gg'
   1578 
   1579    command 'set ft=lua'
   1580    command 'syntax on'
   1581 
   1582    screen:expect {
   1583      grid = [[
   1584      {5:^for} _,item {5:in} {6:ipairs}(items) {5:do}                    |
   1585          {5:local} text, hl_id_cell, count {5:=} unpack(item)  |
   1586          {5:if} hl_id_cell {5:~=} {13:nil} {5:then}                     |
   1587              hl_id {5:=} hl_id_cell                        |
   1588          {5:end}                                           |
   1589          {5:for} _ {5:=} {13:1}, (count {5:or} {13:1}) {5:do}                    |
   1590              {5:local} cell {5:=} line[colpos]                 |
   1591              cell.text {5:=} text                          |
   1592              cell.hl_id {5:=} hl_id                        |
   1593              colpos {5:=} colpos{5:+}{13:1}                         |
   1594          {5:end}                                           |
   1595      {5:end}                                               |
   1596      {1:~                                                 }|*2
   1597                                                        |
   1598    ]],
   1599    }
   1600 
   1601    command 'hi Blendy guibg=Red blend=30'
   1602    command 'hi! Visual guifg=NONE guibg=LightGrey'
   1603    api.nvim_buf_set_extmark(
   1604      0,
   1605      ns,
   1606      1,
   1607      5,
   1608      { virt_text = { { 'blendy text - here', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'blend' }
   1609    )
   1610    api.nvim_buf_set_extmark(
   1611      0,
   1612      ns,
   1613      2,
   1614      5,
   1615      { virt_text = { { 'combining color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'combine' }
   1616    )
   1617    api.nvim_buf_set_extmark(
   1618      0,
   1619      ns,
   1620      3,
   1621      5,
   1622      { virt_text = { { 'replacing color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'replace' }
   1623    )
   1624 
   1625    api.nvim_buf_set_extmark(
   1626      0,
   1627      ns,
   1628      4,
   1629      5,
   1630      { virt_text = { { 'blendy text - here', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'blend', virt_text_hide = true }
   1631    )
   1632    api.nvim_buf_set_extmark(
   1633      0,
   1634      ns,
   1635      5,
   1636      5,
   1637      { virt_text = { { 'combining color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'combine', virt_text_hide = true }
   1638    )
   1639    api.nvim_buf_set_extmark(
   1640      0,
   1641      ns,
   1642      6,
   1643      5,
   1644      { virt_text = { { 'replacing color', 'Blendy' } }, virt_text_pos = 'overlay', hl_mode = 'replace', virt_text_hide = true }
   1645    )
   1646 
   1647    screen:expect {
   1648      grid = [[
   1649      {5:^for} _,item {5:in} {6:ipairs}(items) {5:do}                    |
   1650          {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count {5:=} unpack(item)  |
   1651          {5:i}{12:c}{11:ombining col}{12:or} {13:nil} {5:then}                     |
   1652           {11:replacing color}d_cell                        |
   1653          {5:e}{8:bl}{7:endy}{10: }{7:text}{10: }{7:-}{10: }{7:here}                           |
   1654          {5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do}                    |
   1655           {11:replacing color} line[colpos]                 |
   1656              cell.text {5:=} text                          |
   1657              cell.hl_id {5:=} hl_id                        |
   1658              colpos {5:=} colpos{5:+}{13:1}                         |
   1659          {5:end}                                           |
   1660      {5:end}                                               |
   1661      {1:~                                                 }|*2
   1662                                                        |
   1663    ]],
   1664    }
   1665 
   1666    feed 'V5G'
   1667    screen:expect {
   1668      grid = [[
   1669      {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do}                    |
   1670      {18:    }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)}  |
   1671      {18:    }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then}                     |
   1672      {18:     }{11:replacing color}{18:d_cell}                        |
   1673      {18:    }{5:^e}{17:nd}                                           |
   1674          {5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do}                    |
   1675           {11:replacing color} line[colpos]                 |
   1676              cell.text {5:=} text                          |
   1677              cell.hl_id {5:=} hl_id                        |
   1678              colpos {5:=} colpos{5:+}{13:1}                         |
   1679          {5:end}                                           |
   1680      {5:end}                                               |
   1681      {1:~                                                 }|*2
   1682      {24:-- VISUAL LINE --}                                 |
   1683    ]],
   1684    }
   1685 
   1686    feed 'jj'
   1687    screen:expect {
   1688      grid = [[
   1689      {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do}                    |
   1690      {18:    }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)}  |
   1691      {18:    }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then}                     |
   1692      {18:     }{11:replacing color}{18:d_cell}                        |
   1693      {18:    }{17:end}                                           |
   1694      {18:    }{17:for}{18: _ }{17:=}{18: }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do}                    |
   1695      {18:    }^ {18:   }{17:local}{18: cell }{17:=}{18: line[colpos]}                 |
   1696              cell.text {5:=} text                          |
   1697              cell.hl_id {5:=} hl_id                        |
   1698              colpos {5:=} colpos{5:+}{13:1}                         |
   1699          {5:end}                                           |
   1700      {5:end}                                               |
   1701      {1:~                                                 }|*2
   1702      {24:-- VISUAL LINE --}                                 |
   1703    ]],
   1704    }
   1705  end)
   1706 
   1707  it('can have virtual text of right_align and fixed win_col position', function()
   1708    insert(example_text)
   1709    feed 'gg'
   1710    api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'Very', 'ErrorMsg' } }, virt_text_win_col = 31, hl_mode = 'blend' })
   1711    api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'VERY', 'ErrorMsg' } }, virt_text_pos = 'right_align', hl_mode = 'blend' })
   1712    api.nvim_buf_set_extmark(0, ns, 2, 10, { virt_text = { { 'Much', 'ErrorMsg' } }, virt_text_win_col = 31, hl_mode = 'blend' })
   1713    api.nvim_buf_set_extmark(0, ns, 2, 10, { virt_text = { { 'MUCH', 'ErrorMsg' } }, virt_text_pos = 'right_align', hl_mode = 'blend' })
   1714    api.nvim_buf_set_extmark(0, ns, 3, 14, { virt_text = { { 'Error', 'ErrorMsg' } }, virt_text_win_col = 31, hl_mode = 'blend' })
   1715    api.nvim_buf_set_extmark(0, ns, 3, 14, { virt_text = { { 'ERROR', 'ErrorMsg' } }, virt_text_pos = 'right_align', hl_mode = 'blend' })
   1716    api.nvim_buf_set_extmark(0, ns, 7, 21, { virt_text = { { '-', 'NonText' } }, virt_text_win_col = 4, hl_mode = 'blend' })
   1717    api.nvim_buf_set_extmark(0, ns, 7, 21, { virt_text = { { '-', 'NonText' } }, virt_text_pos = 'right_align', hl_mode = 'blend' })
   1718    -- empty virt_text should not change anything
   1719    api.nvim_buf_set_extmark(0, ns, 8, 0, { virt_text = { { '' } }, virt_text_win_col = 14, hl_mode = 'blend' })
   1720    api.nvim_buf_set_extmark(0, ns, 8, 0, { virt_text = { { '' } }, virt_text_pos = 'right_align', hl_mode = 'blend' })
   1721 
   1722    screen:expect {
   1723      grid = [[
   1724      ^for _,item in ipairs(items) do                    |
   1725          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
   1726          if hl_id_cell ~= nil then  {4:Much}           {4:MUCH}|
   1727              hl_id = hl_id_cell     {4:Error}         {4:ERROR}|
   1728          end                                           |
   1729          for _ = 1, (count or 1) do                    |
   1730              local cell = line[colpos]                 |
   1731          {1:-}   cell.text = text                         {1:-}|
   1732              cell.hl_id = hl_id                        |
   1733              colpos = colpos+1                         |
   1734          end                                           |
   1735      end                                               |
   1736      {1:~                                                 }|*2
   1737                                                        |
   1738    ]],
   1739    }
   1740 
   1741    feed '3G12|i<cr><esc>'
   1742    screen:expect {
   1743      grid = [[
   1744      for _,item in ipairs(items) do                    |
   1745          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
   1746          if hl_i                    {4:Much}           {4:MUCH}|
   1747      ^d_cell ~= nil then                                |
   1748              hl_id = hl_id_cell     {4:Error}         {4:ERROR}|
   1749          end                                           |
   1750          for _ = 1, (count or 1) do                    |
   1751              local cell = line[colpos]                 |
   1752          {1:-}   cell.text = text                         {1:-}|
   1753              cell.hl_id = hl_id                        |
   1754              colpos = colpos+1                         |
   1755          end                                           |
   1756      end                                               |
   1757      {1:~                                                 }|
   1758                                                        |
   1759    ]],
   1760    }
   1761 
   1762    feed 'u:<cr>'
   1763    screen:expect {
   1764      grid = [[
   1765      for _,item in ipairs(items) do                    |
   1766          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
   1767          if hl_i^d_cell ~= nil then  {4:Much}           {4:MUCH}|
   1768              hl_id = hl_id_cell     {4:Error}         {4:ERROR}|
   1769          end                                           |
   1770          for _ = 1, (count or 1) do                    |
   1771              local cell = line[colpos]                 |
   1772          {1:-}   cell.text = text                         {1:-}|
   1773              cell.hl_id = hl_id                        |
   1774              colpos = colpos+1                         |
   1775          end                                           |
   1776      end                                               |
   1777      {1:~                                                 }|*2
   1778      :                                                 |
   1779    ]],
   1780    }
   1781 
   1782    feed '8|i<cr><esc>'
   1783    screen:expect {
   1784      grid = [[
   1785      for _,item in ipairs(items) do                    |
   1786          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
   1787          if                                            |
   1788      ^hl_id_cell ~= nil then         {4:Much}           {4:MUCH}|
   1789              hl_id = hl_id_cell     {4:Error}         {4:ERROR}|
   1790          end                                           |
   1791          for _ = 1, (count or 1) do                    |
   1792              local cell = line[colpos]                 |
   1793          {1:-}   cell.text = text                         {1:-}|
   1794              cell.hl_id = hl_id                        |
   1795              colpos = colpos+1                         |
   1796          end                                           |
   1797      end                                               |
   1798      {1:~                                                 }|
   1799                                                        |
   1800    ]],
   1801    }
   1802 
   1803    feed 'jI-- <esc>..........'
   1804    screen:expect {
   1805      grid = [[
   1806      for _,item in ipairs(items) do                    |
   1807          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
   1808          if                                            |
   1809      hl_id_cell ~= nil then         {4:Much}           {4:MUCH}|
   1810              --^ -- -- -- -- -- -- --{4:Error}- -- hl_i{4:ERROR}|
   1811      l_id_cell                                         |
   1812          end                                           |
   1813          for _ = 1, (count or 1) do                    |
   1814              local cell = line[colpos]                 |
   1815          {1:-}   cell.text = text                         {1:-}|
   1816              cell.hl_id = hl_id                        |
   1817              colpos = colpos+1                         |
   1818          end                                           |
   1819      end                                               |
   1820                                                        |
   1821    ]],
   1822    }
   1823 
   1824    api.nvim_buf_set_extmark(0, ns, 4, 50, { virt_text = { { 'EOL', 'NonText' } } })
   1825    screen:expect {
   1826      grid = [[
   1827      for _,item in ipairs(items) do                    |
   1828          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
   1829          if                                            |
   1830      hl_id_cell ~= nil then         {4:Much}           {4:MUCH}|
   1831              --^ -- -- -- -- -- -- --{4:Error}- -- hl_i{4:ERROR}|
   1832      l_id_cell {1:EOL}                                     |
   1833          end                                           |
   1834          for _ = 1, (count or 1) do                    |
   1835              local cell = line[colpos]                 |
   1836          {1:-}   cell.text = text                         {1:-}|
   1837              cell.hl_id = hl_id                        |
   1838              colpos = colpos+1                         |
   1839          end                                           |
   1840      end                                               |
   1841                                                        |
   1842    ]],
   1843    }
   1844 
   1845    feed '.'
   1846    screen:expect {
   1847      grid = [[
   1848      for _,item in ipairs(items) do                    |
   1849          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
   1850          if                                            |
   1851      hl_id_cell ~= nil then         {4:Much}           {4:MUCH}|
   1852              --^ -- -- -- -- -- -- -- -- -- -- -- hl_id |
   1853      = hl_id_cell {1:EOL}               {4:Error}         {4:ERROR}|
   1854          end                                           |
   1855          for _ = 1, (count or 1) do                    |
   1856              local cell = line[colpos]                 |
   1857          {1:-}   cell.text = text                         {1:-}|
   1858              cell.hl_id = hl_id                        |
   1859              colpos = colpos+1                         |
   1860          end                                           |
   1861      end                                               |
   1862                                                        |
   1863    ]],
   1864    }
   1865 
   1866    command 'set number'
   1867    screen:expect {
   1868      grid = [[
   1869      {2:  1 }for _,item in ipairs(items) do                |
   1870      {2:  2 }    local text, hl_id_cell, cou{4:Very} unpack{4:VERY}|
   1871      {2:    }m)                                            |
   1872      {2:  3 }    if                                        |
   1873      {2:  4 }hl_id_cell ~= nil then         {4:Much}       {4:MUCH}|
   1874      {2:  5 }        --^ -- -- -- -- -- -- -- -- -- -- -- hl|
   1875      {2:    }_id = hl_id_cell {1:EOL}           {4:Error}     {4:ERROR}|
   1876      {2:  6 }    end                                       |
   1877      {2:  7 }    for _ = 1, (count or 1) do                |
   1878      {2:  8 }        local cell = line[colpos]             |
   1879      {2:  9 }    {1:-}   cell.text = text                     {1:-}|
   1880      {2: 10 }        cell.hl_id = hl_id                    |
   1881      {2: 11 }        colpos = colpos+1                     |
   1882      {2: 12 }    end                                       |
   1883                                                        |
   1884    ]],
   1885    }
   1886 
   1887    command 'set cpoptions+=n'
   1888    screen:expect {
   1889      grid = [[
   1890      {2:  1 }for _,item in ipairs(items) do                |
   1891      {2:  2 }    local text, hl_id_cell, cou{4:Very} unpack{4:VERY}|
   1892      m)                                                |
   1893      {2:  3 }    if                                        |
   1894      {2:  4 }hl_id_cell ~= nil then         {4:Much}       {4:MUCH}|
   1895      {2:  5 }        --^ -- -- -- -- -- -- -- -- -- -- -- hl|
   1896      _id = hl_id_cell {1:EOL}           {4:Error}         {4:ERROR}|
   1897      {2:  6 }    end                                       |
   1898      {2:  7 }    for _ = 1, (count or 1) do                |
   1899      {2:  8 }        local cell = line[colpos]             |
   1900      {2:  9 }    {1:-}   cell.text = text                     {1:-}|
   1901      {2: 10 }        cell.hl_id = hl_id                    |
   1902      {2: 11 }        colpos = colpos+1                     |
   1903      {2: 12 }    end                                       |
   1904                                                        |
   1905    ]],
   1906    }
   1907 
   1908    command 'set cpoptions-=n nowrap'
   1909    screen:expect {
   1910      grid = [[
   1911      {2:  1 }for _,item in ipairs(items) do                |
   1912      {2:  2 }    local text, hl_id_cell, cou{4:Very} unpack{4:VERY}|
   1913      {2:  3 }    if                                        |
   1914      {2:  4 }hl_id_cell ~= nil then         {4:Much}       {4:MUCH}|
   1915      {2:  5 }        --^ -- -- -- -- -- -- --{4:Error}- -- {4:ERROR}|
   1916      {2:  6 }    end                                       |
   1917      {2:  7 }    for _ = 1, (count or 1) do                |
   1918      {2:  8 }        local cell = line[colpos]             |
   1919      {2:  9 }    {1:-}   cell.text = text                     {1:-}|
   1920      {2: 10 }        cell.hl_id = hl_id                    |
   1921      {2: 11 }        colpos = colpos+1                     |
   1922      {2: 12 }    end                                       |
   1923      {2: 13 }end                                           |
   1924      {1:~                                                 }|
   1925                                                        |
   1926    ]],
   1927    }
   1928 
   1929    feed '12zl'
   1930    screen:expect {
   1931      grid = [[
   1932      {2:  1 }n ipairs(items) do                            |
   1933      {2:  2 }xt, hl_id_cell, count = unpack({4:Very})      {4:VERY}|
   1934      {2:  3 }                                              |
   1935      {2:  4 }= nil then                     {4:Much}       {4:MUCH}|
   1936      {2:  5 }^- -- -- -- -- -- -- -- -- -- --{4:Error}d = h{4:ERROR}|
   1937      {2:  6 }                                              |
   1938      {2:  7 }1, (count or 1) do                            |
   1939      {2:  8 }l cell = line[colpos]                         |
   1940      {2:  9 }.tex{1:-} = text                                 {1:-}|
   1941      {2: 10 }.hl_id = hl_id                                |
   1942      {2: 11 }os = colpos+1                                 |
   1943      {2: 12 }                                              |
   1944      {2: 13 }                                              |
   1945      {1:~                                                 }|
   1946                                                        |
   1947    ]],
   1948    }
   1949 
   1950    feed('fhi<Tab>')
   1951    screen:expect {
   1952      grid = [[
   1953      {2:  1 }n ipairs(items) do                            |
   1954      {2:  2 }xt, hl_id_cell, count = unpack({4:Very})      {4:VERY}|
   1955      {2:  3 }                                              |
   1956      {2:  4 }= nil then                     {4:Much}       {4:MUCH}|
   1957      {2:  5 }- -- -- -- -- -- -- -- -- -- --{4:Error}^hl_id{4:ERROR}|
   1958      {2:  6 }                                              |
   1959      {2:  7 }1, (count or 1) do                            |
   1960      {2:  8 }l cell = line[colpos]                         |
   1961      {2:  9 }.tex{1:-} = text                                 {1:-}|
   1962      {2: 10 }.hl_id = hl_id                                |
   1963      {2: 11 }os = colpos+1                                 |
   1964      {2: 12 }                                              |
   1965      {2: 13 }                                              |
   1966      {1:~                                                 }|
   1967      {24:-- INSERT --}                                      |
   1968    ]],
   1969    }
   1970 
   1971    feed('<Esc>0')
   1972    screen:expect {
   1973      grid = [[
   1974      {2:  1 }for _,item in ipairs(items) do                |
   1975      {2:  2 }    local text, hl_id_cell, cou{4:Very} unpack{4:VERY}|
   1976      {2:  3 }    if                                        |
   1977      {2:  4 }hl_id_cell ~= nil then         {4:Much}       {4:MUCH}|
   1978      {2:  5 }^        -- -- -- -- -- -- -- --{4:Error}- -- {4:ERROR}|
   1979      {2:  6 }    end                                       |
   1980      {2:  7 }    for _ = 1, (count or 1) do                |
   1981      {2:  8 }        local cell = line[colpos]             |
   1982      {2:  9 }    {1:-}   cell.text = text                     {1:-}|
   1983      {2: 10 }        cell.hl_id = hl_id                    |
   1984      {2: 11 }        colpos = colpos+1                     |
   1985      {2: 12 }    end                                       |
   1986      {2: 13 }end                                           |
   1987      {1:~                                                 }|
   1988                                                        |
   1989    ]],
   1990    }
   1991  end)
   1992 
   1993  it('virtual text win_col out of window does not break display #25645', function()
   1994    screen:try_resize(51, 6)
   1995    command('vnew')
   1996    api.nvim_buf_set_lines(0, 0, -1, false, { string.rep('a', 50) })
   1997    screen:expect {
   1998      grid = [[
   1999      ^aaaaaaaaaaaaaaaaaaaaaaaaa│                         |
   2000      aaaaaaaaaaaaaaaaaaaaaaaaa│{1:~                        }|
   2001      {1:~                        }│{1:~                        }|*2
   2002      {41:[No Name] [+]             }{40:[No Name]                }|
   2003                                                         |
   2004    ]],
   2005    }
   2006    local extmark_opts = { virt_text_win_col = 35, virt_text = { { ' ', 'Comment' } } }
   2007    api.nvim_buf_set_extmark(0, ns, 0, 0, extmark_opts)
   2008    screen:expect_unchanged()
   2009    assert_alive()
   2010  end)
   2011 
   2012  it('can have virtual text on folded line', function()
   2013    insert([[
   2014      11111
   2015      22222
   2016      33333]])
   2017    command('1,2fold')
   2018    screen:try_resize(50, 3)
   2019    feed('zb')
   2020    -- XXX: the behavior of overlay virtual text at non-zero column is strange:
   2021    -- 1. With 'wrap' it is never shown.
   2022    -- 2. With 'nowrap' it is shown only if the extmark is hidden before leftcol.
   2023    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'AA', 'Underlined' } }, hl_mode = 'combine', virt_text_pos = 'overlay' })
   2024    api.nvim_buf_set_extmark(0, ns, 0, 5, { virt_text = { { 'BB', 'Underlined' } }, hl_mode = 'combine', virt_text_win_col = 10 })
   2025    api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'CC', 'Underlined' } }, hl_mode = 'combine', virt_text_pos = 'right_align' })
   2026    screen:expect {
   2027      grid = [[
   2028      {29:AA}{33:-  2 lin}{29:BB}{33:: 11111·····························}{29:CC}|
   2029      3333^3                                             |
   2030                                                        |
   2031    ]],
   2032    }
   2033    command('set nowrap')
   2034    screen:expect_unchanged()
   2035    feed('zl')
   2036    screen:expect {
   2037      grid = [[
   2038      {29:AA}{33:-  2 lin}{29:BB}{33:: 11111·····························}{29:CC}|
   2039      333^3                                              |
   2040                                                        |
   2041    ]],
   2042    }
   2043    feed('zl')
   2044    screen:expect {
   2045      grid = [[
   2046      {29:AA}{33:-  2 lin}{29:BB}{33:: 11111·····························}{29:CC}|
   2047      33^3                                               |
   2048                                                        |
   2049    ]],
   2050    }
   2051    feed('zl')
   2052    screen:expect {
   2053      grid = [[
   2054      {29:AA}{33:-  2 lin}{29:BB}{33:: 11111·····························}{29:CC}|
   2055      3^3                                                |
   2056                                                        |
   2057    ]],
   2058    }
   2059  end)
   2060 
   2061  it('virtual text works below diff filler lines', function()
   2062    screen:try_resize(53, 8)
   2063    insert([[
   2064      aaaaa
   2065      bbbbb
   2066      ccccc
   2067      ddddd
   2068      eeeee]])
   2069    command('rightbelow vnew')
   2070    insert([[
   2071      bbbbb
   2072      ccccc
   2073      ddddd
   2074      eeeee]])
   2075    command('windo diffthis')
   2076    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'AA', 'Underlined' } }, virt_text_pos = 'overlay' })
   2077    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'BB', 'Underlined' } }, virt_text_win_col = 10 })
   2078    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'CC', 'Underlined' } }, virt_text_pos = 'right_align' })
   2079    screen:expect {
   2080      grid = [[
   2081      {37:  }{38:aaaaa                   }│{37:  }{39:------------------------}|
   2082      {37:  }bbbbb                   │{37:  }{28:AA}bbb     {28:BB}          {28:CC}|
   2083      {37:  }ccccc                   │{37:  }ccccc                   |
   2084      {37:  }ddddd                   │{37:  }ddddd                   |
   2085      {37:  }eeeee                   │{37:  }eeee^e                   |
   2086      {1:~                         }│{1:~                         }|
   2087      {40:[No Name] [+]              }{41:[No Name] [+]             }|
   2088                                                           |
   2089    ]],
   2090    }
   2091    command('windo set wrap')
   2092    screen:expect_unchanged()
   2093  end)
   2094 
   2095  it('can have virtual text which combines foreground and background groups', function()
   2096    screen:try_resize(20, 5)
   2097 
   2098    screen:set_default_attr_ids {
   2099      [1] = { bold = true, foreground = Screen.colors.Blue },
   2100      [2] = { background = tonumber('0x123456'), foreground = tonumber('0xbbbbbb') },
   2101      [3] = { background = tonumber('0x123456'), foreground = tonumber('0xcccccc') },
   2102      [4] = { background = tonumber('0x234567'), foreground = tonumber('0xbbbbbb') },
   2103      [5] = { background = tonumber('0x234567'), foreground = tonumber('0xcccccc') },
   2104      [6] = { bold = true, foreground = tonumber('0xcccccc'), background = tonumber('0x234567') },
   2105    }
   2106 
   2107    exec [[
   2108      hi BgOne guibg=#123456
   2109      hi BgTwo guibg=#234567
   2110      hi FgEin guifg=#bbbbbb
   2111      hi FgZwei guifg=#cccccc
   2112      hi VeryBold gui=bold
   2113    ]]
   2114 
   2115    insert('##')
   2116    local vt = {
   2117      { 'a', { 'BgOne', 'FgEin' } },
   2118      { 'b', { 'BgOne', 'FgZwei' } },
   2119      { 'c', { 'BgTwo', 'FgEin' } },
   2120      { 'd', { 'BgTwo', 'FgZwei' } },
   2121      { 'X', { 'BgTwo', 'FgZwei', 'VeryBold' } },
   2122    }
   2123    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'eol' })
   2124    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'right_align' })
   2125    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = vt, virt_text_pos = 'inline' })
   2126    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { vt, vt } })
   2127    screen:expect {
   2128      grid = [[
   2129      {2:a}{3:b}{4:c}{5:d}{6:X}#^# {2:a}{3:b}{4:c}{5:d}{6:X}  {2:a}{3:b}{4:c}{5:d}{6:X}|
   2130      {2:a}{3:b}{4:c}{5:d}{6:X}               |*2
   2131      {1:~                   }|
   2132                          |
   2133    ]],
   2134    }
   2135  end)
   2136 
   2137  it('does not crash when deleting a cleared buffer #15212', function()
   2138    exec_lua [[
   2139      ns = vim.api.nvim_create_namespace("myplugin")
   2140      vim.api.nvim_buf_set_extmark(0, ns, 0, 0, {virt_text = {{"a"}}, end_col = 0})
   2141    ]]
   2142    screen:expect {
   2143      grid = [[
   2144      ^ a                                                |
   2145      {1:~                                                 }|*13
   2146                                                        |
   2147    ]],
   2148    }
   2149 
   2150    exec_lua [[
   2151      vim.api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2152      vim.cmd("bdelete")
   2153    ]]
   2154    screen:expect {
   2155      grid = [[
   2156      ^                                                  |
   2157      {1:~                                                 }|*13
   2158                                                        |
   2159    ]],
   2160    }
   2161    assert_alive()
   2162  end)
   2163 
   2164  it('conceal with conceal char #19007', function()
   2165    screen:try_resize(50, 5)
   2166    insert('foo\n')
   2167    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 0, end_row = 2, conceal = 'X' })
   2168    command('set conceallevel=2')
   2169    screen:expect([[
   2170      {26:X}                                                 |
   2171      ^                                                  |
   2172      {1:~                                                 }|*2
   2173                                                        |
   2174    ]])
   2175    command('set conceallevel=1')
   2176    screen:expect_unchanged()
   2177 
   2178    eq('conceal char has to be printable', pcall_err(api.nvim_buf_set_extmark, 0, ns, 0, 0, { end_col = 0, end_row = 2, conceal = '\255' }))
   2179  end)
   2180 
   2181  it('conceal with composed conceal char', function()
   2182    screen:try_resize(50, 5)
   2183    insert('foo\n')
   2184    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 0, end_row = 2, conceal = 'ẍ̲' })
   2185    command('set conceallevel=2')
   2186    screen:expect([[
   2187      {26:ẍ̲}                                                 |
   2188      ^                                                  |
   2189      {1:~                                                 }|*2
   2190                                                        |
   2191    ]])
   2192    command('set conceallevel=1')
   2193    screen:expect_unchanged()
   2194 
   2195    -- this is rare, but could happen. Save at least the first codepoint
   2196    api.nvim__invalidate_glyph_cache()
   2197    screen:expect {
   2198      grid = [[
   2199      {26:x}                                                 |
   2200      ^                                                  |
   2201      {1:~                                                 }|*2
   2202                                                        |
   2203    ]],
   2204    }
   2205  end)
   2206 
   2207  it('conceal without conceal char #24782', function()
   2208    screen:try_resize(50, 5)
   2209    insert('foobar\n')
   2210    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 3, conceal = '' })
   2211    command('set listchars=conceal:?')
   2212    command('let &conceallevel=1')
   2213    screen:expect([[
   2214      {26:?}bar                                              |
   2215      ^                                                  |
   2216      {1:~                                                 }|*2
   2217                                                        |
   2218    ]])
   2219    command('let &conceallevel=2')
   2220    screen:expect([[
   2221      bar                                               |
   2222      ^                                                  |
   2223      {1:~                                                 }|*2
   2224                                                        |
   2225    ]])
   2226  end)
   2227 
   2228  it('conceal works just before truncated double-width char #21486', function()
   2229    screen:try_resize(40, 4)
   2230    api.nvim_buf_set_lines(0, 0, -1, true, { '', ('a'):rep(37) .. '<>古' })
   2231    api.nvim_buf_set_extmark(0, ns, 1, 37, { end_col = 39, conceal = '' })
   2232    command('setlocal conceallevel=2')
   2233    screen:expect {
   2234      grid = [[
   2235      ^                                        |
   2236      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:>}  |
   2237      古                                      |
   2238                                              |
   2239    ]],
   2240    }
   2241    feed('j')
   2242    screen:expect {
   2243      grid = [[
   2244                                              |
   2245      ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<>{1:>}|
   2246      古                                      |
   2247                                              |
   2248    ]],
   2249    }
   2250  end)
   2251 
   2252  it('redraws properly when adding/removing conceal on non-current line', function()
   2253    screen:try_resize(50, 5)
   2254    api.nvim_buf_set_lines(0, 0, -1, true, { 'abcd', 'efgh', 'ijkl', 'mnop' })
   2255    command('setlocal conceallevel=2')
   2256    screen:expect {
   2257      grid = [[
   2258      ^abcd                                              |
   2259      efgh                                              |
   2260      ijkl                                              |
   2261      mnop                                              |
   2262                                                        |
   2263    ]],
   2264    }
   2265    api.nvim_buf_set_extmark(0, ns, 2, 1, { end_col = 3, conceal = '' })
   2266    screen:expect {
   2267      grid = [[
   2268      ^abcd                                              |
   2269      efgh                                              |
   2270      il                                                |
   2271      mnop                                              |
   2272                                                        |
   2273    ]],
   2274    }
   2275    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2276    screen:expect {
   2277      grid = [[
   2278      ^abcd                                              |
   2279      efgh                                              |
   2280      ijkl                                              |
   2281      mnop                                              |
   2282                                                        |
   2283    ]],
   2284    }
   2285  end)
   2286 
   2287  it('avoids redraw issue #20651', function()
   2288    exec_lua [[
   2289      vim.cmd.normal'10oXXX'
   2290      vim.cmd.normal'gg'
   2291      local ns = vim.api.nvim_create_namespace('ns')
   2292 
   2293      local bufnr = vim.api.nvim_create_buf(false, true)
   2294      vim.api.nvim_open_win(bufnr, false, { relative = 'win', height = 1, width = 1, row = 0, col = 0 })
   2295 
   2296      vim.api.nvim_create_autocmd('CursorMoved', { callback = function()
   2297        local row = vim.api.nvim_win_get_cursor(0)[1] - 1
   2298        vim.api.nvim_buf_set_extmark(0, ns, row, 0, { id = 1 })
   2299        vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {})
   2300        vim.schedule(function()
   2301          vim.api.nvim_buf_set_extmark(0, ns, row, 0, {
   2302            id = 1,
   2303            virt_text = {{'HELLO', 'Normal'}},
   2304          })
   2305        end)
   2306      end
   2307      })
   2308    ]]
   2309 
   2310    for _ = 1, 3 do
   2311      vim.uv.sleep(10)
   2312      feed 'j'
   2313    end
   2314 
   2315    screen:expect {
   2316      grid = [[
   2317      {44: }                                                 |
   2318      XXX                                               |*2
   2319      ^XXX HELLO                                         |
   2320      XXX                                               |*7
   2321      {1:~                                                 }|*3
   2322                                                        |
   2323    ]],
   2324    }
   2325  end)
   2326 
   2327  it('underline attribute with higher priority takes effect #22371', function()
   2328    screen:try_resize(50, 3)
   2329    insert('aaabbbaaa')
   2330    exec([[
   2331      hi TestUL gui=underline guifg=Blue
   2332      hi TestUC gui=undercurl guisp=Red
   2333      hi TestBold gui=bold
   2334    ]])
   2335    screen:set_default_attr_ids({
   2336      [0] = { bold = true, foreground = Screen.colors.Blue },
   2337      [1] = { underline = true, foreground = Screen.colors.Blue },
   2338      [2] = { undercurl = true, special = Screen.colors.Red },
   2339      [3] = { underline = true, foreground = Screen.colors.Blue, special = Screen.colors.Red },
   2340      [4] = { undercurl = true, foreground = Screen.colors.Blue, special = Screen.colors.Red },
   2341      [5] = { bold = true, underline = true, foreground = Screen.colors.Blue },
   2342      [6] = { bold = true, undercurl = true, special = Screen.colors.Red },
   2343    })
   2344 
   2345    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 20 })
   2346    api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUC', priority = 30 })
   2347    screen:expect([[
   2348      {1:aaa}{4:bbb}{1:aa^a}                                         |
   2349      {0:~                                                 }|
   2350                                                        |
   2351    ]])
   2352    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2353    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 20 })
   2354    api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUL', priority = 30 })
   2355    screen:expect([[
   2356      {2:aaa}{3:bbb}{2:aa^a}                                         |
   2357      {0:~                                                 }|
   2358                                                        |
   2359    ]])
   2360    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2361    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 30 })
   2362    api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUC', priority = 20 })
   2363    screen:expect([[
   2364      {1:aaa}{3:bbb}{1:aa^a}                                         |
   2365      {0:~                                                 }|
   2366                                                        |
   2367    ]])
   2368    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2369    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 30 })
   2370    api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUL', priority = 20 })
   2371    screen:expect([[
   2372      {2:aaa}{4:bbb}{2:aa^a}                                         |
   2373      {0:~                                                 }|
   2374                                                        |
   2375    ]])
   2376 
   2377    -- When only one highlight group has an underline attribute, it should always take effect.
   2378    for _, d in ipairs({ -5, 5 }) do
   2379      api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2380      screen:expect([[
   2381        aaabbbaa^a                                         |
   2382        {0:~                                                 }|
   2383                                                          |
   2384      ]])
   2385      api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 25 + d })
   2386      api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 25 - d })
   2387      screen:expect([[
   2388        {1:aaa}{5:bbb}{1:aa^a}                                         |
   2389        {0:~                                                 }|
   2390                                                          |
   2391      ]])
   2392    end
   2393    for _, d in ipairs({ -5, 5 }) do
   2394      api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2395      screen:expect([[
   2396        aaabbbaa^a                                         |
   2397        {0:~                                                 }|
   2398                                                          |
   2399      ]])
   2400      api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 25 + d })
   2401      api.nvim_buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 25 - d })
   2402      screen:expect([[
   2403        {2:aaa}{6:bbb}{2:aa^a}                                         |
   2404        {0:~                                                 }|
   2405                                                          |
   2406      ]])
   2407    end
   2408  end)
   2409 
   2410  it('highlight is combined with syntax and sign linehl #20004', function()
   2411    screen:try_resize(50, 3)
   2412    insert([[
   2413      function Func()
   2414      end]])
   2415    feed('gg')
   2416    command('set ft=lua')
   2417    command('syntax on')
   2418    command('hi default MyMark guibg=LightGrey')
   2419    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 3, hl_mode = 'combine', hl_group = 'MyMark' })
   2420    command('hi default MyLine gui=underline')
   2421    command('sign define CurrentLine linehl=MyLine')
   2422    fn.sign_place(6, 'Test', 'CurrentLine', '', { lnum = 1 })
   2423    screen:expect {
   2424      grid = [[
   2425      {30:^fun}{31:ction}{32: Func()                                   }|
   2426      {6:end}                                               |
   2427                                                        |
   2428    ]],
   2429    }
   2430  end)
   2431 
   2432  it('highlight can combine multiple groups', function()
   2433    screen:try_resize(50, 3)
   2434    command('hi Group1 guibg=Red guifg=Red guisp=Red')
   2435    command('hi Group2 guibg=Blue guifg=Blue')
   2436    command('hi Group3 guibg=Green')
   2437    insert([[example text]])
   2438    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = {} })
   2439    screen:expect([[
   2440      example tex^t                                      |
   2441      {1:~                                                 }|
   2442                                                        |
   2443    ]])
   2444 
   2445    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2446    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1' } })
   2447    screen:expect([[
   2448      {45:example tex^t}                                      |
   2449      {1:~                                                 }|
   2450                                                        |
   2451    ]])
   2452    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2453    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1', 'Group2' } })
   2454    screen:expect([[
   2455      {46:example tex^t}                                      |
   2456      {1:~                                                 }|
   2457                                                        |
   2458    ]])
   2459    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2460    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1', 'Group2', 'Group3' }, hl_eol = true })
   2461    screen:expect([[
   2462      {47:example tex^t                                      }|
   2463      {1:~                                                 }|
   2464                                                        |
   2465    ]])
   2466 
   2467    eq(
   2468      'Invalid hl_group: hl_group item',
   2469      pcall_err(api.nvim_buf_set_extmark, 0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1', 'Group2', { 'fail' } }, hl_eol = true })
   2470    )
   2471  end)
   2472 
   2473  it('highlight works after TAB with sidescroll #14201', function()
   2474    screen:try_resize(50, 3)
   2475    command('set nowrap')
   2476    api.nvim_buf_set_lines(0, 0, -1, true, { '\tword word word word' })
   2477    api.nvim_buf_set_extmark(0, ns, 0, 1, { end_col = 3, hl_group = 'ErrorMsg' })
   2478    screen:expect {
   2479      grid = [[
   2480             ^ {4:wo}rd word word word                       |
   2481      {1:~                                                 }|
   2482                                                        |
   2483    ]],
   2484    }
   2485    feed('7zl')
   2486    screen:expect {
   2487      grid = [[
   2488       {4:^wo}rd word word word                              |
   2489      {1:~                                                 }|
   2490                                                        |
   2491    ]],
   2492    }
   2493    feed('zl')
   2494    screen:expect {
   2495      grid = [[
   2496      {4:^wo}rd word word word                               |
   2497      {1:~                                                 }|
   2498                                                        |
   2499    ]],
   2500    }
   2501    feed('zl')
   2502    screen:expect {
   2503      grid = [[
   2504      {4:^o}rd word word word                                |
   2505      {1:~                                                 }|
   2506                                                        |
   2507    ]],
   2508    }
   2509  end)
   2510 
   2511  it('highlights the beginning of a TAB char correctly #23734', function()
   2512    screen:try_resize(50, 3)
   2513    api.nvim_buf_set_lines(0, 0, -1, true, { 'this is the\ttab' })
   2514    api.nvim_buf_set_extmark(0, ns, 0, 11, { end_col = 15, hl_group = 'ErrorMsg' })
   2515    screen:expect {
   2516      grid = [[
   2517      ^this is the{4:     tab}                               |
   2518      {1:~                                                 }|
   2519                                                        |
   2520    ]],
   2521    }
   2522 
   2523    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2524    api.nvim_buf_set_extmark(0, ns, 0, 12, { end_col = 15, hl_group = 'ErrorMsg' })
   2525    screen:expect {
   2526      grid = [[
   2527      ^this is the     {4:tab}                               |
   2528      {1:~                                                 }|
   2529                                                        |
   2530    ]],
   2531    }
   2532  end)
   2533 
   2534  it('highlight applies to a full TAB on line with matches #20885', function()
   2535    screen:try_resize(50, 3)
   2536    api.nvim_buf_set_lines(0, 0, -1, true, { '\t-- match1', '        -- match2' })
   2537    fn.matchadd('NonText', 'match')
   2538    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, end_col = 0, hl_group = 'Search' })
   2539    api.nvim_buf_set_extmark(0, ns, 1, 0, { end_row = 2, end_col = 0, hl_group = 'Search' })
   2540    screen:expect {
   2541      grid = [[
   2542      {34:       ^ -- }{35:match}{34:1}                                 |
   2543      {34:        -- }{35:match}{34:2}                                 |
   2544                                                        |
   2545    ]],
   2546    }
   2547  end)
   2548 
   2549  it('highlight applies to a full TAB in visual block mode', function()
   2550    screen:try_resize(50, 8)
   2551    command('hi! Visual guifg=NONE guibg=LightGrey')
   2552    api.nvim_buf_set_lines(0, 0, -1, true, { 'asdf', '\tasdf', '\tasdf', '\tasdf', 'asdf' })
   2553    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 5, end_col = 0, hl_group = 'Underlined' })
   2554    screen:expect([[
   2555      {28:^asdf}                                              |
   2556      {28:        asdf}                                      |*3
   2557      {28:asdf}                                              |
   2558      {1:~                                                 }|*2
   2559                                                        |
   2560    ]])
   2561    feed('<C-V>Gll')
   2562    screen:expect([[
   2563      {29:asd}{28:f}                                              |
   2564      {29:   }{28:     asdf}                                      |*3
   2565      {29:as}{28:^df}                                              |
   2566      {1:~                                                 }|*2
   2567      {24:-- VISUAL BLOCK --}                                |
   2568    ]])
   2569  end)
   2570 
   2571  it('highlight works properly with multibyte text and spell #26771', function()
   2572    insert('口口\n')
   2573    screen:try_resize(50, 3)
   2574    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 3, hl_group = 'Search' })
   2575    screen:expect([[
   2576      {34:}                                              |
   2577      ^                                                  |
   2578                                                        |
   2579    ]])
   2580    command('setlocal spell')
   2581    screen:expect([[
   2582      {43:}{42:}                                              |
   2583      ^                                                  |
   2584                                                        |
   2585    ]])
   2586  end)
   2587 
   2588  it('supports multiline highlights', function()
   2589    insert(example_text)
   2590    feed 'gg'
   2591    for _, i in ipairs { 1, 2, 3, 5, 6, 7 } do
   2592      for _, j in ipairs { 2, 5, 10, 15 } do
   2593        api.nvim_buf_set_extmark(0, ns, i, j, { end_col = j + 2, hl_group = 'NonText' })
   2594      end
   2595    end
   2596    screen:expect {
   2597      grid = [[
   2598      ^for _,item in ipairs(items) do                    |
   2599        {1:  }l{1:oc}al {1:te}xt,{1: h}l_id_cell, count = unpack(item)  |
   2600        {1:  }i{1:f }hl_{1:id}_ce{1:ll} ~= nil then                     |
   2601        {1:  } {1:  } hl{1:_i}d ={1: h}l_id_cell                        |
   2602          end                                           |
   2603        {1:  }f{1:or} _ {1:= }1, {1:(c}ount or 1) do                    |
   2604        {1:  } {1:  } lo{1:ca}l c{1:el}l = line[colpos]                 |
   2605        {1:  } {1:  } ce{1:ll}.te{1:xt} = text                          |
   2606              cell.hl_id = hl_id                        |
   2607              colpos = colpos+1                         |
   2608          end                                           |
   2609      end                                               |
   2610      {1:~                                                 }|*2
   2611                                                        |
   2612    ]],
   2613    }
   2614    feed '5<c-e>'
   2615    screen:expect {
   2616      grid = [[
   2617      ^  {1:  }f{1:or} _ {1:= }1, {1:(c}ount or 1) do                    |
   2618        {1:  } {1:  } lo{1:ca}l c{1:el}l = line[colpos]                 |
   2619        {1:  } {1:  } ce{1:ll}.te{1:xt} = text                          |
   2620              cell.hl_id = hl_id                        |
   2621              colpos = colpos+1                         |
   2622          end                                           |
   2623      end                                               |
   2624      {1:~                                                 }|*7
   2625                                                        |
   2626    ]],
   2627    }
   2628 
   2629    api.nvim_buf_set_extmark(0, ns, 1, 0, { end_line = 8, end_col = 10, hl_group = 'ErrorMsg' })
   2630    screen:expect {
   2631      grid = [[
   2632      {4:^  }{36:  }{4:f}{36:or}{4: _ }{36:= }{4:1, }{36:(c}{4:ount or 1) do}                    |
   2633      {4:  }{36:  }{4: }{36:  }{4: lo}{36:ca}{4:l c}{36:el}{4:l = line[colpos]}                 |
   2634      {4:  }{36:  }{4: }{36:  }{4: ce}{36:ll}{4:.te}{36:xt}{4: = text}                          |
   2635      {4:        ce}ll.hl_id = hl_id                        |
   2636              colpos = colpos+1                         |
   2637          end                                           |
   2638      end                                               |
   2639      {1:~                                                 }|*7
   2640                                                        |
   2641    ]],
   2642    }
   2643  end)
   2644 
   2645  local function with_undo_restore(val)
   2646    screen:try_resize(50, 5)
   2647    insert(example_text)
   2648    feed 'gg'
   2649    api.nvim_buf_set_extmark(0, ns, 0, 6, { end_col = 13, hl_group = 'NonText', undo_restore = val })
   2650    screen:expect {
   2651      grid = [[
   2652      ^for _,{1:item in} ipairs(items) do                    |
   2653          local text, hl_id_cell, count = unpack(item)  |
   2654          if hl_id_cell ~= nil then                     |
   2655              hl_id = hl_id_cell                        |
   2656                                                        |
   2657    ]],
   2658    }
   2659 
   2660    api.nvim_buf_set_text(0, 0, 4, 0, 8, { '' })
   2661    screen:expect {
   2662      grid = [[
   2663      ^for {1:em in} ipairs(items) do                        |
   2664          local text, hl_id_cell, count = unpack(item)  |
   2665          if hl_id_cell ~= nil then                     |
   2666              hl_id = hl_id_cell                        |
   2667                                                        |
   2668    ]],
   2669    }
   2670  end
   2671 
   2672  it('highlights do reapply to restored text after delete', function()
   2673    with_undo_restore(true) -- also default behavior
   2674 
   2675    command('silent undo')
   2676    screen:expect {
   2677      grid = [[
   2678      ^for _,{1:item in} ipairs(items) do                    |
   2679          local text, hl_id_cell, count = unpack(item)  |
   2680          if hl_id_cell ~= nil then                     |
   2681              hl_id = hl_id_cell                        |
   2682                                                        |
   2683    ]],
   2684    }
   2685  end)
   2686 
   2687  it("highlights don't reapply to restored text after delete with undo_restore=false", function()
   2688    with_undo_restore(false)
   2689 
   2690    command('silent undo')
   2691    screen:expect {
   2692      grid = [[
   2693      ^for _,it{1:em in} ipairs(items) do                    |
   2694          local text, hl_id_cell, count = unpack(item)  |
   2695          if hl_id_cell ~= nil then                     |
   2696              hl_id = hl_id_cell                        |
   2697                                                        |
   2698    ]],
   2699    }
   2700 
   2701    eq({
   2702      {
   2703        1,
   2704        0,
   2705        8,
   2706        {
   2707          end_col = 13,
   2708          end_right_gravity = false,
   2709          end_row = 0,
   2710          hl_eol = false,
   2711          hl_group = 'NonText',
   2712          undo_restore = false,
   2713          ns_id = ns,
   2714          priority = 4096,
   2715          right_gravity = true,
   2716        },
   2717      },
   2718    }, api.nvim_buf_get_extmarks(0, ns, { 0, 0 }, { 0, -1 }, { details = true }))
   2719  end)
   2720 
   2721  it('virtual text works with rightleft', function()
   2722    screen:try_resize(50, 3)
   2723    insert('abcdefghijklmn')
   2724    feed('0')
   2725    command('set rightleft')
   2726    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'EOL', 'Underlined' } } })
   2727    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'right_align', 'Underlined' } }, virt_text_pos = 'right_align' })
   2728    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'win_col', 'Underlined' } }, virt_text_win_col = 20 })
   2729    api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'overlayed', 'Underlined' } }, virt_text_pos = 'overlay' })
   2730    screen:expect {
   2731      grid = [[
   2732      {28:ngila_thgir}            {28:loc_niw}  {28:LOE} nml{28:deyalrevo}b^a|
   2733      {1:                                                 ~}|
   2734                                                        |
   2735    ]],
   2736    }
   2737 
   2738    insert(('#'):rep(32))
   2739    feed('0')
   2740    screen:expect {
   2741      grid = [[
   2742      {28:ngila_tdeyalrevo}ba#####{28:loc_niw}###################^#|
   2743      {1:                                                 ~}|
   2744                                                        |
   2745    ]],
   2746    }
   2747 
   2748    insert(('#'):rep(16))
   2749    feed('0')
   2750    screen:expect {
   2751      grid = [[
   2752      {28:ngila_thgir}############{28:loc_niw}###################^#|
   2753                                        {28:LOE} nml{28:deyalrevo}|
   2754                                                        |
   2755    ]],
   2756    }
   2757 
   2758    insert('###')
   2759    feed('0')
   2760    screen:expect {
   2761      grid = [[
   2762      #################################################^#|
   2763      {28:ngila_thgir}            {28:loc_niw} {28:LOE} nml{28:deyalrevo}ba#|
   2764                                                        |
   2765    ]],
   2766    }
   2767 
   2768    command('set number')
   2769    screen:expect {
   2770      grid = [[
   2771      #############################################^#{2: 1  }|
   2772      {28:ngila_thgir}        {28:loc_niw} nml{28:deyalrevo}ba#####{2:    }|
   2773                                                        |
   2774    ]],
   2775    }
   2776 
   2777    command('set cpoptions+=n')
   2778    screen:expect {
   2779      grid = [[
   2780      #############################################^#{2: 1  }|
   2781      {28:ngila_thgir}            {28:loc_niw} nml{28:deyalrevo}ba#####|
   2782                                                        |
   2783    ]],
   2784    }
   2785  end)
   2786 
   2787  it('virtual text overwrites double-width char properly', function()
   2788    screen:try_resize(50, 3)
   2789    insert('abcdefghij口klmnopqrstu口vwx口yz')
   2790    feed('0')
   2791    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { '!!!!!', 'Underlined' } }, virt_text_win_col = 11 })
   2792    screen:expect {
   2793      grid = [[
   2794      ^abcdefghij {28:!!!!!}opqrstu口vwx口yz                  |
   2795      {1:~                                                 }|
   2796                                                        |
   2797    ]],
   2798    }
   2799    feed('8x')
   2800    screen:expect {
   2801      grid = [[
   2802      ^ij口klmnopq{28:!!!!!} vwx口yz                          |
   2803      {1:~                                                 }|
   2804                                                        |
   2805    ]],
   2806    }
   2807    feed('3l5x')
   2808    screen:expect {
   2809      grid = [[
   2810      ij口^pqrstu {28:!!!!!} yz                               |
   2811      {1:~                                                 }|
   2812                                                        |
   2813    ]],
   2814    }
   2815    feed('5x')
   2816    screen:expect {
   2817      grid = [[
   2818      ij口^u口vwx {28:!!!!!}                                  |
   2819      {1:~                                                 }|
   2820                                                        |
   2821    ]],
   2822    }
   2823  end)
   2824 
   2825  it('virtual text blending space does not overwrite double-width char', function()
   2826    screen:try_resize(50, 3)
   2827    insert('abcdefghij口klmnopqrstu口vwx口yz')
   2828    feed('0')
   2829    command('hi Blendy guibg=Red blend=30')
   2830    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { ' !  ! ', 'Blendy' } }, virt_text_win_col = 8, hl_mode = 'blend' })
   2831    screen:expect {
   2832      grid = [[
   2833      ^abcdefgh{10:i}{7:!}{10:口}{7:!}{10:l}mnopqrstu口vwx口yz                  |
   2834      {1:~                                                 }|
   2835                                                        |
   2836    ]],
   2837    }
   2838    feed('x')
   2839    screen:expect {
   2840      grid = [[
   2841      ^bcdefghi{10:j}{7:!}{10: k}{7:!}{10:m}nopqrstu口vwx口yz                   |
   2842      {1:~                                                 }|
   2843                                                        |
   2844    ]],
   2845    }
   2846    feed('x')
   2847    screen:expect {
   2848      grid = [[
   2849      ^cdefghij{10: }{7:!}{10:kl}{7:!}{10:n}opqrstu口vwx口yz                    |
   2850      {1:~                                                 }|
   2851                                                        |
   2852    ]],
   2853    }
   2854    feed('x')
   2855    screen:expect {
   2856      grid = [[
   2857      ^defghij口{7:!}{10:lm}{7:!}{10:o}pqrstu口vwx口yz                     |
   2858      {1:~                                                 }|
   2859                                                        |
   2860    ]],
   2861    }
   2862    feed('7x')
   2863    screen:expect {
   2864      grid = [[
   2865      ^口klmnop{10:q}{7:!}{10:st}{7:!}{10:口}vwx口yz                            |
   2866      {1:~                                                 }|
   2867                                                        |
   2868    ]],
   2869    }
   2870  end)
   2871 
   2872  it('virtual text works with double-width char and rightleft', function()
   2873    screen:try_resize(50, 3)
   2874    insert('abcdefghij口klmnopqrstu口vwx口yz')
   2875    feed('0')
   2876    command('set rightleft')
   2877    screen:expect {
   2878      grid = [[
   2879                        zy口xwv口utsrqponmlk口jihgfedcb^a|
   2880      {1:                                                 ~}|
   2881                                                        |
   2882    ]],
   2883    }
   2884    api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'overlayed', 'Underlined' } }, virt_text_pos = 'overlay' })
   2885    api.nvim_buf_set_extmark(0, ns, 0, 14, { virt_text = { { '古', 'Underlined' } }, virt_text_pos = 'overlay' })
   2886    api.nvim_buf_set_extmark(0, ns, 0, 20, { virt_text = { { '\t', 'Underlined' } }, virt_text_pos = 'overlay' })
   2887    api.nvim_buf_set_extmark(0, ns, 0, 29, { virt_text = { { '古', 'Underlined' } }, virt_text_pos = 'overlay' })
   2888    screen:expect {
   2889      grid = [[
   2890                        zy {28:古}wv {28:     }qpon{28:古}k {28:deyalrevo}b^a|
   2891      {1:                                                 ~}|
   2892                                                        |
   2893    ]],
   2894    }
   2895  end)
   2896 
   2897  it('virtual text is drawn correctly after delete and undo #27368', function()
   2898    insert('aaa\nbbb\nccc\nddd\neee')
   2899    command('vsplit')
   2900    api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { 'EOL' } } })
   2901    feed('3gg')
   2902    screen:expect {
   2903      grid = [[
   2904      aaa                      │aaa                     |
   2905      bbb                      │bbb                     |
   2906      ^ccc EOL                  │ccc EOL                 |
   2907      ddd                      │ddd                     |
   2908      eee                      │eee                     |
   2909      {1:~                        }│{1:~                       }|*8
   2910      {41:[No Name] [+]             }{40:[No Name] [+]           }|
   2911                                                        |
   2912    ]],
   2913    }
   2914    feed('dd')
   2915    screen:expect {
   2916      grid = [[
   2917      aaa                      │aaa                     |
   2918      bbb                      │bbb                     |
   2919      ^ddd EOL                  │ddd EOL                 |
   2920      eee                      │eee                     |
   2921      {1:~                        }│{1:~                       }|*9
   2922      {41:[No Name] [+]             }{40:[No Name] [+]           }|
   2923                                                        |
   2924    ]],
   2925    }
   2926    command('silent undo')
   2927    screen:expect {
   2928      grid = [[
   2929      aaa                      │aaa                     |
   2930      bbb                      │bbb                     |
   2931      ^ccc EOL                  │ccc EOL                 |
   2932      ddd                      │ddd                     |
   2933      eee                      │eee                     |
   2934      {1:~                        }│{1:~                       }|*8
   2935      {41:[No Name] [+]             }{40:[No Name] [+]           }|
   2936                                                        |
   2937    ]],
   2938    }
   2939  end)
   2940 
   2941  it('virtual text does not crash with blend, conceal and wrap #27836', function()
   2942    screen:try_resize(50, 3)
   2943    insert(('a'):rep(45) .. '|hidden|' .. ('b'):rep(45))
   2944    command('syntax match test /|hidden|/ conceal')
   2945    command('set conceallevel=2 concealcursor=n')
   2946    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'FOO' } }, virt_text_pos = 'right_align', hl_mode = 'blend' })
   2947    screen:expect {
   2948      grid = [[
   2949      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa  FOO|
   2950      bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b     |
   2951                                                        |
   2952    ]],
   2953    }
   2954  end)
   2955 
   2956  it('works with both hl_group and sign_hl_group', function()
   2957    screen:try_resize(50, 3)
   2958    screen:add_extra_attr_ids({
   2959      [100] = { background = Screen.colors.WebGray, foreground = Screen.colors.Blue, bold = true },
   2960    })
   2961    insert('abcdefghijklmn')
   2962    api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S', sign_hl_group = 'NonText', hl_group = 'Error', end_col = 14 })
   2963    screen:expect([[
   2964      {100:S }{9:abcdefghijklm^n}                                  |
   2965      {1:~                                                 }|
   2966                                                        |
   2967    ]])
   2968  end)
   2969 
   2970  it('virt_text_repeat_linebreak repeats virtual text on wrapped lines', function()
   2971    screen:try_resize(40, 5)
   2972    api.nvim_set_option_value('breakindent', true, {})
   2973    insert(example_text)
   2974    api.nvim_buf_set_extmark(
   2975      0,
   2976      ns,
   2977      1,
   2978      0,
   2979      { virt_text = { { '│', 'NonText' } }, virt_text_pos = 'overlay', virt_text_repeat_linebreak = true }
   2980    )
   2981    api.nvim_buf_set_extmark(
   2982      0,
   2983      ns,
   2984      1,
   2985      3,
   2986      { virt_text = { { '│', 'NonText' } }, virt_text_pos = 'overlay', virt_text_repeat_linebreak = true }
   2987    )
   2988    command('norm gg')
   2989    screen:expect {
   2990      grid = [[
   2991      ^for _,item in ipairs(items) do          |
   2992      {1:│}  {1:│}local text, hl_id_cell, count = unpa|
   2993      {1:│}  {1:│}ck(item)                            |
   2994          if hl_id_cell ~= nil then           |
   2995                                              |
   2996    ]],
   2997    }
   2998    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   2999    api.nvim_buf_set_extmark(
   3000      0,
   3001      ns,
   3002      1,
   3003      0,
   3004      { virt_text = { { '│', 'NonText' } }, virt_text_repeat_linebreak = true, virt_text_win_col = 0 }
   3005    )
   3006    api.nvim_buf_set_extmark(
   3007      0,
   3008      ns,
   3009      1,
   3010      0,
   3011      { virt_text = { { '│', 'NonText' } }, virt_text_repeat_linebreak = true, virt_text_win_col = 2 }
   3012    )
   3013    screen:expect {
   3014      grid = [[
   3015      ^for _,item in ipairs(items) do          |
   3016      {1:│} {1:│} local text, hl_id_cell, count = unpa|
   3017      {1:│} {1:│} ck(item)                            |
   3018          if hl_id_cell ~= nil then           |
   3019                                              |
   3020    ]],
   3021    }
   3022  end)
   3023 
   3024  it('supports URLs', function()
   3025    insert(example_text)
   3026 
   3027    local url1 = 'https://example.com'
   3028    local url2 = 'http://127.0.0.1'
   3029 
   3030    screen:add_extra_attr_ids {
   3031      u = { url = url1 },
   3032      uh = { url = url2, background = Screen.colors.Yellow },
   3033    }
   3034 
   3035    api.nvim_buf_set_extmark(0, ns, 1, 4, {
   3036      end_col = 14,
   3037      url = url1,
   3038    })
   3039    api.nvim_buf_set_extmark(0, ns, 2, 4, {
   3040      end_col = 17,
   3041      hl_group = 'Search',
   3042      url = url2,
   3043    })
   3044 
   3045    screen:expect([[
   3046      for _,item in ipairs(items) do                    |
   3047          {u:local text}, hl_id_cell, count = unpack(item)  |
   3048          {uh:if hl_id_cell} ~= nil then                     |
   3049              hl_id = hl_id_cell                        |
   3050          end                                           |
   3051          for _ = 1, (count or 1) do                    |
   3052              local cell = line[colpos]                 |
   3053              cell.text = text                          |
   3054              cell.hl_id = hl_id                        |
   3055              colpos = colpos+1                         |
   3056          end                                           |
   3057      en^d                                               |
   3058      {1:~                                                 }|*2
   3059                                                        |
   3060    ]])
   3061  end)
   3062 
   3063  it('can replace marks in place with different decorations #27211', function()
   3064    local mark = api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'foo', 'ErrorMsg' } } } })
   3065    screen:expect {
   3066      grid = [[
   3067      ^                                                  |
   3068      {4:foo}                                               |
   3069      {1:~                                                 }|*12
   3070                                                        |
   3071    ]],
   3072    }
   3073 
   3074    api.nvim_buf_set_extmark(0, ns, 0, 0, {
   3075      id = mark,
   3076      virt_text = { { 'testing', 'NonText' } },
   3077      virt_text_pos = 'inline',
   3078    })
   3079    screen:expect {
   3080      grid = [[
   3081      {1:^testing}                                           |
   3082      {1:~                                                 }|*13
   3083                                                        |
   3084    ]],
   3085    }
   3086 
   3087    api.nvim_buf_del_extmark(0, ns, mark)
   3088    screen:expect {
   3089      grid = [[
   3090      ^                                                  |
   3091      {1:~                                                 }|*13
   3092                                                        |
   3093    ]],
   3094    }
   3095 
   3096    n.assert_alive()
   3097  end)
   3098 
   3099  it('priority ordering of overlay or win_col virtual text at same position', function()
   3100    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'A' } }, virt_text_pos = 'overlay', priority = 100 })
   3101    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'A' } }, virt_text_win_col = 30, priority = 100 })
   3102    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'BB' } }, virt_text_pos = 'overlay', priority = 90 })
   3103    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'BB' } }, virt_text_win_col = 30, priority = 90 })
   3104    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'CCC' } }, virt_text_pos = 'overlay', priority = 80 })
   3105    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'CCC' } }, virt_text_win_col = 30, priority = 80 })
   3106    screen:expect([[
   3107      ^ABC                           ABC                 |
   3108      {1:~                                                 }|*13
   3109                                                        |
   3110    ]])
   3111  end)
   3112 
   3113  it('priority ordering of inline and non-inline virtual text at same char', function()
   3114    insert(('?'):rep(40) .. ('!'):rep(30))
   3115    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'A' } }, virt_text_pos = 'overlay', priority = 10 })
   3116    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'a' } }, virt_text_win_col = 15, priority = 10 })
   3117    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'BBBB' } }, virt_text_pos = 'inline', priority = 15 })
   3118    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'C' } }, virt_text_pos = 'overlay', priority = 20 })
   3119    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'c' } }, virt_text_win_col = 17, priority = 20 })
   3120    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'DDDD' } }, virt_text_pos = 'inline', priority = 25 })
   3121    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'E' } }, virt_text_pos = 'overlay', priority = 30 })
   3122    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'e' } }, virt_text_win_col = 19, priority = 30 })
   3123    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'FFFF' } }, virt_text_pos = 'inline', priority = 35 })
   3124    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'G' } }, virt_text_pos = 'overlay', priority = 40 })
   3125    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'g' } }, virt_text_win_col = 21, priority = 40 })
   3126    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'HHHH' } }, virt_text_pos = 'inline', priority = 45 })
   3127    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'I' } }, virt_text_pos = 'overlay', priority = 50 })
   3128    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'i' } }, virt_text_win_col = 23, priority = 50 })
   3129    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'JJJJ' } }, virt_text_pos = 'inline', priority = 55 })
   3130    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'K' } }, virt_text_pos = 'overlay', priority = 60 })
   3131    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { 'k' } }, virt_text_win_col = 25, priority = 60 })
   3132    screen:expect([[
   3133      ???????????????a?c?e????????????????????ABBBCDDDEF|
   3134      FFGHHHIJJJK!!!!!!!!!!g!i!k!!!!!!!!!!!!!^!          |
   3135      {1:~                                                 }|*12
   3136                                                        |
   3137    ]])
   3138    feed('02x$')
   3139    screen:expect([[
   3140      ???????????????a?c?e??????????????????ABBBCDDDEFFF|
   3141      GHHHIJJJK!!!!!!!!!!!!g!i!k!!!!!!!!!!!^!            |
   3142      {1:~                                                 }|*12
   3143                                                        |
   3144    ]])
   3145    feed('02x$')
   3146    screen:expect([[
   3147      ???????????????a?c?e?g??????????????ABBBCDDDEFFFGH|
   3148      HHIJJJK!!!!!!!!!!!!!!!!i!k!!!!!!!!!^!              |
   3149      {1:~                                                 }|*12
   3150                                                        |
   3151    ]])
   3152    feed('02x$')
   3153    screen:expect([[
   3154      ???????????????a?c?e?g????????????ABBBCDDDEFFFGHHH|
   3155      IJJJK!!!!!!!!!!!!!!!!!!i!k!!!!!!!^!                |
   3156      {1:~                                                 }|*12
   3157                                                        |
   3158    ]])
   3159    command('set nowrap')
   3160    feed('0')
   3161    screen:expect([[
   3162      ^???????????????a?c?e?g?i?k????????ABBBCDDDEFFFGHHH|
   3163      {1:~                                                 }|*13
   3164                                                        |
   3165    ]])
   3166    feed('2x')
   3167    screen:expect([[
   3168      ^???????????????a?c?e?g?i?k??????ABBBCDDDEFFFGHHHIJ|
   3169      {1:~                                                 }|*13
   3170                                                        |
   3171    ]])
   3172    feed('2x')
   3173    screen:expect([[
   3174      ^???????????????a?c?e?g?i?k????ABBBCDDDEFFFGHHHIJJJ|
   3175      {1:~                                                 }|*13
   3176                                                        |
   3177    ]])
   3178    feed('2x')
   3179    screen:expect([[
   3180      ^???????????????a?c?e?g?i?k??ABBBCDDDEFFFGHHHIJJJK!|
   3181      {1:~                                                 }|*13
   3182                                                        |
   3183    ]])
   3184  end)
   3185 
   3186  it('conceal_lines', function()
   3187    insert(example_text)
   3188    exec('set number conceallevel=3')
   3189    feed('ggj')
   3190    local not_concealed = {
   3191      grid = [[
   3192        {2:  1 }for _,item in ipairs(items) do                |
   3193        {2:  2 }^    local text, hl_id_cell, count = unpack(ite|
   3194        {2:    }m)                                            |
   3195        {2:  3 }    if hl_id_cell ~= nil then                 |
   3196        {2:  4 }        hl_id = hl_id_cell                    |
   3197        {2:  5 }    end                                       |
   3198        {2:  6 }    for _ = 1, (count or 1) do                |
   3199        {2:  7 }        local cell = line[colpos]             |
   3200        {2:  8 }        cell.text = text                      |
   3201        {2:  9 }        cell.hl_id = hl_id                    |
   3202        {2: 10 }        colpos = colpos+1                     |
   3203        {2: 11 }    end                                       |
   3204        {2: 12 }end                                           |
   3205        {1:~                                                 }|
   3206                                                          |
   3207      ]],
   3208    }
   3209    screen:expect(not_concealed)
   3210    api.nvim_buf_set_extmark(0, ns, 1, 0, { conceal_lines = '' })
   3211    screen:expect_unchanged()
   3212    feed('j')
   3213    local concealed = {
   3214      grid = [[
   3215        {2:  1 }for _,item in ipairs(items) do                |
   3216        {2:  3 }^    if hl_id_cell ~= nil then                 |
   3217        {2:  4 }        hl_id = hl_id_cell                    |
   3218        {2:  5 }    end                                       |
   3219        {2:  6 }    for _ = 1, (count or 1) do                |
   3220        {2:  7 }        local cell = line[colpos]             |
   3221        {2:  8 }        cell.text = text                      |
   3222        {2:  9 }        cell.hl_id = hl_id                    |
   3223        {2: 10 }        colpos = colpos+1                     |
   3224        {2: 11 }    end                                       |
   3225        {2: 12 }end                                           |
   3226        {1:~                                                 }|*3
   3227                                                          |
   3228      ]],
   3229    }
   3230    screen:expect(concealed)
   3231    feed('k')
   3232    screen:expect(not_concealed)
   3233    exec('set concealcursor=n')
   3234    screen:expect(concealed)
   3235    api.nvim_buf_set_extmark(0, ns, 3, 0, { conceal_lines = '' })
   3236    screen:expect({
   3237      grid = [[
   3238        {2:  1 }for _,item in ipairs(items) do                |
   3239        {2:  3 }^    if hl_id_cell ~= nil then                 |
   3240        {2:  5 }    end                                       |
   3241        {2:  6 }    for _ = 1, (count or 1) do                |
   3242        {2:  7 }        local cell = line[colpos]             |
   3243        {2:  8 }        cell.text = text                      |
   3244        {2:  9 }        cell.hl_id = hl_id                    |
   3245        {2: 10 }        colpos = colpos+1                     |
   3246        {2: 11 }    end                                       |
   3247        {2: 12 }end                                           |
   3248        {1:~                                                 }|*4
   3249                                                          |
   3250      ]],
   3251    })
   3252    feed('kjj')
   3253    screen:expect_unchanged()
   3254    api.nvim_buf_set_extmark(0, ns, 4, 0, { conceal_lines = '' })
   3255    feed('kjjjC')
   3256    screen:expect({
   3257      grid = [[
   3258        {2:  1 }for _,item in ipairs(items) do                |
   3259        {2:  3 }    if hl_id_cell ~= nil then                 |
   3260        {2:  5 }^                                              |
   3261        {2:  6 }    for _ = 1, (count or 1) do                |
   3262        {2:  7 }        local cell = line[colpos]             |
   3263        {2:  8 }        cell.text = text                      |
   3264        {2:  9 }        cell.hl_id = hl_id                    |
   3265        {2: 10 }        colpos = colpos+1                     |
   3266        {2: 11 }    end                                       |
   3267        {2: 12 }end                                           |
   3268        {1:~                                                 }|*4
   3269        {24:-- INSERT --}                                      |
   3270      ]],
   3271    })
   3272    feed('<esc>')
   3273    screen:expect({
   3274      grid = [[
   3275        {2:  1 }for _,item in ipairs(items) do                |
   3276        {2:  3 }    if hl_id_cell ~= nil then                 |
   3277        {2:  6 }^    for _ = 1, (count or 1) do                |
   3278        {2:  7 }        local cell = line[colpos]             |
   3279        {2:  8 }        cell.text = text                      |
   3280        {2:  9 }        cell.hl_id = hl_id                    |
   3281        {2: 10 }        colpos = colpos+1                     |
   3282        {2: 11 }    end                                       |
   3283        {2: 12 }end                                           |
   3284        {1:~                                                 }|*5
   3285                                                          |
   3286      ]],
   3287    })
   3288    feed('kji')
   3289    screen:expect({
   3290      grid = [[
   3291        {2:  1 }for _,item in ipairs(items) do                |
   3292        {2:  3 }    if hl_id_cell ~= nil then                 |
   3293        {2:  5 }^                                              |
   3294        {2:  6 }    for _ = 1, (count or 1) do                |
   3295        {2:  7 }        local cell = line[colpos]             |
   3296        {2:  8 }        cell.text = text                      |
   3297        {2:  9 }        cell.hl_id = hl_id                    |
   3298        {2: 10 }        colpos = colpos+1                     |
   3299        {2: 11 }    end                                       |
   3300        {2: 12 }end                                           |
   3301        {1:~                                                 }|*4
   3302        {24:-- INSERT --}                                      |
   3303      ]],
   3304    })
   3305    feed('conceal text')
   3306    screen:expect({
   3307      grid = [[
   3308        {2:  1 }for _,item in ipairs(items) do                |
   3309        {2:  3 }    if hl_id_cell ~= nil then                 |
   3310        {2:  5 }conceal text^                                  |
   3311        {2:  6 }    for _ = 1, (count or 1) do                |
   3312        {2:  7 }        local cell = line[colpos]             |
   3313        {2:  8 }        cell.text = text                      |
   3314        {2:  9 }        cell.hl_id = hl_id                    |
   3315        {2: 10 }        colpos = colpos+1                     |
   3316        {2: 11 }    end                                       |
   3317        {2: 12 }end                                           |
   3318        {1:~                                                 }|*4
   3319        {24:-- INSERT --}                                      |
   3320      ]],
   3321    })
   3322    feed('<esc>')
   3323    screen:expect({
   3324      grid = [[
   3325        {2:  1 }for _,item in ipairs(items) do                |
   3326        {2:  3 }    if hl_id_cell ~= nil then                 |
   3327        {2:  6 }    for _ =^ 1, (count or 1) do                |
   3328        {2:  7 }        local cell = line[colpos]             |
   3329        {2:  8 }        cell.text = text                      |
   3330        {2:  9 }        cell.hl_id = hl_id                    |
   3331        {2: 10 }        colpos = colpos+1                     |
   3332        {2: 11 }    end                                       |
   3333        {2: 12 }end                                           |
   3334        {1:~                                                 }|*5
   3335                                                          |
   3336      ]],
   3337    })
   3338    feed('ggzfj')
   3339    screen:expect({
   3340      grid = [[
   3341        {2:  1 }{33:^+--  2 lines: for _,item in ipairs(items) do··}|
   3342        {2:  3 }    if hl_id_cell ~= nil then                 |
   3343        {2:  6 }    for _ = 1, (count or 1) do                |
   3344        {2:  7 }        local cell = line[colpos]             |
   3345        {2:  8 }        cell.text = text                      |
   3346        {2:  9 }        cell.hl_id = hl_id                    |
   3347        {2: 10 }        colpos = colpos+1                     |
   3348        {2: 11 }    end                                       |
   3349        {2: 12 }end                                           |
   3350        {1:~                                                 }|*5
   3351                                                          |
   3352      ]],
   3353    })
   3354    feed('j')
   3355    screen:expect({
   3356      grid = [[
   3357        {2:  1 }{33:+--  2 lines: for _,item in ipairs(items) do··}|
   3358        {2:  3 }^    if hl_id_cell ~= nil then                 |
   3359        {2:  6 }    for _ = 1, (count or 1) do                |
   3360        {2:  7 }        local cell = line[colpos]             |
   3361        {2:  8 }        cell.text = text                      |
   3362        {2:  9 }        cell.hl_id = hl_id                    |
   3363        {2: 10 }        colpos = colpos+1                     |
   3364        {2: 11 }    end                                       |
   3365        {2: 12 }end                                           |
   3366        {1:~                                                 }|*5
   3367                                                          |
   3368      ]],
   3369    })
   3370    feed('ggzdjzfj')
   3371    screen:expect({
   3372      grid = [[
   3373        {2:  1 }for _,item in ipairs(items) do                |
   3374        {2:  6 }^    for _ = 1, (count or 1) do                |
   3375        {2:  7 }        local cell = line[colpos]             |
   3376        {2:  8 }        cell.text = text                      |
   3377        {2:  9 }        cell.hl_id = hl_id                    |
   3378        {2: 10 }        colpos = colpos+1                     |
   3379        {2: 11 }    end                                       |
   3380        {2: 12 }end                                           |
   3381        {1:~                                                 }|*6
   3382                                                          |
   3383      ]],
   3384    })
   3385    feed('jj')
   3386    screen:expect({
   3387      grid = [[
   3388        {2:  1 }^for _,item in ipairs(items) do                |
   3389        {2:  6 }    for _ = 1, (count or 1) do                |
   3390        {2:  7 }        local cell = line[colpos]             |
   3391        {2:  8 }        cell.text = text                      |
   3392        {2:  9 }        cell.hl_id = hl_id                    |
   3393        {2: 10 }        colpos = colpos+1                     |
   3394        {2: 11 }    end                                       |
   3395        {2: 12 }end                                           |
   3396        {1:~                                                 }|*6
   3397                                                          |
   3398      ]],
   3399    })
   3400    -- Below virtual line belonging to line above concealed line is drawn.
   3401    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'line 1 below' } } } })
   3402    -- Above virtual line belonging to concealed line isn't.
   3403    api.nvim_buf_set_extmark(0, ns, 1, 0, {
   3404      virt_lines = { { { 'line 2 above' } } },
   3405      virt_lines_above = true,
   3406    })
   3407    screen:expect([[
   3408      {2:  1 }for _,item in ipairs(items) do                |
   3409      {2:    }line 1 below                                  |
   3410      {2:  6 }^    for _ = 1, (count or 1) do                |
   3411      {2:  7 }        local cell = line[colpos]             |
   3412      {2:  8 }        cell.text = text                      |
   3413      {2:  9 }        cell.hl_id = hl_id                    |
   3414      {2: 10 }        colpos = colpos+1                     |
   3415      {2: 11 }    end                                       |
   3416      {2: 12 }end                                           |
   3417      {1:~                                                 }|*5
   3418                                                        |
   3419    ]])
   3420    -- w_lines.wl_lastlnum values are valid
   3421    command('set relativenumber concealcursor=')
   3422    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   3423    api.nvim_buf_set_extmark(0, ns, 1, 0, { conceal_lines = '' })
   3424    api.nvim_buf_set_extmark(0, ns, 4, 0, { conceal_lines = '' })
   3425    feed('zE')
   3426    screen:expect([[
   3427      {2:  4 }for _,item in ipairs(items) do                |
   3428      {2:  2 }    if hl_id_cell ~= nil then                 |
   3429      {2:  1 }        hl_id = hl_id_cell                    |
   3430      {2:5   }^conceal text                                  |
   3431      {2:  1 }    for _ = 1, (count or 1) do                |
   3432      {2:  2 }        local cell = line[colpos]             |
   3433      {2:  3 }        cell.text = text                      |
   3434      {2:  4 }        cell.hl_id = hl_id                    |
   3435      {2:  5 }        colpos = colpos+1                     |
   3436      {2:  6 }    end                                       |
   3437      {2:  7 }end                                           |
   3438      {1:~                                                 }|*3
   3439                                                        |
   3440    ]])
   3441    feed('jj')
   3442    screen:expect([[
   3443      {2:  6 }for _,item in ipairs(items) do                |
   3444      {2:  4 }    if hl_id_cell ~= nil then                 |
   3445      {2:  3 }        hl_id = hl_id_cell                    |
   3446      {2:  1 }    for _ = 1, (count or 1) do                |
   3447      {2:7   }^        local cell = line[colpos]             |
   3448      {2:  1 }        cell.text = text                      |
   3449      {2:  2 }        cell.hl_id = hl_id                    |
   3450      {2:  3 }        colpos = colpos+1                     |
   3451      {2:  4 }    end                                       |
   3452      {2:  5 }end                                           |
   3453      {1:~                                                 }|*4
   3454                                                        |
   3455    ]])
   3456    -- Correct relativenumber for line below concealed line #33694
   3457    feed('4Gk')
   3458    screen:expect([[
   3459      {2:  2 }for _,item in ipairs(items) do                |
   3460      {2:3   }    if h^l_id_cell ~= nil then                 |
   3461      {2:  1 }        hl_id = hl_id_cell                    |
   3462      {2:  3 }    for _ = 1, (count or 1) do                |
   3463      {2:  4 }        local cell = line[colpos]             |
   3464      {2:  5 }        cell.text = text                      |
   3465      {2:  6 }        cell.hl_id = hl_id                    |
   3466      {2:  7 }        colpos = colpos+1                     |
   3467      {2:  8 }    end                                       |
   3468      {2:  9 }end                                           |
   3469      {1:~                                                 }|*4
   3470                                                        |
   3471    ]])
   3472    -- Also with above virtual line #32744
   3473    command('set nornu')
   3474    api.nvim_buf_set_extmark(0, ns, 3, 0, { virt_lines = { { { 'virt_below 4' } } } })
   3475    feed('6G')
   3476    screen:expect([[
   3477      {2:  1 }for _,item in ipairs(items) do                |
   3478      {2:  3 }    if hl_id_cell ~= nil then                 |
   3479      {2:  4 }        hl_id = hl_id_cell                    |
   3480      {2:    }virt_below 4                                  |
   3481      {2:  6 }    ^for _ = 1, (count or 1) do                |
   3482      {2:  7 }        local cell = line[colpos]             |
   3483      {2:  8 }        cell.text = text                      |
   3484      {2:  9 }        cell.hl_id = hl_id                    |
   3485      {2: 10 }        colpos = colpos+1                     |
   3486      {2: 11 }    end                                       |
   3487      {2: 12 }end                                           |
   3488      {1:~                                                 }|*3
   3489                                                        |
   3490    ]])
   3491    feed('j')
   3492    screen:expect([[
   3493      {2:  1 }for _,item in ipairs(items) do                |
   3494      {2:  3 }    if hl_id_cell ~= nil then                 |
   3495      {2:  4 }        hl_id = hl_id_cell                    |
   3496      {2:    }virt_below 4                                  |
   3497      {2:  6 }    for _ = 1, (count or 1) do                |
   3498      {2:  7 }    ^    local cell = line[colpos]             |
   3499      {2:  8 }        cell.text = text                      |
   3500      {2:  9 }        cell.hl_id = hl_id                    |
   3501      {2: 10 }        colpos = colpos+1                     |
   3502      {2: 11 }    end                                       |
   3503      {2: 12 }end                                           |
   3504      {1:~                                                 }|*3
   3505                                                        |
   3506    ]])
   3507    -- Even when virtual line is added as line is concealed #32762
   3508    feed('5G')
   3509    api.nvim_buf_clear_namespace(0, ns, 3, 4)
   3510    feed('j')
   3511    api.nvim_buf_set_extmark(0, ns, 3, 0, { virt_lines = { { { 'virt_below 4' } } } })
   3512    screen:expect([[
   3513      {2:  1 }for _,item in ipairs(items) do                |
   3514      {2:  3 }    if hl_id_cell ~= nil then                 |
   3515      {2:  4 }        hl_id = hl_id_cell                    |
   3516      {2:    }virt_below 4                                  |
   3517      {2:  6 }^    for _ = 1, (count or 1) do                |
   3518      {2:  7 }        local cell = line[colpos]             |
   3519      {2:  8 }        cell.text = text                      |
   3520      {2:  9 }        cell.hl_id = hl_id                    |
   3521      {2: 10 }        colpos = colpos+1                     |
   3522      {2: 11 }    end                                       |
   3523      {2: 12 }end                                           |
   3524      {1:~                                                 }|*3
   3525                                                        |
   3526    ]])
   3527    -- No scrolling for concealed topline #33033
   3528    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   3529    api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_lines_above = true, virt_lines = { { { 'virt_above 2' } } } })
   3530    api.nvim_buf_set_extmark(0, ns, 0, 0, { conceal_lines = '' })
   3531    feed('ggjj')
   3532    screen:expect([[
   3533      {2:    }virt_above 2                                  |
   3534      {2:  2 }    local text, hl_id_cell, count = unpack(ite|
   3535      {2:    }m)                                            |
   3536      {2:  3 }^    if hl_id_cell ~= nil then                 |
   3537      {2:  4 }        hl_id = hl_id_cell                    |
   3538      {2:  5 }conceal text                                  |
   3539      {2:  6 }    for _ = 1, (count or 1) do                |
   3540      {2:  7 }        local cell = line[colpos]             |
   3541      {2:  8 }        cell.text = text                      |
   3542      {2:  9 }        cell.hl_id = hl_id                    |
   3543      {2: 10 }        colpos = colpos+1                     |
   3544      {2: 11 }    end                                       |
   3545      {2: 12 }end                                           |
   3546      {1:~                                                 }|
   3547                                                        |
   3548    ]])
   3549    -- No asymmetric topline for <C-E><C-Y> #33182
   3550    feed('4<C-E>')
   3551    exec('set concealcursor=n')
   3552    api.nvim_buf_set_extmark(0, ns, 4, 0, { conceal_lines = '' })
   3553    eq(5, n.fn.line('w0'))
   3554    feed('<C-E><C-Y>')
   3555    eq(5, n.fn.line('w0'))
   3556  end)
   3557 
   3558  it('conceal_lines not checking on invalid row #36057', function()
   3559    exec_lua(function()
   3560      vim.fn.setline(1, { 'foo', 'bar', 'baz' })
   3561      vim.api.nvim_command('set conceallevel=3 scrolloff=3')
   3562      vim.api.nvim_open_win(0, true, { width = 1, height = 1, relative = 'editor', row = 0, col = 0 })
   3563      vim.api.nvim_buf_set_extmark(0, ns, 1, 0, { conceal_lines = '' })
   3564      vim.api.nvim__redraw({ flush = true })
   3565    end)
   3566    n.assert_alive()
   3567  end)
   3568 
   3569  it('redraws the line from which a left gravity mark has moved #27369', function()
   3570    fn.setline(1, { 'aaa', 'bbb', 'ccc', 'ddd' })
   3571    api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'foo' } }, right_gravity = false })
   3572    feed('yyp')
   3573    screen:expect([[
   3574      aaa                                               |
   3575      ^aaa foo                                           |
   3576      bbb                                               |
   3577      ccc                                               |
   3578      ddd                                               |
   3579      {1:~                                                 }|*9
   3580                                                        |
   3581    ]])
   3582  end)
   3583 
   3584  it('redraws extmark that starts and ends outside the screen', function()
   3585    local lines = vim.split(('1'):rep(20), '', { plain = true })
   3586    api.nvim_buf_set_lines(0, 0, -1, true, lines)
   3587    api.nvim_buf_set_extmark(0, ns, 0, 0, { hl_group = 'ErrorMsg', end_row = 19, end_col = 0 })
   3588    screen:expect({
   3589      grid = [[
   3590        {4:^1}                                                 |
   3591        {4:1}                                                 |*13
   3592                                                          |
   3593      ]],
   3594    })
   3595    feed('<C-e>')
   3596    -- Newly visible line should also have the highlight.
   3597    screen:expect({
   3598      grid = [[
   3599        {4:^1}                                                 |
   3600        {4:1}                                                 |*13
   3601                                                          |
   3602      ]],
   3603    })
   3604  end)
   3605 
   3606  it('line("w$", win) considers conceal_lines', function()
   3607    api.nvim_buf_set_lines(0, 0, -1, true, { 'line 1', 'line 2', 'line 3' })
   3608    api.nvim_buf_set_extmark(0, ns, 0, 0, { conceal_lines = '' }) -- conceal line 1
   3609 
   3610    local win = exec_lua(function()
   3611      local provider_ns = vim.api.nvim_create_namespace('test_f_line')
   3612      _G.line_w_dollar = {}
   3613      vim.api.nvim_set_decoration_provider(provider_ns, {
   3614        on_start = function()
   3615          for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
   3616            table.insert(_G.line_w_dollar, { win, vim.fn.line('w$', win) })
   3617          end
   3618        end,
   3619      })
   3620 
   3621      local win = vim.api.nvim_open_win(0, false, {
   3622        relative = 'editor',
   3623        width = 20,
   3624        height = 1,
   3625        row = 0,
   3626        col = 0,
   3627        border = 'single',
   3628      })
   3629      vim.api.nvim_set_option_value('conceallevel', 2, { scope = 'local', win = win })
   3630 
   3631      return win
   3632    end)
   3633 
   3634    local line_w_dollar = exec_lua('return _G.line_w_dollar')
   3635    for _, win_line in ipairs(line_w_dollar) do
   3636      if win_line[1] == win then
   3637        eq(2, win_line[2])
   3638      end
   3639    end
   3640  end)
   3641 end)
   3642 
   3643 describe('decorations: inline virtual text', function()
   3644  local screen ---@type test.functional.ui.screen
   3645  local ns ---@type integer
   3646  before_each(function()
   3647    clear()
   3648    screen = Screen.new(50, 3)
   3649    screen:set_default_attr_ids {
   3650      [1] = { bold = true, foreground = Screen.colors.Blue },
   3651      [2] = { foreground = Screen.colors.Brown },
   3652      [3] = { bold = true, foreground = Screen.colors.SeaGreen },
   3653      [4] = { background = Screen.colors.Red1, foreground = Screen.colors.Gray100 },
   3654      [5] = { background = Screen.colors.Red1, bold = true },
   3655      [6] = { foreground = Screen.colors.DarkCyan },
   3656      [7] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Black },
   3657      [8] = { bold = true },
   3658      [9] = { background = Screen.colors.Plum1 },
   3659      [10] = { foreground = Screen.colors.SlateBlue },
   3660      [11] = { blend = 30, background = Screen.colors.Red1 },
   3661      [12] = { background = Screen.colors.Yellow },
   3662      [13] = { reverse = true },
   3663      [14] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.LightMagenta },
   3664      [15] = { bold = true, reverse = true },
   3665      [16] = { foreground = Screen.colors.Red },
   3666      [17] = { background = Screen.colors.LightGrey, foreground = Screen.colors.DarkBlue },
   3667      [18] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Red },
   3668      [19] = { background = Screen.colors.Yellow, foreground = Screen.colors.SlateBlue },
   3669      [20] = { background = Screen.colors.LightGrey, foreground = Screen.colors.SlateBlue },
   3670      [21] = { reverse = true, foreground = Screen.colors.SlateBlue },
   3671      [22] = { background = Screen.colors.Gray90 },
   3672      [23] = { background = Screen.colors.Gray90, foreground = Screen.colors.Blue, bold = true },
   3673    }
   3674 
   3675    ns = api.nvim_create_namespace 'test'
   3676  end)
   3677 
   3678  it('works', function()
   3679    screen:try_resize(50, 10)
   3680    insert(example_text)
   3681    feed 'gg'
   3682    screen:expect {
   3683      grid = [[
   3684      ^for _,item in ipairs(items) do                    |
   3685          local text, hl_id_cell, count = unpack(item)  |
   3686          if hl_id_cell ~= nil then                     |
   3687              hl_id = hl_id_cell                        |
   3688          end                                           |
   3689          for _ = 1, (count or 1) do                    |
   3690              local cell = line[colpos]                 |
   3691              cell.text = text                          |
   3692              cell.hl_id = hl_id                        |
   3693                                                        |
   3694    ]],
   3695    }
   3696 
   3697    api.nvim_buf_set_extmark(0, ns, 1, 14, { virt_text = { { ': ', 'Special' }, { 'string', 'Type' } }, virt_text_pos = 'inline' })
   3698    screen:expect {
   3699      grid = [[
   3700      ^for _,item in ipairs(items) do                    |
   3701          local text{10:: }{3:string}, hl_id_cell, count = unpack|
   3702      (item)                                            |
   3703          if hl_id_cell ~= nil then                     |
   3704              hl_id = hl_id_cell                        |
   3705          end                                           |
   3706          for _ = 1, (count or 1) do                    |
   3707              local cell = line[colpos]                 |
   3708              cell.text = text                          |
   3709                                                        |
   3710    ]],
   3711    }
   3712 
   3713    screen:try_resize(55, 10)
   3714    screen:expect {
   3715      grid = [[
   3716      ^for _,item in ipairs(items) do                         |
   3717          local text{10:: }{3:string}, hl_id_cell, count = unpack(item|
   3718      )                                                      |
   3719          if hl_id_cell ~= nil then                          |
   3720              hl_id = hl_id_cell                             |
   3721          end                                                |
   3722          for _ = 1, (count or 1) do                         |
   3723              local cell = line[colpos]                      |
   3724              cell.text = text                               |
   3725                                                             |
   3726    ]],
   3727    }
   3728 
   3729    screen:try_resize(56, 10)
   3730    screen:expect {
   3731      grid = [[
   3732      ^for _,item in ipairs(items) do                          |
   3733          local text{10:: }{3:string}, hl_id_cell, count = unpack(item)|
   3734          if hl_id_cell ~= nil then                           |
   3735              hl_id = hl_id_cell                              |
   3736          end                                                 |
   3737          for _ = 1, (count or 1) do                          |
   3738              local cell = line[colpos]                       |
   3739              cell.text = text                                |
   3740              cell.hl_id = hl_id                              |
   3741                                                              |
   3742    ]],
   3743    }
   3744  end)
   3745 
   3746  it('works with 0-width chunk', function()
   3747    screen:try_resize(50, 10)
   3748    insert(example_text)
   3749    feed 'gg'
   3750    screen:expect {
   3751      grid = [[
   3752      ^for _,item in ipairs(items) do                    |
   3753          local text, hl_id_cell, count = unpack(item)  |
   3754          if hl_id_cell ~= nil then                     |
   3755              hl_id = hl_id_cell                        |
   3756          end                                           |
   3757          for _ = 1, (count or 1) do                    |
   3758              local cell = line[colpos]                 |
   3759              cell.text = text                          |
   3760              cell.hl_id = hl_id                        |
   3761                                                        |
   3762    ]],
   3763    }
   3764 
   3765    api.nvim_buf_set_extmark(0, ns, 0, 5, { virt_text = { { '' }, { '' } }, virt_text_pos = 'inline' })
   3766    api.nvim_buf_set_extmark(0, ns, 1, 14, { virt_text = { { '' }, { ': ', 'Special' } }, virt_text_pos = 'inline' })
   3767    api.nvim_buf_set_extmark(0, ns, 1, 48, { virt_text = { { '' }, { '' } }, virt_text_pos = 'inline' })
   3768    screen:expect {
   3769      grid = [[
   3770      ^for _,item in ipairs(items) do                    |
   3771          local text{10:: }, hl_id_cell, count = unpack(item)|
   3772          if hl_id_cell ~= nil then                     |
   3773              hl_id = hl_id_cell                        |
   3774          end                                           |
   3775          for _ = 1, (count or 1) do                    |
   3776              local cell = line[colpos]                 |
   3777              cell.text = text                          |
   3778              cell.hl_id = hl_id                        |
   3779                                                        |
   3780    ]],
   3781    }
   3782 
   3783    api.nvim_buf_set_extmark(0, ns, 1, 14, { virt_text = { { '' }, { 'string', 'Type' } }, virt_text_pos = 'inline' })
   3784    feed('V')
   3785    screen:expect {
   3786      grid = [[
   3787      ^f{7:or _,item in ipairs(items) do}                    |
   3788          local text{10:: }{3:string}, hl_id_cell, count = unpack|
   3789      (item)                                            |
   3790          if hl_id_cell ~= nil then                     |
   3791              hl_id = hl_id_cell                        |
   3792          end                                           |
   3793          for _ = 1, (count or 1) do                    |
   3794              local cell = line[colpos]                 |
   3795              cell.text = text                          |
   3796      {8:-- VISUAL LINE --}                                 |
   3797    ]],
   3798    }
   3799 
   3800    feed('<Esc>jf,')
   3801    screen:expect {
   3802      grid = [[
   3803      for _,item in ipairs(items) do                    |
   3804          local text{10:: }{3:string}^, hl_id_cell, count = unpack|
   3805      (item)                                            |
   3806          if hl_id_cell ~= nil then                     |
   3807              hl_id = hl_id_cell                        |
   3808          end                                           |
   3809          for _ = 1, (count or 1) do                    |
   3810              local cell = line[colpos]                 |
   3811              cell.text = text                          |
   3812                                                        |
   3813    ]],
   3814    }
   3815  end)
   3816 
   3817  it('Normal mode "gM" command works properly', function()
   3818    command([[call setline(1, '123456789')]])
   3819    api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'bbb', 'Special' } }, virt_text_pos = 'inline' })
   3820    api.nvim_buf_set_extmark(0, ns, 0, 7, { virt_text = { { 'bbb', 'Special' } }, virt_text_pos = 'inline' })
   3821    feed('gM')
   3822    screen:expect {
   3823      grid = [[
   3824      12{10:bbb}34^567{10:bbb}89                                   |
   3825      {1:~                                                 }|
   3826                                                        |
   3827    ]],
   3828    }
   3829  end)
   3830 
   3831  local function test_normal_gj_gk()
   3832    screen:try_resize(60, 6)
   3833    command([[call setline(1, repeat([repeat('a', 55)], 2))]])
   3834    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { ('b'):rep(10), 'Special' } }, virt_text_pos = 'inline' })
   3835    api.nvim_buf_set_extmark(0, ns, 1, 40, { virt_text = { { ('b'):rep(10), 'Special' } }, virt_text_pos = 'inline' })
   3836    screen:expect {
   3837      grid = [[
   3838      ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3839      aaaaa                                                       |
   3840      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3841      aaaaa                                                       |
   3842      {1:~                                                           }|
   3843                                                                  |
   3844    ]],
   3845    }
   3846    feed('gj')
   3847    screen:expect {
   3848      grid = [[
   3849      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3850      ^aaaaa                                                       |
   3851      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3852      aaaaa                                                       |
   3853      {1:~                                                           }|
   3854                                                                  |
   3855    ]],
   3856    }
   3857    feed('gj')
   3858    screen:expect {
   3859      grid = [[
   3860      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3861      aaaaa                                                       |
   3862      ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3863      aaaaa                                                       |
   3864      {1:~                                                           }|
   3865                                                                  |
   3866    ]],
   3867    }
   3868    feed('gj')
   3869    screen:expect {
   3870      grid = [[
   3871      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3872      aaaaa                                                       |
   3873      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3874      ^aaaaa                                                       |
   3875      {1:~                                                           }|
   3876                                                                  |
   3877    ]],
   3878    }
   3879    feed('gk')
   3880    screen:expect {
   3881      grid = [[
   3882      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3883      aaaaa                                                       |
   3884      ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3885      aaaaa                                                       |
   3886      {1:~                                                           }|
   3887                                                                  |
   3888    ]],
   3889    }
   3890    feed('gk')
   3891    screen:expect {
   3892      grid = [[
   3893      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3894      ^aaaaa                                                       |
   3895      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3896      aaaaa                                                       |
   3897      {1:~                                                           }|
   3898                                                                  |
   3899    ]],
   3900    }
   3901    feed('gk')
   3902    screen:expect {
   3903      grid = [[
   3904      ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3905      aaaaa                                                       |
   3906      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbbbbbbbbb}aaaaaaaaaa|
   3907      aaaaa                                                       |
   3908      {1:~                                                           }|
   3909                                                                  |
   3910    ]],
   3911    }
   3912  end
   3913 
   3914  describe('Normal mode "gj" "gk" commands work properly', function()
   3915    it('with virtualedit=', function()
   3916      test_normal_gj_gk()
   3917    end)
   3918 
   3919    it('with virtualedit=all', function()
   3920      command('set virtualedit=all')
   3921      test_normal_gj_gk()
   3922    end)
   3923  end)
   3924 
   3925  it('cursor positions are correct with multiple inline virtual text', function()
   3926    insert('12345678')
   3927    api.nvim_buf_set_extmark(0, ns, 0, 4, { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' })
   3928    api.nvim_buf_set_extmark(0, ns, 0, 4, { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' })
   3929    feed '^'
   3930    feed '4l'
   3931    screen:expect {
   3932      grid = [[
   3933      1234{10: virtual text  virtual text }^5678              |
   3934      {1:~                                                 }|
   3935                                                        |
   3936    ]],
   3937    }
   3938  end)
   3939 
   3940  it('adjusts cursor location correctly when inserting around inline virtual text', function()
   3941    insert('12345678')
   3942    feed '$'
   3943    api.nvim_buf_set_extmark(0, ns, 0, 4, { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' })
   3944 
   3945    screen:expect {
   3946      grid = [[
   3947      1234{10: virtual text }567^8                            |
   3948      {1:~                                                 }|
   3949                                                        |
   3950    ]],
   3951    }
   3952  end)
   3953 
   3954  it('has correct highlighting with multi-byte characters', function()
   3955    insert('12345678')
   3956    api.nvim_buf_set_extmark(0, ns, 0, 4, { virt_text = { { 'múlti-byté chñröcters 修补', 'Special' } }, virt_text_pos = 'inline' })
   3957 
   3958    screen:expect {
   3959      grid = [[
   3960      1234{10:múlti-byté chñröcters 修补}567^8                |
   3961      {1:~                                                 }|
   3962                                                        |
   3963    ]],
   3964    }
   3965  end)
   3966 
   3967  it('has correct cursor position when inserting around virtual text', function()
   3968    insert('12345678')
   3969    api.nvim_buf_set_extmark(0, ns, 0, 4, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
   3970    feed '^'
   3971    feed '3l'
   3972    feed 'a'
   3973    screen:expect {
   3974      grid = [[
   3975      1234{10:^virtual text}5678                              |
   3976      {1:~                                                 }|
   3977      {8:-- INSERT --}                                      |
   3978    ]],
   3979    }
   3980    feed '<ESC>'
   3981    screen:expect {
   3982      grid = [[
   3983      123^4{10:virtual text}5678                              |
   3984      {1:~                                                 }|
   3985                                                        |
   3986    ]],
   3987    }
   3988    feed '^'
   3989    feed '4l'
   3990    feed 'i'
   3991    screen:expect {
   3992      grid = [[
   3993      1234{10:^virtual text}5678                              |
   3994      {1:~                                                 }|
   3995      {8:-- INSERT --}                                      |
   3996    ]],
   3997    }
   3998  end)
   3999 
   4000  it('has correct cursor position with virtual text on an empty line', function()
   4001    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
   4002    screen:expect {
   4003      grid = [[
   4004      {10:^virtual text}                                      |
   4005      {1:~                                                 }|
   4006                                                        |
   4007    ]],
   4008    }
   4009  end)
   4010 
   4011  it('text is drawn correctly with a wrapping virtual text', function()
   4012    screen:try_resize(60, 8)
   4013    exec([[
   4014      call setline(1, ['', 'aaa', '', 'bbbbbb'])
   4015      normal gg0
   4016    ]])
   4017    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('X', 60), 'Special' } }, virt_text_pos = 'inline' })
   4018    api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { string.rep('X', 61), 'Special' } }, virt_text_pos = 'inline' })
   4019    feed('$')
   4020    screen:expect {
   4021      grid = [[
   4022      {10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4023      aaa                                                         |
   4024      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4025      {10:X}                                                           |
   4026      bbbbbb                                                      |
   4027      {1:~                                                           }|*2
   4028                                                                  |
   4029    ]],
   4030    }
   4031    feed('j')
   4032    screen:expect {
   4033      grid = [[
   4034      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4035      aa^a                                                         |
   4036      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4037      {10:X}                                                           |
   4038      bbbbbb                                                      |
   4039      {1:~                                                           }|*2
   4040                                                                  |
   4041    ]],
   4042    }
   4043    feed('j')
   4044    screen:expect {
   4045      grid = [[
   4046      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4047      aaa                                                         |
   4048      {10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4049      {10:X}                                                           |
   4050      bbbbbb                                                      |
   4051      {1:~                                                           }|*2
   4052                                                                  |
   4053    ]],
   4054    }
   4055    feed('j')
   4056    screen:expect {
   4057      grid = [[
   4058      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4059      aaa                                                         |
   4060      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4061      {10:X}                                                           |
   4062      bbbbb^b                                                      |
   4063      {1:~                                                           }|*2
   4064                                                                  |
   4065    ]],
   4066    }
   4067    feed('0<C-V>2l2k')
   4068    screen:expect {
   4069      grid = [[
   4070      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4071      {7:aa}^a                                                         |
   4072      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4073      {10:X}                                                           |
   4074      {7:bbb}bbb                                                      |
   4075      {1:~                                                           }|*2
   4076      {8:-- VISUAL BLOCK --}                                          |
   4077    ]],
   4078    }
   4079    feed([[<Esc>/aaa\n\%V<CR>]])
   4080    screen:expect {
   4081      grid = [[
   4082      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4083      {12:^aaa }                                                        |
   4084      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4085      {10:X}                                                           |
   4086      bbbbbb                                                      |
   4087      {1:~                                                           }|*2
   4088      {16:search hit BOTTOM, continuing at TOP}                        |
   4089    ]],
   4090    }
   4091    feed('3ggic')
   4092    screen:expect {
   4093      grid = [[
   4094      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4095      {12:aaa }                                                        |
   4096      c{10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4097      {10:XX}                                                          |
   4098      bbbbbb                                                      |
   4099      {1:~                                                           }|*2
   4100      {8:-- INSERT --}                                                |
   4101    ]],
   4102    }
   4103    feed([[<Esc>/aaa\nc\%V<CR>]])
   4104    screen:expect {
   4105      grid = [[
   4106      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4107      {12:^aaa }                                                        |
   4108      {12:c}{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4109      {10:XX}                                                          |
   4110      bbbbbb                                                      |
   4111      {1:~                                                           }|*2
   4112      {16:search hit BOTTOM, continuing at TOP}                        |
   4113    ]],
   4114    }
   4115  end)
   4116 
   4117  it('cursor position is correct with virtual text attached to hard TABs', function()
   4118    command('set noexpandtab')
   4119    feed('i')
   4120    feed('<TAB>')
   4121    feed('<TAB>')
   4122    feed('test')
   4123    feed('<ESC>')
   4124    api.nvim_buf_set_extmark(0, ns, 0, 1, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
   4125    feed('0')
   4126    screen:expect {
   4127      grid = [[
   4128             ^ {10:virtual text}    test                      |
   4129      {1:~                                                 }|
   4130                                                        |
   4131    ]],
   4132    }
   4133 
   4134    feed('l')
   4135    screen:expect {
   4136      grid = [[
   4137              {10:virtual text}   ^ test                      |
   4138      {1:~                                                 }|
   4139                                                        |
   4140    ]],
   4141    }
   4142 
   4143    feed('l')
   4144    screen:expect {
   4145      grid = [[
   4146              {10:virtual text}    ^test                      |
   4147      {1:~                                                 }|
   4148                                                        |
   4149    ]],
   4150    }
   4151 
   4152    feed('l')
   4153    screen:expect {
   4154      grid = [[
   4155              {10:virtual text}    t^est                      |
   4156      {1:~                                                 }|
   4157                                                        |
   4158    ]],
   4159    }
   4160 
   4161    feed('l')
   4162    screen:expect {
   4163      grid = [[
   4164              {10:virtual text}    te^st                      |
   4165      {1:~                                                 }|
   4166                                                        |
   4167    ]],
   4168    }
   4169  end)
   4170 
   4171  it('cursor position is correct with virtual text on an empty line', function()
   4172    command('set linebreak')
   4173    insert('one twoword')
   4174    feed('0')
   4175    api.nvim_buf_set_extmark(0, ns, 0, 3, { virt_text = { { ': virtual text', 'Special' } }, virt_text_pos = 'inline' })
   4176    screen:expect {
   4177      grid = [[
   4178      ^one{10:: virtual text} twoword                         |
   4179      {1:~                                                 }|
   4180                                                        |
   4181    ]],
   4182    }
   4183  end)
   4184 
   4185  it('search highlight is correct', function()
   4186    insert('foo foo foo bar\nfoo foo foo bar')
   4187    feed('gg0')
   4188    api.nvim_buf_set_extmark(0, ns, 0, 9, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' })
   4189    api.nvim_buf_set_extmark(0, ns, 0, 9, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   4190    api.nvim_buf_set_extmark(0, ns, 1, 9, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   4191    api.nvim_buf_set_extmark(0, ns, 1, 9, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' })
   4192    screen:expect {
   4193      grid = [[
   4194      ^foo foo f{10:AAABBB}oo bar                             |
   4195      foo foo f{10:CCCDDD}oo bar                             |
   4196                                                        |
   4197    ]],
   4198    }
   4199 
   4200    feed('/foo')
   4201    screen:expect {
   4202      grid = [[
   4203      {12:foo} {13:foo} {12:f}{10:AAA}{19:BBB}{12:oo} bar                             |
   4204      {12:foo} {12:foo} {12:f}{19:CCC}{10:DDD}{12:oo} bar                             |
   4205      /foo^                                              |
   4206    ]],
   4207    }
   4208 
   4209    api.nvim_buf_set_extmark(0, ns, 0, 13, { virt_text = { { 'EEE', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   4210    feed('<C-G>')
   4211    screen:expect {
   4212      grid = [[
   4213      {12:foo} {12:foo} {13:f}{10:AAA}{21:BBB}{13:oo} b{10:EEE}ar                          |
   4214      {12:foo} {12:foo} {12:f}{19:CCC}{10:DDD}{12:oo} bar                             |
   4215      /foo^                                              |
   4216    ]],
   4217    }
   4218  end)
   4219 
   4220  it('Visual select highlight is correct', function()
   4221    insert('foo foo foo bar\nfoo foo foo bar')
   4222    feed('gg0')
   4223    api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' })
   4224    api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   4225    api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   4226    api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' })
   4227    feed('8l')
   4228    screen:expect {
   4229      grid = [[
   4230      foo foo {10:AAABBB}^foo bar                             |
   4231      foo foo {10:CCCDDD}foo bar                             |
   4232                                                        |
   4233    ]],
   4234    }
   4235 
   4236    feed('<C-V>')
   4237    feed('2hj')
   4238    screen:expect {
   4239      grid = [[
   4240      foo fo{7:o }{10:AAA}{20:BBB}{7:f}oo bar                             |
   4241      foo fo^o{7: }{20:CCC}{10:DDD}{7:f}oo bar                             |
   4242      {8:-- VISUAL BLOCK --}                                |
   4243    ]],
   4244    }
   4245 
   4246    api.nvim_buf_set_extmark(0, ns, 0, 10, { virt_text = { { 'EEE', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   4247    screen:expect {
   4248      grid = [[
   4249      foo fo{7:o }{10:AAA}{20:BBB}{7:f}o{10:EEE}o bar                          |
   4250      foo fo^o{7: }{20:CCC}{10:DDD}{7:f}oo bar                             |
   4251      {8:-- VISUAL BLOCK --}                                |
   4252    ]],
   4253    }
   4254  end)
   4255 
   4256  it('inside highlight range of another extmark', function()
   4257    insert('foo foo foo bar\nfoo foo foo bar')
   4258    api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' })
   4259    api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   4260    api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   4261    api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' })
   4262    api.nvim_buf_set_extmark(0, ns, 0, 4, { end_col = 11, hl_group = 'Search' })
   4263    api.nvim_buf_set_extmark(0, ns, 1, 4, { end_col = 11, hl_group = 'Search' })
   4264    screen:expect {
   4265      grid = [[
   4266      foo {12:foo }{10:AAA}{19:BBB}{12:foo} bar                             |
   4267      foo {12:foo }{19:CCC}{10:DDD}{12:foo} ba^r                             |
   4268                                                        |
   4269    ]],
   4270    }
   4271  end)
   4272 
   4273  it('inside highlight range of syntax', function()
   4274    insert('foo foo foo bar\nfoo foo foo bar')
   4275    api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'AAA', 'Special' } }, virt_text_pos = 'inline' })
   4276    api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { 'BBB', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   4277    api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'CCC', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   4278    api.nvim_buf_set_extmark(0, ns, 1, 8, { virt_text = { { 'DDD', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' })
   4279    command([[syntax match Search 'foo \zsfoo foo\ze bar']])
   4280    screen:expect {
   4281      grid = [[
   4282      foo {12:foo }{10:AAA}{19:BBB}{12:foo} bar                             |
   4283      foo {12:foo }{19:CCC}{10:DDD}{12:foo} ba^r                             |
   4284                                                        |
   4285    ]],
   4286    }
   4287  end)
   4288 
   4289  it('cursor position is correct when inserting around a virtual text with left gravity', function()
   4290    screen:try_resize(27, 4)
   4291    insert(('a'):rep(15))
   4292    api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { ('>'):rep(43), 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
   4293    command('setlocal showbreak=+ breakindent breakindentopt=shift:2')
   4294    feed('08l')
   4295    screen:expect {
   4296      grid = [[
   4297      aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}|
   4298        {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}|
   4299        {1:+}^aaaaaaa                 |
   4300                                 |
   4301    ]],
   4302    }
   4303    feed('i')
   4304    screen:expect {
   4305      grid = [[
   4306      aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}|
   4307        {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}|
   4308        {1:+}^aaaaaaa                 |
   4309      {8:-- INSERT --}               |
   4310    ]],
   4311    }
   4312    feed([[<C-\><C-O>]])
   4313    screen:expect {
   4314      grid = [[
   4315      aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}|
   4316        {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}|
   4317        {1:+}^aaaaaaa                 |
   4318      {8:-- (insert) --}             |
   4319    ]],
   4320    }
   4321    feed('D')
   4322    screen:expect {
   4323      grid = [[
   4324      aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}|
   4325        {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}|
   4326      {1:^~                          }|
   4327      {8:-- INSERT --}               |
   4328    ]],
   4329    }
   4330    command('setlocal list listchars=eol:$')
   4331    screen:expect {
   4332      grid = [[
   4333      aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>}|
   4334        {1:+}{10:>>>>>>>>>>>>>>>>>>>>>>>>}|
   4335        {1:+^$}                       |
   4336      {8:-- INSERT --}               |
   4337    ]],
   4338    }
   4339    feed('<C-U>')
   4340    screen:expect {
   4341      grid = [[
   4342      {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>}|
   4343        {1:+}{10:>>>>>>>>>>>>>>>>}{1:^$}       |
   4344      {1:~                          }|
   4345      {8:-- INSERT --}               |
   4346    ]],
   4347    }
   4348    feed('a')
   4349    screen:expect {
   4350      grid = [[
   4351      {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>}|
   4352        {1:+}{10:>>>>>>>>>>>>>>>>}a{1:^$}      |
   4353      {1:~                          }|
   4354      {8:-- INSERT --}               |
   4355    ]],
   4356    }
   4357    feed('<Esc>')
   4358    screen:expect {
   4359      grid = [[
   4360      {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>}|
   4361        {1:+}{10:>>>>>>>>>>>>>>>>}^a{1:$}      |
   4362      {1:~                          }|
   4363                                 |
   4364    ]],
   4365    }
   4366    feed('x')
   4367    screen:expect {
   4368      grid = [[
   4369      {10:^>>>>>>>>>>>>>>>>>>>>>>>>>>>}|
   4370        {1:+}{10:>>>>>>>>>>>>>>>>}{1:$}       |
   4371      {1:~                          }|
   4372                                 |
   4373    ]],
   4374    }
   4375  end)
   4376 
   4377  it('cursor position is correct when inserting around virtual texts with both left and right gravity', function()
   4378    screen:try_resize(30, 4)
   4379    command('setlocal showbreak=+ breakindent breakindentopt=shift:2')
   4380    insert(('a'):rep(15))
   4381    api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { ('>'):rep(32), 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
   4382    api.nvim_buf_set_extmark(0, ns, 0, 8, { virt_text = { { ('<'):rep(32), 'Special' } }, virt_text_pos = 'inline', right_gravity = true })
   4383    feed('08l')
   4384    screen:expect {
   4385      grid = [[
   4386      aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}|
   4387        {1:+}{10:>>>>>>>>>><<<<<<<<<<<<<<<<<}|
   4388        {1:+}{10:<<<<<<<<<<<<<<<}^aaaaaaa     |
   4389                                    |
   4390    ]],
   4391    }
   4392    feed('i')
   4393    screen:expect {
   4394      grid = [[
   4395      aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}|
   4396        {1:+}{10:>>>>>>>>>>^<<<<<<<<<<<<<<<<<}|
   4397        {1:+}{10:<<<<<<<<<<<<<<<}aaaaaaa     |
   4398      {8:-- INSERT --}                  |
   4399    ]],
   4400    }
   4401    feed('a')
   4402    screen:expect {
   4403      grid = [[
   4404      aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}|
   4405        {1:+}{10:>>>>>>>>>>}a{10:^<<<<<<<<<<<<<<<<}|
   4406        {1:+}{10:<<<<<<<<<<<<<<<<}aaaaaaa    |
   4407      {8:-- INSERT --}                  |
   4408    ]],
   4409    }
   4410    feed([[<C-\><C-O>]])
   4411    screen:expect {
   4412      grid = [[
   4413      aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}|
   4414        {1:+}{10:>>>>>>>>>>}a{10:<<<<<<<<<<<<<<<<}|
   4415        {1:+}{10:<<<<<<<<<<<<<<<<}^aaaaaaa    |
   4416      {8:-- (insert) --}                |
   4417    ]],
   4418    }
   4419    feed('D')
   4420    screen:expect {
   4421      grid = [[
   4422      aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}|
   4423        {1:+}{10:>>>>>>>>>>}a{10:^<<<<<<<<<<<<<<<<}|
   4424        {1:+}{10:<<<<<<<<<<<<<<<<}           |
   4425      {8:-- INSERT --}                  |
   4426    ]],
   4427    }
   4428    feed('<BS>')
   4429    screen:expect {
   4430      grid = [[
   4431      aaaaaaaa{10:>>>>>>>>>>>>>>>>>>>>>>}|
   4432        {1:+}{10:>>>>>>>>>>^<<<<<<<<<<<<<<<<<}|
   4433        {1:+}{10:<<<<<<<<<<<<<<<}            |
   4434      {8:-- INSERT --}                  |
   4435    ]],
   4436    }
   4437    feed('<C-U>')
   4438    screen:expect {
   4439      grid = [[
   4440      {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}|
   4441        {1:+}{10:>>^<<<<<<<<<<<<<<<<<<<<<<<<<}|
   4442        {1:+}{10:<<<<<<<}                    |
   4443      {8:-- INSERT --}                  |
   4444    ]],
   4445    }
   4446    feed('a')
   4447    screen:expect {
   4448      grid = [[
   4449      {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}|
   4450        {1:+}{10:>>}a{10:^<<<<<<<<<<<<<<<<<<<<<<<<}|
   4451        {1:+}{10:<<<<<<<<}                   |
   4452      {8:-- INSERT --}                  |
   4453    ]],
   4454    }
   4455    feed('<Esc>')
   4456    screen:expect {
   4457      grid = [[
   4458      {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}|
   4459        {1:+}{10:>>}^a{10:<<<<<<<<<<<<<<<<<<<<<<<<}|
   4460        {1:+}{10:<<<<<<<<}                   |
   4461                                    |
   4462    ]],
   4463    }
   4464    feed('x')
   4465    screen:expect {
   4466      grid = [[
   4467      {10:^>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}|
   4468        {1:+}{10:>><<<<<<<<<<<<<<<<<<<<<<<<<}|
   4469        {1:+}{10:<<<<<<<}                    |
   4470                                    |
   4471    ]],
   4472    }
   4473    feed('i')
   4474    screen:expect {
   4475      grid = [[
   4476      {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}|
   4477        {1:+}{10:>>^<<<<<<<<<<<<<<<<<<<<<<<<<}|
   4478        {1:+}{10:<<<<<<<}                    |
   4479      {8:-- INSERT --}                  |
   4480    ]],
   4481    }
   4482    screen:try_resize(32, 4)
   4483    screen:expect {
   4484      grid = [[
   4485      {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}|
   4486        {1:+}{10:^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<}|
   4487        {1:+}{10:<<<}                          |
   4488      {8:-- INSERT --}                    |
   4489    ]],
   4490    }
   4491    command('setlocal nobreakindent')
   4492    screen:expect {
   4493      grid = [[
   4494      {10:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}|
   4495      {1:+}{10:^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<}|
   4496      {1:+}{10:<}                              |
   4497      {8:-- INSERT --}                    |
   4498    ]],
   4499    }
   4500  end)
   4501 
   4502  it('draws correctly with no wrap multiple virtual text, where one is hidden', function()
   4503    insert('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz')
   4504    command('set nowrap')
   4505    api.nvim_buf_set_extmark(0, ns, 0, 50, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
   4506    api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
   4507    feed('$')
   4508    screen:expect {
   4509      grid = [[
   4510      opqrstuvwxyzabcdefghijklmnopqrstuvwx{10:virtual text}y^z|
   4511      {1:~                                                 }|
   4512                                                        |
   4513    ]],
   4514    }
   4515  end)
   4516 
   4517  it('draws correctly with no wrap and a long virtual text', function()
   4518    insert('abcdefghi')
   4519    command('set nowrap')
   4520    api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' })
   4521    feed('$')
   4522    screen:expect([[
   4523      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i|
   4524      {1:~                                                 }|
   4525                                                        |
   4526    ]])
   4527    command('set list listchars+=precedes:!')
   4528    screen:expect([[
   4529      {1:!}{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i|
   4530      {1:~                                                 }|
   4531                                                        |
   4532    ]])
   4533  end)
   4534 
   4535  it('draws correctly with no wrap and multibyte virtual text', function()
   4536    insert('12345678')
   4537    command('set nowrap')
   4538    api.nvim_buf_set_extmark(0, ns, 0, 2, {
   4539      hl_mode = 'replace',
   4540      virt_text = { { 'α口β̳γ̲=', 'Special' }, { '❤️', 'Special' } },
   4541      virt_text_pos = 'inline',
   4542    })
   4543    screen:expect([[
   4544      12{10:α口β̳γ̲=❤️}34567^8                                  |
   4545      {1:~                                                 }|
   4546                                                        |
   4547    ]])
   4548    feed('zl')
   4549    screen:expect([[
   4550      2{10:α口β̳γ̲=❤️}34567^8                                   |
   4551      {1:~                                                 }|
   4552                                                        |
   4553    ]])
   4554    feed('zl')
   4555    screen:expect([[
   4556      {10:α口β̳γ̲=❤️}34567^8                                    |
   4557      {1:~                                                 }|
   4558                                                        |
   4559    ]])
   4560    feed('zl')
   4561    screen:expect([[
   4562      {10:口β̳γ̲=❤️}34567^8                                     |
   4563      {1:~                                                 }|
   4564                                                        |
   4565    ]])
   4566    feed('V')
   4567    screen:expect([[
   4568      {10:口β̳γ̲=❤️}{7:34567}^8                                     |
   4569      {1:~                                                 }|
   4570      {8:-- VISUAL LINE --}                                 |
   4571    ]])
   4572    command('set list listchars+=precedes:!')
   4573    screen:expect([[
   4574      {1:!<}{10:β̳γ̲=❤️}{7:34567}^8                                     |
   4575      {1:~                                                 }|
   4576      {8:-- VISUAL LINE --}                                 |
   4577    ]])
   4578    feed('zl')
   4579    screen:expect([[
   4580      {1:!}{10:β̳γ̲=❤️}{7:34567}^8                                      |
   4581      {1:~                                                 }|
   4582      {8:-- VISUAL LINE --}                                 |
   4583    ]])
   4584    command('set nolist')
   4585    screen:expect([[
   4586      {1:<}{10:β̳γ̲=❤️}{7:34567}^8                                      |
   4587      {1:~                                                 }|
   4588      {8:-- VISUAL LINE --}                                 |
   4589    ]])
   4590    feed('<Esc>')
   4591    screen:expect([[
   4592      {1:<}{10:β̳γ̲=❤️}34567^8                                      |
   4593      {1:~                                                 }|
   4594                                                        |
   4595    ]])
   4596    feed('zl')
   4597    screen:expect([[
   4598      {10:β̳γ̲=❤️}34567^8                                       |
   4599      {1:~                                                 }|
   4600                                                        |
   4601    ]])
   4602    feed('zl')
   4603    screen:expect([[
   4604      {10:γ̲=❤️}34567^8                                        |
   4605      {1:~                                                 }|
   4606                                                        |
   4607    ]])
   4608    feed('zl')
   4609    screen:expect([[
   4610      {10:=❤️}34567^8                                         |
   4611      {1:~                                                 }|
   4612                                                        |
   4613    ]])
   4614    feed('zl')
   4615    screen:expect([[
   4616      {10:❤️}34567^8                                          |
   4617      {1:~                                                 }|
   4618                                                        |
   4619    ]])
   4620    command('set list')
   4621    screen:expect([[
   4622      {1:!<}34567^8                                          |
   4623      {1:~                                                 }|
   4624                                                        |
   4625    ]])
   4626    feed('zl')
   4627    screen:expect([[
   4628      {1:!}34567^8                                           |
   4629      {1:~                                                 }|
   4630                                                        |
   4631    ]])
   4632    command('set nolist')
   4633    screen:expect([[
   4634      {1:<}34567^8                                           |
   4635      {1:~                                                 }|
   4636                                                        |
   4637    ]])
   4638    feed('zl')
   4639    screen:expect([[
   4640      34567^8                                            |
   4641      {1:~                                                 }|
   4642                                                        |
   4643    ]])
   4644    feed('zl')
   4645    screen:expect([[
   4646      4567^8                                             |
   4647      {1:~                                                 }|
   4648                                                        |
   4649    ]])
   4650  end)
   4651 
   4652  it('tabs are the correct length with no wrap following virtual text', function()
   4653    command('set nowrap')
   4654    feed('itest<TAB>a<ESC>')
   4655    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('a', 55), 'Special' } }, virt_text_pos = 'inline' })
   4656    feed('gg$')
   4657    screen:expect {
   4658      grid = [[
   4659      {10:aaaaaaaaaaaaaaaaaaaaaaaaa}test     ^a               |
   4660      {1:~                                                 }|
   4661                                                        |
   4662    ]],
   4663    }
   4664  end)
   4665 
   4666  it('highlighting does not extend with no wrap and a long virtual text', function()
   4667    insert('abcdef')
   4668    command('set nowrap')
   4669    api.nvim_buf_set_extmark(0, ns, 0, 3, { virt_text = { { string.rep('X', 50), 'Special' } }, virt_text_pos = 'inline' })
   4670    feed('$')
   4671    screen:expect {
   4672      grid = [[
   4673      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}de^f|
   4674      {1:~                                                 }|
   4675                                                        |
   4676    ]],
   4677    }
   4678  end)
   4679 
   4680  it('hidden virtual text does not interfere with Visual highlight', function()
   4681    insert('abcdef')
   4682    command('set nowrap')
   4683    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'XXX', 'Special' } }, virt_text_pos = 'inline' })
   4684    feed('V2zl')
   4685    screen:expect {
   4686      grid = [[
   4687      {10:X}{7:abcde}^f                                           |
   4688      {1:~                                                 }|
   4689      {8:-- VISUAL LINE --}                                 |
   4690    ]],
   4691    }
   4692    feed('zl')
   4693    screen:expect {
   4694      grid = [[
   4695      {7:abcde}^f                                            |
   4696      {1:~                                                 }|
   4697      {8:-- VISUAL LINE --}                                 |
   4698    ]],
   4699    }
   4700    feed('zl')
   4701    screen:expect {
   4702      grid = [[
   4703      {7:bcde}^f                                             |
   4704      {1:~                                                 }|
   4705      {8:-- VISUAL LINE --}                                 |
   4706    ]],
   4707    }
   4708  end)
   4709 
   4710  it('highlighting is correct when virtual text wraps with number', function()
   4711    screen:try_resize(50, 5)
   4712    insert([[
   4713    test
   4714    test]])
   4715    command('set number')
   4716    api.nvim_buf_set_extmark(0, ns, 0, 1, { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' })
   4717    feed('gg0')
   4718    screen:expect {
   4719      grid = [[
   4720      {2:  1 }^t{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4721      {2:    }{10:XXXXXXXXXX}est                                 |
   4722      {2:  2 }test                                          |
   4723      {1:~                                                 }|
   4724                                                        |
   4725    ]],
   4726    }
   4727  end)
   4728 
   4729  it('highlighting is correct when virtual text is proceeded with a match', function()
   4730    insert([[test]])
   4731    api.nvim_buf_set_extmark(0, ns, 0, 2, { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
   4732    feed('gg0')
   4733    command('match ErrorMsg /e/')
   4734    screen:expect {
   4735      grid = [[
   4736      ^t{4:e}{10:virtual text}st                                  |
   4737      {1:~                                                 }|
   4738                                                        |
   4739    ]],
   4740    }
   4741    command('match ErrorMsg /s/')
   4742    screen:expect {
   4743      grid = [[
   4744      ^te{10:virtual text}{4:s}t                                  |
   4745      {1:~                                                 }|
   4746                                                        |
   4747    ]],
   4748    }
   4749  end)
   4750 
   4751  it('smoothscroll works correctly when virtual text wraps', function()
   4752    insert('foobar')
   4753    api.nvim_buf_set_extmark(0, ns, 0, 3, { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' })
   4754    command('setlocal smoothscroll')
   4755    screen:expect {
   4756      grid = [[
   4757      foo{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
   4758      {10:XXXXXXXX}ba^r                                       |
   4759                                                        |
   4760    ]],
   4761    }
   4762    feed('<C-E>')
   4763    screen:expect {
   4764      grid = [[
   4765      {1:<<<}{10:XXXXX}ba^r                                       |
   4766      {1:~                                                 }|
   4767                                                        |
   4768    ]],
   4769    }
   4770  end)
   4771 
   4772  it('in diff mode is highlighted correct', function()
   4773    screen:try_resize(50, 10)
   4774    insert([[
   4775    9000
   4776    0009
   4777    0009
   4778    9000
   4779    0009
   4780    ]])
   4781    insert('aaa\tbbb')
   4782    command('set diff')
   4783    api.nvim_buf_set_extmark(0, ns, 0, 1, { virt_text = { { 'test', 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
   4784    api.nvim_buf_set_extmark(0, ns, 5, 0, { virt_text = { { '!', 'Special' } }, virt_text_pos = 'inline' })
   4785    api.nvim_buf_set_extmark(0, ns, 5, 3, { virt_text = { { '' } }, virt_text_pos = 'inline' })
   4786    command('vnew')
   4787    insert([[
   4788    000
   4789    000
   4790    000
   4791    000
   4792    000
   4793    ]])
   4794    insert('aaabbb')
   4795    command('set diff')
   4796    feed('gg0')
   4797    screen:expect {
   4798      grid = [[
   4799      {9:^000                      }│{5:9}{14:test}{9:000                }|
   4800      {9:000                      }│{9:000}{5:9}{9:                    }|*2
   4801      {9:000                      }│{5:9}{9:000                    }|
   4802      {9:000                      }│{9:000}{5:9}{9:                    }|
   4803      {9:aaabbb                   }│{14:!}{9:aaa}{5:    }{9:bbb             }|
   4804      {1:~                        }│{1:~                       }|*2
   4805      {15:[No Name] [+]             }{13:[No Name] [+]           }|
   4806                                                        |
   4807    ]],
   4808    }
   4809    command('wincmd w | set nowrap')
   4810    feed('zl')
   4811    screen:expect {
   4812      grid = [[
   4813      {9:000                      }│{14:test}{9:000                 }|
   4814      {9:000                      }│{9:00}{5:9}{9:                     }|*2
   4815      {9:000                      }│{9:000                     }|
   4816      {9:000                      }│{9:00}{5:9}{9:                     }|
   4817      {9:aaabbb                   }│{9:aaa}{5:    }{9:bb^b              }|
   4818      {1:~                        }│{1:~                       }|*2
   4819      {13:[No Name] [+]             }{15:[No Name] [+]           }|
   4820                                                        |
   4821    ]],
   4822    }
   4823  end)
   4824 
   4825  it('correctly draws when there are multiple overlapping virtual texts on the same line with nowrap', function()
   4826    command('set nowrap')
   4827    insert('a')
   4828    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('a', 55), 'Special' } }, virt_text_pos = 'inline' })
   4829    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('b', 55), 'Special' } }, virt_text_pos = 'inline' })
   4830    feed('$')
   4831    screen:expect {
   4832      grid = [[
   4833      {10:bbbbbbbbbbbbbbbbbbbbbbbbb}^a                        |
   4834      {1:~                                                 }|
   4835                                                        |
   4836    ]],
   4837    }
   4838  end)
   4839 
   4840  it('correctly draws when overflowing virtual text is followed by TAB with no wrap', function()
   4841    command('set nowrap')
   4842    feed('i<TAB>test<ESC>')
   4843    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { string.rep('a', 60), 'Special' } }, virt_text_pos = 'inline' })
   4844    feed('0')
   4845    screen:expect({
   4846      grid = [[
   4847      {10:aaaaaaaaaaaaaaaaaaaaaa}   ^ test                    |
   4848      {1:~                                                 }|
   4849                                                        |
   4850    ]],
   4851    })
   4852  end)
   4853 
   4854  it('does not crash at column 0 when folded in a wide window', function()
   4855    screen:try_resize(82, 5)
   4856    command('hi! CursorLine guibg=NONE guifg=Red gui=NONE')
   4857    command('set cursorline')
   4858    insert([[
   4859      aaaaa
   4860      bbbbb
   4861 
   4862      ccccc]])
   4863    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'foo' } }, virt_text_pos = 'inline' })
   4864    api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { 'bar' } }, virt_text_pos = 'inline' })
   4865    screen:expect {
   4866      grid = [[
   4867      fooaaaaa                                                                          |
   4868      bbbbb                                                                             |
   4869      bar                                                                               |
   4870      {16:cccc^c                                                                             }|
   4871                                                                                        |
   4872    ]],
   4873    }
   4874    command('1,2fold')
   4875    screen:expect {
   4876      grid = [[
   4877      {17:+--  2 lines: aaaaa·······························································}|
   4878      bar                                                                               |
   4879      {16:cccc^c                                                                             }|
   4880      {1:~                                                                                 }|
   4881                                                                                        |
   4882    ]],
   4883    }
   4884    feed('2k')
   4885    screen:expect {
   4886      grid = [[
   4887      {18:^+--  2 lines: aaaaa·······························································}|
   4888      bar                                                                               |
   4889      ccccc                                                                             |
   4890      {1:~                                                                                 }|
   4891                                                                                        |
   4892    ]],
   4893    }
   4894    command('3,4fold')
   4895    screen:expect {
   4896      grid = [[
   4897      {18:^+--  2 lines: aaaaa·······························································}|
   4898      {17:+--  2 lines: ccccc·······························································}|
   4899      {1:~                                                                                 }|*2
   4900                                                                                        |
   4901    ]],
   4902    }
   4903    feed('j')
   4904    screen:expect {
   4905      grid = [[
   4906      {17:+--  2 lines: aaaaa·······························································}|
   4907      {18:^+--  2 lines: ccccc·······························································}|
   4908      {1:~                                                                                 }|*2
   4909                                                                                        |
   4910    ]],
   4911    }
   4912  end)
   4913 
   4914  it('does not crash at right edge of wide window #23848', function()
   4915    screen:try_resize(82, 5)
   4916    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { ('a'):rep(82) }, { 'b' } }, virt_text_pos = 'inline' })
   4917    screen:expect {
   4918      grid = [[
   4919      ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
   4920      b                                                                                 |
   4921      {1:~                                                                                 }|*2
   4922                                                                                        |
   4923    ]],
   4924    }
   4925    command('set nowrap')
   4926    screen:expect {
   4927      grid = [[
   4928      ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
   4929      {1:~                                                                                 }|*3
   4930                                                                                        |
   4931    ]],
   4932    }
   4933    feed('82i0<Esc>0')
   4934    screen:expect {
   4935      grid = [[
   4936      ^0000000000000000000000000000000000000000000000000000000000000000000000000000000000|
   4937      {1:~                                                                                 }|*3
   4938                                                                                        |
   4939    ]],
   4940    }
   4941    command('set wrap')
   4942    screen:expect {
   4943      grid = [[
   4944      ^0000000000000000000000000000000000000000000000000000000000000000000000000000000000|
   4945      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
   4946      b                                                                                 |
   4947      {1:~                                                                                 }|
   4948                                                                                        |
   4949    ]],
   4950    }
   4951  end)
   4952 
   4953  it('lcs-extends is drawn with inline virtual text at end of screen line', function()
   4954    exec([[
   4955      setlocal nowrap list listchars=extends:!
   4956      call setline(1, repeat('a', 51))
   4957    ]])
   4958    api.nvim_buf_set_extmark(0, ns, 0, 50, { virt_text = { { 'bbb', 'Special' } }, virt_text_pos = 'inline' })
   4959    feed('20l')
   4960    screen:expect {
   4961      grid = [[
   4962      aaaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:!}|
   4963      {1:~                                                 }|
   4964                                                        |
   4965    ]],
   4966    }
   4967    feed('zl')
   4968    screen:expect {
   4969      grid = [[
   4970      aaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:!}|
   4971      {1:~                                                 }|
   4972                                                        |
   4973    ]],
   4974    }
   4975    feed('zl')
   4976    screen:expect {
   4977      grid = [[
   4978      aaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:b}{1:!}|
   4979      {1:~                                                 }|
   4980                                                        |
   4981    ]],
   4982    }
   4983    feed('zl')
   4984    screen:expect {
   4985      grid = [[
   4986      aaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bb}{1:!}|
   4987      {1:~                                                 }|
   4988                                                        |
   4989    ]],
   4990    }
   4991    feed('zl')
   4992    screen:expect {
   4993      grid = [[
   4994      aaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{10:bbb}a|
   4995      {1:~                                                 }|
   4996                                                        |
   4997    ]],
   4998    }
   4999  end)
   5000 
   5001  it('lcs-extends is drawn with only inline virtual text offscreen', function()
   5002    command('set nowrap')
   5003    command('set list')
   5004    command('set listchars+=extends:c')
   5005    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'test', 'Special' } }, virt_text_pos = 'inline' })
   5006    insert(string.rep('a', 50))
   5007    feed('gg0')
   5008    screen:expect {
   5009      grid = [[
   5010      ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:c}|
   5011      {1:~                                                 }|
   5012                                                        |
   5013    ]],
   5014    }
   5015  end)
   5016 
   5017  it('blockwise Visual highlight with double-width virtual text (replace)', function()
   5018    screen:try_resize(60, 6)
   5019    insert('123456789\n123456789\n123456789\n123456789')
   5020    api.nvim_buf_set_extmark(0, ns, 1, 1, { virt_text = { { '-口-', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' })
   5021    api.nvim_buf_set_extmark(0, ns, 2, 2, { virt_text = { { '口', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'replace' })
   5022    feed('gg0')
   5023    screen:expect {
   5024      grid = [[
   5025      ^123456789                                                   |
   5026      1{10:-口-}23456789                                               |
   5027      12{10:口}3456789                                                 |
   5028      123456789                                                   |
   5029      {1:~                                                           }|
   5030                                                                  |
   5031    ]],
   5032    }
   5033    feed('<C-V>3jl')
   5034    screen:expect {
   5035      grid = [[
   5036      {7:12}3456789                                                   |
   5037      {7:1}{10:-口-}23456789                                               |
   5038      {7:12}{10:口}3456789                                                 |
   5039      {7:1}^23456789                                                   |
   5040      {1:~                                                           }|
   5041      {8:-- VISUAL BLOCK --}                                          |
   5042    ]],
   5043    }
   5044    feed('l')
   5045    screen:expect {
   5046      grid = [[
   5047      {7:123}456789                                                   |
   5048      {7:1}{10:-口-}23456789                                               |
   5049      {7:12}{10:口}3456789                                                 |
   5050      {7:12}^3456789                                                   |
   5051      {1:~                                                           }|
   5052      {8:-- VISUAL BLOCK --}                                          |
   5053    ]],
   5054    }
   5055    feed('4l')
   5056    screen:expect {
   5057      grid = [[
   5058      {7:1234567}89                                                   |
   5059      {7:1}{10:-口-}{7:23}456789                                               |
   5060      {7:12}{10:口}{7:345}6789                                                 |
   5061      {7:123456}^789                                                   |
   5062      {1:~                                                           }|
   5063      {8:-- VISUAL BLOCK --}                                          |
   5064    ]],
   5065    }
   5066    feed('Ol')
   5067    screen:expect {
   5068      grid = [[
   5069      1{7:234567}89                                                   |
   5070      1{10:-口-}{7:23}456789                                               |
   5071      1{7:2}{10:口}{7:345}6789                                                 |
   5072      1^2{7:34567}89                                                   |
   5073      {1:~                                                           }|
   5074      {8:-- VISUAL BLOCK --}                                          |
   5075    ]],
   5076    }
   5077    feed('l')
   5078    screen:expect {
   5079      grid = [[
   5080      12{7:34567}89                                                   |
   5081      1{10:-口-}{7:23}456789                                               |
   5082      12{10:口}{7:345}6789                                                 |
   5083      12^3{7:4567}89                                                   |
   5084      {1:~                                                           }|
   5085      {8:-- VISUAL BLOCK --}                                          |
   5086    ]],
   5087    }
   5088    feed('l')
   5089    screen:expect {
   5090      grid = [[
   5091      123{7:4567}89                                                   |
   5092      1{10:-口-}{7:23}456789                                               |
   5093      12{10:口}{7:345}6789                                                 |
   5094      123^4{7:567}89                                                   |
   5095      {1:~                                                           }|
   5096      {8:-- VISUAL BLOCK --}                                          |
   5097    ]],
   5098    }
   5099  end)
   5100 
   5101  it('blockwise Visual highlight with double-width virtual text (combine)', function()
   5102    screen:try_resize(60, 6)
   5103    insert('123456789\n123456789\n123456789\n123456789')
   5104    api.nvim_buf_set_extmark(0, ns, 1, 1, { virt_text = { { '-口-', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   5105    api.nvim_buf_set_extmark(0, ns, 2, 2, { virt_text = { { '口', 'Special' } }, virt_text_pos = 'inline', hl_mode = 'combine' })
   5106    feed('gg0')
   5107    screen:expect {
   5108      grid = [[
   5109      ^123456789                                                   |
   5110      1{10:-口-}23456789                                               |
   5111      12{10:口}3456789                                                 |
   5112      123456789                                                   |
   5113      {1:~                                                           }|
   5114                                                                  |
   5115    ]],
   5116    }
   5117    feed('<C-V>3jl')
   5118    screen:expect {
   5119      grid = [[
   5120      {7:12}3456789                                                   |
   5121      {7:1}{20:-}{10:口-}23456789                                               |
   5122      {7:12}{10:口}3456789                                                 |
   5123      {7:1}^23456789                                                   |
   5124      {1:~                                                           }|
   5125      {8:-- VISUAL BLOCK --}                                          |
   5126    ]],
   5127    }
   5128    feed('l')
   5129    screen:expect {
   5130      grid = [[
   5131      {7:123}456789                                                   |
   5132      {7:1}{20:-口}{10:-}23456789                                               |
   5133      {7:12}{20:口}3456789                                                 |
   5134      {7:12}^3456789                                                   |
   5135      {1:~                                                           }|
   5136      {8:-- VISUAL BLOCK --}                                          |
   5137    ]],
   5138    }
   5139    feed('4l')
   5140    screen:expect {
   5141      grid = [[
   5142      {7:1234567}89                                                   |
   5143      {7:1}{20:-口-}{7:23}456789                                               |
   5144      {7:12}{20:口}{7:345}6789                                                 |
   5145      {7:123456}^789                                                   |
   5146      {1:~                                                           }|
   5147      {8:-- VISUAL BLOCK --}                                          |
   5148    ]],
   5149    }
   5150    feed('Ol')
   5151    screen:expect {
   5152      grid = [[
   5153      1{7:234567}89                                                   |
   5154      1{20:-口-}{7:23}456789                                               |
   5155      1{7:2}{20:口}{7:345}6789                                                 |
   5156      1^2{7:34567}89                                                   |
   5157      {1:~                                                           }|
   5158      {8:-- VISUAL BLOCK --}                                          |
   5159    ]],
   5160    }
   5161    feed('l')
   5162    screen:expect {
   5163      grid = [[
   5164      12{7:34567}89                                                   |
   5165      1{10:-}{20:口-}{7:23}456789                                               |
   5166      12{20:口}{7:345}6789                                                 |
   5167      12^3{7:4567}89                                                   |
   5168      {1:~                                                           }|
   5169      {8:-- VISUAL BLOCK --}                                          |
   5170    ]],
   5171    }
   5172    feed('l')
   5173    screen:expect {
   5174      grid = [[
   5175      123{7:4567}89                                                   |
   5176      1{10:-}{20:口-}{7:23}456789                                               |
   5177      12{20:口}{7:345}6789                                                 |
   5178      123^4{7:567}89                                                   |
   5179      {1:~                                                           }|
   5180      {8:-- VISUAL BLOCK --}                                          |
   5181    ]],
   5182    }
   5183  end)
   5184 
   5185  local function test_virt_inline_showbreak_smoothscroll()
   5186    screen:try_resize(30, 6)
   5187    exec([[
   5188      highlight! link LineNr Normal
   5189      setlocal number showbreak=+ breakindent breakindentopt=shift:2
   5190      setlocal scrolloff=0 smoothscroll
   5191      call setline(1, repeat('a', 28))
   5192      normal! $
   5193    ]])
   5194    api.nvim_buf_set_extmark(0, ns, 0, 27, { virt_text = { { ('123'):rep(23) } }, virt_text_pos = 'inline' })
   5195    feed(':<CR>') -- Have a screen line that doesn't start with spaces
   5196    screen:expect {
   5197      grid = [[
   5198        1 aaaaaaaaaaaaaaaaaaaaaaaaaa|
   5199            {1:+}a1231231231231231231231|
   5200            {1:+}23123123123123123123123|
   5201            {1:+}12312312312312312312312|
   5202            {1:+}3^a                     |
   5203      :                             |
   5204    ]],
   5205    }
   5206    feed('<C-E>')
   5207    screen:expect {
   5208      grid = [[
   5209            {1:+}a1231231231231231231231|
   5210            {1:+}23123123123123123123123|
   5211            {1:+}12312312312312312312312|
   5212            {1:+}3^a                     |
   5213      {1:~                             }|
   5214      :                             |
   5215    ]],
   5216    }
   5217    feed('<C-E>')
   5218    screen:expect {
   5219      grid = [[
   5220            {1:+}23123123123123123123123|
   5221            {1:+}12312312312312312312312|
   5222            {1:+}3^a                     |
   5223      {1:~                             }|*2
   5224      :                             |
   5225    ]],
   5226    }
   5227    feed('<C-E>')
   5228    screen:expect {
   5229      grid = [[
   5230            {1:+}12312312312312312312312|
   5231            {1:+}3^a                     |
   5232      {1:~                             }|*3
   5233      :                             |
   5234    ]],
   5235    }
   5236    feed('<C-E>')
   5237    screen:expect {
   5238      grid = [[
   5239            {1:+}3^a                     |
   5240      {1:~                             }|*4
   5241      :                             |
   5242    ]],
   5243    }
   5244    feed('zbi')
   5245    screen:expect {
   5246      grid = [[
   5247        1 aaaaaaaaaaaaaaaaaaaaaaaaaa|
   5248            {1:+}a^1231231231231231231231|
   5249            {1:+}23123123123123123123123|
   5250            {1:+}12312312312312312312312|
   5251            {1:+}3a                     |
   5252      {8:-- INSERT --}                  |
   5253    ]],
   5254    }
   5255    feed('<BS>')
   5256    screen:expect {
   5257      grid = [[
   5258        1 aaaaaaaaaaaaaaaaaaaaaaaaaa|
   5259            {1:+}^12312312312312312312312|
   5260            {1:+}31231231231231231231231|
   5261            {1:+}23123123123123123123123|
   5262            {1:+}a                      |
   5263      {8:-- INSERT --}                  |
   5264    ]],
   5265    }
   5266    feed('<Esc>l')
   5267    feed(':<CR>') -- Have a screen line that doesn't start with spaces
   5268    screen:expect {
   5269      grid = [[
   5270        1 aaaaaaaaaaaaaaaaaaaaaaaaaa|
   5271            {1:+}12312312312312312312312|
   5272            {1:+}31231231231231231231231|
   5273            {1:+}23123123123123123123123|
   5274            {1:+}^a                      |
   5275      :                             |
   5276    ]],
   5277    }
   5278    feed('<C-E>')
   5279    screen:expect {
   5280      grid = [[
   5281            {1:+}12312312312312312312312|
   5282            {1:+}31231231231231231231231|
   5283            {1:+}23123123123123123123123|
   5284            {1:+}^a                      |
   5285      {1:~                             }|
   5286      :                             |
   5287    ]],
   5288    }
   5289    feed('<C-E>')
   5290    screen:expect {
   5291      grid = [[
   5292            {1:+}31231231231231231231231|
   5293            {1:+}23123123123123123123123|
   5294            {1:+}^a                      |
   5295      {1:~                             }|*2
   5296      :                             |
   5297    ]],
   5298    }
   5299    feed('<C-E>')
   5300    screen:expect {
   5301      grid = [[
   5302            {1:+}23123123123123123123123|
   5303            {1:+}^a                      |
   5304      {1:~                             }|*3
   5305      :                             |
   5306    ]],
   5307    }
   5308    feed('<C-E>')
   5309    screen:expect {
   5310      grid = [[
   5311            {1:+}^a                      |
   5312      {1:~                             }|*4
   5313      :                             |
   5314    ]],
   5315    }
   5316    feed('023x$')
   5317    screen:expect {
   5318      grid = [[
   5319        1 aaa12312312312312312312312|
   5320            {1:+}31231231231231231231231|
   5321            {1:+}23123123123123123123123|
   5322            {1:+}^a                      |
   5323      {1:~                             }|
   5324      :                             |
   5325    ]],
   5326    }
   5327    feed('<C-E>')
   5328    screen:expect {
   5329      grid = [[
   5330            {1:+}31231231231231231231231|
   5331            {1:+}23123123123123123123123|
   5332            {1:+}^a                      |
   5333      {1:~                             }|*2
   5334      :                             |
   5335    ]],
   5336    }
   5337    feed('<C-E>')
   5338    screen:expect {
   5339      grid = [[
   5340            {1:+}23123123123123123123123|
   5341            {1:+}^a                      |
   5342      {1:~                             }|*3
   5343      :                             |
   5344    ]],
   5345    }
   5346    feed('<C-E>')
   5347    screen:expect {
   5348      grid = [[
   5349            {1:+}^a                      |
   5350      {1:~                             }|*4
   5351      :                             |
   5352    ]],
   5353    }
   5354    feed('zbi')
   5355    screen:expect {
   5356      grid = [[
   5357        1 aaa^12312312312312312312312|
   5358            {1:+}31231231231231231231231|
   5359            {1:+}23123123123123123123123|
   5360            {1:+}a                      |
   5361      {1:~                             }|
   5362      {8:-- INSERT --}                  |
   5363    ]],
   5364    }
   5365    feed('<C-U>')
   5366    screen:expect {
   5367      grid = [[
   5368        1 ^12312312312312312312312312|
   5369            {1:+}31231231231231231231231|
   5370            {1:+}23123123123123123123a  |
   5371      {1:~                             }|*2
   5372      {8:-- INSERT --}                  |
   5373    ]],
   5374    }
   5375    feed('<Esc>')
   5376    screen:expect {
   5377      grid = [[
   5378        1 12312312312312312312312312|
   5379            {1:+}31231231231231231231231|
   5380            {1:+}23123123123123123123^a  |
   5381      {1:~                             }|*2
   5382                                    |
   5383    ]],
   5384    }
   5385    feed('<C-E>')
   5386    screen:expect {
   5387      grid = [[
   5388            {1:+}31231231231231231231231|
   5389            {1:+}23123123123123123123^a  |
   5390      {1:~                             }|*3
   5391                                    |
   5392    ]],
   5393    }
   5394    feed('<C-E>')
   5395    screen:expect {
   5396      grid = [[
   5397            {1:+}23123123123123123123^a  |
   5398      {1:~                             }|*4
   5399                                    |
   5400    ]],
   5401    }
   5402    feed('zbx')
   5403    screen:expect {
   5404      grid = [[
   5405        1 ^12312312312312312312312312|
   5406            {1:+}31231231231231231231231|
   5407            {1:+}23123123123123123123   |
   5408      {1:~                             }|*2
   5409                                    |
   5410    ]],
   5411    }
   5412    feed('26ia<Esc>a')
   5413    screen:expect {
   5414      grid = [[
   5415        1 aaaaaaaaaaaaaaaaaaaaaaaaaa|
   5416            {1:+}^12312312312312312312312|
   5417            {1:+}31231231231231231231231|
   5418            {1:+}23123123123123123123123|
   5419      {1:~                             }|
   5420      {8:-- INSERT --}                  |
   5421    ]],
   5422    }
   5423    feed([[<C-\><C-O>:setlocal breakindentopt=<CR>]])
   5424    screen:expect {
   5425      grid = [[
   5426        1 aaaaaaaaaaaaaaaaaaaaaaaaaa|
   5427          {1:+}^1231231231231231231231231|
   5428          {1:+}2312312312312312312312312|
   5429          {1:+}3123123123123123123      |
   5430      {1:~                             }|
   5431      {8:-- INSERT --}                  |
   5432    ]],
   5433    }
   5434  end
   5435 
   5436  describe('with showbreak, smoothscroll', function()
   5437    it('and cpoptions-=n', function()
   5438      test_virt_inline_showbreak_smoothscroll()
   5439    end)
   5440 
   5441    it('and cpoptions+=n', function()
   5442      command('set cpoptions+=n')
   5443      -- because of 'breakindent' the screen states are the same
   5444      test_virt_inline_showbreak_smoothscroll()
   5445    end)
   5446  end)
   5447 
   5448  it('before TABs with smoothscroll', function()
   5449    screen:try_resize(30, 6)
   5450    exec([[
   5451      setlocal list listchars=tab:<-> scrolloff=0 smoothscroll
   5452      call setline(1, repeat("\t", 4) .. 'a')
   5453      normal! $
   5454    ]])
   5455    api.nvim_buf_set_extmark(0, ns, 0, 3, { virt_text = { { ('12'):rep(32) } }, virt_text_pos = 'inline' })
   5456    screen:expect {
   5457      grid = [[
   5458      {1:<------><------><------>}121212|
   5459      121212121212121212121212121212|
   5460      1212121212121212121212121212{1:<-}|
   5461      {1:----->}^a                       |
   5462      {1:~                             }|
   5463                                    |
   5464    ]],
   5465    }
   5466    feed('<C-E>')
   5467    screen:expect {
   5468      grid = [[
   5469      {1:<<<}212121212121212121212121212|
   5470      1212121212121212121212121212{1:<-}|
   5471      {1:----->}^a                       |
   5472      {1:~                             }|*2
   5473                                    |
   5474    ]],
   5475    }
   5476    feed('<C-E>')
   5477    screen:expect {
   5478      grid = [[
   5479      {1:<<<}2121212121212121212121212{1:<-}|
   5480      {1:----->}^a                       |
   5481      {1:~                             }|*3
   5482                                    |
   5483    ]],
   5484    }
   5485    feed('<C-E>')
   5486    screen:expect {
   5487      grid = [[
   5488      {1:<<<-->}^a                       |
   5489      {1:~                             }|*4
   5490                                    |
   5491    ]],
   5492    }
   5493    feed('zbh')
   5494    screen:expect {
   5495      grid = [[
   5496      {1:<------><------><------>}121212|
   5497      121212121212121212121212121212|
   5498      1212121212121212121212121212{1:^<-}|
   5499      {1:----->}a                       |
   5500      {1:~                             }|
   5501                                    |
   5502    ]],
   5503    }
   5504    feed('i')
   5505    screen:expect {
   5506      grid = [[
   5507      {1:<------><------><------>}^121212|
   5508      121212121212121212121212121212|
   5509      1212121212121212121212121212{1:<-}|
   5510      {1:----->}a                       |
   5511      {1:~                             }|
   5512      {8:-- INSERT --}                  |
   5513    ]],
   5514    }
   5515    feed('<C-O>:setlocal nolist<CR>')
   5516    screen:expect {
   5517      grid = [[
   5518                              ^121212|
   5519      121212121212121212121212121212|
   5520      1212121212121212121212121212  |
   5521            a                       |
   5522      {1:~                             }|
   5523      {8:-- INSERT --}                  |
   5524    ]],
   5525    }
   5526    feed('<Esc>l')
   5527    screen:expect {
   5528      grid = [[
   5529                              121212|
   5530      121212121212121212121212121212|
   5531      1212121212121212121212121212  |
   5532           ^ a                       |
   5533      {1:~                             }|
   5534                                    |
   5535    ]],
   5536    }
   5537    feed('<C-E>')
   5538    screen:expect {
   5539      grid = [[
   5540      {1:<<<}212121212121212121212121212|
   5541      1212121212121212121212121212  |
   5542           ^ a                       |
   5543      {1:~                             }|*2
   5544                                    |
   5545    ]],
   5546    }
   5547    feed('<C-E>')
   5548    screen:expect {
   5549      grid = [[
   5550      {1:<<<}2121212121212121212121212  |
   5551           ^ a                       |
   5552      {1:~                             }|*3
   5553                                    |
   5554    ]],
   5555    }
   5556    feed('<C-E>')
   5557    screen:expect {
   5558      grid = [[
   5559      {1:<<<}  ^ a                       |
   5560      {1:~                             }|*4
   5561                                    |
   5562    ]],
   5563    }
   5564  end)
   5565 
   5566  it('before a space with linebreak', function()
   5567    screen:try_resize(50, 6)
   5568    exec([[
   5569      setlocal linebreak showbreak=+ breakindent breakindentopt=shift:2
   5570      call setline(1, repeat('a', 50) .. ' ' .. repeat('c', 45))
   5571      normal! $
   5572    ]])
   5573    api.nvim_buf_set_extmark(0, ns, 0, 50, { virt_text = { { ('b'):rep(10) } }, virt_text_pos = 'inline' })
   5574    screen:expect {
   5575      grid = [[
   5576      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
   5577        {1:+}bbbbbbbbbb                                     |
   5578        {1:+}cccccccccccccccccccccccccccccccccccccccccccc^c  |
   5579      {1:~                                                 }|*2
   5580                                                        |
   5581    ]],
   5582    }
   5583    feed('05x$')
   5584    screen:expect {
   5585      grid = [[
   5586      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb|
   5587        {1:+}bbbbb                                          |
   5588        {1:+}cccccccccccccccccccccccccccccccccccccccccccc^c  |
   5589      {1:~                                                 }|*2
   5590                                                        |
   5591    ]],
   5592    }
   5593  end)
   5594 
   5595  it('before double-width char that wraps', function()
   5596    exec([[
   5597      call setline(1, repeat('a', 40) .. '口' .. '12345')
   5598      normal! $
   5599    ]])
   5600    api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { ('b'):rep(9) } }, virt_text_pos = 'inline' })
   5601    screen:expect([[
   5602      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}|
   5603      1234^5                                           |
   5604                                                        |
   5605    ]])
   5606    feed('g0')
   5607    screen:expect([[
   5608      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}|
   5609      ^12345                                           |
   5610                                                        |
   5611    ]])
   5612    command('set showbreak=+++')
   5613    screen:expect([[
   5614      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}|
   5615      {1:+++}^12345                                        |
   5616                                                        |
   5617    ]])
   5618  end)
   5619 
   5620  it('cursor position is correct if end_row or end_col is specified', function()
   5621    screen:try_resize(50, 8)
   5622    api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48), ('c'):rep(48), ('d'):rep(48) })
   5623    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 2, virt_text_pos = 'inline', virt_text = { { 'I1', 'NonText' } } })
   5624    api.nvim_buf_set_extmark(0, ns, 3, 0, { end_col = 2, virt_text_pos = 'inline', virt_text = { { 'I2', 'NonText' } } })
   5625    feed('$')
   5626    screen:expect([[
   5627      {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^a|
   5628      bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb  |
   5629      cccccccccccccccccccccccccccccccccccccccccccccccc  |
   5630      {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd|
   5631      {1:~                                                 }|*3
   5632                                                        |
   5633    ]])
   5634    feed('j')
   5635    screen:expect([[
   5636      {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
   5637      bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b  |
   5638      cccccccccccccccccccccccccccccccccccccccccccccccc  |
   5639      {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd|
   5640      {1:~                                                 }|*3
   5641                                                        |
   5642    ]])
   5643    feed('j')
   5644    screen:expect([[
   5645      {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
   5646      bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb  |
   5647      ccccccccccccccccccccccccccccccccccccccccccccccc^c  |
   5648      {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd|
   5649      {1:~                                                 }|*3
   5650                                                        |
   5651    ]])
   5652    feed('j')
   5653    screen:expect([[
   5654      {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
   5655      bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb  |
   5656      cccccccccccccccccccccccccccccccccccccccccccccccc  |
   5657      {1:I2}ddddddddddddddddddddddddddddddddddddddddddddddd^d|
   5658      {1:~                                                 }|*3
   5659                                                        |
   5660    ]])
   5661  end)
   5662 
   5663  it('is redrawn correctly after delete or redo #27370', function()
   5664    screen:try_resize(50, 12)
   5665    exec([[
   5666      call setline(1, ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff'])
   5667      call setline(3, repeat('c', winwidth(0) - 1))
   5668    ]])
   5669    api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { '!!!' } }, virt_text_pos = 'inline' })
   5670    feed('j')
   5671    local before_delete = [[
   5672      aaa                                               |
   5673      !!!^bbb                                            |
   5674      ccccccccccccccccccccccccccccccccccccccccccccccccc |
   5675      ddd                                               |
   5676      eee                                               |
   5677      fff                                               |
   5678      {1:~                                                 }|*5
   5679                                                        |
   5680    ]]
   5681    screen:expect(before_delete)
   5682    feed('dd')
   5683    local after_delete = [[
   5684      aaa                                               |
   5685      !!!^ccccccccccccccccccccccccccccccccccccccccccccccc|
   5686      cc                                                |
   5687      ddd                                               |
   5688      eee                                               |
   5689      fff                                               |
   5690      {1:~                                                 }|*5
   5691                                                        |
   5692    ]]
   5693    screen:expect(after_delete)
   5694    command('silent undo')
   5695    screen:expect(before_delete)
   5696    command('silent redo')
   5697    screen:expect(after_delete)
   5698    command('silent undo')
   5699    screen:expect(before_delete)
   5700    command('set report=100')
   5701    feed('yypk2P')
   5702    before_delete = [[
   5703      aaa                                               |
   5704      ^bbb                                               |
   5705      bbb                                               |
   5706      !!!bbb                                            |
   5707      bbb                                               |
   5708      ccccccccccccccccccccccccccccccccccccccccccccccccc |
   5709      ddd                                               |
   5710      eee                                               |
   5711      fff                                               |
   5712      {1:~                                                 }|*2
   5713                                                        |
   5714    ]]
   5715    screen:expect(before_delete)
   5716    feed('4dd')
   5717    screen:expect(after_delete)
   5718    command('silent undo')
   5719    screen:expect(before_delete)
   5720    command('silent redo')
   5721    screen:expect(after_delete)
   5722  end)
   5723 
   5724  it('cursor position is correct with invalidated inline virt text', function()
   5725    screen:try_resize(50, 8)
   5726    api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48) })
   5727    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text_pos = 'inline', virt_text = { { 'INLINE', 'NonText' } }, invalidate = true })
   5728    screen:expect([[
   5729      {1:INLINE}^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
   5730      aaaa                                              |
   5731      bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb  |
   5732      {1:~                                                 }|*4
   5733                                                        |
   5734    ]])
   5735    feed('dd$')
   5736    screen:expect([[
   5737      bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b  |
   5738      {1:~                                                 }|*6
   5739                                                        |
   5740    ]])
   5741  end)
   5742 
   5743  it('line size is correct with inline virt text at EOL and showbreak', function()
   5744    screen:try_resize(50, 8)
   5745    insert(('0123456789'):rep(5) .. '\nfoo\nbar')
   5746    api.nvim_buf_set_extmark(0, ns, 0, 50, { virt_text = { { ('x'):rep(145), 'ErrorMsg' } }, virt_text_pos = 'inline' })
   5747 
   5748    command([[set cursorline scrolloff=0 showbreak=>\  smoothscroll]])
   5749    screen:expect([[
   5750      01234567890123456789012345678901234567890123456789|
   5751      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
   5752      {1:> }{4:x}                                               |
   5753      foo                                               |
   5754      {22:ba^r                                               }|
   5755                                                        |
   5756    ]])
   5757    eq(5, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all)
   5758    feed('<C-E>')
   5759    screen:expect([[
   5760      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
   5761      {1:> }{4:x}                                               |
   5762      foo                                               |
   5763      {22:ba^r                                               }|
   5764      {1:~                                                 }|
   5765                                                        |
   5766    ]])
   5767    feed('<C-E>')
   5768    screen:expect([[
   5769      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2
   5770      {1:> }{4:x}                                               |
   5771      foo                                               |
   5772      {22:ba^r                                               }|
   5773      {1:~                                                 }|*2
   5774                                                        |
   5775    ]])
   5776    feed('<C-E>')
   5777    screen:expect([[
   5778      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|
   5779      {1:> }{4:x}                                               |
   5780      foo                                               |
   5781      {22:ba^r                                               }|
   5782      {1:~                                                 }|*3
   5783                                                        |
   5784    ]])
   5785    feed('<C-E>')
   5786    screen:expect([[
   5787      {1:> }{4:x}                                               |
   5788      foo                                               |
   5789      {22:ba^r                                               }|
   5790      {1:~                                                 }|*4
   5791                                                        |
   5792    ]])
   5793    feed('<C-E>')
   5794    screen:expect([[
   5795      foo                                               |
   5796      {22:ba^r                                               }|
   5797      {1:~                                                 }|*5
   5798                                                        |
   5799    ]])
   5800 
   5801    feed('gg$xG$')
   5802    screen:expect([[
   5803      0123456789012345678901234567890123456789012345678{4:x}|
   5804      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
   5805      foo                                               |
   5806      {22:ba^r                                               }|
   5807      {1:~                                                 }|
   5808                                                        |
   5809    ]])
   5810    eq(4, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all)
   5811    feed('<C-E>')
   5812    screen:expect([[
   5813      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
   5814      foo                                               |
   5815      {22:ba^r                                               }|
   5816      {1:~                                                 }|*2
   5817                                                        |
   5818    ]])
   5819    feed('<C-E>')
   5820    screen:expect([[
   5821      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2
   5822      foo                                               |
   5823      {22:ba^r                                               }|
   5824      {1:~                                                 }|*3
   5825                                                        |
   5826    ]])
   5827    feed('<C-E>')
   5828    screen:expect([[
   5829      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|
   5830      foo                                               |
   5831      {22:ba^r                                               }|
   5832      {1:~                                                 }|*4
   5833                                                        |
   5834    ]])
   5835    feed('<C-E>')
   5836    screen:expect([[
   5837      foo                                               |
   5838      {22:ba^r                                               }|
   5839      {1:~                                                 }|*5
   5840                                                        |
   5841    ]])
   5842 
   5843    feed('zb')
   5844    command('set list listchars=eol:$')
   5845    screen:expect([[
   5846      0123456789012345678901234567890123456789012345678{4:x}|
   5847      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
   5848      {1:> $}                                               |
   5849      foo{1:$}                                              |
   5850      {22:ba^r}{23:$}{22:                                              }|
   5851                                                        |
   5852    ]])
   5853    eq(5, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all)
   5854    feed('<C-E>')
   5855    screen:expect([[
   5856      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*3
   5857      {1:> $}                                               |
   5858      foo{1:$}                                              |
   5859      {22:ba^r}{23:$}{22:                                              }|
   5860      {1:~                                                 }|
   5861                                                        |
   5862    ]])
   5863    feed('<C-E>')
   5864    screen:expect([[
   5865      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2
   5866      {1:> $}                                               |
   5867      foo{1:$}                                              |
   5868      {22:ba^r}{23:$}{22:                                              }|
   5869      {1:~                                                 }|*2
   5870                                                        |
   5871    ]])
   5872    feed('<C-E>')
   5873    screen:expect([[
   5874      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|
   5875      {1:> $}                                               |
   5876      foo{1:$}                                              |
   5877      {22:ba^r}{23:$}{22:                                              }|
   5878      {1:~                                                 }|*3
   5879                                                        |
   5880    ]])
   5881    feed('<C-E>')
   5882    screen:expect([[
   5883      {1:> $}                                               |
   5884      foo{1:$}                                              |
   5885      {22:ba^r}{23:$}{22:                                              }|
   5886      {1:~                                                 }|*4
   5887                                                        |
   5888    ]])
   5889    feed('<C-E>')
   5890    screen:expect([[
   5891      foo{1:$}                                              |
   5892      {22:ba^r}{23:$}{22:                                              }|
   5893      {1:~                                                 }|*5
   5894                                                        |
   5895    ]])
   5896 
   5897    feed('gg$xG$')
   5898    screen:expect([[
   5899      012345678901234567890123456789012345678901234567{4:xx}|
   5900      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2
   5901      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}|
   5902      foo{1:$}                                              |
   5903      {22:ba^r}{23:$}{22:                                              }|
   5904      {1:~                                                 }|
   5905                                                        |
   5906    ]])
   5907    eq(4, api.nvim_win_text_height(0, { start_row = 0, end_row = 0 }).all)
   5908    feed('<C-E>')
   5909    screen:expect([[
   5910      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|*2
   5911      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}|
   5912      foo{1:$}                                              |
   5913      {22:ba^r}{23:$}{22:                                              }|
   5914      {1:~                                                 }|*2
   5915                                                        |
   5916    ]])
   5917    feed('<C-E>')
   5918    screen:expect([[
   5919      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|
   5920      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}|
   5921      foo{1:$}                                              |
   5922      {22:ba^r}{23:$}{22:                                              }|
   5923      {1:~                                                 }|*3
   5924                                                        |
   5925    ]])
   5926    feed('<C-E>')
   5927    screen:expect([[
   5928      {1:> }{4:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}{1:$}|
   5929      foo{1:$}                                              |
   5930      {22:ba^r}{23:$}{22:                                              }|
   5931      {1:~                                                 }|*4
   5932                                                        |
   5933    ]])
   5934    feed('<C-E>')
   5935    screen:expect([[
   5936      foo{1:$}                                              |
   5937      {22:ba^r}{23:$}{22:                                              }|
   5938      {1:~                                                 }|*5
   5939                                                        |
   5940    ]])
   5941  end)
   5942 
   5943  it("virtcol('$') is correct with inline virt text at EOL", function()
   5944    insert(('1234567890\n'):rep(6))
   5945    for _, v in ipairs({ { 2, 'a' }, { 3, 'ab' }, { 4, 'abc' }, { 5, 'abcd' }, { 6, 'αβγ口' } }) do
   5946      local ln, tx = unpack(v)
   5947      local co = fn.col({ ln, '$' })
   5948      eq(11, fn.virtcol({ ln, '$' }))
   5949      api.nvim_buf_set_extmark(0, ns, ln - 1, co - 1, { virt_text = { { tx } }, virt_text_pos = 'inline' })
   5950      eq(11 + fn.strwidth(tx), fn.virtcol({ ln, '$' }))
   5951    end
   5952  end)
   5953 end)
   5954 
   5955 describe('decorations: virtual lines', function()
   5956  local screen ---@type test.functional.ui.screen
   5957  local ns ---@type integer
   5958 
   5959  before_each(function()
   5960    clear()
   5961    screen = Screen.new(50, 12)
   5962    screen:add_extra_attr_ids {
   5963      [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow },
   5964    }
   5965 
   5966    ns = api.nvim_create_namespace 'test'
   5967  end)
   5968 
   5969  local example_text2 = [[
   5970 if (h->n_buckets < new_n_buckets) { // expand
   5971  khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t));
   5972  h->keys = new_keys;
   5973  if (kh_is_map && val_size) {
   5974    char *new_vals = krealloc( h->vals_buf, new_n_buckets * val_size);
   5975    h->vals_buf = new_vals;
   5976  }
   5977 }]]
   5978 
   5979  it('works with one line', function()
   5980    insert(example_text2)
   5981    feed '2gg'
   5982    screen:expect {
   5983      grid = [[
   5984      if (h->n_buckets < new_n_buckets) { // expand     |
   5985        ^khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   5986      h->keys, new_n_buckets * sizeof(khkey_t));        |
   5987        h->keys = new_keys;                             |
   5988        if (kh_is_map && val_size) {                    |
   5989          char *new_vals = krealloc( h->vals_buf, new_n_|
   5990      buckets * val_size);                              |
   5991          h->vals_buf = new_vals;                       |
   5992        }                                               |
   5993      }                                                 |
   5994      {1:~                                                 }|
   5995                                                        |
   5996    ]],
   5997    }
   5998 
   5999    api.nvim_buf_set_extmark(0, ns, 1, 33, {
   6000      virt_lines = { { { '>> ', 'NonText' }, { 'krealloc', 'Identifier' }, { ': change the size of an allocation' } } },
   6001      virt_lines_above = true,
   6002    })
   6003 
   6004    screen:expect {
   6005      grid = [[
   6006      if (h->n_buckets < new_n_buckets) { // expand     |
   6007      {1:>> }{25:krealloc}: change the size of an allocation     |
   6008        ^khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6009      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6010        h->keys = new_keys;                             |
   6011        if (kh_is_map && val_size) {                    |
   6012          char *new_vals = krealloc( h->vals_buf, new_n_|
   6013      buckets * val_size);                              |
   6014          h->vals_buf = new_vals;                       |
   6015        }                                               |
   6016      }                                                 |
   6017                                                        |
   6018    ]],
   6019    }
   6020 
   6021    feed '/krealloc<cr>'
   6022    screen:expect {
   6023      grid = [[
   6024      if (h->n_buckets < new_n_buckets) { // expand     |
   6025      {1:>> }{25:krealloc}: change the size of an allocation     |
   6026        khkey_t *new_keys = (khkey_t *){10:^krealloc}((void *)|
   6027      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6028        h->keys = new_keys;                             |
   6029        if (kh_is_map && val_size) {                    |
   6030          char *new_vals = {10:krealloc}( h->vals_buf, new_n_|
   6031      buckets * val_size);                              |
   6032          h->vals_buf = new_vals;                       |
   6033        }                                               |
   6034      }                                                 |
   6035      /krealloc                                         |
   6036    ]],
   6037    }
   6038 
   6039    -- virtual line remains anchored to the extmark
   6040    feed 'i<cr>'
   6041    screen:expect {
   6042      grid = [[
   6043      if (h->n_buckets < new_n_buckets) { // expand     |
   6044        khkey_t *new_keys = (khkey_t *)                 |
   6045      {1:>> }{25:krealloc}: change the size of an allocation     |
   6046      {10:^krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
   6047      hkey_t));                                         |
   6048        h->keys = new_keys;                             |
   6049        if (kh_is_map && val_size) {                    |
   6050          char *new_vals = {10:krealloc}( h->vals_buf, new_n_|
   6051      buckets * val_size);                              |
   6052          h->vals_buf = new_vals;                       |
   6053        }                                               |
   6054      {5:-- INSERT --}                                      |
   6055    ]],
   6056    }
   6057 
   6058    feed '<esc>3+'
   6059    screen:expect {
   6060      grid = [[
   6061      if (h->n_buckets < new_n_buckets) { // expand     |
   6062        khkey_t *new_keys = (khkey_t *)                 |
   6063      {1:>> }{25:krealloc}: change the size of an allocation     |
   6064      {10:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
   6065      hkey_t));                                         |
   6066        h->keys = new_keys;                             |
   6067        if (kh_is_map && val_size) {                    |
   6068          ^char *new_vals = {10:krealloc}( h->vals_buf, new_n_|
   6069      buckets * val_size);                              |
   6070          h->vals_buf = new_vals;                       |
   6071        }                                               |
   6072                                                        |
   6073    ]],
   6074    }
   6075 
   6076    api.nvim_buf_set_extmark(0, ns, 5, 0, {
   6077      virt_lines = { { { '^^ REVIEW:', 'Todo' }, { ' new_vals variable seems unnecessary?', 'Comment' } } },
   6078    })
   6079    screen:expect {
   6080      grid = [[
   6081      if (h->n_buckets < new_n_buckets) { // expand     |
   6082        khkey_t *new_keys = (khkey_t *)                 |
   6083      {1:>> }{25:krealloc}: change the size of an allocation     |
   6084      {10:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
   6085      hkey_t));                                         |
   6086        h->keys = new_keys;                             |
   6087        if (kh_is_map && val_size) {                    |
   6088          ^char *new_vals = {10:krealloc}( h->vals_buf, new_n_|
   6089      buckets * val_size);                              |
   6090      {100:^^ REVIEW:}{18: new_vals variable seems unnecessary?}   |
   6091          h->vals_buf = new_vals;                       |
   6092                                                        |
   6093    ]],
   6094    }
   6095 
   6096    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   6097    screen:expect {
   6098      grid = [[
   6099      if (h->n_buckets < new_n_buckets) { // expand     |
   6100        khkey_t *new_keys = (khkey_t *)                 |
   6101      {10:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
   6102      hkey_t));                                         |
   6103        h->keys = new_keys;                             |
   6104        if (kh_is_map && val_size) {                    |
   6105          ^char *new_vals = {10:krealloc}( h->vals_buf, new_n_|
   6106      buckets * val_size);                              |
   6107          h->vals_buf = new_vals;                       |
   6108        }                                               |
   6109      }                                                 |
   6110                                                        |
   6111    ]],
   6112    }
   6113  end)
   6114 
   6115  it('works with text at the beginning of the buffer', function()
   6116    insert(example_text2)
   6117    feed 'gg'
   6118 
   6119    screen:expect {
   6120      grid = [[
   6121      ^if (h->n_buckets < new_n_buckets) { // expand     |
   6122        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6123      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6124        h->keys = new_keys;                             |
   6125        if (kh_is_map && val_size) {                    |
   6126          char *new_vals = krealloc( h->vals_buf, new_n_|
   6127      buckets * val_size);                              |
   6128          h->vals_buf = new_vals;                       |
   6129        }                                               |
   6130      }                                                 |
   6131      {1:~                                                 }|
   6132                                                        |
   6133    ]],
   6134    }
   6135 
   6136    api.nvim_buf_set_extmark(0, ns, 0, 0, {
   6137      virt_lines = {
   6138        { { 'refactor(khash): ', 'Special' }, { 'take size of values as parameter' } },
   6139        { { 'Author: Dev Devsson, ' }, { 'Tue Aug 31 10:13:37 2021', 'Comment' } },
   6140      },
   6141      virt_lines_above = true,
   6142      right_gravity = false,
   6143    })
   6144 
   6145    -- placing virt_text on topline does not automatically cause a scroll
   6146    screen:expect {
   6147      grid = [[
   6148      ^if (h->n_buckets < new_n_buckets) { // expand     |
   6149        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6150      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6151        h->keys = new_keys;                             |
   6152        if (kh_is_map && val_size) {                    |
   6153          char *new_vals = krealloc( h->vals_buf, new_n_|
   6154      buckets * val_size);                              |
   6155          h->vals_buf = new_vals;                       |
   6156        }                                               |
   6157      }                                                 |
   6158      {1:~                                                 }|
   6159                                                        |
   6160    ]],
   6161      unchanged = true,
   6162    }
   6163 
   6164    feed '<c-b>'
   6165    screen:expect {
   6166      grid = [[
   6167      {16:refactor(khash): }take size of values as parameter |
   6168      Author: Dev Devsson, {18:Tue Aug 31 10:13:37 2021}     |
   6169      if (h->n_buckets < new_n_buckets) { // expand     |
   6170        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6171      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6172        h->keys = new_keys;                             |
   6173        if (kh_is_map && val_size) {                    |
   6174          char *new_vals = krealloc( h->vals_buf, new_n_|
   6175      buckets * val_size);                              |
   6176          h->vals_buf = new_vals;                       |
   6177        ^}                                               |
   6178                                                        |
   6179    ]],
   6180    }
   6181  end)
   6182 
   6183  it('works with text at the end of the buffer', function()
   6184    insert(example_text2)
   6185    feed 'G'
   6186 
   6187    screen:expect {
   6188      grid = [[
   6189      if (h->n_buckets < new_n_buckets) { // expand     |
   6190        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6191      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6192        h->keys = new_keys;                             |
   6193        if (kh_is_map && val_size) {                    |
   6194          char *new_vals = krealloc( h->vals_buf, new_n_|
   6195      buckets * val_size);                              |
   6196          h->vals_buf = new_vals;                       |
   6197        }                                               |
   6198      ^}                                                 |
   6199      {1:~                                                 }|
   6200                                                        |
   6201    ]],
   6202    }
   6203 
   6204    local id = api.nvim_buf_set_extmark(0, ns, 7, 0, {
   6205      virt_lines = { { { 'Grugg' } } },
   6206      right_gravity = false,
   6207    })
   6208 
   6209    screen:expect {
   6210      grid = [[
   6211      if (h->n_buckets < new_n_buckets) { // expand     |
   6212        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6213      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6214        h->keys = new_keys;                             |
   6215        if (kh_is_map && val_size) {                    |
   6216          char *new_vals = krealloc( h->vals_buf, new_n_|
   6217      buckets * val_size);                              |
   6218          h->vals_buf = new_vals;                       |
   6219        }                                               |
   6220      ^}                                                 |
   6221      Grugg                                             |
   6222                                                        |
   6223    ]],
   6224    }
   6225 
   6226    screen:try_resize(50, 11)
   6227    feed('gg')
   6228    screen:expect {
   6229      grid = [[
   6230      ^if (h->n_buckets < new_n_buckets) { // expand     |
   6231        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6232      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6233        h->keys = new_keys;                             |
   6234        if (kh_is_map && val_size) {                    |
   6235          char *new_vals = krealloc( h->vals_buf, new_n_|
   6236      buckets * val_size);                              |
   6237          h->vals_buf = new_vals;                       |
   6238        }                                               |
   6239      }                                                 |
   6240                                                        |
   6241    ]],
   6242    }
   6243 
   6244    feed('G<C-E>')
   6245    screen:expect {
   6246      grid = [[
   6247        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6248      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6249        h->keys = new_keys;                             |
   6250        if (kh_is_map && val_size) {                    |
   6251          char *new_vals = krealloc( h->vals_buf, new_n_|
   6252      buckets * val_size);                              |
   6253          h->vals_buf = new_vals;                       |
   6254        }                                               |
   6255      ^}                                                 |
   6256      Grugg                                             |
   6257                                                        |
   6258    ]],
   6259    }
   6260 
   6261    feed('gg')
   6262    screen:expect {
   6263      grid = [[
   6264      ^if (h->n_buckets < new_n_buckets) { // expand     |
   6265        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6266      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6267        h->keys = new_keys;                             |
   6268        if (kh_is_map && val_size) {                    |
   6269          char *new_vals = krealloc( h->vals_buf, new_n_|
   6270      buckets * val_size);                              |
   6271          h->vals_buf = new_vals;                       |
   6272        }                                               |
   6273      }                                                 |
   6274                                                        |
   6275    ]],
   6276    }
   6277 
   6278    screen:try_resize(50, 12)
   6279    feed('G')
   6280    screen:expect {
   6281      grid = [[
   6282      if (h->n_buckets < new_n_buckets) { // expand     |
   6283        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6284      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6285        h->keys = new_keys;                             |
   6286        if (kh_is_map && val_size) {                    |
   6287          char *new_vals = krealloc( h->vals_buf, new_n_|
   6288      buckets * val_size);                              |
   6289          h->vals_buf = new_vals;                       |
   6290        }                                               |
   6291      ^}                                                 |
   6292      Grugg                                             |
   6293                                                        |
   6294    ]],
   6295    }
   6296 
   6297    api.nvim_buf_del_extmark(0, ns, id)
   6298    screen:expect {
   6299      grid = [[
   6300      if (h->n_buckets < new_n_buckets) { // expand     |
   6301        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6302      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6303        h->keys = new_keys;                             |
   6304        if (kh_is_map && val_size) {                    |
   6305          char *new_vals = krealloc( h->vals_buf, new_n_|
   6306      buckets * val_size);                              |
   6307          h->vals_buf = new_vals;                       |
   6308        }                                               |
   6309      ^}                                                 |
   6310      {1:~                                                 }|
   6311                                                        |
   6312    ]],
   6313    }
   6314  end)
   6315 
   6316  it('works beyond end of the buffer with virt_lines_above', function()
   6317    insert(example_text2)
   6318    feed 'G'
   6319 
   6320    screen:expect {
   6321      grid = [[
   6322      if (h->n_buckets < new_n_buckets) { // expand     |
   6323        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6324      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6325        h->keys = new_keys;                             |
   6326        if (kh_is_map && val_size) {                    |
   6327          char *new_vals = krealloc( h->vals_buf, new_n_|
   6328      buckets * val_size);                              |
   6329          h->vals_buf = new_vals;                       |
   6330        }                                               |
   6331      ^}                                                 |
   6332      {1:~                                                 }|
   6333                                                        |
   6334    ]],
   6335    }
   6336 
   6337    local id = api.nvim_buf_set_extmark(0, ns, 8, 0, {
   6338      virt_lines = { { { 'Grugg' } } },
   6339      virt_lines_above = true,
   6340    })
   6341 
   6342    screen:expect {
   6343      grid = [[
   6344      if (h->n_buckets < new_n_buckets) { // expand     |
   6345        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6346      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6347        h->keys = new_keys;                             |
   6348        if (kh_is_map && val_size) {                    |
   6349          char *new_vals = krealloc( h->vals_buf, new_n_|
   6350      buckets * val_size);                              |
   6351          h->vals_buf = new_vals;                       |
   6352        }                                               |
   6353      ^}                                                 |
   6354      Grugg                                             |
   6355                                                        |
   6356    ]],
   6357    }
   6358 
   6359    feed('dd')
   6360    screen:expect {
   6361      grid = [[
   6362      if (h->n_buckets < new_n_buckets) { // expand     |
   6363        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6364      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6365        h->keys = new_keys;                             |
   6366        if (kh_is_map && val_size) {                    |
   6367          char *new_vals = krealloc( h->vals_buf, new_n_|
   6368      buckets * val_size);                              |
   6369          h->vals_buf = new_vals;                       |
   6370        ^}                                               |
   6371      Grugg                                             |
   6372      {1:~                                                 }|
   6373                                                        |
   6374    ]],
   6375    }
   6376 
   6377    feed('dk')
   6378    screen:expect {
   6379      grid = [[
   6380      if (h->n_buckets < new_n_buckets) { // expand     |
   6381        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6382      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6383        h->keys = new_keys;                             |
   6384        if (kh_is_map && val_size) {                    |
   6385          ^char *new_vals = krealloc( h->vals_buf, new_n_|
   6386      buckets * val_size);                              |
   6387      Grugg                                             |
   6388      {1:~                                                 }|*3
   6389                                                        |
   6390    ]],
   6391    }
   6392 
   6393    feed('dgg')
   6394    screen:expect {
   6395      grid = [[
   6396      ^                                                  |
   6397      Grugg                                             |
   6398      {1:~                                                 }|*9
   6399      --No lines in buffer--                            |
   6400    ]],
   6401    }
   6402 
   6403    api.nvim_buf_del_extmark(0, ns, id)
   6404    screen:expect {
   6405      grid = [[
   6406      ^                                                  |
   6407      {1:~                                                 }|*10
   6408      --No lines in buffer--                            |
   6409    ]],
   6410    }
   6411  end)
   6412 
   6413  it('does not cause syntax ml_get error at the end of a buffer #17816', function()
   6414    command([[syntax region foo keepend start='^foo' end='^$']])
   6415    command('syntax sync minlines=100')
   6416    insert('foo')
   6417    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'bar', 'Comment' } } } })
   6418    screen:expect([[
   6419      fo^o                                               |
   6420      {18:bar}                                               |
   6421      {1:~                                                 }|*9
   6422                                                        |
   6423    ]])
   6424  end)
   6425 
   6426  it('works with a block scrolling up', function()
   6427    screen:try_resize(30, 7)
   6428    insert('aa\nbb\ncc\ndd\nee\nff\ngg\nhh')
   6429    feed 'gg'
   6430 
   6431    api.nvim_buf_set_extmark(0, ns, 6, 0, {
   6432      virt_lines = {
   6433        { { 'they see me' } },
   6434        { { 'scrolling', 'Special' } },
   6435        { { 'they' } },
   6436        { { "hatin'", 'Special' } },
   6437      },
   6438    })
   6439 
   6440    screen:expect {
   6441      grid = [[
   6442      ^aa                            |
   6443      bb                            |
   6444      cc                            |
   6445      dd                            |
   6446      ee                            |
   6447      ff                            |
   6448                                    |
   6449    ]],
   6450    }
   6451 
   6452    feed '<c-e>'
   6453    screen:expect {
   6454      grid = [[
   6455      ^bb                            |
   6456      cc                            |
   6457      dd                            |
   6458      ee                            |
   6459      ff                            |
   6460      gg                            |
   6461                                    |
   6462    ]],
   6463    }
   6464 
   6465    feed '<c-e>'
   6466    screen:expect {
   6467      grid = [[
   6468      ^cc                            |
   6469      dd                            |
   6470      ee                            |
   6471      ff                            |
   6472      gg                            |
   6473      they see me                   |
   6474                                    |
   6475    ]],
   6476    }
   6477 
   6478    feed '<c-e>'
   6479    screen:expect {
   6480      grid = [[
   6481      ^dd                            |
   6482      ee                            |
   6483      ff                            |
   6484      gg                            |
   6485      they see me                   |
   6486      {16:scrolling}                     |
   6487                                    |
   6488    ]],
   6489    }
   6490 
   6491    feed '<c-e>'
   6492    screen:expect {
   6493      grid = [[
   6494      ^ee                            |
   6495      ff                            |
   6496      gg                            |
   6497      they see me                   |
   6498      {16:scrolling}                     |
   6499      they                          |
   6500                                    |
   6501    ]],
   6502    }
   6503 
   6504    feed '<c-e>'
   6505    screen:expect {
   6506      grid = [[
   6507      ^ff                            |
   6508      gg                            |
   6509      they see me                   |
   6510      {16:scrolling}                     |
   6511      they                          |
   6512      {16:hatin'}                        |
   6513                                    |
   6514    ]],
   6515    }
   6516 
   6517    feed '<c-e>'
   6518    screen:expect {
   6519      grid = [[
   6520      ^gg                            |
   6521      they see me                   |
   6522      {16:scrolling}                     |
   6523      they                          |
   6524      {16:hatin'}                        |
   6525      hh                            |
   6526                                    |
   6527    ]],
   6528    }
   6529 
   6530    feed '<c-e>'
   6531    screen:expect {
   6532      grid = [[
   6533      they see me                   |
   6534      {16:scrolling}                     |
   6535      they                          |
   6536      {16:hatin'}                        |
   6537      ^hh                            |
   6538      {1:~                             }|
   6539                                    |
   6540    ]],
   6541    }
   6542 
   6543    feed '<c-e>'
   6544    screen:expect {
   6545      grid = [[
   6546      {16:scrolling}                     |
   6547      they                          |
   6548      {16:hatin'}                        |
   6549      ^hh                            |
   6550      {1:~                             }|*2
   6551                                    |
   6552    ]],
   6553    }
   6554 
   6555    feed '<c-e>'
   6556    screen:expect {
   6557      grid = [[
   6558      they                          |
   6559      {16:hatin'}                        |
   6560      ^hh                            |
   6561      {1:~                             }|*3
   6562                                    |
   6563    ]],
   6564    }
   6565 
   6566    feed '<c-e>'
   6567    screen:expect {
   6568      grid = [[
   6569      {16:hatin'}                        |
   6570      ^hh                            |
   6571      {1:~                             }|*4
   6572                                    |
   6573    ]],
   6574    }
   6575 
   6576    feed '<c-e>'
   6577    screen:expect {
   6578      grid = [[
   6579      ^hh                            |
   6580      {1:~                             }|*5
   6581                                    |
   6582    ]],
   6583    }
   6584  end)
   6585 
   6586  it('works with sign and numbercolumns', function()
   6587    insert(example_text2)
   6588    feed 'gg'
   6589    command 'set number signcolumn=yes'
   6590    screen:expect([[
   6591      {7:  }{8:  1 }^if (h->n_buckets < new_n_buckets) { // expan|
   6592      {7:  }{8:    }d                                           |
   6593      {7:  }{8:  2 }  khkey_t *new_keys = (khkey_t *)krealloc((v|
   6594      {7:  }{8:    }oid *)h->keys, new_n_buckets * sizeof(khkey_|
   6595      {7:  }{8:    }t));                                        |
   6596      {7:  }{8:  3 }  h->keys = new_keys;                       |
   6597      {7:  }{8:  4 }  if (kh_is_map && val_size) {              |
   6598      {7:  }{8:  5 }    char *new_vals = krealloc( h->vals_buf, |
   6599      {7:  }{8:    }new_n_buckets * val_size);                  |
   6600      {7:  }{8:  6 }    h->vals_buf = new_vals;                 |
   6601      {7:  }{8:  7 }  }                                         |
   6602                                                        |
   6603    ]])
   6604 
   6605    local markid = api.nvim_buf_set_extmark(0, ns, 2, 0, {
   6606      virt_lines = {
   6607        { { 'Some special', 'Special' } },
   6608        { { 'remark about codes', 'Comment' } },
   6609      },
   6610    })
   6611 
   6612    screen:expect([[
   6613      {7:  }{8:  1 }^if (h->n_buckets < new_n_buckets) { // expan|
   6614      {7:  }{8:    }d                                           |
   6615      {7:  }{8:  2 }  khkey_t *new_keys = (khkey_t *)krealloc((v|
   6616      {7:  }{8:    }oid *)h->keys, new_n_buckets * sizeof(khkey_|
   6617      {7:  }{8:    }t));                                        |
   6618      {7:  }{8:  3 }  h->keys = new_keys;                       |
   6619      {7:  }{8:    }{16:Some special}                                |
   6620      {7:  }{8:    }{18:remark about codes}                          |
   6621      {7:  }{8:  4 }  if (kh_is_map && val_size) {              |
   6622      {7:  }{8:  5 }    char *new_vals = krealloc( h->vals_buf, |
   6623      {7:  }{8:    }new_n_buckets * val_size);                  |
   6624                                                        |
   6625    ]])
   6626 
   6627    api.nvim_buf_set_extmark(0, ns, 2, 0, {
   6628      virt_lines = {
   6629        { { 'Some special', 'Special' } },
   6630        { { 'remark about codes', 'Comment' } },
   6631      },
   6632      virt_lines_leftcol = true,
   6633      id = markid,
   6634    })
   6635    screen:expect([[
   6636      {7:  }{8:  1 }^if (h->n_buckets < new_n_buckets) { // expan|
   6637      {7:  }{8:    }d                                           |
   6638      {7:  }{8:  2 }  khkey_t *new_keys = (khkey_t *)krealloc((v|
   6639      {7:  }{8:    }oid *)h->keys, new_n_buckets * sizeof(khkey_|
   6640      {7:  }{8:    }t));                                        |
   6641      {7:  }{8:  3 }  h->keys = new_keys;                       |
   6642      {16:Some special}                                      |
   6643      {18:remark about codes}                                |
   6644      {7:  }{8:  4 }  if (kh_is_map && val_size) {              |
   6645      {7:  }{8:  5 }    char *new_vals = krealloc( h->vals_buf, |
   6646      {7:  }{8:    }new_n_buckets * val_size);                  |
   6647                                                        |
   6648    ]])
   6649 
   6650    command('set nonumber relativenumber')
   6651    screen:expect([[
   6652      {7:  }{8:  0 }^if (h->n_buckets < new_n_buckets) { // expan|
   6653      {7:  }{8:    }d                                           |
   6654      {7:  }{8:  1 }  khkey_t *new_keys = (khkey_t *)krealloc((v|
   6655      {7:  }{8:    }oid *)h->keys, new_n_buckets * sizeof(khkey_|
   6656      {7:  }{8:    }t));                                        |
   6657      {7:  }{8:  2 }  h->keys = new_keys;                       |
   6658      {16:Some special}                                      |
   6659      {18:remark about codes}                                |
   6660      {7:  }{8:  3 }  if (kh_is_map && val_size) {              |
   6661      {7:  }{8:  4 }    char *new_vals = krealloc( h->vals_buf, |
   6662      {7:  }{8:    }new_n_buckets * val_size);                  |
   6663                                                        |
   6664    ]])
   6665 
   6666    -- 'relativenumber' is redrawn with virt_lines_leftcol #34649
   6667    feed('j')
   6668    screen:expect([[
   6669      {7:  }{8:  1 }if (h->n_buckets < new_n_buckets) { // expan|
   6670      {7:  }{8:    }d                                           |
   6671      {7:  }{8:  0 }^  khkey_t *new_keys = (khkey_t *)krealloc((v|
   6672      {7:  }{8:    }oid *)h->keys, new_n_buckets * sizeof(khkey_|
   6673      {7:  }{8:    }t));                                        |
   6674      {7:  }{8:  1 }  h->keys = new_keys;                       |
   6675      {16:Some special}                                      |
   6676      {18:remark about codes}                                |
   6677      {7:  }{8:  2 }  if (kh_is_map && val_size) {              |
   6678      {7:  }{8:  3 }    char *new_vals = krealloc( h->vals_buf, |
   6679      {7:  }{8:    }new_n_buckets * val_size);                  |
   6680                                                        |
   6681    ]])
   6682  end)
   6683 
   6684  it('works with hard TABs', function()
   6685    insert(example_text2)
   6686    feed 'gg'
   6687    api.nvim_buf_set_extmark(0, ns, 1, 0, {
   6688      virt_lines = { { { '>>', 'NonText' }, { '\tvery\ttabby', 'Identifier' }, { 'text\twith\ttabs' } } },
   6689    })
   6690    screen:expect {
   6691      grid = [[
   6692      ^if (h->n_buckets < new_n_buckets) { // expand     |
   6693        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6694      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6695      {1:>>}{25:      very    tabby}text       with    tabs      |
   6696        h->keys = new_keys;                             |
   6697        if (kh_is_map && val_size) {                    |
   6698          char *new_vals = krealloc( h->vals_buf, new_n_|
   6699      buckets * val_size);                              |
   6700          h->vals_buf = new_vals;                       |
   6701        }                                               |
   6702      }                                                 |
   6703                                                        |
   6704    ]],
   6705    }
   6706 
   6707    command 'set tabstop=4'
   6708    screen:expect {
   6709      grid = [[
   6710      ^if (h->n_buckets < new_n_buckets) { // expand     |
   6711        khkey_t *new_keys = (khkey_t *)krealloc((void *)|
   6712      h->keys, new_n_buckets * sizeof(khkey_t));        |
   6713      {1:>>}{25:  very    tabby}text   with    tabs              |
   6714        h->keys = new_keys;                             |
   6715        if (kh_is_map && val_size) {                    |
   6716          char *new_vals = krealloc( h->vals_buf, new_n_|
   6717      buckets * val_size);                              |
   6718          h->vals_buf = new_vals;                       |
   6719        }                                               |
   6720      }                                                 |
   6721                                                        |
   6722    ]],
   6723    }
   6724 
   6725    command 'set number'
   6726    screen:expect {
   6727      grid = [[
   6728      {8:  1 }^if (h->n_buckets < new_n_buckets) { // expand |
   6729      {8:  2 }  khkey_t *new_keys = (khkey_t *)krealloc((voi|
   6730      {8:    }d *)h->keys, new_n_buckets * sizeof(khkey_t));|
   6731      {8:    }{1:>>}{25:  very    tabby}text   with    tabs          |
   6732      {8:  3 }  h->keys = new_keys;                         |
   6733      {8:  4 }  if (kh_is_map && val_size) {                |
   6734      {8:  5 }    char *new_vals = krealloc( h->vals_buf, ne|
   6735      {8:    }w_n_buckets * val_size);                      |
   6736      {8:  6 }    h->vals_buf = new_vals;                   |
   6737      {8:  7 }  }                                           |
   6738      {8:  8 }}                                             |
   6739                                                        |
   6740    ]],
   6741    }
   6742 
   6743    command 'set tabstop&'
   6744    screen:expect {
   6745      grid = [[
   6746      {8:  1 }^if (h->n_buckets < new_n_buckets) { // expand |
   6747      {8:  2 }  khkey_t *new_keys = (khkey_t *)krealloc((voi|
   6748      {8:    }d *)h->keys, new_n_buckets * sizeof(khkey_t));|
   6749      {8:    }{1:>>}{25:      very    tabby}text       with    tabs  |
   6750      {8:  3 }  h->keys = new_keys;                         |
   6751      {8:  4 }  if (kh_is_map && val_size) {                |
   6752      {8:  5 }    char *new_vals = krealloc( h->vals_buf, ne|
   6753      {8:    }w_n_buckets * val_size);                      |
   6754      {8:  6 }    h->vals_buf = new_vals;                   |
   6755      {8:  7 }  }                                           |
   6756      {8:  8 }}                                             |
   6757                                                        |
   6758    ]],
   6759    }
   6760  end)
   6761 
   6762  it('scrolls horizontally with virt_lines_overflow = "scroll" #31000', function()
   6763    command('set nowrap signcolumn=yes')
   6764    insert('abcdefghijklmnopqrstuvwxyz')
   6765    api.nvim_buf_set_extmark(0, ns, 0, 0, {
   6766      virt_lines = {
   6767        { { '12α口β̳γ̲=', 'Special' }, { '❤️345678', 'Special' } },
   6768        { { '123\t45\t678', 'NonText' } },
   6769      },
   6770      virt_lines_overflow = 'scroll',
   6771    })
   6772    screen:expect([[
   6773      {7:  }abcdefghijklmnopqrstuvwxy^z                      |
   6774      {7:  }{16:12α口β̳γ̲=❤️345678}                                |
   6775      {7:  }{1:123     45      678}                             |
   6776      {1:~                                                 }|*8
   6777                                                        |
   6778    ]])
   6779    feed('zl')
   6780    screen:expect([[
   6781      {7:  }bcdefghijklmnopqrstuvwxy^z                       |
   6782      {7:  }{16:2α口β̳γ̲=❤️345678}                                 |
   6783      {7:  }{1:23     45      678}                              |
   6784      {1:~                                                 }|*8
   6785                                                        |
   6786    ]])
   6787    feed('zl')
   6788    screen:expect([[
   6789      {7:  }cdefghijklmnopqrstuvwxy^z                        |
   6790      {7:  }{16:α口β̳γ̲=❤️345678}                                  |
   6791      {7:  }{1:3     45      678}                               |
   6792      {1:~                                                 }|*8
   6793                                                        |
   6794    ]])
   6795    feed('zl')
   6796    screen:expect([[
   6797      {7:  }defghijklmnopqrstuvwxy^z                         |
   6798      {7:  }{16:口β̳γ̲=❤️345678}                                   |
   6799      {7:  }{1:     45      678}                                |
   6800      {1:~                                                 }|*8
   6801                                                        |
   6802    ]])
   6803    feed('zl')
   6804    screen:expect([[
   6805      {7:  }efghijklmnopqrstuvwxy^z                          |
   6806      {7:  }{16: β̳γ̲=❤️345678}                                    |
   6807      {7:  }{1:    45      678}                                 |
   6808      {1:~                                                 }|*8
   6809                                                        |
   6810    ]])
   6811    feed('zl')
   6812    screen:expect([[
   6813      {7:  }fghijklmnopqrstuvwxy^z                           |
   6814      {7:  }{16:β̳γ̲=❤️345678}                                     |
   6815      {7:  }{1:   45      678}                                  |
   6816      {1:~                                                 }|*8
   6817                                                        |
   6818    ]])
   6819    feed('zl')
   6820    screen:expect([[
   6821      {7:  }ghijklmnopqrstuvwxy^z                            |
   6822      {7:  }{16:γ̲=❤️345678}                                      |
   6823      {7:  }{1:  45      678}                                   |
   6824      {1:~                                                 }|*8
   6825                                                        |
   6826    ]])
   6827    feed('zl')
   6828    screen:expect([[
   6829      {7:  }hijklmnopqrstuvwxy^z                             |
   6830      {7:  }{16:=❤️345678}                                       |
   6831      {7:  }{1: 45      678}                                    |
   6832      {1:~                                                 }|*8
   6833                                                        |
   6834    ]])
   6835    feed('zl')
   6836    screen:expect([[
   6837      {7:  }ijklmnopqrstuvwxy^z                              |
   6838      {7:  }{16:❤️345678}                                        |
   6839      {7:  }{1:45      678}                                     |
   6840      {1:~                                                 }|*8
   6841                                                        |
   6842    ]])
   6843    feed('zl')
   6844    screen:expect([[
   6845      {7:  }jklmnopqrstuvwxy^z                               |
   6846      {7:  }{16: 345678}                                         |
   6847      {7:  }{1:5      678}                                      |
   6848      {1:~                                                 }|*8
   6849                                                        |
   6850    ]])
   6851    feed('zl')
   6852    screen:expect([[
   6853      {7:  }klmnopqrstuvwxy^z                                |
   6854      {7:  }{16:345678}                                          |
   6855      {7:  }{1:      678}                                       |
   6856      {1:~                                                 }|*8
   6857                                                        |
   6858    ]])
   6859    feed('zl')
   6860    screen:expect([[
   6861      {7:  }lmnopqrstuvwxy^z                                 |
   6862      {7:  }{16:45678}                                           |
   6863      {7:  }{1:     678}                                        |
   6864      {1:~                                                 }|*8
   6865                                                        |
   6866    ]])
   6867    feed('zl')
   6868    screen:expect([[
   6869      {7:  }mnopqrstuvwxy^z                                  |
   6870      {7:  }{16:5678}                                            |
   6871      {7:  }{1:    678}                                         |
   6872      {1:~                                                 }|*8
   6873                                                        |
   6874    ]])
   6875    api.nvim_buf_set_extmark(0, ns, 0, 1, {
   6876      virt_lines = { { { '123\t45\t67', 'NonText' } } },
   6877      virt_lines_leftcol = true,
   6878      virt_lines_overflow = 'trunc',
   6879    })
   6880    api.nvim_buf_set_extmark(0, ns, 0, 2, {
   6881      virt_lines = { { { '123\t45\t6', 'NonText' } } },
   6882      virt_lines_leftcol = false,
   6883      virt_lines_overflow = 'trunc',
   6884    })
   6885    screen:expect([[
   6886      {7:  }mnopqrstuvwxy^z                                  |
   6887      {7:  }{16:5678}                                            |
   6888      {7:  }{1:    678}                                         |
   6889      {1:123     45      67}                                |
   6890      {7:  }{1:123     45      6}                               |
   6891      {1:~                                                 }|*6
   6892                                                        |
   6893    ]])
   6894  end)
   6895 
   6896  it('does not show twice if end_row or end_col is specified #18622', function()
   6897    screen:try_resize(50, 8)
   6898    insert([[
   6899      aaa
   6900      bbb
   6901      ccc
   6902      ddd]])
   6903    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 2, virt_lines = { { { 'VIRT LINE 1', 'NonText' } } } })
   6904    api.nvim_buf_set_extmark(0, ns, 3, 0, { end_col = 2, virt_lines = { { { 'VIRT LINE 2', 'NonText' } } } })
   6905    screen:expect {
   6906      grid = [[
   6907      aaa                                               |
   6908      {1:VIRT LINE 1}                                       |
   6909      bbb                                               |
   6910      ccc                                               |
   6911      dd^d                                               |
   6912      {1:VIRT LINE 2}                                       |
   6913      {1:~                                                 }|
   6914                                                        |
   6915    ]],
   6916    }
   6917  end)
   6918 
   6919  it('works with rightleft', function()
   6920    screen:try_resize(50, 8)
   6921    insert([[
   6922      aaa
   6923      bbb
   6924      ccc
   6925      ddd]])
   6926    command('set number rightleft')
   6927    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'VIRT LINE 1', 'NonText' } } }, virt_lines_leftcol = true })
   6928    api.nvim_buf_set_extmark(0, ns, 3, 0, { virt_lines = { { { 'VIRT LINE 2', 'NonText' } } } })
   6929    screen:expect {
   6930      grid = [[
   6931                                                 aaa{8: 1  }|
   6932                                             {1:1 ENIL TRIV}|
   6933                                                 bbb{8: 2  }|
   6934                                                 ccc{8: 3  }|
   6935                                                 ^ddd{8: 4  }|
   6936                                         {1:2 ENIL TRIV}{8:    }|
   6937      {1:                                                 ~}|
   6938                                                        |
   6939    ]],
   6940    }
   6941  end)
   6942 
   6943  it('works when using dd or yyp #23915 #23916', function()
   6944    insert([[
   6945      line1
   6946      line2
   6947      line3
   6948      line4
   6949      line5]])
   6950    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'foo' } }, { { 'bar' } }, { { 'baz' } } } })
   6951    screen:expect {
   6952      grid = [[
   6953      line1                                             |
   6954      foo                                               |
   6955      bar                                               |
   6956      baz                                               |
   6957      line2                                             |
   6958      line3                                             |
   6959      line4                                             |
   6960      line^5                                             |
   6961      {1:~                                                 }|*3
   6962                                                        |
   6963    ]],
   6964    }
   6965 
   6966    feed('gg')
   6967    feed('yyp')
   6968    screen:expect {
   6969      grid = [[
   6970      line1                                             |
   6971      foo                                               |
   6972      bar                                               |
   6973      baz                                               |
   6974      ^line1                                             |
   6975      line2                                             |
   6976      line3                                             |
   6977      line4                                             |
   6978      line5                                             |
   6979      {1:~                                                 }|*2
   6980                                                        |
   6981    ]],
   6982    }
   6983 
   6984    feed('dd')
   6985    screen:expect {
   6986      grid = [[
   6987      line1                                             |
   6988      foo                                               |
   6989      bar                                               |
   6990      baz                                               |
   6991      ^line2                                             |
   6992      line3                                             |
   6993      line4                                             |
   6994      line5                                             |
   6995      {1:~                                                 }|*3
   6996                                                        |
   6997    ]],
   6998    }
   6999 
   7000    feed('kdd')
   7001    screen:expect([[
   7002      ^line2                                             |
   7003      foo                                               |
   7004      bar                                               |
   7005      baz                                               |
   7006      line3                                             |
   7007      line4                                             |
   7008      line5                                             |
   7009      {1:~                                                 }|*4
   7010                                                        |
   7011    ]])
   7012  end)
   7013 
   7014  it('does not break cursor position with concealcursor #27887', function()
   7015    command('vsplit')
   7016    insert('\n')
   7017    api.nvim_set_option_value('conceallevel', 2, {})
   7018    api.nvim_set_option_value('concealcursor', 'niv', {})
   7019    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'VIRT1' } }, { { 'VIRT2' } } } })
   7020    screen:expect([[
   7021                                                       |
   7022      VIRT1                    VIRT1                   |
   7023      VIRT2                    VIRT2                   |
   7024      ^                                                 |
   7025      {1:~                        }{1:~                       }|*6
   7026      {3:[No Name] [+]             }{2:[No Name] [+]           }|
   7027                                                        |
   7028    ]])
   7029  end)
   7030 
   7031  it('works with full page scrolling #28290', function()
   7032    screen:try_resize(20, 8)
   7033    command('call setline(1, range(20))')
   7034    api.nvim_buf_set_extmark(0, ns, 10, 0, { virt_lines = { { { 'VIRT1' } }, { { 'VIRT2' } } } })
   7035    screen:expect([[
   7036      ^0                   |
   7037      1                   |
   7038      2                   |
   7039      3                   |
   7040      4                   |
   7041      5                   |
   7042      6                   |
   7043                          |
   7044    ]])
   7045    feed('<C-F>')
   7046    screen:expect([[
   7047      ^5                   |
   7048      6                   |
   7049      7                   |
   7050      8                   |
   7051      9                   |
   7052      10                  |
   7053      VIRT1               |
   7054                          |
   7055    ]])
   7056    feed('<C-F>')
   7057    screen:expect([[
   7058      ^10                  |
   7059      VIRT1               |
   7060      VIRT2               |
   7061      11                  |
   7062      12                  |
   7063      13                  |
   7064      14                  |
   7065                          |
   7066    ]])
   7067    feed('<C-F>')
   7068    screen:expect([[
   7069      ^13                  |
   7070      14                  |
   7071      15                  |
   7072      16                  |
   7073      17                  |
   7074      18                  |
   7075      19                  |
   7076                          |
   7077    ]])
   7078    feed('<C-B>')
   7079    screen:expect([[
   7080      10                  |
   7081      VIRT1               |
   7082      VIRT2               |
   7083      11                  |
   7084      12                  |
   7085      13                  |
   7086      ^14                  |
   7087                          |
   7088    ]])
   7089    feed('<C-B>')
   7090    screen:expect([[
   7091      5                   |
   7092      6                   |
   7093      7                   |
   7094      8                   |
   7095      9                   |
   7096      ^10                  |
   7097      VIRT1               |
   7098                          |
   7099    ]])
   7100    feed('<C-B>')
   7101    screen:expect([[
   7102      0                   |
   7103      1                   |
   7104      2                   |
   7105      3                   |
   7106      4                   |
   7107      5                   |
   7108      ^6                   |
   7109                          |
   7110    ]])
   7111  end)
   7112 
   7113  it('not drawn when invalid', function()
   7114    api.nvim_buf_set_lines(0, 0, -1, false, { 'foo', 'bar' })
   7115    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = { { { 'VIRT1' } } }, invalidate = true })
   7116    screen:expect({
   7117      grid = [[
   7118        ^foo                                               |
   7119        VIRT1                                             |
   7120        bar                                               |
   7121        {1:~                                                 }|*8
   7122                                                          |
   7123      ]],
   7124    })
   7125    feed('dd')
   7126    screen:expect({
   7127      grid = [[
   7128        ^bar                                               |
   7129        {1:~                                                 }|*10
   7130                                                          |
   7131      ]],
   7132    })
   7133  end)
   7134 
   7135  it("not revealed before skipcol scrolling up with 'smoothscroll'", function()
   7136    api.nvim_set_option_value('smoothscroll', true, {})
   7137    api.nvim_buf_set_lines(0, 0, -1, false, { ('x'):rep(screen._width * 2) })
   7138    api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines_above = true, virt_lines = { { { 'VIRT1' } } } })
   7139    feed('<C-E>')
   7140    screen:expect([[
   7141      {1:<<<}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^x|
   7142      {1:~                                                 }|*10
   7143                                                        |
   7144    ]])
   7145    feed('<C-Y>')
   7146    screen:expect([[
   7147      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
   7148      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^x|
   7149      {1:~                                                 }|*9
   7150                                                        |
   7151    ]])
   7152    feed('<C-Y>')
   7153    screen:expect([[
   7154      VIRT1                                             |
   7155      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
   7156      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^x|
   7157      {1:~                                                 }|*8
   7158                                                        |
   7159    ]])
   7160  end)
   7161 end)
   7162 
   7163 describe('decorations: signs', function()
   7164  local screen ---@type test.functional.ui.screen
   7165  local ns ---@type integer
   7166 
   7167  before_each(function()
   7168    clear()
   7169    screen = Screen.new(50, 10)
   7170    screen:add_extra_attr_ids {
   7171      [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow },
   7172    }
   7173 
   7174    ns = api.nvim_create_namespace 'test'
   7175    api.nvim_set_option_value('signcolumn', 'auto:9', {})
   7176  end)
   7177 
   7178  local example_test3 = [[
   7179 l1
   7180 l2
   7181 l3
   7182 l4
   7183 l5
   7184 ]]
   7185 
   7186  it('can add a single sign (no end row)', function()
   7187    insert(example_test3)
   7188    feed 'gg'
   7189 
   7190    api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S' })
   7191 
   7192    screen:expect([[
   7193      {7:  }^l1                                              |
   7194      {7:S }l2                                              |
   7195      {7:  }l3                                              |
   7196      {7:  }l4                                              |
   7197      {7:  }l5                                              |
   7198      {7:  }                                                |
   7199      {1:~                                                 }|*3
   7200                                                        |
   7201    ]])
   7202  end)
   7203 
   7204  it('can add a single sign (with end row)', function()
   7205    insert(example_test3)
   7206    feed 'gg'
   7207 
   7208    api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S', end_row = 1 })
   7209 
   7210    screen:expect([[
   7211      {7:  }^l1                                              |
   7212      {7:S }l2                                              |
   7213      {7:  }l3                                              |
   7214      {7:  }l4                                              |
   7215      {7:  }l5                                              |
   7216      {7:  }                                                |
   7217      {1:~                                                 }|*3
   7218                                                        |
   7219    ]])
   7220  end)
   7221 
   7222  it('can add a single sign and text highlight', function()
   7223    insert(example_test3)
   7224    feed 'gg'
   7225 
   7226    api.nvim_buf_set_extmark(0, ns, 1, 0, { sign_text = 'S', hl_group = 'Todo', end_col = 1 })
   7227    screen:expect([[
   7228      {7:  }^l1                                              |
   7229      {7:S }{100:l}2                                              |
   7230      {7:  }l3                                              |
   7231      {7:  }l4                                              |
   7232      {7:  }l5                                              |
   7233      {7:  }                                                |
   7234      {1:~                                                 }|*3
   7235                                                        |
   7236    ]])
   7237 
   7238    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   7239  end)
   7240 
   7241  it('can add multiple signs (single extmark)', function()
   7242    insert(example_test3)
   7243    feed 'gg'
   7244 
   7245    api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S', end_row = 2 })
   7246 
   7247    screen:expect([[
   7248      {7:  }^l1                                              |
   7249      {7:S }l2                                              |
   7250      {7:S }l3                                              |
   7251      {7:  }l4                                              |
   7252      {7:  }l5                                              |
   7253      {7:  }                                                |
   7254      {1:~                                                 }|*3
   7255                                                        |
   7256    ]])
   7257  end)
   7258 
   7259  it('can add multiple signs (multiple extmarks)', function()
   7260    insert(example_test3)
   7261    feed 'gg'
   7262 
   7263    api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S1' })
   7264    api.nvim_buf_set_extmark(0, ns, 3, -1, { sign_text = 'S2', end_row = 4 })
   7265 
   7266    screen:expect([[
   7267      {7:  }^l1                                              |
   7268      {7:S1}l2                                              |
   7269      {7:  }l3                                              |
   7270      {7:S2}l4                                              |
   7271      {7:S2}l5                                              |
   7272      {7:  }                                                |
   7273      {1:~                                                 }|*3
   7274                                                        |
   7275    ]])
   7276  end)
   7277 
   7278  it('can add multiple signs (multiple extmarks) 2', function()
   7279    insert(example_test3)
   7280    feed 'gg'
   7281 
   7282    api.nvim_buf_set_extmark(0, ns, 3, -1, { sign_text = 'S1' })
   7283    api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2', end_row = 3 })
   7284    screen:expect([[
   7285      {7:    }^l1                                            |
   7286      {7:S2  }l2                                            |
   7287      {7:S2  }l3                                            |
   7288      {7:S2S1}l4                                            |
   7289      {7:    }l5                                            |
   7290      {7:    }                                              |
   7291      {1:~                                                 }|*3
   7292                                                        |
   7293    ]])
   7294  end)
   7295 
   7296  it('can add multiple signs (multiple extmarks) 3', function()
   7297    insert(example_test3)
   7298    feed 'gg'
   7299 
   7300    api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S1', end_row = 2 })
   7301    api.nvim_buf_set_extmark(0, ns, 2, -1, { sign_text = 'S2', end_row = 3 })
   7302 
   7303    screen:expect([[
   7304      {7:    }^l1                                            |
   7305      {7:S1  }l2                                            |
   7306      {7:S2S1}l3                                            |
   7307      {7:S2  }l4                                            |
   7308      {7:    }l5                                            |
   7309      {7:    }                                              |
   7310      {1:~                                                 }|*3
   7311                                                        |
   7312    ]])
   7313  end)
   7314 
   7315  it('can add multiple signs (multiple extmarks) 4', function()
   7316    insert(example_test3)
   7317    feed 'gg'
   7318 
   7319    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', end_row = 0 })
   7320    api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2', end_row = 1 })
   7321 
   7322    screen:expect([[
   7323      {7:S1}^l1                                              |
   7324      {7:S2}l2                                              |
   7325      {7:  }l3                                              |
   7326      {7:  }l4                                              |
   7327      {7:  }l5                                              |
   7328      {7:  }                                                |
   7329      {1:~                                                 }|*3
   7330                                                        |
   7331    ]])
   7332  end)
   7333 
   7334  it('works with old signs', function()
   7335    insert(example_test3)
   7336    feed 'gg'
   7337 
   7338    n.command('sign define Oldsign text=x')
   7339    n.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]])
   7340 
   7341    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1' })
   7342    api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2' })
   7343    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S4' })
   7344    api.nvim_buf_set_extmark(0, ns, 2, -1, { sign_text = 'S5' })
   7345 
   7346    screen:expect([[
   7347      {7:S4S1}^l1                                            |
   7348      {7:S2x }l2                                            |
   7349      {7:S5  }l3                                            |
   7350      {7:    }l4                                            |
   7351      {7:    }l5                                            |
   7352      {7:    }                                              |
   7353      {1:~                                                 }|*3
   7354                                                        |
   7355    ]])
   7356  end)
   7357 
   7358  it('works with old signs (with range)', function()
   7359    insert(example_test3)
   7360    feed 'gg'
   7361 
   7362    n.command('sign define Oldsign text=x')
   7363    n.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]])
   7364 
   7365    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1' })
   7366    api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S2' })
   7367    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S3', end_row = 4 })
   7368    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S4' })
   7369    api.nvim_buf_set_extmark(0, ns, 2, -1, { sign_text = 'S5' })
   7370 
   7371    screen:expect([[
   7372      {7:S4S3S1}^l1                                          |
   7373      {7:S3S2x }l2                                          |
   7374      {7:S5S3  }l3                                          |
   7375      {7:S3    }l4                                          |
   7376      {7:S3    }l5                                          |
   7377      {7:      }                                            |
   7378      {1:~                                                 }|*3
   7379                                                        |
   7380    ]])
   7381  end)
   7382 
   7383  it('can add a ranged sign (with start out of view)', function()
   7384    insert(example_test3)
   7385    command 'set signcolumn=yes:2'
   7386    feed 'gg'
   7387    feed '2<C-e>'
   7388 
   7389    api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'X', end_row = 3 })
   7390 
   7391    screen:expect([[
   7392      {7:X   }^l3                                            |
   7393      {7:X   }l4                                            |
   7394      {7:    }l5                                            |
   7395      {7:    }                                              |
   7396      {1:~                                                 }|*5
   7397                                                        |
   7398    ]])
   7399  end)
   7400 
   7401  it('can add lots of signs', function()
   7402    screen:try_resize(40, 10)
   7403    command 'normal 10oa b c d e f g h'
   7404 
   7405    for i = 1, 10 do
   7406      api.nvim_buf_set_extmark(0, ns, i, 0, { end_col = 1, hl_group = 'Todo' })
   7407      api.nvim_buf_set_extmark(0, ns, i, 2, { end_col = 3, hl_group = 'Todo' })
   7408      api.nvim_buf_set_extmark(0, ns, i, 4, { end_col = 5, hl_group = 'Todo' })
   7409      api.nvim_buf_set_extmark(0, ns, i, 6, { end_col = 7, hl_group = 'Todo' })
   7410      api.nvim_buf_set_extmark(0, ns, i, 8, { end_col = 9, hl_group = 'Todo' })
   7411      api.nvim_buf_set_extmark(0, ns, i, 10, { end_col = 11, hl_group = 'Todo' })
   7412      api.nvim_buf_set_extmark(0, ns, i, 12, { end_col = 13, hl_group = 'Todo' })
   7413      api.nvim_buf_set_extmark(0, ns, i, 14, { end_col = 15, hl_group = 'Todo' })
   7414      api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'W' })
   7415      api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'X' })
   7416      api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'Y' })
   7417      api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text = 'Z' })
   7418    end
   7419 
   7420    screen:expect([[
   7421      {7:Z Y X W }{100:a} {100:b} {100:c} {100:d} {100:e} {100:f} {100:g} {100:h}                 |*8
   7422      {7:Z Y X W }{100:a} {100:b} {100:c} {100:d} {100:e} {100:f} {100:g} {100:^h}                 |
   7423                                              |
   7424    ]])
   7425  end)
   7426 
   7427  it('works with priority #19716', function()
   7428    screen:try_resize(20, 3)
   7429    insert(example_test3)
   7430    feed 'gg'
   7431 
   7432    command('sign define Oldsign text=O3')
   7433    command([[exe 'sign place 42 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
   7434 
   7435    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S4', priority = 100 })
   7436    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S2', priority = 5 })
   7437    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S5', priority = 200 })
   7438    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', priority = 1 })
   7439 
   7440    screen:expect([[
   7441      {7:S5S4O3S2S1}^l1        |
   7442      {7:          }l2        |
   7443                          |
   7444    ]])
   7445 
   7446    -- Check truncation works too
   7447    api.nvim_set_option_value('signcolumn', 'auto', {})
   7448 
   7449    screen:expect([[
   7450      {7:S5}^l1                |
   7451      {7:  }l2                |
   7452                          |
   7453    ]])
   7454  end)
   7455 
   7456  it('does not overflow with many old signs #23852', function()
   7457    screen:try_resize(20, 3)
   7458 
   7459    command('set signcolumn:auto:9')
   7460    command('sign define Oldsign text=O3')
   7461    command([[exe 'sign place 01 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
   7462    command([[exe 'sign place 02 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
   7463    command([[exe 'sign place 03 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
   7464    command([[exe 'sign place 04 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
   7465    command([[exe 'sign place 05 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
   7466    command([[exe 'sign place 06 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
   7467    command([[exe 'sign place 07 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
   7468    command([[exe 'sign place 08 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
   7469    command([[exe 'sign place 09 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
   7470    screen:expect([[
   7471      {7:O3O3O3O3O3O3O3O3O3}^  |
   7472      {1:~                   }|
   7473                          |
   7474    ]])
   7475 
   7476    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', priority = 1 })
   7477    screen:expect_unchanged()
   7478 
   7479    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S5', priority = 200 })
   7480    screen:expect([[
   7481      {7:S5O3O3O3O3O3O3O3O3}^  |
   7482      {1:~                   }|
   7483                          |
   7484    ]])
   7485 
   7486    assert_alive()
   7487  end)
   7488 
   7489  it('does not set signcolumn for signs without text', function()
   7490    screen:try_resize(20, 3)
   7491    api.nvim_set_option_value('signcolumn', 'auto', {})
   7492    insert(example_test3)
   7493    feed 'gg'
   7494    api.nvim_buf_set_extmark(0, ns, 0, -1, { number_hl_group = 'Error' })
   7495    screen:expect { grid = [[
   7496      ^l1                  |
   7497      l2                  |
   7498                          |
   7499    ]] }
   7500  end)
   7501 
   7502  it('correct width when removing multiple signs from sentinel line', function()
   7503    screen:try_resize(20, 4)
   7504    insert(example_test3)
   7505    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1', end_row = 3 })
   7506    api.nvim_buf_set_extmark(0, ns, 1, -1, { invalidate = true, sign_text = 'S2' })
   7507    api.nvim_buf_set_extmark(0, ns, 1, -1, { invalidate = true, sign_text = 'S3' })
   7508    feed('2Gdd')
   7509 
   7510    screen:expect([[
   7511      {7:S1}l1                |
   7512      {7:S1}^l3                |
   7513      {7:S1}l4                |
   7514                          |
   7515    ]])
   7516  end)
   7517 
   7518  it('correct width with multiple overlapping signs', function()
   7519    screen:try_resize(20, 4)
   7520    insert(example_test3)
   7521    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S1' })
   7522    api.nvim_buf_set_extmark(0, ns, 0, -1, { sign_text = 'S2', end_row = 2 })
   7523    api.nvim_buf_set_extmark(0, ns, 1, -1, { sign_text = 'S3', end_row = 2 })
   7524    feed('gg')
   7525 
   7526    local s1 = [[
   7527      {7:S2S1}^l1              |
   7528      {7:S3S2}l2              |
   7529      {7:S3S2}l3              |
   7530                          |
   7531    ]]
   7532    screen:expect(s1)
   7533    -- Correct width when :move'ing a line with signs
   7534    command('move2')
   7535    screen:expect([[
   7536      {7:S3    }l2            |
   7537      {7:S3S2S1}^l1            |
   7538      {7:      }l3            |
   7539                          |
   7540    ]])
   7541    command('silent undo')
   7542    screen:expect { grid = s1 }
   7543    command('d')
   7544    screen:expect([[
   7545      {7:S3S2S1}^l2            |
   7546      {7:S3S2  }l3            |
   7547      {7:      }l4            |
   7548                          |
   7549    ]])
   7550    command('d')
   7551    screen:expect([[
   7552      {7:S3S2S1}^l3            |
   7553      {7:      }l4            |
   7554      {7:      }l5            |
   7555                          |
   7556    ]])
   7557  end)
   7558 
   7559  it('correct width when adding and removing multiple signs', function()
   7560    screen:try_resize(20, 4)
   7561    insert(example_test3)
   7562    feed('gg')
   7563    command([[
   7564      let ns = nvim_create_namespace('')
   7565      call nvim_buf_set_extmark(0, ns, 0, 0, {'sign_text':'S1', 'end_row':3})
   7566      let s1 = nvim_buf_set_extmark(0, ns, 2, 0, {'sign_text':'S2', 'end_row':4})
   7567      let s2 = nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'})
   7568      let s3 = nvim_buf_set_extmark(0, ns, 6, 0, {'sign_text':'S3'})
   7569      let s4 = nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'})
   7570      let s5 = nvim_buf_set_extmark(0, ns, 6, 0, {'sign_text':'S3'})
   7571      redraw!
   7572      call nvim_buf_del_extmark(0, ns, s2)
   7573      call nvim_buf_del_extmark(0, ns, s3)
   7574      call nvim_buf_del_extmark(0, ns, s4)
   7575      call nvim_buf_del_extmark(0, ns, s5)
   7576      redraw!
   7577      call nvim_buf_del_extmark(0, ns, s1)
   7578    ]])
   7579    screen:expect([[
   7580      {7:S1}^l1                |
   7581      {7:S1}l2                |
   7582      {7:S1}l3                |
   7583                          |
   7584    ]])
   7585  end)
   7586 
   7587  it('correct width when deleting lines', function()
   7588    screen:try_resize(20, 4)
   7589    insert(example_test3)
   7590    feed('gg')
   7591    command([[
   7592      let ns = nvim_create_namespace('')
   7593      call nvim_buf_set_extmark(0, ns, 4, 0, {'sign_text':'S1'})
   7594      call nvim_buf_set_extmark(0, ns, 4, 0, {'sign_text':'S2'})
   7595      let s3 =  nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'})
   7596      call nvim_buf_del_extmark(0, ns, s3)
   7597      norm 4Gdd
   7598    ]])
   7599    screen:expect([[
   7600      {7:    }l3              |
   7601      {7:S2S1}l5              |
   7602      {7:    }^                |
   7603                          |
   7604    ]])
   7605  end)
   7606 
   7607  it('correct width when splitting lines with signs on different columns', function()
   7608    screen:try_resize(20, 4)
   7609    insert(example_test3)
   7610    feed('gg')
   7611    api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' })
   7612    api.nvim_buf_set_extmark(0, ns, 0, 1, { sign_text = 'S2' })
   7613    feed('a<cr><esc>')
   7614    screen:expect([[
   7615      {7:S1}l                 |
   7616      {7:S2}^1                 |
   7617      {7:  }l2                |
   7618                          |
   7619    ]])
   7620  end)
   7621 
   7622  it('correct width after wiping a buffer', function()
   7623    screen:try_resize(20, 4)
   7624    insert(example_test3)
   7625    feed('gg')
   7626    local buf = api.nvim_get_current_buf()
   7627    api.nvim_buf_set_extmark(buf, ns, 0, 0, { sign_text = 'h' })
   7628    screen:expect([[
   7629      {7:h }^l1                |
   7630      {7:  }l2                |
   7631      {7:  }l3                |
   7632                          |
   7633    ]])
   7634    api.nvim_win_set_buf(0, api.nvim_create_buf(false, true))
   7635    api.nvim_buf_delete(buf, { unload = true, force = true })
   7636    api.nvim_buf_set_lines(buf, 0, -1, false, { '' })
   7637    api.nvim_win_set_buf(0, buf)
   7638    screen:expect { grid = [[
   7639      ^                    |
   7640      {1:~                   }|*2
   7641                          |
   7642    ]] }
   7643  end)
   7644 
   7645  it('correct width with moved marks before undo savepos', function()
   7646    screen:try_resize(20, 4)
   7647    insert(example_test3)
   7648    feed('gg')
   7649    exec_lua([[
   7650      local ns = vim.api.nvim_create_namespace('')
   7651      vim.api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' })
   7652      vim.api.nvim_buf_set_extmark(0, ns, 1, 0, { sign_text = 'S2' })
   7653      local s3 = vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = 'S3' })
   7654      local s4 = vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = 'S4' })
   7655      vim.schedule(function()
   7656        vim.cmd('silent d3')
   7657        vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { id = s3, sign_text = 'S3' })
   7658        vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { id = s4, sign_text = 'S4' })
   7659        vim.cmd('silent undo')
   7660        vim.api.nvim_buf_del_extmark(0, ns, s3)
   7661      end)
   7662    ]])
   7663 
   7664    screen:expect([[
   7665      {7:S1}^l1                |
   7666      {7:S2}l2                |
   7667      {7:S4}l3                |
   7668                          |
   7669    ]])
   7670  end)
   7671 
   7672  it('no crash with sign after many marks #27137', function()
   7673    screen:try_resize(20, 4)
   7674    insert('a')
   7675    for _ = 0, 104 do
   7676      api.nvim_buf_set_extmark(0, ns, 0, 0, { hl_group = 'Error', end_col = 1 })
   7677    end
   7678    api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' })
   7679 
   7680    screen:expect([[
   7681      {7:S1}{9:^a}                 |
   7682      {1:~                   }|*2
   7683                          |
   7684    ]])
   7685  end)
   7686 
   7687  it('correct sort order with multiple namespaces and same id', function()
   7688    local ns2 = api.nvim_create_namespace('')
   7689    api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1', id = 1 })
   7690    api.nvim_buf_set_extmark(0, ns2, 0, 0, { sign_text = 'S2', id = 1 })
   7691 
   7692    screen:expect([[
   7693      {7:S2S1}^                                              |
   7694      {1:~                                                 }|*8
   7695                                                        |
   7696    ]])
   7697  end)
   7698 
   7699  it('correct number of signs after deleting text (#27046)', function()
   7700    command('call setline(1, ["foo"]->repeat(31))')
   7701    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 0, sign_text = 'S1' })
   7702    api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 0, end_col = 3, hl_group = 'Error' })
   7703    api.nvim_buf_set_extmark(0, ns, 9, 0, { end_row = 9, sign_text = 'S2' })
   7704    api.nvim_buf_set_extmark(0, ns, 9, 0, { end_row = 9, end_col = 3, hl_group = 'Error' })
   7705    api.nvim_buf_set_extmark(0, ns, 19, 0, { end_row = 19, sign_text = 'S3' })
   7706    api.nvim_buf_set_extmark(0, ns, 19, 0, { end_row = 19, end_col = 3, hl_group = 'Error' })
   7707    api.nvim_buf_set_extmark(0, ns, 29, 0, { end_row = 29, sign_text = 'S4' })
   7708    api.nvim_buf_set_extmark(0, ns, 29, 0, { end_row = 29, end_col = 3, hl_group = 'Error' })
   7709    api.nvim_buf_set_extmark(0, ns, 30, 0, { end_row = 30, sign_text = 'S5' })
   7710    api.nvim_buf_set_extmark(0, ns, 30, 0, { end_row = 30, end_col = 3, hl_group = 'Error' })
   7711    command('0d29')
   7712 
   7713    screen:expect([[
   7714      {7:S4S3S2S1}{9:^foo}                                       |
   7715      {7:S5      }{9:foo}                                       |
   7716      {1:~                                                 }|*7
   7717      29 fewer lines                                    |
   7718    ]])
   7719 
   7720    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   7721  end)
   7722 
   7723  it([[correct numberwidth with 'signcolumn' set to "number" #28984]], function()
   7724    command('set number numberwidth=1 signcolumn=number')
   7725    api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' })
   7726    screen:expect([[
   7727      {7:S1 }^                                               |
   7728      {1:~                                                 }|*8
   7729                                                        |
   7730    ]])
   7731    api.nvim_buf_del_extmark(0, ns, 1)
   7732    screen:expect([[
   7733      {8:1 }^                                                |
   7734      {1:~                                                 }|*8
   7735                                                        |
   7736    ]])
   7737  end)
   7738 
   7739  it('supports emoji as signs', function()
   7740    insert(example_test3)
   7741    feed 'gg'
   7742    api.nvim_buf_set_extmark(0, ns, 1, 0, { sign_text = '🧑‍🌾' })
   7743    -- VS16 can change width of character
   7744    api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = '❤️' })
   7745    api.nvim_buf_set_extmark(0, ns, 3, 0, { sign_text = '❤' })
   7746    api.nvim_buf_set_extmark(0, ns, 4, 0, { sign_text = '❤x' })
   7747    screen:expect([[
   7748      {7:  }^l1                                              |
   7749      {7:🧑‍🌾}l2                                              |
   7750      {7:❤️}l3                                              |
   7751      {7: }l4                                              |
   7752      {7:x}l5                                              |
   7753      {7:  }                                                |
   7754      {1:~                                                 }|*3
   7755                                                        |
   7756    ]])
   7757    eq("Invalid 'sign_text'", pcall_err(api.nvim_buf_set_extmark, 0, ns, 5, 0, { sign_text = '❤️x' }))
   7758  end)
   7759 
   7760  it('auto signcolumn hides with invalidated sign', function()
   7761    api.nvim_set_option_value('signcolumn', 'auto', {})
   7762    api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1', invalidate = true })
   7763    feed('ia<cr>b<esc>dd')
   7764    screen:expect({
   7765      grid = [[
   7766        ^a                                                 |
   7767        {1:~                                                 }|*8
   7768                                                          |
   7769      ]],
   7770    })
   7771  end)
   7772 
   7773  it('signcolumn correctly tracked with signs beyond eob and pair end before start', function()
   7774    api.nvim_set_option_value('signcolumn', 'auto:2', {})
   7775    api.nvim_set_option_value('filetype', 'lua', {})
   7776    api.nvim_buf_set_lines(0, 0, -1, false, { 'foo', 'bar' })
   7777    api.nvim_buf_set_extmark(0, ns, 2, 0, { sign_text = 'S1' })
   7778    api.nvim_set_hl(0, 'SignColumn', { link = 'Error' })
   7779    screen:expect([[
   7780      ^foo                                               |
   7781      bar                                               |
   7782      {1:~                                                 }|*7
   7783                                                        |
   7784    ]])
   7785    api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S2', end_row = 1 })
   7786    api.nvim_buf_set_lines(0, 0, -1, false, { '-- foo', '-- bar' })
   7787    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   7788    screen:expect([[
   7789      ^-- foo                                            |
   7790      -- bar                                            |
   7791      {1:~                                                 }|*7
   7792                                                        |
   7793    ]])
   7794    assert_alive()
   7795  end)
   7796 end)
   7797 
   7798 describe('decorations: virt_text', function()
   7799  local ns, screen ---@type integer, test.functional.ui.screen
   7800 
   7801  before_each(function()
   7802    clear()
   7803    screen = Screen.new(50, 10)
   7804    ns = api.nvim_create_namespace('test')
   7805  end)
   7806 
   7807  it('avoids regression in #17638', function()
   7808    command 'set number relativenumber'
   7809    command 'normal 4ohello'
   7810    command 'normal aVIRTUAL'
   7811 
   7812    api.nvim_buf_set_extmark(0, ns, 2, 0, {
   7813      virt_text = { { 'hello', 'String' } },
   7814      virt_text_win_col = 20,
   7815    })
   7816 
   7817    screen:expect {
   7818      grid = [[
   7819      {8:  4 }                                              |
   7820      {8:  3 }hello                                         |
   7821      {8:  2 }hello               {26:hello}                     |
   7822      {8:  1 }hello                                         |
   7823      {8:5   }helloVIRTUA^L                                  |
   7824      {1:~                                                 }|*4
   7825                                                        |
   7826    ]],
   7827    }
   7828 
   7829    -- Trigger a screen update
   7830    feed('k')
   7831 
   7832    screen:expect {
   7833      grid = [[
   7834      {8:  3 }                                              |
   7835      {8:  2 }hello                                         |
   7836      {8:  1 }hello               {26:hello}                     |
   7837      {8:4   }hell^o                                         |
   7838      {8:  1 }helloVIRTUAL                                  |
   7839      {1:~                                                 }|*4
   7840                                                        |
   7841    ]],
   7842    }
   7843  end)
   7844 
   7845  it('redraws correctly when re-using extmark ids', function()
   7846    command 'normal 5ohello'
   7847 
   7848    screen:expect {
   7849      grid = [[
   7850                                                        |
   7851      hello                                             |*4
   7852      hell^o                                             |
   7853      {1:~                                                 }|*3
   7854                                                        |
   7855    ]],
   7856    }
   7857 
   7858    for row = 1, 5 do
   7859      api.nvim_buf_set_extmark(0, ns, row, 0, { id = 1, virt_text = { { 'world', 'Normal' } } })
   7860    end
   7861 
   7862    screen:expect {
   7863      grid = [[
   7864                                                        |
   7865      hello                                             |*4
   7866      hell^o world                                       |
   7867      {1:~                                                 }|*3
   7868                                                        |
   7869    ]],
   7870    }
   7871  end)
   7872 
   7873  it('redraws correctly when removing mark whose end ends up in front of start', function()
   7874    command('normal 5ohello')
   7875    api.nvim_buf_set_extmark(0, ns, 2, 0, { end_col = 1, virt_text = { { 'world', 'Normal' } } })
   7876    screen:expect([[
   7877                                                        |
   7878      hello                                             |
   7879      hello world                                       |
   7880      hello                                             |*2
   7881      hell^o                                             |
   7882      {1:~                                                 }|*3
   7883                                                        |
   7884    ]])
   7885    feed('3Gdd')
   7886    api.nvim_buf_clear_namespace(0, ns, 0, -1)
   7887    screen:expect([[
   7888                                                        |
   7889      hello                                             |
   7890      ^hello                                             |
   7891      hello                                             |*2
   7892      {1:~                                                 }|*4
   7893                                                        |
   7894    ]])
   7895  end)
   7896 end)
   7897 
   7898 describe('decorations: window scoped', function()
   7899  local screen ---@type test.functional.ui.screen
   7900  local ns ---@type integer
   7901  local win_other ---@type integer
   7902 
   7903  local url = 'https://example.com'
   7904  before_each(function()
   7905    clear()
   7906    screen = Screen.new(20, 10)
   7907    screen:add_extra_attr_ids {
   7908      [100] = { special = Screen.colors.Red, undercurl = true },
   7909      [101] = { url = 'https://example.com' },
   7910    }
   7911 
   7912    ns = api.nvim_create_namespace 'test'
   7913 
   7914    insert('12345')
   7915 
   7916    win_other = api.nvim_open_win(0, false, {
   7917      col = 0,
   7918      row = 0,
   7919      width = 20,
   7920      height = 10,
   7921      relative = 'win',
   7922      style = 'minimal',
   7923      hide = true,
   7924    })
   7925  end)
   7926 
   7927  local noextmarks = {
   7928    grid = [[
   7929      1234^5               |
   7930      {1:~                   }|*8
   7931                          |
   7932    ]],
   7933  }
   7934 
   7935  local function set_extmark(line, col, opts)
   7936    return api.nvim_buf_set_extmark(0, ns, line, col, opts)
   7937  end
   7938 
   7939  it('hl_group', function()
   7940    set_extmark(0, 0, {
   7941      hl_group = 'Comment',
   7942      end_col = 3,
   7943    })
   7944 
   7945    api.nvim__ns_set(ns, { wins = { 0 } })
   7946 
   7947    screen:expect {
   7948      grid = [[
   7949      {18:123}4^5               |
   7950      {1:~                   }|*8
   7951                          |
   7952    ]],
   7953    }
   7954 
   7955    command 'split'
   7956    command 'only'
   7957 
   7958    screen:expect(noextmarks)
   7959  end)
   7960 
   7961  it('virt_text', function()
   7962    set_extmark(0, 0, {
   7963      virt_text = { { 'a', 'Comment' } },
   7964      virt_text_pos = 'eol',
   7965    })
   7966    set_extmark(0, 5, {
   7967      virt_text = { { 'b', 'Comment' } },
   7968      virt_text_pos = 'inline',
   7969    })
   7970    set_extmark(0, 1, {
   7971      virt_text = { { 'c', 'Comment' } },
   7972      virt_text_pos = 'overlay',
   7973    })
   7974    set_extmark(0, 1, {
   7975      virt_text = { { 'd', 'Comment' } },
   7976      virt_text_pos = 'right_align',
   7977    })
   7978 
   7979    api.nvim__ns_set(ns, { wins = { 0 } })
   7980 
   7981    screen:expect {
   7982      grid = [[
   7983      1{18:c}34^5{18:b} {18:a}           {18:d}|
   7984      {1:~                   }|*8
   7985                          |
   7986    ]],
   7987    }
   7988 
   7989    command 'split'
   7990    command 'only'
   7991 
   7992    screen:expect(noextmarks)
   7993 
   7994    api.nvim__ns_set(ns, { wins = {} })
   7995 
   7996    screen:expect {
   7997      grid = [[
   7998      1{18:c}34^5{18:b} {18:a}           {18:d}|
   7999      {1:~                   }|*8
   8000                          |
   8001    ]],
   8002    }
   8003  end)
   8004 
   8005  it('virt_lines', function()
   8006    set_extmark(0, 0, {
   8007      virt_lines = { { { 'a', 'Comment' } } },
   8008    })
   8009 
   8010    api.nvim__ns_set(ns, { wins = { 0 } })
   8011 
   8012    screen:expect {
   8013      grid = [[
   8014      1234^5               |
   8015      {18:a}                   |
   8016      {1:~                   }|*7
   8017                          |
   8018    ]],
   8019    }
   8020 
   8021    command 'split'
   8022    command 'only'
   8023 
   8024    screen:expect(noextmarks)
   8025  end)
   8026 
   8027  it('redraws correctly with inline virt_text and wrapping', function()
   8028    set_extmark(0, 2, {
   8029      virt_text = { { ('b'):rep(18), 'Comment' } },
   8030      virt_text_pos = 'inline',
   8031    })
   8032 
   8033    api.nvim__ns_set(ns, { wins = { 0 } })
   8034 
   8035    screen:expect {
   8036      grid = [[
   8037      12{18:bbbbbbbbbbbbbbbbbb}|
   8038      34^5                 |
   8039      {1:~                   }|*7
   8040                          |
   8041    ]],
   8042    }
   8043 
   8044    api.nvim__ns_set(ns, { wins = { win_other } })
   8045 
   8046    screen:expect(noextmarks)
   8047  end)
   8048 
   8049  pending('sign_text', function()
   8050    -- TODO(altermo): The window signcolumn width is calculated wrongly (when `signcolumn=auto`)
   8051    -- This happens in function `win_redraw_signcols` on line containing `buf_meta_total(buf, kMTMetaSignText) > 0`
   8052    set_extmark(0, 0, {
   8053      sign_text = 'a',
   8054      sign_hl_group = 'Comment',
   8055    })
   8056 
   8057    api.nvim__ns_set(ns, { wins = { 0 } })
   8058 
   8059    screen:expect {
   8060      grid = [[
   8061      a 1234^5             |
   8062      {2:~                   }|*8
   8063                          |
   8064    ]],
   8065    }
   8066 
   8067    command 'split'
   8068    command 'only'
   8069 
   8070    screen:expect(noextmarks)
   8071  end)
   8072 
   8073  it('statuscolumn hl group', function()
   8074    set_extmark(0, 0, {
   8075      number_hl_group = 'comment',
   8076    })
   8077    set_extmark(0, 0, {
   8078      line_hl_group = 'comment',
   8079    })
   8080 
   8081    command 'set number'
   8082 
   8083    api.nvim__ns_set(ns, { wins = { win_other } })
   8084 
   8085    screen:expect {
   8086      grid = [[
   8087      {8:  1 }1234^5           |
   8088      {1:~                   }|*8
   8089                          |
   8090    ]],
   8091    }
   8092 
   8093    api.nvim__ns_set(ns, { wins = { 0 } })
   8094 
   8095    screen:expect {
   8096      grid = [[
   8097      {18:  1 1234^5           }|
   8098      {1:~                   }|*8
   8099                          |
   8100    ]],
   8101    }
   8102 
   8103    command 'split'
   8104    command 'only'
   8105 
   8106    screen:expect {
   8107      grid = [[
   8108      {8:  1 }1234^5           |
   8109      {1:~                   }|*8
   8110                          |
   8111    ]],
   8112    }
   8113  end)
   8114 
   8115  it('spell', function()
   8116    api.nvim_buf_set_lines(0, 0, -1, true, { 'aa' })
   8117 
   8118    set_extmark(0, 0, {
   8119      spell = true,
   8120      end_col = 2,
   8121    })
   8122 
   8123    command 'set spelloptions=noplainbuffer'
   8124    command 'set spell'
   8125    command 'syntax off'
   8126 
   8127    screen:expect({ unchanged = true })
   8128 
   8129    api.nvim__ns_set(ns, { wins = { win_other } })
   8130 
   8131    screen:expect {
   8132      grid = [[
   8133      a^a                  |
   8134      {1:~                   }|*8
   8135                          |
   8136    ]],
   8137    }
   8138 
   8139    api.nvim__ns_set(ns, { wins = { 0 } })
   8140 
   8141    screen:expect {
   8142      grid = [[
   8143      {100:a^a}                  |
   8144      {1:~                   }|*8
   8145                          |
   8146    ]],
   8147    }
   8148 
   8149    command 'split'
   8150    command 'only'
   8151 
   8152    screen:expect {
   8153      grid = [[
   8154      a^a                  |
   8155      {1:~                   }|*8
   8156                          |
   8157    ]],
   8158    }
   8159  end)
   8160 
   8161  it('url', function()
   8162    set_extmark(0, 0, {
   8163      end_col = 3,
   8164      url = url,
   8165    })
   8166 
   8167    api.nvim__ns_set(ns, { wins = { 0 } })
   8168 
   8169    screen:expect {
   8170      grid = [[
   8171      {101:123}4^5               |
   8172      {1:~                   }|*8
   8173                          |
   8174    ]],
   8175    }
   8176 
   8177    command 'split'
   8178    command 'only'
   8179 
   8180    screen:expect(noextmarks)
   8181  end)
   8182 
   8183  it('change namespace scope', function()
   8184    set_extmark(0, 0, {
   8185      hl_group = 'Comment',
   8186      end_col = 3,
   8187    })
   8188 
   8189    api.nvim__ns_set(ns, { wins = { 0 } })
   8190    eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
   8191 
   8192    screen:expect {
   8193      grid = [[
   8194      {18:123}4^5               |
   8195      {1:~                   }|*8
   8196                          |
   8197    ]],
   8198    }
   8199 
   8200    command 'split'
   8201    command 'only'
   8202 
   8203    screen:expect(noextmarks)
   8204 
   8205    api.nvim__ns_set(ns, { wins = { 0 } })
   8206    eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
   8207 
   8208    screen:expect {
   8209      grid = [[
   8210      {18:123}4^5               |
   8211      {1:~                   }|*8
   8212                          |
   8213    ]],
   8214    }
   8215 
   8216    local win_new = api.nvim_open_win(0, false, {
   8217      col = 0,
   8218      row = 0,
   8219      width = 20,
   8220      height = 10,
   8221      relative = 'win',
   8222      style = 'minimal',
   8223      hide = true,
   8224    })
   8225 
   8226    api.nvim__ns_set(ns, { wins = { win_new } })
   8227    eq({ wins = { win_new } }, api.nvim__ns_get(ns))
   8228 
   8229    screen:expect(noextmarks)
   8230  end)
   8231 
   8232  it('namespace get works', function()
   8233    eq({ wins = {} }, api.nvim__ns_get(ns))
   8234 
   8235    api.nvim__ns_set(ns, { wins = { 0 } })
   8236 
   8237    eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
   8238 
   8239    api.nvim__ns_set(ns, { wins = {} })
   8240 
   8241    eq({ wins = {} }, api.nvim__ns_get(ns))
   8242  end)
   8243 
   8244  it('remove window from namespace scope when deleted', function()
   8245    api.nvim__ns_set(ns, { wins = { 0 } })
   8246 
   8247    eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
   8248 
   8249    command 'split'
   8250    command 'only'
   8251 
   8252    eq({ wins = {} }, api.nvim__ns_get(ns))
   8253  end)
   8254 end)