Merge 9bb186d6b0 into sapling-pr-archive-AdeAttwood
This commit is contained in:
commit
7fd1fe226c
29 changed files with 677 additions and 384 deletions
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run stylua
|
||||
uses: JohnnyMorganz/stylua-action@v3.0.0
|
||||
uses: JohnnyMorganz/stylua-action@v4.0.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: latest
|
||||
|
|
@ -52,6 +52,9 @@ jobs:
|
|||
|
||||
test:
|
||||
name: Build and test
|
||||
strategy:
|
||||
matrix:
|
||||
nvim-version: ["v0.9.5", "stable", "nightly"]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
|
@ -61,10 +64,25 @@ jobs:
|
|||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt update && sudo apt install -y luajit build-essential
|
||||
run: sudo apt update && sudo apt install -y build-essential luarocks
|
||||
|
||||
- name: Install busted
|
||||
run: sudo luarocks install busted
|
||||
|
||||
- name: Install neovim
|
||||
run: |
|
||||
test -d _neovim || {
|
||||
mkdir -p _neovim
|
||||
curl -sL "https://github.com/neovim/neovim/releases/download/${{ matrix.nvim-version }}/nvim-linux64.tar.gz" | tar xzf - --strip-components=1 -C "${PWD}/_neovim"
|
||||
}
|
||||
|
||||
- name: Build
|
||||
run: cargo build --release
|
||||
|
||||
- name: Test
|
||||
run: find lua -name "*_test.lua" | xargs luajit scripts/test.lua
|
||||
- name: Run tests
|
||||
run: |
|
||||
export PATH="${PWD}/_neovim/bin:${PATH}"
|
||||
export VIM="${PWD}/_neovim/share/nvim/runtime"
|
||||
|
||||
nvim --version
|
||||
nvim -l ./scripts/busted.lua -o TAP ./lua/ivy/ 2> /dev/null
|
||||
|
|
|
|||
|
|
@ -10,9 +10,12 @@ self = false
|
|||
read_globals = {
|
||||
"vim",
|
||||
|
||||
"it",
|
||||
"after",
|
||||
"after_each",
|
||||
"assert",
|
||||
"before",
|
||||
"before_each",
|
||||
"describe",
|
||||
"it",
|
||||
"spy",
|
||||
}
|
||||
|
|
|
|||
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -429,9 +429,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.8.1"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ path = "rust/lib.rs"
|
|||
[dependencies]
|
||||
ignore = "0.4.22"
|
||||
fuzzy-matcher = "0.3.7"
|
||||
rayon = "1.8.1"
|
||||
rayon = "1.10.0"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.5.1"
|
||||
|
|
|
|||
94
README.md
94
README.md
|
|
@ -1,6 +1,6 @@
|
|||
<div align="center">
|
||||
|
||||
<img src="assets/logo.svg" alt="ivy.vim" />
|
||||
<img src="assets/logo.svg" alt="ivy.vim" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
|
@ -20,7 +20,47 @@ git clone https://github.com/AdeAttwood/ivy.nvim ~/.config/nvim/pack/bundle/star
|
|||
|
||||
### Plugin managers
|
||||
|
||||
TODO: Add docs in the plugin managers I don't use any
|
||||
Using [lazy.nvim](https://github.com/folke/lazy.nvim)
|
||||
```lua
|
||||
{
|
||||
"AdeAttwood/ivy.nvim",
|
||||
build = "cargo build --release",
|
||||
},
|
||||
```
|
||||
|
||||
TODO: Add more plugin managers
|
||||
|
||||
### Setup / Configuration
|
||||
|
||||
Ivy can be configured with minimal config that will give you all the defaults
|
||||
provided by Ivy.
|
||||
|
||||
```lua
|
||||
require('ivy').setup()
|
||||
```
|
||||
|
||||
With Ivy you can configure your own backends.
|
||||
|
||||
```lua
|
||||
require('ivy').setup {
|
||||
backends = {
|
||||
-- A backend module that will be registered
|
||||
"ivy.backends.buffers",
|
||||
-- Using a table so you can configure a custom keymap overriding the
|
||||
-- default one.
|
||||
{ "ivy.backends.files", { keymap = "<C-p>" } }
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The `setup` function can only be called once, if its called a second time any
|
||||
backends or config will not be used. Ivy does expose the `register_backend`
|
||||
function, this can be used to load backends before or after the setup function
|
||||
is called.
|
||||
|
||||
```lua
|
||||
require('ivy').register_backend("ivy.backends.files")
|
||||
```
|
||||
|
||||
### Compiling
|
||||
|
||||
|
|
@ -56,28 +96,46 @@ cp ./post-merge.sample ./.git/hooks/post-merge
|
|||
|
||||
## Features
|
||||
|
||||
### Commands
|
||||
### Backends
|
||||
|
||||
A command can be run that will launch the completion UI
|
||||
A backend is a module that will provide completion candidates for the UI to
|
||||
show. It will also provide functionality when actions are taken. The Command
|
||||
and Key Map are the default options provided by the backend, they can be
|
||||
customized when you register it.
|
||||
|
||||
| Command | Key Map | Description |
|
||||
| ------------------ | ----------- | ----------------------------------------------------------- |
|
||||
| IvyFd | \<leader\>p | Find files in your project with a custom rust file finder |
|
||||
| IvyAg | \<leader\>/ | Find content in files using the silver searcher |
|
||||
| IvyBuffers | \<leader\>b | Search though open buffers |
|
||||
| IvyLines | | Search the lines in the current buffer |
|
||||
| IvyWorkspaceSymbol | | Search for workspace symbols using the lsp workspace/symbol |
|
||||
| Module | Command | Key Map | Description |
|
||||
| ------------------------------------ | ------------------ | ----------- | ----------------------------------------------------------- |
|
||||
| `ivy.backends.files` | IvyFd | \<leader\>p | Find files in your project with a custom rust file finder |
|
||||
| `ivy.backends.ag` | IvyAg | \<leader\>/ | Find content in files using the silver searcher |
|
||||
| `ivy.backends.rg` | IvyRg | \<leader\>/ | Find content in files using ripgrep cli tool |
|
||||
| `ivy.backends.buffers` | IvyBuffers | \<leader\>b | Search though open buffers |
|
||||
| `ivy.backends.lines` | IvyLines | | Search the lines in the current buffer |
|
||||
| `ivy.backends.lsp-workspace-symbols` | IvyWorkspaceSymbol | | Search for workspace symbols using the lsp workspace/symbol |
|
||||
|
||||
### Actions
|
||||
|
||||
Action can be run on selected candidates provide functionality
|
||||
|
||||
| Action | Description |
|
||||
| -------------- | ------------------------------------------------------------------------------ |
|
||||
| Complete | Run the completion function, usually this will be opening a file |
|
||||
| Peek | Run the completion function on a selection, but don't close the results window |
|
||||
| Vertical Split | Run the completion function in a new vertical split |
|
||||
| Split | Run the completion function in a new split |
|
||||
| Action | Key Map | Description |
|
||||
| -------------- | ----------- | ------------------------------------------------------------------------------ |
|
||||
| Complete | \<CR\> |Run the completion function, usually this will be opening a file |
|
||||
| Vertical Split | \<C-v\> |Run the completion function in a new vertical split |
|
||||
| Split | \<C-s\> |Run the completion function in a new split |
|
||||
| Destroy | \<C-c\> |Close the results window |
|
||||
| Clear | \<C-u\> |Clear the results window |
|
||||
| Delete word | \<C-w\> |Delete the word under the cursor |
|
||||
| Next | \<C-n\> |Move to the next candidate |
|
||||
| Previous | \<C-p\> |Move to the previous candidate |
|
||||
| Next Checkpoint| \<C-M-n\> |Move to the next candidate and keep Ivy open and focussed |
|
||||
| Previous Checkpoint| \<C-M-n\>|Move to the previous candidate and keep Ivy open and focussed |
|
||||
|
||||
Add your own keymaps for an action by adding a `ftplugin/ivy.lua` file in your config.
|
||||
Just add a simple keymap like this:
|
||||
|
||||
```lua
|
||||
vim.api.nvim_set_keymap( "n", "<esc>", "<cmd>lua vim.ivy.destroy()<CR>", { noremap = true, silent = true, nowait = true })
|
||||
```
|
||||
|
||||
|
||||
## API
|
||||
|
||||
|
|
@ -130,7 +188,7 @@ vertical split action it will open the buffer in a new `vsplit`
|
|||
{ content = "Three" },
|
||||
}
|
||||
end,
|
||||
-- Action callback that will be called on the completion or peek actions.
|
||||
-- Action callback that will be called on the completion or checkpoint actions.
|
||||
-- The currently selected item is passed in as the result.
|
||||
function(result) vim.cmd("edit " .. result) end
|
||||
)
|
||||
|
|
|
|||
33
lua/ivy/config.lua
Normal file
33
lua/ivy/config.lua
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
local config_mt = {}
|
||||
config_mt.__index = config_mt
|
||||
|
||||
function config_mt:get_in(config, key_table)
|
||||
local current_value = config
|
||||
for _, key in ipairs(key_table) do
|
||||
if current_value == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
current_value = current_value[key]
|
||||
end
|
||||
|
||||
return current_value
|
||||
end
|
||||
|
||||
function config_mt:get(key_table)
|
||||
return self:get_in(self.user_config, key_table) or self:get_in(self.default_config, key_table)
|
||||
end
|
||||
|
||||
local config = { user_config = {} }
|
||||
|
||||
config.default_config = {
|
||||
backends = {
|
||||
"ivy.backends.buffers",
|
||||
"ivy.backends.files",
|
||||
"ivy.backends.lines",
|
||||
"ivy.backends.rg",
|
||||
"ivy.backends.lsp-workspace-symbols",
|
||||
},
|
||||
}
|
||||
|
||||
return setmetatable(config, config_mt)
|
||||
27
lua/ivy/config_spec.lua
Normal file
27
lua/ivy/config_spec.lua
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
local config = require "ivy.config"
|
||||
|
||||
describe("config", function()
|
||||
before_each(function()
|
||||
config.user_config = {}
|
||||
end)
|
||||
|
||||
it("gets the first item when there is only default values", function()
|
||||
local first_backend = config:get { "backends", 1 }
|
||||
assert.is_equal("ivy.backends.buffers", first_backend)
|
||||
end)
|
||||
|
||||
it("returns nil if we access a key that is not a valid config item", function()
|
||||
assert.is_nil(config:get { "not", "a", "thing" })
|
||||
end)
|
||||
|
||||
it("returns the users overridden config value", function()
|
||||
config.user_config = { backends = { "ivy.my.backend" } }
|
||||
local first_backend = config:get { "backends", 1 }
|
||||
assert.is_equal("ivy.my.backend", first_backend)
|
||||
end)
|
||||
|
||||
it("returns a nested value", function()
|
||||
config.user_config = { some = { nested = "value" } }
|
||||
assert.is_equal(config:get { "some", "nested" }, "value")
|
||||
end)
|
||||
end)
|
||||
57
lua/ivy/controller_spec.lua
Normal file
57
lua/ivy/controller_spec.lua
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
local window = require "ivy.window"
|
||||
local controller = require "ivy.controller"
|
||||
|
||||
describe("controller", function()
|
||||
before_each(function()
|
||||
vim.cmd "highlight IvyMatch cterm=bold gui=bold"
|
||||
window.initialize()
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
controller.destroy()
|
||||
end)
|
||||
|
||||
it("will run the completion", function()
|
||||
controller.run("Testing", function()
|
||||
return { { content = "Some content" } }
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
-- Run all the scheduled tasks
|
||||
vim.wait(0)
|
||||
|
||||
local lines = vim.api.nvim_buf_get_lines(0, 0, -1, true)
|
||||
assert.is_equal(#lines, 1)
|
||||
assert.is_equal(lines[1], "Some content")
|
||||
end)
|
||||
|
||||
it("will not try and highlight the buffer if there is nothing to highlight", function()
|
||||
spy.on(vim, "cmd")
|
||||
|
||||
controller.items = function()
|
||||
return { { content = "Hello" } }
|
||||
end
|
||||
|
||||
controller.update ""
|
||||
|
||||
vim.wait(0)
|
||||
|
||||
assert.spy(vim.cmd).was_called_with "syntax clear IvyMatch"
|
||||
assert.spy(vim.cmd).was_not_called_with "syntax match IvyMatch '[H]'"
|
||||
end)
|
||||
|
||||
it("will escape a - when passing it to be highlighted", function()
|
||||
spy.on(vim, "cmd")
|
||||
|
||||
controller.items = function()
|
||||
return { { content = "Hello" } }
|
||||
end
|
||||
|
||||
controller.update "some-file"
|
||||
|
||||
vim.wait(0)
|
||||
|
||||
assert.spy(vim.cmd).was_called_with "syntax match IvyMatch '[some\\-file]'"
|
||||
end)
|
||||
end)
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
local vim_mock = require "ivy.vim_mock"
|
||||
local window = require "ivy.window"
|
||||
local controller = require "ivy.controller"
|
||||
|
||||
-- The number of the mock buffer where all the test completions gets put
|
||||
local buffer_number = 10
|
||||
|
||||
before_each(function()
|
||||
vim_mock.reset()
|
||||
window.initialize()
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
controller.destroy()
|
||||
end)
|
||||
|
||||
it("will run", function(t)
|
||||
controller.run("Testing", function()
|
||||
return { { content = "Some content" } }
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
local lines = vim_mock.get_lines()
|
||||
local completion_lines = lines[buffer_number]
|
||||
|
||||
t.assert_equal(#completion_lines, 1)
|
||||
t.assert_equal(completion_lines[1], "Some content")
|
||||
end)
|
||||
|
||||
it("will not try and highlight the buffer if there is nothing to highlight", function(t)
|
||||
controller.items = function()
|
||||
return { { content = "Hello" } }
|
||||
end
|
||||
|
||||
controller.update ""
|
||||
local commands = vim_mock.get_commands()
|
||||
t.assert_equal(#commands, 1)
|
||||
end)
|
||||
|
||||
it("will escape a - when passing it to be highlighted", function(t)
|
||||
controller.items = function()
|
||||
return { { content = "Hello" } }
|
||||
end
|
||||
|
||||
controller.update "some-file"
|
||||
local commands = vim_mock.get_commands()
|
||||
local syntax_command = commands[2]
|
||||
|
||||
t.assert_equal("syntax match IvyMatch '[some\\-file]'", syntax_command)
|
||||
end)
|
||||
32
lua/ivy/init.lua
Normal file
32
lua/ivy/init.lua
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
local controller = require "ivy.controller"
|
||||
local config = require "ivy.config"
|
||||
local register_backend = require "ivy.register_backend"
|
||||
|
||||
local ivy = {}
|
||||
ivy.run = controller.run
|
||||
ivy.register_backend = register_backend
|
||||
|
||||
-- Private variable to check if ivy has been setup, this is to prevent multiple
|
||||
-- setups of ivy. This is only exposed for testing purposes.
|
||||
---@private
|
||||
ivy.has_setup = false
|
||||
|
||||
---@class IvySetupOptions
|
||||
---@field backends (IvyBackend | { ["1"]: string, ["2"]: IvyBackendOptions} | string)[]
|
||||
|
||||
---@param user_config IvySetupOptions
|
||||
function ivy.setup(user_config)
|
||||
if ivy.has_setup then
|
||||
return
|
||||
end
|
||||
|
||||
config.user_config = user_config or {}
|
||||
|
||||
for _, backend in ipairs(config:get { "backends" } or {}) do
|
||||
register_backend(backend)
|
||||
end
|
||||
|
||||
ivy.has_setup = true
|
||||
end
|
||||
|
||||
return ivy
|
||||
30
lua/ivy/init_spec.lua
Normal file
30
lua/ivy/init_spec.lua
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
local ivy = require "ivy"
|
||||
local config = require "ivy.config"
|
||||
|
||||
describe("ivy.setup", function()
|
||||
before_each(function()
|
||||
ivy.has_setup = false
|
||||
config.user_config = {}
|
||||
end)
|
||||
|
||||
it("sets the users config options", function()
|
||||
ivy.setup { backends = { "ivy.backends.files" } }
|
||||
assert.is_equal("ivy.backends.files", config:get { "backends", 1 })
|
||||
end)
|
||||
|
||||
it("will not reconfigure if its called twice", function()
|
||||
ivy.setup { backends = { "ivy.backends.files" } }
|
||||
ivy.setup { backends = { "some.backend" } }
|
||||
assert.is_equal("ivy.backends.files", config:get { "backends", 1 })
|
||||
end)
|
||||
|
||||
it("does not crash if you don't pass in any params to the setup function", function()
|
||||
ivy.setup()
|
||||
assert.is_equal("ivy.backends.buffers", config:get { "backends", 1 })
|
||||
end)
|
||||
|
||||
it("will fallback if the key is not set at all in the users config", function()
|
||||
ivy.setup { some_key = "some_value" }
|
||||
assert.is_equal("ivy.backends.buffers", config:get { "backends", 1 })
|
||||
end)
|
||||
end)
|
||||
36
lua/ivy/libivy_spec.lua
Normal file
36
lua/ivy/libivy_spec.lua
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
require "busted.runner"()
|
||||
|
||||
local libivy = require "ivy.libivy"
|
||||
|
||||
describe("libivy", function()
|
||||
it("should run a simple match", function()
|
||||
local score = libivy.ivy_match("term", "I am a serch term")
|
||||
|
||||
assert.is_true(score > 0)
|
||||
end)
|
||||
|
||||
it("should find a dot file", function()
|
||||
local current_dir = libivy.ivy_cwd()
|
||||
local results = libivy.ivy_files(".github/workflows/ci.yml", current_dir)
|
||||
|
||||
assert.is_equal(2, results.length, "Incorrect number of results found")
|
||||
assert.is_equal(".github/workflows/ci.yml", results[2].content, "Invalid matches")
|
||||
end)
|
||||
|
||||
it("will allow you to access the length via the metatable", function()
|
||||
local current_dir = libivy.ivy_cwd()
|
||||
local results = libivy.ivy_files(".github/workflows/ci.yml", current_dir)
|
||||
|
||||
local mt = getmetatable(results)
|
||||
|
||||
assert.is_equal(results.length, mt.__len(results), "The `length` property does not match the __len metamethod")
|
||||
end)
|
||||
|
||||
it("will create an iterator", function()
|
||||
local iter = libivy.ivy_files(".github/workflows/ci.yml", libivy.ivy_cwd())
|
||||
local mt = getmetatable(iter)
|
||||
|
||||
assert.is_equal(type(mt["__index"]), "function")
|
||||
assert.is_equal(type(mt["__len"]), "function")
|
||||
end)
|
||||
end)
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
local libivy = require "ivy.libivy"
|
||||
|
||||
it("should run a simple match", function(t)
|
||||
local score = libivy.ivy_match("term", "I am a serch term")
|
||||
|
||||
if score <= 0 then
|
||||
t.error("Score should not be less than 0 found " .. score)
|
||||
end
|
||||
end)
|
||||
|
||||
it("should find a dot file", function(t)
|
||||
local current_dir = libivy.ivy_cwd()
|
||||
local results = libivy.ivy_files(".github/workflows/ci.yml", current_dir)
|
||||
|
||||
if results.length ~= 2 then
|
||||
t.error("Incorrect number of results found " .. results.length)
|
||||
end
|
||||
|
||||
if results[2].content ~= ".github/workflows/ci.yml" then
|
||||
t.error("Invalid matches: " .. results[2].content)
|
||||
end
|
||||
end)
|
||||
|
||||
it("will allow you to access the length via the metatable", function(t)
|
||||
local current_dir = libivy.ivy_cwd()
|
||||
local results = libivy.ivy_files(".github/workflows/ci.yml", current_dir)
|
||||
|
||||
local mt = getmetatable(results)
|
||||
|
||||
if results.length ~= mt.__len(results) then
|
||||
t.error "The `length` property does not match the __len metamethod"
|
||||
end
|
||||
end)
|
||||
|
||||
it("will create an iterator", function(t)
|
||||
local iter = libivy.ivy_files(".github/workflows/ci.yml", libivy.ivy_cwd())
|
||||
local mt = getmetatable(iter)
|
||||
|
||||
if type(mt["__index"]) ~= "function" then
|
||||
t.error "The iterator does not have an __index metamethod"
|
||||
end
|
||||
|
||||
if type(mt["__len"]) ~= "function" then
|
||||
t.error "The iterator does not have an __len metamethod"
|
||||
end
|
||||
end)
|
||||
29
lua/ivy/matcher_spec.lua
Normal file
29
lua/ivy/matcher_spec.lua
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
local libivy = require "ivy.libivy"
|
||||
|
||||
-- Helper function to test a that string `one` has a higher match score than
|
||||
-- string `two`. If string `one` has a lower score than string `two` a string
|
||||
-- will be returned that can be used in body of an error. If not then `nil` is
|
||||
-- returned and all is good.
|
||||
local match_test = function(term, one, two)
|
||||
local score_one = libivy.ivy_match(term, one)
|
||||
local score_two = libivy.ivy_match(term, two)
|
||||
|
||||
assert.is_true(
|
||||
score_one > score_two,
|
||||
("The score of %s (%d) ranked higher than %s (%d)"):format(one, score_one, two, score_two)
|
||||
)
|
||||
end
|
||||
|
||||
describe("ivy matcher", function()
|
||||
it("should match path separator", function()
|
||||
match_test("file", "some/file.lua", "somefile.lua")
|
||||
end)
|
||||
|
||||
-- it("should match pattern with spaces", function()
|
||||
-- match_test("so fi", "some/file.lua", "somefile.lua")
|
||||
-- end)
|
||||
|
||||
it("should match the start of a string", function()
|
||||
match_test("file", "file.lua", "somefile.lua")
|
||||
end)
|
||||
end)
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
local libivy = require "ivy.libivy"
|
||||
|
||||
-- Helper function to test a that string `one` has a higher match score than
|
||||
-- string `two`. If string `one` has a lower score than string `two` a string
|
||||
-- will be returned that can be used in body of an error. If not then `nil` is
|
||||
-- returned and all is good.
|
||||
local match_test = function(term, one, two)
|
||||
local score_one = libivy.ivy_match(term, one)
|
||||
local score_two = libivy.ivy_match(term, two)
|
||||
|
||||
if score_one < score_two then
|
||||
return one .. " should be ranked higher than " .. two
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
it("sould match path separator", function(t)
|
||||
local result = match_test("file", "some/file.lua", "somefile.lua")
|
||||
if result then
|
||||
t.error(result)
|
||||
end
|
||||
end)
|
||||
|
||||
it("sould match pattern with spaces", function(t)
|
||||
local result = match_test("so fi", "some/file.lua", "somefile.lua")
|
||||
if result then
|
||||
t.error(result)
|
||||
end
|
||||
end)
|
||||
|
||||
it("sould match the start of a string", function(t)
|
||||
local result = match_test("file", "file.lua", "somefile.lua")
|
||||
if result then
|
||||
t.error(result)
|
||||
end
|
||||
end)
|
||||
91
lua/ivy/prompt_spec.lua
Normal file
91
lua/ivy/prompt_spec.lua
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
local prompt = require "ivy.prompt"
|
||||
|
||||
-- Input a list of strings into the prompt
|
||||
local input = function(input_table)
|
||||
for index = 1, #input_table do
|
||||
prompt.input(input_table[index])
|
||||
end
|
||||
end
|
||||
|
||||
describe("prompt", function()
|
||||
before_each(function()
|
||||
prompt.destroy()
|
||||
end)
|
||||
|
||||
it("starts with empty text", function()
|
||||
assert.is_same(prompt.text(), "")
|
||||
end)
|
||||
|
||||
it("can input some text", function()
|
||||
input { "A", "d", "e" }
|
||||
assert.is_same(prompt.text(), "Ade")
|
||||
end)
|
||||
|
||||
it("can delete a char", function()
|
||||
input { "A", "d", "e", "BACKSPACE" }
|
||||
assert.is_same(prompt.text(), "Ad")
|
||||
end)
|
||||
|
||||
it("will reset the text", function()
|
||||
input { "A", "d", "e" }
|
||||
prompt.set "New"
|
||||
assert.is_same(prompt.text(), "New")
|
||||
end)
|
||||
|
||||
it("can move around the a word", function()
|
||||
input { "P", "r", "o", "p", "t", "LEFT", "LEFT", "LEFT", "RIGHT", "m" }
|
||||
assert.is_same(prompt.text(), "Prompt")
|
||||
end)
|
||||
|
||||
it("can delete a word", function()
|
||||
prompt.set "Ade Attwood"
|
||||
input { "DELETE_WORD" }
|
||||
|
||||
assert.is_same(prompt.text(), "Ade ")
|
||||
end)
|
||||
|
||||
it("can delete a word in the middle and leave the cursor at that word", function()
|
||||
prompt.set "Ade middle A"
|
||||
input { "LEFT", "LEFT", "DELETE_WORD", "a" }
|
||||
|
||||
assert.is_same(prompt.text(), "Ade a A")
|
||||
end)
|
||||
|
||||
it("will delete the space and the word if the last word is single space", function()
|
||||
prompt.set "some.thing "
|
||||
input { "DELETE_WORD" }
|
||||
|
||||
assert.is_same(prompt.text(), "some.")
|
||||
end)
|
||||
|
||||
it("will only delete one word from path", function()
|
||||
prompt.set "some/nested/path"
|
||||
input { "DELETE_WORD" }
|
||||
|
||||
assert.is_same(prompt.text(), "some/nested/")
|
||||
end)
|
||||
|
||||
it("will delete tailing space", function()
|
||||
prompt.set "word "
|
||||
input { "DELETE_WORD" }
|
||||
|
||||
assert.is_same(prompt.text(), "")
|
||||
end)
|
||||
|
||||
it("will leave a random space", function()
|
||||
prompt.set "some word "
|
||||
input { "DELETE_WORD" }
|
||||
|
||||
assert.is_same(prompt.text(), "some ")
|
||||
end)
|
||||
|
||||
local special_characters = { ".", "/", "^" }
|
||||
for _, char in ipairs(special_characters) do
|
||||
it(string.format("will stop at a %s", char), function()
|
||||
prompt.set(string.format("key%sValue", char))
|
||||
input { "DELETE_WORD" }
|
||||
|
||||
assert.is_same(prompt.text(), string.format("key%s", char))
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
local prompt = require "ivy.prompt"
|
||||
local vim_mock = require "ivy.vim_mock"
|
||||
|
||||
before_each(function()
|
||||
vim_mock.reset()
|
||||
prompt.destroy()
|
||||
end)
|
||||
|
||||
-- Input a list of strings into the prompt
|
||||
local input = function(input_table)
|
||||
for index = 1, #input_table do
|
||||
prompt.input(input_table[index])
|
||||
end
|
||||
end
|
||||
|
||||
-- Asserts the prompt contains the correct value
|
||||
local assert_prompt = function(t, expected)
|
||||
local text = prompt.text()
|
||||
if text ~= expected then
|
||||
t.error("The prompt text should be '" .. expected .. "' found '" .. text .. "'")
|
||||
end
|
||||
end
|
||||
|
||||
it("starts with empty text", function(t)
|
||||
if prompt.text() ~= "" then
|
||||
t.error "The prompt should start with empty text"
|
||||
end
|
||||
end)
|
||||
|
||||
it("can input some text", function(t)
|
||||
input { "A", "d", "e" }
|
||||
assert_prompt(t, "Ade")
|
||||
end)
|
||||
|
||||
it("can delete a char", function(t)
|
||||
input { "A", "d", "e", "BACKSPACE" }
|
||||
assert_prompt(t, "Ad")
|
||||
end)
|
||||
|
||||
it("will reset the text", function(t)
|
||||
input { "A", "d", "e" }
|
||||
prompt.set "New"
|
||||
assert_prompt(t, "New")
|
||||
end)
|
||||
|
||||
it("can move around the a word", function(t)
|
||||
input { "P", "r", "o", "p", "t", "LEFT", "LEFT", "LEFT", "RIGHT", "m" }
|
||||
assert_prompt(t, "Prompt")
|
||||
end)
|
||||
|
||||
it("can delete a word", function(t)
|
||||
prompt.set "Ade Attwood"
|
||||
input { "DELETE_WORD" }
|
||||
assert_prompt(t, "Ade ")
|
||||
end)
|
||||
|
||||
it("can delete a word in the middle", function(t)
|
||||
prompt.set "Ade middle A"
|
||||
input { "LEFT", "LEFT", "DELETE_WORD" }
|
||||
assert_prompt(t, "Ade A")
|
||||
end)
|
||||
|
||||
it("will delete the space and the word if the last word is single space", function(t)
|
||||
prompt.set "some.thing "
|
||||
input { "DELETE_WORD" }
|
||||
assert_prompt(t, "some.")
|
||||
end)
|
||||
|
||||
it("will only delete one word from path", function(t)
|
||||
prompt.set "some/nested/path"
|
||||
input { "DELETE_WORD" }
|
||||
assert_prompt(t, "some/nested/")
|
||||
end)
|
||||
|
||||
it("will delete tailing space", function(t)
|
||||
prompt.set "word "
|
||||
input { "DELETE_WORD" }
|
||||
assert_prompt(t, "")
|
||||
end)
|
||||
|
||||
it("will leave a random space", function(t)
|
||||
prompt.set "some word "
|
||||
input { "DELETE_WORD" }
|
||||
assert_prompt(t, "some ")
|
||||
end)
|
||||
|
||||
local special_characters = { ".", "/", "^" }
|
||||
for _, char in ipairs(special_characters) do
|
||||
it(string.format("will stop at a %s", char), function(t)
|
||||
prompt.set(string.format("key%sValue", char))
|
||||
input { "DELETE_WORD" }
|
||||
assert_prompt(t, string.format("key%s", char))
|
||||
end)
|
||||
end
|
||||
54
lua/ivy/register_backend.lua
Normal file
54
lua/ivy/register_backend.lua
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
---@class IvyBackend
|
||||
---@field command string The command this backend will have
|
||||
---@field items fun(input: string): { content: string }[] | string The callback function to get the items to select from
|
||||
---@field callback fun(result: string, action: string) The callback function to run when a item is selected
|
||||
---@field description string? The description of the backend, this will be used in the keymaps
|
||||
---@field name string? The name of the backend, this will fallback to the command if its not set
|
||||
---@field keymap string? The keymap to trigger this backend
|
||||
|
||||
---@class IvyBackendOptions
|
||||
---@field command string The command this backend will have
|
||||
---@field keymap string? The keymap to trigger this backend
|
||||
|
||||
---Register a new backend
|
||||
---
|
||||
---This will create all the commands and set all the keymaps for the backend
|
||||
---@param backend IvyBackend
|
||||
local register_backend_class = function(backend)
|
||||
local user_command_options = { bang = true }
|
||||
if backend.description ~= nil then
|
||||
user_command_options.desc = backend.description
|
||||
end
|
||||
|
||||
local name = backend.name or backend.command
|
||||
vim.api.nvim_create_user_command(backend.command, function()
|
||||
vim.ivy.run(name, backend.items, backend.callback)
|
||||
end, user_command_options)
|
||||
|
||||
if backend.keymap ~= nil then
|
||||
vim.api.nvim_set_keymap("n", backend.keymap, "<cmd>" .. backend.command .. "<CR>", { nowait = true, silent = true })
|
||||
end
|
||||
end
|
||||
|
||||
---@param backend IvyBackend | { ["1"]: string, ["2"]: IvyBackendOptions} | string The backend or backend module
|
||||
---@param options IvyBackendOptions? The options for the backend, that will be merged with the backend
|
||||
local register_backend = function(backend, options)
|
||||
if type(backend[1]) == "string" then
|
||||
options = backend[2]
|
||||
backend = require(backend[1])
|
||||
end
|
||||
|
||||
if type(backend) == "string" then
|
||||
backend = require(backend)
|
||||
end
|
||||
|
||||
if options then
|
||||
for key, value in pairs(options) do
|
||||
backend[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
register_backend_class(backend)
|
||||
end
|
||||
|
||||
return register_backend
|
||||
71
lua/ivy/register_backend_spec.lua
Normal file
71
lua/ivy/register_backend_spec.lua
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
local register_backend = require "ivy.register_backend"
|
||||
|
||||
local function get_command(name)
|
||||
local command_iter = vim.api.nvim_get_commands {}
|
||||
|
||||
for _, cmd in pairs(command_iter) do
|
||||
if cmd.name == name then
|
||||
return cmd
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function get_keymap(mode, rhs)
|
||||
local keymap_iter = vim.api.nvim_get_keymap(mode)
|
||||
for _, keymap in pairs(keymap_iter) do
|
||||
if keymap.rhs == rhs then
|
||||
return keymap
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
describe("register_backend", function()
|
||||
after_each(function()
|
||||
vim.api.nvim_del_user_command "IvyFd"
|
||||
|
||||
local keymap = get_keymap("n", "<Cmd>IvyFd<CR>")
|
||||
if keymap then
|
||||
vim.api.nvim_del_keymap("n", keymap.lhs)
|
||||
end
|
||||
end)
|
||||
|
||||
it("registers a backend from a string with the default options", function()
|
||||
register_backend "ivy.backends.files"
|
||||
|
||||
local command = get_command "IvyFd"
|
||||
assert.is_not_nil(command)
|
||||
|
||||
local keymap = get_keymap("n", "<Cmd>IvyFd<CR>")
|
||||
assert.is_not_nil(keymap)
|
||||
end)
|
||||
|
||||
it("allows you to override the keymap", function()
|
||||
register_backend("ivy.backends.files", { keymap = "<C-p>" })
|
||||
|
||||
local keymap = get_keymap("n", "<Cmd>IvyFd<CR>")
|
||||
assert(keymap ~= nil)
|
||||
assert.are.equal("<C-P>", keymap.lhs)
|
||||
end)
|
||||
|
||||
it("allows you to pass in a hole backend module", function()
|
||||
register_backend(require "ivy.backends.files")
|
||||
|
||||
local command = get_command "IvyFd"
|
||||
assert.is_not_nil(command)
|
||||
|
||||
local keymap = get_keymap("n", "<Cmd>IvyFd<CR>")
|
||||
assert.is_not_nil(keymap)
|
||||
end)
|
||||
|
||||
it("allows you to pass in a hole backend module", function()
|
||||
register_backend { "ivy.backends.files", { keymap = "<C-p>" } }
|
||||
|
||||
local keymap = get_keymap("n", "<Cmd>IvyFd<CR>")
|
||||
assert(keymap ~= nil)
|
||||
assert.are.equal("<C-P>", keymap.lhs)
|
||||
end)
|
||||
end)
|
||||
|
|
@ -99,7 +99,9 @@ end
|
|||
utils.line_action = function()
|
||||
return function(item)
|
||||
local line = item:match "^%s+(%d+):"
|
||||
vim.cmd(line)
|
||||
if line ~= nil then
|
||||
vim.cmd(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
11
lua/ivy/utils_escape_spec.lua
Normal file
11
lua/ivy/utils_escape_spec.lua
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
local utils = require "ivy.utils"
|
||||
|
||||
it("will escape a dollar in the file name", function()
|
||||
local result = utils.escape_file_name "/path/to/$file/$name.lua"
|
||||
assert.is_same(result, "/path/to/\\$file/\\$name.lua")
|
||||
end)
|
||||
|
||||
it("will escape a brackets in the file name", function()
|
||||
local result = utils.escape_file_name "/path/to/[file]/[name].lua"
|
||||
assert.is_same(result, "/path/to/\\[file\\]/\\[name\\].lua")
|
||||
end)
|
||||
28
lua/ivy/utils_line_action_spec.lua
Normal file
28
lua/ivy/utils_line_action_spec.lua
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
local utils = require "ivy.utils"
|
||||
local line_action = utils.line_action()
|
||||
|
||||
describe("utils line_action", function()
|
||||
before_each(function()
|
||||
spy.on(vim, "cmd")
|
||||
end)
|
||||
|
||||
it("will run the line command", function()
|
||||
line_action " 4: Some text"
|
||||
|
||||
assert.is_equal(#vim.cmd.calls, 1, "The `vim.cmd` function should be called once")
|
||||
assert.spy(vim.cmd).was_called_with "4"
|
||||
end)
|
||||
|
||||
it("will run with more numbers", function()
|
||||
line_action " 44: Some text"
|
||||
|
||||
assert.is_equal(#vim.cmd.calls, 1, "The `vim.cmd` function should be called once")
|
||||
assert.spy(vim.cmd).was_called_with "44"
|
||||
end)
|
||||
|
||||
it("dose not run any action if no line is found", function()
|
||||
line_action "Some text"
|
||||
|
||||
assert.spy(vim.cmd).was_not_called()
|
||||
end)
|
||||
end)
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
local utils = require "ivy.utils"
|
||||
local line_action = utils.line_action()
|
||||
local vim_mock = require "ivy.vim_mock"
|
||||
|
||||
before_each(function()
|
||||
vim_mock.reset()
|
||||
end)
|
||||
|
||||
it("will run the line command", function(t)
|
||||
line_action " 4: Some text"
|
||||
|
||||
if #vim_mock.commands ~= 1 then
|
||||
t.error "`line_action` command length should be 1"
|
||||
end
|
||||
|
||||
if vim_mock.commands[1] ~= "4" then
|
||||
t.error "`line_action` command should be 4"
|
||||
end
|
||||
end)
|
||||
|
||||
it("will run with more numbers", function(t)
|
||||
line_action " 44: Some text"
|
||||
|
||||
if #vim_mock.commands ~= 1 then
|
||||
t.error "`line_action` command length should be 1"
|
||||
end
|
||||
|
||||
if vim_mock.commands[1] ~= "44" then
|
||||
t.error "`line_action` command should be 44"
|
||||
end
|
||||
end)
|
||||
|
||||
it("dose not run any action if no line is found", function(t)
|
||||
line_action "Some text"
|
||||
|
||||
if #vim_mock.commands ~= 0 then
|
||||
t.error "`line_action` command length should be 1"
|
||||
end
|
||||
end)
|
||||
|
|
@ -1,10 +1,5 @@
|
|||
local utils = require "ivy.utils"
|
||||
local vimgrep_action = utils.vimgrep_action()
|
||||
local vim_mock = require "ivy.vim_mock"
|
||||
|
||||
before_each(function()
|
||||
vim_mock.reset()
|
||||
end)
|
||||
|
||||
local test_data = {
|
||||
{
|
||||
|
|
@ -20,37 +15,42 @@ local test_data = {
|
|||
it = "will skip the line if its not matched",
|
||||
completion = "some/file.lua: This is some text",
|
||||
action = utils.actions.EDIT,
|
||||
commands = { "edit some/file.lua" },
|
||||
commands = { "buffer some/file.lua" },
|
||||
},
|
||||
{
|
||||
it = "will run the vsplit command",
|
||||
completion = "some/file.lua: This is some text",
|
||||
action = utils.actions.VSPLIT,
|
||||
commands = { "vsplit some/file.lua" },
|
||||
commands = { "vsplit | buffer some/file.lua" },
|
||||
},
|
||||
{
|
||||
it = "will run the split command",
|
||||
completion = "some/file.lua: This is some text",
|
||||
action = utils.actions.SPLIT,
|
||||
commands = { "split some/file.lua" },
|
||||
commands = { "split | buffer some/file.lua" },
|
||||
},
|
||||
}
|
||||
|
||||
for i = 1, #test_data do
|
||||
local data = test_data[i]
|
||||
it(data.it, function(t)
|
||||
vimgrep_action(data.completion, data.action)
|
||||
|
||||
if #vim_mock.commands ~= #data.commands then
|
||||
t.error("Incorrect number of commands run expected " .. #data.commands .. " but found " .. #vim_mock.commands)
|
||||
end
|
||||
|
||||
for j = 1, #data.commands do
|
||||
if vim_mock.commands[j] ~= data.commands[j] then
|
||||
t.error(
|
||||
"Incorrect command run expected '" .. data.commands[j] .. "' but found '" .. vim_mock.commands[j] .. "'"
|
||||
)
|
||||
end
|
||||
end
|
||||
describe("utils vimgrep_action", function()
|
||||
before_each(function()
|
||||
spy.on(vim, "cmd")
|
||||
end)
|
||||
end
|
||||
|
||||
after_each(function()
|
||||
vim.cmd:revert()
|
||||
end)
|
||||
|
||||
for i = 1, #test_data do
|
||||
local data = test_data[i]
|
||||
it(data.it, function()
|
||||
assert.is_true(#data.commands > 0, "You must assert that at least one command is run")
|
||||
|
||||
vimgrep_action(data.completion, data.action)
|
||||
assert.is_equal(#vim.cmd.calls, #data.commands, "The `vim.cmd` function should be called once")
|
||||
|
||||
for j = 1, #data.commands do
|
||||
assert.spy(vim.cmd).was_called_with(data.commands[j])
|
||||
end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
32
lua/ivy/window_spec.lua
Normal file
32
lua/ivy/window_spec.lua
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
local window = require "ivy.window"
|
||||
local controller = require "ivy.controller"
|
||||
|
||||
describe("window", function()
|
||||
before_each(function()
|
||||
vim.cmd "highlight IvyMatch cterm=bold gui=bold"
|
||||
window.initialize()
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
controller.destroy()
|
||||
end)
|
||||
|
||||
it("can initialize and destroy the window", function()
|
||||
assert.is_equal(vim.api.nvim_get_current_buf(), window.buffer)
|
||||
|
||||
window.destroy()
|
||||
assert.is_equal(nil, window.buffer)
|
||||
end)
|
||||
|
||||
it("can set items", function()
|
||||
window.set_items { { content = "Line one" } }
|
||||
assert.is_equal("Line one", window.get_current_selection())
|
||||
end)
|
||||
|
||||
it("will set the items when a string is passed in", function()
|
||||
local items = table.concat({ "One", "Two", "Three" }, "\n")
|
||||
window.set_items(items)
|
||||
|
||||
assert.is_equal(items, table.concat(vim.api.nvim_buf_get_lines(window.buffer, 0, -1, true), "\n"))
|
||||
end)
|
||||
end)
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
local vim_mock = require "ivy.vim_mock"
|
||||
local window = require "ivy.window"
|
||||
|
||||
before_each(function()
|
||||
vim_mock.reset()
|
||||
end)
|
||||
|
||||
it("can initialize and destroy the window", function(t)
|
||||
window.initialize()
|
||||
|
||||
t.assert_equal(10, window.get_buffer())
|
||||
t.assert_equal(10, window.buffer)
|
||||
|
||||
window.destroy()
|
||||
t.assert_equal(nil, window.buffer)
|
||||
end)
|
||||
|
||||
it("can set items", function(t)
|
||||
window.initialize()
|
||||
|
||||
window.set_items { { content = "Line one" } }
|
||||
t.assert_equal("Line one", window.get_current_selection())
|
||||
end)
|
||||
|
||||
it("will set the items when a string is passed in", function(t)
|
||||
window.initialize()
|
||||
|
||||
local items = table.concat({ "One", "Two", "Three" }, "\n")
|
||||
window.set_items(items)
|
||||
|
||||
local lines = table.concat(vim_mock.get_lines()[window.buffer], "\n")
|
||||
t.assert_equal(items, lines)
|
||||
end)
|
||||
|
|
@ -5,26 +5,6 @@ local controller = require "ivy.controller"
|
|||
-- luacheck: ignore
|
||||
vim.ivy = controller
|
||||
|
||||
local register_backend = function(backend)
|
||||
assert(backend.command, "The backend must have a command")
|
||||
assert(backend.items, "The backend must have a items function")
|
||||
assert(backend.callback, "The backend must have a callback function")
|
||||
|
||||
local user_command_options = { bang = true }
|
||||
if backend.description ~= nil then
|
||||
user_command_options.desc = backend.description
|
||||
end
|
||||
|
||||
local name = backend.name or backend.command
|
||||
vim.api.nvim_create_user_command(backend.command, function()
|
||||
vim.ivy.run(name, backend.items, backend.callback)
|
||||
end, user_command_options)
|
||||
|
||||
if backend.keymap ~= nil then
|
||||
vim.api.nvim_set_keymap("n", backend.keymap, "<cmd>" .. backend.command .. "<CR>", { nowait = true, silent = true })
|
||||
end
|
||||
end
|
||||
|
||||
vim.paste = (function(overridden)
|
||||
return function(lines, phase)
|
||||
local file_type = vim.api.nvim_buf_get_option(0, "filetype")
|
||||
|
|
@ -36,15 +16,4 @@ vim.paste = (function(overridden)
|
|||
end
|
||||
end)(vim.paste)
|
||||
|
||||
register_backend(require "ivy.backends.buffers")
|
||||
register_backend(require "ivy.backends.files")
|
||||
register_backend(require "ivy.backends.lines")
|
||||
register_backend(require "ivy.backends.lsp-workspace-symbols")
|
||||
|
||||
if vim.fn.executable "rg" then
|
||||
register_backend(require "ivy.backends.rg")
|
||||
elseif vim.fn.executable "ag" then
|
||||
register_backend(require "ivy.backends.ag")
|
||||
end
|
||||
|
||||
vim.cmd "highlight IvyMatch cterm=bold gui=bold"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,11 @@ pub fn find_files(options: Options) -> Vec<String> {
|
|||
builder.overrides(overrides);
|
||||
|
||||
for result in builder.build() {
|
||||
let absolute_candidate = result.unwrap();
|
||||
let absolute_candidate = match result {
|
||||
Ok(absolute_candidate) => absolute_candidate,
|
||||
Err(..) => continue,
|
||||
};
|
||||
|
||||
let candidate_path = absolute_candidate.path().strip_prefix(base_path).unwrap();
|
||||
if candidate_path.is_dir() {
|
||||
continue;
|
||||
|
|
|
|||
8
scripts/busted.lua
Executable file
8
scripts/busted.lua
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
-- Script to run the busted cli tool. You can use this under nvim using be
|
||||
-- below command. Any arguments can be passed in the same as the busted cli.
|
||||
--
|
||||
-- ```bash
|
||||
-- nvim -l scripts/busted.lua
|
||||
-- ```
|
||||
vim.opt.rtp:append(vim.fn.getcwd())
|
||||
require "busted.runner" { standalone = false }
|
||||
Loading…
Reference in a new issue