project_nvim_example.mp4
project.nvim is a Neovim plugin written in Lua that,
under configurable conditions, automatically sets the user's cwd to the current project root
and also allows users to manage, access and selectively include their projects in a history.
This plugin allows you to navigate through projects, "bookmark" and/or discard them, according to your needs.
This was originally forked from ahmedkhalf/project.nvim. Ever since I've decided to extend it and address issues.
You can check some sample videos in EXAMPLES.md.
- Features
- Installation
- Configuration
- Commands
- API
- Utils
- Troubleshooting
- Collaborators
- Contributors
- Alternatives
- License
- Automatically sets the
cwdto the project root directory using pattern matching (LSP optionally) - Users can control whether to run this or not by filetype/buftype
- Functional
checkhealthhook:checkhealth project - Vim help documentation
:h project-nvim - Logging capabilities
:ProjectLog - Natively supports
.nvim.luafiles vim.uimenu support- Telescope Integration
:Telescope projects fzf-luaIntegrationnvim-treeIntegrationneo-treeIntegrationmini.starterIntegration- (NEW)
picker.nvimIntegration
Requirements:
- Neovim >=
v0.11 fd(REQUIRED FOR SESSION MANAGEMENT)ibhagwan/fzf-lua(OPTIONAL, RECOMMENDED)nvim-telescope/telescope.nvim(OPTIONAL, RECOMMENDED)
If you want to add instructions for your plugin manager of preference please raise a BLANK ISSUE.
Use any plugin manager of your choosing.
if has('nvim-0.11')
Plug 'DrKJeff16/project.nvim'
" OPTIONAL
Plug 'nvim-telescope/telescope.nvim' | Plug 'nvim-lua/plenary.nvim'
Plug 'ibhagwan/fzf-lua'
lua << EOF
require('project').setup()
EOF
endif{
'DrKJeff16/project.nvim',
dependencies = { -- OPTIONAL
'nvim-lua/plenary.nvim',
'nvim-telescope/telescope.nvim',
'ibhagwan/fzf-lua',
},
opts = {},
}If you wish to lazy-load this plugin:
{
'DrKJeff16/project.nvim',
cmd = { -- Lazy-load by commands
'Project',
'ProjectAdd',
'ProjectConfig',
'ProjectDelete',
'ProjectExportJSON',
'ProjectImportJSON',
'ProjectHealth',
'ProjectHistory',
'ProjectRecents',
'ProjectRoot',
'ProjectSession',
},
dependencies = { -- OPTIONAL. Choose any of the following
{ 'nvim-telescope/telescope.nvim', dependencies = { 'nvim-lua/plenary.nvim' } },
'wsdjeg/picker.nvim',
'ibhagwan/fzf-lua',
},
opts = {},
}if vim.fn.has('nvim-0.11') == 1 then
require('pckr').add({
{
'DrKJeff16/project.nvim',
requires = { -- OPTIONAL. Choose any of the following
'nvim-lua/plenary.nvim',
'nvim-telescope/telescope.nvim',
'wsdjeg/picker.nvim',
'ibhagwan/fzf-lua',
},
config = function()
require('project').setup()
end,
};
})
endlocal paq = require('paq')
paq({
'DrKJeff16/project.nvim',
-- OPTIONAL. Choose any of the following
'nvim-lua/plenary.nvim',
'nvim-telescope/telescope.nvim',
'wsdjeg/picker.nvim',
'ibhagwan/fzf-lua',
})
require('project.nvim').setup()The package can be found in the LuaRocks webpage.
luarocks install project.nvim # Global install
luarocks install --local project.nvim # Local installTo enable the plugin you must call setup():
require('project').setup()You can find these in config/defaults.lua
Note
The Project.Telescope.ActionNames type is an alias for:
---@alias Project.Telescope.ActionNames
---|'browse_project_files'
---|'change_working_directory'
---|'delete_project'
---|'find_project_files'
---|'help_mappings'
---|'recent_project_files'
---|'search_in_project_files'setup() comes with these defaults:
{
---@param target_dir string
---@param method string
before_attach = function(target_dir, method) end,
---@param dir string
---@param method string
on_attach = function(dir, method) end,
lsp = {
enabled = true,
ignore = {},
use_pattern_matching = false,
no_fallback = false, -- WARNING: USE AT YOUR OWN DISCRETION!!!!
},
manual_mode = false,
patterns = {
'.git',
'.github',
'_darcs',
'.hg',
'.bzr',
'.svn',
'Pipfile',
'pyproject.toml',
'.pre-commit-config.yaml',
'.pre-commit-config.yml',
'.csproj',
'.sln',
'.nvim.lua',
},
different_owners = {
allow = false, -- Allow adding projects with a different owner to the project session
notify = true, -- Notify the user when a project with a different owner is found
},
enable_autochdir = false,
show_hidden = false,
exclude_dirs = {},
silent_chdir = true,
scope_chdir = 'global',
datapath = vim.fn.stdpath('data'),
historysize = 100,
log = {
enabled = false,
max_size = 1.1,
logpath = vim.fn.stdpath('state'),
},
fzf_lua = { enabled = false },
picker = {
enabled = false,
hidden = false, -- Show hidden files
sort = 'newest', ---@type 'newest'|'oldest'
},
disable_on = {
ft = {
'',
'NvimTree',
'TelescopePrompt',
'TelescopeResults',
'alpha',
'checkhealth',
'lazy',
'log',
'ministarter',
'neo-tree',
'notify',
'nvim-pack',
'packer',
'qf',
},
bt = { 'help', 'nofile', 'nowrite', 'terminal' },
},
telescope = {
sort = 'newest', ---@type 'oldest'|'newest'
prefer_file_browser = false,
disable_file_picker = false,
mappings = { ---@type table<'n'|'i', table<string, Project.Telescope.ActionNames>>
n = {
b = 'browse_project_files',
d = 'delete_project',
f = 'find_project_files',
r = 'recent_project_files',
s = 'search_in_project_files',
w = 'change_working_directory',
},
i = {
['<C-b>'] = 'browse_project_files',
['<C-d>'] = 'delete_project',
['<C-f>'] = 'find_project_files',
['<C-r>'] = 'recent_project_files',
['<C-s>'] = 'search_in_project_files',
['<C-w>'] = 'change_working_directory',
},
},
},
}project.nvim comes with a vim-rooter-inspired pattern matching expression engine
to give you better handling of your projects.
For your convenience here come some examples:
To specify the root is a certain directory, prefix it with =:
patterns = { '=src' }To specify the root has a certain directory or file (which may be a glob), just add it to the pattern list:
patterns = { '.git', '.github', '*.sln', 'build/env.sh' }
To specify the root has a certain directory as an ancestor (useful for excluding directories),
prefix it with ^:
patterns = { '^fixtures' }
To specify the root has a certain directory as its direct ancestor/parent
(useful when you put working projects in a common directory), prefix it with \>:
patterns = { '>Latex' }To exclude a pattern, prefix it with `!`
patterns = { '!.git/worktrees', '!=extras', '!^fixtures', '!build/env.sh' }Important
Make sure to put your pattern exclusions first, and then the patterns you DO want included.
Also if you have allow_patterns_for_lsp enabled, it will also work somewhat for your LSP clients.
Make sure these flags are enabled to support nvim-tree.lua:
require('nvim-tree').setup({
sync_root_with_cwd = true,
respect_buf_cwd = true,
update_focused_file = {
enable = true,
update_root = true,
},
})You can use :Neotree filesystem ... when changing a project:
vim.keymap.set('n', '<YOUR-TOGGLE-MAP>', ':Neotree filesystem toggle reveal_force_cwd<CR>', opts)
vim.keymap.set('n', '<YOUR-SHOW-MAP>', ':Neotree filesystem show reveal_force_cwd<CR>', opts)
vim.keymap.set('n', '<YOUR-FLOAT-MAP>', ':Neotree filesystem float reveal_force_cwd<CR>', opts)
-- ... and so onTo enable telescope.nvim integration use the following
code in your config:
require('telescope').setup()
require('telescope').load_extension('projects')After that you can now call it from the command line:
:Telescope projectsYou can also configure the picker when calling require('telescope').setup()
CREDITS: @ldfwbebp
require('telescope').setup({
extensions = {
projects = {
prompt_prefix = " ",
layout_strategy = "horizontal",
layout_config = {
anchor = "N",
height = 0.25,
width = 0.6,
prompt_position = "bottom",
},
},
},
})project.nvim comes with the following mappings for Telescope:
| Normal Mode | Insert Mode | Action |
|---|---|---|
f |
<C-f> |
find_project_files |
b |
<C-b> |
browse_project_files |
d |
<C-d> |
delete_project |
s |
<C-s> |
search_in_project_files |
r |
<C-r> |
recent_project_files |
w |
<C-w> |
change_working_directory |
You can find the Actions in telescope/_extensions/projects/actions.lua.
If you use nvim-mini/mini.starter you can include the
following snippet in your MiniStarter setup:
require('mini.starter').setup({
evaluate_single = true,
items = {
{ name = 'Projects', action = 'Project', section = 'Projects' }, -- Runs `:Project`
{ name = 'Recent Projects', action = 'ProjectRecents', section = 'Projects' }, -- `:ProjectRecents`
-- Other items...
},
})This plugin has a custom integration with @wsdjeg's
picker.nvim.
If enabled, the :ProjectPicker command will be available to you.
To enable it you'll need the plugin installed, then in your setup:
require('project').setup({
picker = {
enabled = true,
sort = 'newest', -- 'newest' or 'oldest'
hidden = false, -- Show hidden files
}
})Mappings:
| Normal Mode | Description |
|---|---|
<C-d> |
Delete the selected project |
<C-w> |
Changes the cwd to the selected project |
You can find the integration in
extensions/picker.lua
and sources/project.lua.
These are the user commands you can call from the cmdline:
The :Project command will open a UI window pointing to all the useful operations
this plugin can provide. This one is subject to change, just as vim.ui is.
See commands.lua for more info.
Important
This command works ONLY if you have picker.nvim installed
and picker.enabled set to true.
The :ProjectPicker command is a dynamically enabled user command that runs
project.nvim through picker.nvim.
If a bang is passed (:ProjectPicker!) and you don't already have picker.hidden set to true,
then a selected project will show hidden files.
This is an alias for :Picker project.
See picker.nvim Integration for more info.
Important
This command works ONLY if you have fzf-lua installed and loaded
and fzf_lua.enabled set to true.
The :ProjectFzf command is a dynamically enabled user command that opens a fzf-lua picker
for project.nvim.
For now it just executes require('project').run_fzf_lua().
Mappings:
| Mapping | Description |
|---|---|
<C-d> |
Delete the selected project |
See extensions/fzf-lua.lua for more info.
Important
This command works ONLY if you have telescope.nvim installed and loaded
The :ProjectTelescope command is a dynamicly enabled User Command that runs
the Telescope projects picker.
A shortcut, to be honest.
See telescope/_extensions/projects.lua for more info.
The :ProjectHealth command runs :checkhealth project in a single command.
See commands.lua for more info.
The :ProjectHistory command toggles the project.nvim history file in a new tab,
which can be exited by pressing q in Normal Mode.
See history.lua for more info.
Important
This command will not be available unless you set log.enabled = true
in your setup().
The :ProjectLog command handles the project.nvim log file.
The valid arguments are:
:ProjectLog clear " Clears the current log file, will close any opened log window
:ProjectLog close " Closes the Log Window
:ProjectLog open " Opens the Log Window
:ProjectLog toggle " Toggles the Log WindowSee log.lua for more info.
The :ProjectAdd command is a manual hook that opens a prompt to input any
directory through a UI prompt, to be saved to your project history.
If your prompt is valid, your cwd will be switched to said directory.
Adding a [!] will set the prompt to your cwd.
This is particularly useful if you've enabled manual_mode in setup().
See commands.lua for more info.
The :ProjectRoot command is a manual hook to set the working directory to the current
file's root, attempting to use any of the setup() detection methods
set by the user.
The command is like doing the following in the cmdline:
:lua require('project.api').on_buf_enter()See commands.lua for more info.
The :ProjectConfig command will toggle your current config in a floating window,
making it easier to access. To exit the window you can either press q in normal mode
or by runnning :ProjectConfig again.
You can also print the output instead by running :ProjectConfig!.
See commands.lua for more info.
The :ProjectDelete command is a utility to delete your projects.
If no arguments are given, a popup with a list of your current projects will be opened.
If one or more arguments are passed, it will expect directories separated
by a space. The arguments have to be directories that are returned by get_recent_projects().
The arguments can be relative, absolute or un-expanded (~/path/to/project).
The command will attemptto parse the args and, unless a ! is passed to the command
(:ProjectDelete!). In that case, invalid args will be ignored.
If there's a successful deletion, you'll recieve a notification denoting success.
Usage:
" Vim command line
:ProjectDelete[!] [/path/to/first [/path/to/second [...]]]- See
:h :ProjectDeletefor more info. - See
commands.luafor more info.
Important
This command requires fd to be installed for it to work!
The :ProjectSession command opens a custom picker with a selection of
your current session projects (stored in History.session_projects). Bear in mind this table gets
filled on runtime.
If you select a session project, your cwd will be changed to what you selected.
If the command is called with a ! (:ProjectSession!) the UI will close.
Otherwise, another custom UI picker will appear for you to select the files/dirs.
Selecting a directory will open another UI picker with its contents, and so on.
See popup.lua for more info.
Warning
Use this script with caution, as you may overwrite your files if doing something reckless!
The :ProjectExportJSON allows the user to save their project history in a JSON format,
allowing a custom indent level if desired.
If the target file already exists and is not empty then a confirmation prompt will appear.
Example usage:
" Will open a prompt
:ProjectExportJSON
" The output file will be `a.json`
:ProjectExportJSON a
" The output file will be `b`, with a tab size of 12
:ProjectExportJSON! b 12
" The output file will be `~/.c.json` (bang here is irrelevant)
:ProjectExportJSON! ~/.c.jsonThe :ProjectImportJSON allows the user to retrieved their saved project history in a JSON format.
Example usage:
" Will open a prompt
:ProjectImportJSON
" Will be treated as `a.json`
:ProjectExportJSON a
:ProjectImportJSON a
" Will be treated as `b`
:ProjectExportJSON! b
:ProjectImportJSON! bThe API can be found in api.lua.
get_project_root() is an API utility for finding out
about the current project's root, if any:
---@type string?, string?
local root, lsp_or_method = require('project').get_project_root()You can get a list of recent projects by running the code below:
local recent_projects = require('project').get_recent_projects() ---@type string[]
vim.notify(vim.inspect(recent_projects))Where get_recent_projects() returns either an empty table {}
or a string array { '/path/to/project1', ... }.
If setup() has been called, it returns a table containing the currently set options.
Otherwise it will return nil.
local config = require('project').get_config()
-- Using `vim.notify()`
vim.notify(vim.inspect(config))
-- Using `vim.print()`
vim.print(config)If no valid args are passed to this function, it will return the following dictionary:
local get_history_paths = require('project').get_history_paths
-- A dictionary table containing all return values below
vim.print(get_history_paths())
--- { datapath = <datapath>, projectpath = <projectpath>, historyfile = <historyfile> }Otherwise, if either 'datapath', 'projectpath' or 'historyfile' are passed,
it will return the string value of said arg:
-- The directory where `project` sets its `datapath`
vim.print(get_history_paths('datapath'))
-- The directory where `project` saves the project history
vim.print(get_history_paths('projectpath'))
-- The path to where `project` saves its recent projects history
vim.print(get_history_paths('historyfile'))A set of utilities that get repeated across the board.
You can import them as shown below:
local ProjUtil = require('project.util')See util.lua for further reference.
These utilities are in part inspired by my own utilities found in Jnvim,
my own Nvim configuration; particularly the User API_
(WIP).
If you're in a UNIX environment, make sure you have read, write and access permissions
(rwx) for the projectpath directory.
Important
The default value is vim.fn.stdpath('data')/project_nvim.
See :h stdpath() for more info.
You can get the value of projectpath by running the following in the cmdline:
:lua vim.print(require('project').get_history_paths('projectpath'))If you lack the required permissions for that directory, you can either:
- Delete that directory (RECOMMENDED)
- Run
chmod 755 <project/path>(NOT SURE IF THIS WILL FIX IT)
|
Richard Steinbrück |
Guennadi Maximov C |
Josip Keresman |
Show these much love!
nvim-telescope/telescope-project.nvimfolke/snacks.nvimcoffebar/neovim-projectLintaoAmons/cd-project.nvimwsdjeg/rooter.nvim