console.log! (and better selection and working permissions)
This commit is contained in:
parent
946ae20d67
commit
9d44128914
14 changed files with 365 additions and 23 deletions
48
findTodos.js
Normal file
48
findTodos.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
// i often dont know what to do
|
||||
// if u want to contribute, run this file first
|
||||
|
||||
const { readFileSync, readdirSync, lstatSync } = require("fs");
|
||||
const { resolve, join } = require("path");
|
||||
|
||||
function walk(dir) {
|
||||
const files = [];
|
||||
const folders = [];
|
||||
const abs = resolve(dir);
|
||||
for (const item of readdirSync(abs)) {
|
||||
if (lstatSync(join(abs, item)).isDirectory()) {
|
||||
folders.push(join(dir, item));
|
||||
} else {
|
||||
files.push(join(dir, item));
|
||||
}
|
||||
}
|
||||
for (const dir of folders) {
|
||||
files.push(...walk(dir));
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
function findTodos(file) {
|
||||
file = file.split("\n");
|
||||
const results = [];
|
||||
for (const line in file) {
|
||||
const hasTodo = file[line].trim().match(/\/\/ ?todo.+/gi);
|
||||
if (!hasTodo) continue;
|
||||
results.push({ line, text: hasTodo[0] });
|
||||
}
|
||||
if (results.length === 0) return [];
|
||||
return results.map((i) => `${String(i.line).padStart(3)}: ${i.text}`);
|
||||
}
|
||||
|
||||
let todos = [];
|
||||
for (const file of walk("src")) {
|
||||
const content = readFileSync(file, "utf8");
|
||||
let found = findTodos(content);
|
||||
if (found.length > 0) {
|
||||
todos.push(`${file}\n${found.join("\n")}`);
|
||||
}
|
||||
}
|
||||
if (todos.length > 0) {
|
||||
console.log(todos.join("\n\n"));
|
||||
} else {
|
||||
console.log("nothing to do!");
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -5,13 +5,11 @@ import * as path from "path";
|
|||
const prevent = [
|
||||
{ key: "enter", ctrl: true, shift: false, alt: false, message: "run" },
|
||||
{ key: "l", ctrl: true, shift: false, alt: false, message: "clear" },
|
||||
{ key: "s", ctrl: true, shift: false, alt: true, message: "format" },
|
||||
];
|
||||
|
||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||
if (require("electron-squirrel-startup")) {
|
||||
// eslint-disable-line global-require
|
||||
app.quit();
|
||||
}
|
||||
if (require("electron-squirrel-startup")) app.quit();
|
||||
|
||||
const createWindow = (): void => {
|
||||
// Create the browser window.
|
||||
|
|
157
src/libs/menu.ts
Normal file
157
src/libs/menu.ts
Normal file
|
@ -0,0 +1,157 @@
|
|||
// keybinds/menu at the top of the window
|
||||
import { Menu, MenuItem, BrowserWindow } from "electron";
|
||||
|
||||
export function generateMenu(win: BrowserWindow): Menu {
|
||||
function call(message: string): void {
|
||||
win.webContents.send("menu", message);
|
||||
}
|
||||
|
||||
const files = [];
|
||||
files.push(
|
||||
new MenuItem({
|
||||
label: "open",
|
||||
accelerator: "CommandOrControl+o",
|
||||
click() {
|
||||
call("open");
|
||||
},
|
||||
})
|
||||
);
|
||||
files.push(
|
||||
new MenuItem({
|
||||
label: "save",
|
||||
accelerator: "CommandOrControl+s",
|
||||
click() {
|
||||
call("save");
|
||||
},
|
||||
})
|
||||
);
|
||||
files.push(
|
||||
new MenuItem({
|
||||
label: "save as",
|
||||
accelerator: "CommandOrControl+shift+s",
|
||||
click() {
|
||||
call("saveAs");
|
||||
},
|
||||
})
|
||||
);
|
||||
files.push(new MenuItem({ type: "separator" }));
|
||||
files.push(
|
||||
new MenuItem({
|
||||
label: "recent",
|
||||
id: "recent",
|
||||
type: "submenu",
|
||||
submenu: [], // TODO add recent items
|
||||
})
|
||||
);
|
||||
files.push(new MenuItem({ type: "separator" }));
|
||||
files.push(
|
||||
new MenuItem({
|
||||
role: "quit",
|
||||
label: "quit",
|
||||
accelerator: "CommandOrControl+q",
|
||||
})
|
||||
);
|
||||
|
||||
const perms = [];
|
||||
function perm(item) {
|
||||
call(`perm-${item.id.split("-")[1]}-${item.checked ? "on" : "off"}`);
|
||||
}
|
||||
perms.push(
|
||||
new MenuItem({
|
||||
label: "fs & path",
|
||||
id: "perm-fs",
|
||||
type: "checkbox",
|
||||
checked: false,
|
||||
click: perm,
|
||||
})
|
||||
);
|
||||
perms.push(
|
||||
new MenuItem({
|
||||
label: "zlib",
|
||||
id: "perm-zlib",
|
||||
|
||||
type: "checkbox",
|
||||
checked: false,
|
||||
click: perm,
|
||||
})
|
||||
);
|
||||
perms.push(
|
||||
new MenuItem({
|
||||
label: "http",
|
||||
id: "perm-http",
|
||||
|
||||
type: "checkbox",
|
||||
checked: false,
|
||||
click: perm,
|
||||
})
|
||||
);
|
||||
perms.push(
|
||||
new MenuItem({
|
||||
label: "https",
|
||||
id: "perm-https",
|
||||
|
||||
type: "checkbox",
|
||||
checked: false,
|
||||
click: perm,
|
||||
})
|
||||
);
|
||||
perms.push(
|
||||
new MenuItem({
|
||||
label: "os",
|
||||
id: "perm-os",
|
||||
type: "checkbox",
|
||||
checked: false,
|
||||
click: perm,
|
||||
})
|
||||
);
|
||||
|
||||
const edit = [];
|
||||
edit.push(new MenuItem({ label: "undo", role: "undo" }));
|
||||
edit.push(new MenuItem({ label: "redo", role: "redo" }));
|
||||
edit.push(new MenuItem({ type: "separator" }));
|
||||
edit.push(new MenuItem({ label: "cut", role: "cut" }));
|
||||
edit.push(new MenuItem({ label: "copy", role: "copy" }));
|
||||
edit.push(new MenuItem({ label: "paste", role: "paste" }));
|
||||
edit.push(new MenuItem({ label: "delete", role: "delete" }));
|
||||
edit.push(new MenuItem({ type: "separator" }));
|
||||
edit.push(
|
||||
new MenuItem({
|
||||
label: "format code",
|
||||
accelerator: "CommandOrControl+alt+s",
|
||||
click() {
|
||||
call("format");
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const code = [];
|
||||
code.push(
|
||||
new MenuItem({
|
||||
label: "run",
|
||||
accelerator: "CommandOrControl+enter",
|
||||
click() {
|
||||
call("run");
|
||||
},
|
||||
})
|
||||
);
|
||||
code.push(
|
||||
new MenuItem({
|
||||
label: "clear console",
|
||||
accelerator: "CommandOrControl+l",
|
||||
click() {
|
||||
call("clear");
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const menu = new Menu();
|
||||
menu.append(new MenuItem({ label: "file", type: "submenu", submenu: files }));
|
||||
menu.append(new MenuItem({ label: "edit", type: "submenu", submenu: edit }));
|
||||
menu.append(
|
||||
new MenuItem({ label: "permissions", type: "submenu", submenu: perms })
|
||||
);
|
||||
menu.append(new MenuItem({ label: "code", type: "submenu", submenu: code }));
|
||||
if (process.argv.includes("--dev"))
|
||||
menu.append(new MenuItem({ role: "viewMenu" }));
|
||||
return menu;
|
||||
}
|
|
@ -1,26 +1,93 @@
|
|||
// runs arbitrary code in a sandbox
|
||||
|
||||
// TODO share context between vms
|
||||
import { NodeVM, VM } from "vm2";
|
||||
let consol;
|
||||
const sandbox = {};
|
||||
const nodevm = new NodeVM({ sandbox, require: null, wrapper: "none" });
|
||||
const vmLibrary: Record<string, NodeVM> = {};
|
||||
const perms: Record<string, boolean> = {
|
||||
fs: false,
|
||||
};
|
||||
const vm = new VM({ sandbox, timeout: 3000 });
|
||||
|
||||
export function reset() {
|
||||
// TODO permissions
|
||||
|
||||
// resets the vm sandbox
|
||||
export function reset(): void {
|
||||
for (let i in sandbox) {
|
||||
delete sandbox[i];
|
||||
}
|
||||
}
|
||||
|
||||
export function run(code): unknown {
|
||||
// run code as a nodejs vm
|
||||
export function run(code: string): unknown {
|
||||
try {
|
||||
return nodevm.run(code);
|
||||
// TODO make console.log work
|
||||
return getVm(permArray()).run(code);
|
||||
} catch (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
export function runLess(code): unknown {
|
||||
// run code in a less fancy vm, for the console
|
||||
export function runLess(code: string): unknown {
|
||||
try {
|
||||
return vm.run(code);
|
||||
} catch (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// set the console redirect output
|
||||
export function setConsole(newConsole): void {
|
||||
consol = newConsole;
|
||||
}
|
||||
|
||||
// set the node require root
|
||||
// TODO: fix
|
||||
// export function setRoot(root: string): void {
|
||||
// nodevm.require.root = root;
|
||||
// }
|
||||
|
||||
// sets a permission
|
||||
export function setPerm(name: string, toggle: boolean): void {
|
||||
if (perms.hasOwnProperty(name)) perms[name] = toggle;
|
||||
}
|
||||
|
||||
// convert permission object into an array
|
||||
function permArray(): Array<string> {
|
||||
const arr: Array<string> = [];
|
||||
for (const perm in perms) {
|
||||
if (perms[perm] === true) arr.push(perm);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
// because vm2
|
||||
function getVm(perms: Array<string>) {
|
||||
const name: string = perms.sort().join(",");
|
||||
if (vmLibrary.hasOwnProperty(name)) return vmLibrary[name];
|
||||
const nodevm = new NodeVM({
|
||||
sandbox,
|
||||
require: {
|
||||
external: false,
|
||||
builtin: perms,
|
||||
},
|
||||
wrapper: "none",
|
||||
console: "redirect",
|
||||
})
|
||||
.on("console.log", (msg) => {
|
||||
if (consol) consol.log(msg);
|
||||
})
|
||||
.on("console.info", (msg) => {
|
||||
if (consol) consol.log(msg);
|
||||
})
|
||||
.on("console.warn", (msg) => {
|
||||
if (consol) consol.warn(msg);
|
||||
})
|
||||
.on("console.error", (msg) => {
|
||||
if (consol) consol.error(msg);
|
||||
});
|
||||
vmLibrary[name] = nodevm;
|
||||
return nodevm;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// creates a console
|
||||
|
||||
import { Element } from "./index";
|
||||
import { create, clear } from "../libs/elements";
|
||||
import { display } from "./inspect";
|
||||
|
@ -37,15 +39,20 @@ export class Console extends Element {
|
|||
highlightActiveLine: false,
|
||||
});
|
||||
this.input.listen("runCode", "enter", () => {
|
||||
// TODO console icons, see more below
|
||||
// need icon for console input, console
|
||||
// output, and code ran from editor
|
||||
// also a icon in front of console editor
|
||||
const code = this.input.editor.session.getValue();
|
||||
new Highlight(content, code);
|
||||
if (this.run) this.run(code);
|
||||
this.input.editor.session.setValue("");
|
||||
});
|
||||
|
||||
bar.dragged = function (e) {
|
||||
const barHeight = 3,
|
||||
minY = 0,
|
||||
maxY = window.innerHeight - barHeight;
|
||||
minY = barHeight,
|
||||
maxY = window.innerHeight;
|
||||
let newY = e.clientY;
|
||||
if (newY < minY) newY = minY;
|
||||
if (newY > maxY) newY = maxY;
|
||||
|
@ -56,7 +63,20 @@ export class Console extends Element {
|
|||
}
|
||||
|
||||
log(obj): void {
|
||||
this.content.append(display(obj));
|
||||
const disp = display(obj);
|
||||
this.content.append(disp);
|
||||
}
|
||||
|
||||
warn(obj): void {
|
||||
const disp = display(obj);
|
||||
disp.classList.add("warn");
|
||||
this.content.append(disp);
|
||||
}
|
||||
|
||||
error(obj): void {
|
||||
const disp = display(obj);
|
||||
disp.classList.add("error");
|
||||
this.content.append(disp);
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// creates part of a draggable bar
|
||||
|
||||
import { Element } from "./index";
|
||||
import { create } from "../libs/elements";
|
||||
|
||||
|
|
27
src/ui/highlight.ts
Normal file
27
src/ui/highlight.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { Element } from "./index";
|
||||
import { create } from "../libs/elements";
|
||||
import { Editor } from "./editor";
|
||||
|
||||
export class Highlight extends Element {
|
||||
constructor(parent: HTMLElement, data: string) {
|
||||
super();
|
||||
const element = create("div", ["highlighted"]);
|
||||
parent.append(element);
|
||||
let e = new Editor(element);
|
||||
e.editor.setOptions({
|
||||
enableBasicAutocompletion: false,
|
||||
enableSnippets: false,
|
||||
enableLiveAutocompletion: false,
|
||||
showGutter: false,
|
||||
readOnly: true,
|
||||
maxLines: 100,
|
||||
highlightActiveLine: false,
|
||||
highlightGutterLine: false,
|
||||
});
|
||||
e.editor.textInput.getElement().disabled = true;
|
||||
e.editor.commands.commmandKeyBinding = {};
|
||||
e.editor.renderer.$cursorLayer.element.style.display = "none";
|
||||
e.editor.session.setValue(data);
|
||||
this.element = element;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
// generates an interactive thing display from (almost) anything in js
|
||||
|
||||
import { create, clear } from "../libs/elements";
|
||||
|
||||
function select(el: HTMLElement): void {
|
||||
|
@ -12,6 +14,7 @@ function select(el: HTMLElement): void {
|
|||
selection.addRange(range);
|
||||
}
|
||||
|
||||
// TODO preview first few array items
|
||||
function displayArray(arr: Array<unknown>): HTMLElement {
|
||||
let expanded = false;
|
||||
const body = create("div", ["expand", "canExpand"]);
|
||||
|
@ -53,6 +56,7 @@ function displayArray(arr: Array<unknown>): HTMLElement {
|
|||
return body;
|
||||
}
|
||||
|
||||
// TODO object preview
|
||||
function displayObject(obj): HTMLElement {
|
||||
let expanded = false;
|
||||
const body = create("div", ["expand", "canExpand"]);
|
||||
|
@ -90,6 +94,7 @@ function displayObject(obj): HTMLElement {
|
|||
return body;
|
||||
}
|
||||
|
||||
// TODO better function display
|
||||
function displayFunction(func: Function): HTMLElement {
|
||||
const str = func.toString();
|
||||
const preview = str.length < 35 ? str : str.slice(0, 33) + "...";
|
||||
|
@ -107,6 +112,7 @@ function displayPart(thing): HTMLElement {
|
|||
return create("div", ["value", "undefined"], "undefined");
|
||||
switch (typeof thing) {
|
||||
case "string":
|
||||
// TODO trim string if its too long
|
||||
return create("div", ["value", "string"], `"${thing}"`);
|
||||
break;
|
||||
case "number":
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
.console {
|
||||
padding: 0.5em;
|
||||
overflow-y: hidden;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-rows: 1fr 3px 3em;
|
||||
|
@ -10,6 +9,8 @@
|
|||
.display,
|
||||
.highlighted {
|
||||
padding: 0.5em;
|
||||
position: relative;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
|
@ -30,16 +31,19 @@
|
|||
top: 0;
|
||||
}
|
||||
|
||||
.highlighted {
|
||||
border: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.highlighted:not(:last-child),
|
||||
.display:not(:last-child) {
|
||||
border-bottom: solid var(--foreground) 1px;
|
||||
}
|
||||
|
||||
.display.warn {
|
||||
background: #ffff0033;
|
||||
}
|
||||
|
||||
.display.error {
|
||||
background: #ff000033;
|
||||
}
|
||||
|
||||
.display div:not(.expand) {
|
||||
cursor: auto;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--selection);
|
||||
}
|
||||
|
||||
body {
|
||||
font: 12px / normal "Monaco", "Menlo", "Ubuntu Mono", "Consolas",
|
||||
"source-code-pro", monospace;
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
// the main part of the ide
|
||||
|
||||
import { ipcRenderer } from "electron";
|
||||
import { Editor } from "../ui/editor";
|
||||
import { Console } from "../ui/console";
|
||||
import { Bar } from "../ui/dragBar";
|
||||
import { formatWithCursor } from "prettier";
|
||||
import { run, runLess } from "../libs/run";
|
||||
import * as vm from "../libs/run";
|
||||
import * as files from "../libs/files";
|
||||
import { basename } from "path";
|
||||
const permissions: Record<string, boolean> = {};
|
||||
|
||||
const main = document.getElementById("main");
|
||||
const [edit, bar, consol] = [
|
||||
|
@ -80,13 +83,14 @@ bar.dragged = function (e) {
|
|||
edit.editor.resize();
|
||||
};
|
||||
|
||||
vm.setConsole(consol);
|
||||
|
||||
consol.run = (code) => {
|
||||
const res = runLess(code);
|
||||
const res = vm.runLess(code);
|
||||
consol.log(res);
|
||||
};
|
||||
|
||||
ipcRenderer.on("menu", (e, message) => {
|
||||
console.log(message);
|
||||
switch (message) {
|
||||
case "save":
|
||||
save();
|
||||
|
@ -101,12 +105,16 @@ ipcRenderer.on("menu", (e, message) => {
|
|||
format();
|
||||
break;
|
||||
case "run":
|
||||
consol.log(run(edit.editor.session.getValue()));
|
||||
consol.log(vm.run(edit.editor.session.getValue()));
|
||||
break;
|
||||
case "clear":
|
||||
consol.clear();
|
||||
break;
|
||||
}
|
||||
if (message.substr(0, 5) === "perm-") {
|
||||
const [type, toggle] = message.substr(5).split("-");
|
||||
vm.setPerm(type, toggle === "on" ? true : false);
|
||||
}
|
||||
});
|
||||
|
||||
function updateTitle(): void {
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
--background: #272822;
|
||||
--foreground: #f8f8f2;
|
||||
--accent: #1186d9;
|
||||
--selection: #f8f8f233;
|
||||
}
|
||||
|
|
Reference in a new issue