refactor: search hotkey (#2059)

- Change the hotkey of searching commit from `Ctrl+F/⌘+F` to `Ctrl+Shift+F/⌘+⇧+F`
- When some list is focused, pressing `Ctrl+F/⌘+F` will auto focus the right searchbox(filterbox) of it

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo
2026-03-03 17:53:26 +08:00
parent dd94da508e
commit 5d37dcc89d
19 changed files with 139 additions and 27 deletions

View File

@@ -303,6 +303,15 @@ namespace SourceGit.Views
remove { RemoveHandler(RowsChangedEvent, value); }
}
public static readonly RoutedEvent<RoutedEventArgs> SearchRequestedEvent =
RoutedEvent.Register<BranchTree, RoutedEventArgs>(nameof(SearchRequested), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
public event EventHandler<RoutedEventArgs> SearchRequested
{
add { AddHandler(SearchRequestedEvent, value); }
remove { RemoveHandler(SearchRequestedEvent, value); }
}
public BranchTree()
{
InitializeComponent();
@@ -566,6 +575,13 @@ namespace SourceGit.Views
private void OnTreeKeyDown(object _, KeyEventArgs e)
{
if (e.Key == Key.F && e.KeyModifiers == (OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
{
RaiseEvent(new RoutedEventArgs(SearchRequestedEvent));
e.Handled = true;
return;
}
if (e.Key is not (Key.Delete or Key.Back))
return;

View File

@@ -18,6 +18,7 @@
<!-- Search & Display Mode -->
<Grid Grid.Row="0" ColumnDefinitions="*,Auto">
<TextBox Grid.Column="0"
x:Name="CommitChangeSearchBox"
Height="26"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
Background="Transparent"

View File

@@ -42,8 +42,8 @@ namespace SourceGit.Views
if (sender is not ChangeCollectionView { SelectedChanges: { Count: > 0 } selectedChanges } view)
return;
if (e.Key == Key.C &&
e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
var cmdKey = OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control;
if (e.Key == Key.C && e.KeyModifiers.HasFlag(cmdKey))
{
var builder = new StringBuilder();
var copyAbsPath = e.KeyModifiers.HasFlag(KeyModifiers.Shift);
@@ -65,6 +65,11 @@ namespace SourceGit.Views
await App.CopyTextAsync(builder.ToString());
e.Handled = true;
}
else if (e.Key == Key.F && e.KeyModifiers == cmdKey)
{
CommitChangeSearchBox.Focus();
e.Handled = true;
}
}
}
}

View File

@@ -103,6 +103,7 @@
<!-- Search & Display Mode -->
<Grid Grid.Row="0" ColumnDefinitions="*,18">
<TextBox Grid.Column="0"
x:Name="ChangeSearchBox"
Height="26"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
Background="Transparent"

View File

@@ -218,7 +218,8 @@ namespace SourceGit.Views
if (sender is not ChangeCollectionView { SelectedChanges: { Count: > 0 } selectedChanges })
return;
if (e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control) && e.Key == Key.C)
var cmdKey = OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control;
if (e.Key == Key.C && e.KeyModifiers.HasFlag(cmdKey))
{
var builder = new StringBuilder();
var copyAbsPath = e.KeyModifiers.HasFlag(KeyModifiers.Shift);
@@ -235,6 +236,11 @@ namespace SourceGit.Views
await App.CopyTextAsync(builder.ToString());
e.Handled = true;
}
else if (e.Key == Key.F && e.KeyModifiers == cmdKey)
{
ChangeSearchBox.Focus();
e.Handled = true;
}
}
}
}

View File

@@ -87,7 +87,7 @@
<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}" />
<TextBlock Grid.Row="1" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+F, macOS=⌘+F}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Shift+F, macOS=⌘+⇧+F}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.OpenSearchCommits}" />
<TextBlock Grid.Row="2" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+1, macOS=⌘+1}"/>

View File

@@ -235,7 +235,7 @@ namespace SourceGit.Views
repo.SelectedViewIndex = 2;
e.Handled = true;
return;
case Key.F:
case Key.F when e.KeyModifiers.HasFlag(KeyModifiers.Shift):
repo.IsSearchingCommits = true;
e.Handled = true;
return;

View File

