2024-06-20 02:02:12 -07:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
using Avalonia.Collections;
|
|
|
|
|
using Avalonia.Threading;
|
|
|
|
|
|
|
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
|
|
|
|
|
|
|
|
namespace SourceGit.ViewModels
|
|
|
|
|
{
|
|
|
|
|
public class InteractiveRebaseItem : ObservableObject
|
|
|
|
|
{
|
|
|
|
|
public Models.Commit Commit
|
|
|
|
|
{
|
|
|
|
|
get;
|
|
|
|
|
private set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Models.InteractiveRebaseAction Action
|
|
|
|
|
{
|
|
|
|
|
get => _action;
|
|
|
|
|
private set => SetProperty(ref _action, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Subject
|
|
|
|
|
{
|
|
|
|
|
get => _subject;
|
|
|
|
|
private set => SetProperty(ref _subject, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string FullMessage
|
|
|
|
|
{
|
|
|
|
|
get => _fullMessage;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (SetProperty(ref _fullMessage, value))
|
|
|
|
|
{
|
|
|
|
|
var normalized = value.ReplaceLineEndings("\n");
|
|
|
|
|
var idx = normalized.IndexOf("\n\n", StringComparison.Ordinal);
|
|
|
|
|
if (idx > 0)
|
|
|
|
|
Subject = normalized.Substring(0, idx).ReplaceLineEndings(" ");
|
|
|
|
|
else
|
|
|
|
|
Subject = value.ReplaceLineEndings(" ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public InteractiveRebaseItem(Models.Commit c, string message)
|
|
|
|
|
{
|
|
|
|
|
Commit = c;
|
|
|
|
|
|
|
|
|
|
_subject = c.Subject;
|
|
|
|
|
_fullMessage = message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetAction(object param)
|
|
|
|
|
{
|
|
|
|
|
Action = (Models.InteractiveRebaseAction)param;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Models.InteractiveRebaseAction _action = Models.InteractiveRebaseAction.Pick;
|
|
|
|
|
private string _subject = string.Empty;
|
|
|
|
|
private string _fullMessage = string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class InteractiveRebase : ObservableObject
|
|
|
|
|
{
|
|
|
|
|
public Models.Branch Current
|
|
|
|
|
{
|
|
|
|
|
get;
|
|
|
|
|
private set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Models.Commit On
|
|
|
|
|
{
|
|
|
|
|
get;
|
|
|
|
|
private set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsLoading
|
|
|
|
|
{
|
|
|
|
|
get => _isLoading;
|
|
|
|
|
private set => SetProperty(ref _isLoading, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public AvaloniaList<InteractiveRebaseItem> Items
|
|
|
|
|
{
|
|
|
|
|
get;
|
|
|
|
|
private set;
|
|
|
|
|
} = new AvaloniaList<InteractiveRebaseItem>();
|
|
|
|
|
|
|
|
|
|
public InteractiveRebaseItem SelectedItem
|
|
|
|
|
{
|
|
|
|
|
get => _selectedItem;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (SetProperty(ref _selectedItem, value))
|
|
|
|
|
DetailContext.Commit = value != null ? value.Commit : null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CommitDetail DetailContext
|
|
|
|
|
{
|
|
|
|
|
get;
|
|
|
|
|
private set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public InteractiveRebase(Repository repo, Models.Branch current, Models.Commit on)
|
|
|
|
|
{
|
|
|
|
|
var repoPath = repo.FullPath;
|
|
|
|
|
_repo = repo;
|
|
|
|
|
|
|
|
|
|
Current = current;
|
|
|
|
|
On = on;
|
|
|
|
|
IsLoading = true;
|
|
|
|
|
DetailContext = new CommitDetail(repoPath);
|
|
|
|
|
|
|
|
|
|
Task.Run(() =>
|
|
|
|
|
{
|
|
|
|
|
var commits = new Commands.QueryCommits(repoPath, $"{on.SHA}...HEAD", false).Result();
|
|
|
|
|
var messages = new Dictionary<string, string>();
|
|
|
|
|
|
|
|
|
|
foreach (var c in commits)
|
|
|
|
|
{
|
|
|
|
|
var fullMessage = new Commands.QueryCommitFullMessage(repoPath, c.SHA).Result();
|
|
|
|
|
messages.Add(c.SHA, fullMessage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Dispatcher.UIThread.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
var list = new List<InteractiveRebaseItem>();
|
|
|
|
|
foreach (var c in commits)
|
|
|
|
|
list.Add(new InteractiveRebaseItem(c, messages[c.SHA]));
|
|
|
|
|
|
|
|
|
|
Items.AddRange(list);
|
|
|
|
|
IsLoading = false;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void MoveItemUp(InteractiveRebaseItem item)
|
|
|
|
|
{
|
|
|
|
|
var idx = Items.IndexOf(item);
|
|
|
|
|
if (idx > 0)
|
|
|
|
|
{
|
|
|
|
|
var prev = Items[idx - 1];
|
|
|
|
|
Items.RemoveAt(idx - 1);
|
|
|
|
|
Items.Insert(idx, prev);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void MoveItemDown(InteractiveRebaseItem item)
|
|
|
|
|
{
|
|
|
|
|
var idx = Items.IndexOf(item);
|
|
|
|
|
if (idx < Items.Count - 1)
|
|
|
|
|
{
|
|
|
|
|
var next = Items[idx + 1];
|
|
|
|
|
Items.RemoveAt(idx + 1);
|
|
|
|
|
Items.Insert(idx, next);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<bool> Start()
|
|
|
|
|
{
|
|
|
|
|
_repo.SetWatcherEnabled(false);
|
|
|
|
|
|
|
|
|
|
var saveFile = Path.Combine(_repo.GitDir, "sourcegit_rebase_jobs.json");
|
2024-07-08 19:16:15 -07:00
|
|
|
|
var collection = new Models.InteractiveRebaseJobCollection();
|
2024-06-20 02:02:12 -07:00
|
|
|
|
for (int i = Items.Count - 1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
var item = Items[i];
|
2024-07-08 19:16:15 -07:00
|
|
|
|
collection.Jobs.Add(new Models.InteractiveRebaseJob()
|
2024-06-20 02:02:12 -07:00
|
|
|
|
{
|
|
|
|
|
SHA = item.Commit.SHA,
|
|
|
|
|
Action = item.Action,
|
|
|
|
|
Message = item.FullMessage,
|
|
|
|
|
});
|
|
|
|
|
}
|
2024-07-08 19:16:15 -07:00
|
|
|
|
File.WriteAllText(saveFile, JsonSerializer.Serialize(collection, JsonCodeGen.Default.InteractiveRebaseJobCollection));
|
2024-06-20 02:02:12 -07:00
|
|
|
|
|
|
|
|
|
return Task.Run(() =>
|
|
|
|
|
{
|
|
|
|
|
var succ = new Commands.InteractiveRebase(_repo.FullPath, On.SHA).Exec();
|
|
|
|
|
if (succ)
|
|
|
|
|
File.Delete(saveFile);
|
|
|
|
|
|
|
|
|
|
Dispatcher.UIThread.Invoke(() => _repo.SetWatcherEnabled(true));
|
|
|
|
|
return succ;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Repository _repo = null;
|
|
|
|
|
private bool _isLoading = false;
|
|
|
|
|
private InteractiveRebaseItem _selectedItem = null;
|
|
|
|
|
}
|
|
|
|
|
}
|