Compare commits

...

31 commits

Author SHA1 Message Date
renovate[bot]
67ca10505d chore(deps): update practically/conventional-tools:1.x
All checks were successful
CI / StyLua (push) Successful in 39s
CI / Luacheck (push) Successful in 57s
CI / Cargo Format (push) Successful in 1m3s
Conventional Tools Commitlint / Commitlint (push) Successful in 1m45s
CI / Build and test (push) Successful in 3m51s
Update the docker digest to a3e9869
2024-12-14 13:53:03 +00:00
16a791e8a6 chore: update dependencies
All checks were successful
CI / Luacheck (pull_request) Successful in 47s
CI / StyLua (pull_request) Successful in 41s
CI / Cargo Format (pull_request) Successful in 1m8s
Conventional Tools Commitlint / Commitlint (pull_request) Successful in 25s
CI / Build and test (pull_request) Successful in 4m42s
CI / StyLua (push) Successful in 34s
CI / Luacheck (push) Successful in 47s
CI / Cargo Format (push) Successful in 1m0s
Conventional Tools Commitlint / Commitlint (push) Successful in 21s
CI / Build and test (push) Successful in 3m29s
Summary:

run `cargo update`

Test Plan:

CI and manual testing
2024-10-27 18:19:10 +00:00
0f364c140d fix: add no require git to rg command backend
Summary:

When using this backend in a directory that is not a git repository, it will
search though all the file. This is mostly a problem when using an alternative
source control like sapling.

When using this backend neovim will just hang until the rg command is done.
When searching node_modules you can imagine how long that takes. This does not
actually fix the issue however, it does make it search though less files.

Test Plan:

This has been used manually on a sapling repo. I have also added
`--no-require-git` to most of the rg defaults in other applications.
2024-10-27 17:28:54 +00:00
6e45d75a1e feat: allow users to configure the window keymaps
All checks were successful
CI / StyLua (pull_request) Successful in 31s
CI / Luacheck (pull_request) Successful in 52s
CI / Cargo Format (pull_request) Successful in 49s
Conventional Tools Commitlint / Commitlint (pull_request) Successful in 13s
CI / Build and test (pull_request) Successful in 2m50s
CI / StyLua (push) Successful in 44s
CI / Luacheck (push) Successful in 1m4s
CI / Cargo Format (push) Successful in 1m12s
Conventional Tools Commitlint / Commitlint (push) Successful in 17s
CI / Build and test (push) Successful in 6m4s
Summary:

Now you can use the setup configuration to overwrite and override the keymaps
in the ivy window. Each of the actions have now been givin a "key", you can use
the keys to run action on keymaps defined in the config. They will all be
registered in the buffer and run when pressed.

The readme has been updated to document how do this.

Test Plan:

We have the tests that still run. It has been tested manually and gone though
QA before getting merged.
2024-10-27 09:28:33 +00:00
renovate[bot]
cfa7e29ae4 fix(deps): update rust crate ignore to v0.4.23
All checks were successful
CI / Luacheck (push) Successful in 27s
CI / StyLua (push) Successful in 13s
CI / Cargo Format (push) Successful in 21s
CI / Build and test (push) Successful in 1m59s
Conventional Tools Commitlint / Commitlint (push) Successful in 5s
Reviewed By: AdeAttwood
Imported From: https://github.com/AdeAttwood/ivy.nvim/pull/93
2024-09-16 19:49:49 +01:00
ded926a4a6 chore: make public api consistent
All checks were successful
CI / Luacheck (pull_request) Successful in 20s
CI / StyLua (pull_request) Successful in 12s
CI / Cargo Format (pull_request) Successful in 18s
CI / Build and test (pull_request) Successful in 2m2s
Conventional Tools Commitlint / Commitlint (pull_request) Successful in 4s
CI / Luacheck (push) Successful in 22s
CI / StyLua (push) Successful in 12s
CI / Cargo Format (push) Successful in 18s
CI / Build and test (push) Successful in 1m52s
Conventional Tools Commitlint / Commitlint (push) Successful in 5s
Summary:

