Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/everduin94/nvim-quick-switcher
Quickly navigate to other files/extensions based on the current file name or jump to nodes in a file via treesitter. Written in Lua.
https://github.com/everduin94/nvim-quick-switcher
lua neovim neovim-plugin nvim plugin treesitter vim
Last synced: about 1 month ago
JSON representation
Quickly navigate to other files/extensions based on the current file name or jump to nodes in a file via treesitter. Written in Lua.
- Host: GitHub
- URL: https://github.com/everduin94/nvim-quick-switcher
- Owner: Everduin94
- License: unlicense
- Created: 2021-12-23T02:29:00.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2024-03-18T00:00:19.000Z (9 months ago)
- Last Synced: 2024-08-07T18:37:04.528Z (5 months ago)
- Topics: lua, neovim, neovim-plugin, nvim, plugin, treesitter, vim
- Language: Lua
- Homepage:
- Size: 7.97 MB
- Stars: 50
- Watchers: 3
- Forks: 4
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Nvim Quick Switcher
Quickly navigate to related/alternate files/extensions based on the current file name. Written in Lua.https://user-images.githubusercontent.com/14320878/205079483-82f2cd39-915e-485a-a5c6-20b188e1b26b.mp4
## Features
- 🦕 Switch to files with common prefix (example: "tasks"):
- `tasks.component.ts` --> `tasks.component.html`
- `tasks.component.html` --> `tasks.component.scss`
- `tasks.component.scss` --> `tasks.component.ts`
- 🦎 Toggle between file extensions
- `tasks.cpp` <--> `tasks.h`
- `tasks.html` <--> `tasks.css`
- 🐙 Switch to files with different suffix
- `tasks.component.ts` --> `tasks.module.ts`
- `tasks.component.ts` --> `tasks.component.spec.ts`
- `tasks.query.ts` --> `tasks.store.ts`
- 🐒 Find files by Wilcard (Glob) or Regex
- `tasks.ts` --> `tasks.spec.ts` | `tasks.test.ts`
- `tasks.ts` --> `tasks.css` | `tasks.scss` | `tasks.sass`
- `/tasks.components.ts` --> `state/tasks.query.ts`
- `state/tasks.query.ts` --> `../tasks.component.ts`
- `controller.lua` --> `controller_spec.lua`
- `controller-util.lua` --> `controller-service.lua`
- 🌳 Navigate inside files with Treesitter Queries## Installation
Vim-plug
```vim
Plug 'Everduin94/nvim-quick-switcher'
```Packer
```lua
use {
"Everduin94/nvim-quick-switcher",
}
```## Usage
Switcher has 4 functions. `switch`, `toggle`, `find`, `inline_ts_switch`. No setup function call required. Just call a function with the desired arguments.
For more examples, see `Recipes`
### ➡️ Switch
*Gets "prefix" of file name, switches to `prefix`.`suffix`*`switch(search_string, options)`
#### Example
`require('nvim-quick-switcher').switch('component.ts')`
- `ticket.component.html` --> `ticket.component.ts`#### Options
```lua
{
split = 'vertical'|'horizontal'|nil -- nil is default
size = 100 -- # of columns | rows. default is 50% split
ignore_prefix = false -- useful for navigating to files like "index.ts" or "+page.svelte"
}
```### 🔄 Toggle
*Toggles `prefix`.`suffix`, based on current suffix / file extension*`toggle(search_string_one, search_string_two, options)`
For `options` see `Common Options`
#### Example
`require('nvim-quick-switcher').toggle('cpp', 'h')`
- `node.cpp` --> `node.h`
- `node.h` --> `node.cpp`### 🔍 Find
*Uses gnu/linux `find` & `grep` to find file and switch to `prefix`+`pattern`*`find(search_string, options)`
#### Example
`require('nvim-quick-switcher').find('*query*')`
- Allows wild cards, i.e. first argument is search parameter for gnu/linux find
- file: `ticket.component.ts` --> pattern: `ticket*query*``require('nvim-quick-switcher').find('.+css|.+scss|.+sass', { regex = true })`
- Uses find, then filters via grep regex, i.e. first argument is regex
- file: `ticket.component.ts` --> find: `ticket*` --> grep: `.+css|.+scss|.+sass`
- When using backslash, may have to escape via `\\`If multiple matches are found will prompt UI Select.
- You can use options like `prefix` or `regex` to make your searches more specific. See `Recipes` for examples.If no results are found, will search backwards one directory, see `reverse`
#### Options
```lua
{
split = 'vertical'|'horizontal'|nil
size = 100
regex = false, -- If true, first argument uses regex instead of find string/wildcard.
maxdepth = 2, -- directory depth
reverse = true, -- false will disable reverse search when no results are found
path = nil, -- overwrite path (experimental).
prefix = 'default',
-- full: stop at last period
-- short: stop at first _ or -
-- long: stop at last _
-- default: stop at first period.
-- lua function (you can pass a lua function to create a custom prefix)
regex_type = 'E' -- default regex extended. See grep for types.
ignore_prefix = false -- useful for navigating to files like "index.ts" or "+page.svelte"
}
```### 🌳 Inline Switch (Treesitter)
Requires `nvim-treesitter/nvim-treesitter`*Uses treesitter queries to navigate inside of a file*
`inline_ts_switch(file_type, query_string, options)`
#### Example
`require('nvim-quick-switcher').inline_ts_switch('svelte', '(script_element (end_tag) @capture)')`
- Places cursor at start of `` node#### Options
```lua
{
goto_end = false, -- go to start of node if false, go to end of node if true
avoid_set_jump = false, -- do not add to jumplist if true
}
```### 🚀 Find by Function (Advanced)
Accepts a lua function that provides path/file information as an argument, and returns a file path as a string. Useful for switching across directories / folders.
i.e. the user is provided file path data to then build an entire file path, that gets passed to vim select, that gets passed to navigate.`require('nvim-quick-switcher').find_by_fn(fn, options)`
#### Example
This example switches from a test folder to a src folder (and vice versa) like in to a Java J-Unit project.
```lua
local ex_find_test_fn = function (p)
local path = p.path;
local file_name = p.prefix;
local result = path:gsub('src', 'test') .. '/' .. file_name .. '*';
return result;
endlocal find_src_fn = function (p)
local path = p.path;
local file_name = p.prefix;
local result = path:gsub('test', 'src') .. '/' .. file_name .. '*';
return result;
endrequire('nvim-quick-switcher').find_by_fn(ex_find_test_fn)
require('nvim-quick-switcher').find_by_fn(find_src_fn)
```#### Args
```lua
prefix -- The prefix of the file (task.component.ts) --> task
full_prefix -- (task.component.ts) --> task.component
full_suffix -- (task.component.ts) --> component.ts
short_prefix -- (task-util.lua) --> task
file_type -- (task-util.lua) --> lua
file_name -- (src/tasks/task-util.lua) --> task-util.lua
path -- (src/tasks/task-util.lua) --> src/tasks/task-util.lua
```### 🌌 Common Options
Options common for file location functions (`switch/toggle/find/find_by_fn`).
```lua
{
only_existing = false,
only_existing_notify = false,
}
```
`only_existing` Causes the switcher to check if the target file exists
before switching to it.
`only_existing_notify` will print if the file does not exist.## Recipes (My Keymaps)
*My configuration for nvim-quick-switcher. Written in Lua*```lua
local opts = { noremap = true, silent = true }local function find(file_regex, opts)
return function() require('nvim-quick-switcher').find(file_regex, opts) end
endlocal function inline_ts_switch(file_type, scheme)
return function() require('nvim-quick-switcher').inline_ts_switch(file_type, scheme) end
endlocal function find_by_fn(fn, opts)
return function() require('nvim-quick-switcher').find_by_fn(fn, opts) end
end-- Styles
vim.keymap.set("n", "oi", find('.+css|.+scss|.+sass', { regex = true, prefix='full' }), opts)-- Types
vim.keymap.set("n", "orm", find('.+model.ts|.+models.ts|.+types.ts', { regex = true }), opts)-- Util
vim.keymap.set("n", "ol", find('*util.*', { prefix = 'short' }), opts)-- Tests
vim.keymap.set("n", "ot", find('.+test|.+spec', { regex = true, prefix='full' }), opts)-- Project Specific Keymaps
-- * Maps keys based on project using an auto command. Ideal for reusing keymaps based on context.
-- * Example: In Angular, `oo` switches to .component.html. In Svelte, `oo` switches to *page.svelte
vim.api.nvim_create_autocmd({'UIEnter'}, {
callback = function(event)
local is_angular = next(vim.fs.find({ "angular.json", "nx.json" }, { upward = true }))
local is_svelte = next(vim.fs.find({ "svelte.config.js", "svelte.config.ts" }, { upward = true }))-- Angular
if is_angular then
print('Angular')
vim.keymap.set("n", "oo", find('.component.html'), opts)
vim.keymap.set("n", "ou", find('.component.ts'), opts)
vim.keymap.set("n", "op", find('.module.ts'), opts)
vim.keymap.set("n", "oy", find('.service.ts'), opts)
end-- SvelteKit
if is_svelte then
print('Svelte')
vim.keymap.set("n", "oo", find('*page.svelte', { maxdepth = 1, ignore_prefix = true }), opts)
vim.keymap.set("n", "ou", find('.*page.server(.+js|.+ts)|.*page(.+js|.+ts)', { maxdepth = 1, regex = true, ignore_prefix = true }), opts)
vim.keymap.set("n", "op", find('*layout.svelte', { maxdepth = 1, ignore_prefix = true }), opts)-- Inline TS
vim.keymap.set("n", "oj", inline_ts_switch('svelte', '(script_element (end_tag) @capture)'), opts)
vim.keymap.set("n", "ok", inline_ts_switch('svelte', '(style_element (start_tag) @capture)'), opts)
end
end
})-- Redux-like
vim.keymap.set("n", "ore", find('*effects.ts'), opts)
vim.keymap.set("n", "ora", find('*actions.ts'), opts)
vim.keymap.set("n", "orw", find('*store.ts'), opts)
vim.keymap.set("n", "orf", find('*facade.ts'), opts)
vim.keymap.set("n", "ors", find('.+query.ts|.+selectors.ts|.+selector.ts', { regex = true }), opts)
vim.keymap.set("n", "orr", find('.+reducer.ts|.+repository.ts', { regex = true }), opts)-- Java J-Unit (Advanced Example)
local find_test_fn = function (p)
local path = p.path;
local file_name = p.prefix;
local result = path:gsub('src', 'test') .. '/' .. file_name .. '*';
return result;
endlocal find_src_fn = function (p)
local path = p.path;
local file_name = p.prefix;
local result = path:gsub('test', 'src') .. '/' .. file_name .. '*';
return result;
endvim.keymap.set("n", "ojj", find_by_fn(find_test_fn), opts)
vim.keymap.set("n", "ojk", find_by_fn(find_src_fn), opts)
```## Personal Motivation
Many moons ago, as a sweet summer child, I used VS Code with an extension called "Angular Switcher".
Angular switcher enables switching to various file extensions related to the current component.I wanted to take that idea and make it work for many frameworks or file extensions
I currently use nvim-quick-switcher on a daily basis for Svelte / Svelte-Kit, Angular Components, Tests, Stylesheets, Lua util files, and Redux-like files.
## Alternatives
- [projectionist](https://github.com/tpope/vim-projectionist)