Skip to content

Commit aa30305

Browse files
Added phantom files and file renaming focus
1 parent 688dc84 commit aa30305

File tree

4 files changed

+98
-19
lines changed

4 files changed

+98
-19
lines changed

CodeEdit/Features/CEWorkspace/Models/CEWorkspaceFile.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ final class CEWorkspaceFile: Codable, Comparable, Hashable, Identifiable, Editor
164164
FileIcon.iconColor(fileType: type)
165165
}
166166

167+
/// Indicates whether the file is phantom (not yet created on disk)
168+
var isPhantom: Bool = false
169+
167170
init(
168171
id: String,
169172
url: URL,

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

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,35 @@ extension ProjectNavigatorMenu {
8181
try? process.run()
8282
}
8383

84-
// TODO: allow custom file names
8584
/// Action that creates a new untitled file
8685
@objc
8786
func newFile() {
8887
guard let item else { return }
89-
do {
90-
if let newFile = try workspace?.workspaceFileManager?.addFile(fileName: "untitled", toFile: item) {
91-
workspace?.listenerModel.highlightedFileItem = newFile
92-
workspace?.editorManager?.openTab(item: newFile)
88+
let phantomFile = CEWorkspaceFile(
89+
id: UUID().uuidString,
90+
url: item.url.appendingPathComponent("Untitled"),
91+
changeType: nil,
92+
staged: false
93+
)
94+
phantomFile.isPhantom = true
95+
phantomFile.parent = item
96+
97+
// Add phantom file to parent's children temporarily for display
98+
if let workspace = workspace,
99+
let fileManager = workspace.workspaceFileManager {
100+
_ = fileManager.childrenOfFile(item)
101+
fileManager.flattenedFileItems[phantomFile.id] = phantomFile
102+
if fileManager.childrenMap[item.id] == nil {
103+
fileManager.childrenMap[item.id] = []
93104
}
94-
} catch {
95-
let alert = NSAlert(error: error)
96-
alert.addButton(withTitle: "Dismiss")
97-
alert.runModal()
105+
fileManager.childrenMap[item.id]?.append(phantomFile.id)
106+
}
107+
108+
workspace?.listenerModel.highlightedFileItem = phantomFile
109+
sender.outlineView.reloadData()
110+
111+
DispatchQueue.main.async {
112+
self.renameFile()
98113
}
99114
}
100115

@@ -103,11 +118,11 @@ extension ProjectNavigatorMenu {
103118
func renameFile() {
104119
guard let newFile = workspace?.listenerModel.highlightedFileItem else { return }
105120
let row = sender.outlineView.row(forItem: newFile)
106-
guard row > 0,
121+
guard row >= 0,
107122
let cell = sender.outlineView.view(
108123
atColumn: 0,
109124
row: row,
110-
makeIfNecessary: false
125+
makeIfNecessary: true
111126
) as? ProjectNavigatorTableViewCell else {
112127
return
113128
}

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

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,72 @@ final class ProjectNavigatorTableViewCell: FileSystemTableViewCell {
5656

5757
override func controlTextDidEndEditing(_ obj: Notification) {
5858
guard let fileItem else { return }
59-
textField?.backgroundColor = fileItem.validateFileName(for: textField?.stringValue ?? "") ? .none : errorRed
60-
if fileItem.validateFileName(for: textField?.stringValue ?? "") {
61-
let destinationURL = fileItem.url
62-
.deletingLastPathComponent()
63-
.appending(path: textField?.stringValue ?? "")
64-
delegate?.moveFile(file: fileItem, to: destinationURL)
59+
60+
if fileItem.isPhantom {
61+
handlePhantomFileCompletion(fileItem: fileItem, wasCancelled: false)
6562
} else {
66-
textField?.stringValue = fileItem.labelFileName()
63+
textField?.backgroundColor = fileItem.validateFileName(for: textField?.stringValue ?? "") ? .none : errorRed
64+
if fileItem.validateFileName(for: textField?.stringValue ?? "") {
65+
let destinationURL = fileItem.url
66+
.deletingLastPathComponent()
67+
.appending(path: textField?.stringValue ?? "")
68+
delegate?.moveFile(file: fileItem, to: destinationURL)
69+
} else {
70+
textField?.stringValue = fileItem.labelFileName()
71+
}
6772
}
6873
delegate?.cellDidFinishEditing()
6974
}
75+
76+
private func handlePhantomFileCompletion(fileItem: CEWorkspaceFile, wasCancelled: Bool) {
77+
if wasCancelled {
78+
if let workspace = delegate as? ProjectNavigatorViewController,
79+
let workspaceFileManager = workspace.workspace?.workspaceFileManager {
80+
removePhantomFile(fileItem: fileItem, fileManager: workspaceFileManager)
81+
}
82+
return
83+
}
84+
85+
let newName = textField?.stringValue ?? ""
86+
if !newName.isEmpty && newName.isValidFilename {
87+
if let workspace = delegate as? ProjectNavigatorViewController,
88+
let workspaceFileManager = workspace.workspace?.workspaceFileManager,
89+
let parent = fileItem.parent {
90+
do {
91+
let newFile = try workspaceFileManager.addFile(
92+
fileName: newName,
93+
toFile: parent
94+
)
95+
96+
removePhantomFile(fileItem: fileItem, fileManager: workspaceFileManager)
97+
workspace.workspace?.listenerModel.highlightedFileItem = newFile
98+
workspace.workspace?.editorManager?.openTab(item: newFile)
99+
100+
} catch {
101+
let alert = NSAlert(error: error)
102+
alert.addButton(withTitle: "Dismiss")
103+
alert.runModal()
104+
removePhantomFile(fileItem: fileItem, fileManager: workspaceFileManager)
105+
}
106+
}
107+
} else {
108+
if let workspace = delegate as? ProjectNavigatorViewController,
109+
let workspaceFileManager = workspace.workspace?.workspaceFileManager {
110+
removePhantomFile(fileItem: fileItem, fileManager: workspaceFileManager)
111+
}
112+
}
113+
}
114+
115+
private func removePhantomFile(fileItem: CEWorkspaceFile, fileManager: CEWorkspaceFileManager) {
116+
fileManager.flattenedFileItems.removeValue(forKey: fileItem.id)
117+
118+
if let parent = fileItem.parent,
119+
let childrenIds = fileManager.childrenMap[parent.id] {
120+
fileManager.childrenMap[parent.id] = childrenIds.filter { $0 != fileItem.id }
121+
}
122+
123+
if let workspace = delegate as? ProjectNavigatorViewController {
124+
workspace.outlineView.reloadData()
125+
}
126+
}
70127
}

CodeEdit/Features/NavigatorArea/ProjectNavigator/OutlineView/ProjectNavigatorViewController+NSOutlineViewDelegate.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ extension ProjectNavigatorViewController: NSOutlineViewDelegate {
4444

4545
guard let item = outlineView.item(atRow: selectedIndex) as? CEWorkspaceFile else { return }
4646

47-
if !item.isFolder && shouldSendSelectionUpdate {
47+
if !item.isFolder && !item.isPhantom && shouldSendSelectionUpdate {
4848
shouldSendSelectionUpdate = false
4949
if workspace?.editorManager?.activeEditor.selectedTab?.file != item {
5050
workspace?.editorManager?.activeEditor.openTab(file: item, asTemporary: true)
@@ -131,6 +131,10 @@ extension ProjectNavigatorViewController: NSOutlineViewDelegate {
131131
outlineView.selectRowIndexes(.init(integer: row), byExtendingSelection: false)
132132
shouldSendSelectionUpdate = true
133133

134+
if fileItem.isPhantom {
135+
return
136+
}
137+
134138
if row < 0 {
135139
let alert = NSAlert()
136140
alert.messageText = NSLocalizedString(

0 commit comments

Comments
 (0)