Skip to content

Commit 5270688

Browse files
committed
fixed init file issue
1 parent f1cfa67 commit 5270688

2 files changed

Lines changed: 125 additions & 29 deletions

File tree

stencil.yaml

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,47 @@
1-
# Stencil Configuration File
2-
# ... (omitted for brevity, content is correct)
1+
# Stencil Configuration File
2+
# --------------------------
3+
# This file is used to define the UI elements for your application.
4+
# You can generate different outputs (like HTML or a desktop app) from the same config.
5+
6+
# Optional configuration for the project
7+
config:
8+
# The backend determines the output format.
9+
# Supported backends: "html", "imgui"
10+
# Default is "html".
11+
backend: "html"
12+
version: "1.0.0"
13+
author: "Your Name"
14+
15+
# The 'app' section defines the sequence of UI elements to be rendered.
16+
app:
17+
# 'title': Sets the main title of the page or window.
18+
- title: "My Awesome App"
19+
20+
# 'text': A block of text. Can be multi-line using the '|' character.
21+
- text: |
22+
Welcome to Stencil!
23+
This is a simple example of a UI defined in YAML.
24+
25+
# 'button': A clickable button.
26+
# 'label' is the text on the button.
27+
# 'callback' is the function name that will be called when clicked.
28+
# Stencil generates a placeholder for this function.
29+
- button:
30+
label: "Click Me!"
31+
callback: "onButtonClick"
32+
33+
# 'separator': A horizontal line to divide sections.
34+
- separator
35+
36+
# 'input': A text input field.
37+
# 'label' is the text displayed next to the input.
38+
# 'placeholder' is the text that appears when the input is empty.
39+
- input:
40+
label: "Your Name"
41+
placeholder: "Enter your name..."
42+
43+
- button:
44+
label: "Submit"
45+
callback: "doSomething"
46+
47+
- text: "© 2025 Your Company"

stencil/cli.py

Lines changed: 78 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,88 @@
11
import argparse
2-
from pathlib import Path
32
import json
43
import sys
54
import time
5+
from pathlib import Path
6+
67
import yaml
7-
from watchdog.observers import Observer
88
from watchdog.events import FileSystemEventHandler
9+
from watchdog.observers import Observer
910

10-
from stencil.main import run, generate_tree
11+
from stencil.main import generate_tree, run
1112

1213
CONFIG_FILES = ["stencil.yaml", "stencil.json"]
1314
DEFAULT_YAML_PATH = Path.cwd() / "stencil.yaml"
1415

