| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095 |
- import 'package:xterm/core/color.dart';
- import 'package:xterm/core/mouse.dart';
- import 'package:xterm/core/escape/handler.dart';
- import 'package:xterm/utils/ascii.dart';
- import 'package:xterm/utils/byte_consumer.dart';
- import 'package:xterm/utils/char_code.dart';
- import 'package:xterm/utils/lookup_table.dart';
- /// [EscapeParser] translates control characters and escape sequences into
- /// function calls that the terminal can handle.
- ///
- /// Design goals:
- /// * Zero object allocation during processing.
- /// * No internal state. Same input will always produce same output.
- class EscapeParser {
- final EscapeHandler handler;
- EscapeParser(this.handler);
- final _queue = ByteConsumer();
- /// Start of sequence or character being processed. Useful for debugging.
- var tokenBegin = 0;
- /// End of sequence or character being processed. Useful for debugging.
- int get tokenEnd => _queue.totalConsumed;
- void write(String chunk) {
- _queue.unrefConsumedBlocks();
- _queue.add(chunk);
- _process();
- }
- void _process() {
- while (_queue.isNotEmpty) {
- tokenBegin = _queue.totalConsumed;
- final char = _queue.consume();
- if (char == Ascii.ESC) {
- final processed = _processEscape();
- if (!processed) {
- _queue.rollback(tokenEnd - tokenBegin);
- return;
- }
- } else {
- _processChar(char);
- }
- }
- }
- void _processChar(int char) {
- if (char > _sbcHandlers.maxIndex) {
- handler.writeChar(char);
- return;
- }
- final sbcHandler = _sbcHandlers[char];
- if (sbcHandler == null) {
- handler.unkownEscape(char);
- return;
- }
- sbcHandler();
- }
- /// Processes a sequence of characters that starts with an escape character.
- /// Returns [true] if the sequence was processed, [false] if it was not.
- bool _processEscape() {
- if (_queue.isEmpty) return false;
- final escapeChar = _queue.consume();
- final escapeHandler = _escHandlers[escapeChar];
- if (escapeHandler == null) {
- handler.unkownEscape(escapeChar);
- return true;
- }
- return escapeHandler();
- }
- late final _sbcHandlers = FastLookupTable<_SbcHandler>({
- 0x07: handler.bell,
- 0x08: handler.backspaceReturn,
- 0x09: handler.tab,
- 0x0a: handler.lineFeed,
- 0x0b: handler.lineFeed,
- 0x0c: handler.lineFeed,
- 0x0d: handler.carriageReturn,
- 0x0e: handler.shiftOut,
- 0x0f: handler.shiftIn,
- });
- late final _escHandlers = FastLookupTable<_EscHandler>({
- '['.charCode: _escHandleCSI,
- ']'.charCode: _escHandleOSC,
- '7'.charCode: _escHandleSaveCursor,
- '8'.charCode: _escHandleRestoreCursor,
- 'D'.charCode: _escHandleIndex,
- 'E'.charCode: _escHandleNextLine,
- 'H'.charCode: _escHandleTabSet,
- 'M'.charCode: _escHandleReverseIndex,
- // 'P'.charCode: _unsupportedHandler, // Sixel
- // 'c'.charCode: _unsupportedHandler,
- // '#'.charCode: _unsupportedHandler,
- '('.charCode: _escHandleDesignateCharset0, // SCS - G0
- ')'.charCode: _escHandleDesignateCharset1, // SCS - G1
- // '*'.charCode: _voidHandler(1), // TODO: G2 (vt220)
- // '+'.charCode: _voidHandler(1), // TODO: G3 (vt220)
- '>'.charCode: _escHandleResetAppKeypadMode, // TODO: Normal Keypad
- '='.charCode: _escHandleSetAppKeypadMode, // TODO: Application Keypad
- });
- /// `ESC 7` Save Cursor (DECSC)
- ///
- /// https://terminalguide.namepad.de/seq/a_esc_a7/
- bool _escHandleSaveCursor() {
- handler.saveCursor();
- return true;
- }
- /// `ESC 8` Restore Cursor (DECRC)
- ///
- /// https://terminalguide.namepad.de/seq/a_esc_a8/
- bool _escHandleRestoreCursor() {
- handler.restoreCursor();
- return true;
- }
- /// `ESC D` Index (IND)
- ///
- /// https://terminalguide.namepad.de/seq/a_esc_cd/
- bool _escHandleIndex() {
- handler.index();
- return true;
- }
- /// `ESC E` Next Line (NEL)
- ///
- /// https://terminalguide.namepad.de/seq/a_esc_ce/
- bool _escHandleNextLine() {
- handler.nextLine();
- return true;
- }
- /// `ESC H` Horizontal Tab Set (HTS)
- ///
- /// https://terminalguide.namepad.de/seq/a_esc_ch/
- bool _escHandleTabSet() {
- handler.setTapStop();
- return true;
- }
- /// `ESC M` Reverse Index (RI)
- ///
- /// https://terminalguide.namepad.de/seq/a_esc_cm/
- bool _escHandleReverseIndex() {
- handler.reverseIndex();
- return true;
- }
- bool _escHandleDesignateCharset0() {
- if (_queue.isEmpty) return false;
- _queue.consume();
- handler.designateCharset(0);
- return true;
- }
- bool _escHandleDesignateCharset1() {
- if (_queue.isEmpty) return false;
- _queue.consume();
- handler.designateCharset(1);
- return true;
- }
- /// `ESC >` Reset Application Keypad Mode (DECKPNM)
- ///
- /// https://terminalguide.namepad.de/seq/a_esc_x3c_greater_than/
- bool _escHandleSetAppKeypadMode() {
- handler.setAppKeypadMode(true);
- return true;
- }
- /// `ESC =` Set Application Keypad Mode (DECKPAM)
- ///
- /// https://terminalguide.namepad.de/seq/a_esc_x3d_equals/
- bool _escHandleResetAppKeypadMode() {
- handler.setAppKeypadMode(false);
- return true;
- }
- bool _escHandleCSI() {
- final consumed = _consumeCsi();
- if (!consumed) return false;
- final csiHandler = _csiHandlers[_csi.finalByte];
- if (csiHandler == null) {
- handler.unknownCSI(_csi.finalByte);
- } else {
- csiHandler();
- }
- return true;
- }
- /// The last parsed [_Csi]. This is a mutable singletion by design to reduce
- /// object allocations.
- final _csi = _Csi(finalByte: 0, params: []);
- /// Parse a CSI from the head of the queue. Return false if the CSI isn't
- /// complete. After a CSI is successfully parsed, [_csi] is updated.
- bool _consumeCsi() {
- if (_queue.isEmpty) {
- return false;
- }
- _csi.params.clear();
- // test whether the csi is a `CSI ? Ps ...` or `CSI Ps ...`
- final prefix = _queue.peek();
- if (prefix >= Ascii.colon && prefix <= Ascii.questionMark) {
- _csi.prefix = prefix;
- _queue.consume();
- } else {
- _csi.prefix = null;
- }
- var param = 0;
- var hasParam = false;
- while (true) {
- // The sequence isn't completed, just ignore it.
- if (_queue.isEmpty) {
- return false;
- }
- final char = _queue.consume();
- if (char == Ascii.semicolon) {
- if (hasParam) {
- _csi.params.add(param);
- }
- param = 0;
- continue;
- }
- if (char >= Ascii.num0 && char <= Ascii.num9) {
- hasParam = true;
- param *= 10;
- param += char - Ascii.num0;
- continue;
- }
- if (char > Ascii.NULL && char < Ascii.num0) {
- // intermediates.add(char);
- continue;
- }
- if (char >= Ascii.atSign && char <= Ascii.tilde) {
- if (hasParam) {
- _csi.params.add(param);
- }
- _csi.finalByte = char;
- return true;
- }
- }
- }
- late final _csiHandlers = FastLookupTable<_CsiHandler>({
- // 'a'.codeUnitAt(0): _csiHandleCursorHorizontalRelative,
- 'b'.codeUnitAt(0): _csiHandleRepeatPreviousCharacter,
- 'c'.codeUnitAt(0): _csiHandleSendDeviceAttributes,
- 'd'.codeUnitAt(0): _csiHandleLinePositionAbsolute,
- 'f'.codeUnitAt(0): _csiHandleCursorPosition,
- 'g'.codeUnitAt(0): _csiHandelClearTabStop,
- 'h'.codeUnitAt(0): _csiHandleMode,
- 'l'.codeUnitAt(0): _csiHandleMode,
- 'm'.codeUnitAt(0): _csiHandleSgr,
- 'n'.codeUnitAt(0): _csiHandleDeviceStatusReport,
- 'r'.codeUnitAt(0): _csiHandleSetMargins,
- 't'.codeUnitAt(0): _csiWindowManipulation,
- 'A'.codeUnitAt(0): _csiHandleCursorUp,
- 'B'.codeUnitAt(0): _csiHandleCursorDown,
- 'C'.codeUnitAt(0): _csiHandleCursorForward,
- 'D'.codeUnitAt(0): _csiHandleCursorBackward,
- 'E'.codeUnitAt(0): _csiHandleCursorNextLine,
- 'F'.codeUnitAt(0): _csiHandleCursorPrecedingLine,
- 'G'.codeUnitAt(0): _csiHandleCursorHorizontalAbsolute,
- 'H'.codeUnitAt(0): _csiHandleCursorPosition,
- 'J'.codeUnitAt(0): _csiHandleEraseDisplay,
- 'K'.codeUnitAt(0): _csiHandleEraseLine,
- 'L'.codeUnitAt(0): _csiHandleInsertLines,
- 'M'.codeUnitAt(0): _csiHandleDeleteLines,
- 'P'.codeUnitAt(0): _csiHandleDelete,
- 'S'.codeUnitAt(0): _csiHandleScrollUp,
- 'T'.codeUnitAt(0): _csiHandleScrollDown,
- 'X'.codeUnitAt(0): _csiHandleEraseCharacters,
- '@'.codeUnitAt(0): _csiHandleInsertBlankCharacters,
- });
- /// `ESC [ Ps a` Cursor Horizontal Position Relative (HPR)
- ///
- /// https://terminalguide.namepad.de/seq/csi_sa/
- // void _csiHandleCursorHorizontalRelative() {
- // if (_csi.params.isEmpty) {
- // handler.cursorHorizontal(1);
- // } else {
- // handler.cursorHorizontal(_csi.params[0]);
- // }
- // }
- /// `ESC [ Ps b` Repeat Previous Character (REP)
- ///
- /// https://terminalguide.namepad.de/seq/csi_sb/
- void _csiHandleRepeatPreviousCharacter() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- if (amount == 0) amount = 1;
- }
- handler.repeatPreviousCharacter(amount);
- }
- /// `ESC [ Ps c` Device Attributes (DA)
- ///
- /// https://terminalguide.namepad.de/seq/csi_sc/
- void _csiHandleSendDeviceAttributes() {
- switch (_csi.prefix) {
- case Ascii.greaterThan:
- return handler.sendSecondaryDeviceAttributes();
- case Ascii.equal:
- return handler.sendTertiaryDeviceAttributes();
- default:
- handler.sendPrimaryDeviceAttributes();
- }
- }
- /// `ESC [ Ps d` Cursor Vertical Position Absolute (VPA)
- ///
- /// https://terminalguide.namepad.de/seq/csi_sd/
- void _csiHandleLinePositionAbsolute() {
- var y = 1;
- if (_csi.params.isNotEmpty) {
- y = _csi.params[0];
- }
- handler.setCursorY(y - 1);
- }
- /// `ESC [ Ps ; Ps f` Alias: Set Cursor Position
- ///
- /// https://terminalguide.namepad.de/seq/csi_sf/
- void _csiHandleCursorPosition() {
- var row = 1;
- var col = 1;
- if (_csi.params.length == 2) {
- row = _csi.params[0];
- col = _csi.params[1];
- }
- handler.setCursor(col - 1, row - 1);
- }
- /// `ESC [ Ps g` Tab Clear (TBC)
- ///
- /// https://terminalguide.namepad.de/seq/csi_sg/
- void _csiHandelClearTabStop() {
- var cmd = 0;
- if (_csi.params.length == 1) {
- cmd = _csi.params[0];
- }
- switch (cmd) {
- case 0:
- return handler.clearTabStopUnderCursor();
- default:
- return handler.clearAllTabStops();
- }
- }
- /// - `ESC [ [ Pm ] h Set Mode (SM)` https://terminalguide.namepad.de/seq/csi_sm/
- /// - `ESC [ ? [ Pm ] h` Set Mode (?) (SM) https://terminalguide.namepad.de/seq/csi_sh__p/
- /// - `ESC [ [ Pm ] l` Reset Mode (RM) https://terminalguide.namepad.de/seq/csi_rm/
- /// - `ESC [ ? [ Pm ] l` Reset Mode (?) (RM) https://terminalguide.namepad.de/seq/csi_sl__p/
- void _csiHandleMode() {
- final isEnabled = _csi.finalByte == Ascii.h;
- final isDecModes = _csi.prefix == Ascii.questionMark;
- if (isDecModes) {
- for (var mode in _csi.params) {
- _setDecMode(mode, isEnabled);
- }
- } else {
- for (var mode in _csi.params) {
- _setMode(mode, isEnabled);
- }
- }
- }
- /// `ESC [ [ Ps ] m` Select Graphic Rendition (SGR)
- ///
- /// https://terminalguide.namepad.de/seq/csi_sm/
- void _csiHandleSgr() {
- final params = _csi.params;
- if (params.isEmpty) {
- return handler.resetCursorStyle();
- }
- for (var i = 0; i < _csi.params.length; i++) {
- final param = params[i];
- switch (param) {
- case 0:
- handler.resetCursorStyle();
- continue;
- case 1:
- handler.setCursorBold();
- continue;
- case 2:
- handler.setCursorFaint();
- continue;
- case 3:
- handler.setCursorItalic();
- continue;
- case 4:
- handler.setCursorUnderline();
- continue;
- case 5:
- handler.setCursorBlink();
- continue;
- case 7:
- handler.setCursorInverse();
- continue;
- case 8:
- handler.setCursorInvisible();
- continue;
- case 9:
- handler.setCursorStrikethrough();
- continue;
- case 21:
- handler.unsetCursorBold();
- continue;
- case 22:
- handler.unsetCursorFaint();
- continue;
- case 23:
- handler.unsetCursorItalic();
- continue;
- case 24:
- handler.unsetCursorUnderline();
- continue;
- case 25:
- handler.unsetCursorBlink();
- continue;
- case 27:
- handler.unsetCursorInverse();
- continue;
- case 28:
- handler.unsetCursorInvisible();
- continue;
- case 29:
- handler.unsetCursorStrikethrough();
- continue;
- case 30:
- handler.setForegroundColor16(NamedColor.black);
- continue;
- case 31:
- handler.setForegroundColor16(NamedColor.red);
- continue;
- case 32:
- handler.setForegroundColor16(NamedColor.green);
- continue;
- case 33:
- handler.setForegroundColor16(NamedColor.yellow);
- continue;
- case 34:
- handler.setForegroundColor16(NamedColor.blue);
- continue;
- case 35:
- handler.setForegroundColor16(NamedColor.magenta);
- continue;
- case 36:
- handler.setForegroundColor16(NamedColor.cyan);
- continue;
- case 37:
- handler.setForegroundColor16(NamedColor.white);
- continue;
- case 38:
- final mode = params[i + 1];
- switch (mode) {
- case 2:
- final r = params[i + 2];
- final g = params[i + 3];
- final b = params[i + 4];
- handler.setForegroundColorRgb(r, g, b);
- i += 4;
- break;
- case 5:
- final index = params[i + 2];
- handler.setForegroundColor256(index);
- i += 2;
- break;
- }
- continue;
- case 39:
- handler.resetForeground();
- continue;
- case 40:
- handler.setBackgroundColor16(NamedColor.black);
- continue;
- case 41:
- handler.setBackgroundColor16(NamedColor.red);
- continue;
- case 42:
- handler.setBackgroundColor16(NamedColor.green);
- continue;
- case 43:
- handler.setBackgroundColor16(NamedColor.yellow);
- continue;
- case 44:
- handler.setBackgroundColor16(NamedColor.blue);
- continue;
- case 45:
- handler.setBackgroundColor16(NamedColor.magenta);
- continue;
- case 46:
- handler.setBackgroundColor16(NamedColor.cyan);
- continue;
- case 47:
- handler.setBackgroundColor16(NamedColor.white);
- continue;
- case 48:
- final mode = params[i + 1];
- switch (mode) {
- case 2:
- final r = params[i + 2];
- final g = params[i + 3];
- final b = params[i + 4];
- handler.setBackgroundColorRgb(r, g, b);
- i += 4;
- break;
- case 5:
- final index = params[i + 2];
- handler.setBackgroundColor256(index);
- i += 2;
- break;
- }
- continue;
- case 49:
- handler.resetBackground();
- continue;
- case 90:
- handler.setForegroundColor16(NamedColor.brightBlack);
- continue;
- case 91:
- handler.setForegroundColor16(NamedColor.brightRed);
- continue;
- case 92:
- handler.setForegroundColor16(NamedColor.brightGreen);
- continue;
- case 93:
- handler.setForegroundColor16(NamedColor.brightYellow);
- continue;
- case 94:
- handler.setForegroundColor16(NamedColor.brightBlue);
- continue;
- case 95:
- handler.setForegroundColor16(NamedColor.brightMagenta);
- continue;
- case 96:
- handler.setForegroundColor16(NamedColor.brightCyan);
- continue;
- case 97:
- handler.setForegroundColor16(NamedColor.brightWhite);
- continue;
- case 100:
- handler.setBackgroundColor16(NamedColor.brightBlack);
- continue;
- case 101:
- handler.setBackgroundColor16(NamedColor.brightRed);
- continue;
- case 102:
- handler.setBackgroundColor16(NamedColor.brightGreen);
- continue;
- case 103:
- handler.setBackgroundColor16(NamedColor.brightYellow);
- continue;
- case 104:
- handler.setBackgroundColor16(NamedColor.brightBlue);
- continue;
- case 105:
- handler.setBackgroundColor16(NamedColor.brightMagenta);
- continue;
- case 106:
- handler.setBackgroundColor16(NamedColor.brightCyan);
- continue;
- case 107:
- handler.setBackgroundColor16(NamedColor.brightWhite);
- continue;
- default:
- handler.unsupportedStyle(param);
- continue;
- }
- }
- }
- /// `ESC [ Ps n` Device Status Report [Dispatch] (DSR)
- ///
- /// https://terminalguide.namepad.de/seq/csi_sn/
- void _csiHandleDeviceStatusReport() {
- if (_csi.params.isEmpty) return;
- switch (_csi.params[0]) {
- case 5:
- return handler.sendOperatingStatus();
- case 6:
- return handler.sendCursorPosition();
- }
- }
- /// `ESC [ Ps ; Ps r` Set Top and Bottom Margins (DECSTBM)
- ///
- /// https://terminalguide.namepad.de/seq/csi_sr/
- void _csiHandleSetMargins() {
- var top = 1;
- int? bottom;
- if (_csi.params.length > 2) return;
- if (_csi.params.isNotEmpty) {
- top = _csi.params[0];
- if (_csi.params.length == 2) {
- bottom = _csi.params[1] - 1;
- }
- }
- handler.setMargins(top - 1, bottom);
- }
- /// `ESC [ Ps t` Window operations [DISPATCH]
- ///
- /// https://terminalguide.namepad.de/seq/csi_st/
- void _csiWindowManipulation() {
- // Not supported.
- }
- /// `ESC [ Ps A` Cursor Up (CUU)
- ///
- /// https://terminalguide.namepad.de/seq/csi_ca/
- void _csiHandleCursorUp() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- if (amount == 0) amount = 1;
- }
- handler.moveCursorY(-amount);
- }
- /// `ESC [ Ps B` Cursor Down (CUD)
- ///
- /// https://terminalguide.namepad.de/seq/csi_cb/
- void _csiHandleCursorDown() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- if (amount == 0) amount = 1;
- }
- handler.moveCursorY(amount);
- }
- /// `ESC [ Ps C` Cursor Right (CUF)
- ///
- /// Cursor Right (CUF)
- void _csiHandleCursorForward() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- if (amount == 0) amount = 1;
- }
- handler.moveCursorX(amount);
- }
- /// `ESC [ Ps D` Cursor Left (CUB)
- ///
- /// https://terminalguide.namepad.de/seq/csi_cd/
- void _csiHandleCursorBackward() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- if (amount == 0) amount = 1;
- }
- handler.moveCursorX(-amount);
- }
- /// `ESC [ Ps E` Cursor Next Line (CNL)
- ///
- /// https://terminalguide.namepad.de/seq/csi_ce/
- void _csiHandleCursorNextLine() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- if (amount == 0) amount = 1;
- }
- handler.cursorNextLine(amount);
- }
- /// `ESC [ Ps F` Cursor Previous Line (CPL)
- ///
- /// https://terminalguide.namepad.de/seq/csi_cf/
- void _csiHandleCursorPrecedingLine() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- if (amount == 0) amount = 1;
- }
- handler.cursorPrecedingLine(amount);
- }
- void _csiHandleCursorHorizontalAbsolute() {
- var x = 1;
- if (_csi.params.isNotEmpty) {
- x = _csi.params[0];
- if (x == 0) x = 1;
- }
- handler.setCursorX(x - 1);
- }
- /// ESC [ Ps J Erase Display [Dispatch] (ED)
- ///
- /// https://terminalguide.namepad.de/seq/csi_cj/
- void _csiHandleEraseDisplay() {
- var cmd = 0;
- if (_csi.params.length == 1) {
- cmd = _csi.params[0];
- }
- switch (cmd) {
- case 0:
- return handler.eraseDisplayBelow();
- case 1:
- return handler.eraseDisplayAbove();
- case 2:
- return handler.eraseDisplay();
- case 3:
- return handler.eraseScrollbackOnly();
- }
- }
- /// `ESC [ Ps K` Erase Line [Dispatch] (EL)
- ///
- /// https://terminalguide.namepad.de/seq/csi_ck/
- void _csiHandleEraseLine() {
- var cmd = 0;
- if (_csi.params.length == 1) {
- cmd = _csi.params[0];
- }
- switch (cmd) {
- case 0:
- return handler.eraseLineRight();
- case 1:
- return handler.eraseLineLeft();
- case 2:
- return handler.eraseLine();
- }
- }
- /// `ESC [ Ps L` Insert Line (IL)
- ///
- /// https://terminalguide.namepad.de/seq/csi_cl/
- void _csiHandleInsertLines() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- }
- handler.insertLines(amount);
- }
- /// ESC [ Ps M Delete Line (DL)
- ///
- /// https://terminalguide.namepad.de/seq/csi_cm/
- void _csiHandleDeleteLines() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- }
- handler.deleteLines(amount);
- }
- /// ESC [ Ps P Delete Character (DCH)
- ///
- /// https://terminalguide.namepad.de/seq/csi_cp/
- void _csiHandleDelete() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- }
- handler.deleteChars(amount);
- }
- /// `ESC [ Ps S` Scroll Up (SU)
- ///
- /// https://terminalguide.namepad.de/seq/csi_cs/
- void _csiHandleScrollUp() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- }
- handler.scrollUp(amount);
- }
- /// `ESC [ Ps T `Scroll Down (SD)
- ///
- /// https://terminalguide.namepad.de/seq/csi_ct_1param/
- void _csiHandleScrollDown() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- }
- handler.scrollDown(amount);
- }
- /// `ESC [ Ps X` Erase Character (ECH)
- ///
- /// https://terminalguide.namepad.de/seq/csi_cx/
- void _csiHandleEraseCharacters() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- }
- handler.eraseChars(amount);
- }
- /// `ESC [ Ps @` Insert Blanks (ICH)
- ///
- /// https://terminalguide.namepad.de/seq/csi_x40_at/
- ///
- /// Inserts amount spaces at current cursor position moving existing cell
- /// contents to the right. The contents of the amount right-most columns in
- /// the scroll region are lost. The cursor position is not changed.
- void _csiHandleInsertBlankCharacters() {
- var amount = 1;
- if (_csi.params.isNotEmpty) {
- amount = _csi.params[0];
- }
- handler.insertBlankChars(amount);
- }
- void _setMode(int mode, bool enabled) {
- switch (mode) {
- case 4:
- return handler.setInsertMode(enabled);
- case 20:
- return handler.setLineFeedMode(enabled);
- default:
- return handler.setUnknownMode(mode, enabled);
- }
- }
- void _setDecMode(int mode, bool enabled) {
- switch (mode) {
- case 1:
- return handler.setCursorKeysMode(enabled);
- case 3:
- return handler.setColumnMode(enabled);
- case 5:
- return handler.setReverseDisplayMode(enabled);
- case 6:
- return handler.setOriginMode(enabled);
- case 7:
- return handler.setAutoWrapMode(enabled);
- case 9:
- return enabled
- ? handler.setMouseMode(MouseMode.clickOnly)
- : handler.setMouseMode(MouseMode.none);
- case 12:
- case 13:
- return handler.setCursorBlinkMode(enabled);
- case 25:
- return handler.setCursorVisibleMode(enabled);
- case 47:
- if (enabled) {
- return handler.useAltBuffer();
- } else {
- return handler.useMainBuffer();
- }
- case 66:
- return handler.setAppKeypadMode(enabled);
- case 1000:
- case 10061000:
- return enabled
- ? handler.setMouseMode(MouseMode.upDownScroll)
- : handler.setMouseMode(MouseMode.none);
- case 1001:
- return enabled
- ? handler.setMouseMode(MouseMode.upDownScroll)
- : handler.setMouseMode(MouseMode.none);
- case 1002:
- return enabled
- ? handler.setMouseMode(MouseMode.upDownScrollDrag)
- : handler.setMouseMode(MouseMode.none);
- case 1003:
- return enabled
- ? handler.setMouseMode(MouseMode.upDownScrollMove)
- : handler.setMouseMode(MouseMode.none);
- case 1004:
- return handler.setReportFocusMode(enabled);
- case 1005:
- return enabled
- ? handler.setMouseReportMode(MouseReportMode.utf)
- : handler.setMouseReportMode(MouseReportMode.normal);
- case 1006:
- return enabled
- ? handler.setMouseReportMode(MouseReportMode.sgr)
- : handler.setMouseReportMode(MouseReportMode.normal);
- case 1007:
- return handler.setAltBufferMouseScrollMode(enabled);
- case 1015:
- return enabled
- ? handler.setMouseReportMode(MouseReportMode.urxvt)
- : handler.setMouseReportMode(MouseReportMode.normal);
- case 1047:
- if (enabled) {
- handler.useAltBuffer();
- } else {
- handler.clearAltBuffer();
- handler.useMainBuffer();
- }
- return;
- case 1048:
- if (enabled) {
- return handler.saveCursor();
- } else {
- return handler.restoreCursor();
- }
- case 1049:
- if (enabled) {
- handler.saveCursor();
- handler.clearAltBuffer();
- handler.useAltBuffer();
- } else {
- handler.useMainBuffer();
- }
- return;
- case 2004:
- return handler.setBracketedPasteMode(enabled);
- default:
- return handler.setUnknownDecMode(mode, enabled);
- }
- }
- bool _escHandleOSC() {
- final consumed = _consumeOsc();
- if (!consumed) return false;
- if (_osc.length < 2) {
- return true;
- }
- final ps = _osc[0];
- final pt = _osc[1];
- switch (ps) {
- case '0':
- handler.setTitle(pt);
- handler.setIconName(pt);
- break;
- case '1':
- handler.setIconName(pt);
- break;
- case '2':
- handler.setTitle(pt);
- break;
- default:
- handler.unknownOSC(ps);
- }
- return true;
- }
- final _osc = <String>[];
- bool _consumeOsc() {
- _osc.clear();
- final param = StringBuffer();
- while (true) {
- if (_queue.isEmpty) {
- return false;
- }
- final char = _queue.consume();
- // OSC terminates with BEL
- if (char == Ascii.BEL) {
- _osc.add(param.toString());
- return true;
- }
- /// OSC terminates with ST
- if (char == Ascii.ESC) {
- if (_queue.isEmpty) {
- return false;
- }
- if (_queue.consume() == Ascii.backslash) {
- _osc.add(param.toString());
- }
- return true;
- }
- /// Parse next parameter
- if (char == Ascii.semicolon) {
- _osc.add(param.toString());
- param.clear();
- continue;
- }
- param.writeCharCode(char);
- }
- }
- }
- class _Csi {
- _Csi({
- required this.params,
- required this.finalByte,
- // required this.intermediates,
- });
- int? prefix;
- List<int> params;
- int finalByte;
- // final List<int> intermediates;
- @override
- String toString() {
- return params.join(';') + String.fromCharCode(finalByte);
- }
- }
- /// Function that handles a sequence of characters that starts with an escape.
- /// Returns [true] if the sequence was processed, [false] if it was not.
- typedef _EscHandler = bool Function();
- typedef _SbcHandler = void Function();
- typedef _CsiHandler = void Function();
|