Right now we have two ways to access the public api we have `require('ivy')`
and `vim.ivy. Each way has a different api that will cause some confusion.

Now both apis are the same so anyone that wants to integrate with ivy can do so
without having to figure out what one they need to use.

Test Plan:

The unit tests cover most of the work, I have also been using this locally for
quite some time now with now issues.
2024-09-03 19:34:17 +01:00
f910955ad1 ci: run stylua via npx rather than via action
All checks were successful
CI / Luacheck (push) Successful in 22s
CI / StyLua (push) Successful in 12s
CI / Cargo Format (push) Successful in 19s
CI / Build and test (push) Successful in 1m50s
Conventional Tools Commitlint / Commitlint (push) Successful in 5s
Summary:

This is so we don't need the GITHUB_TOKEN that can not be added in forgejo. I
am giving it a go and the `GITHUB_` prefix is reserved for secrets. There are
also issues with the action in a forgejo environment due to the API not
resolving to github.

This now should work on both platforms. So we can maintain github compatibility
for any pull requests that may come that way.

Test Plan:

Run the CI on github and forgejo, this will need to be a manual process to
validate this works.

Pull Request: #2
2024-09-03 19:20:09 +01:00
Ádran Farias Carnavale
7efb98baab
docs: installation instructions with mini.deps
This commit introduces a brief guide about how to install this plugin
using the `mini.deps` package manager

ref: https://github.com/echasnovski/mini.deps
2024-07-29 08:55:54 +01:00
ShaolunWang
f3585c8cde feat: support windows
Summary:
Add windows support by checking `dll` instead of `so` or `dylib` on windows in `libivy.lua`

Author: @ShaolunWang
Imported From: https://github.com/AdeAttwood/ivy.nvim/pull/90

Test Plan: None provided provided by the author.

Differential Revision: https://ph.baln.co.uk/D7
2024-07-24 16:32:15 +01:00
fef45c2d7e chore: add script for a quick integration test
Summary:
This is just a little script that will run a search and print out the timings
for each of the searches that ivy will preform.

For example running

```
nvim -l ./scripts/integration.lua /path/to/repo test 2> /dev/null
```

will output

```
t       0.074737
te      0.016494
tes     0.018898
test    0.017214
```

Test Plan:
Does not really require testing, this is a little helper script for
development. If it does not work on another machine then we can cross that
bridge when we come to it.

Reviewers: AdeAttwood

Reviewed By: AdeAttwood

Differential Revision: https://ph.baln.co.uk/D2
2024-07-21 12:06:32 +01:00
57d652cb9d ci: run tests on more versions of nvim
Summary:

Right now we are only running the tests on the nightly build of nvim. I would
like to try and maintain support for a few releases. One of the goals of this
project is to be stable. This means trying our best to maintain BC, for this I
have setup running the tests on older versions of nvim.

Right now we have:

- *nightly* Make sure we support the new releases, we can hopefully fix issues
  before this gets releases.
- *stable* This is the main version we support
- *v0.9.5* Maintain the old stable, some OSs like Ubuntu lack behind, would be
  nice to maintain that.

Test Plan:

CI, I have done a quick run before finalizing the change
2024-07-02 20:50:58 +01:00
e121ba7a9f fix: panic on files you don't have access to
Summary:

When you are in a project that has files the user cannot read, ivy's finder
will panic will a permission denied error. This can quite easily happen when
using docker on a project, it's quite common to mount a directory into a docker
container that is run as a different user I.E. MySQL. The other example I can
think of is when you are running tests in a container, the test output may be
owned by the containers' user.

When running ivy this is an example of the kind of panic you would get.

```
thread '<unnamed>' panicked at rust/finder.rs:34:41:
  called `Result::unwrap()` on an `Err` value: WithPath {
    path: "/tmp/workspace/mysql/#innodb_redo", err: Io(
      Custom {
        kind: PermissionDenied, error: Error {
          depth: 2, inner: Io {
            path: Some("/tmp/workspace/mysql/#innodb_redo"),
            err: Os {
              code: 13,
              kind: PermissionDenied,
              message: "Permission denied"
            }
          }
        }
      }
    )
  }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
