Some checks failed
		
		
	
	Detach Plugins / check (FlyGrep.vim) (push) Has been cancelled
				
			Detach Plugins / check (GitHub.vim) (push) Has been cancelled
				
			Detach Plugins / check (JavaUnit.vim) (push) Has been cancelled
				
			Detach Plugins / check (SourceCounter.vim) (push) Has been cancelled
				
			Detach Plugins / check (cpicker.nvim) (push) Has been cancelled
				
			Detach Plugins / check (dein-ui.vim) (push) Has been cancelled
				
			Detach Plugins / check (git.vim) (push) Has been cancelled
				
			Detach Plugins / check (iedit.vim) (push) Has been cancelled
				
			Detach Plugins / check (scrollbar.vim) (push) Has been cancelled
				
			Detach Plugins / check (vim-chat) (push) Has been cancelled
				
			Detach Plugins / check (vim-cheat) (push) Has been cancelled
				
			Detach Plugins / check (vim-todo) (push) Has been cancelled
				
			Detach Plugins / check (xmake.vim) (push) Has been cancelled
				
			test / Linux (nvim, nightly) (push) Has been cancelled
				
			test / Linux (nvim, v0.3.8) (push) Has been cancelled
				
			test / Linux (nvim, v0.4.0) (push) Has been cancelled
				
			test / Linux (nvim, v0.4.2) (push) Has been cancelled
				
			test / Linux (nvim, v0.4.3) (push) Has been cancelled
				
			test / Linux (nvim, v0.4.4) (push) Has been cancelled
				
			test / Linux (nvim, v0.5.0) (push) Has been cancelled
				
			test / Linux (nvim, v0.5.1) (push) Has been cancelled
				
			test / Linux (nvim, v0.6.0) (push) Has been cancelled
				
			test / Linux (nvim, v0.6.1) (push) Has been cancelled
				
			test / Linux (nvim, v0.7.0) (push) Has been cancelled
				
			test / Linux (nvim, v0.7.2) (push) Has been cancelled
				
			test / Linux (nvim, v0.8.0) (push) Has been cancelled
				
			test / Linux (nvim, v0.8.1) (push) Has been cancelled
				
			test / Linux (nvim, v0.8.2) (push) Has been cancelled
				
			test / Linux (nvim, v0.8.3) (push) Has been cancelled
				
			test / Linux (nvim, v0.9.0) (push) Has been cancelled
				
			test / Linux (nvim, v0.9.1) (push) Has been cancelled
				
			test / Linux (true, vim, v7.4.052) (push) Has been cancelled
				
			test / Linux (true, vim, v7.4.1689) (push) Has been cancelled
				
			test / Linux (true, vim, v7.4.629) (push) Has been cancelled
				
			test / Linux (true, vim, v8.0.0027) (push) Has been cancelled
				
			test / Linux (true, vim, v8.0.0183) (push) Has been cancelled
				
			test / Linux (vim, nightly) (push) Has been cancelled
				
			test / Linux (vim, v8.0.0184) (push) Has been cancelled
				
			test / Linux (vim, v8.0.1453) (push) Has been cancelled
				
			test / Linux (vim, v8.1.2269) (push) Has been cancelled
				
			test / Linux (vim, v8.2.2434) (push) Has been cancelled
				
			test / Linux (vim, v8.2.3995) (push) Has been cancelled
				
			test / Windows (nvim, nightly) (push) Has been cancelled
				
			test / Windows (nvim, v0.3.8) (push) Has been cancelled
				
			test / Windows (nvim, v0.4.2) (push) Has been cancelled
				
			test / Windows (nvim, v0.4.3) (push) Has been cancelled
				
			test / Windows (nvim, v0.4.4) (push) Has been cancelled
				
			test / Windows (nvim, v0.5.0) (push) Has been cancelled
				
			test / Windows (nvim, v0.5.1) (push) Has been cancelled
				
			test / Windows (nvim, v0.6.0) (push) Has been cancelled
				
			test / Windows (nvim, v0.6.1) (push) Has been cancelled
				
			test / Windows (nvim, v0.7.0) (push) Has been cancelled
				
			test / Windows (nvim, v0.7.2) (push) Has been cancelled
				
			test / Windows (nvim, v0.8.0) (push) Has been cancelled
				
			test / Windows (nvim, v0.8.1) (push) Has been cancelled
				
			test / Windows (nvim, v0.8.2) (push) Has been cancelled
				
			test / Windows (nvim, v0.8.3) (push) Has been cancelled
				
			test / Windows (nvim, v0.9.0) (push) Has been cancelled
				
			test / Windows (nvim, v0.9.1) (push) Has been cancelled
				
			test / Windows (vim, nightly) (push) Has been cancelled
				
			test / Windows (vim, v7.4.1185) (push) Has been cancelled
				
			test / Windows (vim, v7.4.1689) (push) Has been cancelled
				
			test / Windows (vim, v8.0.0027) (push) Has been cancelled
				
			test / Windows (vim, v8.0.1453) (push) Has been cancelled
				
			test / Windows (vim, v8.1.2269) (push) Has been cancelled
				
			test / Windows (vim, v8.2.2434) (push) Has been cancelled
				
			test / Windows (vim, v8.2.3995) (push) Has been cancelled
				
			docker / docker (push) Has been cancelled
				
			mirror / check (coding) (push) Has been cancelled
				
			mirror / check (gitee) (push) Has been cancelled
				
			mirror / check (gitlab) (push) Has been cancelled
				
			
		
			
				
	
	
		
			485 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			485 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
