Skip to content

Commit 35c073f

Browse files
committed
fix(terminal): update terminal code
1 parent 1544fb1 commit 35c073f

File tree

3 files changed

+82
-65
lines changed

3 files changed

+82
-65
lines changed
Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
<pre class="window-terminal-container dracula-ansi-theme" [ngClass]="{ large: options.size === 'large' }" slimScroll [options]="scrollOptions" [scrollEvents]="scrollEvents">
2-
<div class="command columns log" *ngFor="let cmd of commands; let i = index;" [id]="i">
3-
<div class="terminal">
4-
<span class="icon">
5-
<img *ngIf="cmd.visible" src="images/icons/collapse.svg" (click)="toogleCommand(i)">
6-
<img *ngIf="!cmd.visible" src="images/icons/expand.svg" (click)="toogleCommand(i)">
7-
</span>
8-
<div class="output" [class.is-hidden]="!cmd.visible" [innerHTML]="cmd.output"></div>
9-
<div class="output" [class.is-hidden]="cmd.visible" [innerHTML]="cmd.command"></div>
10-
</div>
1+
<div class="window-terminal-container dracula-ansi-theme" [ngClass]="{ large: options.size === 'large' }" slimScroll [options]="scrollOptions" [scrollEvents]="scrollEvents">
2+
<div class="terminal" *ngFor="let cmd of commands; let i = index;" [id]="i">
3+
<span class="icon">
4+
<img *ngIf="cmd.visible" src="images/icons/collapse.svg" (click)="toogleCommand(i)">
5+
<img *ngIf="!cmd.visible" src="images/icons/expand.svg" (click)="toogleCommand(i)">
6+
</span>
7+
<span class="command" [innerHTML]="cmd.command"></span>
8+
<pre class="output" [class.is-hidden]="!cmd.visible" [innerHTML]="cmd.output"></pre>
119
</div>
12-
</pre>
10+
</div>

src/app/components/app-terminal/app-terminal.component.ts

Lines changed: 40 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import {
2-
Component, ElementRef, OnInit, Input, SimpleChange, EventEmitter, NgZone } from '@angular/core';
1+
import { Component, ElementRef, OnInit, Input, SimpleChange, EventEmitter } from '@angular/core';
32
import { ISlimScrollOptions, SlimScrollEvent } from 'ngx-slimscroll';
43

