Scripts/New-FGBranchExplorer.ps1
function New-FGBranchExplorer($Root) { $Explorer = [PowerShellFar.PowerExplorer]::new("71ebb500-c8e1-4544-827a-8456c3611f8e") $Explorer.Data = @{ Root = $Root SetCurrentOnce = $true FileDescriptions = @{} } $Explorer.Functions = 'CreateFile, DeleteFiles, RenameFile' $Explorer.AsCreateFile = {FGBranchExplorer_AsCreateFile @args} $Explorer.AsCreatePanel = {FGBranchExplorer_AsCreatePanel @args} $Explorer.AsDeleteFiles = {FGBranchExplorer_AsDeleteFiles @args} $Explorer.AsGetFiles = {FGBranchExplorer_AsGetFiles @args} $Explorer.AsRenameFile = {FGBranchExplorer_AsRenameFile @args} $Explorer } function FGBranchExplorer_AsCreatePanel($Explorer) { $panel = [FarNet.Panel]$Explorer $panel.Title = "Branches: $($Explorer.Data.Root)" $panel.ViewMode = 0 $panel.SortMode = 'Unsorted' $Explorer.Data.Panel = $panel $co = [FarNet.SetColumn]@{ Kind = "O"; Name = "Current"; Width = 1 } $cn = [FarNet.SetColumn]@{ Kind = "N"; Name = "Branch" } $cd = [FarNet.SetColumn]@{ Kind = "Z"; Name = "Commit" } $plan0 = [FarNet.PanelPlan]::new() $plan0.Columns = $co, $cn, $cd $panel.SetPlan(0, $plan0) $plan1 = $plan0.Clone() $plan1.IsFullScreen = $true $panel.SetPlan(9, $plan1) $panel.add_KeyPressed({ ### [Enter] checkout branch if ($_.Key.Is([FarNet.KeyCode]::Enter)) { $_.Ignore = $true $file = $this.CurrentFile # skip the current branch if (!$file -or $file.Owner) { return } $name = $file.Name if ($name.StartsWith('remotes/')) { $res = Invoke-Error {git -C $this.Explorer.Data.Root checkout -t $name} } else { $res = Invoke-Error {git -C $this.Explorer.Data.Root checkout $name} } if ($LASTEXITCODE) { throw $res } $this.Update($true) $this.Redraw() return } ### [F3] gitk branch if ($_.Key.Is([FarNet.KeyCode]::F3)) { $_.Ignore = $true $file = $this.CurrentFile # skip the detached branch if (!$file -or $file.Name -like '(*)') { return } Push-Location -LiteralPath $this.Explorer.Data.Root gitk $file.Name Pop-Location return } }) $panel } function FGBranchExplorer_AsGetFiles($Explorer) { # use and drop files prepared by the task if ($Explorer.Data.Files) { $Explorer.Data.Files $Explorer.Data.Files = $null return } # get git branches $res = Invoke-Error {git -C $Explorer.Data.Root branch -a --list --quiet} if ($LASTEXITCODE) { throw $res } # make files, use cached descriptions to avoid blanks in some cases $Files = [System.Collections.Generic.List[object]]@() foreach($line in $res) { if ($line.Contains('->')) { continue } if ($line -notmatch '^(\*)?\s*(.+)') { continue } $name = $Matches[2] $file = New-FarFile -Name $name -Description $Explorer.Data.FileDescriptions[$name] if ($Matches[1]) { # mark current branch if (Invoke-Error {git status -s}) { $file.Owner = '>' } else { $file.Owner = '*' } # set current panel file if ($Explorer.Data.SetCurrentOnce) { $Explorer.Data.Panel.PostName($name) $Explorer.Data.SetCurrentOnce = $false } } $Files.Add($file) } $Files # get descriptions, skip remotes and detached branches Start-FarTask -Data Explorer, Files { . $PSScriptRoot\Basic.ps1 foreach($file in $Data.Files) { if ($file.Name -notlike 'remotes/*' -and $file.Name -notlike '(*)') { $description = Invoke-Error {git -C $Data.Explorer.Data.Root log --pretty=format:%s -1 $file.Name} $file.Description = $description $Data.Explorer.Data.FileDescriptions[$file.Name] = $description } } job { $Data.Explorer.Data.Files = $Data.Files $Data.Explorer.Data.Panel.Update($true) $Data.Explorer.Data.Panel.Redraw() } } } function FGBranchExplorer_AsCreateFile($Explorer, $2) { $oldBranch = Invoke-Error {git -C $Explorer.Data.Root branch --show-current} if ($LASTEXITCODE) { throw $oldBranch } $newBranch = $Far.Input('New branch name', 'GitBranch', "New branch from $oldBranch") if (!$newBranch) { $2.Result = 'Ignore' return } $res = Invoke-Error {git -C $Explorer.Data.Root checkout -b $newBranch} if ($LASTEXITCODE) { $2.Result = 'Ignore' Show-FarMessage "Error on create branch $newBranch`n$res" -Caption FarGit -LeftAligned -IsWarning } } function FGBranchExplorer_AsDeleteFiles($Explorer, $2) { # ask if ($2.UI) { $text = @" $($2.Files.Count) branch(es): $($2.Files -join "`n") "@ if (Show-FarMessage $text Delete YesNo -LeftAligned) { $2.Result = 'Ignore' return } } # delete foreach($file in $2.Files) { $branch = $file.Name $remote = '' if ($branch -match '^remotes/(?<remote>[^/]+)/(?<branch>.+)') { $branch = $Matches.branch $remote = $Matches.remote } $res = Invoke-Error { if ($remote) { git -C $Explorer.Data.Root push $remote --delete $branch } elseif ($2.Force) { git -C $Explorer.Data.Root branch -D $branch } else { git -C $Explorer.Data.Root branch -d $branch } $Explorer.Data.FileDescriptions.Remove($branch) } if ($LASTEXITCODE) { $2.Result = 'Incomplete' $2.FilesToStay.Add($file) if ($2.UI) { Show-FarMessage "Error on delete branch $branch`n$res" -Caption FarGit -LeftAligned -IsWarning } } } } function FGBranchExplorer_AsRenameFile($Explorer, $2) { $oldName = $2.File.Name $newName = ([string]$Far.Input('New branch name', 'GitBranch', 'Rename branch', $oldName)).Trim() if (!$newName) { $2.Result = 'Ignore' return } $res = Invoke-Error {git -C $Explorer.Data.Root branch -m $oldName $newName} if ($LASTEXITCODE) { $2.Result = 'Ignore' Show-FarMessage "Error on rename branch $oldName to $newName`n$res" -Caption FarGit -LeftAligned -IsWarning } else { $2.PostName = $newName $Explorer.Data.FileDescriptions.Remove($oldName) } } |