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

Add some directory manipulation nodes #2519

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from __future__ import annotations

from pathlib import Path

from nodes.properties.inputs import DirectoryInput, NumberInput
from nodes.properties.outputs import DirectoryOutput

from .. import value_group


@value_group.register(
schema_id="chainner:utility:back_directory",
name="Back Directory",
description="Traverse up/back from a directory the specified number of times.",
icon="BsFolder",
inputs=[
DirectoryInput(
"Directory", must_exist=False, label_style="hidden", has_handle=True
),
NumberInput("Amount back", has_handle=True, minimum=1, precision=0, default=1),
],
outputs=[
DirectoryOutput(
"Directory",
output_type="Directory { path: navigateBackPath(Input0.path, Input1) }",
),
],
)
def back_directory_node(directory: Path, amt: int) -> Path:
result = directory
for _ in range(amt):
result = result.parent
return result
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from __future__ import annotations

from pathlib import Path

from nodes.properties.inputs import DirectoryInput
from nodes.properties.outputs import TextOutput

from .. import value_group


@value_group.register(
schema_id="chainner:utility:directory_to_text",
name="Directory to Text",
description="Converts a directory path into usable text.",
icon="BsFolder",
inputs=[
DirectoryInput(
"Directory", must_exist=False, label_style="hidden", has_handle=True
),
],
outputs=[
TextOutput(
"Directory Text",
output_type="Input0.path",
),
],
)
def directory_to_text_node(directory: Path) -> str:
return str(directory)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from __future__ import annotations

from pathlib import Path

from nodes.properties.inputs import BoolInput, DirectoryInput, TextInput
from nodes.properties.outputs import DirectoryOutput

from .. import value_group


@value_group.register(
schema_id="chainner:utility:into_directory",
name="Into Directory",
RunDevelopment marked this conversation as resolved.
Show resolved Hide resolved
description="Goes forward into a directory.",
icon="BsFolder",
inputs=[
DirectoryInput(
"Directory", must_exist=False, label_style="hidden", has_handle=True
),
TextInput("Folder", has_handle=True),
BoolInput("Create if not exists", default=True),
],
outputs=[
DirectoryOutput(
"Directory",
output_type="Directory { path: combinePath(Input0.path, Input1) }",
),
],
)
def into_directory_node(directory: Path, folder: str, create_path: bool) -> Path:
resolved = (directory / folder).resolve()
if create_path and not resolved.exists():
resolved.mkdir(parents=True)
elif not resolved.exists():
raise FileNotFoundError(f"Directory does not exist: {resolved}")
Comment on lines +32 to +35
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the directory must always exist?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Do you not think so? I don't think we should be passing in invalid directories into nodes willy nilly

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't like it.

  1. This means that the correctness of a chain now depends on the file system. If user A has folder foo but user B doesn't, it's not gonna work for user B unless they check that box. Depending on the file system is unavoidable for node like Load Image (singular), but it can be avoided here.
  2. This leads to errors being ignored. Nodes like Load Images don't allow non-existent directories as input for obvious reasons. So if you always just create those directories, then Load Images can't error for incorrect chains.
  3. We already allow passing non-existent directories. Save Image and the Directory node support it.
  4. Side effects. You turned this node into a side effect node.

return resolved
19 changes: 19 additions & 0 deletions src/common/types/chainner-builtin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
handleNumberLiterals,
intersect,
literal,
wrapBinary,
wrapQuaternary,
wrapScopedUnary,
wrapTernary,
Expand Down Expand Up @@ -360,3 +361,21 @@ export const parseColorJson = wrapScopedUnary(
return createInstance(colorDesc);
}
);

export const combinePath = wrapBinary(
(dir: StringPrimitive, next: StringPrimitive): Arg<StringPrimitive> => {
if (dir.type === 'literal' && next.type === 'literal') {
return literal(path.join(dir.value, next.value));
}
return StringType.instance;
}
);

export const navigateBackPath = wrapBinary(
(dir: StringPrimitive, backNum: NumberPrimitive): Arg<StringPrimitive> => {
if (dir.type === 'literal' && backNum.type === 'literal') {
return literal(path.join(dir.value, '../'.repeat(backNum.value)));
}
return StringType.instance;
}
);
6 changes: 6 additions & 0 deletions src/common/types/chainner-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
} from '@chainner/navi';
import { lazy } from '../util';
import {
combinePath,
formatTextPattern,
navigateBackPath,
padCenter,
padEnd,
padStart,
Expand Down Expand Up @@ -127,6 +129,8 @@ intrinsic def padEnd(text: string, width: uint, padding: string): string;
intrinsic def padCenter(text: string, width: uint, padding: string): string;
intrinsic def splitFilePath(path: string): SplitFilePath;
intrinsic def parseColorJson(json: string): Color;
intrinsic def combinePath(path: string, next: string): string;
intrinsic def navigateBackPath(path: string, amount: uint): string;
`;

export const getChainnerScope = lazy((): Scope => {
Expand All @@ -140,6 +144,8 @@ export const getChainnerScope = lazy((): Scope => {
padCenter: makeScoped(padCenter),
splitFilePath,
parseColorJson,
combinePath: makeScoped(combinePath),
navigateBackPath: makeScoped(navigateBackPath),
};

const definitions = parseDefinitions(new SourceDocument(code, 'chainner-internal'));
Expand Down
Loading