Adding a new MarkDown note buffer for each universe

This commit is contained in:
2023-08-03 18:38:48 +02:00
parent bd76893282
commit 4c239c12f1
8 changed files with 135 additions and 162 deletions

View File

@ -4,8 +4,6 @@ import { tryEvaluate } from "./Evaluator";
import { MidiConnection } from "./IO/MidiConnection";
// @ts-ignore
import { webaudioOutput, samples } from '@strudel.cycles/webaudio';
// @ts-ignore
import { ZZFX, zzfx } from "zzfx";
interface TimePoint {
bar: number,
@ -426,9 +424,6 @@ export class UserAPI {
// Trivial functions
// =============================================================
// Small ZZFX interface for playing with this synth
zzfx = (...thing: number[]) => zzfx(...thing);
sound = async (values: object) => {
webaudioOutput(sound(values), 0.00)
}

View File

@ -6,12 +6,13 @@ export interface Universe {
global: File
locals: { [key: number]: File }
init: File
notes: File
}
export interface File {
candidate: string
committed: string
evaluations: number
committed?: string
evaluations?: number
}
export interface Settings {
@ -36,7 +37,8 @@ export const template_universe = {
8: { candidate: "", committed: "", evaluations: 0},
9: { candidate: "", committed: "", evaluations: 0},
},
init: { candidate: "", committed: "", evaluations: 0 }
init: { candidate: "", committed: "", evaluations: 0 },
notes: { candidate: "" },
}
export const template_universes = {
@ -53,7 +55,8 @@ export const template_universes = {
8: { candidate: "", committed: "", evaluations: 0},
9: { candidate: "", committed: "", evaluations: 0},
},
init: { candidate: "", committed: "", evaluations: 0 }
init: { candidate: "", committed: "", evaluations: 0 },
notes: { candidate: "// NOTES" },
},
"Help": tutorial_universe,
}

View File

@ -1,114 +0,0 @@
import { Decoration, DecorationSet } from "@codemirror/view"
import { StateField, StateEffect, ChangeDesc } from "@codemirror/state"
import { EditorView } from "@codemirror/view"
import { invertedEffects } from "@codemirror/commands"
import { Extension } from "@codemirror/state"
function mapRange(range: {from: number, to: number}, change: ChangeDesc) {
let from = change.mapPos(range.from), to = change.mapPos(range.to)
return from < to ? {from, to} : undefined
}
const addHighlight = StateEffect.define<{from: number, to: number}>({
map: mapRange
})
const removeHighlight = StateEffect.define<{from: number, to: number}>({
map: mapRange
})
const highlight = Decoration.mark({
attributes: {style: `background-color: #ffad42`}
})
const highlightedRanges = StateField.define({
create() {
return Decoration.none
},
update(ranges, tr) {
ranges = ranges.map(tr.changes)
for (let e of tr.effects) {
if (e.is(addHighlight))
ranges = addRange(ranges, e.value)
else if (e.is(removeHighlight))
ranges = cutRange(ranges, e.value)
}
return ranges
},
provide: field => EditorView.decorations.from(field)
})
function cutRange(ranges: DecorationSet, r: {from: number, to: number}) {
let leftover: any[] = []
ranges.between(r.from, r.to, (from, to, deco) => {
if (from < r.from) leftover.push(deco.range(from, r.from))
if (to > r.to) leftover.push(deco.range(r.to, to))
})
return ranges.update({
filterFrom: r.from,
filterTo: r.to,
filter: () => false,
add: leftover
})
}
function addRange(ranges: DecorationSet, r: {from: number, to: number}) {
ranges.between(r.from, r.to, (from, to) => {
if (from < r.from) r = {from, to: r.to}
if (to > r.to) r = {from: r.from, to}
})
return ranges.update({
filterFrom: r.from,
filterTo: r.to,
filter: () => false,
add: [highlight.range(r.from, r.to)]
})
}
const invertHighlight = invertedEffects.of(tr => {
let found = []
for (let e of tr.effects) {
if (e.is(addHighlight)) found.push(removeHighlight.of(e.value))
else if (e.is(removeHighlight)) found.push(addHighlight.of(e.value))
}
let ranges = tr.startState.field(highlightedRanges)
tr.changes.iterChangedRanges((chFrom, chTo) => {
ranges.between(chFrom, chTo, (rFrom, rTo) => {
if (rFrom >= chFrom || rTo <= chTo) {
let from = Math.max(chFrom, rFrom), to = Math.min(chTo, rTo)
if (from < to) found.push(addHighlight.of({from, to}))
}
})
})
return found
})
export function highlightSelection(view: EditorView) {
view.dispatch({
effects: view.state.selection.ranges.filter(r => !r.empty)
.map(r => addHighlight.of(r))
})
return true
}
export function unhighlightSelection(view: EditorView) {
let highlighted = view.state.field(highlightedRanges)
let effects: any[] = []
for (let sel of view.state.selection.ranges) {
highlighted.between(sel.from, sel.to, (rFrom, rTo) => {
let from = Math.max(sel.from, rFrom), to = Math.min(sel.to, rTo)
if (from < to) effects.push(removeHighlight.of({from, to}))
})
}
view.dispatch({effects})
return true
}
export function rangeHighlighting(): Extension {
return [
highlightedRanges,
invertHighlight,
]
}

View File

@ -3,15 +3,11 @@ import { EditorView } from "codemirror";
import { editorSetup } from "./EditorSetup";
import { EditorState, Compartment } from "@codemirror/state";
import { javascript } from "@codemirror/lang-javascript";
import { markdown } from "@codemirror/lang-markdown";
import { Clock } from "./Clock";
import { vim } from "@replit/codemirror-vim";
import { AppSettings } from "./AppSettings";
import { ViewUpdate } from "@codemirror/view";
import {
highlightSelection,
unhighlightSelection,
rangeHighlighting,
} from "./highlightSelection";
import { UserAPI } from "./API";
import { Extension } from "@codemirror/state";
import {
@ -29,9 +25,10 @@ export class Editor {
universes: Universes = template_universes;
selected_universe: string;
local_index: number = 1;
editor_mode: "global" | "local" | "init" = "local";
editor_mode: "global" | "local" | "init" | "notes" = "local";
fontSize: Compartment;
vimModeCompartment : Compartment;
chosenLanguage: Compartment
settings = new AppSettings();
editorExtensions: Extension[] = [];
@ -77,6 +74,9 @@ export class Editor {
init_button: HTMLButtonElement = document.getElementById(
"init-button"
) as HTMLButtonElement;
note_button: HTMLButtonElement = document.getElementById(
"note-button"
) as HTMLButtonElement;
settings_button: HTMLButtonElement = document.getElementById(
"settings-button"
) as HTMLButtonElement;
@ -136,6 +136,7 @@ export class Editor {
this.fontSize = new Compartment();
this.vimModeCompartment = new Compartment();
this.chosenLanguage = new Compartment();
const vimPlugin = this.settings.vimMode ? vim() : [];
const fontSizeModif = EditorView.theme( {
"&": {
@ -151,8 +152,7 @@ export class Editor {
this.vimModeCompartment.of(vimPlugin),
editorSetup,
oneDark,
rangeHighlighting(),
javascript(),
this.chosenLanguage.of(javascript()),
EditorView.updateListener.of((v: ViewUpdate) => {
v;
// This is the event listener for the editor
@ -221,7 +221,6 @@ export class Editor {
// Ctrl + Enter or Return: Evaluate the hovered code block
if ((event.key === "Enter" || event.key === "Return") && event.ctrlKey) {
event.preventDefault();
// const code = this.getCodeBlock();
this.currentFile().candidate = this.view.state.doc.toString();
this.flashBackground('#2d313d', 200)
}
@ -234,7 +233,6 @@ export class Editor {
event.preventDefault(); // Prevents the addition of a new line
this.currentFile().candidate = this.view.state.doc.toString();
this.flashBackground('#2d313d', 200)
// const code = this.getSelectedLines();
}
// This is the modal to switch between universes
@ -253,6 +251,12 @@ export class Editor {
this.view.focus();
}
if (event.ctrlKey && event.key === "n") {
event.preventDefault();
this.changeModeFromInterface("notes");
this.view.focus();
}
if (event.ctrlKey && event.key === "g") {
event.preventDefault();
this.changeModeFromInterface("global");
@ -346,6 +350,10 @@ export class Editor {
this.init_button.addEventListener("click", () =>
this.changeModeFromInterface("init")
);
this.note_button.addEventListener("click", () =>
this.changeModeFromInterface("notes")
);
this.settings_button.addEventListener("click", () => {
this.font_size_slider.value = this.settings.font_size.toString();
@ -391,7 +399,6 @@ export class Editor {
})
this.buffer_search.addEventListener("keydown", (event) => {
// this.changeModeFromInterface("local");
if (event.key === "Enter") {
let query = this.buffer_search.value;
if (query.length > 2 && query.length < 20) {
@ -406,6 +413,10 @@ export class Editor {
tryEvaluate(this, this.universes[this.selected_universe.toString()].init)
}
get note_buffer() {
return this.universes[this.selected_universe.toString()].notes;
}
get global_buffer() {
return this.universes[this.selected_universe.toString()].global;
}
@ -431,12 +442,11 @@ export class Editor {
this.updateEditorView();
}
changeModeFromInterface(mode: "global" | "local" | "init") {
changeModeFromInterface(mode: "global" | "local" | "init" | "notes") {
const interface_buttons: HTMLElement[] = [
this.local_button,
this.global_button,
this.init_button
this.local_button, this.global_button,
this.init_button, this.note_button,
];
let changeColor = (button: HTMLElement) => {
@ -467,15 +477,32 @@ export class Editor {
if (!this.local_script_tabs.classList.contains("hidden")) {
this.local_script_tabs.classList.add("hidden");
}
this.editor_mode = "global"; changeColor(this.global_button);
this.editor_mode = "global"
changeColor(this.global_button);
break;
case "init":
if (!this.local_script_tabs.classList.contains("hidden")) {
this.local_script_tabs.classList.add("hidden");
}
this.editor_mode = "init"; changeColor(this.init_button);
this.editor_mode = "init"
changeColor(this.init_button);
break;
case "notes":
if (!this.local_script_tabs.classList.contains("hidden")) {
this.local_script_tabs.classList.add("hidden");
}
this.editor_mode = "notes"
changeColor(this.note_button);
break;
}
// If the editor is in notes mode, we need to update the selectedLanguage
this.view.dispatch({
effects: this.chosenLanguage.reconfigure(this.editor_mode == "notes" ? markdown() : javascript())
})
console.log(this.chosenLanguage.get(this.view.state))
this.updateEditorView();
}
@ -555,6 +582,8 @@ export class Editor {
return this.local_buffer;
case "init":
return this.init_buffer;
case "notes":
return this.note_buffer;
}
}
@ -601,15 +630,7 @@ export class Editor {
) {
endLine = state.doc.line(endLine.number + 1);
}
// this.view.dispatch({selection: {anchor: 0 + startLine.from, head: endLine.to}});
highlightSelection(this.view);
setTimeout(() => {
unhighlightSelection(this.view);
this.view.dispatch({ selection: { anchor: cursor, head: cursor } });
}, 200);
let result_string = state.doc.sliceString(startLine.from, endLine.to);
result_string = result_string
.split("\n")
@ -639,13 +660,6 @@ export class Editor {
});
// Release the selection and get the cursor back to its original position
// Blink the text!
highlightSelection(this.view);
setTimeout(() => {
unhighlightSelection(this.view);
this.view.dispatch({ selection: { anchor: from, head: from } });
}, 200);
return state.doc.sliceString(fromLine.from, toLine.to);
};

View File

@ -19,6 +19,8 @@ const init_buffer=`
// loaded!
`
const note_buffer='// Notes buffer: a buffer to write your notes.'
export const tutorial_universe = {
global: { candidate: global_text, committed: global_text, evaluations: 0 },
locals: {
@ -32,5 +34,6 @@ export const tutorial_universe = {
8: { candidate: local_buffer, committed: local_buffer, evaluations: 0 },
9: { candidate: local_buffer, committed: local_buffer, evaluations: 0 },
},
init: { candidate: init_buffer, committed: init_buffer, evaluations: 0 }
init: { candidate: init_buffer, committed: init_buffer, evaluations: 0 },
notes: { candidate: note_buffer },
}