-
-
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
Changes from 7 commits
37991e3
2973302
f687001
8732bf5
9ec9c91
26526cf
6662b04
4119fb9
0d673ba
d0e15b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
CKolkey marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
local M = {} | ||
function M.echo(value) | ||
local notification = require("neogit.lib.notification") | ||
notification.create("Echo: " .. value) | ||
end | ||
|
||
return M |
CKolkey marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
local popup = require("neogit.lib.popup") | ||
local actions = require("neogit.popups.echo.actions") | ||
|
||
local M = {} | ||
|
||
function M.create(...) | ||
local args = { ... } | ||
local p = popup.builder():name("NeogitEchoPopup") | ||
for k, v in ipairs(args) do | ||
p:action(tostring(k), tostring(v), function() | ||
actions.echo(v) | ||
end) | ||
end | ||
|
||
local p = p:build() | ||
|
||
p:show() | ||
|
||
return p | ||
end | ||
|
||
return M |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
local M = {} | ||
|
||
---@param name string | ||
---@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 commentThe 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 commentThe 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
I originally had it be plain argument, and Essentially, this function will create a keymapping ready function, which will supply the The normal flow is
In most cases, if the popup.create requires no special loading or arguments,
This is usually called lifting and creating a function which "fills in" some arguments and returns a function, eg |
||
f() | ||
end | ||
|
||
return function() | ||
local ok, value = pcall(require, "neogit.popups." .. name) | ||
if ok then | ||
assert(value, "popup is not nil") | ||
assert(value.create, "popup has create function") | ||
|
||
f(value.create) | ||
else | ||
local notification = require("neogit.lib.notification") | ||
notification.create(string.format("No such popup: %q", name), vim.log.levels.ERROR) | ||
end | ||
end | ||
end | ||
|
||
--- Returns an array useful for creating mappings for the available popups | ||
---@return table<string, Mapping> | ||
function M.mappings_table() | ||
local config = require("neogit.config") | ||
local async = require("plenary.async") | ||
return { | ||
{ | ||
"HelpPopup", | ||
"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 commentThe 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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps splitting it as well into an There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
} | ||
end), | ||
}, | ||
{ "DiffPopup", "Diff", M.open("diff") }, | ||
{ "PullPopup", "Pull", M.open("pull") }, | ||
{ | ||
"RebasePopup", | ||
"Rebase", | ||
M.open("rebase", function(f) | ||
local status = require("neogit.status") | ||
local line = status.status_buffer:get_current_line() | ||
f { line[1]:match("^(%x%x%x%x%x%x%x+)") } | ||
end), | ||
}, | ||
{ "MergePopup", "Merge", M.open("merge") }, | ||
{ "PushPopup", "Push", M.open("push") }, | ||
{ "CommitPopup", "Commit", M.open("commit") }, | ||
{ "LogPopup", "Log", M.open("log") }, | ||
{ | ||
"CherryPickPopup", | ||
"Cherry Pick", | ||
{ | ||
"nv", | ||
M.open( | ||
"cherry_pick", | ||
async.void(function(f) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you verify that this needs to be There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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 commentThe 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 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>
|
||
local selection = nil | ||
|
||
if vim.api.nvim_get_mode().mode == "V" then | ||
local status = require("neogit.status") | ||
selection = status.get_selected_commits() | ||
end | ||
|
||
f { commits = selection } | ||
end) | ||
), | ||
true, | ||
}, | ||
}, | ||
{ "BranchPopup", "Branch", M.open("branch") }, | ||
{ "FetchPopup", "Fetch", M.open("fetch") }, | ||
{ "ResetPopup", "Reset", M.open("reset") }, | ||
{ | ||
"RevertPopup", | ||
"Revert", | ||
M.open("revert", function(f) | ||
local status = require("neogit.status") | ||
local line = status.status_buffer:get_current_line() | ||
f { commits = { line[1]:match("^(%x%x%x%x%x%x%x+)") } } | ||
end), | ||
}, | ||
{ "RemotePopup", "Remote", M.open("remote") }, | ||
{ | ||
"StashPopup", | ||
"Stash", | ||
M.open("stash", function(f) | ||
local status = require("neogit.status") | ||
local line = status.status_buffer:get_current_line() | ||
f { | ||
name = line[1]:match("^(stash@{%d+})"), | ||
} | ||
end), | ||
}, | ||
} | ||
end | ||
|
||
function M.test() | ||
M.open("echo", function(f) | ||
f("a", "b") | ||
end)() | ||
end | ||
|
||
return M |
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