54
import * as AnsiUp from 'ansi_up';
@@ -16,7 +15,7 @@ export class AppTerminalComponent implements OnInit {
1615
scrollEvents: EventEmitter<SlimScrollEvent>;
1716
commands: { command: string, visible: boolean, output: string }[];
1817

19-
constructor(private elementRef: ElementRef, private ngZone: NgZone) {
18+
constructor(private elementRef: ElementRef) {
2019
this.scrollOptions = {
2120
position: 'right',
2221
barBackground: '#11121A',
@@ -33,6 +32,7 @@ export class AppTerminalComponent implements OnInit {
3332
};
3433

3534
this.scrollEvents = new EventEmitter<SlimScrollEvent>();
35+
this.commands = [];
3636
}
3737

3838
ngOnInit() {
@@ -46,52 +46,46 @@ export class AppTerminalComponent implements OnInit {
4646
return;
4747
}
4848

49-
this.ngZone.run(() => {
50-
const el = this.elementRef.nativeElement.querySelector('.window-terminal-container');
51-
if (typeof this.data.clear !== 'undefined') {
52-
el.innerHTML = '';
53-
} else {
54-
let output: string = this.au.ansi_to_html(this.data);
55-
if (output) {
56-
if (this.commands.length > 0) {
57-
if (output.indexOf('==&gt;') !== -1) {
58-
let command = output.split('</span>')[0] + '</span>';
59-
this.commands.push({
60-
command: command,
61-
visible: true,
62-
output: output
63-
});
64-
} else {
65-
this.commands[this.commands.length - 1].command += ` ${output}`;
66-
}
67-
} else {
68-
let regexp = /<span(.*)==&gt;/gi;
69-
regexp.lastIndex = 1;
70-
let match = regexp.exec(output);
71-
if (match) {
72-
let indexEnd = match.index;
73-
let indexStart = 0;
74-
while (indexEnd >= 0) {
75-
let log = output.substring(indexStart, indexEnd);
76-
let command = log.split('</span>')[0] + '</span>';
77-
this.commands.push({
78-
command: command,
79-
visible: true,
80-
output: log
81-
});
82-
indexStart = indexEnd;
83-
indexEnd = regexp.exec(output).index;
84-
}
85-
}
86-
}
87-
}
49+
if (typeof this.data.clear !== 'undefined') {
50+
this.commands = [];
51+
} else {
52+
const output: string = this.au.ansi_to_html(this.data);
53+
const regex = /<span(.*)==&gt;(.*)<\/span>/g;
54+
let match;
55+
let commands: string[] = [];
8856

89-
const recalculateEvent = new SlimScrollEvent({ type: 'recalculate' });
90-
const bottomEvent = new SlimScrollEvent({ type: 'scrollToBottom', duration: 300 });
57+
if (output.match(regex)) {
58+
while (match = regex.exec(output)) { commands.push(match[0]); }
59+
60+
if (commands.length > 1) {
61+
this.commands = [];
62+
}
9163

92-
setTimeout(() => el.scrollTop = el.scrollHeight);
64+
this.commands = commands.reduce((acc, curr, i) => {
65+
const next = commands[i + 1] || '';
66+
const re = new RegExp('(' + curr + ')(' + '[\\s\\S]*' + ')(' + next + ')');
67+
return acc.concat({
68+
command: curr,
69+
visible: i === commands.length - 1 ? true : false,
70+
output: output.match(re) && output.match(re)[2] ? output.match(re)[2].trim() : ''
71+
});
72+
}, this.commands);
73+
} else {
74+
this.commands[this.commands.length - 1].output += output;
75+
this.commands = this.commands.map((cmd, i) => {
76+
cmd.visible = i === this.commands.length - 1 ? true : false;
77+
return cmd;
78+
});
9379
}
94-
});
80+
81+
const recalculateEvent = new SlimScrollEvent({ type: 'recalculate' });
82+
const bottomEvent = new SlimScrollEvent({ type: 'scrollToBottom', duration: 300 });
83+
84+
setTimeout(() => {
85+
this.scrollEvents.emit(recalculateEvent);
86+
this.scrollEvents.emit(bottomEvent);
87+
});
88+
}
9589
}
9690

9791
toogleCommand(index: number) {

src/app/styles/terminal.sass

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
margin: 0
99
font-family: monaco, monospace
1010
font-size: 12px
11-
padding: 0
11+
padding: 10px 0
1212
height: 400px
1313
background: #111111
1414
border-radius: 4px
@@ -19,13 +19,38 @@
1919
&.large
2020
height: 700px
2121

22-
.output
22+
.terminal
23+
display: inline-block
24+
text-align: left
2325
padding: 0
2426
margin: 0
25-
26-
.terminal
27-
display: flex
28-
align-items: left
29-
height: 100%
3027
width: 100%
31-
text-align: left
28+
29+
.icon
30+
display: block
31+
float: left
32+
padding: 0
33+
margin: 0
34+
35+
img
36+
width: 24px
37+
height: 24px
38+
39+
.output
40+
display: inline-block
41+
width: 100%
42+
color: #e5e5e5
43+
margin: 0 !important
44+
font-family: monaco, monospace
45+
font-size: 12px
46+
padding: 0 20px !important
47+
background: #111111
48+
49+
.command
50+
display: block
51+
float: left
52+
53+
.ansi-yellow-fg
54+
color: #FFEE58 !important
55+
font-weight: bold !important
56+
font-size: 13px

0 commit comments

Comments
 (0)