Skip to content

Commit 5c75bb8

Browse files
committed
feature: allows to re-order multiple commits in Interactive Rebase window (#1675)
Signed-off-by: leo <longshuang@msn.cn>
1 parent 89bc8a7 commit 5c75bb8

File tree

4 files changed

+207
-99
lines changed

4 files changed

+207
-99
lines changed

src/Resources/Icons.axaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@
8989
<StreamGeometry x:Key="Icons.Minus">M0 512M1024 512M512 0M512 1024M64 576h896V448H64z</StreamGeometry>
9090
<StreamGeometry x:Key="Icons.Modified">M896 64H128C96 64 64 96 64 128v768c0 32 32 64 64 64h768c32 0 64-32 64-64V128c0-32-32-64-64-64z m-64 736c0 16-17 32-32 32H224c-18 0-32-12-32-32V224c0-16 16-32 32-32h576c15 0 32 16 32 32v576zM512 384c-71 0-128 57-128 128s57 128 128 128 128-57 128-128-57-128-128-128z</StreamGeometry>
9191
<StreamGeometry x:Key="Icons.More">M0 512M1024 512M512 0M512 1024M813 448c-46 0-83 37-83 83 0 46 37 83 83 83 46 0 83-37 83-83 0-46-37-83-83-83zM211 448C165 448 128 485 128 531c0 46 37 83 83 83 46 0 83-37 83-83 0-46-37-83-83-83zM512 448c-46 0-83 37-83 83 0 46 37 83 83 83 46 0 83-37 83-83C595 485 558 448 512 448z</StreamGeometry>
92-
<StreamGeometry x:Key="Icons.Move">M299 811 299 725 384 725 384 811 299 811M469 811 469 725 555 725 555 811 469 811M640 811 640 725 725 725 725 811 640 811M299 640 299 555 384 555 384 640 299 640M469 640 469 555 555 555 555 640 469 640M640 640 640 555 725 555 725 640 640 640M299 469 299 384 384 384 384 469 299 469M469 469 469 384 555 384 555 469 469 469M640 469 640 384 725 384 725 469 640 469M299 299 299 213 384 213 384 299 299 299M469 299 469 213 555 213 555 299 469 299M640 299 640 213 725 213 725 299 640 299Z</StreamGeometry>
9392
<StreamGeometry x:Key="Icons.MoveTo">M64 363l0 204 265 0L329 460c0-11 6-18 14-20C349 437 355 437 362 441c93 60 226 149 226 149 33 22 34 60 0 82 0 0-133 89-226 149-14 9-32-3-32-18l-1-110L64 693l0 117c0 41 34 75 75 75l746 0c41 0 75-34 75-74L960 364c0-0 0-1 0-1L64 363zM64 214l0 75 650 0-33-80c-16-38-62-69-103-69l-440 0C97 139 64 173 64 214z</StreamGeometry>
9493
<StreamGeometry x:Key="Icons.OpenWith">M683 409v204L1024 308 683 0v191c-413 0-427 526-427 526c117-229 203-307 427-307zm85 492H102V327h153s38-63 114-122H51c-28 0-51 27-51 61v697c0 34 23 61 51 61h768c28 0 51-27 51-61V614l-102 100v187z</StreamGeometry>
9594
<StreamGeometry x:Key="Icons.OrderByName">M841 627A43 43 0 00811 555h-299v85h196l-183 183A43 43 0 00555 896h299v-85h-196l183-183zM299 170H213v512H85l171 171 171-171H299zM725 128h-85c-18 0-34 11-40 28l-117 313h91L606 384h154l32 85h91l-117-313A43 43 0 00725 128zm-88 171 32-85h26l32 85h-90z</StreamGeometry>

src/ViewModels/InteractiveRebase.cs

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ public string FullMessage
6464
}
6565
}
6666

