diff --git a/src/Commands/LFS.cs b/src/Commands/LFS.cs index a48fae55..068e8ac5 100644 --- a/src/Commands/LFS.cs +++ b/src/Commands/LFS.cs @@ -77,7 +77,7 @@ namespace SourceGit.Commands var rs = cmd.ReadToEnd(); if (rs.IsSuccess) { - var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + var lines = rs.StdOut.Split(new char[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { var match = REG_LOCK().Match(line); diff --git a/src/Converters/IntConverters.cs b/src/Converters/IntConverters.cs index 8235a3ef..6bfee48d 100644 --- a/src/Converters/IntConverters.cs +++ b/src/Converters/IntConverters.cs @@ -18,5 +18,8 @@ namespace SourceGit.Converters public static readonly FuncValueConverter IsNotOne = new FuncValueConverter(v => v != 1); + + public static readonly FuncValueConverter IsBadSubjectLength = + new FuncValueConverter(v => v > ViewModels.Preference.Instance.SubjectGuideLength); } } diff --git a/src/Models/InteractiveRebaseEditor.cs b/src/Models/InteractiveRebaseEditor.cs index 607fe37a..911258d4 100644 --- a/src/Models/InteractiveRebaseEditor.cs +++ b/src/Models/InteractiveRebaseEditor.cs @@ -79,7 +79,7 @@ namespace SourceGit.Models if (!File.Exists(doneFile)) return -1; - var done = File.ReadAllText(doneFile).Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries); + var done = File.ReadAllText(doneFile).Split(new char[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries); if (done.Length > jobs.Count) return -1; diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index d6b6f56b..abda0adc 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -105,6 +105,8 @@ PARENTS REFS SHA + Enter commit subject & message + Git uses an empty line to separate the subject and extra message body. Repository Configure Email Address Email address @@ -328,6 +330,7 @@ Language History Commits Restore windows + Subject Guide Length Use fixed tab width in titlebar GIT Fetch remotes automatically @@ -520,7 +523,6 @@ You can stage this file now. COMMIT COMMIT & PUSH - Enter commit message CTRL + Enter CONFLICTS DETECTED FILE CONFLICTS ARE RESOLVED diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 14af9f76..56f0edce 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -108,6 +108,8 @@ 父提交 相关引用 提交指纹 + 填写提交信息 + Git使用空白行来划分提交信息中的主题与内容 仓库配置 电子邮箱 邮箱地址 @@ -331,6 +333,7 @@ 显示语言 最大历史提交数 启动时恢复上次打开的仓库 + SUBJECT字数检测 使用固定宽度的标题栏标签 GIT配置 启用定时自动拉取远程更新 @@ -522,7 +525,6 @@ 现在您已可将其加入暂存区中 提交 提交并推送 - 填写提交信息 CTRL + Enter 检测到冲突 文件冲突已解决 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 613d40ce..80152a37 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -108,6 +108,8 @@ 父提交 相關引用 提交指紋 + 填寫提交資訊 + Git使用空白行來劃分提交資訊中的主題與內容 倉庫配置 電子郵箱 郵箱地址 @@ -331,6 +333,7 @@ 顯示語言 最大歷史提交數 啟動時恢復上次開啟的倉庫 + SUBJECT字數檢測 使用固定寬度的標題欄標籤 GIT配置 啟用定時自動拉取遠端更新 @@ -522,7 +525,6 @@ 現在您已可將其加入暫存區中 提交 提交併推送 - 填寫提交資訊 CTRL + Enter 檢測到衝突 檔案衝突已解決 diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml index 36be8895..a646cc46 100644 --- a/src/Resources/Styles.axaml +++ b/src/Resources/Styles.axaml @@ -1,7 +1,6 @@ diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index 0e8b2b37..5a152f2d 100644 --- a/src/ViewModels/Preference.cs +++ b/src/ViewModels/Preference.cs @@ -134,6 +134,12 @@ namespace SourceGit.ViewModels set => SetProperty(ref _maxHistoryCommits, value); } + public int SubjectGuideLength + { + get => _subjectGuideLength; + set => SetProperty(ref _subjectGuideLength, value); + } + public bool RestoreTabs { get => _restoreTabs; @@ -534,9 +540,11 @@ namespace SourceGit.ViewModels private LayoutInfo _layout = new LayoutInfo(); private int _maxHistoryCommits = 20000; + private int _subjectGuideLength = 50; private bool _restoreTabs = false; private bool _useFixedTabWidth = true; private bool _check4UpdatesOnStartup = true; + private bool _useTwoColumnsLayoutInHistories = false; private bool _useSideBySideDiff = false; private bool _useSyntaxHighlighting = false; diff --git a/src/Views/CommitMessageTextBox.axaml b/src/Views/CommitMessageTextBox.axaml new file mode 100644 index 00000000..d85a01e1 --- /dev/null +++ b/src/Views/CommitMessageTextBox.axaml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Views/CommitMessageTextBox.axaml.cs b/src/Views/CommitMessageTextBox.axaml.cs new file mode 100644 index 00000000..d7b2e8a6 --- /dev/null +++ b/src/Views/CommitMessageTextBox.axaml.cs @@ -0,0 +1,112 @@ +using System; + +using Avalonia; +using Avalonia.Controls; + +using AvaloniaEdit.Document; +using AvaloniaEdit.Rendering; + +namespace SourceGit.Views +{ + public partial class CommitMessageTextBox : UserControl + { + public static readonly StyledProperty TextProperty = + AvaloniaProperty.Register(nameof(Text), string.Empty); + + public static readonly StyledProperty SubjectLengthProperty = + AvaloniaProperty.Register(nameof(SubjectLength)); + + public string Text + { + get => GetValue(TextProperty); + set => SetValue(TextProperty, value); + } + + public int SubjectLength + { + get => GetValue(SubjectLengthProperty); + set => SetValue(SubjectLengthProperty, value); + } + + public TextDocument Document + { + get; + private set; + } + + public CommitMessageTextBox() + { + Document = new TextDocument(Text); + InitializeComponent(); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == TextProperty) + { + if (!_isDocumentTextChanging) + Document.Text = Text; + } + } + + private void OnTextEditorLayoutUpdated(object sender, EventArgs e) + { + var view = TextEditor.TextArea?.TextView; + if (view is { VisualLinesValid: true }) + { + if (_subjectEndLineNumber == 0) + { + SubjectGuideLine.Margin = new Thickness(1, view.DefaultLineHeight + 2, 1, 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.TextBottom) - view.VerticalOffset + 2; + SubjectGuideLine.Margin = new Thickness(1, y, 1, 0); + SubjectGuideLine.IsVisible = true; + return; + } + } + } + + SubjectGuideLine.IsVisible = false; + } + + private void OnTextEditorTextChanged(object sender, EventArgs e) + { + _isDocumentTextChanging = true; + SetCurrentValue(TextProperty, Document.Text); + _isDocumentTextChanging = false; + + var setSubject = false; + for (int i = 0; i < Document.LineCount; i++) + { + var line = Document.Lines[i]; + if (line.LineNumber > 1 && line.Length == 0) + { + var subject = Text.Substring(0, line.Offset).ReplaceLineEndings(" ").Trim(); + SetCurrentValue(SubjectLengthProperty, subject.Length); + setSubject = true; + break; + } + + _subjectEndLineNumber = line.LineNumber; + } + + if (setSubject) + return; + + SetCurrentValue(SubjectLengthProperty, Text.ReplaceLineEndings(" ").Trim().Length); + } + + private bool _isDocumentTextChanging = false; + private int _subjectEndLineNumber = 0; + } +} diff --git a/src/Views/CreateTag.axaml b/src/Views/CreateTag.axaml index 637e8702..f3de6717 100644 --- a/src/Views/CreateTag.axaml +++ b/src/Views/CreateTag.axaml @@ -14,11 +14,11 @@ Classes="bold" Text="{DynamicResource Text.CreateTag.Title}"/> - - + diff --git a/src/Views/InteractiveRebase.axaml b/src/Views/InteractiveRebase.axaml index 64e66bd5..8e966509 100644 --- a/src/Views/InteractiveRebase.axaml +++ b/src/Views/InteractiveRebase.axaml @@ -163,8 +163,8 @@ - - + + @@ -179,12 +179,7 @@ - + diff --git a/src/Views/Preference.axaml b/src/Views/Preference.axaml index b84354aa..8151add5 100644 --- a/src/Views/Preference.axaml +++ b/src/Views/Preference.axaml @@ -58,7 +58,7 @@ - + + + + + + + 0,0,0,4 + 0 + 0 + 8 + 16 + 16 + + - + + + - - diff --git a/src/Views/RevisionFiles.axaml b/src/Views/RevisionFiles.axaml index 2d08e7d5..82a06b9f 100644 --- a/src/Views/RevisionFiles.axaml +++ b/src/Views/RevisionFiles.axaml @@ -2,11 +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:m="using:SourceGit.Models" xmlns:vm="using:SourceGit.ViewModels" xmlns:v="using:SourceGit.Views" - xmlns:c="using:SourceGit.Converters" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="SourceGit.Views.RevisionFiles" x:DataType="vm:CommitDetail"> diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index ce177d5c..22ee8123 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -105,19 +105,12 @@ namespace SourceGit.Views set => SetValue(UseSyntaxHighlightingProperty, value); } - /// - /// ShowHiddenSymbols StyledProperty definition - /// public static readonly StyledProperty ShowHiddenSymbolsProperty = AvaloniaProperty.Register(nameof(ShowHiddenSymbols), false); - /// - /// Gets or sets the ShowHiddenSymbols property. This StyledProperty - /// indicates that show hidden symbol like space and tab - /// public bool ShowHiddenSymbols { - get => this.GetValue(ShowHiddenSymbolsProperty); + get => GetValue(ShowHiddenSymbolsProperty); set => SetValue(ShowHiddenSymbolsProperty, value); } diff --git a/src/Views/WorkingCopy.axaml b/src/Views/WorkingCopy.axaml index d05236d5..b6700940 100644 --- a/src/Views/WorkingCopy.axaml +++ b/src/Views/WorkingCopy.axaml @@ -159,19 +159,10 @@ - +