console.log! (and better selection and working permissions)

This commit is contained in:
sample-text-here 2021-01-12 16:31:22 -08:00
parent 946ae20d67
commit 9d44128914
14 changed files with 365 additions and 23 deletions

48
findTodos.js Normal file
View 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.

View file

@ -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
View 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;
}

View file

@ -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;
}

View file

@ -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 {

View file

@ -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
View 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;
}
}

View file

@ -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":

View file

@ -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;
}

View file

@ -6,6 +6,10 @@
padding: 0;
}
::selection {
background: var(--selection);
}
body {
font: 12px / normal "Monaco", "Menlo", "Ubuntu Mono", "Consolas",
"source-code-pro", monospace;

View file

@ -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 {

View file

@ -2,4 +2,5 @@
--background: #272822;
--foreground: #f8f8f2;
--accent: #1186d9;
--selection: #f8f8f233;
}