Giter Club home page Giter Club logo

workspaces.nvim's Introduction

workspaces.nvim

a simple plugin to manage workspace directories in neovim

workspaces.nvim provides a few simple commands for managing workspace directories in neovim. A workspace is a name and a path, and opening a workspace will set the current directory to the correct path.

  • Register a workspace with :WorkspacesAdd
  • Open a registered workspace with :WorkspacesOpen [name]
  • Hooks may be registered to provide additional functionality
  • A telescope extension :Telescope workspaces is provided for fuzzy finding over workspaces

Nothing runs automatically. The idea is that workspace creation is an infrequent task, so there shouldn't be any need for automatic workspace registration, or heuristics to determine if a directory is a workspace. A command and telescope extension are provided to make it simple to open a workspace, but what that means beyond changing directories is left up to you by customizing the hooks. See Examples for inspiration on hooks!

Note that this plugin is small in scope and complexity. It has been stable for a long time. Just because I am not making changes doesn't mean it's been abandoned! It was designed to be small and stable, and it will stay that way.

Semantics

Because naming could be confusing, here are some definitions:

  • Workspaces: as described above, are project directories. The purpose of this plugin being to switch easily between these project directories.

  • Dirs: These are directories that contain workspaces. It allows to easily sync multiple workspaces contained in a directory. For example, you might have a directory called projects on your machine, that contains all your projects. Just register this directory as a dir with :WorkspacesAddDir and all the workspaces contained in it will be automatically added to the list of workspaces when running :WorkspacesSyncDirs.

Installation

Install with your favorite neovim package manager. Be sure to run the setup function if you wish to change the default configuration or register the user commands.

require("workspaces").setup()

The setup function accepts a table to modify the default configuration:

{
    -- path to a file to store workspaces data in
    -- on a unix system this would be ~/.local/share/nvim/workspaces
    path = vim.fn.stdpath("data") .. "/workspaces",

    -- to change directory for nvim (:cd), or only for window (:lcd)
    -- deprecated, use cd_type instead
    -- global_cd = true,

    -- controls how the directory is changed. valid options are "global", "local", and "tab"
    --   "global" changes directory for the neovim process. same as the :cd command
    --   "local" changes directory for the current window. same as the :lcd command
    --   "tab" changes directory for the current tab. same as the :tcd command
    --
    -- if set, overrides the value of global_cd
    cd_type = "global",

    -- sort the list of workspaces by name after loading from the workspaces path.
    sort = true,

    -- sort by recent use rather than by name. requires sort to be true
    mru_sort = true,

    -- option to automatically activate workspace when opening neovim in a workspace directory
    auto_open = false,

    -- enable info-level notifications after adding or removing a workspace
    notify_info = true,

    -- lists of hooks to run after specific actions
    -- hooks can be a lua function or a vim command (string)
    -- lua hooks take a name, a path, and an optional state table
    -- if only one hook is needed, the list may be omitted
    hooks = {
        add = {},
        remove = {},
        rename = {},
        open_pre = {},
        open = {},
    },
}

For example, the following settings will add a hook to run :Telescope find_files after opening a workspace, and keep the default workspaces path:

require("workspaces").setup({
    hooks = {
        open = { "Telescope find_files" },
    }
})

Commands

The setup function registers the following user commands:

  • :WorkspacesAdd [name] [path]

    The workspace with the specified name and path will be registered.

  • :WorkspacesAddDir [path]

The directory with the specified or current path will be registered and each one of its sub folders stored as workspaces.

  • :WorkspacesRemove [name]

    The workspace with the specified name will be removed.

  • :WorkspacesRemoveDir [name]

    The directory with the specified name will be removed as well as all of its associated workspaces.

  • :WorkspacesRename [name] [new_name]

    The workspace with the specified name will be renamed to new_name.

  • :WorkspacesList

    Prints all workspaces.

  • :WorkspacesListDirs

    Prints all directories.

  • :WorkspacesOpen [name]

    Opens the named workspace. opening a workspace means to change the current directory to that workspace's path.

  • :WorkspacesSyncDirs

    Synchronize workspaces from registered directories.

