refactor: allows to specify startup options for external shell/terminal (#1856)

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo
2025-12-12 11:31:00 +08:00
parent 96fbe38f40
commit 7111ffba2a
10 changed files with 70 additions and 43 deletions

View File

@@ -11,6 +11,7 @@ namespace SourceGit.Models
public string Type { get; set; }
public string Name { get; set; }
public string Exec { get; set; }
public string Args { get; set; }
public Bitmap Icon
{
@@ -32,18 +33,18 @@ namespace SourceGit.Models
new ShellOrTerminal("git-bash", "Git Bash", "bash.exe"),
new ShellOrTerminal("pwsh", "PowerShell", "pwsh.exe|powershell.exe"),
new ShellOrTerminal("cmd", "Command Prompt", "cmd.exe"),
new ShellOrTerminal("wt", "Windows Terminal", "wt.exe")
new ShellOrTerminal("wt", "Windows Terminal", "wt.exe", "-d .")
};
}
else if (OperatingSystem.IsMacOS())
{
Supported = new List<ShellOrTerminal>()
{
new ShellOrTerminal("mac-terminal", "Terminal", ""),
new ShellOrTerminal("iterm2", "iTerm", ""),
new ShellOrTerminal("warp", "Warp", ""),
new ShellOrTerminal("ghostty", "Ghostty", ""),
new ShellOrTerminal("kitty", "kitty", "")
new ShellOrTerminal("mac-terminal", "Terminal", "Terminal"),
new ShellOrTerminal("iterm2", "iTerm", "iTerm"),
new ShellOrTerminal("warp", "Warp", "Warp"),
new ShellOrTerminal("ghostty", "Ghostty", "Ghostty"),
new ShellOrTerminal("kitty", "kitty", "kitty")
};
}
else
@@ -57,19 +58,20 @@ namespace SourceGit.Models
new ShellOrTerminal("deepin-terminal", "Deepin Terminal", "deepin-terminal"),
new ShellOrTerminal("mate-terminal", "MATE Terminal", "mate-terminal"),
new ShellOrTerminal("foot", "Foot", "foot"),
new ShellOrTerminal("wezterm", "WezTerm", "wezterm"),
new ShellOrTerminal("ptyxis", "Ptyxis", "ptyxis"),
new ShellOrTerminal("wezterm", "WezTerm", "wezterm", "start --cwd ."),
new ShellOrTerminal("ptyxis", "Ptyxis", "ptyxis", "--new-window --working-directory=."),
new ShellOrTerminal("kitty", "kitty", "kitty"),
new ShellOrTerminal("custom", "Custom", ""),
};
}
}
public ShellOrTerminal(string type, string name, string exec)
public ShellOrTerminal(string type, string name, string exec, string args = null)
{
Type = type;
Name = name;
Exec = exec;
Args = args;
}
}
}

View File

