From fc7b728fe4edf5afe77ff791763a87f1e04f0486 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Fri, 30 May 2025 00:30:54 -0500 Subject: [PATCH] refactoring LSP to its own service --- .../common/services/editor/editors.service.ts | 17 +++- src/app/common/services/lsp.service.ts | 77 +++++++++++++++++++ .../ace => common/services}/webworker.ts | 0 src/app/editor/ace/ace-editor.component.ts | 65 +++------------- src/app/editor/editors.component.ts | 40 ++++------ 5 files changed, 117 insertions(+), 82 deletions(-) create mode 100644 src/app/common/services/lsp.service.ts rename src/app/{editor/ace => common/services}/webworker.ts (100%) diff --git a/src/app/common/services/editor/editors.service.ts b/src/app/common/services/editor/editors.service.ts index 87bd0f7..cdfd8cf 100644 --- a/src/app/common/services/editor/editors.service.ts +++ b/src/app/common/services/editor/editors.service.ts @@ -4,19 +4,30 @@ import { BehaviorSubject, ReplaySubject, Observable } from 'rxjs'; import { ServiceMessage } from '../../types/service-message.type'; + @Injectable({ providedIn: 'root' }) export class EditorsService { - private dataSubject: ReplaySubject = new ReplaySubject(1); + private messageSubject: ReplaySubject = new ReplaySubject(1); + private activationSubject: ReplaySubject = new ReplaySubject(1); constructor() {} setData(data: ServiceMessage): void { - this.dataSubject.next(data); + this.messageSubject.next(data); } getData$(): Observable { - return this.dataSubject.asObservable(); + return this.messageSubject.asObservable(); } + + setActiveEditor(data: string): void { + this.activationSubject.next(data); + } + + newActiveEditor$(): Observable { + return this.activationSubject.asObservable(); + } + } \ No newline at end of file diff --git a/src/app/common/services/lsp.service.ts b/src/app/common/services/lsp.service.ts new file mode 100644 index 0000000..6e159c7 --- /dev/null +++ b/src/app/common/services/lsp.service.ts @@ -0,0 +1,77 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, ReplaySubject, Observable } from 'rxjs'; + +import { AceLanguageClient, LanguageClientConfig } from 'ace-linters/build/ace-language-client'; +import { LanguageProvider } from "ace-linters"; + + + +@Injectable({ + providedIn: 'root' +}) +export class LSPService { + lspConfigData!: {}; + languageProvider!: any; + + constructor() { + this.loadLSPService(); + } + + private loadLSPService() { + this.getLspConfigData().then((lspConfigData: string) => { + this.lspConfigData = JSON.parse(lspConfigData); + + if (this.lspConfigData["message"]) { + console.log( + "Warning: LSP this.lspConfigData is a 'message'", + this.lspConfigData + ); + + this.lspConfigData = {}; + } + }).then(() => { + this.loadLanguageProviders(); + }); + } + + public registerEditor(editor: any): void { + this.languageProvider.registerEditor(editor); + } + + private getLspConfigData(): Promise { + return window.fs.getLspConfigData(); + } + + private loadLanguageProviders(): void { + this.languageProvider = this.getLanguageProviderWithClientServers(); +// this.languageProvider = this.getLanguageProviderWithWebWorker(); + } + + private getLanguageProviderWithClientServers() { + let _initializationOptions = {}; + + if (Object.keys(this.lspConfigData).length !== 0) { +// _initializationOptions = this.lspConfigData[ this.editor.session.getMode() ]["initialization-options"]; + _initializationOptions = this.lspConfigData[ "python" ]["initialization-options"]; + } + + let servers: LanguageClientConfig[] = [ + { + module: () => import("ace-linters/build/language-client"), + modes: "python", + type: "socket", + socket: new WebSocket("ws://127.0.0.1:9999/python"), +// socket: new WebSocket("ws://127.0.0.1:9999/?name=pylsp"), + initializationOptions: _initializationOptions + } + ]; + + return AceLanguageClient.for(servers); + } + + + private getLanguageProviderWithWebWorker() { + let worker = new Worker(new URL('./webworker.js', import.meta.url)); + return LanguageProvider.create(worker); + } +} \ No newline at end of file diff --git a/src/app/editor/ace/webworker.ts b/src/app/common/services/webworker.ts similarity index 100% rename from src/app/editor/ace/webworker.ts rename to src/app/common/services/webworker.ts diff --git a/src/app/editor/ace/ace-editor.component.ts b/src/app/editor/ace/ace-editor.component.ts index fbdecd8..9cb7630 100644 --- a/src/app/editor/ace/ace-editor.component.ts +++ b/src/app/editor/ace/ace-editor.component.ts @@ -1,18 +1,15 @@ import { Component, ElementRef, ViewChild, Input } from '@angular/core'; -import { AceLanguageClient, LanguageClientConfig } from 'ace-linters/build/ace-language-client'; - // Import Ace and its modes/themes so that `ace` global is defined import * as ace from 'ace-builds/src-noconflict/ace'; import 'ace-builds/src-noconflict/theme-one_dark'; import "ace-builds/src-noconflict/ext-language_tools"; -import { LanguageProvider } from "ace-linters"; - import { EditorSettings } from "../../common/configs/editor.config"; +import { ServiceMessage } from '../../common/types/service-message.type'; import { EditorsService } from '../../common/services/editor/editors.service'; -import { ServiceMessage } from '../../common/types/service-message.type'; +import { LSPService } from '../../common/services/lsp.service'; @@ -24,8 +21,7 @@ import { ServiceMessage } from '../../common/types/service-message.type'; templateUrl: './ace-editor.component.html', styleUrl: './ace-editor.component.css', host: { - 'class': 'col', - '(click)': 'onClick($event)' + 'class': 'col' } }) export class AceEditorComponent { @@ -34,16 +30,16 @@ export class AceEditorComponent { @ViewChild('editor') editorElm!: ElementRef; editor!: any; uuid!: string; - lspConfigData!: {}; - constructor(private editorsService: EditorsService) { - } + constructor( + private editorsService: EditorsService, + private lspService: LSPService + ) {} public ngAfterViewInit(): void { this.loadAce(); - this.loadLanguageProviders(); } public loadAce(): void { @@ -52,52 +48,15 @@ export class AceEditorComponent { this.editor = ace.edit( this.editorElm.nativeElement ); this.editor.setOptions( this.editorSettings.CONFIG ); // this.editor.commands.addCommands( this.editorSettings.KEYBINDINGS ); - } - protected onClick(event: any) { - let message = new ServiceMessage(); - message.action = "set-editor"; - message.message = this.uuid; - message.uuid = this.uuid; - - this.editorsService.setData(message); - } - - public loadLanguageProviders(): void { - let languageProvider = this.getLanguageProviderWithClientServers(); -// let languageProvider = this.getLanguageProviderWithWebWorker(); - languageProvider.registerEditor(this.editor); + this.editor.on("focus", () => { + this.editorsService.setActiveEditor(this.uuid); + }); } - - - public getLanguageProviderWithClientServers() { - let _initializationOptions = {}; - - if (Object.keys(this.lspConfigData).length !== 0) { -// _initializationOptions = this.lspConfigData[ this.editor.session.getMode() ]["initialization-options"]; - _initializationOptions = this.lspConfigData[ "python" ]["initialization-options"]; - } - - let servers: LanguageClientConfig[] = [ - { - module: () => import("ace-linters/build/language-client"), - modes: "python", - type: "socket", - socket: new WebSocket("ws://127.0.0.1:9999/python"), -// socket: new WebSocket("ws://127.0.0.1:9999/?name=pylsp"), - initializationOptions: _initializationOptions - } - ]; - - return AceLanguageClient.for(servers); - } - - - public getLanguageProviderWithWebWorker() { - let worker = new Worker(new URL('./webworker.js', import.meta.url)); - return LanguageProvider.create(worker); + public registerEditorToLSP() { + this.lspService.registerEditor(this.editor); } } \ No newline at end of file diff --git a/src/app/editor/editors.component.ts b/src/app/editor/editors.component.ts index fc302ea..f3b56db 100644 --- a/src/app/editor/editors.component.ts +++ b/src/app/editor/editors.component.ts @@ -50,28 +50,19 @@ export class EditorsComponent { public ngAfterViewInit(): void { - this.editorsService.getData$().pipe( + this.loadSubscribers(); + + let editor = this.createEditor(); + this.activeEditor = editor.instance.uuid; + this.createEditor(); + } + + loadSubscribers() { + this.editorsService.newActiveEditor$().pipe( takeUntil(this.unsubscribe) - ).subscribe((data: ServiceMessage) => { - if (data.action === "set-editor") - this.activeEditor = data.uuid; + ).subscribe((uuid: string) => { + this.activeEditor = uuid; }); - - this.getLspConfigData().then((lspConfigData: string) => { - this.lspConfigData = JSON.parse(lspConfigData); - - if (this.lspConfigData["message"]) { - console.log( - "Warning: LSP this.lspConfigData is a 'message'", - this.lspConfigData - ); - this.lspConfigData = {}; - } - - let editor = this.createEditor(); - this.activeEditor = editor.instance.uuid; - this.createEditor(); - }) } ngOnDestroy() { @@ -79,15 +70,10 @@ export class EditorsComponent { this.unsubscribe.complete(); } - private getLspConfigData(): Promise { - return window.fs.getLspConfigData(); - } - private createEditor() { const component = this.containerRef.createComponent(AceEditorComponent); component.instance.editorSettings = this.editorSettings; component.instance.uuid = uuid.v4(); - component.instance.lspConfigData = this.lspConfigData; this.editors.set(component.instance.uuid, component) return component; @@ -97,8 +83,10 @@ export class EditorsComponent { this.loadFilesList(event).then((session: EditSession | undefined | null) => { if ( !session ) return; - let editor = this.editors.get(this.activeEditor)?.instance.editor; + let editorComponent = this.editors.get(this.activeEditor)?.instance; + let editor = editorComponent.editor; editor?.setSession(session); + // editorComponent.registerEditorToLSP(); }); }