mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-05-22 12:45:00 +00:00
refactor<*>: rewrite all codes...
This commit is contained in:
parent
89ff8aa744
commit
30ab8ae954
342 changed files with 17208 additions and 19633 deletions
22
src/Models/AvatarServer.cs
Normal file
22
src/Models/AvatarServer.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// 支持的头像服务器
|
||||
/// </summary>
|
||||
public class AvatarServer {
|
||||
public string Name { get; set; }
|
||||
public string Url { get; set; }
|
||||
|
||||
public static List<AvatarServer> Supported = new List<AvatarServer>() {
|
||||
new AvatarServer("Gravatar官网", "https://www.gravatar.com/avatar/"),
|
||||
new AvatarServer("Gravatar中国CDN", "https://cdn.s.loli.top/avatar/"),
|
||||
};
|
||||
|
||||
public AvatarServer(string name, string url) {
|
||||
Name = name;
|
||||
Url = url;
|
||||
}
|
||||
}
|
||||
}
|
12
src/Models/BlameLine.cs
Normal file
12
src/Models/BlameLine.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// 追溯中的行信息
|
||||
/// </summary>
|
||||
public class BlameLine {
|
||||
public string LineNumber { get; set; }
|
||||
public string CommitSHA { get; set; }
|
||||
public string Author { get; set; }
|
||||
public string Time { get; set; }
|
||||
public string Content { get; set; }
|
||||
}
|
||||
}
|
16
src/Models/Branch.cs
Normal file
16
src/Models/Branch.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// 分支数据
|
||||
/// </summary>
|
||||
public class Branch {
|
||||
public string Name { get; set; }
|
||||
public string FullName { get; set; }
|
||||
public string Head { get; set; }
|
||||
public string HeadSubject { get; set; }
|
||||
public bool IsLocal { get; set; }
|
||||
public bool IsCurrent { get; set; }
|
||||
public string Upstream { get; set; }
|
||||
public string UpstreamTrackStatus { get; set; }
|
||||
public string Remote { get; set; }
|
||||
}
|
||||
}
|
25
src/Models/CRLFOption.cs
Normal file
25
src/Models/CRLFOption.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// 自动换行处理方式
|
||||
/// </summary>
|
||||
public class CRLFOption {
|
||||
public string Display { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string Desc { get; set; }
|
||||
|
||||
public static List<CRLFOption> Supported = new List<CRLFOption>() {
|
||||
new CRLFOption("TRUE", "true", "Commit as LF, checkout as CRLF"),
|
||||
new CRLFOption("INPUT", "input", "Only convert for commit"),
|
||||
new CRLFOption("FALSE", "false", "Do NOT convert"),
|
||||
};
|
||||
|
||||
public CRLFOption(string display, string value, string desc) {
|
||||
Display = display;
|
||||
Value = value;
|
||||
Desc = desc;
|
||||
}
|
||||
}
|
||||
}
|
74
src/Models/Change.cs
Normal file
74
src/Models/Change.cs
Normal file
|
@ -0,0 +1,74 @@
|
|||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// Git变更
|
||||
/// </summary>
|
||||
public class Change {
|
||||
|
||||
/// <summary>
|
||||
/// 显示模式
|
||||
/// </summary>
|
||||
public enum DisplayMode {
|
||||
Tree,
|
||||
List,
|
||||
Grid,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 变更状态码
|
||||
/// </summary>
|
||||
public enum Status {
|
||||
None,
|
||||
Modified,
|
||||
Added,
|
||||
Deleted,
|
||||
Renamed,
|
||||
Copied,
|
||||
Unmerged,
|
||||
Untracked,
|
||||
}
|
||||
|
||||
public Status Index { get; set; }
|
||||
public Status WorkTree { get; set; } = Status.None;
|
||||
public string Path { get; set; } = "";
|
||||
public string OriginalPath { get; set; } = "";
|
||||
|
||||
public bool IsAddedToIndex {
|
||||
get {
|
||||
if (Index == Status.None || Index == Status.Untracked) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsConflit {
|
||||
get {
|
||||
if (Index == Status.Unmerged || WorkTree == Status.Unmerged) return true;
|
||||
if (Index == Status.Added && WorkTree == Status.Added) return true;
|
||||
if (Index == Status.Deleted && WorkTree == Status.Deleted) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(Status index, Status workTree = Status.None) {
|
||||
Index = index;
|
||||
WorkTree = workTree;
|
||||
|
||||
if (index == Status.Renamed || workTree == Status.Renamed) {
|
||||
var idx = Path.IndexOf('\t');
|
||||
if (idx >= 0) {
|
||||
OriginalPath = Path.Substring(0, idx);
|
||||
Path = Path.Substring(idx + 1);
|
||||
} else {
|
||||
idx = Path.IndexOf(" -> ");
|
||||
if (idx > 0) {
|
||||
OriginalPath = Path.Substring(0, idx);
|
||||
Path = Path.Substring(idx + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Path[0] == '"') Path = Path.Substring(1, Path.Length - 2);
|
||||
if (!string.IsNullOrEmpty(OriginalPath) && OriginalPath[0] == '"') OriginalPath = OriginalPath.Substring(1, OriginalPath.Length - 2);
|
||||
}
|
||||
}
|
||||
}
|
21
src/Models/Commit.cs
Normal file
21
src/Models/Commit.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// 提交记录
|
||||
/// </summary>
|
||||
public class Commit {
|
||||
public string SHA { get; set; } = "";
|
||||
public string ShortSHA => SHA.Substring(0, 8);
|
||||
public User Author { get; set; } = new User();
|
||||
public User Committer { get; set; } = new User();
|
||||
public string Subject { get; set; } = "";
|
||||
public string Message { get; set; } = "";
|
||||
public List<string> Parents { get; set; } = new List<string>();
|
||||
public List<Decorator> Decorators { get; set; } = new List<Decorator>();
|
||||
public bool HasDecorators => Decorators.Count > 0;
|
||||
public bool IsMerged { get; set; } = false;
|
||||
public Thickness Margin { get; set; } = new Thickness(0);
|
||||
}
|
||||
}
|
21
src/Models/Decorator.cs
Normal file
21
src/Models/Decorator.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// 修饰类型
|
||||
/// </summary>
|
||||
public enum DecoratorType {
|
||||
None,
|
||||
CurrentBranchHead,
|
||||
LocalBranchHead,
|
||||
RemoteBranchHead,
|
||||
Tag,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提交的附加修饰
|
||||
/// </summary>
|
||||
public class Decorator {
|
||||
public DecoratorType Type { get; set; } = DecoratorType.None;
|
||||
public string Name { get; set; } = "";
|
||||
}
|
||||
}
|
15
src/Models/Exception.cs
Normal file
15
src/Models/Exception.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// 错误通知
|
||||
/// </summary>
|
||||
public static class Exception {
|
||||
public static Action<string> Handler { get; set; }
|
||||
|
||||
public static void Raise(string error) {
|
||||
Handler?.Invoke(error);
|
||||
}
|
||||
}
|
||||
}
|
9
src/Models/FileSizeChange.cs
Normal file
9
src/Models/FileSizeChange.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// 文件大小变化
|
||||
/// </summary>
|
||||
public class FileSizeChange {
|
||||
public long OldSize = 0;
|
||||
public long NewSize = 0;
|
||||
}
|
||||
}
|
36
src/Models/GitFlow.cs
Normal file
36
src/Models/GitFlow.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// GitFlow的分支类型
|
||||
/// </summary>
|
||||
public enum GitFlowBranchType {
|
||||
None,
|
||||
Feature,
|
||||
Release,
|
||||
Hotfix,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GitFlow相关设置
|
||||
/// </summary>
|
||||
public class GitFlow {
|
||||
public string Feature { get; set; }
|
||||
public string Release { get; set; }
|
||||
public string Hotfix { get; set; }
|
||||
|
||||
public bool IsEnabled {
|
||||
get {
|
||||
return !string.IsNullOrEmpty(Feature)
|
||||
&& !string.IsNullOrEmpty(Release)
|
||||
&& !string.IsNullOrEmpty(Hotfix);
|
||||
}
|
||||
}
|
||||
|
||||
public GitFlowBranchType GetBranchType(string name) {
|
||||
if (!IsEnabled) return GitFlowBranchType.None;
|
||||
if (name.StartsWith(Feature)) return GitFlowBranchType.Feature;
|
||||
if (name.StartsWith(Release)) return GitFlowBranchType.Release;
|
||||
if (name.StartsWith(Hotfix)) return GitFlowBranchType.Hotfix;
|
||||
return GitFlowBranchType.None;
|
||||
}
|
||||
}
|
||||
}
|
12
src/Models/Group.cs
Normal file
12
src/Models/Group.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// 仓库列表分组
|
||||
/// </summary>
|
||||
public class Group {
|
||||
public string Id { get; set; } = "";
|
||||
public string Name { get; set; } = "";
|
||||
public string Parent { get; set; } = "";
|
||||
public bool IsExpanded { get; set; } = false;
|
||||
}
|
||||
}
|
10
src/Models/LFSChange.cs
Normal file
10
src/Models/LFSChange.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// LFS对象变更
|
||||
/// </summary>
|
||||
public class LFSChange {
|
||||
public LFSObject Old;
|
||||
public LFSObject New;
|
||||
public bool IsValid => Old != null || New != null;
|
||||
}
|
||||
}
|
9
src/Models/LFSObject.cs
Normal file
9
src/Models/LFSObject.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// LFS对象
|
||||
/// </summary>
|
||||
public class LFSObject {
|
||||
public string OID { get; set; }
|
||||
public long Size { get; set; }
|
||||
}
|
||||
}
|
22
src/Models/Locale.cs
Normal file
22
src/Models/Locale.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// 支持的语言
|
||||
/// </summary>
|
||||
public class Locale {
|
||||
public string Name { get; set; }
|
||||
public string Resource { get; set; }
|
||||
|
||||
public static List<Locale> Supported = new List<Locale>() {
|
||||
new Locale("English", "en_US"),
|
||||
new Locale("简体中文", "zh_CN"),
|
||||
};
|
||||
|
||||
public Locale(string name, string res) {
|
||||
Name = name;
|
||||
Resource = res;
|
||||
}
|
||||
}
|
||||
}
|
25
src/Models/MergeOption.cs
Normal file
25
src/Models/MergeOption.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// 合并方式
|
||||
/// </summary>
|
||||
public class MergeOption {
|
||||
public string Name { get; set; }
|
||||
public string Desc { get; set; }
|
||||
public string Arg { get; set; }
|
||||
|
||||
public static List<MergeOption> Supported = new List<MergeOption>() {
|
||||
new MergeOption("Default", "Fast-forward if possible", ""),
|
||||
new MergeOption("No Fast-forward", "Always create a merge commit", "--no-ff"),
|
||||
new MergeOption("Squash", "Use '--squash'", "--squash"),
|
||||
new MergeOption("Don't commit", "Merge without commit", "--no-commit"),
|
||||
};
|
||||
|
||||
public MergeOption(string n, string d, string a) {
|
||||
Name = n;
|
||||
Desc = d;
|
||||
Arg = a;
|
||||
}
|
||||
}
|
||||
}
|
119
src/Models/MergeTool.cs
Normal file
119
src/Models/MergeTool.cs
Normal file
|
@ -0,0 +1,119 @@
|
|||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// 外部合并工具
|
||||
/// </summary>
|
||||
public class MergeTool {
|
||||
public int Type { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Exec { get; set; }
|
||||
public string Cmd { get; set; }
|
||||
public Func<string> Finder { get; set; }
|
||||
|
||||
public static List<MergeTool> Supported = new List<MergeTool>() {
|
||||
new MergeTool(0, "--", "", "", () => ""),
|
||||
new MergeTool(1, "Visual Studio Code", "Code.exe", "-n --wait \"$MERGED\"", FindVSCode),
|
||||
new MergeTool(2, "Visual Studio 2017/2019", "vsDiffMerge.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\" //m", FindVSMerge),
|
||||
new MergeTool(3, "Tortoise Merge", "TortoiseMerge.exe", "-base:\"$BASE\" -theirs:\"$REMOTE\" -mine:\"$LOCAL\" -merged:\"$MERGED\"", FindTortoiseMerge),
|
||||
new MergeTool(4, "KDiff3", "kdiff3.exe", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", FindKDiff3),
|
||||
new MergeTool(5, "Beyond Compare 4", "BComp.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", FindBCompare),
|
||||
};
|
||||
|
||||
public MergeTool(int type, string name, string exec, string cmd, Func<string> finder) {
|
||||
Type = type;
|
||||
Name = name;
|
||||
Exec = exec;
|
||||
Cmd = cmd;
|
||||
Finder = finder;
|
||||
}
|
||||
|
||||
private static string FindVSCode() {
|
||||
var root = RegistryKey.OpenBaseKey(
|
||||
RegistryHive.LocalMachine,
|
||||
Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32);
|
||||
|
||||
var vscode = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C26E74D1-022E-4238-8B9D-1E7564A36CC9}_is1");
|
||||
if (vscode != null) {
|
||||
return vscode.GetValue("DisplayIcon") as string;
|
||||
}
|
||||
|
||||
vscode = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{1287CAD5-7C8D-410D-88B9-0D1EE4A83FF2}_is1");
|
||||
if (vscode != null) {
|
||||
return vscode.GetValue("DisplayIcon") as string;
|
||||
}
|
||||
|
||||
vscode = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F8A2A208-72B3-4D61-95FC-8A65D340689B}_is1");
|
||||
if (vscode != null) {
|
||||
return vscode.GetValue("DisplayIcon") as string;
|
||||
}
|
||||
|
||||
vscode = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{EA457B21-F73E-494C-ACAB-524FDE069978}_is1");
|
||||
if (vscode != null) {
|
||||
return vscode.GetValue("DisplayIcon") as string;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private static string FindVSMerge() {
|
||||
var dir = @"C:\Program Files (x86)\Microsoft Visual Studio";
|
||||
if (Directory.Exists($"{dir}\\2019")) {
|
||||
dir += "\\2019";
|
||||
} else if (Directory.Exists($"{dir}\\2017")) {
|
||||
dir += "\\2017";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (Directory.Exists($"{dir}\\Community")) {
|
||||
dir += "\\Community";
|
||||
} else if (Directory.Exists($"{dir}\\Enterprise")) {
|
||||
dir += "\\Enterprise";
|
||||
} else if (Directory.Exists($"{dir}\\Professional")) {
|
||||
dir += "\\Professional";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
return $"{dir}\\Common7\\IDE\\CommonExtensions\\Microsoft\\TeamFoundation\\Team Explorer\\vsDiffMerge.exe";
|
||||
}
|
||||
|
||||
private static string FindTortoiseMerge() {
|
||||
var root = RegistryKey.OpenBaseKey(
|
||||
RegistryHive.LocalMachine,
|
||||
Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32);
|
||||
|
||||
var tortoiseSVN = root.OpenSubKey("SOFTWARE\\TortoiseSVN");
|
||||
if (tortoiseSVN == null) return "";
|
||||
return tortoiseSVN.GetValue("TMergePath") as string;
|
||||
}
|
||||
|
||||
private static string FindKDiff3() {
|
||||
var root = RegistryKey.OpenBaseKey(
|
||||
RegistryHive.LocalMachine,
|
||||
Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32);
|
||||
|
||||
var kdiff = root.OpenSubKey(@"SOFTWARE\KDiff3\diff-ext");
|
||||
if (kdiff == null) return "";
|
||||
return kdiff.GetValue("diffcommand") as string;
|
||||
}
|
||||
|
||||
private static string FindBCompare() {
|
||||
var root = RegistryKey.OpenBaseKey(
|
||||
RegistryHive.LocalMachine,
|
||||
Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32);
|
||||
|
||||
var bc = root.OpenSubKey(@"SOFTWARE\Scooter Software\Beyond Compare");
|
||||
if (bc == null) return "";
|
||||
|
||||
var exec = bc.GetValue("ExePath") as string;
|
||||
var dir = Path.GetDirectoryName(exec);
|
||||
return $"{dir}\\BComp.exe";
|
||||
}
|
||||
}
|
||||
}
|
21
src/Models/Object.cs
Normal file
21
src/Models/Object.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// 提交中元素类型
|
||||
/// </summary>
|
||||
public enum ObjectType {
|
||||
None,
|
||||
Blob,
|
||||
Tree,
|
||||
Tag,
|
||||
Commit,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Git提交中的元素
|
||||
/// </summary>
|
||||
public class Object {
|
||||
public string SHA { get; set; }
|
||||
public ObjectType Type { get; set; }
|
||||
public string Path { get; set; }
|
||||
}
|
||||
}
|
314
src/Models/Preference.cs
Normal file
314
src/Models/Preference.cs
Normal file
|
@ -0,0 +1,314 @@
|
|||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
#if NET48
|
||||
using Newtonsoft.Json;
|
||||
#else
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
#endif
|
||||
|
||||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// 程序配置
|
||||
/// </summary>
|
||||
public class Preference {
|
||||
private static readonly string SAVE_PATH = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"SourceGit",
|
||||
"preference_v4.json");
|
||||
private static Preference instance = null;
|
||||
|
||||
/// <summary>
|
||||
/// 通用配置
|
||||
/// </summary>
|
||||
public class GeneralInfo {
|
||||
|
||||
/// <summary>
|
||||
/// 显示语言
|
||||
/// </summary>
|
||||
public string Locale { get; set; } = "en_US";
|
||||
|
||||
/// <summary>
|
||||
/// 头像服务器
|
||||
/// </summary>
|
||||
public string AvatarServer { get; set; } = "https://www.gravatar.com/avatar/";
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用深色主题
|
||||
/// </summary>
|
||||
public bool UseDarkTheme { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 启用更新检测
|
||||
/// </summary>
|
||||
public bool CheckForUpdate { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 上一次检测的时间(用于控制每天仅第一次启动软件时,检测)
|
||||
/// </summary>
|
||||
public int LastCheckDay { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 启用自动拉取远程变更(每10分钟一次)
|
||||
/// </summary>
|
||||
public bool AutoFetchRemotes { get; set; } = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Git配置
|
||||
/// </summary>
|
||||
public class GitInfo {
|
||||
|
||||
/// <summary>
|
||||
/// git.exe所在路径
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 默认克隆路径
|
||||
/// </summary>
|
||||
public string DefaultCloneDir { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 外部合并工具配置
|
||||
/// </summary>
|
||||
public class MergeToolInfo {
|
||||
|
||||
/// <summary>
|
||||
/// 合并工具类型
|
||||
/// </summary>
|
||||
public int Type { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 合并工具可执行文件路径
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用设置
|
||||
/// </summary>
|
||||
public class WindowInfo {
|
||||
|
||||
/// <summary>
|
||||
/// 最近一次设置的宽度
|
||||
/// </summary>
|
||||
public double Width { get; set; } = 800;
|
||||
|
||||
/// <summary>
|
||||
/// 最近一次设置的高度
|
||||
/// </summary>
|
||||
public double Height { get; set; } = 600;
|
||||
|
||||
/// <summary>
|
||||
/// 将提交信息面板与提交记录左右排布
|
||||
/// </summary>
|
||||
public bool MoveCommitInfoRight { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 使用合并Diff视图
|
||||
/// </summary>
|
||||
public bool UseCombinedDiff { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 未暂存视图中变更显示方式
|
||||
/// </summary>
|
||||
public Change.DisplayMode ChangeInUnstaged { get; set; } = Change.DisplayMode.Tree;
|
||||
|
||||
/// <summary>
|
||||
/// 暂存视图中变更显示方式
|
||||
/// </summary>
|
||||
public Change.DisplayMode ChangeInStaged { get; set; } = Change.DisplayMode.Tree;
|
||||
|
||||
/// <summary>
|
||||
/// 提交信息视图中变更显示方式
|
||||
/// </summary>
|
||||
public Change.DisplayMode ChangeInCommitInfo { get; set; } = Change.DisplayMode.Tree;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 全局配置
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public static Preference Instance {
|
||||
get {
|
||||
if (instance == null) return Load();
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测配置是否
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public bool IsReady {
|
||||
get {
|
||||
return !string.IsNullOrEmpty(Git.Path) && File.Exists(Git.Path);
|
||||
}
|
||||
}
|
||||
|
||||
#region DATA
|
||||
public GeneralInfo General { get; set; } = new GeneralInfo();
|
||||
public GitInfo Git { get; set; } = new GitInfo();
|
||||
public MergeToolInfo MergeTool { get; set; } = new MergeToolInfo();
|
||||
public WindowInfo Window { get; set; } = new WindowInfo();
|
||||
public List<Group> Groups { get; set; } = new List<Group>();
|
||||
public List<Repository> Repositories { get; set; } = new List<Repository>();
|
||||
#endregion
|
||||
|
||||
#region LOAD_SAVE
|
||||
public static Preference Load() {
|
||||
if (!File.Exists(SAVE_PATH)) {
|
||||
instance = new Preference();
|
||||
} else {
|
||||
#if NET48
|
||||
instance = JsonConvert.DeserializeObject<Preference>(File.ReadAllText(SAVE_PATH));
|
||||
#else
|
||||
instance = JsonSerializer.Deserialize<Preference>(File.ReadAllText(SAVE_PATH));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!instance.IsReady) {
|
||||
var reg = RegistryKey.OpenBaseKey(
|
||||
RegistryHive.LocalMachine,
|
||||
Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32);
|
||||
var git = reg.OpenSubKey("SOFTWARE\\GitForWindows");
|
||||
if (git != null) {
|
||||
instance.Git.Path = Path.Combine(git.GetValue("InstallPath") as string, "bin", "git.exe");
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void Save() {
|
||||
var dir = Path.GetDirectoryName(SAVE_PATH);
|
||||
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
|
||||
|
||||
#if NET48
|
||||
var data = JsonConvert.SerializeObject(instance, Formatting.Indented);
|
||||
#else
|
||||
var data = JsonSerializer.Serialize(instance, new JsonSerializerOptions() { WriteIndented = true });
|
||||
#endif
|
||||
File.WriteAllText(SAVE_PATH, data);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region METHOD_ON_GROUPS
|
||||
public Group AddGroup(string name, string parentId) {
|
||||
var group = new Group() {
|
||||
Name = name,
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
Parent = parentId,
|
||||
IsExpanded = false,
|
||||
};
|
||||
|
||||
Groups.Add(group);
|
||||
Groups.Sort((l, r) => l.Name.CompareTo(r.Name));
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
public Group FindGroup(string id) {
|
||||
foreach (var group in Groups) {
|
||||
if (group.Id == id) return group;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RenameGroup(string id, string newName) {
|
||||
foreach (var group in Groups) {
|
||||
if (group.Id == id) {
|
||||
group.Name = newName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Groups.Sort((l, r) => l.Name.CompareTo(r.Name));
|
||||
}
|
||||
|
||||
public void RemoveGroup(string id) {
|
||||
int removedIdx = -1;
|
||||
|
||||
for (int i = 0; i < Groups.Count; i++) {
|
||||
if (Groups[i].Id == id) {
|
||||
removedIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedIdx >= 0) Groups.RemoveAt(removedIdx);
|
||||
}
|
||||
|
||||
public bool IsSubGroup(string parent, string subId) {
|
||||
if (string.IsNullOrEmpty(parent)) return false;
|
||||
if (parent == subId) return true;
|
||||
|
||||
var g = FindGroup(subId);
|
||||
if (g == null) return false;
|
||||
|
||||
g = FindGroup(g.Parent);
|
||||
while (g != null) {
|
||||
if (g.Id == parent) return true;
|
||||
g = FindGroup(g.Parent);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region METHOD_ON_REPOSITORIES
|
||||
public Repository AddRepository(string path, string gitDir, string groupId) {
|
||||
var repo = FindRepository(path);
|
||||
if (repo != null) return repo;
|
||||
|
||||
var dir = new DirectoryInfo(path);
|
||||
repo = new Repository() {
|
||||
Path = dir.FullName,
|
||||
GitDir = gitDir,
|
||||
Name = dir.Name,
|
||||
GroupId = groupId,
|
||||
};
|
||||
|
||||
Repositories.Add(repo);
|
||||
Repositories.Sort((l, r) => l.Name.CompareTo(r.Name));
|
||||
return repo;
|
||||
}
|
||||
|
||||
public Repository FindRepository(string path) {
|
||||
var dir = new DirectoryInfo(path);
|
||||
foreach (var repo in Repositories) {
|
||||
if (repo.Path == dir.FullName) return repo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RenameRepository(string path, string newName) {
|
||||
var repo = FindRepository(path);
|
||||
if (repo == null) return;
|
||||
|
||||
repo.Name = newName;
|
||||
Repositories.Sort((l, r) => l.Name.CompareTo(r.Name));
|
||||
}
|
||||
|
||||
public void RemoveRepository(string path) {
|
||||
var dir = new DirectoryInfo(path);
|
||||
var removedIdx = -1;
|
||||
|
||||
for (int i = 0; i < Repositories.Count; i++) {
|
||||
if (Repositories[i].Path == dir.FullName) {
|
||||
removedIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedIdx >= 0) Repositories.RemoveAt(removedIdx);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
10
src/Models/Remote.cs
Normal file
10
src/Models/Remote.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// 远程
|
||||
/// </summary>
|
||||
public class Remote {
|
||||
public string Name { get; set; }
|
||||
public string URL { get; set; }
|
||||
}
|
||||
}
|
48
src/Models/Repository.cs
Normal file
48
src/Models/Repository.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
#if NET48
|
||||
using Newtonsoft.Json;
|
||||
#else
|
||||
using System.Text.Json.Serialization;
|
||||
#endif
|
||||
|
||||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// 仓库
|
||||
/// </summary>
|
||||
public class Repository {
|
||||
|
||||
#region PROPERTIES_SAVED
|
||||
public string Name { get; set; } = "";
|
||||
public string Path { get; set; } = "";
|
||||
public string GitDir { get; set; } = "";
|
||||
public string GroupId { get; set; } = "";
|
||||
public int Bookmark { get; set; } = 0;
|
||||
public List<string> Filters { get; set; } = new List<string>();
|
||||
public List<string> CommitMessages { get; set; } = new List<string>();
|
||||
#endregion
|
||||
|
||||
#region PROPERTIES_RUNTIME
|
||||
[JsonIgnore] public List<Remote> Remotes = new List<Remote>();
|
||||
[JsonIgnore] public List<Branch> Branches = new List<Branch>();
|
||||
[JsonIgnore] public GitFlow GitFlow = new GitFlow();
|
||||
#endregion
|
||||
|
||||
public void PushCommitMessage(string message) {
|
||||
if (string.IsNullOrEmpty(message)) return;
|
||||
|
||||
int exists = CommitMessages.Count;
|
||||
if (exists > 0) {
|
||||
var last = CommitMessages[0];
|
||||
if (last == message) return;
|
||||
}
|
||||
|
||||
if (exists >= 10) {
|
||||
CommitMessages.RemoveRange(9, exists - 9);
|
||||
}
|
||||
|
||||
CommitMessages.Insert(0, message);
|
||||
}
|
||||
}
|
||||
}
|
27
src/Models/ResetMode.cs
Normal file
27
src/Models/ResetMode.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// 重置方式
|
||||
/// </summary>
|
||||
public class ResetMode {
|
||||
public string Name { get; set; }
|
||||
public string Desc { get; set; }
|
||||
public string Arg { get; set; }
|
||||
public Brush Color { get; set; }
|
||||
|
||||
public static List<ResetMode> Supported = new List<ResetMode>() {
|
||||
new ResetMode("Soft", "Keep all changes. Stage differences", "--soft", Brushes.Green),
|
||||
new ResetMode("Mixed", "Keep all changes. Unstage differences", "--mixed", Brushes.Yellow),
|
||||
new ResetMode("Hard", "Discard all changes", "--hard", Brushes.Red),
|
||||
};
|
||||
|
||||
public ResetMode(string n, string d, string a, Brush b) {
|
||||
Name = n;
|
||||
Desc = d;
|
||||
Arg = a;
|
||||
Color = b;
|
||||
}
|
||||
}
|
||||
}
|
11
src/Models/Stash.cs
Normal file
11
src/Models/Stash.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// 贮藏
|
||||
/// </summary>
|
||||
public class Stash {
|
||||
public string Name { get; set; } = "";
|
||||
public string SHA { get; set; } = "";
|
||||
public User Author { get; set; } = new User();
|
||||
public string Message { get; set; } = "";
|
||||
}
|
||||
}
|
10
src/Models/Tag.cs
Normal file
10
src/Models/Tag.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// 标签
|
||||
/// </summary>
|
||||
public class Tag {
|
||||
public string Name { get; set; }
|
||||
public string SHA { get; set; }
|
||||
public bool IsFiltered { get; set; }
|
||||
}
|
||||
}
|
34
src/Models/TextChanges.cs
Normal file
34
src/Models/TextChanges.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// Diff文本文件变化
|
||||
/// </summary>
|
||||
public class TextChanges {
|
||||
|
||||
public enum LineMode {
|
||||
None,
|
||||
Normal,
|
||||
Indicator,
|
||||
Added,
|
||||
Deleted,
|
||||
}
|
||||
|
||||
public class Line {
|
||||
public LineMode Mode = LineMode.Normal;
|
||||
public string Content = "";
|
||||
public string OldLine = "";
|
||||
public string NewLine = "";
|
||||
|
||||
public Line(LineMode mode, string content, string oldLine, string newLine) {
|
||||
Mode = mode;
|
||||
Content = content;
|
||||
OldLine = oldLine;
|
||||
NewLine = newLine;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsBinary = false;
|
||||
public List<Line> Lines = new List<Line>();
|
||||
}
|
||||
}
|
9
src/Models/TextLine.cs
Normal file
9
src/Models/TextLine.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// 文件中的一行内容
|
||||
/// </summary>
|
||||
public class TextLine {
|
||||
public int Number { get; set; }
|
||||
public string Data { get; set; }
|
||||
}
|
||||
}
|
26
src/Models/User.cs
Normal file
26
src/Models/User.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// Git用户
|
||||
/// </summary>
|
||||
public class User {
|
||||
private static readonly Regex REG_FORMAT = new Regex(@"\w+ (.*) <(.*)> (\d{10}) [\+\-]\d+");
|
||||
|
||||
public string Name { get; set; } = "";
|
||||
public string Email { get; set; } = "";
|
||||
public string Time { get; set; } = "";
|
||||
|
||||
public void Parse(string data) {
|
||||
var match = REG_FORMAT.Match(data);
|
||||
if (!match.Success) return;
|
||||
|
||||
var time = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(int.Parse(match.Groups[3].Value));
|
||||
|
||||
Name = match.Groups[1].Value;
|
||||
Email = match.Groups[2].Value;
|
||||
Time = time.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
}
|
||||
}
|
63
src/Models/Version.cs
Normal file
63
src/Models/Version.cs
Normal file
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
|
||||
#if NET48
|
||||
using Newtonsoft.Json;
|
||||
#else
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
#endif
|
||||
|
||||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// Gitee开放API中Release信息格式
|
||||
/// </summary>
|
||||
public class Version {
|
||||
#if NET48
|
||||
[JsonProperty(PropertyName = "id")]
|
||||
public ulong Id { get; set; }
|
||||
[JsonProperty(PropertyName = "tag_name")]
|
||||
public string TagName { get; set; }
|
||||
[JsonProperty(PropertyName = "target_commitish")]
|
||||
public string CommitSHA { get; set; }
|
||||
[JsonProperty(PropertyName = "prerelease")]
|
||||
public bool PreRelease { get; set; }
|
||||
[JsonProperty(PropertyName = "name")]
|
||||
public string Name { get; set; }
|
||||
[JsonProperty(PropertyName = "body")]
|
||||
public string Body { get; set; }
|
||||
[JsonProperty(PropertyName = "created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
#else
|
||||
[JsonPropertyName("id")]
|
||||
public ulong Id { get; set; }
|
||||
[JsonPropertyName("tag_name")]
|
||||
public string TagName { get; set; }
|
||||
[JsonPropertyName("target_commitish")]
|
||||
public string CommitSHA { get; set; }
|
||||
[JsonPropertyName("prerelease")]
|
||||
public bool PreRelease { get; set; }
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("body")]
|
||||
public string Body { get; set; }
|
||||
[JsonPropertyName("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
#endif
|
||||
public string PublishTime {
|
||||
get { return CreatedAt.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); }
|
||||
}
|
||||
|
||||
public string IsPrerelease {
|
||||
get { return PreRelease ? "YES" : "NO"; }
|
||||
}
|
||||
|
||||
public static Version Load(string data) {
|
||||
#if NET48
|
||||
return JsonConvert.DeserializeObject<Version>(data);
|
||||
#else
|
||||
return JsonSerializer.Deserialize<Version>(data);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
237
src/Models/Watcher.cs
Normal file
237
src/Models/Watcher.cs
Normal file
|
@ -0,0 +1,237 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
|
||||
/// <summary>
|
||||
/// 文件系统更新监视
|
||||
/// </summary>
|
||||
public class Watcher {
|
||||
/// <summary>
|
||||
/// 打开仓库事件
|
||||
/// </summary>
|
||||
public static event Action<Repository> Opened;
|
||||
|
||||
/// <summary>
|
||||
/// 跳转到指定提交的事件
|
||||
/// </summary>
|
||||
public event Action<string> Navigate;
|
||||
/// <summary>
|
||||
/// 工作副本变更
|
||||
/// </summary>
|
||||
public event Action WorkingCopyChanged;
|
||||
/// <summary>
|
||||
/// 分支数据变更
|
||||
/// </summary>
|
||||
public event Action BranchChanged;
|
||||
/// <summary>
|
||||
/// 标签变更
|
||||
/// </summary>
|
||||
public event Action TagChanged;
|
||||
/// <summary>
|
||||
/// 贮藏变更
|
||||
/// </summary>
|
||||
public event Action StashChanged;
|
||||
/// <summary>
|
||||
/// 子模块变更
|
||||
/// </summary>
|
||||
public event Action SubmoduleChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 打开仓库事件
|
||||
/// </summary>
|
||||
/// <param name="repo"></param>
|
||||
public static void Open(Repository repo) {
|
||||
if (all.ContainsKey(repo.Path)) return;
|
||||
|
||||
var watcher = new Watcher();
|
||||
watcher.Start(repo.Path, repo.GitDir);
|
||||
all.Add(repo.Path, watcher);
|
||||
|
||||
Opened?.Invoke(repo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止指定的监视器
|
||||
/// </summary>
|
||||
/// <param name="repoPath"></param>
|
||||
public static void Close(string repoPath) {
|
||||
if (!all.ContainsKey(repoPath)) return;
|
||||
all[repoPath].Stop();
|
||||
all.Remove(repoPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取得一个仓库的监视器
|
||||
/// </summary>
|
||||
/// <param name="repoPath"></param>
|
||||
/// <returns></returns>
|
||||
public static Watcher Get(string repoPath) {
|
||||
if (all.ContainsKey(repoPath)) return all[repoPath];
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停或启用监听
|
||||
/// </summary>
|
||||
/// <param name="repoPath"></param>
|
||||
/// <param name="enabled"></param>
|
||||
public static void SetEnabled(string repoPath, bool enabled) {
|
||||
if (all.ContainsKey(repoPath)) {
|
||||
var watcher = all[repoPath];
|
||||
if (enabled) {
|
||||
if (watcher.lockCount > 0) watcher.lockCount--;
|
||||
} else {
|
||||
watcher.lockCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 跳转到指定的提交
|
||||
/// </summary>
|
||||
/// <param name="commit"></param>
|
||||
public void NavigateTo(string commit) {
|
||||
Navigate?.Invoke(commit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制刷新
|
||||
/// </summary>
|
||||
public void Refresh() {
|
||||
updateWC = 1;
|
||||
updateBranch = 1;
|
||||
updateSubmodules = 1;
|
||||
updateStashes = 1;
|
||||
updateTags = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅强制更新本地变化
|
||||
/// </summary>
|
||||
public void RefreshWC() {
|
||||
updateWC = 0;
|
||||
WorkingCopyChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void Start(string repo, string gitDir) {
|
||||
wcWatcher = new FileSystemWatcher();
|
||||
wcWatcher.Path = repo;
|
||||
wcWatcher.Filter = "*";
|
||||
wcWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.CreationTime;
|
||||
wcWatcher.IncludeSubdirectories = true;
|
||||
wcWatcher.Created += OnWorkingCopyChanged;
|
||||
wcWatcher.Renamed += OnWorkingCopyChanged;
|
||||
wcWatcher.Changed += OnWorkingCopyChanged;
|
||||
wcWatcher.Deleted += OnWorkingCopyChanged;
|
||||
wcWatcher.EnableRaisingEvents = true;
|
||||
|
||||
repoWatcher = new FileSystemWatcher();
|
||||
repoWatcher.Path = gitDir;
|
||||
repoWatcher.Filter = "*";
|
||||
repoWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName;
|
||||
repoWatcher.IncludeSubdirectories = true;
|
||||
repoWatcher.Created += OnRepositoryChanged;
|
||||
repoWatcher.Renamed += OnRepositoryChanged;
|
||||
repoWatcher.Changed += OnRepositoryChanged;
|
||||
repoWatcher.Deleted += OnRepositoryChanged;
|
||||
repoWatcher.EnableRaisingEvents = true;
|
||||
|
||||
timer = new Timer(Tick, null, 100, 100);
|
||||
}
|
||||
|
||||
private void Stop() {
|
||||
repoWatcher.EnableRaisingEvents = false;
|
||||
repoWatcher.Dispose();
|
||||
repoWatcher = null;
|
||||
|
||||
wcWatcher.EnableRaisingEvents = false;
|
||||
wcWatcher.Dispose();
|
||||
wcWatcher = null;
|
||||
|
||||
timer.Dispose();
|
||||
timer = null;
|
||||
|
||||
Navigate = null;
|
||||
WorkingCopyChanged = null;
|
||||
BranchChanged = null;
|
||||
TagChanged = null;
|
||||
StashChanged = null;
|
||||
SubmoduleChanged = null;
|
||||
}
|
||||
|
||||
private void OnRepositoryChanged(object o, FileSystemEventArgs e) {
|
||||
if (string.IsNullOrEmpty(e.Name)) return;
|
||||
|
||||
if (e.Name.StartsWith("modules", StringComparison.Ordinal)) {
|
||||
updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
|
||||
} else if (e.Name.StartsWith("refs\\tags", StringComparison.Ordinal)) {
|
||||
updateTags = DateTime.Now.AddSeconds(.5).ToFileTime();
|
||||
} else if (e.Name.StartsWith("refs\\stash", StringComparison.Ordinal)) {
|
||||
updateStashes = DateTime.Now.AddSeconds(.5).ToFileTime();
|
||||
} else if (e.Name.Equals("HEAD", StringComparison.Ordinal) ||
|
||||
e.Name.EndsWith("_HEAD", StringComparison.Ordinal) ||
|
||||
e.Name.StartsWith("refs\\heads\\", StringComparison.Ordinal) ||
|
||||
e.Name.StartsWith("refs\\remotes\\", StringComparison.Ordinal)) {
|
||||
updateBranch = DateTime.Now.AddSeconds(.5).ToFileTime();
|
||||
} else if (e.Name.StartsWith("objects\\") || e.Name.Equals("index", StringComparison.Ordinal)) {
|
||||
updateWC = DateTime.Now.AddSeconds(.5).ToFileTime();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWorkingCopyChanged(object o, FileSystemEventArgs e) {
|
||||
if (string.IsNullOrEmpty(e.Name)) return;
|
||||
if (e.Name == ".git" || e.Name.StartsWith(".git\\", StringComparison.Ordinal)) return;
|
||||
|
||||
updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
|
||||
}
|
||||
|
||||
private void Tick(object sender) {
|
||||
if (lockCount > 0) return;
|
||||
|
||||
var now = DateTime.Now.ToFileTime();
|
||||
if (updateBranch > 0 && now > updateBranch) {
|
||||
BranchChanged?.Invoke();
|
||||
WorkingCopyChanged?.Invoke();
|
||||
updateBranch = 0;
|
||||
updateWC = 0;
|
||||
}
|
||||
|
||||
if (updateWC > 0 && now > updateWC) {
|
||||
WorkingCopyChanged?.Invoke();
|
||||
updateWC = 0;
|
||||
}
|
||||
|
||||
if (updateSubmodules > 0 && now > updateSubmodules) {
|
||||
SubmoduleChanged?.Invoke();
|
||||
updateSubmodules = 0;
|
||||
}
|
||||
|
||||
if (updateStashes > 0 && now > updateStashes) {
|
||||
StashChanged?.Invoke();
|
||||
updateStashes = 0;
|
||||
}
|
||||
|
||||
if (updateTags > 0 && now > updateTags) {
|
||||
TagChanged?.Invoke();
|
||||
updateTags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#region PRIVATES
|
||||
private static Dictionary<string, Watcher> all = new Dictionary<string, Watcher>();
|
||||
|
||||
private FileSystemWatcher repoWatcher = null;
|
||||
private FileSystemWatcher wcWatcher = null;
|
||||
private Timer timer = null;
|
||||
private int lockCount = 0;
|
||||
private long updateWC = 0;
|
||||
private long updateBranch = 0;
|
||||
private long updateSubmodules = 0;
|
||||
private long updateStashes = 0;
|
||||
private long updateTags = 0;
|
||||
#endregion
|
||||
}
|
||||
}
|
25
src/Models/WhitespaceOption.cs
Normal file
25
src/Models/WhitespaceOption.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace SourceGit.Models {
|
||||
/// <summary>
|
||||
/// 应用补丁时空白字符的处理方式
|
||||
/// </summary>
|
||||
public class WhitespaceOption {
|
||||
public string Name { get; set; }
|
||||
public string Desc { get; set; }
|
||||
public string Arg { get; set; }
|
||||
|
||||
public static List<WhitespaceOption> Supported = new List<WhitespaceOption>() {
|
||||
new WhitespaceOption("Apply.NoWarn", "Apply.NoWarn.Desc", "nowarn"),
|
||||
new WhitespaceOption("Apply.Warn", "Apply.Warn.Desc", "warn"),
|
||||
new WhitespaceOption("Apply.Error", "Apply.Error.Desc", "error"),
|
||||
new WhitespaceOption("Apply.ErrorAll", "Apply.ErrorAll.Desc", "error-all")
|
||||
};
|
||||
|
||||
public WhitespaceOption(string n, string d, string a) {
|
||||
Name = App.Text(n);
|
||||
Desc = App.Text(d);
|
||||
Arg = a;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue