Compare commits

..

No commits in common. "4a3ef6267f38b96f8542915624124a32388a869b" and "790e1f6c4b999be31feb26b19925a5aa7cb40390" have entirely different histories.

34 changed files with 128 additions and 828 deletions

View file

@ -1,39 +0,0 @@
name: Publish to Buildkite
on:
workflow_call:
secrets:
BUILDKITE_TOKEN:
required: true
jobs:
publish:
name: Publish to Buildkite
runs-on: ubuntu-latest
strategy:
matrix:
runtime: [linux-x64, linux-arm64]
steps:
- name: Download package artifacts
uses: actions/download-artifact@v4
with:
name: package.${{ matrix.runtime }}
path: packages
- name: Publish DEB package
env:
BUILDKITE_TOKEN: ${{ secrets.BUILDKITE_TOKEN }}
run: |
FILE=$(echo packages/*.deb)
curl -X POST https://api.buildkite.com/v2/packages/organizations/sourcegit/registries/sourcegit-deb/packages \
-H "Authorization: Bearer $BUILDKITE_TOKEN" \
-F "file=@$FILE" \
--fail
- name: Publish RPM package
env:
BUILDKITE_TOKEN: ${{ secrets.BUILDKITE_TOKEN }}
run: |
FILE=$(echo packages/*.rpm)
curl -X POST https://api.buildkite.com/v2/packages/organizations/sourcegit/registries/sourcegit-rpm/packages \
-H "Authorization: Bearer $BUILDKITE_TOKEN" \
-F "file=@$FILE" \
--fail

View file

@ -24,11 +24,6 @@ jobs:
uses: ./.github/workflows/package.yml
with:
version: ${{ needs.version.outputs.version }}
publish-packages:
name: Publish Packages
uses: ./.github/workflows/publish-packages.yml
secrets:
BUILDKITE_TOKEN: ${{ secrets.BUILDKITE_TOKEN }}
release:
needs: [package, version]
name: Release

View file

@ -47,7 +47,7 @@
## Translation Status
[![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-99.58%25-yellow)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-99.86%25-yellow)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-97.03%25-yellow)](TRANSLATION.md) [![it__IT](https://img.shields.io/badge/it__IT-97.45%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-98.87%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-100.00%25-brightgreen)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-100.00%25-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-100.00%25-brightgreen)](TRANSLATION.md)
[![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-99.86%25-yellow)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-97.87%25-yellow)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-97.30%25-yellow)](TRANSLATION.md) [![it__IT](https://img.shields.io/badge/it__IT-97.73%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-99.15%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-100.00%25-brightgreen)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-100.00%25-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-100.00%25-brightgreen)](TRANSLATION.md)
## How to Use

View file

@ -18,7 +18,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
.github\workflows\package.yml = .github\workflows\package.yml
.github\workflows\release.yml = .github\workflows\release.yml
.github\workflows\localization-check.yml = .github\workflows\localization-check.yml
.github\workflows\publish-packages.yml = .github\workflows\publish-packages.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{49A7C2D6-558C-4FAA-8F5D-EEE81497AED7}"

View file

@ -1,26 +1,38 @@
### de_DE.axaml: 99.58%
### de_DE.axaml: 99.86%
<details>
<summary>Missing Keys</summary>
- Text.CommitDetail.Files.Search
- Text.Diff.UseBlockNavigation
- Text.WorkingCopy.CommitToEdit
</details>
### es_ES.axaml: 99.86%
### es_ES.axaml: 97.87%
<details>
<summary>Missing Keys</summary>
- Text.Diff.UseBlockNavigation
- Text.CommitDetail.Info.Children
- Text.Fetch.Force
- Text.Preference.Appearance.FontSize
- Text.Preference.Appearance.FontSize.Default
- Text.Preference.Appearance.FontSize.Editor
- Text.Preference.General.ShowChildren
- Text.Repository.FilterCommits
- Text.Repository.FilterCommits.Default
- Text.Repository.FilterCommits.Exclude
- Text.Repository.FilterCommits.Include
- Text.Repository.HistoriesOrder
- Text.Repository.HistoriesOrder.ByDate
- Text.Repository.HistoriesOrder.Topo
- Text.SHALinkCM.NavigateTo
- Text.WorkingCopy.CommitToEdit
</details>
### fr_FR.axaml: 97.03%
### fr_FR.axaml: 97.30%
<details>
@ -29,8 +41,6 @@
- Text.CherryPick.AppendSourceToMessage
- Text.CherryPick.Mainline.Tips
- Text.CommitCM.CherryPickMultiple
- Text.CommitDetail.Files.Search
- Text.Diff.UseBlockNavigation
- Text.Fetch.Force
- Text.Preference.Appearance.FontSize
- Text.Preference.Appearance.FontSize.Default
@ -50,18 +60,16 @@
</details>
### it_IT.axaml: 97.45%
### it_IT.axaml: 97.73%
<details>
<summary>Missing Keys</summary>
- Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children
- Text.Configure.IssueTracker.AddSampleGitLabMergeRequest
- Text.Configure.OpenAI.Preferred
- Text.Configure.OpenAI.Preferred.Tip
- Text.Diff.UseBlockNavigation
- Text.Fetch.Force
- Text.Preference.General.ShowChildren
- Text.Repository.FilterCommits
@ -77,15 +85,13 @@
</details>
### pt_BR.axaml: 98.87%
### pt_BR.axaml: 99.15%
<details>
<summary>Missing Keys</summary>
- Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children
- Text.Diff.UseBlockNavigation
- Text.Fetch.Force
- Text.Preference.General.ShowChildren
- Text.Repository.FilterCommits

View file

@ -1 +1 @@
8.42
8.41

View file

@ -7,7 +7,6 @@ URL: https://sourcegit-scm.github.io/
Source: https://github.com/sourcegit-scm/sourcegit/archive/refs/tags/v%_version.tar.gz
Requires: libX11.so.6()(%{__isa_bits}bit)
Requires: libSM.so.6()(%{__isa_bits}bit)
Requires: libicu
%define _build_id_links none

View file

@ -164,12 +164,7 @@ namespace SourceGit
var resDic = new ResourceDictionary();
var overrides = JsonSerializer.Deserialize(File.ReadAllText(themeOverridesFile), JsonCodeGen.Default.ThemeOverrides);
foreach (var kv in overrides.BasicColors)
{
if (kv.Key.Equals("SystemAccentColor", StringComparison.Ordinal))
resDic["SystemAccentColor"] = kv.Value;
else
resDic[$"Color.{kv.Key}"] = kv.Value;
}
resDic[$"Color.{kv.Key}"] = kv.Value;
if (overrides.GraphColors.Count > 0)
Models.CommitGraph.SetPens(overrides.GraphColors, overrides.GraphPenThickness);

View file

@ -1,19 +1,19 @@
namespace SourceGit.Commands
{
public class QueryRevisionFileNames : Command
public class QueryCurrentRevisionFiles : Command
{
public QueryRevisionFileNames(string repo, string revision)
public QueryCurrentRevisionFiles(string repo)
{
WorkingDirectory = repo;
Context = repo;
Args = $"ls-tree -r -z --name-only {revision}";
Args = "ls-tree -r --name-only HEAD";
}
public string[] Result()
{
var rs = ReadToEnd();
if (rs.IsSuccess)
return rs.StdOut.Split('\0', System.StringSplitOptions.RemoveEmptyEntries);
return rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
return [];
}

View file

@ -12,7 +12,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = $"ls-tree -z {sha}";
Args = $"ls-tree {sha}";
if (!string.IsNullOrEmpty(parentFolder))
Args += $" -- \"{parentFolder}\"";
@ -20,27 +20,11 @@ namespace SourceGit.Commands
public List<Models.Object> Result()
{
var rs = ReadToEnd();
if (rs.IsSuccess)
{
var start = 0;
var end = rs.StdOut.IndexOf('\0', start);
while (end > 0)
{
var line = rs.StdOut.Substring(start, end - start);
Parse(line);
start = end + 1;
end = rs.StdOut.IndexOf('\0', start);
}
if (start < rs.StdOut.Length)
Parse(rs.StdOut.Substring(start));
}
Exec();
return _objects;
}
private void Parse(string line)
protected override void OnReadline(string line)
{
var match = REG_FORMAT().Match(line);
if (!match.Success)

View file

@ -7,8 +7,6 @@ namespace SourceGit.Models
public List<string> Ahead { get; set; } = new List<string>();
public List<string> Behind { get; set; } = new List<string>();
public bool IsVisible => Ahead.Count > 0 || Behind.Count > 0;
public override string ToString()
{
if (Ahead.Count == 0 && Behind.Count == 0)

View file

@ -15,7 +15,6 @@
<StreamGeometry x:Key="Icons.Clean">M797 829a49 49 0 1049 49 49 49 0 00-49-49zm147-114A49 49 0 10992 764a49 49 0 00-49-49zM928 861a49 49 0 1049 49A49 49 0 00928 861zm-5-586L992 205 851 64l-71 71a67 67 0 00-94 0l235 235a67 67 0 000-94zm-853 128a32 32 0 00-32 50 1291 1291 0 0075 112L288 552c20 0 25 21 8 37l-93 86a1282 1282 0 00120 114l100-32c19-6 28 15 14 34l-40 55c26 19 53 36 82 53a89 89 0 00115-20 1391 1391 0 00256-485l-188-188s-306 224-595 198z</StreamGeometry>
<StreamGeometry x:Key="Icons.Clone">M1280 704c0 141-115 256-256 256H288C129 960 0 831 0 672c0-126 80-232 192-272A327 327 0 01192 384c0-177 143-320 320-320 119 0 222 64 277 160C820 204 857 192 896 192c106 0 192 86 192 192 0 24-5 48-13 69C1192 477 1280 580 1280 704zm-493-128H656V352c0-18-14-32-32-32h-96c-18 0-32 14-32 32v224h-131c-29 0-43 34-23 55l211 211c12 12 33 12 45 0l211-211c20-20 6-55-23-55z</StreamGeometry>
<StreamGeometry x:Key="Icons.Code">M853 102H171C133 102 102 133 102 171v683C102 891 133 922 171 922h683C891 922 922 891 922 853V171C922 133 891 102 853 102zM390 600l-48 48L205 512l137-137 48 48L301 512l88 88zM465 819l-66-18L559 205l66 18L465 819zm218-171L634 600 723 512l-88-88 48-48L819 512 683 649z</StreamGeometry>
<StreamGeometry x:Key="Icons.CodeBlock">M320 171A21 21 0 00299 192v213c0 49-32 85-61 107 30 22 61 58 61 107V832A21 21 0 00320 853h85v85H320A107 107 0 01213 832V619c0-11-8-26-32-42a157 157 0 00-33-17c-11-4-18-5-20-5v-85c2 0 9-1 20-5a157 157 0 0033-17c24-16 32-32 32-42V192A107 107 0 01320 85h85v85H320zm384 0h-85V85H704A107 107 0 01811 192v213c0 11 8 26 32 42 11 7 22 13 33 17 11 4 18 5 20 5v85c-2 0-9 1-20 5a157 157 0 00-33 17c-24 16-32 31-32 42V832A107 107 0 01704 939h-85v-85H704A21 21 0 00725 832V619c0-49 32-85 61-107-30-22-61-58-61-107V192A21 21 0 00704 171z</StreamGeometry>
<StreamGeometry x:Key="Icons.ColorPicker">M128 854h768v86H128zM390 797c13 13 29 19 48 19s35-6 45-19l291-288c26-22 26-64 0-90L435 83l-61 61L426 192l-272 269c-22 22-22 64 0 90l237 246zm93-544 211 211-32 32H240l243-243zM707 694c0 48 38 86 86 86 48 0 86-38 86-86 0-22-10-45-26-61L794 576l-61 61c-13 13-26 35-26 58z</StreamGeometry>
<StreamGeometry x:Key="Icons.Commit">M796 471A292 292 0 00512 256a293 293 0 00-284 215H0v144h228A293 293 0 00512 832a291 291 0 00284-217H1024V471h-228M512 688A146 146 0 01366 544A145 145 0 01512 400c80 0 146 63 146 144A146 146 0 01512 688</StreamGeometry>
<StreamGeometry x:Key="Icons.CommitMessageGenerator">M796 561a5 5 0 014 7l-39 90a5 5 0 004 7h100a5 5 0 014 8l-178 247a5 5 0 01-9-4l32-148a5 5 0 00-5-6h-89a5 5 0 01-4-7l86-191a5 5 0 014-3h88zM731 122a73 73 0 0173 73v318a54 54 0 00-8-1H731V195H244v634h408l-16 73H244a73 73 0 01-73-73V195a73 73 0 0173-73h488zm-219 366v73h-195v-73h195zm146-146v73H317v-73h341z</StreamGeometry>

View file

@ -121,7 +121,6 @@
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">Search Changes...</x:String>
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">FILES</x:String>
<x:String x:Key="Text.CommitDetail.Files.LFS" xml:space="preserve">LFS File</x:String>
<x:String x:Key="Text.CommitDetail.Files.Search" xml:space="preserve">Search Files...</x:String>
<x:String x:Key="Text.CommitDetail.Files.Submodule" xml:space="preserve">Submodule</x:String>
<x:String x:Key="Text.CommitDetail.Info" xml:space="preserve">INFORMATION</x:String>
<x:String x:Key="Text.CommitDetail.Info.Author" xml:space="preserve">AUTHOR</x:String>
@ -247,7 +246,6 @@
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">Swap</x:String>
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">Syntax Highlighting</x:String>
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">Line Word Wrap</x:String>
<x:String x:Key="Text.Diff.UseBlockNavigation" xml:space="preserve">Enable Block-Navigation</x:String>
<x:String x:Key="Text.Diff.UseMerger" xml:space="preserve">Open in Merge Tool</x:String>
<x:String x:Key="Text.Diff.VisualLines.All" xml:space="preserve">Show All Lines</x:String>
<x:String x:Key="Text.Diff.VisualLines.Decr" xml:space="preserve">Decrease Number of Visible Lines</x:String>

View file

@ -126,12 +126,10 @@
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">Buscar Cambios...</x:String>
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">ARCHIVOS</x:String>
<x:String x:Key="Text.CommitDetail.Files.LFS" xml:space="preserve">Archivo LFS</x:String>
<x:String x:Key="Text.CommitDetail.Files.Search" xml:space="preserve">Buscar Archivos...</x:String>
<x:String x:Key="Text.CommitDetail.Files.Submodule" xml:space="preserve">Submódulo</x:String>
<x:String x:Key="Text.CommitDetail.Info" xml:space="preserve">INFORMACIÓN</x:String>
<x:String x:Key="Text.CommitDetail.Info.Author" xml:space="preserve">AUTOR</x:String>
<x:String x:Key="Text.CommitDetail.Info.Changed" xml:space="preserve">CAMBIADO</x:String>
<x:String x:Key="Text.CommitDetail.Info.Children" xml:space="preserve">HIJOS</x:String>
<x:String x:Key="Text.CommitDetail.Info.Committer" xml:space="preserve">COMMITTER</x:String>
<x:String x:Key="Text.CommitDetail.Info.ContainsIn" xml:space="preserve">Ver refs que contienen este commit</x:String>
<x:String x:Key="Text.CommitDetail.Info.ContainsIn.Title" xml:space="preserve">COMMIT ESTÁ CONTENIDO EN</x:String>
@ -274,7 +272,6 @@
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Fast-Forward (sin checkout)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">Fetch</x:String>
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">Fetch todos los remotos</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">Utilizar opción '--force'</x:String>
<x:String x:Key="Text.Fetch.NoTags" xml:space="preserve">Fetch sin etiquetas</x:String>
<x:String x:Key="Text.Fetch.Remote" xml:space="preserve">Remoto:</x:String>
<x:String x:Key="Text.Fetch.Title" xml:space="preserve">Fetch Cambios Remotos</x:String>
@ -440,9 +437,6 @@
<x:String x:Key="Text.Preference.AI.Server" xml:space="preserve">Servidor</x:String>
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">APARIENCIA</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Fuente por defecto</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize" xml:space="preserve">Tamaño de fuente</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Default" xml:space="preserve">Por defecto</x:String>
<x:String x:Key="Text.Preference.Appearance.FontSize.Editor" xml:space="preserve">Editor</x:String>
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Fuente Monospace</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Usar solo fuente monospace en el editor de texto</x:String>
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Tema</x:String>
@ -458,7 +452,6 @@
<x:String x:Key="Text.Preference.General.Locale" xml:space="preserve">Idioma</x:String>
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">Commits en el historial</x:String>
<x:String x:Key="Text.Preference.General.ShowAuthorTime" xml:space="preserve">Mostrar hora del autor en lugar de la hora del commit en el gráfico</x:String>
<x:String x:Key="Text.Preference.General.ShowChildren" xml:space="preserve">Mostrar hijos en los detalles de commit</x:String>
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Longitud de la guía del asunto</x:String>
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Habilitar Auto CRLF</x:String>
@ -548,13 +541,6 @@
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Habilitar Opción '--reflog'</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Abrir en el Explorador</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Buscar Ramas/Etiquetas/Submódulos</x:String>
<x:String x:Key="Text.Repository.FilterCommits" xml:space="preserve">Visibilidad en el Gráfico</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Default" xml:space="preserve">Desestablecer</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Exclude" xml:space="preserve">Ocultar en el Gráfico de Commits</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Include" xml:space="preserve">Filtrar en el Gráfico de Commits</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder" xml:space="preserve">Cambiar Modo de Ordenación</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.ByDate" xml:space="preserve">Fecha de Commit (--date-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Topológicamente (--topo-order)</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">RAMAS LOCALES</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Navegar a HEAD</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Habilitar Opción '--first-parent'</x:String>
@ -607,7 +593,6 @@
<x:String x:Key="Text.SelfUpdate.Title" xml:space="preserve">Actualización de Software</x:String>
<x:String x:Key="Text.SelfUpdate.UpToDate" xml:space="preserve">Actualmente no hay actualizaciones disponibles.</x:String>
<x:String x:Key="Text.SHALinkCM.CopySHA" xml:space="preserve">Copiar SHA</x:String>
<x:String x:Key="Text.SHALinkCM.NavigateTo" xml:space="preserve">Ir a</x:String>
<x:String x:Key="Text.Squash" xml:space="preserve">Squash Commits</x:String>
<x:String x:Key="Text.Squash.Into" xml:space="preserve">En:</x:String>
<x:String x:Key="Text.SSHKey" xml:space="preserve">Clave Privada SSH:</x:String>
@ -685,7 +670,6 @@
<x:String x:Key="Text.WorkingCopy.CommitAndPush" xml:space="preserve">COMMIT &amp; PUSH</x:String>
<x:String x:Key="Text.WorkingCopy.CommitMessageHelper" xml:space="preserve">Plantilla/Historias</x:String>
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">Activar evento de clic</x:String>
<x:String x:Key="Text.WorkingCopy.CommitToEdit" xml:space="preserve">Commit (Editar)</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">Stagear todos los cambios y commit</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithoutFiles" xml:space="preserve">¡Commit vacío detectado! ¿Quieres continuar (--allow-empty)?</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">CONFLICTOS DETECTADOS</x:String>

View file

@ -124,7 +124,6 @@
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">Найти изменения....</x:String>
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">ФАЙЛЫ</x:String>
<x:String x:Key="Text.CommitDetail.Files.LFS" xml:space="preserve">Файл ХБФ</x:String>
<x:String x:Key="Text.CommitDetail.Files.Search" xml:space="preserve">Поиск файлов...</x:String>
<x:String x:Key="Text.CommitDetail.Files.Submodule" xml:space="preserve">Подмодуль</x:String>
<x:String x:Key="Text.CommitDetail.Info" xml:space="preserve">ИНФОРМАЦИЯ</x:String>
<x:String x:Key="Text.CommitDetail.Info.Author" xml:space="preserve">АВТОР</x:String>
@ -251,7 +250,6 @@
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">Обмен</x:String>
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">Подсветка синтаксиса </x:String>
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">Перенос слов в строке</x:String>
<x:String x:Key="Text.Diff.UseBlockNavigation" xml:space="preserve">Разрешить навигацию по блокам</x:String>
<x:String x:Key="Text.Diff.UseMerger" xml:space="preserve">Открыть в инструменте слияния </x:String>
<x:String x:Key="Text.Diff.VisualLines.All" xml:space="preserve">Показывать все линии</x:String>
<x:String x:Key="Text.Diff.VisualLines.Decr" xml:space="preserve">Уменьшить количество видимых линий</x:String>

View file

@ -124,7 +124,6 @@
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">查找变更...</x:String>
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">文件列表</x:String>
<x:String x:Key="Text.CommitDetail.Files.LFS" xml:space="preserve">LFS文件</x:String>
<x:String x:Key="Text.CommitDetail.Files.Search" xml:space="preserve">查找文件...</x:String>
<x:String x:Key="Text.CommitDetail.Files.Submodule" xml:space="preserve">子模块</x:String>
<x:String x:Key="Text.CommitDetail.Info" xml:space="preserve">基本信息</x:String>
<x:String x:Key="Text.CommitDetail.Info.Author" xml:space="preserve">修改者</x:String>
@ -250,7 +249,6 @@
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">交换比对双方</x:String>
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">语法高亮</x:String>
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">自动换行</x:String>
<x:String x:Key="Text.Diff.UseBlockNavigation" xml:space="preserve">启用基于变更块的跳转</x:String>
<x:String x:Key="Text.Diff.UseMerger" xml:space="preserve">使用外部合并工具查看</x:String>
<x:String x:Key="Text.Diff.VisualLines.All" xml:space="preserve">显示完整文件</x:String>
<x:String x:Key="Text.Diff.VisualLines.Decr" xml:space="preserve">减少可见的行数</x:String>

View file

@ -124,7 +124,6 @@
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">搜尋變更...</x:String>
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">檔案列表</x:String>
<x:String x:Key="Text.CommitDetail.Files.LFS" xml:space="preserve">LFS 檔案</x:String>
<x:String x:Key="Text.CommitDetail.Files.Search" xml:space="preserve">搜尋檔案...</x:String>
<x:String x:Key="Text.CommitDetail.Files.Submodule" xml:space="preserve">子模組</x:String>
<x:String x:Key="Text.CommitDetail.Info" xml:space="preserve">基本資訊</x:String>
<x:String x:Key="Text.CommitDetail.Info.Author" xml:space="preserve">作者</x:String>
@ -250,7 +249,6 @@
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">交換比對雙方</x:String>
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">語法上色</x:String>
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">自動換行</x:String>
<x:String x:Key="Text.Diff.UseBlockNavigation" xml:space="preserve">啟用基於變更區塊的導航</x:String>
<x:String x:Key="Text.Diff.UseMerger" xml:space="preserve">使用外部合併工具檢視</x:String>
<x:String x:Key="Text.Diff.VisualLines.All" xml:space="preserve">顯示檔案的全部內容</x:String>
<x:String x:Key="Text.Diff.VisualLines.Decr" xml:space="preserve">減少可見的行數</x:String>

View file

@ -856,7 +856,12 @@
</Border.Effect>
</Border>
<Border BorderThickness="0" Margin="8,4" MaxHeight="400">
<Border BorderThickness="0"
Margin="8,4"
MaxWidth="{DynamicResource FlyoutThemeMaxWidth}"
MinHeight="{DynamicResource MenuFlyoutThemeMinHeight}"
HorizontalAlignment="Stretch"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer Theme="{StaticResource FluentMenuScrollViewer}">
<ItemsPresenter Name="PART_ItemsPresenter"
Margin="{DynamicResource MenuFlyoutScrollerMargin}"

View file

@ -1,124 +0,0 @@
using System.Collections.Generic;
using Avalonia.Collections;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
public class BlockNavigation : ObservableObject
{
public class Block
{
public int Start { get; set; } = 0;
public int End { get; set; } = 0;
public Block(int start, int end)
{
Start = start;
End = end;
}
public bool IsInRange(int line)
{
return line >= Start && line <= End;
}
}
public AvaloniaList<Block> Blocks
{
get;
} = [];
public int Current
{
get => _current;
private set => SetProperty(ref _current, value);
}
public string Indicator
{
get
{
if (Blocks.Count == 0)
return "-/-";
if (_current >= 0 && _current < Blocks.Count)
return $"{_current + 1}/{Blocks.Count}";
return $"-/{Blocks.Count}";
}
}
public BlockNavigation(object context)
{
Blocks.Clear();
Current = -1;
var lines = new List<Models.TextDiffLine>();
if (context is Models.TextDiff combined)
lines = combined.Lines;
else if (context is TwoSideTextDiff twoSide)
lines = twoSide.Old;
if (lines.Count == 0)
return;
var lineIdx = 0;
var blockStartIdx = 0;
var isNewBlock = true;
var blocks = new List<Block>();
foreach (var line in lines)
{
lineIdx++;
if (line.Type == Models.TextDiffLineType.Added ||
line.Type == Models.TextDiffLineType.Deleted ||
line.Type == Models.TextDiffLineType.None)
{
if (isNewBlock)
{
isNewBlock = false;
blockStartIdx = lineIdx;
}
}
else
{
if (!isNewBlock)
{
blocks.Add(new Block(blockStartIdx, lineIdx - 1));
isNewBlock = true;
}
}
}
if (!isNewBlock)
blocks.Add(new Block(blockStartIdx, lines.Count - 1));
Blocks.AddRange(blocks);
}
public Block GetCurrentBlock()
{
return (_current >= 0 && _current < Blocks.Count) ? Blocks[_current] : null;
}
public Block GotoNext()
{
if (Blocks.Count == 0)
return null;
Current = (_current + 1) % Blocks.Count;
return Blocks[_current];
}
public Block GotoPrev()
{
if (Blocks.Count == 0)
return null;
Current = _current == -1 ? Blocks.Count - 1 : (_current - 1 + Blocks.Count) % Blocks.Count;
return Blocks[_current];
}
private int _current = -1;
}
}

View file

@ -82,7 +82,7 @@ namespace SourceGit.ViewModels
{
get;
private set;
} = [];
} = new AvaloniaList<string>();
public string SearchChangeFilter
{
@ -106,71 +106,13 @@ namespace SourceGit.ViewModels
{
get;
private set;
} = [];
} = new AvaloniaList<Models.CommitLink>();
public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
{
get => _repo.Settings?.IssueTrackerRules;
}
public string RevisionFileSearchFilter
{
get => _revisionFileSearchFilter;
set
{
if (SetProperty(ref _revisionFileSearchFilter, value))
{
RevisionFileSearchSuggestion.Clear();
if (!string.IsNullOrEmpty(value))
{
if (_revisionFiles.Count == 0)
{
var sha = Commit.SHA;
Task.Run(() =>
{
var files = new Commands.QueryRevisionFileNames(_repo.FullPath, sha).Result();
Dispatcher.UIThread.Invoke(() =>
{
if (sha == Commit.SHA)
{
_revisionFiles.Clear();
_revisionFiles.AddRange(files);
if (!string.IsNullOrEmpty(_revisionFileSearchFilter))
UpdateRevisionFileSearchSuggestion();
}
});
});
}
else
{
UpdateRevisionFileSearchSuggestion();
}
}
else
{
IsRevisionFileSearchSuggestionOpen = false;
GC.Collect();
}
}
}
}
public AvaloniaList<string> RevisionFileSearchSuggestion
{
get;
private set;
} = [];
public bool IsRevisionFileSearchSuggestionOpen
{
get => _isRevisionFileSearchSuggestionOpen;
set => SetProperty(ref _isRevisionFileSearchSuggestionOpen, value);
}
public CommitDetail(Repository repo)
{
_repo = repo;
@ -205,23 +147,17 @@ namespace SourceGit.ViewModels
{
_repo = null;
_commit = null;
if (_changes != null)
_changes.Clear();
if (_visibleChanges != null)
_visibleChanges.Clear();
if (_selectedChanges != null)
_selectedChanges.Clear();
_signInfo = null;
_searchChangeFilter = null;
_diffContext = null;
_viewRevisionFileContent = null;
_cancelToken = null;
WebLinks.Clear();
_revisionFiles.Clear();
RevisionFileSearchSuggestion.Clear();
}
public void NavigateTo(string commitSHA)
@ -239,11 +175,6 @@ namespace SourceGit.ViewModels
SearchChangeFilter = string.Empty;
}
public void ClearRevisionFileSearchFilter()
{
RevisionFileSearchFilter = string.Empty;
}
public Models.Commit GetParent(string sha)
{
return new Commands.QuerySingleCommit(_repo.FullPath, sha).Result();
@ -612,8 +543,6 @@ namespace SourceGit.ViewModels
private void Refresh()
{
_changes = null;
_revisionFiles.Clear();
FullMessage = string.Empty;
SignInfo = null;
Changes = [];
@ -621,10 +550,6 @@ namespace SourceGit.ViewModels
SelectedChanges = null;
ViewRevisionFileContent = null;
Children.Clear();
RevisionFileSearchFilter = string.Empty;
IsRevisionFileSearchSuggestionOpen = false;
GC.Collect();
if (_commit == null)
return;
@ -791,24 +716,6 @@ namespace SourceGit.ViewModels
menu.Items.Add(new MenuItem() { Header = "-" });
}
private void UpdateRevisionFileSearchSuggestion()
{
var suggestion = new List<string>();
foreach (var file in _revisionFiles)
{
if (file.Contains(_revisionFileSearchFilter, StringComparison.OrdinalIgnoreCase) &&
file.Length != _revisionFileSearchFilter.Length)
suggestion.Add(file);
if (suggestion.Count >= 100)
break;
}
RevisionFileSearchSuggestion.Clear();
RevisionFileSearchSuggestion.AddRange(suggestion);
IsRevisionFileSearchSuggestionOpen = suggestion.Count > 0;
}
[GeneratedRegex(@"^version https://git-lfs.github.com/spec/v\d+\r?\noid sha256:([0-9a-f]+)\r?\nsize (\d+)[\r\n]*$")]
private static partial Regex REG_LFS_FORMAT();
@ -829,8 +736,5 @@ namespace SourceGit.ViewModels
private DiffContext _diffContext = null;
private object _viewRevisionFileContent = null;
private Commands.Command.CancelToken _cancelToken = null;
private List<string> _revisionFiles = [];
private string _revisionFileSearchFilter = string.Empty;
private bool _isRevisionFileSearchSuggestionOpen = false;
}
}

View file

@ -206,12 +206,6 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _useFullTextDiff, value);
}
public bool UseBlockNavigationInDiffView
{
get => _useBlockNavigationInDiffView;
set => SetProperty(ref _useBlockNavigationInDiffView, value);
}
public Models.ChangeViewMode UnstagedChangeViewMode
{
get => _unstagedChangeViewMode;
@ -620,7 +614,6 @@ namespace SourceGit.ViewModels
private bool _enableDiffViewWordWrap = false;
private bool _showHiddenSymbolsInDiffView = false;
private bool _useFullTextDiff = false;
private bool _useBlockNavigationInDiffView = false;
private Models.ChangeViewMode _unstagedChangeViewMode = Models.ChangeViewMode.List;
private Models.ChangeViewMode _stagedChangeViewMode = Models.ChangeViewMode.List;

View file

@ -427,12 +427,12 @@ namespace SourceGit.ViewModels
{
// Ignore
}
_autoFetchTimer.Dispose();
_autoFetchTimer = null;
_settings = null;
_historiesFilterMode = Models.FilterMode.None;
_autoFetchTimer.Dispose();
_autoFetchTimer = null;
_watcher?.Dispose();
_histories.Cleanup();
_workingCopy.Cleanup();
@ -2147,7 +2147,7 @@ namespace SourceGit.ViewModels
{
Task.Run(() =>
{
var files = new Commands.QueryRevisionFileNames(_fullpath, "HEAD").Result();
var files = new Commands.QueryCurrentRevisionFiles(_fullpath).Result();
Dispatcher.UIThread.Invoke(() =>
{
if (_searchCommitFilterType != 3)

View file

@ -16,18 +16,6 @@
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
<Path Width="14" Height="14" Margin="8,0" Data="{StaticResource Icons.Branch}"/>
<TextBlock Text="{Binding Target.FriendlyName}"/>
<Border Height="18"
Margin="8,0,0,0"
Padding="8,0"
VerticalAlignment="Center"
CornerRadius="9"
Background="{DynamicResource Brush.Badge}"
IsVisible="{Binding Target.TrackStatus.IsVisible}">
<TextBlock Foreground="{DynamicResource Brush.BadgeFG}"
FontFamily="{DynamicResource Fonts.Monospace}"
FontSize="10"
Text="{Binding Target.TrackStatus}"/>
</Border>
</StackPanel>
<Border Grid.Row="1" Grid.Column="1" Height="32" IsVisible="{Binding !Target.IsLocal}">

View file

@ -42,22 +42,9 @@
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Branch">
<Grid Height="26" ColumnDefinitions="22,*,Auto">
<Grid Height="26" ColumnDefinitions="22,*">
<Path Grid.Column="0" Width="10" Height="10" Margin="4,0,8,0" Data="{StaticResource Icons.Branch}" />
<TextBlock Grid.Column="1" Text="{Binding FriendlyName}" Classes="primary" />
<Border Grid.Column="2"
Height="18"
Margin="8,0"
Padding="8,0"
VerticalAlignment="Center"
CornerRadius="9"
Background="{DynamicResource Brush.Badge}"
IsVisible="{Binding TrackStatus.IsVisible}">
<TextBlock Foreground="{DynamicResource Brush.BadgeFG}"
FontFamily="{DynamicResource Fonts.Monospace}"
FontSize="10"
Text="{Binding TrackStatus}"/>
</Border>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>

View file

@ -42,17 +42,6 @@
<Path Width="12" Height="12" Stretch="Uniform" Margin="0,6,0,0" Data="{StaticResource Icons.Up}"/>
</Button>
<Border>
<Border.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="IsTextDiff"/>
<Binding Source="{x:Static vm:Preference.Instance}" Path="UseBlockNavigationInDiffView" Mode="OneWay"/>
</MultiBinding>
</Border.IsVisible>
<TextBlock x:Name="BlockNavigationIndicator" Classes="primary" Margin="0,0,0,0" FontSize="11" Text="-/-"/>
</Border>
<Button Classes="icon_button"
Width="28"
Click="OnGotoNextChange"
@ -61,14 +50,6 @@
<Path Width="12" Height="12" Stretch="Uniform" Margin="0,6,0,0" Data="{StaticResource Icons.Down}"/>
</Button>
<ToggleButton Classes="line_path"
Width="28"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseBlockNavigationInDiffView, Mode=TwoWay}"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.UseBlockNavigation}">
<Path Width="13" Height="13" Data="{StaticResource Icons.CodeBlock}" Margin="0,3,0,0"/>
</ToggleButton>
<Button Classes="icon_button"
Width="28"
Command="{Binding IncrUnified}"
@ -260,8 +241,7 @@
<DataTemplate DataType="m:TextDiff">
<v:TextDiffView
UseSideBySideDiff="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=OneWay}"
UseBlockNavigation="{Binding Source={x:Static vm:Preference.Instance}, Path=UseBlockNavigationInDiffView, Mode=OneWay}"
BlockNavigationIndicator="{Binding #BlockNavigationIndicator.Text, Mode=OneWayToSource}"/>
UseFullTextDiff="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFullTextDiff, Mode=OneWay}"/>
</DataTemplate>
<!-- Empty or only EOL changes -->

View file

@ -13,15 +13,27 @@ namespace SourceGit.Views
private void OnGotoPrevChange(object _, RoutedEventArgs e)
{
var textDiff = this.FindDescendantOfType<TextDiffView>();
textDiff?.GotoPrevChange();
var textDiff = this.FindDescendantOfType<ThemedTextDiffPresenter>();
if (textDiff == null)
return;
textDiff.GotoPrevChange();
if (textDiff is SingleSideTextDiffPresenter presenter)
presenter.ForceSyncScrollOffset();
e.Handled = true;
}
private void OnGotoNextChange(object _, RoutedEventArgs e)
{
var textDiff = this.FindDescendantOfType<TextDiffView>();
textDiff?.GotoNextChange();
var textDiff = this.FindDescendantOfType<ThemedTextDiffPresenter>();
if (textDiff == null)
return;
textDiff.GotoNextChange();
if (textDiff is SingleSideTextDiffPresenter presenter)
presenter.ForceSyncScrollOffset();
e.Handled = true;
}
}

View file

@ -430,43 +430,31 @@ namespace SourceGit.Views
if (ShowAsDateTime)
return DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss");
var now = DateTime.Now;
var today = DateTime.Today;
var localTime = DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime();
var span = now - localTime;
if (span.TotalMinutes < 1)
return App.Text("Period.JustNow");
if (span.TotalHours < 1)
return App.Text("Period.MinutesAgo", (int)span.TotalMinutes);
if (span.TotalDays < 1)
return App.Text("Period.HoursAgo", (int)span.TotalHours);
var lastDay = now.AddDays(-1).Date;
if (localTime >= lastDay)
return App.Text("Period.Yesterday");
if ((localTime.Year == now.Year && localTime.Month == now.Month) || span.TotalDays < 28)
if (localTime >= today)
{
var diffDay = now.Date - localTime.Date;
return App.Text("Period.DaysAgo", (int)diffDay.TotalDays);
var now = DateTime.Now;
var timespan = now - localTime;
if (timespan.TotalHours > 1)
return App.Text("Period.HoursAgo", (int)timespan.TotalHours);
return timespan.TotalMinutes < 1 ? App.Text("Period.JustNow") : App.Text("Period.MinutesAgo", (int)timespan.TotalMinutes);
}
var lastMonth = now.AddMonths(-1).Date;
if (localTime.Year == lastMonth.Year && localTime.Month == lastMonth.Month)
return App.Text("Period.LastMonth");
if (localTime.Year == now.Year || localTime > now.AddMonths(-11))
var diffYear = today.Year - localTime.Year;
if (diffYear == 0)
{
var diffMonth = (12 + now.Month - localTime.Month) % 12;
return App.Text("Period.MonthsAgo", diffMonth);
var diffMonth = today.Month - localTime.Month;
if (diffMonth > 0)
return diffMonth == 1 ? App.Text("Period.LastMonth") : App.Text("Period.MonthsAgo", diffMonth);
var diffDay = today.Day - localTime.Day;
return diffDay == 1 ? App.Text("Period.Yesterday") : App.Text("Period.DaysAgo", diffDay);
}
var diffYear = now.Year - localTime.Year;
if (diffYear == 1)
return App.Text("Period.LastYear");
return App.Text("Period.YearsAgo", diffYear);
return diffYear == 1 ? App.Text("Period.LastYear") : App.Text("Period.YearsAgo", diffYear);
}
private IDisposable _refreshTimer = null;

View file

@ -1,3 +1,5 @@
using System;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;

View file

@ -144,68 +144,6 @@ namespace SourceGit.Views
InitializeComponent();
}
public void SetSearchResult(string file)
{
_rows.Clear();
_searchResult.Clear();
var rows = new List<ViewModels.RevisionFileTreeNode>();
if (string.IsNullOrEmpty(file))
{
MakeRows(rows, _tree, 0);
}
else
{
var vm = DataContext as ViewModels.CommitDetail;
if (vm == null || vm.Commit == null)
return;
var objects = vm.GetRevisionFilesUnderFolder(file);
if (objects == null || objects.Count != 1)
return;
var routes = file.Split('/', StringSplitOptions.None);
if (routes.Length == 1)
{
_searchResult.Add(new ViewModels.RevisionFileTreeNode
{
Backend = objects[0]
});
}
else
{
var last = _searchResult;
var prefix = string.Empty;
for (var i = 0; i < routes.Length - 1; i++)
{
var folder = new ViewModels.RevisionFileTreeNode
{
Backend = new Models.Object
{
Type = Models.ObjectType.Tree,
Path = prefix + routes[i],
},
IsExpanded = true,
};
last.Add(folder);
last = folder.Children;
prefix = folder.Backend + "/";
}
last.Add(new ViewModels.RevisionFileTreeNode
{
Backend = objects[0]
});
}
MakeRows(rows, _searchResult, 0);
}
_rows.AddRange(rows);
GC.Collect();
}
public void ToggleNodeIsExpanded(ViewModels.RevisionFileTreeNode node)
{
_disableSelectionChangingEvent = true;
@ -251,7 +189,6 @@ namespace SourceGit.Views
{
_tree.Clear();
_rows.Clear();
_searchResult.Clear();
var vm = DataContext as ViewModels.CommitDetail;
if (vm == null || vm.Commit == null)
@ -371,6 +308,5 @@ namespace SourceGit.Views
private List<ViewModels.RevisionFileTreeNode> _tree = [];
private AvaloniaList<ViewModels.RevisionFileTreeNode> _rows = [];
private bool _disableSelectionChangingEvent = false;
private List<ViewModels.RevisionFileTreeNode> _searchResult = [];
}
}

View file

@ -4,7 +4,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
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">
@ -15,96 +14,17 @@
<ColumnDefinition Width="*" MinWidth="100"/>
</Grid.ColumnDefinitions>
<!-- Left -->
<Grid Grid.Column="0" RowDefinitions="26,*">
<Grid Grid.Row="0" Height="26">
<TextBox Grid.Row="0"
x:Name="TxtSearchRevisionFiles"
Height="26"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
Background="Transparent"
CornerRadius="4"
Watermark="{DynamicResource Text.CommitDetail.Files.Search}"
Text="{Binding RevisionFileSearchFilter, Mode=TwoWay}"
KeyDown="OnSearchBoxKeyDown"
TextChanged="OnSearchBoxTextChanged">
<TextBox.InnerLeftContent>
<Path Width="14" Height="14" Margin="4,0,0,0" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Search}"/>
</TextBox.InnerLeftContent>
<TextBox.InnerRightContent>
<Button Classes="icon_button"
IsVisible="{Binding RevisionFileSearchFilter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
Command="{Binding ClearRevisionFileSearchFilter}">
<Path Width="14" Height="14" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Clear}"/>
</Button>
</TextBox.InnerRightContent>
</TextBox>
<Popup PlacementTarget="{Binding #TxtSearchRevisionFiles}"
Placement="BottomEdgeAlignedLeft"
HorizontalOffset="-8" VerticalAlignment="-8"
IsOpen="{Binding IsRevisionFileSearchSuggestionOpen}">
<Border Margin="8" VerticalAlignment="Top" Effect="drop-shadow(0 0 8 #80000000)">
<Border Background="{DynamicResource Brush.Popup}" CornerRadius="4" Padding="4" BorderThickness="0.65" BorderBrush="{DynamicResource Brush.Accent}">
<ListBox x:Name="SearchSuggestionBox"
Background="Transparent"
SelectionMode="Single"
ItemsSource="{Binding RevisionFileSearchSuggestion}"
MaxHeight="400"
Focusable="True"
KeyDown="OnSearchSuggestionBoxKeyDown">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="MinHeight" Value="26"/>
<Setter Property="CornerRadius" Value="4"/>
</Style>
<Style Selector="ListBox">
<Setter Property="FocusAdorner">
<FocusAdornerTemplate>
<Grid/>
</FocusAdornerTemplate>
</Setter>
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="x:String">
<StackPanel Background="Transparent" Orientation="Vertical" Margin="8,4" DoubleTapped="OnSearchSuggestionDoubleTapped">
<StackPanel Orientation="Horizontal">
<Path Width="12" Height="12" Data="{StaticResource Icons.File}"/>
<TextBlock Classes="primary" Margin="6,0,0,0" Text="{Binding Converter={x:Static c:PathConverters.PureFileName}}"/>
</StackPanel>
<TextBlock Classes="primary" FontSize="12" Margin="18,2,0,0" Foreground="{DynamicResource Brush.FG2}" Text="{Binding Converter={x:Static c:PathConverters.PureDirectoryName}}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
</Border>
</Popup>
</Grid>
<!-- File Tree -->
<Border Grid.Row="1" Margin="0,4,0,0" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" Background="{DynamicResource Brush.Contents}">
<v:RevisionFileTreeView x:Name="FileTree" Revision="{Binding Commit.SHA}"/>
</Border>
</Grid>
<!-- File Tree -->
<Border Grid.Column="0" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" Background="{DynamicResource Brush.Contents}">
<v:RevisionFileTreeView Revision="{Binding Commit.SHA}"/>
</Border>
<GridSplitter Grid.Column="1"
MinWidth="1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="Transparent"/>
<!-- Right: File Content Viewer -->
<!-- File Content Viewer -->
<Grid Grid.Column="2">
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}">
<v:RevisionFileContentViewer Content="{Binding ViewRevisionFileContent}"/>

View file

@ -3,7 +3,6 @@ using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
@ -119,81 +118,5 @@ namespace SourceGit.Views
{
InitializeComponent();
}
private void OnSearchBoxKeyDown(object _, KeyEventArgs e)
{
var vm = DataContext as ViewModels.CommitDetail;
if (vm == null)
return;
if (e.Key == Key.Enter)
{
FileTree.SetSearchResult(vm.RevisionFileSearchFilter);
e.Handled = true;
}
else if (e.Key == Key.Down || e.Key == Key.Up)
{
if (vm.IsRevisionFileSearchSuggestionOpen)
{
SearchSuggestionBox.Focus(NavigationMethod.Tab);
SearchSuggestionBox.SelectedIndex = 0;
}
e.Handled = true;
}
else if (e.Key == Key.Escape)
{
if (vm.IsRevisionFileSearchSuggestionOpen)
{
vm.RevisionFileSearchSuggestion.Clear();
vm.IsRevisionFileSearchSuggestionOpen = false;
}
e.Handled = true;
}
}
private void OnSearchBoxTextChanged(object _, TextChangedEventArgs e)
{
if (string.IsNullOrEmpty(TxtSearchRevisionFiles.Text))
FileTree.SetSearchResult(null);
}
private void OnSearchSuggestionBoxKeyDown(object _, KeyEventArgs e)
{
var vm = DataContext as ViewModels.CommitDetail;
if (vm == null)
return;
if (e.Key == Key.Escape)
{
vm.RevisionFileSearchSuggestion.Clear();
e.Handled = true;
}
else if (e.Key == Key.Enter && SearchSuggestionBox.SelectedItem is string content)
{
vm.RevisionFileSearchFilter = content;
TxtSearchRevisionFiles.CaretIndex = content.Length;
FileTree.SetSearchResult(vm.RevisionFileSearchFilter);
e.Handled = true;
}
}
private void OnSearchSuggestionDoubleTapped(object sender, TappedEventArgs e)
{
var vm = DataContext as ViewModels.CommitDetail;
if (vm == null)
return;
var content = (sender as StackPanel)?.DataContext as string;
if (!string.IsNullOrEmpty(content))
{
vm.RevisionFileSearchFilter = content;
TxtSearchRevisionFiles.CaretIndex = content.Length;
FileTree.SetSearchResult(vm.RevisionFileSearchFilter);
}
e.Handled = true;
}
}
}

View file

@ -31,8 +31,7 @@
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"
BlockNavigation="{Binding #ThisControl.BlockNavigation, Mode=TwoWay}"/>
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
<Rectangle Grid.Column="1" Fill="{DynamicResource Brush.Border2}" Width="1" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
@ -63,8 +62,7 @@
WordWrap="False"
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"
BlockNavigation="{Binding #ThisControl.BlockNavigation, Mode=TwoWay}"/>
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
<Rectangle Grid.Column="1" Fill="{DynamicResource Brush.Border2}" Width="1" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
@ -85,8 +83,7 @@
WordWrap="False"
ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"
BlockNavigation="{Binding #ThisControl.BlockNavigation, Mode=TwoWay}"/>
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/>
<Rectangle Grid.Column="3" Fill="{DynamicResource Brush.Border2}" Width="1" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>

View file

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Text;
@ -255,10 +254,6 @@ namespace SourceGit.Views
if (_presenter.Document == null || !textView.VisualLinesValid)
return;
var changeBlock = _presenter.BlockNavigation?.GetCurrentBlock();
Brush changeBlockBG = new SolidColorBrush(Colors.Gray, 0.25);
Pen changeBlockFG = new Pen(Brushes.Gray);
var lines = _presenter.GetLines();
var width = textView.Bounds.Width;
foreach (var line in textView.VisualLines)
@ -271,61 +266,50 @@ namespace SourceGit.Views
break;
var info = lines[index - 1];
var bg = GetBrushByLineType(info.Type);
if (bg == null)
continue;
var startY = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.LineTop) - textView.VerticalOffset;
var endY = line.GetTextLineVisualYPosition(line.TextLines[^1], VisualYPosition.LineBottom) - textView.VerticalOffset;
drawingContext.DrawRectangle(bg, null, new Rect(0, startY, width, endY - startY));
var bg = GetBrushByLineType(info.Type);
if (bg != null)
if (info.Highlights.Count > 0)
{
drawingContext.DrawRectangle(bg, null, new Rect(0, startY, width, endY - startY));
var highlightBG = info.Type == Models.TextDiffLineType.Added ? _presenter.AddedHighlightBrush : _presenter.DeletedHighlightBrush;
var processingIdxStart = 0;
var processingIdxEnd = 0;
var nextHightlight = 0;
if (info.Highlights.Count > 0)
foreach (var tl in line.TextLines)
{
var highlightBG = info.Type == Models.TextDiffLineType.Added ? _presenter.AddedHighlightBrush : _presenter.DeletedHighlightBrush;
var processingIdxStart = 0;
var processingIdxEnd = 0;
var nextHighlight = 0;
processingIdxEnd += tl.Length;
foreach (var tl in line.TextLines)
var y = line.GetTextLineVisualYPosition(tl, VisualYPosition.LineTop) - textView.VerticalOffset;
var h = line.GetTextLineVisualYPosition(tl, VisualYPosition.LineBottom) - textView.VerticalOffset - y;
while (nextHightlight < info.Highlights.Count)
{
processingIdxEnd += tl.Length;
var highlight = info.Highlights[nextHightlight];
if (highlight.Start >= processingIdxEnd)
break;
var y = line.GetTextLineVisualYPosition(tl, VisualYPosition.LineTop) - textView.VerticalOffset;
var h = line.GetTextLineVisualYPosition(tl, VisualYPosition.LineBottom) - textView.VerticalOffset - y;
var start = line.GetVisualColumn(highlight.Start < processingIdxStart ? processingIdxStart : highlight.Start);
var end = line.GetVisualColumn(highlight.End >= processingIdxEnd ? processingIdxEnd : highlight.End + 1);
while (nextHighlight < info.Highlights.Count)
{
var highlight = info.Highlights[nextHighlight];
if (highlight.Start >= processingIdxEnd)
break;
var x = line.GetTextLineVisualXPosition(tl, start) - textView.HorizontalOffset;
var w = line.GetTextLineVisualXPosition(tl, end) - textView.HorizontalOffset - x;
var rect = new Rect(x, y, w, h);
drawingContext.DrawRectangle(highlightBG, null, rect);
var start = line.GetVisualColumn(highlight.Start < processingIdxStart ? processingIdxStart : highlight.Start);
var end = line.GetVisualColumn(highlight.End >= processingIdxEnd ? processingIdxEnd : highlight.End + 1);
if (highlight.End >= processingIdxEnd)
break;
var x = line.GetTextLineVisualXPosition(tl, start) - textView.HorizontalOffset;
var w = line.GetTextLineVisualXPosition(tl, end) - textView.HorizontalOffset - x;
var rect = new Rect(x, y, w, h);
drawingContext.DrawRectangle(highlightBG, null, rect);
if (highlight.End >= processingIdxEnd)
break;
nextHighlight++;
}
processingIdxStart = processingIdxEnd;
nextHightlight++;
}
}
}
if (changeBlock != null && changeBlock.IsInRange(index))
{
drawingContext.DrawRectangle(changeBlockBG, null, new Rect(0, startY, width, endY - startY));
if (index == changeBlock.Start)
drawingContext.DrawLine(changeBlockFG, new Point(0, startY), new Point(width, startY));
if (index == changeBlock.End)
drawingContext.DrawLine(changeBlockFG, new Point(0, endY), new Point(width, endY));
processingIdxStart = processingIdxEnd;
}
}
}
}
@ -502,15 +486,6 @@ namespace SourceGit.Views
set => SetValue(DisplayRangeProperty, value);
}
public static readonly StyledProperty<ViewModels.BlockNavigation> BlockNavigationProperty =
AvaloniaProperty.Register<ThemedTextDiffPresenter, ViewModels.BlockNavigation>(nameof(BlockNavigation));
public ViewModels.BlockNavigation BlockNavigation
{
get => GetValue(BlockNavigationProperty);
set => SetValue(BlockNavigationProperty, value);
}
protected override Type StyleKeyOverride => typeof(TextEditor);
public ThemedTextDiffPresenter(TextArea area, TextDocument doc) : base(area, doc)
@ -545,19 +520,6 @@ namespace SourceGit.Views
public void GotoPrevChange()
{
var blockNavigation = BlockNavigation;
if (blockNavigation != null)
{
var prev = blockNavigation.GotoPrev();
if (prev != null)
{
TextArea.Caret.Line = prev.Start;
ScrollToLine(prev.Start);
}
return;
}
var firstLineIdx = DisplayRange.StartIdx;
if (firstLineIdx <= 1)
return;
@ -601,19 +563,6 @@ namespace SourceGit.Views
public void GotoNextChange()
{
var blockNavigation = BlockNavigation;
if (blockNavigation != null)
{
var next = blockNavigation.GotoNext();
if (next != null)
{
TextArea.Caret.Line = next.Start;
ScrollToLine(next.Start);
}
return;
}
var lines = GetLines();
var lastLineIdx = DisplayRange.EndIdx;
if (lastLineIdx >= lines.Count - 1)
@ -716,22 +665,6 @@ namespace SourceGit.Views
{
InvalidateVisual();
}
else if (change.Property == BlockNavigationProperty)
{
var oldValue = change.OldValue as ViewModels.BlockNavigation;
var newValue = change.NewValue as ViewModels.BlockNavigation;
if (oldValue != null)
oldValue.PropertyChanged -= OnBlockNavigationPropertyChanged;
if (newValue != null)
newValue.PropertyChanged += OnBlockNavigationPropertyChanged;
InvalidateVisual();
}
}
private void OnBlockNavigationPropertyChanged(object _1, PropertyChangedEventArgs _2)
{
TextArea.TextView.Redraw();
}
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
@ -1156,8 +1089,6 @@ namespace SourceGit.Views
public void ForceSyncScrollOffset()
{
if (_scrollViewer == null)
return;
if (DataContext is ViewModels.TwoSideTextDiff diff)
diff.SyncScrollOffset = _scrollViewer?.Offset ?? Vector.Zero;
}
@ -1513,6 +1444,15 @@ namespace SourceGit.Views
set => SetValue(UseSideBySideDiffProperty, value);
}
public static readonly StyledProperty<bool> UseFullTextDiffProperty =
AvaloniaProperty.Register<TextDiffView, bool>(nameof(UseFullTextDiff));
public bool UseFullTextDiff
{
get => GetValue(UseFullTextDiffProperty);
set => SetValue(UseFullTextDiffProperty, value);
}
public static readonly StyledProperty<TextDiffViewChunk> SelectedChunkProperty =
AvaloniaProperty.Register<TextDiffView, TextDiffViewChunk>(nameof(SelectedChunk));
@ -1540,33 +1480,6 @@ namespace SourceGit.Views
set => SetValue(EnableChunkSelectionProperty, value);
}
public static readonly StyledProperty<bool> UseBlockNavigationProperty =
AvaloniaProperty.Register<TextDiffView, bool>(nameof(UseBlockNavigation));
public bool UseBlockNavigation
{
get => GetValue(UseBlockNavigationProperty);
set => SetValue(UseBlockNavigationProperty, value);
}
public static readonly StyledProperty<ViewModels.BlockNavigation> BlockNavigationProperty =
AvaloniaProperty.Register<TextDiffView, ViewModels.BlockNavigation>(nameof(BlockNavigation));
public ViewModels.BlockNavigation BlockNavigation
{
get => GetValue(BlockNavigationProperty);
set => SetValue(BlockNavigationProperty, value);
}
public static readonly StyledProperty<string> BlockNavigationIndicatorProperty =
AvaloniaProperty.Register<TextDiffView, string>(nameof(BlockNavigationIndicator));
public string BlockNavigationIndicator
{
get => GetValue(BlockNavigationIndicatorProperty);
set => SetValue(BlockNavigationIndicatorProperty, value);
}
static TextDiffView()
{
UseSideBySideDiffProperty.Changed.AddClassHandler<TextDiffView>((v, _) =>
@ -1574,7 +1487,7 @@ namespace SourceGit.Views
v.RefreshContent(v.DataContext as Models.TextDiff, false);
});
UseBlockNavigationProperty.Changed.AddClassHandler<TextDiffView>((v, _) =>
UseFullTextDiffProperty.Changed.AddClassHandler<TextDiffView>((v, _) =>
{
v.RefreshContent(v.DataContext as Models.TextDiff, false);
});
@ -1600,32 +1513,6 @@ namespace SourceGit.Views
InitializeComponent();
}
public void GotoPrevChange()
{
var presenter = this.FindDescendantOfType<ThemedTextDiffPresenter>();
if (presenter == null)
return;
presenter.GotoPrevChange();
if (presenter is SingleSideTextDiffPresenter singleSide)
singleSide.ForceSyncScrollOffset();
BlockNavigationIndicator = BlockNavigation?.Indicator ?? string.Empty;
}
public void GotoNextChange()
{
var presenter = this.FindDescendantOfType<ThemedTextDiffPresenter>();
if (presenter == null)
return;
presenter.GotoNextChange();
if (presenter is SingleSideTextDiffPresenter singleSide)
singleSide.ForceSyncScrollOffset();
BlockNavigationIndicator = BlockNavigation?.Indicator ?? string.Empty;
}
protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);
@ -1664,17 +1551,6 @@ namespace SourceGit.Views
Editor.Content = diff;
}
if (UseBlockNavigation)
{
BlockNavigation = new ViewModels.BlockNavigation(Editor.Content);
BlockNavigationIndicator = BlockNavigation.Indicator;
}
else
{
BlockNavigation = null;
BlockNavigationIndicator = "-/-";
}
IsUnstagedChange = diff.Option.IsUnstaged;
EnableChunkSelection = diff.Option.WorkingCopyChange != null;
}

View file

@ -239,6 +239,7 @@
Margin="8,0,0,0"
HorizontalAlignment="Left"
IsChecked="{Binding UseAmend, Mode=TwoWay}"
IsVisible="{Binding InProgressContext, Converter={x:Static ObjectConverters.IsNull}}"
Content="{DynamicResource Text.WorkingCopy.Amend}"/>
<v:LoadingIcon Grid.Column="5" Width="18" Height="18" IsVisible="{Binding IsCommitting}"/>