sgr.dart 9.3 KB

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