Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

neovim/tests/bugabinga/cmdline/popupmenu_spec.lua

Raw
describe('popupmenu.on_show', function()
  before_each(function()
    package.loaded['bugabinga.cmdline.popupmenu'] = nil
  end)

  after_each(function()
    local ok, popupmenu = pcall(require, 'bugabinga.cmdline.popupmenu')
    if ok then
      popupmenu.on_hide()
    end
  end)

  it('handles empty items', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    local ok = pcall(function()
      popupmenu.on_show({}, -1, 0, 0, -1)
    end)
    assert.is_true(ok)
  end)

  it('creates window with items', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    local initial_win_count = #vim.api.nvim_list_wins()
    popupmenu.on_show({{'foo', 'Variable', ''}, {'bar', 'Function', ''}}, 0, 0, 0, -1)
    local wins = vim.api.nvim_list_wins()
    assert.equal(initial_win_count + 1, #wins, 'should create a new window')
    local new_win = wins[#wins]
    local config = vim.api.nvim_win_get_config(new_win)
    assert(type(config) == 'table', 'window config should be a table')
    local buf = vim.api.nvim_win_get_buf(new_win)
    local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
    assert(#lines > 0, 'buffer should have lines')
  end)

  it('hides safely when no window exists', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    local ok = pcall(function()
      popupmenu.on_hide()
      popupmenu.on_hide()
    end)
    assert.is_true(ok)
  end)
end)

describe('popupmenu.on_select', function()
  before_each(function()
    package.loaded['bugabinga.cmdline.popupmenu'] = nil
  end)

  after_each(function()
    local ok, popupmenu = pcall(require, 'bugabinga.cmdline.popupmenu')
    if ok then
      popupmenu.on_hide()
    end
  end)

  it('does not error without window', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    local ok = pcall(function()
      popupmenu.on_select(0)
    end)
    assert.is_true(ok)
  end)
end)

describe('popupmenu buffer cleanup', function()
  before_each(function()
    package.loaded['bugabinga.cmdline.popupmenu'] = nil
  end)

  after_each(function()
    local ok, popupmenu = pcall(require, 'bugabinga.cmdline.popupmenu')
    if ok then
      popupmenu.on_hide()
    end
  end)

  it('deletes buffer after on_hide', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    local initial_buf_count = #vim.api.nvim_list_bufs()
    popupmenu.on_show({{'foo', 'Variable', ''}}, 0, 0, 0, -1)
    local buf_count_after_show = #vim.api.nvim_list_bufs()
    assert(buf_count_after_show > initial_buf_count, 'should create a new buffer')
    local wins_before_hide = #vim.api.nvim_list_wins()
    popupmenu.on_hide()
    local wins_after_hide = #vim.api.nvim_list_wins()
    assert(wins_after_hide < wins_before_hide, 'window should be hidden')
    assert(buf_count_after_show > #vim.api.nvim_list_bufs(), 'buffer should be deleted')
    local ok = pcall(popupmenu.on_hide)
    assert(ok, 'on_hide should be idempotent')
  end)
end)

describe('popupmenu highlights', function()
  before_each(function()
    package.loaded['bugabinga.cmdline.popupmenu'] = nil
    package.loaded['bugabinga.cmdline.render'] = nil
    package.loaded['bugabinga.cmdline.position'] = nil
  end)

  after_each(function()
    local ok, popupmenu = pcall(require, 'bugabinga.cmdline.popupmenu')
    if ok then
      popupmenu.on_hide()
    end
  end)

  local function find_buf()
    local wins = vim.api.nvim_list_wins()
    for _, win in ipairs(wins) do
      local config = vim.api.nvim_win_get_config(win)
      if config.zindex and config.zindex == 201 then
        return vim.api.nvim_win_get_buf(win)
      end
    end
    return nil
  end

  local function get_extmarks(buf)
    local ns = vim.api.nvim_create_namespace 'bugabinga.cmdline.popupmenu'
    return vim.api.nvim_buf_get_extmarks(buf, ns, 0, -1, { details = true })
  end

  it('applies PmenuMatch extmark when prefix matches abbr', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    popupmenu.on_show({{'foobar', '', ''}}, 0, 0, 0, -1, 'foo')
    local buf = find_buf()
    assert(buf ~= nil, 'popupmenu buffer should exist')
    local extmarks = get_extmarks(buf)
    local match_marks = vim.iter(extmarks):filter(function(m)
      return m[4].hl_group == 'PmenuMatch'
    end):totable()
    assert.equal(1, #match_marks, 'should have one PmenuMatch extmark')
    assert.equal(0, match_marks[1][3], 'PmenuMatch should start at col 0')
    assert.equal(3, match_marks[1][4].end_col, 'PmenuMatch should span 3 bytes (foo)')
  end)

  it('applies PmenuKind extmark over kind icon', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    popupmenu.on_show({{'bar', 'Function', ''}}, 0, 0, 0, -1, '')
    local buf = find_buf()
    assert.is_not_nil(buf)
    local extmarks = get_extmarks(buf)
    local kind_marks = vim.iter(extmarks):filter(function(m)
      return m[4].hl_group == 'PmenuKind'
    end):totable()
    assert.equal(1, #kind_marks, 'should have one PmenuKind extmark')
    assert.equal(0, kind_marks[1][3], 'PmenuKind should start at col 0')
    assert(kind_marks[1][4].end_col > 1, 'PmenuKind should span icon + space')
  end)

  it('applies no extmarks when prefix empty and no kind', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    popupmenu.on_show({{'baz', '', ''}}, 0, 0, 0, -1, '')
    local buf = find_buf()
    assert.is_not_nil(buf)
    local extmarks = get_extmarks(buf)
    assert.equal(0, #extmarks, 'should have no extmarks')
  end)

  it('applies both PmenuMatch and PmenuKind when both apply', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    local icon = require 'std.icon'
    popupmenu.on_show({{'foobar', 'Variable', ''}}, 0, 0, 0, -1, 'foo')
    local buf = find_buf()
    assert.is_not_nil(buf)
    local extmarks = get_extmarks(buf)
    local hl_groups = vim.iter(extmarks):map(function(m)
      return m[4].hl_group
    end):totable()
    assert(vim.list_contains(hl_groups, 'PmenuMatch'), 'should have PmenuMatch')
    assert(vim.list_contains(hl_groups, 'PmenuKind'), 'should have PmenuKind')
  end)

  it('applies no PmenuMatch when prefix does not match abbr', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    popupmenu.on_show({{'bar', '', ''}}, 0, 0, 0, -1, 'foo')
    local buf = find_buf()
    assert.is_not_nil(buf)
    local extmarks = get_extmarks(buf)
    local match_marks = vim.iter(extmarks):filter(function(m)
      return m[4].hl_group == 'PmenuMatch'
    end):totable()
    assert.equal(0, #match_marks, 'should have no PmenuMatch when prefix does not match')
  end)

  it('offsets PmenuMatch by kind icon when kind present', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    popupmenu.on_show({{'foobar', 'Function', ''}}, 0, 0, 0, -1, 'foo')
    local buf = find_buf()
    assert.is_not_nil(buf)
    local extmarks = get_extmarks(buf)
    local match_marks = vim.iter(extmarks):filter(function(m)
      return m[4].hl_group == 'PmenuMatch'
    end):totable()
    assert.equal(1, #match_marks)
    local kind_marks = vim.iter(extmarks):filter(function(m)
      return m[4].hl_group == 'PmenuKind'
    end):totable()
    assert.equal(1, #kind_marks, 'should have a PmenuKind extmark')
    assert.equal(kind_marks[1][4].end_col, match_marks[1][3], 'PmenuMatch should start where PmenuKind ended')
    assert.equal(match_marks[1][3] + 3, match_marks[1][4].end_col, 'PmenuMatch should span 3 bytes')
  end)

  it('highlights multiple items each with their own match extmark', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    popupmenu.on_show({{'foo', '', ''}, {'fbar', '', ''}}, 0, 0, 0, -1, 'f')
    local buf = find_buf()
    assert.is_not_nil(buf)
    local extmarks = get_extmarks(buf)
    local match_marks = vim.iter(extmarks):filter(function(m)
      return m[4].hl_group == 'PmenuMatch'
    end):totable()
    assert.equal(2, #match_marks, 'each item should have its own PmenuMatch extmark')
  end)

  it('does not error when prefix is nil', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    local ok = pcall(function()
      popupmenu.on_show({{'foo', '', ''}}, 0, 0, 0, -1)
    end)
    assert(ok, 'should not error with nil prefix')
    local buf = find_buf()
    assert.is_not_nil(buf)
    local extmarks = get_extmarks(buf)
    local match_marks = vim.iter(extmarks):filter(function(m)
      return m[4].hl_group == 'PmenuMatch'
    end):totable()
    assert.equal(0, #match_marks, 'should have no PmenuMatch with nil/empty prefix')
  end)
end)

describe('popupmenu scrollbar', function()
  before_each(function()
    package.loaded['bugabinga.cmdline.popupmenu'] = nil
    package.loaded['bugabinga.cmdline.render'] = nil
    package.loaded['bugabinga.cmdline.position'] = nil
  end)

  after_each(function()
    local ok, popupmenu = pcall(require, 'bugabinga.cmdline.popupmenu')
    if ok then
      popupmenu.on_hide()
    end
  end)

  local function find_buf()
    local wins = vim.api.nvim_list_wins()
    for _, win in ipairs(wins) do
      local config = vim.api.nvim_win_get_config(win)
      if config.zindex and config.zindex == 201 then
        return vim.api.nvim_win_get_buf(win)
      end
    end
    return nil
  end

  local function get_scroll_extmarks(buf)
    if not buf or not vim.api.nvim_buf_is_valid(buf) then
      return {}
    end
    local ns = vim.api.nvim_create_namespace 'bugabinga.cmdline.popupmenu'
    local marks = vim.api.nvim_buf_get_extmarks(buf, ns, 0, -1, { details = true })
    return vim.iter(marks):filter(function(m)
      local vt = m[4].virt_text
      return vt and (#vt > 0)
    end):totable()
  end

  it('no scrollbar when items fit in viewport', function()
    local popupmenu = require 'bugabinga.cmdline.popupmenu'
    popupmenu.on_show({{'a','',''}, {'b','',''}, {'c','',''}}, 0, 0, 0, -1, '')
    local buf = find_buf()
    assert(buf ~= nil, 'popupmenu should exist')
    local scroll_marks = get_scroll_extmarks(buf)
    assert.equal(0, #scroll_marks, 'no scrollbar when items fit (pumheight unlimited = all visible)')
  end)
end)