diff --git a/VERSION b/VERSION index 8162fd55..9e16784b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.18 \ No newline at end of file +8.19 \ No newline at end of file diff --git a/src/App.JsonCodeGen.cs b/src/App.JsonCodeGen.cs index 61f00074..50d589a2 100644 --- a/src/App.JsonCodeGen.cs +++ b/src/App.JsonCodeGen.cs @@ -9,5 +9,6 @@ namespace SourceGit [JsonSerializable(typeof(List))] [JsonSerializable(typeof(Dictionary))] [JsonSerializable(typeof(ViewModels.Preference))] + [JsonSerializable(typeof(ViewModels.RepositorySettings))] internal partial class JsonCodeGen : JsonSerializerContext { } } diff --git a/src/App.axaml.cs b/src/App.axaml.cs index 0b319792..db0a4644 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -187,6 +187,18 @@ namespace SourceGit } } + public static async Task GetClipboardTextAsync() + { + if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + if (desktop.MainWindow.Clipboard is { } clipboard) + { + return await clipboard.GetTextAsync(); + } + } + return default; + } + public static string Text(string key, params object[] args) { var fmt = Current.FindResource($"Text.{key}") as string; @@ -259,6 +271,21 @@ namespace SourceGit }); } + public static ViewModels.Repository FindOpenedRepository(string repoPath) + { + if (Current is App app && app._launcher != null) + { + foreach (var page in app._launcher.Pages) + { + var id = page.Node.Id.Replace("\\", "/"); + if (id == repoPath && page.Data is ViewModels.Repository repo) + return repo; + } + } + + return null; + } + public static void Quit() { if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) @@ -288,9 +315,10 @@ namespace SourceGit _launcher = new ViewModels.Launcher(); desktop.MainWindow = new Views.Launcher() { DataContext = _launcher }; - if (ViewModels.Preference.Instance.ShouldCheck4UpdateOnStartup) + var pref = ViewModels.Preference.Instance; + if (pref.ShouldCheck4UpdateOnStartup) { - ViewModels.Preference.Save(); + pref.Save(); Check4Update(); } } @@ -317,18 +345,6 @@ namespace SourceGit }); } - public static async Task GetClipboardTextAsync() - { - if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { - if (desktop.MainWindow.Clipboard is { } clipboard) - { - return await clipboard.GetTextAsync(); - } - } - return default; - } - private ViewModels.Launcher _launcher = null; private ResourceDictionary _activeLocale = null; private ResourceDictionary _colorOverrides = null; diff --git a/src/Commands/IsLFSFiltered.cs b/src/Commands/IsLFSFiltered.cs index b29039de..2a7234bb 100644 --- a/src/Commands/IsLFSFiltered.cs +++ b/src/Commands/IsLFSFiltered.cs @@ -6,7 +6,15 @@ { WorkingDirectory = repo; Context = repo; - Args = $"check-attr -a -z \"{path}\""; + Args = $"check-attr -z filter \"{path}\""; + RaiseError = false; + } + + public IsLFSFiltered(string repo, string sha, string path) + { + WorkingDirectory = repo; + Context = repo; + Args = $"check-attr --source {sha} -z filter \"{path}\""; RaiseError = false; } diff --git a/src/Commands/QueryFileSize.cs b/src/Commands/QueryFileSize.cs index 5ce7641e..c36984dd 100644 --- a/src/Commands/QueryFileSize.cs +++ b/src/Commands/QueryFileSize.cs @@ -4,7 +4,6 @@ namespace SourceGit.Commands { public partial class QueryFileSize : Command { - [GeneratedRegex(@"^\d+\s+\w+\s+[0-9a-f]+\s+(\d+)\s+.*$")] private static partial Regex REG_FORMAT(); @@ -25,9 +24,7 @@ namespace SourceGit.Commands { var match = REG_FORMAT().Match(rs.StdOut); if (match.Success) - { return long.Parse(match.Groups[1].Value); - } } return 0; diff --git a/src/Commands/SaveRevisionFile.cs b/src/Commands/SaveRevisionFile.cs index 6c200940..99e89093 100644 --- a/src/Commands/SaveRevisionFile.cs +++ b/src/Commands/SaveRevisionFile.cs @@ -10,7 +10,7 @@ namespace SourceGit.Commands { public static void Run(string repo, string revision, string file, string saveTo) { - var isLFSFiltered = new IsLFSFiltered(repo, file).Result(); + var isLFSFiltered = new IsLFSFiltered(repo, revision, file).Result(); if (isLFSFiltered) { var tmpFile = saveTo + ".tmp"; diff --git a/src/ViewModels/Blame.cs b/src/ViewModels/Blame.cs index bef29219..79770c6f 100644 --- a/src/ViewModels/Blame.cs +++ b/src/ViewModels/Blame.cs @@ -49,9 +49,8 @@ namespace SourceGit.ViewModels public void NavigateToCommit(string commitSHA) { - var repo = Preference.FindRepository(_repo); - if (repo != null) - repo.NavigateToCommit(commitSHA); + var repo = App.FindOpenedRepository(_repo); + repo?.NavigateToCommit(commitSHA); } private readonly string _repo = string.Empty; diff --git a/src/ViewModels/BranchCompare.cs b/src/ViewModels/BranchCompare.cs index be133bd2..634d18a6 100644 --- a/src/ViewModels/BranchCompare.cs +++ b/src/ViewModels/BranchCompare.cs @@ -110,9 +110,8 @@ namespace SourceGit.ViewModels public void NavigateTo(string commitSHA) { - var repo = Preference.FindRepository(_repo); - if (repo != null) - repo.NavigateToCommit(commitSHA); + var repo = App.FindOpenedRepository(_repo); + repo?.NavigateToCommit(commitSHA); } public void ClearSearchFilter() diff --git a/src/ViewModels/Clone.cs b/src/ViewModels/Clone.cs index 89eff488..bd74b754 100644 --- a/src/ViewModels/Clone.cs +++ b/src/ViewModels/Clone.cs @@ -128,8 +128,8 @@ namespace SourceGit.ViewModels CallUIThread(() => { - var repo = Preference.AddRepository(path, Path.Combine(path, ".git")); - var node = Preference.FindOrAddNodeByRepositoryPath(repo.FullPath, null, true); + var normalizedPath = path.Replace("\\", "/"); + var node = Preference.FindOrAddNodeByRepositoryPath(normalizedPath, null, true); _launcher.OpenRepositoryInTab(node, _page); }); diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index 04fe8129..c401f20a 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Avalonia.Controls; @@ -12,7 +13,7 @@ using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels { - public class CommitDetail : ObservableObject + public partial class CommitDetail : ObservableObject { public DiffContext DiffContext { @@ -110,9 +111,8 @@ namespace SourceGit.ViewModels public void NavigateTo(string commitSHA) { - var repo = Preference.FindRepository(_repo); - if (repo != null) - repo.NavigateToCommit(commitSHA); + var repo = App.FindOpenedRepository(_repo); + repo?.NavigateToCommit(commitSHA); } public void ClearSearchChangeFilter() @@ -165,39 +165,26 @@ namespace SourceGit.ViewModels var contentStream = Commands.QueryFileContent.Run(_repo, _commit.SHA, file.Path); var content = new StreamReader(contentStream).ReadToEnd(); - if (content.StartsWith("version https://git-lfs.github.com/spec/", StringComparison.Ordinal)) + var matchLFS = REG_LFS_FORMAT().Match(content); + if (matchLFS.Success) { var obj = new Models.RevisionLFSObject() { Object = new Models.LFSObject() }; - var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries); - if (lines.Length == 3) - { - foreach (var line in lines) - { - if (line.StartsWith("oid sha256:", StringComparison.Ordinal)) - { - obj.Object.Oid = line.Substring(11); - } - else if (line.StartsWith("size ", StringComparison.Ordinal)) - { - obj.Object.Size = long.Parse(line.Substring(5)); - } - } - Dispatcher.UIThread.Invoke(() => - { - ViewRevisionFileContent = obj; - }); - return; - } - } + obj.Object.Oid = matchLFS.Groups[1].Value; + obj.Object.Size = long.Parse(matchLFS.Groups[2].Value); - Dispatcher.UIThread.Invoke(() => + Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = obj); + } + else { - ViewRevisionFileContent = new Models.RevisionTextFile() + Dispatcher.UIThread.Invoke(() => { - FileName = file.Path, - Content = content - }; - }); + ViewRevisionFileContent = new Models.RevisionTextFile() + { + FileName = file.Path, + Content = content + }; + }); + } }); break; case Models.ObjectType.Commit: @@ -332,6 +319,7 @@ namespace SourceGit.ViewModels var blame = new MenuItem(); blame.Header = App.Text("Blame"); blame.Icon = App.CreateMenuIcon("Icons.Blame"); + blame.IsEnabled = file.Type == Models.ObjectType.Blob; blame.Click += (o, ev) => { var window = new Views.Blame() { DataContext = new Blame(_repo, file.Path, _commit.SHA) }; @@ -465,6 +453,9 @@ namespace SourceGit.ViewModels } } + [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(); + private static readonly HashSet IMG_EXTS = new HashSet() { ".ico", ".bmp", ".jpg", ".png", ".jpeg" diff --git a/src/ViewModels/DiffContext.cs b/src/ViewModels/DiffContext.cs index cb84e54d..c3531ffc 100644 --- a/src/ViewModels/DiffContext.cs +++ b/src/ViewModels/DiffContext.cs @@ -111,27 +111,34 @@ namespace SourceGit.ViewModels if (latest.TextDiff != null) { - var repo = Preference.FindRepository(_repo); - if (repo != null && repo.Submodules.Contains(_option.Path)) + var count = latest.TextDiff.Lines.Count; + var isSubmodule = false; + if (count <= 3) { var submoduleDiff = new Models.SubmoduleDiff(); var submoduleRoot = $"{_repo}/{_option.Path}".Replace("\\", "/"); - foreach (var line in latest.TextDiff.Lines) + isSubmodule = true; + for (int i = 1; i < count; i++) { + var line = latest.TextDiff.Lines[i]; + if (!line.Content.StartsWith("Subproject commit ", StringComparison.Ordinal)) + { + isSubmodule = false; + break; + } + + var sha = line.Content.Substring(18); if (line.Type == Models.TextDiffLineType.Added) - { - var sha = line.Content.Substring("Subproject commit ".Length); submoduleDiff.New = QuerySubmoduleRevision(submoduleRoot, sha); - } else if (line.Type == Models.TextDiffLineType.Deleted) - { - var sha = line.Content.Substring("Subproject commit ".Length); submoduleDiff.Old = QuerySubmoduleRevision(submoduleRoot, sha); - } } - rs = submoduleDiff; + + if (isSubmodule) + rs = submoduleDiff; } - else + + if (!isSubmodule) { latest.TextDiff.File = _option.Path; rs = latest.TextDiff; diff --git a/src/ViewModels/Init.cs b/src/ViewModels/Init.cs index a4e27341..2e582ccc 100644 --- a/src/ViewModels/Init.cs +++ b/src/ViewModels/Init.cs @@ -1,5 +1,4 @@ -using System.IO; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace SourceGit.ViewModels { @@ -29,11 +28,10 @@ namespace SourceGit.ViewModels if (!succ) return false; - var gitDir = Path.GetFullPath(Path.Combine(_targetPath, ".git")); CallUIThread(() => { - var repo = Preference.AddRepository(_targetPath, gitDir); - Preference.FindOrAddNodeByRepositoryPath(repo.FullPath, _parentNode, true); + var normalizedPath = _targetPath.Replace("\\", "/"); + Preference.FindOrAddNodeByRepositoryPath(normalizedPath, _parentNode, true); }); return true; diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index 11f17d29..df5cf641 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -48,9 +48,8 @@ namespace SourceGit.ViewModels return; } - var gitDir = new Commands.QueryGitDir(root).Result(); - var repo = Preference.AddRepository(root, gitDir); - var node = Preference.FindOrAddNodeByRepositoryPath(repo.FullPath, null, false); + var normalized = root.Replace("\\", "/"); + var node = Preference.FindOrAddNodeByRepositoryPath(normalized, null, false); OpenRepositoryInTab(node, null); } else if (Preference.Instance.RestoreTabs) @@ -59,7 +58,15 @@ namespace SourceGit.ViewModels { var node = Preference.FindNode(id); if (node == null) - continue; + { + node = new RepositoryNode() + { + Id = id, + Name = Path.GetFileName(id), + Bookmark = 0, + IsRepository = true, + }; + } OpenRepositoryInTab(node, null); } @@ -72,19 +79,26 @@ namespace SourceGit.ViewModels public void Quit() { - Preference.Instance.OpenedTabs.Clear(); + var pref = Preference.Instance; + pref.OpenedTabs.Clear(); - if (Preference.Instance.RestoreTabs) + if (pref.RestoreTabs) { foreach (var page in Pages) { if (page.Node.IsRepository) - Preference.Instance.OpenedTabs.Add(page.Node.Id); + pref.OpenedTabs.Add(page.Node.Id); } } - Preference.Instance.LastActiveTabIdx = Pages.IndexOf(ActivePage); - Preference.Save(); + pref.LastActiveTabIdx = Pages.IndexOf(ActivePage); + pref.Save(); + + foreach (var page in Pages) + { + if (page.Data is Repository repo) + repo.Close(); + } } public void AddNewTab() @@ -211,14 +225,27 @@ namespace SourceGit.ViewModels } } - var repo = Preference.FindRepository(node.Id); - if (repo == null || !Path.Exists(repo.FullPath)) + if (!Path.Exists(node.Id)) { var ctx = page == null ? ActivePage.Node.Id : page.Node.Id; App.RaiseException(ctx, "Repository does NOT exists any more. Please remove it."); return; } + var gitDir = new Commands.QueryGitDir(node.Id).Result(); + if (string.IsNullOrEmpty(gitDir)) + { + var ctx = page == null ? ActivePage.Node.Id : page.Node.Id; + App.RaiseException(ctx, "Given path is not a valid git repository!"); + return; + } + + var repo = new Repository() + { + FullPath = node.Id, + GitDir = gitDir, + }; + repo.Open(); Commands.AutoFetch.AddRepository(repo.FullPath); diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index edcbc7e1..5198a8b8 100644 --- a/src/ViewModels/Preference.cs +++ b/src/ViewModels/Preference.cs @@ -37,23 +37,14 @@ namespace SourceGit.ViewModels } } - // It will cause some issue on Linux. See https://github.com/sourcegit-scm/sourcegit/issues/99 - // _instance.Repositories.RemoveAll(x => !Directory.Exists(x.FullPath)); - if (_instance.DefaultFont == null) - { _instance.DefaultFont = FontManager.Current.DefaultFontFamily; - } if (_instance.MonospaceFont == null) - { _instance.MonospaceFont = new FontFamily("fonts:SourceGit#JetBrains Mono"); - } if (!_instance.IsGitConfigured) - { _instance.GitInstallPath = Native.OS.FindGitExecutable(); - } return _instance; } @@ -274,9 +265,8 @@ namespace SourceGit.ViewModels set { if (value is null or < 1) - { return; - } + if (Commands.AutoFetch.Interval != value) { Commands.AutoFetch.Interval = (int)value; @@ -308,12 +298,6 @@ namespace SourceGit.ViewModels set => SetProperty(ref _externalMergeToolPath, value); } - public List Repositories - { - get; - set; - } = new List(); - public AvaloniaList RepositoryNodes { get => _repositoryNodes; @@ -366,20 +350,14 @@ namespace SourceGit.ViewModels list.Sort((l, r) => { if (l.IsRepository != r.IsRepository) - { return l.IsRepository ? 1 : -1; - } else - { return l.Name.CompareTo(r.Name); - } }); collection.Clear(); foreach (var one in list) - { collection.Add(one); - } } public static RepositoryNode FindNode(string id) @@ -451,39 +429,9 @@ namespace SourceGit.ViewModels container.Add(one); } - public static Repository FindRepository(string path) + public void Save() { - foreach (var repo in _instance.Repositories) - { - if (repo.FullPath == path) - return repo; - } - return null; - } - - public static Repository AddRepository(string rootDir, string gitDir) - { - var normalized = rootDir.Replace('\\', '/'); - var repo = FindRepository(normalized); - if (repo != null) - { - repo.GitDir = gitDir; - return repo; - } - - repo = new Repository() - { - FullPath = normalized, - GitDir = gitDir - }; - - _instance.Repositories.Add(repo); - return repo; - } - - public static void Save() - { - var data = JsonSerializer.Serialize(_instance, JsonCodeGen.Default.Preference); + var data = JsonSerializer.Serialize(this, JsonCodeGen.Default.Preference); File.WriteAllText(_savePath, data); } diff --git a/src/ViewModels/Pull.cs b/src/ViewModels/Pull.cs index 657f52a6..5a62f5b3 100644 --- a/src/ViewModels/Pull.cs +++ b/src/ViewModels/Pull.cs @@ -55,8 +55,8 @@ namespace SourceGit.ViewModels public bool UseRebase { - get => _repo.PreferRebaseInsteadOfMerge; - set => _repo.PreferRebaseInsteadOfMerge = value; + get => _repo.Settings.PreferRebaseInsteadOfMerge; + set => _repo.Settings.PreferRebaseInsteadOfMerge = value; } public Pull(Repository repo, Models.Branch specifiedRemoteBranch) diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 30e5710a..6ca97e15 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.IO; -using System.Text.Json.Serialization; +using System.Text.Json; using System.Threading.Tasks; using Avalonia.Collections; @@ -14,6 +14,45 @@ using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels { + public class RepositorySettings : ObservableObject + { + public bool PreferRebaseInsteadOfMerge + { + get; + set; + } = true; + + public AvaloniaList Filters + { + get; + set; + } = new AvaloniaList(); + + public AvaloniaList CommitMessages + { + get; + set; + } = new AvaloniaList(); + + public void PushCommitMessage(string message) + { + var existIdx = CommitMessages.IndexOf(message); + if (existIdx == 0) + return; + + if (existIdx > 0) + { + CommitMessages.Move(existIdx, 0); + return; + } + + if (CommitMessages.Count > 9) + CommitMessages.RemoveRange(9, CommitMessages.Count - 9); + + CommitMessages.Insert(0, message); + } + } + public class Repository : ObservableObject, Models.IRepository { public string FullPath @@ -39,25 +78,12 @@ namespace SourceGit.ViewModels set => SetProperty(ref _gitDir, value); } - public bool PreferRebaseInsteadOfMerge + public RepositorySettings Settings { - get; - set; - } = true; + get => _settings; + private set => SetProperty(ref _settings, value); + } - public AvaloniaList Filters - { - get; - set; - } = new AvaloniaList(); - - public AvaloniaList CommitMessages - { - get; - set; - } = new AvaloniaList(); - - [JsonIgnore] public int SelectedViewIndex { get => _selectedViewIndex; @@ -81,14 +107,12 @@ namespace SourceGit.ViewModels } } - [JsonIgnore] public object SelectedView { get => _selectedView; set => SetProperty(ref _selectedView, value); } - [JsonIgnore] public string SearchBranchFilter { get => _searchBranchFilter; @@ -104,75 +128,64 @@ namespace SourceGit.ViewModels } } - [JsonIgnore] public List Remotes { get => _remotes; private set => SetProperty(ref _remotes, value); } - [JsonIgnore] public List Branches { get => _branches; private set => SetProperty(ref _branches, value); } - [JsonIgnore] public List LocalBranchTrees { get => _localBranchTrees; private set => SetProperty(ref _localBranchTrees, value); } - [JsonIgnore] public List RemoteBranchTrees { get => _remoteBranchTrees; private set => SetProperty(ref _remoteBranchTrees, value); } - [JsonIgnore] public List Worktrees { get => _worktrees; private set => SetProperty(ref _worktrees, value); } - [JsonIgnore] public List Tags { get => _tags; private set => SetProperty(ref _tags, value); } - [JsonIgnore] public List VisibleTags { get => _visibleTags; private set => SetProperty(ref _visibleTags, value); } - [JsonIgnore] public List Submodules { get => _submodules; private set => SetProperty(ref _submodules, value); } - [JsonIgnore] public int WorkingCopyChangesCount { get => _workingCopy == null ? 0 : _workingCopy.Count; } - [JsonIgnore] public int StashesCount { get => _stashesPage == null ? 0 : _stashesPage.Stashes.Count; } - [JsonIgnore] public bool IncludeUntracked { get => _includeUntracked; @@ -183,7 +196,6 @@ namespace SourceGit.ViewModels } } - [JsonIgnore] public bool IsSearching { get => _isSearching; @@ -199,63 +211,54 @@ namespace SourceGit.ViewModels } } - [JsonIgnore] public int SearchCommitFilterType { get => _searchCommitFilterType; set => SetProperty(ref _searchCommitFilterType, value); } - [JsonIgnore] public string SearchCommitFilter { get => _searchCommitFilter; set => SetProperty(ref _searchCommitFilter, value); } - [JsonIgnore] public List SearchedCommits { get => _searchedCommits; set => SetProperty(ref _searchedCommits, value); } - [JsonIgnore] public bool IsTagGroupExpanded { get => _isTagGroupExpanded; set => SetProperty(ref _isTagGroupExpanded, value); } - [JsonIgnore] public bool IsSubmoduleGroupExpanded { get => _isSubmoduleGroupExpanded; set => SetProperty(ref _isSubmoduleGroupExpanded, value); } - [JsonIgnore] public bool IsWorktreeGroupExpanded { get => _isWorktreeGroupExpanded; set => SetProperty(ref _isWorktreeGroupExpanded, value); } - [JsonIgnore] public InProgressContext InProgressContext { get => _inProgressContext; private set => SetProperty(ref _inProgressContext, value); } - [JsonIgnore] public bool HasUnsolvedConflicts { get => _hasUnsolvedConflicts; private set => SetProperty(ref _hasUnsolvedConflicts, value); } - [JsonIgnore] public Models.Commit SearchResultSelectedCommit { get => _searchResultSelectedCommit; @@ -264,6 +267,16 @@ namespace SourceGit.ViewModels public void Open() { + var settingsFile = Path.Combine(_gitDir, "sourcegit.settings"); + try + { + _settings = JsonSerializer.Deserialize(File.ReadAllText(settingsFile), JsonCodeGen.Default.RepositorySettings); + } + catch + { + _settings = new RepositorySettings(); + } + _watcher = new Models.Watcher(this); _histories = new Histories(this); _workingCopy = new WorkingCopy(this); @@ -280,6 +293,10 @@ namespace SourceGit.ViewModels { SelectedView = 0.0; // Do NOT modify. Used to remove exists widgets for GC.Collect + var settingsSerialized = JsonSerializer.Serialize(_settings, JsonCodeGen.Default.RepositorySettings); + File.WriteAllText(Path.Combine(_gitDir, "sourcegit.settings"), settingsSerialized); + _settings = null; + _watcher.Dispose(); _histories.Cleanup(); _workingCopy.Cleanup(); @@ -436,7 +453,7 @@ namespace SourceGit.ViewModels public void ClearHistoriesFilter() { - Filters.Clear(); + _settings.Filters.Clear(); Task.Run(() => { @@ -525,15 +542,15 @@ namespace SourceGit.ViewModels var changed = false; if (toggle) { - if (!Filters.Contains(filter)) + if (!_settings.Filters.Contains(filter)) { - Filters.Add(filter); + _settings.Filters.Add(filter); changed = true; } } else { - changed = Filters.Remove(filter); + changed = _settings.Filters.Remove(filter); } if (changed) @@ -637,7 +654,7 @@ namespace SourceGit.ViewModels { var tags = new Commands.QueryTags(FullPath).Result(); foreach (var tag in tags) - tag.IsFiltered = Filters.Contains(tag.Name); + tag.IsFiltered = _settings.Filters.Contains(tag.Name); Dispatcher.UIThread.Invoke(() => { @@ -652,7 +669,7 @@ namespace SourceGit.ViewModels var limits = $"-{Preference.Instance.MaxHistoryCommits} "; var validFilters = new List(); - foreach (var filter in Filters) + foreach (var filter in _settings.Filters) { if (filter.StartsWith("refs/", StringComparison.Ordinal)) { @@ -670,12 +687,12 @@ namespace SourceGit.ViewModels { limits += string.Join(" ", validFilters); - if (Filters.Count != validFilters.Count) + if (_settings.Filters.Count != validFilters.Count) { Dispatcher.UIThread.Post(() => { - Filters.Clear(); - Filters.AddRange(validFilters); + _settings.Filters.Clear(); + _settings.Filters.AddRange(validFilters); }); } } @@ -851,22 +868,23 @@ namespace SourceGit.ViewModels public void OpenSubmodule(string submodule) { var root = Path.GetFullPath(Path.Combine(_fullpath, submodule)); - var gitDir = new Commands.QueryGitDir(root).Result(); - var repo = Preference.AddRepository(root, gitDir); + var normalizedPath = root.Replace("\\", "/"); - var node = new RepositoryNode() + var node = Preference.FindNode(normalizedPath); + if (node == null) { - Id = repo.FullPath, - Name = Path.GetFileName(repo.FullPath), - Bookmark = 0, - IsRepository = true, - }; + node = new RepositoryNode() + { + Id = normalizedPath, + Name = Path.GetFileName(normalizedPath), + Bookmark = 0, + IsRepository = true, + }; + } var launcher = App.GetTopLevel().DataContext as Launcher; if (launcher != null) - { launcher.OpenRepositoryInTab(node, null); - } } public void AddWorktree() @@ -883,16 +901,17 @@ namespace SourceGit.ViewModels public void OpenWorktree(Models.Worktree worktree) { - var gitDir = new Commands.QueryGitDir(worktree.FullPath).Result(); - var repo = Preference.AddRepository(worktree.FullPath, gitDir); - - var node = new RepositoryNode() + var node = Preference.FindNode(worktree.FullPath); + if (node == null) { - Id = repo.FullPath, - Name = Path.GetFileName(repo.FullPath), - Bookmark = 0, - IsRepository = true, - }; + node = new RepositoryNode() + { + Id = worktree.FullPath, + Name = Path.GetFileName(worktree.FullPath), + Bookmark = 0, + IsRepository = true, + }; + } var launcher = App.GetTopLevel().DataContext as Launcher; if (launcher != null) @@ -1814,7 +1833,7 @@ namespace SourceGit.ViewModels private BranchTreeNode.Builder BuildBranchTree(List branches, List remotes) { var builder = new BranchTreeNode.Builder(); - builder.SetFilters(Filters); + builder.SetFilters(_settings.Filters); if (string.IsNullOrEmpty(_searchBranchFilter)) { @@ -1858,6 +1877,7 @@ namespace SourceGit.ViewModels private string _fullpath = string.Empty; private string _gitDir = string.Empty; + private RepositorySettings _settings = null; private Models.Watcher _watcher = null; private Histories _histories = null; diff --git a/src/ViewModels/RevisionCompare.cs b/src/ViewModels/RevisionCompare.cs index 80a06757..2f288ab6 100644 --- a/src/ViewModels/RevisionCompare.cs +++ b/src/ViewModels/RevisionCompare.cs @@ -118,9 +118,8 @@ namespace SourceGit.ViewModels public void NavigateTo(string commitSHA) { - var repo = Preference.FindRepository(_repo); - if (repo != null) - repo.NavigateToCommit(commitSHA); + var repo = App.FindOpenedRepository(_repo); + repo?.NavigateToCommit(commitSHA); } public void ClearSearchFilter() diff --git a/src/ViewModels/Welcome.cs b/src/ViewModels/Welcome.cs index 415c56ee..bb5690a7 100644 --- a/src/ViewModels/Welcome.cs +++ b/src/ViewModels/Welcome.cs @@ -90,7 +90,6 @@ namespace SourceGit.ViewModels public ContextMenu CreateContextMenu(RepositoryNode node) { var menu = new ContextMenu(); - var hasRepo = Preference.FindRepository(node.Id) != null; if (!node.IsRepository && node.SubNodes.Count > 0) { @@ -115,7 +114,6 @@ namespace SourceGit.ViewModels var edit = new MenuItem(); edit.Header = App.Text("Welcome.Edit"); edit.Icon = App.CreateMenuIcon("Icons.Edit"); - edit.IsEnabled = !node.IsRepository || hasRepo; edit.Click += (_, e) => { node.Edit(); @@ -128,7 +126,6 @@ namespace SourceGit.ViewModels var explore = new MenuItem(); explore.Header = App.Text("Repository.Explore"); explore.Icon = App.CreateMenuIcon("Icons.Folder.Open"); - explore.IsEnabled = hasRepo; explore.Click += (_, e) => { node.OpenInFileManager(); @@ -139,7 +136,6 @@ namespace SourceGit.ViewModels var terminal = new MenuItem(); terminal.Header = App.Text("Repository.Terminal"); terminal.Icon = App.CreateMenuIcon("Icons.Terminal"); - terminal.IsEnabled = hasRepo; terminal.Click += (_, e) => { node.OpenTerminal(); diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 5d99da24..8b32240c 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -1113,7 +1113,7 @@ namespace SourceGit.ViewModels public ContextMenu CreateContextMenuForCommitMessages() { var menu = new ContextMenu(); - if (_repo.CommitMessages.Count == 0) + if (_repo.Settings.CommitMessages.Count == 0) { var empty = new MenuItem(); empty.Header = App.Text("WorkingCopy.NoCommitHistories"); @@ -1128,7 +1128,7 @@ namespace SourceGit.ViewModels menu.Items.Add(tip); menu.Items.Add(new MenuItem() { Header = "-" }); - foreach (var message in _repo.CommitMessages) + foreach (var message in _repo.Settings.CommitMessages) { var dump = message; @@ -1228,7 +1228,7 @@ namespace SourceGit.ViewModels return; } - PushCommitMessage(); + _repo.Settings.PushCommitMessage(_commitMessage); SetDetail(null); IsCommitting = true; @@ -1257,27 +1257,6 @@ namespace SourceGit.ViewModels }); } - private void PushCommitMessage() - { - var existIdx = _repo.CommitMessages.IndexOf(CommitMessage); - if (existIdx == 0) - { - return; - } - else if (existIdx > 0) - { - _repo.CommitMessages.Move(existIdx, 0); - return; - } - - if (_repo.CommitMessages.Count > 9) - { - _repo.CommitMessages.RemoveRange(9, _repo.CommitMessages.Count - 9); - } - - _repo.CommitMessages.Insert(0, CommitMessage); - } - private Repository _repo = null; private bool _isLoadingData = false; private bool _isStaging = false; diff --git a/src/Views/Blame.axaml.cs b/src/Views/Blame.axaml.cs index d4c2da28..1dacad12 100644 --- a/src/Views/Blame.axaml.cs +++ b/src/Views/Blame.axaml.cs @@ -378,11 +378,9 @@ namespace SourceGit.Views private void OnCommitSHAPointerPressed(object sender, PointerPressedEventArgs e) { - if (DataContext is ViewModels.Blame blame) - { - var txt = sender as TextBlock; + if (sender is TextBlock txt && DataContext is ViewModels.Blame blame) blame.NavigateToCommit(txt.Text); - } + e.Handled = true; } diff --git a/src/Views/LauncherTabBar.axaml.cs b/src/Views/LauncherTabBar.axaml.cs index e2618425..d9220b4d 100644 --- a/src/Views/LauncherTabBar.axaml.cs +++ b/src/Views/LauncherTabBar.axaml.cs @@ -47,13 +47,13 @@ namespace SourceGit.Views var selected = LauncherTabsList.ContainerFromIndex(selectedIdx); var activeStartX = selected.Bounds.X; var activeEndX = activeStartX + selected.Bounds.Width; - if (activeStartX > endX + 6 || activeEndX < startX - 6) + if (activeStartX > endX + 5 || activeEndX < startX - 5) return; var geo = new StreamGeometry(); var angle = Math.PI / 2; var x = 0.0; - var y = height + 0.5; + var y = height + 0.25; using (var ctx = geo.Open()) { var drawLeftX = activeStartX - startX + LauncherTabsScroller.Bounds.X; @@ -68,11 +68,11 @@ namespace SourceGit.Views } else { - x = drawLeftX - 6; + x = drawLeftX - 5; ctx.BeginFigure(new Point(x, y), true); x = drawLeftX; - y -= 6; - ctx.ArcTo(new Point(x, y), new Size(6.5, 6.5), angle, false, SweepDirection.CounterClockwise); + y -= 5; + ctx.ArcTo(new Point(x, y), new Size(5, 5), angle, false, SweepDirection.CounterClockwise); y = 6; ctx.LineTo(new Point(x, y)); x += 6; @@ -87,17 +87,17 @@ namespace SourceGit.Views x = drawRightX; y = 6; ctx.ArcTo(new Point(x, y), new Size(6, 6), angle, false, SweepDirection.Clockwise); - y = height - 6; + y = height + 0.25 - 5; ctx.LineTo(new Point(x, y)); - x += 6; - y = height + 0.5; - ctx.ArcTo(new Point(x, y), new Size(6.5, 6.5), angle, false, SweepDirection.CounterClockwise); + x += 5; + y = height + 0.25; + ctx.ArcTo(new Point(x, y), new Size(5, 5), angle, false, SweepDirection.CounterClockwise); } else { x = LauncherTabsScroller.Bounds.Right; ctx.LineTo(new Point(x, y)); - y = height + 0.5; + y = height + 0.25; ctx.LineTo(new Point(x, y)); } } diff --git a/src/Views/Repository.axaml b/src/Views/Repository.axaml index 6e7873e9..edbf9432 100644 --- a/src/Views/Repository.axaml +++ b/src/Views/Repository.axaml @@ -794,14 +794,14 @@ - + - + diff --git a/src/Views/RevisionFiles.axaml.cs b/src/Views/RevisionFiles.axaml.cs index 4b4fc449..954f0ecc 100644 --- a/src/Views/RevisionFiles.axaml.cs +++ b/src/Views/RevisionFiles.axaml.cs @@ -9,8 +9,6 @@ using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Interactivity; using Avalonia.Media; -using Avalonia.Media.Imaging; -using Avalonia.Styling; using AvaloniaEdit; using AvaloniaEdit.Document; diff --git a/src/Views/Welcome.axaml.cs b/src/Views/Welcome.axaml.cs index aa5054c4..0fb89989 100644 --- a/src/Views/Welcome.axaml.cs +++ b/src/Views/Welcome.axaml.cs @@ -253,11 +253,10 @@ namespace SourceGit.Views return; } - var gitDir = new Commands.QueryGitDir(root).Result(); Dispatcher.UIThread.Invoke(() => { - var repo = ViewModels.Preference.AddRepository(root, gitDir); - var node = ViewModels.Preference.FindOrAddNodeByRepositoryPath(repo.FullPath, parent, true); + var normalizedPath = root.Replace("\\", "/"); + var node = ViewModels.Preference.FindOrAddNodeByRepositoryPath(normalizedPath, parent, true); launcher.OpenRepositoryInTab(node, page); }); });