diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index cc5c56c5..165afaa4 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -105,8 +105,8 @@
PARENTS
REFS
SHA
- Enter commit subject & message
- Git uses an empty line to separate the subject and extra message body.
+ Enter commit subject
+ Description
Repository Configure
Email Address
Email address
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index 543eb8ea..59a1f3ba 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -108,8 +108,8 @@
父提交
相关引用
提交指纹
- 填写提交信息
- Git使用空白行来划分提交信息中的主题与内容
+ 填写提交信息主题
+ 详细描述
仓库配置
电子邮箱
邮箱地址
diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml
index c97d994d..90476146 100644
--- a/src/Resources/Locales/zh_TW.axaml
+++ b/src/Resources/Locales/zh_TW.axaml
@@ -108,8 +108,8 @@
父提交
相關引用
提交指紋
- 填寫提交資訊
- Git使用空白行來劃分提交資訊中的主題與內容
+ 填寫提交信息主題
+ 詳細描述
倉庫配置
電子郵箱
郵箱地址
diff --git a/src/Views/CommitMessageTextBox.axaml b/src/Views/CommitMessageTextBox.axaml
index 779d9c7b..96d902b7 100644
--- a/src/Views/CommitMessageTextBox.axaml
+++ b/src/Views/CommitMessageTextBox.axaml
@@ -2,9 +2,9 @@
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:ae="using:AvaloniaEdit"
xmlns:c="using:SourceGit.Converters"
xmlns:vm="using:SourceGit.ViewModels"
+ xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.CommitMessageTextBox"
x:Name="ThisControl">
@@ -12,52 +12,67 @@
BorderThickness="1"
BorderBrush="{DynamicResource Brush.Border2}"
CornerRadius="4">
-
-
-
+
+
+
+
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/src/Views/CommitMessageTextBox.axaml.cs b/src/Views/CommitMessageTextBox.axaml.cs
index afefacb2..f87275ee 100644
--- a/src/Views/CommitMessageTextBox.axaml.cs
+++ b/src/Views/CommitMessageTextBox.axaml.cs
@@ -2,122 +2,137 @@ using System;
using Avalonia;
using Avalonia.Controls;
-
-using AvaloniaEdit.Document;
-using AvaloniaEdit.Rendering;
+using Avalonia.Input;
+using Avalonia.Interactivity;
namespace SourceGit.Views
{
+ public class EnhancedTextBox : TextBox
+ {
+ public static readonly RoutedEvent PreviewKeyDownEvent =
+ RoutedEvent.Register(nameof(KeyEventArgs), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
+
+ public event EventHandler PreviewKeyDown
+ {
+ add { AddHandler(PreviewKeyDownEvent, value); }
+ remove { RemoveHandler(PreviewKeyDownEvent, value); }
+ }
+
+ protected override Type StyleKeyOverride => typeof(TextBox);
+
+ protected override void OnKeyDown(KeyEventArgs e)
+ {
+ var dump = new KeyEventArgs()
+ {
+ RoutedEvent = PreviewKeyDownEvent,
+ Route = RoutingStrategies.Direct,
+ Source = e.Source,
+ Key = e.Key,
+ KeyModifiers = e.KeyModifiers,
+ PhysicalKey = e.PhysicalKey,
+ KeySymbol = e.KeySymbol,
+ };
+
+ RaiseEvent(dump);
+
+ if (dump.Handled)
+ e.Handled = true;
+ else
+ base.OnKeyDown(e);
+ }
+ }
+
public partial class CommitMessageTextBox : UserControl
{
+ public enum TextChangeWay
+ {
+ None,
+ FromSource,
+ FromEditor,
+ }
+
public static readonly StyledProperty TextProperty =
AvaloniaProperty.Register(nameof(Text), string.Empty);
- public static readonly DirectProperty SubjectLengthProperty =
- AvaloniaProperty.RegisterDirect(nameof(SubjectLength), o => o.SubjectLength);
+ public static readonly StyledProperty SubjectProperty =
+ AvaloniaProperty.Register(nameof(Subject), string.Empty);
+
+ public static readonly StyledProperty DescriptionProperty =
+ AvaloniaProperty.Register(nameof(Description), string.Empty);
- public static readonly DirectProperty TotalLengthProperty =
- AvaloniaProperty.RegisterDirect(nameof(TotalLength), o => o.TotalLength);
-
public string Text
{
get => GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
- public int SubjectLength
+ public string Subject
{
- get => _subjectLength;
- private set => SetAndRaise(SubjectLengthProperty, ref _subjectLength, value);
+ get => GetValue(SubjectProperty);
+ set => SetValue(SubjectProperty, value);
}
- public int TotalLength
+ public string Description
{
- get => _totalLength;
- private set => SetAndRaise(TotalLengthProperty, ref _totalLength, value);
+ get => GetValue(DescriptionProperty);
+ set => SetValue(DescriptionProperty, value);
}
- public TextDocument Document
- {
- get;
- }
-
public CommitMessageTextBox()
{
- Document = new TextDocument(Text);
InitializeComponent();
}
-
+
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
- if (change.Property == TextProperty && !_isDocumentTextChanging)
- Document.Text = Text;
- }
-
- private void OnTextEditorLayoutUpdated(object sender, EventArgs e)
- {
- var view = TextEditor.TextArea?.TextView;
- if (view is { VisualLinesValid: true })
+ if (change.Property == TextProperty && _changingWay == TextChangeWay.None)
{
- if (_subjectEndLineNumber == 0)
+ _changingWay = TextChangeWay.FromSource;
+ var normalized = Text.ReplaceLineEndings("\n").Trim();
+ var subjectEnd = normalized.IndexOf("\n\n", StringComparison.Ordinal);
+ if (subjectEnd == -1)
{
- SubjectGuideLine.Margin = new Thickness(0, view.DefaultLineHeight + 3, 0, 0);
- SubjectGuideLine.IsVisible = true;
- return;
- }
-
- foreach (var line in view.VisualLines)
- {
- var lineNumber = line.FirstDocumentLine.LineNumber;
- if (lineNumber == _subjectEndLineNumber)
- {
- var y = line.GetTextLineVisualYPosition(line.TextLines[^1], VisualYPosition.LineBottom) - view.VerticalOffset + 3;
- SubjectGuideLine.Margin = new Thickness(0, y, 0, 0);
- SubjectGuideLine.IsVisible = true;
- return;
- }
- }
- }
-
- SubjectGuideLine.IsVisible = false;
- }
-
- private void OnTextEditorTextChanged(object sender, EventArgs e)
- {
- var text = Document.Text;
- _isDocumentTextChanging = true;
- SetCurrentValue(TextProperty, text);
- TotalLength = text.Trim().Length;
- _isDocumentTextChanging = false;
-
- var foundData = false;
- for (var i = 0; i < Document.LineCount; i++)
- {
- var line = Document.Lines[i];
- if (line.Length == 0)
- {
- if (foundData)
- {
- SubjectLength = text[..line.Offset].ReplaceLineEndings(" ").Trim().Length;
- return;
- }
+ SetCurrentValue(SubjectProperty, normalized.ReplaceLineEndings(" "));
+ SetCurrentValue(DescriptionProperty, string.Empty);
}
else
{
- foundData = true;
+ SetCurrentValue(SubjectProperty, normalized.Substring(0, subjectEnd).ReplaceLineEndings(" "));
+ SetCurrentValue(DescriptionProperty, normalized.Substring(subjectEnd + 2));
}
-
- _subjectEndLineNumber = line.LineNumber;
+ _changingWay = TextChangeWay.None;
+ }
+ else if ((change.Property == SubjectProperty || change.Property == DescriptionProperty) && _changingWay == TextChangeWay.None)
+ {
+ _changingWay = TextChangeWay.FromEditor;
+ SetCurrentValue(TextProperty, $"{Subject}\n\n{Description}");
+ _changingWay = TextChangeWay.None;
}
-
- SubjectLength = text.ReplaceLineEndings(" ").Trim().Length;
}
- private bool _isDocumentTextChanging = false;
- private int _subjectEndLineNumber = 0;
- private int _totalLength = 0;
- private int _subjectLength = 0;
+ private void OnSubjectTextBoxPreviewKeyDown(object sender, KeyEventArgs e)
+ {
+ if ((e.Key == Key.Enter && e.KeyModifiers == KeyModifiers.None)
+ || (e.Key == Key.Right && SubjectEditor.CaretIndex == Subject.Length))
+ {
+ DescriptionEditor.Focus();
+ DescriptionEditor.CaretIndex = 0;
+ e.Handled = true;
+ }
+ }
+
+ private void OnDescriptionTextBoxPreviewKeyDown(object sender, KeyEventArgs e)
+ {
+ if ((e.Key == Key.Back || e.Key == Key.Left) && DescriptionEditor.CaretIndex == 0)
+ {
+ SubjectEditor.Focus();
+ SubjectEditor.CaretIndex = Subject.Length;
+ e.Handled = true;
+ }
+ }
+
+ private TextChangeWay _changingWay = TextChangeWay.None;
}
}