Skip to content

Commit 9cd69a2

Browse files
committed
#134: added support for terminal Clear screen command (J)
1 parent 14ba3e6 commit 9cd69a2

6 files changed

Lines changed: 395 additions & 16 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Example of the user interface during script execution:
1818
- Different script parameter types
1919
- Alerts
2020
- Logging and auditing
21-
- Formatted output support (colors, styles, caret positioning)
21+
- Formatted output support (colors, styles, cursor positioning, clearing)
2222
- Download of script output files
2323
- Admin page (admin.html) with script execution logs
2424

web-src/js/components/terminal/terminal_model.js

Lines changed: 96 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ export class TerminalModel {
4848
}
4949

5050
write(text) {
51-
this.buffer += text;
51+
const buffer = this.buffer + text;
5252
let lastReadIndex = 0;
5353

5454
let commandBuffer = null;
5555
let currentText = '';
5656

57-
for (let i = 0; i < this.buffer.length; i++) {
58-
const char = this.buffer[i];
57+
for (let i = 0; i < buffer.length; i++) {
58+
const char = buffer[i];
5959

6060
if (commandBuffer !== null) {
6161
commandBuffer += char;
@@ -114,7 +114,7 @@ export class TerminalModel {
114114
}
115115

116116
this.flushText(currentText);
117-
this.buffer = this.buffer.substr(lastReadIndex + 1);
117+
this.buffer = buffer.substr(lastReadIndex + 1);
118118

119119
const changedLines = this.changedLines;
120120
this.changedLines = [];
@@ -163,23 +163,87 @@ export class TerminalModel {
163163
this.addChangedLine(this.currentLine);
164164
}
165165

166-
clearLineToLeft() {
167-
if (this.currentPosition === 0) {
166+
clearLineToLeft(position) {
167+
if (position === 0) {
168168
return;
169169
}
170170

171171
const line = this.getLine(this.currentLine);
172-
if (line.length <= this.currentPosition) {
172+
if (line.length <= position) {
173173
this.lines[this.currentLine] = '';
174174
this.addChangedLine(this.currentLine);
175175
return;
176176
}
177177

178-
const spaces = ' '.repeat(this.currentPosition);
179-
this.lines[this.currentLine] = spaces + line.substring(this.currentPosition);
178+
const spaces = ' '.repeat(position);
179+
this.lines[this.currentLine] = spaces + line.substring(position);
180180
this.addChangedLine(this.currentLine);
181181
}
182182

183+
deleteBottomLines(startLine) {
184+
const oldEnd = this.lines.length;
185+
if (oldEnd <= startLine) {
186+
return;
187+
}
188+
189+
for (let i = startLine; i <= this.lines.length; i++) {
190+
this.lineStyles.delete(i);
191+
}
192+
193+
for (let i = this.changedLines.length - 1; i >= 0; i--) {
194+
const changedLine = this.changedLines[i];
195+
if (changedLine >= startLine) {
196+
this.changedLines.splice(i, 1);
197+
} else {
198+
break;
199+
}
200+
}
201+
202+
this.lines = this.lines.splice(0, startLine);
203+
this.maxLine = Math.max(0, startLine - 1);
204+
205+
this.savedCursorPosition = null;
206+
207+
for (const listener of this.listeners) {
208+
listener.linesDeleted(startLine, oldEnd);
209+
}
210+
}
211+
212+
deleteTopLines(linesCount) {
213+
if (linesCount <= 0) {
214+
return;
215+
}
216+
217+
for (let i = 0; i < linesCount; i++) {
218+
this.lineStyles.delete(i);
219+
}
220+
221+
for (let i = 0; i < this.lines.length; i++) {
222+
const oldIndex = i + linesCount;
223+
if (this.lineStyles.has(oldIndex)) {
224+
this.lineStyles.set(i, this.lineStyles.get(oldIndex));
225+
this.lineStyles.delete(oldIndex);
226+
}
227+
}
228+
229+
this.lines = this.lines.splice(linesCount);
230+
231+
this.currentLine = Math.max(0, this.currentLine - linesCount);
232+
233+
this.savedCursorPosition = null;
234+
235+
this.maxLine = Math.max(0, this.lines.length - 1);
236+
this.changedLines = [];
237+
238+
for (const listener of this.listeners) {
239+
listener.cleared();
240+
}
241+
242+
for (let i = 0; i < this.lines.length; i++) {
243+
this.changedLines.push(i);
244+
}
245+
}
246+
183247
getStyle(line) {
184248
return this.lineStyles.get(line);
185249
}
@@ -534,7 +598,7 @@ class ClearLineHandler extends CommandHandler {
534598
if (direction === 0) {
535599
terminal.clearLineToRight();
536600
} else if (direction === 1) {
537-
terminal.clearLineToLeft();
601+
terminal.clearLineToLeft(terminal.currentPosition);
538602
} else if (direction === 2) {
539603
terminal.clearFullLine();
540604
} else {
@@ -543,10 +607,31 @@ class ClearLineHandler extends CommandHandler {
543607
}
544608
}
545609

610+
class ClearScreenHandler extends CommandHandler {
611+
constructor() {
612+
super();
613+
}
614+
615+
handle(args, terminal) {
616+
const direction = args[0];
617+
618+
if (direction === 0) {
619+
terminal.deleteBottomLines(terminal.currentLine + 1);
620+
} else if (direction === 1) {
621+
terminal.deleteTopLines(terminal.currentLine);
622+
terminal.clearLineToLeft(terminal.currentPosition + 1);
623+
} else if ((direction === 2) || (direction === 3)) {
624+
terminal.clear();
625+
} else {
626+
console.log('WARN! Unsupported [' + direction + 'J command');
627+
}
628+
}
629+
}
630+
546631
const COMMAND_HANDLERS = new Map();
547632
COMMAND_HANDLERS.set('m', new SetGraphicsCommandHandler());
548633
COMMAND_HANDLERS.set('K', new ClearLineHandler());
549-
COMMAND_HANDLERS.set('J', null);
634+
COMMAND_HANDLERS.set('J', new ClearScreenHandler());
550635
COMMAND_HANDLERS.set('H', new MoveCursorToPositionHandler());
551636
COMMAND_HANDLERS.set('f', new MoveCursorToPositionHandler());
552637
COMMAND_HANDLERS.set('A', new MoveCursorVerticallyHandler(true));

web-src/js/components/terminal/terminal_view.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,16 @@ export class Terminal {
171171
cleared() {
172172
destroyChildren(this.element);
173173
}
174+
175+
linesDeleted(startLine, endLine) {
176+
if (startLine >= this.element.childElementCount) {
177+
return;
178+
}
179+
180+
const lastIndex = Math.min(endLine - 1, this.element.childElementCount - 1);
181+
for (let i = lastIndex; i >= startLine; i--) {
182+
const childNode = this.element.childNodes[i];
183+
this.element.removeChild(childNode);
184+
}
185+
}
174186
}

0 commit comments

Comments
 (0)