more cleanup
This commit is contained in:
parent
bd8ac12eb1
commit
d992569d6f
11 changed files with 272 additions and 308 deletions
|
@ -4,12 +4,7 @@ its not actually really an ide but i dont care
|
|||
|
||||
### using
|
||||
|
||||
press ctrl-alt-s to format file,
|
||||
press ctrl-enter to run
|
||||
|
||||
you need a `return` to actually get a value from your program
|
||||
|
||||
ctrl-s, ctrl-o, and ctrl-shift-s do as expected
|
||||
look at the menu items if you "need" a tutorial
|
||||
|
||||
### building
|
||||
|
||||
|
|
118
src/index.ts
118
src/index.ts
|
@ -6,17 +6,18 @@ import {
|
|||
MenuItem,
|
||||
shell,
|
||||
dialog,
|
||||
Notification,
|
||||
} from "electron";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { generateMenu } from "./libs/menu";
|
||||
import { generateMenu, generateRecents } from "./libs/menu";
|
||||
import { parse } from "./libs/args";
|
||||
import { paths, options, reload } from "./libs/options";
|
||||
import { Bind } from "./libs/keybind";
|
||||
import event from "./libs/events";
|
||||
const args = parse();
|
||||
const allowed = ["js", "json", "md", "txt", "mlog"];
|
||||
const keys = [];
|
||||
const sessions = [];
|
||||
|
||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||
if (require("electron-squirrel-startup")) app.quit();
|
||||
|
@ -27,7 +28,9 @@ function regenMenu(): void {
|
|||
new MenuItem({
|
||||
label: "help",
|
||||
role: "help",
|
||||
click: (): void => showHelp(),
|
||||
click: (): void => {
|
||||
createWindow("help.html").setMenu(null);
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -35,31 +38,48 @@ function regenMenu(): void {
|
|||
|
||||
while (keys.length > 0) keys.pop();
|
||||
|
||||
for (let category in options.keybinds) {
|
||||
const binds = options.keybinds[category];
|
||||
for (let bind in binds) {
|
||||
if (!["run", "clear", "format", "showFile"].includes(bind)) continue;
|
||||
keys.push({ bind: new Bind(binds[bind]), message: bind });
|
||||
}
|
||||
const binds = options.keybinds;
|
||||
const override = { ...binds.files, ...binds.code };
|
||||
for (let bind in override) {
|
||||
keys.push({ bind: new Bind(override[bind]), message: bind });
|
||||
}
|
||||
|
||||
if (!new Bind(binds.files.config).isValid()) {
|
||||
new Notification({
|
||||
title: "achievement unlocked",
|
||||
body: "why did you do that",
|
||||
}).show();
|
||||
}
|
||||
}
|
||||
|
||||
function createWindow(): BrowserWindow {
|
||||
function createWindow(file: string, options = {}): BrowserWindow {
|
||||
const win = new BrowserWindow({
|
||||
height: 350,
|
||||
width: 350,
|
||||
show: false,
|
||||
// TODO: make an icon that doesn't make my eyes bleed
|
||||
// icon: path.join(__dirname, "assets", "icon.png"),
|
||||
...options,
|
||||
});
|
||||
sessions.push(win);
|
||||
|
||||
win.loadFile(path.join(__dirname, "window", file));
|
||||
|
||||
win.once("ready-to-show", () => {
|
||||
win.show();
|
||||
});
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
function createSession(): BrowserWindow {
|
||||
const win = createWindow("index.html", {
|
||||
height: 400,
|
||||
width: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true,
|
||||
},
|
||||
show: false,
|
||||
});
|
||||
|
||||
// and load the index.html of the app.
|
||||
win.loadFile(path.join(__dirname, "window/index.html"));
|
||||
|
||||
win.once("ready-to-show", () => {
|
||||
win.show();
|
||||
});
|
||||
|
||||
win.webContents.on("before-input-event", (e, input) => {
|
||||
|
@ -68,12 +88,18 @@ function createWindow(): BrowserWindow {
|
|||
press.shift = input.shift;
|
||||
press.alt = input.alt;
|
||||
if (!press.isValid()) return;
|
||||
for (const i of keys) {
|
||||
for (let i of keys) {
|
||||
if (press.isSame(i.bind)) {
|
||||
e.preventDefault();
|
||||
|
||||
win.webContents.send("menu", i.message);
|
||||
break;
|
||||
if (i.message === "quit") {
|
||||
win.close();
|
||||
const index = sessions.indexOf(win);
|
||||
if (index < 0) return;
|
||||
sessions.splice(index, 1);
|
||||
if (sessions.length <= 0) return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -81,61 +107,37 @@ function createWindow(): BrowserWindow {
|
|||
return win;
|
||||
}
|
||||
|
||||
function showHelp(): void {
|
||||
const help = new BrowserWindow({
|
||||
height: 350,
|
||||
width: 350,
|
||||
show: false,
|
||||
});
|
||||
|
||||
help.loadFile(path.join(__dirname, "window/help.html"));
|
||||
help.setMenu(null);
|
||||
|
||||
help.once("ready-to-show", () => {
|
||||
help.show();
|
||||
});
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on("ready", () => {
|
||||
const win = createWindow();
|
||||
reload();
|
||||
regenMenu();
|
||||
const win = createSession();
|
||||
win.once("ready-to-show", () => {
|
||||
if (args.file) {
|
||||
// (ab)use openRecent
|
||||
win.webContents.send("openRecent", args.file);
|
||||
}
|
||||
});
|
||||
regenMenu();
|
||||
});
|
||||
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
app.on("activate", () => {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
app.on("window-all-closed", app.quit);
|
||||
|
||||
// TODO: only reload needed parts
|
||||
// seperate event for a full reload
|
||||
const reloadEv = event("reload");
|
||||
const reloadEv = event("reload", true);
|
||||
function reloadAll(): void {
|
||||
reloadEv.fire();
|
||||
reload();
|
||||
regenMenu();
|
||||
}
|
||||
|
||||
function reloadRecent(): void {
|
||||
reload();
|
||||
regenMenu();
|
||||
}
|
||||
|
||||
fs.watchFile(paths.config, reloadAll);
|
||||
event("shouldReload").addListener(reloadAll);
|
||||
event("showFile").addListener((file) => shell.showItemInFolder(file[0]));
|
||||
event("reload.force", true).addListener(reloadAll);
|
||||
event("reload.recents", true).addListener(reloadRecent);
|
||||
event("showFile", true).addListener((file) => shell.showItemInFolder(file));
|
||||
|
|
|
@ -8,7 +8,7 @@ export enum EventScope {
|
|||
export class Event {
|
||||
readonly name: string = "";
|
||||
listeners: Array<Function> = [];
|
||||
scope: EventScope = EventScope.global;
|
||||
scope: EventScope = EventScope.process;
|
||||
|
||||
constructor(name: string) {
|
||||
this.name = name;
|
||||
|
@ -41,9 +41,10 @@ export class Event {
|
|||
}
|
||||
}
|
||||
|
||||
export default function eventsInterface(name: string) {
|
||||
export default function eventsInterface(name: string, isGlobal = false) {
|
||||
if (Object.prototype.hasOwnProperty.call(events, name)) return events[name];
|
||||
const event = new Event(name);
|
||||
if (isGlobal) event.scope = EventScope.global;
|
||||
events[name] = event;
|
||||
return event;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { remote } from "electron";
|
|||
import event from "../libs/events";
|
||||
import { options, paths, save } from "./options";
|
||||
|
||||
const updateEv = event("updateRecent");
|
||||
const updateEv = event("reload.recents", true);
|
||||
export function touch(path: string): void {
|
||||
const r = options.internal.recent;
|
||||
if (r.indexOf(path) >= 0) r.splice(r.indexOf(path), 1);
|
||||
|
@ -14,18 +14,6 @@ export function touch(path: string): void {
|
|||
updateEv.fire();
|
||||
}
|
||||
|
||||
export function saveSketch(value: string): void {
|
||||
fs.writeFileSync(paths.sketch, value);
|
||||
}
|
||||
|
||||
export function loadSketch(): string {
|
||||
return fs.readFileSync(paths.sketch, "utf8");
|
||||
}
|
||||
|
||||
export function backup(file: string): void {
|
||||
fs.writeFileSync(options.backup, file);
|
||||
}
|
||||
|
||||
export function saveFile(path: string, value: string): void {
|
||||
fs.writeFileSync(path, value);
|
||||
}
|
||||
|
@ -34,13 +22,13 @@ export function openFile(path: string): string {
|
|||
return fs.readFileSync(path, "utf8");
|
||||
}
|
||||
|
||||
export function fileOpen(): string[] {
|
||||
return remote.dialog.showOpenDialogSync({
|
||||
export function fileOpen(): string {
|
||||
return (remote.dialog.showOpenDialogSync({
|
||||
title: "open file",
|
||||
properties: ["openFile"],
|
||||
filters: options.filters,
|
||||
defaultPath: options.filesDir,
|
||||
});
|
||||
}) || [])[0];
|
||||
}
|
||||
|
||||
export function fileSave(): string {
|
||||
|
|
|
@ -16,7 +16,7 @@ function call(message: string) {
|
|||
return () => send("menu", message);
|
||||
}
|
||||
|
||||
function generateRecents(fileNames: Array<string>): Menu {
|
||||
export function generateRecents(fileNames: Array<string>): Menu {
|
||||
const recents = new Menu();
|
||||
for (const file of fileNames) {
|
||||
recents.append(
|
||||
|
|
|
@ -93,13 +93,14 @@ const defaultOptions: Options = {
|
|||
format: "ctrl-alt-s",
|
||||
},
|
||||
files: {
|
||||
open: "ctrl-s",
|
||||
save: "ctrl-o",
|
||||
open: "ctrl-o",
|
||||
save: "ctrl-s",
|
||||
saveAs: "ctrl-shift-s",
|
||||
openRecent: "ctrl-shift-o",
|
||||
showFile: "ctrl-shift-e",
|
||||
sketchpad: "ctrl-alt-o",
|
||||
quit: "ctrl-q",
|
||||
config: "ctrl-,",
|
||||
},
|
||||
},
|
||||
internal: {
|
||||
|
@ -129,6 +130,7 @@ const vm = new NodeVM({
|
|||
|
||||
export function reload(): void {
|
||||
const newOpts: Options = deepCopy<Options>(defaultOptions);
|
||||
|
||||
try {
|
||||
const json = JSON.parse(fs.readFileSync(paths.internal, "utf8"));
|
||||
if (typeof json !== "object") throw "not object";
|
||||
|
@ -144,7 +146,9 @@ export function reload(): void {
|
|||
if (typeof result !== "object") throw "result not an object";
|
||||
if (!result) throw "result is null";
|
||||
assign(newOpts, result);
|
||||
} catch {}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
const allFilters: Array<string> = [];
|
||||
for (let i of newOpts.filters) {
|
||||
|
@ -152,7 +156,7 @@ export function reload(): void {
|
|||
}
|
||||
newOpts.filters.push({ name: "all", extensions: allFilters });
|
||||
|
||||
if (!isOptions(options)) throw "invalid options";
|
||||
if (!isOptions(newOpts)) throw "invalid options";
|
||||
Object.assign(options, newOpts);
|
||||
|
||||
if (!fs.existsSync(options.filesDir)) {
|
||||
|
|
|
@ -5,7 +5,7 @@ export function deepCopyArray(arr: Array<any>) {
|
|||
if (i instanceof Array) {
|
||||
out.push(deepCopyArray(i));
|
||||
} else {
|
||||
out.push(deepCopy<Object>(i));
|
||||
out.push(deepCopy(i));
|
||||
}
|
||||
} else {
|
||||
out.push(i);
|
||||
|
@ -21,7 +21,7 @@ export function deepCopy<T = Object>(obj: Object): T {
|
|||
if (obj[i] instanceof Array) {
|
||||
out[i] = deepCopyArray(obj[i]);
|
||||
} else {
|
||||
out[i] = deepCopy<Object>(obj[i]);
|
||||
out[i] = deepCopy(obj[i]);
|
||||
}
|
||||
} else {
|
||||
out[i] = obj[i];
|
||||
|
|
|
@ -77,6 +77,9 @@ export class Editor extends Element {
|
|||
case "js":
|
||||
session.setMode("ace/mode/javascript");
|
||||
break;
|
||||
case "ts":
|
||||
session.setMode("ace/mode/typescript");
|
||||
break;
|
||||
case "json":
|
||||
session.setMode("ace/mode/json");
|
||||
break;
|
||||
|
|
|
@ -26,6 +26,7 @@ export class Popup extends Element {
|
|||
super();
|
||||
this.options = { ...defaultOpts, ...options };
|
||||
const el = create("div", ["popup"], text);
|
||||
el.style.display = "none";
|
||||
if (this.options.dots) el.classList.add("dots");
|
||||
parent.append(el);
|
||||
this.element = el;
|
||||
|
|
|
@ -8,161 +8,85 @@ import { Bar } from "../ui/dragBar";
|
|||
import { Popup } from "../ui/popup";
|
||||
import { formatWithCursor } from "prettier";
|
||||
import * as vm from "../libs/run";
|
||||
import * as files from "../libs/files";
|
||||
import { basename, extname } from "path";
|
||||
import * as ts from "../libs/compile";
|
||||
import event from "../libs/events";
|
||||
import { paths, options, reload } from "../libs/options";
|
||||
import { rebind } from "./scripts/editorKeybinds";
|
||||
import { FileHandler } from "./scripts/fileHandler";
|
||||
|
||||
const main = document.getElementById("main");
|
||||
const [edit, bar, consol] = [
|
||||
new Editor(main),
|
||||
new Bar(main, "leftRight"),
|
||||
new Console(main),
|
||||
];
|
||||
rebind(edit);
|
||||
|
||||
const reloadPopup = new Popup(document.body, "reloaded!", { fade: 2000 });
|
||||
const edit = new Editor(main);
|
||||
const bar = new Bar(main, "leftRight");
|
||||
const consol = new Console(main);
|
||||
const reloadPopup = new Popup(document.body, "reloaded!", { fade: 1000 });
|
||||
|
||||
bar.element.style.gridArea = "resize";
|
||||
rebind(edit);
|
||||
|
||||
let filePath = null,
|
||||
ext = "js",
|
||||
updated = false;
|
||||
const files = new FileHandler(edit);
|
||||
const ev = {
|
||||
showFile: event("showFile"),
|
||||
openedConfig: event("warn.config"),
|
||||
reload: event("reload", true),
|
||||
open: event("file.open"),
|
||||
};
|
||||
|
||||
edit.listen("showSettingsMenu", "ctrl-,", () => {
|
||||
openPath(paths.config);
|
||||
ev.openedConfig.addListener(() => {
|
||||
consol.createAppender(true, "#e6e155")("you are editing a config file");
|
||||
});
|
||||
|
||||
const shouldReload = event("shouldReload");
|
||||
event("reload").addListener(() => {
|
||||
ev.reload.addListener(() => {
|
||||
reloadPopup.show();
|
||||
reload();
|
||||
rebind(edit);
|
||||
edit.listen("showSettingsMenu", options.keybinds.files.config, () => {
|
||||
files.openPath(paths.config);
|
||||
});
|
||||
});
|
||||
|
||||
ev.open.addListener(() => {
|
||||
files.updated = false;
|
||||
updateTitle();
|
||||
|
||||
// ace editor bug
|
||||
window.blur();
|
||||
window.focus();
|
||||
});
|
||||
|
||||
edit.editor.session.on("change", () => {
|
||||
if (filePath === null) {
|
||||
files.saveSketch(edit.editor.session.getValue());
|
||||
} else {
|
||||
files.backup(edit.editor.session.getValue());
|
||||
}
|
||||
updated = true;
|
||||
files.backup();
|
||||
files.updated = true;
|
||||
updateTitle();
|
||||
});
|
||||
|
||||
// let reopenIndex = 0,
|
||||
// reopenTimeout = null;
|
||||
|
||||
// TODO: make file management less awful
|
||||
function postOpen(newPath: string): void {
|
||||
queueMicrotask(() => {
|
||||
updated = false;
|
||||
updateTitle();
|
||||
});
|
||||
filePath = newPath;
|
||||
ext = extname(newPath || ".js").replace(/^\./, "");
|
||||
if (newPath) edit.editor.session.setValue(files.openFile(newPath));
|
||||
edit.mode(ext);
|
||||
if (newPath === paths.config)
|
||||
consol.createAppender(true, "#e6e155")("you are editing a config file");
|
||||
}
|
||||
|
||||
function confirmOpen() {
|
||||
if (updated && filePath && !window.confirm("your file isnt saved, continue?"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function save(): void {
|
||||
if (!filePath) filePath = files.fileSave();
|
||||
if (!filePath) return;
|
||||
updated = false;
|
||||
updateTitle();
|
||||
files.saveFile(filePath, edit.editor.session.getValue());
|
||||
if (filePath === paths.config) shouldReload.fire();
|
||||
files.touch(filePath);
|
||||
}
|
||||
|
||||
function saveAs(): void {
|
||||
const newPath = files.fileSave();
|
||||
if (!filePath) return;
|
||||
updated = false;
|
||||
updateTitle();
|
||||
files.saveFile(newPath, edit.editor.session.getValue());
|
||||
}
|
||||
|
||||
function open(): void {
|
||||
if (!confirmOpen()) return;
|
||||
// reopenIndex--;
|
||||
// if (reopenIndex < 0) {
|
||||
// reopenIndex = -1;
|
||||
// openPath((files.fileOpen() || [])[0], true);
|
||||
// return;
|
||||
// }
|
||||
// const newPath = options.internal.recent[reopenIndex];
|
||||
// if (newPath) {
|
||||
// files.openFileKeepPath(newPath);
|
||||
// postOpen(newPath);
|
||||
// clearTimeout(reopenTimeout);
|
||||
// reopenTimeout = setTimeout(() => {
|
||||
// files.recentFile(newPath);
|
||||
// reopenIndex = -1;
|
||||
// }, 2000);
|
||||
// return;
|
||||
// }
|
||||
openPath((files.fileOpen() || [])[0], true);
|
||||
}
|
||||
|
||||
function openPath(newPath: string, force = false): void {
|
||||
if (!newPath) return;
|
||||
if (!force && !confirmOpen()) return;
|
||||
postOpen(newPath);
|
||||
if (filePath !== newPath) files.touch(newPath);
|
||||
}
|
||||
|
||||
// TODO: cyclic open/close
|
||||
function reopen(): void {
|
||||
// reopenIndex++;
|
||||
// if (reopenIndex >= options.maxRecent) {
|
||||
// reopenIndex = options.maxRecent - 1;
|
||||
// }
|
||||
// const newPath = options.internal.recent[reopenIndex];
|
||||
// if (newPath) {
|
||||
// files.openFileKeepPath(newPath);
|
||||
// postOpen(newPath);
|
||||
// clearTimeout(reopenTimeout);
|
||||
// reopenTimeout = setTimeout(() => {
|
||||
// reopenIndex = -1;
|
||||
// files.recentFile(newPath);
|
||||
// }, 2000);
|
||||
// }
|
||||
const newPath = options.internal.recent[filePath ? 1 : 0];
|
||||
if (newPath) openPath(newPath);
|
||||
}
|
||||
|
||||
function openSketch(): void {
|
||||
if (!confirmOpen()) return;
|
||||
edit.editor.session.setValue(files.loadSketch());
|
||||
postOpen(null);
|
||||
}
|
||||
|
||||
function format(): void {
|
||||
if (ext === "txt") return;
|
||||
if (!["js", "ts", "json", "md"].includes(files.ext)) return;
|
||||
const editor = edit.editor;
|
||||
const cursor = editor.selection.getCursor();
|
||||
const index = editor.session.doc.positionToIndex(cursor);
|
||||
const value = editor.session.getValue();
|
||||
let parser = null;
|
||||
switch (files.ext) {
|
||||
case "js":
|
||||
parser = "babel";
|
||||
break;
|
||||
case "ts":
|
||||
parser = "babel-typescript";
|
||||
break;
|
||||
case "json":
|
||||
case "md":
|
||||
parser = files.ext;
|
||||
break;
|
||||
}
|
||||
if (!parser) return;
|
||||
const result = formatWithCursor(value, {
|
||||
cursorOffset: index,
|
||||
parser: ext === "js" ? "babel" : ext,
|
||||
parser,
|
||||
});
|
||||
editor.session.doc.setValue(result.formatted);
|
||||
const position = editor.session.doc.indexToPosition(result.cursorOffset);
|
||||
editor.clearSelection();
|
||||
editor.moveCursorToPosition(position);
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
bar.dragged = function (e): void {
|
||||
|
@ -190,9 +114,8 @@ consol.run = (code): void => {
|
|||
};
|
||||
|
||||
function run(): void {
|
||||
const code = edit.editor.session.getValue();
|
||||
console.log(ext);
|
||||
switch (ext) {
|
||||
const code = files.value;
|
||||
switch (files.ext) {
|
||||
case "js":
|
||||
const res = vm.run(code);
|
||||
consol[res.err ? "error" : "log"](res.value);
|
||||
|
@ -210,13 +133,13 @@ function run(): void {
|
|||
ipcRenderer.on("menu", (e, message) => {
|
||||
switch (message) {
|
||||
case "save":
|
||||
save();
|
||||
files.save();
|
||||
break;
|
||||
case "saveAs":
|
||||
saveAs();
|
||||
files.saveAs();
|
||||
break;
|
||||
case "open":
|
||||
open();
|
||||
files.open();
|
||||
break;
|
||||
case "format":
|
||||
format();
|
||||
|
@ -228,27 +151,29 @@ ipcRenderer.on("menu", (e, message) => {
|
|||
consol.clear();
|
||||
break;
|
||||
case "reopen":
|
||||
reopen();
|
||||
// reopen();
|
||||
break;
|
||||
case "sketch":
|
||||
openSketch();
|
||||
files.openPath(paths.sketch);
|
||||
break;
|
||||
case "showFile":
|
||||
if (filePath) ipcRenderer.send("showFile", filePath);
|
||||
if (files.path) ev.showFile.fire(files.path);
|
||||
break;
|
||||
}
|
||||
updateTitle();
|
||||
});
|
||||
|
||||
ipcRenderer.on("openRecent", (e, path) => {
|
||||
openPath(path);
|
||||
files.openPath(path);
|
||||
});
|
||||
|
||||
function updateTitle(): void {
|
||||
let title = "jside";
|
||||
if (filePath) {
|
||||
title += " - " + basename(filePath) + (updated ? "*" : "");
|
||||
if (files.path) {
|
||||
title += " - " + files.name;
|
||||
if (files.updated) title += "*";
|
||||
}
|
||||
document.title = title;
|
||||
}
|
||||
|
||||
edit.editor.session.doc.setValue(files.loadSketch());
|
||||
files.openPath(paths.sketch);
|
||||
|
|
|
@ -1,94 +1,139 @@
|
|||
// TODO: clean up and use this file instead
|
||||
/*
|
||||
function postOpen(newPath: string): void {
|
||||
queueMicrotask(() => {
|
||||
updated = false;
|
||||
updateTitle();
|
||||
});
|
||||
filePath = newPath;
|
||||
ext = extname(newPath || ".js").replace(/^\./, "");
|
||||
if (newPath) edit.editor.session.setValue(files.openFile(newPath));
|
||||
edit.mode(ext);
|
||||
if (newPath === paths.config)
|
||||
consol.raw("you are editing a config file", "warn");
|
||||
}
|
||||
import * as files from "../../libs/files";
|
||||
import { basename, extname } from "path";
|
||||
import { paths, options } from "../../libs/options";
|
||||
import event from "../../libs/events";
|
||||
import { Editor } from "../../ui/editor";
|
||||
|
||||
function confirmOpen() {
|
||||
if (updated && filePath && !window.confirm("your file isnt saved, continue?"))
|
||||
const ev = {
|
||||
open: event("file.open"),
|
||||
save: event("file.save"),
|
||||
saveAs: event("file.saveAs"),
|
||||
reload: event("reload.force"),
|
||||
openedConfig: event("warn.config"),
|
||||
};
|
||||
|
||||
export class FileHandler {
|
||||
path: string = null;
|
||||
edit: Editor = null;
|
||||
updated = false;
|
||||
|
||||
constructor(edit: Editor) {
|
||||
this.edit = edit;
|
||||
}
|
||||
|
||||
get ext() {
|
||||
return extname(this.path).replace(/^\./, "");
|
||||
}
|
||||
|
||||
get name() {
|
||||
return basename(this.path);
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.edit.editor.session.getValue();
|
||||
}
|
||||
|
||||
set value(val) {
|
||||
this.edit.editor.session.setValue(val);
|
||||
}
|
||||
|
||||
confirm() {
|
||||
if (!this.updated) return true;
|
||||
if (!this.path) return true;
|
||||
if (window.confirm("your file isnt saved, continue?")) return true;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function save(): void {
|
||||
if (!filePath) filePath = files.fileSave();
|
||||
if (!filePath) return;
|
||||
updated = false;
|
||||
updateTitle();
|
||||
files.saveFile(filePath, edit.editor.session.getValue());
|
||||
if (filePath === paths.config) shouldReload.fire();
|
||||
if(filePath !== newPath) files.recentFile(newPath);
|
||||
}
|
||||
openPath(path: string): void {
|
||||
if (!path) return;
|
||||
if (!this.confirm()) return;
|
||||
this.path = path;
|
||||
if (path) this.value = files.openFile(path);
|
||||
this.edit.mode(this.ext || "js");
|
||||
if (path === paths.config) ev.openedConfig.fire();
|
||||
files.touch(path);
|
||||
this.updated = false;
|
||||
ev.open.fire(path);
|
||||
}
|
||||
|
||||
function saveAs(): void {
|
||||
const newPath = files.fileSave();
|
||||
if (!filePath) return;
|
||||
updated = false;
|
||||
updateTitle();
|
||||
files.saveFile(newPath, edit.editor.session.getValue());
|
||||
}
|
||||
open(): void {
|
||||
if (!this.confirm()) return;
|
||||
const oldPath = this.path;
|
||||
this.path = null;
|
||||
this.openPath(files.fileOpen());
|
||||
if (!this.path) this.path = oldPath;
|
||||
}
|
||||
|
||||
function open(): void {
|
||||
if (!confirmOpen()) return;
|
||||
// reopenIndex--;
|
||||
// if (reopenIndex < 0) {
|
||||
// reopenIndex = -1;
|
||||
// openPath((files.fileOpen() || [])[0], true);
|
||||
// return;
|
||||
// }
|
||||
// const newPath = options.internal.recent[reopenIndex];
|
||||
// if (newPath) {
|
||||
// files.openFileKeepPath(newPath);
|
||||
// postOpen(newPath);
|
||||
// clearTimeout(reopenTimeout);
|
||||
// reopenTimeout = setTimeout(() => {
|
||||
// files.recentFile(newPath);
|
||||
// reopenIndex = -1;
|
||||
// }, 2000);
|
||||
// return;
|
||||
// }
|
||||
openPath((files.fileOpen() || [])[0], true);
|
||||
}
|
||||
save(): void {
|
||||
if (!this.path) this.path = files.fileSave();
|
||||
if (!this.path) return;
|
||||
this.updated = false;
|
||||
files.saveFile(this.path, this.value);
|
||||
files.touch(this.path);
|
||||
if (this.path === paths.config) ev.reload.fire();
|
||||
ev.save.fire(this.path);
|
||||
}
|
||||
|
||||
function openPath(newPath: string, force = false): void {
|
||||
if (!newPath) return;
|
||||
if (!force && !confirmOpen()) return;
|
||||
postOpen(newPath);
|
||||
if(filePath !== newPath) files.recentFile(newPath);
|
||||
saveAs(): void {
|
||||
const oldPath = this.path;
|
||||
this.path = null;
|
||||
this.save();
|
||||
if (!this.path) {
|
||||
this.path = oldPath;
|
||||
} else {
|
||||
ev.saveAs.fire(this.path);
|
||||
}
|
||||
}
|
||||
|
||||
backup() {
|
||||
const path = this.path ? options.backup : paths.sketch;
|
||||
files.saveFile(path, this.value);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: cyclic open/close
|
||||
function reopen(): void {
|
||||
// reopenIndex++;
|
||||
// if (reopenIndex >= options.maxRecent) {
|
||||
// reopenIndex = options.maxRecent - 1;
|
||||
// }
|
||||
// const newPath = options.internal.recent[reopenIndex];
|
||||
// if (newPath) {
|
||||
// files.openFileKeepPath(newPath);
|
||||
// postOpen(newPath);
|
||||
// clearTimeout(reopenTimeout);
|
||||
// reopenTimeout = setTimeout(() => {
|
||||
// reopenIndex = -1;
|
||||
// files.recentFile(newPath);
|
||||
// }, 2000);
|
||||
// }
|
||||
const newPath = options.internal.recent[filePath ? 1 : 0];
|
||||
if (newPath) openPath(newPath);
|
||||
}
|
||||
// TODO: also ~~fix~~ re-add reopen, it's buggy
|
||||
|
||||
function openSketch(): void {
|
||||
if (!confirmOpen()) return;
|
||||
edit.editor.session.setValue(files.loadSketch());
|
||||
postOpen(null);
|
||||
}
|
||||
*/
|
||||
// let reopenIndex = 0,
|
||||
// reopenTimeout = null;
|
||||
|
||||
// function open(): void {
|
||||
// if (!confirmOpen()) return;
|
||||
// reopenIndex--;
|
||||
// if (reopenIndex < 0) {
|
||||
// reopenIndex = -1;
|
||||
// openPath((files.fileOpen() || [])[0], true);
|
||||
// return;
|
||||
// }
|
||||
// const newPath = options.internal.recent[reopenIndex];
|
||||
// if (newPath) {
|
||||
// files.openFileKeepPath(newPath);
|
||||
// postOpen(newPath);
|
||||
// clearTimeout(reopenTimeout);
|
||||
// reopenTimeout = setTimeout(() => {
|
||||
// files.recentFile(newPath);
|
||||
// reopenIndex = -1;
|
||||
// }, 2000);
|
||||
// return;
|
||||
// }
|
||||
// openPath((files.fileOpen() || [])[0], true);
|
||||
// }
|
||||
|
||||
// function reopen(): void {
|
||||
// reopenIndex++;
|
||||
// if (reopenIndex >= options.maxRecent) {
|
||||
// reopenIndex = options.maxRecent - 1;
|
||||
// }
|
||||
// const newPath = options.internal.recent[reopenIndex];
|
||||
// if (newPath) {
|
||||
// files.openFileKeepPath(newPath);
|
||||
// postOpen(newPath);
|
||||
// clearTimeout(reopenTimeout);
|
||||
// reopenTimeout = setTimeout(() => {
|
||||
// reopenIndex = -1;
|
||||
// files.recentFile(newPath);
|
||||
// }, 2000);
|
||||
// }
|
||||
// const newPath = options.internal.recent[filePath ? 1 : 0];
|
||||
// if (newPath) openPath(newPath);
|
||||
// }
|
||||
|
|
Reference in a new issue