11use std:: { collections:: HashMap , fmt:: Display } ;
22
3- use bstr:: ByteSlice ;
3+ use bstr:: { BString , ByteSlice } ;
44use but_core:: ref_metadata:: StackId ;
55use but_ctx:: Context ;
66use but_hunk_assignment:: HunkAssignment ;
77use gitbutler_command_context:: CommandContext ;
88
9+ fn branch_names ( ctx : & Context ) -> anyhow:: Result < Vec < BString > > {
10+ let guard = ctx. shared_worktree_access ( ) ;
11+ let meta = ctx. meta ( guard. read_permission ( ) ) ?;
12+ let head_info = but_workspace:: head_info ( & ctx. repo , & meta, Default :: default ( ) ) ?;
13+ let mut branch_names: Vec < BString > = Vec :: new ( ) ;
14+ for stack in head_info. stacks {
15+ for segment in stack. segments {
16+ if let Some ( ref_info) = segment. ref_info {
17+ branch_names. push ( ref_info. ref_name . shorten ( ) . to_owned ( ) ) ;
18+ }
19+ }
20+ }
21+ Ok ( branch_names)
22+ }
23+
924pub struct IdDb {
1025 branch_name_to_cli_id : HashMap < String , CliId > ,
1126 unassigned : CliId ,
1227}
1328
1429impl IdDb {
15- pub fn new ( ctx : & CommandContext ) -> anyhow:: Result < Self > {
30+ pub fn new ( ctx : & Context ) -> anyhow:: Result < Self > {
1631 let mut max_zero_count = 1 ; // Ensure at least two "0" in ID.
17- let stacks = crate :: utils :: commits :: stacks ( ctx) ?;
32+ let branch_names = branch_names ( ctx) ?;
1833 let mut pairs_to_count: HashMap < u16 , u8 > = HashMap :: new ( ) ;
1934 fn u8_pair_to_u16 ( two : [ u8 ; 2 ] ) -> u16 {
2035 two[ 0 ] as u16 * 256 + two[ 1 ] as u16
2136 }
22- for stack in & stacks {
23- for head in & stack. heads {
24- for pair in head. name . windows ( 2 ) {
25- let pair: [ u8 ; 2 ] = pair. try_into ( ) ?;
26- if !pair[ 0 ] . is_ascii_alphanumeric ( ) || !pair[ 1 ] . is_ascii_alphanumeric ( ) {
27- continue ;
28- }
29- let could_collide_with_commits =
30- pair[ 0 ] . is_ascii_hexdigit ( ) && pair[ 1 ] . is_ascii_hexdigit ( ) ;
31- if could_collide_with_commits {
32- continue ;
33- }
34- let u16pair = u8_pair_to_u16 ( pair) ;
35- pairs_to_count
36- . entry ( u16pair)
37- . and_modify ( |count| * count = count. saturating_add ( 1 ) )
38- . or_insert ( 1 ) ;
37+ for branch_name in & branch_names {
38+ for pair in branch_name. windows ( 2 ) {
39+ let pair: [ u8 ; 2 ] = pair. try_into ( ) ?;
40+ if !pair[ 0 ] . is_ascii_alphanumeric ( ) || !pair[ 1 ] . is_ascii_alphanumeric ( ) {
41+ continue ;
3942 }
40- for field in head. name . fields_with ( |c| c != '0' ) {
41- max_zero_count = std:: cmp:: max ( field. len ( ) , max_zero_count) ;
43+ let could_collide_with_commits =
44+ pair[ 0 ] . is_ascii_hexdigit ( ) && pair[ 1 ] . is_ascii_hexdigit ( ) ;
45+ if could_collide_with_commits {
46+ continue ;
4247 }
48+ let u16pair = u8_pair_to_u16 ( pair) ;
49+ pairs_to_count
50+ . entry ( u16pair)
51+ . and_modify ( |count| * count = count. saturating_add ( 1 ) )
52+ . or_insert ( 1 ) ;
53+ }
54+ for field in branch_name. fields_with ( |c| c != '0' ) {
55+ max_zero_count = std:: cmp:: max ( field. len ( ) , max_zero_count) ;
4356 }
4457 }
4558
4659 let mut branch_name_to_cli_id: HashMap < String , CliId > = HashMap :: new ( ) ;
47- for stack in stacks {
48- ' head: for head in & stack. heads {
49- // Find first non-conflicting pair and use it as CliId.
50- for pair in head. name . windows ( 2 ) {
51- let pair: [ u8 ; 2 ] = pair. try_into ( ) ?;
52- let u16pair = u8_pair_to_u16 ( pair) ;
53- if let Some ( 1 ) = pairs_to_count. get ( & u16pair) {
54- let name = head. name . to_string ( ) ;
55- let id = str:: from_utf8 ( & pair)
56- . expect ( "if we stored it, it's ascii-alphanum" )
57- . to_owned ( ) ;
58- branch_name_to_cli_id. insert ( name. clone ( ) , CliId :: Branch { name, id } ) ;
59- continue ' head;
60- }
60+ ' branch_name: for branch_name in & branch_names {
61+ // Find first non-conflicting pair and use it as CliId.
62+ for pair in branch_name. windows ( 2 ) {
63+ let pair: [ u8 ; 2 ] = pair. try_into ( ) ?;
64+ let u16pair = u8_pair_to_u16 ( pair) ;
65+ if let Some ( 1 ) = pairs_to_count. get ( & u16pair) {
66+ let name = branch_name. to_string ( ) ;
67+ let id = str:: from_utf8 ( & pair)
68+ . expect ( "if we stored it, it's ascii-alphanum" )
69+ . to_owned ( ) ;
70+ branch_name_to_cli_id. insert ( name. clone ( ) , CliId :: Branch { name, id } ) ;
71+ continue ' branch_name;
6172 }
6273 }
6374 }
@@ -69,21 +80,15 @@ impl IdDb {
6980 } )
7081 }
7182
72- fn find_branches_by_name (
73- & mut self ,
74- ctx : & CommandContext ,
75- name : & str ,
76- ) -> anyhow:: Result < Vec < CliId > > {
77- let stacks = crate :: utils:: commits:: stacks ( ctx) ?;
83+ fn find_branches_by_name ( & mut self , ctx : & Context , name : & str ) -> anyhow:: Result < Vec < CliId > > {
84+ let branch_names = branch_names ( ctx) ?;
7885 let mut matches = Vec :: new ( ) ;
7986
80- for stack in stacks {
81- for head in & stack. heads {
82- let branch_name = head. name . to_string ( ) ;
83- // Exact match or partial match
84- if branch_name == name || branch_name. contains ( name) {
85- matches. push ( self . branch ( & branch_name) . clone ( ) )
86- }
87+ for branch_name in branch_names {
88+ let branch_name = branch_name. to_string ( ) ;
89+ // Exact match or partial match
90+ if branch_name == name || branch_name. contains ( name) {
91+ matches. push ( self . branch ( & branch_name) . clone ( ) )
8792 }
8893 }
8994
@@ -204,12 +209,12 @@ impl CliId {
204209 }
205210
206211 // TODO: make callers of this function pass IdDb instead
207- let mut id_db = IdDb :: new ( & ctx. legacy_ctx ( ) ? ) ?;
212+ let mut id_db = IdDb :: new ( ctx) ?;
208213
209214 let mut matches = Vec :: new ( ) ;
210215
211216 // First, try exact branch name match
212- if let Ok ( branch_matches) = id_db. find_branches_by_name ( & ctx. legacy_ctx ( ) ? , s) {
217+ if let Ok ( branch_matches) = id_db. find_branches_by_name ( ctx, s) {
213218 matches. extend ( branch_matches) ;
214219 }
215220
@@ -230,7 +235,7 @@ impl CliId {
230235 . into_iter ( )
231236 . filter ( |id| id. matches_prefix ( s) )
232237 . for_each ( |id| cli_matches. push ( id) ) ;
233- crate :: status:: all_branches ( & ctx. legacy_ctx ( ) ? ) ?
238+ crate :: status:: all_branches ( ctx) ?
234239 . into_iter ( )
235240 . filter ( |id| id. matches_prefix ( s) )
236241 . for_each ( |id| cli_matches. push ( id) ) ;
@@ -253,7 +258,7 @@ impl CliId {
253258 . into_iter ( )
254259 . filter ( |id| id. matches ( s) )
255260 . for_each ( |id| cli_matches. push ( id) ) ;
256- crate :: status:: all_branches ( & ctx. legacy_ctx ( ) ? ) ?
261+ crate :: status:: all_branches ( ctx) ?
257262 . into_iter ( )
258263 . filter ( |id| id. matches ( s) )
259264 . for_each ( |id| cli_matches. push ( id) ) ;
0 commit comments