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

feat: Ability to switch between loaded scopes

Open dpetka2001 opened this issue 1 year ago • 7 comments

I know you can currently can do something like Grapple cycle forward scope=name_of_scope, but it would be really nice if some kind of API would be made available to the user to cycle through the loaded scopes. Maybe something like Grapple cycle_loaded next/previous. This way I can just set specific keymaps that cycle through my loaded scopes instead of having to specify the scope that I want to cycle through.

dpetka2001 avatar Mar 18 '24 20:03 dpetka2001

I like this suggestion. One clarification, there are two UIs for scopes: one for the scopes and one for the loaded scopes. Were you referring to one in particular?

Scopes image

Loaded Scopes image

cbochs avatar Mar 20 '24 20:03 cbochs

I was referring to the second picture of Loaded Scopes, as like I understand it is the scopes that user has enabled by using the corresponding scopes from the first picture.

So, for example, if I open the first picture, I'm able to enable 2 scopes for a buffer by pressing <S-CR> on 2 different scopes (let's say cwd and git_branch). Then, in the loaded scopes window it will show these 2 scopes enabled by the user. What I was thinking is that instead of opening the loading scopes window, I could specify keymaps to cycle through next/prev loaded scope and have directly access to the tags of the currently used scope. That would also show in the lualine component of the plugin hopefully.

So just an API like cycle_loaded next/prev (or forward/backward like it already is when you do grapple cycle forward scope=name_of_scope). Because right now you have to specify the scope you want to cycle to. But in the loaded scopes you could maybe just do cycle_loaded forward/backward without specifying a scope. It would just cycle through the next/prev loaded scope of the ones that are present in the loaded scopes window.

dpetka2001 avatar Mar 20 '24 20:03 dpetka2001

So, for example, if I open the first picture, I'm able to enable 2 scopes for a buffer by pressing <S-CR> on 2 different scopes (let's say cwd and git_branch)

It might be good to clarify a couple things here.

The action <S-CR> is not necessarily "enabling", but instead changing the default scope used (the one set during Grapple.setup). There can only be one default scope in use at some point in time.

The Loaded Scopes window primarily shows information on which "tag containers" have been loaded. These "tag containers" have an ID (usually a pseudo file path), which is determined when a scope is "resolved".

For example, let's say you're in ~/git/grapple.nvim. The following scopes can resolve to something like:

  • Scope: git_branch > Resolved ID: ~/git/grapple.nvim:branch1 (git checkout branch1)
  • Scope: git_branch > Resolved ID: ~/git/grapple.nvim:branch2 (git checkout branch2)
  • Scope: git > Resolved ID: ~/git/grapple.nvim
  • Scope: cwd > Resolved ID ~/git/grapple.nvim
  • Scope: global > Resolved ID global

So, if you have selected or opened any tags for the git and global scopes then the Loaded Scopes window will show:

image

Now, if you select or open the cwd scope, since it resolved to the same ID your Loaded Scopes will not change since both git and cwd resolve to the same ID.

(or forward/backward like it already is when you do grapple cycle forward scope=name_of_scope).

To be honest, I'm beginning to warm up to the verbiage next and prev{ious}. I might think about soft-deprecating (forward, backward) for (next, prev).

Because right now you have to specify the scope you want to cycle to. But in the loaded scopes you could maybe just do cycle_loaded forward/backward without specifying a scope. It would just cycle through the next/prev loaded scope of the ones that are present in the loaded scopes window.

I like the idea of something like this:

---@param type "tags" | "scopes" | "loaded"
---@param direction "next" | "prev"
---@param opts? grapple.options | { name: string } | { id: string }
function Grapple.cycle(type, direction, opts)
    ...
end

With user command:

Grapple cycle {type} {direction} [opts...]

Where opts allows the user to specify a "starting point" (e.g. { index = 1 } for tags, { name = "git" } for scopes, { id = "global" } for loaded). This would of course be a breaking change, but might be worth the refactor.

cbochs avatar Mar 21 '24 04:03 cbochs

Now, if you select or open the cwd scope, since it resolved to the same ID your Loaded Scopes will not change since both git and cwd resolve to the same ID.

Thank you for this clarification. I wasn't aware of this, but just tried it and observed the behavior you're describing. Now I understand better the resolution of ID that happens behind the scenes. With that in mind, I believe it would be good if you documented the example you provided in your previous post about the resolution of IDs. That way it falls to the user to make sure to differentiate between different IDs in the loaded scopes window.

I really don't know what the best way to do it would be. I just saw that you enabled in loaded scopes window to show with <S-CR> only loaded scopes or even unloaded scopes. That means you keep some kind of state for the loaded scopes?

The purpose of the initial post (and after you clarified about how ID resolution happens) is something like the following workflow to be achieved (if possible of course, you're the one who maintains the code and I won't be expecting all users' requested features to be catered to): Let's say that the user is fully aware of the ID resolution that happens about how the loaded scopes window shows the loaded scopes. So, let's say the user has changed the default scope to the cwd scope and the global one with the different tags between the 2. So in the loaded scopes, you will see the ID of the resolved cwd scope and the global scope. Maybe the user will add another git branch scope in the future and it will also show in the loaded scopes window. I would like to assign 2 keymaps. 1 to go the next loaded scope and 1 to go the previous loaded scope from the IDs that are present in the loaded scopes window.

dpetka2001 avatar Mar 21 '24 09:03 dpetka2001

With that in mind, I believe it would be good if you documented the example you provided in your previous post about the resolution of IDs.

Will make sure to update!

That means you keep some kind of state for the loaded scopes?

Yup. And if you're curious it's right here 🙂

I would like to assign 2 keymaps. 1 to go the next loaded scope and 1 to go the previous loaded scope from the IDs that are present in the loaded scopes window.

I've made a few improvements recently to managing save files and the Loaded Scopes window (see: new keymaps in Loaded Scopes window and Grapple.prune). I think Grapple is in a good place to implement something along the lines of:

---@param type "tags" | "scopes" | "loaded"
---@param direction "next" | "prev"
---@param opts? grapple.options | { name: string } | { id: string }
function Grapple.cycle(type, direction, opts)
    ...
end

Then you could add your keybinds like:

vim.keymap.set("n", "", "<cmd>Grapple cycle loaded next<cr>")
vim.keymap.set("n", "", "<cmd>Grapple cycle loaded prev<cr>")

cbochs avatar Mar 21 '24 17:03 cbochs

Thank you very much for taking time to implement this. I look forward to its completion.

dpetka2001 avatar Mar 21 '24 18:03 dpetka2001

@dpetka2001 With 6c88bfde677036fd638fc11851383e370a374c69, Grapple now supports cycling through scopes. While you cannot cycle through scope IDs quite yet, you can accomplish the above workflow by hiding the scopes you do not use. For example,

Hide all scopes but global, git, and git_branch (see: grapple.scope_definition.shown:

require("grapple").setup({
    default_scopes = {
        git = { shown = true },
        git_branch = { shown = true },
        global = { shown = true },
    }

})

Cycle through the above three scopes with

require("grapple").cycle_scopes("next")
require("grapple").cycle_scopes("prev")

cbochs avatar Apr 27 '24 17:04 cbochs