added project manager and updated documentation
This commit is contained in:
+17
-1
@@ -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
@@ -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
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user