Skip to content

Commit fa97d44

Browse files
committed
feature: supports to open file with detected external tools (#1882)
Signed-off-by: leo <[email protected]>
1 parent 5b818b6 commit fa97d44

File tree

13 files changed

+151
-65
lines changed

13 files changed

+151
-65
lines changed

src/Models/ExternalTool.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public ExternalTool(string name, string icon, string execFile, Func<string, stri
2020
{
2121
Name = name;
2222
ExecFile = execFile;
23-
_execArgsGenerator = execArgsGenerator ?? (repo => repo.Quoted());
23+
_execArgsGenerator = execArgsGenerator ?? (path => path.Quoted());
2424

2525
try
2626
{
@@ -34,13 +34,12 @@ public ExternalTool(string name, string icon, string execFile, Func<string, stri
3434
}
3535
}
3636

37-
public void Open(string repo)
37+
public void Open(string path)
3838
{
3939
Process.Start(new ProcessStartInfo()
4040
{
41-
WorkingDirectory = repo,
4241
FileName = ExecFile,
43-
Arguments = _execArgsGenerator.Invoke(repo),
42+
Arguments = _execArgsGenerator.Invoke(path),
4443
UseShellExecute = false,
4544
});
4645
}

src/Native/Windows.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,10 +449,15 @@ private void OpenFolderAndSelectFile(string folderPath)
449449
}
450450
}
451451

452-
private string GenerateCommandlineArgsForVisualStudio(string repo)
452+
private string GenerateCommandlineArgsForVisualStudio(string path)
453453
{
454-
var sln = FindVSSolutionFile(new DirectoryInfo(repo), 4);
455-
return string.IsNullOrEmpty(sln) ? repo.Quoted() : sln.Quoted();
454+
if (Directory.Exists(path))
455+
{
456+
var sln = FindVSSolutionFile(new DirectoryInfo(path), 4);
457+
return string.IsNullOrEmpty(sln) ? path.Quoted() : sln.Quoted();
458+
}
459+
460+
return path.Quoted();
456461
}
457462

458463
private string FindVSSolutionFile(DirectoryInfo dir, int leftDepth)

src/Resources/Locales/en_US.axaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,9 +536,10 @@
536536
<x:String x:Key="Text.MoveRepositoryNode.Target" xml:space="preserve">Select parent node for:</x:String>
537537
<x:String x:Key="Text.Name" xml:space="preserve">Name:</x:String>
538538
<x:String x:Key="Text.NotConfigured" xml:space="preserve">Git has NOT been configured. Please to go [Preferences] and configure it first.</x:String>
539+
<x:String x:Key="Text.Open" xml:space="preserve">Open</x:String>
540+
<x:String x:Key="Text.Open.SystemDefaultEditor" xml:space="preserve">Default Editor (System)</x:String>
539541
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">Open Data Storage Directory</x:String>
540542
<x:String x:Key="Text.OpenInExternalMergeTool" xml:space="preserve">Open in Merge Tool</x:String>
541-
<x:String x:Key="Text.OpenWith" xml:space="preserve">Open with...</x:String>
542543
<x:String x:Key="Text.Optional" xml:space="preserve">Optional.</x:String>
543544
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">Create New Tab</x:String>
544545
<x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">Bookmark</x:String>

src/Resources/Locales/zh_CN.axaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,9 +540,10 @@
540540
<x:String x:Key="Text.MoveRepositoryNode.Target" xml:space="preserve">请选择目标分组:</x:String>
541541
<x:String x:Key="Text.Name" xml:space="preserve">名称 :</x:String>
542542
<x:String x:Key="Text.NotConfigured" xml:space="preserve">GIT尚未配置。请打开【偏好设置】配置GIT路径。</x:String>
543+
<x:String x:Key="Text.Open" xml:space="preserve">打开</x:String>
544+
<x:String x:Key="Text.Open.SystemDefaultEditor" xml:space="preserve">系统默认编辑器</x:String>
543545
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">浏览应用数据目录</x:String>
544546
<x:String x:Key="Text.OpenInExternalMergeTool" xml:space="preserve">使用外部对比工具查看</x:String>
545-
<x:String x:Key="Text.OpenWith" xml:space="preserve">打开文件...</x:String>
546547
<x:String x:Key="Text.Optional" xml:space="preserve">选填。</x:String>
547548
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">新建空白页</x:String>
548549
<x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">设置书签</x:String>

src/Resources/Locales/zh_TW.axaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,9 +540,10 @@
540540
<x:String x:Key="Text.MoveRepositoryNode.Target" xml:space="preserve">請選擇目標分組:</x:String>
541541
<x:String x:Key="Text.Name" xml:space="preserve">名稱:</x:String>
542542
<x:String x:Key="Text.NotConfigured" xml:space="preserve">尚未設定 Git。請開啟 [偏好設定] 以設定 Git 路徑。</x:String>
543+
<x:String x:Key="Text.Open" xml:space="preserve">開啟</x:String>
544+
<x:String x:Key="Text.Open.SystemDefaultEditor" xml:space="preserve">系統預設編輯器</x:String>
543545
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">瀏覽程式資料目錄</x:String>
544546
<x:String x:Key="Text.OpenInExternalMergeTool" xml:space="preserve">使用外部比對工具檢視</x:String>
545-
<x:String x:Key="Text.OpenWith" xml:space="preserve">開啟檔案...</x:String>
546547
<x:String x:Key="Text.Optional" xml:space="preserve">選填。</x:String>
547548
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">新增分頁</x:String>
548549
<x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">設定書籤</x:String>

src/ViewModels/CommitDetail.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ public async Task ViewRevisionFileAsync(Models.Object file)
318318
}
319319
}
320320

