Compare commits

..

3 commits

Author SHA1 Message Date
leo
85b83990a8
code_style: run dotnet format
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
2024-09-25 16:24:04 +08:00
leo
acf71a30b8
enhance: re-calculate the opened repositories in active workspace (#511) 2024-09-25 15:07:23 +08:00
leo
28c59ee0ab
code_style: move the code to initialize informations to spawn git sub-process to function Models.Command.CreateGitStartInfo 2024-09-25 10:57:37 +08:00
9 changed files with 118 additions and 93 deletions

View file

@ -40,59 +40,7 @@ namespace SourceGit.Commands
public bool Exec() public bool Exec()
{ {
var start = new ProcessStartInfo(); var start = CreateGitStartInfo();
start.FileName = Native.OS.GitExecutable;
start.Arguments = "--no-pager -c core.quotepath=off -c credential.helper=manager ";
start.UseShellExecute = false;
start.CreateNoWindow = true;
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.StandardOutputEncoding = Encoding.UTF8;
start.StandardErrorEncoding = Encoding.UTF8;
// Force using this app as SSH askpass program
var selfExecFile = Process.GetCurrentProcess().MainModule!.FileName;
if (!OperatingSystem.IsLinux())
start.Environment.Add("DISPLAY", "required");
start.Environment.Add("SSH_ASKPASS", selfExecFile); // Can not use parameter here, because it invoked by SSH with `exec`
start.Environment.Add("SSH_ASKPASS_REQUIRE", "prefer");
start.Environment.Add("SOURCEGIT_LAUNCH_AS_ASKPASS", "TRUE");
// If an SSH private key was provided, sets the environment.
if (!string.IsNullOrEmpty(SSHKey))
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new -i '{SSHKey}'");
else
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new");
// Force using en_US.UTF-8 locale to avoid GCM crash
if (OperatingSystem.IsLinux())
start.Environment.Add("LANG", "en_US.UTF-8");
// Fix sometimes `LSEnvironment` not working on macOS
if (OperatingSystem.IsMacOS())
start.Environment.Add("PATH", "/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin");
// Force using this app as git editor.
switch (Editor)
{
case EditorType.CoreEditor:
start.Arguments += $"-c core.editor=\"\\\"{selfExecFile}\\\" --core-editor\" ";
break;
case EditorType.RebaseEditor:
start.Arguments += $"-c core.editor=\"\\\"{selfExecFile}\\\" --rebase-message-editor\" -c sequence.editor=\"\\\"{selfExecFile}\\\" --rebase-todo-editor\" -c rebase.abbreviateCommands=true ";
break;
default:
start.Arguments += "-c core.editor=true ";
break;
}
// Append command args
start.Arguments += Args;
// Working directory
if (!string.IsNullOrEmpty(WorkingDirectory))
start.WorkingDirectory = WorkingDirectory;
var errs = new List<string>(); var errs = new List<string>();
var proc = new Process() { StartInfo = start }; var proc = new Process() { StartInfo = start };
var isCancelled = false; var isCancelled = false;
@ -186,20 +134,9 @@ namespace SourceGit.Commands
public ReadToEndResult ReadToEnd() public ReadToEndResult ReadToEnd()
{ {
var start = new ProcessStartInfo(); var start = CreateGitStartInfo();
start.FileName = Native.OS.GitExecutable;
start.Arguments = "--no-pager -c core.quotepath=off " + Args;
start.UseShellExecute = false;
start.CreateNoWindow = true;
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.StandardOutputEncoding = Encoding.UTF8;
start.StandardErrorEncoding = Encoding.UTF8;
if (!string.IsNullOrEmpty(WorkingDirectory))
start.WorkingDirectory = WorkingDirectory;
var proc = new Process() { StartInfo = start }; var proc = new Process() { StartInfo = start };
try try
{ {
proc.Start(); proc.Start();
@ -227,7 +164,68 @@ namespace SourceGit.Commands
return rs; return rs;
} }
protected virtual void OnReadline(string line) { } protected virtual void OnReadline(string line)
{
// Implemented by derived class
}
private ProcessStartInfo CreateGitStartInfo()
{
var start = new ProcessStartInfo();
start.FileName = Native.OS.GitExecutable;
start.Arguments = "--no-pager -c core.quotepath=off -c credential.helper=manager ";
start.UseShellExecute = false;
start.CreateNoWindow = true;
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.StandardOutputEncoding = Encoding.UTF8;
start.StandardErrorEncoding = Encoding.UTF8;
// Force using this app as SSH askpass program
var selfExecFile = Process.GetCurrentProcess().MainModule!.FileName;
if (!OperatingSystem.IsLinux())
start.Environment.Add("DISPLAY", "required");
start.Environment.Add("SSH_ASKPASS", selfExecFile); // Can not use parameter here, because it invoked by SSH with `exec`
start.Environment.Add("SSH_ASKPASS_REQUIRE", "prefer");
start.Environment.Add("SOURCEGIT_LAUNCH_AS_ASKPASS", "TRUE");
// If an SSH private key was provided, sets the environment.
if (!string.IsNullOrEmpty(SSHKey))
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new -i '{SSHKey}'");
else
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new");
// Force using en_US.UTF-8 locale to avoid GCM crash
if (OperatingSystem.IsLinux())
start.Environment.Add("LANG", "en_US.UTF-8");
// Fix sometimes `LSEnvironment` not working on macOS
if (OperatingSystem.IsMacOS())
start.Environment.Add("PATH", "/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin");
// Force using this app as git editor.
switch (Editor)
{
case EditorType.CoreEditor:
start.Arguments += $"-c core.editor=\"\\\"{selfExecFile}\\\" --core-editor\" ";
break;
case EditorType.RebaseEditor:
start.Arguments += $"-c core.editor=\"\\\"{selfExecFile}\\\" --rebase-message-editor\" -c sequence.editor=\"\\\"{selfExecFile}\\\" --rebase-todo-editor\" -c rebase.abbreviateCommands=true ";
break;
default:
start.Arguments += "-c core.editor=true ";
break;
}
// Append command args
start.Arguments += Args;
// Working directory
if (!string.IsNullOrEmpty(WorkingDirectory))
start.WorkingDirectory = WorkingDirectory;
return start;
}
[GeneratedRegex(@"\d+%")] [GeneratedRegex(@"\d+%")]
private static partial Regex REG_PROGRESS(); private static partial Regex REG_PROGRESS();

View file

@ -18,7 +18,7 @@ namespace SourceGit.Converters
{ {
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
return v; return v;
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length; var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
if (v.StartsWith(home, StringComparison.Ordinal)) if (v.StartsWith(home, StringComparison.Ordinal))

View file

@ -43,12 +43,13 @@ namespace SourceGit.Models
{ {
_mode = mode; _mode = mode;
YAxes = [new Axis() { YAxes = [new Axis()
{
TextSize = 10, TextSize = 10,
MinLimit = 0, MinLimit = 0,
SeparatorsPaint = new SolidColorPaint(new SKColor(0x40808080)) { StrokeThickness = 1 } SeparatorsPaint = new SolidColorPaint(new SKColor(0x40808080)) { StrokeThickness = 1 }
}]; }];
if (mode == StaticsticsMode.ThisWeek) if (mode == StaticsticsMode.ThisWeek)
{ {
for (int i = 0; i < 7; i++) for (int i = 0; i < 7; i++)

View file

@ -38,7 +38,7 @@ namespace SourceGit.Models
extension = ".sh"; extension = ".sh";
else if (extension == ".kt" || extension == ".kts") else if (extension == ".kt" || extension == ".kts")
extension = ".kotlin"; extension = ".kotlin";
foreach (var grammar in s_extraGrammars) foreach (var grammar in s_extraGrammars)
{ {
if (grammar.Extension.Equals(extension, StringComparison.OrdinalIgnoreCase)) if (grammar.Extension.Equals(extension, StringComparison.OrdinalIgnoreCase))
@ -87,7 +87,7 @@ namespace SourceGit.Models
public ICollection<string> GetInjections(string scopeName) => _backend.GetInjections(scopeName); public ICollection<string> GetInjections(string scopeName) => _backend.GetInjections(scopeName);
public IRawGrammar GetGrammar(string scopeName) => GrammarUtility.GetGrammar(scopeName, _backend); public IRawGrammar GetGrammar(string scopeName) => GrammarUtility.GetGrammar(scopeName, _backend);
public string GetScope(string filename) => GrammarUtility.GetScope(filename, _backend); public string GetScope(string filename) => GrammarUtility.GetScope(filename, _backend);
private readonly RegistryOptions _backend = new(defaultTheme); private readonly RegistryOptions _backend = new(defaultTheme);
} }
@ -95,8 +95,8 @@ namespace SourceGit.Models
{ {
public static TextMate.Installation CreateForEditor(TextEditor editor) public static TextMate.Installation CreateForEditor(TextEditor editor)
{ {
return editor.InstallTextMate(Application.Current?.ActualThemeVariant == ThemeVariant.Dark ? return editor.InstallTextMate(Application.Current?.ActualThemeVariant == ThemeVariant.Dark ?
new RegistryOptionsWrapper(ThemeName.DarkPlus) : new RegistryOptionsWrapper(ThemeName.DarkPlus) :
new RegistryOptionsWrapper(ThemeName.LightPlus)); new RegistryOptionsWrapper(ThemeName.LightPlus));
} }

View file

@ -32,8 +32,8 @@ namespace SourceGit.ViewModels
{ {
PopupHost.Active = value; PopupHost.Active = value;
if (!_ignoreIndexChange && value is { Data: Repository }) if (!_ignoreIndexChange && value is { Data: Repository repo })
ActiveWorkspace.ActiveIdx = Pages.IndexOf(value); ActiveWorkspace.ActiveIdx = ActiveWorkspace.Repositories.IndexOf(repo.FullPath);
} }
} }
} }
@ -131,10 +131,22 @@ namespace SourceGit.ViewModels
public void MoveTab(LauncherPage from, LauncherPage to) public void MoveTab(LauncherPage from, LauncherPage to)
{ {
_ignoreIndexChange = true;
var fromIdx = Pages.IndexOf(from); var fromIdx = Pages.IndexOf(from);
var toIdx = Pages.IndexOf(to); var toIdx = Pages.IndexOf(to);
Pages.Move(fromIdx, toIdx); Pages.Move(fromIdx, toIdx);
ActivePage = from; ActivePage = from;
ActiveWorkspace.Repositories.Clear();
foreach (var p in Pages)
{
if (p.Data is Repository r)
ActiveWorkspace.Repositories.Add(r.FullPath);
}
ActiveWorkspace.ActiveIdx = ActiveWorkspace.Repositories.IndexOf(from.Node.Id);
_ignoreIndexChange = false;
} }
public void GotoNextTab() public void GotoNextTab()
@ -164,7 +176,9 @@ namespace SourceGit.ViewModels
var last = Pages[0]; var last = Pages[0];
if (last.Data is Repository repo) if (last.Data is Repository repo)
{ {
ActiveWorkspace.Repositories.Remove(repo.FullPath); ActiveWorkspace.Repositories.Clear();
ActiveWorkspace.ActiveIdx = 0;
Models.AutoFetchManager.Instance.RemoveRepository(repo.FullPath); Models.AutoFetchManager.Instance.RemoveRepository(repo.FullPath);
repo.Close(); repo.Close();
@ -180,6 +194,7 @@ namespace SourceGit.ViewModels
App.Quit(0); App.Quit(0);
} }
_ignoreIndexChange = false;
return; return;
} }
@ -213,6 +228,8 @@ namespace SourceGit.ViewModels
if (Pages.Count == 1) if (Pages.Count == 1)
return; return;
_ignoreIndexChange = true;
var id = ActivePage.Node.Id; var id = ActivePage.Node.Id;
foreach (var one in Pages) foreach (var one in Pages)
{ {
@ -221,12 +238,17 @@ namespace SourceGit.ViewModels
} }
Pages = new AvaloniaList<LauncherPage> { ActivePage }; Pages = new AvaloniaList<LauncherPage> { ActivePage };
ActiveWorkspace.ActiveIdx = 0;
OnPropertyChanged(nameof(Pages)); OnPropertyChanged(nameof(Pages));
_ignoreIndexChange = false;
GC.Collect(); GC.Collect();
} }
public void CloseRightTabs() public void CloseRightTabs()
{ {
_ignoreIndexChange = true;
var endIdx = Pages.IndexOf(ActivePage); var endIdx = Pages.IndexOf(ActivePage);
for (var i = Pages.Count - 1; i > endIdx; i--) for (var i = Pages.Count - 1; i > endIdx; i--)
{ {
@ -234,6 +256,7 @@ namespace SourceGit.ViewModels
Pages.Remove(Pages[i]); Pages.Remove(Pages[i]);
} }
_ignoreIndexChange = false;
GC.Collect(); GC.Collect();
} }
@ -270,7 +293,6 @@ namespace SourceGit.ViewModels
}; };
repo.Open(); repo.Open();
ActiveWorkspace.AddRepository(repo.FullPath);
Models.AutoFetchManager.Instance.AddRepository(repo.FullPath, repo.GitDir); Models.AutoFetchManager.Instance.AddRepository(repo.FullPath, repo.GitDir);
if (page == null) if (page == null)
@ -294,6 +316,16 @@ namespace SourceGit.ViewModels
} }
ActivePage = page; ActivePage = page;
ActiveWorkspace.Repositories.Clear();
foreach (var p in Pages)
{
if (p.Data is Repository r)
ActiveWorkspace.Repositories.Add(r.FullPath);
}
if (!_ignoreIndexChange)
ActiveWorkspace.ActiveIdx = ActiveWorkspace.Repositories.IndexOf(node.Id);
} }
public void DispatchNotification(string pageId, string message, bool isError) public void DispatchNotification(string pageId, string message, bool isError)

