diff --git a/POPUP.md b/POPUP.md index 0721f1af..c56df43d 100644 --- a/POPUP.md +++ b/POPUP.md @@ -10,6 +10,7 @@ stablization and any required features are merged into Neovim, we can upstream this and expose the API in vimL to create better compatibility. ## Notices +- **2021-09-19:** we now follow Vim's convention of the first line/column of the screen being indexed 1, so that 0 can be used for centering. - **2021-08-19:** we now follow Vim's default to `noautocmd` on popup creation. This can be overriden with `vim_options.noautocmd=false` ## List of Neovim Features Required: diff --git a/lua/plenary/popup/init.lua b/lua/plenary/popup/init.lua index 83d727c0..268b2703 100644 --- a/lua/plenary/popup/init.lua +++ b/lua/plenary/popup/init.lua @@ -98,6 +98,43 @@ function popup.create(what, vim_options) local win_opts = {} win_opts.relative = "editor" + -- 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 = vim_options.width or 1 + local height + if type(what) == "number" then + height = vim.api.nvim_buf_line_count(what) + else + for _, v in ipairs(what) do + width = math.max(width, #v) + end + height = #what + end + win_opts.width = utils.bounded(width, vim_options.minwidth, vim_options.maxwidth) + win_opts.height = utils.bounded(height, vim_options.minheight, vim_options.maxheight) + + -- 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 + local cursor_relative_pos = function(pos_str, dim) assert(string.find(pos_str, "^cursor"), "Invalid value for " .. dim) win_opts.relative = "cursor" @@ -110,37 +147,24 @@ function popup.create(what, vim_options) return line end - if vim_options.line then + 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 + win_opts.row = vim_options.line - 1 end else - -- TODO: It says it needs to be "vertically cenetered"?... - -- wut is that. - win_opts.row = 0 + win_opts.row = math.floor((vim.o.lines - win_opts.height) / 2) end - if vim_options.col then + 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 + win_opts.col = vim_options.col - 1 end else - -- TODO: It says it needs to be "horizontally cenetered"?... - win_opts.col = 0 - end - - if vim_options.pos then - if vim_options.pos == "center" then - -- TODO: Do centering.. - 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 + win_opts.col = math.floor((vim.o.columns - win_opts.width) / 2) end -- , fixed When FALSE (the default), and: @@ -153,25 +177,6 @@ function popup.create(what, vim_options) win_opts.style = "minimal" - -- 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 = vim_options.width or 1 - local height - if type(what) == "number" then - height = vim.api.nvim_buf_line_count(what) - else - for _, v in ipairs(what) do - width = math.max(width, #v) - end - height = #what - end - win_opts.width = utils.bounded(width, vim_options.minwidth, vim_options.maxwidth) - win_opts.height = utils.bounded(height, vim_options.minheight, vim_options.maxheight) - -- 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 diff --git a/tests/plenary/strings_spec.lua b/tests/plenary/strings_spec.lua index 2ce3d9e7..cbab7896 100644 --- a/tests/plenary/strings_spec.lua +++ b/tests/plenary/strings_spec.lua @@ -50,8 +50,14 @@ describe("strings", function() { args = { "abcde", 6, nil, 1 }, expected = { single = "abcde", double = "abcde" } }, { args = { "abcde", 5, nil, 1 }, expected = { single = "abcde", double = "abcde" } }, { args = { "abcde", 4, nil, 1 }, expected = { single = "abc…", double = "ab…" } }, - { args = { "アイウエオ", 11, nil, 1 }, expected = { single = "アイウエオ", double = "アイウエオ" } }, - { args = { "アイウエオ", 10, nil, 1 }, expected = { single = "アイウエオ", double = "アイウエオ" } }, + { + args = { "アイウエオ", 11, nil, 1 }, + expected = { single = "アイウエオ", double = "アイウエオ" }, + }, + { + args = { "アイウエオ", 10, nil, 1 }, + expected = { single = "アイウエオ", double = "アイウエオ" }, + }, { args = { "アイウエオ", 9, nil, 1 }, expected = { single = "アイウエ…", double = "アイウ…" } }, { args = { "アイウエオ", 8, nil, 1 }, expected = { single = "アイウ…", double = "アイウ…" } }, { args = { "├─┤", 7, nil, 1 }, expected = { single = "├─┤", double = "├─┤" } }, @@ -64,8 +70,14 @@ describe("strings", function() { args = { "abcde", 6, nil, -1 }, expected = { single = "abcde", double = "abcde" } }, { args = { "abcde", 5, nil, -1 }, expected = { single = "abcde", double = "abcde" } }, { args = { "abcde", 4, nil, -1 }, expected = { single = "…cde", double = "…de" } }, - { args = { "アイウエオ", 11, nil, -1 }, expected = { single = "アイウエオ", double = "アイウエオ" } }, - { args = { "アイウエオ", 10, nil, -1 }, expected = { single = "アイウエオ", double = "アイウエオ" } }, + { + args = { "アイウエオ", 11, nil, 1 }, + expected = { single = "アイウエオ", double = "アイウエオ" }, + }, + { + args = { "アイウエオ", 10, nil, 1 }, + expected = { single = "アイウエオ", double = "アイウエオ" }, + }, { args = { "アイウエオ", 9, nil, -1 }, expected = { single = "…イウエオ", double = "…ウエオ" } }, { args = { "アイウエオ", 8, nil, -1 }, expected = { single = "…ウエオ", double = "…ウエオ" } }, { args = { "├─┤", 7, nil, -1 }, expected = { single = "├─┤", double = "├─┤" } },