diff --git a/TRANSLATION.md b/TRANSLATION.md index 21706eb2..facab0ab 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -6,7 +6,7 @@ This document shows the translation status of each locale file in the repository ### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen) -### ![de__DE](https://img.shields.io/badge/de__DE-95.19%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-95.07%25-yellow)
Missing keys in de_DE.axaml @@ -37,6 +37,7 @@ This document shows the translation status of each locale file in the repository - Text.Preferences.Appearance.EditorTabWidth - Text.Preferences.General.ShowTagsInGraph - Text.Preferences.Git.IgnoreCRAtEOLInDiff +- Text.Repository.Search.ByContent - Text.Repository.ViewLogs - Text.StashCM.SaveAsPatch - Text.ViewLogs @@ -53,7 +54,7 @@ This document shows the translation status of each locale file in the repository ### ![es__ES](https://img.shields.io/badge/es__ES-%E2%88%9A-brightgreen) -### ![fr__FR](https://img.shields.io/badge/fr__FR-96.49%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-96.37%25-yellow)
Missing keys in fr_FR.axaml @@ -75,6 +76,7 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.StageAllThenCommit - Text.ConfirmEmptyCommit.WithLocalChanges - Text.Preferences.Git.IgnoreCRAtEOLInDiff +- Text.Repository.Search.ByContent - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear @@ -88,7 +90,7 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-96.23%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-96.11%25-yellow)
Missing keys in it_IT.axaml @@ -112,6 +114,7 @@ This document shows the translation status of each locale file in the repository - Text.CopyFullPath - Text.Preferences.General.ShowTagsInGraph - Text.Preferences.Git.IgnoreCRAtEOLInDiff +- Text.Repository.Search.ByContent - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear @@ -125,7 +128,7 @@ This document shows the translation status of each locale file in the repository
-### ![ja__JP](https://img.shields.io/badge/ja__JP-96.23%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-96.11%25-yellow)
Missing keys in ja_JP.axaml @@ -148,6 +151,7 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.WithLocalChanges - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.FilterCommits +- Text.Repository.Search.ByContent - Text.Repository.Tags.OrderByNameDes - Text.Repository.ViewLogs - Text.ViewLogs @@ -162,7 +166,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-87.79%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-87.68%25-yellow)
Missing keys in pt_BR.axaml @@ -235,6 +239,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.HistoriesOrder - Text.Repository.Notifications.Clear - Text.Repository.OnlyHighlightCurrentBranchInHistories +- Text.Repository.Search.ByContent - Text.Repository.Skip - Text.Repository.Tags.OrderByCreatorDate - Text.Repository.Tags.OrderByNameAsc @@ -266,7 +271,7 @@ This document shows the translation status of each locale file in the repository ### ![ru__RU](https://img.shields.io/badge/ru__RU-%E2%88%9A-brightgreen) -### ![ta__IN](https://img.shields.io/badge/ta__IN-96.49%25-yellow) +### ![ta__IN](https://img.shields.io/badge/ta__IN-96.37%25-yellow)
Missing keys in ta_IN.axaml @@ -288,6 +293,7 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.StageAllThenCommit - Text.ConfirmEmptyCommit.WithLocalChanges - Text.Preferences.Git.IgnoreCRAtEOLInDiff +- Text.Repository.Search.ByContent - Text.Repository.ViewLogs - Text.UpdateSubmodules.Target - Text.ViewLogs @@ -301,7 +307,7 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-97.66%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-97.54%25-yellow)
Missing keys in uk_UA.axaml @@ -319,6 +325,7 @@ This document shows the translation status of each locale file in the repository - Text.CommitMessageTextBox.SubjectCount - Text.ConfigureWorkspace.Name - Text.Preferences.Git.IgnoreCRAtEOLInDiff +- Text.Repository.Search.ByContent - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear diff --git a/VERSION b/VERSION index 70f2a59f..fe39b2a2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2025.15 \ No newline at end of file +2025.16 \ No newline at end of file diff --git a/src/App.axaml.cs b/src/App.axaml.cs index 822084dc..c54b616d 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -552,6 +552,7 @@ namespace SourceGit _launcher = new ViewModels.Launcher(startupRepo); desktop.MainWindow = new Views.Launcher() { DataContext = _launcher }; + desktop.ShutdownMode = ShutdownMode.OnMainWindowClose; #if !DISABLE_UPDATE_DETECTION if (pref.ShouldCheck4UpdateOnStartup()) diff --git a/src/Commands/CountLocalChangesWithoutUntracked.cs b/src/Commands/CountLocalChangesWithoutUntracked.cs index 0ba508f8..a704f313 100644 --- a/src/Commands/CountLocalChangesWithoutUntracked.cs +++ b/src/Commands/CountLocalChangesWithoutUntracked.cs @@ -8,7 +8,7 @@ namespace SourceGit.Commands { WorkingDirectory = repo; Context = repo; - Args = "--no-optional-locks status -uno --ignore-submodules=dirty --porcelain"; + Args = "--no-optional-locks status -uno --ignore-submodules=all --porcelain"; } public int Result() diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs index a60f4cc5..a354b816 100644 --- a/src/Commands/Diff.cs +++ b/src/Commands/Diff.cs @@ -105,7 +105,7 @@ namespace SourceGit.Commands } else if (line.StartsWith("-size ", StringComparison.Ordinal)) { - _result.LFSDiff.Old.Size = long.Parse(line.AsSpan().Slice(6)); + _result.LFSDiff.Old.Size = long.Parse(line.AsSpan(6)); } } else if (ch == '+') @@ -116,12 +116,12 @@ namespace SourceGit.Commands } else if (line.StartsWith("+size ", StringComparison.Ordinal)) { - _result.LFSDiff.New.Size = long.Parse(line.AsSpan().Slice(6)); + _result.LFSDiff.New.Size = long.Parse(line.AsSpan(6)); } } else if (line.StartsWith(" size ", StringComparison.Ordinal)) { - _result.LFSDiff.New.Size = _result.LFSDiff.Old.Size = long.Parse(line.AsSpan().Slice(6)); + _result.LFSDiff.New.Size = _result.LFSDiff.Old.Size = long.Parse(line.AsSpan(6)); } return; } diff --git a/src/Commands/GitIgnore.cs b/src/Commands/GitIgnore.cs index e666eba6..8b351f5e 100644 --- a/src/Commands/GitIgnore.cs +++ b/src/Commands/GitIgnore.cs @@ -8,7 +8,14 @@ namespace SourceGit.Commands { var file = Path.Combine(repo, ".gitignore"); if (!File.Exists(file)) + { File.WriteAllLines(file, [pattern]); + return; + } + + var org = File.ReadAllText(file); + if (!org.EndsWith('\n')) + File.AppendAllLines(file, ["", pattern]); else File.AppendAllLines(file, [pattern]); } diff --git a/src/Commands/QueryCommits.cs b/src/Commands/QueryCommits.cs index dd3c39b4..9e1d9918 100644 --- a/src/Commands/QueryCommits.cs +++ b/src/Commands/QueryCommits.cs @@ -26,11 +26,7 @@ namespace SourceGit.Commands { search += $"-i --committer=\"{filter}\""; } - else if (method == Models.CommitSearchMethod.ByFile) - { - search += $"-- \"{filter}\""; - } - else + else if (method == Models.CommitSearchMethod.ByMessage) { var argsBuilder = new StringBuilder(); argsBuilder.Append(search); @@ -45,10 +41,18 @@ namespace SourceGit.Commands search = argsBuilder.ToString(); } + else if (method == Models.CommitSearchMethod.ByFile) + { + search += $"-- \"{filter}\""; + } + else + { + search = $"-G\"{filter}\""; + } WorkingDirectory = repo; Context = repo; - Args = $"log -1000 --date-order --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s " + search; + Args = $"log -1000 --date-order --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s {search}"; _findFirstMerged = false; } diff --git a/src/Commands/Statistics.cs b/src/Commands/Statistics.cs index ea0b86de..e11c1740 100644 --- a/src/Commands/Statistics.cs +++ b/src/Commands/Statistics.cs @@ -40,7 +40,7 @@ namespace SourceGit.Commands if (dateEndIdx == -1) return; - var dateStr = line.AsSpan().Slice(0, dateEndIdx); + var dateStr = line.AsSpan(0, dateEndIdx); if (double.TryParse(dateStr, out var date)) statistics.AddCommit(line.Substring(dateEndIdx + 1), date); } diff --git a/src/Converters/PathConverters.cs b/src/Converters/PathConverters.cs index dd7cfa49..ac1e61e5 100644 --- a/src/Converters/PathConverters.cs +++ b/src/Converters/PathConverters.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using Avalonia.Data.Converters; @@ -22,7 +22,7 @@ namespace SourceGit.Converters var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length; if (v.StartsWith(home, StringComparison.Ordinal)) - return "~" + v.Substring(prefixLen); + return $"~{v.AsSpan(prefixLen)}"; return v; }); diff --git a/src/Models/AvatarManager.cs b/src/Models/AvatarManager.cs index a506d886..a9ef3eb4 100644 --- a/src/Models/AvatarManager.cs +++ b/src/Models/AvatarManager.cs @@ -196,7 +196,7 @@ namespace SourceGit.Models private string GetEmailHash(string email) { var lowered = email.ToLower(CultureInfo.CurrentCulture).Trim(); - var hash = MD5.HashData(Encoding.Default.GetBytes(lowered).AsSpan()); + var hash = MD5.HashData(Encoding.Default.GetBytes(lowered)); var builder = new StringBuilder(hash.Length * 2); foreach (var c in hash) builder.Append(c.ToString("x2")); diff --git a/src/Models/Bisect.cs b/src/Models/Bisect.cs index d1021113..2ed8beb2 100644 --- a/src/Models/Bisect.cs +++ b/src/Models/Bisect.cs @@ -14,8 +14,8 @@ namespace SourceGit.Models public enum BisectCommitFlag { None = 0, - Good = 1, - Bad = 2, + Good = 1 << 0, + Bad = 1 << 1, } public class Bisect diff --git a/src/Models/Commit.cs b/src/Models/Commit.cs index 1980e622..ef5a34bc 100644 --- a/src/Models/Commit.cs +++ b/src/Models/Commit.cs @@ -13,6 +13,7 @@ namespace SourceGit.Models ByCommitter, ByMessage, ByFile, + ByContent, } public class Commit diff --git a/src/Models/DiffOption.cs b/src/Models/DiffOption.cs index 5f491d58..5e2aec8d 100644 --- a/src/Models/DiffOption.cs +++ b/src/Models/DiffOption.cs @@ -12,7 +12,7 @@ namespace SourceGit.Models { get; set; - } = false; + } = true; public Change WorkingCopyChange => _workingCopyChange; public bool IsUnstaged => _isUnstaged; diff --git a/src/Models/DiffResult.cs b/src/Models/DiffResult.cs index e7d17994..b2d91310 100644 --- a/src/Models/DiffResult.cs +++ b/src/Models/DiffResult.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; @@ -147,7 +147,7 @@ namespace SourceGit.Models public void GenerateNewPatchFromSelection(Change change, string fileBlobGuid, TextDiffSelection selection, bool revert, string output) { var isTracked = !string.IsNullOrEmpty(fileBlobGuid); - var fileGuid = isTracked ? fileBlobGuid.Substring(0, 8) : "00000000"; + var fileGuid = isTracked ? fileBlobGuid : "00000000"; var builder = new StringBuilder(); builder.Append("diff --git a/").Append(change.Path).Append(" b/").Append(change.Path).Append('\n'); diff --git a/src/Models/DirtyState.cs b/src/Models/DirtyState.cs new file mode 100644 index 00000000..2b9d898d --- /dev/null +++ b/src/Models/DirtyState.cs @@ -0,0 +1,12 @@ +using System; + +namespace SourceGit.Models +{ + [Flags] + public enum DirtyState + { + None = 0, + HasLocalChanges = 1 << 0, + HasPendingPullOrPush = 1 << 1, + } +} diff --git a/src/Models/ExternalMerger.cs b/src/Models/ExternalMerger.cs index d97d3933..fe67ad6a 100644 --- a/src/Models/ExternalMerger.cs +++ b/src/Models/ExternalMerger.cs @@ -43,6 +43,7 @@ namespace SourceGit.Models new ExternalMerger(8, "codium", "VSCodium", "VSCodium.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""), new ExternalMerger(9, "p4merge", "P4Merge", "p4merge.exe", "-tw 4 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", "-tw 4 \"$LOCAL\" \"$REMOTE\""), new ExternalMerger(10, "plastic_merge", "Plastic SCM", "mergetool.exe", "-s=\"$REMOTE\" -b=\"$BASE\" -d=\"$LOCAL\" -r=\"$MERGED\" --automatic", "-s=\"$LOCAL\" -d=\"$REMOTE\""), + new ExternalMerger(11, "meld", "Meld", "Meld.exe", "\"$LOCAL\" \"$BASE\" \"$REMOTE\" --output \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), }; } else if (OperatingSystem.IsMacOS()) diff --git a/src/Models/Worktree.cs b/src/Models/Worktree.cs index bc40e320..3f954650 100644 --- a/src/Models/Worktree.cs +++ b/src/Models/Worktree.cs @@ -1,4 +1,5 @@ -using CommunityToolkit.Mvvm.ComponentModel; +using System; +using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.Models { @@ -22,12 +23,12 @@ namespace SourceGit.Models get { if (IsDetached) - return $"deteched HEAD at {Head.Substring(10)}"; + return $"deteched HEAD at {Head.AsSpan(10)}"; - if (Branch.StartsWith("refs/heads/", System.StringComparison.Ordinal)) + if (Branch.StartsWith("refs/heads/", StringComparison.Ordinal)) return Branch.Substring(11); - if (Branch.StartsWith("refs/remotes/", System.StringComparison.Ordinal)) + if (Branch.StartsWith("refs/remotes/", StringComparison.Ordinal)) return Branch.Substring(13); return Branch; diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index 7a3da294..8eb49a3e 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -236,7 +236,7 @@ ALT Kopieren Dateimodus geändert - Ignoriere Leerzeichenänderungen und EOL + Ignoriere Leerzeichenänderungen LFS OBJEKT ÄNDERUNG Nächste Änderung KEINE ÄNDERUNG ODER NUR ZEILEN-ENDE ÄNDERUNGEN diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 538ac1f1..f4c62a90 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -253,7 +253,7 @@ Copy File Mode Changed First Difference - Ignore Whitespace Change and EOL + Ignore All Whitespace Changes Last Difference LFS OBJECT CHANGE Next Difference @@ -605,6 +605,7 @@ Search Commit Author Committer + Content File Message SHA diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index 82913d24..c9978b2a 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -257,7 +257,7 @@ Copiar Modo de Archivo Cambiado Primera Diferencia - Ignorar Cambio de Espacios en Blanco y EOL + Ignorar Cambio de Espacios en Blanco Última Diferencia CAMBIO DE OBJETO LFS Siguiente Diferencia @@ -609,6 +609,7 @@ Buscar Commit Autor Committer + Contenido Archivo Mensaje SHA diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index f45a83d9..0529702d 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -241,7 +241,7 @@ Copier Mode de fichier changé Première différence - Ignorer les changements d'espaces et EOL + Ignorer les changements d'espaces Dernière différence CHANGEMENT D'OBJET LFS Différence suivante diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index b7d2568a..545261e9 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -240,7 +240,7 @@ Copia Modalità File Modificata Prima differenza - Ignora Modifiche agli Spazi e EOL + Ignora Modifiche agli Spazi Ultima differenza MODIFICA OGGETTO LFS Differenza Successiva diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml index c50504e1..48d55500 100644 --- a/src/Resources/Locales/ja_JP.axaml +++ b/src/Resources/Locales/ja_JP.axaml @@ -241,7 +241,7 @@ コピー ファイルモードが変更されました 先頭の差分 - 空白の変更とEOLを無視 + 空白の変更を無視 最後の差分 LFSオブジェクトの変更 次の差分 diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index a4e9d883..2a693151 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -217,7 +217,7 @@ ANTIGO Copiar Modo de Arquivo Alterado - Ignorar mudanças de espaço em branco e EOL + Ignorar mudanças de espaço em branco MUDANÇA DE OBJETO LFS Próxima Diferença SEM MUDANÇAS OU APENAS MUDANÇAS DE EOL diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index a3fe2b3a..4c8ea4bf 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -59,7 +59,7 @@ Отклонить все изменения. Перемотать вперёд к ${0}$ Извлечь ${0}$ в ${1}$... - Поток Git - Завершение ${0}$ + Git-процесс - Завершение ${0}$ Влить ${0}$ в ${1}$... Влить {0} выделенных веток в текущую Загрузить ${0}$ @@ -195,8 +195,8 @@ Восстанавливать вкладки при запуске ПРОДОЛЖИТЬ Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty)? - Подготовить все и зафиксировать ревизию - Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty) или отложить все, затем зафиксировать ревизию? + Сформировать всё и зафиксировать ревизию + Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty) или отложить всё, затем зафиксировать ревизию? Общепринятый помощник по ревизии Кардинальные изменения: Закрытая тема: @@ -251,21 +251,21 @@ Удалить метку Метка: Удалить из внешнего репозитория - РАЗНИЦА БИНАРНИКОВ + СРАВНЕНИЕ БИНАРНИКОВ НОВЫЙ СТАРЫЙ Копировать Режим файла изменён - Первое различие - Игнорировать изменение пробелов и EOL - Последнее различие + Первое сравнение + Игнорировать изменения пробелов + Последнее сравнение ИЗМЕНЕНИЕ ОБЪЕКТА LFS - Следующее различие + Следующее сравнение НИКАКИХ ИЗМЕНЕНИЙ ИЛИ МЕНЯЕТСЯ ТОЛЬКО EOL - Предыдущее различие + Предыдущее сравнение Сохранить как заплатку Показывать скрытые символы - Различие рядом + Сравнение рядом ПОДМОДУЛЬ НОВЫЙ Обмен @@ -305,41 +305,41 @@ Открыть расширенный инструмент слияния Взять версию ${0}$ Сохранить как файл заплатки... - Подготовить - Подготовленные {0} файлы - Подготовленные изменения в выбранной(ых) строке(ах) + Сформировать + Сформированные {0} файлы + Сформированные изменения в выбранной(ых) строке(ах) Отложить... Отложить {0} файлов... - Снять подготовленный - Неподготовленные {0} файлы - Неподготовленные изменения в выбранной(ых) строке(ах) + Расформировать + Несформированные {0} файлы + Несформированные изменения в выбранной(ых) строке(ах) Использовать мой (checkout --ours) Использовать их (checkout --theirs) История файлов ИЗМЕНИТЬ СОДЕРЖИМОЕ - Git-поток + Git-процесс Ветка разработчика: Свойство: Свойство префикса: - ПОТОК - Свойства завершения - ПОТОК - Закончить исправление - ПОТОК - Завершить выпуск + ПРОЦЕСС - Свойства завершения + ПРОЦЕСС - Закончить исправление + ПРОЦЕСС - Завершить выпуск Цель: Исправление: Префикс исправлений: - Создать Git-поток + Создать Git-процесс Держать ветку Производственная ветка: Выпуск: Префикс выпуска: Свойство запуска... - ПОТОК - Свойство запуска + ПРОЦЕСС - Свойство запуска Запуск исправлений... - ПОТОК - Запуск исправлений + ПРОЦЕСС - Запуск исправлений Ввести имя Запуск выпуска... - ПОТОК - Запуск выпуска + ПРОЦЕСС - Запуск выпуска Префикс метки версии: Git LFS (хранилище больших файлов) Добавить шаблон отслеживания... @@ -388,9 +388,9 @@ Создать новую вкладку Открыть диалоговое окно настроек РЕПОЗИТОРИЙ - Зафиксировать подготовленные изменения - Зафиксировать и выложить подготовленные изменения - Подготовить все изменения и зафиксировать + Зафиксировать сформированные изменения + Зафиксировать и выложить сформированные изменения + Сформировать все изменения и зафиксировать Создать новую ветку на основе выбранной ветки Отклонить выбранные изменения Извлечение, запускается сразу @@ -399,7 +399,7 @@ Загрузить, запускается сразу Выложить, запускается сразу Принудительно перезагрузить репозиторий - Подготовленные/Неподготовленные выбранные изменения + Сформированные/Несформированные выбранные изменения Переключить на «Изменения» Переключить на «Истории» Переключить на «Отложенные» @@ -409,8 +409,8 @@ Найти предыдущее совпадение Открыть панель поиска Отклонить - Подготовить - Снять из подготовленных + Сформировать + Расформировать Создать репозиторий Путь: Выполняется частичный перенос ревизий (cherry-pick). @@ -463,9 +463,9 @@ Вчера Параметры ОТКРЫТЬ ИИ - Запрос на анализ различий + Запрос на анализ сравнения Ключ API - Произвести запрос на тему + Создать запрос на тему Модель Имя: Сервер @@ -482,9 +482,9 @@ Переопределение темы Использовать фиксированную ширину табуляции в строке заголовка. Использовать системное окно - ИНСТРУМЕНТ РАЗЛИЧИЙ/СЛИЯНИЯ + ИНСТРУМЕНТ СРАВНЕНИЙ/СЛИЯНИЯ Путь установки - Введите путь для инструмента различия/слияния + Введите путь для инструмента сравнения/слияния Инструмент ОСНОВНЫЕ Проверить обновления при старте @@ -501,7 +501,7 @@ Электроная почта пользователя Общая электроная почта пользователя git Разрешить (--prune) при скачивании - Разрешить (--ignore-cr-at-eol) в различии + Разрешить (--ignore-cr-at-eol) в сравнении Для работы программы требуется версия Git (>= 2.23.0) Путь установки Разрешить верификацию HTTP SSL @@ -609,6 +609,7 @@ Поиск ревизии Автор Ревизор + Содержимое Файл Сообщение SHA @@ -673,8 +674,8 @@ Хранить отложенные файлы Сообщение: Имя тайника (необязательно) - Только подготовленные изменения - Подготовленные так и неподготовленные изменения выбранных файлов будут сохранены!!! + Только сформированные изменения + Сформированные так и несформированные изменения выбранных файлов будут сохранены!!! Отложить локальные изменения Принять Отбросить @@ -739,14 +740,14 @@ Игнорировать файлы в том же каталоге Игнорировать только эти файлы Изменить - Теперь вы можете подготовить этот файл. + Теперь вы можете сформировать этот файл. ЗАФИКСИРОВАТЬ ЗАФИКСИРОВАТЬ и ОТПРАВИТЬ Шаблон/Истории Запустить событие щелчка Зафиксировать (Редактировать) - Подготовить все изменения и зафиксировать - Вы подготовили {0} файл(ов), но отображается только {1} файл(ов) ({2} файл(ов) отфильтровано). Вы хотите продолжить? + Сформировать все изменения и зафиксировать + Вы сформировали {0} файл(ов), но отображается только {1} файл(ов) ({2} файл(ов) отфильтровано). Вы хотите продолжить? ОБНАРУЖЕНЫ КОНФЛИКТЫ ОТКРЫТЬ ВНЕШНИЙ ИНСТРУМЕНТ СЛИЯНИЯ ОТКРЫТЬ ВСЕ КОНФЛИКТЫ ВО ВНЕШНЕМ ИНСТРУМЕНТЕ СЛИЯНИЯ @@ -758,12 +759,12 @@ НЕТ ШАБЛОНОВ РЕВИЗИИ Щёлкните правой кнопкой мыши выбранный файл(ы) и разрешите конфликты. Завершение работы - ПОДГОТОВЛЕННЫЕ - СНЯТЬ ПОДГОТОВЛЕННЫЙ - СНЯТЬ ВСЕ ПОДГОТОВЛЕННЫЕ - НЕПОДГОТОВЛЕННЫЕ - ПОДГОТОВИТЬ - ВСЕ ПОДГОТОВИТЬ + СФОРМИРОВАННЫЕ + РАСФОРМИРОВАТЬ + РАСФОРМИРОВАТЬ ВСЁ + НЕСФОРМИРОВАННЫЕ + СФОРМИРОВАТЬ + СФОРМИРОВАТЬ ВСЁ ОТКРЫТЬ СПИСОК НЕОТСЛЕЖИВАЕМЫХ ФАЙЛОВ Шаблон: ${0}$ РАБОЧЕЕ ПРОСТРАНСТВО: diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml index b4e4d939..02c138c6 100644 --- a/src/Resources/Locales/ta_IN.axaml +++ b/src/Resources/Locales/ta_IN.axaml @@ -241,7 +241,7 @@ நகல் கோப்பு முறை மாற்றப்பட்டது முதல் வேறுபாடு - வெள்ளைவெளி மாற்றத்தை மற்றும் EOL புறக்கணி + வெள்ளைவெளி மாற்றத்தை புறக்கணி கடைசி வேறுபாடு பெகோஅ பொருள் மாற்றம் அடுத்த வேறுபாடு diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 39bf38e4..8ee210e9 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -257,7 +257,7 @@ 复制 文件权限已变化 首个差异 - 忽略空白符号变化和EOL + 忽略空白符号变化 最后一个差异 LFS对象变更 下一个差异 @@ -609,6 +609,7 @@ 查找提交 作者 提交者 + 变更内容 文件 提交信息 提交指纹 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 181adb69..7430d609 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -257,7 +257,7 @@ 複製 檔案權限已變更 第一個差異 - 忽略空白符號變化和 EOL + 忽略空白符號變化 最後一個差異 LFS 物件變更 下一個差異 @@ -609,6 +609,7 @@ 搜尋提交 作者 提交者 + 變更內容 檔案 提交訊息 提交編號 diff --git a/src/ViewModels/Archive.cs b/src/ViewModels/Archive.cs index 7ce0d968..a4a4f6eb 100644 --- a/src/ViewModels/Archive.cs +++ b/src/ViewModels/Archive.cs @@ -1,4 +1,5 @@ -using System.ComponentModel.DataAnnotations; +using System; +using System.ComponentModel.DataAnnotations; using System.IO; using System.Threading.Tasks; @@ -31,7 +32,7 @@ namespace SourceGit.ViewModels { _repo = repo; _revision = commit.SHA; - _saveFile = $"archive-{commit.SHA.Substring(0, 10)}.zip"; + _saveFile = $"archive-{commit.SHA.AsSpan(0, 10)}.zip"; BasedOn = commit; } diff --git a/src/ViewModels/Blame.cs b/src/ViewModels/Blame.cs index 7cfa8eac..c04842e5 100644 --- a/src/ViewModels/Blame.cs +++ b/src/ViewModels/Blame.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Threading.Tasks; using Avalonia.Threading; @@ -30,7 +31,7 @@ namespace SourceGit.ViewModels { _repo = repo; - Title = $"{file} @ {revision.Substring(0, 10)}"; + Title = $"{file} @ {revision.AsSpan(0, 10)}"; Task.Run(() => { var result = new Commands.Blame(repo, file, revision).Result(); diff --git a/src/ViewModels/Checkout.cs b/src/ViewModels/Checkout.cs index 5a51e2d1..a96ac79a 100644 --- a/src/ViewModels/Checkout.cs +++ b/src/ViewModels/Checkout.cs @@ -62,6 +62,8 @@ namespace SourceGit.ViewModels CallUIThread(() => { + ProgressDescription = "Waiting for branch updated..."; + var b = _repo.Branches.Find(x => x.IsLocal && x.Name == Branch); if (b != null && _repo.HistoriesFilterMode == Models.FilterMode.Included) _repo.SetBranchFilterMode(b, Models.FilterMode.Included, true, false); @@ -70,6 +72,7 @@ namespace SourceGit.ViewModels _repo.SetWatcherEnabled(true); }); + Task.Delay(400).Wait(); return rs; }); } diff --git a/src/ViewModels/CommandLog.cs b/src/ViewModels/CommandLog.cs index 4286b93f..e73bc1ec 100644 --- a/src/ViewModels/CommandLog.cs +++ b/src/ViewModels/CommandLog.cs @@ -13,15 +13,16 @@ namespace SourceGit.ViewModels private set; } = string.Empty; - public DateTime Time + public DateTime StartTime { get; } = DateTime.Now; - public string TimeStr + public DateTime EndTime { - get => Time.ToString("T"); - } + get; + private set; + } = DateTime.Now; public bool IsComplete { @@ -69,6 +70,8 @@ namespace SourceGit.ViewModels _builder.Clear(); _builder = null; + EndTime = DateTime.Now; + OnPropertyChanged(nameof(IsComplete)); if (_onNewLineReceived != null) diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index 6581d7bb..fdaa29f1 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -642,10 +642,37 @@ namespace SourceGit.ViewModels rule.Matches(inlines, message); } - var matches = REG_SHA_FORMAT().Matches(message); - for (int i = 0; i < matches.Count; i++) + var urlMatches = REG_URL_FORMAT().Matches(message); + for (int i = 0; i < urlMatches.Count; i++) { - var match = matches[i]; + var match = urlMatches[i]; + if (!match.Success) + continue; + + var start = match.Index; + var len = match.Length; + var intersect = false; + foreach (var link in inlines) + { + if (link.Intersect(start, len)) + { + intersect = true; + break; + } + } + + if (intersect) + continue; + + var url = message.Substring(start, len); + if (Uri.IsWellFormedUriString(url, UriKind.Absolute)) + inlines.Add(new Models.InlineElement(Models.InlineElementType.Link, start, len, url)); + } + + var shaMatches = REG_SHA_FORMAT().Matches(message); + for (int i = 0; i < shaMatches.Count; i++) + { + var match = shaMatches[i]; if (!match.Success) continue; @@ -840,6 +867,9 @@ namespace SourceGit.ViewModels RevisionFileSearchSuggestion = suggestion; } + [GeneratedRegex(@"\b(https?://|ftp://)[\w\d\._/\-~%@()+:?&=#!]*[\w\d/]")] + private static partial Regex REG_URL_FORMAT(); + [GeneratedRegex(@"\b([0-9a-fA-F]{6,40})\b")] private static partial Regex REG_SHA_FORMAT(); diff --git a/src/ViewModels/ConfigureWorkspace.cs b/src/ViewModels/ConfigureWorkspace.cs index 6dc0f82e..ec885b2f 100644 --- a/src/ViewModels/ConfigureWorkspace.cs +++ b/src/ViewModels/ConfigureWorkspace.cs @@ -9,7 +9,6 @@ namespace SourceGit.ViewModels public AvaloniaList Workspaces { get; - private set; } public Workspace Selected @@ -51,6 +50,36 @@ namespace SourceGit.ViewModels Workspaces.Remove(_selected); } + public void MoveSelectedUp() + { + if (_selected == null) + return; + + var idx = Workspaces.IndexOf(_selected); + if (idx == 0) + return; + + Workspaces.Move(idx - 1, idx); + + Preferences.Instance.Workspaces.RemoveAt(idx); + Preferences.Instance.Workspaces.Insert(idx - 1, _selected); + } + + public void MoveSelectedDown() + { + if (_selected == null) + return; + + var idx = Workspaces.IndexOf(_selected); + if (idx == Workspaces.Count - 1) + return; + + Workspaces.Move(idx + 1, idx); + + Preferences.Instance.Workspaces.RemoveAt(idx); + Preferences.Instance.Workspaces.Insert(idx + 1, _selected); + } + private Workspace _selected = null; private bool _canDeleteSelected = false; } diff --git a/src/ViewModels/CreateBranch.cs b/src/ViewModels/CreateBranch.cs index d51a709d..dd190e18 100644 --- a/src/ViewModels/CreateBranch.cs +++ b/src/ViewModels/CreateBranch.cs @@ -150,6 +150,12 @@ namespace SourceGit.ViewModels _repo.SetWatcherEnabled(true); }); + if (CheckoutAfterCreated) + { + CallUIThread(() => ProgressDescription = "Waiting for branch updated..."); + Task.Delay(400).Wait(); + } + return true; }); } diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index 84ba96e4..d9425059 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using Avalonia.Collections; @@ -584,7 +584,7 @@ namespace SourceGit.ViewModels var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length; if (path.StartsWith(home, StringComparison.Ordinal)) - path = "~" + path.Substring(prefixLen); + path = $"~{path.AsSpan(prefixLen)}"; } Title = $"[{workspace}] {name} ({path})"; diff --git a/src/ViewModels/LauncherPage.cs b/src/ViewModels/LauncherPage.cs index 288770bc..b97ef6f7 100644 --- a/src/ViewModels/LauncherPage.cs +++ b/src/ViewModels/LauncherPage.cs @@ -1,5 +1,8 @@ using System; + using Avalonia.Collections; +using Avalonia.Media; + using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels @@ -18,6 +21,12 @@ namespace SourceGit.ViewModels set => SetProperty(ref _data, value); } + public IBrush DirtyBrush + { + get => _dirtyBrush; + private set => SetProperty(ref _dirtyBrush, value); + } + public Popup Popup { get => _popup; @@ -56,6 +65,26 @@ namespace SourceGit.ViewModels App.CopyText(_node.Id); } + public void ChangeDirtyState(Models.DirtyState flag, bool remove) + { + if (remove) + { + if (_dirtyState.HasFlag(flag)) + _dirtyState -= flag; + } + else + { + _dirtyState |= flag; + } + + if (_dirtyState.HasFlag(Models.DirtyState.HasLocalChanges)) + DirtyBrush = Brushes.Gray; + else if (_dirtyState.HasFlag(Models.DirtyState.HasPendingPullOrPush)) + DirtyBrush = Brushes.RoyalBlue; + else + DirtyBrush = null; + } + public bool CanCreatePopup() { return _popup == null || !_popup.InProgress; @@ -104,6 +133,8 @@ namespace SourceGit.ViewModels private RepositoryNode _node = null; private object _data = null; + private IBrush _dirtyBrush = null; + private Models.DirtyState _dirtyState = Models.DirtyState.None; private Popup _popup = null; } } diff --git a/src/ViewModels/RenameBranch.cs b/src/ViewModels/RenameBranch.cs index d730c83e..22cd2688 100644 --- a/src/ViewModels/RenameBranch.cs +++ b/src/ViewModels/RenameBranch.cs @@ -58,12 +58,15 @@ namespace SourceGit.ViewModels return Task.Run(() => { + var isCurrent = Target.IsCurrent; var oldName = Target.FullName; var succ = Commands.Branch.Rename(_repo.FullPath, Target.Name, fixedName, log); log.Complete(); CallUIThread(() => { + ProgressDescription = "Waiting for branch updated..."; + if (succ) { foreach (var filter in _repo.Settings.HistoriesFilters) @@ -80,6 +83,10 @@ namespace SourceGit.ViewModels _repo.MarkBranchesDirtyManually(); _repo.SetWatcherEnabled(true); }); + + if (isCurrent) + Task.Delay(400).Wait(); + return succ; }); } diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 1db1d6f3..289d890f 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -994,6 +994,8 @@ namespace SourceGit.ViewModels if (_workingCopy != null) _workingCopy.HasRemotes = remotes.Count > 0; + + GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasPendingPullOrPush, !CurrentBranch.TrackStatus.IsVisible); }); } @@ -1101,6 +1103,7 @@ namespace SourceGit.ViewModels { LocalChangesCount = changes.Count; OnPropertyChanged(nameof(InProgressContext)); + GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasLocalChanges, changes.Count == 0); }); } diff --git a/src/ViewModels/ScanRepositories.cs b/src/ViewModels/ScanRepositories.cs index 307694ea..cec932eb 100644 --- a/src/ViewModels/ScanRepositories.cs +++ b/src/ViewModels/ScanRepositories.cs @@ -38,6 +38,12 @@ namespace SourceGit.ViewModels IgnoreInaccessible = true, }); + // Make sure this task takes at least 0.5s to avoid that the popup panel do not disappear very quickly. + var remain = 500 - (int)watch.Elapsed.TotalMilliseconds; + watch.Stop(); + if (remain > 0) + Task.Delay(remain).Wait(); + Dispatcher.UIThread.Invoke(() => { var normalizedRoot = rootDir.FullName.Replace("\\", "/"); @@ -61,12 +67,6 @@ namespace SourceGit.ViewModels Welcome.Instance.Refresh(); }); - // Make sure this task takes at least 0.5s to avoid that the popup panel do not disappear very quickly. - var remain = 500 - (int)watch.Elapsed.TotalMilliseconds; - watch.Stop(); - if (remain > 0) - Task.Delay(remain).Wait(); - return true; }); } diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 4d35b5c2..762f1176 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -635,7 +635,7 @@ namespace SourceGit.ViewModels } else if (_inProgressContext is RevertInProgress revert) { - useTheirs.Header = App.Text("FileCM.ResolveUsing", $"{revert.Head.SHA.AsSpan().Slice(0, 10)} (revert)"); + useTheirs.Header = App.Text("FileCM.ResolveUsing", $"{revert.Head.SHA.AsSpan(0, 10)} (revert)"); useMine.Header = App.Text("FileCM.ResolveUsing", _repo.CurrentBranch.Name); } else if (_inProgressContext is MergeInProgress merge) @@ -993,7 +993,7 @@ namespace SourceGit.ViewModels } else if (_inProgressContext is RevertInProgress revert) { - useTheirs.Header = App.Text("FileCM.ResolveUsing", $"{revert.Head.SHA.AsSpan().Slice(0, 10)} (revert)"); + useTheirs.Header = App.Text("FileCM.ResolveUsing", $"{revert.Head.SHA.AsSpan(0, 10)} (revert)"); useMine.Header = App.Text("FileCM.ResolveUsing", _repo.CurrentBranch.Name); } else if (_inProgressContext is MergeInProgress merge) @@ -1417,7 +1417,7 @@ namespace SourceGit.ViewModels var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length; if (gitTemplate.StartsWith(home, StringComparison.Ordinal)) - friendlyName = $"~{gitTemplate.AsSpan().Slice(prefixLen)}"; + friendlyName = $"~{gitTemplate.AsSpan(prefixLen)}"; } var gitTemplateItem = new MenuItem(); diff --git a/src/Views/AIAssistant.axaml b/src/Views/AIAssistant.axaml index c9a37f3b..96ce56ec 100644 --- a/src/Views/AIAssistant.axaml +++ b/src/Views/AIAssistant.axaml @@ -39,12 +39,12 @@ + Background="{DynamicResource Brush.Contents}" + Content="{Binding Text}"/> diff --git a/src/Views/AIAssistant.axaml.cs b/src/Views/AIAssistant.axaml.cs index f8519b7c..f865cabe 100644 --- a/src/Views/AIAssistant.axaml.cs +++ b/src/Views/AIAssistant.axaml.cs @@ -15,6 +15,15 @@ namespace SourceGit.Views { public class AIResponseView : TextEditor { + public static readonly StyledProperty ContentProperty = + AvaloniaProperty.Register(nameof(Content), string.Empty); + + public string Content + { + get => GetValue(ContentProperty); + set => SetValue(ContentProperty, value); + } + protected override Type StyleKeyOverride => typeof(TextEditor); public AIResponseView() : base(new TextArea(), new TextDocument()) @@ -58,6 +67,16 @@ namespace SourceGit.Views GC.Collect(); } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == ContentProperty) + { + Text = Content; + } + } + private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) { var selected = SelectedText; diff --git a/src/Views/CommandLogTime.cs b/src/Views/CommandLogTime.cs new file mode 100644 index 00000000..2f24d890 --- /dev/null +++ b/src/Views/CommandLogTime.cs @@ -0,0 +1,80 @@ +using System; +using System.Threading; + +using Avalonia; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Threading; + +namespace SourceGit.Views +{ + public class CommandLogTime : TextBlock + { + public static readonly StyledProperty LogProperty = + AvaloniaProperty.Register(nameof(Log), null); + + public ViewModels.CommandLog Log + { + get => GetValue(LogProperty); + set => SetValue(LogProperty, value); + } + + protected override Type StyleKeyOverride => typeof(TextBlock); + + protected override void OnUnloaded(RoutedEventArgs e) + { + base.OnUnloaded(e); + StopTimer(); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == LogProperty) + { + StopTimer(); + + if (change.NewValue is ViewModels.CommandLog log) + SetupCommandLog(log); + else + Text = string.Empty; + } + } + + private void SetupCommandLog(ViewModels.CommandLog log) + { + Text = GetDisplayText(log); + if (log.IsComplete) + return; + + _refreshTimer = new Timer(_ => + { + Dispatcher.UIThread.Invoke(() => + { + Text = GetDisplayText(log); + if (log.IsComplete) + StopTimer(); + }); + }, null, 0, 100); + } + + private void StopTimer() + { + if (_refreshTimer is { }) + { + _refreshTimer.Dispose(); + _refreshTimer = null; + } + } + + private string GetDisplayText(ViewModels.CommandLog log) + { + var endTime = log.IsComplete ? log.EndTime : DateTime.Now; + var duration = (endTime - log.StartTime).ToString(@"hh\:mm\:ss\.fff"); + return $"{log.StartTime:T} ({duration})"; + } + + private Timer _refreshTimer = null; + } +} diff --git a/src/Views/CommitSubjectPresenter.cs b/src/Views/CommitSubjectPresenter.cs index f64323c0..86e0fd54 100644 --- a/src/Views/CommitSubjectPresenter.cs +++ b/src/Views/CommitSubjectPresenter.cs @@ -178,6 +178,7 @@ namespace SourceGit.Views foreach (var rule in rules) rule.Matches(_elements, subject); + _elements.Sort((l, r) => l.Start - r.Start); _needRebuildInlines = true; InvalidateVisual(); } @@ -318,7 +319,6 @@ namespace SourceGit.Views foreground); _inlines.Add(new Inline(x, normal, null)); - x += normal.WidthIncludingTrailingWhitespace; } } diff --git a/src/Views/ConfigureWorkspace.axaml b/src/Views/ConfigureWorkspace.axaml index 169df154..c65b8879 100644 --- a/src/Views/ConfigureWorkspace.axaml +++ b/src/Views/ConfigureWorkspace.axaml @@ -79,19 +79,39 @@ - - - - - - - - - + + + diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml index c4da158d..9ca99abe 100644 --- a/src/Views/DiffView.axaml +++ b/src/Views/DiffView.axaml @@ -155,7 +155,6 @@ diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml index 568854fd..86a96528 100644 --- a/src/Views/Histories.axaml +++ b/src/Views/Histories.axaml @@ -24,7 +24,7 @@ - + - + - - + + @@ -121,8 +121,8 @@ - - + + diff --git a/src/Views/Histories.axaml.cs b/src/Views/Histories.axaml.cs index 89c68934..d49d9735 100644 --- a/src/Views/Histories.axaml.cs +++ b/src/Views/Histories.axaml.cs @@ -205,7 +205,7 @@ namespace SourceGit.Views foreach (var item in selected) { if (item is Models.Commit commit) - builder.AppendLine($"{commit.SHA.Substring(0, 10)} - {commit.Subject}"); + builder.AppendLine($"{commit.SHA.AsSpan(0, 10)} - {commit.Subject}"); } App.CopyText(builder.ToString()); diff --git a/src/Views/LauncherTabBar.axaml b/src/Views/LauncherTabBar.axaml index 73b48f58..0376e259 100644 --- a/src/Views/LauncherTabBar.axaml +++ b/src/Views/LauncherTabBar.axaml @@ -68,14 +68,29 @@ Data="{StaticResource Icons.Repositories}" IsVisible="{Binding !Node.IsRepository}" IsHitTestVisible="False"/> - + + + + + + + + diff --git a/src/Views/RepositoryConfigure.axaml.cs b/src/Views/RepositoryConfigure.axaml.cs index 455731aa..2c80dd45 100644 --- a/src/Views/RepositoryConfigure.axaml.cs +++ b/src/Views/RepositoryConfigure.axaml.cs @@ -1,4 +1,5 @@ using Avalonia.Controls; +using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Platform.Storage; @@ -33,5 +34,13 @@ namespace SourceGit.Views e.Handled = true; } + + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + + if (!e.Handled && e.Key == Key.Escape) + Close(); + } } } diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index ad2f8cea..78a67bae 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -126,7 +126,7 @@ namespace SourceGit.Views typeface, presenter.FontSize, presenter.Foreground); - context.DrawText(txt, new Point(Bounds.Width - txt.Width, y - txt.Height * 0.5)); + context.DrawText(txt, new Point(Bounds.Width - txt.Width, y - (txt.Height * 0.5))); } } } @@ -212,7 +212,7 @@ namespace SourceGit.Views } if (indicator != null) - context.DrawText(indicator, new Point(0, y - indicator.Height * 0.5)); + context.DrawText(indicator, new Point(0, y - (indicator.Height * 0.5))); } } } @@ -1047,7 +1047,8 @@ namespace SourceGit.Views // The first selected line (partial selection) if (i == startIdx && startPosition.Column > 1) { - builder.AppendLine(line.Content.Substring(startPosition.Column - 1)); + builder.Append(line.Content.AsSpan(startPosition.Column - 1)); + builder.Append(Environment.NewLine); continue; } @@ -1061,7 +1062,14 @@ namespace SourceGit.Views // For the last line (selection range is within original source) if (i == endIdx) { - builder.Append(endPosition.Column - 1 < line.Content.Length ? line.Content.Substring(0, endPosition.Column - 1) : line.Content); + if (endPosition.Column - 1 < line.Content.Length) + { + builder.Append(line.Content.AsSpan(0, endPosition.Column - 1)); + } + else + { + builder.Append(line.Content); + } break; } @@ -1251,7 +1259,7 @@ namespace SourceGit.Views { if (line.Content.Length > 10000) { - builder.Append(line.Content.Substring(0, 1000)); + builder.Append(line.Content.AsSpan(0, 1000)); builder.Append($"...({line.Content.Length - 1000} character trimmed)"); } else @@ -1741,7 +1749,7 @@ namespace SourceGit.Views } var top = chunk.Y + (chunk.Height >= 36 ? 16 : 4); - var right = (chunk.Combined || !chunk.IsOldSide) ? 16 : v.Bounds.Width * 0.5f + 16; + var right = (chunk.Combined || !chunk.IsOldSide) ? 16 : (v.Bounds.Width * 0.5f) + 16; v.Popup.Margin = new Thickness(0, top, right, 0); v.Popup.IsVisible = true; }); diff --git a/src/Views/ViewLogs.axaml b/src/Views/ViewLogs.axaml index ccdd1f4d..1fb44d66 100644 --- a/src/Views/ViewLogs.axaml +++ b/src/Views/ViewLogs.axaml @@ -12,7 +12,7 @@ Title="{DynamicResource Text.ViewLogs}" Icon="/App.ico" Width="800" Height="500" - CanResize="False" + CanResize="True" WindowStartupLocation="CenterOwner"> @@ -38,7 +38,13 @@ - + + + + + + + - + - + @@ -103,6 +109,12 @@ Fill="{DynamicResource Brush.FG2}" IsVisible="{Binding Logs.Count, Converter={x:Static c:IntConverters.IsZero}}"/> + +