See :h workspaces-usage for more information on the commands.

Lua API

The workspaces commands may also be accessed from Lua

local workspaces = require("workspaces")

workspaces.add(path: string, name: string)

workspaces.add_dir(path: string)

workspaces.remove(name: string)

workspaces.remove_dir(name: string)

workspaces.rename(name: string, new_name: string)

workspaces.list()

workspaces.list_dirs()

workspaces.open(name: string)

workspaces.get(): table

workspaces.name(): string|nil

workspaces.path(): string|nil

workspaces.sync_dirs()

workspaces.get_custom(name: string): string|nil

workspaces.set_custom(name: string, data: string)

See :h workspaces-api for more information on the API functions.

Telescope Picker

workspaces.nvim is bundled with a telescope picker extension. To enable, add the following to your config

telescope.load_extension("workspaces")

The picker will list all workspaces. <cr> will open the selected workspace, running any registered hooks. <c-t> will open the selected workspace in a new tab.

To keep nvim in insert mode (for example, when chaining multiple telescope pickers), add the following to your telescope setup function.

require("telescope").setup({
  extensions = {
    workspaces = {
      -- keep insert mode after selection in the picker, default is false
      keep_insert = true,
    }
  }
})

Examples

Remember that more than one hook is allowed, so these may be combined in creative ways! Hooks may also be registered after adding and removing workspaces, not only after opening a workspace.

See Configuration Recipes and Troubleshooting on the wiki for more inspiration and help configuring the plugin. Feel free to contribute your setup!

fzf file finder

Change directory to the workspace and run fzf.

require("workspaces").setup({
    hooks = {
        open = "FZF",
    }
})

Open a file tree

Open nvim-tree.

require("workspaces").setup({
    hooks = {
        open = "NvimTreeOpen",
    }
})

Load a saved session

Load any saved sessions using natecraddock/sessions.nvim.

require("workspaces").setup({
    hooks = {
        open_pre = {
          -- If recording, save current session state and stop recording
          "SessionsStop",

          -- delete all buffers (does not save changes)
          "silent %bdelete!",
        },
        open = function()
          require("sessions").load(nil, { silent = true })
        end,
    }
})

Combo

Open nvim-tree and a telescope file picker.

require("workspaces").setup({
    hooks = {
        open = { "NvimTreeOpen", "Telescope find_files" },
    }
})

If you create a hook you think is useful, let me know and I might just add it to this list!

Related

workspaces.nvim is a simple plugin with the ability to be extended through hooks. Nothing is registered or opened automatically. If you want a plugin to be less manual, try an alternative:

workspaces.nvim's People

Contributors

antonk52 avatar apmyplol avatar bvtthead avatar caerphoto avatar ices2 avatar natecraddock avatar parsifa1 avatar ryansch avatar valjed avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

workspaces.nvim's Issues

add api arguments don't work as intended

When trying to add a workspace using workspaces.add(path: string, name: string), using a full path, the path is modified and it doesn't work.

For example, when running

require('workspaces').add('/home/myuser/tmp', 'testname')

I get an error "Path '/home/myuser/testname' does not exist" (where /home/myuser is my cwd in this case). However, if I swap the arguments (use "testname" as path, and "/home/myuser/tmp" as name), it works as intended.

WorkspaceListDirs is not functioning

Hello, I'm encountering an issue when trying to use WorkspaceListDirs. A warning is presented that no workspaces are registered. I know that they are because the WorkspaceList command functions as expected.

Screen.Recording.2024-01-14.at.10.57.11.AM.mov

Workspaces in `workspaces` file are not found

Hi,

I recently had an issue opening workspaces using WorkspacesOpen: nothing happened when selecting them from the telescope interface. Using :messages, I saw that the workspace "does not exist" according to the plugin.

I checked the .local/share/nvim/workspaces file and found the workspace. The directory exists as well. I dug into the plugin code and found that the workspace is given as non-existent as the type attribute check added in #18 fails.

if (workspace.name == name or (path and direq(workspace.path, path))) and workspace.type == type then

