1- use anyhow:: { Context , bail} ;
21use but_core:: RefMetadata ;
3- use but_graph:: workspace:: { Stack , StackSegment } ;
4- use but_rebase:: graph_rebase:: {
5- Editor , Selector , SuccessfulRebase ,
6- mutate:: { SegmentDelimiter , SelectorSet , SomeSelectors } ,
7- } ;
2+ use but_rebase:: graph_rebase:: SuccessfulRebase ;
83
94/// Outcome of moving branches between or out of stacks.
105///
@@ -20,12 +15,11 @@ pub struct Outcome<'ws, 'meta, M: RefMetadata> {
2015
2116pub ( super ) mod function {
2217
18+ use crate :: branch:: segment_disconnect:: { DisconnectParameters , get_disconnect_parameters} ;
2319 use but_core:: RefMetadata ;
2420 use but_core:: ref_metadata:: StackId ;
2521 use but_rebase:: graph_rebase:: mutate:: SomeSelectors ;
2622
27- use super :: get_disconnect_parameters;
28-
2923 use super :: Outcome ;
3024 use anyhow:: Context ;
3125 use anyhow:: bail;
@@ -105,14 +99,17 @@ pub(super) mod function {
10599 . select_reference ( lower_bound_ref)
106100 . context ( "Failed to find target reference in graph." ) ?;
107101
108- let ( subject_delimiter, children_to_disconnect, parents_to_disconnect) =
109- get_disconnect_parameters (
110- & editor,
111- & workspace,
112- source_stack,
113- subject_segment,
114- workspace_head,
115- ) ?;
102+ let DisconnectParameters {
103+ delimiter : subject_delimiter,
104+ children_to_disconnect,
105+ parents_to_disconnect,
106+ } = get_disconnect_parameters (
107+ & editor,
108+ & workspace,
109+ source_stack,
110+ subject_segment,
111+ workspace_head,
112+ ) ?;
116113
117114 editor. disconnect_segment_from (
118115 subject_delimiter. clone ( ) ,
@@ -202,14 +199,17 @@ pub(super) mod function {
202199 . select_reference ( target_segment_ref_name)
203200 . context ( "Failed to find target reference in graph." ) ?;
204201
205- let ( subject_delimiter, children_to_disconnect, parents_to_disconnect) =
206- get_disconnect_parameters (
207- & editor,
208- & workspace,
209- & source_stack,
210- & subject_segment,
211- workspace_head,
212- ) ?;
202+ let DisconnectParameters {
203+ delimiter : subject_delimiter,
204+ children_to_disconnect,
205+ parents_to_disconnect,
206+ } = get_disconnect_parameters (
207+ & editor,
208+ & workspace,
209+ & source_stack,
210+ & subject_segment,
211+ workspace_head,
212+ ) ?;
213213
214214 let skip_reconnect_step = source_stack. segments . len ( ) == 1 ;
215215 editor. disconnect_segment_from (
@@ -311,158 +311,3 @@ pub(super) mod function {
311311 Ok ( ( own_context ( source) , own_context ( destination) ) )
312312 }
313313}
314-
315- /// Get the right disconnect parameters for the given subject segment and source stack.
316- ///
317- /// This function determines which are the right parents and children to disconnect,
318- /// as well as the right segment delimiter to move.
319- fn get_disconnect_parameters < ' ws , ' meta , M : RefMetadata > (
320- editor : & Editor < ' ws , ' meta , M > ,
321- workspace : & but_graph:: Workspace ,
322- source_stack : & Stack ,
323- subject_segment : & StackSegment ,
324- workspace_head : gix:: ObjectId ,
325- ) -> anyhow:: Result < (
326- SegmentDelimiter < Selector , Selector > ,
327- SelectorSet ,
328- SelectorSet ,
329- ) > {
330- let index_of_segment = source_stack
331- . segments
332- . iter ( )
333- . position ( |segment| segment. id == subject_segment. id )
334- . context ( "BUG: Unable to find subject segment on source stack." ) ?;
335-
336- let subject_segment_ref_name = subject_segment
337- . ref_name ( )
338- . context ( "Subject segment doesn't have a ref name." ) ?;
339- let delimiter_child = editor
340- . select_reference ( subject_segment_ref_name)
341- . context ( "Failed to find subject reference in graph." ) ?;
342- let delimiter_parent = match subject_segment. commits . last ( ) {
343- Some ( last_commit) => editor
344- . select_commit ( last_commit. id )
345- . context ( "Failed to find last commit in subject segment in graph." ) ?,
346- None => {
347- // Subject segment is empty, move only the reference
348- delimiter_child
349- }
350- } ;
351-
352- // The delimiter for the segment we want to move, is the reference selector
353- // as the child, and the last commit inside the branch as the parent.
354- // If the branch is empty, we take the reference selector as the parent as well.
355- let delimiter = SegmentDelimiter {
356- child : delimiter_child,
357- parent : delimiter_parent,
358- } ;
359-
360- // The parent segment in the stack if any.
361- // This will be `None` if the branch we want to move is at the bottom of the stack.
362- let stack_base_segment = subject_segment. base_segment_id . and_then ( |base_segment_id| {
363- source_stack
364- . segments
365- . iter ( )
366- . find ( |segment| segment. id == base_segment_id)
367- } ) ;
368-
369- // The parent segment in the graph.
370- // If the `stack_base_segment` is `None` but there's a `base_segment_id` defined, it means we'll find it in the
371- // graph data, and it's probably the target branch, which is not included in the workspace.
372- let graph_base_segment = subject_segment
373- . base_segment_id
374- . map ( |segment_idx| & workspace. graph [ segment_idx] ) ;
375-
376- let parents_to_disconnect = if let Some ( stack_base_segment) = stack_base_segment {
377- // Base segment is part of the source stack.
378- select_segment ( editor, stack_base_segment) ?
379- } else if let Some ( graph_base_segment) = graph_base_segment {
380- // Base segment is outside of workspace (probably target branch).
381- select_segment ( editor, graph_base_segment) ?
382- } else if subject_segment. base_segment_id . is_some ( ) {
383- // Base segment could not be found, but there is an ID defined. Error out.
384- bail ! (
385- "Failed to find the base segment of the subject we want to move, even if it seems to be defined"
386- ) ;
387- } else {
388- // Nothing found. Remove all parents.
389- SelectorSet :: All
390- } ;
391-
392- if index_of_segment == 0 {
393- // This is the top-most segment in the stack, so the parent is the workspace commit.
394- let workspace_head_selector = editor
395- . select_commit ( workspace_head)
396- . context ( "Failed to find workspace head in graph." ) ?;
397- let selectors = SomeSelectors :: new ( vec ! [ workspace_head_selector] ) ?;
398- let children_to_disconnect = SelectorSet :: Some ( selectors) ;
399-
400- return Ok ( ( delimiter, children_to_disconnect, parents_to_disconnect) ) ;
401- }
402-
403- // Segment on top of the subject segment in the stack.
404- let child_segment = source_stack. segments . get ( index_of_segment - 1 ) . context (
405- "BUG: Unable to find child segment of subject segment but expected it to exist." ,
406- ) ?;
407-
408- // If branch stacked on top of the branch we want to move is empty, we only need to disconnect
409- // the reference from it.
410- // Otherwise, disconnect the last commit on the segment.
411- let child_selector = match child_segment. commits . last ( ) {
412- Some ( last_commit) => editor
413- . select_commit ( last_commit. id )
414- . context ( "Failed to find last commit of child segment in graph." ) ,
415- None => {
416- // The segment on top of the subject segment is empty. Select the reference.
417- let child_segment_ref_name = child_segment
418- . ref_name ( )
419- . context ( "Child segment doesn't have a ref name." ) ?;
420- editor
421- . select_reference ( child_segment_ref_name)
422- . context ( "Failed to find child segment reference in graph." )
423- }
424- } ?;
425- let selectors = SomeSelectors :: new ( vec ! [ child_selector] ) ?;
426- let children_to_disconnect = SelectorSet :: Some ( selectors) ;
427-
428- Ok ( ( delimiter, children_to_disconnect, parents_to_disconnect) )
429- }
430-
431- /// Select a segment by its ref name if available, otherwise fall back to its tip commit.
432- fn select_segment < M : RefMetadata > (
433- editor : & Editor < ' _ , ' _ , M > ,
434- segment : & impl SegmentLike ,
435- ) -> anyhow:: Result < SelectorSet > {
436- let selector = if let Some ( ref_name) = segment. ref_name ( ) {
437- editor. select_reference ( ref_name) ?
438- } else if let Some ( tip) = segment. tip ( ) {
439- editor. select_commit ( tip) ?
440- } else {
441- bail ! ( "Base segment has neither a ref name nor any commits." ) ;
442- } ;
443- let selectors = SomeSelectors :: new ( vec ! [ selector] ) ?;
444- Ok ( SelectorSet :: Some ( selectors) )
445- }
446-
447- trait SegmentLike {
448- fn ref_name ( & self ) -> Option < & gix:: refs:: FullNameRef > ;
449- fn tip ( & self ) -> Option < gix:: ObjectId > ;
450- }
451-
452- impl SegmentLike for StackSegment {
453- fn ref_name ( & self ) -> Option < & gix:: refs:: FullNameRef > {
454- self . ref_name ( )
455- }
456- fn tip ( & self ) -> Option < gix:: ObjectId > {
457- self . tip ( )
458- }
459- }
460-
461- impl SegmentLike for but_graph:: Segment {
462- fn ref_name ( & self ) -> Option < & gix:: refs:: FullNameRef > {
463- self . ref_name ( )
464- }
465- fn tip ( & self ) -> Option < gix:: ObjectId > {
466- self . tip ( )
467- }
468- }
0 commit comments