mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-22 20:37:19 -08:00
feature: add auto complete box for searching commits by file path
This commit is contained in:
parent
addfb449cc
commit
7f8b8a19a0
4 changed files with 235 additions and 35 deletions
21
src/Commands/QueryCurrentRevisionFiles.cs
Normal file
21
src/Commands/QueryCurrentRevisionFiles.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryCurrentRevisionFiles : Command
|
||||
{
|
||||
public QueryCurrentRevisionFiles(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "ls-tree -r --name-only HEAD";
|
||||
}
|
||||
|
||||
public string[] Result()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
if (rs.IsSuccess)
|
||||
return rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using System.IO;
|
|||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
|
@ -170,8 +171,15 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
SearchedCommits = new List<Models.Commit>();
|
||||
SearchCommitFilter = string.Empty;
|
||||
SearchCommitFilterSuggestion.Clear();
|
||||
IsSearchCommitSuggestionOpen = false;
|
||||
_revisionFiles.Clear();
|
||||
|
||||
if (value)
|
||||
{
|
||||
SelectedViewIndex = 0;
|
||||
UpdateCurrentRevisionFilesForSearchSuggestion();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,15 +193,59 @@ namespace SourceGit.ViewModels
|
|||
public int SearchCommitFilterType
|
||||
{
|
||||
get => _searchCommitFilterType;
|
||||
set => SetProperty(ref _searchCommitFilterType, value);
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _searchCommitFilterType, value))
|
||||
UpdateCurrentRevisionFilesForSearchSuggestion();
|
||||
}
|
||||
}
|
||||
|
||||
public string SearchCommitFilter
|
||||
{
|
||||
get => _searchCommitFilter;
|
||||
set => SetProperty(ref _searchCommitFilter, value);
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _searchCommitFilter, value) &&
|
||||
_searchCommitFilterType == 3 &&
|
||||
!string.IsNullOrEmpty(value) &&
|
||||
value.Length >= 2 &&
|
||||
_revisionFiles.Count > 0)
|
||||
{
|
||||
var suggestion = new List<string>();
|
||||
foreach (var file in _revisionFiles)
|
||||
{
|
||||
if (file.Contains(value, StringComparison.OrdinalIgnoreCase) && file.Length != value.Length)
|
||||
{
|
||||
suggestion.Add(file);
|
||||
if (suggestion.Count > 100)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SearchCommitFilterSuggestion.Clear();
|
||||
SearchCommitFilterSuggestion.AddRange(suggestion);
|
||||
IsSearchCommitSuggestionOpen = SearchCommitFilterSuggestion.Count > 0;
|
||||
}
|
||||
else if (SearchCommitFilterSuggestion.Count > 0)
|
||||
{
|
||||
SearchCommitFilterSuggestion.Clear();
|
||||
IsSearchCommitSuggestionOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSearchCommitSuggestionOpen
|
||||
{
|
||||
get => _isSearchCommitSuggestionOpen;
|
||||
set => SetProperty(ref _isSearchCommitSuggestionOpen, value);
|
||||
}
|
||||
|
||||
public AvaloniaList<string> SearchCommitFilterSuggestion
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new AvaloniaList<string>();
|
||||
|
||||
public List<Models.Commit> SearchedCommits
|
||||
{
|
||||
get => _searchedCommits;
|
||||
|
@ -306,6 +358,9 @@ namespace SourceGit.ViewModels
|
|||
_visibleTags.Clear();
|
||||
_submodules.Clear();
|
||||
_searchedCommits.Clear();
|
||||
|
||||
_revisionFiles.Clear();
|
||||
SearchCommitFilterSuggestion.Clear();
|
||||
}
|
||||
|
||||
public void RefreshAll()
|
||||
|
@ -450,6 +505,8 @@ namespace SourceGit.ViewModels
|
|||
return;
|
||||
|
||||
IsSearchLoadingVisible = true;
|
||||
IsSearchCommitSuggestionOpen = false;
|
||||
SearchCommitFilterSuggestion.Clear();
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
|
@ -1886,6 +1943,20 @@ namespace SourceGit.ViewModels
|
|||
return visible;
|
||||
}
|
||||
|
||||
private void UpdateCurrentRevisionFilesForSearchSuggestion()
|
||||
{
|
||||
_revisionFiles.Clear();
|
||||
|
||||
if (_searchCommitFilterType == 3)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
var files = new Commands.QueryCurrentRevisionFiles(_fullpath).Result();
|
||||
Dispatcher.UIThread.Invoke(() => _revisionFiles.AddRange(files));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private string _fullpath = string.Empty;
|
||||
private string _gitDir = string.Empty;
|
||||
private Models.RepositorySettings _settings = null;
|
||||
|
@ -1899,9 +1970,11 @@ namespace SourceGit.ViewModels
|
|||
|
||||
private bool _isSearching = false;
|
||||
private bool _isSearchLoadingVisible = false;
|
||||
private bool _isSearchCommitSuggestionOpen = false;
|
||||
private int _searchCommitFilterType = 0;
|
||||
private string _searchCommitFilter = string.Empty;
|
||||
private List<Models.Commit> _searchedCommits = new List<Models.Commit>();
|
||||
private List<string> _revisionFiles = new List<string>();
|
||||
|
||||
private bool _isLocalBranchGroupExpanded = true;
|
||||
private bool _isRemoteGroupExpanded = false;
|
||||
|
|
|
@ -453,40 +453,92 @@
|
|||
</Grid>
|
||||
|
||||
<!-- Commit Search Panel -->
|
||||
<Grid Grid.Row="1" RowDefinitions="Auto,32,*" Margin="8,0,4,8" IsVisible="{Binding IsSearching}" PropertyChanged="OnSearchCommitPanelPropertyChanged">
|
||||
<Grid Grid.Row="1" RowDefinitions="24,32,*" Margin="8,0,4,8" IsVisible="{Binding IsSearching}" PropertyChanged="OnSearchCommitPanelPropertyChanged">
|
||||
<!-- Search Input Box -->
|
||||
<TextBox Grid.Row="0"
|
||||
x:Name="TxtSearchCommitsBox"
|
||||
Height="24"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"
|
||||
Background="{DynamicResource Brush.Contents}"
|
||||
CornerRadius="4"
|
||||
Watermark="{DynamicResource Text.Repository.Search}"
|
||||
Text="{Binding SearchCommitFilter, Mode=TwoWay}"
|
||||
VerticalContentAlignment="Center"
|
||||
KeyDown="OnSearchKeyDown">
|
||||
<TextBox.InnerLeftContent>
|
||||
<Path Width="14" Height="14"
|
||||
Margin="6,0,0,0"
|
||||
Fill="{DynamicResource Brush.FG2}"
|
||||
Data="{StaticResource Icons.Search}"/>
|
||||
</TextBox.InnerLeftContent>
|
||||
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button"
|
||||
Width="16"
|
||||
Margin="0,0,6,0"
|
||||
Command="{Binding ClearSearchCommitFilter}"
|
||||
IsVisible="{Binding SearchCommitFilter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
HorizontalAlignment="Right">
|
||||
<Grid Grid.Row="0">
|
||||
<TextBox x:Name="TxtSearchCommitsBox"
|
||||
Height="24"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"
|
||||
Background="{DynamicResource Brush.Contents}"
|
||||
CornerRadius="4"
|
||||
Watermark="{DynamicResource Text.Repository.Search}"
|
||||
Text="{Binding SearchCommitFilter, Mode=TwoWay}"
|
||||
VerticalContentAlignment="Center"
|
||||
KeyDown="OnSearchKeyDown">
|
||||
<TextBox.InnerLeftContent>
|
||||
<Path Width="14" Height="14"
|
||||
Margin="0,1,0,0"
|
||||
Fill="{DynamicResource Brush.FG1}"
|
||||
Data="{StaticResource Icons.Clear}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
Margin="6,0,0,0"
|
||||
Fill="{DynamicResource Brush.FG2}"
|
||||
Data="{StaticResource Icons.Search}"/>
|
||||
</TextBox.InnerLeftContent>
|
||||
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button"
|
||||
Width="16"
|
||||
Margin="0,0,6,0"
|
||||
Command="{Binding ClearSearchCommitFilter}"
|
||||
IsVisible="{Binding SearchCommitFilter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
HorizontalAlignment="Right">
|
||||
<Path Width="14" Height="14"
|
||||
Margin="0,1,0,0"
|
||||
Fill="{DynamicResource Brush.FG1}"
|
||||
Data="{StaticResource Icons.Clear}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
|
||||
<Popup PlacementTarget="#TxtSearchCommitsBox"
|
||||
Placement="BottomEdgeAlignedLeft"
|
||||
HorizontalOffset="-8" VerticalAlignment="-8"
|
||||
IsOpen="{Binding IsSearchCommitSuggestionOpen}">
|
||||
<Border Margin="8" VerticalAlignment="Top" Effect="drop-shadow(0 0 8 #80000000)">
|
||||
<Border Background="{DynamicResource Brush.Popup}" CornerRadius="4" Padding="4" BorderThickness="0.65" BorderBrush="{DynamicResource Brush.Accent}">
|
||||
<ListBox x:Name="SearchSuggestionBox"
|
||||
Background="Transparent"
|
||||
SelectionMode="Single"
|
||||
ItemsSource="{Binding SearchCommitFilterSuggestion}"
|
||||
MaxHeight="400"
|
||||
Focusable="True"
|
||||
KeyDown="OnSearchSuggestionBoxKeyDown">
|
||||
<ListBox.Styles>
|
||||
<Style Selector="ListBoxItem">
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="MinHeight" Value="26"/>
|
||||
<Setter Property="CornerRadius" Value="4"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="ListBox">
|
||||
<Setter Property="FocusAdorner">
|
||||
<FocusAdornerTemplate>
|
||||
<Grid/>
|
||||
</FocusAdornerTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ListBox.Styles>
|
||||
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate DataType="x:String">
|
||||
<StackPanel Background="Transparent" Orientation="Vertical" Margin="8,4" DoubleTapped="OnSearchSuggestionDoubleTapped">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.File}"/>
|
||||
<TextBlock Classes="primary" Margin="6,0,0,0" Text="{Binding Converter={x:Static c:PathConverters.PureFileName}}"/>
|
||||
</StackPanel>
|
||||
<TextBlock Classes="primary" FontSize="12" Margin="18,2,0,0" Foreground="{DynamicResource Brush.FG2}" Text="{Binding Converter={x:Static c:PathConverters.PureDirectoryName}}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Border>
|
||||
</Border>
|
||||
</Popup>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" ColumnDefinitions="Auto,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
|
|
|
@ -29,11 +29,33 @@ namespace SourceGit.Views
|
|||
|
||||
private void OnSearchKeyDown(object _, KeyEventArgs e)
|
||||
{
|
||||
var repo = DataContext as ViewModels.Repository;
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
if (DataContext is ViewModels.Repository repo && !string.IsNullOrWhiteSpace(repo.SearchCommitFilter))
|
||||
if (!string.IsNullOrWhiteSpace(repo.SearchCommitFilter))
|
||||
repo.StartSearchCommits();
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
if (repo.IsSearchCommitSuggestionOpen)
|
||||
{
|
||||
SearchSuggestionBox.Focus(NavigationMethod.Tab);
|
||||
SearchSuggestionBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Escape)
|
||||
{
|
||||
if (repo.IsSearchCommitSuggestionOpen)
|
||||
{
|
||||
repo.SearchCommitFilterSuggestion.Clear();
|
||||
repo.IsSearchCommitSuggestionOpen = false;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
@ -272,5 +294,37 @@ namespace SourceGit.Views
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSearchSuggestionBoxKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
var repo = DataContext as ViewModels.Repository;
|
||||
if (e.Key == Key.Escape)
|
||||
{
|
||||
repo.IsSearchCommitSuggestionOpen = false;
|
||||
repo.SearchCommitFilterSuggestion.Clear();
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Enter && SearchSuggestionBox.SelectedItem is string content)
|
||||
{
|
||||
repo.SearchCommitFilter = content;
|
||||
TxtSearchCommitsBox.CaretIndex = content.Length;
|
||||
repo.StartSearchCommits();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSearchSuggestionDoubleTapped(object sender, TappedEventArgs e)
|
||||
{
|
||||
var repo = DataContext as ViewModels.Repository;
|
||||
var content = (sender as StackPanel)?.DataContext as string;
|
||||
if (!string.IsNullOrEmpty(content))
|
||||
{
|
||||
repo.SearchCommitFilter = content;
|
||||
TxtSearchCommitsBox.CaretIndex = content.Length;
|
||||
repo.StartSearchCommits();
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue