Merge branch 'monaco'

This commit is contained in:
Kristóf Tóth 2018-06-15 13:36:48 +02:00
commit 0305d73c49
13 changed files with 455 additions and 1217 deletions

View File

@ -24,8 +24,8 @@
"output": "./" "output": "./"
},{ },{
"glob": "**/*", "glob": "**/*",
"input": "node_modules/brace/", "input": "./node_modules/ngx-monaco-editor/assets/monaco",
"output": "./" "output": "./assets/monaco/"
} }
], ],
"styles": [ "styles": [

View File

@ -5,10 +5,7 @@
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve --proxy-config proxy.conf.json", "start": "ng serve --proxy-config proxy.conf.json",
"build": "ng build --prod --aot --build-optimizer", "build": "ng build --prod --aot --build-optimizer"
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
@ -23,14 +20,13 @@
"@angular/router": "^6.0.2", "@angular/router": "^6.0.2",
"@ng-bootstrap/ng-bootstrap": "^2.0.0", "@ng-bootstrap/ng-bootstrap": "^2.0.0",
"bootstrap": "^4.0.0", "bootstrap": "^4.0.0",
"brace": "^0.11.0",
"classlist.js": "^1.1.20150312", "classlist.js": "^1.1.20150312",
"core-js": "^2.5.4", "core-js": "^2.5.4",
"ng2-ace-editor": "^0.3.7", "ngx-monaco-editor": "^6.0.0",
"node-sass": "^4.7.2", "node-sass": "^4.7.2",
"rxjs": "^6.0.0", "rxjs": "^6.0.0",
"rxjs-compat": "^6.1.0", "rxjs-compat": "^6.1.0",
"rxjs-websockets": "^4.0.0", "rxjs-websockets": "^5.0.0",
"showdown": "^1.8.5", "showdown": "^1.8.5",
"xterm": "^3.1.0", "xterm": "^3.1.0",
"zone.js": "^0.8.26" "zone.js": "^0.8.26"
@ -40,21 +36,11 @@
"@angular/cli": "^6.0.3", "@angular/cli": "^6.0.3",
"@angular/compiler-cli": "^6.0.2", "@angular/compiler-cli": "^6.0.2",
"@angular/language-service": "^6.0.2", "@angular/language-service": "^6.0.2",
"@types/jasmine": "~2.8.6",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4", "@types/node": "~8.9.4",
"@types/showdown": "^1.7.2", "@types/showdown": "^1.7.2",
"codelyzer": "~4.2.1", "codelyzer": "~4.2.1",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~1.7.1",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~1.4.2",
"karma-jasmine": "~1.1.1",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.3.0",
"ts-node": "~5.0.1", "ts-node": "~5.0.1",
"tslint": "~5.9.1", "tslint": "^5.10.0",
"typescript": "~2.7.2" "typescript": "~2.7.2"
} }
} }

View File

@ -6,7 +6,6 @@ import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { AceEditorModule } from 'ng2-ace-editor';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
@ -28,6 +27,7 @@ import { DeploymentNotificationService } from './services/deployment-notificatio
import { SafePipe } from './pipes/safe.pipe'; import { SafePipe } from './pipes/safe.pipe';
import { ConsoleComponent } from './console/console.component'; import { ConsoleComponent } from './console/console.component';
import { ProcessLogService } from './services/processlog.service'; import { ProcessLogService } from './services/processlog.service';
import { MonacoEditorModule } from 'ngx-monaco-editor';
@NgModule({ @NgModule({
@ -49,8 +49,8 @@ import { ProcessLogService } from './services/processlog.service';
FormsModule, FormsModule,
HttpClientModule, HttpClientModule,
NgbModule.forRoot(), NgbModule.forRoot(),
AceEditorModule,
AppRoutingModule, AppRoutingModule,
MonacoEditorModule.forRoot()
], ],
providers: [ providers: [
MarkdownService, MarkdownService,

View File

@ -30,6 +30,8 @@ export const config = {
showDeployButton: true, showDeployButton: true,
reloadIframeOnDeploy: true, reloadIframeOnDeploy: true,
showConsoleOnDeploy: true, showConsoleOnDeploy: true,
autoDetectFileLanguage: true,
showMiniMap: false
}, },
terminal: { terminal: {
route: 'shell' route: 'shell'

View File

@ -59,7 +59,7 @@
} }
.tfw-ide { .tfw-ide {
background-color: $tao-plum-900; background-color: #1e1e1e; // vscode dark theme
} }
.tfw-sidebar { .tfw-sidebar {

View File

@ -93,8 +93,8 @@ export class DashboardComponent implements OnInit, OnDestroy {
setLayout(layout: string) { setLayout(layout: string) {
this.layout = layout; this.layout = layout;
// We need to trigger a 'resize' event manually, otherwise ace editor stays collapsed // We need to trigger a 'resize' event manually, otherwise editor stays collapsed
// Ace editors 'resize' event listener requires a parameter of force=true // editor 'resize' event listener requires a parameter of force=true
setTimeout(() => window.dispatchEvent(new Event('resize', {force: true} as any)), 0); setTimeout(() => window.dispatchEvent(new Event('resize', {force: true} as any)), 0);
} }

View File

@ -37,11 +37,8 @@
</div> </div>
</div> </div>
<div (keyup)="setCodeState(CodeState.DIRTY); setDeployButtonState(DeployButtonState.TODEPLOY); resetAutoSaveCountdown()" <ngx-monaco-editor [(ngModel)]="code"
ace-editor class="tfw-ide-editor"
[(text)]="code" (keyup)="editorWriteHanlder()"
[mode]="language" [options]="editorOptions"
[theme]="theme" ></ngx-monaco-editor>
[options]="options"
class="tfw-ace-editor">
</div>

View File

@ -9,9 +9,10 @@
grid-template-columns: 8fr 1fr; grid-template-columns: 8fr 1fr;
} }
.tfw-ace-editor { .tfw-ide-editor {
height: calc(100% - 67px); height: calc(100% - 67px);
width: 100%; width: 100%;
overflow: hidden;
} }
.btn-group { .btn-group {
@ -23,8 +24,8 @@
} }
.tfw-tab-btn { .tfw-tab-btn {
background-color: white; background-color: gray;
border: 1px solid $tao-plum-900; color: $tao-gray-600;
border-left: 0; border-left: 0;
border-right: 0; border-right: 0;
border-radius: 100px; border-radius: 100px;
@ -35,7 +36,7 @@
.active, .active,
.disabled, .disabled,
&:disabled { &:disabled {
background-color: $tao-plum-100; background-color: white;
font-weight: bolder; font-weight: bolder;
color: black; color: black;
border: 0; border: 0;

View File

@ -3,29 +3,14 @@
import { ChangeDetectorRef, Component, EventEmitter, OnInit, Output } from '@angular/core'; import { ChangeDetectorRef, Component, EventEmitter, OnInit, Output } from '@angular/core';
import * as brace from 'brace';
import 'brace/ext/modelist';
import 'brace/ext/language_tools';
import 'brace/mode/c_cpp';
import 'brace/mode/csharp';
import 'brace/mode/java';
import 'brace/mode/typescript';
import 'brace/mode/javascript';
import 'brace/mode/json';
import 'brace/mode/python';
import 'brace/mode/sql';
import 'brace/theme/cobalt';
import { IDECommand } from '../message-types/ide-command'; import { IDECommand } from '../message-types/ide-command';
import { WebSocketService } from '../services/websocket.service'; import { WebSocketService } from '../services/websocket.service';
import { ProcessManagerService } from '../services/processmanager.service'; import { ProcessManagerService } from '../services/processmanager.service';
import { DeploymentNotificationService } from '../services/deployment-notification.service'; import { DeploymentNotificationService } from '../services/deployment-notification.service';
import { config } from '../config'; import { config } from '../config';
import { CommandMessage } from '../message-types/command-message'; import { CommandMessage } from '../message-types/command-message';
import { LanguageMap } from './language-map';
const modelist = brace.acequire('ace/ext/modelist'); import { filter, first } from 'rxjs/operators';
const langTools = brace.acequire('ace/ext/language_tools');
enum DeployButtonState { enum DeployButtonState {
@ -62,20 +47,22 @@ export class IdeComponent implements OnInit {
showDeployButton: boolean = config.ide.showDeployButton; showDeployButton: boolean = config.ide.showDeployButton;
autosave = null; autosave = null;
language: string = config.ide.defaultLanguage; editorOptions = {
theme = 'cobalt'; theme: 'vs-dark',
language: config.ide.defaultLanguage,
glyphMargin: false,
minimap: {enabled: config.ide.showMiniMap}
};
@Output() newLogs = new EventEmitter<any>(); @Output() newLogs = new EventEmitter<any>();
options: any = {enableBasicAutocompletion: true, command_handlers = {
enableSnippets: true, 'reload': this.reloadHandler.bind(this),
enableLiveAutocompletion: true}; 'read': this.readHandler.bind(this),
'select': this.selectHandler.bind(this),
command_handlers = {'reload': this.reloadHandler.bind(this), 'write': this.writeHandler.bind(this),
'read': this.readHandler.bind(this), 'selectdir': this.selectdirHandler.bind(this)
'select': this.selectHandler.bind(this), };
'write': this.writeHandler.bind(this),
'selectdir': this.selectdirHandler.bind(this)};
constructor(private webSocketService: WebSocketService, constructor(private webSocketService: WebSocketService,
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
@ -85,6 +72,7 @@ export class IdeComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.webSocketService.connect(); this.webSocketService.connect();
this.subscribeWS(); this.subscribeWS();
this.subscribeFirstLanguageDetection();
this.requestCode(); this.requestCode();
this.initProcessManagerService(); this.initProcessManagerService();
this.resetAutoSaveCountdown(); this.resetAutoSaveCountdown();
@ -97,6 +85,15 @@ export class IdeComponent implements OnInit {
}); });
} }
subscribeFirstLanguageDetection() {
this.webSocketService.observeKey<CommandMessage>(this.key_id).pipe(
filter(message => message.data.command === 'read'),
first()
).subscribe(
() => this.autoDetectEditorLanguageIfEnabled(this.filename)
);
}
initProcessManagerService() { initProcessManagerService() {
this.processManagerService.init(); this.processManagerService.init();
this.processManagerService.subscribeCallback( this.processManagerService.subscribeCallback(
@ -117,7 +114,7 @@ export class IdeComponent implements OnInit {
this.processManagerService.subscribeErrorCallback( this.processManagerService.subscribeErrorCallback(
config.ide.deployProcessName, config.ide.deployProcessName,
(event) => this.setDeployButtonState(DeployButtonState.FAILED) () => this.setDeployButtonState(DeployButtonState.FAILED)
); );
} }
@ -125,12 +122,12 @@ export class IdeComponent implements OnInit {
this.filename = data.filename; this.filename = data.filename;
this.directory = data.directory; this.directory = data.directory;
this.code = (data.content != null) ? data.content : this.code; this.code = (data.content != null) ? data.content : this.code;
this.language = modelist.getModeForPath(this.filename).name;
this.files = data.files; this.files = data.files;
} }
selectHandler(data: IDECommand) { selectHandler(data: IDECommand) {
this.updateFileData(data); this.updateFileData(data);
this.autoDetectEditorLanguageIfEnabled(this.filename);
} }
reloadHandler(data: CommandMessage) { reloadHandler(data: CommandMessage) {
@ -151,6 +148,24 @@ export class IdeComponent implements OnInit {
this.updateFileData(data); this.updateFileData(data);
} }
autoDetectEditorLanguageIfEnabled(filename: string) {
if (!config.ide.autoDetectFileLanguage) {
return;
}
const extension = filename.substr(filename.lastIndexOf('.') + 1);
let language = LanguageMap[extension];
language = (language === undefined) ? 'text' : language;
this.setEditorLanguage(language);
}
setEditorLanguage(lang: string) {
this.editorOptions = Object.assign(
{},
this.editorOptions,
{ language: lang }
);
}
resetAutoSaveCountdown() { resetAutoSaveCountdown() {
if (this.autosave) { if (this.autosave) {
clearInterval(this.autosave); clearInterval(this.autosave);
@ -169,6 +184,12 @@ export class IdeComponent implements OnInit {
this.requestCode(); this.requestCode();
} }
editorWriteHanlder() {
this.setCodeState(CodeState.DIRTY);
this.setDeployButtonState(DeployButtonState.TODEPLOY);
this.resetAutoSaveCountdown();
}
setCodeState(state: CodeState) { setCodeState(state: CodeState) {
this.codeState = state; this.codeState = state;
} }

View File

@ -0,0 +1,36 @@
// Copyright (C) 2018 Avatao.com Innovative Learning Kft.
// All Rights Reserved. See LICENSE file for details.
export const LanguageMap: { [extension: string]: string; } = {
bat: 'bat',
clje: 'clojure',
coffee: 'coffee',
c: 'cpp',
h: 'cpp',
cpp: 'cpp',
hpp: 'cpp',
cs: 'csharp',
fs: 'fsharp',
go: 'go',
html: 'html',
java: 'java',
js: 'javascript',
ts: 'typescript',
lua: 'lua',
md: 'markdown',
m: 'objective-c',
mm: 'objective-c',
php: 'php',
py: 'python',
r: 'r',
rb: 'ruby',
rs: 'rust',
rlib: 'rust',
sql: 'sql',
swift: 'swift',
xml: 'xml',
yml: 'yaml',
css: 'css',
less: 'less',
scss: 'scss'
};

View File

@ -5,7 +5,7 @@ import { Injectable } from '@angular/core';
import { WebSocketService } from './websocket.service'; import { WebSocketService } from './websocket.service';
import { ProcessLogCommand } from '../message-types/process-log-command'; import { ProcessLogCommand } from '../message-types/process-log-command';
import { config } from '../config'; import { config } from '../config';
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { BehaviorSubject } from 'rxjs';
import { LogMessage } from '../message-types/log-message'; import { LogMessage } from '../message-types/log-message';
import { CommandMessage } from '../message-types/command-message'; import { CommandMessage } from '../message-types/command-message';

View File

@ -3,3 +3,9 @@
@import '../node_modules/xterm/dist/xterm.css'; @import '../node_modules/xterm/dist/xterm.css';
@import "assets/scss/main"; @import "assets/scss/main";
body, html {
height: 100vh;
width: 100vw;
overflow: hidden;
}

1485
yarn.lock

File diff suppressed because it is too large Load Diff