axkirillov / easypick.nvim

A neovim plugin that lets you easily create Telescope pickers from arbitrary console commands
MIT License
373 stars 8 forks source link

Add option to adjust entry_maker #6

Closed peterfication closed 1 year ago

peterfication commented 1 year ago

So one can adjust the entries that are loaded from the external command.

I would be happy to provide a PR for this if it makes sense to you.

peterfication commented 1 year ago

I just made a PR as I had the changes made locally anyways: https://github.com/axkirillov/easypick.nvim/pull/7

axkirillov commented 1 year ago

Hey! Thank you for the submission! Can you share what are you using it for?

peterfication commented 1 year ago

Sure :) Even though it's very hacky still.

I want to have a Telescope command to show me all Git hunks. So not only the files like :Telescope git_status does, but each hunk, so you potentially see a file multiple times. I haven't found a ready made solution for that yet.

For that I have a script that reads git diff and outputs file names with line numbers:

output = `git --no-pager diff -U0`

exit if output == ''

files = output.split('diff --git')[1..]

hunks = files.flat_map do |file|
  file_name = file.split("\n")[0].split[-1].gsub('b/', '')
  file.split('@@ -').filter_map do |hunk|
    next unless hunk.include? '@@'

    hunk_lines = hunk.split("\n")
    line_number = hunk.split[1].split(',')[0].to_i
    hunk_title = hunk_lines[1]
    if hunk_title.gsub('+', '').gsub(' ', ' ') == '' && hunk_lines.length >= 2
      hunk_title = hunk_lines[2]
      line_number += 1
    end

    {
      file_name: file_name,
      line_number: line_number,
      file: file,
      hunk: hunk,
      title: hunk_title
    }
  end
end

output = `git ls-files --others --exclude-standard`
untracked_files = output.split("\n").map do |file_name|
  {
    file_name: file_name,
    line_number: 1
  }
end

hunks += untracked_files

hunks.each do |hunk|
  puts "#{hunk[:file_name]}:#{hunk[:line_number]} #{hunk[:title]}"
end

Then I need the entry_maker option to parse it properly:

      local easypick = require("easypick")

      easypick.setup({
        pickers = {
          {
            name = "git_hunks",
            command = "ruby ~/path/to/git.rb",
            previewer = require("telescope.previewers").vim_buffer_vimgrep.new({}),
            opts = {
              prompt_title = "Git hunks",
              initial_mode = 'insert',
            },
            entry_maker = function(entry)
              local filename, lnum_string = entry:match("([^:]+):(%d+).*")
              local lnum = tonumber(lnum_string)

              return {
                value = filename,
                display = entry,
                ordinal = entry,
                filename = filename,
                lnum = lnum,
              }
            end,
          }
        },
      })

The goal for me would be to have a small Telescope plugin in lua that does this.

Maybe there are easier built-in ways to achieve this but I haven't found them yet.

axkirillov commented 1 year ago

Ahhh, awesome! Sometimes I wish I had something like this, handling hunks but in a telescope-like fashion. I'll merge the pr.

peterfication commented 1 year ago

For anyone passing by here, I adjusted my config to use the Git contrib command git jump diff (this is without easypick though):

      local git_hunks = function()
        require("telescope.pickers")
          .new({
            finder = require("telescope.finders").new_oneshot_job({ "git", "jump", "--stdout", "diff" }, {
              entry_maker = function(line)
                local filename, lnum_string = line:match("([^:]+):(%d+).*")
                return {
                  value = filename,
                  display = line,
                  ordinal = line,
                  filename = filename,
                  lnum = tonumber(lnum_string),
                }
              end,
            }),
            sorter = require("telescope.sorters").get_generic_fuzzy_sorter(),
            previewer = require("telescope.config").values.grep_previewer({}),
            results_title = "Git hunks",
            prompt_title = "Git hunks",
            layout_strategy = "flex",
          }, {})
          :find()
      end

      vim.keymap.set("n", "<Leader>gs", git_hunks, {})