Skip to content

Commit dca8f8b

Browse files
committed
feature: warn when commit subject line goes beyond a certain number of characters (#201)
1 parent d3042bb commit dca8f8b

16 files changed

+236
-43
lines changed

src/Commands/LFS.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public void Prune(Action<string> outputHandler)
7777
var rs = cmd.ReadToEnd();
7878
if (rs.IsSuccess)
7979
{
80-
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
80+
var lines = rs.StdOut.Split(new char[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries);
8181
foreach (var line in lines)
8282
{
8383
var match = REG_LOCK().Match(line);

src/Converters/IntConverters.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@ public static class IntConverters
1818

1919
public static readonly FuncValueConverter<int, bool> IsNotOne =
2020
new FuncValueConverter<int, bool>(v => v != 1);
21+
22+
public static readonly FuncValueConverter<int, bool> IsBadSubjectLength =
23+
new FuncValueConverter<int, bool>(v => v > ViewModels.Preference.Instance.SubjectGuideLength);
2124
}
2225
}

src/Models/InteractiveRebaseEditor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public static int Process(string file)
7979
if (!File.Exists(doneFile))
8080
return -1;
8181

82-
var done = File.ReadAllText(doneFile).Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries);
82+
var done = File.ReadAllText(doneFile).Split(new char[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries);
8383
if (done.Length > jobs.Count)
8484
return -1;
8585

src/Resources/Locales/en_US.axaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@
105105
<x:String x:Key="Text.CommitDetail.Info.Parents" xml:space="preserve">PARENTS</x:String>
106106
<x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">REFS</x:String>
107107
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">SHA</x:String>
108+
<x:String x:Key="Text.CommitMessageTextBox.Placeholder" xml:space="preserve">Enter commit subject &amp; message</x:String>
109+
<x:String x:Key="Text.CommitMessageTextBox.Tip" xml:space="preserve">Git uses an empty line to separate the subject and extra message body.</x:String>
108110
<x:String x:Key="Text.Configure" xml:space="preserve">Repository Configure</x:String>
109111
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Email Address</x:String>
110112
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Email address</x:String>
@@ -328,6 +330,7 @@
328330
<x:String x:Key="Text.Preference.General.Locale" xml:space="preserve">Language</x:String>
329331
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">History Commits</x:String>
330332
<x:String x:Key="Text.Preference.General.RestoreTabs" xml:space="preserve">Restore windows</x:String>
333+
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Subject Guide Length</x:String>
331334
<x:String x:Key="Text.Preference.General.UseFixedTabWidth" xml:space="preserve">Use fixed tab width in titlebar</x:String>
332335
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String>
333336
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">Fetch remotes automatically</x:String>
@@ -520,7 +523,6 @@
520523
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">You can stage this file now.</x:String>
521524
<x:String x:Key="Text.WorkingCopy.Commit" xml:space="preserve">COMMIT</x:String>
522525
<x:String x:Key="Text.WorkingCopy.CommitAndPush" xml:space="preserve">COMMIT &amp; PUSH</x:String>
523-
<x:String x:Key="Text.WorkingCopy.CommitMessageTip" xml:space="preserve">Enter commit message</x:String>
524526
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">CTRL + Enter</x:String>
525527
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">CONFLICTS DETECTED</x:String>
526528
<x:String x:Key="Text.WorkingCopy.Conflicts.Resolved" xml:space="preserve">FILE CONFLICTS ARE RESOLVED</x:String>

src/Resources/Locales/zh_CN.axaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@
108108
<x:String x:Key="Text.CommitDetail.Info.Parents" xml:space="preserve">父提交</x:String>
109109
<x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">相关引用</x:String>
110110
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">提交指纹</x:String>
111+
<x:String x:Key="Text.CommitMessageTextBox.Placeholder" xml:space="preserve">填写提交信息</x:String>
112+
<x:String x:Key="Text.CommitMessageTextBox.Tip" xml:space="preserve">Git使用空白行来划分提交信息中的主题与内容</x:String>
111113
<x:String x:Key="Text.Configure" xml:space="preserve">仓库配置</x:String>
112114
<x:String x:Key="Text.Configure.Email" xml:space="preserve">电子邮箱</x:String>
113115
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">邮箱地址</x:String>
@@ -331,6 +333,7 @@
331333
<x:String x:Key="Text.Preference.General.Locale" xml:space="preserve">显示语言</x:String>
332334
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">最大历史提交数</x:String>
333335
<x:String x:Key="Text.Preference.General.RestoreTabs" xml:space="preserve">启动时恢复上次打开的仓库</x:String>
336+
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">SUBJECT字数检测</x:String>
334337
<x:String x:Key="Text.Preference.General.UseFixedTabWidth" xml:space="preserve">使用固定宽度的标题栏标签</x:String>
335338
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT配置</x:String>
336339
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">启用定时自动拉取远程更新</x:String>
@@ -522,7 +525,6 @@
522525
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">现在您已可将其加入暂存区中</x:String>
523526
<x:String x:Key="Text.WorkingCopy.Commit" xml:space="preserve">提交</x:String>
524527
<x:String x:Key="Text.WorkingCopy.CommitAndPush" xml:space="preserve">提交并推送</x:String>
525-
<x:String x:Key="Text.WorkingCopy.CommitMessageTip" xml:space="preserve">填写提交信息</x:String>
526528
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">CTRL + Enter</x:String>
527529
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">检测到冲突</x:String>
528530
<x:String x:Key="Text.WorkingCopy.Conflicts.Resolved" xml:space="preserve">文件冲突已解决</x:String>

src/Resources/Locales/zh_TW.axaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@
108108
<x:String x:Key="Text.CommitDetail.Info.Parents" xml:space="preserve">父提交</x:String>
109109
<x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">相關引用</x:String>
110110
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">提交指紋</x:String>
111+
<x:String x:Key="Text.CommitMessageTextBox.Placeholder" xml:space="preserve">填寫提交資訊</x:String>
112+
<x:String x:Key="Text.CommitMessageTextBox.Tip" xml:space="preserve">Git使用空白行來劃分提交資訊中的主題與內容</x:String>
111113
<x:String x:Key="Text.Configure" xml:space="preserve">倉庫配置</x:String>
112114
<x:String x:Key="Text.Configure.Email" xml:space="preserve">電子郵箱</x:String>
113115
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">郵箱地址</x:String>
@@ -331,6 +333,7 @@
331333
<x:String x:Key="Text.Preference.General.Locale" xml:space="preserve">顯示語言</x:String>
332334
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">最大歷史提交數</x:String>
333335
<x:String x:Key="Text.Preference.General.RestoreTabs" xml:space="preserve">啟動時恢復上次開啟的倉庫</x:String>
336+
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">SUBJECT字數檢測</x:String>
334337
<x:String x:Key="Text.Preference.General.UseFixedTabWidth" xml:space="preserve">使用固定寬度的標題欄標籤</x:String>
335338
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT配置</x:String>
336339
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">啟用定時自動拉取遠端更新</x:String>
@@ -522,7 +525,6 @@
522525
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">現在您已可將其加入暫存區中</x:String>
523526
<x:String x:Key="Text.WorkingCopy.Commit" xml:space="preserve">提交</x:String>
524527
<x:String x:Key="Text.WorkingCopy.CommitAndPush" xml:space="preserve">提交併推送</x:String>
525-
<x:String x:Key="Text.WorkingCopy.CommitMessageTip" xml:space="preserve">填寫提交資訊</x:String>
526528
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">CTRL + Enter</x:String>
527529
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">檢測到衝突</x:String>
528530
<x:String x:Key="Text.WorkingCopy.Conflicts.Resolved" xml:space="preserve">檔案衝突已解決</x:String>

src/Resources/Styles.axaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<Styles xmlns="https://github.com/avaloniaui"
22
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
33
xmlns:vm="using:SourceGit.ViewModels"
4-
xmlns:c="using:SourceGit.Converters"
54
xmlns:ae="using:AvaloniaEdit"
65
xmlns:aes="using:AvaloniaEdit.Search">
76
<Design.PreviewWith>

src/ViewModels/Preference.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ public int MaxHistoryCommits
134134
set => SetProperty(ref _maxHistoryCommits, value);
135135
}
136136

137+
public int SubjectGuideLength
138+
{
139+
get => _subjectGuideLength;
140+
set => SetProperty(ref _subjectGuideLength, value);
141+
}
142+
137143
public bool RestoreTabs
138144
{
139145
get => _restoreTabs;
@@ -534,9 +540,11 @@ private static bool RemoveNodeRecursive(RepositoryNode node, AvaloniaList<Reposi
534540
private LayoutInfo _layout = new LayoutInfo();
535541

536542
private int _maxHistoryCommits = 20000;
543+
private int _subjectGuideLength = 50;
537544
private bool _restoreTabs = false;
538545
private bool _useFixedTabWidth = true;
539546
private bool _check4UpdatesOnStartup = true;
547+
540548
private bool _useTwoColumnsLayoutInHistories = false;
541549
private bool _useSideBySideDiff = false;
542550
private bool _useSyntaxHighlighting = false;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<UserControl xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:ae="using:AvaloniaEdit"
6+
xmlns:c="using:SourceGit.Converters"
7+
xmlns:vm="using:SourceGit.ViewModels"
8+
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
9+
x:Class="SourceGit.Views.CommitMessageTextBox"
10+
x:Name="ThisControl">
11+
<Border Background="{DynamicResource Brush.Contents}"
12+
BorderThickness="1"
13+
BorderBrush="{DynamicResource Brush.Border2}"
14+
CornerRadius="4">
15+
<Grid RowDefinitions="*,Auto">
16+
<Grid Grid.Row="0">
17+
<ae:TextEditor x:Name="TextEditor"
18+
Foreground="{DynamicResource Brush.FG1}"
19+
Background="Transparent"
20+
Padding="2,1"
21+
BorderThickness="0"
22+
WordWrap="True"
23+
Document="{Binding #ThisControl.Document}"
24+
TextChanged="OnTextEditorTextChanged"
25+
LayoutUpdated="OnTextEditorLayoutUpdated"/>
26+
27+
<TextBlock Text="{DynamicResource Text.CommitMessageTextBox.Placeholder}"
28+
Foreground="{DynamicResource Brush.FG2}"
29+
HorizontalAlignment="Left"
30+
VerticalAlignment="Top"
31+
Margin="2,1"
32+
IsVisible="{Binding #ThisControl.Text, Converter={x:Static StringConverters.IsNullOrEmpty}}"
33+
IsHitTestVisible="False"/>
34+
35+
<Rectangle x:Name="SubjectGuideLine"
36+
Height="1"
37+
HorizontalAlignment="Stretch"
38+
VerticalAlignment="Top"
39+
IsHitTestVisible="False"
40+
Fill="{DynamicResource Brush.Border2}"/>
41+
</Grid>
42+
43+
<Border Grid.Row="1" CornerRadius="0,0,4,4" BorderThickness="0,1,0,0" BorderBrush="{DynamicResource Brush.Border2}" Background="{DynamicResource Brush.Window}" ClipToBounds="True">
44+
<Grid ColumnDefinitions="Auto,*,Auto">
45+
<Path Grid.Column="0" Height="12" Width="12" Margin="4,0,0,0" Data="{DynamicResource Icons.Info}" ToolTip.Tip="{DynamicResource Text.CommitMessageTextBox.Tip}"/>
46+
<StackPanel Grid.Column="2" Orientation="Horizontal" Margin="4,2">
47+
<TextBlock Text="Subject:" FontSize="10" Foreground="{DynamicResource Brush.FG2}"/>
48+
<TextBlock Classes="monospace" Margin="2,0,0,0" FontSize="10" Text="{Binding #ThisControl.SubjectLength}"/>
49+
<TextBlock Classes="monospace" FontSize="10" Text="/"/>
50+
<TextBlock Classes="monospace" FontSize="10" Text="{Binding Source={x:Static vm:Preference.Instance}, Path=SubjectGuideLength}"/>
51+
<Path Width="10" Height="10" Margin="4,0,0,0" Data="{StaticResource Icons.Error}" Fill="DarkGoldenrod" IsVisible="{Binding #ThisControl.SubjectLength, Converter={x:Static c:IntConverters.IsBadSubjectLength}}"/>
52+
<TextBlock Margin="8,0,0,0" Text="Total:" FontSize="10" Foreground="{DynamicResource Brush.FG2}"/>
53+
<TextBlock Classes="monospace" Margin="2,0,0,0" FontSize="10" Text="{Binding #ThisControl.Text.Length}"/>
54+
</StackPanel>
55+
</Grid>
56+
</Border>
57+
</Grid>
58+
</Border>
59+
</UserControl>
60+
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
using System;
2+
3+
using Avalonia;
4+
using Avalonia.Controls;
5+
6+
using AvaloniaEdit.Document;
7+
using AvaloniaEdit.Rendering;
8+
9+
namespace SourceGit.Views
10+
{
11+
public partial class CommitMessageTextBox : UserControl
12+
{
13+
public static readonly StyledProperty<string> TextProperty =
14+
AvaloniaProperty.Register<CommitMessageTextBox, string>(nameof(Text), string.Empty);
15+
16+
public static readonly StyledProperty<int> SubjectLengthProperty =
17+
AvaloniaProperty.Register<CommitMessageTextBox, int>(nameof(SubjectLength));
18+
19+
public string Text
20+
{
21+
get => GetValue(TextProperty);
22+
set => SetValue(TextProperty, value);
23+
}
24+
25+
public int SubjectLength
26+
{
27+
get => GetValue(SubjectLengthProperty);
28+
set => SetValue(SubjectLengthProperty, value);
29+
}
30+
31+
public TextDocument Document
32+
{
33+
get;
34+
private set;
35+
}
36+
37+
public CommitMessageTextBox()
38+
{
39+
Document = new TextDocument(Text);
40+
InitializeComponent();
41+
}
42+
43+
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
44+
{
45+
base.OnPropertyChanged(change);
46+
47+
if (change.Property == TextProperty)
48+
{
49+
if (!_isDocumentTextChanging)
50+
Document.Text = Text;
51+
}
52+
}
53+
54+
private void OnTextEditorLayoutUpdated(object sender, EventArgs e)
55+
{
56+
var view = TextEditor.TextArea?.TextView;
57+
if (view is { VisualLinesValid: true })
58+
{
59+
if (_subjectEndLineNumber == 0)
60+
{
61+
SubjectGuideLine.Margin = new Thickness(1, view.DefaultLineHeight + 2, 1, 0);
62+
SubjectGuideLine.IsVisible = true;
63+
return;
64+
}
65+
66+
foreach (var line in view.VisualLines)
67+
{
68+
var lineNumber = line.FirstDocumentLine.LineNumber;
69+
if (lineNumber == _subjectEndLineNumber)
70+
{
71+
var y = line.GetTextLineVisualYPosition(line.TextLines[^1], VisualYPosition.TextBottom) - view.VerticalOffset + 2;
72+
SubjectGuideLine.Margin = new Thickness(1, y, 1, 0);
73+
SubjectGuideLine.IsVisible = true;
74+
return;
75+
}
76+
}
77+
}
78+
79+
SubjectGuideLine.IsVisible = false;
80+
}
81+
82+
private void OnTextEditorTextChanged(object sender, EventArgs e)
83+
{
84+
_isDocumentTextChanging = true;
85+
SetCurrentValue(TextProperty, Document.Text);
86+
_isDocumentTextChanging = false;
87+
88+
var setSubject = false;
89+
for (int i = 0; i < Document.LineCount; i++)
90+
{
91+
var line = Document.Lines[i];
92+
if (line.LineNumber > 1 && line.Length == 0)
93+
{
94+
var subject = Text.Substring(0, line.Offset).ReplaceLineEndings(" ").Trim();
95+
SetCurrentValue(SubjectLengthProperty, subject.Length);
96+
setSubject = true;
97+
break;
98+
}
99+
100+
_subjectEndLineNumber = line.LineNumber;
101+
}
102+
103+
if (setSubject)
104+
return;
105+
106+
SetCurrentValue(SubjectLengthProperty, Text.ReplaceLineEndings(" ").Trim().Length);
107+
}
108+
109+
private bool _isDocumentTextChanging = false;
110+
private int _subjectEndLineNumber = 0;
111+
}
112+
}

0 commit comments

Comments
 (0)