diff --git a/package-lock.json b/package-lock.json index 492ffc86..972ae449 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,8 @@ "electron-window-state": "5.0.3", "font-scanner": "0.2.1", "mdn-data": "2.8.0", - "opentype.js": "1.3.4" + "opentype.js": "1.3.4", + "pyodide": "0.26.1" }, "devDependencies": { "@mdn/browser-compat-data": "5.5.40", @@ -9977,6 +9978,39 @@ "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true }, + "node_modules/pyodide": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/pyodide/-/pyodide-0.26.1.tgz", + "integrity": "sha512-P+Gm88nwZqY7uBgjbQH8CqqU6Ei/rDn7pS1t02sNZsbyLJMyE2OVXjgNuqVT3KqYWnyGREUN0DbBUCJqk8R0ew==", + "license": "Apache-2.0", + "dependencies": { + "ws": "^8.5.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/pyodide/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", diff --git a/package.json b/package.json index 1e1b871f..0f9f5f84 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,7 @@ "electron-window-state": "5.0.3", "font-scanner": "0.2.1", "mdn-data": "2.8.0", - "opentype.js": "1.3.4" + "opentype.js": "1.3.4", + "pyodide": "0.26.1" } } diff --git a/src/electron/preload.cljs b/src/electron/preload.cljs index 9d5a7632..cc7c9e17 100644 --- a/src/electron/preload.cljs +++ b/src/electron/preload.cljs @@ -7,8 +7,11 @@ ["mdn-data" :as mdn] ;; deprecating in favor of w3c/webref ["opentype.js" :as opentype] ["os" :as os] + ["pyodide" :refer [loadPyodide]] [config])) +(def pyodide (atom nil)) + (defn text->path "https://github.com/opentypejs/opentype.js#loading-a-font-synchronously-nodejs" [text {:keys [font-url x y font-size]}] @@ -21,6 +24,7 @@ :receive (fn [channel f] ;; Strip event (_) as it includes `sender` (.on ipcRenderer channel (fn [_ args] (f args)))) + :runPython #(.runPython ^js @pyodide %) :mdn mdn :webrefCss css :platform (.platform os) @@ -33,7 +37,8 @@ (defn ^:export init [] ;; https://docs.sentry.io/platforms/javascript/guides/electron/#configuring-the-client #_(.init Sentry (clj->js config/sentry-options)) - ;; Expose protected methods that allow the renderer process to use the + (.then (loadPyodide) #(reset! pyodide %)) + ;; Expose protected methods that allow the renderer process to use the ;; ipcRenderer without exposing the entire object ;; https://www.electronjs.org/docs/api/context-bridge (.exposeInMainWorld contextBridge "api" (clj->js api))) diff --git a/src/renderer/reepl/codemirror.cljs b/src/renderer/reepl/codemirror.cljs index 38e25c2f..515fcb28 100644 --- a/src/renderer/reepl/codemirror.cljs +++ b/src/renderer/reepl/codemirror.cljs @@ -8,6 +8,7 @@ ["codemirror/addon/runmode/runmode.js"] ["codemirror/mode/clojure/clojure.js"] ["codemirror/mode/javascript/javascript.js"] + ["codemirror/mode/python/python.js"] ["react" :as react] [clojure.string :as str] [reagent.core :as r])) diff --git a/src/renderer/reepl/core.cljs b/src/renderer/reepl/core.cljs index e5a7b54c..b2f1ca04 100644 --- a/src/renderer/reepl/core.cljs +++ b/src/renderer/reepl/core.cljs @@ -3,6 +3,7 @@ ["react-resizable-panels" :refer [Panel PanelResizeHandle]] [cljs.reader] [cljs.tools.reader] + [platform] [re-frame.core :as rf] [reagent.core :as ra] [renderer.components :as comp] @@ -91,7 +92,8 @@ cm-opts)] [:div.self-start.h-full.flex.items-center (repl-mode-button :cljs) - (repl-mode-button :js)] + (repl-mode-button :js) + (when platform/electron? (repl-mode-button :py))] [comp/toggle-icon-button {:active? repl-history? :active-icon "chevron-down" diff --git a/src/renderer/reepl/replumb.cljs b/src/renderer/reepl/replumb.cljs index 777b9e33..216ce4fa 100644 --- a/src/renderer/reepl/replumb.cljs +++ b/src/renderer/reepl/replumb.cljs @@ -237,10 +237,10 @@ cljs.js/*load-fn* (js-attrs proto)))))) (defn js-completion - [text] + [mode text] (let [parts (vec (.split text ".")) completing (or (last parts) "") - prefix #(str "js/" (str/join "." (conj (vec (butlast parts)) %))) + prefix #(str (when (= mode :cljs) "js/") (str/join "." (conj (vec (butlast parts)) %))) possibles (js-attrs (reduce aget js/window (butlast parts)))] (->> possibles (filter #(not= -1 (.indexOf % completing))) @@ -289,10 +289,13 @@ cljs.js/*load-fn* (filter matches? names)))))) (defn process-apropos - [text] - (if (zero? (.indexOf text "js/")) - (js-completion (.slice text 3)) - (cljs-completion text))) + [mode text] + (case mode + :js (js-completion mode text) + :cljs (if (zero? (.indexOf text "js/")) + (js-completion mode (.slice text 3)) + (cljs-completion text)) + :py [])) (defn get-forms [m] diff --git a/src/renderer/reepl/views.cljs b/src/renderer/reepl/views.cljs index 3e543dc2..b248498f 100644 --- a/src/renderer/reepl/views.cljs +++ b/src/renderer/reepl/views.cljs @@ -21,13 +21,20 @@ (defn root [] [reepl/repl - :execute #(replumb/run-repl (if (= @(rf/subscribe [:repl-mode]) :cljs) %1 (str "(js/eval \"" %1 "\")")) {:warning-as-error true} %2) - :complete-word replumb/process-apropos - :get-docs replumb/process-doc + :execute #(replumb/run-repl (case @(rf/subscribe [:repl-mode]) + :cljs %1 + :js (str "(js/eval \"" %1 "\")") + :py (str "(js/window.api.runPython \"" %1 "\")")) + {:warning-as-error true} %2) + :complete-word (fn [text] (replumb/process-apropos @(rf/subscribe [:repl-mode]) text)) + :get-docs (if (= @(rf/subscribe [:repl-mode]) :cljs) replumb/process-doc #()) :state repl-state :show-value-opts {:showers [show-devtools/show-devtools (partial show-function/show-fn-with-docs maybe-fn-docs)]} - :js-cm-opts {:mode (if (= @(rf/subscribe [:repl-mode]) :cljs) "clojure" "javascript") + :js-cm-opts {:mode (case + :cljs "clojure" + :js "javascript" + :py "python") :keyMap "default" :showCursorWhenSelecting true}])
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: