Merge branch 'main' of https://github.com/Bubobubobubobubo/Topos into logicaltime
This commit is contained in:
15
index.html
15
index.html
@ -65,7 +65,7 @@
|
||||
</svg>
|
||||
</a>
|
||||
<a title="Eval button" id="eval-button-1" class="mr-2 hover:text-gray-900 hover:bg-gray-800 px-2 py-2 rounded-lg">
|
||||
<svg class="w-8 h-8 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 20">
|
||||
<svg class="w-8 h-8 text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 20">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 1v5h-5M2 19v-5h5m10-4a8 8 0 0 1-14.947 3.97M1 10a8 8 0 0 1 14.947-3.97"/>
|
||||
</svg>
|
||||
</a>
|
||||
@ -76,7 +76,7 @@
|
||||
</svg>
|
||||
</a>
|
||||
<a title="Open Documentation" id="doc-button-1" class="mr-2 hover:text-gray-900 hover:bg-gray-800 px-2 py-2 rounded-lg">
|
||||
<svg class="w-8 h-8 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 18">
|
||||
<svg class="w-8 h-8 text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 18">
|
||||
<path d="M9 1.334C7.06.594 1.646-.84.293.653a1.158 1.158 0 0 0-.293.77v13.973c0 .193.046.383.134.55.088.167.214.306.366.403a.932.932 0 0 0 .5.147c.176 0 .348-.05.5-.147 1.059-.32 6.265.851 7.5 1.65V1.334ZM19.707.653C18.353-.84 12.94.593 11 1.333V18c1.234-.799 6.436-1.968 7.5-1.65a.931.931 0 0 0 .5.147.931.931 0 0 0 .5-.148c.152-.096.279-.235.366-.403.088-.167.134-.357.134-.55V1.423a1.158 1.158 0 0 0-.293-.77Z"/>
|
||||
</svg>
|
||||
</a>
|
||||
@ -214,8 +214,8 @@
|
||||
<!-- This is a lateral bar that will inherit the header buttons if the window is too small. -->
|
||||
<aside class="
|
||||
flex flex-col items-center w-14
|
||||
h-screen py-2 overflow-y-hidden
|
||||
border-r rtl:border-l max-h-fit
|
||||
h-screen py-2 border-r
|
||||
rtl:border-l max-h-fit
|
||||
rtl:border-r-0 bg-neutral-900
|
||||
dark:border-neutral-700 border-none"
|
||||
>
|
||||
@ -255,6 +255,7 @@
|
||||
|
||||
<!-- Other buttons -->
|
||||
|
||||
<!--
|
||||
<a title="Play button" id="play-button-2" class="pl-2 p-1.5 text-gray-700 focus:outline-nones transition-colors duration-200 rounded-lg dark:text-gray-200 hover:bg-gray-800 sm:landscape:hidden">
|
||||
<svg class="w-8 h-8 text-white block xl:hidden" fill="currentColor" viewBox="0 0 14 16">
|
||||
<path d="M0 .984v14.032a1 1 0 0 0 1.506.845l12.006-7.016a.974.974 0 0 0 0-1.69L1.506.139A1 1 0 0 0 0 .984Z"/>
|
||||
@ -273,11 +274,13 @@
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<a title="Clear button" id="clear-button-2" class="pl-2 p-1.5 text-gray-700 focus:outline-nones transition-colors duration-200 rounded-lg dark:text-gray-200 hover:bg-gray-800">
|
||||
<a title="Clear button" id="clear-button-2" class="hidden lg:block pl-2 p-1.5 text-gray-700 focus:outline-nones transition-colors duration-200 rounded-lg text-white hover:bg-gray-800">
|
||||
<svg class="w-8 h-8 text-white block xl:hidden" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 17 20">
|
||||
<path d="M7.958 19.393a7.7 7.7 0 0 1-6.715-3.439c-2.868-4.832 0-9.376.944-10.654l.091-.122a3.286 3.286 0 0 0 .765-3.288A1 1 0 0 1 4.6.8c.133.1.313.212.525.347A10.451 10.451 0 0 1 10.6 9.3c.5-1.06.772-2.213.8-3.385a1 1 0 0 1 1.592-.758c1.636 1.205 4.638 6.081 2.019 10.441a8.177 8.177 0 0 1-7.053 3.795Z"/>
|
||||
</svg>
|
||||
</a>
|
||||
-->
|
||||
|
||||
|
||||
<a title="Open settings" id="settings-button" class="lg:block sm:hidden p-2 text-gray-200 ml-1 absolute bottom-2 focus:outline-nones transition-colors duration-200 rounded-lg text-gray-200 bg-gray-800">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
@ -289,7 +292,7 @@
|
||||
|
||||
<!-- Tabs for local files -->
|
||||
<div class="min-w-screen flex grow flex-col">
|
||||
<ul id="local-script-tabs" class="text-xl flex text-sm font-medium text-center text-white dark:text-white bg-neutral-900 space-x-2 lg:space-x-8">
|
||||
<ul id="local-script-tabs" class="text-xl flex text-sm font-medium text-center text-white bg-neutral-900 space-x-2 lg:space-x-8">
|
||||
<li class="pl-5">
|
||||
<a title="Local Script 1" id="tab-1" class="bg-orange-300 inline-block px-4 py-1 text-white hover:bg-gray-800">1</a>
|
||||
</li>
|
||||
|
||||
321
src/API.ts
321
src/API.ts
@ -22,21 +22,230 @@ interface ControlChange {
|
||||
value: number;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// Array prototype extensions: easier work with lists
|
||||
// ======================================================================
|
||||
|
||||
declare global {
|
||||
interface Array<T> {
|
||||
palindrome(): T[];
|
||||
random(index: number): T;
|
||||
rand(index: number): T;
|
||||
degrade(amount: number): T;
|
||||
repeatAll(amount: number): T;
|
||||
repeatPair(amount: number): T;
|
||||
repeatOdd(amount: number): T;
|
||||
loop(index: number): T;
|
||||
div(division: number): T;
|
||||
shuffle(): this;
|
||||
rotate(steps: number): this;
|
||||
unique(): this;
|
||||
}
|
||||
}
|
||||
|
||||
Array.prototype.shuffle = function () {
|
||||
/**
|
||||
* Shuffles the array in place.
|
||||
*
|
||||
* @returns The shuffled array
|
||||
*/
|
||||
let currentIndex = this.length,
|
||||
randomIndex;
|
||||
while (currentIndex !== 0) {
|
||||
randomIndex = Math.floor(Math.random() * currentIndex);
|
||||
currentIndex--;
|
||||
[this[currentIndex], this[randomIndex]] = [
|
||||
this[randomIndex],
|
||||
this[currentIndex],
|
||||
];
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.rotate = function (steps: number) {
|
||||
/**
|
||||
* Rotates the array in place.
|
||||
*
|
||||
* @param steps - The number of steps to rotate the array by
|
||||
* @returns The rotated array
|
||||
*/
|
||||
const length = this.length;
|
||||
if (steps < 0) {
|
||||
steps = length + (steps % length);
|
||||
} else if (steps > 0) {
|
||||
steps = steps % length;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
const rotated = this.splice(-steps, steps);
|
||||
this.unshift(...rotated);
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.unique = function () {
|
||||
/**
|
||||
* Removes duplicate elements from the array in place.
|
||||
*
|
||||
* @returns The array without duplicates
|
||||
*/
|
||||
const seen = new Set();
|
||||
let writeIndex = 0;
|
||||
for (let readIndex = 0; readIndex < this.length; readIndex++) {
|
||||
const value = this[readIndex];
|
||||
if (!seen.has(value)) {
|
||||
seen.add(value);
|
||||
this[writeIndex++] = value;
|
||||
}
|
||||
}
|
||||
this.length = writeIndex;
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.degrade = function <T>(this: T[], amount: number) {
|
||||
/**
|
||||
* Removes elements from the array at random. If the array has
|
||||
* only one element left, it will not be removed.
|
||||
*
|
||||
* @param amount - The amount of elements to remove
|
||||
* @returns The degraded array
|
||||
*/
|
||||
if (amount < 0 || amount > 100) {
|
||||
throw new Error("Amount should be between 0 and 100");
|
||||
}
|
||||
if (this.length <= 1) {
|
||||
return this;
|
||||
}
|
||||
for (let i = 0; i < this.length; ) {
|
||||
const rand = Math.random() * 100;
|
||||
if (rand < amount) {
|
||||
if (this.length > 1) {
|
||||
this.splice(i, 1);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.repeatAll = function <T>(this: T[], amount: number) {
|
||||
/**
|
||||
* Repeats all elements in the array n times.
|
||||
*
|
||||
* @param amount - The amount of times to repeat the elements
|
||||
* @returns The repeated array
|
||||
*/
|
||||
if (amount < 1) {
|
||||
throw new Error("Amount should be at least 1");
|
||||
}
|
||||
let result = [];
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
for (let j = 0; j < amount; j++) {
|
||||
result.push(this[i]);
|
||||
}
|
||||
}
|
||||
this.length = 0;
|
||||
this.push(...result);
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.repeatPair = function <T>(this: T[], amount: number) {
|
||||
/**
|
||||
* Repeats all elements in the array n times, except for the
|
||||
* elements at odd indexes.
|
||||
*
|
||||
* @param amount - The amount of times to repeat the elements
|
||||
* @returns The repeated array
|
||||
*/
|
||||
if (amount < 1) {
|
||||
throw new Error("Amount should be at least 1");
|
||||
}
|
||||
|
||||
let result = [];
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
// If the index is even, repeat the element
|
||||
if (i % 2 === 0) {
|
||||
for (let j = 0; j < amount; j++) {
|
||||
result.push(this[i]);
|
||||
}
|
||||
} else {
|
||||
result.push(this[i]);
|
||||
}
|
||||
}
|
||||
|
||||
this.length = 0;
|
||||
this.push(...result);
|
||||
return this;
|
||||
};
|
||||
|
||||
Array.prototype.repeatOdd = function <T>(this: T[], amount: number) {
|
||||
/**
|
||||
* Repeats all elements in the array n times, except for the
|
||||
* elements at even indexes.
|
||||
*
|
||||
* @param amount - The amount of times to repeat the elements
|
||||
* @returns The repeated array
|
||||
*
|
||||
* @remarks
|
||||
* This function is the opposite of repeatPair.
|
||||
*/
|
||||
if (amount < 1) {
|
||||
throw new Error("Amount should be at least 1");
|
||||
}
|
||||
|
||||
let result = [];
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
// If the index is odd, repeat the element
|
||||
if (i % 2 !== 0) {
|
||||
for (let j = 0; j < amount; j++) {
|
||||
result.push(this[i]);
|
||||
}
|
||||
} else {
|
||||
result.push(this[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the original array
|
||||
this.length = 0;
|
||||
this.push(...result);
|
||||
return this;
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
Array.prototype.palindrome = function (index) {
|
||||
Array.prototype.palindrome = function <T>() {
|
||||
/**
|
||||
* Returns a palindrome of the array.
|
||||
*
|
||||
* @returns The palindrome of the array
|
||||
*/
|
||||
let left_to_right = Array.from(this);
|
||||
let right_to_left = Array.from(this.reverse());
|
||||
return left_to_right.concat(right_to_left);
|
||||
};
|
||||
// @ts-ignore
|
||||
Array.prototype.random = function (index) {
|
||||
return this[Math.floor(Math.random() * this.length)];
|
||||
};
|
||||
// @ts-ignore
|
||||
Array.prototype.loop = function (index) {
|
||||
|
||||
Array.prototype.loop = function <T>(this: T[], index: number): T {
|
||||
/**
|
||||
* Returns an element from the array based on the index.
|
||||
* The index will wrap over the array.
|
||||
*
|
||||
* @param index - The index of the element to return
|
||||
* @returns The element at the given index
|
||||
*/
|
||||
return this[index % this.length];
|
||||
};
|
||||
// @ts-ignore
|
||||
|
||||
Array.prototype.random = function () {
|
||||
/**
|
||||
* Returns a random element from the array.
|
||||
*
|
||||
* @returns A random element from the array
|
||||
*/
|
||||
return this[Math.floor(Math.random() * this.length)];
|
||||
};
|
||||
Array.prototype.rand = Array.prototype.random;
|
||||
|
||||
/**
|
||||
@ -51,19 +260,16 @@ Array.prototype.in = function <T>(this: T[], value: T): boolean {
|
||||
return this.includes(value);
|
||||
};
|
||||
|
||||
async function loadSamples() {
|
||||
// const ds = "https://raw.githubusercontent.com/felixroos/dough-samples/main/";
|
||||
export async function loadSamples() {
|
||||
return Promise.all([
|
||||
initAudioOnFirstClick(),
|
||||
samples("github:Bubobubobubobubo/Topos-Samples/main"),
|
||||
samples("github:tidalcycles/Dirt-Samples/master").then(() =>
|
||||
registerSynthSounds()
|
||||
),
|
||||
samples("github:Bubobubobubobubo/Topos-Samples/main"),
|
||||
]);
|
||||
}
|
||||
|
||||
loadSamples();
|
||||
|
||||
export const generateCacheKey = (...args: any[]): string => {
|
||||
return args.map((arg) => JSON.stringify(arg)).join(",");
|
||||
};
|
||||
@ -92,6 +298,10 @@ export class UserAPI {
|
||||
//this.load = samples("github:tidalcycles/Dirt-Samples/master");
|
||||
}
|
||||
|
||||
_all_samples = (): object => {
|
||||
return soundMap.get();
|
||||
};
|
||||
|
||||
_reportError = (error: any): void => {
|
||||
console.log(error);
|
||||
clearTimeout(this.errorTimeoutID);
|
||||
@ -236,7 +446,11 @@ export class UserAPI {
|
||||
}
|
||||
};
|
||||
|
||||
public midi = (value: number|object = 60): NoteEvent => {
|
||||
public midi = (
|
||||
value: number | object = 60,
|
||||
velocity?: number,
|
||||
channel?: number
|
||||
): NoteEvent => {
|
||||
/**
|
||||
* Sends a MIDI note to the current MIDI output.
|
||||
*
|
||||
@ -244,6 +458,24 @@ export class UserAPI {
|
||||
* @param options - an object containing options for that note
|
||||
* { channel: 0, velocity: 100, duration: 0.5 }
|
||||
*/
|
||||
|
||||
if (velocity !== undefined) {
|
||||
// Check if value is of type number
|
||||
if (typeof value === "number") {
|
||||
value = { note: value };
|
||||
}
|
||||
// @ts-ignore
|
||||
value["velocity"] = velocity;
|
||||
}
|
||||
|
||||
if (channel !== undefined) {
|
||||
if (typeof value === "number") {
|
||||
value = { note: value };
|
||||
}
|
||||
// @ts-ignore
|
||||
value["channel"] = channel;
|
||||
}
|
||||
|
||||
return new NoteEvent(value, this.app);
|
||||
};
|
||||
|
||||
@ -323,8 +555,8 @@ export class UserAPI {
|
||||
this.app.api.patternCache.set(key, player);
|
||||
}
|
||||
if ((player && player.notStarted()) || player.played) {
|
||||
player.callTime = this.epulse();
|
||||
player.played = false;
|
||||
player.callTime = this.epulse();
|
||||
player.played = false;
|
||||
}
|
||||
return player;
|
||||
};
|
||||
@ -702,6 +934,30 @@ export class UserAPI {
|
||||
// Probability functions
|
||||
// =============================================================
|
||||
|
||||
public prob = (p: number): boolean => {
|
||||
/**
|
||||
* Returns true p% of the time.
|
||||
*
|
||||
* @param p - The probability of returning true
|
||||
* @returns True p% of the time
|
||||
*/
|
||||
return this.randomGen() * 100 < p;
|
||||
};
|
||||
|
||||
public toss = (): boolean => {
|
||||
/**
|
||||
* Returns true 50% of the time.
|
||||
*
|
||||
* @returns True 50% of the time
|
||||
* @see sometimes
|
||||
* @see rarely
|
||||
* @see often
|
||||
* @see almostAlways
|
||||
* @see almostNever
|
||||
*/
|
||||
return this.randomGen() > 0.5;
|
||||
};
|
||||
|
||||
public odds = (n: number, sec: number = 15): boolean => {
|
||||
/**
|
||||
* Returns true n% of the time.
|
||||
@ -865,6 +1121,10 @@ export class UserAPI {
|
||||
return this.app.clock.pulses_since_origin;
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Time Filters
|
||||
// =============================================================
|
||||
|
||||
onbar = (n: number, ...bar: number[]): boolean => {
|
||||
// n is acting as a modulo on the bar number
|
||||
const bar_list = [...Array(n).keys()].map((i) => i + 1);
|
||||
@ -889,7 +1149,7 @@ export class UserAPI {
|
||||
let integral_part = Math.floor(b);
|
||||
let decimal_part = b - integral_part;
|
||||
final_pulses.push(
|
||||
integral_part === this.app.clock.time_position.beat &&
|
||||
integral_part === this.app.clock.time_position.beat &&
|
||||
this.app.clock.time_position.pulse ===
|
||||
decimal_part * this.app.clock.ppqn
|
||||
);
|
||||
@ -897,30 +1157,6 @@ export class UserAPI {
|
||||
return final_pulses.some((p) => p == true);
|
||||
};
|
||||
|
||||
prob = (p: number): boolean => {
|
||||
/**
|
||||
* Returns true p% of the time.
|
||||
*
|
||||
* @param p - The probability of returning true
|
||||
* @returns True p% of the time
|
||||
*/
|
||||
return this.randomGen() * 100 < p;
|
||||
};
|
||||
|
||||
toss = (): boolean => {
|
||||
/**
|
||||
* Returns true 50% of the time.
|
||||
*
|
||||
* @returns True 50% of the time
|
||||
* @see sometimes
|
||||
* @see rarely
|
||||
* @see often
|
||||
* @see almostAlways
|
||||
* @see almostNever
|
||||
*/
|
||||
return this.randomGen() > 0.5;
|
||||
};
|
||||
|
||||
public min = (...values: number[]): number => {
|
||||
/**
|
||||
* Returns the minimum value of a list of numbers.
|
||||
@ -1235,13 +1471,12 @@ export class UserAPI {
|
||||
// Trivial functions
|
||||
// =============================================================
|
||||
|
||||
sound = (sound: string|object) => {
|
||||
sound = (sound: string | object) => {
|
||||
return new SoundEvent(sound, this.app);
|
||||
};
|
||||
|
||||
snd = this.sound;
|
||||
samples = samples;
|
||||
soundMap = soundMap;
|
||||
|
||||
log = console.log;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -8,10 +8,10 @@ export class RestEvent extends Event {
|
||||
}
|
||||
|
||||
_fallbackMethod = (): Event => {
|
||||
return this;
|
||||
return RestEvent.createRestProxy(this.values["duration"], this.app);
|
||||
}
|
||||
|
||||
public static createRestProxy = (duration: number, app: Editor) => {
|
||||
public static createRestProxy = (duration: number, app: Editor): RestEvent => {
|
||||
const instance = new RestEvent(duration, app);
|
||||
return new Proxy(instance, {
|
||||
// @ts-ignore
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
export class SkipEvent {
|
||||
|
||||
_fallbackMethod = (): SkipEvent => {
|
||||
return this;
|
||||
return SkipEvent.createSkipProxy();
|
||||
}
|
||||
|
||||
public static createSkipProxy = () => {
|
||||
public static createSkipProxy = (): SkipEvent => {
|
||||
const instance = new SkipEvent();
|
||||
return new Proxy(instance, {
|
||||
// @ts-ignore
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { type Editor } from '../main';
|
||||
import { AudibleEvent } from './AbstractEvents';
|
||||
import { midiToFreq, noteFromPc } from 'zifferjs';
|
||||
import { type Editor } from "../main";
|
||||
import { AudibleEvent } from "./AbstractEvents";
|
||||
import { midiToFreq, noteFromPc } from "zifferjs";
|
||||
|
||||
import {
|
||||
superdough,
|
||||
@ -8,7 +8,6 @@ import {
|
||||
} from "superdough";
|
||||
|
||||
export class SoundEvent extends AudibleEvent {
|
||||
|
||||
constructor(sound: string | object, public app: Editor) {
|
||||
super(app);
|
||||
if (typeof sound === "string") this.values = { s: sound, dur: 0.5 };
|
||||
|
||||
80
src/main.ts
80
src/main.ts
@ -14,10 +14,10 @@ import { indentWithTab } from "@codemirror/commands";
|
||||
import { vim } from "@replit/codemirror-vim";
|
||||
import { AppSettings, Universe } from "./AppSettings";
|
||||
import { editorSetup } from "./EditorSetup";
|
||||
import { documentation } from "./Documentation";
|
||||
import { documentation_factory } from "./Documentation";
|
||||
import { EditorView } from "codemirror";
|
||||
import { Clock } from "./Clock";
|
||||
import { UserAPI } from "./API";
|
||||
import { loadSamples, UserAPI } from "./API";
|
||||
import "./style.css";
|
||||
import {
|
||||
Universes,
|
||||
@ -27,9 +27,6 @@ import {
|
||||
} from "./AppSettings";
|
||||
import { tryEvaluate } from "./Evaluator";
|
||||
|
||||
type Documentation = { [key: string]: string };
|
||||
const Docs: Documentation = documentation;
|
||||
|
||||
// Importing showdown and setting up the markdown converter
|
||||
import showdown from "showdown";
|
||||
showdown.setFlavor("github");
|
||||
@ -37,8 +34,8 @@ import showdownHighlight from "showdown-highlight";
|
||||
const classMap = {
|
||||
h1: "text-white lg:text-4xl text-xl lg:ml-4 lg:mx-4 mx-2 lg:my-4 my-2 lg:mb-8 mb-4 bg-neutral-900 rounded-lg py-2 px-2",
|
||||
h2: "text-white lg:text-3xl text-xl lg:ml-4 lg:mx-4 mx-2 lg:my-4 my-2 lg:mb-8 mb-4 bg-neutral-900 rounded-lg py-2 px-2",
|
||||
ul: "text-underline",
|
||||
li: "ml-12 list-disc lg:text-2xl text-base text-white lg:mx-4 mx-2 my-4 lg:pl-4 my-2 leading-normal",
|
||||
ul: "text-underline pl-6",
|
||||
li: "list-disc lg:text-2xl text-base text-white lg:mx-4 mx-2 my-4 my-2 leading-normal",
|
||||
p: "lg:text-2xl text-base text-white lg:mx-4 mx-2 my-4 leading-normal",
|
||||
a: "lg:text-2xl text-base text-orange-300",
|
||||
code: "lg:my-4 sm:my-1 text-base lg:text-xl block whitespace-pre overflow-x-hidden",
|
||||
@ -66,7 +63,7 @@ export class Editor {
|
||||
universes: Universes = template_universes;
|
||||
selected_universe: string;
|
||||
local_index: number = 1;
|
||||
editor_mode: "global" | "local" | "init" | "notes" = "local";
|
||||
editor_mode: "global" | "local" | "init" | "notes" = "global";
|
||||
fontSize: Compartment;
|
||||
withLineNumbers: Compartment;
|
||||
vimModeCompartment: Compartment;
|
||||
@ -78,6 +75,7 @@ export class Editor {
|
||||
userPlugins: Extension[] = [];
|
||||
state: EditorState;
|
||||
api: UserAPI;
|
||||
docs: { [key: string]: string } = {};
|
||||
|
||||
// Audio stuff
|
||||
audioContext: AudioContext;
|
||||
@ -92,19 +90,19 @@ export class Editor {
|
||||
// Transport elements
|
||||
play_buttons: HTMLButtonElement[] = [
|
||||
document.getElementById("play-button-1") as HTMLButtonElement,
|
||||
document.getElementById("play-button-2") as HTMLButtonElement,
|
||||
//document.getElementById("play-button-2") as HTMLButtonElement,
|
||||
];
|
||||
pause_buttons: HTMLButtonElement[] = [
|
||||
document.getElementById("pause-button-1") as HTMLButtonElement,
|
||||
document.getElementById("pause-button-2") as HTMLButtonElement,
|
||||
//document.getElementById("pause-button-2") as HTMLButtonElement,
|
||||
];
|
||||
stop_buttons: HTMLButtonElement[] = [
|
||||
document.getElementById("stop-button-1") as HTMLButtonElement,
|
||||
document.getElementById("stop-button-2") as HTMLButtonElement,
|
||||
//document.getElementById("stop-button-2") as HTMLButtonElement,
|
||||
];
|
||||
clear_buttons: HTMLButtonElement[] = [
|
||||
document.getElementById("clear-button-1") as HTMLButtonElement,
|
||||
document.getElementById("clear-button-2") as HTMLButtonElement,
|
||||
//document.getElementById("clear-button-2") as HTMLButtonElement,
|
||||
];
|
||||
documentation_button: HTMLButtonElement = document.getElementById(
|
||||
"doc-button-1"
|
||||
@ -235,31 +233,13 @@ export class Editor {
|
||||
];
|
||||
|
||||
let dynamicPlugins = new Compartment();
|
||||
this.state = EditorState.create({
|
||||
extensions: [
|
||||
...this.editorExtensions,
|
||||
EditorView.lineWrapping,
|
||||
dynamicPlugins.of(this.userPlugins),
|
||||
Prec.highest(
|
||||
keymap.of([
|
||||
{
|
||||
key: "Ctrl-Enter",
|
||||
run: () => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
])
|
||||
),
|
||||
keymap.of([indentWithTab]),
|
||||
],
|
||||
doc: this.universes[this.selected_universe].locals[this.local_index]
|
||||
.candidate,
|
||||
});
|
||||
|
||||
this.view = new EditorView({
|
||||
parent: document.getElementById("editor") as HTMLElement,
|
||||
state: this.state,
|
||||
// ================================================================================
|
||||
// Building the documentation
|
||||
loadSamples().then(() => {
|
||||
this.docs = documentation_factory(this);
|
||||
});
|
||||
// ================================================================================
|
||||
|
||||
// ================================================================================
|
||||
// Application event listeners
|
||||
@ -579,6 +559,33 @@ export class Editor {
|
||||
(globalThis as Record<string, any>)[name] = value;
|
||||
});
|
||||
|
||||
this.state = EditorState.create({
|
||||
extensions: [
|
||||
...this.editorExtensions,
|
||||
EditorView.lineWrapping,
|
||||
dynamicPlugins.of(this.userPlugins),
|
||||
Prec.highest(
|
||||
keymap.of([
|
||||
{
|
||||
key: "Ctrl-Enter",
|
||||
run: () => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
])
|
||||
),
|
||||
keymap.of([indentWithTab]),
|
||||
],
|
||||
doc: this.universes[this.selected_universe].global.candidate,
|
||||
});
|
||||
|
||||
this.view = new EditorView({
|
||||
parent: document.getElementById("editor") as HTMLElement,
|
||||
state: this.state,
|
||||
});
|
||||
|
||||
this.changeModeFromInterface("global");
|
||||
|
||||
// Loading from URL bar
|
||||
let url = new URLSearchParams(window.location.search);
|
||||
if (url !== undefined) {
|
||||
@ -660,10 +667,11 @@ export class Editor {
|
||||
const converter = new showdown.Converter({
|
||||
emoji: true,
|
||||
moreStyling: true,
|
||||
backslashEscapesHTMLTags: true,
|
||||
extensions: [showdownHighlight({ auto_detection: true }), ...bindings],
|
||||
});
|
||||
const converted_markdown = converter.makeHtml(
|
||||
Docs[this.currentDocumentationPane]
|
||||
this.docs[this.currentDocumentationPane]
|
||||
);
|
||||
function wrapCodeWithPre(inputString: string): string {
|
||||
let newString = inputString.replace(/<code>/g, "<pre><code>");
|
||||
|
||||
Reference in New Issue
Block a user