-
-
Notifications
You must be signed in to change notification settings - Fork 251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: auto load popups and auto populate help
popup
#601
Conversation
This allows less locations to edit when adding a new popup
1b4c1a2
to
35d39ac
Compare
This ensures that when new popups are added they are also visible in the help buffer and not forgotten, as well as working the same when accessed
35d39ac
to
f687001
Compare
Figured when working on #599 that I'd make it such that the This way it is easier to contribute new ones, as there were previously 3 different files oyu had to change to add one, now it is only one. This is almost ready, just have to fix the lints. |
Yeah, consolidating that is a great move. |
Yes, the help buffer is a lot more useful now and is guaranteed to work the same (rather than error out as a popup required an argument when starting, but was supplied |
It all works on my side, and the tests. Though it is quite a large change as it touches the status buffer, so let me know if you find anything |
lua/neogit/popups/echo/actions.lua
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this just for testing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is for a unit test inside M.test
lua/neogit/popups/init.lua
Outdated
---@param f nil|fun(create: fun(...)): any | ||
--- Creates a curried function which will open the popup with the given name when called | ||
function M.open(name, f) | ||
f = f or function(f) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain how this works and why? 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes absolutely.
It is a function which given a popup name will return a function (which takes 0 arguments) which will when called load the popup neogit.popups/{name}
module, and then pass its create
function to the second argument f
.
f
can then call the create
function with any arguments it likes, or whenever it wants.
I originally had it be plain argument, and create
was called inside the open
returned function instead, but this allows async and sleeping, as well as aborting the popup using the supplied function.
Essentially, this function will create a keymapping ready function, which will supply f
with the means to open the correct popup.
the f = f or function(create) create() end
will simply call the create
function directly with no arguments if no second argument is supplied. Most popups don't need any extra arguments, but some do, such as stashing.
The normal flow is
open
loads popup module
uses f
to help calling the popup.create
method.
In most cases, if the popup.create requires no special loading or arguments,
popup.open("my_awesome_popup") -> function() which opens popup
is enough
This is usually called lifting and creating a function which "fills in" some arguments and returns a function, eg function(a,b) -> function(b)
is called currying (partial application)
"Help", | ||
M.open("help", function(f) | ||
f { | ||
use_magit_keybindings = config.values.use_magit_keybindings, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little torn on this pattern of reaching into the status buffer for stuff. On the one hand, its a little cleaner than needing to pass the line into the constructor, but on the other hand it makes this function dependent on external state instead of passing that state in as an argument.
Not saying to change this, just voicing my thoughts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I am as well.
I usually go about coding with a domain driven approach. Some code lives in a certain domain/space, and can enter a smaller contained domain. Code usually becomes messier when a code enters a larger domain than which is was called from. Think of a graph which has to remain acyclic, like a tree.
The status buffer would need a bit of splitting like you did for the repository.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps splitting it as well into an init/view
and actions
and then using actions in other places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Splitting the status buffer up is a longer-term goal of mine, but it clearly will take some doing. It also pre-dates the buffer lib, so doesn't really take advantage of the library that all the popups/buffers do. Eventually I'd like the status buffer to not have a special place like it currently does, and just be one more view (albeit the "main" view), but given the size/complexity of it, thats not a simple undertaking. So, small bits here and there.
It may be a good middle-step to use the init/view
/actions
pattern - I'm not against that.
Generally I really like this - hopefully I'll make some time later to look in more detail. Left some comments, I can definitely tell you're more at home with functional style stuff than I am - I dig that. Nice to learn new stuff |
Everything looks great, except hitting All the other popups seems to work though :) |
That is strange. I am not getting that error, though it makes the popup close itself, likely a "race" between closing the previous popup and opening a new popup with the same name |
This behavior can be seen on master as well |
It can? The help popup comes up fine for me. (also, this is why we need better test coverage) |
Yes. What happens if you do For me that opens and then closes the help popup. There are definitely a lot of the older parts of the neogit that need to be fixed and are quite buggy and magic. |
Do you think the explaination of It is essentially to avoid doing repeatedly ["Foo"] = function() require("neogit.popups.foo").create() end, -- Most common usage
["Bar"] = function() require("neogit.popups.bar").create({ msg = input.read_message() }) end, and allows ["Foo"] = popups.open("foo"), -- Most common usage
["Bar"] = popus.open("bar", function(c) c({ msg = input.read_message() }) end), The invoked callback can also do something async and open the popup later as well. |
How about we merge this for now, and then fix any outlying errors afterwards? The contributing PR depends on this one, and having the contributing guide merged sooner than later would be preferred |
Lemme just verify the help popup is working first |
Ok, the problem was on my end: I had So, everything looks good, but maybe we can improve the error handling? |
Oh, great. I'll fix that then. What did |
lua/neogit/popups/init.lua
Outdated
"nv", | ||
M.open( | ||
"cherry_pick", | ||
async.void(function(f) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you verify that this needs to be async.void
? I'm not sure that it's needed, especially considering the revert popup isn't, and... they're real similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it needs to either, it was how it was at present.
The difference is that async.void may run on the next microtick, though not exactly sure. It should be immediate unless it needs that microframe delay for getting the visual selection. Will remove and tset
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, pretty sure I added that because I had no idea how async stuff worked when I did.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested it and it works without.
There is an error on master when doing AA
on a visual selection. More testing (again) would catch it
Error executing vim.schedule lua callback: ...share/nvim/lazy/plenary.nvim/lua/plenary/async/async.lua:18: The coroutine failed with this message: ...rs/teiroberts/dev/nvim/neogit/lua/neogit/lib/git/cli.lua:749: invalid value (table) at index 8 in table for 'concat'
stack traceback:
[C]: in function 'error'
...share/nvim/lazy/plenary.nvim/lua/plenary/async/async.lua:18: in function 'callback_or_next'
...share/nvim/lazy/plenary.nvim/lua/plenary/async/async.lua:45: in function <...share/nvim/lazy/plenary.nvim/lua/plenary/async/async.lua:44>
with If I add this to the mappings = {
status = {
["l"] = "Toggle",
["h"] = "Toggle",
},
},
Without that |
Oh that's interesting, so the require fails because setup code is run when the module is loaded, and that fails. I thought that require would only fail if not found, but I suppose it failing if anything errors makes sense, as lua allows generating modules entirely programmatically when loading instead of from a file (if you are crazy enough to do that and throw debuggabability out of the window) |
a31b775
to
d0e15b5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work :D
The error popup is a nice touch
vim.keymap.set('n', '<leader>gc', neogit.popups.open("commit")) Would be enough if you do not want to pass extra data to the popup create function. |
This allows less locations to edit when adding a new popup