diff --git a/lua/Polydev/configs.lua b/lua/Polydev/configs.lua index dc43ccf..47ab1c5 100644 --- a/lua/Polydev/configs.lua +++ b/lua/Polydev/configs.lua @@ -59,9 +59,9 @@ function M.setup(user_opts) }, }, terminal = { - mode = "split", -- floating or split + mode = "split", win = { - type = "horizontal", anchor = "bottom", size = "20" -- type: "vertical" or "horizonal" -- anchor: "below" or "right" or "center" or "corner" -- size: amount of cols or rows based on percentage without percente symbol + type = "horizontal", anchor = "bottom", size = "20" }, border = { enabled = true, @@ -70,14 +70,9 @@ function M.setup(user_opts) }, } - -- First merge global and terminal M.user_config = vim.tbl_deep_extend("force", {}, defaults, user_opts or {}) + local langs = default_languages(M.user_config.globals.project_root) - -- Now use the final resolved project_root from user_config - local root = M.user_config.globals.project_root - local langs = default_languages(root) - - -- Inject languages into the config, respecting user overrides for lang, conf in pairs(langs) do M.user_config[lang] = vim.tbl_deep_extend("force", conf, M.user_config[lang] or {}) end diff --git a/lua/Polydev/init.lua b/lua/Polydev/init.lua index 23798c4..f14d95a 100644 --- a/lua/Polydev/init.lua +++ b/lua/Polydev/init.lua @@ -21,7 +21,26 @@ function M.setup(opts) }) vim.api.nvim_create_autocmd("ColorScheme", { callback = function() - require("Polydev.styles").setup_highlights() + local function define(name, o) + if vim.fn.hlexists(name) == 0 then + vim.api.nvim_set_hl(0, name, o) + end + end + + define("PolydevNormal", { + fg = vim.api.nvim_get_hl(0, { name = "NormalFloat", link = true }).fg, + bg = vim.api.nvim_get_hl(0, { name = "Normal", link = true }).bg, + }) + + define("PolydevBorder", { + fg = vim.api.nvim_get_hl(0, { name = "FloatBorder", link = true }).fg, + bg = vim.api.nvim_get_hl(0, { name = "Normal", link = true }).bg, + }) + + define("PolydevTitle", { + fg = vim.api.nvim_get_hl(0, { name = "FloatTitle", link = true }).fg, bold = true, + bg = vim.api.nvim_get_hl(0, { name = "Normal", link = true }).bg, + }) end, }) end diff --git a/lua/Polydev/languages.lua b/lua/Polydev/languages.lua index be8662e..12e5168 100644 --- a/lua/Polydev/languages.lua +++ b/lua/Polydev/languages.lua @@ -95,7 +95,7 @@ M.languages = { local success = vim.v.shell_error == 0 if not success then - local term_buf, term_win = utils.terminal({ cmd }) + local term_buf = utils.terminal({ cmd }) vim.api.nvim_set_option_value("modifiable", true, { buf = term_buf }) vim.api.nvim_buf_set_lines(term_buf, 0, -1, false, diff --git a/lua/Polydev/presets.lua b/lua/Polydev/presets.lua index 5c1658f..d27aea5 100644 --- a/lua/Polydev/presets.lua +++ b/lua/Polydev/presets.lua @@ -1,28 +1,17 @@ local M = {} ----@class padding ----@field left_padding integer ----@field right_padding integer ----@field top_padding integer ----@field bottom_padding integer - ----@class preset_list ----@field right padding ----@field corner padding - ----@type preset_list local presets = { right = { - left_padding = 100, - right_padding = 0, - top_padding = 0, - bottom_padding = 0, + left = 100, + right = 0, + top = 0, + bottom = 0, }, corner = { - left_padding = 100, - right_padding = 0, - top_padding = 25, - bottom_padding = 0, + left = 100, + right = 0, + top = 25, + bottom = 0, } } diff --git a/lua/Polydev/styles.lua b/lua/Polydev/styles.lua deleted file mode 100644 index c7867a0..0000000 --- a/lua/Polydev/styles.lua +++ /dev/null @@ -1,26 +0,0 @@ -local M = {} - -function M.setup_highlights() - local function define(name, opts) - if vim.fn.hlexists(name) == 0 then - vim.api.nvim_set_hl(0, name, opts) - end - end - - define("PolydevNormal", { - fg = vim.api.nvim_get_hl(0, { name = "NormalFloat", link = true }).fg, - bg = vim.api.nvim_get_hl(0, { name = "Normal", link = true }).bg, - }) - - define("PolydevBorder", { - fg = vim.api.nvim_get_hl(0, { name = "Function", link = true }).fg, - bg = vim.api.nvim_get_hl(0, { name = "Normal", link = true }).bg, - }) - - define("PolydevTitle", { - fg = vim.api.nvim_get_hl(0, { name = "FloatTitle", link = true }).fg, bold = true, - bg = vim.api.nvim_get_hl(0, { name = "Normal", link = true }).bg, - }) -end - -return M diff --git a/lua/Polydev/ui.lua b/lua/Polydev/ui.lua index 01bb813..5627b3b 100644 --- a/lua/Polydev/ui.lua +++ b/lua/Polydev/ui.lua @@ -7,196 +7,192 @@ local function get_entries(path) 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) + 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 Popup = require("nui.popup") - local Layout = require("nui.layout") - local cwd = vim.fn.expand(vim.fn.getcwd()) - local entries = get_entries(cwd) - local current_view = vim.deepcopy(entries) + 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 popup = Popup({ - enter = true, - focusable = true, - border = { - style = "rounded", -- "double", "none", "rounded", "shadow", "single" or "solid". - text = { top = " Results ", top_align = "center" }, - }, - position = "50%", - buf_options = { modifiable = true, readonly = false }, - win_options = { - winhighlight = "Normal:PolydevNormal,FloatBorder:PolydevBorder,FloatTitle:PolydevTitle", - } + local tabs = { "Projects", "Recents" } + local selected = 1 + local selected_tab = tabs[selected] + + 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 layout = Layout( - { - position = "50%", - size = { width = "80%", height = "90%" }, - }, - Layout.Box({ Layout.Box(popup, { grow = 1 }) }, { dir = "row" }) - ) - layout:mount() - ---@return table, integer - local function get_selected_entry() - local row = vim.api.nvim_win_get_cursor(popup.winid)[1] - 1 - return current_view[row], row - end + 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, + } - ---@return string, string - local function get_inputs() - local l, n - vim.ui.input({ prompt = "Enter language for new file: " }, function(lang) - vim.ui.input({ prompt = "Enter file 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 + 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() - entries = get_entries(cwd) - local root = vim.fn.expand(project_root) + 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) - if not cwd:find(root, 1, true) then - cwd = root - entries = get_entries(cwd) - end + 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) - 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) + 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) - if not popup.bufnr then return end - vim.api.nvim_buf_set_lines(popup.bufnr, 0, -1, false, {}) - for i, item in ipairs(current_view) do - local line = string.format("%-2d | %-27s | %-6s", i, item.name, item.type) - vim.api.nvim_buf_set_lines(popup.bufnr, -1, -1, false, { line }) - end + 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 - popup:map("n", "", function() popup:unmount() 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 - popup:map("n", "a", function() - vim.ui.input({ prompt = "New folder name: " }, function(input) - if input then - vim.fn.mkdir(cwd .. "/" .. input, "p") + 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 }) + end + + -- Open file + for tab, buf in pairs(content_bufs) do + 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) - end) + end, { buffer = buf }) - popup:map("n", "R", function() - local entry = get_selected_entry() - if 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) - - popup:map("n", "", function() - local entry = get_selected_entry() - if entry.type == "directory" then - cwd = entry.full_path - vim.cmd("cd " .. cwd) - update_screen() - end - if entry.type == "file" then - popup:unmount() - vim.cmd("edit " .. vim.fn.fnameescape(entry.full_path)) - end - end) - - popup:map("n", "D", function() - local entry = get_selected_entry() - if 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) - - popup:map("n", "%", function() - local lang, name = get_inputs() - if lang == nil or lang == "" then return print("Error: Can't have a blank name for lang") end - if templates.files[lang].run then - popup:unmount() - if name ~= nil and name ~= "" then - templates.files[lang].run(name) - end - else - print("Error: No File creation method for " .. lang) - end - end) - - popup:map("n", "x", function() - local lang, name = get_inputs() - if lang == nil or lang == "" then return print("Error: Can't have a blank name for lang") end - if templates.extras.run then - popup:unmount() - if name ~= nil and name ~= "" then - templates.extras.run(lang, name) - end - else - print("Error: No File creation method for " .. lang) - end - end) - - popup:map("n", "d", function() - local lang, name = get_inputs() - local opts = {} - opts = vim.tbl_deep_extend("force", {}, require("Polydev.configs").get(lang), opts or {}) - if lang == nil or lang == "" then return print("Error: Can't have a blank name for lang") end - if templates.projects[lang].run then - popup:unmount() - 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) - - popup:mount() - update_screen() + end end return M diff --git a/lua/Polydev/utils.lua b/lua/Polydev/utils.lua index e524d2b..b72a89b 100644 --- a/lua/Polydev/utils.lua +++ b/lua/Polydev/utils.lua @@ -15,8 +15,7 @@ end ---@return string function M.get_project_name() - local root = M.get_project_root() - return vim.fn.fnamemodify(root, ":t") + return vim.fn.fnamemodify(M.get_project_root(), ":t") end ---@param path_segments table @@ -36,9 +35,8 @@ function M.init_git(path, gitignore_lines) vim.fn.system({ "git", "-C", path, "init" }) if gitignore_lines and #gitignore_lines > 0 then - local gitignore_path = { path, ".gitignore" } local contents = table.concat(gitignore_lines, "\n") - M.write_file(gitignore_path, contents) + M.write_file({ path, ".gitignore" }, contents) end end @@ -55,10 +53,10 @@ function M.terminal(cmd) local col if opts ~= nil then - width = math.max(1, math.floor(ui.width * 0.9) - opts.left_padding - opts.right_padding) - height = math.max(1, math.floor(ui.height * 0.9) - opts.top_padding - opts.bottom_padding) - row = math.floor((ui.height - height) / 2) + opts.top_padding - col = math.floor((ui.width - width) / 2) + opts.left_padding + width = math.max(1, math.floor(ui.width * 0.9) - opts.left - opts.right) + height = math.max(1, math.floor(ui.height * 0.9) - opts.top - opts.bottom) + row = math.floor((ui.height - height) / 2) + opts.top + col = math.floor((ui.width - width) / 2) + opts.left end if opts == nil then width = math.max(1, math.floor(ui.width * 0.9))