feature: add hotkey Alt+Down/⌥+Down to goto parent of selected commit (#2104)

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo
2026-02-08 00:35:50 +08:00
parent c624fbf969
commit ef14642d4e
10 changed files with 240 additions and 5 deletions

View File

@@ -467,6 +467,7 @@
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">Remote:</x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">Track files named '{0}'</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">Track all *{0} files</x:String>
<x:String x:Key="Text.GotoParentSelector" xml:space="preserve">Select Parent</x:String>
<x:String x:Key="Text.Histories" xml:space="preserve">HISTORY</x:String>
<x:String x:Key="Text.Histories.Header.Author" xml:space="preserve">AUTHOR</x:String>
<x:String x:Key="Text.Histories.Header.AuthorTime" xml:space="preserve">AUTHOR TIME</x:String>
@@ -496,6 +497,7 @@
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Stage all changes and commit</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Fetch, starts directly</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Dashboard mode (Default)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoToParent" xml:space="preserve">Goto parent of selected commit</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenCommandPalette" xml:space="preserve">Open command palette</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Commit search mode</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Pull, starts directly</x:String>

View File

@@ -471,6 +471,7 @@
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">远程 </x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">跟踪名为'{0}'的文件</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">跟踪所有 *{0} 文件</x:String>
<x:String x:Key="Text.GotoParentSelector" xml:space="preserve">选择前往的父提交</x:String>
<x:String x:Key="Text.Histories" xml:space="preserve">历史记录</x:String>
<x:String x:Key="Text.Histories.Header.Author" xml:space="preserve">作者</x:String>
<x:String x:Key="Text.Histories.Header.AuthorTime" xml:space="preserve">修改时间</x:String>
@@ -500,6 +501,7 @@
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">自动暂存全部变更并提交</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">拉取 (fetch) 远程变更</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">切换左边栏为分支/标签等显示模式(默认)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoToParent" xml:space="preserve">前往选中提交的父提交</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenCommandPalette" xml:space="preserve">打开快捷命令面板</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">切换左边栏为提交搜索模式</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">拉回 (pull) 远程变更</x:String>

View File

@@ -471,6 +471,7 @@
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">遠端存放庫:</x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">追蹤名稱為「{0}」的檔案</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">追蹤所有 *{0} 檔案</x:String>
<x:String x:Key="Text.GotoParentSelector" xml:space="preserve">選取要前往的父提交</x:String>
<x:String x:Key="Text.Histories" xml:space="preserve">歷史記錄</x:String>
<x:String x:Key="Text.Histories.Header.Author" xml:space="preserve">作者</x:String>
<x:String x:Key="Text.Histories.Header.AuthorTime" xml:space="preserve">修改時間</x:String>
@@ -500,6 +501,7 @@
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">自動暫存全部變更並提交</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">提取 (fetch) 遠端的變更</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">切換左邊欄為分支/標籤等顯示模式 (預設)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoToParent" xml:space="preserve">前往所選提交的父提交</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenCommandPalette" xml:space="preserve">開啟命令面板</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">切換左邊欄為歷史搜尋模式</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">拉取 (pull) 遠端的變更</x:String>

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
namespace SourceGit.ViewModels
{
public class GotoParentSelector
{
public List<Models.Commit> Parents
{
get;
}
public GotoParentSelector(Histories owner, List<Models.Commit> parents)
{
Parents = parents;
_owner = owner;
}
public void Sure(Models.Commit commit)
{
_owner.NavigateTo(commit.SHA);
}
private Histories _owner;
}
}

View File

@@ -254,6 +254,13 @@ namespace SourceGit.ViewModels
}
}
public async Task<Models.Commit> GetCommitAsync(string sha)
{
return await new Commands.QuerySingleCommit(_repo.FullPath, sha)
.GetResultAsync()
.ConfigureAwait(false);
}
public async Task<bool> CheckoutBranchByDecoratorAsync(Models.Decorator decorator)
{
if (decorator == null)

View File

@@ -0,0 +1,103 @@
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="using:SourceGit.Models"
xmlns:v="using:SourceGit.Views"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="520" d:DesignHeight="230"
x:Class="SourceGit.Views.GotoParentSelector"
x:DataType="vm:GotoParentSelector"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.GotoParentSelector}"
Width="600" SizeToContent="Height"
CanResize="False"
WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,Auto">
<!-- TitleBar -->
<Grid Grid.Row="0" Height="28" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
PointerPressed="BeginMoveWindow"/>
<Path Width="14" Height="14"
Margin="10,0,0,0"
HorizontalAlignment="Left"
Data="{StaticResource Icons.GotoParent}"
IsVisible="{OnPlatform True, macOS=False}"/>
<TextBlock Classes="bold"
Text="{DynamicResource Text.GotoParentSelector}"
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<v:CaptionButtons HorizontalAlignment="Right"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<ListBox Grid.Row="1"
Focusable="True"
Margin="8" Padding="4"
ItemsSource="{Binding Parents}"
SelectionMode="AlwaysSelected"
BorderThickness="0"
Background="Transparent"
Grid.IsSharedSizeScope="True"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
Loaded="OnListLoaded"
KeyDown="OnListKeyDown">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="28"/>
<Setter Property="CornerRadius" Value="4"/>
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Spacing="2"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Commit">
<Grid Background="Transparent" Tapped="OnListItemTapped">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="CommitSHAColumn"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="CommitTimeColumn"/>
</Grid.ColumnDefinitions>
<v:Avatar Grid.Column="0"
Width="16" Height="16"
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"
User="{Binding Author}"/>
<Border Grid.Column="1" Margin="2,0,0,0" ClipToBounds="True">
<TextBlock Text="{Binding Subject}" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"/>
</Border>
<TextBlock Grid.Column="2"
Margin="4,0,0,0"
Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
Foreground="DarkOrange"
VerticalAlignment="Center"/>
<TextBlock Grid.Column="3"
Margin="4,0"
Text="{Binding CommitterTimeShortStr}"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</v:ChromelessWindow>

View File

@@ -0,0 +1,49 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace SourceGit.Views
{
public partial class GotoParentSelector : ChromelessWindow
{
public GotoParentSelector()
{
CloseOnESC = true;
InitializeComponent();
}
private void OnListLoaded(object sender, RoutedEventArgs e)
{
(sender as ListBox)?.Focus();
}
private void OnListKeyDown(object sender, KeyEventArgs e)
{
if (e is not { Key: Key.Enter, KeyModifiers: KeyModifiers.None })
return;
if (DataContext is not ViewModels.GotoParentSelector vm)
return;
if (sender is not ListBox { SelectedItem: Models.Commit commit })
return;
vm.Sure(commit);
Close();
e.Handled = true;
}
private void OnListItemTapped(object sender, TappedEventArgs e)
{
if (sender is not Control { DataContext: Models.Commit commit })
return;
if (DataContext is ViewModels.GotoParentSelector vm)
vm.Sure(commit);
Close();
e.Handled = true;
}
}
}

View File

@@ -24,6 +24,12 @@
</v:HistoriesLayout.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
<!-- DataGrid hardcodes all the arrow keys, so we need a fake button to intercept this shortcut key -->
<Button Width="0" Height="0"
Click="OnGotoParent"
HotKey="Alt+Down"
IsVisible="False"/>
<DataGrid x:Name="CommitListContainer"
Classes="static_scrollbar"
ScrollViewer.AllowAutoHide="False"

View File

@@ -159,6 +159,42 @@ namespace SourceGit.Views
dataGrid.ScrollIntoView(dataGrid.SelectedItem, null);
}
private async void OnGotoParent(object sender, RoutedEventArgs e)
{
if (DataContext is not ViewModels.Histories vm)
return;
if (!CommitListContainer.IsKeyboardFocusWithin)
return;
if (CommitListContainer.SelectedItems is not { Count: 1 } selected)
return;
if (selected[0] is not Models.Commit { Parents.Count: > 0 } commit)
return;
e.Handled = true;
if (commit.Parents.Count == 1)
{
vm.NavigateTo(commit.Parents[0]);
return;
}
var parents = new List<Models.Commit>();
foreach (var sha in commit.Parents)
{
var c = await vm.GetCommitAsync(sha);
if (c != null)
parents.Add(c);
}
if (parents.Count == 1)
vm.NavigateTo(parents[0].SHA);
else if (parents.Count > 1)
await App.ShowDialog(new ViewModels.GotoParentSelector(vm, parents));
}
private void OnCommitListLayoutUpdated(object _1, EventArgs _2)
{
if (!IsLoaded)
@@ -513,7 +549,7 @@ namespace SourceGit.Views
var messages = new List<string>();
foreach (var c in selected)
{
var message = await vm.GetCommitFullMessageAsync(c);
var message = await vm!.GetCommitFullMessageAsync(c);
messages.Add(message);
}

View File

@@ -83,7 +83,7 @@
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Increase}}"
Margin="0,8"/>
<Grid RowDefinitions="20,20,20,20,20,20,20,20,20,20,20,20,20" ColumnDefinitions="150,*">
<Grid RowDefinitions="20,20,20,20,20,20,20,20,20,20,20,20,20,20" ColumnDefinitions="150,*">
<TextBlock Grid.Row="0" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Shift+H, macOS=⌘+⇧+H}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.GoHome}" />
@@ -119,9 +119,12 @@
<TextBlock Grid.Row="11" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Shift+P, macOS=⌘+⇧+P}"/>
<TextBlock Grid.Row="11" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.OpenCommandPalette}" />
<TextBlock Grid.Row="12" Grid.Column="0" Classes="bold" Text="F5"/>
<TextBlock Grid.Row="12" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Refresh}" />
<TextBlock Grid.Row="12" Grid.Column="0" Classes="bold" Text="{OnPlatform Alt+Down, macOS=⌥+Down}"/>
<TextBlock Grid.Row="12" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.GoToParent}" />
<TextBlock Grid.Row="13" Grid.Column="0" Classes="bold" Text="F5"/>
<TextBlock Grid.Row="13" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Refresh}" />
</Grid>
<TextBlock Text="{DynamicResource Text.Hotkeys.TextEditor}"