mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-26 21:17:20 -08:00
Compare commits
7 commits
b9d7f908c9
...
547c28adb8
Author | SHA1 | Date | |
---|---|---|---|
|
547c28adb8 | ||
|
a5594130ed | ||
|
d4302b4faa | ||
|
5707d0b79a | ||
|
d21a8f2449 | ||
|
f6e1e65a53 | ||
|
06fd49ba92 |
21 changed files with 216 additions and 78 deletions
|
@ -11,7 +11,7 @@ namespace SourceGit.Commands
|
||||||
Context = repo;
|
Context = repo;
|
||||||
Args = includeUntracked ? "add ." : "add -u .";
|
Args = includeUntracked ? "add ." : "add -u .";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Add(string repo, List<Models.Change> changes)
|
public Add(string repo, List<Models.Change> changes)
|
||||||
{
|
{
|
||||||
WorkingDirectory = repo;
|
WorkingDirectory = repo;
|
||||||
|
|
|
@ -4,17 +4,37 @@ namespace SourceGit.Commands
|
||||||
{
|
{
|
||||||
public class Commit : Command
|
public class Commit : Command
|
||||||
{
|
{
|
||||||
public Commit(string repo, string message, bool amend)
|
public Commit(string repo, string message, bool amend, bool signOff)
|
||||||
{
|
{
|
||||||
var file = Path.GetTempFileName();
|
_tmpFile = Path.GetTempFileName();
|
||||||
File.WriteAllText(file, message);
|
File.WriteAllText(_tmpFile, message);
|
||||||
|
|
||||||
WorkingDirectory = repo;
|
WorkingDirectory = repo;
|
||||||
Context = repo;
|
Context = repo;
|
||||||
TraitErrorAsOutput = true;
|
TraitErrorAsOutput = true;
|
||||||
Args = $"commit --allow-empty --file=\"{file}\"";
|
Args = $"commit --allow-empty --file=\"{_tmpFile}\"";
|
||||||
if (amend)
|
if (amend)
|
||||||
Args += " --amend --no-edit";
|
Args += " --amend --no-edit";
|
||||||
|
if (signOff)
|
||||||
|
Args += " --signoff";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Run()
|
||||||
|
{
|
||||||
|
var succ = Exec();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(_tmpFile);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return succ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _tmpFile = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,12 @@ namespace SourceGit.Models
|
||||||
set;
|
set;
|
||||||
} = 10;
|
} = 10;
|
||||||
|
|
||||||
|
public bool EnableSignOffForCommit
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
} = false;
|
||||||
|
|
||||||
public void PushCommitMessage(string message)
|
public void PushCommitMessage(string message)
|
||||||
{
|
{
|
||||||
var existIdx = CommitMessages.IndexOf(message);
|
var existIdx = CommitMessages.IndexOf(message);
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
<x:String x:Key="Text.BinaryNotSupported" xml:space="preserve">BINÄRE DATEI NICHT UNTERSTÜTZT!!!</x:String>
|
<x:String x:Key="Text.BinaryNotSupported" xml:space="preserve">BINÄRE DATEI NICHT UNTERSTÜTZT!!!</x:String>
|
||||||
<x:String x:Key="Text.Blame" xml:space="preserve">Blame</x:String>
|
<x:String x:Key="Text.Blame" xml:space="preserve">Blame</x:String>
|
||||||
<x:String x:Key="Text.BlameTypeNotSupported" xml:space="preserve">BLAME WIRD BEI DIESER DATEI NICHT UNTERSTÜTZT!!!</x:String>
|
<x:String x:Key="Text.BlameTypeNotSupported" xml:space="preserve">BLAME WIRD BEI DIESER DATEI NICHT UNTERSTÜTZT!!!</x:String>
|
||||||
<x:String x:Key="Text.BranchCM.Checkout" xml:space="preserve">Auscheken von ${0}$...</x:String>
|
<x:String x:Key="Text.BranchCM.Checkout" xml:space="preserve">Auschecken von ${0}$...</x:String>
|
||||||
<x:String x:Key="Text.BranchCM.CompareWithBranch" xml:space="preserve">Mit Branch vergleichen</x:String>
|
<x:String x:Key="Text.BranchCM.CompareWithBranch" xml:space="preserve">Mit Branch vergleichen</x:String>
|
||||||
<x:String x:Key="Text.BranchCM.CompareWithHead" xml:space="preserve">Mit HEAD vergleichen</x:String>
|
<x:String x:Key="Text.BranchCM.CompareWithHead" xml:space="preserve">Mit HEAD vergleichen</x:String>
|
||||||
<x:String x:Key="Text.BranchCM.CompareWithWorktree" xml:space="preserve">Mit Worktree vergleichen</x:String>
|
<x:String x:Key="Text.BranchCM.CompareWithWorktree" xml:space="preserve">Mit Worktree vergleichen</x:String>
|
||||||
|
@ -161,6 +161,13 @@
|
||||||
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Arbeitsplätze</x:String>
|
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Arbeitsplätze</x:String>
|
||||||
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Farbe</x:String>
|
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Farbe</x:String>
|
||||||
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Zuletzt geöffnete Tabs beim Starten wiederherstellen</x:String>
|
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Zuletzt geöffnete Tabs beim Starten wiederherstellen</x:String>
|
||||||
|
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">Konventionelle Commit-Hilfe</x:String>
|
||||||
|
<x:String x:Key="Text.ConventionalCommit.BreakingChanges" xml:space="preserve">Inkompatible Änderung:</x:String>
|
||||||
|
<x:String x:Key="Text.ConventionalCommit.ClosedIssue" xml:space="preserve">Geschlossenes Ticket:</x:String>
|
||||||
|
<x:String x:Key="Text.ConventionalCommit.Detail" xml:space="preserve">Änderungen im Detail:</x:String>
|
||||||
|
<x:String x:Key="Text.ConventionalCommit.Scope" xml:space="preserve">Geltungsbereich:</x:String>
|
||||||
|
<x:String x:Key="Text.ConventionalCommit.ShortDescription" xml:space="preserve">Kurzbeschreibung:</x:String>
|
||||||
|
<x:String x:Key="Text.ConventionalCommit.Type" xml:space="preserve">Art der Änderung:</x:String>
|
||||||
<x:String x:Key="Text.Copy" xml:space="preserve">Kopieren</x:String>
|
<x:String x:Key="Text.Copy" xml:space="preserve">Kopieren</x:String>
|
||||||
<x:String x:Key="Text.CopyAllText" xml:space="preserve">Kopiere gesamten Text</x:String>
|
<x:String x:Key="Text.CopyAllText" xml:space="preserve">Kopiere gesamten Text</x:String>
|
||||||
<x:String x:Key="Text.CopyMessage" xml:space="preserve">COMMIT-NACHRICHT KOPIEREN</x:String>
|
<x:String x:Key="Text.CopyMessage" xml:space="preserve">COMMIT-NACHRICHT KOPIEREN</x:String>
|
||||||
|
@ -323,6 +330,9 @@
|
||||||
<x:String x:Key="Text.Histories.Header.SHA" xml:space="preserve">SHA</x:String>
|
<x:String x:Key="Text.Histories.Header.SHA" xml:space="preserve">SHA</x:String>
|
||||||
<x:String x:Key="Text.Histories.Header.Time" xml:space="preserve">COMMIT ZEITPUNKT</x:String>
|
<x:String x:Key="Text.Histories.Header.Time" xml:space="preserve">COMMIT ZEITPUNKT</x:String>
|
||||||
<x:String x:Key="Text.Histories.Selected" xml:space="preserve">{0} COMMITS AUSGEWÄHLT</x:String>
|
<x:String x:Key="Text.Histories.Selected" xml:space="preserve">{0} COMMITS AUSGEWÄHLT</x:String>
|
||||||
|
<x:String x:Key="Text.Histories.Tips" xml:space="preserve">Halte 'Strg' oder 'Umschalt', um mehrere Commits auszuwählen.</x:String>
|
||||||
|
<x:String x:Key="Text.Histories.Tips.MacOS" xml:space="preserve">Halte ⌘ oder ⇧, um mehrere Commits auszuwählen</x:String>
|
||||||
|
<x:String x:Key="Text.Histories.Tips.Prefix" xml:space="preserve">TIPPS:</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys" xml:space="preserve">Tastaturkürzel Referenz</x:String>
|
<x:String x:Key="Text.Hotkeys" xml:space="preserve">Tastaturkürzel Referenz</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys.Global" xml:space="preserve">GLOBAL</x:String>
|
<x:String x:Key="Text.Hotkeys.Global" xml:space="preserve">GLOBAL</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys.Global.CancelPopup" xml:space="preserve">Aktuelles Popup schließen</x:String>
|
<x:String x:Key="Text.Hotkeys.Global.CancelPopup" xml:space="preserve">Aktuelles Popup schließen</x:String>
|
||||||
|
@ -498,6 +508,7 @@
|
||||||
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Alles löschen</x:String>
|
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Alles löschen</x:String>
|
||||||
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">Repository Einstellungen</x:String>
|
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">Repository Einstellungen</x:String>
|
||||||
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">WEITER</x:String>
|
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">WEITER</x:String>
|
||||||
|
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Option '--reflog' einschalten</x:String>
|
||||||
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Öffne im Datei-Browser</x:String>
|
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Öffne im Datei-Browser</x:String>
|
||||||
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Suche Branches/Tags/Submodule</x:String>
|
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Suche Branches/Tags/Submodule</x:String>
|
||||||
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">GEFILTERT:</x:String>
|
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">GEFILTERT:</x:String>
|
||||||
|
@ -590,6 +601,7 @@
|
||||||
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">Submodul löschen</x:String>
|
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">Submodul löschen</x:String>
|
||||||
<x:String x:Key="Text.Sure" xml:space="preserve">OK</x:String>
|
<x:String x:Key="Text.Sure" xml:space="preserve">OK</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">Tag-Namen kopieren</x:String>
|
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">Tag-Namen kopieren</x:String>
|
||||||
|
<x:String x:Key="Text.TagCM.CopyMessage" xml:space="preserve">Tag-Nachricht kopieren</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">Lösche ${0}$...</x:String>
|
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">Lösche ${0}$...</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">Pushe ${0}$...</x:String>
|
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">Pushe ${0}$...</x:String>
|
||||||
<x:String x:Key="Text.URL" xml:space="preserve">URL:</x:String>
|
<x:String x:Key="Text.URL" xml:space="preserve">URL:</x:String>
|
||||||
|
|
|
@ -143,6 +143,7 @@
|
||||||
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Fetch remotes automatically</x:String>
|
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Fetch remotes automatically</x:String>
|
||||||
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minute(s)</x:String>
|
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minute(s)</x:String>
|
||||||
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Default Remote</x:String>
|
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Default Remote</x:String>
|
||||||
|
<x:String x:Key="Text.Configure.Git.EnableSignOff" xml:space="preserve">Enable --signoff for commit</x:String>
|
||||||
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE TRACKER</x:String>
|
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE TRACKER</x:String>
|
||||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Add Sample Github Rule</x:String>
|
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Add Sample Github Rule</x:String>
|
||||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Add Sample Jira Rule</x:String>
|
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Add Sample Jira Rule</x:String>
|
||||||
|
|
|
@ -146,6 +146,7 @@
|
||||||
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">启用定时自动拉取远程更新</x:String>
|
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">启用定时自动拉取远程更新</x:String>
|
||||||
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">分钟</x:String>
|
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">分钟</x:String>
|
||||||
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">默认远程</x:String>
|
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">默认远程</x:String>
|
||||||
|
<x:String x:Key="Text.Configure.Git.EnableSignOff" xml:space="preserve">提交信息追加署名 (--signoff)</x:String>
|
||||||
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE追踪</x:String>
|
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE追踪</x:String>
|
||||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增匹配Github Issue规则</x:String>
|
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增匹配Github Issue规则</x:String>
|
||||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">新增匹配Jira规则</x:String>
|
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">新增匹配Jira规则</x:String>
|
||||||
|
|
|
@ -146,6 +146,7 @@
|
||||||
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">啟用定時自動提取 (fetch) 遠端更新</x:String>
|
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">啟用定時自動提取 (fetch) 遠端更新</x:String>
|
||||||
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">分鐘</x:String>
|
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">分鐘</x:String>
|
||||||
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">預設遠端存放庫</x:String>
|
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">預設遠端存放庫</x:String>
|
||||||
|
<x:String x:Key="Text.Configure.Git.EnableSignOff" xml:space="preserve">提交資訊追加署名 (--signoff)</x:String>
|
||||||
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">Issue 追蹤</x:String>
|
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">Issue 追蹤</x:String>
|
||||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增符合 GitHub Issue 規則</x:String>
|
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增符合 GitHub Issue 規則</x:String>
|
||||||
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">新增符合 Jira 規則</x:String>
|
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">新增符合 Jira 規則</x:String>
|
||||||
|
|
|
@ -80,21 +80,23 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
private void UpdateVisibleLocks()
|
private void UpdateVisibleLocks()
|
||||||
{
|
{
|
||||||
|
var visible = new List<Models.LFSLock>();
|
||||||
|
|
||||||
if (!_showOnlyMyLocks)
|
if (!_showOnlyMyLocks)
|
||||||
{
|
{
|
||||||
VisibleLocks = _cachedLocks;
|
foreach (var lfsLock in _cachedLocks)
|
||||||
|
visible.Add(lfsLock);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var visible = new List<Models.LFSLock>();
|
|
||||||
foreach (var lfsLock in _cachedLocks)
|
foreach (var lfsLock in _cachedLocks)
|
||||||
{
|
{
|
||||||
if (lfsLock.User == _userName)
|
if (lfsLock.User == _userName)
|
||||||
visible.Add(lfsLock);
|
visible.Add(lfsLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
VisibleLocks = visible;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VisibleLocks = visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string _repo;
|
private string _repo;
|
||||||
|
|
|
@ -577,7 +577,7 @@ namespace SourceGit.ViewModels
|
||||||
private bool RemoveInvalidRepositoriesRecursive(List<RepositoryNode> collection)
|
private bool RemoveInvalidRepositoriesRecursive(List<RepositoryNode> collection)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
for (int i = collection.Count - 1; i >= 0; i--)
|
for (int i = collection.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var node = collection[i];
|
var node = collection[i];
|
||||||
|
|
|
@ -60,6 +60,12 @@ namespace SourceGit.ViewModels
|
||||||
set => SetProperty(ref _httpProxy, value);
|
set => SetProperty(ref _httpProxy, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool EnableSignOffForCommit
|
||||||
|
{
|
||||||
|
get => _repo.Settings.EnableSignOffForCommit;
|
||||||
|
set => _repo.Settings.EnableSignOffForCommit = value;
|
||||||
|
}
|
||||||
|
|
||||||
public bool EnableAutoFetch
|
public bool EnableAutoFetch
|
||||||
{
|
{
|
||||||
get => _repo.Settings.EnableAutoFetch;
|
get => _repo.Settings.EnableAutoFetch;
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
return Task.Run(() =>
|
return Task.Run(() =>
|
||||||
{
|
{
|
||||||
var succ = new Commands.Commit(_repo.FullPath, _message, true).Exec();
|
var succ = new Commands.Commit(_repo.FullPath, _message, true, _repo.Settings.EnableSignOffForCommit).Run();
|
||||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||||
return succ;
|
return succ;
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
var succ = new Commands.Reset(_repo.FullPath, Target.SHA, "--soft").Exec();
|
var succ = new Commands.Reset(_repo.FullPath, Target.SHA, "--soft").Exec();
|
||||||
if (succ)
|
if (succ)
|
||||||
succ = new Commands.Commit(_repo.FullPath, _message, true).Exec();
|
succ = new Commands.Commit(_repo.FullPath, _message, true, _repo.Settings.EnableSignOffForCommit).Run();
|
||||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||||
return succ;
|
return succ;
|
||||||
});
|
});
|
||||||
|
|
|
@ -33,11 +33,6 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
public class WorkingCopy : ObservableObject
|
public class WorkingCopy : ObservableObject
|
||||||
{
|
{
|
||||||
public string RepoPath
|
|
||||||
{
|
|
||||||
get => _repo.FullPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IncludeUntracked
|
public bool IncludeUntracked
|
||||||
{
|
{
|
||||||
get => _repo.IncludeUntracked;
|
get => _repo.IncludeUntracked;
|
||||||
|
@ -408,6 +403,25 @@ namespace SourceGit.ViewModels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void GenerateCommitMessageByAI()
|
||||||
|
{
|
||||||
|
if (!Models.OpenAI.IsValid)
|
||||||
|
{
|
||||||
|
App.RaiseException(_repo.FullPath, "Bad configuration for OpenAI");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_staged is { Count: > 0 })
|
||||||
|
{
|
||||||
|
var dialog = new Views.AIAssistant(_repo.FullPath, _staged, generated => CommitMessage = generated);
|
||||||
|
App.OpenDialog(dialog);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
App.RaiseException(_repo.FullPath, "No files added to commit!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Commit()
|
public void Commit()
|
||||||
{
|
{
|
||||||
DoCommit(false, false, false);
|
DoCommit(false, false, false);
|
||||||
|
@ -1311,7 +1325,7 @@ namespace SourceGit.ViewModels
|
||||||
succ = new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Exec();
|
succ = new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Exec();
|
||||||
|
|
||||||
if (succ)
|
if (succ)
|
||||||
succ = new Commands.Commit(_repo.FullPath, _commitMessage, _useAmend).Exec();
|
succ = new Commands.Commit(_repo.FullPath, _commitMessage, _useAmend, _repo.Settings.EnableSignOffForCommit).Run();
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
xmlns:c="using:SourceGit.Converters"
|
xmlns:c="using:SourceGit.Converters"
|
||||||
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="120"
|
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="120"
|
||||||
x:Class="SourceGit.Views.AIAssistant"
|
x:Class="SourceGit.Views.AIAssistant"
|
||||||
x:DataType="vm:WorkingCopy"
|
|
||||||
x:Name="ThisControl"
|
x:Name="ThisControl"
|
||||||
Icon="/App.ico"
|
Icon="/App.ico"
|
||||||
Title="{DynamicResource Text.AIAssistant}"
|
Title="{DynamicResource Text.AIAssistant}"
|
||||||
|
@ -55,6 +54,7 @@
|
||||||
Margin="16"
|
Margin="16"
|
||||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
|
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
|
Text="Generating commit message... Please wait!"
|
||||||
TextTrimming="CharacterEllipsis"/>
|
TextTrimming="CharacterEllipsis"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</v:ChromelessWindow>
|
</v:ChromelessWindow>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -13,28 +15,36 @@ namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
_cancel = new CancellationTokenSource();
|
_cancel = new CancellationTokenSource();
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
ProgressMessage.Text = "Generating commit message... Please wait!";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GenerateCommitMessage()
|
public AIAssistant(string repo, List<Models.Change> changes, Action<string> onDone)
|
||||||
{
|
{
|
||||||
if (DataContext is ViewModels.WorkingCopy vm)
|
_repo = repo;
|
||||||
|
_changes = changes;
|
||||||
|
_onDone = onDone;
|
||||||
|
_cancel = new CancellationTokenSource();
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnOpened(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnOpened(e);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(_repo))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
var message = new Commands.GenerateCommitMessage(_repo, _changes, _cancel.Token, SetDescription).Result();
|
||||||
|
if (_cancel.IsCancellationRequested)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
{
|
{
|
||||||
var message = new Commands.GenerateCommitMessage(vm.RepoPath, vm.Staged, _cancel.Token, SetDescription).Result();
|
_onDone?.Invoke(message);
|
||||||
if (_cancel.IsCancellationRequested)
|
Close();
|
||||||
return;
|
});
|
||||||
|
}, _cancel.Token);
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
|
||||||
{
|
|
||||||
if (DataContext is ViewModels.WorkingCopy wc)
|
|
||||||
wc.CommitMessage = message;
|
|
||||||
|
|
||||||
Close();
|
|
||||||
});
|
|
||||||
}, _cancel.Token);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnClosing(WindowClosingEventArgs e)
|
protected override void OnClosing(WindowClosingEventArgs e)
|
||||||
|
@ -50,12 +60,12 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
private void SetDescription(string message)
|
private void SetDescription(string message)
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
Dispatcher.UIThread.Invoke(() => ProgressMessage.Text = message);
|
||||||
{
|
|
||||||
ProgressMessage.Text = message;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string _repo;
|
||||||
|
private List<Models.Change> _changes;
|
||||||
|
private Action<string> _onDone;
|
||||||
private CancellationTokenSource _cancel;
|
private CancellationTokenSource _cancel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,7 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
if (chars.Count >= 2 && char.IsAsciiLetterOrDigit(chars[0]) && char.IsAsciiLetterOrDigit(chars[^1]))
|
if (chars.Count >= 2 && char.IsAsciiLetterOrDigit(chars[0]) && char.IsAsciiLetterOrDigit(chars[^1]))
|
||||||
return string.Format("{0}{1}", chars[0], chars[^1]);
|
return string.Format("{0}{1}", chars[0], chars[^1]);
|
||||||
|
|
||||||
return name.Substring(0, 1);
|
return name.Substring(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Configure.Git}"/>
|
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Configure.Git}"/>
|
||||||
</TabItem.Header>
|
</TabItem.Header>
|
||||||
|
|
||||||
<Grid Margin="16,4,16,8" RowDefinitions="32,32,32,32,32,32,32,32" ColumnDefinitions="Auto,*">
|
<Grid Margin="16,4,16,8" RowDefinitions="32,32,32,32,32,32,32,32,32" ColumnDefinitions="Auto,*">
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||||
Margin="0,0,8,0"
|
Margin="0,0,8,0"
|
||||||
|
@ -123,10 +123,14 @@
|
||||||
IsChecked="{Binding GPGCommitSigningEnabled, Mode=TwoWay}"/>
|
IsChecked="{Binding GPGCommitSigningEnabled, Mode=TwoWay}"/>
|
||||||
|
|
||||||
<CheckBox Grid.Row="6" Grid.Column="1"
|
<CheckBox Grid.Row="6" Grid.Column="1"
|
||||||
|
Content="{DynamicResource Text.Configure.Git.EnableSignOff}"
|
||||||
|
IsChecked="{Binding EnableSignOffForCommit, Mode=TwoWay}"/>
|
||||||
|
|
||||||
|
<CheckBox Grid.Row="7" Grid.Column="1"
|
||||||
Content="{DynamicResource Text.Preference.GPG.TagEnabled}"
|
Content="{DynamicResource Text.Preference.GPG.TagEnabled}"
|
||||||
IsChecked="{Binding GPGTagSigningEnabled, Mode=TwoWay}"/>
|
IsChecked="{Binding GPGTagSigningEnabled, Mode=TwoWay}"/>
|
||||||
|
|
||||||
<StackPanel Grid.Row="7" Grid.Column="1" Orientation="Horizontal">
|
<StackPanel Grid.Row="8" Grid.Column="1" Orientation="Horizontal">
|
||||||
<CheckBox x:Name="AutoFetchCheckBox"
|
<CheckBox x:Name="AutoFetchCheckBox"
|
||||||
Content="{DynamicResource Text.Configure.Git.AutoFetch}"
|
Content="{DynamicResource Text.Configure.Git.AutoFetch}"
|
||||||
IsChecked="{Binding EnableAutoFetch, Mode=TwoWay}"/>
|
IsChecked="{Binding EnableAutoFetch, Mode=TwoWay}"/>
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace SourceGit.Views
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnChangeContextRequested(object sender, ContextRequestedEventArgs e)
|
private void OnChangeContextRequested(object sender, ContextRequestedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is ViewModels.StashesPage vm && sender is Grid grid)
|
if (DataContext is ViewModels.StashesPage vm && sender is Grid grid)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,6 @@ using System.Text;
|
||||||
|
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Primitives;
|
|
||||||
using Avalonia.Data;
|
using Avalonia.Data;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
@ -72,6 +71,8 @@ namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
_usePresenter = usePresenter;
|
_usePresenter = usePresenter;
|
||||||
_isOld = isOld;
|
_isOld = isOld;
|
||||||
|
|
||||||
|
Margin = new Thickness(8, 0);
|
||||||
ClipToBounds = true;
|
ClipToBounds = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +146,89 @@ namespace SourceGit.Views
|
||||||
private bool _isOld = false;
|
private bool _isOld = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class LineModifyTypeMargin : AbstractMargin
|
||||||
|
{
|
||||||
|
public LineModifyTypeMargin()
|
||||||
|
{
|
||||||
|
Margin = new Thickness(1, 0);
|
||||||
|
ClipToBounds = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Render(DrawingContext context)
|
||||||
|
{
|
||||||
|
var presenter = this.FindAncestorOfType<ThemedTextDiffPresenter>();
|
||||||
|
if (presenter == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var lines = presenter.GetLines();
|
||||||
|
var view = TextView;
|
||||||
|
if (view != null && view.VisualLinesValid)
|
||||||
|
{
|
||||||
|
var typeface = view.CreateTypeface();
|
||||||
|
foreach (var line in view.VisualLines)
|
||||||
|
{
|
||||||
|
if (line.IsDisposed || line.FirstDocumentLine == null || line.FirstDocumentLine.IsDeleted)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var index = line.FirstDocumentLine.LineNumber;
|
||||||
|
if (index > lines.Count)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var info = lines[index - 1];
|
||||||
|
var y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.LineMiddle) - view.VerticalOffset;
|
||||||
|
var indicator = null as FormattedText;
|
||||||
|
if (info.Type == Models.TextDiffLineType.Added)
|
||||||
|
{
|
||||||
|
indicator = new FormattedText(
|
||||||
|
"+",
|
||||||
|
CultureInfo.CurrentCulture,
|
||||||
|
FlowDirection.LeftToRight,
|
||||||
|
typeface,
|
||||||
|
presenter.FontSize,
|
||||||
|
Brushes.Green);
|
||||||
|
}
|
||||||
|
else if (info.Type == Models.TextDiffLineType.Deleted)
|
||||||
|
{
|
||||||
|
indicator = new FormattedText(
|
||||||
|
"-",
|
||||||
|
CultureInfo.CurrentCulture,
|
||||||
|
FlowDirection.LeftToRight,
|
||||||
|
typeface,
|
||||||
|
presenter.FontSize,
|
||||||
|
Brushes.Red);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indicator != null)
|
||||||
|
context.DrawText(indicator, new Point(0, y - indicator.Height * 0.5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
|
{
|
||||||
|
var presenter = this.FindAncestorOfType<ThemedTextDiffPresenter>();
|
||||||
|
if (presenter == null)
|
||||||
|
return new Size(0, 0);
|
||||||
|
|
||||||
|
var maxLineNumber = presenter.GetMaxLineNumber();
|
||||||
|
var typeface = TextView.CreateTypeface();
|
||||||
|
var test = new FormattedText(
|
||||||
|
$"-",
|
||||||
|
CultureInfo.CurrentCulture,
|
||||||
|
FlowDirection.LeftToRight,
|
||||||
|
typeface,
|
||||||
|
presenter.FontSize,
|
||||||
|
Brushes.White);
|
||||||
|
return new Size(test.Width, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDataContextChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnDataContextChanged(e);
|
||||||
|
InvalidateMeasure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class LineBackgroundRenderer : IBackgroundRenderer
|
public class LineBackgroundRenderer : IBackgroundRenderer
|
||||||
{
|
{
|
||||||
public KnownLayer Layer => KnownLayer.Background;
|
public KnownLayer Layer => KnownLayer.Background;
|
||||||
|
@ -674,10 +758,11 @@ namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
public CombinedTextDiffPresenter() : base(new TextArea(), new TextDocument())
|
public CombinedTextDiffPresenter() : base(new TextArea(), new TextDocument())
|
||||||
{
|
{
|
||||||
TextArea.LeftMargins.Add(new LineNumberMargin(false, true) { Margin = new Thickness(8, 0) });
|
TextArea.LeftMargins.Add(new LineNumberMargin(false, true));
|
||||||
TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
|
TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
|
||||||
TextArea.LeftMargins.Add(new LineNumberMargin(false, false) { Margin = new Thickness(8, 0) });
|
TextArea.LeftMargins.Add(new LineNumberMargin(false, false));
|
||||||
TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
|
TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
|
||||||
|
TextArea.LeftMargins.Add(new LineModifyTypeMargin());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override List<Models.TextDiffLine> GetLines()
|
public override List<Models.TextDiffLine> GetLines()
|
||||||
|
@ -878,8 +963,9 @@ namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
public SingleSideTextDiffPresenter() : base(new TextArea(), new TextDocument())
|
public SingleSideTextDiffPresenter() : base(new TextArea(), new TextDocument())
|
||||||
{
|
{
|
||||||
TextArea.LeftMargins.Add(new LineNumberMargin(true, false) { Margin = new Thickness(8, 0) });
|
TextArea.LeftMargins.Add(new LineNumberMargin(true, false));
|
||||||
TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
|
TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
|
||||||
|
TextArea.LeftMargins.Add(new LineModifyTypeMargin());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override List<Models.TextDiffLine> GetLines()
|
public override List<Models.TextDiffLine> GetLines()
|
||||||
|
|
|
@ -199,7 +199,7 @@
|
||||||
<Button Grid.Column="1"
|
<Button Grid.Column="1"
|
||||||
Classes="icon_button"
|
Classes="icon_button"
|
||||||
Margin="4,2,0,0"
|
Margin="4,2,0,0"
|
||||||
Click="OnOpenAIAssist"
|
Command="{Binding GenerateCommitMessageByAI}"
|
||||||
ToolTip.Tip="{DynamicResource Text.AIAssistant.Tip}"
|
ToolTip.Tip="{DynamicResource Text.AIAssistant.Tip}"
|
||||||
ToolTip.Placement="Top"
|
ToolTip.Placement="Top"
|
||||||
ToolTip.VerticalOffset="0">
|
ToolTip.VerticalOffset="0">
|
||||||
|
|
|
@ -120,38 +120,13 @@ namespace SourceGit.Views
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnOpenAIAssist(object _, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (!Models.OpenAI.IsValid)
|
|
||||||
{
|
|
||||||
App.RaiseException(null, "Bad configuration for OpenAI");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DataContext is ViewModels.WorkingCopy vm)
|
|
||||||
{
|
|
||||||
if (vm.Staged is { Count: > 0 })
|
|
||||||
{
|
|
||||||
var dialog = new AIAssistant() { DataContext = vm };
|
|
||||||
dialog.GenerateCommitMessage();
|
|
||||||
App.OpenDialog(dialog);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
App.RaiseException(null, "No files added to commit!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnOpenConventionalCommitHelper(object _, RoutedEventArgs e)
|
private void OnOpenConventionalCommitHelper(object _, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is ViewModels.WorkingCopy vm)
|
if (DataContext is ViewModels.WorkingCopy vm)
|
||||||
{
|
{
|
||||||
var dialog = new ConventionalCommitMessageBuilder()
|
var dialog = new ConventionalCommitMessageBuilder()
|
||||||
{
|
{
|
||||||
DataContext = new ViewModels.ConventionalCommitMessageBuilder(vm)
|
DataContext = new ViewModels.ConventionalCommitMessageBuilder(vm)
|
||||||
};
|
};
|
||||||
|
|
||||||
App.OpenDialog(dialog);
|
App.OpenDialog(dialog);
|
||||||
|
|
Loading…
Reference in a new issue