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
+64 -48
View File
@@ -13,19 +13,23 @@ This is the **recommended** way if you're using [Lazy.nvim](https://github.com/f
```lua ```lua
{ {
"DarthMooMancer/Polydev", "DarthMooMancer/Polydev",
opts = { dependencies = {
lua = { "MunifTanjim/nui.nvim",
project_root = "~/Projects/Lua", "nvim-lua/plenary.nvim"
keybinds = {
["<leader>pr"] = "LuaRun",
},
}, },
terminal = { opts = {
border = true, lua = {
number = true, project_root = "~/Projects/Lua",
keybinds = {
["<leader>pr"] = "LuaRun",
},
},
terminal = {
border = true,
number = true,
},
}, },
},
} }
``` ```
@@ -38,20 +42,26 @@ 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 = {
project_root = "~/Projects/Rust", project_root = "~/Projects/Rust",
keybinds = { keybinds = {
["<leader>pb"] = "RustBuild", ["<leader>pb"] = "RustBuild",
["<leader>pr"] = "RustRun", ["<leader>pr"] = "RustRun",
},
},
terminal = {
border = true,
number = true,
}, },
},
terminal = {
border = true,
number = true,
},
}) })
``` ```
@@ -63,21 +73,25 @@ For fans of [Packer.nvim](https://github.com/wbthomason/packer.nvim):
```lua ```lua
use({ use({
"DarthMooMancer/Polydev", "DarthMooMancer/Polydev",
config = function() requires = {
require("Polydev").setup({ "MunifTanjim/nui.nvim",
python = { "nvim-lua/plenary.nvim"
project_root = "~/Projects/Python", },
keybinds = { config = function()
["<leader>pb"] = "PythonPip", require("Polydev").setup({
["<leader>pr"] = "PythonRun", python = {
}, project_root = "~/Projects/Python",
}, keybinds = {
terminal = { ["<leader>pb"] = "PythonPip",
relativenumber = true, ["<leader>pr"] = "PythonRun",
}, },
}) },
end, terminal = {
relativenumber = true,
},
})
end,
}) })
``` ```
@@ -89,20 +103,22 @@ 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({
c = { c = {
project_root = "~/Projects/C", project_root = "~/Projects/C",
keybinds = { keybinds = {
["<leader>pb"] = "CBuild", ["<leader>pb"] = "CBuild",
["<leader>pr"] = "CRun", ["<leader>pr"] = "CRun",
}, },
}, },
terminal = { terminal = {
number = true, number = true,
}, },
}) })
EOF EOF
``` ```
@@ -120,8 +136,8 @@ Then in your config:
```lua ```lua
require("Polydev").setup({ require("Polydev").setup({
terminal = { terminal = {
border = true, border = true,
}, },
}) })
``` ```
+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
} }
}) })
``` ```
+235 -29
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 = {}
@@ -21,37 +19,247 @@ function M.load_language_module(lang, opts)
local ok, lang_module = pcall(require, "Polydev.languages." .. lang) local ok, lang_module = pcall(require, "Polydev.languages." .. lang)
if ok and lang_module.setup then if ok and lang_module.setup then
local lang_opts = opts and opts[lang] or {} local lang_opts = opts and opts[lang] or {}
lang_module.setup(lang_opts) lang_module.setup(lang_opts)
M.loaded_languages[lang] = lang_module M.loaded_languages[lang] = lang_module
return true return true
end end
return false return false
end end
function M.create_project() -- Get entries in a given path
local opts = {} local function get_entries(path)
vim.ui.input({ prompt = "Enter language for project: " }, function(lang) local result = {}
if not lang or lang == "" then return print("Project creation canceled.") end local handle = vim.loop.fs_scandir(path)
opts = vim.tbl_deep_extend("force", {}, config.get(lang), opts or {}) if not handle then return result end
if M.load_language_module(lang) and templates.projects[lang] and templates.projects[lang].run then while true do
templates.create_project(lang, opts.project_root) local name, type = vim.loop.fs_scandir_next(handle)
else if not name then break end
print("Error: No project creation method for " .. lang) -- 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 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) end)
return result
end end
function M.create_new_file() -- Fuzzy search
vim.ui.input({ prompt = "Enter language for new file: " }, function(lang) local function fuzzy_filter(list, query)
if not lang or lang == "" then return print("File creation canceled.") end 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
if M.load_language_module(lang) and templates.files[lang] and templates.files[lang].run then -- Main function
templates.create_new_file(lang) local function open_filtered_table()
else local display_dir = vim.fn.expand(vim.fn.getcwd())
print("Error: No File creation method for " .. lang) 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
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 = {}
vim.ui.input({ prompt = "Enter language for project: " }, function(lang)
if not lang or lang == "" then return print("Project creation canceled.") end
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
templates.create_project(lang, opts.project_root)
vim.cmd("cd " .. templates.dir .. "/src")
refresh()
render()
else
print("Error: No project creation method for " .. lang)
end
end)
end)
-- Renames Files and Folders
popup:map("n", "R", function()
local entry = get_selected_entry()
if entry 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)
refresh()
render()
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 end
---@param opts table ---@param opts table
@@ -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