nvim-telescope / telescope.nvim

Find, Filter, Preview, Pick. All lua, all the time.
MIT License
15.33k stars 821 forks source link

Combining grep_string and live_grep to a third option #1766

Open premell opened 2 years ago

premell commented 2 years ago

Whenever I want to search for a string I find it 50/50 whether I want to search for the string under the cursor or not. So instead of requiring the cognitive overhead of having two different keybindings for live_grep and grep_string, I'd suggest combining them (as a third option).

So when you search for a string it takes the string under the cursor, but has it grayed out like an auto complete suggestion. You can then easily press enter if you want to search for that word, or simply ignore it and type whatever.

pidgeon777 commented 2 years ago

Seems an interesting idea.

premell commented 2 years ago

I can add aswell that this is how most other IDE's work. For example if you do ctrl+shift+f in vscode or intellij, you automatically search for the word under the cursor. I'd prefer to have it greyed out but that is preference

ghost commented 2 years ago

I got nerd sniped trying to come up with a way to do this from what exists, and with some help from Gitter came up with this.

function _G.Cword()
    return vim.fn.expand("<cword>")
end

vim.cmd [[
    function! Cword(A, L, P)
        return v:lua.Cword()
    endfunction
]]

i_input = function() 
  vim.fn.input({
    prompt = 'Search term: ',
    completion = 'custom,Cword
  })
end

require('telescope.builtin.files').grep_string({search = i_input()})

Just press tab to enter the word under cursor as the search for grep_string. Alternatively replace completion in the input function with default to get the word under cursor already entered (but you have to backspace it out if you decide to search for something else).

If this is in a requirable module you should be able to make the return function not a global by adding require to the v:lua call, but I haven't tested it.

premell commented 2 years ago

thank you for your response. Unfortunately I am not able to get your code to work. I get the following error: image

danielo515 commented 2 years ago

this is not as fancy as having the term greyed out, but it works good enough for me:

-- utility function for the <C-f> find key
function M.grep_files(opts)
    opts = opts or {}
    local cwd = vim.fn.getcwd()
    local theme_opts = themes.get_ivy({
        sorting_strategy = "ascending",
        layout_strategy = "bottom_pane",
        prompt_prefix = ">> ",
        prompt_title = "~ Grep " .. cwd .. " ~",
        search_dirs = { cwd },
    })
    opts = vim.tbl_deep_extend("force", theme_opts, opts)
    vim.ui.input({
        default = vim.fn.expand("<cword>"),
    }, function(text)
        builtin.grep_string(vim.tbl_extend("force", opts, { search = text }))
    end)
end
AZanellato commented 2 years ago

This is one of the reasons I don't drop the fzf plugin. I want a separate search command and Telescope (from my understanding) doesn't offer that.

fdschmidt93 commented 2 years ago

Just skimming over this thread I think folks would probably best help themselves with something like this?

https://github.com/nvim-telescope/telescope.nvim/issues/1939

Seems cleaner and more "vimmy" to me than completion. Relatively easily implemented with your own little customization. You can pass an initial query to a picker via default_text. In brief, the idea is E: finishing this sentence, to launch the picker with the word under cursor in select mode. Then you can immediately overwrite if you want or just act on the mapping. Or add your own mapping to leave select mode and append or something.

In particular

local my_grep = function()
  local cword = vim.fn.expand("<cword>")
  require("telescope.builtin").live_grep({
    default_text = cword,
    on_complete = cword ~= "" and {
      function(picker)
        local mode = vim.fn.mode()
        local keys = mode ~= "n" and "<ESC>" or ""
        vim.api.nvim_feedkeys(
          vim.api.nvim_replace_termcodes(keys .. [[^v$<C-g>]], true, false, true),
          "n",
          true
        )
        -- should you have more callbacks, just pop the first one
        table.remove(picker._completion_callbacks, 1)
        -- copy mappings s.t. eg <C-n>, <C-p> works etc
        vim.tbl_map(function(mapping)
          vim.api.nvim_buf_set_keymap(0, "s", mapping.lhs, mapping.rhs, {})
        end, vim.api.nvim_buf_get_keymap(0, "i"))
      end,
    } or nil,
  })