fatal runtime error: Rust panics must be rethrown
```

Ref: #83

Test Plan:

This has been tested locally, right now we don't have any unit tests for this.
We may setup some more testing in the future. This was a little hard to
recreate with out docker and mysql.
2024-06-30 15:06:56 +01:00
9af13d0031 docs: add setup config and backends to the readme
Summary:

Now we have a setup function with some config we better tell ppl about it. This
add the setup and config options into the readme.

It also replaces the "Command" with "Backends" to make it a little easier to
understand what needs to be configured. The backend concept has only just been
exposed publicly recently. It now makes since rename this section to line up
with the config.

Test Plan:

N / A
2024-06-30 15:00:56 +01:00
72f3fcac4e docs: remove 'peek' from the docs
Summary:

When we were flushing out the docs, we found some inconsistency in the naming
of checkpoint and peek. They were referring to the same thing.

This removes the word 'peek' in favor of 'checkpoint'

Test Plan:

N / A
2024-06-30 15:00:56 +01:00
a2287f1179 ci: update the test command for better output
Summary:

Now we are running the tests in neovim we get some output printed to stderr.
This is not helpful in the test output, and obfuscate errors.

This throws any unneeded output to `/dev/null` so we can focus of the tests
that have failed. It also moves over to using TAP output for a more descriptive
out put in CI.

Test Plan:

CI, running the test will validate this
2024-06-30 15:00:28 +01:00
Arne Van Maele
611aa54902 feat: add custom keymap section 2024-06-27 21:22:07 +01:00
Arne Van Maele
d19bdc4dfd feat: add keymaps for actions 2024-06-27 21:22:07 +01:00
d6d782b584 feat: setup configuration with default fallbacks
Summary:

Now the users configuration and the default configuration is separated. This
will make it easier to setup ivy with some defaults. Right now we only have the
backends configurable however, it looks like we will be making other components
of ivy configurable.

To use this you can now call `ivy.setup` with no parameters and you will get
the default config. You can also call it with a partial config and if the
option is not found in the users config it will fallback to the users config
value.

Test Plan:

Manual testing and with unit tests in CI
2024-06-27 21:12:37 +01:00
f4d9b67370 feat: implement a setup function
Summary:

Now when using ivy.nvim you will need to call the `setup` function. This will
need to register any backends you want to use. This is an example config, this
can be put into a plugin in `~/.config/nvim/plugin/ivy.lua` for example.

```lua
require('ivy').setup {
  backends = {
    "ivy.backends.buffers",
    "ivy.backends.files",
  },
}
```

If you are using Lazy you can use the `config` directly to call the setup
function.

```lua
return {
  "AdeAttwood/ivy.nvim",
  build = "cargo build --release",
  config = {
    backends = {
      "ivy.backends.buffers",
      "ivy.backends.files",
    }
  }
}
```

The `setup` function can only be called once, if its called a second time any
backends or config will not be used. The module 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")
```

As well as the `register_backend` the core `run`function is exposed. With this
exposed we should be able to build anything we want.

```lua
vim.ivy.run(
  "Title",
  function(input)
    return {
      { content = "One" },
      { content = "Two" },
      { content = "Three" },
    }
  end,
  function(result) vim.cmd("edit " .. result) end
)
```

Test Plan:

Not much to test in this one, it has been tested locally on my config that does
not use any plugin managers, also a sandbox Lazy env using `NVIM_APPNAME`
NVIM_APPNAME
2024-06-27 21:12:37 +01:00
91b6db9d76 feat: split out register backend so it can be used as an external API
Summary:

Split out the register backend function from being a private function. A
backend is a table that will define all of the attributes for a run function.
The attributes are as follows:

- **command** The name of the command that will be registered as a vim user command.
- **items** The callback function that will be passed to the run function that will gather the items for selection
- **callback** The callback function run when an item is selected

The following are optional:

- **keymap** The string passed to `nvim_set_keymap`, this will always be registered in normal mode
- **description** The text description that will be used in the user command
- **name** The name of the backend, this will fallback to the command if its not set

It will also allow to register a backend in a couple of different ways:

- With a backend module table
- With a backend module name
- With a backend module name and override options

This will look for for a lua module `ivy.backends.files`. The module will be
required and registered as a backend.

```lua
register_backend "ivy.backends.files"
```

This will do the same with the module string however, before the backend is
registered the keymap will be overridden

```lua
register_backend({ "ivy.backends.file", { keymap = "<C-p>" } })
```

Test Plan:

CI / Manual testing locally
2024-06-27 21:12:37 +01:00
4803045d4e test: remove all the old tests
Summary:

Removes all the old tests that are not using busted. They have now been
replaced with the busted ones.

Test Plan:

CI
2024-06-16 17:23:45 +01:00
cb4f5860ef ci: setup the new tests in github actions
Summary:

This runs the new tests in our existing CI. We will remove the old tests later
when we know everything runs together so we know everything works.

Test Plan:

CI
2024-06-16 17:17:16 +01:00
37cad71291 test: move the suite over to busted
Summary:

Right now we are using a custom test runner. This move the suite over to
busted, this will make things much more maintainable going forward. The two
main reasons for moving are.

1) The custom runner as some bugs, when running assertions we are not getting
the correct results.

2) All of the busted mocking features. We can use spy and mock, this will allow
us to remove the nvim_mock. This file is not amazing and confuses the lsp
often.

Test Plan:

CI
2024-06-16 17:17:16 +01:00
Arne Van Maele
d7b368355f feat: add Lazy.nvim installation to the readme 2024-06-12 07:40:11 +01:00
renovate[bot]
829bb008b8 fix(deps): update rust crate rayon to 1.10.0 2024-03-25 08:48:35 +00:00
renovate[bot]
6ffdb7795a fix(deps): update rust crate rayon to 1.9.0 2024-02-28 09:21:29 +00:00
cf3e7e3044 fix: opening file with square brackets in them
Summary:

Fixes an issue where you could not open files that were already open with ivy.
If the file path contains a square brackets and that file is already loaded
into a buffer, ivy will throw an error when trying to open it via "files" or
"buffers".

This is an issue with the file escaping before we try and cal `buffer` passing
in the file path to go to the buffer rather than open a new buffer.

This is common with JS frameworks like next js for parameters in file based
routing.

Test Plan:

Test have been added for this change. I have also added tests for the dollar
that was previously handled.
2024-02-13 09:27:09 +00:00
renovate[bot]
6dd5323380 chore(deps): update johnnymorganz/stylua-action action to v4 2024-02-13 09:26:58 +00:00
c32698cf25 feat: don't search in sapling source control directories
This file should be treated as the .git dir and not show up in the candidates
list for files.
2024-01-17 21:15:24 +00:00
renovate[bot]
e5f00bfb1e fix(deps): update rust crate rayon to 1.8.1 2024-01-17 21:14:17 +00:00
7ecc6f1226 feat: don't require a git directory to use .gitignore files
When we are searching we don't want to have to initialize git repo to use a
.gitignore file. This should just ignore any file in a .gitignore always
2024-01-17 21:02:27 +00:00
35 changed files with 996 additions and 665 deletions

View file

@ -29,11 +29,7 @@ jobs:
uses: actions/checkout@v4
- name: Run stylua
uses: JohnnyMorganz/stylua-action@v3.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
version: latest
args: --check .
run: npx @johnnymorganz/stylua-bin --check .
cargo-format:
name: Cargo Format
@ -52,6 +48,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 +60,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

View file

@ -8,7 +8,7 @@ jobs:
commits:
name: Commitlint
runs-on: ubuntu-latest
container: practically/conventional-tools:1.x@sha256:647d6e4b3edfcbac6054b90f74d2c61a022152751b94484d54e13695a9e27377
container: practically/conventional-tools:1.x@sha256:a3e98697743d8801c694b92553da733aff0fbae6bf92876b13c92343a569f049
steps:
- name: Checkout
uses: actions/checkout@v4

View file

@ -10,9 +10,12 @@ self = false
read_globals = {
"vim",
"it",
"after",
"after_each",
"assert",
"before",
"before_each",
"describe",
"it",
"spy",
}