It fails because my workspaces file has no type column yet and the workspace.type attribute is nil. The solution was to delete my workspaces file and start a new one. Not pleasant, but not the end of the world either.

Leaving this here for anyone who might run into the same issue.

Cannot find util.path.sep in default configuration

At first, thank you for this wonderful plugin, really appreciate it.

During my installation, I directly copied the configuration code from the "Installation" part. And this error emerged.
I am new to lua. Could you give me any hints about this?

Error detected while processing /Users/swellmai/.config/nvim/init.lua:
E5113: Error while calling lua chunk: .../swellmai/.config/nvim/lua/plugin_configs/workspaces.lua:5: attempt to index global 'util' (a nil value)
stack traceback:
.../swellmai/.config/nvim/lua/plugin_configs/workspaces.lua:5: in main chunk
[C]: in function 'require'
/Users/swellmai/.config/nvim/lua/plugin_configs/init.lua:6: in main chunk
[C]: in function 'require'
/Users/swellmai/.config/nvim/init.lua:8: in main chunk
Press ENTER or type command to continue

It looks like nvim can't find the location of "util".

Here is my config for workspaces.nvim
截屏2022-07-06 15 52 36

Failure to open a workspace from another workspace

workspaces.setup({
  hooks = {
    -- hooks run before change directory
    open_pre = {
      "SessionsStop",
      "silent %bdelete!",
    },

    -- load any saved session from current directory
    open = function()
      require("sessions").load(nil, { silent = true })
    end,
  },
})

this config used to work before this commit b26f8720a4053af46a36d1e1ff110a647d66046f and when i updated this plugin it doesn't, i think it has something to do with the path because when i do WorkspacesOpen something the working directory doesn't change and it loads the same session.

[Feature proposal] Config workspaces folders

Hello,

First of all thanks for this useful plugin!!
I'm using it since few days and I really like it.
To explain my proposal first some context:
I'm used to store my projects in few places (like perso / pro)
And these folders are only composed of projects (or workspaces) but they change often, I clone a lot of projects, remove them etc.
And I noticed that I don't think to add them manually each time.
I don't want any automatic tracking like does project.nvim because I tried already and it ends with really weird unwanted projects in the list.
Based on that I think it would be really valuable, pretty easy to implement to add a list of folders in the config where each folder is a workspace.
To avoid logic to run at every nvim startup time we could just add a sync method for example that would sync workspaces based on what's currently in the folders workspaces.

Let me know what you think about it, if you ok with the idea I can give it a shot. ☮️

:WorkspaceOpen affects all splits, this behavior is not desired.

When I have multiple splits, and I do :WorkspacesOpen [name] in one of the splits, it changes cwd for all the splits, which is not desired, because semantically it should only do :lcd instead of :cd.

Another bug is: if I cancel in telescope's popup window, cwd still changes, which is also not desired.

[Question] Usage of type field in the obtained list of workspaces

I did not find the discussions tab, so I apologize for raising an issue

I noticed a type field along with other relevant information in a single item from the table returned by require("workspaces").get():

{                                                                                                                                                
    last_opened = "2023-08-18T09:56:56",
    name = "project",
    path = "/home/user/code/project/",
    type = ""
}

I wanted to know if this type field was being used by workspaces.
If it wasn't, I'd want to:

  • store additional information related to that particular workspace, for e.g. storing the language/package-manager/build-system of the project. (via some command or via the lua api)
  • get the same info back and use it somewhere else in my configuration

Keep_insert not working

Hello, I use now your plugin as primary workspace jumping, and it works very well, congrats, and thanks !

