Constructed menu; moved files to sub newton folder; WIP save system added

This commit is contained in:
2025-06-01 13:49:18 -05:00
parent ae43722881
commit 82e2afa601
10 changed files with 241 additions and 123 deletions

79
newton/app.js Normal file
View File

@@ -0,0 +1,79 @@
const { BrowserWindow } = require('electron');
const path = require('node:path');
const { menu } = require('./menu');
const { newtonFs } = require('./fs');
const BASE_PATH = '../dist/app';
const ICON_PATH = `${BASE_PATH}/resources/newton.png`;
let args = [];
// Note: https://tinydew4.gitbooks.io/electron/content/api/browser-window.html
const createWindow = (startType = "build", debug = false, args = []) => {
this.args = args;
const win = new BrowserWindow({
title: "Newton",
width: 800,
height: 600,
minWidth: 800,
minHeight: 600,
show: false,
transparent: true,
icon: path.join(__dirname, ICON_PATH),
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
enableRemoteModule: false,
plugins: true,
webSecurity: true,
sandbox: true,
}
});
win.once('ready-to-show', () => {
win.show()
});
menu.load(win);
// win.setAutoHideMenuBar(true)
if (debug == true) {
win.webContents.openDevTools();
}
if (startType === "build") {
win.loadFile(
path.join(__dirname, `${BASE_PATH}/index.html`)
);
}
if (startType === "ng-serve") {
win.loadURL('http://localhost:4200');
}
// const child = new BrowserWindow({parent: win, modal: true, show: false})
// child.loadFile(
// path.join(__dirname, `${BASE_PATH}/index.html`)
// );
// child.once('ready-to-show', () => {
// child.show()
// });
return win;
}
module.exports = {
newton: {
createWindow: createWindow,
fs: newtonFs,
}
};

96
newton/fs.js Normal file
View File

@@ -0,0 +1,96 @@
const { dialog } = require('electron');
const path = require('node:path');
const fs = require('node:fs');
const os = require('os')
const BASE_PATH = '../dist/app';
const LSP_CONFIG_PATH = `${BASE_PATH}/resources/lsp-servers-config.json`;
let window = null;
const getFileContents = (_path, useRelativePath = false) => {
console.log(`Getting Contents For: ${_path}`);
try {
if (!useRelativePath) {
return fs.readFileSync(_path, 'utf8');
} else {
return fs.readFileSync(path.join(__dirname, _path), 'utf8');
}
} catch(err) {
return `{"message": {"type": "error", "text": "Error: Could not read ${_path}"}}`;
}
}
const getLspConfigData = () => {
const config = getFileContents(LSP_CONFIG_PATH, true);
return config.replaceAll("{user.home}", os.homedir());
}
const saveFile = (fpath, content) => {
fs.writeFile(fpath, content, (err) => {
if (!err) return
console.error("An error ocurred writing to the file " + err.message)
});
}
const saveFileAs = (content) => {
dialog.showSaveDialog().then((response) => {
if (response.canceled) {
console.log("You didn't save the file");
return;
}
saveFile(response.filePath, content);
});
}
const openFiles = (startPath) => {
dialog.showOpenDialog(
{
title: "Open File(s):",
defaultPath: (startPath) ? startPath : os.homedir(),
filters: [
{"c": [".h", ".c"]},
{"cpp": ["hpp", "cpp"]},
{"html": ["js", "css", "scss", "html", "ts"]},
{"java": ["java"]},
{"python": ["py", "pyc"]},
{"rust": ["r", "rc"]},
{"text": ["txt", "log", "md"]},
{"go": ["go"]},
],
properties: [
'openFile',
'multiSelections'
]
}
).then((response) => {
if (response.canceled) {
console.log("Canceled file open request...");
return;
}
window.webContents.send('load-files', response.filePaths);
});
}
const setWindow = (win) => {
window = win;
}
module.exports = {
newtonFs: {
openFiles: openFiles,
saveFile: saveFile,
saveFileAs: saveFileAs,
getFileContents: getFileContents,
getLspConfigData: getLspConfigData,
setWindow: setWindow
}
};

90
newton/main.js Normal file
View File

