mirror of
https://fastgit.cc/github.com/sourcegit-scm/sourcegit
synced 2026-04-24 02:40:24 +08:00
feature: supports to open file with detected external tools (#1882)
Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -536,9 +536,10 @@
|
||||
<x:String x:Key="Text.MoveRepositoryNode.Target" xml:space="preserve">Select parent node for:</x:String>
|
||||
<x:String x:Key="Text.Name" xml:space="preserve">Name:</x:String>
|
||||
<x:String x:Key="Text.NotConfigured" xml:space="preserve">Git has NOT been configured. Please to go [Preferences] and configure it first.</x:String>
|
||||
<x:String x:Key="Text.Open" xml:space="preserve">Open</x:String>
|
||||
<x:String x:Key="Text.Open.SystemDefaultEditor" xml:space="preserve">Default Editor (System)</x:String>
|
||||
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">Open Data Storage Directory</x:String>
|
||||
<x:String x:Key="Text.OpenInExternalMergeTool" xml:space="preserve">Open in Merge Tool</x:String>
|
||||
<x:String x:Key="Text.OpenWith" xml:space="preserve">Open with...</x:String>
|
||||
<x:String x:Key="Text.Optional" xml:space="preserve">Optional.</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">Create New Tab</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">Bookmark</x:String>
|
||||
|
||||
@@ -540,9 +540,10 @@
|
||||
<x:String x:Key="Text.MoveRepositoryNode.Target" xml:space="preserve">请选择目标分组:</x:String>
|
||||
<x:String x:Key="Text.Name" xml:space="preserve">名称 :</x:String>
|
||||
<x:String x:Key="Text.NotConfigured" xml:space="preserve">GIT尚未配置。请打开【偏好设置】配置GIT路径。</x:String>
|
||||
<x:String x:Key="Text.Open" xml:space="preserve">打开</x:String>
|
||||
<x:String x:Key="Text.Open.SystemDefaultEditor" xml:space="preserve">系统默认编辑器</x:String>
|
||||
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">浏览应用数据目录</x:String>
|
||||
<x:String x:Key="Text.OpenInExternalMergeTool" xml:space="preserve">使用外部对比工具查看</x:String>
|
||||
<x:String x:Key="Text.OpenWith" xml:space="preserve">打开文件...</x:String>
|
||||
<x:String x:Key="Text.Optional" xml:space="preserve">选填。</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">新建空白页</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">设置书签</x:String>
|
||||
|
||||
@@ -540,9 +540,10 @@
|
||||
<x:String x:Key="Text.MoveRepositoryNode.Target" xml:space="preserve">請選擇目標分組:</x:String>
|
||||
<x:String x:Key="Text.Name" xml:space="preserve">名稱:</x:String>
|
||||
<x:String x:Key="Text.NotConfigured" xml:space="preserve">尚未設定 Git。請開啟 [偏好設定] 以設定 Git 路徑。</x:String>
|
||||
<x:String x:Key="Text.Open" xml:space="preserve">開啟</x:String>
|
||||
<x:String x:Key="Text.Open.SystemDefaultEditor" xml:space="preserve">系統預設編輯器</x:String>
|
||||
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">瀏覽程式資料目錄</x:String>
|
||||
<x:String x:Key="Text.OpenInExternalMergeTool" xml:space="preserve">使用外部比對工具檢視</x:String>
|
||||
<x:String x:Key="Text.OpenWith" xml:space="preserve">開啟檔案...</x:String>
|
||||
<x:String x:Key="Text.Optional" xml:space="preserve">選填。</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">新增分頁</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">設定書籤</x:String>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<Models.Change> changes, Models.Change next)
|
||||
{
|
||||
var canStaged = await GetCanStageChangesAsync(changes);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
Background="Transparent"
|
||||
Click="OnOpenFileWithDefaultEditor"
|
||||
IsVisible="{Binding CanOpenWithDefaultEditor, Mode=OneWay}"
|
||||
ToolTip.Tip="{DynamicResource Text.OpenWith}">
|
||||
ToolTip.Tip="{DynamicResource Text.Open}">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.OpenWith}"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
HotKey="{OnPlatform Ctrl+O, macOS=⌘+O}">
|
||||
<ToolTip.Tip>
|
||||
<TextBlock>
|
||||
<Run Text="{DynamicResource Text.OpenWith}"/>
|
||||
<Run Text="{DynamicResource Text.Open}"/>
|
||||
<Run Text=" "/>
|
||||
<Run Text="{OnPlatform Ctrl+O, macOS=⌘+O}" FontSize="11" Foreground="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"/>
|
||||
</TextBlock>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user