Skip to content

Commit 65aa1b2

Browse files
committed
fix: resolve nested path creation from parent listings
Fixes: Acode-Foundation#1745
1 parent d79a906 commit 65aa1b2

File tree

2 files changed

+85
-83
lines changed

2 files changed

+85
-83
lines changed

src/lib/openFolder.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ function execOperation(type, action, url, $target, name) {
664664
newName = helpers.fixFilename(newName);
665665
if (!newName) return;
666666
startLoading();
667+
const isNestedPath = newName.split("/").filter(Boolean).length > 1;
667668
let newUrl;
668669

669670
if (action === "new file") {
@@ -672,6 +673,14 @@ function execOperation(type, action, url, $target, name) {
672673
newUrl = await helpers.createFileStructure(url, newName, false);
673674
}
674675
if (!newUrl) return;
676+
677+
if (isNestedPath) {
678+
openFolder.find(url)?.reload();
679+
await FileList.refresh();
680+
toast(strings.success);
681+
return;
682+
}
683+
675684
newName = Url.basename(newUrl.uri);
676685
if ($target.unclasped) {
677686
if (newUrl.type === "file") {

src/utils/helpers.js

Lines changed: 76 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -418,73 +418,28 @@ export default {
418418
const terminalBasePath = isAcodeTerminalPublicSafUri
419419
? decodeURIComponent(treeSegment.split("::")[0] || "")
420420
: "";
421-
422-
if (isExternalStorageUri) {
423-
baseFolder = decodeURIComponent(currentUri.split("%3A")[1].split("/")[0]);
424-
} else if (
425-
!(isExternalStorageUri || isTermuxUri || isAcodeTerminalPublicSafUri)
426-
) {
427-
// Handle nested paths for regular file:// URIs
428-
const pathParts = pathString.split("/").filter(Boolean);
429-
let currentPath = uri;
430-
let firstCreatedPath = null;
431-
let firstCreatedType = null;
432-
433-
for (let i = 0; i < pathParts.length; i++) {
434-
const isLastPart = i === pathParts.length - 1;
435-
const partName = pathParts[i];
436-
const newPath = Url.join(currentPath, partName);
437-
438-
if (isLastPart && isFile) {
439-
// Create file if it's the last part and we're creating a file
440-
if (!(await fsOperation(newPath).exists())) {
441-
await fsOperation(currentPath).createFile(partName);
442-
if (firstCreatedPath === null) {
443-
firstCreatedPath = newPath;
444-
firstCreatedType = "file";
445-
}
446-
}
447-
} else {
448-
// Create directory for intermediate parts or when creating a folder
449-
if (!(await fsOperation(newPath).exists())) {
450-
await fsOperation(currentPath).createDirectory(partName);
451-
if (firstCreatedPath === null) {
452-
firstCreatedPath = newPath;
453-
firstCreatedType = "folder";
454-
}
455-
}
456-
}
457-
currentPath = newPath;
421+
const getTargetUri = (baseUri, name, index) => {
422+
if (
423+
!(isExternalStorageUri || isTermuxUri || isAcodeTerminalPublicSafUri)
424+
) {
425+
return Url.join(baseUri, name);
458426
}
459427

460-
return {
461-
uri: firstCreatedPath || Url.join(uri, pathParts[0]),
462-
type:
463-
firstCreatedType ||
464-
(isFile && pathParts.length === 1 ? "file" : "folder"),
465-
};
466-
}
467-
468-
for (let i = 0; i < parts.length; i++) {
469-
const isLastElement = i === parts.length - 1;
470-
const name = parts[i];
471-
let fullUri = currentUri;
472-
473-
// Adjust URI for special cases
428+
let fullUri = baseUri;
474429
if (isExternalStorageUri) {
475-
if (!isSpecialCase && i === 0) {
430+
if (!isSpecialCase && index === 0) {
476431
fullUri += `::primary:${baseFolder}/${name}`;
477432
} else {
478433
fullUri += `/${name}`;
479434
}
480435
} else if (isTermuxUri) {
481-
if (!isSpecialCase && i === 0) {
436+
if (!isSpecialCase && index === 0) {
482437
fullUri += `::/data/data/com.termux/files/home/${name}`;
483438
} else {
484439
fullUri += `/${name}`;
485440
}
486441
} else if (isAcodeTerminalPublicSafUri) {
487-
if (!isSpecialCase && i === 0) {
442+
if (!isSpecialCase && index === 0) {
488443
const sanitizedBase = terminalBasePath.endsWith("/")
489444
? `${terminalBasePath}${name}`
490445
: `${terminalBasePath}/${name}`;
@@ -493,41 +448,79 @@ export default {
493448
fullUri += `/${name}`;
494449
}
495450
}
496-
497-
if (isLastElement && isFile) {
498-
// Create file if it's the last element and isFile is true
499-
if (!(await fsOperation(fullUri).exists())) {
500-
await fsOperation(currentUri).createFile(name);
501-
} else {
502-
return;
503-
}
504-
} else {
505-
// Create directory
506-
if (!(await fsOperation(fullUri).exists())) {
507-
await fsOperation(currentUri).createDirectory(name);
508-
} else {
509-
return;
451+
return fullUri;
452+
};
453+
const getExpectedType = (isLastPart) =>
454+
isLastPart && isFile ? "file" : "folder";
455+
const ensureEntry = async (baseUri, targetUri, name, expectedType) => {
456+
const entries = await fsOperation(baseUri).lsDir();
457+
const existingEntry = entries.find((entry) => entry.name === name);
458+
459+
if (existingEntry) {
460+
const actualType =
461+
existingEntry.isDirectory || existingEntry.isFile === false
462+
? "folder"
463+
: "file";
464+
if (actualType !== expectedType) {
465+
throw new Error(
466+
`${name} already exists as a ${actualType}, expected ${expectedType}.`,
467+
);
510468
}
469+
470+
return {
471+
url: existingEntry.url || targetUri,
472+
created: false,
473+
type: expectedType,
474+
};
511475
}
512-
currentUri = fullUri;
476+
477+
const createdUrl =
478+
expectedType === "file"
479+
? await fsOperation(baseUri).createFile(name)
480+
: await fsOperation(baseUri).createDirectory(name);
481+
482+
return {
483+
url: createdUrl || targetUri,
484+
created: true,
485+
type: expectedType,
486+
};
487+
};
488+
let firstCreatedPath = null;
489+
let firstCreatedType = null;
490+
let firstTargetUri = uri;
491+
492+
if (isExternalStorageUri) {
493+
baseFolder = decodeURIComponent(currentUri.split("%3A")[1].split("/")[0]);
513494
}
514-
let tileType;
515-
if (isFile && parts.length === 1) {
516-
tileType = "file";
517-
} else {
518-
const urlParts = currentUri.split("/");
519-
const pathParts = pathString.split("/");
520-
const pathStartIndex = urlParts.findIndex(
521-
(part) => part === pathParts[0],
495+
if (parts[0]) {
496+
firstTargetUri = getTargetUri(uri, parts[0], 0);
497+
}
498+
499+
for (let i = 0; i < parts.length; i++) {
500+
const isLastElement = i === parts.length - 1;
501+
const name = parts[i];
502+
const targetUri = getTargetUri(currentUri, name, i);
503+
const expectedType = getExpectedType(isLastElement);
504+
const entry = await ensureEntry(
505+
currentUri,
506+
targetUri,
507+
name,
508+
expectedType,
522509
);
523-
if (pathStartIndex !== -1) {
524-
const pathEndIndex = pathStartIndex + pathParts.length;
525-
urlParts.splice(pathStartIndex + 1, pathEndIndex - pathStartIndex - 1);
510+
511+
if (entry.created && firstCreatedPath === null) {
512+
firstCreatedPath = entry.url;
513+
firstCreatedType = expectedType;
526514
}
527-
currentUri = urlParts.join("/");
528-
tileType = "folder";
515+
516+
currentUri = entry.url;
529517
}
530-
return { uri: currentUri, type: tileType };
518+
519+
return {
520+
uri: firstCreatedPath || firstTargetUri,
521+
type:
522+
firstCreatedType || (isFile && parts.length === 1 ? "file" : "folder"),
523+
};
531524
},
532525
formatDownloadCount(downloadCount) {
533526
const units = ["", "K", "M", "B", "T"];

0 commit comments

Comments
 (0)