@@ -0,0 +1,90 @@
try {
require('electron-reloader')(module)
} catch {}
const { app, ipcMain } = require('electron');
const { newton } = require('./app');
let startType = "";
let isDebug = false;
let args = [];
const loadArgs = () => {
console.log("\n\nStart KArgs:");
const hasStartAs = app.commandLine.hasSwitch("start-as");
if (hasStartAs) {
startType = app.commandLine.getSwitchValue("start-as");
console.log("Has start-as switch...");
console.log(startType);
}
const hasDebug = app.commandLine.hasSwitch("app-debug");
if (hasDebug) {
isDebug = app.commandLine.getSwitchValue("app-debug");
console.log("Has app-debug switch...");
console.log(isDebug);
}
console.log("\n\nStart VArgs:");
args = process.argv.slice(4); // remove up to --start-as ...
args.forEach((val, index, array) => {
console.log(index + ': ' + val);
console.log();
});
}
const loadHandlers = () => {
ipcMain.handle('getLspConfigData', (eve) => newton.fs.getLspConfigData());
ipcMain.handle('getFileContents', (eve, file) => newton.fs.getFileContents(file));
ipcMain.handle('openFiles', (eve, startPath) => newton.fs.openFiles(startPath));
ipcMain.handle('saveFile', (eve, path, content) => newton.fs.saveFile(path, content));
ipcMain.handle('saveFileAs', (eve, content) => newton.fs.saveFileAs(content));
}
app.whenReady().then(() => {
loadArgs();
loadHandlers();
let window = newton.createWindow(startType, isDebug, args);
newton.fs.setWindow(window);
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
newton.createWindow(startType, isDebug, args);
};
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
};
})
process.on('uncaughtException', (error) => {
if (error.message != null) {
console.log(error.message);
}
if (error.stack != null) {
console.log(error.stack);
}
});
process.on('unhandledRejection', function(error = {}) {
if (error.message != null) {
console.log(error.message);
}
if (error.stack != null) {
console.log(error.stack);
}
});

104
newton/menu.js Normal file
View File

@@ -0,0 +1,104 @@
const { Menu } = require('electron');
const load = (win) => {
const menu = Menu.buildFromTemplate([
{
label: "File",
submenu: [
{
label: 'New',
click: () => win.webContents.send('menu-actions', "new-file")
}, {
label: 'Open',
click: () => win.webContents.send('menu-actions', "open-files")
}, {
label: 'save',
click: () => win.webContents.send('menu-actions', "save-file")
}, {
label: 'Save As',
click: () => win.webContents.send('menu-actions', "save-file-as")
}, {
label: 'Terminal',
click: () => {}
}
]
}, {
label: "Edit",
submenu: [
{
label: 'Undo',
click: () => win.webContents.send('menu-actions', "undo")
}, {
label: 'Redo',
click: () => win.webContents.send('menu-actions', "redo")
}, {
label: 'Cut',
click: () => win.webContents.send('menu-actions', "cut")
}, {
label: 'Copy',
click: () => win.webContents.send('menu-actions', "copy")
}, {
label: 'Paste',
click: () => win.webContents.send('menu-actions', "paste")
}, {
label: 'Delete',
click: () => win.webContents.send('menu-actions', "delete")
}, {
label: 'Select All',
click: () => win.webContents.send('menu-actions', "select-all")
}, {
label: 'Indent',
click: () => win.webContents.send('menu-actions', "blockindent")
}, {
label: 'De-Indent',
click: () => win.webContents.send('menu-actions', "blockoutdent")
}, {
label: 'To Upper Case',
click: () => win.webContents.send('menu-actions', "touppercase")
}, {
label: 'To Lower Case',
click: () => win.webContents.send('menu-actions', "tolowercase")
},
]
}, {
label: "View",
submenu: [
{
label: 'Zoom In',
click: () => win.webContents.send('menu-actions', "zoom-in")
}, {
label: 'Zoom Out',
click: () => win.webContents.send('menu-actions', "zoom-out")
}, {
label: 'Toggle Full Screen',
click: () => { win.setFullScreen(!win.fullScreen) }
}, {
label: 'Toggle Developer Tools',
click: () => win.webContents.toggleDevTools()
}
]
}, {
label: "Help",
submenu: [
{
label: 'About',
click: () => win.webContents.send('menu-actions', "show-about")
}
]
},
]);
Menu.setApplicationMenu(menu)
}
module.exports = {
menu: {
load: load
}
};

21
newton/preload.js Normal file
View File

@@ -0,0 +1,21 @@
const { contextBridge, ipcRenderer, webUtils } = require('electron')
contextBridge.exposeInMainWorld('electron', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron,
});
contextBridge.exposeInMainWorld('main', {
onMenuActions: (callback) => ipcRenderer.on('menu-actions', (_event, action) => callback(action)),
});
contextBridge.exposeInMainWorld('fs', {
getLspConfigData: () => ipcRenderer.invoke("getLspConfigData"),
getFileContents: (file) => ipcRenderer.invoke("getFileContents", file),
openFiles: (startPath) => ipcRenderer.invoke("openFiles", startPath),
saveFile: (path, content) => ipcRenderer.invoke("saveFile", path, content),
saveFileAs: (content) => ipcRenderer.invoke("saveFileAs", content),
getPathForFile: (file) => webUtils.getPathForFile(file),
onLoadFiles: (callback) => ipcRenderer.on('load-files', (_event, files) => callback(files)),
});