diff --git a/src/Models/Commit.cs b/src/Models/Commit.cs index de299ed6b..ded142053 100644 --- a/src/Models/Commit.cs +++ b/src/Models/Commit.cs @@ -37,6 +37,7 @@ public bool IsHighlightedInGraph public bool IsCommitterVisible => !Author.Equals(Committer) || AuthorTime != CommitterTime; public bool IsCurrentHead => Decorators.Find(x => x.Type is DecoratorType.CurrentBranchHead or DecoratorType.CurrentCommitHead) != null; public bool HasDecorators => Decorators.Count > 0; + public virtual bool IsLocalChanges => false; public string FirstParentToCompare => Parents.Count > 0 ? $"{SHA}^" : EmptyTreeHash.Guess(SHA); public string GetFriendlyName() diff --git a/src/Models/CommitGraph.cs b/src/Models/CommitGraph.cs index 916a79b1b..c8b359325 100644 --- a/src/Models/CommitGraph.cs +++ b/src/Models/CommitGraph.cs @@ -41,6 +41,7 @@ public class Path(int color, bool isHighlighted) public List Points { get; } = []; public int Color { get; } = color; public bool IsHighlighted { get; } = isHighlighted; + public bool IsDashed { get; set; } = false; } public class Link @@ -57,6 +58,7 @@ public enum DotType Default, Head, Merge, + LocalChanges, } public class Dot @@ -110,6 +112,13 @@ public static CommitGraph Generate(List commits, bool firstParentOnlyEna { major.Next = commit.Parents[0]; major.Goto(offsetX, offsetY, halfHeight); + + // The link from local changes to HEAD is dashed, but the rest of this branch is not. + if (major.Path.IsDashed) + { + major.Detach(); + temp.Paths.Add(major.Path); + } } else { @@ -185,6 +194,7 @@ public static CommitGraph Generate(List commits, bool firstParentOnlyEna if (commit.Parents.Count > 0) { major = new PathHelper(commit.Parents[0], isHighlighted, colorPicker.Next(), new Point(offsetX, offsetY)); + major.Path.IsDashed = commit.IsLocalChanges; unsolved.Add(major); temp.Paths.Add(major.Path); } @@ -199,7 +209,9 @@ public static CommitGraph Generate(List commits, bool firstParentOnlyEna var position = new Point(major?.LastX ?? offsetX, offsetY); var dotColor = major?.Path.Color ?? 0; var anchor = new Dot() { Center = position, Color = dotColor, IsHighlighted = isHighlighted }; - if (commit.IsCurrentHead) + if (commit.IsLocalChanges) + anchor.Type = DotType.LocalChanges; + else if (commit.IsCurrentHead) anchor.Type = DotType.Head; else if (commit.Parents.Count > 1) anchor.Type = DotType.Merge; @@ -406,6 +418,20 @@ public void Highlight() _endY = 0; } + /// + /// End the current path and continue with a new one (with the same color and highlighted state) from the end. + /// + public void Detach() + { + var color = Path.Color; + var isHighlighted = Path.IsHighlighted; + Add(LastX, _lastY); + + Path = new Path(color, isHighlighted); + Path.Points.Add(new Point(LastX, _lastY)); + _endY = 0; + } + private void Add(double x, double y) { if (_endY < y) diff --git a/src/Models/LocalChangesNode.cs b/src/Models/LocalChangesNode.cs new file mode 100644 index 000000000..c63c2d9a6 --- /dev/null +++ b/src/Models/LocalChangesNode.cs @@ -0,0 +1,34 @@ +namespace SourceGit.Models +{ + /// + /// Pseudo commit used to display local changes as a node (not yet attached) in the commit graph. + /// + public class LocalChangesNode : Commit + { + public const string NodeSHA = "LOCALCHANGES0000000000000000000000000000"; + + public override bool IsLocalChanges => true; + + public int Count + { + get => _count; + set + { + if (SetProperty(ref _count, value)) + { + // The localized label is provided by view (so it follows locale changes), subject only holds the count. + Subject = $"({value})"; + OnPropertyChanged(nameof(Subject)); + } + } + } + + public LocalChangesNode() + { + SHA = NodeSHA; + IsMerged = true; + } + + private int _count = 0; + } +} diff --git a/src/Resources/Locales/ca_ES.axaml b/src/Resources/Locales/ca_ES.axaml index a37a7709d..23840a220 100644 --- a/src/Resources/Locales/ca_ES.axaml +++ b/src/Resources/Locales/ca_ES.axaml @@ -530,6 +530,8 @@ Branca actual i comissions seleccionades Només les comissions seleccionades Comissions seleccionades (només el primer pare) + Canvis locals + Obre a la pàgina de canvis locals {0} COMISSIONS SELECCIONADES MOSTRA LES COLUMNES Mantingueu premuda «Ctrl» o «Maj» per seleccionar diverses comissions. @@ -852,6 +854,7 @@ Només comissions decorades Només el primer pare MOSTRA ELS INDICADORS + Canvis locals com a node del gràfic Mostra les comissions perdudes Mostra els submòduls com a arbre Mostra les etiquetes com a arbre diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index 9c59fd3de..0cf29d34f 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -511,6 +511,8 @@ $1, $2, … Werte der Eingabe-Steuerelemente Nur aktueller Branch Aktueller Branch & ausgewählte Commits Nur ausgewählte Commits + Lokale Änderungen + Auf der Seite Änderungen öffnen {0} COMMITS AUSGEWÄHLT SPALTEN ANZEIGEN Halte ‚Strg‘ oder ‚Umschalt‘, um mehrere Commits auszuwählen. @@ -821,6 +823,7 @@ $1, $2, … Werte der Eingabe-Steuerelemente Nur dekorierte Commits Nur ersten Vorgänger anzeigen ANZEIGE-FLAGS + Lokale Änderungen als Knoten im Graph Verlorene Commits anzeigen Zeige Submodule als Baumstruktur Zeige Tags als Baumstruktur diff --git a/src/Resources/Locales/el_GR.axaml b/src/Resources/Locales/el_GR.axaml index 22cb8b4c7..9eaacc378 100644 --- a/src/Resources/Locales/el_GR.axaml +++ b/src/Resources/Locales/el_GR.axaml @@ -511,6 +511,8 @@ Μόνο ο τρέχων κλάδος Τρέχων κλάδος & επιλεγμένα commits Μόνο τα επιλεγμένα commits + Τοπικές αλλαγές + Άνοιγμα στη σελίδα τοπικών αλλαγών ΕΠΙΛΕΓΜΕΝΑ {0} COMMITS ΕΜΦΑΝΙΣΗ ΣΤΗΛΩΝ Κρατήστε 'Ctrl' ή 'Shift' για να επιλέξετε πολλαπλά commits. @@ -817,6 +819,7 @@ Μόνο commits με αναφορές Μόνο πρώτος γονέας ΕΜΦΑΝΙΣΗ ΣΗΜΑΙΩΝ + Τοπικές αλλαγές ως κόμβος στο γράφημα Εμφάνιση χαμένων commits Εμφάνιση υπομονάδων ως δέντρο Εμφάνιση ετικετών ως δέντρο diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 1b1f29d8f..8c5c8278e 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -533,6 +533,8 @@ Current Branch & Selected Commits Selected Commits Only Selected Commits (First-parent Only) + Local changes + Open in Local Changes page SELECTED {0} COMMITS SHOW COLUMNS Hold 'Ctrl' or 'Shift' to select multiple commits. @@ -855,6 +857,7 @@ Decorated commits only First-parent only SHOW FLAGS + Local changes as graph node Show lost commits Show Submodules as Tree Show Tags as Tree diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index 8bbe163bc..cd0a17dd1 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -530,6 +530,8 @@ Rama Actual y los Commits Seleccionados Solo los Commits Seleccionados Commits seleccionados (Solamente el primer padre) + Cambios locales + Abrir en la página de cambios {0} COMMITS SELECCIONADOS MOSTRAR COLUMNAS Mantén 'Ctrl' o 'Shift' para seleccionar múltiples commits. @@ -851,6 +853,7 @@ Sólo los commits decorados Mostrar sólo el primer padre MOSTRAR FLAGS + Cambios locales como nodo del gráfico Mostrar commits perdidos Mostrar Submódulos como Árbol Mostrar Etiquetas como Árbol diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index 6b7bacef1..fb8e0234a 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -484,6 +484,8 @@ Branche courante uniquement Branche courante et commits sélectionnés Commits sélectionnés uniquement + Changements locaux + Ouvrir dans la page Changements {0} COMMITS SÉLECTIONNÉS AFFICHER LES COLONNES Maintenir 'Ctrl' ou 'Shift' enfoncée pour sélectionner plusieurs commits. @@ -781,6 +783,7 @@ Commits décorés uniquement Premier parent uniquement AFFICHER LES FLAGS + Changements locaux comme nœud du graphe Afficher les commits perdus Afficher les sous-modules en tant qu'arbre Voir les Tags en tant qu'arbre diff --git a/src/Resources/Locales/he_IL.axaml b/src/Resources/Locales/he_IL.axaml index 153f55ef7..400dc0b7b 100644 --- a/src/Resources/Locales/he_IL.axaml +++ b/src/Resources/Locales/he_IL.axaml @@ -484,6 +484,8 @@ ה־Branch הנוכחי בלבד ה־Branch הנוכחי ו־Commits שנבחרו Commits שנבחרו בלבד + שינויים מקומיים + פתח בעמוד השינויים המקומיים נבחרו {0} COMMITS הצג עמודות החזק 'Ctrl' או 'Shift' לבחירת מספר commits. @@ -781,6 +783,7 @@ Commits מעוטרים בלבד First-parent בלבד הצג דגלים + שינויים מקומיים כצומת בגרף הצג commits אבודים הצג Submodules כעץ הצג Tags כעץ diff --git a/src/Resources/Locales/id_ID.axaml b/src/Resources/Locales/id_ID.axaml index d8eda31ee..f3430b651 100644 --- a/src/Resources/Locales/id_ID.axaml +++ b/src/Resources/Locales/id_ID.axaml @@ -511,6 +511,8 @@ Hanya Branch Saat Ini Branch Saat Ini & Commit Terpilih Hanya Commit Terpilih + Perubahan lokal + Buka di halaman Perubahan Lokal DIPILIH {0} COMMIT TAMPILKAN KOLOM Tahan 'Ctrl' atau 'Shift' untuk memilih beberapa commit. @@ -822,6 +824,7 @@ Hanya commit yang didekorasi Hanya first-parent TAMPILKAN FLAG + Perubahan lokal sebagai node grafik Tampilkan commit yang hilang Tampilkan Submodule sebagai Pohon Tampilkan Tag sebagai Pohon diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index eee191ced..f742e574c 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -452,6 +452,8 @@ ${pure_files:N} Come ${files:N}, ma senza cartelle ORA COMMIT GRAFICO E OGGETTO SHA + Modifiche locali + Apri nella pagina Modifiche locali {0} COMMIT SELEZIONATI Tieni premuto 'Ctrl' o 'Shift' per selezionare più commit. Tieni premuto ⌘ o ⇧ per selezionare più commit. @@ -726,6 +728,7 @@ ${pure_files:N} Come ${files:N}, ma senza cartelle Solo commit decorati Solo primo genitore MOSTRA FLAG + Modifiche locali come nodo del grafico Mostra commit persi Mostra i Sottomoduli Come Albero Mostra Tag come Albero diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml index fdef11c27..5d93b9b88 100644 --- a/src/Resources/Locales/ja_JP.axaml +++ b/src/Resources/Locales/ja_JP.axaml @@ -520,6 +520,8 @@ 現在のブランチ & 選択したコミット 選択したコミットのみ 選択したコミットかつ最初の親コミットのみ + ローカルの変更 + ローカルの変更ページで開く {0} コミットを選択しました 表示する列 'Ctrl' または 'Shift' キーを押しながらで、複数のコミットを選択できます。 @@ -841,6 +843,7 @@ 参照付きのコミットのみ 最初の親コミットのみ 表示フラグ + ローカルの変更をグラフのノードとして表示 消失したコミットを表示 サブモジュールをツリー形式で表示 タグをツリー形式で表示 diff --git a/src/Resources/Locales/ko_KR.axaml b/src/Resources/Locales/ko_KR.axaml index e3dda7a43..6d8cf9d92 100644 --- a/src/Resources/Locales/ko_KR.axaml +++ b/src/Resources/Locales/ko_KR.axaml @@ -483,6 +483,8 @@ 현재 브랜치만 현재 브랜치와 선택한 커밋 선택한 커밋만 + 로컬 변경 사항 + 로컬 변경 사항 페이지에서 열기 {0}개 커밋 선택됨 표시할 역 'Ctrl' 또는 'Shift' 키를 누른 채로 여러 커밋을 선택하세요. @@ -789,6 +791,7 @@ 장식된(Decorated) 커밋만 첫 번째 부모만 플래그 표시 + 로컬 변경 사항을 그래프 노드로 표시 유실된(Lost) 커밋 표시 서브모듈을 트리로 표시 태그를 트리로 표시 diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index 5084f0180..65a4455d4 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -327,6 +327,8 @@ HORA DO COMMIT GRÁFICO & ASSUNTO SHA + Alterações locais + Abrir na página de alterações SELECIONADO {0} COMMITS Segure 'Ctrl' ou 'Shift' para selecionar múltiplos commits. Segure ⌘ ou ⇧ para selecionar múltiplos commits. @@ -517,6 +519,7 @@ Mensagem SHA Branch Atual + Alterações locais como nó do gráfico Exibir Tags como Árvore Estatísticas SUBMÓDULOS diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index 1c06deabe..998074ebe 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -530,6 +530,8 @@ Текущая ветка и выбранные ревизии Только выбранные ревизии Выбранные ревизии (Только первый родитель) + Локальные изменения + Открыть на странице изменений ВЫБРАНО РЕВИЗИЙ: {0} ПОКАЗЫВАТЬ КОЛОНКИ Удерживайте Ctrl или Shift, чтобы выбрать несколько ревизий. @@ -851,6 +853,7 @@ Только оформленные ревизии Показывать только первый родительский ПОКАЗЫВАТЬ ФЛАГИ + Локальные изменения как узел графа Показывать потерянные ревизии Показывать подмодули как дерево Показывать метки как каталог diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml index 3473ff1ca..10db66d9a 100644 --- a/src/Resources/Locales/ta_IN.axaml +++ b/src/Resources/Locales/ta_IN.axaml @@ -312,6 +312,8 @@ உறுதிமொழி நேரம் வரைபடம் & பொருள் பாகொவ + உள்ளக மாற்றங்கள் + உள்ளக மாற்றங்கள் பக்கத்தில் திற தேர்ந்தெடுக்கப்பட்ட {0} உறுதிமொழிகள் பல உறுதிமொழிகளைத் தேர்ந்தெடுக்க 'கட்டுப்பாடு' அல்லது 'உயர்த்து'ஐ அழுத்திப் பிடி. பல உறுதிமொழிகளைத் தேர்ந்தெடுக்க ⌘ அல்லது ⇧ ஐ அழுத்திப் பிடி. @@ -522,6 +524,7 @@ செய்தி பாகொவ தற்போதைய கிளை + உள்ளக மாற்றங்களை வரைபட முனையாகக் காட்டு குறிச்சொற்களை மரமாகக் காட்டு தவிர் புள்ளிவிவரங்கள் diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml index 5f44193e3..eedfa81f0 100644 --- a/src/Resources/Locales/uk_UA.axaml +++ b/src/Resources/Locales/uk_UA.axaml @@ -316,6 +316,8 @@ ЧАС КОМІТУ ГРАФ ТА ТЕМА SHA + Локальні зміни + Відкрити на сторінці локальних змін ВИБРАНО {0} КОМІТІВ Утримуйте 'Ctrl' або 'Shift' для вибору кількох комітів. Утримуйте ⌘ або ⇧ для вибору кількох комітів. @@ -526,6 +528,7 @@ Повідомлення SHA Поточна гілка + Локальні зміни як вузол графа Показати теги як дерево ПРОПУСТИТИ Статистика diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 3716d725a..b044311c5 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -537,6 +537,8 @@ 当前分支和选中的提交 仅选中的提交 仅选中的提交 (First-parent 模式) + 本地更改 + 在本地更改页面中打开 已选中 {0} 项提交 显示列 可以按住 Ctrl 或 Shift 键选择多个提交 @@ -859,6 +861,7 @@ 仅显示分支、标签所引用的提交 仅显示合并提交中的第一个提交 显示内容 + 将本地更改显示为图中的节点 显示丢失引用的提交 以树型结构展示 以树型结构展示 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 92bfffb3e..451972a1d 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -530,6 +530,8 @@ 目前分支和選取的提交 僅選取的提交 僅選取的提交 (First-parent 模式) + 本機變更 + 在本機變更頁面中開啟 已選取 {0} 項提交 顯示欄位 可以按住 Ctrl 或 Shift 鍵選擇多個提交 @@ -852,6 +854,7 @@ 只顯示分支和標籤引用的提交 只顯示合併提交的第一父提交 顯示內容 + 將本機變更顯示為圖表中的節點 顯示失去參照的提交 以樹狀結構顯示 以樹狀結構顯示 diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index 128b53ff9..b7a0c633d 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -102,11 +102,25 @@ public bool IsCommitTimeColumnVisible } } + public bool ShowLocalChanges + { + get => Preferences.Instance.ShowLocalChangesInGraph; + set + { + if (Preferences.Instance.ShowLocalChangesInGraph != value) + { + Preferences.Instance.ShowLocalChangesInGraph = value; + RefreshLocalChangesNode(); + } + } + } + public List Commits { get => _commits; set { + value = ApplyLocalChangesNode(value); GenerateGraph(value); if (SetProperty(ref _commits, value)) PostCommitsChanged(); @@ -294,6 +308,13 @@ public Models.BisectState UpdateBisectInfo() return Models.BisectState.WaitingForMark; } + public void RefreshLocalChangesNode() + { + var commits = ApplyLocalChangesNode(_commits); + if (commits != _commits) + Commits = commits; + } + public void NavigateTo(string commitSHA) { var commit = _commits.Find(x => x.SHA.StartsWith(commitSHA, StringComparison.Ordinal)); @@ -491,6 +512,12 @@ public void CompareWithWorktree(Models.Commit commit) private void PostCommitsChanged() { + if (_followHeadAfterLocalChangesRemoved) + { + SelectCurrentHead(false); + return; + } + if (_selectedCommits.Count == 0) return; @@ -516,11 +543,54 @@ private void PostCommitsChanged() } } + // Local changes node has gone (committed, stashed or discarded), select current HEAD instead. + if (selected.Count == 0 && _selectedCommits is [{ IsLocalChanges: true }]) + { + SelectCurrentHead(true); + return; + } + SelectedCommits = selected; } + private void SelectCurrentHead(bool followHeadOnNextRefresh) + { + var head = _commits.Find(x => x.IsCurrentHead); + SelectedCommits = head != null ? [head] : []; + _followHeadAfterLocalChangesRemoved = followHeadOnNextRefresh; + } + + private List ApplyLocalChangesNode(List commits) + { + var count = _repo.LocalChangesCount; + var hasNode = commits.Count > 0 && commits[0].IsLocalChanges; + + Models.Commit head = null; + if (Preferences.Instance.ShowLocalChangesInGraph && count > 0 && !_repo.IsBare) + head = commits.Find(x => x.IsCurrentHead); + + _localChangesNode.Count = count; + + if (head == null) + return hasNode ? commits.GetRange(1, commits.Count - 1) : commits; + + if (hasNode && _localChangesNode.Parents[0].Equals(head.SHA, StringComparison.Ordinal)) + return commits; + + _localChangesNode.Parents = [head.SHA]; + + var list = new List(commits.Count + 1) { _localChangesNode }; + if (hasNode) + list.AddRange(commits.GetRange(1, commits.Count - 1)); + else + list.AddRange(commits); + return list; + } + private void PostSelectedCommitsChanged() { + _followHeadAfterLocalChangesRemoved = false; + if (_ignoreSelectionChange) return; @@ -529,6 +599,11 @@ private void PostSelectedCommitsChanged() _searchCommitContext.Selected = null; DetailContext = Models.Null.Instance; } + else if (_selectedCommits is [{ IsLocalChanges: true }]) + { + _searchCommitContext.Selected = null; + DetailContext = _repo.WorkingCopy; + } else if (_selectedCommits.Count == 1) { var c = _selectedCommits[0]; @@ -547,10 +622,19 @@ private void PostSelectedCommitsChanged() { _searchCommitContext.Selected = null; - if (_detailContext is RevisionCompare compare) + if (_selectedCommits[0].IsLocalChanges || _selectedCommits[1].IsLocalChanges) + { + var commit = _selectedCommits[0].IsLocalChanges ? _selectedCommits[1] : _selectedCommits[0]; + DetailContext = new RevisionCompare(_repo, commit, null); + } + else if (_detailContext is RevisionCompare compare) + { compare.SetTargets(_selectedCommits[1], _selectedCommits[0]); + } else + { DetailContext = new RevisionCompare(_repo, _selectedCommits[1], _selectedCommits[0]); + } } else { @@ -583,6 +667,8 @@ private void GenerateGraph(List commits) private CommitDetailSharedData _commitDetailSharedData = null; private bool _isLoading = true; private List _commits = []; + private Models.LocalChangesNode _localChangesNode = new(); + private bool _followHeadAfterLocalChangesRemoved = false; private Models.CommitGraph _graph = null; private List _selectedCommits = []; private Models.Bisect _bisect = null; diff --git a/src/ViewModels/Preferences.cs b/src/ViewModels/Preferences.cs index 4803ec429..c59865fe4 100644 --- a/src/ViewModels/Preferences.cs +++ b/src/ViewModels/Preferences.cs @@ -211,6 +211,12 @@ public bool UseCompactBranchNamesInGraph set => SetProperty(ref _useCompactBranchNamesInGraph, value); } + public bool ShowLocalChangesInGraph + { + get => _showLocalChangesInGraph; + set => SetProperty(ref _showLocalChangesInGraph, value); + } + public bool UseTwoColumnsLayoutInHistories { get => _useTwoColumnsLayoutInHistories; @@ -830,6 +836,7 @@ private bool RemoveInvalidRepositoriesRecursive(List collection) private string _ignoreUpdateTag = string.Empty; private bool _showTagsInGraph = true; + private bool _showLocalChangesInGraph = false; private bool _useTwoColumnsLayoutInHistories = false; private bool _displayTimeAsPeriodInHistories = false; private bool _useSideBySideDiff = false; diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 1ea5951a8..442ab41d1 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -1348,6 +1348,7 @@ public void RefreshWorkingCopyChanges() _workingCopy.SetData(changes); LocalChangesCount = changes.Count; + _histories?.RefreshLocalChangesNode(); OnPropertyChanged(nameof(InProgressContext)); GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasLocalChanges, changes.Count == 0); }); diff --git a/src/Views/CommitGraph.cs b/src/Views/CommitGraph.cs index 88a8217c6..bf37b81c1 100644 --- a/src/Views/CommitGraph.cs +++ b/src/Views/CommitGraph.cs @@ -108,6 +108,8 @@ private void DrawCurves(DrawingContext context, Models.CommitGraph graph, double var geo = new StreamGeometry(); var pen = line.IsHighlighted ? Models.CommitGraph.Pens[line.Color] : grayedPen; + if (line.IsDashed) + pen = new Pen(pen.Brush, pen.Thickness, s_dashStyle); using (var ctx = geo.Open()) { @@ -187,6 +189,9 @@ private void DrawAnchors(DrawingContext context, Models.CommitGraph graph, doubl context.DrawEllipse(dotFill, pen, center, 6, 6); context.DrawEllipse(pen.Brush, null, center, 3, 3); break; + case Models.CommitGraph.DotType.LocalChanges: + context.DrawEllipse(dotFill, new Pen(pen.Brush, pen.Thickness, s_dashStyle), center, 6, 6); + break; case Models.CommitGraph.DotType.Merge: context.DrawEllipse(pen.Brush, null, center, 6, 6); context.DrawLine(dotFillPen, new Point(center.X, center.Y - 3), new Point(center.X, center.Y + 3)); @@ -199,6 +204,8 @@ private void DrawAnchors(DrawingContext context, Models.CommitGraph graph, doubl } } + private static readonly DashStyle s_dashStyle = new DashStyle([2, 2], 0); + private Models.CommitGraph _graph = null; private Models.CommitGraphLayout _layout = null; } diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml index a3d24529f..3dd66f980 100644 --- a/src/Views/Histories.axaml +++ b/src/Views/Histories.axaml @@ -148,7 +148,17 @@ Subject="{Binding Subject}" IssueTrackers="{Binding $parent[v:Histories].IssueTrackers}" FontWeight="{Binding IsCurrentHead, Converter={x:Static c:BoolConverters.IsBoldToFontWeight}}" - Opacity="{Binding IsMerged, Converter={x:Static c:BoolConverters.IsMergedToOpacity}}"/> + Opacity="{Binding IsMerged, Converter={x:Static c:BoolConverters.IsMergedToOpacity}}" + IsVisible="{Binding !IsLocalChanges}"/> + + + + + @@ -162,7 +172,7 @@ - + - + - + - + + + + + diff --git a/src/Views/Histories.axaml.cs b/src/Views/Histories.axaml.cs index 846c59d1b..5c446acfc 100644 --- a/src/Views/Histories.axaml.cs +++ b/src/Views/Histories.axaml.cs @@ -234,7 +234,7 @@ protected override async void OnKeyDown(KeyEventArgs e) var builder = new StringBuilder(); foreach (var item in selected) { - if (item is Models.Commit commit) + if (item is Models.Commit { IsLocalChanges: false } commit) builder.Append(commit.SHA.AsSpan(0, 10)).Append(" - ").AppendLine(commit.Subject); } @@ -465,7 +465,10 @@ protected override void OnDataContextChanged(EventArgs e) base.OnDataContextChanged(e); if (DataContext is ViewModels.Histories vm) + { CommitListContainer.Columns[1].Width = new(vm.AuthorColumnWidth, DataGridLengthUnitType.Pixel); + vm.RefreshLocalChangesNode(); // `ShowLocalChangesInGraph` may have been changed in other repository. + } } private void OnCommitListHeaderPointerMoved(object sender, PointerEventArgs e) @@ -595,6 +598,16 @@ private void OnOpenAdvancedOptions(object sender, RoutedEventArgs e) ev.Handled = true; }; + var localChanges = new MenuItem(); + localChanges.Header = App.Text("Repository.ShowLocalChangesInGraph"); + if (histories.ShowLocalChanges) + localChanges.Icon = this.CreateMenuIcon("Icons.Check"); + localChanges.Click += (_, ev) => + { + histories.ShowLocalChanges = !histories.ShowLocalChanges; + ev.Handled = true; + }; + var order = new MenuItem(); order.Header = new TextBlock() { Text = App.Text("Repository.HistoriesOrder"), FontWeight = FontWeight.Bold }; order.IsEnabled = false; @@ -729,6 +742,7 @@ private void OnOpenAdvancedOptions(object sender, RoutedEventArgs e) menu.Items.Add(reflog); menu.Items.Add(firstParentOnly); menu.Items.Add(simplifyByDecoration); + menu.Items.Add(localChanges); menu.Items.Add(new MenuItem() { Header = "-" }); menu.Items.Add(order); menu.Items.Add(dateOrder); @@ -810,7 +824,15 @@ private void OnCommitListContextRequested(object sender, ContextRequestedEventAr commits.Add(c); } - if (selected.Count > 1) + if (commits.Find(x => x.IsLocalChanges) != null) + { + if (selected.Count == 1) + { + var menu = CreateContextMenuForLocalChanges(repo); + menu.Open(CommitListContainer); + } + } + else if (selected.Count > 1) { var menu = CreateContextMenuForMultipleCommits(repo, commits); menu.Open(CommitListContainer); @@ -832,6 +854,13 @@ private async void OnCommitListDoubleTapped(object sender, TappedEventArgs e) CommitListContainer.SelectedItems is { Count: 1 } && e.Source is Control { DataContext: Models.Commit c }) { + if (c.IsLocalChanges) + { + if (this.FindAncestorOfType() is { DataContext: ViewModels.Repository repo }) + repo.SelectedViewIndex = 1; + return; + } + if (histories.Bisect != null) { histories.CheckoutCommitDetached(c); @@ -889,6 +918,43 @@ private void OnOpenDetailsAsStandalone(object sender, RoutedEventArgs e) e.Handled = true; } + private ContextMenu CreateContextMenuForLocalChanges(ViewModels.Repository repo) + { + var stash = new MenuItem(); + stash.Header = App.Text("Stash.Title"); + stash.Icon = this.CreateMenuIcon("Icons.Stashes.Add"); + stash.Click += async (_, e) => + { + await repo.StashAllAsync(false); + e.Handled = true; + }; + + var discard = new MenuItem(); + discard.Header = App.Text("Repository.DiscardAll"); + discard.Icon = this.CreateMenuIcon("Icons.Undo"); + discard.Click += (_, e) => + { + repo.WorkingCopy.DiscardAllChanges(); + e.Handled = true; + }; + + var openPage = new MenuItem(); + openPage.Header = App.Text("Histories.LocalChanges.OpenPage"); + openPage.Icon = this.CreateMenuIcon("Icons.Changes"); + openPage.Click += (_, e) => + { + repo.SelectedViewIndex = 1; + e.Handled = true; + }; + + var menu = new ContextMenu(); + menu.Items.Add(stash); + menu.Items.Add(discard); + menu.Items.Add(new MenuItem() { Header = "-" }); + menu.Items.Add(openPage); + return menu; + } + private ContextMenu CreateContextMenuForMultipleCommits(ViewModels.Repository repo, List selected) { var canCherryPick = true;