diff --git a/newton/fs.js b/newton/fs.js index e704cb0..1718c9c 100644 --- a/newton/fs.js +++ b/newton/fs.js @@ -89,14 +89,14 @@ const saveFile = (fpath, content) => { }); } -const saveFileAs = (content) => { - dialog.showSaveDialog().then((response) => { +const saveFileAs = () => { + return dialog.showSaveDialog().then((response) => { if (response.canceled) { console.debug("You didn't save the file"); return; } - saveFile(response.filePath, content); + return response.filePath; }); } diff --git a/newton/preload.js b/newton/preload.js index 5af2649..bb6b9b9 100644 --- a/newton/preload.js +++ b/newton/preload.js @@ -18,7 +18,7 @@ contextBridge.exposeInMainWorld('fs', { getFileContents: (path) => ipcRenderer.invoke("getFileContents", path), openFiles: (startPath) => ipcRenderer.invoke("openFiles", startPath), saveFile: (path, content) => ipcRenderer.invoke("saveFile", path, content), - saveFileAs: (content) => ipcRenderer.invoke("saveFileAs", content), + saveFileAs: () => ipcRenderer.invoke("saveFileAs"), closeFile: (path) => ipcRenderer.invoke("closeFile", path), getPathForFile: (file) => webUtils.getPathForFile(file), onLoadFiles: (callback) => ipcRenderer.on('load-files', (_event, paths) => callback(paths)), diff --git a/src/app/common/services/editor/files.service.ts b/src/app/common/services/editor/files.service.ts index f16d6a2..908239d 100644 --- a/src/app/common/services/editor/files.service.ts +++ b/src/app/common/services/editor/files.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { ReplaySubject, Observable } from 'rxjs'; import { EditSession } from 'ace-builds'; @@ -17,12 +17,12 @@ import { ServiceMessage } from '../../types/service-message.type'; export class FilesService { private messageSubject: ReplaySubject = new ReplaySubject(1); + private tabsService: TabsService = inject(TabsService); + files: Map; - constructor( - private tabsService: TabsService, - ) { + constructor() { this.files = new Map(); } @@ -64,15 +64,17 @@ export class FilesService { return files[ files.length - 1 ]; } - async addFile(path: string, file: NewtonFile): Promise { + async addFile(path: string, file: NewtonFile, loadFileContents: boolean = true, data: string = ""): Promise { try { let pathParts = path.split("/"); file.fname = pathParts[ pathParts.length - 1 ]; file.path = path; file.hash = btoa(file.path); - let data = await window.fs.getFileContents(file.path); - file.session = new EditSession(data); + if (loadFileContents) + data = await window.fs.getFileContents(file.path); + + file.session = new EditSession(data); file.session.setMode( getModeForPath( file.path ).mode ); diff --git a/src/app/common/types/file.type.ts b/src/app/common/types/file.type.ts index aa167f0..ed157e4 100644 --- a/src/app/common/types/file.type.ts +++ b/src/app/common/types/file.type.ts @@ -2,8 +2,8 @@ import { EditSession } from 'ace-builds'; export interface NewtonFile extends File { - fname: string, - path: string, - hash: string, - session: EditSession + fname?: string, + path?: string, + hash?: string, + session?: EditSession, } \ No newline at end of file diff --git a/src/app/editor/editors.component.ts b/src/app/editor/editors.component.ts index 2d511b9..fd57d58 100644 --- a/src/app/editor/editors.component.ts +++ b/src/app/editor/editors.component.ts @@ -1,4 +1,4 @@ -import { Component, ElementRef, ViewChild, TemplateRef, ComponentRef, ViewContainerRef } from '@angular/core'; +import { Component, ViewChild, ViewContainerRef, inject } from '@angular/core'; import { Subject, takeUntil } from 'rxjs'; import { NewtonEditorComponent } from "./newton-editor/newton-editor.component"; @@ -27,17 +27,17 @@ import { ServiceMessage } from '../common/types/service-message.type'; } }) export class EditorsComponent { - private unsubscribe = new Subject(); + private unsubscribe: Subject = new Subject(); + + private editorsService: EditorsService = inject(EditorsService); + private tabsService: TabsService = inject(TabsService); + private filesService: FilesService = inject(FilesService); @ViewChild('containerRef', {read: ViewContainerRef}) containerRef!: ViewContainerRef; activeEditor!: string; - constructor( - private editorsService: EditorsService, - private tabsService: TabsService, - private filesService: FilesService - ) { + constructor() { } diff --git a/src/app/editor/info-bar/info-bar.component.ts b/src/app/editor/info-bar/info-bar.component.ts index 3fc6a31..2c9cf3e 100644 --- a/src/app/editor/info-bar/info-bar.component.ts +++ b/src/app/editor/info-bar/info-bar.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, inject } from '@angular/core'; import { Subject, takeUntil } from 'rxjs'; import { InfoBarService } from '../../common/services/editor/info-bar/info-bar.service'; @@ -17,7 +17,9 @@ import { InfoBarService } from '../../common/services/editor/info-bar/info-bar.s } }) export class InfoBarComponent { - private unsubscribe = new Subject(); + private unsubscribe: Subject = new Subject(); + + private infoBarService: InfoBarService = inject(InfoBarService); fpath: string = ""; path: string = ""; @@ -26,9 +28,7 @@ export class InfoBarComponent { ftype: string = ""; - constructor( - private infoBarService: InfoBarService - ) {} + constructor() {} public ngAfterViewInit(): void { diff --git a/src/app/editor/modals/files-modal.component.ts b/src/app/editor/modals/files-modal.component.ts index 9ef0190..9e580c0 100644 --- a/src/app/editor/modals/files-modal.component.ts +++ b/src/app/editor/modals/files-modal.component.ts @@ -1,4 +1,4 @@ -import { Component } from "@angular/core"; +import { Component, inject } from "@angular/core"; import { CommonModule } from "@angular/common"; import { Subject, takeUntil } from 'rxjs'; @@ -25,16 +25,16 @@ import { ServiceMessage } from '../../common/types/service-message.type'; } }) export class FilesModalComponent { - private unsubscribe = new Subject(); + private unsubscribe: Subject = new Subject(); + + private filesModalService: FilesModalService = inject(FilesModalService); + private tabsService: TabsService = inject(TabsService); filesModal!: bootstrap.Modal; files: any[] = []; - constructor( - private filesModalService: FilesModalService, - private tabsService: TabsService - ) { + constructor() { } diff --git a/src/app/editor/newton-editor/newton-editor.base.ts b/src/app/editor/newton-editor/newton-editor.base.ts index 0d8825b..d7819a4 100644 --- a/src/app/editor/newton-editor/newton-editor.base.ts +++ b/src/app/editor/newton-editor/newton-editor.base.ts @@ -1,31 +1,80 @@ -import { Directive, ElementRef, Input, ViewChild } from '@angular/core'; +import { Directive, ElementRef, Input, ViewChild, inject } from '@angular/core'; import * as uuid from 'uuid'; +import { InfoBarService } from '../../common/services/editor/info-bar/info-bar.service'; +import { FilesModalService } from '../../common/services/editor/modals/files-modal.service'; +import { LSPService } from '../../common/services/lsp.service'; +import { TabsService } from '../../common/services/editor/tabs/tabs.service'; +import { EditorsService } from '../../common/services/editor/editors.service'; +import { FilesService } from '../../common/services/editor/files.service'; + import { EditorSettings } from "../../common/configs/editor.config"; import { NewtonFile } from '../../common/types/file.type'; +import { ServiceMessage } from '../../common/types/service-message.type'; + @Directive() export class NewtonEditorBase { + public uuid: string = uuid.v4();; + public isDefault: boolean = false; + public leftSiblingUUID!: string; + public rightSiblingUUID!: string; + + protected infoBarService: InfoBarService = inject(InfoBarService); + protected filesModalService: FilesModalService = inject(FilesModalService); + protected lspService: LSPService = inject(LSPService); + protected tabsService: TabsService = inject(TabsService); + protected editorsService: EditorsService = inject(EditorsService); + protected filesService: FilesService = inject(FilesService); + @ViewChild('editor') editorElm!: ElementRef; @Input() editorSettings!: typeof EditorSettings; - editor!: any; - uuid!: string; - leftSiblingUUID!: string; - rightSiblingUUID!: string; - cutBuffer: string = ""; - timerId: number = -1; - activeFile!: NewtonFile; - isDefault: boolean = false; + + public editor!: any; + public activeFile!: NewtonFile; + + public cutBuffer: string = ""; + public timerId: number = -1; - constructor( - ) { - this.uuid = uuid.v4(); + constructor() { } + public selectLeftEditor() { + let message = new ServiceMessage(); + message.action = "select-left-editor"; + message.editorUUID = this.uuid; + + this.editorsService.sendMessage(message); + } + + public selectRightEditor() { + let message = new ServiceMessage(); + message.action = "select-right-editor"; + message.editorUUID = this.uuid; + + this.editorsService.sendMessage(message); + } + + public moveSessionLeft() { + let message = new ServiceMessage(); + message.action = "move-session-left"; + message.editorUUID = this.uuid; + + this.editorsService.sendMessage(message); + } + + public moveSessionRight() { + let message = new ServiceMessage(); + message.action = "move-session-right"; + message.editorUUID = this.uuid; + + this.editorsService.sendMessage(message); + } + public addActiveStyling() { this.editorElm.nativeElement.classList.add("active-editor") } @@ -46,61 +95,43 @@ export class NewtonEditorBase { this.editor.showKeyboardShortcuts(); } - protected search() { + public search() { console.log(this.editor.session.getMode()["$id"]); } - protected destroySession() { + public destroySession() { this.editor.session.destroy(); } - protected quit() { - window.main.quit(); - } - - protected toggleFullScreen() { + public toggleFullScreen() { window.main.toggleFullScreen(); } - protected openFiles() { - let startDir = ""; - if (this.activeFile) { - let pathParts = this.activeFile.path.split("/"); - pathParts.pop(); - startDir = pathParts.join( '/' ); - } - - window.fs.openFiles(startDir); - } - - protected saveFile() { - if (!this.activeFile) { - this.saveFileAs(); - return; - } - - const text = this.activeFile.session.getValue(); - window.fs.saveFile(this.activeFile.path, text); - } - - protected saveFileAs() { - const text = this.editor.session.getValue(); - window.fs.saveFileAs(text); - } - - protected zoomIn() { + public zoomIn() { this.editor.setFontSize( parseInt(this.editor.getFontSize()) + 1 ) } - protected zoomOut() { + public zoomOut() { this.editor.setFontSize( parseInt(this.editor.getFontSize()) - 1 ) } - protected cutText() { + public movelinesUp() { + this.editor.execCommand("movelinesup"); + } + + public movelinesDown() { + this.editor.execCommand("movelinesdown"); + } + + public duplicateLines() { + this.editor.execCommand("copylinesdown"); + } + + public cutText() { let cutText = this.editor.getSelectedText(); this.editor.remove(); navigator.clipboard.writeText(cutText).catch(() => { @@ -108,54 +139,30 @@ export class NewtonEditorBase { }); } - protected copyText() { + public copyText() { let copyText = this.editor.getSelectedText(); navigator.clipboard.writeText(copyText).catch(() => { console.error("Unable to copy text..."); }); } - protected pasteText() { + public pasteText() { navigator.clipboard.readText().then((pasteText) => { this.editor.insert(pasteText, true); }); } - protected movelinesUp() { - this.editor.execCommand("movelinesup"); + protected updateInfoBar() { + this.infoBarService.setInfoBarFPath(this.activeFile?.path) + this.infoBarService.setInfoBarCursorPos( + this.editor.getCursorPosition() + ); + this.infoBarService.setInfoBarFType( + this.editor.session.getMode()["$id"] + ); } - protected movelinesDown() { - this.editor.execCommand("movelinesdown"); + private quit() { + window.main.quit(); } - - protected duplicateLines() { - this.editor.execCommand("copylinesdown"); - } - - protected cutToBuffer() { - if (this.timerId) { clearTimeout(this.timerId); } - - const cursorPosition = this.editor.getCursorPosition(); - let lineText = this.editor.session.getLine(cursorPosition.row); - this.cutBuffer += `${lineText}\n`; - - this.editor.session.removeFullLines(cursorPosition.row, cursorPosition.row) - this.setBufferClearTimeout(); - } - - protected pasteCutBuffer() { - if (this.timerId) { clearTimeout(this.timerId); } - - this.editor.insert(this.cutBuffer, true); - this.setBufferClearTimeout(); - } - - private setBufferClearTimeout(timeout: number = 5000) { - this.timerId = setTimeout(() => { - this.cutBuffer = ""; - this.timerId = -1; - }, timeout); - } - } \ No newline at end of file diff --git a/src/app/editor/newton-editor/newton-editor.component.ts b/src/app/editor/newton-editor/newton-editor.component.ts index bb7fd5e..a721772 100644 --- a/src/app/editor/newton-editor/newton-editor.component.ts +++ b/src/app/editor/newton-editor/newton-editor.component.ts @@ -9,14 +9,9 @@ import "ace-builds/src-noconflict/ext-language_tools"; import "ace-builds/src-noconflict/theme-one_dark"; import "ace-builds/src-noconflict/theme-dracula"; -import { InfoBarService } from '../../common/services/editor/info-bar/info-bar.service'; -import { FilesModalService } from '../../common/services/editor/modals/files-modal.service'; -import { LSPService } from '../../common/services/lsp.service'; -import { TabsService } from '../../common/services/editor/tabs/tabs.service'; -import { EditorsService } from '../../common/services/editor/editors.service'; - import { NewtonEditorBase } from './newton-editor.base'; +import { NewtonFile } from '../../common/types/file.type'; import { ServiceMessage } from '../../common/types/service-message.type'; @@ -35,13 +30,7 @@ import { ServiceMessage } from '../../common/types/service-message.type'; export class NewtonEditorComponent extends NewtonEditorBase { - constructor( - private infoBarService: InfoBarService, - private editorsService: EditorsService, - private lspService: LSPService, - private tabsService: TabsService, - private filesModalService: FilesModalService - ) { + constructor() { super(); } @@ -141,15 +130,6 @@ export class NewtonEditorComponent extends NewtonEditorBase { }); } - public updateInfoBar() { - this.infoBarService.setInfoBarFPath(this.activeFile?.path) - this.infoBarService.setInfoBarCursorPos( - this.editor.getCursorPosition() - ); - this.infoBarService.setInfoBarFType( - this.editor.session.getMode()["$id"] - ); - } public newBuffer() { let buffer = ace.createEditSession([""]); @@ -158,36 +138,74 @@ export class NewtonEditorComponent extends NewtonEditorBase { this.updateInfoBar(); } - public selectLeftEditor() { - let message = new ServiceMessage(); - message.action = "select-left-editor"; - message.editorUUID = this.uuid; + protected openFiles() { + let startDir = ""; + if (this.activeFile) { + let pathParts = this.activeFile.path.split("/"); + pathParts.pop(); + startDir = pathParts.join( '/' ); + } - this.editorsService.sendMessage(message); + window.fs.openFiles(startDir); } - public selectRightEditor() { - let message = new ServiceMessage(); - message.action = "select-right-editor"; - message.editorUUID = this.uuid; + protected saveFile() { + if (!this.activeFile) { + this.saveFileAs(); + return; + } - this.editorsService.sendMessage(message); + const text = this.activeFile.session.getValue(); + window.fs.saveFile(this.activeFile.path, text); } - public moveSessionLeft() { - let message = new ServiceMessage(); - message.action = "move-session-left"; - message.editorUUID = this.uuid; + protected saveFileAs() { + window.fs.saveFileAs().then((path: string) => { + if (!path) return; - this.editorsService.sendMessage(message); + let file: NewtonFile = new File([""], path, { + type: "text/plain", + }); + + const text = this.editor.session.getValue(); + window.fs.saveFile(path, text); + this.filesService.addFile( + path, + file, + false, + text + ).then(() => { + this.activeFile = this.filesService.get(path); + this.editor.setSession(this.activeFile.session); + this.filesService.addTab(this.activeFile); + }); + + }); } - public moveSessionRight() { - let message = new ServiceMessage(); - message.action = "move-session-right"; - message.editorUUID = this.uuid; + protected cutToBuffer() { + if (this.timerId) { clearTimeout(this.timerId); } - this.editorsService.sendMessage(message); + const cursorPosition = this.editor.getCursorPosition(); + let lineText = this.editor.session.getLine(cursorPosition.row); + this.cutBuffer += `${lineText}\n`; + + this.editor.session.removeFullLines(cursorPosition.row, cursorPosition.row) + this.setBufferClearTimeout(); + } + + protected pasteCutBuffer() { + if (this.timerId) { clearTimeout(this.timerId); } + + this.editor.insert(this.cutBuffer, true); + this.setBufferClearTimeout(); + } + + private setBufferClearTimeout(timeout: number = 5000) { + this.timerId = setTimeout(() => { + this.cutBuffer = ""; + this.timerId = -1; + }, timeout); } } \ No newline at end of file diff --git a/src/app/editor/tabs/tabs.component.ts b/src/app/editor/tabs/tabs.component.ts index 3a41154..561bb7e 100644 --- a/src/app/editor/tabs/tabs.component.ts +++ b/src/app/editor/tabs/tabs.component.ts @@ -1,4 +1,4 @@ -import { Component, ChangeDetectorRef } from '@angular/core'; +import { Component, ChangeDetectorRef, inject } from '@angular/core'; import { CommonModule } from '@angular/common'; import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop'; import { Subject, takeUntil } from 'rxjs'; @@ -25,18 +25,18 @@ import { ServiceMessage } from '../../common/types/service-message.type'; } }) export class TabsComponent { - private unsubscribe = new Subject(); + private unsubscribe: Subject = new Subject(); + + private editorsService: EditorsService = inject(EditorsService); + private tabsService: TabsService = inject(TabsService); + private changeDetectorRef: ChangeDetectorRef = inject(ChangeDetectorRef); activeTab!: string; - tabs: any[] = []; + tabs: any[] = []; newIndex: number = -1; - constructor( - private editorsService: EditorsService, - private tabsService: TabsService, - private changeDetectorRef: ChangeDetectorRef - ) { + constructor() { } public ngAfterViewInit(): void { diff --git a/src/polyfills.ts b/src/polyfills.ts index ffeaf57..7b409b5 100644 --- a/src/polyfills.ts +++ b/src/polyfills.ts @@ -28,7 +28,7 @@ declare global { getFileContents: (arg0: any) => Promise, openFiles: (arg0) => Promise, saveFile: (arg0: any, arg1: any) => Promise, - saveFileAs: (arg0: any) => Promise, + saveFileAs: () => Promise, closeFile: (arg0: any) => Promise, getPathForFile: any, onLoadFiles: (arg0: any) => Promise,