Skip to content

Commit 4956b91

Browse files
committed
feat(branch): added interactive list to select branches
1 parent 63c52ac commit 4956b91

File tree

5 files changed

+177
-17
lines changed

5 files changed

+177
-17
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
local Buffer = require("neogit.lib.buffer")
2+
local ui = require 'neogit.buffers.branch_select_view.ui'
3+
4+
local M = {}
5+
6+
-- @class BranchSelectViewBuffer
7+
-- @field branches the branches list
8+
-- @field action action dispatched by line selection
9+
-- @field buffer Buffer
10+
-- @see Buffer
11+
--
12+
--- Creates a new BranchSelectViewBuffer
13+
-- @param branches
14+
-- @param action
15+
-- @return BranchSelectViewBuffer
16+
function M.new(branches, action)
17+
local instance = {
18+
action = action,
19+
branches = branches,
20+
buffer = nil
21+
}
22+
23+
setmetatable(instance, { __index = M })
24+
25+
return instance
26+
end
27+
28+
function M:close()
29+
self.buffer:close()
30+
self.buffer = nil
31+
end
32+
33+
function M:open()
34+
self.buffer = Buffer.create {
35+
name = "NeogitBranchSelectView",
36+
filetype = "NeogitBranchSelectView",
37+
kind = "split",
38+
mappings = {
39+
n = {
40+
["<enter>"] = function(buffer)
41+
local current_line = buffer:get_current_line()
42+
local branch_name = current_line[1]
43+
if self.action then
44+
self.action(branch_name)
45+
end
46+
self:close()
47+
end,
48+
}
49+
},
50+
render = function()
51+
return ui.View(self.branches)
52+
end
53+
}
54+
end
55+
56+
return M
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
local Ui = require 'neogit.lib.ui'
2+
local util = require 'neogit.lib.util'
3+
4+
local row = Ui.row
5+
local text = Ui.text
6+
local map = util.map
7+
8+
local M = {}
9+
10+
function M.View(branches)
11+
return map(branches, function(branch_name)
12+
return row{
13+
text(branch_name)
14+
}
15+
end)
16+
end
17+
18+
return M

lua/neogit/lib/git/branch.lua

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,18 @@ local function parse_branches(branches)
1515
return other_branches
1616
end
1717

18-
local function get_local_branches()
18+
function M.get_local_branches()
1919
local branches = cli.branch
2020
.list
21-
.call()
21+
.call_sync()
22+
23+
return parse_branches(branches)
24+
end
25+
26+
function M.get_remote_branches()
27+
local branches = cli.branch
28+
.remotes
29+
.call_sync()
2230

2331
return parse_branches(branches)
2432
end
@@ -27,7 +35,7 @@ function M.get_all_branches()
2735
local branches = cli.branch
2836
.list
2937
.all
30-
.call()
38+
.call_sync()
3139

3240
return parse_branches(branches)
3341
end
@@ -64,7 +72,7 @@ function M.prompt_for_branch(options)
6472
end
6573

6674
function M.checkout_local()
67-
local branches = get_local_branches()
75+
local branches = M.get_local_branches()
6876

6977
a.util.scheduler()
7078
local chosen = M.prompt_for_branch(branches)
@@ -111,4 +119,12 @@ function M.checkout_new()
111119
cli.interactive_git_cmd(tostring(cli.checkout.new_branch(name)))
112120
end
113121

122+
function M.current()
123+
local branch_name = cli.branch.current.call_sync()
124+
if #branch_name > 0 then
125+
return branch_name[1]
126+
end
127+
return nil
128+
end
129+
114130
return M

lua/neogit/lib/git/cli.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ local configurations = {
120120
return function (branch)
121121
return tbl.b(branch)
122122
end
123+
end,
124+
new_branch_with_start_point = function (tbl)
125+
return function (branch, start_point)
126+
return tbl.args(branch, start_point).b()
127+
end
123128
end
124129
}
125130
}),
@@ -195,6 +200,7 @@ local configurations = {
195200
remotes = '-r',
196201
current = '--show-current',
197202
very_verbose = '-vv',
203+
move = '-m',
198204
},
199205
aliases = {
200206
name = function (tbl)

lua/neogit/popups/branch.lua

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,29 @@ local cli = require 'neogit.lib.git.cli'
44
local popup = require('neogit.lib.popup')
55
local branch = require('neogit.lib.git.branch')
66
local operation = require('neogit.operations')
7+
local BranchSelectViewBuffer = require 'neogit.buffers.branch_select_view'
8+
local input = require('neogit.lib.input')
9+
10+
local function format_branches(list)
11+
local branches = {}
12+
for _,name in ipairs(list) do
13+
local name_formatted = name:match("^remotes/(.*)") or name
14+
if not name_formatted:match('^(.*)/HEAD') then
15+
table.insert(branches, name_formatted)
16+
end
17+
end
18+
return branches
19+
end
20+
21+
local function parse_remote_branch_name(remote_name)
22+
local offset = remote_name:find('/')
23+
if not offset then return nil, nil end
24+
25+
local remote = remote_name:sub(1, offset-1)
26+
local branch_name = remote_name:sub(offset+1, remote_name:len())
27+
28+
return remote, branch_name
29+
end
730

831
function M.create()
932
local p = popup.builder()
@@ -13,27 +36,68 @@ function M.create()
1336
status.refresh(true)
1437
end))
1538
:action("b", "checkout branch/revision", operation('checkout_branch', function ()
16-
branch.checkout()
17-
status.refresh(true)
39+
local branches = format_branches(branch.get_all_branches())
40+
BranchSelectViewBuffer.new(branches, function (selected_branch)
41+
if selected_branch == '' then return end
42+
43+
cli.checkout.branch(selected_branch).call_sync()
44+
status.dispatch_refresh(true)
45+
end):open()
1846
end))
1947
:action("d", "delete local branch", operation('delete_branch', function ()
20-
branch.delete()
21-
status.refresh(true)
48+
local branches = branch.get_local_branches()
49+
BranchSelectViewBuffer.new(branches, function (selected_branch)
50+
cli.branch.delete.name(selected_branch).call_sync()
51+
status.dispatch_refresh(true)
52+
end):open()
2253
end))
2354
:action("D", "delete local branch and remote", operation('delete_branch', function ()
24-
local branch = branch.delete()
25-
if branch and branch ~= '' then
26-
cli.interactive_git_cmd(tostring(cli.push.remote("origin").delete.to(branch)))
27-
end
28-
status.refresh(true)
55+
local branches = format_branches(branch.get_remote_branches())
56+
BranchSelectViewBuffer.new(branches, function (selected_branch)
57+
if selected_branch == '' then return end
58+
59+
local remote, branch_name = parse_remote_branch_name(selected_branch)
60+
if not remote or not branch_name then return end
61+
62+
cli.branch.delete.name(branch_name).call_sync()
63+
cli.push.remote(remote).delete.to(branch_name).call_sync()
64+
status.dispatch_refresh(true)
65+
end):open()
2966
end))
3067
:action("l", "checkout local branch", operation('checkout_local-branch', function ()
31-
branch.checkout_local()
32-
status.refresh(true)
68+
local branches = branch.get_local_branches()
69+
BranchSelectViewBuffer.new(branches, function (selected_branch)
70+
if selected_branch == '' then return end
71+
cli.checkout.branch(selected_branch).call_sync()
72+
status.dispatch_refresh(true)
73+
end):open()
3374
end))
3475
:action("c", "checkout new branch", operation('checkout_create-branch', function ()
35-
branch.checkout_new()
36-
status.refresh(true)
76+
local branches = format_branches(branch.get_all_branches())
77+
BranchSelectViewBuffer.new(branches, function(selected_branch)
78+
if selected_branch == '' then return end
79+
80+
local name = input.get_user_input('branch > ')
81+
if not name or name == '' then return end
82+
83+
cli.checkout.new_branch_with_start_point(name, selected_branch).call_sync()
84+
status.dispatch_refresh(true)
85+
end):open()
86+
end))
87+
:action("m", "rename branch", operation('rename_branch', function ()
88+
local current_branch = branch.current() or ''
89+
local branches = branch.get_local_branches()
90+
table.insert(branches, current_branch)
91+
92+
BranchSelectViewBuffer.new(branches, function (selected_branch)
93+
if selected_branch == '' then return end
94+
95+
local new_name = input.get_user_input('new branch name > ')
96+
if not new_name or new_name == '' then return end
97+
98+
cli.branch.move.args(selected_branch, new_name).call_sync()
99+
status.dispatch_refresh(true)
100+
end):open()
37101
end))
38102
:build()
39103

0 commit comments

Comments
 (0)