very basic code editing!
This commit is contained in:
parent
6b90d883e9
commit
1e91232bd6
@ -7,6 +7,7 @@ import { font } from "./font.ts";
|
|||||||
// import { keyDown, keyPressed, keyReleased } from "./keyboard.ts";
|
// import { keyDown, keyPressed, keyReleased } from "./keyboard.ts";
|
||||||
import { addToContext } from "./runcode.ts";
|
import { addToContext } from "./runcode.ts";
|
||||||
import { resetRepl } from "./repl.ts";
|
import { resetRepl } from "./repl.ts";
|
||||||
|
import { COLOR } from "./colors.ts";
|
||||||
|
|
||||||
// deno-fmt-ignore
|
// deno-fmt-ignore
|
||||||
const sprites = [
|
const sprites = [
|
||||||
@ -46,13 +47,13 @@ export const drawSprite = (x: number, y: number, spr: number) => {
|
|||||||
setPixelsInRect(x, y, 8, sprites[spr]);
|
setPixelsInRect(x, y, 8, sprites[spr]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const drawChar = (x: number, y: number, char: string) => {
|
export const drawChar = (x: number, y: number, char: string, color: number) => {
|
||||||
setPixelsInRect(x, y, 4, font[char]);
|
setPixelsInRect(x, y, 4, font[char].map(n => n*color));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const drawText = (x: number, y: number, text: string) => {
|
export const drawText = (x: number, y: number, text: string, color?: number) => {
|
||||||
[...text].forEach((char, i) => {
|
[...text].forEach((char, i) => {
|
||||||
drawChar(x+4*i, y, char);
|
drawChar(x+4*i, y, char, color ?? COLOR.WHITE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"sheet_type": "code",
|
"sheet_type": "code",
|
||||||
"value": "x = code_sheet(1);\nreturn ({init: () => {y = 0}, update: () => {y += speed; if (y > 127) {y = -6}}, draw: () => {cls(); txt(x, y, 'hello world')}})"
|
"value": "x = code_sheet(1);\nreturn {\n\tinit: () => {y = 0},\n\tupdate: () => {\n\t\ty += speed;\n\t\tif (y > 127) {\n\t\t\ty = -6\n\t\t}\n\t},\n\tdraw: () => {\n\t\tcls();\n\t\ttxt(x, y, 'hello world')\n\t}\n}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"sheet_type": "code",
|
"sheet_type": "code",
|
||||||
|
13
colors.ts
Normal file
13
colors.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
const colors = {
|
||||||
|
BLACK: [0, 0, 0],
|
||||||
|
WHITE: [1, 1, 1],
|
||||||
|
RED: [1, 0, 0],
|
||||||
|
YELLOW: [1, 1, 0],
|
||||||
|
GREEN: [0, 1, 0],
|
||||||
|
BLUE: [0, 0, 1],
|
||||||
|
DARKBLUE: [0.1, 0.05, 0.4],
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const palette: Array<[number, number, number, number]> = Object.values(colors).map(val => [...val, 1]);
|
||||||
|
|
||||||
|
export const COLOR = Object.fromEntries(Object.keys(colors).map((name, i) => [name, Number(i)])) as {[key in keyof typeof colors]: number};
|
174
editmode.ts
174
editmode.ts
@ -1,11 +1,179 @@
|
|||||||
import { clearScreen } from "./window.ts"
|
import { clearScreen, fillRect } from "./window.ts";
|
||||||
|
import { font, fontWidth, fontHeight } from "./font.ts";
|
||||||
|
import { drawText } from "./builtins.ts";
|
||||||
|
import { COLOR } from "./colors.ts";
|
||||||
|
import { getCart } from "./cart.ts";
|
||||||
|
import {getSheet, setSheet} from "./sheet.ts";
|
||||||
|
import { K, getKeyboardString, getKeysPressed, keyDown, keyPressed, shiftKeyDown } from "./keyboard.ts";
|
||||||
|
|
||||||
|
// deno-lint-ignore prefer-const
|
||||||
|
let tab: "code" | "sprite" | "map" | "sfx" | "music" = "code";
|
||||||
|
|
||||||
|
const codeTabState = {
|
||||||
|
scrollX: 0,
|
||||||
|
scrollY: 0,
|
||||||
|
anchor: 0,
|
||||||
|
focus: 0,
|
||||||
|
get focusX() {return indexToGrid(this.code, this.focus).x;},
|
||||||
|
get focusY() {return indexToGrid(this.code, this.focus).y;},
|
||||||
|
get anchorX() {return indexToGrid(this.code, this.anchor).x;},
|
||||||
|
get anchorY() {return indexToGrid(this.code, this.anchor).y;},
|
||||||
|
isCollapsed() {
|
||||||
|
return this.anchor === this.focus;
|
||||||
|
},
|
||||||
|
clampInRange(n: number) {
|
||||||
|
return Math.max(0, Math.min(n, this.code.length))
|
||||||
|
},
|
||||||
|
setSelection(anchor: number | {x: number, y: number}, focus?: number | {x: number, y: number}) {
|
||||||
|
if (typeof anchor !== "number") {
|
||||||
|
anchor = gridToIndex(this.code, anchor.x, anchor.y);
|
||||||
|
}
|
||||||
|
focus = focus ?? anchor;
|
||||||
|
if (typeof focus !== "number") {
|
||||||
|
focus = gridToIndex(this.code, focus.x, focus.y);
|
||||||
|
}
|
||||||
|
this.anchor = this.clampInRange(anchor),
|
||||||
|
this.focus = this.clampInRange(focus);
|
||||||
|
},
|
||||||
|
setFocus(focus: number | {x: number, y: number}) {
|
||||||
|
if (typeof focus !== "number") {
|
||||||
|
focus = gridToIndex(this.code, focus.x, focus.y);
|
||||||
|
}
|
||||||
|
this.focus = this.clampInRange(focus);
|
||||||
|
},
|
||||||
|
insertText(text: string) {
|
||||||
|
const {code, anchor, focus} = this;
|
||||||
|
this.code = code.slice(0, Math.min(anchor, focus)) + text + code.slice(Math.max(anchor, focus));
|
||||||
|
this.setSelection(Math.min(anchor, focus) + text.length);
|
||||||
|
},
|
||||||
|
// indent(char) {
|
||||||
|
// const lines = this.code.split("\n").
|
||||||
|
// },
|
||||||
|
backspace() {
|
||||||
|
const {code, focus} = this;
|
||||||
|
if (this.isCollapsed()) {
|
||||||
|
if (focus > 0) {
|
||||||
|
this.code = code.slice(0, focus-1) + code.slice(focus);
|
||||||
|
this.setSelection(focus-1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.insertText("");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
get code() {
|
||||||
|
return getSheet(0);
|
||||||
|
},
|
||||||
|
set code(val) {
|
||||||
|
setSheet(0, "code", val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const indexToGrid = (str: string, index: number) => {
|
||||||
|
const linesUpTo = str.slice(0,index).split("\n");
|
||||||
|
return {
|
||||||
|
x: linesUpTo[linesUpTo.length-1].length,
|
||||||
|
y: linesUpTo.length - 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const gridToIndex = (str: string, x: number, y: number) => {
|
||||||
|
const lines = str.split("\n");
|
||||||
|
if (y < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (y >= lines.length) {
|
||||||
|
return str.length;
|
||||||
|
}
|
||||||
|
return lines.slice(0, y).join("\n").length+Math.min(x, lines[y].length)+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const drawCodeField = (code: string, x: number, y: number, w: number, h: number) => {
|
||||||
|
const {
|
||||||
|
scrollX,
|
||||||
|
scrollY,
|
||||||
|
anchor,
|
||||||
|
focus,
|
||||||
|
} = codeTabState;
|
||||||
|
const {
|
||||||
|
x: focusX,
|
||||||
|
y: focusY,
|
||||||
|
} = indexToGrid(code, focus);
|
||||||
|
const {
|
||||||
|
x: anchorX,
|
||||||
|
y: anchorY,
|
||||||
|
} = indexToGrid(code, anchor);
|
||||||
|
fillRect(x, y, w, h, COLOR.DARKBLUE);
|
||||||
|
if (anchor === focus) {
|
||||||
|
fillRect(x+focusX*fontWidth-scrollX, y+focusY*(fontHeight+1)-scrollY, fontWidth+1, fontHeight+1, COLOR.RED);
|
||||||
|
} else {
|
||||||
|
fillRect(x+anchorX*fontWidth-scrollX, y+anchorY*(fontHeight+1)-scrollY, fontWidth+1, fontHeight+1, COLOR.GREEN);
|
||||||
|
fillRect(x+focusX*fontWidth-scrollX, y+focusY*(fontHeight+1)-scrollY, fontWidth+1, fontHeight+1, COLOR.YELLOW);
|
||||||
|
}
|
||||||
|
code.split("\n").forEach((line, i) => {
|
||||||
|
drawText(x-scrollX, 1+y+i*(fontHeight+1)-scrollY, line);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const update = () => {
|
const update = () => {
|
||||||
|
if (tab === "code") {
|
||||||
|
const {code, anchor, focus, focusX, focusY} = codeTabState;
|
||||||
|
const keyboardString = getKeyboardString();
|
||||||
|
if (keyboardString) {
|
||||||
|
codeTabState.insertText(keyboardString);
|
||||||
|
}
|
||||||
|
if (keyPressed(K.ENTER)) {
|
||||||
|
codeTabState.insertText("\n");
|
||||||
|
}
|
||||||
|
if (keyPressed(K.TAB)) {
|
||||||
|
if (!shiftKeyDown()) {
|
||||||
|
if (codeTabState.isCollapsed()) {
|
||||||
|
codeTabState.insertText("\n");
|
||||||
|
} else {
|
||||||
|
// codeTabState.indent("\t");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// codeTabState.outdent(/\t| /);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keyPressed(K.BACKSPACE)) {
|
||||||
|
codeTabState.backspace();
|
||||||
|
}
|
||||||
|
if (keyPressed(K.ARROW_RIGHT)) {
|
||||||
|
if (shiftKeyDown()) {
|
||||||
|
codeTabState.setFocus(focus+1);
|
||||||
|
} else {
|
||||||
|
codeTabState.setSelection(focus+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keyPressed(K.ARROW_LEFT)) {
|
||||||
|
if (shiftKeyDown()) {
|
||||||
|
codeTabState.setFocus(focus-1);
|
||||||
|
} else {
|
||||||
|
codeTabState.setSelection(focus-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keyPressed(K.ARROW_DOWN)) {
|
||||||
|
if (shiftKeyDown()) {
|
||||||
|
codeTabState.setFocus({x: focusX, y: focusY+1});
|
||||||
|
} else {
|
||||||
|
codeTabState.setSelection({x: focusX, y: focusY+1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keyPressed(K.ARROW_UP)) {
|
||||||
|
if (shiftKeyDown()) {
|
||||||
|
codeTabState.setFocus({x: focusX, y: focusY-1});
|
||||||
|
} else {
|
||||||
|
codeTabState.setSelection({x: focusX, y: focusY-1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const draw = () => {
|
const draw = () => {
|
||||||
clearScreen()
|
clearScreen();
|
||||||
|
if (tab === "code") {
|
||||||
|
drawCodeField(getSheet(0), 0, 8, 128, 112);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const editmode = {
|
export const editmode = {
|
||||||
|
11
font.ts
11
font.ts
@ -14,6 +14,9 @@
|
|||||||
* 96 chars * 9 bytes =
|
* 96 chars * 9 bytes =
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export const fontWidth = 4;
|
||||||
|
export const fontHeight = 6;
|
||||||
|
|
||||||
// deno-fmt-ignore
|
// deno-fmt-ignore
|
||||||
export const font: {[key: string]: Array<number>} = {
|
export const font: {[key: string]: Array<number>} = {
|
||||||
"A": [
|
"A": [
|
||||||
@ -456,6 +459,14 @@ export const font: {[key: string]: Array<number>} = {
|
|||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
],
|
],
|
||||||
|
"\t": [
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
],
|
||||||
"<": [
|
"<": [
|
||||||
0, 0, 0, 1,
|
0, 0, 0, 1,
|
||||||
0, 0, 1, 0,
|
0, 0, 1, 0,
|
||||||
|
20
keyboard.ts
20
keyboard.ts
@ -1,3 +1,5 @@
|
|||||||
|
import { font } from "./font.ts";
|
||||||
|
|
||||||
const keyboard = new Map<number, {first: boolean, repeat: boolean, held: boolean}>();
|
const keyboard = new Map<number, {first: boolean, repeat: boolean, held: boolean}>();
|
||||||
|
|
||||||
export const K = {
|
export const K = {
|
||||||
@ -126,3 +128,21 @@ export const getKeysPressed = () => {
|
|||||||
}).map(([key]) => key);
|
}).map(([key]) => key);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getKeyboardString = () => {
|
||||||
|
let str = "";
|
||||||
|
for (const key of getKeysPressed()) {
|
||||||
|
let char = String.fromCharCode(key).toLowerCase();
|
||||||
|
if (shiftKeyDown()) {
|
||||||
|
if (char in shiftMap) {
|
||||||
|
char = shiftMap[char as keyof typeof shiftMap];
|
||||||
|
} else {
|
||||||
|
char = char.toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (char in font) {
|
||||||
|
str += char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
8
repl.ts
8
repl.ts
@ -3,6 +3,7 @@ import { getKeysPressed, shiftKeyDown, shiftMap, K } from "./keyboard.ts";
|
|||||||
import { font } from "./font.ts";
|
import { font } from "./font.ts";
|
||||||
import { addToContext, evalCode } from "./runcode.ts";
|
import { addToContext, evalCode } from "./runcode.ts";
|
||||||
import { clearScreen, fillRect } from "./window.ts";
|
import { clearScreen, fillRect } from "./window.ts";
|
||||||
|
import { COLOR } from "./colors.ts";
|
||||||
|
|
||||||
const lineHeight = 6;
|
const lineHeight = 6;
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ addToContext("print", print);
|
|||||||
addToContext("printVal", printVal);
|
addToContext("printVal", printVal);
|
||||||
|
|
||||||
const update = () => {
|
const update = () => {
|
||||||
|
// TODO: model this after the newer editmode.ts version using getKeyboardString
|
||||||
for (const key of getKeysPressed()) {
|
for (const key of getKeysPressed()) {
|
||||||
let char = String.fromCharCode(key).toLowerCase();
|
let char = String.fromCharCode(key).toLowerCase();
|
||||||
if (shiftKeyDown()) {
|
if (shiftKeyDown()) {
|
||||||
@ -108,7 +110,7 @@ const update = () => {
|
|||||||
|
|
||||||
const drawTextAbove = () => {
|
const drawTextAbove = () => {
|
||||||
textLinesAbove.forEach((line, i) => {
|
textLinesAbove.forEach((line, i) => {
|
||||||
fillRect(0, 1+i*lineHeight, 4*(line.length+1)+1, lineHeight+1, 0);
|
fillRect(0, 1+i*lineHeight, 4*(line.length+1)+1, lineHeight+1, COLOR.BLACK);
|
||||||
drawText(-1, 1+i*lineHeight, line);
|
drawText(-1, 1+i*lineHeight, line);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -118,8 +120,8 @@ const draw = () => {
|
|||||||
|
|
||||||
drawTextAbove();
|
drawTextAbove();
|
||||||
|
|
||||||
fillRect(0, 1+textLinesAbove.length*lineHeight, 4*(2+maxLineLen+1)+1, lineHeight+1, 0);
|
fillRect(0, 1+textLinesAbove.length*lineHeight, 4*(2+maxLineLen+1)+1, lineHeight+1, COLOR.BLACK);
|
||||||
fillRect((2+index)*4, textLinesAbove.length*lineHeight+1, 4, lineHeight-1, 3);
|
fillRect((2+index)*4, textLinesAbove.length*lineHeight+1, 4, lineHeight-1, COLOR.RED);
|
||||||
drawText(-1, 1+textLinesAbove.length*lineHeight, "> "+currentLine);
|
drawText(-1, 1+textLinesAbove.length*lineHeight, "> "+currentLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
7
sheet.ts
7
sheet.ts
@ -3,10 +3,15 @@ import { runCode, addToContext } from "./runcode.ts";
|
|||||||
|
|
||||||
export type SheetType = "code" | "spritesheet" | "map" | "sfx" | "patterns" | "fonts";
|
export type SheetType = "code" | "spritesheet" | "map" | "sfx" | "patterns" | "fonts";
|
||||||
|
|
||||||
const getSheet = (n: number) => {
|
export const getSheet = (n: number) => {
|
||||||
return getCart()[n].value;
|
return getCart()[n].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deno-lint-ignore no-explicit-any
|
||||||
|
export const setSheet = (n: number, type: SheetType, value: any) => {
|
||||||
|
return getCart()[n] = {sheet_type: type, value};
|
||||||
|
}
|
||||||
|
|
||||||
export const codeSheet = (sheet: number) => {
|
export const codeSheet = (sheet: number) => {
|
||||||
const code = getSheet(sheet);
|
const code = getSheet(sheet);
|
||||||
return runCode(code);
|
return runCode(code);
|
||||||
|
11
window.ts
11
window.ts
@ -4,6 +4,7 @@ import {
|
|||||||
gl,
|
gl,
|
||||||
} from "./deps.ts";
|
} from "./deps.ts";
|
||||||
export {mainloop} from "./deps.ts";
|
export {mainloop} from "./deps.ts";
|
||||||
|
import { palette } from "./colors.ts";
|
||||||
|
|
||||||
const window = createWindow({
|
const window = createWindow({
|
||||||
title: "Faux",
|
title: "Faux",
|
||||||
@ -113,16 +114,6 @@ const px = (x: number, y: number) => {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
const palette: Array<[number, number, number, number]> = [
|
|
||||||
[0, 0, 0, 0],
|
|
||||||
[1, 1, 1, 1],
|
|
||||||
[0, 0, 0, 1],
|
|
||||||
[1, 0, 0, 1],
|
|
||||||
[1, 1, 0, 1],
|
|
||||||
[0, 1, 0, 1],
|
|
||||||
[0, 0, 1, 1],
|
|
||||||
];
|
|
||||||
|
|
||||||
const paletteX6 = palette.map(rgba => [...rgba, ...rgba, ...rgba, ...rgba, ...rgba, ...rgba]);
|
const paletteX6 = palette.map(rgba => [...rgba, ...rgba, ...rgba, ...rgba, ...rgba, ...rgba]);
|
||||||
|
|
||||||
const c = (n: number) => {
|
const c = (n: number) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user