Wiring of info bar
This commit is contained in:
parent
dbbc6deaae
commit
0675985a5e
@ -1,4 +1,5 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
|
<info-bar></info-bar>
|
||||||
<tabs></tabs>
|
<tabs></tabs>
|
||||||
<editors></editors>
|
<editors></editors>
|
||||||
</div>
|
</div>
|
@ -1,6 +1,7 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
|
|
||||||
|
import { InfoBarComponent } from './editor/info-bar/info-bar.component';
|
||||||
import { TabsComponent } from './editor/tabs/tabs.component';
|
import { TabsComponent } from './editor/tabs/tabs.component';
|
||||||
import { EditorsComponent } from './editor/editors.component';
|
import { EditorsComponent } from './editor/editors.component';
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ import { EditorsComponent } from './editor/editors.component';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
imports: [
|
imports: [
|
||||||
|
InfoBarComponent,
|
||||||
TabsComponent,
|
TabsComponent,
|
||||||
EditorsComponent
|
EditorsComponent
|
||||||
],
|
],
|
||||||
|
61
src/app/common/services/editor/info-bar/info-bar.service.ts
Normal file
61
src/app/common/services/editor/info-bar/info-bar.service.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { BehaviorSubject, ReplaySubject, Observable } from 'rxjs';
|
||||||
|
|
||||||
|
import { ServiceMessage } from '../../../types/service-message.type';
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class InfoBarService {
|
||||||
|
private dataSubject: ReplaySubject<ServiceMessage> = new ReplaySubject<ServiceMessage>(1);
|
||||||
|
private fpathSubject: ReplaySubject<string> = new ReplaySubject<string>(1);
|
||||||
|
private cursorPosSubject: ReplaySubject<any> = new ReplaySubject<any>(1);
|
||||||
|
private encodeingSubject: ReplaySubject<string> = new ReplaySubject<string>(1);
|
||||||
|
private ftypeSubject: ReplaySubject<string> = new ReplaySubject<string>(1);
|
||||||
|
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
|
||||||
|
setData(data: ServiceMessage): void {
|
||||||
|
this.dataSubject.next(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
getData$(): Observable<ServiceMessage> {
|
||||||
|
return this.dataSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
setInfoBarFPath(data: string): void {
|
||||||
|
this.fpathSubject.next(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateInfoBarFPath$(): Observable<string> {
|
||||||
|
return this.fpathSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
setInfoBarCursorPos(data: any): void {
|
||||||
|
this.cursorPosSubject.next(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateInfoBarCursorPos$(): Observable<any> {
|
||||||
|
return this.cursorPosSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
setInfoBarEncodeing(data: string): void {
|
||||||
|
this.encodeingSubject.next(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateInfoBarEncodeing$(): Observable<string> {
|
||||||
|
return this.encodeingSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
setInfoBarFType(data: string): void {
|
||||||
|
this.ftypeSubject.next(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateInfoBarFType$(): Observable<string> {
|
||||||
|
return this.ftypeSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -33,7 +33,7 @@ export class AceEditorBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected search() {
|
protected search() {
|
||||||
console.log(this.editor.getSession()["$modeId"])
|
console.log(this.editor.session.getMode()["$id"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected openFiles() {
|
protected openFiles() {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from "@angular/core";
|
||||||
|
|
||||||
// Import Ace and its modes/themes so that `ace` global is defined
|
// Import Ace and its modes/themes so that `ace` global is defined
|
||||||
import * as ace from 'ace-builds/src-noconflict/ace';
|
import * as ace from "ace-builds/src-noconflict/ace";
|
||||||
import 'ace-builds/src-noconflict/theme-one_dark';
|
import "ace-builds/src-noconflict/theme-one_dark";
|
||||||
|
import "ace-builds/src-noconflict/theme-dracula";
|
||||||
import "ace-builds/src-noconflict/ext-language_tools";
|
import "ace-builds/src-noconflict/ext-language_tools";
|
||||||
|
|
||||||
|
import { InfoBarService } from '../../common/services/editor/info-bar/info-bar.service';
|
||||||
import { EditorsService } from '../../common/services/editor/editors.service';
|
import { EditorsService } from '../../common/services/editor/editors.service';
|
||||||
import { LSPService } from '../../common/services/lsp.service';
|
import { LSPService } from '../../common/services/lsp.service';
|
||||||
|
|
||||||
@ -27,6 +29,7 @@ export class AceEditorComponent extends AceEditorBase {
|
|||||||
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private infoBarService: InfoBarService,
|
||||||
private editorsService: EditorsService,
|
private editorsService: EditorsService,
|
||||||
private lspService: LSPService
|
private lspService: LSPService
|
||||||
) {
|
) {
|
||||||
@ -62,14 +65,14 @@ export class AceEditorComponent extends AceEditorBase {
|
|||||||
exec: () => {
|
exec: () => {
|
||||||
this.movelinesUp();
|
this.movelinesUp();
|
||||||
},
|
},
|
||||||
readOnly: true
|
readOnly: false
|
||||||
}, {
|
}, {
|
||||||
name: "movelinesDown",
|
name: "movelinesDown",
|
||||||
bindKey: {win: "ctrl-down", mac: "ctrl-down"},
|
bindKey: {win: "ctrl-down", mac: "ctrl-down"},
|
||||||
exec: () => {
|
exec: () => {
|
||||||
this.movelinesDown();
|
this.movelinesDown();
|
||||||
},
|
},
|
||||||
readOnly: true
|
readOnly: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "duplicateLines",
|
name: "duplicateLines",
|
||||||
@ -77,7 +80,7 @@ export class AceEditorComponent extends AceEditorBase {
|
|||||||
exec: () => {
|
exec: () => {
|
||||||
this.duplicateLines();
|
this.duplicateLines();
|
||||||
},
|
},
|
||||||
readOnly: true
|
readOnly: false
|
||||||
}, {
|
}, {
|
||||||
name: "zoomIn",
|
name: "zoomIn",
|
||||||
bindKey: {win: "ctrl-=", mac: "ctrl-="},
|
bindKey: {win: "ctrl-=", mac: "ctrl-="},
|
||||||
@ -98,61 +101,95 @@ export class AceEditorComponent extends AceEditorBase {
|
|||||||
exec: () => {
|
exec: () => {
|
||||||
this.cutToBuffer();
|
this.cutToBuffer();
|
||||||
},
|
},
|
||||||
readOnly: true
|
readOnly: false
|
||||||
}, {
|
}, {
|
||||||
name: "pasteCutBuffer",
|
name: "pasteCutBuffer",
|
||||||
bindKey: {win: "ctrl-u", mac: "ctrl-u"},
|
bindKey: {win: "ctrl-u", mac: "ctrl-u"},
|
||||||
exec: () => {
|
exec: () => {
|
||||||
this.pasteCutBuffer();
|
this.pasteCutBuffer();
|
||||||
},
|
},
|
||||||
readOnly: true
|
readOnly: false
|
||||||
}, {
|
}, {
|
||||||
name: "destroySession",
|
name: "destroySession",
|
||||||
bindKey: {win: "ctrl-w", mac: "ctrl-w"},
|
bindKey: {win: "ctrl-w", mac: "ctrl-w"},
|
||||||
exec: () => {
|
exec: () => {
|
||||||
this.editor.session.destroy();
|
this.editor.session.destroy();
|
||||||
},
|
},
|
||||||
readOnly: true
|
readOnly: false
|
||||||
}, {
|
}, {
|
||||||
name: "openFiles",
|
name: "openFiles",
|
||||||
bindKey: {win: "ctrl-o", mac: "ctrl-o"},
|
bindKey: {win: "ctrl-o", mac: "ctrl-o"},
|
||||||
exec: () => {
|
exec: () => {
|
||||||
this.openFiles();
|
this.openFiles();
|
||||||
},
|
},
|
||||||
readOnly: true
|
readOnly: false
|
||||||
}, {
|
}, {
|
||||||
name: "saveFile",
|
name: "saveFile",
|
||||||
bindKey: {win: "ctrl-s", mac: "ctrl-s"},
|
bindKey: {win: "ctrl-s", mac: "ctrl-s"},
|
||||||
exec: () => {
|
exec: () => {
|
||||||
this.saveFile();
|
this.saveFile();
|
||||||
},
|
},
|
||||||
readOnly: true
|
readOnly: false
|
||||||
}, {
|
}, {
|
||||||
name: "saveFileAs",
|
name: "saveFileAs",
|
||||||
bindKey: {win: "ctrl-shift-s", mac: "ctrl-shift-s"},
|
bindKey: {win: "ctrl-shift-s", mac: "ctrl-shift-s"},
|
||||||
exec: () => {
|
exec: () => {
|
||||||
this.saveFileAs();
|
this.saveFileAs();
|
||||||
},
|
},
|
||||||
readOnly: true
|
readOnly: false
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Note: https://github.com/mkslanc/ace-linters/blob/c286d85c558530aa1b0597d02108bc782abd4736/packages/ace-linters/src/language-provider.ts#L277
|
|
||||||
// found on focus ^ might have other signals we can watch like session being set, etc.
|
// Note: https://ajaxorg.github.io/ace-api-docs/interfaces/ace.Ace.EditorEvents.html
|
||||||
|
this.editor.on("click", () => {
|
||||||
|
this.updateInfoBar();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.editor.on("input", () => {
|
||||||
|
this.updateInfoBar();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.editor.on("keyboardActivity", (e) => {
|
||||||
|
switch(e.command.name) {
|
||||||
|
case "golineup":
|
||||||
|
case "golinedown":
|
||||||
|
case "gotoleft":
|
||||||
|
case "gotoright":
|
||||||
|
this.infoBarService.setInfoBarCursorPos(
|
||||||
|
this.editor.getCursorPosition()
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.editor.on("focus", () => {
|
this.editor.on("focus", () => {
|
||||||
this.editorsService.setActiveEditor(this.uuid);
|
this.editorsService.setActiveEditor(this.uuid);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.editor.on("changeSession", (session) => {
|
this.editor.on("changeSession", (session) => {
|
||||||
this.lspService.registerEditor(this.editor);
|
this.lspService.registerEditor(this.editor);
|
||||||
|
this.updateInfoBar();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public updateInfoBar() {
|
||||||
|
this.infoBarService.setInfoBarFPath(this.activeFile?.path)
|
||||||
|
this.infoBarService.setInfoBarCursorPos(
|
||||||
|
this.editor.getCursorPosition()
|
||||||
|
);
|
||||||
|
this.infoBarService.setInfoBarFType(
|
||||||
|
this.editor.session.getMode()["$id"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public newBuffer() {
|
public newBuffer() {
|
||||||
let buffer = ace.createEditSession([""]);
|
let buffer = ace.createEditSession([""]);
|
||||||
this.editor.setSession(buffer);
|
this.editor.setSession(buffer);
|
||||||
this.activeFile = null;
|
this.activeFile = null;
|
||||||
|
this.updateInfoBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,3 +1,3 @@
|
|||||||
.dropzone {
|
.dropzone {
|
||||||
height: 95vh;
|
height: 92vh;
|
||||||
}
|
}
|
||||||
|
0
src/app/editor/info-bar/info-bar.component.css
Normal file
0
src/app/editor/info-bar/info-bar.component.css
Normal file
15
src/app/editor/info-bar/info-bar.component.html
Normal file
15
src/app/editor/info-bar/info-bar.component.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<div class="col col-md-6" title="{{fpath || '...'}}">
|
||||||
|
{{path || "..."}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col col-md-2">
|
||||||
|
{{cursorPos || "1:1"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col col-md-2">
|
||||||
|
{{encodeing || "utf-8"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col col-md-2">
|
||||||
|
{{ftype || "text"}}
|
||||||
|
</div>
|
76
src/app/editor/info-bar/info-bar.component.ts
Normal file
76
src/app/editor/info-bar/info-bar.component.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
|
||||||
|
import { InfoBarService } from '../../common/services/editor/info-bar/info-bar.service';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'info-bar',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
],
|
||||||
|
templateUrl: './info-bar.component.html',
|
||||||
|
styleUrl: './info-bar.component.css',
|
||||||
|
host: {
|
||||||
|
'class': 'row info-bar'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export class InfoBarComponent {
|
||||||
|
private unsubscribe = new Subject<void>();
|
||||||
|
|
||||||
|
fpath: string = "";
|
||||||
|
path: string = "";
|
||||||
|
cursorPos: string = "";
|
||||||
|
encodeing: string = "";
|
||||||
|
ftype: string = "";
|
||||||
|
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private infoBarService: InfoBarService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
|
||||||
|
public ngAfterViewInit(): void {
|
||||||
|
this.loadSubscribers();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
loadSubscribers() {
|
||||||
|
|
||||||
|
this.infoBarService.updateInfoBarFPath$().pipe(
|
||||||
|
takeUntil(this.unsubscribe)
|
||||||
|
).subscribe((fpath: string) => {
|
||||||
|
this.fpath = fpath;
|
||||||
|
let _path = fpath;
|
||||||
|
|
||||||
|
if (fpath?.length > 67) {
|
||||||
|
_path = "..." + fpath.slice(fpath.length - 67, fpath.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.path = _path;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.infoBarService.updateInfoBarCursorPos$().pipe(
|
||||||
|
takeUntil(this.unsubscribe)
|
||||||
|
).subscribe((cursorPos: any) => {
|
||||||
|
this.cursorPos = `${cursorPos.row + 1}:${cursorPos.column}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.infoBarService.updateInfoBarEncodeing$().pipe(
|
||||||
|
takeUntil(this.unsubscribe)
|
||||||
|
).subscribe((encodeing: string) => {
|
||||||
|
this.encodeing = encodeing;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.infoBarService.updateInfoBarFType$().pipe(
|
||||||
|
takeUntil(this.unsubscribe)
|
||||||
|
).subscribe((ftype: string) => {
|
||||||
|
let mode = ftype.split("/");
|
||||||
|
this.ftype = mode[ mode.length - 1 ];
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,22 @@
|
|||||||
.tab,
|
.tab {
|
||||||
.title,
|
display: flex;
|
||||||
.close-button {
|
overflow: auto;
|
||||||
color: rgba(255, 255, 255, 0.64);
|
float: left;
|
||||||
|
margin-right: 2em;
|
||||||
|
font-size: 0.2em;
|
||||||
|
|
||||||
|
border-top-style: solid;
|
||||||
|
border-top-color: #ffffff64;
|
||||||
|
border-top-width: 2px;
|
||||||
|
|
||||||
|
border-left-style: solid;
|
||||||
|
border-left-color: #ffffff64;
|
||||||
|
border-left-width: 2px;
|
||||||
|
|
||||||
|
border-right-style: solid;
|
||||||
|
border-right-color: #ffffff64;
|
||||||
|
border-right-width: 2px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab:hover {
|
.tab:hover {
|
||||||
|
@ -21,7 +21,7 @@ import { ServiceMessage } from '../../common/types/service-message.type';
|
|||||||
templateUrl: './tabs.component.html',
|
templateUrl: './tabs.component.html',
|
||||||
styleUrl: './tabs.component.css',
|
styleUrl: './tabs.component.css',
|
||||||
host: {
|
host: {
|
||||||
'class': 'tabs scroller'
|
'class': 'row tabs scroller'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
export class TabsComponent {
|
export class TabsComponent {
|
||||||
|
@ -12,3 +12,8 @@
|
|||||||
.ace_autocomplete {
|
.ace_autocomplete {
|
||||||
background-color: #25282c !important;
|
background-color: #25282c !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ace_sb-v,
|
||||||
|
.ace_sb-h {
|
||||||
|
width: 0.8em !important;
|
||||||
|
}
|
@ -19,34 +19,19 @@ body {
|
|||||||
|
|
||||||
/* CLASSES */
|
/* CLASSES */
|
||||||
|
|
||||||
|
.info-bar {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: rgba(255, 255, 255, 0.84);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.tabs {
|
.tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
padding-bottom: 0.4em;
|
padding-bottom: 0.4em;
|
||||||
padding-top: 0.4em;
|
padding-top: 0.4em;
|
||||||
}
|
color: rgba(255, 255, 255, 0.64);
|
||||||
|
|
||||||
|
|
||||||
.tab {
|
|
||||||
display: flex;
|
|
||||||
overflow: auto;
|
|
||||||
float: left;
|
|
||||||
margin-right: 2em;
|
|
||||||
font-size: 0.2em;
|
|
||||||
|
|
||||||
border-top-style: solid;
|
|
||||||
border-top-color: #ffffff64;
|
|
||||||
border-top-width: 2px;
|
|
||||||
|
|
||||||
border-left-style: solid;
|
|
||||||
border-left-color: #ffffff64;
|
|
||||||
border-left-width: 2px;
|
|
||||||
|
|
||||||
border-right-style: solid;
|
|
||||||
border-right-color: #ffffff64;
|
|
||||||
border-right-width: 2px;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user