diff --git a/lua/Polydev/ui.lua b/lua/Polydev/ui.lua index 3a32dd2..5cf3bd3 100644 --- a/lua/Polydev/ui.lua +++ b/lua/Polydev/ui.lua @@ -3,273 +3,286 @@ local M = {} ---@param path string ---@return table local function get_entries(path) - local result = {} - local handle = vim.uv.fs_scandir(path) - if not handle then return result end - while true do - local name, type = vim.uv.fs_scandir_next(handle) - if not name then break end - table.insert(result, { - name = name .. (type == "directory" and "/" or ""), - type = type, - full_path = path .. "/" .. name, - }) - end - table.sort(result, function(a, b) - if a.type == "directory" and b.type ~= "directory" then return true end - if b.type == "directory" and a.type ~= "directory" then return false end - return a.name < b.name - end) - return result + local result = {} + local handle = vim.uv.fs_scandir(path) + if not handle then return result end + while true do + local name, type = vim.uv.fs_scandir_next(handle) + if not name then break end + table.insert(result, { + name = name .. (type == "directory" and "/" or ""), + type = type, + full_path = path .. "/" .. name, + }) + end + table.sort(result, function(a, b) + if a.type == "directory" and b.type ~= "directory" then return true end + if b.type == "directory" and a.type ~= "directory" then return false end + return a.name < b.name + end) + return result end ---@param project_root string function M.manager(project_root) - local templates = require("Polydev.templates") - local ui = vim.api.nvim_list_uis()[1] - local width, height = math.floor(ui.width * 0.8), math.floor(ui.height * 0.9) - local row, col = math.floor((ui.height - height) / 2), math.floor((ui.width - width) / 2) - local content_row = row + 2 - local content_height = height - 3 + local templates = require("Polydev.templates") + local ui = vim.api.nvim_list_uis()[1] + local width, height = math.floor(ui.width * 0.8), math.floor(ui.height * 0.9) + local row, col = math.floor((ui.height - height) / 2), math.floor((ui.width - width) / 2) + local content_row = row + 2 + local content_height = height - 3 - local tabs = { "Projects", "Recents" } - local selected = 1 - local selected_tab = tabs[selected] + local tabs = { "Projects", "Recents" } + local selected = 1 + local selected_tab = tabs[selected] - local cwd = vim.fn.getcwd() - local current_view = {} + local cwd = vim.fn.getcwd() + local current_view = {} - local tab_buf = vim.api.nvim_create_buf(false, true) - local tab_win = vim.api.nvim_open_win(tab_buf, false, { - relative = "editor", - width = width, - height = 1, - row = row, - col = col, - style = "minimal", - border = "rounded", - }) + local tab_buf = vim.api.nvim_create_buf(false, true) + local tab_win = vim.api.nvim_open_win(tab_buf, false, { + relative = "editor", + width = width, + height = 1, + row = row, + col = col, + style = "minimal", + border = "rounded", + }) - local content_bufs = { - Projects = vim.api.nvim_create_buf(false, true), - Recents = vim.api.nvim_create_buf(false, true), - } + local content_bufs = { + Projects = vim.api.nvim_create_buf(false, true), + Recents = vim.api.nvim_create_buf(false, true), + } - local content_wins = { - Projects = vim.api.nvim_open_win(content_bufs.Projects, true, { - relative = "editor", - width = width, - height = content_height, - row = content_row, - col = col, - style = "minimal", - border = "rounded", - }), - Recents = nil, - } + local content_wins = { + Projects = vim.api.nvim_open_win(content_bufs.Projects, true, { + relative = "editor", + width = width, + height = content_height, + row = content_row, + col = col, + style = "minimal", + border = "rounded", + }), + Recents = nil, + } - local function update_tab_bar() - local line = {} - for i, tab in ipairs(tabs) do - local label = (i == selected and "[ " .. tab .. " ]") or (" " .. tab .. " ") - table.insert(line, label) - end - vim.api.nvim_buf_set_lines(tab_buf, 0, -1, false, { table.concat(line, " ") }) - end - - local function update_screen() - if selected_tab == "Projects" then - local entries = get_entries(cwd) - local root = vim.fn.expand(project_root) - if not cwd:find(root, 1, true) then - cwd = root - entries = get_entries(cwd) - end - if cwd ~= root then - table.insert(entries, 1, { - name = "../", - type = "directory", - full_path = vim.fn.fnamemodify(cwd, ":h"), - is_up = true, - }) - end - current_view = vim.deepcopy(entries) - - local lines = {} - for i, item in ipairs(current_view) do - table.insert(lines, string.format("%-2d | %-27s | %-6s", i, item.name, item.type)) - end - vim.api.nvim_buf_set_lines(content_bufs.Projects, 0, -1, false, lines) - - elseif selected_tab == "Recents" then - local oldfiles = vim.v.oldfiles - local valid = {} - for _, file in ipairs(oldfiles) do - if vim.fn.filereadable(file) == 1 then - table.insert(valid, file) - end - end - current_view = vim.tbl_map(function(f) - return { name = vim.fn.fnamemodify(f, ":t"), full_path = f, type = "file" } - end, valid) - - local lines = {} - for i, item in ipairs(current_view) do - table.insert(lines, string.format("%-2d | %-40s", i, item.full_path)) - end - vim.api.nvim_buf_set_lines(content_bufs.Recents, 0, -1, false, lines) - end - end - - local function get_selected_entry() - local win = content_wins[selected_tab] - if not win or not vim.api.nvim_win_is_valid(win) then return end - local row = vim.api.nvim_win_get_cursor(win)[1] - return current_view[row], row - end - - ---@param type string - ---@return string, string - local function get_inputs(type) - local l, n - vim.ui.input({ prompt = "Enter language for new " .. type .. ": " }, function(lang) - if lang == nil then return end - vim.ui.input({ prompt = "Enter ".. type .. " name: " }, function(name) - if not lang or lang == "" then return end - if not name or name == "" then return end - l, n = lang, name - end) - end) - return l, n - end - - local function switch_tab(index) - if content_wins[selected_tab] and vim.api.nvim_win_is_valid(content_wins[selected_tab]) then - vim.api.nvim_win_hide(content_wins[selected_tab]) - end - - selected = ((index - 1) % #tabs) + 1 - selected_tab = tabs[selected] - - if not content_wins[selected_tab] or not vim.api.nvim_win_is_valid(content_wins[selected_tab]) then - content_wins[selected_tab] = vim.api.nvim_open_win(content_bufs[selected_tab], true, { - relative = "editor", - width = width, - height = content_height, - row = content_row, - col = col, - style = "minimal", - border = "rounded", - }) - else - vim.api.nvim_set_current_win(content_wins[selected_tab]) - end - - update_tab_bar() - update_screen() - end - - update_tab_bar() - update_screen() - - -- Shared mappings - for _, buf in pairs(content_bufs) do - vim.keymap.set("n", "", function() switch_tab(selected + 1) end, { buffer = buf }) - vim.keymap.set("n", "gT", function() switch_tab(selected - 1) end, { buffer = buf }) - vim.keymap.set("n", "", function() - for _, win in pairs(content_wins) do - if win and vim.api.nvim_win_is_valid(win) then - pcall(vim.api.nvim_win_close, win, true) - end - end - pcall(vim.api.nvim_win_close, tab_win, true) - end, { buffer = buf }) - vim.keymap.set("n", "a", function () - vim.ui.input({ prompt = "New folder name: " }, function(input) - if input then - vim.fn.mkdir(cwd .. "/" .. input, "p") - update_screen() - end - end) - end, { buffer = buf }) - vim.keymap.set("n", "R", function () - local entry = get_selected_entry() - if entry ~= nil and not entry.is_up then - vim.ui.input({ prompt = "Rename: ", default = entry.name }, function(input) - if input then - local new_path = cwd .. "/" .. input - vim.fn.rename(entry.full_path, new_path) - update_screen() - end - end) - end - end, { buffer = buf }) - vim.keymap.set("n", "D", function() - local entry = get_selected_entry() - if entry ~= nil and not entry.is_up then - vim.ui.input({ prompt = "Deletion of " .. entry.name .. ": (y/N) Defaults to N: " }, function(input) - if input == "y" or input == "Y" then - vim.fn.delete(entry.full_path, "rf") - update_screen() - end - end) - end - end, {buffer = buf}) - vim.keymap.set("n", "%", function() - local lang, name = get_inputs("file") - if lang == nil or lang == "" then return print("Error: Lang cannot be nil") end - if templates.files[lang].run then - if name ~= nil and name ~= "" then - templates.files[lang].run(name) - end - else - print("Error: No File creation method for " .. lang) - end - end, { buffer = buf }) - vim.keymap.set("n", "x", function() - local lang, name = get_inputs("aux file") - if lang == nil or lang == "" then return print("Error: Lang cannot be nil") end - if templates.extras.run then - if name ~= nil and name ~= "" then - templates.extras.run(lang, name) - end - else - print("Error: No File creation method for " .. lang) - end - end, {buffer = buf}) - vim.keymap.set("n", "d", function () - local lang, name = get_inputs("project") - local opts = {} - opts = vim.tbl_deep_extend("force", {}, require("Polydev.configs").get(lang), opts or {}) - if lang == nil or lang == "" then return print("Error: Lang cannot be nil") end - if templates.projects[lang].run then - if name ~= nil and name ~= "" then - templates.projects[lang].run(name, opts.project_root) - end - else - print("Error: No project creation method for " .. lang) - end - end, { buffer = buf }) - vim.keymap.set("n", "", function() - local entry = get_selected_entry() - if not entry then return end - - if entry.type == "file" then + local function close_all_windows() for _, win in pairs(content_wins) do - if win and vim.api.nvim_win_is_valid(win) then - pcall(vim.api.nvim_win_close, win, true) - end + if win and vim.api.nvim_win_is_valid(win) then + pcall(vim.api.nvim_win_close, win, true) + end end pcall(vim.api.nvim_win_close, tab_win, true) - vim.cmd("edit " .. vim.fn.fnameescape(entry.full_path)) + end - elseif entry.type == "directory" then - cwd = entry.full_path - vim.cmd("cd " .. cwd) + + local function update_tab_bar() + local line = {} + for i, tab in ipairs(tabs) do + local label = (i == selected and "[ " .. tab .. " ]") or (" " .. tab .. " ") + table.insert(line, label) + end + vim.api.nvim_buf_set_lines(tab_buf, 0, -1, false, { table.concat(line, " ") }) + end + + local function update_screen() + if selected_tab == "Projects" then + local entries = get_entries(cwd) + local root = vim.fn.expand(project_root) + if not cwd:find(root, 1, true) then + cwd = root + entries = get_entries(cwd) + end + if cwd ~= root then + table.insert(entries, 1, { + name = "../", + type = "directory", + full_path = vim.fn.fnamemodify(cwd, ":h"), + is_up = true, + }) + end + current_view = vim.deepcopy(entries) + + local lines = {} + for i, item in ipairs(current_view) do + table.insert(lines, string.format("%-2d | %-27s | %-6s", i, item.name, item.type)) + end + vim.api.nvim_buf_set_lines(content_bufs.Projects, 0, -1, false, lines) + + elseif selected_tab == "Recents" then + local oldfiles = vim.v.oldfiles + local valid = {} + for _, file in ipairs(oldfiles) do + if vim.fn.filereadable(file) == 1 then + table.insert(valid, file) + end + end + current_view = vim.tbl_map(function(f) + return { name = vim.fn.fnamemodify(f, ":t"), full_path = f, type = "file" } + end, valid) + + local lines = {} + for i, item in ipairs(current_view) do + table.insert(lines, string.format("%-2d | %-40s", i, item.full_path)) + end + vim.api.nvim_buf_set_lines(content_bufs.Recents, 0, -1, false, lines) + end + end + + local function get_selected_entry() + local win = content_wins[selected_tab] + if not win or not vim.api.nvim_win_is_valid(win) then return end + local row = vim.api.nvim_win_get_cursor(win)[1] + return current_view[row], row + end + + ---@param type string + ---@return string, string + local function get_inputs(type) + local l, n + vim.ui.input({ prompt = "Enter language for new " .. type .. ": " }, function(lang) + if lang == nil then return end + vim.ui.input({ prompt = "Enter ".. type .. " name: " }, function(name) + if not lang or lang == "" then return end + if not name or name == "" then return end + l, n = lang, name + end) + end) + return l, n + end + + local function switch_tab(index) + if content_wins[selected_tab] and vim.api.nvim_win_is_valid(content_wins[selected_tab]) then + vim.api.nvim_win_hide(content_wins[selected_tab]) + end + + selected = ((index - 1) % #tabs) + 1 + selected_tab = tabs[selected] + + if not content_wins[selected_tab] or not vim.api.nvim_win_is_valid(content_wins[selected_tab]) then + content_wins[selected_tab] = vim.api.nvim_open_win(content_bufs[selected_tab], true, { + relative = "editor", + width = width, + height = content_height, + row = content_row, + col = col, + style = "minimal", + border = "rounded", + }) + else + vim.api.nvim_set_current_win(content_wins[selected_tab]) + end + + update_tab_bar() update_screen() - end - end, { buffer = buf }) - end + end + + update_tab_bar() + update_screen() + + -- Shared mappings + for _, buf in pairs(content_bufs) do + vim.keymap.set("n", "", function() switch_tab(selected + 1) end, { buffer = buf }) + vim.keymap.set("n", "gT", function() switch_tab(selected - 1) end, { buffer = buf }) + vim.keymap.set("n", "", function() + for _, win in pairs(content_wins) do + if win and vim.api.nvim_win_is_valid(win) then + pcall(vim.api.nvim_win_close, win, true) + end + end + pcall(vim.api.nvim_win_close, tab_win, true) + end, { buffer = buf }) + vim.keymap.set("n", "a", function () + vim.ui.input({ prompt = "New folder name: " }, function(input) + if input then + vim.fn.mkdir(cwd .. "/" .. input, "p") + update_screen() + end + end) + end, { buffer = buf }) + vim.keymap.set("n", "R", function () + local entry = get_selected_entry() + if entry ~= nil and not entry.is_up then + vim.ui.input({ prompt = "Rename: ", default = entry.name }, function(input) + if input then + local new_path = cwd .. "/" .. input + vim.fn.rename(entry.full_path, new_path) + update_screen() + end + end) + end + end, { buffer = buf }) + vim.keymap.set("n", "D", function() + local entry = get_selected_entry() + if entry ~= nil and not entry.is_up then + vim.ui.input({ prompt = "Deletion of " .. entry.name .. ": (y/N) Defaults to N: " }, function(input) + if input == "y" or input == "Y" then + vim.fn.delete(entry.full_path, "rf") + update_screen() + end + end) + end + end, {buffer = buf}) + vim.keymap.set("n", "%", function() + local lang, name = get_inputs("file") + if lang == nil or lang == "" then return print("Error: Lang cannot be nil") end + if templates.files[lang].run then + if name ~= nil and name ~= "" then + close_all_windows() + templates.files[lang].run(name) + end + else + print("Error: No File creation method for " .. lang) + end + end, { buffer = buf }) + vim.keymap.set("n", "x", function() + local lang, name = get_inputs("aux file") + if lang == nil or lang == "" then return print("Error: Lang cannot be nil") end + if templates.extras.run then + if name ~= nil and name ~= "" then + close_all_windows() + templates.extras.run(lang, name) + end + else + print("Error: No File creation method for " .. lang) + end + end, {buffer = buf}) + vim.keymap.set("n", "d", function () + local lang, name = get_inputs("project") + local opts = {} + opts = vim.tbl_deep_extend("force", {}, require("Polydev.configs").get(lang), opts or {}) + if lang == nil or lang == "" then return print("Error: Lang cannot be nil") end + if templates.projects[lang].run then + if name ~= nil and name ~= "" then + close_all_windows() + templates.projects[lang].run(name, opts.project_root) + end + else + print("Error: No project creation method for " .. lang) + end + end, { buffer = buf }) + vim.keymap.set("n", "", function() + local entry = get_selected_entry() + if not entry then return end + + if entry.type == "file" then + for _, win in pairs(content_wins) do + if win and vim.api.nvim_win_is_valid(win) then + pcall(vim.api.nvim_win_close, win, true) + end + end + pcall(vim.api.nvim_win_close, tab_win, true) + vim.cmd("edit " .. vim.fn.fnameescape(entry.full_path)) + + elseif entry.type == "directory" then + cwd = entry.full_path + vim.cmd("cd " .. cwd) + update_screen() + end + end, { buffer = buf }) + end end return M