Setup editor, remove tauri for now
17
README.md
|
@ -2,13 +2,16 @@
|
||||||
|
|
||||||
|
|
||||||
# planned for v1
|
# planned for v1
|
||||||
- [ ] sprite manager
|
- [ ] ability to play project
|
||||||
- [ ] level manager
|
- [ ] monaco code editor
|
||||||
- [ ] monaco editor
|
- [ ] export project for sprig
|
||||||
- [ ] **export project for sprig**
|
- [ ] docs site
|
||||||
|
- [ ] typescript support (esbuild prob)
|
||||||
|
|
||||||
|
|
||||||
# planned for v2
|
# planned for v2
|
||||||
- [ ] typescript support (esbuild prob)
|
- [ ] sprite manager
|
||||||
- [ ] build project as a standalone `.html` file (maybe vite?)
|
- [ ] level manager
|
||||||
- [ ] run on device
|
- [ ] build project as a standalone `.html` file
|
||||||
|
- [ ] run on device
|
||||||
|
- [ ] downloadable version
|
BIN
bun.lockb
14
package.json
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "sprig-rs",
|
"name": "sprigsy",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||||
"@tailwindcss/typography": "^0.5.14",
|
"@tailwindcss/typography": "^0.5.14",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
|
"babel-walk": "^3.0.0",
|
||||||
"prettier": "^3.1.1",
|
"prettier": "^3.1.1",
|
||||||
"prettier-plugin-svelte": "^3.1.2",
|
"prettier-plugin-svelte": "^3.1.2",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
"prettier-plugin-tailwindcss": "^0.6.5",
|
||||||
|
@ -24,12 +25,13 @@
|
||||||
"svelte-check": "^3.6.0",
|
"svelte-check": "^3.6.0",
|
||||||
"tailwindcss": "^3.4.9",
|
"tailwindcss": "^3.4.9",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^5.0.3"
|
"vite": "^5.0.3",
|
||||||
},
|
"@babel/parser": "^7.25.3",
|
||||||
"type": "module",
|
|
||||||
"dependencies": {
|
|
||||||
"@sveltejs/adapter-static": "^3.0.4",
|
"@sveltejs/adapter-static": "^3.0.4",
|
||||||
|
"constrained-editor-plugin": "^1.3.0",
|
||||||
"monaco-editor": "^0.50.0",
|
"monaco-editor": "^0.50.0",
|
||||||
|
"sprig": "^1.1.3",
|
||||||
"sveltekit-adapter-deno": "^0.12.1"
|
"sveltekit-adapter-deno": "^0.12.1"
|
||||||
}
|
},
|
||||||
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|
3
src-tauri/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
||||||
# Generated by Cargo
|
|
||||||
# will have compiled files and executables
|
|
||||||
/target/
|
|
3689
src-tauri/Cargo.lock
generated
|
@ -1,26 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "app"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "A Tauri App"
|
|
||||||
authors = ["you"]
|
|
||||||
license = ""
|
|
||||||
repository = ""
|
|
||||||
default-run = "app"
|
|
||||||
edition = "2021"
|
|
||||||
rust-version = "1.60"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
tauri-build = { version = "1.5.3", features = [] }
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
serde_json = "1.0"
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
tauri = { version = "1.7.0", features = [] }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
|
|
||||||
# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.
|
|
||||||
# DO NOT REMOVE!!
|
|
||||||
custom-protocol = [ "tauri/custom-protocol" ]
|
|
|
@ -1,3 +0,0 @@
|
||||||
fn main() {
|
|
||||||
tauri_build::build()
|
|
||||||
}
|
|
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 9 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 49 KiB |
|
@ -1,8 +0,0 @@
|
||||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
tauri::Builder::default()
|
|
||||||
.run(tauri::generate_context!())
|
|
||||||
.expect("error while running tauri application");
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
{
|
|
||||||
"build": {
|
|
||||||
"beforeBuildCommand": "bun run build",
|
|
||||||
"beforeDevCommand": "bun run dev",
|
|
||||||
"devPath": "http://localhost:5173",
|
|
||||||
"distDir": "../buid"
|
|
||||||
},
|
|
||||||
"package": {
|
|
||||||
"productName": "sprigsy",
|
|
||||||
"version": "0.1.0"
|
|
||||||
},
|
|
||||||
"tauri": {
|
|
||||||
"allowlist": {
|
|
||||||
"all": false
|
|
||||||
},
|
|
||||||
"bundle": {
|
|
||||||
"active": true,
|
|
||||||
"category": "DeveloperTool",
|
|
||||||
"copyright": "",
|
|
||||||
"deb": {
|
|
||||||
"depends": []
|
|
||||||
},
|
|
||||||
"externalBin": [],
|
|
||||||
"icon": [
|
|
||||||
"icons/32x32.png",
|
|
||||||
"icons/128x128.png",
|
|
||||||
"icons/128x128@2x.png",
|
|
||||||
"icons/icon.icns",
|
|
||||||
"icons/icon.ico"
|
|
||||||
],
|
|
||||||
"identifier": "com.tauri.dev",
|
|
||||||
"longDescription": "",
|
|
||||||
"macOS": {
|
|
||||||
"entitlements": null,
|
|
||||||
"exceptionDomain": "",
|
|
||||||
"frameworks": [],
|
|
||||||
"providerShortName": null,
|
|
||||||
"signingIdentity": null
|
|
||||||
},
|
|
||||||
"resources": [],
|
|
||||||
"shortDescription": "",
|
|
||||||
"targets": "all",
|
|
||||||
"windows": {
|
|
||||||
"certificateThumbprint": null,
|
|
||||||
"digestAlgorithm": "sha256",
|
|
||||||
"timestampUrl": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"security": {
|
|
||||||
"csp": null
|
|
||||||
},
|
|
||||||
"updater": {
|
|
||||||
"active": false
|
|
||||||
},
|
|
||||||
"windows": [
|
|
||||||
{
|
|
||||||
"fullscreen": false,
|
|
||||||
"height": 600,
|
|
||||||
"resizable": true,
|
|
||||||
"title": "Sprigsy Editor",
|
|
||||||
"width": 800
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +1,7 @@
|
||||||
@import 'tailwindcss/base';
|
@import 'tailwindcss/base';
|
||||||
@import 'tailwindcss/components';
|
@import 'tailwindcss/components';
|
||||||
@import 'tailwindcss/utilities';
|
@import 'tailwindcss/utilities';
|
||||||
|
|
||||||
|
body, html {
|
||||||
|
|
||||||
|
}
|
191
src/lib/Editor.svelte
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import * as monaco from 'monaco-editor';
|
||||||
|
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
|
||||||
|
import {} from 'sprig/web';
|
||||||
|
import { constrainedEditor } from 'constrained-editor-plugin';
|
||||||
|
import { parse } from '@babel/parser';
|
||||||
|
|
||||||
|
let editorContainer: HTMLDivElement;
|
||||||
|
let editor: import('monaco-editor').editor.IStandaloneCodeEditor;
|
||||||
|
// const monaco = await import ('monaco-editor')
|
||||||
|
// Initial code inside the function
|
||||||
|
function debounce<A, T = void>(func: (this: T, ...args: A[]) => any, timeout = 300) {
|
||||||
|
let timer: number;
|
||||||
|
return function (this: T, ...args: A[]) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
func.apply(this, args);
|
||||||
|
}, timeout);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let code = `console.log('Hello sprig!');`;
|
||||||
|
onMount(async () => {
|
||||||
|
globalThis.process = {};
|
||||||
|
globalThis.process.env = {};
|
||||||
|
const { recursive } = await import('babel-walk');
|
||||||
|
await addGlobalTypes();
|
||||||
|
setupEditor();
|
||||||
|
self.MonacoEnvironment = {
|
||||||
|
getWorker: function (_: any, label: string) {
|
||||||
|
return new tsWorker();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to add global types
|
||||||
|
async function addGlobalTypes() {
|
||||||
|
const sprigTypeDef = (await import('./editorcontext/sprig.d.ts?raw')).default;
|
||||||
|
monaco.languages.typescript.typescriptDefaults.addExtraLib(
|
||||||
|
sprigTypeDef,
|
||||||
|
'context/sprig.d.ts'
|
||||||
|
);
|
||||||
|
const globalTypeDef = (await import('./editorcontext/global.d.ts?raw')).default;
|
||||||
|
monaco.languages.typescript.typescriptDefaults.addExtraLib(
|
||||||
|
globalTypeDef,
|
||||||
|
'context/global.d.ts'
|
||||||
|
);
|
||||||
|
|
||||||
|
// IMPLEMENT ONCE v2 IS DONE!
|
||||||
|
// const sprigsyTypeDef = (await import('./editorcontext/sprigsy.d.ts?raw')).default;
|
||||||
|
// monaco.languages.typescript.typescriptDefaults.addExtraLib(
|
||||||
|
// sprigsyTypeDef,
|
||||||
|
// 'context/sprigsy.d.ts'
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
const disallowedIdentifiers = ['window', 'globalThis'];
|
||||||
|
type ASTState = {
|
||||||
|
disallowedWarnings: { identifier: string; loc: [number, number, number, number] }[];
|
||||||
|
};
|
||||||
|
const ASTWalker = recursive<ASTState>({
|
||||||
|
Identifier(node, state, c) {
|
||||||
|
console;
|
||||||
|
if (disallowedIdentifiers.includes(node.name)) {
|
||||||
|
state.disallowedWarnings.push({
|
||||||
|
identifier: node.name,
|
||||||
|
loc: [
|
||||||
|
node.loc?.start?.line!,
|
||||||
|
node.loc?.start?.column!,
|
||||||
|
node.loc?.end?.line!,
|
||||||
|
node.loc?.end?.column!
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const checkBabel = debounce(() => {
|
||||||
|
console.log('checking for uhh');
|
||||||
|
const ast = parse(editor.getValue(), {
|
||||||
|
plugins: ['typescript']
|
||||||
|
});
|
||||||
|
const state: ASTState = { disallowedWarnings: [] };
|
||||||
|
ASTWalker(ast, state);
|
||||||
|
console.log(state);
|
||||||
|
state.disallowedWarnings.forEach((v) => {
|
||||||
|
monaco.editor.setModelMarkers(editor.getModel()!, editor.getId(), [
|
||||||
|
{
|
||||||
|
message: `'${v.identifier}' is not allowed.`,
|
||||||
|
severity: monaco.MarkerSeverity.Error,
|
||||||
|
startLineNumber: v.loc[0],
|
||||||
|
startColumn: v.loc[1]+1,
|
||||||
|
endLineNumber: v.loc[2],
|
||||||
|
endColumn: v.loc[3]+1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Function to set up the editor
|
||||||
|
function setupEditor() {
|
||||||
|
editor = monaco.editor.create(editorContainer, {
|
||||||
|
value: `function game(api: sprig.FullSprigAPI): void {
|
||||||
|
${code}
|
||||||
|
}`,
|
||||||
|
language: 'typescript',
|
||||||
|
automaticLayout: true,
|
||||||
|
scrollBeyondLastLine: false,
|
||||||
|
theme: 'vs-dark'
|
||||||
|
});
|
||||||
|
|
||||||
|
const model = editor.getModel()!;
|
||||||
|
// Mark function declaration and closing brace as read-only
|
||||||
|
// editor.createDecorationsCollection(
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// range: new monaco.Range(1, 1, 1, 28),
|
||||||
|
// options: {
|
||||||
|
// className: 'read-only',
|
||||||
|
// isWholeLine: true
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// range: new monaco.Range(
|
||||||
|
// model.getLineCount(),
|
||||||
|
// 1,
|
||||||
|
// model.getLineCount(),
|
||||||
|
// model.getLineMaxColumn(model.getLineCount())
|
||||||
|
// ),
|
||||||
|
// options: {
|
||||||
|
// className: 'read-only',
|
||||||
|
// isWholeLine: true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
|
||||||
|
// Disable editing in read-only regions
|
||||||
|
// editor.onDidChangeModelContent((event) => {
|
||||||
|
// event.changes.forEach((change) => {
|
||||||
|
// const { range } = change;
|
||||||
|
|
||||||
|
// if (
|
||||||
|
// (range.startLineNumber === 1 && range.endLineNumber === 1) ||
|
||||||
|
// (range.startLineNumber === model.getLineCount() &&
|
||||||
|
// range.endLineNumber === model.getLineCount())
|
||||||
|
// ) {
|
||||||
|
// editor.executeEdits('revert-read-only', [
|
||||||
|
// {
|
||||||
|
// range: new monaco.Range(
|
||||||
|
// range.startLineNumber,
|
||||||
|
// range.startColumn,
|
||||||
|
// range.endLineNumber,
|
||||||
|
// range.endColumn
|
||||||
|
// ),
|
||||||
|
// text: '',
|
||||||
|
// forceMoveMarkers: true
|
||||||
|
// }
|
||||||
|
// ]);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
const constrainedInstance = constrainedEditor(monaco);
|
||||||
|
constrainedInstance.initializeIn(editor);
|
||||||
|
constrainedInstance.addRestrictionsTo(model, [
|
||||||
|
{
|
||||||
|
range: [2, 1, 2, code.length + 2], // Range of Function definition
|
||||||
|
allowMultiline: true,
|
||||||
|
label: 'funcDefinition'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
editor.onDidChangeModelContent((event) => {
|
||||||
|
console.log(event.changes);
|
||||||
|
console.log(model.getValueInEditableRanges());
|
||||||
|
checkBabel();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
if (editor) {
|
||||||
|
editor.dispose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div bind:this={editorContainer} class="editor-container"></div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.editor-container {
|
||||||
|
height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
10
src/lib/editorcontext/global.d.ts
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import "./sprig"
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
var setTimeout: sprig.FullSprigAPI['setTimeout'];
|
||||||
|
var setInterval: sprig.FullSprigAPI['setInterval'];
|
||||||
|
var clearTimeout: sprig.FullSprigAPI['clearTimeout'];
|
||||||
|
var clearInterval: sprig.FullSprigAPI['clearInterval'];
|
||||||
|
|
||||||
|
var tones: typeof sprig['tones']
|
||||||
|
}
|
75
src/lib/editorcontext/sprig.d.ts
vendored
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
declare namespace sprig {
|
||||||
|
export declare const VALID_INPUTS: readonly ["w", "s", "a", "d", "i", "j", "k", "l"];
|
||||||
|
export type InputKey = typeof VALID_INPUTS[number];
|
||||||
|
export interface AddTextOptions {
|
||||||
|
x?: number;
|
||||||
|
y?: number;
|
||||||
|
color?: string;
|
||||||
|
}
|
||||||
|
export declare class SpriteType {
|
||||||
|
type: string;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
readonly dx: number;
|
||||||
|
readonly dy: number;
|
||||||
|
remove(): void;
|
||||||
|
}
|
||||||
|
export type Rgba = [number, number, number, number];
|
||||||
|
export interface TextElement {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
color: Rgba;
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
export interface GameState {
|
||||||
|
legend: [string, string][];
|
||||||
|
texts: TextElement[];
|
||||||
|
dimensions: {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
sprites: SpriteType[];
|
||||||
|
solids: string[];
|
||||||
|
pushable: Record<string, string[]>;
|
||||||
|
background: string | null;
|
||||||
|
}
|
||||||
|
export interface PlayTuneRes {
|
||||||
|
end(): void;
|
||||||
|
isPlaying(): boolean;
|
||||||
|
}
|
||||||
|
// export declare const tones: Record<string, number>;
|
||||||
|
// export declare const instruments: readonly ["sine", "triangle", "square", "sawtooth"];
|
||||||
|
export type InstrumentType = typeof instruments[number];
|
||||||
|
// export declare const instrumentKey: Record<string, InstrumentType>;
|
||||||
|
// export declare const reverseInstrumentKey: Record<"sine" | "triangle" | "square" | "sawtooth", string>;
|
||||||
|
export type Tune = [number, ...(InstrumentType | number | string)[]][];
|
||||||
|
export interface FullSprigAPI {
|
||||||
|
map(template: TemplateStringsArray, ...params: string[]): string;
|
||||||
|
bitmap(template: TemplateStringsArray, ...params: string[]): string;
|
||||||
|
color(template: TemplateStringsArray, ...params: string[]): string;
|
||||||
|
tune(template: TemplateStringsArray, ...params: string[]): string;
|
||||||
|
setMap(string: string): void;
|
||||||
|
addText(str: string, opts?: AddTextOptions): void;
|
||||||
|
clearText(): void;
|
||||||
|
addSprite(x: number, y: number, type: string): void;
|
||||||
|
getGrid(): SpriteType[][];
|
||||||
|
getTile(x: number, y: number): SpriteType[];
|
||||||
|
tilesWith(...matchingTypes: string[]): SpriteType[][];
|
||||||
|
clearTile(x: number, y: number): void;
|
||||||
|
setSolids(types: string[]): void;
|
||||||
|
setPushables(map: Record<string, string[]>): void;
|
||||||
|
setBackground(type: string): void;
|
||||||
|
getFirst(type: string): SpriteType | undefined;
|
||||||
|
getAll(type: string): SpriteType[];
|
||||||
|
width(): number;
|
||||||
|
height(): number;
|
||||||
|
setLegend(...bitmaps: [string, string][]): void;
|
||||||
|
onInput(key: InputKey, fn: () => void): void;
|
||||||
|
afterInput(fn: () => void): void;
|
||||||
|
playTune(text: string, n?: number): PlayTuneRes;
|
||||||
|
setTimeout(fn: TimerHandler, ms: number): number;
|
||||||
|
setInterval(fn: TimerHandler, ms: number): number;
|
||||||
|
clearTimeout(id: number): void;
|
||||||
|
clearInterval(id: number): void;
|
||||||
|
}
|
||||||
|
}
|
11
src/lib/editorcontext/sprigsy.d.ts
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/**
|
||||||
|
* API for sprigsy
|
||||||
|
* this is provided because your project has sprigsy v2 enabeled
|
||||||
|
*/
|
||||||
|
declare namespace sprigsy {
|
||||||
|
/**
|
||||||
|
* Retrieve a sprite key for the sprite name
|
||||||
|
* @param name Sprite name
|
||||||
|
*/
|
||||||
|
function spriteKeyFor(name: string): string
|
||||||
|
}
|
|
@ -1 +1,2 @@
|
||||||
export const prerender = true;
|
export const prerender = true;
|
||||||
|
export const ssr = false
|
|
@ -1,2 +1,8 @@
|
||||||
<h1>Welcome to SvelteKit</h1>
|
<script>
|
||||||
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
|
import Editor from "$lib/Editor.svelte";
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<div class="">
|
||||||
|
<Editor />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|