415
Cargo.lock generated
View file

@ -4,9 +4,9 @@ version = 3
[[package]]
name = "aho-corasick"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
@ -19,27 +19,21 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstyle"
version = "1.0.0"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56"
[[package]]
name = "autocfg"
version = "1.1.0"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bstr"
version = "1.8.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
dependencies = [
"memchr",
"serde",
@ -47,9 +41,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.11.0"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "cast"
@ -57,12 +51,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -71,9 +59,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "ciborium"
version = "0.2.0"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f"
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
dependencies = [
"ciborium-io",
"ciborium-ll",
@ -82,15 +70,15 @@ dependencies = [
[[package]]
name = "ciborium-io"
version = "0.2.0"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369"
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
[[package]]
name = "ciborium-ll"
version = "0.2.0"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b"
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
dependencies = [
"ciborium-io",
"half",
@ -98,29 +86,28 @@ dependencies = [
[[package]]
name = "clap"
version = "4.3.0"
version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc"
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.3.0"
version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990"
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
dependencies = [
"anstyle",
"bitflags",
"clap_lex",
]
[[package]]
name = "clap_lex"
version = "0.5.0"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "criterion"
@ -160,65 +147,40 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.10"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"once_cell",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.11"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
dependencies = [
"cfg-if",
"once_cell",
]
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "either"
version = "1.8.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "errno"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "fuzzy-matcher"
@ -231,34 +193,38 @@ dependencies = [
[[package]]
name = "globset"
version = "0.4.14"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19"
dependencies = [
"aho-corasick",
"bstr",
"log",
"regex-automata",
"regex-syntax 0.8.2",
"regex-syntax",
]
[[package]]
name = "half"
version = "1.8.2"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
dependencies = [
"cfg-if",
"crunchy",
]
[[package]]
name = "hermit-abi"
version = "0.3.1"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
[[package]]
name = "ignore"
version = "0.4.22"
version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
dependencies = [
"crossbeam-deque",
"globset",
@ -271,42 +237,30 @@ dependencies = [
]
[[package]]
name = "io-lifetimes"
version = "1.0.11"
name = "is-terminal"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
dependencies = [
"hermit-abi",
"libc",
"windows-sys",
]
[[package]]
name = "is-terminal"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
name = "itertools"
version = "0.10.4"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8bf247779e67a9082a4790b45e71ac7cfd1321331a5c856a74a9faebdab78d0"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.3"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "ivy"
@ -320,72 +274,57 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.60"
version = "0.3.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.144"
version = "0.2.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
[[package]]
name = "log"
version = "0.4.20"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "memchr"
version = "2.6.4"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "num-traits"
version = "0.2.15"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.14.0"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "oorandom"
version = "11.1.3"
version = "11.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
[[package]]
name = "plotters"
version = "0.3.4"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97"
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
dependencies = [
"num-traits",
"plotters-backend",
@ -396,42 +335,42 @@ dependencies = [
[[package]]
name = "plotters-backend"
version = "0.3.4"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
[[package]]
name = "plotters-svg"
version = "0.3.3"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f"
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
dependencies = [
"plotters-backend",
]
[[package]]
name = "proc-macro2"
version = "1.0.43"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
version = "1.8.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
@ -439,9 +378,9 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.12.0"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
@ -449,55 +388,38 @@ dependencies = [
[[package]]
name = "regex"
version = "1.6.0"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"regex-syntax 0.6.27",
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.8.2",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.27"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rustix"
version = "0.37.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
]
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "ryu"
version = "1.0.11"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "same-file"
@ -508,26 +430,20 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.144"
version = "1.0.213"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.144"
version = "1.0.213"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5"
dependencies = [
"proc-macro2",
"quote",
@ -536,20 +452,21 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.85"
version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "1.0.99"
version = "2.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
dependencies = [
"proc-macro2",
"quote",
@ -558,10 +475,11 @@ dependencies = [
[[package]]
name = "thread_local"
version = "1.1.4"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if",
"once_cell",
]
@ -577,15 +495,15 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.4"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "walkdir"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
@ -593,19 +511,20 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.83"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
dependencies = [
"cfg-if",
"once_cell",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.83"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
dependencies = [
"bumpalo",
"log",
@ -618,9 +537,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.83"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -628,9 +547,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.83"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
dependencies = [
"proc-macro2",
"quote",
@ -641,69 +560,57 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.83"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
[[package]]
name = "web-sys"
version = "0.3.60"
version = "0.3.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"winapi",
"windows-sys 0.59.0",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
@ -712,42 +619,48 @@ dependencies = [
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View file

@ -11,7 +11,7 @@ path = "rust/lib.rs"
[dependencies]
ignore = "0.4.22"
fuzzy-matcher = "0.3.7"
rayon = "1.8.0"
rayon = "1.10.0"
[dev-dependencies]
criterion = "0.5.1"

131
README.md
View file

@ -20,7 +20,90 @@ 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",
},
```
Using [mini.deps](https://github.com/echasnovski/mini.deps)
```lua
local deps = require "mini.deps"
deps.later(function() -- Or `deps.now` if you want this to be loaded immediately
local build = function(args)
local obj = vim
.system(
{ "cargo", "build", "--release", string.format("%s%s%s", "--manifest-path=", args.path, "/Cargo.toml") },
{ text = true }
)
:wait()
vim.print(vim.inspect(obj))
end
deps.add {
source = "AdeAttwood/ivy.nvim",
hooks = {
post_install = build,
post_checkout = build,
},
}
end)
```
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>" } },
},
-- Set mappings of your own, you can use the action `key` to define the
-- action you want.
mappings = {
["<CR>"] = "complete"
}
}
```
When defining config overrides in the setup function, this will overwrite any
default config, not merge it. To merge the configuration you can use the
`vim.tbl_extend` use the default configuration and add any extra.
```lua
require("ivy").setup {
mappings = vim.tbl_extend("force", config:get { "mappings" }, {
["<esc>"] = "destroy",
}),
}
```
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 +139,38 @@ 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 | Default 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 | Default Key Map | Description |
| ------------------- | --------------------- | --------------- | ---------------------------------------------------------------- |
| Complete | `complete` | \<CR\> | Run the completion function, usually this will be opening a file |
| Vertical Split | `vsplit` | \<C-v\> | Run the completion function in a new vertical split |
| Split | `split` | \<C-s\> | Run the completion function in a new split |
| Destroy | `destroy` | \<C-c\> | Close the results window |
| Clear | `clear` | \<C-u\> | Clear the results window |
| Delete word | `delete_word` | \<C-w\> | Delete the word under the cursor |
| Next | `next` | \<C-n\> | Move to the next candidate |
| Previous | `previous` | \<C-p\> | Move to the previous candidate |
| Next Checkpoint | `next_checkpoint` | \<C-M-n\> | Move to the next candidate and keep Ivy open and focussed |
| Previous Checkpoint | `previous_checkpoint` | \<C-M-n\> | Move to the previous candidate and keep Ivy open and focussed |
## API
@ -130,9 +223,11 @@ 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
function(result)
vim.cmd("edit " .. result)
end
)
```

View file

@ -5,7 +5,7 @@ local rg = {
command = "IvyRg",
description = "Run ripgrep to search for content in files",
keymap = "<leader>/",
items = utils.command_finder "rg --vimgrep --",
items = utils.command_finder "rg --no-require-git --max-columns 200 --vimgrep --",
callback = utils.vimgrep_action(),
}

48
lua/ivy/config.lua Normal file
View file

@ -0,0 +1,48 @@
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",
},
mappings = {
["<C-c>"] = "destroy",
["<C-u>"] = "clear",
["<C-n>"] = "next",
["<C-p>"] = "previous",
["<C-M-n>"] = "next_checkpoint",
["<C-M-p>"] = "previous_checkpoint",
["<CR>"] = "complete",
["<C-v>"] = "vsplit",
["<C-s>"] = "split",
["<BS>"] = "backspace",
["<Left>"] = "left",
["<Right>"] = "right",
["<C-w>"] = "delete_word",
},
}
return setmetatable(config, config_mt)

27
lua/ivy/config_spec.lua Normal file
View 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)

View file

@ -3,7 +3,6 @@ local prompt = require "ivy.prompt"
local utils = require "ivy.utils"
local controller = {}
controller.action = utils.actions
controller.items = nil
controller.callback = nil
@ -56,7 +55,7 @@ end
controller.checkpoint = function()
vim.api.nvim_set_current_win(window.origin)
controller.callback(window.get_current_selection(), controller.action.CHECKPOINT)
controller.callback(window.get_current_selection(), utils.actions.CHECKPOINT)
vim.api.nvim_set_current_win(window.window)
end

View 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)

View file

@ -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)

49
lua/ivy/init.lua Normal file
View file

@ -0,0 +1,49 @@
local controller = require "ivy.controller"
local libivy = require "ivy.libivy"
local config = require "ivy.config"
local utils = require "ivy.utils"
local register_backend = require "ivy.register_backend"
local ivy = {}
ivy.action = utils.actions
ivy.utils = utils
ivy.match = libivy.ivy_match
ivy.run = controller.run
ivy.register_backend = register_backend
ivy.checkpoint = controller.checkpoint
ivy.paste = controller.paste
ivy.complete = controller.complete
ivy.destroy = controller.destroy
ivy.input = controller.input
ivy.next = controller.next
ivy.previous = controller.previous
ivy.search = controller.search
-- 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
View 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)

View file

@ -1,7 +1,22 @@
local library_path = (function()
local root = string.sub(debug.getinfo(1).source, 2, #"/libivy.lua" * -1)
local release_path = root .. "../../target/release"
return package.searchpath("libivyrs", release_path .. "/?.so;" .. release_path .. "/?.dylib;")
local current_vim_version = vim.version()
local minimum_supported_version = vim.version.parse "0.9.5"
local is_windows
if vim.version.gt(current_vim_version, minimum_supported_version) then
is_windows = vim.uv.os_uname().sysname == "Windows_NT"
else
is_windows = vim.loop.os_uname().sysname == "Windows_NT"
end
if is_windows then
return package.searchpath("ivyrs", release_path .. "/?.dll;")
else
return package.searchpath("libivyrs", release_path .. "/?.so;" .. release_path .. "/?.dylib;")
end
end)()
local ffi = require "ffi"

36
lua/ivy/libivy_spec.lua Normal file
View 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)

View file

@ -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
View 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)

View file

@ -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
View 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)

View file

@ -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

View 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

View 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)

View file

@ -99,12 +99,15 @@ 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
utils.escape_file_name = function(input)
return string.gsub(input, "([$])", "\\%1")
local file, _ = string.gsub(input, "([$%]\\[])", "\\%1")
return file
end
return utils

View 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)

View 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)

View file

@ -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)

View file

@ -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)

View file

@ -1,3 +1,5 @@
local config = require "ivy.config"
-- Constent options that will be used for the keymaps
local opts = { noremap = true, silent = true, nowait = true }
@ -37,6 +39,24 @@ local function call_gc(items)
end
end
local callbacks = {
destroy = "<cmd>lua vim.ivy.destroy()<CR>",
clear = "<cmd>lua vim.ivy.search('')<CR>",
next = "<cmd>lua vim.ivy.next()<CR>",
previous = "<cmd>lua vim.ivy.previous()<CR>",
next_checkpoint = "<cmd>lua vim.ivy.next(); vim.ivy.checkpoint()<CR>",
previous_checkpoint = "<cmd>lua vim.ivy.previous(); vim.ivy.checkpoint()<CR>",
complete = "<cmd>lua vim.ivy.complete(vim.ivy.action.EDIT)<CR>",
vsplit = "<cmd>lua vim.ivy.complete(vim.ivy.action.VSPLIT)<CR>",
split = "<cmd>lua vim.ivy.complete(vim.ivy.action.SPLIT)<CR>",
backspace = "<cmd>lua vim.ivy.input('BACKSPACE')<CR>",
left = "<cmd>lua vim.ivy.input('LEFT')<CR>",
right = "<cmd>lua vim.ivy.input('RIGHT')<CR>",
delete_word = "<cmd>lua vim.ivy.input('DELETE_WORD')<CR>",
}
local window = {}
window.index = 0
@ -75,25 +95,15 @@ window.make_buffer = function()
vim.api.nvim_buf_set_keymap(window.buffer, "n", chars[index], "<cmd>lua vim.ivy.input('" .. char .. "')<CR>", opts)
end
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-c>", "<cmd>lua vim.ivy.destroy()<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-u>", "<cmd>lua vim.ivy.search('')<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-n>", "<cmd>lua vim.ivy.next()<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-p>", "<cmd>lua vim.ivy.previous()<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-M-n>", "<cmd>lua vim.ivy.next(); vim.ivy.checkpoint()<CR>", opts)
vim.api.nvim_buf_set_keymap(
window.buffer,
"n",
"<C-M-p>",
"<cmd>lua vim.ivy.previous(); vim.ivy.checkpoint()<CR>",
opts
)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<CR>", "<cmd>lua vim.ivy.complete(vim.ivy.action.EDIT)<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-v>", "<cmd>lua vim.ivy.complete(vim.ivy.action.VSPLIT)<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-s>", "<cmd>lua vim.ivy.complete(vim.ivy.action.SPLIT)<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<BS>", "<cmd>lua vim.ivy.input('BACKSPACE')<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<Left>", "<cmd>lua vim.ivy.input('LEFT')<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<Right>", "<cmd>lua vim.ivy.input('RIGHT')<CR>", opts)
vim.api.nvim_buf_set_keymap(window.buffer, "n", "<C-w>", "<cmd>lua vim.ivy.input('DELETE_WORD')<CR>", opts)
local mappings = config:get { "mappings" }
assert(mappings, "The mappings key is missing from the config, something has gone horribly wrong")
for key, value in pairs(mappings) do
if callbacks[value] == nil then
error("The mapping '" .. value .. "' is not a valid ivy callback")
end
vim.api.nvim_buf_set_keymap(window.buffer, "n", key, callbacks[value], opts)
end
end
window.get_current_selection = function()

32
lua/ivy/window_spec.lua Normal file
View 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)

View file

@ -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)

View file

@ -1,29 +1,9 @@
local controller = require "ivy.controller"
local api = require "ivy"
-- Put the controller in to the vim global so we can access it in mappings
-- better without requires. You can call controller commands like `vim.ivy.xxx`.
-- 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.ivy = api
vim.paste = (function(overridden)
return function(lines, phase)
@ -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"

View file

@ -10,18 +10,27 @@ pub fn find_files(options: Options) -> Vec<String> {
let base_path = &fs::canonicalize(options.directory).unwrap();
let mut builder = WalkBuilder::new(base_path);
// Search for hidden files and directories
builder.hidden(false);
// Don't require a git repo to use .gitignore files. We want to use the .gitignore files
// wherever we are
builder.require_git(false);
// TODO(ade): Remove unwraps and find a good way to get the errors into the UI. Currently there
// is no way to handel errors in the rust library
let mut override_builder = OverrideBuilder::new("");
override_builder.add("!.git").unwrap();
override_builder.add("!.sl").unwrap();
let overrides = override_builder.build().unwrap();
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
View 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 }

30
scripts/integration.lua Normal file
View file

@ -0,0 +1,30 @@
vim.opt.rtp:append(vim.fn.getcwd())
local ivy = require "ivy"
local prompt = require "ivy.prompt"
require "plugin.ivy"
if #vim.v.argv ~= 5 then
print "[ERROR] Expected 5 arguments"
print " Usage: nvim -l ./scripts/integration.lua <directory> <search>"
return
end
ivy.setup()
vim.fn.chdir(vim.v.argv[4])
print("Working in " .. vim.fn.getcwd())
vim.cmd "IvyFd"
for _, value in pairs(vim.split(vim.v.argv[5], "")) do
local start_time = os.clock()
vim.ivy.input(value)
vim.wait(0)
local running_time = os.clock() - start_time
io.stdout:write(prompt.text() .. "\t" .. running_time .. "\n")
end