end

seems to work reasonably well for me in 1 minute tests.

danielo515 commented 2 years ago

Just skimming over this thread I think folks would probably best help themselves with something like this?

1939

Seems cleaner and more "vimmy" to me than completion. Relatively easily implemented with your own little customization. You can pass an initial query to a picker via default_text. In brief, the idea is

In particular

local my_grep = function()
  local cword = vim.fn.expand("<cword>")
  require("telescope.builtin").live_grep({
    default_text = cword,
    on_complete = cword ~= "" and {
      function(picker)
        local mode = vim.fn.mode()
        local keys = mode ~= "n" and "<ESC>" or ""
        vim.api.nvim_feedkeys(
          vim.api.nvim_replace_termcodes(keys .. [[^v$<C-g>]], true, false, true),
          "n",
          true
        )
        -- should you have more callbacks, just pop the first one
        table.remove(picker._completion_callbacks, 1)
        -- copy mappings s.t. eg <C-n>, <C-p> works etc
        vim.tbl_map(function(mapping)
          vim.api.nvim_buf_set_keymap(0, "s", mapping.lhs, mapping.rhs, {})
        end, vim.api.nvim_buf_get_keymap(0, "i"))
      end,
    } or nil,
  })
end

seems to work reasonably well for me in 1 minute tests.

Thanks for the snippet. Can you explain a bit more? Does it open with the default text selected? Why does it need to remove the first picker completion callback? Accessing _properties makes me uncomfortable 😄 Also, why remap all the i mappings to select mode?

fdschmidt93 commented 2 years ago

Does it open with the default text selected?

If you have a word under the cursor yes, otherwise. Realized my previous comment was a bit incomplete.

Why does it need to remove the first picker completion callback?

You don't want to land in select mode every time you relaunch (i.e. type in the prompt) the finder. You could also write this without accessing _, but here I'm just making sure it shouldn't conflict with other callbacks you might have (I guess, well depends, might still conflict, best-effort to reduce likelihood).

Also, why remap all the i mappings to select mode?

Have you considered the code comment?

    -- copy mappings s.t. eg <C-n>, <C-p> works etc ? 

If the default_text is what you want, you would like to be able to move to a selection and select. That is not possible by default since telescope.nvim doesn't handle select mode mappings.

premell commented 2 years ago

Thank you for the snippet! It works wonders. There are some things I would personally add. For instance if you are in select mode, it should use the highlighted text instead of the word under the cursor.

My question now though, isnt this just a better in most situations than the current default? Sure anyone who wants to use it could just copy the snippet, but what do you think of either changing the default live grep or adding a new default picker?

fdschmidt93 commented 2 years ago

My question now though, isnt this just a better in most situations than the current default?

I agree it's a cool feature, but probably not, unless someone addresses

which is an enormous amount of work to get right etc. I encourage you to make your pitch in a feature request and subsequent PR (should request be well received). I'm afraid though I personally won't sit down to see this through, which easily is something between 2-20 hours of actual work until it's merged (hard to estimate).

Compare that to, being a bit knowledge about lua and neovim api/functions/etc, being able to implement yourself to your liking in 20mins or less. Consequently, I'm afraid maintenance/feature complexity trade-off is rather unfavorable.

premell commented 2 years ago

this is super user-specific -- user expectations here are not easily well defined

I would actually disagree with this though. This is the default behavior for several code editors, including vs code. Vscode is the most used code editor, so I wouldnt call it super user-specific. I would actually argue that most people would find the feature enjoyable and intuitive.

I do understand the other points though and I can see how its not worth to implement. I might try to work on it sometime if I get time over.

But thank you for your time, snippet and explanation.

danielo515 commented 2 years ago