--- popup.lua
 | 
						|
---
 | 
						|
--- Wrapper to make the popup api from vim in neovim.
 | 
						|
--- Hope to get this part merged in at some point in the future.
 | 
						|
---
 | 
						|
--- Please make sure to update "POPUP.md" with any changes and/or notes.
 | 
						|
 | 
						|
local Border = require "plenary.window.border"
 | 
						|
local Window = require "plenary.window"
 | 
						|
local utils = require "plenary.popup.utils"
 | 
						|
 | 
						|
local if_nil = vim.F.if_nil
 | 
						|
 | 
						|
local popup = {}
 | 
						|
 | 
						|
popup._pos_map = {
 | 
						|
  topleft = "NW",
 | 
						|
  topright = "NE",
 | 
						|
  botleft = "SW",
 | 
						|
  botright = "SE",
 | 
						|
}
 | 
						|
 | 
						|
-- Keep track of hidden popups, so we can load them with popup.show()
 | 
						|
popup._hidden = {}
 | 
						|
 | 
						|
-- Keep track of popup borders, so we don't have to pass them between functions
 | 
						|
popup._borders = {}
 | 
						|
 | 
						|
local function dict_default(options, key, default)
 | 
						|
  if options[key] == nil then
 | 
						|
    return default[key]
 | 
						|
  else
 | 
						|
    return options[key]
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
-- Callbacks to be called later by popup.execute_callback
 | 
						|
popup._callbacks = {}
 | 
						|
 | 
						|
-- Convert the positional {vim_options} to compatible neovim options and add them to {win_opts}
 | 
						|
-- If an option is not given in {vim_options}, fall back to {default_opts}
 | 
						|
