{"id":13411120,"url":"https://github.com/vijaymarupudi/nvim-fzf","last_synced_at":"2025-03-14T16:33:58.363Z","repository":{"id":38385824,"uuid":"326232922","full_name":"vijaymarupudi/nvim-fzf","owner":"vijaymarupudi","description":"A Lua API for using fzf in neovim.","archived":false,"fork":false,"pushed_at":"2024-10-21T15:35:16.000Z","size":4073,"stargazers_count":347,"open_issues_count":2,"forks_count":13,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-06T05:36:45.035Z","etag":null,"topics":["asynchronous","fuzzy-search","fzf","lua","neovim","plugin","vim"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vijaymarupudi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-02T17:16:57.000Z","updated_at":"2025-02-27T18:13:29.000Z","dependencies_parsed_at":"2024-10-22T15:22:04.882Z","dependency_job_id":null,"html_url":"https://github.com/vijaymarupudi/nvim-fzf","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vijaymarupudi%2Fnvim-fzf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vijaymarupudi%2Fnvim-fzf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vijaymarupudi%2Fnvim-fzf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vijaymarupudi%2Fnvim-fzf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vijaymarupudi","download_url":"https://codeload.github.com/vijaymarupudi/nvim-fzf/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243610834,"owners_count":20319034,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asynchronous","fuzzy-search","fzf","lua","neovim","plugin","vim"],"created_at":"2024-07-30T20:01:11.534Z","updated_at":"2025-03-14T16:33:57.746Z","avatar_url":"https://github.com/vijaymarupudi.png","language":"Lua","funding_links":[],"categories":["Fuzzy Finder","Lua"],"sub_categories":["Markdown and LaTeX","Assembly"],"readme":"# nvim-fzf\n\nAn asynchronous Lua API for using `fzf` in Neovim (\u003e= 0.5). Allows for full asynchronicity for UI speed and usability.\n\nPreview:\n\n![](https://raw.githubusercontent.com/vijaymarupudi/nvim-fzf-commands/master/gifs/bufferpicker2.gif)\n\nNote how in the example above, information is passed freely between\nneovim and `fzf`. Neovim is previewing the buffer in a split that you have\nselected *in `fzf`*.  Using this library, you can perform anything in\nresponse to `fzf` events and keybindings.\n\nSome handcrafted useful commands at\n\n* [`fzf-lua`](https://github.com/ibhagwan/fzf-lua)\n* [`nvim-fzf-commands`](https://github.com/vijaymarupudi/nvim-fzf-commands).\n\nTested on Linux, MacOS, and Windows.\n\n## Requirements\n\n* `fzf` binary\n\n## Usage\n\n```lua\nlocal fzf = require(\"fzf\")\n\ncoroutine.wrap(function()\n  local result = fzf.fzf({\"choice 1\", \"choice 2\"}, \"--ansi\")\n  -- result is a list of lines that fzf returns, if the user has chosen\n  if result then\n    print(result[1])\n  end\nend)()\n```\n\n![](gifs/example_1.gif)\n\n## Table of contents\n\n* [Usage](#usage)\n* [Installation](#installation)\n* [Important information](#important-information)\n* [API Functions](#api-functions)\n* [Main API](#main-api)\n* [Action API](#action-api-fzf-previews-bindings-actions-in-lua)\n* [Helpers](#helpers)\n* [Examples](#examples)\n* [How it works](#how-it-works)\n* [FAQ](#faq)\n\n## Installation\n\n```vimscript\nPlug 'vijaymarupudi/nvim-fzf'\n```\n\n## Important information\n\n**All `fzf` functions should be run in a coroutine.**\n\nExample:\n\n```lua\nlocal fzf = require(\"fzf\")\n\ncoroutine.wrap(function()\n  local result = fzf.fzf({\"choice 1\", \"choice 2\"})\n  if result then\n    print(result[1])\n  end\nend)()\n```\n\n## API Functions\n\nRequire this plugin using `local fzf = require('fzf')`\n\n* `fzf.fzf(contents, [fzf_cli_args], [options])`\n\n  An fzf function that opens a centered floating window and closes it\n  after the user has chosen.\n\n  Example:\n\n  ```lua\n  local results = fzf.fzf({\"Option 1\", \"Option 2\"}, \"--nth 1\")\n  if results then\n    -- do something\n  end\n  ```\n\n  `options`: an optional **table**, taking optional\n  settings. You can use this to change the default floating window\n  behavior or the fzf binary.\n\n  * `options.title` (optional string): title of the window\n  * `options.title_pos` (string, default: 'center'): where the title should be placed\n  * `options.width` (number/\"max\"): width of the window. If \"max\", will take up the entire screen.\n  * `options.height` (number/\"max\"): height of the window. If \"max\", will take up the entire screen.\n  * `options.row` (number): row from top where window starts\n  * `options.col` (number): column from left where window starts\n  * `options.relative` ('win', 'editor', 'cursor'): window position relative to\n  * `options.border` (boolean | string | table, default: true): whether to display a border\n    * if `border` is `false`, a border won't be shown\n    * if `border` is `true`, a rounded border will be shown\n    * if `border` is anything else, it is passed directly to\n      `nvim_open_win`\n  * `options.window_on_create` (function): a function that's\n    called after the window is created. Use this function to configure\n    the various properties of the window such as background highlight\n    group.\n  * `options.fzf_binary` (string): The name (or path) of the `fzf` (or\n    `skim`) executable.\n  * `options.fzf_cwd` (string): The path of the working directory to run\n    the fzf command in.\n  * `options.fzf_cli_args` (string): Additional fzf command line\n    arguments to prepend to the arguments supplied to the fzf functions.\n    This is only useful when used in conjunction with\n    `fzf.default_options`.\n\n  **NOTE**: `options` inherits its properties from\n  `fzf.default_options`. If you'd like to change the defaults for\n  all nvim-fzf functions, modify this table e.g.\n  `require(\"fzf\").default_options = { border = false }`\n\n  Example:\n\n  ```lua\n  local results = fzf.fzf({\"Option 1\", \"Option 2\"},\n    \"--nth 1\",\n    { width = 30, height = 10, border = false })\n  if results then\n    -- do something\n  end\n  ```\n\n* `fzf.fzf_relative(contents, [fzf_cli_args], [options])`\n\n  An fzf function that opens a centered floating window relative to the\n  current split and closes it after the user has chosen.\n  (Same as setting `options.relative = 'win'`)\n\n  Example:\n\n  ```lua\n  local results = fzf.fzf_relative({\"Option 1\", \"Option 2\"}, \"--nth 1\")\n  if results then\n    -- do something\n  end\n  ```\n\n  `options`: an optional **table** taking optional\n  settings. See `fzf.fzf` for information on settings.\n\n* `fzf.provided_win_fzf(contents, [fzf_cli_args], [options])`\n\n  Runs fzf in the current window, and closes it after the user has\n  chosen. Allows for the user to provide the fzf window.\n\n  ```lua\n  -- for a vertical fzf\n  vim.cmd [[ vertical new ]]\n  fzf.provided_win_fzf(contents, fzf_cli_args)\n  ```\n\n* `fzf.raw_fzf(contents, [fzf_cli_args], [options])`\n\n  An fzf function that runs fzf in the current window. See `Main API`\n  for more details about the general API.\n\n**NOTE**: nvim-fzf inherits nvim's environmental variables. This means\nthat options in `$FZF_DEFAULT_OPTS` and other environment variables are\nrespected. You can override them using command line switches or\n`:let-environment`.\n\n## Main API\n\n`fzf(contents, [fzf_cli_args])`\n\n* `contents`\n\n  * if **string**: a shell command\n\n    ```lua\n    local result = fzf(\"fd\")\n    ```\n\n  * if **table**: a list of strings or string convertibles\n\n    ```lua\n    local result = fzf({1, 2, \"item\"})\n    ```\n\n  * if **function**: `nvim-fzf` calls the function with a callback function to\n    write vals to the fzf pipe. This api is asynchronous, making it\n    possible to use fzf for long running applications and making the\n    user interface snappy. Callbacks can be concurrent.\n\n    * `cb(value, finished_cb)`\n\n      * `value`: A value to write to fzf\n      * `finished_cb(err)`: A callback called with an err if there is an\n        error writing the value to fzf. This can occur if the user has\n        already picked a value in fzf.\n\n    ```lua\n    local result = fzf(function(cb)\n      cb(\"value_1\", function(err)\n        -- this error can happen if the user has already chosen a value\n        -- before the information was sent to fzf\n        if err then\n          return\n        end\n        cb(\"value_2\", function(err)\n          if err then\n            return\n          end\n          cb(nil) -- to close the pipe to fzf, this removes the loading\n                  -- indicator in fzf\n        end)\n      end)\n    end)\n    ```\n\n    The function is also called with two other optional arguments for more\n    advanced usage.\n\n    * The 2nd argument is a variant of the callback function (which is\n      passed as the 1st argument), but it does not add newlines to the\n      elements. This is useful to pass through information directly to\n      the pipe.\n\n    * The 3rd argument is the `vim.loop` / `luv` pipe to FZF. Use as you\n      see fit!\n\n* `fzf_cli_args`: **string**, A list of command line arguments for fzf.\n\n    Can use to expect different key bindings (e.g. `--expect\n    ctrl-t,ctrl-v`), previews, and coloring.\n\n* **return values**\n\n  * **table**, the lines that fzf returns in the shell\n    as a table. If not lines are returned by fzf, the function returns nil\n    for an easy conditional check.\n\n    ```lua\n    local result = fzf(\"fd\")\n    if result then\n      -- do something with result[1]\n    end\n    ```\n\n    ```lua\n    local result = fzf(\"fd\", \"--multi\")\n    if result then\n      -- do something with result[1] to result[#result]\n    end\n    ```\n\n    ```lua\n    local result = fzf(\"fd\", \"--expect=ctrl-t\")\n    if result then\n      if result[1] == \"ctrl-t\" then\n        -- do something with result[2]\n      else\n        -- do something with result[2]\n      end\n    end\n    ```\n\n  * **number**: Representing fzf's exit code.\n\n\n\n## Action API (fzf Previews, Bindings, Actions in Lua)\n\nSometimes you want to use neovim information in fzf (such as previews of\nnon file buffers, bindings to delete buffers, or change colorschemes).\nfzf expects a shell command for these parameters. Making your own shell\ncommand and setting up RPC can be cumbersome. This plugin provides an\neasy API to run a lua function / closure in response to these actions.\n\n```lua\nlocal fzf = require \"fzf\".fzf\nlocal action = require \"fzf.actions\".action\n\ncoroutine.wrap(function()\n  -- items is a table of selected or hovered fzf items\n  local shell = action(function(items, fzf_lines, fzf_cols)\n    -- only one item will be hovered at any time, so get the selection\n    -- out and convert it to a number\n    local buf = tonumber(items[1])\n\n    -- you can return either a string or a table to show in the preview\n    -- window\n    return vim.api.nvim_buf_get_lines(buf, 0, -1, false)\n  end)\n\n  fzf(vim.api.nvim_list_bufs(), \"--preview \" .. shell)\nend)()\n```\n\n![](gifs/example_2.gif)\n\n`require(\"fzf.actions\").action(fn, [fzf_field_expression])`\n\n* `fn(selections, fzf_lines, fzf_cols)`: A function that takes a\n  selection, performs an action, and optionally returns either a `table`\n  or `string` to print to stdout. *This command is shell-escaped, so\n  that you can easily append it to the `--preview` fzf cli argument.*\n\n  * `selections`: a `table` of strings selected in `fzf`\n  * `fzf_lines`: number of lines in the preview window i.e.\n    `$FZF_PREVIEW_LINES`\n  * `fzf_cols`: number of cols in the preview window i.e.\n    `$FZF_PREVIEW_COLS`\n\n* `fzf_field_expression` (string, optional, default: `\"{+}\"`): This fzf\n  field expression determines what items are sent to the action\n  function.\n\n* **return value**: a shell-escaped string to append to the `fzf` command\n  line arguments (`fzf_cli_args`) for `fzf` to run.\n\n\n`require(\"fzf.actions\").raw_action(fn, [fzf_field_expression])`\n\n* Same as above, except it is not shell-escaped, so you can use it for\n  complicated `--bind` functions. Take care to escape the result of\n  this function before using it, as it contains spaces and quotes.\n\n  ```lua\n  local fzf = require(\"fzf\").fzf\n  local raw_action = require(\"fzf.actions\").raw_action\n\n  local raw_act_string = raw_action(function(args)\n    -- do something with the args\n  end)\n\n  local bind_string =\n  vim.fn.shellescape(string.format(\"--bind=ctrl-r:reload(%s)\",\n  raw_act_string))\n\n  coroutine.wrap(function()\n    fzf({1, 2, 3, 4}, \"--multi \" .. bind_string)\n  end)()\n  ```\n\n`require(\"fzf.actions\").async_action(fn, [fzf_field_expression])`\n\n\n* `fn(pipe, selections, fzf_lines, fzf_cols)`: Similar to `action(...)`,\n  but `fn` is passed an additional argument, the `libuv` / `vim.loop`\n  pipe to `fzf`, as the first argument. Users can write to this pipe\n  using `uv.write(pipe, data, callback)` and are expected to close the\n  pipe using `uv.close(pipe)`.\n\n  This function can be used for previews that take a long time to render\n  and calculate from neovim.\n\n`require(\"fzf.actions\").raw_async_action(fn, [fzf_field_expression])`\n\n* Same as above, except it is not shell-escaped, so you can use it for\n  complicated `--bind` functions. Take care to escape the result of\n  this function before using it, as it contains spaces and quotes.\n\n\n## Helpers\n\nAsynchronous programming is hard. For the case when you want to accept a\nshell command, and simply transform each line into another line,\n`nvim-fzf` has a helper function that returns a function that\nasynchronously applies the transformation, which can be passed right\ninto `fzf`.\n\n`require(\"fzf.helpers\").cmd_line_transformer(cmd, fn)`\n\n* `cmd`\n  * if **string**: the shell command to transform\n  * if **table**: a table taking the following properties\n    * `cmd.cmd` (string): the shell command to transform\n    * `cmd.cwd` (string, optional): the working directory to run the\n      shell script in.\n    * `cmd.pid_cb` (function, optional): a callback called with the pid\n      of the shell command when available.\n* `fn` (function): a function that takes as input a line from the shell\n  command (string) and returns a new line to be sent to `fzf` (string).\n\n```lua\nlocal fzf = require(\"fzf\")\nlocal fzf_helpers = require(\"fzf.helpers\")\n\ncoroutine.wrap(function()\n\n  -- the transformation function runs for each line in the command\n  local fzf_fn = fzf_helpers.cmd_line_transformer(\"seq 1000\", function(x)\n    local n = tonumber(x)\n    return tostring(n * n)\n  end)\n\n  local choices = fzf.fzf(fzf_fn)\n\nend)()\n```\n\n`require(\"fzf.helpers\").choices_to_shell_cmd_previewer(fn,\n[fzf_field_expression])`\n\n* `fn(items, fzf_lines, fzf_cols)`: A function that is expected to\n  return a shell cmd string to run asynchronously and feed to `fzf`.\n  This allows the user to use Lua to parse the input from fzf before\n  performantly using an external process to preview the output.\n\n  ```lua\n  local fzf = require(\"fzf\")\n  local helpers = require(\"fzf.helpers\")\n\n\n  coroutine.wrap(function ()\n    local action = helpers.choices_to_shell_cmd_previewer(function(items)\n      return \"seq \" .. vim.fn.shellescape(tostring(items[1])) \n    end)\n    fzf.fzf(\"seq 1 1000\", \"--preview=\" .. action)\n  end)()\n  ```\n\n* `fzf_field_expression`: See above\n\n## Examples\n\n**Filetype picker**\n\n![](gifs/example_3.gif)\n\n```lua\nlocal fts = {\n  \"typescript\",\n  \"javascript\",\n  \"lua\",\n  \"python\",\n  \"vim\",\n  \"markdown\",\n  \"sh\"\n}\n\n\ncoroutine.wrap(function()\n  local choice = require \"fzf\".fzf(fts)\n  if choice then\n    vim.cmd(string.format(\"set ft=%s\", choice[1]))\n  end\nend)()\n```\n\n**Colorscheme picker**\n\nThis example provides a live preview of the colorscheme while the user\nis choosing between them. An example showing the advantages of nvim-fzf\nand the `--preview` fzf cli arg.\n\n![](https://raw.githubusercontent.com/vijaymarupudi/nvim-fzf-commands/master/gifs/colorschemes.gif)\n\n```lua\nlocal action = require(\"fzf.actions\").action\n\nlocal function get_colorschemes()\n  local colorscheme_vim_files = vim.fn.globpath(vim.o.rtp, \"colors/*.vim\", true, true)\n  local colorschemes = {}\n  for _, colorscheme_file in ipairs(colorscheme_vim_files) do\n    local colorscheme = vim.fn.fnamemodify(colorscheme_file, \":t:r\")\n    table.insert(colorschemes, colorscheme)\n  end\n  return colorschemes\nend\n\nlocal function get_current_colorscheme()\n  if vim.g.colors_name then\n    return vim.g.colors_name\n  else\n    return 'default'\n  end\nend\n\n\ncoroutine.wrap(function ()\n  local preview_function = action(function (args)\n    if args then\n      local colorscheme = args[1]\n      vim.cmd(\"colorscheme \" .. colorscheme)\n    end\n  end)\n\n  local current_colorscheme = get_current_colorscheme()\n  local choices = fzf(get_colorschemes(), \"--preview=\" .. preview_function .. \" --preview-window right:0\") \n  if not choices then\n    vim.cmd(\"colorscheme \" .. current_colorscheme)\n  else\n    vim.cmd(\"colorscheme \" .. choices[1])\n  end\nend)()\n\n```\n\n\n**Helptags picker**\n\nThis is a bit complex example that is completely asynchronous for\nperformance reasons. It also uses the `fzf` `--expect` command line flag.\n\n![](gifs/example_4.gif)\n\n```lua\nlocal runtimepaths = vim.api.nvim_list_runtime_paths()\nlocal uv = vim.loop\nlocal fzf = require('fzf').fzf\n\nlocal function readfilecb(path, callback)\n  uv.fs_open(path, \"r\", 438, function(err, fd)\n    if err then\n      callback(err)\n      return\n    end\n    uv.fs_fstat(fd, function(err, stat)\n      if err then\n        callback(err)\n        return\n      end\n      uv.fs_read(fd, stat.size, 0, function(err, data)\n        if err then\n          callback(err)\n          return\n        end\n        uv.fs_close(fd, function(err)\n          if err then\n            callback(err)\n            return\n          end\n          return callback(nil, data)\n        end)\n      end)\n    end)\n  end)\nend\n\nlocal function readfile(name)\n  local co = coroutine.running()\n  readfilecb(name, function (err, data)\n    coroutine.resume(co, err, data)\n  end)\n  local err, data = coroutine.yield()\n  if err then error(err) end\n  return data\nend\n\nlocal function deal_with_tags(tagfile, cb)\n  local co = coroutine.running()\n  coroutine.wrap(function ()\n    local success, data = pcall(readfile, tagfile)\n    if success then\n      for i, line in ipairs(vim.split(data, \"\\n\")) do\n        local items = vim.split(line, \"\\t\")\n        -- escape codes for grey\n        local tag = string.format(\"%s\\t\\27[0;37m%s\\27[0m\", items[1], items[2])\n        local co = coroutine.running()\n        cb(tag, function ()\n          coroutine.resume(co)\n        end)\n        coroutine.yield()\n      end\n    end\n    coroutine.resume(co)\n  end)()\n  coroutine.yield()\nend\n\nlocal fzf_function = function (cb)\n  local total_done = 0\n  for i, rtp in ipairs(runtimepaths) do\n    local tagfile = table.concat({rtp, \"doc\", \"tags\"}, \"/\")\n    -- wrapping to make all the file reading concurrent\n    coroutine.wrap(function ()\n      deal_with_tags(tagfile, cb)\n      total_done = total_done + 1\n      if total_done == #runtimepaths then\n        cb(nil)\n      end\n    end)()\n  end\nend\n\ncoroutine.wrap(function ()\n  local result = fzf(fzf_function, \"--nth 1 --ansi --expect=ctrl-t,ctrl-s,ctrl-v\")\n  if not result then\n    return\n  end\n  local choice = vim.split(result[2], \"\\t\")[1]\n  local key = result[1]\n  local windowcmd\n  if key == \"\" or key == \"ctrl-s\" then\n    windowcmd = \"\"\n  elseif key == \"ctrl-v\" then\n    windowcmd = \"vertical\"\n  elseif key == \"ctrl-t\" then\n    windowcmd = \"tab\"\n  else\n    print(\"Not implemented!\")\n    error(\"Not implemented!\")\n  end\n\n  vim.cmd(string.format(\"%s h %s\", windowcmd, choice))\nend)()\n```\n\n## How it works\n\nThis plugin uses a temporary named pipe, and uses it to communicate to\n`fzf`.\n\n## FAQ\n\n* Does this conflict with `fzf.vim`?\n\n  This library **does not conflict** with\n  [`fzf.vim`](https://github.com/junegunn/fzf.vim) or the fzf vim API.\n\n* How do I change the color of the default floating window spawned by\n  `fzf.fzf`?\n\n  You need to set the `winhl` option for the default window. You can do\n  this for each command or globally by using the `window_on_create`\n  option.\n\n  This makes the background of the popup window the same color of the\n  backgrounds of normal windows. Example:\n\n  ```lua\n  require(\"fzf\").default_options = {\n    window_on_create = function()\n      vim.cmd(\"set winhl=Normal:Normal\")\n    end\n  }\n  ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvijaymarupudi%2Fnvim-fzf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvijaymarupudi%2Fnvim-fzf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvijaymarupudi%2Fnvim-fzf/lists"}