1795cd4

Branches > main > 1795cd4 > files

Nvim - Replace fzf with a lua picker, use it for vim.ui.select

Grahp, 2026-10-25

Commit: 1795cd4931b01904f523471844c325f60d84ba20
Parent: 149093b

6 changed files:

nvim/lua/colors.lua modified (view file)

@@ -148,3 +148,5 @@  hl(0, "Jump", {bg = highlight_bg}) hl(0, "JumpDisambiguator", {bg = highlight_bg, bold = true, fg = "#2ad6d6"})++hl(0, "PickerMatch", {fg = green})

nvim/lua/fuzzy.lua deleted (view file)

@@ -1,36 +0,0 @@-local api = vim.api-local fn = vim.fn--local ui = require("utils.ui")--local function fzf_window(win)-  local tmp = fn.tempname()-  local cmd = 'fzf --pointer=">" --gutter=" " --prompt="" --no-info --no-scrollbar' .. ">" .. fn.shellescape(tmp)--  fn.termopen({"sh", "-c", cmd}, {-    on_exit = function()-      pcall(api.nvim_win_close, win, true)-      if fn.filereadable(tmp) == 1 then-        local sel = fn.readfile(tmp)[1]-        os.remove(tmp)-        if sel and #sel > 0 then-          vim.cmd("edit " .. fn.fnameescape(sel))-        end-      end-    end})-  vim.cmd("startinsert")-end--local function fuzzy_find()-  if fn.executable("fzf") ~= 1 then-    print("You don't have fzf, can't fuzzy find!")-  else-    local win = ui.open_fullscreen_window()-    local ok = pcall(fzf_window, win)-    if not ok then-      pcall(api.nvim_win_close, win, true)-    end-  end-end--return {fuzzy_find = fuzzy_find}

nvim/lua/keybindings.lua modified (view file)

@@ -46,7 +46,7 @@  keymap("n", "<Space>u", function() require("plugins.oil").open() end) -keymap("n", "<Space>g", function() require("fuzzy").fuzzy_find() end)+keymap("n", "<Space>g", function() require("picker").files() end)  keymap({"n", "v", "o"}, ";", function() require("jump").jump() end) 

nvim/lua/lazy_ui.lua modified (view file)

@@ -10,3 +10,6 @@   group = group,   callback = function() vim.hl.on_yank() end, })++--- Code actions and anything else that asks to pick from a list+vim.ui.select = function(...) require("picker").select(...) end

nvim/lua/picker.lua added (view file)

@@ -0,0 +1,132 @@+local api = vim.api+local fn = vim.fn++local ns = api.nvim_create_namespace("dev.grahp.picker")++local function float(row, height)+  local buf = api.nvim_create_buf(false, true)+  vim.bo[buf].bufhidden = "wipe"+  local win = api.nvim_open_win(buf, false, {+    relative = "editor",+    row = row,+    col = 0,+    width = vim.o.columns,+    height = height,+    style = "minimal",+    border = "none"+  })+  return win, buf+end++--- Fullscreen fuzzy picker, prompt at the bottom and matches going up from it+--- on_choice gets the picked string, or nil if cancelled+local function pick(items, on_choice)+  local orig_win = api.nvim_get_current_win()+  local orig_cursor = api.nvim_win_get_cursor(orig_win)+  local h = vim.o.lines - 1+  local list_win, list_buf = float(0, h)+  local prompt_win, prompt_buf = float(h, 1)+  vim.wo[list_win].cursorline = true+  api.nvim_set_current_win(prompt_win)++  local p = {items = items, query = "", matches = {}}+  local done = false++  local function query() return api.nvim_buf_get_lines(prompt_buf, 0, 1, false)[1] end++  local function refilter()+    p.query = query()+    local res = p.query == "" and {vim.list_slice(p.items, 1, h), {}}+                or fn.matchfuzzypos(p.items, p.query, {limit = h})+    p.matches = res[1]+    local lines = {}+    for row = 1, h do lines[row] = p.matches[h - row + 1] or "" end+    api.nvim_buf_set_lines(list_buf, 0, -1, false, lines)+    api.nvim_buf_clear_namespace(list_buf, ns, 0, -1)+    for i, positions in ipairs(res[2]) do+      for _, pos in ipairs(positions) do+        local col = vim.str_byteindex(p.matches[i], "utf-32", pos, false)+        api.nvim_buf_set_extmark(list_buf, ns, h - i, col, {end_col = col + 1, hl_group = "PickerMatch"})+      end+    end+    api.nvim_win_set_cursor(list_win, {h, 0})+  end++  local function close(choice)+    if done then return end+    done = true+    vim.cmd("stopinsert")+    pcall(api.nvim_win_close, prompt_win, true)+    pcall(api.nvim_win_close, list_win, true)+    vim.schedule(function()+      --- Leaving insert mode nudges the cursor left, code actions care about where it is+      pcall(api.nvim_win_set_cursor, orig_win, orig_cursor)+      on_choice(choice)+    end)+  end++  local function accept()+    --- TextChangedI waits for typeahead, so typing fast then <CR> can be stale+    if query() ~= p.query then refilter() end+    close(p.matches[h - api.nvim_win_get_cursor(list_win)[1] + 1])+  end++  local function move(d)+    return function()+      local row = api.nvim_win_get_cursor(list_win)[1] + d+      if row <= h and row > h - #p.matches then api.nvim_win_set_cursor(list_win, {row, 0}) end+    end+  end++  local keys = {["<CR>"] = accept,+                ["<Esc>"] = function() close() end,+                ["<C-c>"] = function() close() end,+                ["<Down>"] = move(1), ["<C-j>"] = move(1), ["<C-n>"] = move(1), ["<Tab>"] = move(1),+                ["<Up>"] = move(-1), ["<C-k>"] = move(-1), ["<C-p>"] = move(-1), ["<S-Tab>"] = move(-1)}+  for lhs, f in pairs(keys) do+    vim.keymap.set({"i", "n"}, lhs, f, {buffer = prompt_buf, nowait = true})+  end++  api.nvim_create_autocmd({"TextChangedI", "TextChanged"}, {buffer = prompt_buf, callback = refilter})+  api.nvim_create_autocmd("WinLeave", {buffer = prompt_buf, callback = function() close() end})++  function p.set_items(new)+    if not done then p.items = new; refilter() end+  end++  refilter()+  vim.cmd("startinsert")+  return p

Show all 133 lines

nvim/lua/utils/ui.lua deleted (view file)

@@ -1,18 +0,0 @@--local api = vim.api-local o = vim.o--local function open_fullscreen_window()-  local buf = api.nvim_create_buf(false, true)-  return api.nvim_open_win(buf, true, {-    relative = "editor",-    row = 0,-    col = 0,-    width = o.columns,-    height = o.lines,-    style = "minimal",-    border = "none"-  })-end--return {open_fullscreen_window = open_fullscreen_window}