local function add_position_config(win_opts, vim_options, default_opts)
 | 
						|
  default_opts = default_opts or {}
 | 
						|
 | 
						|
  local cursor_relative_pos = function(pos_str, dim)
 | 
						|
    assert(string.find(pos_str, "^cursor"), "Invalid value for " .. dim)
 | 
						|
    win_opts.relative = "cursor"
 | 
						|
    local line = 0
 | 
						|
    if (pos_str):match "cursor%+(%d+)" then
 | 
						|
      line = line + tonumber((pos_str):match "cursor%+(%d+)")
 | 
						|
    elseif (pos_str):match "cursor%-(%d+)" then
 | 
						|
      line = line - tonumber((pos_str):match "cursor%-(%d+)")
 | 
						|
    end
 | 
						|
    return line
 | 
						|
  end
 | 
						|
 | 
						|
  -- Feels like maxheight, minheight, maxwidth, minwidth will all be related
 | 
						|
  --
 | 
						|
  -- maxheight  Maximum height of the contents, excluding border and padding.
 | 
						|
  -- minheight  Minimum height of the contents, excluding border and padding.
 | 
						|
  -- maxwidth  Maximum width of the contents, excluding border, padding and scrollbar.
 | 
						|
  -- minwidth  Minimum width of the contents, excluding border, padding and scrollbar.
 | 
						|
  local width = if_nil(vim_options.width, default_opts.width)
 | 
						|
  local height = if_nil(vim_options.height, default_opts.height)
 | 
						|
  win_opts.width = utils.bounded(width, vim_options.minwidth, vim_options.maxwidth)
 | 
						|
  win_opts.height = utils.bounded(height, vim_options.minheight, vim_options.maxheight)
 | 
						|
 | 
						|
  if vim_options.line and vim_options.line ~= 0 then
 | 
						|
    if type(vim_options.line) == "string" then
 | 
						|
      win_opts.row = cursor_relative_pos(vim_options.line, "row")
 | 
						|
    else
 | 
						|
      win_opts.row = vim_options.line - 1
 | 
						|
    end
 | 
						|
  else
 | 
						|
    win_opts.row = math.floor((vim.o.lines - win_opts.height) / 2)
 | 
						|
  end
 | 
						|
 | 
						|
  if vim_options.col and vim_options.col ~= 0 then
 | 
						|
    if type(vim_options.col) == "string" then
 | 
						|
      win_opts.col = cursor_relative_pos(vim_options.col, "col")
 | 
						|
    else
 | 
						|
      win_opts.col = vim_options.col - 1
 | 
						|
    end
 | 
						|
  else
 | 
						|
    win_opts.col = math.floor((vim.o.columns - win_opts.width) / 2)
 | 
						|
  end
 | 
						|
 | 
						|
  -- pos
 | 
						|
  --
 | 
						|
  -- Using "topleft", "topright", "botleft", "botright" defines what corner of the popup "line"
 | 
						|
  -- and "col" are used for. When not set "topleft" behaviour is used.
 | 
						|
  -- Alternatively "center" can be used to position the popup in the center of the Neovim window,
 | 
						|
  -- in which case "line" and "col" are ignored.
 | 
						|
  if vim_options.pos then
 | 
						|
    if vim_options.pos == "center" then
 | 
						|
      vim_options.line = 0
 | 
						|
      vim_options.col = 0
 | 
						|
      win_opts.anchor = "NW"
 | 
						|
    else
 | 
						|
      win_opts.anchor = popup._pos_map[vim_options.pos]
 | 
						|
    end
 | 
						|
  else
 | 
						|
    win_opts.anchor = "NW" -- This is the default, but makes `posinvert` easier to implement
 | 
						|
  end
 | 
						|
 | 
						|
  -- , fixed    When FALSE (the default), and:
 | 
						|
  -- ,      - "pos" is "botleft" or "topleft", and
 | 
						|
  -- ,      - "wrap" is off, and
 | 
						|
  -- ,      - the popup would be truncated at the right edge of
 | 
						|
  -- ,        the screen, then
 | 
						|
  -- ,     the popup is moved to the left so as to fit the
 | 
						|
  -- ,     contents on the screen.  Set to TRUE to disable this.
 | 
						|
end
 | 
						|
 | 
						|
