Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select multiple files in the project navigator #1906

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CodeEdit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
30E6D0012A6E505200A58B20 /* NavigatorSidebarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E6D0002A6E505200A58B20 /* NavigatorSidebarViewModel.swift */; };
3E0196732A3921AC002648D8 /* codeedit_shell_integration_rc.zsh in Resources */ = {isa = PBXBuildFile; fileRef = 3E0196722A3921AC002648D8 /* codeedit_shell_integration_rc.zsh */; };
3E01967A2A392B45002648D8 /* codeedit_shell_integration.bash in Resources */ = {isa = PBXBuildFile; fileRef = 3E0196792A392B45002648D8 /* codeedit_shell_integration.bash */; };
4A6F0DB52CBA462B00499627 /* ProjectNavigatorMenuActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A6F0DB42CBA462B00499627 /* ProjectNavigatorMenuActions.swift */; };
4E7F066629602E7B00BB3C12 /* CodeEditSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E7F066529602E7B00BB3C12 /* CodeEditSplitViewController.swift */; };
4EE96ECB2960565E00FFBEA8 /* DocumentsUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE96ECA2960565E00FFBEA8 /* DocumentsUnitTests.swift */; };
4EE96ECE296059E000FFBEA8 /* NSHapticFeedbackPerformerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE96ECD296059E000FFBEA8 /* NSHapticFeedbackPerformerMock.swift */; };
Expand Down Expand Up @@ -773,6 +774,7 @@
30E6D0002A6E505200A58B20 /* NavigatorSidebarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigatorSidebarViewModel.swift; sourceTree = "<group>"; };
3E0196722A3921AC002648D8 /* codeedit_shell_integration_rc.zsh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = codeedit_shell_integration_rc.zsh; sourceTree = "<group>"; };
3E0196792A392B45002648D8 /* codeedit_shell_integration.bash */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = codeedit_shell_integration.bash; sourceTree = "<group>"; };
4A6F0DB42CBA462B00499627 /* ProjectNavigatorMenuActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectNavigatorMenuActions.swift; sourceTree = "<group>"; };
4E7F066529602E7B00BB3C12 /* CodeEditSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeEditSplitViewController.swift; sourceTree = "<group>"; };
4EE96ECA2960565E00FFBEA8 /* DocumentsUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentsUnitTests.swift; sourceTree = "<group>"; };
4EE96ECD296059E000FFBEA8 /* NSHapticFeedbackPerformerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSHapticFeedbackPerformerMock.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1461,6 +1463,7 @@
6CC17B502C43311900834E2C /* ProjectNavigatorViewController+NSOutlineViewDataSource.swift */,
285FEC6F27FE4B9800E57D53 /* ProjectNavigatorTableViewCell.swift */,
285FEC7127FE4EEF00E57D53 /* ProjectNavigatorMenu.swift */,
4A6F0DB42CBA462B00499627 /* ProjectNavigatorMenuActions.swift */,
D7DC4B75298FFBE900D6C83D /* ProjectNavigatorViewController+OutlineTableViewCellDelegate.swift */,
EC0870F62A455F6400EB8692 /* ProjectNavigatorViewController+NSMenuDelegate.swift */,
);
Expand Down Expand Up @@ -4286,6 +4289,7 @@
587B9DA629300ABD00AC7927 /* ToolbarBranchPicker.swift in Sources */,
6C6BD6F629CD145F00235D17 /* ExtensionInfo.swift in Sources */,
04BA7C202AE2D92B00584E1C /* GitClient+Status.swift in Sources */,
4A6F0DB52CBA462B00499627 /* ProjectNavigatorMenuActions.swift in Sources */,
58F2EB05292FB2B0004A9BDE /* Settings.swift in Sources */,
6CBD1BC62978DE53006639D5 /* Font+Caption3.swift in Sources */,
30E6D0012A6E505200A58B20 /* NavigatorSidebarViewModel.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,29 @@ extension CEWorkspaceFileManager {
}
}

/// This function deletes multiple files or folders from the current project by erasing immediately.
/// - Parameters:
/// - files: The files to delete
/// - confirmDelete: True to present an alert to confirm the delete.
public func batchDelete(files: Set<CEWorkspaceFile>, confirmDelete: Bool = true) {
let deleteConfirmation = NSAlert()
deleteConfirmation.messageText = "Are you sure you want to delete the \(files.count) selected items?"
deleteConfirmation.informativeText = "\(files.count) items will be deleted immediately. You cannot undo this action."
deleteConfirmation.alertStyle = .critical
deleteConfirmation.addButton(withTitle: "Delete")
deleteConfirmation.buttons.last?.hasDestructiveAction = true
deleteConfirmation.addButton(withTitle: "Cancel")
if !confirmDelete || deleteConfirmation.runModal() == .alertFirstButtonReturn {
for file in files where fileManager.fileExists(atPath: file.url.path) {
do {
try fileManager.removeItem(at: file.url)
} catch {
fatalError(error.localizedDescription)
LeonardoLarranaga marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}

/// This function duplicates the item or folder
/// - Parameter file: The file to duplicate
/// - Authors: Mattijs Eikelenboom, KaiTheRedNinja. *Moved from 7c27b1e*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ final class ProjectNavigatorMenu: NSMenu {
/// The workspace, for opening the item
var workspace: WorkspaceDocument?

var outlineView: NSOutlineView
/// The `ProjectNavigatorViewController` is being called from.
/// By sending it, we can access it's variables and functions.
var sender: ProjectNavigatorViewController

init(sender: NSOutlineView) {
outlineView = sender
init(_ sender: ProjectNavigatorViewController) {
self.sender = sender
super.init(title: "Options")
}

Expand All @@ -42,9 +44,9 @@ final class ProjectNavigatorMenu: NSMenu {
return mItem
}

/// Setup the menu and disables certain items when `isFile` is false
/// - Parameter isFile: A flag indicating that the item is a file instead of a directory
private func setupMenu() {
/// Configures the menu based on the current selection in the outline view.
/// - Menu items get added depending on the amount of selected items.
private func setupMenu() { // swiftlint:disable:this function_body_length
guard let item else { return }
let showInFinder = menuItem("Show in Finder", action: #selector(showInFinder))

Expand Down Expand Up @@ -92,19 +94,30 @@ final class ProjectNavigatorMenu: NSMenu {
showFileInspector,
NSMenuItem.separator(),
newFile,
newFolder,
NSMenuItem.separator(),
rename,
trash,
delete,
duplicate,
NSMenuItem.separator(),
sortByName,
sortByType,
NSMenuItem.separator(),
sourceControl,
newFolder
]

if canCreateFolderFromSelection() {
items.append(menuItem("New Folder from Selection", action: #selector(newFolderFromSelection)))
}
items.append(NSMenuItem.separator())
if selectedItems().count == 1 {
items.append(rename)
}

items.append(
contentsOf: [
trash,
delete,
duplicate,
NSMenuItem.separator(),
sortByName,
sortByType,
NSMenuItem.separator(),
sourceControl,
]
)

setSubmenu(openAsMenu(item: item), for: openAs)
setSubmenu(sourceControlMenu(item: item), for: sourceControl)
}
Expand Down Expand Up @@ -183,87 +196,6 @@ final class ProjectNavigatorMenu: NSMenu {
removeAllItems()
setupMenu()
}

/// Action that opens **Finder** at the items location.
@objc
private func showInFinder() {
item?.showInFinder()
}

/// Action that opens the item, identical to clicking it.
@objc
private func openInTab() {
if let item {
workspace?.editorManager?.openTab(item: item)
}
}

/// Action that opens in an external editor
@objc
private func openWithExternalEditor() {
item?.openWithExternalEditor()
}

// TODO: allow custom file names
/// Action that creates a new untitled file
@objc
private func newFile() {
guard let item else { return }
do {
try workspace?.workspaceFileManager?.addFile(fileName: "untitled", toFile: item)
} catch {
let alert = NSAlert(error: error)
alert.addButton(withTitle: "Dismiss")
alert.runModal()
}
outlineView.expandItem(item.isFolder ? item : item.parent)
}

// TODO: allow custom folder names
/// Action that creates a new untitled folder
@objc
private func newFolder() {
guard let item else { return }
workspace?.workspaceFileManager?.addFolder(folderName: "untitled", toFile: item)
outlineView.expandItem(item)
outlineView.expandItem(item.isFolder ? item : item.parent)
}

/// Opens the rename file dialogue on the cell this was presented from.
@objc
private func renameFile() {
let row = outlineView.row(forItem: item)
guard row > 0,
let cell = outlineView.view(
atColumn: 0,
row: row,
makeIfNecessary: false
) as? ProjectNavigatorTableViewCell else {
return
}
outlineView.window?.makeFirstResponder(cell.textField)
}

/// Action that moves the item to trash.
@objc
private func trash() {
guard let item else { return }
workspace?.workspaceFileManager?.trash(file: item)
}

/// Action that deletes the item immediately.
@objc
private func delete() {
guard let item else { return }
workspace?.workspaceFileManager?.delete(file: item)
}

/// Action that duplicates the item
@objc
private func duplicate() {
guard let item else { return }
workspace?.workspaceFileManager?.duplicate(file: item)
}
}

extension NSMenuItem {
Expand Down
Loading