Skip to content

Commit 1ee085a

Browse files
authored
Merge pull request #13 from leftibot/fix/issue-12-add-more-examples-to-playground
Fix #12: Add more examples to playground
2 parents 130f68c + a2e7b97 commit 1ee085a

2 files changed

Lines changed: 195 additions & 36 deletions

File tree

playground.html

Lines changed: 177 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,61 @@
1111
{% include common.html %}
1212

1313
<style>
14-
.playground-wrap {
14+
.playground-outer {
1515
display: flex;
1616
gap: 0;
1717
min-height: 500px;
18+
}
19+
.examples-sidebar {
20+
width: 220px;
21+
min-width: 220px;
22+
border: 1px solid #ddd;
23+
border-radius: 4px 0 0 4px;
24+
background: #f9f9f9;
25+
overflow-y: auto;
26+
}
27+
.examples-sidebar-header {
28+
background: #f5f5f5;
29+
padding: 6px 12px;
30+
font-size: 0.8rem;
31+
text-transform: uppercase;
32+
letter-spacing: 0.1em;
33+
color: #888;
34+
border-bottom: 1px solid #ddd;
35+
}
36+
.example-item {
37+
display: block;
38+
width: 100%;
39+
text-align: left;
40+
padding: 8px 12px;
41+
border: none;
42+
border-bottom: 1px solid #eee;
43+
background: transparent;
44+
cursor: pointer;
45+
font-size: 0.85rem;
46+
color: #555;
47+
transition: background 0.15s;
48+
}
49+
.example-item:hover {
50+
background: #eef;
51+
}
52+
.example-item.active {
53+
background: #d9534f;
54+
color: #fff;
55+
}
56+
.playground-main {
57+
flex: 1;
58+
display: flex;
59+
flex-direction: column;
60+
min-width: 0;
61+
}
62+
.playground-wrap {
63+
display: flex;
64+
gap: 0;
65+
flex: 1;
1866
border: 1px solid #ddd;
19-
border-radius: 4px;
67+
border-left: none;
68+
border-radius: 0 4px 4px 0;
2069
overflow: hidden;
2170
}
2271
.playground-panel {
@@ -79,6 +128,12 @@
79128
font-size: 0.75rem;
80129
color: #999;
81130
}
131+
.playground-controls label {
132+
font-size: 0.8rem;
133+
color: #666;
134+
margin-bottom: 0;
135+
cursor: pointer;
136+
}
82137
</style>
83138

84139
</head>
@@ -93,40 +148,30 @@ <h3>Interactive Playground <span id="chai-status" class="loading">Loading&hellip
93148
</div>
94149

95150
<div class="body-with-margin">
96-
<div class="playground-wrap">
97-
<div class="playground-panel">
98-
<div class="playground-panel-header">Input</div>
99-
<textarea id="chai-input" spellcheck="false">// Welcome to ChaiScript!
100-
// Write your code here and click Run (or press Ctrl+Enter).
101-
102-
def greet(name) {
103-
return "Hello, " + name + "!"
104-
}
105-
106-
print(greet("World"))
107-
print(greet("ChaiScript"))
108-
109-
// Math example
110-
def factorial(n) {
111-
if (n &lt;= 1) { return 1 }
112-
return n * factorial(n - 1)
113-
}
114-
115-
print("5! = " + to_string(factorial(5)))
116-
print("10! = " + to_string(factorial(10)))
117-
</textarea>
118-
</div>
119-
<div class="playground-divider"></div>
120-
<div class="playground-panel">
121-
<div class="playground-panel-header">Output</div>
122-
<div id="chai-output"></div>
151+
<div class="playground-outer">
152+
<div class="examples-sidebar">
153+
<div class="examples-sidebar-header">Examples</div>
123154
</div>
124-
</div>
155+
<div class="playground-main">
156+
<div class="playground-wrap">
157+
<div class="playground-panel">
158+
<div class="playground-panel-header">Input</div>
159+
<textarea id="chai-input" spellcheck="false"></textarea>
160+
</div>
161+
<div class="playground-divider"></div>
162+
<div class="playground-panel">
163+
<div class="playground-panel-header">Output</div>
164+
<div id="chai-output"></div>
165+
</div>
166+
</div>
125167

126-
<div class="playground-controls">
127-
<button id="btn-run" class="btn btn-danger" disabled>Run</button>
128-
<button id="btn-clear" class="btn btn-default">Clear</button>
129-
<span class="hint">Ctrl+Enter to run</span>
168+
<div class="playground-controls">
169+
<button id="btn-run" class="btn btn-danger" disabled>Run</button>
170+
<button id="btn-clear" class="btn btn-default">Clear</button>
171+
<label><input type="checkbox" id="chk-live" checked> Live execution</label>
172+
<span class="hint">Ctrl+Enter to run</span>
173+
</div>
174+
</div>
130175
</div>
131176
</div>
132177

@@ -136,6 +181,86 @@ <h3>Interactive Playground <span id="chai-status" class="loading">Loading&hellip
136181
var btnRun = document.getElementById('btn-run');
137182
var btnClear = document.getElementById('btn-clear');
138183
var statusEl = document.getElementById('chai-status');
184+
var chkLive = document.getElementById('chk-live');
185+
var sidebar = document.querySelector('.examples-sidebar');
186+
var debounceTimer = null;
187+
var runtimeReady = false;
188+
189+
var examples = [
190+
{
191+
name: "Hello World",
192+
code: '// Hello World\nprint("Hello, ChaiScript!")\n'
193+
},
194+
{
195+
name: "Variables &amp; Types",
196+
code: '// Variables & Types\nvar x = 42\nvar pi = 3.14159\nvar name = "ChaiScript"\nvar flag = true\n\nprint("x = " + to_string(x))\nprint("pi = " + to_string(pi))\nprint("name = " + name)\nprint("flag = " + to_string(flag))\n\n// Type inspection\nprint("type of x: " + type_name(x))\nprint("type of pi: " + type_name(pi))\nprint("type of name: " + type_name(name))\n'
197+
},
198+
{
199+
name: "Functions",
200+
code: '// Functions\ndef greet(name) {\n return "Hello, " + name + "!"\n}\n\ndef factorial(n) {\n if (n <= 1) { return 1 }\n return n * factorial(n - 1)\n}\n\ndef fibonacci(n) {\n if (n <= 1) { return n }\n return fibonacci(n - 1) + fibonacci(n - 2)\n}\n\nprint(greet("World"))\nprint("5! = " + to_string(factorial(5)))\nprint("fib(10) = " + to_string(fibonacci(10)))\n'
201+
},
202+
{
203+
name: "Conditionals",
204+
code: '// Conditionals\ndef classify(n) {\n if (n > 0) {\n return "positive"\n } else if (n < 0) {\n return "negative"\n } else {\n return "zero"\n }\n}\n\nprint(classify(5))\nprint(classify(-3))\nprint(classify(0))\n\n// Ternary-style with inline if\nvar x = 10\nvar label = if (x > 5) { "big" } else { "small" }\nprint(to_string(x) + " is " + label)\n'
205+
},
206+
{
207+
name: "Loops",
208+
code: '// For loop\nfor (var i = 0; i < 5; ++i) {\n print("i = " + to_string(i))\n}\n\n// While loop\nvar n = 1\nwhile (n <= 32) {\n print("2^" + to_string(n) + " region")\n n = n * 2\n}\n\n// Range-based for\nvar items = [10, 20, 30, 40, 50]\nfor (item : items) {\n print("item: " + to_string(item))\n}\n'
209+
},
210+
{
211+
name: "Strings",
212+
code: '// String operations\nvar s = "Hello, ChaiScript!"\nprint("Original: " + s)\nprint("Size: " + to_string(s.size()))\nprint("Find \'Chai\': " + to_string(s.find("Chai")))\n\n// String concatenation\nvar first = "Chai"\nvar second = "Script"\nprint(first + second)\n\n// Converting to string\nprint("The answer is " + to_string(42))\nprint("Pi is about " + to_string(3.14))\n'
213+
},
214+
{
215+
name: "Vectors &amp; Maps",
216+
code: '// Vectors\nvar v = [1, 2, 3, 4, 5]\nprint("Vector: " + to_string(v))\nprint("Size: " + to_string(v.size()))\nprint("First: " + to_string(v[0]))\n\nv.push_back(6)\nprint("After push_back: " + to_string(v))\n\n// Maps\nvar m = ["name": "ChaiScript", "version": "7"]\nprint("Name: " + m["name"])\nprint("Version: " + m["version"])\n\nm["author"] = "Jason Turner"\nprint("Author: " + m["author"])\n'
217+
},
218+
{
219+
name: "Lambdas",
220+
code: '// Lambda functions\nvar square = fun(x) { return x * x }\nvar add = fun(a, b) { return a + b }\n\nprint("square(5) = " + to_string(square(5)))\nprint("add(3, 4) = " + to_string(add(3, 4)))\n\n// Higher-order functions\ndef apply(f, x) {\n return f(x)\n}\n\nprint("apply(square, 7) = " + to_string(apply(square, 7)))\n\n// Lambda with capture\nvar offset = 10\nvar add_offset = fun(x) { return x + offset }\nprint("add_offset(5) = " + to_string(add_offset(5)))\n'
221+
},
222+
{
223+
name: "Classes",
224+
code: '// Classes and objects\nclass Point {\n var x\n var y\n def Point(x, y) {\n this.x = x\n this.y = y\n }\n def to_string() {\n return "(" + to_string(this.x) + ", " + to_string(this.y) + ")"\n }\n}\n\nvar p1 = Point(3, 4)\nvar p2 = Point(1, 2)\nprint("p1 = " + p1.to_string())\nprint("p2 = " + p2.to_string())\nprint("p1.x = " + to_string(p1.x))\n'
225+
},
226+
{
227+
name: "Guards",
228+
code: '// Method guards\ndef describe(x) : x > 0 {\n print(to_string(x) + " is positive")\n}\n\ndef describe(x) : x < 0 {\n print(to_string(x) + " is negative")\n}\n\ndef describe(x) : x == 0 {\n print(to_string(x) + " is zero")\n}\n\ndescribe(5)\ndescribe(-3)\ndescribe(0)\n'
229+
},
230+
{
231+
name: "Error Handling",
232+
code: '// Error handling with try/catch\ntry {\n var x = 10 / 0\n print("This may or may not print")\n} catch (e) {\n print("Caught: " + to_string(e))\n}\n\n// Throwing exceptions\ndef safe_sqrt(x) {\n if (x < 0) {\n throw("Cannot take sqrt of negative number")\n }\n // Simple Newton\'s method approximation\n var guess = x / 2.0\n for (var i = 0; i < 20; ++i) {\n guess = (guess + x / guess) / 2.0\n }\n return guess\n}\n\nprint("sqrt(25) = " + to_string(safe_sqrt(25.0)))\n\ntry {\n safe_sqrt(-1.0)\n} catch (e) {\n print("Caught: " + to_string(e))\n}\n'
233+
},
234+
{
235+
name: "Scope &amp; Variables",
236+
code: '// Variable scoping\nvar x = "global"\n\ndef show_scope() {\n var x = "local"\n print("Inside function: " + x)\n}\n\nshow_scope()\nprint("Outside function: " + x)\n\n// Global assignment\ndef modify_global() {\n // Use := for global reassignment\n x = "modified"\n}\n\nmodify_global()\nprint("After modify: " + x)\n'
237+
}
238+
];
239+
240+
function buildSidebar() {
241+
for (var i = 0; i < examples.length; ++i) {
242+
var btn = document.createElement('button');
243+
btn.className = 'example-item';
244+
btn.innerHTML = examples[i].name;
245+
btn.setAttribute('data-index', i);
246+
btn.addEventListener('click', function() {
247+
selectExample(parseInt(this.getAttribute('data-index'), 10));
248+
});
249+
sidebar.appendChild(btn);
250+
}
251+
}
252+
253+
function selectExample(index) {
254+
var items = sidebar.querySelectorAll('.example-item');
255+
for (var i = 0; i < items.length; ++i) {
256+
items[i].className = 'example-item' + (i === index ? ' active' : '');
257+
}
258+
inputEl.value = examples[index].code;
259+
outputEl.innerHTML = '';
260+
if (runtimeReady) {
261+
runCode();
262+
}
263+
}
139264

140265
function appendOutput(text, className) {
141266
var line = document.createElement('div');
@@ -156,27 +281,41 @@ <h3>Interactive Playground <span id="chai-status" class="loading">Loading&hellip
156281
statusEl.textContent = 'Ready';
157282
statusEl.className = 'ready';
158283
btnRun.disabled = false;
284+
runtimeReady = true;
285+
selectExample(0);
159286
}
160287
};
161288