67+
public bool IsDropBeforeVisible
68+
{
69+
get => _isDropBeforeVisible;
70+
set => SetProperty(ref _isDropBeforeVisible, value);
71+
}
72+
73+
public bool IsDropAfterVisible
74+
{
75+
get => _isDropAfterVisible;
76+
set => SetProperty(ref _isDropAfterVisible, value);
77+
}
78+
6779
public InteractiveRebaseItem(int order, Models.Commit c, string message, bool canSquashOrFixup)
6880
{
6981
OriginalOrder = order;
@@ -76,6 +88,8 @@ public InteractiveRebaseItem(int order, Models.Commit c, string message, bool ca
7688
private string _subject;
7789
private string _fullMessage;
7890
private bool _canSquashOrFixup = true;
91+
private bool _isDropBeforeVisible = false;
92+
private bool _isDropAfterVisible = false;
7993
}
8094

8195
public class InteractiveRebase : ObservableObject
@@ -188,30 +202,6 @@ public void SelectCommits(List<InteractiveRebaseItem> items)
188202
}
189203
}
190204

191-
public void MoveItemUp(InteractiveRebaseItem item)
192-
{
193-
var idx = Items.IndexOf(item);
194-
if (idx > 0)
195-
{
196-
var prev = Items[idx - 1];
197-
Items.RemoveAt(idx - 1);
198-
Items.Insert(idx, prev);
199-
UpdateItems();
200-
}
201-
}
202-
203-
public void MoveItemDown(InteractiveRebaseItem item)
204-
{
205-
var idx = Items.IndexOf(item);
206-
if (idx < Items.Count - 1)
207-
{
208-
var next = Items[idx + 1];
209-
Items.RemoveAt(idx + 1);
210-
Items.Insert(idx, next);
211-
UpdateItems();
212-
}
213-
}
214-
215205
public void ChangeAction(List<InteractiveRebaseItem> selected, Models.InteractiveRebaseAction action)
216206
{
217207
if (action == Models.InteractiveRebaseAction.Squash || action == Models.InteractiveRebaseAction.Fixup)
@@ -231,6 +221,41 @@ public void ChangeAction(List<InteractiveRebaseItem> selected, Models.Interactiv
231221
UpdateItems();
232222
}
233223

224+
public void Move(List<InteractiveRebaseItem> commits, int index)
225+
{
226+
var hashes = new HashSet<string>();
227+
foreach (var c in commits)
228+
hashes.Add(c.Commit.SHA);
229+
230+
var before = new List<InteractiveRebaseItem>();
231+
var ordered = new List<InteractiveRebaseItem>();
232+
var after = new List<InteractiveRebaseItem>();
233+
234+
for (int i = 0; i < index; i++)
235+
{
236+
var item = Items[i];
237+
if (!hashes.Contains(item.Commit.SHA))
238+
before.Add(item);
239+
else
240+
ordered.Add(item);
241+
}
242+
243+
for (int i = index; i < Items.Count; i++)
244+
{
245+
var item = Items[i];
246+
if (!hashes.Contains(item.Commit.SHA))
247+
after.Add(item);
248+
else
249+
ordered.Add(item);
250+
}
251+
252+
Items.Clear();
253+
Items.AddRange(before);
254+
Items.AddRange(ordered);
255+
Items.AddRange(after);
256+
UpdateItems();
257+
}
258+
234259
public async Task<bool> Start()
235260
{
236261
using var lockWatcher = _repo.LockWatcher();

src/Views/InteractiveRebase.axaml

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,29 @@
3838
</Grid>
3939

4040
<!-- Operation Information -->
41-
<Grid Grid.Row="1" ColumnDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,*" Margin="8">
42-
<TextBlock Grid.Column="0" Text="{DynamicResource Text.InteractiveRebase.Target}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/>
43-
<Path Grid.Column="1" Width="14" Height="14" Margin="8,0,0,0" Data="{StaticResource Icons.Branch}"/>
44-
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{Binding Current.FriendlyName}" Margin="8,0,0,0"/>
45-
46-
<TextBlock Grid.Column="3" Margin="48,0,0,0" Text="{DynamicResource Text.InteractiveRebase.On}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/>
47-
<Path Grid.Column="4" Width="14" Height="14" Margin="8,0,0,0" Data="{StaticResource Icons.Commit}"/>
48-
<TextBlock Grid.Column="5" VerticalAlignment="Center" Text="{Binding On.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
49-
<TextBlock Grid.Column="6" VerticalAlignment="Center" Text="{Binding On.Subject}" Margin="4,0,0,0" TextTrimming="CharacterEllipsis"/>
41+
<Grid Grid.Row="1" Margin="8" ColumnDefinitions="*,Auto">
42+
<StackPanel Grid.Column="0" Orientation="Horizontal" ClipToBounds="True">
43+
<TextBlock Text="{DynamicResource Text.InteractiveRebase.Target}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/>
44+
<Path Width="14" Height="14" Margin="8,0,0,0" Data="{StaticResource Icons.Branch}"/>
45+
<TextBlock VerticalAlignment="Center" Text="{Binding Current.FriendlyName}" Margin="8,0,0,0"/>
46+
47+
<TextBlock Margin="16,0,0,0" Text="{DynamicResource Text.InteractiveRebase.On}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/>
48+
<Path Width="14" Height="14" Margin="8,0,0,0" Data="{StaticResource Icons.Commit}"/>
49+
<TextBlock VerticalAlignment="Center" Text="{Binding On.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
50+
<TextBlock VerticalAlignment="Center" Text="{Binding On.Subject}" Margin="4,0,0,0"/>
51+
</StackPanel>
52+
53+
<Border Grid.Column="1" Background="Transparent" Width="20" Height="20">
54+
<ToolTip.Tip>
55+
<TextBlock>
56+
<Run Text="{DynamicResource Text.InteractiveRebase.ReorderTip}"/>
57+
<Run Text=" "/>
58+
<Run Text="{OnPlatform 'Ctrl+Up/Ctrl+Down', macOS='⌘+Up/⌘+Down'}" FontSize="11" Foreground="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"/>
59+
</TextBlock>
60+
</ToolTip.Tip>
61+
62+
<Path Width="14" Height="14" Data="{StaticResource Icons.Info}"/>
63+
</Border>
5064
</Grid>
5165

5266
<!-- Body -->
@@ -81,9 +95,16 @@
8195

8296
<v:InteractiveRebaseListBox.ItemTemplate>
8397
<DataTemplate DataType="vm:InteractiveRebaseItem">
84-
<Grid Height="26" Margin="8,0" ClipToBounds="True">
98+
<Grid Height="26"
99+
Margin="8,0"
100+
Background="Transparent"
101+
ClipToBounds="True"
102+
PointerPressed="OnRowPointerPressed"
103+
DragDrop.AllowDrop="True"
104+
DragDrop.DragOver="OnRowDragOver"
105+
DragDrop.DragLeave="OnRowDragLeave"
106+
DragDrop.Drop="OnRowDrop">
85107
<Grid.ColumnDefinitions>
86-
<ColumnDefinition Width="16"/>
87108
<ColumnDefinition Width="Auto" SharedSizeGroup="CommitOrderColumn"/>
88109
<ColumnDefinition Width="110"/>
89110
<ColumnDefinition Width="*"/>
@@ -93,42 +114,23 @@
93114
<ColumnDefinition Width="Auto" SharedSizeGroup="CommitTimeColumn"/>
94115
</Grid.ColumnDefinitions>
95116

96-
<!-- Drag & Drop Anchor -->
97-
<Border Grid.Column="0" Background="Transparent"
98-
PointerPressed="OnRowHeaderPointerPressed"
99-
DragDrop.AllowDrop="True"
100-
DragDrop.DragOver="OnRowHeaderDragOver">
101-
<ToolTip.Tip>
102-
<TextBlock>
103-
<Run Text="{DynamicResource Text.InteractiveRebase.ReorderTip}"/>
104-
<Run Text=" "/>
105-
<Run Text="{OnPlatform 'Ctrl+Up/Ctrl+Down', macOS='⌘+Up/⌘+Down'}" FontSize="11" Foreground="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"/>
106-
</TextBlock>
107-
</ToolTip.Tip>
108-
<Path Width="14" Height="14"
109-
Data="{StaticResource Icons.Move}"
110-
Fill="{DynamicResource Brush.FG2}"
111-
HorizontalAlignment="Center"
112-
VerticalAlignment="Center"/>
113-
</Border>
114-
115117
<!-- Original Order -->
116-
<TextBlock Grid.Column="1"
118+
<TextBlock Grid.Column="0"
117119
Margin="4,0,0,0"
118120
FontFamily="{DynamicResource Fonts.Monospace}"
119121
Text="{Binding OriginalOrder, StringFormat='#{0}'}"
120122
HorizontalAlignment="Center"/>
121123

122124
<!-- Action -->
123-
<Button Grid.Column="2" Opacity="1" Margin="4,0,0,0" Padding="8,2" Background="Transparent" Click="OnButtonActionClicked">
125+
<Button Grid.Column="1" Opacity="1" Margin="4,0,0,0" Padding="8,2" Background="Transparent" Click="OnButtonActionClicked">
124126
<StackPanel Orientation="Horizontal">
125127
<Ellipse Width="14" Height="14" Fill="{Binding Action, Converter={x:Static c:InteractiveRebaseActionConverters.ToIconBrush}}"/>
126128
<TextBlock Margin="8,0" Text="{Binding Action, Converter={x:Static c:InteractiveRebaseActionConverters.ToName}}"/>
127129
</StackPanel>
128130
</Button>
129131

130132
<!-- Subject -->
131-
<Grid Grid.Column="3" ColumnDefinitions="Auto,*" ClipToBounds="True">
133+
<Grid Grid.Column="2" ColumnDefinitions="Auto,*" ClipToBounds="True">
132134
<Button Grid.Column="0"
133135
Classes="icon_button"
134136
Margin="0,0,6,0" Padding="0"
@@ -150,26 +152,40 @@
150152
</Grid>
151153

152154
<!-- Author Avatar -->
153-
<v:Avatar Grid.Column="4"
155+
<v:Avatar Grid.Column="3"
154156
Width="16" Height="16"
155157
Margin="8,0,0,0"
156158
VerticalAlignment="Center"
157159
User="{Binding Commit.Author}"/>
158160

159161
<!-- Author Name -->
160-
<Border Grid.Column="5" ClipToBounds="True">
162+
<Border Grid.Column="4" ClipToBounds="True">
161163
<TextBlock Margin="6,0,12,0" Text="{Binding Commit.Author.Name}"/>
162164
</Border>
163165

164166
<!-- Commit SHA -->
165-
<Border Grid.Column="6" ClipToBounds="True">
167+
<Border Grid.Column="5" ClipToBounds="True">
166168
<TextBlock Text="{Binding Commit.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"/>
167169
</Border>
168170

169171
<!-- Commit Time -->
170-
<Border Grid.Column="7">
172+
<Border Grid.Column="6">
171173
<TextBlock Margin="16,0,8,0" Text="{Binding Commit.CommitterTimeStr}"/>
172174
</Border>
175+
176+
<!-- Drop Indicator -->
177+
<Rectangle Grid.Column="0" Grid.ColumnSpan="7"
178+
Height="2"
179+
VerticalAlignment="Top"
180+
Fill="{DynamicResource Brush.Accent}"
181+
IsVisible="{Binding IsDropBeforeVisible, Mode=OneWay}"
182+
IsHitTestVisible="False"/>
183+
<Rectangle Grid.Column="0" Grid.ColumnSpan="7"
184+
Height="2"
185+
VerticalAlignment="Bottom"
186+
Fill="{DynamicResource Brush.Accent}"
187+
IsVisible="{Binding IsDropAfterVisible, Mode=OneWay}"
188+
IsHitTestVisible="False"/>
173189
</Grid>
174190
</DataTemplate>
175191
</v:InteractiveRebaseListBox.ItemTemplate>

0 commit comments

Comments
 (0)