feat(core): the file explorer, text editor and image viewer's file operations after Java, measured against Java
FileCases does what the windows of FILIUS' file explorer and text editor do to a host's files: new folder, delete, copy, cut and paste, rename, import, save and save as. The core's filePrograms.ts does the same on the node's file system; the file system renames an entry in its place, as Java's tree does. Departures from Java: a folder name that comes to no name makes nothing, a paste onto a name there already is refused, a rename to a name with a slash or blanks at its ends is refused and one of the case only is done, save as and import onto a folder's name are refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -343,6 +343,32 @@ export class VirtualFileSystem {
|
||||
return this.existingPath(destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Java's rename (Datei.setName, DefaultMutableTreeNode.setUserObject): the
|
||||
* entry keeps its place among its folder's entries, also when only its
|
||||
* case changes; another entry of the folder may not have the name yet.
|
||||
* Returns the new path.
|
||||
*/
|
||||
renameInPlace(rawPath: string, newName: string): string {
|
||||
if (newName.includes('/') || newName.includes('\\')) fail('invalidPathComponent', newName);
|
||||
const sourcePath = this.existingPath(rawPath);
|
||||
if (sourcePath === '/') fail('cannotMutateRoot');
|
||||
const destination = normalizedAbsolutePath(join(parentPath(sourcePath), newName));
|
||||
if (entryName(destination) !== newName) fail('invalidPathComponent', newName);
|
||||
const taken = this.existingPathIfPresent(destination);
|
||||
if (taken !== undefined && !swiftEqual(taken, sourcePath)) fail('itemAlreadyExists', destination);
|
||||
this.transaction((candidate) => {
|
||||
const store: Store = new Map();
|
||||
for (const [key, entry] of candidate.store) {
|
||||
const inside = entry.path === sourcePath || entry.path.startsWith(`${sourcePath}/`);
|
||||
const path = inside ? destination + entry.path.slice(sourcePath.length) : entry.path;
|
||||
store.set(inside ? keyOf(path) : key, { path, content: entry.content });
|
||||
}
|
||||
candidate.store = store;
|
||||
});
|
||||
return destination;
|
||||
}
|
||||
|
||||
deleteItem(rawPath: string, recursive = false): void {
|
||||
const path = this.existingPath(rawPath);
|
||||
if (path === '/') fail('cannotMutateRoot');
|
||||
|
||||
Reference in New Issue
Block a user