added project manager and updated documentation

This commit is contained in:
DarthMooMancer
2025-04-21 05:19:27 -04:00
parent 467d864eb4
commit a725faaac8
4 changed files with 316 additions and 87 deletions
+17 -1
View File
@@ -14,6 +14,10 @@ This is the **recommended** way if you're using [Lazy.nvim](https://github.com/f
```lua ```lua
{ {
"DarthMooMancer/Polydev", "DarthMooMancer/Polydev",
dependencies = {
"MunifTanjim/nui.nvim",
"nvim-lua/plenary.nvim"
},
opts = { opts = {
lua = { lua = {
project_root = "~/Projects/Lua", project_root = "~/Projects/Lua",
@@ -38,7 +42,13 @@ This is the **recommended** way if you're using [Lazy.nvim](https://github.com/f
For users of [mini.nvim](https://github.com/echasnovski/mini.nvim)'s dependency manager: For users of [mini.nvim](https://github.com/echasnovski/mini.nvim)'s dependency manager:
```lua ```lua
MiniDeps.add({ source = "DarthMooMancer/Polydev" }) MiniDeps.add({
source = "DarthMooMancer/Polydev"
depends = {
"MunifTanjim/nui.nvim",
"nvim-lua/plenary.nvim"
}
})
require("Polydev").setup({ require("Polydev").setup({
rust = { rust = {
@@ -64,6 +74,10 @@ For fans of [Packer.nvim](https://github.com/wbthomason/packer.nvim):
```lua ```lua
use({ use({
"DarthMooMancer/Polydev", "DarthMooMancer/Polydev",
requires = {
"MunifTanjim/nui.nvim",
"nvim-lua/plenary.nvim"
},
config = function() config = function()
require("Polydev").setup({ require("Polydev").setup({
python = { python = {
@@ -89,6 +103,8 @@ Even if you're still using [vim-plug](https://github.com/junegunn/vim-plug), you
```vim ```vim
Plug 'DarthMooMancer/Polydev' Plug 'DarthMooMancer/Polydev'
Plug 'MunifTanjim/nui.nvim'
Plug 'nvim-lua/plenary.nvim'
lua << EOF lua << EOF
require("Polydev").setup({ require("Polydev").setup({
+5 -4
View File
@@ -1,5 +1,8 @@
# Setup and Customizing Polydev # Setup and Customizing Polydev
## Project Manager
Follows the netrw keybinds and allows for project management all in one spot
## 🔧 Project Name Customization ## 🔧 Project Name Customization
You can easily customize the default directory for your project! The project can be created from any directory, and Polydev will automatically create the required project root directory for you. You can easily customize the default directory for your project! The project can be created from any directory, and Polydev will automatically create the required project root directory for you.
@@ -44,11 +47,10 @@ return {
... ...
opts = { opts = {
<language> = { <language> = {
["<Esc>"] = "CloseTerminal", -- Universal, can be changed per language for now
["<leader>pb"] = "languageBuild", -- Per-language ["<leader>pb"] = "languageBuild", -- Per-language
["<leader>pr"] = "languageRun", -- Per-language ["<leader>pr"] = "languageRun", -- Per-language
["<leader>nf"] = "NewLanguageFile", -- Universal
["<leader>nh"] = "NewLanguageSecondaryFile", -- Universal ["<leader>nh"] = "NewLanguageSecondaryFile", -- Universal
["<leader>po"] = "OpenSmartTable", -- Universal
} }
} }
... ...
@@ -60,11 +62,10 @@ return {
```lua ```lua
require("Polydev").language.setup({ require("Polydev").language.setup({
keybinds = { keybinds = {
["<Esc>"] = "CloseTerminal", -- Universal, can be changed per language for now
["<leader>pb"] = "languageBuild", -- Per-language ["<leader>pb"] = "languageBuild", -- Per-language
["<leader>pr"] = "languageRun", -- Per-language ["<leader>pr"] = "languageRun", -- Per-language
["<leader>nf"] = "NewLanguageFile", -- Universal
["<leader>nh"] = "NewLanguageSecondaryFile", -- Universal ["<leader>nh"] = "NewLanguageSecondaryFile", -- Universal
["<leader>po"] = "OpenSmartTable", -- Universal
} }
}) })
``` ```
+225 -19
View File
@@ -1,11 +1,9 @@
---@module "Polydev.configs"
local config = require("Polydev.configs") local config = require("Polydev.configs")
---@module "Polydev.utils"
local utils = require("Polydev.utils") local utils = require("Polydev.utils")
---@module "Polydev.templates"
local templates = require("Polydev.templates") local templates = require("Polydev.templates")
local Popup = require("nui.popup")
local event = require("nui.utils.autocmd").event
local Path = require("plenary.path")
---@type table ---@type table
local M = {} local M = {}
@@ -29,30 +27,240 @@ function M.load_language_module(lang, opts)
return false return false
end end
function M.create_project() -- Get entries in a given path
local function get_entries(path)
local result = {}
local handle = vim.loop.fs_scandir(path)
if not handle then return result end
while true do
local name, type = vim.loop.fs_scandir_next(handle)
if not name then break end
-- Check if this is a project file
local is_project = false
if type == "file" then
local ext = name:match("%.([^%.]+)$")
if ext == "project" then
is_project = true
type = "project"
end
end
table.insert(result, {
name = name .. (type == "directory" and "/" or ""),
type = type,
full_path = path .. "/" .. name,
is_project = is_project
})
end
table.sort(result, function(a, b)
-- Sort projects first, then directories, then files
if a.is_project ~= b.is_project then
return a.is_project
end
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
-- Fuzzy search
local function fuzzy_filter(list, query)
local result = {}
query = query:lower()
for _, entry in ipairs(list) do
if entry.name:lower():find(query) then
table.insert(result, entry)
end
end
return result
end
-- Main function
local function open_filtered_table()
local display_dir = vim.fn.expand(vim.fn.getcwd())
local cwd = display_dir
local entries = get_entries(cwd)
local current_view = vim.deepcopy(entries)
local popup = Popup({
enter = true,
focusable = true,
border = {
style = "rounded",
text = { top = " Project Manager ", top_align = "center" },
highlight = "Normal",
},
position = "50%",
size = { width = 60, height = 14 },
buf_options = { modifiable = true, readonly = false },
})
local function get_selected_entry()
local row = vim.api.nvim_win_get_cursor(0)[1] - 1
return current_view[row], row
end
local function refresh()
entries = get_entries(cwd)
local root = vim.fn.expand("~/Projects")
if cwd ~= root then
table.insert(entries, 1, {
name = "../",
type = "directory",
full_path = Path:new(cwd):parent():absolute(),
is_up = true
})
end
current_view = vim.deepcopy(entries)
end
local function render()
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("%-3d | %-30s | %-6s", i, item.name, item.type)
vim.api.nvim_buf_set_lines(popup.bufnr, -1, -1, false, { line })
end
-- Add key mappings legend
local hints = {
"",
"Keybinds:",
" <CR> : Open file / Enter directory",
" <BS> : Go to parent directory",
" / : Filter (fuzzy search)",
" a : Create new folder",
" % : Create new file",
" d : Create new project",
" R : Rename file/folder",
" D : Delete file/folder",
" q : Quit popup",
}
vim.api.nvim_buf_set_lines(popup.bufnr, -1, -1, false, hints)
end
local function prompt_filter()
vim.ui.input({ prompt = "Search: " }, function(input)
if input then
current_view = fuzzy_filter(entries, input)
render()
end
end)
end
-- Mappings
popup:map("n", "q", function() popup:unmount() end)
popup:map("n", "/", prompt_filter)
-- Creates a new folder
popup:map("n", "a", function()
vim.ui.input({ prompt = "New folder name:" }, function(input)
if input then
vim.fn.mkdir(cwd .. "/" .. input, "p")
refresh()
render()
end
end)
end)
-- Deletes Folder and confirms deletion
popup:map("n", "D", function()
local entry = get_selected_entry()
if entry and not entry.is_up then
vim.ui.input({ prompt = "(y/N) Defaults to N: " .. entry.name }, function(input)
if input == "y" or input == "Y" then
vim.fn.delete(entry.full_path, "rf")
refresh()
render()
end
end)
end
end)
-- Creates a new file in project
popup:map("n", "%", function()
vim.ui.input({ prompt = "Enter language for new file: " }, function(lang)
if not lang or lang == "" then return print("File creation canceled.") end
if M.load_language_module(lang) and templates.files[lang] and templates.files[lang].run then
vim.ui.input({ prompt = "Enter file name: " }, function(file_name)
if not file_name or file_name == "" then return print("File creation canceled.") end
templates.files[lang].run(file_name)
refresh()
render()
end)
else
print("Error: No File creation method for " .. lang)
end
end)
end)
-- Creates a new project
popup:map("n", "d", function()
local opts = {} local opts = {}
vim.ui.input({ prompt = "Enter language for project: " }, function(lang) vim.ui.input({ prompt = "Enter language for project: " }, function(lang)
if not lang or lang == "" then return print("Project creation canceled.") end if not lang or lang == "" then return print("Project creation canceled.") end
opts = vim.tbl_deep_extend("force", {}, config.get(lang), opts or {}) opts = vim.tbl_deep_extend("force", {}, config.get(lang), opts or {})
if M.load_language_module(lang) and templates.projects[lang] and templates.projects[lang].run then if M.load_language_module(lang) and templates.projects[lang] and templates.projects[lang].run then
templates.create_project(lang, opts.project_root) templates.create_project(lang, opts.project_root)
vim.cmd("cd " .. templates.dir .. "/src")
refresh()
render()
else else
print("Error: No project creation method for " .. lang) print("Error: No project creation method for " .. lang)
end end
end) end)
end end)
function M.create_new_file() -- Renames Files and Folders
vim.ui.input({ prompt = "Enter language for new file: " }, function(lang) popup:map("n", "R", function()
if not lang or lang == "" then return print("File creation canceled.") end local entry = get_selected_entry()
if entry and not entry.is_up then
if M.load_language_module(lang) and templates.files[lang] and templates.files[lang].run then vim.ui.input({ prompt = "Rename:", default = entry.name }, function(input)
templates.create_new_file(lang) if input then
else local new_path = cwd .. "/" .. input
print("Error: No File creation method for " .. lang) vim.fn.rename(entry.full_path, new_path)
refresh()
render()
end end
end) end)
end end
end)
-- Changes working directory or edits a file
popup:map("n", "<CR>", function()
local entry = get_selected_entry()
if entry and entry.type == "directory" then
cwd = entry.full_path
vim.cmd("cd " .. cwd)
refresh()
render()
end
if entry and entry.type == "file" then
vim.cmd("edit " .. entry.name)
end
end)
popup:map("n", "<BS>", function()
local parent = Path:new(cwd):parent():absolute()
if parent ~= cwd then
cwd = parent
refresh()
render()
end
end)
popup:on(event.BufLeave, function() popup:unmount() end)
popup:mount()
refresh()
render()
end
---@param opts table ---@param opts table
function M.setup(opts) function M.setup(opts)
@@ -64,10 +272,8 @@ function M.setup(opts)
config.user_config[lang] = vim.tbl_deep_extend("force", default, user_opts) config.user_config[lang] = vim.tbl_deep_extend("force", default, user_opts)
end end
vim.api.nvim_create_user_command("NewProject", M.create_project, {}) vim.api.nvim_create_user_command("OpenSmartTable", open_filtered_table, {})
vim.api.nvim_create_user_command("NewFile", M.create_new_file, {}) vim.keymap.set("n", "<leader>po", ":OpenSmartTable<CR>", { silent = true })
vim.keymap.set("n", "<leader>np", ":NewProject<CR>", { silent = true })
vim.keymap.set("n", "<leader>nf", ":NewFile<CR>", { silent = true })
vim.api.nvim_create_autocmd("FileType", { vim.api.nvim_create_autocmd("FileType", {
pattern = "*", pattern = "*",
callback = function() callback = function()
+12 -6
View File
@@ -9,7 +9,7 @@ local utils = require("Polydev.utils")
local M = {} local M = {}
---@class TemplateLanguage ---@class TemplateLanguage
---@field run fun(project_name: string, project_root: string): nil ---@field run fun(project_name: string, project_root: string): string
---@class Projects ---@class Projects
---@field java TemplateLanguage ---@field java TemplateLanguage
@@ -35,7 +35,7 @@ public class Main {
} }
]] ]]
utils.write_file(full_project_root .. "/src/Main.java", main_java_content) utils.write_file(full_project_root .. "/src/Main.java", main_java_content)
return nil return full_project_root
end end
}, },
python = { python = {
@@ -69,7 +69,7 @@ setup(
vim.fn.setenv("VIRTUAL_ENV", venv_path) vim.fn.setenv("VIRTUAL_ENV", venv_path)
vim.fn.setenv("PATH", venv_path .. "/bin:" .. vim.fn.getenv("PATH")) vim.fn.setenv("PATH", venv_path .. "/bin:" .. vim.fn.getenv("PATH"))
print("Virtual environment activated for " .. project_name) print("Virtual environment activated for " .. project_name)
return nil return full_project_root
end end
}, },
lua = { lua = {
@@ -83,7 +83,7 @@ return M
]]) ]])
utils.write_file(full_project_root .. "/" .. project_name .. ".polydev", "[[DO NOT REMOVE THIS FILE]]") utils.write_file(full_project_root .. "/" .. project_name .. ".polydev", "[[DO NOT REMOVE THIS FILE]]")
vim.cmd("edit " .. full_project_root .. "/lua/" .. project_name .. "/init.lua") vim.cmd("edit " .. full_project_root .. "/lua/" .. project_name .. "/init.lua")
return nil return full_project_root
end end
}, },
c = { c = {
@@ -150,6 +150,7 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
]])) ]]))
vim.cmd("edit " .. full_project_root .. "/src/main.c") vim.cmd("edit " .. full_project_root .. "/src/main.c")
vim.fn.system(string.format("cd %s/build/ && cmake .. && cmake --build .", full_project_root)) vim.fn.system(string.format("cd %s/build/ && cmake .. && cmake --build .", full_project_root))
return full_project_root
end end
}, },
cpp = { cpp = {
@@ -218,7 +219,7 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
]])) ]]))
vim.fn.system(string.format("cd %s/build/ && cmake .. && cmake --build .", full_project_root)) vim.fn.system(string.format("cd %s/build/ && cmake .. && cmake --build .", full_project_root))
vim.cmd("edit " .. full_project_root .. "/src/main.cpp") vim.cmd("edit " .. full_project_root .. "/src/main.cpp")
return nil return full_project_root
end end
}, },
rust = { rust = {
@@ -226,6 +227,7 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
local full_project_root = vim.fn.expand(project_root) .. "/" .. project_name local full_project_root = vim.fn.expand(project_root) .. "/" .. project_name
vim.fn.system("cargo new " .. full_project_root) vim.fn.system("cargo new " .. full_project_root)
vim.cmd("edit " .. full_project_root .. "/src/main.rs") vim.cmd("edit " .. full_project_root .. "/src/main.rs")
return full_project_root
end end
}, },
html = { html = {
@@ -246,6 +248,7 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
</html> </html>
]] ]]
utils.write_file(full_project_root .. "index.html", main_html_content) utils.write_file(full_project_root .. "index.html", main_html_content)
return full_project_root
end end
}, },
} }
@@ -376,12 +379,15 @@ public class %s {
} }
} }
---@type string
M.dir = ""
---@param lang TemplatesLanguageName ---@param lang TemplatesLanguageName
---@param project_root string ---@param project_root string
function M.create_project(lang, project_root) function M.create_project(lang, project_root)
vim.ui.input({ prompt = "Enter project name: " }, function(project_name) vim.ui.input({ prompt = "Enter project name: " }, function(project_name)
if not project_name or project_name == "" then return print("Project creation canceled.") end if not project_name or project_name == "" then return print("Project creation canceled.") end
M.projects[lang].run(project_name, project_root) M.dir = M.projects[lang].run(project_name, project_root)
end) end)
end end