From 309ffb794bac945e0eee7e6d85c3c419720c3839 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Wed, 18 Oct 2023 00:51:08 +0300
Subject: [PATCH 1/4] feat(SDK): apply config (app & editor configs) from SDK
 `setConfig`

---
 src/livecodes/core.ts | 46 +++++++++++++++++++++++++++++++------------
 1 file changed, 33 insertions(+), 13 deletions(-)

diff --git a/src/livecodes/core.ts b/src/livecodes/core.ts
index 1a8822102..1aaa723ab 100644
--- a/src/livecodes/core.ts
+++ b/src/livecodes/core.ts
@@ -1167,17 +1167,38 @@ const loadConfig = async (
   // load config
   await bootstrap(true);
 
-  updateUI(config);
+  await applyConfig(config);
 
   changingContent = false;
 };
 
-const updateUI = (config: Config) => {
-  window.deps.showMode(config.mode);
-  configureToolsPane(config.tools, config.mode);
-  if (config.autotest) {
+const applyConfig = async (newConfig: Partial<Config>) => {
+  if (!isEmbed) {
+    loadSettings(getConfig());
+  }
+  if (newConfig.mode) {
+    window.deps.showMode(newConfig.mode);
+  }
+  if (newConfig.tools) {
+    configureToolsPane(newConfig.tools, newConfig.mode);
+  }
+  if (newConfig.zoom) {
+    zoom(newConfig.zoom);
+  }
+  if (newConfig.theme) {
+    setTheme(newConfig.theme);
+  }
+  if (newConfig.autotest) {
     UI.getWatchTestsButton()?.classList.remove('disabled');
   }
+  const editorConfig = {
+    ...getEditorConfig(newConfig as Config),
+    ...getFormatterConfig(newConfig as Config),
+  };
+  const hasEditorConfig = Object.values(editorConfig).some((value) => value != null);
+  if (hasEditorConfig) {
+    await reloadEditors({ ...getConfig(), ...newConfig });
+  }
 };
 
 const setUserConfig = (newConfig: Partial<UserConfig> | null, save = true) => {
@@ -4139,18 +4160,17 @@ const createApi = (): API => {
   };
 
   const apiSetConfig = async (newConfig: Partial<Config>): Promise<Config> => {
-    const newAppConfig = {
+    const newAppConfig: Config = {
       ...getConfig(),
       ...buildConfig(newConfig),
     };
-
-    // TODO: apply changes in App AppConfig, UserConfig & EditorConfig
-    if (newAppConfig.mode !== getConfig().mode) {
-      window.deps.showMode(newAppConfig.mode);
-    }
-
     setConfig(newAppConfig);
-    await loadConfig(newAppConfig);
+    await applyConfig(newConfig);
+    const content = getContentConfig(newConfig as Config);
+    const hasContent = Object.values(content).some((value) => value != null);
+    if (hasContent) {
+      await loadConfig(newAppConfig);
+    }
     return newAppConfig;
   };
 

From 5caa15832e0a055e17778a3d80d4fd223e4a8c93 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Wed, 18 Oct 2023 22:17:56 +0300
Subject: [PATCH 2/4] patch ruby `$0`  to be `__FILE__`

---
 src/livecodes/core.ts                            | 16 ++++++++--------
 .../languages/ruby-wasm/lang-ruby-wasm-script.ts |  3 ++-
 src/livecodes/languages/ruby/lang-ruby.ts        |  3 ++-
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/src/livecodes/core.ts b/src/livecodes/core.ts
index 1aaa723ab..1c55ee3e0 100644
--- a/src/livecodes/core.ts
+++ b/src/livecodes/core.ts
@@ -1166,7 +1166,6 @@ const loadConfig = async (
 
   // load config
   await bootstrap(true);
-
   await applyConfig(config);
 
   changingContent = false;
@@ -3740,29 +3739,30 @@ const configureToolsPane = (
   tools: Config['tools'] | undefined,
   mode: Config['mode'] | undefined,
 ) => {
+  if (!toolsPane) return;
   if (mode === 'result' && (!tools || tools.status === '' || tools.status === 'none')) {
-    toolsPane?.hide();
+    toolsPane.hide();
     return;
   }
   if (tools?.active) {
-    toolsPane?.setActiveTool(tools.active);
+    toolsPane.setActiveTool(tools.active);
   }
   if (!tools) {
-    toolsPane?.close();
+    toolsPane.close();
     return;
   }
   if (tools.status === 'none') {
-    toolsPane?.hide();
+    toolsPane.hide();
     return;
   }
   if (tools.status === 'full') {
-    toolsPane?.maximize();
+    toolsPane.maximize();
   }
   if (tools.status === 'open') {
-    toolsPane?.open();
+    toolsPane.open();
   }
   if (tools.status === 'closed' || tools.status === '') {
-    toolsPane?.close();
+    toolsPane.close();
   }
   // TODO: handle tools.enabled
 };
diff --git a/src/livecodes/languages/ruby-wasm/lang-ruby-wasm-script.ts b/src/livecodes/languages/ruby-wasm/lang-ruby-wasm-script.ts
index 35fdcfd1d..53da421af 100644
--- a/src/livecodes/languages/ruby-wasm/lang-ruby-wasm-script.ts
+++ b/src/livecodes/languages/ruby-wasm/lang-ruby-wasm-script.ts
@@ -34,7 +34,8 @@ livecodes.rubyWasm.run =
     await init(hasImports(code));
     const { DefaultRubyVM } = (window as any)['ruby-wasm-wasi'];
     const { vm } = await DefaultRubyVM(livecodes.rubyWasm.module);
-    vm.eval(code);
+    const patch = code.includes('$0') ? '$0 = __FILE__\\n' : '';
+    vm.eval(patch + code);
     parent.postMessage({ type: 'loading', payload: false }, '*');
   });
 
diff --git a/src/livecodes/languages/ruby/lang-ruby.ts b/src/livecodes/languages/ruby/lang-ruby.ts
index b16c879ed..a91b98d8d 100644
--- a/src/livecodes/languages/ruby/lang-ruby.ts
+++ b/src/livecodes/languages/ruby/lang-ruby.ts
@@ -30,7 +30,8 @@ export const ruby: LanguageSpecs = {
           'ruby',
           config,
         );
-        return (self as any).Opal.compile(code, options);
+        const patch = code.includes('$0') ? '$0 = __FILE__\\n' : '';
+        return (self as any).Opal.compile(patch + code, options);
       };
     },
     scripts: ({ compiled, config }) => {

From e3d71bdc5bef9a03724dc78232b5056766f3f326 Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@gmail.com>
Date: Wed, 18 Oct 2023 22:47:13 +0300
Subject: [PATCH 3/4] fix e2e

---
 e2e/specs/starter.spec.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/e2e/specs/starter.spec.ts b/e2e/specs/starter.spec.ts
index 590cd25e6..14a8996de 100644
--- a/e2e/specs/starter.spec.ts
+++ b/e2e/specs/starter.spec.ts
@@ -278,7 +278,7 @@ test.describe('Starter Templates from UI', () => {
 
     await waitForEditorFocus(app);
     await waitForResultUpdate();
-    await app.waitForTimeout(3_000);
+    await app.waitForTimeout(6_000);
 
     const titleText = await getResult().innerText('h1');
     expect(titleText).toBe('Hello, PHP!');
@@ -788,7 +788,7 @@ test.describe('Starter Templates from URL', () => {
 
     await waitForEditorFocus(app);
     await waitForResultUpdate();
-    await app.waitForTimeout(3_000);
+    await app.waitForTimeout(6_000);
 
     const titleText = await getResult().innerText('h1');
     expect(titleText).toBe('Hello, PHP!');

From 1191f770dd4ec7fd13da23042c562d56b086111b Mon Sep 17 00:00:00 2001
From: Hatem Hosny <hatemhosny@users.noreply.github.com>
Date: Thu, 19 Oct 2023 09:06:40 +0300
Subject: [PATCH 4/4] fix php-wasm starter template

---
 src/livecodes/templates/starter/php-wasm-starter.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/livecodes/templates/starter/php-wasm-starter.ts b/src/livecodes/templates/starter/php-wasm-starter.ts
index f4322e740..c262bee2b 100644
--- a/src/livecodes/templates/starter/php-wasm-starter.ts
+++ b/src/livecodes/templates/starter/php-wasm-starter.ts
@@ -29,6 +29,7 @@ body {
   script: {
     language: 'php-wasm',
     content: `
+<?php
 $title = 'PHP';
 vrzno_eval('document.getElementById("title").innerText = "' . $title . '"');