nvim-telescope / telescope.nvim

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

Builtin Vim commands #2803

Open janpeterd opened 11 months ago

janpeterd commented 11 months ago

Is your feature request related to a problem? Please describe. I often forget or want to browse through the native VIM commands (like find, vimgrep, ...). I know that these are all described in the help pages, but these pages are filled with other information that I don't want to filter through when I try to find a command.

Describe the solution you'd like I think that adding an option to the builtin.commands to include VIM commands would be a improvement. The tricky thing is what info to display in the other columns. I don't really know what information you can get about these commands, so just having a description or the help page, or nothing would be fine for me.

Describe alternatives you've considered Alternatively a separate builtin called vim_commands or something would solve the issue.

Additional context This image shows that builtin vim commands aren't included in builtin.commands. afbeelding

jamestrew commented 11 months ago

I'm not sure if there's an easy way to do this. In my very quick looking around, I don't see a way to get a list of all Ex commands. The nvim_get_commands function which we use for builtin.commands explicitly states they don't currently support getting builtin Ex commands.

If there is a command/function available to fetch all Ex commands, I think this will be a good value add to telescope.

see :h :index

mortezadadgar commented 11 months ago

By quickly taking a look at cmp-cmdline source cde turn out that vim.fn.getcompletion("", "cmdline"))) can be used to get a list of all possible cmdline items. adding this and a sort_lastused option could make commands picker to be used as like emacs's minibuffer.

jamestrew commented 11 months ago

Yeah that could probably work.

Adding sort_lastused would be a little more involved.

MovieMaker93 commented 11 months ago

If you don't mind, I'd like to take on this issue, but it is my first attempt to contribute to the Nvim ecosystem. So, I would appreciate some guidance on how to move forward on this issue. First, how can I test the plugin on my local machine (and debug it)? Then, I quickly watched the code, and based on the comments above, I should add to this:

      finder = finders.new_table {
        results = (function()
          local command_iter = vim.api.nvim_get_commands {}
          local commands = {}

          for _, cmd in pairs(command_iter) do
            table.insert(commands, cmd)
          end

the vim.fn.getcompletion("", "cmdline"))) that returns a list of all the Ex commands. What I don't get is adding the sort_lastused option. Is it necessary for the enhancement? Have I found the correct location where to insert the getcompletition list? Thanks

jamestrew commented 11 months ago

For sure, go for it.

For developing/testing/debugging, you can fork a copy and clone to some directory. Then (for lazy) use the dir option to point to your forked copy of telescope:

{
  "nvim-telescope/telescope.nvim",
  dir = "path/to/your/telescope.nvim",
  -- ...other options
}

Generally for something like this I just relaunch neovim to test changes and use vim.print/print to "log" stuff. There's more sophisticated approaches but it's shouldn't be necessary here.

As for the code location, you got it. That anonymous function results = (function() ... end())() needs to return a list of the commands we want telescope to search over. I think all you need to do is swap vim.api.nvim_get_commands {} for vim.fn.getcompletion("", "cmdline") (or is it the "command" option?) making sure getcompletion has a superset of the command from nvim_get_commands.

If the show_buf_command option is false, you'll have to remove those commands (nvim_buf_get_commands) from the list of commands.

I think that's pretty much it. Don't worry about the sort_lastused option for now.

MovieMaker93 commented 11 months ago

For sure, go for it.

For developing/testing/debugging, you can fork a copy and clone to some directory. Then (for lazy) use the dir option to point to your forked copy of telescope:

{
  "nvim-telescope/telescope.nvim",
  dir = "path/to/your/telescope.nvim",
  -- ...other options
}

Generally, for something like this, I just relaunch neovim to test changes and use vim.print/print to "log" stuff. There's more sophisticated approaches but it's shouldn't be necessary here.

As for the code location, you got it. That anonymous function results = (function() ... end())() needs to return a list of the commands we want telescope to search over. I think all you need to do is swap vim.api.nvim_get_commands {} for vim.fn.getcompletion("", "cmdline") (or is it the "command" option?) making sure getcompletion has a superset of the command from nvim_get_commands.

If the show_buf_command option is false, you'll have to remove those commands (nvim_buf_get_commands) from the list of commands.

I think that's pretty much it. Don't worry about the sort_lastused option for now.

There are some differences between the actual behaviour of vim.api.nvim_get_commands {} and the vim.fn.getcompletion("", "cmdline"). The first command returns a list of command names, and each command name has a list of values like this one: { Alpha = { bang = true, bar = true, definition = 'require"alpha".start(false)', keepscript = false, name = "Alpha", nargs = "0", preview = false, register = false, script_id = -8 }, The same command above with the vim.fn.getcompletion("", "cmdline") return only the list of command names without specifying a list of value for each one like: Alpha Therefore, there are some modifications to address:

  1. The actual entry_marker logic won't work anymore (needs to be reworked or deleted)
  2. The different logic based on the value of the selection: if val.nargs == "0" can't be handled due to the lack of this information

In my opinion, the solution could be:

  1. Remove the entry_marker logic or think another one (we need to display only the names)
  2. Remove the logic based on the nargs value

What do you think? Do you think I should proceed further?

Thanks

jamestrew commented 11 months ago

Hmm yeah you're right. Upon closer inspection, looks like we need more info than just the command name (goes to show how little I use the commands picker :joy:). In that case I think we're back to finding some way to get a list of all Ex commands + the auxiliary info for them.

MovieMaker93 commented 11 months ago

Hmm yeah you're right. Upon closer inspection, looks like we need more info than just the command name (goes to show how little I use the commands picker 😂). In that case I think we're back to finding some way to get a list of all Ex commands + the auxiliary info for them.

Maybe we could use vim.fn.getcompletion("", "cmdline") paired with the function vim.api.nvim_parse_cmd that gets in input the name of the command and returns all the info. Therefore, the flow could be like this:

  1. Gets command names with vim.fn.getcompletion("", "cmdline")
  2. Construct the dictionary with as key the name of the command and value as the return type of vim.api.nvim_parse_cmd
  3. Adds this dictionary to the table commands

After those steps, I guess we can keep the existing entry and selection logic without further modification. Could this be a viable implementation?

jamestrew commented 11 months ago

That could work, but I'm a little bit unsure about the performance implications of calling nvim_parse_cmd hundreds of times. If you're willing to give it a try to see that'll be great. But I agree, this should help avoid significant modifications to the entry maker and selection logic, which I prefer.

MovieMaker93 commented 11 months ago

@jamestrew Besides the performance implication (slower for sure), I didn't manage to get a proper working solution. Some of the Ex commands give an error when passed to the nvim_parse_cmd() function like:

      local command_iter = vim.fn.getcompletion("", "cmdline")
          local commands_formatted = {}

          for _, cmd in pairs(command_iter) do
            local command_parse = {}
            if
              cmd ~= "keepjumps"
              and cmd ~= "keepalt"
              and cmd ~= "horizontal"
              and cmd ~= "confirm"
              and cmd ~= "browse"
              and cmd ~= "botright"
              and cmd ~= "aboveleft"
              and cmd ~= "belowright"
            then
              command_parse = vim.api.nvim_parse_cmd(cmd, {})
              commands_formatted[cmd] = command_parse
              -- table.insert(commands, commands_formatted)
            end
          end

You can clearly see that I've tried to skip some of the problematics, but every time, I caught another problematic parse command error. Maybe that's the reason why the nvim_get_commands() doesn't include Ex commands :) We need to investigate further for another solution I guess.

jamestrew commented 11 months ago

Yeah those look like command modifiers so they aren't really valid standalone commands. I suppose we can wrap the nvim_parse_cmd call inside a pcall but definitely feels like we're getting into a very hacky territory.

I don't have a ton of ideas at the moment. It might be better just to wait for vim.api.nvim_get_commands({ builtin = true }) to become supported.

rudiejd commented 11 months ago

why not just show the help page (could copy the code from Telescope helptags) for the builtin command instead of showing modifiers?

jamestrew commented 11 months ago

@rudiejd we'd still need to know nargs to know what to do when a command is selected in telescope (call directly or wait for args to be passed).

jamestrew commented 10 months ago

slightly related but just learned about https://github.com/jonarrien/telescope-cmdline.nvim haven't tried it myself yet but looks pretty cool. gonna try it out.

MovieMaker93 commented 6 months ago

slightly related but just learned about https://github.com/jonarrien/telescope-cmdline.nvim haven't tried it myself yet but looks pretty cool. gonna try it out

After checking the code, I figured out he uses the pcall wrapper for the cmdline system command:

local run = function(cmd)
  if tonumber(cmd) then
    vim.api.nvim_exec2(cmd, {})
    return
  end

  vim.fn.histadd("cmd", cmd)

  local cmd_ok, nvim_cmd = pcall(vim.api.nvim_parse_cmd, cmd, {})
  if not cmd_ok then
    vim.notify('Invalid command: ' .. cmd, vim.log.levels.ERROR, {})
    return
  end