@@ -87,20 +87,15 @@ namespace SourceGit.Native
}
}
public void OpenTerminal(string workdir)
public void OpenTerminal(string workdir, string args)
{
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var cwd = string.IsNullOrEmpty(workdir) ? home : workdir;
var terminal = OS.ShellOrTerminal;
var startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = cwd;
startInfo.FileName = terminal;
if (terminal.EndsWith("wezterm", StringComparison.OrdinalIgnoreCase))
startInfo.Arguments = $"start --cwd {cwd.Quoted()}";
else if (terminal.EndsWith("ptyxis", StringComparison.OrdinalIgnoreCase))
startInfo.Arguments = $"--new-window --working-directory={cwd.Quoted()}";
startInfo.FileName = OS.ShellOrTerminal;
startInfo.Arguments = args;
try
{

View File

@@ -62,15 +62,7 @@ namespace SourceGit.Native
public string FindTerminal(Models.ShellOrTerminal shell)
{
return shell.Type switch
{
"mac-terminal" => "Terminal",
"iterm2" => "iTerm",
"warp" => "Warp",
"ghostty" => "Ghostty",
"kitty" => "kitty",
_ => string.Empty,
};
return shell.Exec;
}
public List<Models.ExternalTool> FindExternalTools()
@@ -101,7 +93,7 @@ namespace SourceGit.Native
Process.Start("open", $"{path.Quoted()} -R");
}
public void OpenTerminal(string workdir)
public void OpenTerminal(string workdir, string _)
{
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var dir = string.IsNullOrEmpty(workdir) ? home : workdir;

View File

@@ -21,7 +21,7 @@ namespace SourceGit.Native
string FindTerminal(Models.ShellOrTerminal shell);
List<Models.ExternalTool> FindExternalTools();
void OpenTerminal(string workdir);
void OpenTerminal(string workdir, string args);
void OpenInFileManager(string path, bool select);
void OpenBrowser(string url);
void OpenWithDefaultEditor(string file);
@@ -70,6 +70,12 @@ namespace SourceGit.Native
set;
} = string.Empty;
public static string ShellOrTerminalArgs
{
get;
set;
} = string.Empty;
public static List<Models.ExternalTool> ExternalTools
{
get;
@@ -168,6 +174,8 @@ namespace SourceGit.Native
ShellOrTerminal = string.Empty;
else
ShellOrTerminal = _backend.FindTerminal(shell);
ShellOrTerminalArgs = shell.Args;
}
public static Models.DiffMergeTool GetDiffMergeTool(bool onlyDiff)
@@ -212,7 +220,7 @@ namespace SourceGit.Native
if (string.IsNullOrEmpty(ShellOrTerminal))
App.RaiseException(workdir, "Terminal is not specified! Please confirm that the correct shell/terminal has been configured.");
else
_backend.OpenTerminal(workdir);
_backend.OpenTerminal(workdir, ShellOrTerminalArgs);
}
public static void OpenWithDefaultEditor(string file)

View File

@@ -203,7 +203,7 @@ namespace SourceGit.Native
Process.Start(info);
}
public void OpenTerminal(string workdir)
public void OpenTerminal(string workdir, string args)
{
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var cwd = string.IsNullOrEmpty(workdir) ? home : workdir;
@@ -218,11 +218,7 @@ namespace SourceGit.Native
var startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = cwd;
startInfo.FileName = terminal;
// Directly launching `Windows Terminal` need to specify the `-d` parameter
if (terminal.EndsWith("wt.exe", StringComparison.OrdinalIgnoreCase))
startInfo.Arguments = $"-d {cwd.Quoted()}";
startInfo.Arguments = args;
Process.Start(startInfo);
}

View File

@@ -629,6 +629,7 @@
<x:String x:Key="Text.Preferences.GPG.UserKey.Placeholder" xml:space="preserve">User's gpg signing key</x:String>
<x:String x:Key="Text.Preferences.Integration" xml:space="preserve">INTEGRATION</x:String>
<x:String x:Key="Text.Preferences.Shell" xml:space="preserve">SHELL/TERMINAL</x:String>
<x:String x:Key="Text.Preferences.Shell.Args" xml:space="preserve">Arguments</x:String>
<x:String x:Key="Text.Preferences.Shell.Path" xml:space="preserve">Path</x:String>
<x:String x:Key="Text.Preferences.Shell.Type" xml:space="preserve">Shell/Terminal</x:String>
<x:String x:Key="Text.PruneRemote" xml:space="preserve">Prune Remote</x:String>

View File

@@ -633,6 +633,7 @@
<x:String x:Key="Text.Preferences.GPG.UserKey.Placeholder" xml:space="preserve">输入签名提交所使用的KEY</x:String>
<x:String x:Key="Text.Preferences.Integration" xml:space="preserve">第三方工具集成</x:String>
<x:String x:Key="Text.Preferences.Shell" xml:space="preserve">终端/SHELL</x:String>
<x:String x:Key="Text.Preferences.Shell.Args" xml:space="preserve">启动参数</x:String>
<x:String x:Key="Text.Preferences.Shell.Path" xml:space="preserve">安装路径</x:String>
<x:String x:Key="Text.Preferences.Shell.Type" xml:space="preserve">终端/SHELL</x:String>
<x:String x:Key="Text.PruneRemote" xml:space="preserve">清理远程已删除分支</x:String>

View File