15-
DEFAULT_YAML_CONTENT = """# Stencil Configuration File
16-
# ... (omitted for brevity, content is correct)
16+
17+
DEFAULT_YAML_CONTENT = """ # Stencil Configuration File
18+
# --------------------------
19+
# This file is used to define the UI elements for your application.
20+
# You can generate different outputs (like HTML or a desktop app) from the same config.
21+
22+
# Optional configuration for the project
23+
config:
24+
# The backend determines the output format.
25+
# Supported backends: "html", "imgui"
26+
# Default is "html".
27+
backend: "html"
28+
version: "1.0.0"
29+
author: "Your Name"
30+
31+
# The 'app' section defines the sequence of UI elements to be rendered.
32+
app:
33+
# 'title': Sets the main title of the page or window.
34+
- title: "My Awesome App"
35+
36+
# 'text': A block of text. Can be multi-line using the '|' character.
37+
- text: |
38+
Welcome to Stencil!
39+
This is a simple example of a UI defined in YAML.
40+
41+
# 'button': A clickable button.
42+
# 'label' is the text on the button.
43+
# 'callback' is the function name that will be called when clicked.
44+
# Stencil generates a placeholder for this function.
45+
- button:
46+
label: "Click Me!"
47+
callback: "onButtonClick"
48+
49+
# 'separator': A horizontal line to divide sections.
50+
- separator
51+
52+
# 'input': A text input field.
53+
# 'label' is the text displayed next to the input.
54+
# 'placeholder' is the text that appears when the input is empty.
55+
- input:
56+
label: "Your Name"
57+
placeholder: "Enter your name..."
58+
59+
- button:
60+
label: "Submit"
61+
callback: "doSomething"
62+
63+
- text: "© 2025 Your Company"
1764
"""
1865

66+
1967
def find_config():
2068
root = Path.cwd()
2169
for f in CONFIG_FILES:
2270
if (root / f).exists():
2371
return root / f
2472
return None
2573

74+
2675
def handle_init():
2776
if DEFAULT_YAML_PATH.exists():
2877
print(f"'{DEFAULT_YAML_PATH.name}' already exists in this directory.")
2978
return 0
30-
79+
3180
with open(DEFAULT_YAML_PATH, "w") as f:
3281
f.write(DEFAULT_YAML_CONTENT)
3382
print(f"Successfully created a default '{DEFAULT_YAML_PATH.name}'.")
3483
return 0
3584

85+
3686
def do_generate(args):
3787
config_path = find_config()
3888
if not config_path:
@@ -46,15 +96,16 @@ def do_generate(args):
4696
config_data = yaml.safe_load(f)
4797
else:
4898
config_data = json.load(f)
49-
99+
50100
tree = generate_tree(config_data)
51101
run(tree, config_data, args)
52102
except (ValueError, TypeError) as e:
53103
print(f"Error processing config file '{config_path.name}': {e}", file=sys.stderr)
54104
return 1
55-
105+
56106
return 0
57107

108+
58109
class ConfigChangeHandler(FileSystemEventHandler):
59110
def __init__(self, args):
60111
self.args = args
@@ -70,46 +121,45 @@ def on_modified(self, event):
70121
do_generate(self.args)
71122
self.last_run = time.time()
72123

124+
73125
def main():
74-
parser = argparse.ArgumentParser(
75-
description="A tool to generate UI from a simple config file.",
76-
prog="stencil"
77-
)
126+
parser = argparse.ArgumentParser(description="A tool to generate UI from a simple config file.", prog="stencil")
78127
subparsers = parser.add_subparsers(dest="command", help="Available commands")
79128

80129
subparsers.add_parser("init", help="Create a default stencil.yaml file.")
81130
gen_parser = subparsers.add_parser("generate", help="Generate UI from config file (default action).")
82131
gen_parser.add_argument("-w", "--watch", action="store_true", help="Watch config and regenerate automatically")
83-
gen_parser.add_argument("-b", "--backend", type=str, default=None, help="The backend to use (html, imgui), overrides config file")
132+
gen_parser.add_argument(
133+
"-b", "--backend", type=str, default=None, help="The backend to use (html, imgui), overrides config file"
134+
)
84135

85136
args, unknown = parser.parse_known_args()
86-
137+
87138
if args.command is None:
88139
if unknown:
89-
# If there are unknown args and no command, maybe the user tried 'stencil --watch'
90-
if '--watch' in unknown or '-w' in unknown:
91-
# Re-parse as if 'generate' was passed
92-
args = parser.parse_args(['generate'] + sys.argv[1:])
93-
else:
94-
parser.print_help()
95-
return 1
140+
# If there are unknown args and no command, maybe the user tried 'stencil --watch'
141+
if "--watch" in unknown or "-w" in unknown:
142+
# Re-parse as if 'generate' was passed
143+
args = parser.parse_args(["generate"] + sys.argv[1:])
144+
else:
145+
parser.print_help()
146+
return 1
96147
else:
97-
# Default to generate
98-
args = parser.parse_args(['generate'])
99-
148+
# Default to generate
149+
args = parser.parse_args(["generate"])
100150

101151
if args.command == "init":
102152
return handle_init()
103153
elif args.command == "generate":
104154
result = do_generate(args)
105155
if result != 0:
106156
return result
107-
157+
108158
if args.watch:
109159
config_path = find_config()
110160
if not config_path:
111161
return 1
112-
162+
113163
event_handler = ConfigChangeHandler(args)
114164
observer = Observer()
115165
observer.schedule(event_handler, path=config_path.parent, recursive=False)
@@ -122,11 +172,12 @@ def main():
122172
observer.stop()
123173
print("\nObserver stopped.")
124174
observer.join()
125-
175+
126176
return 0
127177
else:
128178
parser.print_help()
129179
return 1
130180

181+
131182
if __name__ == "__main__":
132183
sys.exit(main())

0 commit comments

Comments
 (0)