| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- import 'dart:collection';
- import 'package:xterm/terminal/modes.dart';
- import 'package:xterm/terminal/sgr.dart';
- import 'package:xterm/terminal/terminal.dart';
- typedef CsiSequenceHandler = void Function(CSI, Terminal);
- final _csiHandlers = <int, CsiSequenceHandler>{
- 'c'.codeUnitAt(0): csiSendDeviceAttributesHandler,
- 'd'.codeUnitAt(0): csiLinePositionAbsolute,
- 'f'.codeUnitAt(0): csiCursorPositionHandler,
- 'g'.codeUnitAt(0): csiTabClearHandler,
- 'h'.codeUnitAt(0): csiModeHandler,
- 'l'.codeUnitAt(0): csiModeHandler,
- 'm'.codeUnitAt(0): sgrHandler,
- 'n'.codeUnitAt(0): csiDeviceStatusReportHandler,
- 'r'.codeUnitAt(0): csiSetMarginsHandler, // DECSTBM
- 't'.codeUnitAt(0): csiWindowManipulation,
- 'A'.codeUnitAt(0): csiCursorUpHandler,
- 'B'.codeUnitAt(0): csiCursorDownHandler,
- 'C'.codeUnitAt(0): csiCursorForwardHandler,
- 'D'.codeUnitAt(0): csiCursorBackwardHandler,
- 'E'.codeUnitAt(0): csiCursorNextLineHandler,
- 'F'.codeUnitAt(0): csiCursorPrecedingLineHandler,
- 'G'.codeUnitAt(0): csiCursorHorizontalAbsoluteHandler,
- 'H'.codeUnitAt(0): csiCursorPositionHandler,
- 'J'.codeUnitAt(0): csiEraseInDisplayHandler,
- 'K'.codeUnitAt(0): csiEraseInLineHandler,
- 'L'.codeUnitAt(0): csiInsertLinesHandler,
- 'M'.codeUnitAt(0): csiDeleteLinesHandler,
- 'P'.codeUnitAt(0): csiDeleteHandler,
- 'S'.codeUnitAt(0): csiScrollUpHandler,
- 'T'.codeUnitAt(0): csiScrollDownHandler,
- 'X'.codeUnitAt(0): csiEraseCharactersHandler,
- '@'.codeUnitAt(0): csiInsertBlankCharactersHandler,
- };
- class CSI {
- CSI({
- required this.params,
- required this.finalByte,
- required this.intermediates,
- });
- final List<String> params;
- final int finalByte;
- final List<int> intermediates;
- @override
- String toString() {
- return params.join(';') + String.fromCharCode(finalByte);
- }
- }
- CSI? _parseCsi(Queue<int> queue) {
- final paramBuffer = StringBuffer();
- final intermediates = <int>[];
- while (queue.isNotEmpty) {
- // TODO: handle special case when queue is empty as this time.
- final char = queue.removeFirst();
- if (char >= 0x30 && char <= 0x3F) {
- paramBuffer.writeCharCode(char);
- continue;
- }
- if (char > 0 && char <= 0x2F) {
- intermediates.add(char);
- continue;
- }
- const csiMin = 0x40;
- const csiMax = 0x7e;
- if (char >= csiMin && char <= csiMax) {
- final params = paramBuffer.toString().split(';');
- return CSI(
- params: params,
- finalByte: char,
- intermediates: intermediates,
- );
- }
- }
- }
- void csiHandler(Queue<int> queue, Terminal terminal) {
- final csi = _parseCsi(queue);
- if (csi == null) {
- return;
- }
- terminal.debug.onCsi(csi);
- final handler = _csiHandlers[csi.finalByte];
- if (handler != null) {
- handler(csi, terminal);
- return;
- }
- terminal.debug.onError('unknown: $csi');
- }
- void csiEraseInDisplayHandler(CSI csi, Terminal terminal) {
- var ps = '0';
- if (csi.params.isNotEmpty) {
- ps = csi.params.first;
- }
- switch (ps) {
- case '':
- case '0':
- terminal.buffer.eraseDisplayFromCursor();
- break;
- case '1':
- terminal.buffer.eraseDisplayToCursor();
- break;
- case '2':
- case '3':
- terminal.buffer.eraseDisplay();
- break;
- default:
- terminal.debug.onError("Unsupported ED: CSI $ps J");
- }
- }
- void csiEraseInLineHandler(CSI csi, Terminal terminal) {
- var ps = '0';
- if (csi.params.isNotEmpty) {
- ps = csi.params.first;
- }
- switch (ps) {
- case '':
- case '0':
- terminal.buffer.eraseLineFromCursor();
- break;
- case '1':
- terminal.buffer.eraseLineToCursor();
- break;
- case '2':
- terminal.buffer.eraseLine();
- break;
- default:
- terminal.debug.onError("Unsupported EL: CSI $ps K");
- }
- }
- void csiCursorPositionHandler(CSI csi, Terminal terminal) {
- var x = 1;
- var y = 1;
- if (csi.params.length == 2) {
- y = int.tryParse(csi.params[0]) ?? x;
- x = int.tryParse(csi.params[1]) ?? y;
- }
- terminal.buffer.setPosition(x - 1, y - 1);
- }
- void csiLinePositionAbsolute(CSI csi, Terminal terminal) {
- var row = 1;
- if (csi.params.isNotEmpty) {
- row = int.tryParse(csi.params.first) ?? row;
- }
- terminal.buffer.setCursorY(row - 1);
- }
- void csiCursorHorizontalAbsoluteHandler(CSI csi, Terminal terminal) {
- var x = 1;
- if (csi.params.isNotEmpty) {
- x = int.tryParse(csi.params.first) ?? x;
- }
- terminal.buffer.setCursorX(x - 1);
- }
- void csiCursorForwardHandler(CSI csi, Terminal terminal) {
- var offset = 1;
- if (csi.params.isNotEmpty) {
- offset = int.tryParse(csi.params.first) ?? offset;
- }
- terminal.buffer.movePosition(offset, 0);
- }
- void csiCursorBackwardHandler(CSI csi, Terminal terminal) {
- var offset = 1;
- if (csi.params.isNotEmpty) {
- offset = int.tryParse(csi.params.first) ?? offset;
- }
- terminal.buffer.movePosition(-offset, 0);
- }
- void csiEraseCharactersHandler(CSI csi, Terminal terminal) {
- var count = 1;
- if (csi.params.isNotEmpty) {
- count = int.tryParse(csi.params.first) ?? count;
- }
- terminal.buffer.eraseCharacters(count);
- }
- void csiModeHandler(CSI csi, Terminal terminal) {
- // terminal.ActiveBuffer().ClearSelection()
- return csiSetModes(csi, terminal);
- }
- void csiDeviceStatusReportHandler(CSI csi, Terminal terminal) {
- if (csi.params.isEmpty) return;
- switch (csi.params[0]) {
- case "5":
- terminal.onInput("\x1b[0n");
- break;
- case "6": // report cursor position
- terminal.onInput("\x1b[${terminal.cursorX + 1};${terminal.cursorY + 1}R");
- break;
- default:
- terminal.debug
- .onError('Unknown Device Status Report identifier: ${csi.params[0]}');
- return;
- }
- }
- void csiSendDeviceAttributesHandler(CSI csi, Terminal terminal) {
- var response = '?1;2';
- if (csi.params.isNotEmpty && csi.params.first.startsWith('>')) {
- response = '>0;0;0';
- }
- terminal.onInput('\x1b[${response}c');
- }
- void csiCursorUpHandler(CSI csi, Terminal terminal) {
- var distance = 1;
- if (csi.params.isNotEmpty) {
- distance = int.tryParse(csi.params.first) ?? distance;
- }
- terminal.buffer.movePosition(0, -distance);
- }
- void csiCursorDownHandler(CSI csi, Terminal terminal) {
- var distance = 1;
- if (csi.params.isNotEmpty) {
- distance = int.tryParse(csi.params.first) ?? distance;
- }
- terminal.buffer.movePosition(0, distance);
- }
- /// DECSTBM – Set Top and Bottom Margins (DEC Private)
- ///
- /// ESC [ Pn; Pn r
- ///
- /// This sequence sets the top and bottom margins to define the scrolling
- /// region. The first parameter is the line number of the first line in the
- /// scrolling region; the second parameter is the line number of the bottom line
- /// in the scrolling region. Default is the en tire screen (no margins). The
- /// minimum size of the scrolling region allowed is two lines, i.e., the top
- /// margin must be less than the bottom margin. The cursor is placed in the home
- /// position (see Origin Mode DECOM).
- void csiSetMarginsHandler(CSI csi, Terminal terminal) {
- var top = 1;
- var bottom = terminal.viewHeight;
- if (csi.params.length > 2) {
- return;
- }
- if (csi.params.isNotEmpty) {
- top = int.tryParse(csi.params[0]) ?? top;
- if (csi.params.length > 1) {
- bottom = int.tryParse(csi.params[1]) ?? bottom;
- }
- }
- terminal.buffer.setVerticalMargins(top - 1, bottom - 1);
- terminal.buffer.setPosition(0, 0);
- }
- void csiDeleteHandler(CSI csi, Terminal terminal) {
- var count = 1;
- if (csi.params.isNotEmpty) {
- count = int.tryParse(csi.params.first) ?? count;
- }
- if (count < 1) {
- count = 1;
- }
- terminal.buffer.deleteChars(count);
- }
- void csiTabClearHandler(CSI csi, Terminal terminal) {
- // TODO
- }
- void csiWindowManipulation(CSI csi, Terminal terminal) {
- // not supported
- }
- void csiCursorNextLineHandler(CSI csi, Terminal terminal) {
- var count = 1;
- if (csi.params.isNotEmpty) {
- count = int.tryParse(csi.params.first) ?? count;
- }
- if (count < 1) {
- count = 1;
- }
- terminal.buffer.moveCursorY(count);
- terminal.buffer.setCursorX(0);
- }
- void csiCursorPrecedingLineHandler(CSI csi, Terminal terminal) {
- var count = 1;
- if (csi.params.isNotEmpty) {
- count = int.tryParse(csi.params.first) ?? count;
- }
- if (count < 1) {
- count = 1;
- }
- terminal.buffer.moveCursorY(-count);
- terminal.buffer.setCursorX(0);
- }
- void csiInsertLinesHandler(CSI csi, Terminal terminal) {
- var count = 1;
- if (csi.params.isNotEmpty) {
- count = int.tryParse(csi.params.first) ?? count;
- }
- if (count < 1) {
- count = 1;
- }
- terminal.buffer.insertLines(count);
- }
- void csiDeleteLinesHandler(CSI csi, Terminal terminal) {
- var count = 1;
- if (csi.params.isNotEmpty) {
- count = int.tryParse(csi.params.first) ?? count;
- }
- if (count < 1) {
- count = 1;
- }
- terminal.buffer.deleteLines(count);
- }
- void csiScrollUpHandler(CSI csi, Terminal terminal) {
- var count = 1;
- if (csi.params.isNotEmpty) {
- count = int.tryParse(csi.params.first) ?? count;
- }
- if (count < 1) {
- count = 1;
- }
- terminal.buffer.areaScrollUp(count);
- }
- void csiScrollDownHandler(CSI csi, Terminal terminal) {
- var count = 1;
- if (csi.params.isNotEmpty) {
- count = int.tryParse(csi.params.first) ?? count;
- }
- if (count < 1) {
- count = 1;
- }
- terminal.buffer.areaScrollDown(count);
- }
- void csiInsertBlankCharactersHandler(CSI csi, Terminal terminal) {
- var count = 1;
- if (csi.params.isNotEmpty) {
- count = int.tryParse(csi.params.first) ?? count;
- }
- if (count < 1) {
- count = 1;
- }
- terminal.buffer.insertBlankCharacters(count);
- }
|