telescope.nvim icon indicating copy to clipboard operation
telescope.nvim copied to clipboard

Builtin Vim commands

Open janpeterd opened this issue 1 year ago • 15 comments

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

janpeterd avatar Dec 02 '23 14:12 janpeterd

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

jamestrew avatar Dec 02 '23 21:12 jamestrew

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.

mortezadadgar avatar Dec 17 '23 17:12 mortezadadgar

Yeah that could probably work.

Adding sort_lastused would be a little more involved.

jamestrew avatar Dec 17 '23 20:12 jamestrew

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

MovieMaker93 avatar Dec 18 '23 19:12 MovieMaker93

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.

jamestrew avatar Dec 19 '23 00:12 jamestrew

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

MovieMaker93 avatar Dec 19 '23 17:12 MovieMaker93

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.

jamestrew avatar Dec 19 '23 23:12 jamestrew

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?

MovieMaker93 avatar Dec 20 '23 02:12 MovieMaker93

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.

jamestrew avatar Dec 20 '23 14:12 jamestrew

@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.

MovieMaker93 avatar Dec 20 '23 18:12 MovieMaker93

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.

jamestrew avatar Dec 21 '23 01:12 jamestrew

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

rudiejd avatar Dec 23 '23 21:12 rudiejd

@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 avatar Dec 23 '23 22:12 jamestrew

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.

jamestrew avatar Jan 07 '24 04:01 jamestrew

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

MovieMaker93 avatar May 08 '24 20:05 MovieMaker93