Skip to content

Commit 92fb4c8

Browse files
committed
feature: add hotkeys to copy file path
Signed-off-by: leo <[email protected]>
1 parent f2778ee commit 92fb4c8

9 files changed

+104
-7
lines changed

src/ViewModels/BranchCompare.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ public void ClearSearchFilter()
114114
SearchFilter = string.Empty;
115115
}
116116

117+
public string GetAbsPath(string path)
118+
{
119+
return Native.OS.GetAbsPath(_repo, path);
120+
}
121+
117122
public ContextMenu CreateChangeContextMenu()
118123
{
119124
if (_selectedChanges is not { Count: 1 })
@@ -155,6 +160,7 @@ public ContextMenu CreateChangeContextMenu()
155160
var copyPath = new MenuItem();
156161
copyPath.Header = App.Text("CopyPath");
157162
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
163+
copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
158164
copyPath.Click += async (_, ev) =>
159165
{
160166
await App.CopyTextAsync(change.Path);
@@ -165,6 +171,7 @@ public ContextMenu CreateChangeContextMenu()
165171
var copyFullPath = new MenuItem();
166172
copyFullPath.Header = App.Text("CopyFullPath");
167173
copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
174+
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
168175
copyFullPath.Click += async (_, e) =>
169176
{
170177
await App.CopyTextAsync(Native.OS.GetAbsPath(_repo, change.Path));

src/ViewModels/CommitDetail.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,11 @@ await Commands.SaveRevisionFile
241241
Native.OS.OpenWithDefaultEditor(tmpFile);
242242
}
243243

244+
public string GetAbsPath(string path)
245+
{
246+
return Native.OS.GetAbsPath(_repo.FullPath, path);
247+
}
248+
244249
public ContextMenu CreateChangeContextMenuByFolder(ChangeTreeNode node, List<Models.Change> changes)
245250
{
246251
var fullPath = Native.OS.GetAbsPath(_repo.FullPath, node.FullPath);
@@ -293,6 +298,7 @@ public ContextMenu CreateChangeContextMenuByFolder(ChangeTreeNode node, List<Mod
293298
var copyPath = new MenuItem();
294299
copyPath.Header = App.Text("CopyPath");
295300
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
301+
copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
296302
copyPath.Click += async (_, ev) =>
297303
{
298304
await App.CopyTextAsync(node.FullPath);
@@ -302,6 +308,7 @@ public ContextMenu CreateChangeContextMenuByFolder(ChangeTreeNode node, List<Mod
302308
var copyFullPath = new MenuItem();
303309
copyFullPath.Header = App.Text("CopyFullPath");
304310
copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
311+
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
305312
copyFullPath.Click += async (_, e) =>
306313
{
307314
await App.CopyTextAsync(fullPath);
@@ -432,6 +439,7 @@ public ContextMenu CreateChangeContextMenu(Models.Change change)
432439
var copyPath = new MenuItem();
433440
copyPath.Header = App.Text("CopyPath");
434441
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
442+
copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
435443
copyPath.Click += async (_, ev) =>
436444
{
437445
await App.CopyTextAsync(change.Path);
@@ -441,6 +449,7 @@ public ContextMenu CreateChangeContextMenu(Models.Change change)
441449
var copyFullPath = new MenuItem();
442450
copyFullPath.Header = App.Text("CopyFullPath");
443451
copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
452+
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
444453
copyFullPath.Click += async (_, e) =>
445454
{
446455
await App.CopyTextAsync(fullPath);
@@ -477,6 +486,7 @@ public ContextMenu CreateRevisionFileContextMenuByFolder(string path)
477486
var copyPath = new MenuItem();
478487
copyPath.Header = App.Text("CopyPath");
479488
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
489+
copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
480490
copyPath.Click += async (_, ev) =>
481491
{
482492
await App.CopyTextAsync(path);
@@ -486,6 +496,7 @@ public ContextMenu CreateRevisionFileContextMenuByFolder(string path)
486496
var copyFullPath = new MenuItem();
487497
copyFullPath.Header = App.Text("CopyFullPath");
488498
copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
499+
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
489500
copyFullPath.Click += async (_, e) =>
490501
{
491502
await App.CopyTextAsync(fullPath);
@@ -622,6 +633,7 @@ await Commands.SaveRevisionFile
622633
var copyPath = new MenuItem();
623634
copyPath.Header = App.Text("CopyPath");
624635
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
636+
copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
625637
copyPath.Click += async (_, ev) =>
626638
{
627639
await App.CopyTextAsync(file.Path);
@@ -631,6 +643,7 @@ await Commands.SaveRevisionFile
631643
var copyFullPath = new MenuItem();
632644
copyFullPath.Header = App.Text("CopyFullPath");
633645
copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
646+
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
634647
copyFullPath.Click += async (_, e) =>
635648
{
636649
await App.CopyTextAsync(fullPath);

src/ViewModels/RevisionCompare.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ public ContextMenu CreateChangeContextMenu()
168168
var copyPath = new MenuItem();
169169
copyPath.Header = App.Text("CopyPath");
170170
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
171+
copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
171172
copyPath.Click += async (_, ev) =>
172173
{
173174
await App.CopyTextAsync(change.Path);
@@ -178,6 +179,7 @@ public ContextMenu CreateChangeContextMenu()
178179
var copyFullPath = new MenuItem();
179180
copyFullPath.Header = App.Text("CopyFullPath");
180181
copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
182+
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
181183
copyFullPath.Click += async (_, e) =>
182184
{
183185
await App.CopyTextAsync(Native.OS.GetAbsPath(_repo, change.Path));

src/ViewModels/StashesPage.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ public ContextMenu MakeContextMenuForChange()
276276
var copyPath = new MenuItem();
277277
copyPath.Header = App.Text("CopyPath");
278278
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
279+
copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
279280
copyPath.Click += async (_, ev) =>
280281
{
281282
await App.CopyTextAsync(change.Path);
@@ -285,6 +286,7 @@ public ContextMenu MakeContextMenuForChange()
285286
var copyFullPath = new MenuItem();
286287
copyFullPath.Header = App.Text("CopyFullPath");
287288
copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
289+
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
288290
copyFullPath.Click += async (_, e) =>
289291
{
290292
await App.CopyTextAsync(Native.OS.GetAbsPath(_repo.FullPath, change.Path));

src/ViewModels/WorkingCopy.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold
10091009
var copy = new MenuItem();
10101010
copy.Header = App.Text("CopyPath");
10111011
copy.Icon = App.CreateMenuIcon("Icons.Copy");
1012+
copy.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
10121013
copy.Click += async (_, e) =>
10131014
{
10141015
await App.CopyTextAsync(hasSelectedFolder ? selectedSingleFolder : change.Path);
@@ -1018,6 +1019,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold
10181019
var copyFullPath = new MenuItem();
10191020
copyFullPath.Header = App.Text("CopyFullPath");
10201021
copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
1022+
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
10211023
copyFullPath.Click += async (_, e) =>
10221024
{
10231025
await App.CopyTextAsync(hasSelectedFolder ? Native.OS.GetAbsPath(_repo.FullPath, selectedSingleFolder) : path);
@@ -1197,6 +1199,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold
11971199
var copy = new MenuItem();
11981200
copy.Header = App.Text("CopyPath");
11991201
copy.Icon = App.CreateMenuIcon("Icons.Copy");
1202+
copy.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
12001203
copy.Click += async (_, e) =>
12011204
{
12021205
await App.CopyTextAsync(selectedSingleFolder);
@@ -1206,6 +1209,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold
12061209
var copyFullPath = new MenuItem();
12071210
copyFullPath.Header = App.Text("CopyPath");
12081211
copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
1212+
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
12091213
copyFullPath.Click += async (_, e) =>
12101214
{
12111215
await App.CopyTextAsync(Native.OS.GetAbsPath(_repo.FullPath, selectedSingleFolder));
@@ -1500,6 +1504,7 @@ public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder
15001504
var copyPath = new MenuItem();
15011505
copyPath.Header = App.Text("CopyPath");
15021506
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
1507+
copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
15031508
copyPath.Click += async (_, e) =>
15041509
{
15051510
await App.CopyTextAsync(hasSelectedFolder ? selectedSingleFolder : change.Path);
@@ -1509,6 +1514,7 @@ public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder
15091514
var copyFullPath = new MenuItem();
15101515
copyFullPath.Header = App.Text("CopyFullPath");
15111516
copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
1517+
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
15121518
copyFullPath.Click += async (_, e) =>
15131519
{
15141520
var target = hasSelectedFolder ? Native.OS.GetAbsPath(_repo.FullPath, selectedSingleFolder) : path;
@@ -1608,6 +1614,7 @@ public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder
16081614
var copyPath = new MenuItem();
16091615
copyPath.Header = App.Text("CopyPath");
16101616
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
1617+
copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
16111618
copyPath.Click += async (_, e) =>
16121619
{
16131620
await App.CopyTextAsync(selectedSingleFolder);
@@ -1617,6 +1624,7 @@ public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder
16171624
var copyFullPath = new MenuItem();
16181625
copyFullPath.Header = App.Text("CopyFullPath");
16191626
copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
1627+
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
16201628
copyFullPath.Click += async (_, e) =>
16211629
{
16221630
await App.CopyTextAsync(Native.OS.GetAbsPath(_repo.FullPath, selectedSingleFolder));

src/Views/ChangeCollectionView.axaml.cs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,46 @@ public class ChangeCollectionContainer : ListBox
3333
{
3434
protected override Type StyleKeyOverride => typeof(ListBox);
3535

36-
protected override void OnKeyDown(KeyEventArgs e)
36+
protected override async void OnKeyDown(KeyEventArgs e)
3737
{
38-
if (SelectedItems is [ViewModels.ChangeTreeNode { IsFolder: true } node] && e.KeyModifiers == KeyModifiers.None)
38+
if (SelectedItems is [ViewModels.ChangeTreeNode node])
3939
{
40-
if ((node.IsExpanded && e.Key == Key.Left) || (!node.IsExpanded && e.Key == Key.Right))
40+
if (((e.Key == Key.Left && node.IsExpanded) || (e.Key == Key.Right && !node.IsExpanded)) &&
41+
e.KeyModifiers == KeyModifiers.None)
4142
{
4243
this.FindAncestorOfType<ChangeCollectionView>()?.ToggleNodeIsExpanded(node);
4344
e.Handled = true;
4445
}
46+
else if (e.Key == Key.C &&
47+
e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
48+
{
49+
var path = node.FullPath;
50+
51+
if (e.KeyModifiers.HasFlag(KeyModifiers.Shift))
52+
{
53+
do
54+
{
55+
var repoView = this.FindAncestorOfType<Repository>();
56+
if (repoView is { DataContext: ViewModels.Repository repo })
57+
{
58+
path = Native.OS.GetAbsPath(repo.FullPath, path);
59+
break;
60+
}
61+
62+
var branchCompareView = this.FindAncestorOfType<BranchCompare>();
63+
if (branchCompareView is { DataContext: ViewModels.BranchCompare branchCompare })
64+
{
65+
path = branchCompare.GetAbsPath(path);
66+
break;
67+
}
68+
69+
// NOTE: if there is another window uses ChangeCollectionView, add it here!
70+
} while (false);
71+
}
72+
73+
await App.CopyTextAsync(path);
74+
e.Handled = true;
75+
}
4576
}
4677

4778
if (!e.Handled && e.Key != Key.Space && e.Key != Key.Enter)
@@ -112,7 +143,7 @@ public ChangeCollectionView()
112143

113144
public void ToggleNodeIsExpanded(ViewModels.ChangeTreeNode node)
114145
{
115-
if (Content is ViewModels.ChangeCollectionAsTree tree)
146+
if (Content is ViewModels.ChangeCollectionAsTree tree && node.IsFolder)
116147
{
117148
node.IsExpanded = !node.IsExpanded;
118149

src/Views/CommitDetail.axaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
<ListBox Background="Transparent"
3434
Margin="64,0,8,4"
3535
SelectionMode="Single"
36-
ItemsSource="{Binding Changes, Converter={x:Static c:ListConverters.Top100Changes}}">
36+
ItemsSource="{Binding Changes, Converter={x:Static c:ListConverters.Top100Changes}}"
37+
KeyDown="OnCommitListKeyDown">
3738
<ListBox.Styles>
3839
<Style Selector="ListBoxItem">
3940
<Setter Property="Padding" Value="0"/>

src/Views/CommitDetail.axaml.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using Avalonia.Controls;
23
using Avalonia.Input;
34

@@ -31,5 +32,21 @@ private void OnChangeContextRequested(object sender, ContextRequestedEventArgs e
3132

3233
e.Handled = true;
3334
}
35+
36+
private async void OnCommitListKeyDown(object sender, KeyEventArgs e)
37+
{
38+
if (DataContext is ViewModels.CommitDetail detail && sender is Grid { DataContext: Models.Change change })
39+
{
40+
if (e.Key == Key.C && e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
41+
{
42+
var path = change.Path;
43+
if (e.KeyModifiers.HasFlag(KeyModifiers.Shift))
44+
path = detail.GetAbsPath(path);
45+
46+
await App.CopyTextAsync(path);
47+
e.Handled = true;
48+
}
49+
}
50+
}
3451
}
3552
}

src/Views/RevisionFileTreeView.axaml.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,30 @@ public class RevisionFileRowsListBox : ListBox
108108

109109
protected override async void OnKeyDown(KeyEventArgs e)
110110
{
111-
if (SelectedItem is ViewModels.RevisionFileTreeNode { IsFolder: true } node && e.KeyModifiers == KeyModifiers.None)
111+
if (SelectedItem is ViewModels.RevisionFileTreeNode node)
112112
{
113-
if ((node.IsExpanded && e.Key == Key.Left) || (!node.IsExpanded && e.Key == Key.Right))
113+
if (node.IsFolder &&
114+
e.KeyModifiers == KeyModifiers.None &&
115+
(node.IsExpanded && e.Key == Key.Left) || (!node.IsExpanded && e.Key == Key.Right))
114116
{
115117
var tree = this.FindAncestorOfType<RevisionFileTreeView>();
116118
await tree?.ToggleNodeIsExpandedAsync(node);
117119
e.Handled = true;
118120
}
121+
else if (e.Key == Key.C &&
122+
e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
123+
{
124+
var detailView = this.FindAncestorOfType<CommitDetail>();
125+
if (detailView is { DataContext: ViewModels.CommitDetail detail })
126+
{
127+
var path = node.Backend?.Path ?? string.Empty;
128+
if (e.KeyModifiers.HasFlag(KeyModifiers.Shift))
129+
path = detail.GetAbsPath(path);
130+
131+
await App.CopyTextAsync(path);
132+
e.Handled = true;
133+
}
134+
}
119135
}
120136

121137
if (!e.Handled)

0 commit comments

Comments
 (0)