mirror of
https://github.com/RGBCube/nu_scripts
synced 2025-07-30 13:47:46 +00:00
Improve git completions (#1087)
* Fix previous logic assuming single remote name `origin` * Fix wrong Local vs Remote branch name descriptions * Fix git branch output with multiple branches per line breaking auto-completions * Fix current branch not showing up in git checkout branch completions * Fix remote branches not showing up when local branch with upstream exists despite them being different refs * Show more contextual information in completion descriptions * Use consistent sorting between command completions; Local branches before remote branches before files before commits, with sorting from git kept intact Change implementation to a more encapsulated and type-specific approach: * Use for-each-ref instead of git branch with manual current branch query and current and HEAD ref removal * Separate local and remote branch logic for good case separation * Use separate for-each-ref calls for early case separation * Decorate local and remote branch information in their respective cases instead of content-conditional * Decorate with 'Branch, Local|Remote, Commit Sha1 Subject, upstream [head|behind x] * Use new consistent description format '{Type}' | '{Type}, Commit {Sha1} Subject | '{Type}, {Subtype}, {Commit Sha1+Subject}, {upstream name + track} * Dissolves some spread out logic, dropping commands get-all-git-branches and extract-remote-branches-nonlocal-short and extract-mergable-sources Influenced completions: `git checkout`, `git switch`, `git merge` --- Screenshot:  Should resolve #1041 Screenshot from before, showing a wrong classification of a local branch as remote branch: 
This commit is contained in:
parent
4d0f184096
commit
3ad271f838
1 changed files with 29 additions and 47 deletions
|
@ -81,52 +81,21 @@ module git-completion-utils {
|
|||
| each { split row ' ' -n 9 | last }
|
||||
}
|
||||
|
||||
export def get-all-git-branches []: nothing -> list<string> {
|
||||
^git branch -a --format '%(refname:lstrip=2)%09%(upstream:lstrip=2)' | lines | str trim | filter { not ($in ends-with 'HEAD' ) }
|
||||
export def get-all-git-local-refs []: nothing -> list<record<ref: string, obj: string, upstream: string, subject: string>> {
|
||||
^git for-each-ref --format '%(refname:lstrip=2)%09%(objectname:short)%09%(upstream:remotename)%(upstream:track)%09%(contents:subject)' refs/heads | lines | parse "{ref}\t{obj}\t{upstream}\t{subject}"
|
||||
}
|
||||
|
||||
# Extract remote branches which do not have local counterpart
|
||||
export def extract-remote-branches-nonlocal-short [current: string]: list<string> -> list<string> {
|
||||
# Input is a list of lines, like:
|
||||
# ╭────┬────────────────────────────────────────────────╮
|
||||
# │ 0 │ feature/awesome-1 origin/feature/awesome-1 │
|
||||
# │ 1 │ fix/bug-1 origin/fix/bug-1 │
|
||||
# │ 2 │ main origin/main │
|
||||
# │ 3 │ origin/HEAD │
|
||||
# │ 4 │ origin/feature/awesome-1 │
|
||||
# │ 5 │ origin/fix/bug-1 │
|
||||
# │ 6 │ origin/feature/awesome-2 │
|
||||
# │ 7 │ origin/main │
|
||||
# │ 8 │ upstream/main │
|
||||
# │ 9 │ upstream/awesome-3 │
|
||||
# ╰────┴────────────────────────────────────────────────╯
|
||||
# and we pick ['feature/awesome-2', 'awesome-3']
|
||||
let lines = $in
|
||||
let long_current = if ($current | is-empty) { '' } else { $'origin/($current)' }
|
||||
let branches = $lines | filter { ($in != $long_current) and not ($in starts-with $"($current)\t") }
|
||||
let tracked_remotes = $branches | find --no-highlight "\t" | each { split row "\t" -n 2 | get 1 }
|
||||
let floating_remotes = $lines | filter { "\t" not-in $in and $in not-in $tracked_remotes }
|
||||
$floating_remotes | each {
|
||||
let v = $in | split row -n 2 '/' | get 1
|
||||
if $v == $current { null } else $v
|
||||
}
|
||||
}
|
||||
|
||||
export def extract-mergable-sources [current: string]: list<string> -> list<record<value: string, description: string>> {
|
||||
let lines = $in
|
||||
let long_current = if ($current | is-empty) { '' } else { $'origin/($current)' }
|
||||
let branches = $lines | filter { ($in != $long_current) and not ($in starts-with $"($current)\t") }
|
||||
let git_table: list<record<n: string, u: string>> = $branches | each {|v| if "\t" in $v { $v | split row "\t" -n 2 | {n: $in.0, u: $in.1 } } else {n: $v, u: null } }
|
||||
let siblings = $git_table | where u == null and n starts-with 'origin/' | get n | str substring 7..
|
||||
let remote_branches = $git_table | filter {|r| $r.u == null and not ($r.n starts-with 'origin/') } | get n
|
||||
[...($siblings | wrap value | insert description Local), ...($remote_branches | wrap value | insert description Remote)]
|
||||
export def get-all-git-remote-refs []: nothing -> list<record<ref: string, obj: string, subject: string>> {
|
||||
^git for-each-ref --format '%(refname:lstrip=2)%09%(objectname:short)%09%(contents:subject)' refs/remotes | lines | parse "{ref}\t{obj}\t{subject}"
|
||||
}
|
||||
|
||||
# Get local branches, remote branches which can be passed to `git merge`
|
||||
export def get-mergable-sources []: nothing -> list<record<value: string, description: string>> {
|
||||
let current = (^git branch --show-current) # Can be empty if in detached HEAD
|
||||
(get-all-git-branches | extract-mergable-sources $current)
|
||||
}
|
||||
# expensive: (^git show --no-patch --format=%s $x.obj)
|
||||
let local = get-all-git-local-refs | each {|x| {value: $x.ref description: $'Branch, Local, ($x.obj) ($x.subject), (if ($x.upstream | is-not-empty) { $x.upstream } else { "no upstream" } )'} } | insert style 'light_blue'
|
||||
let remote = get-all-git-remote-refs | each {|x| {value: $x.ref description: $'Branch, Remote, ($x.obj) ($x.subject)'} } | insert style 'blue_italic'
|
||||
$local | append $remote
|
||||
}
|
||||
}
|
||||
|
||||
def "nu-complete git available upstream" [] {
|
||||
|
@ -165,15 +134,28 @@ def "nu-complete git remote branches with prefix" [] {
|
|||
# Yield local and remote branch names which can be passed to `git merge`
|
||||
def "nu-complete git mergable sources" [] {
|
||||
use git-completion-utils *
|
||||
(get-mergable-sources)
|
||||
let branches = get-mergable-sources
|
||||
{
|
||||
options: {
|
||||
case_sensitive: false,
|
||||
completion_algorithm: prefix,
|
||||
sort: false,
|
||||
},
|
||||
completions: $branches
|
||||
}
|
||||
}
|
||||
|
||||
def "nu-complete git switch" [] {
|
||||
use git-completion-utils *
|
||||
let current = (^git branch --show-current) # Can be empty if in detached HEAD
|
||||
let local_branches = ^git branch --format '%(refname:short)' | lines | filter { $in != $current } | wrap value | insert description 'Local branch'
|
||||
let remote_branches = (get-all-git-branches | extract-remote-branches-nonlocal-short $current) | wrap value | insert description 'Remote branch'
|
||||
[...$local_branches, ...$remote_branches]
|
||||
let branches = get-mergable-sources
|
||||
{
|
||||
options: {
|
||||
case_sensitive: false,
|
||||
completion_algorithm: prefix,
|
||||
sort: false,
|
||||
},
|
||||
completions: $branches
|
||||
}
|
||||
}
|
||||
|
||||
def "nu-complete git checkout" [context: string, position?:int] {
|
||||
|
@ -199,9 +181,9 @@ def "nu-complete git checkout" [context: string, position?:int] {
|
|||
}
|
||||
# The first argument can be local branches, remote branches, files and commits
|
||||
# Get local and remote branches
|
||||
let branches = (get-mergable-sources) | insert style {|row| if $row.description == 'Local' { 'blue' } else 'blue_italic' } | update description { $in + ' branch' }
|
||||
let branches = get-mergable-sources
|
||||
let files = (get-checkoutable-files) | wrap value | insert description 'File' | insert style green
|
||||
let commits = ^git rev-list -n 400 --remotes --oneline | lines | split column -n 2 ' ' value description | insert style light_cyan_dimmed
|
||||
let commits = ^git rev-list -n 400 --remotes --oneline | lines | split column -n 2 ' ' value description | upsert description {|x| $'Commit, ($x.value) ($x.description)' } | insert style 'light_cyan_dimmed'
|
||||
{
|
||||
options: {
|
||||
case_sensitive: false,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue