[work]spaceman[ager] for your workspaces
Provides a way to a open workspaces given the parent directories or specific workspaces.
I developed this plugin to solve the very specific problem that I had to manually manage each of the workspaces. While
plugins like workspaces.nvim
allow for setting directories, you must manually sync them each time and the directories
are stored away from the config. With this plugin, you can set a list of these parent folders and they will
automatically match the list of workspaces.
~/
├── Documents/Projects/ # Point at this
│ ├── lua_projects
│ ├── c_projects
│ └── cool_website
└── dotfiles/ # And this
├── nvim # But not these!
├── helix
└── other_program
If you have used Visual Studio Code, this is similar to their File: Open Recent...
action.
And the obligatory usage video:
spaceman-example.mp4
- nvim-telescope/telescope.nvim if you want to use the Telescope adapter
A basic setup to turn your ~/Documents/Projects
folder into a workspace parent and enable the keymaps:
-- lazy.nvim
{
"FireIsGood/spaceman.nvim",
config = function()
require("spaceman").setup({
directories = {
"~/Documents/Projects"
},
use_default_keymaps = true,
})
end,
}
-- packer
use {
"FireIsGood/spaceman.nvim",
config = function ()
require("spaceman").setup({
directories = {
"~/Documents/Projects"
},
use_default_keymaps = true,
})
end,
}
The spaceman.nvim plugin comes with of the default keymaps disabled by default and does not automatically have directories or workspaces set up.
For a full list of options and examples of using specific directory and workspace setups, see Configuration below.
Note
Directory refers to the parent of multiple workspaces. Workspaces refers to specific workspaces.
By default, only the commands are registered. You can enable the default keymaps in the configuration or call these commands separately.
Command | Default Keymap | API Call | Description |
---|---|---|---|
:Spaceman |
<leader>wo |
require("spaceman").open_workspaces() |
Find and open a workspace |
:SpacemanDirectory |
<leader>wd |
require("spaceman").open_directories() |
Find and open a directory (workspace parent) in the default app |
:SpacemanCount |
<leader>wc |
require("spaceman").count_workspaces() |
Count the number of workspaces |
:SpacemanPrevious |
<leader>wp |
require("spaceman").open_previous_workspace() |
Open the previous workspace |
require("spaceman").api_open_workspace(path) |
Open a specific workspace |
The default configuration is as follows:
-- default config
require("spaceman").setup({
directories = {}, -- List of directories
workspaces = {}, -- List of workspaces in the format { "name", "path" } or a string of the path
sort_by_recent = true, -- Whether to sort with recently opened workspaces in front
use_default_keymaps = false, -- Whether to register keymaps
use_default_hooks = true, -- Whether to use default hooks (write all files, clear highlights, close buffers)
use_sessions = true, -- Whether to use sessions (RECOMMENDED FOR MOST USERS)
rename_function = nil, -- Function to rename your folders
adapter = "telescope", -- Which adapter to use, either "telescope" or "vim-ui" (for compatibility)
hooks = { -- Hooks of a single Vim command, a table of vim commands, a Lua function, or nil
before_move = nil, -- Before changing directory
after_move = nil, -- After changing directory
},
telescope_opts = nil, -- Options to pass to the telescope window
data_path = vim.fn.stdpath("data") .. "/spaceman_data.json", -- Stores recently used workspaces
sessions_path = vim.fn.stdpath("data") .. "/sessions", -- Stores sessions
})
Each entry in directories
is a path to the parent of many workspaces. Each entry in workspaces
is a specific
workspace with its custom name and the path. Workspaces can override specific folders in a directory entry if you would
like a specific name or if you would like to include nested workspaces.
All paths are expanded and normalized, so you can use ~
as short for your home directory.
Basic setup using directories, workspaces:
require("spaceman").setup({
-- Workspace parents
directories = {
"~/Documents/Programming",
"~/Documents/Fishing",
"~/Documents/Whatever_You_Want",
},
-- Individual named workspaces
workspaces = {
{ "Nvim-Data", "~/.local/share/nvim" },
{ "Config", "~/.config/nvim" },
"~/Desktop",
"~/Desktop/cool_project", -- Nesting is okay!
},
-- Enable the default keymaps
use_default_keymaps = true,
})
Updating the configuration's directories or workspaces requires a restart due to various limitations, but any directories you specify here will always show their current contents. If you create new folders inside a directory you will not have to restart to see them, but if you want to specify a new directory or workspace folder you must restart.
Note
Workspaces linking to the same folder will override directories.
Further Examples
Hooks can be either a string with a single command, a table of strings of commands, or a function to be run.
require("spaceman").setup({
-- [OTHER SETTINGS]
hooks = {
-- before_move = "noh" -- A single command (string)
before_move = { "noh", "echo 'bye'" } -- A table of commands (strings)
after_move = function() print("hi") end -- A function
}
})
You can either use the User Commands or the Lua API.
-- User commands
map("n", "<leader>oj", ":Spaceman", { desc = "Open workspaces" })
map("n", "<leader>ok", ":SpacemanDirectory", { desc = "Open directories" })
map("n", "<leader>ol", ":SpacemanCount", { desc = "Count workspaces" })
-- Lua API
map("n", "<leader>oj", require("spaceman").open_workspaces, { desc = "Open workspaces" })
map("n", "<leader>ok", require("spaceman").open_directories, { desc = "Open directories" })
map("n", "<leader>ol", require("spaceman").count_workspaces, { desc = "Count workspaces" })
The custom rename function is run on ALL names, including custom workspace names. This is mostly for personal taste, though you could technically just call every project "Joe" or something.
require("spaceman").setup({
-- [OTHER SETTINGS]
rename_function = function(name)
return string.gsub(" " .. name, "%W%l", string.upper):sub(2) -- Name to title case
-- return string.gsub(name, "[-_]", " ") -- Underline and dash to space
-- return string.gsub(name, "[-%s]", "_") -- Space and dash to underline
-- return "Joe" -- Joe
end,
})
You can disable sorting if you want a truly declarative config with no recent files. If you also don't want to save the
data file at all, you can change the path to nil
require("spaceman").setup({
-- [OTHER SETTINGS]
sort_by_recent = false,
data_path = nil, -- Optional: don't save the data path at all
})
You may set a table of opts, either literally or through preset themes. See Telescope
Themes or :help telescope.setup()
more details on these
tables.
require("spaceman").setup({
-- [OTHER SETTINGS]
telescope_opts = require("telescope.themes").get_dropdown({
prompt_title = "Cool Dropdown",
results_title = "Items or Something",
scroll_strategy = "limit",
}),
})
If you don't want to use telescope for any reason, you can explicitly switch to using the vim-ui menu. If you don't have telescope installed and don't explicitly set the adapter here, you will get a warning every time you list workspaces.
require("spaceman").setup({
-- [OTHER SETTINGS]
adapter = "vim-ui",
})
The data file tracks timestamps for your recently used folders. The sessions folder holds your session files. If you wanted to share these across machines, you can change where they is saved.
require("spaceman").setup({
-- [OTHER SETTINGS]
data_path = "~/Documents/sync-or-whatever/spaceman_data.json", -- Store the file in a sync folder
sessions_path = "~/Documents/sync-or-whatever/sessions", -- Store session files in a sync folder subdirectory
})
Sessions are already built-in to the plugin. This is more for if you want different features or have existing sessions through this plugin.
require("spaceman").setup({
-- [OTHER SETTINGS]
use_sessions = false,
hooks = {
before_move = { "SessionsStop" },
after_move = { "SessionsLoad" },
},
})
If you want to work on the plugin yourself
First, clone the repo:
git clone git@github.com:FireIsGood/spaceman.nvim.git
Add the plugin's folder as a local plugin:
-- lazy.nvim
{
dir = "~/Documents/Programming/spaceman.nvim",
-- Your other settings
}
-- packer
use {
"~/Documents/Programming/spaceman.nvim",
-- Your other settings
}
The files are laid out as follows:
lua/
└── spaceman/
├── adapters/
│ ├── telescope.lua # Telescope adapter
│ └── vim-ui.lua # Vim UI adapter
├── config.lua # User configuration
├── default_commands # User Command setup
├── default_keymaps # Keymap setup
├── init.lua # API and setup function
├── json.lua # File system JSON helper functions
├── sessions.lua # Session saving and loading
├── util.lua # File system and general utilities
└── workspace.lua # General function calls (linked by API)
README.md
LICENSE
.stylua.toml
(Tree made with tree.nathanfriend.io)
There are already many plugins to manage workspace folders based on file patterns, manual additions, or Git repositories. As such, this project's goal is not to search based on those types of criteria, but specifically the single-depth children of provided parent folders.
If you wish to have the non-goal features described above, consider these options:
- project.nvim manages based on file patterns
- workspaces.nvim manages workspaces manually
- whaler.nvim looks for git directories
- projections.nvim similar style with pattern matching, but more config
For more plugins in that vein, check out the Telescope Extensions wiki.
Feel free to make issues or pull requests!