From e04d28d8c76e97ea2700b1624b7b004e70af52d5 Mon Sep 17 00:00:00 2001 From: Timo Date: Tue, 7 Jan 2025 02:52:40 +0100 Subject: [PATCH] Dummy REPL added as target option (#291) --- README.md | 58 ++++++++++++++++++ packages/repl/lib/index.ts | 2 + packages/repl/lib/repl/dummy.ts | 81 ++++++++++++++++++++++++++ packages/web/src/components/editor.tsx | 4 +- packages/web/src/settings.json | 9 ++- 5 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 packages/repl/lib/repl/dummy.ts diff --git a/README.md b/README.md index f651456e..13e80772 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,40 @@ Web-based P2P collaborative editor for live coding music and graphics ## Usage +### Keybindings + +*Some keybindings may differ depending on the language/target you choose, and the operating system* + +| Keybinding | Function | +| ------------------------- | ------------------------------------ | +| `alt/option` `enter` | Evaluate all | +| `ctrl/cmd` `enter` | Evaluate block, Evaluate selection | +| `shift` `enter` | Evaluate line | +| `ctrl/cmd/option/alt` `.` | Silence (output depends on language) | +| `cmd/ctrl` `shift` `h` | Show/Hide editor panels | +| `cmd/ctrl` `x` | Cut selected text | +| `cmd/ctrl` `c` | Copy selected text | +| `cmd/ctrl` `v` | Paste cut/copied text | +| `cmd/ctrl` `z/u` | Undo edit | +| `cmd/ctrl` `shift` `z/u` | Redo edit | +| `cmd/ctrl` `}` | add indentation | +| `cmd/ctrl` `{` | remove indentation | +| `cmd/ctrl` `f` | search and replace | + +*On Mac:* + +| `ctrl` `e` | jump to end of the line | +| `ctrl` `a` | jump to the beginning of the line | +| `ctrl` `t` | move character one step right | +| `ctrl` `y` | delete selected text | +| `ctrl` `o` | insert linebreak | +| `ctrl` `d` | delete character on the right of cursor | +| `ctrl` `h` | backspace character on the left of cursor | +| `ctrl` `l` | select whole line after cursor | +| `ctrl` `v` | jump to bottom end | +| `ctrl` `b` | move cursor to the left | +| `ctrl` `n` | move cursor down | + ### Public server **WARNING - Please Read**: Using a public server can be dangerous as _anyone_ @@ -138,6 +172,20 @@ connect to your local server, because of their own network configuration. ### Supported REPL targets +#### Dummy + +The "dummy" target is a REPL target that forwards messages to an OSC server. It +does not have any syntax highlighting and can be used for any purpose you like. +This is useful if you want to use a language that is not yet supported in Flok, +and can receive OSC messages. + +Use `flok-repl` with the `-t dummy` parameter. + +By default, it will send OSC messages to port 3001. Code evaluations are sent as +a string (including all line breaks, whitespaces, etc.) to the OSC address +`/flok`. If you use the `panic` shortcut key, you will receive the OSC message +`/flok silence`, which you can use to stop all your audio/visual processes. + #### TidalCycles Use `flok-repl` with the `-t tidal` parameter. @@ -319,6 +367,16 @@ To run production build: npm start ``` +To run the repl while developing go to: + +```sh +cd packages/repl/ +``` + +```sh +npm exec -- flok-repl -H ws://localhost:3000 -s -t -T user: +``` + ### Packages overview This repository is a monorepo, with multiple modular packages. Each package diff --git a/packages/repl/lib/index.ts b/packages/repl/lib/index.ts index d70c41ab..26da2fe9 100644 --- a/packages/repl/lib/index.ts +++ b/packages/repl/lib/index.ts @@ -10,6 +10,7 @@ import FoxDotREPL from "./repl/foxdot.js"; import RenardoREPL from "./repl/renardo.js"; import MercuryREPL from "./repl/mercury.js"; import SardineREPL from "./repl/sardine.js"; +import DummyREPL from "./repl/dummy.js"; import path from "path"; import fs from "fs"; @@ -23,6 +24,7 @@ const replClasses = { renardo: RenardoREPL, mercury: MercuryREPL, sardine: SardineREPL, + dummy: DummyREPL }; function createREPLFor(repl: string, ctx: CommandREPLContext) { diff --git a/packages/repl/lib/repl/dummy.ts b/packages/repl/lib/repl/dummy.ts new file mode 100644 index 00000000..d0849858 --- /dev/null +++ b/packages/repl/lib/repl/dummy.ts @@ -0,0 +1,81 @@ +import { BaseREPL, BaseREPLContext } from "../repl.js"; +import osc from "osc"; +import debugModule from "debug"; + +const debug = debugModule("flok:repl:dummy"); + +const { UDPPort } = osc; + +// A dummy/free/open REPL +// The repl doesn't have any specific language, it just forwards the +// text to an assigned OSC port 3001 +// The address used is /flok + +// $ flok-repl -t free +// +// Sends the code over OSC to port 3001 on localhost +// Port can be assigned by choice +// +class DummyREPL extends BaseREPL { + udpPort: typeof UDPPort; + port: number; + started: boolean; + portReady: boolean; + + constructor(ctx: BaseREPLContext) { + super(ctx); + + this.port = 3001; + this.started = false; + this.portReady = false; + } + + start() { + super.start(); + + this.udpPort = new UDPPort({ + metadata: true, + }); + + // Listen for incoming OSC messages. + this.udpPort.on("message", function (oscMsg, timeTag, info) { + debug("An OSC message just arrived!", oscMsg); + debug("Remote info is: ", info); + }); + + // Open the socket. + this.udpPort.open(); + + // When the port is read, send an OSC message + const that = this; + this.udpPort.on("ready", function () { + that.portReady = true; + }); + + this.started = true; + } + + write(body: string) { + if (!this.portReady) { + debug("UDP Port is not ready yet."); + return; + } + + const newBody = this.prepare(body); + const obj = { + address: "/flok", + args: [ + { + type: "s", + value: newBody, + }, + ], + }; + this.udpPort.send(obj, "127.0.0.1", this.port); + + const lines = newBody.split("\n"); + this.emitter.emit("data", { type: "stdin", lines }); + } +} + +export default DummyREPL; \ No newline at end of file diff --git a/packages/web/src/components/editor.tsx b/packages/web/src/components/editor.tsx index 4d455c8c..425221b3 100644 --- a/packages/web/src/components/editor.tsx +++ b/packages/web/src/components/editor.tsx @@ -137,7 +137,7 @@ export const Editor = ({ document, settings, ref, ...props }: EditorProps) => { const readOnly = !!query.get("readOnly"); const language: string = langByTarget[document.target] || defaultLanguage; - const languageExtension = langExtensionsByLanguage[language] || javascript; + const languageExtension = langExtensionsByLanguage[language] || null; const extensions = [ EditorView.theme({ "&": { @@ -175,7 +175,7 @@ export const Editor = ({ document, settings, ref, ...props }: EditorProps) => { }, }), flokSetup(document, { readOnly }), - languageExtension(), + languageExtension ? languageExtension() : [], highlightExtension, readOnly ? EditorState.readOnly.of(true) : [], lineNumbers ? lineNumbersExtension() : [], diff --git a/packages/web/src/settings.json b/packages/web/src/settings.json index fa5d1fc9..1ce4428b 100644 --- a/packages/web/src/settings.json +++ b/packages/web/src/settings.json @@ -9,7 +9,8 @@ "sardine", "sclang", "strudel", - "tidal" + "tidal", + "dummy" ], "defaultTarget": "hydra", "langByTarget": { @@ -22,7 +23,8 @@ "sardine": "python", "sclang": "javascript", "strudel": "javascript", - "tidal": "tidal" + "tidal": "tidal", + "dummy": "none" }, "targetsWithDocumentEvalMode": [ "mercury-web", @@ -40,7 +42,8 @@ "mercury-web": "silence", "hydra": "hush()", "strudel": "silence", - "sardine": "panic()" + "sardine": "panic()", + "dummy": "silence" }, "webTargets": ["hydra", "mercury-web", "punctual", "strudel"], "repoUrl": "https://github.com/munshkr/flok",