feature: supports parameters in commit template (#487)

- ${files_num} will be replaced with staged changes count
- ${files} will be replaced with changed file paths
- ${files:N} will be replaced with top N changes file paths and with `and {TOTAL - N} other files` at end of replaced string.
This commit is contained in:
leo 2024-09-18 20:11:34 +08:00
parent 6932ce44a9
commit 900ebd8282
No known key found for this signature in database
2 changed files with 61 additions and 7 deletions

View file

@ -1,9 +1,17 @@
using CommunityToolkit.Mvvm.ComponentModel; using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.Models namespace SourceGit.Models
{ {
public class CommitTemplate : ObservableObject public partial class CommitTemplate : ObservableObject
{ {
[GeneratedRegex(@"\$\{files(\:\d+)?\}")]
private static partial Regex REG_COMMIT_TEMPLATE_FILES();
public string Name public string Name
{ {
get => _name; get => _name;
@ -16,6 +24,56 @@ namespace SourceGit.Models
set => SetProperty(ref _content, value); set => SetProperty(ref _content, value);
} }
public string Apply(List<Change> changes)
{
var content = _content.Replace("${files_num}", $"{changes.Count}");
var matches = REG_COMMIT_TEMPLATE_FILES().Matches(content);
if (matches.Count == 0)
return content;
var builder = new StringBuilder();
var last = 0;
for (int i = 0; i < matches.Count; i++)
{
var match = matches[i];
if (!match.Success)
continue;
var start = match.Index;
if (start != last)
builder.Append(content.Substring(last, start - last));
var countStr = match.Groups[1].Value;
var paths = new List<string>();
var more = string.Empty;
if (countStr is { Length: <= 1 })
{
foreach (var c in changes)
paths.Add(c.Path);
}
else
{
var count = Math.Min(int.Parse(countStr.Substring(1)), changes.Count);
for (int j = 0; j < count; j++)
paths.Add(changes[i].Path);
if (count < changes.Count)
more = $" and {changes.Count - count} other files";
}
builder.Append(string.Join(", ", paths));
if (!string.IsNullOrEmpty(more))
builder.Append(more);
last = start + match.Length;
}
if (last != content.Length - 1)
builder.Append(content.Substring(last));
return builder.ToString();
}
private string _name = string.Empty; private string _name = string.Empty;
private string _content = string.Empty; private string _content = string.Empty;
} }

View file

@ -780,13 +780,9 @@ namespace SourceGit.ViewModels
foreach (var change in _selectedUnstaged) foreach (var change in _selectedUnstaged)
{ {
if (change.IsConflit) if (change.IsConflit)
{
hasConflicts = true; hasConflicts = true;
}
else else
{
hasNoneConflicts = true; hasNoneConflicts = true;
}
} }
if (hasConflicts) if (hasConflicts)
@ -1160,7 +1156,7 @@ namespace SourceGit.ViewModels
item.Icon = App.CreateMenuIcon("Icons.Code"); item.Icon = App.CreateMenuIcon("Icons.Code");
item.Click += (_, e) => item.Click += (_, e) =>
{ {
CommitMessage = template.Content; CommitMessage = template.Apply(_staged);
e.Handled = true; e.Handled = true;
}; };
menu.Items.Add(item); menu.Items.Add(item);