camspiers / snap

A fast finder system for neovim.
The Unlicense
490 stars 17 forks source link

Request: a mechanism for adding decorations to results #46

Open wbthomason opened 3 years ago

wbthomason commented 3 years ago

What do you think of adding a mechanism for rendering decorations (e.g. devicons, a score display, etc.) next to results of producers?

I took a stab at a hacky way of implementing this for devicons, which almost works:

local snap = require('snap')
local icons = require('nvim-web-devicons')
require('nvim-web-devicons').setup({default = true})

local function icons_consumer(producer)
  return function(request)
    local fnamemodify = vim.fn.fnamemodify
    local get_icon = icons.get_icon
    for results in snap.consume(producer, request) do
      if type(results) == 'table' then
        coroutine.yield(vim.tbl_map(function(path)
          local filename = snap.sync(function() return fnamemodify(path, ':t:r') end)
          local extension = snap.sync(function() return fnamemodify(path, ':e') end)
          local icon = get_icon(filename, extension)
          return icon .. ' ' .. path
        end, results))
      else
        coroutine.yield(nil)
      end
    end
  end
end

local function icon_remover(view)
  return function(request)
    local first_space = string.find(request.selection, ' ')
    request.selection = string.sub(request.selection, first_space + 1)
    view(request)
  end
end

snap.register.map('n', '<Leader>s', snap.create(function()
  return {
    prompt = 'Files',
    producer = snap.get('consumer.fzy')(icons_consumer(snap.get('producer.git.file'))),
    select = snap.get('select.file').select,
    multiselect = snap.get('select.file').multiselect,
    views = {icon_remover(snap.get('preview.file'))}
  }
end))

However, the previewer wrapped with icon_remover doesn't display anything, and it seems hacky to tack on and then remove the symbol to get e.g. the viewer, selecter, etc. to work correctly.

One thought is that there could be a special metadata item "decorations" or "decorator" - either a table of strings or a function taking a string or MetaResult as its argument - which the results display runs to get the "rendered" version of each result (which could naturally be cached for performance), without modifying the actual text of the result (as passed to a ViewProducer via request.selection, etc.)

Does that seem like something you'd like to add to snap/a reasonable approach to doing this?

beauwilliams commented 3 years ago

Yep, was just thinking of something similar related to this suggestion. Would also be nice to apply some form of sed to results. i.e sed s/\/Users\/admin\/.dotfiles\/nvim\///

So that you only get the filenames in the list not the paths.

I tried looking around but not sure if this is doable right now without some hacking around.

camspiers commented 3 years ago

I'm definitely going to implement this, just need some time.

beauwilliams commented 3 years ago

Wonderful. Things are moving along great no rush mate!

camspiers commented 3 years ago

@wbthomason Seems like a reasonable approach to me. We could add a display function to each meta result, and on around here: https://github.com/camspiers/snap/blob/main/fnl/snap/init.fnl#L293 call it if it exists instead of calling tostring on the table. The way we call it will be like how we call the positions function if it exists here: https://github.com/camspiers/snap/blob/main/fnl/snap/init.fnl#L330

camspiers commented 3 years ago

@wbthomason If you want to work on it please feel free!

wbthomason commented 3 years ago

I started on something in #47; however, there are still a few bugs remaining with it.