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

This commit is contained in:
itdominator 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
}
};

View File

@ -3,11 +3,9 @@ try {
} catch {} } catch {}
const { app, ipcMain } = require('electron');
const { app, ipcMain, dialog } = require('electron');
const { newton } = require('./app'); const { newton } = require('./app');
const path = require('node:path');
const fs = require('node:fs');
@ -39,45 +37,24 @@ const loadArgs = () => {
console.log(index + ': ' + val); console.log(index + ': ' + val);
console.log(); console.log();
}); });
}
const saveFile = (path, content) => {
console.log("...");
}
const saveFileAs = (content) => {
console.log(content);
dialog.showSaveDialog((fileName) => {
console.log(fileName);
if (fileName === undefined){
console.log("You didn't save the file");
return;
}
// fileName is a string that contains the path and filename created in the save file dialog.
fs.writeFile(fileName, content, (err) => {
if(err){
alert("An error ocurred creating the file "+ err.message)
}
alert("The file has been succesfully saved");
});
});
} }
const loadHandlers = () => { const loadHandlers = () => {
ipcMain.handle('getLspConfigData', (eve) => newton.getLspConfigData()); ipcMain.handle('getLspConfigData', (eve) => newton.fs.getLspConfigData());
ipcMain.handle('getFileContents', (eve, file) => newton.getFileContents(file)); ipcMain.handle('getFileContents', (eve, file) => newton.fs.getFileContents(file));
ipcMain.handle('saveFile', (eve, path, content) => saveFile(path, "Some text to save into the file")); ipcMain.handle('openFiles', (eve, startPath) => newton.fs.openFiles(startPath));
ipcMain.handle('saveFileAs', (eve, content) => saveFileAs("Some text to save into the file")); ipcMain.handle('saveFile', (eve, path, content) => newton.fs.saveFile(path, content));
ipcMain.handle('saveFileAs', (eve, content) => newton.fs.saveFileAs(content));
} }
app.whenReady().then(() => { app.whenReady().then(() => {
loadArgs(); loadArgs();
loadHandlers(); loadHandlers();
newton.createWindow(startType, isDebug, args);
let window = newton.createWindow(startType, isDebug, args);
newton.fs.setWindow(window);
}) })
app.on('activate', () => { app.on('activate', () => {

View File

@ -1,53 +1,8 @@
const { BrowserWindow, Menu } = require('electron'); const { Menu } = require('electron');
const path = require('node:path');
const fs = require('node:fs');
const os = require('os')
// const BASE_PATH = 'dist/app/browser'; const load = (win) => {
const BASE_PATH = 'dist/app';
const ICON_PATH = `${BASE_PATH}/resources/newton.png`;
const LSP_CONFIG_PATH = `${BASE_PATH}/resources/lsp-servers-config.json`;
let args = [];
const createWindow = (startType = "build", debug = false, args = []) => {
this.args = args;
const win = new BrowserWindow({
width: 800,
height: 600,
transparent: true,
icon: path.join(__dirname, ICON_PATH),
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
enableRemoteModule: false,
}
});
setupMenu(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 setupMenu = (win) => {
const menu = Menu.buildFromTemplate([ const menu = Menu.buildFromTemplate([
{ {
label: "File", label: "File",
@ -57,16 +12,16 @@ const setupMenu = (win) => {
click: () => win.webContents.send('menu-actions', "new-file") click: () => win.webContents.send('menu-actions', "new-file")
}, { }, {
label: 'Open', label: 'Open',
click: () => win.webContents.send('load-files', [path.join(__dirname, `${BASE_PATH}/index.html`)]) click: () => win.webContents.send('menu-actions', "open-files")
}, {
label: 'Terminal',
click: () => {}
}, { }, {
label: 'save', label: 'save',
click: () => win.webContents.send('menu-actions', "save-file") click: () => win.webContents.send('menu-actions', "save-file")
}, { }, {
label: 'Save As', label: 'Save As',
click: () => win.webContents.send('menu-actions', "save-file-as") click: () => win.webContents.send('menu-actions', "save-file-as")
}, {
label: 'Terminal',
click: () => {}
} }
] ]
}, { }, {
@ -140,31 +95,10 @@ const setupMenu = (win) => {
Menu.setApplicationMenu(menu) Menu.setApplicationMenu(menu)
} }
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());
}
module.exports = { module.exports = {
newton: { menu: {
createWindow: createWindow, load: load
getFileContents: getFileContents,
getLspConfigData: getLspConfigData
} }
}; };

View File

@ -13,6 +13,7 @@ contextBridge.exposeInMainWorld('main', {
contextBridge.exposeInMainWorld('fs', { contextBridge.exposeInMainWorld('fs', {
getLspConfigData: () => ipcRenderer.invoke("getLspConfigData"), getLspConfigData: () => ipcRenderer.invoke("getLspConfigData"),
getFileContents: (file) => ipcRenderer.invoke("getFileContents", file), getFileContents: (file) => ipcRenderer.invoke("getFileContents", file),
openFiles: (startPath) => ipcRenderer.invoke("openFiles", startPath),
saveFile: (path, content) => ipcRenderer.invoke("saveFile", path, content), saveFile: (path, content) => ipcRenderer.invoke("saveFile", path, content),
saveFileAs: (content) => ipcRenderer.invoke("saveFileAs", content), saveFileAs: (content) => ipcRenderer.invoke("saveFileAs", content),
getPathForFile: (file) => webUtils.getPathForFile(file), getPathForFile: (file) => webUtils.getPathForFile(file),

View File

@ -2,7 +2,7 @@
"name": "Newton Editor", "name": "Newton Editor",
"version": "0.0.1", "version": "0.0.1",
"description": "A uniquly simple quasi-IDE for hardcore developers.", "description": "A uniquly simple quasi-IDE for hardcore developers.",
"main": "main.js", "main": "newton/main.js",
"scripts": { "scripts": {
"app": "ng build --base-href ./ && electron . --trace-warnings --start-as=build", "app": "ng build --base-href ./ && electron . --trace-warnings --start-as=build",
"electron-build": "electron . --trace-warnings --start-as=build", "electron-build": "electron . --trace-warnings --start-as=build",

View File

@ -19,6 +19,7 @@ declare global {
fs: { fs: {
getLspConfigData: () => Promise<string>, getLspConfigData: () => Promise<string>,
getFileContents: (arg0: any) => Promise<string>, getFileContents: (arg0: any) => Promise<string>,
openFiles: (arg0) => Promise<string>,
saveFile: (arg0: any, arg1: any) => Promise<string>, saveFile: (arg0: any, arg1: any) => Promise<string>,
saveFileAs: (arg0: any) => Promise<string>, saveFileAs: (arg0: any) => Promise<string>,
getPathForFile: any, getPathForFile: any,

View File

@ -1,6 +1,7 @@
import { Directive, ElementRef, Input, ViewChild } from '@angular/core'; import { Directive, ElementRef, Input, ViewChild } from '@angular/core';
import { EditorSettings } from "../../common/configs/editor.config"; import { EditorSettings } from "../../common/configs/editor.config";
import { NewtonFile } from '../../common/types/file.type';
@ -12,6 +13,7 @@ export class AceEditorBase {
uuid!: string; uuid!: string;
cutBuffer: string = ""; cutBuffer: string = "";
timerId: number = -1; timerId: number = -1;
activeFile!: NewtonFile;
constructor( constructor(
@ -22,9 +24,25 @@ export class AceEditorBase {
console.log(this.editor.getSession()["$modeId"]) console.log(this.editor.getSession()["$modeId"])
} }
protected openFiles() {
let startDir = "";
if (this.activeFile) {
let pathParts = this.activeFile.path.split("/");
pathParts.pop();
startDir = pathParts.join( '/' );
}
window.fs.openFiles(startDir);
}
protected saveFile() { protected saveFile() {
const text = this.editor.session.getValue(); if (!this.activeFile) {
// window.fs.saveFile(text); this.saveFileAs();
return;
}
const text = this.activeFile.session.getValue();
window.fs.saveFile(this.activeFile.path, text);
} }
protected saveFileAs() { protected saveFileAs() {

View File

@ -109,6 +109,13 @@ export class AceEditorComponent extends AceEditorBase {
this.editor.session.destroy(); this.editor.session.destroy();
}, },
readOnly: true readOnly: true
}, {
name: "openFiles",
bindKey: {win: "ctrl-o", mac: "ctrl-o"},
exec: () => {
this.openFiles();
},
readOnly: true
}, { }, {
name: "saveFile", name: "saveFile",
bindKey: {win: "ctrl-s", mac: "ctrl-s"}, bindKey: {win: "ctrl-s", mac: "ctrl-s"},

View File

@ -75,8 +75,8 @@ export class EditorsComponent {
this.addTab(file); this.addTab(file);
} }
let session = this.files.get(paths[ paths.length - 1 ]).session; let file = this.files.get(paths[ paths.length - 1 ]);
this.setSession(session); this.setSession(file);
}); });
window.main.onMenuActions(async (action: string) => { window.main.onMenuActions(async (action: string) => {
@ -86,6 +86,9 @@ export class EditorsComponent {
switch ( action ) { switch ( action ) {
case "new-file": case "new-file":
break; break;
case "open-files":
editorComponent.openFiles();
break;
case "save-file": case "save-file":
editorComponent.saveFile(); editorComponent.saveFile();
break; break;
@ -130,23 +133,25 @@ export class EditorsComponent {
} }
protected onFileDropped(files: any) { protected onFileDropped(files: any) {
this.loadFilesList(files).then((session: EditSession | undefined | null) => { this.loadFilesList(files).then((file: NewtonFile | undefined | null) => {
this.setSession(session); this.setSession(file);
}); });
} }
private async setSession(session: EditSession | undefined | null) { private async setSession(file: NewtonFile | undefined | null) {
if ( !session ) return; if ( !file ) return;
let editorComponent = this.getActiveEditorComponent();
let editor = editorComponent.editor;
let editor = this.getActiveEditor(); editorComponent.activeFile = file;
editor?.setSession(session); editor.setSession(file.session);
} }
private getSession() { private getSession() {
let editorComponent = this.editors.get(this.activeEditor)?.instance; let editorComponent = this.editors.get(this.activeEditor)?.instance;
let editor = editorComponent.editor; let editor = editorComponent.editor;
return editor?.getSession(); return editor.getSession();
} }
private getActiveEditorComponent(): any { private getActiveEditorComponent(): any {
@ -159,7 +164,7 @@ export class EditorsComponent {
return editor; return editor;
} }
private async loadFilesList(files: Array<NewtonFile>): Promise<EditSession | undefined | null> { private async loadFilesList(files: Array<NewtonFile>): Promise<NewtonFile | undefined | null> {
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {
const file = files[i]; const file = files[i];
const path = window.fs.getPathForFile(file); const path = window.fs.getPathForFile(file);
@ -171,7 +176,7 @@ export class EditorsComponent {
this.addTab(file); this.addTab(file);
} }
return files[ files.length - 1 ].session; return files[ files.length - 1 ];
} }
private async addFile(path: string, file: NewtonFile): Promise<void> { private async addFile(path: string, file: NewtonFile): Promise<void> {