diff --git a/README.md b/README.md index fae7b8b..c333988 100644 --- a/README.md +++ b/README.md @@ -1,78 +1,79 @@
# ivy.nvim An [ivy-mode](https://github.com/abo-abo/swiper#ivy) port to neovim. Ivy is a generic completion mechanism for ~~Emacs~~ Nvim
## Installation ### Manually ```sh git clone https://github.com/AdeAttwood/ivy.nvim ~/.config/nvim/pack/bundle/start/ivy.nvim ``` ### Plugin managers TODO: Add docs in the plugin managers I don't use any ### 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. ```sh cmake -DCMAKE_BUILD_TYPE=Release -B build/Release && (cd build/Release; make -j) ``` If you are missing build dependencies, you can install them via apt. ```sh sudo apt-get install build-essential pkg-config cmake ``` ## Features ### Commands A command can be run that will launch the completion UI | Command | Key Map | Description | | ---------- | ----------- | ------------------------------------------------------ | | IvyFd | \p | Find files in your project with the fd cli file finder | | IvyAg | \/ | Find content in files using the silver searcher | | IvyBuffers | \b | Search though open buffers | +| IvyLines | | Search the lines in the current buffer | ### 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 | ## API ```lua 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 { "One", "Two", Three } end, -- Action callback that will be called on the completion or peek actions. -- The currently selected item is passed in as the result. function(result) vim.cmd("edit " .. result) end ) ``` ## Other stuff you might like - [ivy-mode](https://github.com/abo-abo/swiper#ivy) - An emacs package that was the inspiration for this nvim plugin - [Command-T](https://github.com/wincent/command-t) - Vim plugin I used before I started this one - [telescope.nvim](https://github.com/nvim-telescope/telescope.nvim) - Another competition plugin, lots of people are using diff --git a/lua/ivy/utils.lua b/lua/ivy/utils.lua index c087167..6fa8f67 100644 --- a/lua/ivy/utils.lua +++ b/lua/ivy/utils.lua @@ -1,57 +1,64 @@ local utils = {} utils.command_finder = function(command, min) if min == nil then min = 3 end return function(input) -- Dont run the commands unless we have somting to search that wont -- return a ton of results or on some commands the command files with -- no search term if #input < min then return "-- Please type more than " .. min .. " chars --" end -- TODO(ade): Think if we want to start escaping the command here. I -- dont know if its causing issues while trying to use regex especially -- with word boundaries `input:gsub("'", "\\'"):gsub('"', '\\"')` local handle = io.popen(command .. " " .. input .. " 2>&1") if handle == nil then return {} end local result = handle:read "*a" handle:close() return result end end utils.vimgrep_action = function() return function(item) -- Match file and line form vimgrep style commands local file = item:match "([^:]+):" local line = item:match ":(%d+):" -- Cant do anything if we cant find a file to go to if file == nil then return end vim.cmd("edit " .. file) if line ~= nil then vim.cmd(line) end end end utils.file_action = function() return function(file) if file == nil then return end vim.cmd("edit " .. file) end end +utils.line_action = function() + return function(item) + local line = item:match "^%s+(%d+):" + vim.cmd(line) + end +end + return utils diff --git a/plugin/ivy.lua b/plugin/ivy.lua index 92f22f6..2744c71 100644 --- a/plugin/ivy.lua +++ b/plugin/ivy.lua @@ -1,47 +1,69 @@ local controller = require "ivy.controller" local utils = require "ivy.utils" local libivy = require "ivy.libivy" -- 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`. vim.ivy = controller vim.api.nvim_create_user_command("IvyAg", function() vim.ivy.run("AG", utils.command_finder "ag", utils.vimgrep_action()) end, { bang = true, desc = "Run ag to search for content in files" }) vim.api.nvim_create_user_command("IvyFd", function() vim.ivy.run("Files", function(term) return libivy.ivy_files(term, vim.fn.getcwd()) end, utils.file_action()) end, { bang = true, desc = "Find files in the project" }) vim.api.nvim_create_user_command("IvyBuffers", function() vim.ivy.run("Buffers", function(input) local list = {} local buffers = vim.api.nvim_list_bufs() for index = 1, #buffers do local buffer = buffers[index] -- Get the relative path from the current working directory. We need to -- substring +2 to remove the `/` from the start of the path to give us a -- true relative path local buffer_name = vim.api.nvim_buf_get_name(buffer):sub(#vim.fn.getcwd() + 2, -1) if vim.api.nvim_buf_is_loaded(buffer) and #buffer_name > 0 then local score = libivy.ivy_match(input, buffer_name) if score > -200 or #input == 0 then table.insert(list, { score, buffer_name }) end end end table.sort(list, function(a, b) return a[1] < b[1] end) return list end, utils.file_action()) end, { bang = true, desc = "List all of the current open buffers" }) +vim.api.nvim_create_user_command("IvyLines", function() + vim.ivy.run("Lines", function(input) + local list = {} + + local lines = vim.api.nvim_buf_get_lines(vim.ivy.origin(), 0, -1, false) + for index = 1, #lines do + local line = lines[index] + local score = libivy.ivy_match(input, line) + if score > -200 then + local prefix = string.rep(" ", 4 - #tostring(index)) .. index .. ": " + table.insert(list, { score, prefix .. line }) + end + end + + table.sort(list, function(a, b) + return a[1] < b[1] + end) + + return list + end, utils.line_action()) +end, { bang = true, desc = "List all of the current open buffers" }) + vim.api.nvim_set_keymap("n", "b", "IvyBuffers", { nowait = true, silent = true }) vim.api.nvim_set_keymap("n", "p", "IvyFd", { nowait = true, silent = true }) vim.api.nvim_set_keymap("n", "/", "IvyAg", { nowait = true, silent = true })