nirish

config files for niri window manager
Log | Files | Refs | README | LICENSE

find.lua (3434B)


      1 --[[
      2     This file is an internal file-browser addon.
      3     It should not be imported like a normal module.
      4 
      5     Allows searching the current directory.
      6 ]]--
      7 
      8 local msg = require "mp.msg"
      9 local fb = require "file-browser"
     10 local input_loaded, input = pcall(require, "mp.input")
     11 local user_input_loaded, user_input = pcall(require, "user-input-module")
     12 
     13 ---@type ParserConfig
     14 local find = {
     15     api_version = "1.3.0"
     16 }
     17 
     18 ---@type thread|nil
     19 local latest_coroutine = nil
     20 
     21 ---@type State
     22 local global_fb_state = getmetatable(fb.get_state()).__original
     23 
     24 ---@param name string
     25 ---@param query string
     26 ---@return boolean
     27 local function compare(name, query)
     28     if name:find(query) then return true end
     29     if name:lower():find(query) then return true end
     30     if name:upper():find(query) then return true end
     31 
     32     return false
     33 end
     34 
     35 ---@async
     36 ---@param key Keybind
     37 ---@param state State
     38 ---@param co thread
     39 ---@return boolean?
     40 local function main(key, state, co)
     41     if not state.list then return false end
     42 
     43     ---@type string
     44     local text
     45     if key.name == "find/find" then text = "Find: enter search string"
     46     else text = "Find: enter advanced search string" end
     47 
     48     if input_loaded then
     49         input.get({
     50             prompt = text .. "\n>",
     51             id = "file-browser/find",
     52             submit = fb.coroutine.callback(),
     53         })
     54     elseif user_input_loaded then
     55         user_input.get_user_input( fb.coroutine.callback(), { text = text, id = "find", replace = true } )
     56     end
     57 
     58     local query, error = coroutine.yield()
     59     if input_loaded then input.terminate() end
     60     if not query then return msg.debug(error) end
     61 
     62     -- allow the directory to be changed before this point
     63     local list = fb.get_list()
     64     local parse_id = global_fb_state.co
     65 
     66     if key.name == "find/find" then
     67         query = fb.pattern_escape(query)
     68     end
     69 
     70     local results = {}
     71 
     72     for index, item in ipairs(list) do
     73         if compare(item.label or item.name, query) then
     74             table.insert(results, index)
     75         end
     76     end
     77 
     78     if (#results < 1) then
     79         msg.warn("No matching items for '"..query.."'")
     80         return
     81     end
     82 
     83     --keep cycling through the search results if any are found
     84     --putting this into a separate coroutine removes any passthrough ambiguity
     85     --the final return statement should return to `step_find` not any other function
     86     ---@async
     87     fb.coroutine.run(function()
     88         latest_coroutine = coroutine.running()
     89         ---@type number
     90         local rindex = 1
     91         while (true) do
     92 
     93             if rindex == 0 then rindex = #results
     94             elseif rindex == #results + 1 then rindex = 1 end
     95 
     96             fb.set_selected_index(results[rindex])
     97             local direction = coroutine.yield(true) --[[@as number]]
     98             rindex = rindex + direction
     99 
    100             if parse_id ~= global_fb_state.co then
    101                 latest_coroutine = nil
    102                 return
    103             end
    104         end
    105     end)
    106 end
    107 
    108 local function step_find(key)
    109     if not latest_coroutine then return false end
    110     ---@type number
    111     local direction = 0
    112     if key.name == "find/next" then direction = 1
    113     elseif key.name == "find/prev" then direction = -1 end
    114     return fb.coroutine.resume_err(latest_coroutine, direction)
    115 end
    116 
    117 find.keybinds = {
    118     {"Ctrl+f", "find", main, {}},
    119     {"Ctrl+F", "find_advanced", main, {}},
    120     {"n", "next", step_find, {}},
    121     {"N", "prev", step_find, {}},
    122 }
    123 
    124 return find