321-
public async Task OpenRevisionFileWithDefaultEditorAsync(string file)
321+
public async Task OpenRevisionFileAsync(string file, Models.ExternalTool tool)
322322
{
323323
var fullPath = Native.OS.GetAbsPath(_repo.FullPath, file);
324324
var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? "";
@@ -329,7 +329,10 @@ await Commands.SaveRevisionFile
329329
.RunAsync(_repo.FullPath, _commit.SHA, file, tmpFile)
330330
.ConfigureAwait(false);
331331

332-
Native.OS.OpenWithDefaultEditor(tmpFile);
332+
if (tool == null)
333+
Native.OS.OpenWithDefaultEditor(tmpFile);
334+
else
335+
tool.Open(tmpFile);
333336
}
334337

335338
public async Task SaveRevisionFileAsync(Models.Object file, string saveTo)

src/ViewModels/WorkingCopy.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -335,13 +335,6 @@ public void SetData(List<Models.Change> changes, CancellationToken cancellationT
335335
});
336336
}
337337

338-
public void OpenWithDefaultEditor(Models.Change c)
339-
{
340-
var absPath = Native.OS.GetAbsPath(_repo.FullPath, c.Path);
341-
if (File.Exists(absPath))
342-
Native.OS.OpenWithDefaultEditor(absPath);
343-
}
344-
345338
public async Task StageChangesAsync(List<Models.Change> changes, Models.Change next)
346339
{
347340
var canStaged = await GetCanStageChangesAsync(changes);

src/Views/CommitDetail.axaml.cs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,44 @@ public ContextMenu CreateChangeContextMenu(Models.Change change)
209209
if (DataContext is not ViewModels.CommitDetail { Repository: { } repo, Commit: { } commit } vm)
210210
return null;
211211

212+
var openWith = new MenuItem();
213+
openWith.Header = App.Text("Open");
214+
openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
215+
openWith.IsEnabled = change.Index != Models.ChangeState.Deleted;
216+
if (openWith.IsEnabled)
217+
{
218+
var defaultEditor = new MenuItem();
219+
defaultEditor.Header = App.Text("Open.SystemDefaultEditor");
220+
defaultEditor.Click += async (_, ev) =>
221+
{
222+
await vm.OpenRevisionFileAsync(change.Path, null);
223+
ev.Handled = true;
224+
};
225+
226+
openWith.Items.Add(defaultEditor);
227+
228+
var tools = Native.OS.ExternalTools;
229+
if (tools.Count > 0)
230+
{
231+
openWith.Items.Add(new MenuItem() { Header = "-" });
232+
233+
for (var i = 0; i < tools.Count; i++)
234+
{
235+
var tool = tools[i];
236+
var item = new MenuItem();
237+
item.Header = tool.Name;
238+
item.Icon = new Image { Width = 16, Height = 16, Source = tool.IconImage };
239+
item.Click += async (_, ev) =>
240+
{
241+
await vm.OpenRevisionFileAsync(change.Path, tool);
242+
ev.Handled = true;
243+
};
244+
245+
openWith.Items.Add(item);
246+
}
247+
}
248+
}
249+
212250
var openWithMerger = new MenuItem();
213251
openWithMerger.Header = App.Text("OpenInExternalMergeTool");
214252
openWithMerger.Icon = App.CreateMenuIcon("Icons.OpenWith");
@@ -219,16 +257,6 @@ public ContextMenu CreateChangeContextMenu(Models.Change change)
219257
ev.Handled = true;
220258
};
221259

222-
var openWith = new MenuItem();
223-
openWith.Header = App.Text("OpenWith");
224-
openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
225-
openWith.IsEnabled = change.Index != Models.ChangeState.Deleted;
226-
openWith.Click += async (_, ev) =>
227-
{
228-
await vm.OpenRevisionFileWithDefaultEditorAsync(change.Path);
229-
ev.Handled = true;
230-
};
231-
232260
var fullPath = Native.OS.GetAbsPath(repo.FullPath, change.Path);
233261
var explore = new MenuItem();
234262
explore.Header = App.Text("RevealFile");
@@ -291,8 +319,8 @@ public ContextMenu CreateChangeContextMenu(Models.Change change)
291319
};
292320

293321
var menu = new ContextMenu();
294-
menu.Items.Add(openWithMerger);
295322
menu.Items.Add(openWith);
323+
menu.Items.Add(openWithMerger);
296324
menu.Items.Add(explore);
297325
menu.Items.Add(new MenuItem { Header = "-" });
298326
menu.Items.Add(history);

src/Views/FileHistories.axaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@
169169
Background="Transparent"
170170
Click="OnOpenFileWithDefaultEditor"
171171
IsVisible="{Binding CanOpenWithDefaultEditor, Mode=OneWay}"
172-
ToolTip.Tip="{DynamicResource Text.OpenWith}">
172+
ToolTip.Tip="{DynamicResource Text.Open}">
173173
<Path Width="12" Height="12" Data="{StaticResource Icons.OpenWith}"/>
174174
</Button>
175175
</Grid>

src/Views/RevisionFileTreeView.axaml.cs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -495,15 +495,43 @@ private ContextMenu CreateRevisionFileContextMenu(ViewModels.Repository repo, Vi
495495
var menu = new ContextMenu();
496496

497497
var openWith = new MenuItem();
498-
openWith.Header = App.Text("OpenWith");
498+
openWith.Header = App.Text("Open");
499499
openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
500-
openWith.Tag = OperatingSystem.IsMacOS() ? "⌘+O" : "Ctrl+O";
501500
openWith.IsEnabled = file.Type == Models.ObjectType.Blob;
502-
openWith.Click += async (_, ev) =>
501+
if (openWith.IsEnabled)
503502
{
504-
await vm.OpenRevisionFileWithDefaultEditorAsync(file.Path);
505-
ev.Handled = true;
506-
};
503+
var defaultEditor = new MenuItem();
504+
defaultEditor.Header = App.Text("Open.SystemDefaultEditor");
505+
defaultEditor.Tag = OperatingSystem.IsMacOS() ? "⌘+O" : "Ctrl+O";
506+
defaultEditor.Click += async (_, ev) =>
507+
{
508+
await vm.OpenRevisionFileAsync(file.Path, null);
509+
ev.Handled = true;
510+
};
511+
512+
openWith.Items.Add(defaultEditor);
513+
514+
var tools = Native.OS.ExternalTools;
515+
if (tools.Count > 0)
516+
{
517+
openWith.Items.Add(new MenuItem() { Header = "-" });
518+
519+
for (var i = 0; i < tools.Count; i++)
520+
{
521+
var tool = tools[i];
522+
var item = new MenuItem();
523+
item.Header = tool.Name;
524+
item.Icon = new Image { Width = 16, Height = 16, Source = tool.IconImage };
525+
item.Click += async (_, ev) =>
526+
{
527+
await vm.OpenRevisionFileAsync(file.Path, tool);
528+
ev.Handled = true;
529+
};
530+
531+
openWith.Items.Add(item);
532+
}
533+
}
534+
}
507535

508536
var saveAs = new MenuItem();
509537
saveAs.Header = App.Text("SaveAs");

0 commit comments

Comments
 (0)