summaryrefslogtreecommitdiff
path: root/lua/99/window/init.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/99/window/init.lua')
-rw-r--r--lua/99/window/init.lua439
1 files changed, 242 insertions, 197 deletions
diff --git a/lua/99/window/init.lua b/lua/99/window/init.lua
index 85f9da5..3475d5a 100644
--- a/lua/99/window/init.lua
+++ b/lua/99/window/init.lua
@@ -1,9 +1,10 @@
--- @class _99.window.Module
--- @field active_windows _99.window.Window[]
local M = {
- active_windows = {},
+ active_windows = {},
}
local nsid = vim.api.nvim_create_namespace("99.window.error")
+local nvim_win_is_valid = vim.api.nvim_win_is_valid
--- @class _99.window.Config
--- @field width number
@@ -20,285 +21,329 @@ local nsid = vim.api.nvim_create_namespace("99.window.error")
--- @param lines string[]
--- @return string[]
local function ensure_no_new_lines(lines)
- local display_lines = {}
- for _, line in ipairs(lines) do
- local split_lines = vim.split(line, "\n")
- for _, clean_line in ipairs(split_lines) do
- table.insert(display_lines, clean_line)
- end
+ local display_lines = {}
+ for _, line in ipairs(lines) do
+ local split_lines = vim.split(line, "\n")
+ for _, clean_line in ipairs(split_lines) do
+ table.insert(display_lines, clean_line)
end
- return display_lines
+ end
+ return display_lines
end
--- @return number
--- @return number
local function get_ui_dimensions()
- local ui = vim.api.nvim_list_uis()[1]
- return ui.width, ui.height
+ local ui = vim.api.nvim_list_uis()[1]
+ return ui.width, ui.height
end
--- @return _99.window.Config
local function create_window_top_config()
- local width, _ = get_ui_dimensions()
- return {
- width = width - 2,
- height = 3,
- anchor = "NE",
- }
+ local width, _ = get_ui_dimensions()
+ return {
+ width = width - 2,
+ height = 3,
+ anchor = "NE",
+ }
end
--- @return _99.window.Config
local function create_window_top_left_config()
- local width, _ = get_ui_dimensions()
- return {
- width = math.floor(width / 3),
- height = 3,
- anchor = "NE",
- }
+ local width, _ = get_ui_dimensions()
+ return {
+ width = math.floor(width / 3),
+ height = 3,
+ anchor = "NE",
+ }
end
--- @return _99.window.Config
local function create_window_full_screen()
- local width, height = get_ui_dimensions()
- return {
- width = width - 2,
- height = height - 2,
- anchor = "NE",
- }
+ local width, height = get_ui_dimensions()
+ return {
+ width = width - 2,
+ height = height - 2,
+ anchor = "NE",
+ }
+end
+
+--- @param config _99.window.Config
+---@param offset_bottom number | nil
+--- @return _99.window.Config
+local function create_window_inside(config, offset_bottom)
+ offset_bottom = offset_bottom or 0
+ return {
+ width = config.width - 2,
+ height = 1,
+ row = config.row + config.height - offset_bottom,
+ col = config.col + 1,
+ anchor = config.anchor,
+ }
end
--- @return _99.window.Config
local function create_centered_window()
- local width, height = get_ui_dimensions()
- local win_width = math.floor(width * 2 / 3)
- local win_height = math.floor(height / 3)
- return {
- width = win_width,
- height = win_height,
- row = math.floor((height - win_height) / 2),
- col = math.floor((width - win_width) / 2),
- }
+ local width, height = get_ui_dimensions()
+ local win_width = math.floor(width * 2 / 3)
+ local win_height = math.floor(height / 3)
+ return {
+ width = win_width,
+ height = win_height,
+ row = math.floor((height - win_height) / 2),
+ col = math.floor((width - win_width) / 2),
+ }
end
--- @param config _99.window.Config
--- @param win_config vim.api.keyset.win_config
--- @return _99.window.Window
local function create_floating_window(config, win_config)
- local buf_id = vim.api.nvim_create_buf(false, true)
- local win_id = vim.api.nvim_open_win(buf_id, true, {
- relative = "editor",
- width = config.width,
- height = config.height,
- row = config.row or 0,
- col = config.col or 0,
- anchor = config.anchor,
- style = "minimal",
- border = win_config.border,
- title = win_config.title,
- title_pos = "center",
- })
- local window = {
- config = config,
- win_id = win_id,
- buf_id = buf_id,
- }
- vim.wo[win_id].wrap = true
+ local buf_id = vim.api.nvim_create_buf(false, true)
+ local win_id = vim.api.nvim_open_win(buf_id, true, {
+ relative = "editor",
+ width = config.width,
+ height = config.height,
+ row = config.row or 0,
+ col = config.col or 0,
+ anchor = config.anchor,
+ style = "minimal",
+ border = win_config.border,
+ title = win_config.title,
+ title_pos = "center",
+ zindex = win_config.zindex,
+ })
+ local window = {
+ config = config,
+ win_id = win_id,
+ buf_id = buf_id,
+ }
+ vim.wo[win_id].wrap = true
- table.insert(M.active_windows, window)
- return window
+ table.insert(M.active_windows, window)
+ return window
end
--- @param window _99.window.Window
local function highlight_error(window)
- local line_count = vim.api.nvim_buf_line_count(window.buf_id)
+ local line_count = vim.api.nvim_buf_line_count(window.buf_id)
- if line_count > 0 then
- vim.api.nvim_buf_set_extmark(window.buf_id, nsid, 0, 0, {
- end_row = 1,
- hl_group = "Normal",
- hl_eol = true,
- })
- end
+ if line_count > 0 then
+ vim.api.nvim_buf_set_extmark(window.buf_id, nsid, 0, 0, {
+ end_row = 1,
+ hl_group = "Normal",
+ hl_eol = true,
+ })
+ end
- if line_count > 1 then
- vim.api.nvim_buf_set_extmark(window.buf_id, nsid, 1, 0, {
- end_row = line_count,
- hl_group = "ErrorMsg",
- hl_eol = true,
- })
- end
+ if line_count > 1 then
+ vim.api.nvim_buf_set_extmark(window.buf_id, nsid, 1, 0, {
+ end_row = line_count,
+ hl_group = "ErrorMsg",
+ hl_eol = true,
+ })
+ end
end
--- @param error_text string
--- @return _99.window.Window
function M.display_error(error_text)
- local window = create_floating_window(create_window_top_config(), {
- title = " 99 Error ",
- border = "rounded",
- })
- local lines = vim.split(error_text, "\n")
+ local window = create_floating_window(create_window_top_config(), {
+ title = " 99 Error ",
+ border = "rounded",
+ })
+ local lines = vim.split(error_text, "\n")
- table.insert(lines, 1, "")
- table.insert(
- lines,
- 1,
- "99: Fatal operational error encountered (error logs may have more in-depth information)"
- )
+ table.insert(lines, 1, "")
+ table.insert(
+ lines,
+ 1,
+ "99: Fatal operational error encountered (error logs may have more in-depth information)"
+ )
- vim.api.nvim_buf_set_lines(window.buf_id, 0, -1, false, lines)
- highlight_error(window)
- return window
+ vim.api.nvim_buf_set_lines(window.buf_id, 0, -1, false, lines)
+ highlight_error(window)
+ return window
end
--- @param window _99.window.Window
local function window_close(window)
- if vim.api.nvim_win_is_valid(window.win_id) then
- vim.api.nvim_win_close(window.win_id, true)
- end
- if vim.api.nvim_buf_is_valid(window.buf_id) then
- vim.api.nvim_buf_delete(window.buf_id, { force = true })
- end
-
- local found = false
- for i, w in ipairs(M.active_windows) do
- if w.buf_id == window.buf_id and w.win_id == window.win_id then
- found = true
- table.remove(M.active_windows, i)
- break
- end
- end
-
- assert(
- found,
- "somehow we have closed a window that did not belong to the windows library"
- )
+ if nvim_win_is_valid(window.win_id) then
+ vim.api.nvim_win_close(window.win_id, true)
+ end
+ if vim.api.nvim_buf_is_valid(window.buf_id) then
+ vim.api.nvim_buf_delete(window.buf_id, { force = true })
+ end
end
--- @param text string
function M.display_cancellation_message(text)
- local config = create_window_top_left_config()
- local window = create_floating_window(config, {
- title = " 99 Cancelled ",
- border = "rounded",
- })
- local lines = vim.split(text, "\n")
+ local config = create_window_top_left_config()
+ local window = create_floating_window(config, {
+ title = " 99 Cancelled ",
+ border = "rounded",
+ })
+ local lines = vim.split(text, "\n")
- vim.api.nvim_buf_set_lines(window.buf_id, 0, -1, false, lines)
+ vim.api.nvim_buf_set_lines(window.buf_id, 0, -1, false, lines)
- vim.api.nvim_buf_set_extmark(window.buf_id, nsid, 0, 0, {
- end_row = vim.api.nvim_buf_line_count(window.buf_id),
- hl_group = "WarningMsg",
- hl_eol = true,
- })
+ vim.api.nvim_buf_set_extmark(window.buf_id, nsid, 0, 0, {
+ end_row = vim.api.nvim_buf_line_count(window.buf_id),
+ hl_group = "WarningMsg",
+ hl_eol = true,
+ })
- vim.defer_fn(function()
- window_close(window)
- end, 5000)
+ vim.defer_fn(function()
+ if nvim_win_is_valid(window.win_id) then
+ M.clear_active_popups()
+ end
+ end, 5000)
- return window
+ return window
end
--- TODO: i dont like how the other interfaces have text being passed in
--- but this one is lines. probably need to revisit this
--- @param lines string[]
function M.display_full_screen_message(lines)
- --- TODO: i really dislike that i am closing and opening windows
- --- i think it would be better to perserve the one that is already open
- --- but i just want this to work and then later... ohh much later, ill fix
- --- this basic nonsense
- M.clear_active_popups()
- local window = create_floating_window(create_window_full_screen(), {
- title = " 99 ",
- border = "rounded",
- })
- local display_lines = ensure_no_new_lines(lines)
- vim.api.nvim_buf_set_lines(window.buf_id, 0, -1, false, display_lines)
+ --- TODO: i really dislike that i am closing and opening windows
+ --- i think it would be better to perserve the one that is already open
+ --- but i just want this to work and then later... ohh much later, ill fix
+ --- this basic nonsense
+ M.clear_active_popups()
+ local window = create_floating_window(create_window_full_screen(), {
+ title = " 99 ",
+ border = "rounded",
+ })
+ local display_lines = ensure_no_new_lines(lines)
+ vim.api.nvim_buf_set_lines(window.buf_id, 0, -1, false, display_lines)
end
--- @return _99.window.Window
--- @return _99.window.Config
function M.create_centered_window()
- M.clear_active_popups()
- local config = create_centered_window()
- local window = create_floating_window(config, {
- title = " 99 ",
- border = "rounded",
- })
- return window, config
+ M.clear_active_popups()
+ local config = create_centered_window()
+ local window = create_floating_window(config, {
+ title = " 99 ",
+ border = "rounded",
+ })
+ return window, config
end
--- @param message string[]
function M.display_centered_message(message)
- M.clear_active_popups()
- local config = create_centered_window()
- local window = create_floating_window(config, {
- title = " 99 ",
- border = "rounded",
- })
- local display_lines = ensure_no_new_lines(message)
+ M.clear_active_popups()
+ local config = create_centered_window()
+ local window = create_floating_window(config, {
+ title = " 99 ",
+ border = "rounded",
+ })
+ local display_lines = ensure_no_new_lines(message)
- vim.api.nvim_buf_set_lines(window.buf_id, 0, -1, false, display_lines)
+ vim.api.nvim_buf_set_lines(window.buf_id, 0, -1, false, display_lines)
- return window
+ return window
end
---- @param cb fun(success: boolean, result: string): nil
---- @param opts {}
-function M.capture_input(cb, opts)
- _ = opts
+--- @param win _99.window.Window
+--- @param name string
+local function set_defaul_win_options(win, name)
+ vim.api.nvim_buf_set_name(win.buf_id, name)
+ vim.wo[win.win_id].number = true
+ vim.bo[win.buf_id].filetype = "99"
+ vim.bo[win.buf_id].buftype = "acwrite"
+ vim.bo[win.buf_id].bufhidden = "wipe"
+ vim.bo[win.buf_id].swapfile = false
+end
- --- TODO: styling should be extendable
- M.clear_active_popups()
- local config = create_centered_window()
- local win = create_floating_window(config, {
- title = " 99 Prompt ",
- border = "rounded",
- })
+--- @class _99.window.CaptureInputOpts
+--- @field cb fun(success: boolean, result: string): nil
+--- @field on_load? fun(): nil
- vim.api.nvim_buf_set_name(win.buf_id, "99-prompt")
- vim.wo[win.win_id].number = true
- vim.bo[win.buf_id].filetype = "99"
- vim.bo[win.buf_id].buftype = "acwrite"
- vim.bo[win.buf_id].bufhidden = "wipe"
- vim.bo[win.buf_id].swapfile = false
+--- @param opts _99.window.CaptureInputOpts
+function M.capture_input(opts)
+ _ = opts
+ M.clear_active_popups()
- local group = vim.api.nvim_create_augroup(
- "99_present_prompt_" .. win.buf_id,
- { clear = true }
- )
+ local config = create_centered_window()
+ local win = create_floating_window(config, {
+ title = " 99 Prompt ",
+ border = "rounded",
+ })
- vim.api.nvim_create_autocmd("BufWriteCmd", {
- group = group,
- buffer = win.buf_id,
- callback = function()
- local lines = vim.api.nvim_buf_get_lines(win.buf_id, 0, -1, false)
- local result = table.concat(lines, "\n")
- M.clear_active_popups()
- cb(true, result)
- end,
- })
+ set_defaul_win_options(win, "99-prompt")
+ vim.api.nvim_set_current_win(win.win_id)
- vim.api.nvim_create_autocmd("BufUnload", {
- group = group,
- buffer = win.buf_id,
- callback = function()
- vim.api.nvim_del_augroup_by_id(group)
- end,
- })
+ local group = vim.api.nvim_create_augroup(
+ "99_present_prompt_" .. win.buf_id,
+ { clear = true }
+ )
- vim.keymap.set("n", "q", function()
+ vim.api.nvim_create_autocmd("BufLeave", {
+ group = group,
+ buffer = win.buf_id,
+ callback = function()
+ if nvim_win_is_valid(win.win_id) then
+ vim.api.nvim_set_current_win(win.win_id)
+ else
M.clear_active_popups()
- cb(false, "")
- end, { buffer = win.buf_id, nowait = true })
+ end
+ end,
+ })
+
+ vim.api.nvim_create_autocmd("BufWriteCmd", {
+ group = group,
+ buffer = win.buf_id,
+ callback = function()
+ if not nvim_win_is_valid(win.win_id) then
+ return
+ end
+ local lines = vim.api.nvim_buf_get_lines(win.buf_id, 0, -1, false)
+ local result = table.concat(lines, "\n")
+ M.clear_active_popups()
+ opts.cb(true, result)
+ end,
+ })
+
+ vim.api.nvim_create_autocmd("BufUnload", {
+ group = group,
+ buffer = win.buf_id,
+ callback = function()
+ if not nvim_win_is_valid(win.win_id) then
+ return
+ end
+ vim.api.nvim_del_augroup_by_id(group)
+ end,
+ })
+
+ vim.api.nvim_create_autocmd("WinClosed", {
+ group = group,
+ pattern = tostring(win.win_id),
+ callback = function()
+ if not nvim_win_is_valid(win.win_id) then
+ return
+ end
+ M.clear_active_popups()
+ opts.cb(false, "")
+ end,
+ })
+
+ vim.keymap.set("n", "q", function()
+ M.clear_active_popups()
+ opts.cb(false, "")
+ end, { buffer = win.buf_id, nowait = true })
+
+ if opts.on_load then
+ vim.schedule(opts.on_load)
+ end
end
---- not worried about perf, we will likely only ever have 1 maybe 2 windows
---- ever open at the same time
function M.clear_active_popups()
- while #M.active_windows > 0 do
- local window = M.active_windows[1]
- window_close(window)
- end
+ for _, window in ipairs(M.active_windows) do
+ window_close(window)
+ end
+ M.active_windows = {}
end
return M