diff --git a/src/Models/ExternalTool.cs b/src/Models/ExternalTool.cs
index f453c08f..bd04f2f9 100644
--- a/src/Models/ExternalTool.cs
+++ b/src/Models/ExternalTool.cs
@@ -20,7 +20,7 @@ namespace SourceGit.Models
{
Name = name;
ExecFile = execFile;
- _execArgsGenerator = execArgsGenerator ?? (repo => repo.Quoted());
+ _execArgsGenerator = execArgsGenerator ?? (path => path.Quoted());
try
{
@@ -34,13 +34,12 @@ namespace SourceGit.Models
}
}
- public void Open(string repo)
+ public void Open(string path)
{
Process.Start(new ProcessStartInfo()
{
- WorkingDirectory = repo,
FileName = ExecFile,
- Arguments = _execArgsGenerator.Invoke(repo),
+ Arguments = _execArgsGenerator.Invoke(path),
UseShellExecute = false,
});
}
diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs
index 8439d702..70e01796 100644
--- a/src/Native/Windows.cs
+++ b/src/Native/Windows.cs
@@ -449,10 +449,15 @@ namespace SourceGit.Native
}
}
- private string GenerateCommandlineArgsForVisualStudio(string repo)
+ private string GenerateCommandlineArgsForVisualStudio(string path)
{
- var sln = FindVSSolutionFile(new DirectoryInfo(repo), 4);
- return string.IsNullOrEmpty(sln) ? repo.Quoted() : sln.Quoted();
+ if (Directory.Exists(path))
+ {
+ var sln = FindVSSolutionFile(new DirectoryInfo(path), 4);
+ return string.IsNullOrEmpty(sln) ? path.Quoted() : sln.Quoted();
+ }
+
+ return path.Quoted();
}
private string FindVSSolutionFile(DirectoryInfo dir, int leftDepth)
diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index 9eb5fe94..e204baac 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -536,9 +536,10 @@
Select parent node for:
Name:
Git has NOT been configured. Please to go [Preferences] and configure it first.
+ Open
+ Default Editor (System)
Open Data Storage Directory
Open in Merge Tool
- Open with...
Optional.
Create New Tab
Bookmark
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index 242373ad..c4dbdc05 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -540,9 +540,10 @@
请选择目标分组:
名称 :
GIT尚未配置。请打开【偏好设置】配置GIT路径。
+ 打开
+ 系统默认编辑器
浏览应用数据目录
使用外部对比工具查看
- 打开文件...
选填。
新建空白页
设置书签
diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml
index 1ddc9f16..c46bb316 100644
--- a/src/Resources/Locales/zh_TW.axaml
+++ b/src/Resources/Locales/zh_TW.axaml
@@ -540,9 +540,10 @@
請選擇目標分組:
名稱:
尚未設定 Git。請開啟 [偏好設定] 以設定 Git 路徑。
+ 開啟
+ 系統預設編輯器
瀏覽程式資料目錄
使用外部比對工具檢視
- 開啟檔案...
選填。
新增分頁
設定書籤
diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs
index c272689d..119ae753 100644
--- a/src/ViewModels/CommitDetail.cs
+++ b/src/ViewModels/CommitDetail.cs
@@ -318,7 +318,7 @@ namespace SourceGit.ViewModels
}
}
- public async Task OpenRevisionFileWithDefaultEditorAsync(string file)
+ public async Task OpenRevisionFileAsync(string file, Models.ExternalTool tool)
{
var fullPath = Native.OS.GetAbsPath(_repo.FullPath, file);
var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? "";
@@ -329,7 +329,10 @@ namespace SourceGit.ViewModels
.RunAsync(_repo.FullPath, _commit.SHA, file, tmpFile)
.ConfigureAwait(false);
- Native.OS.OpenWithDefaultEditor(tmpFile);
+ if (tool == null)
+ Native.OS.OpenWithDefaultEditor(tmpFile);
+ else
+ tool.Open(tmpFile);
}
public async Task SaveRevisionFileAsync(Models.Object file, string saveTo)
diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs
index 1cc24429..78d069d0 100644
--- a/src/ViewModels/WorkingCopy.cs
+++ b/src/ViewModels/WorkingCopy.cs
@@ -335,13 +335,6 @@ namespace SourceGit.ViewModels
});
}
- public void OpenWithDefaultEditor(Models.Change c)
- {
- var absPath = Native.OS.GetAbsPath(_repo.FullPath, c.Path);
- if (File.Exists(absPath))
- Native.OS.OpenWithDefaultEditor(absPath);
- }
-
public async Task StageChangesAsync(List changes, Models.Change next)
{
var canStaged = await GetCanStageChangesAsync(changes);
diff --git a/src/Views/CommitDetail.axaml.cs b/src/Views/CommitDetail.axaml.cs
index 9dbfbe13..7bba82e6 100644
--- a/src/Views/CommitDetail.axaml.cs
+++ b/src/Views/CommitDetail.axaml.cs
@@ -209,6 +209,44 @@ namespace SourceGit.Views
if (DataContext is not ViewModels.CommitDetail { Repository: { } repo, Commit: { } commit } vm)
return null;
+ var openWith = new MenuItem();
+ openWith.Header = App.Text("Open");
+ openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
+ openWith.IsEnabled = change.Index != Models.ChangeState.Deleted;
+ if (openWith.IsEnabled)
+ {
+ var defaultEditor = new MenuItem();
+ defaultEditor.Header = App.Text("Open.SystemDefaultEditor");
+ defaultEditor.Click += async (_, ev) =>
+ {
+ await vm.OpenRevisionFileAsync(change.Path, null);
+ ev.Handled = true;
+ };
+
+ openWith.Items.Add(defaultEditor);
+
+ var tools = Native.OS.ExternalTools;
+ if (tools.Count > 0)
+ {
+ openWith.Items.Add(new MenuItem() { Header = "-" });
+
+ for (var i = 0; i < tools.Count; i++)
+ {
+ var tool = tools[i];
+ var item = new MenuItem();
+ item.Header = tool.Name;
+ item.Icon = new Image { Width = 16, Height = 16, Source = tool.IconImage };
+ item.Click += async (_, ev) =>
+ {
+ await vm.OpenRevisionFileAsync(change.Path, tool);
+ ev.Handled = true;
+ };
+
+ openWith.Items.Add(item);
+ }
+ }
+ }
+
var openWithMerger = new MenuItem();
openWithMerger.Header = App.Text("OpenInExternalMergeTool");
openWithMerger.Icon = App.CreateMenuIcon("Icons.OpenWith");
@@ -219,16 +257,6 @@ namespace SourceGit.Views
ev.Handled = true;
};
- var openWith = new MenuItem();
- openWith.Header = App.Text("OpenWith");
- openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
- openWith.IsEnabled = change.Index != Models.ChangeState.Deleted;
- openWith.Click += async (_, ev) =>
- {
- await vm.OpenRevisionFileWithDefaultEditorAsync(change.Path);
- ev.Handled = true;
- };
-
var fullPath = Native.OS.GetAbsPath(repo.FullPath, change.Path);
var explore = new MenuItem();
explore.Header = App.Text("RevealFile");
@@ -291,8 +319,8 @@ namespace SourceGit.Views
};
var menu = new ContextMenu();
- menu.Items.Add(openWithMerger);
menu.Items.Add(openWith);
+ menu.Items.Add(openWithMerger);
menu.Items.Add(explore);
menu.Items.Add(new MenuItem { Header = "-" });
menu.Items.Add(history);
diff --git a/src/Views/FileHistories.axaml b/src/Views/FileHistories.axaml
index ba296bfa..2988f2c5 100644
--- a/src/Views/FileHistories.axaml
+++ b/src/Views/FileHistories.axaml
@@ -169,7 +169,7 @@
Background="Transparent"
Click="OnOpenFileWithDefaultEditor"
IsVisible="{Binding CanOpenWithDefaultEditor, Mode=OneWay}"
- ToolTip.Tip="{DynamicResource Text.OpenWith}">
+ ToolTip.Tip="{DynamicResource Text.Open}">
diff --git a/src/Views/RevisionFileTreeView.axaml.cs b/src/Views/RevisionFileTreeView.axaml.cs
index 2ad6b0e8..3c0721e4 100644
--- a/src/Views/RevisionFileTreeView.axaml.cs
+++ b/src/Views/RevisionFileTreeView.axaml.cs
@@ -495,15 +495,43 @@ namespace SourceGit.Views
var menu = new ContextMenu();
var openWith = new MenuItem();
- openWith.Header = App.Text("OpenWith");
+ openWith.Header = App.Text("Open");
openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
- openWith.Tag = OperatingSystem.IsMacOS() ? "⌘+O" : "Ctrl+O";
openWith.IsEnabled = file.Type == Models.ObjectType.Blob;
- openWith.Click += async (_, ev) =>
+ if (openWith.IsEnabled)
{
- await vm.OpenRevisionFileWithDefaultEditorAsync(file.Path);
- ev.Handled = true;
- };
+ var defaultEditor = new MenuItem();
+ defaultEditor.Header = App.Text("Open.SystemDefaultEditor");
+ defaultEditor.Tag = OperatingSystem.IsMacOS() ? "⌘+O" : "Ctrl+O";
+ defaultEditor.Click += async (_, ev) =>
+ {
+ await vm.OpenRevisionFileAsync(file.Path, null);
+ ev.Handled = true;
+ };
+
+ openWith.Items.Add(defaultEditor);
+
+ var tools = Native.OS.ExternalTools;
+ if (tools.Count > 0)
+ {
+ openWith.Items.Add(new MenuItem() { Header = "-" });
+
+ for (var i = 0; i < tools.Count; i++)
+ {
+ var tool = tools[i];
+ var item = new MenuItem();
+ item.Header = tool.Name;
+ item.Icon = new Image { Width = 16, Height = 16, Source = tool.IconImage };
+ item.Click += async (_, ev) =>
+ {
+ await vm.OpenRevisionFileAsync(file.Path, tool);
+ ev.Handled = true;
+ };
+
+ openWith.Items.Add(item);
+ }
+ }
+ }
var saveAs = new MenuItem();
saveAs.Header = App.Text("SaveAs");
diff --git a/src/Views/RevisionFiles.axaml b/src/Views/RevisionFiles.axaml
index 4144f3ed..7c1c9912 100644
--- a/src/Views/RevisionFiles.axaml
+++ b/src/Views/RevisionFiles.axaml
@@ -151,7 +151,7 @@
HotKey="{OnPlatform Ctrl+O, macOS=⌘+O}">
-
+
diff --git a/src/Views/RevisionFiles.axaml.cs b/src/Views/RevisionFiles.axaml.cs
index dd51943c..a4a01b65 100644
--- a/src/Views/RevisionFiles.axaml.cs
+++ b/src/Views/RevisionFiles.axaml.cs
@@ -82,7 +82,7 @@ namespace SourceGit.Views
private async void OnOpenFileWithDefaultEditor(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModels.CommitDetail { CanOpenRevisionFileWithDefaultEditor: true } vm)
- await vm.OpenRevisionFileWithDefaultEditorAsync(vm.ViewRevisionFilePath);
+ await vm.OpenRevisionFileAsync(vm.ViewRevisionFilePath, null);
e.Handled = true;
}
diff --git a/src/Views/WorkingCopy.axaml.cs b/src/Views/WorkingCopy.axaml.cs
index 4f88a169..b786b0d9 100644
--- a/src/Views/WorkingCopy.axaml.cs
+++ b/src/Views/WorkingCopy.axaml.cs
@@ -110,7 +110,10 @@ namespace SourceGit.Views
e.KeyModifiers == (OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control) &&
vm.SelectedUnstaged is { Count: 1 })
{
- vm.OpenWithDefaultEditor(vm.SelectedUnstaged[0]);
+ var change = vm.SelectedUnstaged[0];
+ var fullpath = Native.OS.GetAbsPath(vm.Repository.FullPath, change.Path);
+ if (File.Exists(fullpath))
+ Native.OS.OpenWithDefaultEditor(fullpath);
e.Handled = true;
}
else if (e.Key is Key.C &&
@@ -143,7 +146,10 @@ namespace SourceGit.Views
e.KeyModifiers == (OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control) &&
vm.SelectedStaged is { Count: 1 })
{
- vm.OpenWithDefaultEditor(vm.SelectedStaged[0]);
+ var change = vm.SelectedStaged[0];
+ var fullpath = Native.OS.GetAbsPath(vm.Repository.FullPath, change.Path);
+ if (File.Exists(fullpath))
+ Native.OS.OpenWithDefaultEditor(fullpath);
e.Handled = true;
}
else if (e.Key is Key.C &&
@@ -254,6 +260,7 @@ namespace SourceGit.Views
{
var change = selectedUnstaged[0];
var path = Native.OS.GetAbsPath(repo.FullPath, change.Path);
+ TryAddOpenFileToContextMenu(menu, path);
if (!change.IsConflicted || change.ConflictReason is Models.ConflictReason.BothAdded or Models.ConflictReason.BothModified)
{
@@ -273,18 +280,6 @@ namespace SourceGit.Views
menu.Items.Add(openMerger);
}
- var openWith = new MenuItem();
- openWith.Header = App.Text("OpenWith");
- openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
- openWith.Tag = OperatingSystem.IsMacOS() ? "⌘+O" : "Ctrl+O";
- openWith.IsEnabled = File.Exists(path);
- openWith.Click += (_, e) =>
- {
- vm.OpenWithDefaultEditor(change);
- e.Handled = true;
- };
- menu.Items.Add(openWith);
-
var explore = new MenuItem();
explore.Header = App.Text("RevealFile");
explore.Icon = App.CreateMenuIcon("Icons.Explore");
@@ -934,17 +929,6 @@ namespace SourceGit.Views
ev.Handled = true;
};
- var openWith = new MenuItem();
- openWith.Header = App.Text("OpenWith");
- openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
- openWith.Tag = OperatingSystem.IsMacOS() ? "⌘+O" : "Ctrl+O";
- openWith.IsEnabled = File.Exists(path);
- openWith.Click += (_, e) =>
- {
- vm.OpenWithDefaultEditor(change);
- e.Handled = true;
- };
-
var explore = new MenuItem();
explore.IsEnabled = File.Exists(path) || Directory.Exists(path);
explore.Header = App.Text("RevealFile");
@@ -1005,8 +989,8 @@ namespace SourceGit.Views
e.Handled = true;
};
+ TryAddOpenFileToContextMenu(menu, path);
menu.Items.Add(openWithMerger);
- menu.Items.Add(openWith);
menu.Items.Add(explore);
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(unstage);
@@ -1274,6 +1258,49 @@ namespace SourceGit.Views
return menu;
}
+ private void TryAddOpenFileToContextMenu(ContextMenu menu, string fullpath)
+ {
+ var openWith = new MenuItem();
+ openWith.Header = App.Text("Open");
+ openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
+ openWith.IsEnabled = File.Exists(fullpath);
+ if (openWith.IsEnabled)
+ {
+ var defaultEditor = new MenuItem();
+ defaultEditor.Header = App.Text("Open.SystemDefaultEditor");
+ defaultEditor.Tag = OperatingSystem.IsMacOS() ? "⌘+O" : "Ctrl+O";
+ defaultEditor.Click += (_, ev) =>
+ {
+ Native.OS.OpenWithDefaultEditor(fullpath);
+ ev.Handled = true;
+ };
+
+ openWith.Items.Add(defaultEditor);
+
+ var tools = Native.OS.ExternalTools;
+ if (tools.Count > 0)
+ {
+ openWith.Items.Add(new MenuItem() { Header = "-" });
+
+ for (var i = 0; i < tools.Count; i++)
+ {
+ var tool = tools[i];
+ var item = new MenuItem();
+ item.Header = tool.Name;
+ item.Icon = new Image { Width = 16, Height = 16, Source = tool.IconImage };
+ item.Click += (_, e) =>
+ {
+ tool.Open(fullpath);
+ e.Handled = true;
+ };
+
+ openWith.Items.Add(item);
+ }
+ }
+ }
+ menu.Items.Add(openWith);
+ }
+
private void TryToAddCustomActionsToContextMenu(ViewModels.Repository repo, ContextMenu menu, string path)
{
var actions = repo.GetCustomActions(Models.CustomActionScope.File);