Skip to content

Configuration Recipes

Steven Noble edited this page Sep 2, 2024 · 6 revisions

This page is a place to share various configurations for workspaces.nvim. If you make something useful please share it here!

Editing Instructions:
Please follow the following format:

Short Title or Description (h2)

Dependencies: list required plugins if applicable

briefly explain the behavior

require("workspaces.nvim").setup({
  -- setup code here
})

Further details, notes, instructions, etc. here.

If you feel the need to deviate from this format that is fine, but try to keep things organized!

Recipes

Telescope file finder

Dependencies: nvim-telescope/telescope.nvim

Opens a Telescope file fuzzy finder after switching directories.

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

Open nvim-tree

Dependencies: kyazdani42/nvim-tree.lua

Ensures NvimTree is open after switching directories

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

Simple sessions.nvim integration

Dependencies: natecraddock/sessions.nvim

Uses sessions.nvim to load a saved buffer, window, and tab layout from the current directory after opening a workspace. If no session exists, nothing happens.

require("workspaces").setup({
  hooks = {
    open_pre = {
      "SessionsStop",
      "silent %bdelete!",
    },
    open = {
      function()
        require("sessions").load(nil, { silent = true })
      end
    }
  },
})

Note that the sessions.load() function assumes a default sessions path has been configured

Autosave and Autoload CWD Session with possession.nvim

Dependencies: jedrzejboczar/possession.nvim

The following snippet saves the session of the current cwd before switching if it exists, and loads the session of the newly opened cwd if it exists.

--- Convert the given workspace.nvim path to a possession.nvim path
local function to_possesion_path(path)
    path = path:gsub("^" .. os.getenv("HOME"), "~")
    path = path:gsub("/$", "")
    return path
end

require("workspaces").setup({
    hooks = {
        open_pre = function(name, path, state)
            local workspaces = require("workspaces")
            local possession_paths = require("possession.paths")
            local possession_config = require("possession.config")
            local possession_session = require("possession.session")

            local curr_path = workspaces.path()
            if not curr_path then return end

            local autosave_info = possession_session.autosave_info()
            if not possession_config.autosave.on_load or not autosave_info then return end

            local next_session = possession_paths.session(to_possesion_path(path))
            if next_session:exists() then
                local session_data = vim.json.decode(next_session:read())
                if session_data.name == autosave_info.name then return end
            end

            possession_session.autosave()
            vim.wait(100, function() end) -- Stupid hack to wait for Neo-tree to close and open before/after saving
        end,
        --- Automatically load the session of the given workspace if it exists.
        --- Otherwise, just close down the current session.
        open = function(name, path, state)
            path = to_possesion_path(path)

            if require("possession.paths").session(path):exists() then
                require("possession.session").load(path, { skip_autosave = true })
            else
                require("possession.session").close()
            end
        end,
    },
})

Automatically change workspace when switching buffers

This relatively complex recipe creates an autocommand to allow you to work on multiple workspaces within a single neovim session.

When a buffer / window is focused, and it is not in the current workspace, the active workspace will be switched to the correct one, if found.

-- returns true if `dir` is a child of `parent`
local is_dir_in_parent = function(dir, parent)
  if parent == nil then return false end
  local ws_str_find, _ = string.find(dir, parent, 1, true)
  if ws_str_find == 1 then
    return true
  else
    return false
  end
end

-- convenience function which wraps is_dir_in_parent with active file
-- and workspace.
local current_file_in_ws = function()
  local workspaces = require('workspaces')
  local ws_path = require('workspaces.util').path
  local current_ws = workspaces.path()
  local current_file_dir = ws_path.parent(vim.fn.expand('%:p', true))

  return is_dir_in_parent(current_file_dir, current_ws)
end

-- set workspace when changing buffers
local my_ws_grp = vim.api.nvim_create_augroup("my_ws_grp", { clear = true })
vim.api.nvim_create_autocmd({ "BufEnter", "VimEnter" }, {
  callback = function()
    -- do nothing if not file type
    local buf_type = vim.api.nvim_get_option_value("buftype", { buf = 0 })
    if (buf_type ~= "" and buf_type ~= "acwrite") then
      return
    end

    -- do nothing if already within active workspace
    if current_file_in_ws() then
      return
    end

    local workspaces = require('workspaces')
    local ws_path = require('workspaces.util').path
    local current_file_dir = ws_path.parent(vim.fn.expand('%:p', true))

    -- filtered_ws contains workspace entries that contain current file
    local filtered_ws = vim.tbl_filter(function(entry)
      return is_dir_in_parent(current_file_dir, entry.path)
    end, workspaces.get())

    -- select the longest match
    local selected_workspace = nil
    for _, value in pairs(filtered_ws) do
      if not selected_workspace then
        selected_workspace = value
      end
      if string.len(value.path) > string.len(selected_workspace.path) then
        selected_workspace = value
      end
    end

    if selected_workspace then workspaces.open(selected_workspace.name) end
  end,

  group = my_ws_grp
})

-- use below example if using any `open` hooks, such as telescope, otherwise
-- the hook will run every time when switching to a buffer from a different
-- workspace.

require("workspaces").setup({
  hooks = {
    open = {
      -- do not run hooks if file already in active workspace
      function()
        if current_file_in_ws() then
          return false
        end
      end,

      function()
        require('telescope.builtin').find_files()
      end,
    }
  }
})

Trigger telescope.find_files after telescope.workspaces

You might want to move Telescope logic out of the open hook and into a user command like the one shown below, so that:

  • changing the working directory using Telescope opens a Telescope file finder
  • automatically changing the working directory by entering a file from a different workspace does not open a Telescope file finder
vim.api.nvim_create_user_command(
  'SwitchWorkspace',
  function(opts)
    local buf = vim.api.nvim_get_current_buf()

     cmd_id = vim.api.nvim_create_autocmd(
       'DirChanged',
       {
         callback = function(args)
           if buf == vim.api.nvim_get_current_buf() then
             require('telescope.builtin').find_files({ cwd = args.file })
             vim.api.nvim_del_autocmd(cmd_id)
           end
           
           vim.api.nvim_set_current_dir(args.file)
         end
       }
      )

      require('telescope').extensions.workspaces.workspaces()
    end,
  { nargs = 0 }
)