function popup.create(what, vim_options)
 | 
						|
  vim_options = vim.deepcopy(vim_options)
 | 
						|
 | 
						|
  local bufnr
 | 
						|
  if type(what) == "number" then
 | 
						|
    bufnr = what
 | 
						|
  else
 | 
						|
    bufnr = vim.api.nvim_create_buf(false, true)
 | 
						|
    assert(bufnr, "Failed to create buffer")
 | 
						|
 | 
						|
    vim.api.nvim_buf_set_option(bufnr, "bufhidden", "wipe")
 | 
						|
 | 
						|
    -- TODO: Handle list of lines
 | 
						|
    if type(what) == "string" then
 | 
						|
      what = { what }
 | 
						|
    else
 | 
						|
      assert(type(what) == "table", '"what" must be a table')
 | 
						|
    end
 | 
						|
 | 
						|
    -- padding    List with numbers, defining the padding
 | 
						|
    --     above/right/below/left of the popup (similar to CSS).
 | 
						|
    --     An empty list uses a padding of 1 all around.  The
 | 
						|
    --     padding goes around the text, inside any border.
 | 
						|
    --     Padding uses the 'wincolor' highlight.
 | 
						|
    --     Example: [1, 2, 1, 3] has 1 line of padding above, 2
 | 
						|
    --     columns on the right, 1 line below and 3 columns on
 | 
						|
    --     the left.
 | 
						|
    if vim_options.padding then
 | 
						|
      local pad_top, pad_right, pad_below, pad_left
 | 
						|
      if vim.tbl_isempty(vim_options.padding) then
 | 
						|
        pad_top = 1
 | 
						|
        pad_right = 1
 | 
						|
        pad_below = 1
 | 
						|
        pad_left = 1
 | 
						|
      else
 | 
						|
        local padding = vim_options.padding
 | 
						|
        pad_top = padding[1] or 0
 | 
						|
        pad_right = padding[2] or 0
 | 
						|
        pad_below = padding[3] or 0
 | 
						|
        pad_left = padding[4] or 0
 | 
						|
      end
 | 
						|
 | 
						|
      local left_padding = string.rep(" ", pad_left)
 | 
						|
      local right_padding = string.rep(" ", pad_right)
 | 
						|
      for index = 1, #what do
 | 
						|
        what[index] = string.format("%s%s%s", left_padding, what[index], right_padding)
 | 
						|
      end
 | 
						|
 | 
						|
      for _ = 1, pad_top do
 | 
						|
        table.insert(what, 1, "")
 | 
						|
      end
 | 
						|
 | 
						|
      for _ = 1, pad_below do
 | 
						|
        table.insert(what, "")
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, what)
 | 
						|
  end
 | 
						|
 | 
						|
  local option_defaults = {
 | 
						|
    posinvert = true,
 | 
						|
    zindex = 50,
 | 
						|
  }
 | 
						|
 | 
						|
  vim_options.width = if_nil(vim_options.width, 1)
 | 
						|
  if type(what) == "number" then
 | 
						|
    vim_options.height = vim.api.nvim_buf_line_count(what)
 | 
						|
  else
 | 
						|
    for _, v in ipairs(what) do
 | 
						|
      vim_options.width = math.max(vim_options.width, #v)
 | 
						|
    end
 | 
						|
    vim_options.height = #what
 | 
						|
  end
 | 
						|
 | 
						|
  local win_opts = {}
 | 
						|
  win_opts.relative = "editor"
 | 
						|
  win_opts.style = "minimal"
 | 
						|
 | 
						|
  -- Add positional and sizing config to win_opts
 | 
						|
  add_position_config(win_opts, vim_options, { width = 1, height = 1 })
 | 
						|
 | 
						|
  -- posinvert, When FALSE the value of "pos" is always used.  When
 | 
						|
  -- ,   TRUE (the default) and the popup does not fit
 | 
						|
  -- ,   vertically and there is more space on the other side
 | 
						|
  -- ,   then the popup is placed on the other side of the
 | 
						|
  -- ,   position indicated by "line".
 | 
						|
  if dict_default(vim_options, "posinvert", option_defaults) then
 | 
						|
    if win_opts.anchor == "NW" or win_opts.anchor == "NE" then
 | 
						|
      if win_opts.row + win_opts.height > vim.o.lines and win_opts.row * 2 > vim.o.lines then
 | 
						|
        -- Don't know why, but this is how vim adjusts it
 | 
						|
        win_opts.row = win_opts.row - win_opts.height - 2
 | 
						|
      end
 | 
						|
    elseif win_opts.anchor == "SW" or win_opts.anchor == "SE" then
 | 
						|
      if win_opts.row - win_opts.height < 0 and win_opts.row * 2 < vim.o.lines then
 | 
						|
        -- Don't know why, but this is how vim adjusts it
 | 
						|
        win_opts.row = win_opts.row + win_opts.height + 2
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  -- textprop, When present the popup is positioned next to a text
 | 
						|
  -- ,   property with this name and will move when the text
 | 
						|
  -- ,   property moves.  Use an empty string to remove.  See
 | 
						|
  -- ,   |popup-textprop-pos|.
 | 
						|
  -- related:
 | 
						|
  --   textpropwin
 | 
						|
  --   textpropid
 | 
						|
 | 
						|
  -- zindex, Priority for the popup, default 50.  Minimum value is
 | 
						|
  -- ,   1, maximum value is 32000.
 | 
						|
  local zindex = dict_default(vim_options, "zindex", option_defaults)
 | 
						|
  win_opts.zindex = utils.bounded(zindex, 1, 32000)
 | 
						|
 | 
						|
  -- noautocmd, undocumented vim default per https://github.com/vim/vim/issues/5737
 | 
						|
  win_opts.noautocmd = if_nil(vim_options.noautocmd, true)
 | 
						|
 | 
						|
  -- focusable,
 | 
						|
  -- vim popups are not focusable windows
 | 
						|
  win_opts.focusable = if_nil(vim_options.focusable, false)
 | 
						|
 | 
						|
  local win_id
 | 
						|
  if vim_options.hidden then
 | 
						|
    assert(false, "I have not implemented this yet and don't know how")
 | 
						|
  else
 | 
						|
    win_id = vim.api.nvim_open_win(bufnr, false, win_opts)
 | 
						|
  end
 | 
						|
 | 
						|
  -- Moved, handled after since we need the window ID
 | 
						|
  if vim_options.moved then
 | 
						|
    if vim_options.moved == "any" then
 | 
						|
      vim.lsp.util.close_preview_autocmd({ "CursorMoved", "CursorMovedI" }, win_id)
 | 
						|
    elseif vim_options.moved == "word" then
 | 
						|
      -- TODO: Handle word, WORD, expr, and the range functions... which seem hard?
 | 
						|
    end
 | 
						|
  else
 | 
						|
    local silent = false
 | 
						|
    vim.cmd(
 | 
						|
      string.format(
 | 
						|
        "autocmd BufDelete %s <buffer=%s> ++once ++nested :lua require('plenary.window').try_close(%s, true)",
 | 
						|
        (silent and "<silent>") or "",
 | 
						|
        bufnr,
 | 
						|
        win_id
 | 
						|
      )
 | 
						|
    )
 | 
						|
  end
 | 
						|
 | 
						|
  if vim_options.time then
 | 
						|
    local timer = vim.loop.new_timer()
 | 
						|
    timer:start(
 | 
						|
      vim_options.time,
 | 
						|
      0,
 | 
						|
      vim.schedule_wrap(function()
 | 
						|
        Window.try_close(win_id, false)
 | 
						|
      end)
 | 
						|
    )
 | 
						|
  end
 | 
						|
 | 
						|
  -- Buffer Options
 | 
						|
  if vim_options.cursorline then
 | 
						|
    vim.api.nvim_win_set_option(win_id, "cursorline", true)
 | 
						|
  end
 | 
						|
 | 
						|
  if vim_options.wrap ~= nil then
 | 
						|
    -- set_option wrap should/will trigger autocmd, see https://github.com/neovim/neovim/pull/13247
 | 
						|
    if vim_options.noautocmd then
 | 
						|
      vim.cmd(string.format("noautocmd lua vim.api.nvim_set_option(%s, wrap, %s)", win_id, vim_options.wrap))
 | 
						|
    else
 | 
						|
      vim.api.nvim_win_set_option(win_id, "wrap", vim_options.wrap)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  -- ===== Not Implemented Options =====
 | 
						|
  -- flip: not implemented at the time of writing
 | 
						|
  -- Mouse:
 | 
						|
  --    mousemoved: no idea how to do the things with the mouse, so it's an exercise for the reader.
 | 
						|
  --    drag: mouses are hard
 | 
						|
  --    resize: mouses are hard
 | 
						|
  --    close: mouses are hard
 | 
						|
  --
 | 
						|
  -- scrollbar
 | 
						|
  -- scrollbarhighlight
 | 
						|
  -- thumbhighlight
 | 
						|
 | 
						|
  -- tabpage: seems useless
 | 
						|
 | 
						|
  -- Create border
 | 
						|
 | 
						|
  local should_show_border = nil
 | 
						|
  local border_options = {}
 | 
						|
 | 
						|
  -- border    List with numbers, defining the border thickness
 | 
						|
  --     above/right/below/left of the popup (similar to CSS).
 | 
						|
  --     Only values of zero and non-zero are recognized.
 | 
						|
  --     An empty list uses a border all around.
 | 
						|
  if vim_options.border then
 | 
						|
    should_show_border = true
 | 
						|
 | 
						|
    if type(vim_options.border) == "boolean" or vim.tbl_isempty(vim_options.border) then
 | 
						|
      border_options.border_thickness = Border._default_thickness
 | 
						|
    elseif #vim_options.border == 4 then
 | 
						|
      border_options.border_thickness = {
 | 
						|
        top = utils.bounded(vim_options.border[1], 0, 1),
 | 
						|
        right = utils.bounded(vim_options.border[2], 0, 1),
 | 
						|
        bot = utils.bounded(vim_options.border[3], 0, 1),
 | 
						|
        left = utils.bounded(vim_options.border[4], 0, 1),
 | 
						|
      }
 | 
						|
    else
 | 
						|
      error(string.format("Invalid configuration for border: %s", vim.inspect(vim_options.border)))
 | 
						|
    end
 | 
						|
  elseif vim_options.border == false then
 | 
						|
    should_show_border = false
 | 
						|
  end
 | 
						|
 | 
						|
  if (should_show_border == nil or should_show_border) and vim_options.borderchars then
 | 
						|
    should_show_border = true
 | 
						|
 | 
						|
    -- borderchars  List with characters, defining the character to use
 | 
						|
    --     for the top/right/bottom/left border.  Optionally
 | 
						|
    --     followed by the character to use for the
 | 
						|
    --     topleft/topright/botright/botleft corner.
 | 
						|
    --     Example: ['-', '|', '-', '|', '┌', '┐', '┘', '└']
 | 
						|
    --     When the list has one character it is used for all.
 | 
						|
    --     When the list has two characters the first is used for
 | 
						|
    --     the border lines, the second for the corners.
 | 
						|
    --     By default a double line is used all around when
 | 
						|
    --     'encoding' is "utf-8" and 'ambiwidth' is "single",
 | 
						|
    --     otherwise ASCII characters are used.
 | 
						|
 | 
						|
    local b_top, b_right, b_bot, b_left, b_topleft, b_topright, b_botright, b_botleft
 | 
						|
    if vim_options.borderchars == nil then
 | 
						|
      b_top, b_right, b_bot, b_left, b_topleft, b_topright, b_botright, b_botleft =
 | 
						|
        "═", "║", "═", "║", "╔", "╗", "╝", "╚"
 | 
						|
    elseif #vim_options.borderchars == 1 then
 | 
						|
      local b_char = vim_options.borderchars[1]
 | 
						|
      b_top, b_right, b_bot, b_left, b_topleft, b_topright, b_botright, b_botleft =
 | 
						|
        b_char, b_char, b_char, b_char, b_char, b_char, b_char, b_char
 | 
						|
    elseif #vim_options.borderchars == 2 then
 | 
						|
      local b_char = vim_options.borderchars[1]
 | 
						|
      local c_char = vim_options.borderchars[2]
 | 
						|
      b_top, b_right, b_bot, b_left, b_topleft, b_topright, b_botright, b_botleft =
 | 
						|
        b_char, b_char, b_char, b_char, c_char, c_char, c_char, c_char
 | 
						|
    elseif #vim_options.borderchars == 8 then
 | 
						|
      b_top, b_right, b_bot, b_left, b_topleft, b_topright, b_botright, b_botleft = unpack(vim_options.borderchars)
 | 
						|
    else
 | 
						|
      error(string.format 'Not enough arguments for "borderchars"')
 | 
						|
    end
 | 
						|
 | 
						|
    border_options.top = b_top
 | 
						|
    border_options.bot = b_bot
 | 
						|
    border_options.right = b_right
 | 
						|
    border_options.left = b_left
 | 
						|
    border_options.topleft = b_topleft
 | 
						|
    border_options.topright = b_topright
 | 
						|
    border_options.botright = b_botright
 | 
						|
    border_options.botleft = b_botleft
 | 
						|
  end
 | 
						|
 | 
						|
  -- title
 | 
						|
  if vim_options.title then
 | 
						|
    -- TODO: Check out how title works with weird border combos.
 | 
						|
    border_options.title = vim_options.title
 | 
						|
  end
 | 
						|
 | 
						|
  local border = nil
 | 
						|
  if should_show_border then
 | 
						|
    border_options.focusable = vim_options.border_focusable
 | 
						|
    border_options.highlight = vim_options.borderhighlight and string.format("Normal:%s", vim_options.borderhighlight)
 | 
						|
    border_options.titlehighlight = vim_options.titlehighlight
 | 
						|
    border = Border:new(bufnr, win_id, win_opts, border_options)
 | 
						|
    popup._borders[win_id] = border
 | 
						|
  end
 | 
						|
 | 
						|
  if vim_options.highlight then
 | 
						|
    vim.api.nvim_win_set_option(
 | 
						|
      win_id,
 | 
						|
      "winhl",
 | 
						|
      string.format("Normal:%s,EndOfBuffer:%s", vim_options.highlight, vim_options.highlight)
 | 
						|
    )
 | 
						|
  end
 | 
						|
 | 
						|
  -- enter
 | 
						|
  local should_enter = vim_options.enter
 | 
						|
  if should_enter == nil then
 | 
						|
    should_enter = true
 | 
						|
  end
 | 
						|
 | 
						|
  if should_enter then
 | 
						|
    -- set focus after border creation so that it's properly placed (especially
 | 
						|
    -- in relative cursor layout)
 | 
						|
    if vim_options.noautocmd then
 | 
						|
      vim.cmd("noautocmd lua vim.api.nvim_set_current_win(" .. win_id .. ")")
 | 
						|
    else
 | 
						|
      vim.api.nvim_set_current_win(win_id)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  -- callback
 | 
						|
  if vim_options.callback then
 | 
						|
    popup._callbacks[bufnr] = function()
 | 
						|
      -- (jbyuki): Giving win_id is pointless here because it's closed right afterwards
 | 
						|
      -- but it might make more sense once hidden is implemented
 | 
						|
      local row, _ = unpack(vim.api.nvim_win_get_cursor(win_id))
 | 
						|
      vim_options.callback(win_id, what[row])
 | 
						|
      vim.api.nvim_win_close(win_id, true)
 | 
						|
    end
 | 
						|
    vim.api.nvim_buf_set_keymap(
 | 
						|
      bufnr,
 | 
						|
      "n",
 | 
						|
      "<CR>",
 | 
						|
      '<cmd>lua require"popup".execute_callback(' .. bufnr .. ")<CR>",
 | 
						|
      { noremap = true }
 | 
						|
    )
 | 
						|
  end
 | 
						|
 | 
						|
  -- TODO: Perhaps there's a way to return an object that looks like a window id,
 | 
						|
  --    but actually has some extra metadata about it.
 | 
						|
  --
 | 
						|
  --    This would make `hidden` a lot easier to manage
 | 
						|
  return win_id, {
 | 
						|
    win_id = win_id,
 | 
						|
    border = border,
 | 
						|
  }
 | 
						|
