mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-15 15:48:29 +00:00
paren marking
This commit is contained in:
parent
82b75e2690
commit
e5f462814e
@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
||||
import * as Tone from 'tone';
|
||||
import CodeMirror, { markEvent } from './CodeMirror';
|
||||
import CodeMirror, { markEvent, markParens } from './CodeMirror';
|
||||
import cx from './cx';
|
||||
import { evaluate } from './evaluate';
|
||||
import logo from './logo.svg';
|
||||
@ -156,6 +156,7 @@ function App() {
|
||||
styleSelectedText: true,
|
||||
cursorBlinkRate: 0,
|
||||
}}
|
||||
onCursor={markParens}
|
||||
onChange={(_: any, __: any, value: any) => setCode(value)}
|
||||
/>
|
||||
<span className="p-4 absolute top-0 right-0 text-xs whitespace-pre text-right pointer-events-none">
|
||||
|
||||
@ -6,7 +6,7 @@ import 'codemirror/mode/pegjs/pegjs.js';
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
import 'codemirror/theme/material.css';
|
||||
|
||||
export default function CodeMirror({ value, onChange, options, editorDidMount }: any) {
|
||||
export default function CodeMirror({ value, onChange, onCursor, options, editorDidMount }: any) {
|
||||
options = options || {
|
||||
mode: 'javascript',
|
||||
theme: 'material',
|
||||
@ -14,7 +14,15 @@ export default function CodeMirror({ value, onChange, options, editorDidMount }:
|
||||
styleSelectedText: true,
|
||||
cursorBlinkRate: 500,
|
||||
};
|
||||
return <CodeMirror2 value={value} options={options} onBeforeChange={onChange} editorDidMount={editorDidMount} />;
|
||||
return (
|
||||
<CodeMirror2
|
||||
value={value}
|
||||
options={options}
|
||||
onBeforeChange={onChange}
|
||||
editorDidMount={editorDidMount}
|
||||
onCursor={(editor, data) => onCursor?.(editor, data)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const markEvent = (editor) => (time, event) => {
|
||||
@ -24,23 +32,88 @@ export const markEvent = (editor) => (time, event) => {
|
||||
}
|
||||
// mark active event
|
||||
const marks = locs.map(({ start, end }) =>
|
||||
editor
|
||||
.getDoc()
|
||||
.markText(
|
||||
{ line: start.line - 1, ch: start.column },
|
||||
{ line: end.line - 1, ch: end.column },
|
||||
{ css: 'background-color: #FFCA28; color: black' }
|
||||
)
|
||||
editor.getDoc().markText(
|
||||
{ line: start.line - 1, ch: start.column },
|
||||
{ line: end.line - 1, ch: end.column },
|
||||
//{ css: 'background-color: #FFCA28; color: black' } // background-color is now used by parent marking
|
||||
{ css: 'outline: 1px solid #FFCA28; box-sizing:border-box' }
|
||||
)
|
||||
);
|
||||
//Tone.Transport.schedule(() => { // problem: this can be cleared by scheduler...
|
||||
setTimeout(() => {
|
||||
marks.forEach((mark) => mark.clear());
|
||||
// }, '+' + event.duration * 0.5);
|
||||
}, event.duration * 0.9 * 1000);
|
||||
}, event.duration /* * 0.9 */ * 1000);
|
||||
};
|
||||
|
||||
// idea: to improve highlighting, all patterns that appear anywhere in the code could be queried seperately
|
||||
// the created events could then be used to highlight primitives as long as they are active
|
||||
// this would create a less flickery output, with no duplications
|
||||
// it would be seperated completely from the querying that happens to get the sound output
|
||||
// it would also allow highlighting primitives that don't even end up in the sounding events (just for visual purposes)
|
||||
let parenMark;
|
||||
export const markParens = (editor, data) => {
|
||||
const v = editor.getDoc().getValue();
|
||||
const marked = getCurrentParenArea(v, data);
|
||||
parenMark?.clear();
|
||||
parenMark = editor.getDoc().markText(...marked, { css: 'background-color: #00000020' }); //
|
||||
};
|
||||
|
||||
// returns { line, ch } from absolute character offset
|
||||
export function offsetToPosition(offset, code) {
|
||||
const lines = code.split('\n');
|
||||
let line = 0;
|
||||
let ch = 0;
|
||||
for (let i = 0; i < offset; i++) {
|
||||
if (ch === lines[line].length) {
|
||||
line++;
|
||||
ch = 0;
|
||||
} else {
|
||||
ch++;
|
||||
}
|
||||
}
|
||||
return { line, ch };
|
||||
}
|
||||
|
||||
// returns absolute character offset from { line, ch }
|
||||
export function positionToOffset(position, code) {
|
||||
const lines = code.split('\n');
|
||||
let offset = 0;
|
||||
for (let i = 0; i < position.line; i++) {
|
||||
offset += lines[i].length + 1;
|
||||
}
|
||||
offset += position.ch;
|
||||
return offset;
|
||||
}
|
||||
|
||||
// given code and caret position, the functions returns the indices of the parens we are in
|
||||
export function getCurrentParenArea(code, caretPosition) {
|
||||
const caret = positionToOffset(caretPosition, code);
|
||||
let open, i, begin, end;
|
||||
// walk left
|
||||
i = caret;
|
||||
open = 0;
|
||||
while (i > 0) {
|
||||
if (code[i - 1] === '(') {
|
||||
open--;
|
||||
} else if (code[i - 1] === ')') {
|
||||
open++;
|
||||
}
|
||||
if(open === -1) {
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
begin = i;
|
||||
// walk right
|
||||
i = caret;
|
||||
open = 0;
|
||||
while (i < code.length) {
|
||||
if (code[i] === '(') {
|
||||
open--;
|
||||
} else if (code[i] === ')') {
|
||||
open++;
|
||||
}
|
||||
if(open === 1) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
end = i;
|
||||
return [begin, end].map((o) => offsetToPosition(o, code));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user