162289
function runCode() {
163290
var code = inputEl.value;
164291
if (!code.trim()) { return; }
165292

166-
appendOutput('> Running...', 'chai-output-line');
293+
outputEl.innerHTML = '';
167294
try {
168295
Module.eval(code);
169296
} catch (e) {
170297
appendOutput('Error: ' + e.message, 'chai-output-error');
171298
}
172-
appendOutput('', 'chai-output-line');
299+
}
300+
301+
function scheduleLiveRun() {
302+
if (!chkLive.checked || !runtimeReady) { return; }
303+
if (debounceTimer !== null) {
304+
clearTimeout(debounceTimer);
305+
}
306+
debounceTimer = setTimeout(function() {
307+
debounceTimer = null;
308+
runCode();
309+
}, 500);
173310
}
174311

175312
btnRun.addEventListener('click', runCode);
176313
btnClear.addEventListener('click', function() {
177314
outputEl.innerHTML = '';
178315
});
179316

317+
inputEl.addEventListener('input', scheduleLiveRun);
318+
180319
inputEl.addEventListener('keydown', function(e) {
181320
if (e.ctrlKey && e.key === 'Enter') {
182321
e.preventDefault();
@@ -190,6 +329,8 @@ <h3>Interactive Playground <span id="chai-status" class="loading">Loading&hellip
190329
this.selectionStart = this.selectionEnd = start + 2;
191330
}
192331
});
332+
333+
buildSidebar();
193334
</script>
194335
<script src="/playground/chaiscript.js"></script>
195336

