Skip to content

Commit 8c0b650

Browse files
author
Iakov Senatov
committed
feat: Copy as Pathname in all context menus (⌥⌘C)
- FileAction, DirectoryAction, MultiSelectionAction: add .copyAsPathname case - FileContextMenu, DirectoryContextMenu, MultiSelectionContextMenu: add menu item after Copy - FindFilesResultsView: add Copy as Pathname to search results context menu - All 3 action handlers: implement pasteboard copy of file path(s) - Multiple files: paths joined with newline - Shortcut hint: ⌥⌘C (Finder-style)
1 parent 68644eb commit 8c0b650

File tree

12 files changed

+60
-0
lines changed

12 files changed

+60
-0
lines changed

GUI/Info.plist

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@
3131
<key>UTTypeTagSpecification</key>
3232
<dict/>
3333
</dict>
34+
<dict>
35+
<key>UTTypeIdentifier</key>
36+
<string>com.senatov.miminavigator.column-id</string>
37+
<key>UTTypeDescription</key>
38+
<string>MiMiNavigator Column ID</string>
39+
<key>UTTypeConformsTo</key>
40+
<array>
41+
<string>public.data</string>
42+
</array>
43+
<key>UTTypeTagSpecification</key>
44+
<dict/>
45+
</dict>
3446
</array>
3547
<key>NSAppTransportSecurity</key>
3648
<dict>

GUI/Resources/Localizable.xcstrings

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@
178178
},
179179
"%lld shortcuts" : {
180180

181+
},
182+
"%lld%%" : {
183+
"comment" : "A label showing the current UI scale percentage.",
184+
"isCommentAutoGenerated" : true
181185
},
182186
"%lld×" : {
183187
"comment" : "A label showing the number of times to retry on connection drop. The argument is the number of retry attempts.",
@@ -732,6 +736,9 @@
732736
},
733737
"Date Mod." : {
734738

739+
},
740+
"Default interface scale" : {
741+
735742
},
736743
"Delete" : {
737744
"comment" : "Delete button",

GUI/Sources/ContextMenu/ActionsEnums/DirectoryAction.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ enum DirectoryAction: String, CaseIterable, Identifiable {
1919
// Edit section
2020
case cut
2121
case copy
22+
case copyAsPathname
2223
case paste
2324
case duplicate
2425

@@ -53,6 +54,7 @@ enum DirectoryAction: String, CaseIterable, Identifiable {
5354
case .viewLister: return "Quick Look"
5455
case .cut: return "Cut"
5556
case .copy: return "Copy"
57+
case .copyAsPathname: return "Copy as Pathname"
5658
case .paste: return "Paste"
5759
case .duplicate: return "Duplicate"
5860
case .compress: return "Compress"
@@ -77,6 +79,7 @@ enum DirectoryAction: String, CaseIterable, Identifiable {
7779
case .viewLister: return "eye"
7880
case .cut: return "scissors"
7981
case .copy: return "doc.on.doc"
82+
case .copyAsPathname: return "doc.on.doc.fill"
8083
case .paste: return "doc.on.clipboard"
8184
case .duplicate: return "plus.square.on.square"
8285
case .compress: return "archivebox"
@@ -98,6 +101,7 @@ enum DirectoryAction: String, CaseIterable, Identifiable {
98101
case .openInNewTab: return "⌘T"
99102
case .cut: return "⌘X"
100103
case .copy: return "⌘C"
104+
case .copyAsPathname: return "⌥⌘C"
101105
case .paste: return "⌘V"
102106
case .duplicate: return "⌘D"
103107
case .delete: return "⌘⌫"

GUI/Sources/ContextMenu/ActionsEnums/FileAction.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ enum FileAction: String, CaseIterable, Identifiable {
2121
// Edit section
2222
case cut
2323
case copy
24+
case copyAsPathname
2425
case paste
2526
case duplicate
2627

@@ -54,6 +55,7 @@ enum FileAction: String, CaseIterable, Identifiable {
5455
case .viewLister: return "Quick Look"
5556
case .cut: return "Cut"
5657
case .copy: return "Copy"
58+
case .copyAsPathname: return "Copy as Pathname"
5759
case .paste: return "Paste"
5860
case .duplicate: return "Duplicate"
5961
case .compress: return "Compress"
@@ -77,6 +79,7 @@ enum FileAction: String, CaseIterable, Identifiable {
7779
case .viewLister: return "eye"
7880
case .cut: return "scissors"
7981
case .copy: return "doc.on.doc"
82+
case .copyAsPathname: return "doc.on.doc.fill"
8083
case .paste: return "doc.on.clipboard"
8184
case .duplicate: return "plus.square.on.square"
8285
case .compress: return "archivebox"
@@ -96,6 +99,7 @@ enum FileAction: String, CaseIterable, Identifiable {
9699
switch self {
97100
case .cut: return "⌘X"
98101
case .copy: return "⌘C"
102+
case .copyAsPathname: return "⌥⌘C"
99103
case .paste: return "⌘V"
100104
case .openInNewTab: return "⌘T"
101105
case .duplicate: return "⌘D"

GUI/Sources/ContextMenu/ActionsEnums/MultiSelectionAction.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ enum MultiSelectionAction: String, CaseIterable, Identifiable {
1313
// Clipboard
1414
case cut
1515
case copy
16+
case copyAsPathname
1617
case paste
1718

1819
// Operations
@@ -32,6 +33,7 @@ enum MultiSelectionAction: String, CaseIterable, Identifiable {
3233
switch self {
3334
case .cut: return "Cut"
3435
case .copy: return "Copy"
36+
case .copyAsPathname: return "Copy as Pathname"
3537
case .paste: return "Paste"
3638
case .compress: return "Compress"
3739
case .share: return "Share..."
@@ -45,6 +47,7 @@ enum MultiSelectionAction: String, CaseIterable, Identifiable {
4547
switch self {
4648
case .cut: return "scissors"
4749
case .copy: return "doc.on.doc"
50+
case .copyAsPathname: return "doc.on.doc.fill"
4851
case .paste: return "doc.on.clipboard"
4952
case .compress: return "archivebox"
5053
case .share: return "square.and.arrow.up"
@@ -58,6 +61,7 @@ enum MultiSelectionAction: String, CaseIterable, Identifiable {
5861
switch self {
5962
case .cut: return "⌘X"
6063
case .copy: return "⌘C"
64+
case .copyAsPathname: return "⌥⌘C"
6165
case .paste: return "⌘V"
6266
case .delete: return "⌘⌫"
6367
default: return nil

GUI/Sources/ContextMenu/Menus/DirectoryContextMenu.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ struct DirectoryContextMenu: View {
4141
// ═══════════════════════════════════════════
4242
menuButton(.cut)
4343
menuButton(.copy)
44+
menuButton(.copyAsPathname)
4445
menuButton(.paste)
4546
menuButton(.duplicate)
4647

GUI/Sources/ContextMenu/Menus/FileContextMenu.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ struct FileContextMenu: View {
4141
// ═══════════════════════════════════════════
4242
menuButton(.cut)
4343
menuButton(.copy)
44+
menuButton(.copyAsPathname)
4445
menuButton(.paste)
4546
menuButton(.duplicate)
4647

GUI/Sources/ContextMenu/Menus/MultiSelectionContextMenu.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct MultiSelectionContextMenu: View {
3030
// ═══════════════════════════════════════════
3131
menuButton(.cut)
3232
menuButton(.copy)
33+
menuButton(.copyAsPathname)
3334
menuButton(.paste)
3435

3536
Divider()

GUI/Sources/ContextMenu/Services/Coordinator/DirectoryActionsHandler.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ extension ContextMenuCoordinator {
6464
case .copy:
6565
clipboard.copy(files: batchFiles, from: panel)
6666

67+
case .copyAsPathname:
68+
let paths = batchFiles.map { $0.urlValue.path }
69+
let pasteboard = NSPasteboard.general
70+
pasteboard.clearContents()
71+
pasteboard.setString(paths.joined(separator: "\n"), forType: .string)
72+
log.info("[DirectoryActions] copied \(paths.count) pathname(s) to clipboard")
73+
6774
case .paste:
6875
Task {
6976
await performPaste(to: panel, appState: appState)

GUI/Sources/ContextMenu/Services/Coordinator/FileActionsHandler.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ extension ContextMenuCoordinator {
6262
case .copy:
6363
clipboard.copy(files: batchFiles, from: panel)
6464

65+
case .copyAsPathname:
66+
let paths = batchFiles.map { $0.urlValue.path }
67+
let pasteboard = NSPasteboard.general
68+
pasteboard.clearContents()
69+
pasteboard.setString(paths.joined(separator: "\n"), forType: .string)
70+
log.info("[FileActions] copied \(paths.count) pathname(s) to clipboard")
71+
6572
case .paste:
6673
Task {
6774
await performPaste(to: panel, appState: appState)

0 commit comments

Comments
 (0)