sgr.dart 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. import 'package:xterm/buffer/cell_flags.dart';
  2. import 'package:xterm/theme/terminal_color.dart';
  3. import 'package:xterm/terminal/csi.dart';
  4. import 'package:xterm/terminal/terminal.dart';
  5. import 'package:xterm/util/lookup_table.dart';
  6. /// SGR selects one or more character attributes at the same time.
  7. /// Multiple params (up to 32) are applied from in order from left to right.
  8. /// The changed attributes are applied to all new characters received.
  9. /// If you move characters in the viewport by scrolling or any other means,
  10. /// then the attributes move with the characters.
  11. void sgrHandler(CSI csi, Terminal terminal) {
  12. final params = csi.params.toList();
  13. if (params.isEmpty) {
  14. params.add(0);
  15. }
  16. for (var i = 0; i < params.length; i++) {
  17. final param = params[i];
  18. switch (param) {
  19. case 0:
  20. terminal.cursor.fg = terminal.theme.foreground;
  21. terminal.cursor.bg = TerminalColor.transparent;
  22. terminal.cursor.flags = 0x00;
  23. break;
  24. case 1:
  25. terminal.cursor.flags |= CellFlags.bold;
  26. break;
  27. case 2:
  28. terminal.cursor.flags |= CellFlags.faint;
  29. break;
  30. case 3:
  31. terminal.cursor.flags |= CellFlags.italic;
  32. break;
  33. case 4:
  34. terminal.cursor.flags |= CellFlags.underline;
  35. break;
  36. case 5:
  37. terminal.cursor.flags |= CellFlags.blink;
  38. break;
  39. case 7:
  40. terminal.cursor.flags |= CellFlags.inverse;
  41. break;
  42. case 8:
  43. terminal.cursor.flags |= CellFlags.invisible;
  44. break;
  45. case 21:
  46. terminal.cursor.flags &= ~CellFlags.bold;
  47. break;
  48. case 22:
  49. terminal.cursor.flags &= ~CellFlags.faint;
  50. break;
  51. case 23:
  52. terminal.cursor.flags &= ~CellFlags.italic;
  53. break;
  54. case 24:
  55. terminal.cursor.flags &= ~CellFlags.underline;
  56. break;
  57. case 25:
  58. terminal.cursor.flags &= ~CellFlags.blink;
  59. break;
  60. case 27:
  61. terminal.cursor.flags &= ~CellFlags.inverse;
  62. break;
  63. case 28:
  64. terminal.cursor.flags &= ~CellFlags.invisible;
  65. break;
  66. case 29:
  67. // not strikethrough
  68. break;
  69. case 39:
  70. terminal.cursor.fg = terminal.theme.foreground;
  71. break;
  72. case 30:
  73. terminal.cursor.fg = terminal.theme.black;
  74. break;
  75. case 31:
  76. terminal.cursor.fg = terminal.theme.red;
  77. break;
  78. case 32:
  79. terminal.cursor.fg = terminal.theme.green;
  80. break;
  81. case 33:
  82. terminal.cursor.fg = terminal.theme.yellow;
  83. break;
  84. case 34:
  85. terminal.cursor.fg = terminal.theme.blue;
  86. break;
  87. case 35:
  88. terminal.cursor.fg = terminal.theme.magenta;
  89. break;
  90. case 36:
  91. terminal.cursor.fg = terminal.theme.cyan;
  92. break;
  93. case 37:
  94. terminal.cursor.fg = terminal.theme.white;
  95. break;
  96. case 90:
  97. terminal.cursor.fg = terminal.theme.brightBlack;
  98. break;
  99. case 91:
  100. terminal.cursor.fg = terminal.theme.brightRed;
  101. break;
  102. case 92:
  103. terminal.cursor.fg = terminal.theme.brightGreen;
  104. break;
  105. case 93:
  106. terminal.cursor.fg = terminal.theme.brightYellow;
  107. break;
  108. case 94:
  109. terminal.cursor.fg = terminal.theme.brightBlue;
  110. break;
  111. case 95:
  112. terminal.cursor.fg = terminal.theme.brightMagenta;
  113. break;
  114. case 96:
  115. terminal.cursor.fg = terminal.theme.brightCyan;
  116. break;
  117. case 97:
  118. terminal.cursor.fg = terminal.theme.brightWhite;
  119. break;
  120. case 49:
  121. terminal.cursor.bg = terminal.theme.background;
  122. break;
  123. case 40:
  124. terminal.cursor.bg = terminal.theme.black;
  125. break;
  126. case 41:
  127. terminal.cursor.bg = terminal.theme.red;
  128. break;
  129. case 42:
  130. terminal.cursor.bg = terminal.theme.green;
  131. break;
  132. case 43:
  133. terminal.cursor.bg = terminal.theme.yellow;
  134. break;
  135. case 44:
  136. terminal.cursor.bg = terminal.theme.blue;
  137. break;
  138. case 45:
  139. terminal.cursor.bg = terminal.theme.magenta;
  140. break;
  141. case 46:
  142. terminal.cursor.bg = terminal.theme.cyan;
  143. break;
  144. case 47:
  145. terminal.cursor.bg = terminal.theme.white;
  146. break;
  147. case 100:
  148. terminal.cursor.bg = terminal.theme.brightBlack;
  149. break;
  150. case 101:
  151. terminal.cursor.bg = terminal.theme.brightRed;
  152. break;
  153. case 102:
  154. terminal.cursor.bg = terminal.theme.brightGreen;
  155. break;
  156. case 103:
  157. terminal.cursor.bg = terminal.theme.brightYellow;
  158. break;
  159. case 104:
  160. terminal.cursor.bg = terminal.theme.brightBlue;
  161. break;
  162. case 105:
  163. terminal.cursor.bg = terminal.theme.brightMagenta;
  164. break;
  165. case 106:
  166. terminal.cursor.bg = terminal.theme.brightCyan;
  167. break;
  168. case 107:
  169. terminal.cursor.bg = terminal.theme.brightWhite;
  170. break;
  171. case 38: // set foreground
  172. final colorResult = parseAnsiColour(params, i, terminal);
  173. terminal.cursor.fg = colorResult[0];
  174. i += colorResult[1];
  175. break;
  176. case 48: // set background
  177. final colorResult = parseAnsiColour(params, i, terminal);
  178. terminal.cursor.bg = colorResult[0];
  179. i += colorResult[1];
  180. break;
  181. default:
  182. terminal.debug.onError('unknown SGR: $param');
  183. }
  184. }
  185. }
  186. /// parse a color from [params] starting from [offset].
  187. /// Returns a list with 2 entries. Index 0 = color, Index 1 = number of params used
  188. List<int> parseAnsiColour(List<int> params, int offset, Terminal terminal) {
  189. final length = params.length - offset;
  190. if (length > 2) {
  191. switch (params[offset + 1]) {
  192. case 5:
  193. // 8 bit colour
  194. final colNum = params[offset + 2];
  195. if (colNum >= 256 || colNum < 0) {
  196. return [TerminalColor.empty(), 2];
  197. }
  198. return [parse8BitSgrColour(colNum, terminal), 2];
  199. case 2:
  200. if (length < 4) {
  201. return [TerminalColor.empty(), 0];
  202. }
  203. // 24 bit colour
  204. if (length == 5) {
  205. final r = params[offset + 2];
  206. final g = params[offset + 3];
  207. final b = params[offset + 4];
  208. return [TerminalColor.fromARGB(0xff, r, g, b), 4];
  209. }
  210. if (length > 5) {
  211. // ISO/IEC International Standard 8613-6
  212. final r = params[offset + 3];
  213. final g = params[offset + 4];
  214. final b = params[offset + 5];
  215. return [TerminalColor.fromARGB(0xff, r, g, b), 5];
  216. }
  217. }
  218. }
  219. return [TerminalColor.empty(), 0];
  220. }
  221. final grayscaleColors = FastLookupTable({
  222. 232: 0xff080808,
  223. 233: 0xff121212,
  224. 234: 0xff1c1c1c,
  225. 235: 0xff262626,
  226. 236: 0xff303030,
  227. 237: 0xff3a3a3a,
  228. 238: 0xff444444,
  229. 239: 0xff4e4e4e,
  230. 240: 0xff585858,
  231. 241: 0xff626262,
  232. 242: 0xff6c6c6c,
  233. 243: 0xff767676,
  234. 244: 0xff808080,
  235. 245: 0xff8a8a8a,
  236. 246: 0xff949494,
  237. 247: 0xff9e9e9e,
  238. 248: 0xffa8a8a8,
  239. 249: 0xffb2b2b2,
  240. 250: 0xffbcbcbc,
  241. 251: 0xffc6c6c6,
  242. 252: 0xffd0d0d0,
  243. 253: 0xffdadada,
  244. 254: 0xffe4e4e4,
  245. 255: 0xffeeeeee,
  246. });
  247. int parse8BitSgrColour(int colNum, Terminal terminal) {
  248. // https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
  249. switch (colNum) {
  250. case 0:
  251. return terminal.theme.black;
  252. case 1:
  253. return terminal.theme.red;
  254. case 2:
  255. return terminal.theme.green;
  256. case 3:
  257. return terminal.theme.yellow;
  258. case 4:
  259. return terminal.theme.blue;
  260. case 5:
  261. return terminal.theme.magenta;
  262. case 6:
  263. return terminal.theme.cyan;
  264. case 7:
  265. return terminal.theme.white;
  266. case 8:
  267. return terminal.theme.brightBlack;
  268. case 9:
  269. return terminal.theme.brightRed;
  270. case 10:
  271. return terminal.theme.brightGreen;
  272. case 11:
  273. return terminal.theme.brightYellow;
  274. case 12:
  275. return terminal.theme.brightBlue;
  276. case 13:
  277. return terminal.theme.brightMagenta;
  278. case 14:
  279. return terminal.theme.brightCyan;
  280. case 15:
  281. return terminal.theme.white;
  282. }
  283. if (colNum < 232) {
  284. var r = 0;
  285. var g = 0;
  286. var b = 0;
  287. final index = colNum - 16;
  288. for (var i = 0; i < index; i++) {
  289. if (b == 0) {
  290. b = 95;
  291. } else if (b < 255) {
  292. b += 40;
  293. } else {
  294. b = 0;
  295. if (g == 0) {
  296. g = 95;
  297. } else if (g < 255) {
  298. g += 40;
  299. } else {
  300. g = 0;
  301. if (r == 0) {
  302. r = 95;
  303. } else if (r < 255) {
  304. r += 40;
  305. } else {
  306. break;
  307. }
  308. }
  309. }
  310. }
  311. return TerminalColor.fromARGB(0xff, r, g, b);
  312. }
  313. return grayscaleColors[colNum.clamp(232, 255)]!;
  314. }