@@ -633,6 +633,7 @@
<x:String x:Key="Text.Preferences.GPG.UserKey.Placeholder" xml:space="preserve">填寫簽章提交所使用的金鑰</x:String>
<x:String x:Key="Text.Preferences.Integration" xml:space="preserve">第三方工具整合</x:String>
<x:String x:Key="Text.Preferences.Shell" xml:space="preserve">終端機/Shell</x:String>
<x:String x:Key="Text.Preferences.Shell.Args" xml:space="preserve">啟動參數</x:String>
<x:String x:Key="Text.Preferences.Shell.Path" xml:space="preserve">安裝路徑</x:String>
<x:String x:Key="Text.Preferences.Shell.Type" xml:space="preserve">終端機/Shell</x:String>
<x:String x:Key="Text.PruneRemote" xml:space="preserve">清理遠端已刪除分支</x:String>

View File

@@ -349,7 +349,7 @@ namespace SourceGit.ViewModels
get => _shellOrTerminal;
set
{
if (SetProperty(ref _shellOrTerminal, value))
if (SetProperty(ref _shellOrTerminal, value) && !_isLoading)
{
if (value >= 0 && value < Models.ShellOrTerminal.Supported.Count)
Native.OS.SetShellOrTerminal(Models.ShellOrTerminal.Supported[value]);
@@ -357,6 +357,7 @@ namespace SourceGit.ViewModels
Native.OS.SetShellOrTerminal(null);
OnPropertyChanged(nameof(ShellOrTerminalPath));
OnPropertyChanged(nameof(ShellOrTerminalArgs));
}
}
}
@@ -374,6 +375,19 @@ namespace SourceGit.ViewModels
}
}
public string ShellOrTerminalArgs
{
get => Native.OS.ShellOrTerminalArgs;
set
{
if (value != Native.OS.ShellOrTerminalArgs)
{
Native.OS.ShellOrTerminalArgs = value;
OnPropertyChanged();
}
}
}
public int ExternalMergeToolType
{
get => Native.OS.ExternalMergerType;

View File

@@ -471,7 +471,7 @@
<TextBlock Classes="bold" Margin="4,0,0,0" Text="{DynamicResource Text.Preferences.Shell}"/>
</StackPanel>
<Rectangle Margin="0,8" Fill="{DynamicResource Brush.Border2}" Height=".6" HorizontalAlignment="Stretch"/>
<Grid Margin="8,0,0,0" RowDefinitions="32,Auto">
<Grid Margin="8,0,0,0" RowDefinitions="32,Auto,Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="IntegrationLabel"/>
<ColumnDefinition Width="*"/>
@@ -479,7 +479,7 @@
<TextBlock Grid.Row="0" Grid.Column="0"
Text="{DynamicResource Text.Preferences.Shell.Type}"
HorizontalAlignment="Right"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,16,0"/>
<ComboBox Grid.Row="0" Grid.Column="1"
MinHeight="28"
@@ -497,11 +497,14 @@
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="1" Grid.Column="0"
Text="{DynamicResource Text.Preferences.Shell.Path}"
HorizontalAlignment="Right"
Margin="0,0,16,0"
IsVisible="{OnPlatform True, macOS=False}"/>
<Border Grid.Row="1" Grid.Column="0"
Height="32"
Margin="0,0,16,0"
IsVisible="{OnPlatform True, macOS=False}">
<TextBlock Grid.Row="1" Grid.Column="0"
Text="{DynamicResource Text.Preferences.Shell.Path}"
HorizontalAlignment="Right" />
</Border>
<TextBox Grid.Row="1" Grid.Column="1"
Height="28"
CornerRadius="3"
@@ -513,6 +516,20 @@
</Button>
</TextBox.InnerRightContent>
</TextBox>
<Border Grid.Row="2" Grid.Column="0"
Height="32"
Margin="0,0,16,0"
IsVisible="{OnPlatform True, macOS=False}">
<TextBlock Grid.Row="1" Grid.Column="0"
Text="{DynamicResource Text.Preferences.Shell.Args}"
HorizontalAlignment="Right" />
</Border>
<TextBox Grid.Row="2" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding ShellOrTerminalArgs, Mode=TwoWay}"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<StackPanel Orientation="Horizontal" Margin="0,24,0,0">