end
 | 
						|
 | 
						|
-- Move popup with window id {win_id} to the position specified with {vim_options}.
 | 
						|
-- {vim_options} may contain the following items that determine the popup position/size:
 | 
						|
-- - line
 | 
						|
-- - col
 | 
						|
-- - height
 | 
						|
-- - width
 | 
						|
-- - maxheight/minheight
 | 
						|
-- - maxwidth/minwidth
 | 
						|
-- - pos
 | 
						|
-- Unimplemented vim options here include: fixed
 | 
						|
function popup.move(win_id, vim_options)
 | 
						|
  -- Create win_options
 | 
						|
  local win_opts = {}
 | 
						|
  win_opts.relative = "editor"
 | 
						|
 | 
						|
  local current_pos = vim.api.nvim_win_get_position(win_id)
 | 
						|
  local default_opts = {
 | 
						|
    width = vim.api.nvim_win_get_width(win_id),
 | 
						|
    height = vim.api.nvim_win_get_height(win_id),
 | 
						|
    row = current_pos[1],
 | 
						|
    col = current_pos[2],
 | 
						|
  }
 | 
						|
 | 
						|
  -- Add positional and sizing config to win_opts
 | 
						|
  add_position_config(win_opts, vim_options, default_opts)
 | 
						|
 | 
						|
  -- Update content window
 | 
						|
  vim.api.nvim_win_set_config(win_id, win_opts)
 | 
						|
 | 
						|
  -- Update border window (if present)
 | 
						|
  local border = popup._borders[win_id]
 | 
						|
  if border ~= nil then
 | 
						|
    border:move(win_opts, border._border_win_options)
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
function popup.execute_callback(bufnr)
 | 
						|
  if popup._callbacks[bufnr] then
 | 
						|
    local wrapper = popup._callbacks[bufnr]
 | 
						|
    wrapper()
 | 
						|
    popup._callbacks[bufnr] = nil
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
return popup
 |