sgr.dart 9.3 KB

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