Skip to content

Commit

Permalink
Merge pull request #12 from vague2k/add-dir-popup
Browse files Browse the repository at this point in the history
feat: Manually add dirs. resolves #10
  • Loading branch information
LintaoAmons authored Feb 22, 2024
2 parents 405cf5c + c45061c commit f9009fd
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 26 deletions.
9 changes: 9 additions & 0 deletions lua/cd-project/adapter/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ local function cd_project()
require("cd-project.adapter.vim-ui").cd_project()
end

local function manual_cd_project()
local projects_picker = vim.g.cd_project_config.projects_picker
if projects_picker == "telescope" then
return require("cd-project.adapter.telescope").manual_cd_project()
end
require("cd-project.adapter.vim-ui").manual_cd_project()
end

return {
cd_project = cd_project,
manual_cd_project = manual_cd_project,
}
85 changes: 73 additions & 12 deletions lua/cd-project/adapter/telescope.lua
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
local utils = require("cd-project.utils")
local success, _ = pcall(require, "telescope.pickers")
if not success then
utils.log_error("telescope not installed")
return
end
local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local conf = require("telescope.config").values
local actions = require("telescope.actions")
local action_state = require("telescope.actions.state")

local repo = require("cd-project.project-repo")
local api = require("cd-project.api")

---@param opts? table
local cd_project = function(opts)
local utils = require("cd-project.utils")
local success, _ = pcall(require, "telescope.pickers")
if not success then
utils.log_error("telescope not installed")
return
end
local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local conf = require("telescope.config").values
local actions = require("telescope.actions")
local action_state = require("telescope.actions.state")
opts = opts or {}
local projects = repo.get_projects()
local maxLength = 0
Expand All @@ -25,7 +26,7 @@ local cd_project = function(opts)

pickers
.new(opts, {
attach_mappings = function(prompt_bufnr, map)
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
actions.close(prompt_bufnr)
---@type CdProject.Project
Expand All @@ -51,6 +52,66 @@ local cd_project = function(opts)
:find()
end

local manual_cd_project = function(opts)
opts = opts or {}

local find_command = utils.check_for_find_cmd()
if not find_command then
utils.log_error("You need to install fd or find.")
return
end

-- Harding coding the Home directory as a starting point for finding
-- directories is desireable since it's very unlikely a user will have
-- a project worth adding to the cd list in any parent dir relative to the home dir.
-- On Windows: ~ == "<drive>:/Users/<user>"
vim.fn.jobstart(find_command, {
cwd = vim.fn.expand("~"),
stdout_buffered = true,
on_stdout = function(_, data)
pickers
.new(opts, {
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
actions.close(prompt_bufnr)
local selected_dir = action_state.get_selected_entry().value
local formatted_path = utils.format_dir_based_on_os(selected_dir)

vim.ui.input({ prompt = "Add a project name: " }, function(name)
if not name or name == "" then
vim.notify(
'No name given, using "'
.. utils.get_tail_of_path(formatted_path)
.. '" instead'
)
local project = api.build_project_obj(formatted_path)
if not project then
return
end
return api.add_project(project)
end

local project = api.build_project_obj(formatted_path, name)
if not project then
return
end
return api.add_project(project)
end)
end)
return true
end,
prompt_title = "Select dir to add",
finder = finders.new_table({
results = data,
}),
sorter = conf.file_sorter(opts),
})
:find()
end,
})
end

return {
cd_project = cd_project,
manual_cd_project = manual_cd_project,
}
23 changes: 23 additions & 0 deletions lua/cd-project/adapter/vim-ui.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,29 @@ local function cd_project(opts)
end)
end

local function manual_cd_project()
vim.ui.input({ prompt = "Add a project path: " }, function(path)
if not path or path == "" then
return utils.log_error("No path given, quitting.")
end

vim.ui.input({ prompt = "Add a project name: " }, function(name)
if not name or name == "" then
vim.notify('No name given, using "' .. utils.get_tail_of_path(path) .. '" instead')
return api.add_project(path)
end

local project = api.build_project_obj(path, name)
if not project then
return
end

return api.add_project(project)
end)
end)
end

return {
cd_project = cd_project,
manual_cd_project = manual_cd_project,
}
54 changes: 41 additions & 13 deletions lua/cd-project/api.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
local cd_hooks = require("cd-project.hooks")
local project = require("cd-project.project-repo")
local repo = require("cd-project.project-repo")
local utils = require("cd-project.utils")

---@return string|nil
Expand Down Expand Up @@ -28,7 +28,7 @@ end

---@return string[]
local function get_project_paths()
local projects = project.get_projects()
local projects = repo.get_projects()
local paths = {}
for _, value in ipairs(projects) do
table.insert(paths, value.path)
Expand All @@ -38,7 +38,7 @@ end