@@ -42,7 +42,7 @@
<TextBlock>
<Run Text="{DynamicResource Text.Repository.Search}" Foreground="{DynamicResource Brush.FG1}"/>
<Run Text=" "/>
<Run Text="{OnPlatform Ctrl+F, macOS=⌘+F}" FontSize="11" Foreground="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"/>
<Run Text="{OnPlatform Ctrl+Shift+F, macOS=⌘+⇧+F}" FontSize="11" Foreground="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"/>
</TextBlock>
</ToolTip.Tip>
<Path Width="12" Height="12" Stretch="Fill" HorizontalAlignment="Center" Data="{StaticResource Icons.Search}"/>
@@ -191,6 +191,7 @@
<!-- Filter Branches/Tags/Submodules -->
<TextBox Grid.Row="1"
x:Name="FilterBox"
Height="26"
Margin="8,6,4,0"
BorderThickness="1"
@@ -253,7 +254,8 @@
Nodes="{Binding LocalBranchTrees}"
IsVisible="{Binding IsLocalBranchGroupExpanded}"
SelectionChanged="OnLocalBranchTreeSelectionChanged"
RowsChanged="OnLeftSidebarRowsChanged"/>
RowsChanged="OnLeftSidebarRowsChanged"
SearchRequested="OnToggleFilter"/>
<!-- Remotes -->
<ToggleButton Grid.Row="2" Classes="group_expander" IsChecked="{Binding IsRemoteGroupExpanded, Mode=TwoWay}">
@@ -286,7 +288,8 @@
Nodes="{Binding RemoteBranchTrees}"
IsVisible="{Binding IsRemoteGroupExpanded}"
SelectionChanged="OnRemoteBranchTreeSelectionChanged"
RowsChanged="OnLeftSidebarRowsChanged"/>
RowsChanged="OnLeftSidebarRowsChanged"
SearchRequested="OnToggleFilter"/>
<!-- Tags -->
<ToggleButton Grid.Row="4" Classes="group_expander" IsChecked="{Binding IsTagGroupExpanded, Mode=TwoWay}">
@@ -331,7 +334,8 @@
Focusable="False"
IsVisible="{Binding IsTagGroupExpanded, Mode=OneWay}"
SelectionChanged="OnTagsSelectionChanged"
RowsChanged="OnLeftSidebarRowsChanged"/>
RowsChanged="OnLeftSidebarRowsChanged"
SearchRequested="OnToggleFilter"/>
<!-- Submodules -->
<ToggleButton Grid.Row="6" Classes="group_expander" IsChecked="{Binding IsSubmoduleGroupExpanded, Mode=TwoWay}">
@@ -373,7 +377,8 @@
Content="{Binding VisibleSubmodules}"
RowsChanged="OnLeftSidebarRowsChanged"
Focusable="False"
IsVisible="{Binding IsSubmoduleGroupExpanded, Mode=OneWay}"/>
IsVisible="{Binding IsSubmoduleGroupExpanded, Mode=OneWay}"
SearchRequested="OnToggleFilter"/>
<!-- Worktrees -->
<ToggleButton Grid.Row="8" Classes="group_expander" IsChecked="{Binding IsWorktreeGroupExpanded, Mode=TwoWay}">

View File

@@ -20,6 +20,12 @@ namespace SourceGit.Views
UpdateLeftSidebarLayout();
}
private void OnToggleFilter(object _, RoutedEventArgs e)
{
FilterBox.Focus();
e.Handled = true;
}
private void OnSearchCommitPanelPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == IsVisibleProperty && sender is Grid { IsVisible: true })

View File

@@ -69,6 +69,7 @@
<!-- Search & Display Mode -->
<Grid Grid.Row="0" ColumnDefinitions="*,18">
<TextBox Grid.Column="0"
x:Name="RevisionCompareChangeSearchBox"
Height="26"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
Background="Transparent"

View File

@@ -241,7 +241,8 @@ namespace SourceGit.Views
if (sender is not ChangeCollectionView { SelectedChanges: { Count: > 0 } selectedChanges })
return;
if (e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control) && e.Key == Key.C)
var cmdKey = OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control;
if (e.Key == Key.C && e.KeyModifiers.HasFlag(cmdKey))
{
var builder = new StringBuilder();
var copyAbsPath = e.KeyModifiers.HasFlag(KeyModifiers.Shift);
@@ -258,6 +259,11 @@ namespace SourceGit.Views
await App.CopyTextAsync(builder.ToString());
e.Handled = true;
}
else if (e.Key == Key.F && e.KeyModifiers == cmdKey)
{
RevisionCompareChangeSearchBox.Focus();
e.Handled = true;
}
}
}
}

View File

@@ -113,6 +113,14 @@ namespace SourceGit.Views
protected override async void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.F && e.KeyModifiers == (OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
{
var panel = this.FindAncestorOfType<RevisionFileTreeView>();
panel.RaiseEvent(new RoutedEventArgs(RevisionFileTreeView.SearchRequestedEvent));
e.Handled = true;
return;
}
if (SelectedItem is ViewModels.RevisionFileTreeNode node)
{
if (node.IsFolder &&
@@ -189,6 +197,15 @@ namespace SourceGit.Views
public AvaloniaList<ViewModels.RevisionFileTreeNode> Rows { get; } = [];
public static readonly RoutedEvent<RoutedEventArgs> SearchRequestedEvent =
RoutedEvent.Register<BranchTree, RoutedEventArgs>(nameof(SearchRequested), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
public event EventHandler<RoutedEventArgs> SearchRequested
{
add { AddHandler(SearchRequestedEvent, value); }
remove { RemoveHandler(SearchRequestedEvent, value); }
}
public RevisionFileTreeView()
{
InitializeComponent();

View File

@@ -102,7 +102,7 @@
<!-- File Tree -->
<Border Grid.Row="1" Margin="0,4,0,0" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" Background="{DynamicResource Brush.Contents}">
<v:RevisionFileTreeView x:Name="FileTree" Revision="{Binding Commit.SHA}"/>
<v:RevisionFileTreeView x:Name="FileTree" Revision="{Binding Commit.SHA}" SearchRequested="OnToggleSearch"/>
</Border>
</Grid>

View File

@@ -11,6 +11,12 @@ namespace SourceGit.Views
InitializeComponent();
}
private void OnToggleSearch(object _, RoutedEventArgs e)
{
TxtSearchRevisionFiles.Focus();
e.Handled = true;
}
private async void OnSearchBoxKeyDown(object _, KeyEventArgs e)
{
if (DataContext is not ViewModels.CommitDetail vm)

View File

@@ -10,7 +10,7 @@
x:Class="SourceGit.Views.SubmodulesView">
<UserControl.DataTemplates>
<DataTemplate DataType="vm:SubmoduleCollectionAsTree">
<ListBox Classes="repo_left_content_list" Padding="0,0,2,0" ItemsSource="{Binding Rows}" SelectionMode="Single">
<ListBox Classes="repo_left_content_list" Padding="0,0,2,0" ItemsSource="{Binding Rows}" SelectionMode="Single" KeyDown="OnKeyDown">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="CornerRadius" Value="4"/>
@@ -139,7 +139,7 @@
</DataTemplate>
<DataTemplate DataType="vm:SubmoduleCollectionAsList">
<ListBox Classes="repo_left_content_list" ItemsSource="{Binding Submodules}" SelectionMode="Single">
<ListBox Classes="repo_left_content_list" ItemsSource="{Binding Submodules}" SelectionMode="Single" KeyDown="OnKeyDown">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="CornerRadius" Value="4"/>

View File

@@ -97,6 +97,15 @@ namespace SourceGit.Views
remove { RemoveHandler(RowsChangedEvent, value); }
}
public static readonly RoutedEvent<RoutedEventArgs> SearchRequestedEvent =
RoutedEvent.Register<BranchTree, RoutedEventArgs>(nameof(SearchRequested), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
public event EventHandler<RoutedEventArgs> SearchRequested
{
add { AddHandler(SearchRequestedEvent, value); }
remove { RemoveHandler(SearchRequestedEvent, value); }
}
public int Rows
{
get;
@@ -315,5 +324,15 @@ namespace SourceGit.Views
e.Handled = true;
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.F && e.KeyModifiers == (OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
{
RaiseEvent(new RoutedEventArgs(SearchRequestedEvent));
e.Handled = true;
return;
}
}
}
}

View File

@@ -116,6 +116,15 @@ namespace SourceGit.Views
remove { RemoveHandler(RowsChangedEvent, value); }
}
public static readonly RoutedEvent<RoutedEventArgs> SearchRequestedEvent =
RoutedEvent.Register<BranchTree, RoutedEventArgs>(nameof(SearchRequested), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
public event EventHandler<RoutedEventArgs> SearchRequested
{
add { AddHandler(SearchRequestedEvent, value); }
remove { RemoveHandler(SearchRequestedEvent, value); }
}
public int Rows
{
get;
@@ -429,6 +438,13 @@ namespace SourceGit.Views
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.F && e.KeyModifiers == (OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
{
RaiseEvent(new RoutedEventArgs(SearchRequestedEvent));
e.Handled = true;
return;
}
if (e.Key is not (Key.Delete or Key.Back))
return;

View File

@@ -26,7 +26,8 @@
<!-- Search Filter -->
<Border Grid.Row="0" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}">
<TextBox Height="24"
<TextBox x:Name="LocalChangesSearchBox"
Height="24"
Margin="4,0"
BorderThickness="1"
CornerRadius="12"

View File

@@ -94,6 +94,8 @@ namespace SourceGit.Views
{
if (DataContext is ViewModels.WorkingCopy vm)
{
var cmdKey = OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control;
if (e.Key is Key.Space or Key.Enter)
{
var next = UnstagedChangesView.GetNextChangeWithoutSelection();
@@ -106,9 +108,7 @@ namespace SourceGit.Views
vm.Discard(vm.SelectedUnstaged);
e.Handled = true;
}
else if (e.Key is Key.O &&
e.KeyModifiers == (OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control) &&
vm.SelectedUnstaged is { Count: 1 })
else if (e.Key is Key.O && e.KeyModifiers == cmdKey && vm.SelectedUnstaged is { Count: 1 })
{
var change = vm.SelectedUnstaged[0];
var fullpath = Native.OS.GetAbsPath(vm.Repository.FullPath, change.Path);
@@ -116,9 +116,7 @@ namespace SourceGit.Views
Native.OS.OpenWithDefaultEditor(fullpath);
e.Handled = true;
}
else if (e.Key is Key.C &&
e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control) &&
vm.SelectedUnstaged is { Count: 1 })
else if (e.Key is Key.C && e.KeyModifiers.HasFlag(cmdKey) && vm.SelectedUnstaged is { Count: 1 })
{
var change = vm.SelectedUnstaged[0];
if (e.KeyModifiers.HasFlag(KeyModifiers.Shift))
@@ -128,6 +126,11 @@ namespace SourceGit.Views
e.Handled = true;
}
else if (e.Key is Key.F && e.KeyModifiers == cmdKey)
{
LocalChangesSearchBox.Focus();
e.Handled = true;
}
}
}
@@ -135,6 +138,8 @@ namespace SourceGit.Views
{
if (DataContext is ViewModels.WorkingCopy vm)
{
var cmdKey = OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control;
if (e.Key is Key.Space or Key.Enter)
{
var next = StagedChangesView.GetNextChangeWithoutSelection();
@@ -142,9 +147,7 @@ namespace SourceGit.Views
StagedChangesView.TakeFocus();
e.Handled = true;
}
else if (e.Key is Key.O &&
e.KeyModifiers == (OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control) &&
vm.SelectedStaged is { Count: 1 })
else if (e.Key is Key.O && e.KeyModifiers == cmdKey && vm.SelectedStaged is { Count: 1 })
{
var change = vm.SelectedStaged[0];
var fullpath = Native.OS.GetAbsPath(vm.Repository.FullPath, change.Path);
@@ -152,9 +155,7 @@ namespace SourceGit.Views
Native.OS.OpenWithDefaultEditor(fullpath);
e.Handled = true;
}
else if (e.Key is Key.C &&
e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control) &&
vm.SelectedStaged is { Count: 1 })
else if (e.Key is Key.C && e.KeyModifiers.HasFlag(cmdKey) && vm.SelectedStaged is { Count: 1 })
{
var change = vm.SelectedStaged[0];
if (e.KeyModifiers.HasFlag(KeyModifiers.Shift))
@@ -164,6 +165,11 @@ namespace SourceGit.Views
e.Handled = true;
}
else if (e.Key is Key.F && e.KeyModifiers == cmdKey)
{
LocalChangesSearchBox.Focus();
e.Handled = true;
}
}
}