ansi.dart 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import 'dart:collection';
  2. import 'package:xterm/terminal/csi.dart';
  3. import 'package:xterm/terminal/osc.dart';
  4. import 'package:xterm/terminal/terminal.dart';
  5. /// Handler of terminal sequences. Returns true if the sequence is consumed,
  6. /// false to indicate that the sequence is not completed and no charater is
  7. /// consumed from the queue.
  8. typedef AnsiHandler = bool Function(Queue<int>, Terminal);
  9. bool ansiHandler(Queue<int> queue, Terminal terminal) {
  10. // The sequence isn't completed, just ignore it.
  11. if (queue.isEmpty) {
  12. return false;
  13. }
  14. final charAfterEsc = queue.removeFirst();
  15. final handler = _ansiHandlers[charAfterEsc];
  16. if (handler != null) {
  17. if (handler != csiHandler && handler != oscHandler) {
  18. terminal.debug.onEsc(charAfterEsc);
  19. }
  20. final finished = handler(queue, terminal);
  21. if (!finished) {
  22. queue.addFirst(charAfterEsc);
  23. }
  24. return finished;
  25. }
  26. terminal.debug.onError('unsupported ansi sequence: $charAfterEsc');
  27. return true;
  28. }
  29. final _ansiHandlers = <int, AnsiHandler>{
  30. '['.codeUnitAt(0): csiHandler,
  31. ']'.codeUnitAt(0): oscHandler,
  32. '7'.codeUnitAt(0): _ansiSaveCursorHandler,
  33. '8'.codeUnitAt(0): _ansiRestoreCursorHandler,
  34. 'D'.codeUnitAt(0): _ansiIndexHandler,
  35. 'E'.codeUnitAt(0): _ansiNextLineHandler,
  36. 'H'.codeUnitAt(0): _ansiTabSetHandler,
  37. 'M'.codeUnitAt(0): _ansiReverseIndexHandler,
  38. 'P'.codeUnitAt(0): _unsupportedHandler, // Sixel
  39. 'c'.codeUnitAt(0): _unsupportedHandler,
  40. '#'.codeUnitAt(0): _unsupportedHandler,
  41. '('.codeUnitAt(0): _scsHandler(0), // SCS - G0
  42. ')'.codeUnitAt(0): _scsHandler(1), // SCS - G1
  43. '*'.codeUnitAt(0): _voidHandler(1), // TODO: G2 (vt220)
  44. '+'.codeUnitAt(0): _voidHandler(1), // TODO: G3 (vt220)
  45. '>'.codeUnitAt(0): _voidHandler(0), // TODO: Normal Keypad
  46. '='.codeUnitAt(0): _voidHandler(0), // TODO: Application Keypad
  47. };
  48. AnsiHandler _voidHandler(int sequenceLength) {
  49. return (queue, terminal) {
  50. if (queue.length < sequenceLength) {
  51. return false;
  52. }
  53. for (var i = 0; i < sequenceLength; i++) {
  54. queue.removeFirst();
  55. }
  56. return true;
  57. };
  58. }
  59. bool _unsupportedHandler(Queue<int> queue, Terminal terminal) {
  60. // print('unimplemented ansi sequence.');
  61. return true;
  62. }
  63. bool _ansiSaveCursorHandler(Queue<int> queue, Terminal terminal) {
  64. terminal.buffer.saveCursor();
  65. return true;
  66. }
  67. bool _ansiRestoreCursorHandler(Queue<int> queue, Terminal terminal) {
  68. terminal.buffer.restoreCursor();
  69. return true;
  70. }
  71. /// https://vt100.net/docs/vt100-ug/chapter3.html#IND IND – Index
  72. ///
  73. /// ESC D
  74. ///
  75. /// This sequence causes the active position to move downward one line without
  76. /// changing the column position. If the active position is at the bottom
  77. /// margin, a scroll up is performed.
  78. bool _ansiIndexHandler(Queue<int> queue, Terminal terminal) {
  79. terminal.buffer.index();
  80. return true;
  81. }
  82. bool _ansiReverseIndexHandler(Queue<int> queue, Terminal terminal) {
  83. terminal.buffer.reverseIndex();
  84. return true;
  85. }
  86. /// SCS – Select Character Set
  87. ///
  88. /// The appropriate G0 and G1 character sets are designated from one of the five
  89. /// possible character sets. The G0 and G1 sets are invoked by the codes SI and
  90. /// SO (shift in and shift out) respectively.
  91. AnsiHandler _scsHandler(int which) {
  92. return (Queue<int> queue, Terminal terminal) {
  93. // The sequence isn't completed, just ignore it.
  94. if (queue.isEmpty) {
  95. return false;
  96. }
  97. final name = queue.removeFirst();
  98. terminal.buffer.charset.designate(which, name);
  99. return true;
  100. };
  101. }
  102. bool _ansiNextLineHandler(Queue<int> queue, Terminal terminal) {
  103. terminal.buffer.newLine();
  104. terminal.buffer.setCursorX(0);
  105. return true;
  106. }
  107. bool _ansiTabSetHandler(Queue<int> queue, Terminal terminal) {
  108. terminal.tabSetAtCursor();
  109. return true;
  110. }