---@return string[]
local function get_project_names()
local projects = project.get_projects()
local projects = repo.get_projects()
local path_names = {}
for _, value in ipairs(projects) do
table.insert(path_names, value.name)
Expand All @@ -58,26 +58,50 @@ local function cd_project(dir)
end
end

---@param path string
---@param name? string
---@param desc? string|nil
---@return CdProject.Project|nil
local function build_project_obj(path, name, desc)
local normalized_path = vim.fn.expand(path)
if vim.fn.isdirectory(normalized_path) == 0 then
return utils.log_error(normalized_path .. " is not a directory")
end

return {
path = normalized_path,
name = name or utils.get_tail_of_path(normalized_path),
desc = desc,
}
end

---@param project CdProject.Project
local function add_project(project)
local projects = repo.get_projects()

if vim.tbl_contains(get_project_paths(), project.path) then
return vim.notify("Project already exists: " .. project.path)
end

table.insert(projects, project)
repo.write_projects(projects)
vim.notify("Project added: \n" .. project.path)
end

local function add_current_project()
local project_dir = find_project_dir()

if not project_dir then
return utils.log_err("Can't find project path of current file")
end

local projects = project.get_projects()
local project = build_project_obj(project_dir)

if vim.tbl_contains(get_project_paths(), project_dir) then
return vim.notify("Project already exists: " .. project_dir)
if not project then
return
end

local new_project = {
path = project_dir,
name = utils.get_tail_of_path(project_dir),
}
table.insert(projects, new_project)
project.write_projects(projects)
vim.notify("Project added: \n" .. project_dir)
add_project(project)
end

local function back()
Expand All @@ -90,7 +114,11 @@ end

return {
cd_project = cd_project,
build_project_obj = build_project_obj,
get_project_paths = get_project_paths,
get_project_names = get_project_names,
add_current_project = add_current_project,
add_project = add_project,
back = back,
find_project_dir = find_project_dir,
}
54 changes: 53 additions & 1 deletion lua/cd-project/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ end
---@param path string
local function get_tail_of_path(path)
-- Remove leading directories, keep the last part
return path:match("([^/]+)$")
local tail = path:match("([^/]+)$")
local parent = path:match("^.*%/([^/]+)/?$") -- Get the parent directory
-- if foo/ return foo
if parent and not tail then
return parent
-- if foo/bar, return bar
else
return tail -- Return only the tail if there is no parent
end
end

---@param project CdProject.Project
Expand All @@ -22,8 +30,52 @@ local function format_entry(project, max_len)
return string.format("%-" .. max_len .. "s", project.name) .. " | " .. project.path
end

local check_for_find_cmd = function()
local find_command = (function()
if 1 == vim.fn.executable("fd") then
return { "fd", "--type", "d", "--color", "never" }
elseif 1 == vim.fn.executable("fdfind") then
return { "fdfind", "--type", "d", "--color", "never" }
elseif 1 == vim.fn.executable("find") and vim.fn.has("win32") == 0 then
return { "find", ".", "-type", "d" }
end
end)()
return find_command
end

---@param path string
---@return string
-- should be used in the telescope adapter's manual_cd_project method
local function format_dir_based_on_os(path)
-- the "before format" example belows are how paths are passed to api.add_project

local is_mac = vim.loop.os_uname().sysname == "Darwin"
-- local is_linux = vim.loop.os_uname().sysname == "Linux"
local is_windows = vim.loop.os_uname().sysname:find("Windows") and true or false

-- before format: /foo/barbuzz
-- after format: /foo/bar/buzz
if is_mac then
return vim.fn.expand("~") .. "/" .. path
end

-- before format: C:\User\namepathname
-- after format: C:\User\name\pathname
if is_windows then
return vim.fn.expand("~") .. "\\" .. path
end

-- Linux
-- before format: ./foo/bar/buzz
-- after format: /home/user/foo/bar/buzz
local format_linux_path = path:gsub("^%./", vim.fn.expand("~") .. "/")
return format_linux_path
end

return {
log_error = log_error,
get_tail_of_path = get_tail_of_path,
format_entry = format_entry,
check_for_find_cmd = check_for_find_cmd,
format_dir_based_on_os = format_dir_based_on_os,
}
1 change: 1 addition & 0 deletions plugin/cd-project.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ vim.g.cd_project_current_project = api.find_project_dir()

vim.api.nvim_create_user_command("CdProject", adapter.cd_project, {})
vim.api.nvim_create_user_command("CdProjectAdd", api.add_current_project, {})
vim.api.nvim_create_user_command("CdProjectManualAdd", adapter.manual_cd_project, {})
vim.api.nvim_create_user_command("CdProjectBack", api.back, {})

0 comments on commit f9009fd

Please sign in to comment.