It seems that keep_insert is not working, this is my telescope config and my workspace one:

		use({
			"nvim-telescope/telescope.nvim",
			config = function()
				local actions = require("telescope.actions")
				require("telescope").setup({
					defaults = require("telescope.themes").get_ivy({
						winblend = 10,
						mappings = {
							i = {
								["<C-j>"] = actions.move_selection_next,
								["<C-k>"] = actions.move_selection_previous,

								["<C-q>"] = actions.send_selected_to_qflist + actions.open_qflist,
								["<C-a>"] = actions.send_to_qflist + actions.open_qflist,
							},
							n = {
								["<C-q>"] = actions.send_selected_to_qflist + actions.open_qflist,
								["<C-a>"] = actions.send_to_qflist + actions.open_qflist,
							},
						},
					}),
					extensions = {
						["ui-select"] = require("telescope.themes").get_cursor(),
						workspaces = {
							keep_insert = true,
						},
					},
				})

				require("telescope").load_extension("ui-select")
				require("telescope").load_extension("fzf")
				require("telescope").load_extension("workspaces")
			end,
			requires = {
				"nvim-lua/popup.nvim",
				"nvim-telescope/telescope-ui-select.nvim",
				"nvim-telescope/telescope-fzf-native.nvim",
				"natecraddock/workspaces.nvim",
			},
		})

		use({
			"natecraddock/workspaces.nvim",
			config = function()
				require("workspaces").setup({
					hooks = {
						open = { "Telescope find_files" },
					},
				})
			end,
		})

PS: not related to this issue, but I don't feel like creating an other issue for this:
Would it be possible to provide vim.notify messages after a WorkspaceAdd, WorkspaceRemove, WorkspaceList (if no workspaces) ?

Telescope integration

Hello, thanks for the great plugin! I have a question: there is a way to execute others commands, like, rename and delete, through Telescope? I can't found anything about this on documentation

Consider not changing directories

I have :tcd as a use-case instead of :cd or :lcd. The way this plugin is structured, it'd need to add something like a cd_cmd to the options to accommodate the three cd commands. However, at that point, it would simplify the API to simply let the user cd themselves on a hook. Thoughts?

Add support for lsp workspace variable

(In fact I thought this is the whole purpose of this plugin, to manage lsp workspace settings)

I failed to understand the purpose of listdir and syncdir. What is the point in assigning dirs to workspace?

Please improve the documentation. Thanks!

I would just write the purpose clearly:

Choosing workspace by default would just change the cwd, but you can add hooks. And additional functionality.

Option to change local instead of global path

Nice plugin! I have tried it out and prefer it over telescope-project as yours is more configurable.

One option I would like to see is to make the path change when opening a workspace local instead of global. I like to have one tab per project/workspace open in nvim, so global path changes are a bit of a nuisance to me.

It could be a plugin option à la use_local_path=True. I saw that you're using nvim_set_current_dir for the path changes, which does not seem to have a local alternative, so maybe something like vim.cmd[[lcd path/to/workspace]]?

Rename problem

How I can rename my workspace from something like "name" to: "newname - [category]" etc.? It can't take spaces etc...

[Bug] Removing a workspace by name accidentally removes the workspace at the current directory

Removing a workspace by executing :WorkspacesRemove WS_NAME, sometimes removes the workspace with the path to the current working directory.

The bug seems to be at line 293 in remove_workspace_or_directory

local remove_workspace_or_directory = function(name, is_dir, from_dir_update)
local type_name = is_dir and "Directory" or "Workspace"
local path = cwd()
local workspace, i = find(name, path, is_dir)
if not workspace then
if not name then
return
end
notify.warn(string.format("%s '%s' does not exist", type_name, name))
return
end
local workspaces = load_workspaces()
table.remove(workspaces, i)
store_workspaces(workspaces)
if not is_dir and not from_dir_update then
run_hooks(config.hooks.remove, workspace.name, workspace.path)
end
if config.notify_info and (not from_dir_update or is_dir) then
notify.info(string.format("%s [%s -> %s] removed", type_name, workspace.name, workspace.path))
end
end

  1. path is set to current working directory even if name is not nil
  2. find returns a workspace whose path matches the current working directory
  3. The wrong workspace gets removed

Proposed fix:
Change line 293 to

local path = (not name and cwd()) or nil

Option auto_open failed to take effect

I couldn't find the error in this function, but it didn't work properly on my device. When I entered nvim on the path of the existing Workspace, it couldn't automatically load the session:

local enable_autoload = function()
    -- create autocmd for every file at the start of neovim that checks the current working directory
    -- and if the cwd  matches a workspace directory then activate the corresponding workspace
      vim.api.nvim_create_autocmd({ "VimEnter" }, {
          pattern = "*",
          callback = function()
              for _, workspace in pairs(get_workspaces_and_dirs().workspaces) do
                  if workspace.path == cwd() then
                      M.open(workspace.name)
              end
            end
          end,
      })
end

and this is my config:

return {
    "natecraddock/workspaces.nvim",
    dependencies = { "natecraddock/sessions.nvim" },
    event = "VeryLazy",
    config = function()
        require("telescope").load_extension "workspaces"
        require("sessions").setup {
            events = { "WinEnter", "User", "VimLeavePre" },
            absolute = true,
            session_filepath = vim.fn.stdpath "data" .. "/sessions",
        }
        require("workspaces").setup {
            auto_open = true,
            sort = true,
            mru_sort = true,
            hooks = {
                add = {
                    "SessionsSave",
                },
                open_pre = {
                    "SessionsStop",
                    "silent %bdelete!",
                },
                open = function()
                    require("sessions").load(nil, { silent = true })
                end,
            },
        }
    end,
}

As an aside, is it possible to add feature that automatically stop session recording when my current working directory is no longer the working path I set? Thank you very much. Your plug-in is very light and easy to use.

Info notifications

After a WorkspacesAdd or WorkspacesRemove a notification indicating success, and after WorkspacesList a notification warning if there are no workspaces.

Put this behind a configuration boolean.

Originally posted in #6 (comment)

Adding an MRU sort

I'm working on a plugin that wraps your workspaces.nvim and sessions.nvim: https://github.com/ryansch/habitats.nvim

I'd like to add the ability to sort the list by most recently used and I think I have three options:

  1. Add an ability to track a last opened time to workspaces.nvim
  2. Add an ability to attach arbitrary user data to workspaces in workspaces.nvim
  3. Add my own data structure in habitats.nvim to track the data I'm interested in and link it to a workspace

Would you be interested in either of options 1 or 2?

(Recipe) Automatically change workspace when changing buffers

I normally use a single neovim instance and work in different projects (workspaces) in it.

This would present an issue when switching to a different pane/buffer belonging to a different workspace. The old workspace would still remain active, so any actions (such as telescope search) would be constrained to the other workspace, unless I were to manually switch.

So I created an autocommand to do this automatically when switching buffers, unless the file is already in the current active workspace. Please consider if this would be worthwile including in the wiki.

Implementation can be seen in my forked wiki repo.

Looking for a maintainer

Hi! I hope you are all doing well!

I no longer use Neovim regularly, but I really would like to keep this plugin alive. It's been really simple to maintain, but I worry about the long-term.

So I'm looking for someone willing to step in and maintain this plugin. Either

  1. Someone who is willing to fork and create the new official project or
  2. Someone who wants to co-maintain the project

I think the second is the simplest, and no one has to update their configs to point to a new repository.

If no one steps up, I will try my best to make sure this works for as long as possible. But I won't make any promises. If a future Neovim release would cause an unreasonable amount of work for me to update this plugin, I probably wouldn't update it.

Sorry if that's sad news for anyone, and I apologize if this breaks someone's workflow someday. I don't think this plugin will stop working anytime soon, but if it does... 😬

[Bug] - `auto_open` setup property opening telescope with `modifiable` off

Description

When the property auto_open is set with value true, and we open in a previous added project the telescope open with modifiable off.

P.S. If it's not a workspaces bug, can someone give me a hand to fix it?

test.mp4

Config

local vim = vim
local M = {}

local ok, package = pcall(require, "workspaces")
if not ok then
  return vim.notify("Failed to require package `workspaces`")
end

package.setup({
  auto_open = true, -- FIX: Cannot make changes, 'modifiable' is off
  notify_info = false,
  hooks = {
    open = "Telescope find_files",
    -- open = "NvimTreeOpen",
  }
})

local telescope_ok, telescope = pcall(require, "telescope")
if not telescope_ok then
  return vim.notify("Failed to require package `telescope`")
end

telescope.load_extension("workspaces")

M.open = function()
  telescope.extensions.workspaces.workspaces()
end

return M

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.