# vim-project **Repository Path**: ottobryant_admin/vim-project ## Basic Information - **Project Name**: vim-project - **Description**: No description available - **Primary Language**: Unknown - **License**: Unlicense - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-07-08 - **Last Updated**: 2024-07-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README icon # vim-project

screenshot

A vim plugin to manage projects and sessions. **Features** - Switch between projects Project-wide - Search files by name - Find in files - Find and replace (**experimental**) - Run tasks - Search git log and file history - Config - Session (optional) You can save session per branch if both vim feature `job` and shell command `tail` are present. ---

Add / Open a project

screenshot ➡️ screenshot ➡️ screenshot

---

Search files / Find in files / Find and replace in a project

screenshot screenshot screenshot

--- * [Basic Usage](#basic-usage) * [Installation](#installation) * [Show file icon](#show-file-icon) * [Uninstallation](#uninstallation) * [Workflow](#workflow) * [Commands](#commands) * [:Project ``](#project-path) * [:ProjectNew ``](#projectnew-path) * [Search files / Find in files](#search-files--find-in-files) * [Config for search / find](#config-for-search--find) * [Run tasks](#run-tasks) * [Git Integration](#git-integration) * [Config and Keymappings](#config-and-keymappings) * [Config files](#config-files) * [Project local config](#project-local-config) * [Switch between files](#switch-between-files) * [Session options](#session-options) * [Project views](#project-views) * [Global variables](#global-variables) * [Statusline](#statusline) * [Title](#title) * [Debug](#debug) * [Credits](#credits) ## Basic Usage - `:Project ` - `:ProjectNew ` - `:ProjectList` - `:ProjectSearchFiles` - `:ProjectFindInFiles` - `:ProjectRun` - `:ProjectGitLog` - `:ProjectFileHistory` In a list, filter by typing. Select an item by c-j, c-k or the arrow keys. Then press Enter to open it. See [Config and Keymappings](#config_keymappings) for details. ## Installation - [fd][4] - [rg][5] or [ag][6] - this plugin It's recommended to install [fd][4] and one of [rg][5] or [ag][6] to improve search performance. You can install this plugin just like others.
How to install - [VundleVim][1] Plugin 'leafOfTree/vim-project' - [vim-pathogen][2] cd ~/.vim/bundle git clone https://github.com/leafOfTree/vim-project --depth 1 - [vim-plug][3] Plug 'leafOfTree/vim-project' - Or manually, clone this plugin to `path/to/this_plugin`, and add it to `rtp` in vimrc set rtp+=path/to/this_plugin
### Show file icon To enable file icon in front of file name, you need to install - [Nerd Fonts][7] choose one and use it in Vim - [nerdfont.vim][8] - [glyph-palette.vim][9] (Optional, color icons) nerd-font ## Uninstallation You need to remove this plugin as well as `config_home` (default: `~/.vim/vim-project-config`). ## Workflow - Add `:Project ` | `:ProjectNew ` - Open `:ProjectList` | `:ProjectOpen ` - Quit `:ProjectQuit` | Open another project | Quit vim - Remove `:ProjectRemove ` ## Commands | Command | Description | |----------------------------|------------------------------------------| | Project `` | Add existing project, then open it | | ProjectNew `` | Create new project by running predefined tasks | | ProjectList | Show all projects | | ProjectSearchFiles | Search files by name | | ProjectFindInFiles | Find given string/regexp (at least 2 chars) in files | | ProjectRun | Run a task defined by `tasks` config | | ProjectGitLog | Show git log | | ProjectGitFileHistory | Show file history | | ProjectGitBranch | Show all git branches | | ProjectGitTag | Show all git tags | | ProjectRoot | Open project root | | ProjectConfig | Open project config `init.vim` (effective after save) | | ProjectAllConfig | Open all projects config `project.add.vim` | | ProjectInfo | Show project brief info | | ProjectAllInfo | Show project all info | | ProjectOpen `` | Open a project by name | | ProjectRemove `` | Remove a project by name | | ProjectRename `` `` | Rename a project of `name` to `new_name`. Its folder's name is renamed, too | | ProjectQuit | Quit project | | ProjectIgnore `` | Ignore project for auto detection | > You can try adjusting `wildmenu`, `wildmode` for enhanced command-line completion ### :Project `` `path`: If `path` is relative or a project name , it'll search with both current working directory and `g:vim_project_config.project_base` as path base . In addition, you can use Tab to auto complete the path. > Relative means path doesn't start with `/`, `~` or `C:/`. Optional: you can add "note" which will be shown on project list by `:Project "note for project"`. Example ```vim Project /path/to/demo Project /path/to/demo "This is a demo" " Current working directory (:pwd) is /path/to Project demo Project ../to " g:vim_project_config.project_base is set to ['/path/to'] Project demo ``` ### :ProjectNew `` `:ProjectNew` will use `new_project_base` or else current working directory as path base location except for a absolute `path`. - `path` can be a relative path or a name. you can use Tab to auto complete. - If `path` is a git url, the command will use `git clone ` to create a new project. `new_tasks` defines tasks to create new project. - `name`: task name - `cmd`: command to run - `args`: optional, the value is from what user types and will be appended to `cmd` By default, the config is ```vim \'new_tasks': [ \{ 'name': 'git', 'cmd': 'git clone', 'args': 'url' }, \{ 'name': 'empty', 'cmd': 'mkdir' }, \], \`new_project_base`: '' ``` `new_tasks_post_cmd` defines the command to run after project is created. By default, it's empty `''`. Example ```vim let g:vim_project_config = { \... \'new_tasks': [ \ { 'name': 'mdbook', 'cmd': 'mdbook init' }, \ { 'name': 'vite', 'cmd': 'npm create vite@latest' }, \ { 'name': 'create react app', 'cmd': 'npx create-react-app' }, \ { 'name': 'spring', 'cmd': 'spring init' }, \ { 'name': 'degit', 'cmd': 'degit', 'args': 'url' }, \ { 'name': 'git', 'cmd': 'git clone', 'args': 'url' }, \ { 'name': 'empty directory', 'cmd': 'mkdir' }, \], \'new_tasks_post_cmd': 'touch README.md && git init && git add . && git commit -m "Init"', \`new_project_base`: '/path/to/projects', \... ``` `new_tasks_post_cmd` can also be a Function reference (`Funcref`). Its arguments are the project name (`string`), the task (`dict`), and the actual cmd (`string`). ```vim function! NewTasksPostCmd(name, task, cmd) if a:task.name == 'git' return endif return 'touch README.md && git init && git add . && git commit -m "Init"' \.'git remote add origin https://github.com/username/'.a:name endfunction ... \'new_tasks_post_cmd': function('NewTasksPostCmd'), ``` ### Search files / Find in files - `:ProjectSearchFiles` Under the hood, it tries [[fd][4], `find`, `glob (vim function)`] for the first available one as the search engine. - `:ProjectFindInFiles` Under the hood, it tries [[rg][5], [ag][6], `grep`, `vimgrep (vim function)`] for the first available one as the search engine. It's recommended to install one of [[fd][4], `find`] and one of [[rg][5], [ag][6], `grep`]. They have better performance especially for Windows users and large projects. However, none of them will respect `.gitignore` serving as a search engine for consistency. To enable `:ProjectFindInFiles` on visually selected word, use `noremap` as follows ```vim noremap :ProjectFindInFiles ``` #### Config for search / find For consistency, the behaviors are controlled as below no matter which engine is used. Both `Search files` and `Find in files` - Include & Exclude Check the following options in the [config](#config_keymappings). - `include` - `exclude` The following are specific options to extend the above. The final result is like `include (global + local)` + `search_include (global + local)`. - `search_include` - `find_in_files_include` - `search_exclude` - `find_in_files_exclude` `Find in files` - Match case Prefix your input with `\C`. By default, it's case insensitive. - Regexp Prefix your input with `\E`. By default, it's treated as a literal/fixed string. `Find and replace` ⚠️ Please note this feature is not fully tested. It may cause unexpected changes to your files. Always remember to commit your changes before running it. Feel free to open an issue if anything goes wrong. When `Find in files`, you can press - c-r to start to replace - Enter or c-y to confirm - c-d to dismiss any item on the list ### Run tasks `:ProjectRun` run a task defined by `tasks`. A task contains - `name`: task name - `cmd`: command to run in terminal through shell - `args`: optional, the value is from what user types and will be appended to `cmd` - `cd`: optional, change directory to current project relatively - `show`, `hide`: optional, both are a list of patterns to fiter task output For example, with below local config ```vim let g:vim_project_local_config = { \'tasks': [ \{ \'name': 'npm', \'cmd' : 'npm run', \'args': 'script name', \'cd' : 'webapp', \}, \{ \'name': 'build', \'cmd': 'npm build' \'show': ['tests run.*in', '^\s\+'], \'hide': ['info'], \}, \{ \'name': 'terminal', \'cmd': '' \}, \], \} ``` **Run, Rerun, Stop**: You can press - Enter to run/rerun the task - c-q to stop the task and remove its output. - c-o to open the corresponding terminal buffer **Vim terminal**: If you set `cmd` to empty string `''`, it'll call `:terminal` to open a new Vim terminal window. ### Git Integration - `:ProjectGitLog`: Show git log - `:ProjectGitFileHistory`: Show history of current opened file. Works on visually selected lines. - `:ProjectGitBranch`: Show branches - `:ProjectGitTag`: Show tags #### Git status and changelist management - `:ProjectGitStatus`: Show local changes. You can create changelist to organize your local changes. Support basic operations like `commit`, `rollback`, `push`, and `pull`. Below are git related key mappings for the corresponding diff, changes, and local changes buffer. ``` let g:vim_project_config.git_diff_mappings = { \'jump_to_source': "\", \} let g:vim_project_config.git_changes_mappings = { \'open_file': "\", \} let g:vim_project_config.git_local_changes_mappings = { \'commit': 'c', \'rollback_file': 'R', \'open_changelist_or_file': "\", \'new_changelist': 'a', \'move_to_changelist': 'm', \'rename_changelist': 'r', \'delete_changelist': 'd', \'pull': 'u', \'push': 'p', \'pull_and_push': 'P', \} ``` ## Config and Keymappings The config consists of following two parts - `g:vim_project_config` (global, in `.vimrc`) - `g:vim_project_local_config` (project local, in project's `init.vim`) The `g:vim_project_config` should be set in `.vimrc`. Its default value is below. You can copy it as a starting point. ```vim let g:vim_project_config = { \'config_home': '~/.vim/vim-project-config', \'project_base': ['~'], \'use_session': 0, \'open_root_when_use_session': 0, \'check_branch_when_use_session': 0, \'project_root': './', \'auto_load_on_start': 0, \'include': ['./'], \'exclude': ['.git', 'node_modules', '.DS_Store'], \'search_include': [], \'find_in_files_include': [], \'search_exclude': [], \'find_in_files_exclude': [], \'auto_detect': 'no', \'auto_detect_file': ['.git', '.svn'], \'ask_create_directory': 'no', \'project_views': [], \'file_mappings': {}, \'tasks': [], \'new_tasks': [ \{ 'name': 'git', 'cmd': 'git clone', 'args': 'url' }, \{ 'name': 'empty', 'cmd': 'mkdir' }, \], \'new_project_base': '', \'new_tasks_post_cmd': '', \'commit_message': '', \'debug': 0, \} " Keymappings for list prompt let g:vim_project_config.list_mappings = { \'open': "\", \'close_list': "\", \'clear_char': ["\", "\"], \'clear_word': "\", \'clear_all': "\", \'prev_item': ["\", "\"], \'next_item': ["\", "\"], \'first_item': ["\", "\"], \'last_item': ["\", "\"], \'scroll_up': "\", \'scroll_down': "\", \'paste': "\", \'switch_to_list': "\", \} let g:vim_project_config.list_mappings_projects = { \'prev_view': "\", \'next_view': "\", \} let g:vim_project_config.list_mappings_search_files = { \'open_split': "\", \'open_vsplit': "\", \'open_tabedit': "\", \} let g:vim_project_config.list_mappings_find_in_files = { \'open_split': "\", \'open_vsplit': "\", \'open_tabedit': "\", \'replace_prompt': "\", \'replace_dismiss_item': "\", \'replace_confirm': "\", \} let g:vim_project_config.list_mappings_run_tasks = { \'run_task': "\", \'stop_task': "\", \'open_task_terminal': "\", \} let g:vim_project_config.list_mappings_git = { \'checkout_revision': "\", \} ``` | Option | Description | |-------------------------------|-------------------------------------------------------------------------------| | config_home | The directory for all config files | | project_base | A list of base directories used for path in `:Project path` | | use_session | Use session | | open_root_when_use_session | When session used, always open project root at the beginning | | check_branch_when_use_session | When session used, keep one for each branch | | project_root | Starting directory or file when fist launching project | | auto_detect | Auto detect projects when opening a file.
Choose 'always', 'ask', or 'no' | | auto_detect_file | File used to detect potential projects | | auto_load_on_start | Auto load a project if Vim starts within its directory | | ask_create_directory | Ask if need to create directory when `:Project ` doesn't find it | | list_mappings | Keymappings for list prompt | | include | Including folders | | exclude | Excluding folders/files | | search_include | Including folders for search files | | find_in_files_include | Including folders for find in files | | search_exclude | Excluding folders/files for search files | | find_in_files_exclude | Excluding folders/files for find in files | | file_mappings | Keymappings to switch between files quickly | | tasks | tasks to run using vim 'terminal' feature | | project_views | Define project views by `[[show-pattern, hide-pattern?], ...]` | | commit_message | Default commit message. Can be string or Function reference. | | debug | Show debug messages | ### Config files The config files are located at `~/.vim/vim-project-config/`, where `~/.vim/vim-project-config//` is for each project. `:ProjectAllConfig` and `:ProjectConfig` will open corresponding config files. ``` ~/.vim/vim-project-config/ | project.add.vim " Added projects | project.igonre.vim " Ignored projects | / | init.vim | quit.vim | sessions/ " session for each branch | master.vim | dev.vim ``` Open - Load session - Source project's `init.vim` Quit - Save session - Source project's `quit.vim` `init.vim` will get reloaded once you change and save it. ### Project local config These options, **list or dict types are extended**, others overridden, via `g:vim_project_local_config` in the project's `init.vim`. E.g. ```vim let g:vim_project_local_config = { \'include': ['./'], \'exclude': ['.git', 'node_modules', '.DS_Store'], \'project_root': './', \'use_session': 0, \'open_root_when_use_session': 0, \'check_branch_when_use_session': 0, \} ``` For the project local `file_mappings`, see below. ### Switch between files You can define mappings to frequently changed files in the project's `init.vim`. For example as below, you can - Switch to file `autoload/project.vim` by `'a` and so on - Switch between files `['autoload/project.vim', 'plugin/project.vim']` by `'l` - Switch between file types such as `*.html` and `*.css` at the same path with `'t` - Switch to file returned by user-defined function with `'c` - Switch to file returned by `:h lambda` expression with `'d` ```vim function! StyleInUpperDir() let upper_dir = expand('%:p:h:h') let name = expand('%:r') return upper_dir.'/'.name.'.css' endfunction let g:vim_project_local_config.file_mappings = { \'r': 'README.md', \'a': 'autoload/project.vim', \'p': 'plugin/project.vim', \'l': ['autoload/project.vim', 'plugin/project.vim'], \'t': ['html', 'css'], \'c': function('StyleInUpperDir'), \'i': {-> $vim_project_config.'/init.vim'}, \'d': {-> expand('%:p:h:h').'/'.expand('%:r').'.css'}, \} ``` With `file_open_types`, you can use `'a`, `'va`, `'sa`, `'ta'` to edit file in different ways ```vim let g:vim_project_config.file_open_types = { \'': 'edit', \'v': 'vsplit', \'s': 'split', \'t': 'tabedit', \} ``` ### Session options See `:h sessionoptions`. ### Project views In project list, you can switch between different views with tab and s-tab. You can set `project_views` to `[[show_pattern, hide_patten?], ...]` like ```vim let g:vim_project_config.project_views = [ \['vim', 'plugin'], \['^vue'], \['^react$'], \['.*', 'archived'] \] ``` ## Global variables - `g:vim_project` *dict*: current project info - `$vim_project` *string*: current project path - `$vim_project_config` *string*: current project config path ## Statusline You can get current project info from `g:vim_project`. Try `echo g:vim_project` after opening a project. For example, define a function called `GetProjectInfo` and add `%{GetProjectInfo()}` to `statusline` to show current project name and branch. ```vim function! GetProjectInfo() if exists('g:vim_project') && !empty(g:vim_project) let name = g:vim_project.name let branch = g:vim_project.branch if empty(branch) return '['.name.']' else return '['.name.', '.branch.']' endif else return '' endif endfunction set statusline=%<%t%m\ %y\ %=%{GetProjectInfo()} ``` ### Title Or you can show project info on window title ```vim set title titlestring=%{GetTitle()} function! GetTitle() if exists('g:vim_project') && !empty(g:vim_project) return g:vim_project.name.' - '.expand('%') else return expand('%:p').' - '.expand('%') endif endfunction ``` ## Debug If something goes wrong, you can try - `:ProjectInfo` - `:ProjectAllInfo` - `:echo g:vim_project` - `:let g:vim_project_config.debug = 1` ## Credits Thanks to timsofteng for the great idea. It all started with that. [1]: https://github.com/VundleVim/Vundle.vim [2]: https://github.com/tpope/vim-pathogen [3]: https://github.com/junegunn/vim-plug [4]: https://github.com/sharkdp/fd [5]: https://github.com/BurntSushi/ripgrep [6]: https://github.com/ggreer/the_silver_searcher [7]: https://github.com/ryanoasis/nerd-fonts [8]: https://github.com/lambdalisue/nerdfont.vim [9]: https://github.com/lambdalisue/glyph-palette.vim