@fdschmidt93 thank you very much for your snippet, your explanation and your time. This is probably abusing you, but I have a similar situation where, instead of using live-grep I use grep_string. In order to decide what to pass as search term I open a little vim.ui.input. I set it to have a default content of cword, however, this is not always desirable, and having to clear it before I can type anything in it is a bit cumbersome. Do you know if there is a similar solution to what you proposed? or maybe provide the input with an auto-completion of the current cword? I looked at the documentation, but doesn't seem to be an easy way to do this from lua.

Thanks

fdschmidt93 commented 2 years ago

or maybe provide the input with an auto-completion of the current cword

This should be possible, but highly dependent on how the vim.ui.input implementation handles the complete argument via custom or customlist (you can use v:lua, see :h v:lua via a global function). I at some point played around with this (though I don't recall whether that worked withdressing.nvim`, on the cmdline it worked).

For instance, the following works

x = function()
    return { "hello", "test" }
end
vim.fn.input({ prompt = "Enter: ", completion = "customlist,v:lua.x" })
-- analogously with some function of yours
vim.fn.input({ prompt = "Enter: ", completion = "customlist,v:lua.require'fds.utils'.complete" })

but I haven't gotten it to work with vim.ui.input (dressing.nvim) even though it should. I guess you can always fall back to vim.fn.input.

danielo515 commented 2 years ago

but I haven't gotten it to work with vim.ui.input (dressing.nvim) even though it should. I guess you can always fall back to vim.fn.input.

Yeah, that is the point, making it work with dressing.nvim. I tried to simplify the example provided at https://github.com/nvim-telescope/telescope.nvim/issues/1766#issuecomment-1090308814 and returning a fixed string works, but trying to expand the current cword does not. So, to put it in code:

-- this works
  vim.cmd [[
    function! Cword(A, L, P)
        return "hello"
    endfunction
]]

-- this does not

  vim.cmd [[
    function! Cword(A, L, P)
        let word = expand("<cword>")
        return word
    endfunction
]]

-- using it

  opts = vim.tbl_deep_extend("force", theme_opts, opts)
  vim.ui.input({
    completion = 'custom,Cword',
  }, function(text)
    builtin.grep_string(vim.tbl_extend("force", opts, { search = text }))
  end)
end

Never thought you can call lua from custom like that, I have to try it out

danielo515 commented 2 years ago

Yes, as you said completion = "customlist,v:lua.require'fds.utils'.complete" doesn't work at all. It complains that no such function called v:lua.require'fds.utils'.complete exists.

fdschmidt93 commented 2 years ago

Yes, as you said completion = "customlist,v:lua.require'fds.utils'.complete" doesn't work at all. It complains that no such function called v:lua.require'fds.utils'.complete exists.

Yes, because require'fds.utils'.complete is some function I wrote for testing in my namespace. I encourage you to do your own digging here, since I feel I've assisted your efforts to a (more than one) solution more than sufficiently.

danielo515 commented 1 year ago

Yes, indeed you did, and I'm very thankful for it. I just used your example to use the same context, but indeed I wrote my own function and tried with that. If I keep asking you here is because there is no other place that I know which is telescope specific. But yeah, let's leave the thread hijack

El vie., 10 jun. 2022 17:25, Fabian David Schmidt @.***> escribió:

Yes, as you said completion = "customlist,v:lua.require'fds.utils'.complete" doesn't work at all. It complains that no such function called v:lua.require'fds.utils'.complete exists.

Yes, because require'fds.utils'.complete is some function I wrote for testing in my namespace. I encourage you to do your own digging here, since I feel I've assisted your efforts to a (more than one) solution more than sufficiently.

— Reply to this email directly, view it on GitHub https://github.com/nvim-telescope/telescope.nvim/issues/1766#issuecomment-1152479848, or unsubscribe https://github.com/notifications/unsubscribe-auth/AARKJWML6GYVHSDDHH4VUVDVONNADANCNFSM5PVIRBYA . You are receiving this because you commented.Message ID: @.***>

justrajdeep commented 2 months ago

Very newbie here, how do i use this?