test_playground.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,24 @@ assert_file_contains "grammar.html" "railroad"
5656
# 6. Navigation includes grammar link
5757
assert_file_contains "_includes/header.html" "grammar"
5858

59+
# 7. Playground has examples sidebar
60+
assert_file_contains "playground.html" "examples-sidebar"
61+
assert_file_contains "playground.html" "example-item"
62+
63+
# 8. Playground has live execution with debounce
64+
assert_file_contains "playground.html" "debounceTimer"
65+
assert_file_contains "playground.html" "addEventListener.*input"
66+
67+
# 9. Playground examples cover major ChaiScript features
68+
assert_file_contains "playground.html" "Variables &amp; Types"
69+
assert_file_contains "playground.html" "Functions"
70+
assert_file_contains "playground.html" "Loops"
71+
assert_file_contains "playground.html" "Strings"
72+
assert_file_contains "playground.html" "Vectors &amp; Maps"
73+
assert_file_contains "playground.html" "Classes"
74+
assert_file_contains "playground.html" "Lambdas"
75+
assert_file_contains "playground.html" "Error Handling"
76+
5977
if [ "$FAIL" -ne 0 ]; then
6078
echo ""
6179
echo "RESULT: SOME TESTS FAILED"

0 commit comments

Comments
 (0)