ansiparser.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /* eslint-disable no-plusplus, no-continue */
  2. const foregroundColors = {
  3. "30": "black",
  4. "31": "red",
  5. "32": "green",
  6. "33": "yellow",
  7. "34": "blue",
  8. "35": "magenta",
  9. "36": "cyan",
  10. "37": "white",
  11. "90": "grey",
  12. } as Record<string, string>;
  13. const backgroundColors = {
  14. "40": "black",
  15. "41": "red",
  16. "42": "green",
  17. "43": "yellow",
  18. "44": "blue",
  19. "45": "magenta",
  20. "46": "cyan",
  21. "47": "white",
  22. } as Record<string, string>;
  23. const styles = {
  24. "1": "bold",
  25. "3": "italic",
  26. "4": "underline",
  27. } as Record<string, string>;
  28. const eraseChar = (matchingText: any, result: any) => {
  29. if (matchingText.length) {
  30. return [matchingText.substr(0, matchingText.length - 1), result];
  31. } else if (result.length) {
  32. const index = result.length - 1;
  33. const { text } = result[index];
  34. const newResult =
  35. text.length === 1
  36. ? result.slice(0, result.length - 1)
  37. : result.map((item: any, i: number) =>
  38. index === i
  39. ? { ...item, text: text.substr(0, text.length - 1) }
  40. : item
  41. );
  42. return [matchingText, newResult];
  43. }
  44. return [matchingText, result];
  45. };
  46. const ansiparse = (str: string) => {
  47. let matchingControl = null;
  48. let matchingData = null;
  49. let matchingText = "";
  50. let ansiState = [] as any[];
  51. let result = [] as any[];
  52. let state = {} as any;
  53. for (let i = 0; i < str.length; i++) {
  54. if (matchingControl !== null) {
  55. if (matchingControl === "\x1b" && str[i] === "[") {
  56. if (matchingText) {
  57. state.text = matchingText;
  58. result.push(state);
  59. state = {};
  60. matchingText = "";
  61. }
  62. matchingControl = null;
  63. matchingData = "";
  64. } else {
  65. matchingText += matchingControl + str[i];
  66. matchingControl = null;
  67. }
  68. continue;
  69. } else if (matchingData !== null) {
  70. if (str[i] === ";") {
  71. ansiState.push(matchingData);
  72. matchingData = "";
  73. } else if (str[i] === "m") {
  74. ansiState.push(matchingData);
  75. matchingData = null;
  76. matchingText = "";
  77. for (let a = 0; a < ansiState.length; a++) {
  78. const ansiCode = ansiState[a];
  79. if (foregroundColors[ansiCode]) {
  80. state.foreground = foregroundColors[ansiCode];
  81. } else if (backgroundColors[ansiCode]) {
  82. state.background = backgroundColors[ansiCode];
  83. } else if (ansiCode === 39) {
  84. delete state.foreground;
  85. } else if (ansiCode === 49) {
  86. delete state.background;
  87. } else if (styles[ansiCode]) {
  88. state[styles[ansiCode]] = true;
  89. } else if (ansiCode === 22) {
  90. state.bold = false;
  91. } else if (ansiCode === 23) {
  92. state.italic = false;
  93. } else if (ansiCode === 24) {
  94. state.underline = false;
  95. }
  96. }
  97. ansiState = [];
  98. } else {
  99. matchingData += str[i];
  100. }
  101. continue;
  102. }
  103. if (str[i] === "\x1b") {
  104. matchingControl = str[i];
  105. } else if (str[i] === "\u0008") {
  106. [matchingText, result] = eraseChar(matchingText, result);
  107. } else {
  108. matchingText += str[i];
  109. }
  110. }
  111. if (matchingText) {
  112. state.text = matchingText + (matchingControl || "");
  113. result.push(state);
  114. }
  115. return result;
  116. };
  117. export default ansiparse;