Coder Social home page Coder Social logo

ivy.nvim's Introduction

ivy.vim

An ivy-mode port to neovim. Ivy is a generic completion mechanism for Emacs Nvim

Installation

Manually

git clone https://github.com/AdeAttwood/ivy.nvim ~/.config/nvim/pack/bundle/start/ivy.nvim

Plugin managers

Using lazy.nvim

{
    "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.

require('ivy').setup()

With Ivy you can configure your own backends.

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.

require('ivy').register_backend("ivy.backends.files")

Compiling

For the native searching, you will need to compile the shard library. You can do that by running the below command in the root of the plugin.

cargo build --release

You will need to have the rust toolchain installed. You can find more about that here

If you get a linker error you may need to install build-essential to get ld. This is a common issue if you are running the benchmarks in a VM

error: linker `cc` not found
  |
  = note: No such file or directory (os error 2)

To configure auto compiling you can use the post-merge git hook to compile the library automatically when you update the package. This works well if you are managing your plugins via git. For an example installation you can run the following command. NOTE: This will overwrite any post-merge hooks you have already installed.

cp ./post-merge.sample ./.git/hooks/post-merge

Features

Backends

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.

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

vim.api.nvim_set_keymap( "n", "<esc>", "<cmd>lua vim.ivy.destroy()<CR>", { noremap = true, silent = true, nowait = true })

API

ivy.run

The ivy.run function is the core function in the plugin, it will launch the completion window and display the items from your items function. When the users accept one of the candidates with an action, it will call the callback function to in most cases open the item in the desired location.

  ---@param name string
  ---@param items fun(input: string): { content: string }[] | string
  ---@param callback fun(result: string, action: string)
  vim.ivy.run = function(name, items, callback) end

Name string

The name is the display name for the command and will be the name of the buffer in the completion window

Items fun(input: string): { content: string }[] | string

The items function is a function that will return the candidates to display in the completion window. This can return a string where each line will be a completion item. Or an array of tables where the content will be the completion item.

Callback fun(result: string, action: string)

The function that will run when the user selects a completion item. Generally this will open the item in the desired location. For example, in the file finder with will open the file in a new buffer. If the user selects the vertical split action it will open the buffer in a new vsplit

Example

  vim.ivy.run(
    -- The name given to the results window and displayed to the user
    "Title",
    -- Call back function to get all the candidates that will be displayed in
    -- the results window, The `input` will be passed in, so you can filter
    -- your results with the value from the prompt
    function(input)
      return {
        { content = "One" },
        { content = "Two" },
        { content = "Three" },
      }
    end,
    -- 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
  )

Benchmarks

Benchmarks are of various tasks that ivy will do. The purpose of the benchmarks are to give us a baseline on where to start when trying to optimize performance in the matching and sorting, not to put ivy against other tools. When starting to optimize, you will probably need to get a baseline on your hardware.

There are fixtures provided that will create the directory structure of the kubernetes source code, from somewhere around commit sha 985c9202ccd250a5fe22c01faf0d8f83d804b9f3. This will create a directory tree of 23511 files a relative large source tree to get a good idea of performance. To create the source tree under /tmp/ivy-trees/kubernetes run the following command. This will need to be run for the benchmarks to run.

# Create the source trees
bash ./scripts/fixtures.bash

# Run the benchmark script
luajit ./scripts/benchmark.lua

Current benchmark status running on a e2-standard-2 2 vCPU + 8 GB memory VM running on GCP.

IvyRs (Lua)

Name Total Average Min Max
ivy_match(file.lua) 1000000x 04.153531 (s) 00.000004 (s) 00.000003 (s) 00.002429 (s)
ivy_files(kubernetes) 100x 03.526795 (s) 00.035268 (s) 00.021557 (s) 00.037127 (s)

IvyRs (Criterion)

Name Min Mean Max
ivy_files(kubernetes) 19.727 ms 19.784 ms 19.842 ms
ivy_match(file.lua) 2.6772 µs 2.6822 µs 2.6873 µs

CPP

Name Total Average Min Max
ivy_match(file.lua) 1000000x 01.855197 (s) 00.000002 (s) 00.000001 (s) 00.000177 (s)
ivy_files(kubernetes) 100x 14.696396 (s) 00.146964 (s) 00.056604 (s) 00.168478 (s)

Other stuff you might like

  • ivy-mode - An emacs package that was the inspiration for this nvim plugin
  • Command-T - Vim plugin I used before I started this one
  • telescope.nvim - Another competition plugin, lots of people are using

ivy.nvim's People

Contributors

adeattwood avatar arnevm123 avatar dependabot[bot] avatar renovate[bot] avatar shaolunwang avatar xymist avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ivy.nvim's Issues

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

This repository currently has no open or pending branches.

Detected dependencies

cargo
Cargo.toml
  • ignore 0.4.22
  • fuzzy-matcher 0.3.7
  • rayon 1.10.0
  • criterion 0.5.1
github-actions
.github/workflows/ci.yml
  • actions/checkout v4
  • actions/checkout v4
  • JohnnyMorganz/stylua-action v4.0.0
  • actions/checkout v4
  • actions/checkout v4
.github/workflows/ct-commitlint.yml
  • actions/checkout v4
  • practically/conventional-tools 1.x@sha256:647d6e4b3edfcbac6054b90f74d2c61a022152751b94484d54e13695a9e27377

  • Check this box to trigger a request for Renovate to run again on this repository

Allow the end user to use internal utils and libivy.

Problem to solve

I was playing around with the plugin and tried to make a recent files backend.
Some issues that I found while doing this were that I had to reimplement some basic functionality form the utils (file_action for this one).
I also did not have the ability to search, it would be handy to have access to the libivy API (eg. ivy_match).

Proposal

Exposing (part of) the utils and libivy API to the user.
I understand that this would mean that these need to be documented, so I see why this would be something to do with caution.

Further details

I played around with it locally, and I just exposed utils and libivy (same as run and register backend) then I could just create a backend file in my local config and require this file.
Then I can copy paste a backend from the source code to my local nvim config.

Then I can call ivy.register_backend(require("local.backends.ag")) after calling the setup function, and it works just like the internal backends.

I think exposing these API's will make it really easy for users to implement personal commands.
Eg. recent files is just 90% copy pasting of buffers and then just changing getting buffers to getting recent files.

A lot of functionality can easily be ported over from looking at Telescope (that's how I found the oldfiles)).

And then these user made commands can be kept in the wiki section.

Not sure what your thoughts on this would be.
If anything is not clear, feel free to ask 😄

Crash when searching for pattern with - in it

When searching for input-text.jsx ivy crashes, and you are unable to continue to use vim. The same behaviour happens for every ivy command when the search pattern contains a -

Error executing vim.schedule lua callback: ...g/nvim/pack/bundle/start/ivy.nvim/lua/ivy/controller.lua:42: Vim(syntax):E944: Reverse range in character class
stack traceback:
        [C]: in function 'cmd'
        ...g/nvim/pack/bundle/start/ivy.nvim/lua/ivy/controller.lua:42: in function ''
        vim/_editor.lua: in function ''
        vim/_editor.lua: in function <vim/_editor.lua:0>

Allow the disabling of the default keymaps

Problem to solve

Currently the default keymaps are always set. It would be nice to let the user decide if they want the default keymaps.

Proposal

Most plugins use a setup function that takes in a config, not sure what your vision on this would be, as ivy.nvim does not seem to have one as of now.

Does not open terminal buffers

Description

When running ivy buffers IvyBuffers with a terminal buffer in the buffer list, selecting that buffer opens a blank text buffer with the name of the terminal.

image

Expected Behaviour

Open the terminal buffer when selected

Actual Behaviour

An empty buffer is opened when selecting the terminal buffer.

Steps to Reproduce the Problem

  1. Open any buffer
  2. Open a terminal buffer with :term
  3. Navigate away from the terminal buffer back to the first buffer
  4. Run IvyBuffers and select the terminal buffer

Unable to paste into the prompt

When pasting text, when ivy is active, it pastes the text into the completion window. The correct behaviour for this is to set the prompt to the pasted text and then filter the results on the new content of the prompt.

Allow the user to customise the key maps in the completion buffer

Problem to solve

As mentioned by @arnevm123 in #81 (comment)

Also, should the keymaps for the window be configurable? Most of them seem very intuitive and don't need changing for me, except for maybe next/ next checkpoint or the previous versions.

There are many plugins that already do this, I think we will be able to take inspiration from them and implement something that is familiar to use.

Proposal

Add the keycaps into the config and allow the users to override it to their liking.

Further details

There are many plugins that already do this

Links / References

Crash when running IvyLines

Error executing vim.schedule lua callback: ...onfig/nvim/pack/bundle/start/ivy.nvim/lua/ivy/window.lua:99: Cursor position outside buffer
stack traceback:
        [C]: in function 'nvim_win_set_cursor'
        ...onfig/nvim/pack/bundle/start/ivy.nvim/lua/ivy/window.lua:99: in function 'update'
        ...onfig/nvim/pack/bundle/start/ivy.nvim/lua/ivy/window.lua:130: in function 'set_items'
        ...g/nvim/pack/bundle/start/ivy.nvim/lua/ivy/controller.lua:35: in function <...g/nvim/pack/bundle/start/ivy.nvim/lua/ivy/controller.lua:34
>

Unable to open files with $ character in

Description

When trying to edit a file with a $ character in, it will open up a different file. This is probably due to the file name not getting escaped before trying to open it.

Expected Behaviour

The correct file gets opened

Actual Behaviour

A file gets opened with a filename before the $

Steps to Reproduce the Problem

  1. Create a new file touch test\$file.txt
  2. Open vim and search for the file <leader>p test$file.txt
  3. Select test$file.txt with <CR>
  4. A file with the name test.txt is opened

Finder panics when it finds a file it cannot read

Description

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.

Expected Behaviour

Ivy should not panic, the files you cannot read should be skipped and not included in the candidates.

Actual Behaviour

Ivy will panic with the below error. It has been formatted a bit, it's kinda messy in nvim.

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

Steps to Reproduce the Problem

  1. Create a project dir mkdir /tmp/workspace
  2. Go into the project dir cd /tmp/workspace
  3. Boot a mysql container docker run --rm -e MYSQL_RANDOM_ROOT_PASSWORD=true -v $PWD/mysql:/var/lib/mysql mysql
  4. Open nvim nvim
  5. Run :IvyFd

Confusing error when libivyrs.so is not found

Description

I have made this a bug bit, it's a bit of both. You get a really confusing error when you have not compiled or compiled libivyrs.so without the --release flag and ffi cant find it.

It spews out a large red error message that boils down to

.config/nvim/pack/bundle/start/ivy.nvim/lua/ivy/../../target/release/libivyrs.so: cannot open shared object file: No such file or directory

Expected Behaviour

A helpful message with a link to the docs on how to compile libivyrs.so. I think there should be a link to the compiling section in the readme that will give the information needed to compile the lib correctly.

https://github.com/AdeAttwood/ivy.nvim#compiling

Actual Behaviour

You get a length message that does not mean a lot.

Steps to Reproduce the Problem

  1. Install the plugin
git clone https://github.com/AdeAttwood/ivy.nvim ~/.config/nvim/pack/bundle/start/ivy.nvim
  1. Optional compile the plugin in debug mode without the --release flag
cargo build
  1. Open neovim

Add a wiki page for custom commands

Problem to solve

Since the plugin is easily customizable with custom actions it would be nice to have a community driven section where code snippets are shared.
Since this is just a community section it should be easy to maintain and a low barrier to add stuff.

Does not work with macOS

Description

Unable to load libivyrs.so on macOS. This is because mac does not use .so files they use .dylib. When you compile ivy on Mac, you get the output target/release/libivyrs.dylib. When we load the lib via FFI, we need to check for both files.

Expected Behaviour

Opening vim does not cause errors and you can use ivy.

Actual Behaviour

When you open vim you get the message

libivyrs.so not found! Please ensure you have complied ......

Steps to Reproduce the Problem

  1. Clone and compile ivy on macOS
  2. Open vim

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.