From 2b30e36fade3272081f7166bc0ec614b0b7da1c9 Mon Sep 17 00:00:00 2001 From: Andrew Haynes Date: Mon, 3 Aug 2026 16:03:08 -0400 Subject: [PATCH] major changes to try and fix a bunch of random bugs --- README.md | 1 + lua/Polydev/health.lua | 157 ++++++++++++++++++++++++++++++++++++++ lua/Polydev/languages.lua | 12 +-- lua/Polydev/ui.lua | 84 ++++++++++---------- lua/Polydev/utils.lua | 2 +- 5 files changed, 204 insertions(+), 52 deletions(-) create mode 100644 lua/Polydev/health.lua diff --git a/README.md b/README.md index d833dc8..b14bcf6 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ * Integrated terminal for flexible command execution * Lightweight, fast project manager UI * Minimal configuration with extensibility in mind +* Built-in diagnostics with `:checkhealth Polydev` > 📚 [View the full documentation](https://git.moomancer.xyz/DarthMooMancer/polydev/wiki/Home$0) for setup, configuration, and usage details. diff --git a/lua/Polydev/health.lua b/lua/Polydev/health.lua new file mode 100644 index 0000000..ad822ce --- /dev/null +++ b/lua/Polydev/health.lua @@ -0,0 +1,157 @@ +local ok, health = pcall(require, "vim.health") +if not ok then + health = nil +end + +local new_api = health ~= nil and type(health.start) == "function" + +local function report_start(name) + if new_api then health.start(name) else vim.health.report_start(name) end +end + +local function report_ok(msg) + if new_api then health.ok(msg) else vim.health.report_ok(msg) end +end + +local function report_info(msg) + if new_api then health.info(msg) else vim.health.report_info(msg) end +end + +local function report_warn(msg, advice) + if new_api then + health.warn(msg, advice) + else + vim.health.report_warn(msg, advice) + end +end + +local function report_error(msg, advice) + if new_api then + health.error(msg, advice) + else + vim.health.report_error(msg, advice) + end +end + +local M = {} + +local function fmt_langs(langs) + if type(langs) == "table" then + return "[" .. table.concat(langs, ", ") .. "]" + end + return "[" .. tostring(langs) .. "]" +end + +local function check_nvim_version() + if vim.fn.has("nvim-0.10") == 1 then + report_ok(string.format("Neovim %s detected.", tostring(vim.version()))) + else + report_error("Polydev requires Neovim 0.10 or newer.", "You are running " .. tostring(vim.version())) + end +end + +local function check_setup() + local ok_configs, configs = pcall(require, "Polydev.configs") + if not ok_configs then + report_error("Could not load Polydev.configs", tostring(configs)) + return nil + end + if next(configs.user_config or {}) == nil then + report_warn("Polydev.setup() has not run.", + "Add require('Polydev').setup() to your Neovim config, or make sure plugin/Polydev.lua is sourced by your plugin manager.") + return nil + end + report_ok("Polydev.setup() ran and the config is loaded.") + return configs +end + +local function check_project_root(configs) + if not configs then return end + local root = configs.get("globals").project_root + local expanded = vim.fn.expand(root) + if vim.fn.isdirectory(expanded) == 1 then + if vim.fn.filewritable(expanded) == 2 then + report_ok(string.format("project_root exists and is writable: %s", expanded)) + else + report_warn(string.format("project_root exists but is not writable: %s", expanded)) + end + else + report_warn(string.format("project_root does not exist yet: %s", expanded), + "It is created automatically the first time the manager is opened.") + end +end + +local function check_ui_input() + local ok_default, default = pcall(require, "vim.ui") + if ok_default and default.input and vim.ui.input ~= default.input then + report_warn("vim.ui.input has been overridden, likely by a UI plugin such as dressing.nvim or nui.nvim.", + "An asynchronous override can break project/file creation from the manager. Polydev now uses callbacks, but report here if it still misbehaves.") + else + report_ok("vim.ui.input is Neovim's default (synchronous) implementation.") + end +end + +local function check_tools() + local tools = { + { name = "git", langs = "all" }, + { name = "node", langs = "javascript" }, + { name = "python3", langs = "python" }, + { name = "pip3", langs = "python" }, + { name = "javac", langs = "java" }, + { name = "java", langs = "java" }, + { name = "cmake", langs = { "c", "cpp" } }, + { name = "cc", langs = { "c", "cpp" } }, + { name = "clang", langs = { "c", "cpp" } }, + { name = "clang-format", langs = { "c", "cpp" } }, + { name = "clang-tidy", langs = { "c", "cpp" } }, + { name = "cargo", langs = "rust" }, + { name = "lua", langs = "lua" }, + { name = "luajit", langs = "lua" }, + } + for _, t in ipairs(tools) do + if vim.fn.executable(t.name) == 1 then + report_ok(string.format("%s is available for %s.", t.name, fmt_langs(t.langs))) + else + report_warn(string.format("%s was not found.", t.name), + "Project templates for " .. fmt_langs(t.langs) .. " may fail without it.") + end + end + + if vim.fn.executable("python3") == 1 then + vim.fn.system("python3 -c 'import venv' 2>/dev/null") + if vim.v.shell_error == 0 then + report_ok("python3 venv module is available.") + else + report_warn("python3 venv module is missing.", + "Python project creation sets up a virtualenv and needs python3 -m venv.") + end + end +end + +local function check_walkup() + local scripts = vim.api.nvim_get_runtime_file("bash_scripts/walkup.sh", false) + if #scripts == 0 then + report_error("bash_scripts/walkup.sh was not found on the runtimepath.", + "Reinstall the plugin so bash_scripts/ sits next to lua/ and plugin/.") + return + end + local script = scripts[1] + if vim.fn.executable(script) == 1 then + report_ok(string.format("bash_scripts/walkup.sh found and executable: %s", script)) + else + report_warn(string.format("bash_scripts/walkup.sh is not executable: %s", script), + "Run: chmod +x " .. script) + end +end + +function M.check() + report_start("Polydev") + check_nvim_version() + local configs = check_setup() + check_project_root(configs) + check_ui_input() + check_tools() + check_walkup() +end + +return M diff --git a/lua/Polydev/languages.lua b/lua/Polydev/languages.lua index 0e30b43..b770acd 100644 --- a/lua/Polydev/languages.lua +++ b/lua/Polydev/languages.lua @@ -38,12 +38,12 @@ M.languages = { if not vim.v.shell_error == 0 then local term_buf = utils.terminal({ cmd }) - vim.api.nvim_set_option_value("modifiable", true, { win = term_buf }) + vim.api.nvim_set_option_value("modifiable", true, { buf = term_buf }) vim.api.nvim_buf_set_lines(term_buf, 0, -1, false, vim.list_extend({ "Error during compilation:" }, vim.split(output, "\n", { trimempty = true })) ) - vim.api.nvim_set_option_value("modifiable", false, { win = term_buf }) + vim.api.nvim_set_option_value("modifiable", false, { buf = term_buf }) else utils.terminal({ "node " .. root .. "/main.js" }) end @@ -65,12 +65,12 @@ M.languages = { if not vim.v.shell_error == 0 then local term_buf = utils.terminal({ cmd }) - vim.api.nvim_set_option_value("modifiable", true, { win = term_buf }) + vim.api.nvim_set_option_value("modifiable", true, { buf = term_buf }) vim.api.nvim_buf_set_lines(term_buf, 0, -1, false, vim.list_extend({ "Error during compilation:" }, vim.split(output, "\n", { trimempty = true })) ) - vim.api.nvim_set_option_value("modifiable", false, { win = term_buf }) + vim.api.nvim_set_option_value("modifiable", false, { buf = term_buf }) else utils.terminal({ "java -cp " .. root, "build" .. " Main" }) end @@ -161,12 +161,12 @@ M.languages = { if not vim.v.shell_error == 0 then local term_buf = utils.terminal(cmd) - vim.api.nvim_set_option_value("modifiable", true, { win = term_buf }) + vim.api.nvim_set_option_value("modifiable", true, { buf = term_buf }) vim.api.nvim_buf_set_lines(term_buf, 0, -1, false, vim.list_extend({ "Error during compilation:" }, vim.split(output, "\n", { trimempty = true })) ) - vim.api.nvim_set_option_value("modifiable", false, { win = term_buf }) + vim.api.nvim_set_option_value("modifiable", false, { buf = term_buf }) else utils.terminal({ "cargo run" }) end diff --git a/lua/Polydev/ui.lua b/lua/Polydev/ui.lua index c9725f8..38d0b57 100644 --- a/lua/Polydev/ui.lua +++ b/lua/Polydev/ui.lua @@ -26,9 +26,8 @@ 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.40), math.floor(ui.height * 0.4) - local row, col = math.floor((ui.height - height) / 3), math.floor((ui.width - width) / 2) + local width, height = math.floor(vim.o.columns * 0.40), math.floor(vim.o.lines * 0.4) + local row, col = math.floor((vim.o.lines - height) / 3), math.floor((vim.o.columns - width) / 2) local content_row = row + 2 local content_height = height - 3 @@ -53,8 +52,11 @@ function M.manager(project_root) end local function update_screen() - local entries = get_entries(cwd) local root = vim.fn.expand(project_root) + if vim.fn.isdirectory(root) == 0 then + vim.fn.mkdir(root, "p") + end + local entries = get_entries(cwd) if not cwd:find(root, 1, true) then cwd = root entries = get_entries(cwd) @@ -70,8 +72,13 @@ function M.manager(project_root) 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)) + if #current_view == 0 then + table.insert(lines, "No projects found in " .. cwd) + table.insert(lines, "Press d to create a project, or a to add a folder.") + else + for i, item in ipairs(current_view) do + table.insert(lines, string.format("%-2d | %-27s | %-6s", i, item.name, item.type)) + end end vim.api.nvim_buf_set_lines(content_buf, 0, -1, false, lines) end @@ -84,18 +91,15 @@ function M.manager(project_root) end ---@param type string - ---@return string, string - local function get_inputs(type) - local l, n + ---@param callback fun(lang: string, name: string) + local function get_inputs(type, callback) 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 lang or lang == "" then return end + vim.ui.input({ prompt = "Enter " .. type .. " name: " }, function(name) if not name or name == "" then return end - l, n = lang, name + callback(lang, name) end) end) - return l, n end update_screen() @@ -138,42 +142,32 @@ function M.manager(project_root) 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) + get_inputs("file", function(lang, name) + local file = templates.files[lang] + if not file or not file.run then + return print("Error: No file creation method for " .. lang) end - else - print("Error: No File creation method for " .. lang) - end + close_all_windows() + file.run(name) + 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 + get_inputs("aux file", function(lang, name) + close_all_windows() + templates.extras.run(lang, name) + 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) + vim.keymap.set("n", "d", function() + get_inputs("project", function(lang, name) + local project = templates.projects[lang] + if not project or not project.run then + return print("Error: No project creation method for " .. lang) end - else - print("Error: No project creation method for " .. lang) - end + local opts = require("Polydev.configs").get(lang) + local run_root = opts.project_root or project_root + close_all_windows() + project.run(name, run_root) + end) end, { buffer = buf }) vim.keymap.set("n", "", function() local entry = get_selected_entry() diff --git a/lua/Polydev/utils.lua b/lua/Polydev/utils.lua index 18cbb64..793b11d 100644 --- a/lua/Polydev/utils.lua +++ b/lua/Polydev/utils.lua @@ -26,7 +26,7 @@ end ---@param content string function M.write_file(path_segments, content) local path = table.concat(path_segments, "/") - local file = assert(io.open(path, "w"), "Fucking dumbass code: Error creating file: " .. path) + local file = assert(io.open(path, "w"), "Error creating file: " .. path) file:write(content) file:close() vim.cmd("edit " .. path)