Skip to content

Commit 3e4eec7

Browse files
Fix file not being created if FS event occured
1 parent 7cf8bc6 commit 3e4eec7

File tree

5 files changed

+57
-12
lines changed

5 files changed

+57
-12
lines changed

CodeEdit/Features/CEWorkspace/Models/CEWorkspaceFileManager+DirectoryEvents.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ extension CEWorkspaceFileManager {
152152
let directoryContentsUrlsRelativePaths = directoryContentsUrls.map({ $0.relativePath })
153153
for (idx, oldURL) in (childrenMap[fileItem.id] ?? []).map({ URL(filePath: $0) }).enumerated().reversed()
154154
where !directoryContentsUrlsRelativePaths.contains(oldURL.relativePath) {
155+
// Don't remove phantom files, they don't exist on disk yet
156+
// They will be cleaned up when the user finishes editing
157+
if let existingFile = flattenedFileItems[oldURL.relativePath],
158+
existingFile.phantomFile != nil {
159+
continue
160+
}
155161
flattenedFileItems.removeValue(forKey: oldURL.relativePath)
156162
childrenMap[fileItem.id]?.remove(at: idx)
157163
}

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

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,49 @@ struct ProjectNavigatorOutlineView: NSViewControllerRepresentable {
8585
guard let outlineView = controller?.outlineView else { return }
8686
let selectedRows = outlineView.selectedRowIndexes.compactMap({ outlineView.item(atRow: $0) })
8787

88-
// If some text view inside the outline view is first responder right now, push the update off
89-
// until editing is finished using the `shouldReloadAfterDoneEditing` flag.
88+
// Check if we're currently editing a phantom file and capture its text
89+
var editingPhantomFile: CEWorkspaceFile?
90+
var capturedText: String?
91+
var capturedSelectionRange: NSRange?
92+
9093
if outlineView.window?.firstResponder !== outlineView
9194
&& outlineView.window?.firstResponder is NSTextView
9295
&& (outlineView.window?.firstResponder as? NSView)?.isDescendant(of: outlineView) == true {
93-
controller?.shouldReloadAfterDoneEditing = true
94-
} else {
95-
for item in updatedItems {
96-
outlineView.reloadItem(item, reloadChildren: true)
96+
// Find the cell being edited by traversing up from the text view
97+
var currentView = outlineView.window?.firstResponder as? NSView
98+
capturedSelectionRange = (outlineView.window?.firstResponder as? NSTextView)?.selectedRange
99+
100+
while let view = currentView {
101+
if let cell = view as? ProjectNavigatorTableViewCell,
102+
let fileItem = cell.fileItem,
103+
fileItem.phantomFile != nil {
104+
editingPhantomFile = fileItem
105+
capturedText = cell.textField?.stringValue
106+
break
107+
}
108+
currentView = view.superview
109+
}
110+
}
111+
112+
// Reload all items with children
113+
for item in updatedItems {
114+
outlineView.reloadItem(item, reloadChildren: true)
115+
}
116+
117+
// If we were editing a phantom file, restore the text field and focus
118+
if let phantomFile = editingPhantomFile, let text = capturedText {
119+
let row = outlineView.row(forItem: phantomFile)
120+
if row >= 0,
121+
let cell = outlineView.view(
122+
atColumn: 0,
123+
row: row,
124+
makeIfNecessary: false
125+
) as? ProjectNavigatorTableViewCell {
126+
cell.textField?.stringValue = text
127+
outlineView.window?.makeFirstResponder(cell.textField)
128+
if let selectionRange = capturedSelectionRange {
129+
cell.textField?.currentEditor()?.selectedRange = selectionRange
130+
}
97131
}
98132
}
99133

@@ -102,6 +136,12 @@ struct ProjectNavigatorOutlineView: NSViewControllerRepresentable {
102136
controller?.shouldSendSelectionUpdate = false
103137
outlineView.selectRowIndexes(IndexSet(selectedIndexes), byExtendingSelection: false)
104138
controller?.shouldSendSelectionUpdate = true
139+
140+
// Reselect the file that is currently active in the editor so it still appears highlighted
141+
if outlineView.selectedRowIndexes.isEmpty,
142+
let activeFileID = workspace?.editorManager?.activeEditor.selectedTab?.file.id {
143+
controller?.updateSelection(itemID: activeFileID)
144+
}
105145
}
106146

107147
deinit {

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@ final class ProjectNavigatorTableViewCell: FileSystemTableViewCell {
5858
guard let fileItem else { return }
5959

6060
if fileItem.phantomFile != nil {
61+
// Capture the text field value before any async work
62+
let enteredName = textField?.stringValue ?? ""
6163
DispatchQueue.main.async { [weak fileItem, weak self] in
6264
guard let fileItem, let self = self else { return }
63-
self.handlePhantomFileCompletion(fileItem: fileItem, wasCancelled: false)
65+
self.handlePhantomFileCompletion(fileItem: fileItem, wasCancelled: false, enteredName: enteredName)
6466
}
6567
} else {
6668
textField?.backgroundColor = fileItem.validateFileName(for: textField?.stringValue ?? "") ? .none : errorRed
@@ -76,7 +78,7 @@ final class ProjectNavigatorTableViewCell: FileSystemTableViewCell {
7678
delegate?.cellDidFinishEditing()
7779
}
7880

79-
private func handlePhantomFileCompletion(fileItem: CEWorkspaceFile, wasCancelled: Bool) {
81+
private func handlePhantomFileCompletion(fileItem: CEWorkspaceFile, wasCancelled: Bool, enteredName: String = "") {
8082
if wasCancelled {
8183
if let workspace = delegate as? ProjectNavigatorViewController,
8284
let workspaceFileManager = workspace.workspace?.workspaceFileManager {
@@ -85,7 +87,7 @@ final class ProjectNavigatorTableViewCell: FileSystemTableViewCell {
8587
return
8688
}
8789

88-
let newName = textField?.stringValue ?? ""
90+
let newName = enteredName.isEmpty ? (textField?.stringValue ?? "") : enteredName
8991
if !newName.isEmpty && newName.isValidFilename {
9092
if let workspace = delegate as? ProjectNavigatorViewController,
9193
let workspaceFileManager = workspace.workspace?.workspaceFileManager,

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ extension ProjectNavigatorViewController: OutlineTableViewCellDelegate {
4141
}
4242

4343
func cellDidFinishEditing() {
44-
guard shouldReloadAfterDoneEditing else { return }
4544
outlineView.reloadData()
4645
}
4746
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ final class ProjectNavigatorViewController: NSViewController {
6464
/// to open the file a second time.
6565
var shouldSendSelectionUpdate: Bool = true
6666

67-
var shouldReloadAfterDoneEditing: Bool = false
68-
6967
var filterIsEmpty: Bool {
7068
workspace?.navigatorFilter.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true
7169
}

0 commit comments

Comments
 (0)