diff --git a/.stylua.toml b/.stylua.toml new file mode 100644 index 0000000..6601564 --- /dev/null +++ b/.stylua.toml @@ -0,0 +1,6 @@ +column_width = 120 +line_endings = "Unix" +indent_type = "Spaces" +indent_width = 2 +quote_style = "AutoPreferSingle" +no_call_parentheses = false diff --git a/lua/workspace/init.lua b/lua/workspace/init.lua index bdac754..92a8038 100644 --- a/lua/workspace/init.lua +++ b/lua/workspace/init.lua @@ -11,12 +11,26 @@ local finders = require('telescope.finders') local pickers = require('telescope.pickers') local sorters = require('telescope.sorters') local actions = require('telescope.actions') -local action_set = require("telescope.actions.set") -local action_state = require("telescope.actions.state") -local tmux = require("workspace.tmux") +local action_set = require('telescope.actions.set') +local action_state = require('telescope.actions.state') +local tmux = require('workspace.tmux') + +local function validate_search_git_subfolders(workspace) + local opts = workspace.search_git_subfolders + if opts and not opts.enable == 0 then + return false + end + + return true +end local function validate_workspace(workspace) - if not workspace.name or not workspace.path or not workspace.keymap then + if + not workspace.name + or not workspace.path + or not workspace.keymap + or not validate_search_git_subfolders(workspace) + then return false end return true @@ -37,66 +51,137 @@ local function validate_options(options) end local default_options = { + -- add option to loo for sub folders with .git workspaces = { - --{ name = "Projects", path = "~/Projects", keymap = { "o" } }, + --{ name = "Projects", path = "~/Projects", keymap = { "o" }, opts = { search_git_subfolders = { enabled = true, depth = 2} } }, }, tmux_session_name_generator = function(project_name, workspace_name) local session_name = string.upper(project_name) return session_name - end + end, } +-- fixes the full path to ~/ if it matches to $HOME +local function expand_tilde(path) + local home_dir = vim.fn.expand('$HOME') + if string.match(path, '^' .. home_dir) then + return string.gsub(path, '^' .. home_dir, '~') + end + return path +end +local function find_git_directories(path, depth, max_depth) + local result = {} -local function open_workspace_popup(workspace, options) + -- Check if we've reached our depth limit + if depth >= max_depth then + return result + end + + -- Iterate through all items in the current directory + for _, item in ipairs(vim.fn.readdir(path)) do + local full_path = vim.fn.expand(path .. '/' .. item) + + -- Skip if item is not a directory + if vim.fn.isdirectory(full_path) == 0 then + goto continue + end + + -- Check if .git exists in the current directory + if vim.fn.glob(full_path .. '/.git') ~= '' then + table.insert(result, full_path) + goto continue + end + + if item == '.' or item == '..' or item == '.git' then + goto continue + end + + -- Recursively search subdirectories + local sub_results = find_git_directories(full_path, depth + 1, max_depth) + + -- Add subdirectory results + for _, sub_result in ipairs(sub_results) do + table.insert(result, sub_result) + end + + ::continue:: + end + + local unique_result = {} + for _, _path in ipairs(result) do + if not unique_result[_path] then + table.insert(unique_result, _path) + end + end + return unique_result +end + +local function open_workspace_popup(workspace, options) if not tmux.is_running() then - vim.api.nvim_err_writeln("Tmux is not running or not in a tmux session") + vim.api.nvim_err_writeln('Tmux is not running or not in a tmux session') return end local workspace_path = vim.fn.expand(workspace.path) -- Expand the ~ symbol - local folders = vim.fn.globpath(workspace_path, '*', 1, 1) + local projects = vim.fn.globpath(workspace_path, '*', 1, 1) + + local opts = workspace.opts or {} + -- if search_git_subfolders is enabled + if opts and opts.search_git_subfolders.enable then + local max_depth = opts.search_git_subfolders.max_depth or 2 + for _, folder in ipairs(projects) do + local child_folders = find_git_directories(folder, 1, max_depth) + for _, child_folder in ipairs(child_folders) do + if vim.fn.isdirectory(child_folder) then + table.insert(projects, child_folder) + end + end + end + end local entries = {} table.insert(entries, { - value = "newProject", - display = "Create new project", - ordinal = "Create new project", + value = 'newProject', + display = 'Create new project', + ordinal = 'Create new project', }) - for _, folder in ipairs(folders) do + for _, folder in ipairs(projects) do table.insert(entries, { value = folder, - display = workspace.path .. "/" .. folder:match("./([^/]+)$"), + display = expand_tilde(folder), ordinal = folder, }) end - pickers.new({ - results_title = workspace.name, - prompt_title = "Search in " .. workspace.name .. " workspace", - }, { - finder = finders.new_table { - results = entries, - entry_maker = function(entry) - return { - value = entry.value, - display = entry.display, - ordinal = entry.ordinal, - } + pickers + .new({ + results_title = workspace.name, + prompt_title = 'Search in ' .. workspace.name .. ' workspace', + }, { + finder = finders.new_table({ + results = entries, + entry_maker = function(entry) + return { + value = entry.value, + display = entry.display, + ordinal = entry.ordinal, + } + end, + }), + sorter = sorters.get_fuzzy_file(), + attach_mappings = function() + action_set.select:replace(function(prompt_bufnr) + local selection = action_state.get_selected_entry(prompt_bufnr) + actions.close(prompt_bufnr) + tmux.manage_session(selection.value, workspace, options) + end) + return true end, - }, - sorter = sorters.get_fuzzy_file(), - attach_mappings = function() - action_set.select:replace(function(prompt_bufnr) - local selection = action_state.get_selected_entry(prompt_bufnr) - actions.close(prompt_bufnr) - tmux.manage_session(selection.value, workspace, options) - end) - return true - end, - }):find() + }) + :find() end ---@divider @@ -106,7 +191,7 @@ end ---@brief ]] function M.tmux_sessions() if not tmux.is_running() then - vim.api.nvim_err_writeln("Tmux is not running or not in a tmux session") + vim.api.nvim_err_writeln('Tmux is not running or not in a tmux session') return end @@ -121,30 +206,32 @@ function M.tmux_sessions() }) end - pickers.new({ - results_title = "Tmux Sessions", - prompt_title = "Select a Tmux session", - }, { - finder = finders.new_table { - results = entries, - entry_maker = function(entry) - return { - value = entry.value, - display = entry.display, - ordinal = entry.ordinal, - } + pickers + .new({ + results_title = 'Tmux Sessions', + prompt_title = 'Select a Tmux session', + }, { + finder = finders.new_table({ + results = entries, + entry_maker = function(entry) + return { + value = entry.value, + display = entry.display, + ordinal = entry.ordinal, + } + end, + }), + sorter = sorters.get_fuzzy_file(), + attach_mappings = function() + action_set.select:replace(function(prompt_bufnr) + local selection = action_state.get_selected_entry(prompt_bufnr) + actions.close(prompt_bufnr) + tmux.attach(selection.value) + end) + return true end, - }, - sorter = sorters.get_fuzzy_file(), - attach_mappings = function() - action_set.select:replace(function(prompt_bufnr) - local selection = action_state.get_selected_entry(prompt_bufnr) - actions.close(prompt_bufnr) - tmux.attach(selection.value) - end) - return true - end, - }):find() + }) + :find() end ---@mod workspace.setup setup @@ -171,15 +258,16 @@ end --- * `workspace_name` string: Name of the workspace --- function M.setup(user_options) - local options = vim.tbl_deep_extend("force", default_options, user_options or {}) + local options = vim.tbl_deep_extend('force', default_options, user_options or {}) if not validate_options(options) then -- Display an error message and example options - vim.api.nvim_err_writeln("Invalid setup options. Provide options like this:") + vim.api.nvim_err_writeln('Invalid setup options. Provide options like this:') vim.api.nvim_err_writeln([[{ workspaces = { { name = "Workspace1", path = "~/path/to/workspace1", keymap = { "w" } }, { name = "Workspace2", path = "~/path/to/workspace2", keymap = { "x" } }, + { name = "Workspace2", path = "~/path/to/workspace2", keymap = { "x" }, opts = { search_git_subfolders { enable = true, max_depth = 2} } }, } }]]) return @@ -188,7 +276,7 @@ function M.setup(user_options) for _, workspace in ipairs(options.workspaces or {}) do vim.keymap.set('n', workspace.keymap[1], function() open_workspace_popup(workspace, options) - end, { noremap = true, desc = workspace.keymap.desc or ("Open workspace " .. workspace.name) }) + end, { noremap = true, desc = workspace.keymap.desc or ('Open workspace ' .. workspace.name) }) end end diff --git a/lua/workspace/tmux.lua b/lua/workspace/tmux.lua index 8c0e71b..f9be02c 100644 --- a/lua/workspace/tmux.lua +++ b/lua/workspace/tmux.lua @@ -2,14 +2,14 @@ local M = {} function M.manage_session(project_path, workspace, options) local project_name - if project_path == "newProject" then - project_name = vim.fn.input("Enter project name: ") + if project_path == 'newProject' then + project_name = vim.fn.input('Enter project name: ') if project_name and #project_name > 0 then - project_path = vim.fn.fnamemodify(vim.fn.expand(workspace.path .. "/" .. project_name), ":p") - os.execute("mkdir -p " .. project_path) + project_path = vim.fn.fnamemodify(vim.fn.expand(workspace.path .. '/' .. project_name), ':p') + os.execute('mkdir -p ' .. project_path) end else - project_name = project_path:match("./([^/]+)$"); + project_name = project_path:match('./([^/]+)$') end local session_name = options.tmux_session_name_generator(project_name, workspace.name) @@ -17,25 +17,25 @@ function M.manage_session(project_path, workspace, options) if session_name == nil then session_name = string.upper(project_name) end - session_name = session_name:gsub("[^%w_]", "_") + session_name = session_name:gsub('[^%w_]', '_') - local tmux_session_check = os.execute("tmux has-session -t=" .. session_name .. " 2> /dev/null") + local tmux_session_check = os.execute('tmux has-session -t=' .. session_name .. ' 2> /dev/null') if tmux_session_check ~= 0 then - os.execute("tmux new-session -ds " .. session_name .. " -c " .. project_path) + os.execute('tmux new-session -ds ' .. session_name .. ' -c ' .. project_path) end - os.execute("tmux switch-client -t " .. session_name) + os.execute('tmux switch-client -t ' .. session_name) end function M.attach(session_name) - local tmux_session_check = os.execute("tmux has-session -t=" .. session_name .. " 2> /dev/null") + local tmux_session_check = os.execute('tmux has-session -t=' .. session_name .. ' 2> /dev/null') if tmux_session_check == 0 then - os.execute("tmux switch-client -t " .. session_name) + os.execute('tmux switch-client -t ' .. session_name) end end function M.is_running() - local tmux_running = os.execute("pgrep tmux > /dev/null") + local tmux_running = os.execute('pgrep tmux > /dev/null') local in_tmux = vim.fn.exists('$TMUX') == 1 if tmux_running == 0 and in_tmux then return true