View file

@ -51,12 +51,6 @@ namespace SourceGit.ViewModels
get => new SolidColorBrush(_color); get => new SolidColorBrush(_color);
} }
public void AddRepository(string repo)
{
if (!Repositories.Contains(repo))
Repositories.Add(repo);
}
private string _name = string.Empty; private string _name = string.Empty;
private uint _color = 4278221015; private uint _color = 4278221015;
private bool _isActive = false; private bool _isActive = false;

View file

@ -41,7 +41,7 @@ namespace SourceGit.Views
e.Handled = true; e.Handled = true;
} }
} }
if (!e.Handled && e.Key != Key.Space) if (!e.Handled && e.Key != Key.Space)
base.OnKeyDown(e); base.OnKeyDown(e);
} }
@ -166,10 +166,10 @@ namespace SourceGit.Views
{ {
if (lastUnselected == -1) if (lastUnselected == -1)
continue; continue;
break; break;
} }
lastUnselected = i; lastUnselected = i;
} }
} }
@ -186,10 +186,10 @@ namespace SourceGit.Views
{ {
if (lastUnselected == -1) if (lastUnselected == -1)
continue; continue;
break; break;
} }
lastUnselected = i; lastUnselected = i;
} }
@ -244,7 +244,7 @@ namespace SourceGit.Views
_disableSelectionChangingEvent = true; _disableSelectionChangingEvent = true;
var selected = new List<Models.Change>(); var selected = new List<Models.Change>();
if (sender is ListBox { SelectedItems: {} selectedItems }) if (sender is ListBox { SelectedItems: { } selectedItems })
{ {
foreach (var item in selectedItems) foreach (var item in selectedItems)
{ {

View file

@ -117,7 +117,7 @@ namespace SourceGit.Views
e.Handled = true; e.Handled = true;
} }
} }
if (!e.Handled) if (!e.Handled)
base.OnKeyDown(e); base.OnKeyDown(e);
} }

View file

@ -25,7 +25,7 @@ namespace SourceGit.Views
e.Handled = true; e.Handled = true;
} }
} }
public class RepositoryListBox : ListBox public class RepositoryListBox : ListBox
{ {
protected override Type StyleKeyOverride => typeof(ListBox); protected override Type StyleKeyOverride => typeof(ListBox);
@ -40,7 +40,7 @@ namespace SourceGit.Views
e.Handled = true; e.Handled = true;
} }
} }
if (!e.Handled) if (!e.Handled)
base.OnKeyDown(e); base.OnKeyDown(e);
} }