Skip to content

Commit 6c85d99

Browse files
Added copy path and copy relative path options in project navigator menu
1 parent 13d98b7 commit 6c85d99

File tree

3 files changed

+55
-16
lines changed

3 files changed

+55
-16
lines changed

CodeEdit/Features/Editor/TabBar/Views/EditorTabBarContextMenu.swift

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
// Created by Khan Winter on 6/4/22.
66
//
77

8-
import Foundation
98
import SwiftUI
9+
import Foundation
1010

1111
extension View {
1212
func tabBarContextMenu(item: CEWorkspaceFile, isTemporary: Bool) -> some View {
@@ -149,24 +149,21 @@ struct EditorTabBarContextMenu: ViewModifier {
149149
guard let rootPath = workspace.workspaceFileManager?.folderUrl else {
150150
return
151151
}
152-
// Calculate the relative path
153-
var rootComponents = rootPath.standardizedFileURL.pathComponents
154-
var destinationComponents = item.url.standardizedFileURL.pathComponents
155-
156-
// Remove any same path components
157-
while !rootComponents.isEmpty && !destinationComponents.isEmpty
158-
&& rootComponents.first == destinationComponents.first {
159-
rootComponents.remove(at: 0)
160-
destinationComponents.remove(at: 0)
152+
let destinationComponents = item.url.standardizedFileURL.pathComponents
153+
let baseComponents = rootPath.standardizedFileURL.pathComponents
154+
155+
// Find common prefix length
156+
var prefixCount = 0
157+
while prefixCount < min(destinationComponents.count, baseComponents.count)
158+
&& destinationComponents[prefixCount] == baseComponents[prefixCount] {
159+
prefixCount += 1
161160
}
162-
163-
// Make a "../" for each remaining component in the root URL
164-
var relativePath: String = String(repeating: "../", count: rootComponents.count)
165-
// Add the remaining components for the destination url.
166-
relativePath += destinationComponents.joined(separator: "/")
161+
// Build the relative path
162+
let upPath = String(repeating: "../", count: baseComponents.count - prefixCount)
163+
let downPath = destinationComponents[prefixCount...].joined(separator: "/")
167164

168165
// Copy it to the clipboard
169166
NSPasteboard.general.clearContents()
170-
NSPasteboard.general.setString(relativePath, forType: .string)
167+
NSPasteboard.general.setString(upPath + downPath, forType: .string)
171168
}
172169
}

CodeEdit/Features/NavigatorArea/ProjectNavigator/OutlineView/ProjectNavigatorMenu.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ final class ProjectNavigatorMenu: NSMenu {
5555
let openExternalEditor = menuItem("Open with External Editor", action: #selector(openWithExternalEditor))
5656
let openAs = menuItem("Open As", action: nil)
5757

58+
let copyPath = menuItem("Copy Path", action: #selector(copyPath))
59+
let copyRelativePath = menuItem("Copy Relative Path", action: #selector(copyRelativePath))
60+
5861
let showFileInspector = menuItem("Show File Inspector", action: nil)
5962

6063
let newFile = menuItem("New File...", action: #selector(newFile))
@@ -91,6 +94,9 @@ final class ProjectNavigatorMenu: NSMenu {
9194
openExternalEditor,
9295
openAs,
9396
NSMenuItem.separator(),
97+
copyPath,
98+
copyRelativePath,
99+
NSMenuItem.separator(),
94100
showFileInspector,
95101
NSMenuItem.separator(),
96102
newFile,

CodeEdit/Features/NavigatorArea/ProjectNavigator/OutlineView/ProjectNavigatorMenuActions.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,42 @@ extension ProjectNavigatorMenu {
222222
}
223223
}
224224

225+
/// Copies the absolute path of the selected files
226+
@objc
227+
func copyPath() {
228+
let paths = selectedItems().map {
229+
$0.url.standardizedFileURL.path
230+
}.sorted().joined(separator: "\n")
231+
NSPasteboard.general.clearContents()
232+
NSPasteboard.general.setString(paths, forType: .string)
233+
}
234+
235+
/// Copies the relative path of the selected files
236+
@objc
237+
func copyRelativePath() {
238+
guard let rootPath = workspace?.workspaceFileManager?.folderUrl else {
239+
return
240+
}
241+
let paths = selectedItems().map {
242+
let destinationComponents = $0.url.standardizedFileURL.pathComponents
243+
let baseComponents = rootPath.standardizedFileURL.pathComponents
244+
245+
// Find common prefix length
246+
var prefixCount = 0
247+
while prefixCount < min(destinationComponents.count, baseComponents.count)
248+
&& destinationComponents[prefixCount] == baseComponents[prefixCount] {
249+
prefixCount += 1
250+
}
251+
// Build the relative path
252+
let upPath = String(repeating: "../", count: baseComponents.count - prefixCount)
253+
let downPath = destinationComponents[prefixCount...].joined(separator: "/")
254+
return upPath + downPath
255+
}.sorted().joined(separator: "\n")
256+
257+
NSPasteboard.general.clearContents()
258+
NSPasteboard.general.setString(paths, forType: .string)
259+
}
260+
225261
private func reloadData() {
226262
sender.outlineView.reloadData()
227263
sender.filteredContentChildren.removeAll()

0 commit comments

Comments
 (0)