@@ -248,6 +248,138 @@ class MessageImage extends StatelessWidget {
248
248
}
249
249
}
250
250
251
+ // Highlighted code block styles adapted from:
252
+ // https://github.com/zulip/zulip/blob/213387249e7ba7772084411b22d8cef64b135dd0/web/styles/pygments.css
253
+
254
+ // .hll { background-color: hsl(60deg 100% 90%); }
255
+ final _kCodeBlockStyleHll = TextStyle (backgroundColor: const HSLColor .fromAHSL (1 , 60 , 1 , 0.90 ).toColor ());
256
+ // .c { color: hsl(180deg 33% 37%); font-style: italic; }
257
+ final _kCodeBlockStyleC = TextStyle (color: const HSLColor .fromAHSL (1 , 180 , 0.33 , 0.37 ).toColor (), fontStyle: FontStyle .italic);
258
+ // TODO: Borders are hard in TextSpan, see the comment in `_buildInlineCode`
259
+ // So, using a lighter background color for now (precisely it's
260
+ // the text color used in web app in `.err` class in dark mode)
261
+ //
262
+ // .err { border: 1px solid hsl(0deg 100% 50%); }
263
+ const _kCodeBlockStyleErr = TextStyle (backgroundColor: Color (0xffe2706e ));
264
+ // .k { color: hsl(332deg 70% 38%); }
265
+ final _kCodeBlockStyleK = TextStyle (color: const HSLColor .fromAHSL (1 , 332 , 0.7 , 0.38 ).toColor ());
266
+ // .o { color: hsl(332deg 70% 38%); }
267
+ final _kCodeBlockStyleO = TextStyle (color: const HSLColor .fromAHSL (1 , 332 , 0.7 , 0.38 ).toColor ());
268
+ // .cm { color: hsl(180deg 33% 37%); font-style: italic; }
269
+ final _kCodeBlockStyleCm = TextStyle (color: const HSLColor .fromAHSL (1 , 180 , 0.33 , 0.37 ).toColor (), fontStyle: FontStyle .italic);
270
+ // .cp { color: hsl(38deg 100% 36%); }
271
+ final _kCodeBlockStyleCp = TextStyle (color: const HSLColor .fromAHSL (1 , 38 , 1 , 0.36 ).toColor ());
272
+ // .c1 { color: hsl(0deg 0% 67%); font-style: italic; }
273
+ final _kCodeBlockStyleC1 = TextStyle (color: const HSLColor .fromAHSL (1 , 0 , 0 , 0.67 ).toColor (), fontStyle: FontStyle .italic);
274
+ // .cs { color: hsl(180deg 33% 37%); font-style: italic; }
275
+ final _kCodeBlockStyleCs = TextStyle (color: const HSLColor .fromAHSL (1 , 180 , 0.33 , 0.37 ).toColor (), fontStyle: FontStyle .italic);
276
+ // .gd { color: hsl(0deg 100% 31%); }
277
+ final _kCodeBlockStyleGd = TextStyle (color: const HSLColor .fromAHSL (1 , 0 , 1 , 0.31 ).toColor ());
278
+ // .ge { font-style: italic; }
279
+ const _kCodeBlockStyleGe = TextStyle (fontStyle: FontStyle .italic);
280
+ // .gr { color: hsl(0deg 100% 50%); }
281
+ final _kCodeBlockStyleGr = TextStyle (color: const HSLColor .fromAHSL (1 , 0 , 1 , 0.50 ).toColor ());
282
+ // .gh { color: hsl(240deg 100% 25%); font-weight: bold; }
283
+ final _kCodeBlockStyleGh = TextStyle (color: const HSLColor .fromAHSL (1 , 240 , 1 , 0.25 ).toColor (), fontWeight: FontWeight .bold);
284
+ // .gi { color: hsl(120deg 100% 31%); }
285
+ final _kCodeBlockStyleGi = TextStyle (color: const HSLColor .fromAHSL (1 , 120 , 1 , 0.31 ).toColor ());
286
+ // .go { color: hsl(0deg 0% 50%); }
287
+ final _kCodeBlockStyleGo = TextStyle (color: const HSLColor .fromAHSL (1 , 0 , 0 , 0.50 ).toColor ());
288
+ // .gp { color: hsl(240deg 100% 25%); font-weight: bold; }
289
+ final _kCodeBlockStyleGp = TextStyle (color: const HSLColor .fromAHSL (1 , 240 , 1 , 0.25 ).toColor (), fontWeight: FontWeight .bold);
290
+ // .gs { font-weight: bold; }
291
+ const _kCodeBlockStyleGs = TextStyle (fontWeight: FontWeight .bold);
292
+ // .gu { color: hsl(300deg 100% 25%); font-weight: bold; }
293
+ final _kCodeBlockStyleGu = TextStyle (color: const HSLColor .fromAHSL (1 , 300 , 1 , 0.25 ).toColor (), fontWeight: FontWeight .bold);
294
+ // .gt { color: hsl(221deg 100% 40%); }
295
+ final _kCodeBlockStyleGt = TextStyle (color: const HSLColor .fromAHSL (1 , 221 , 1 , 0.40 ).toColor ());
296
+ // .kc { color: hsl(332deg 70% 38%); font-weight: bold; }
297
+ final _kCodeBlockStyleKc = TextStyle (color: const HSLColor .fromAHSL (1 , 332 , 0.70 , 0.38 ).toColor (), fontWeight: FontWeight .bold);
298
+ // .kd { color: hsl(332deg 70% 38%); }
299
+ final _kCodeBlockStyleKd = TextStyle (color: const HSLColor .fromAHSL (1 , 332 , 0.70 , 0.38 ).toColor ());
300
+ // .kn { color: hsl(332deg 70% 38%); font-weight: bold; }
301
+ final _kCodeBlockStyleKn = TextStyle (color: const HSLColor .fromAHSL (1 , 332 , 0.70 , 0.38 ).toColor (), fontWeight: FontWeight .bold);
302
+ // .kp { color: hsl(332deg 70% 38%); }
303
+ final _kCodeBlockStyleKp = TextStyle (color: const HSLColor .fromAHSL (1 , 332 , 0.70 , 0.38 ).toColor ());
304
+ // .kr { color: hsl(332deg 70% 38%); font-weight: bold; }
305
+ final _kCodeBlockStyleKr = TextStyle (color: const HSLColor .fromAHSL (1 , 332 , 0.70 , 0.38 ).toColor (), fontWeight: FontWeight .bold);
306
+ // .kt { color: hsl(332deg 70% 38%); }
307
+ final _kCodeBlockStyleKt = TextStyle (color: const HSLColor .fromAHSL (1 , 332 , 0.70 , 0.38 ).toColor ());
308
+ // .m { color: hsl(0deg 0% 40%); }
309
+ final _kCodeBlockStyleM = TextStyle (color: const HSLColor .fromAHSL (1 , 0 , 0 , 0.40 ).toColor ());
310
+ // .s { color: hsl(86deg 57% 40%); }
311
+ final _kCodeBlockStyleS = TextStyle (color: const HSLColor .fromAHSL (1 , 86 , 0.57 , 0.40 ).toColor ());
312
+ // .na { color: hsl(71deg 55% 36%); }
313
+ final _kCodeBlockStyleNa = TextStyle (color: const HSLColor .fromAHSL (1 , 71 , 0.55 , 0.36 ).toColor ());
314
+ // .nb { color: hsl(195deg 100% 35%); }
315
+ final _kCodeBlockStyleNb = TextStyle (color: const HSLColor .fromAHSL (1 , 195 , 1 , 0.35 ).toColor ());
316
+ // .nc { color: hsl(264deg 27% 50%); font-weight: bold; }
317
+ final _kCodeBlockStyleNc = TextStyle (color: const HSLColor .fromAHSL (1 , 264 , 0.27 , 0.50 ).toColor (), fontWeight: FontWeight .bold);
318
+ // .no { color: hsl(0deg 100% 26%); }
319
+ final _kCodeBlockStyleNo = TextStyle (color: const HSLColor .fromAHSL (1 , 0 , 1 , 0.26 ).toColor ());
320
+ // .nd { color: hsl(276deg 100% 56%); }
321
+ final _kCodeBlockStyleNd = TextStyle (color: const HSLColor .fromAHSL (1 , 276 , 1 , 0.56 ).toColor ());
322
+ // .ni { color: hsl(0deg 0% 60%); font-weight: bold; }
323
+ final _kCodeBlockStyleNi = TextStyle (color: const HSLColor .fromAHSL (1 , 0 , 0 , 0.60 ).toColor (), fontWeight: FontWeight .bold);
324
+ // .ne { color: hsl(2deg 62% 52%); font-weight: bold; }
325
+ final _kCodeBlockStyleNe = TextStyle (color: const HSLColor .fromAHSL (1 , 2 , 0.62 , 0.52 ).toColor (), fontWeight: FontWeight .bold);
326
+ // .nf { color: hsl(264deg 27% 50%); }
327
+ final _kCodeBlockStyleNf = TextStyle (color: const HSLColor .fromAHSL (1 , 264 , 0.27 , 0.50 ).toColor ());
328
+ // .nl { color: hsl(60deg 100% 31%); }
329
+ final _kCodeBlockStyleNl = TextStyle (color: const HSLColor .fromAHSL (1 , 60 , 1 , 0.31 ).toColor ());
330
+ // .nn { color: hsl(264deg 27% 50%); font-weight: bold; }
331
+ final _kCodeBlockStyleNn = TextStyle (color: const HSLColor .fromAHSL (1 , 264 , 0.27 , 0.50 ).toColor (), fontWeight: FontWeight .bold);
332
+ // .nt { color: hsl(120deg 100% 25%); font-weight: bold; }
333
+ final _kCodeBlockStyleNt = TextStyle (color: const HSLColor .fromAHSL (1 , 120 , 1 , 0.25 ).toColor (), fontWeight: FontWeight .bold);
334
+ // .nv { color: hsl(241deg 68% 28%); }
335
+ final _kCodeBlockStyleNv = TextStyle (color: const HSLColor .fromAHSL (1 , 241 , 0.68 , 0.28 ).toColor ());
336
+ // .nx { color: hsl(0deg 0% 26%); }
337
+ final _kCodeBlockStyleNx = TextStyle (color: const HSLColor .fromAHSL (1 , 0 , 0 , 0.26 ).toColor ());
338
+ // .ow { color: hsl(276deg 100% 56%); font-weight: bold; }
339
+ final _kCodeBlockStyleOw = TextStyle (color: const HSLColor .fromAHSL (1 , 276 , 1 , 0.56 ).toColor (), fontWeight: FontWeight .bold);
340
+ // .w { color: hsl(0deg 0% 73%); }
341
+ final _kCodeBlockStyleW = TextStyle (color: const HSLColor .fromAHSL (1 , 0 , 0 , 0.73 ).toColor ());
342
+ // .mf { color: hsl(195deg 100% 35%); }
343
+ final _kCodeBlockStyleMf = TextStyle (color: const HSLColor .fromAHSL (1 , 195 , 1 , 0.35 ).toColor ());
344
+ // .mh { color: hsl(195deg 100% 35%); }
345
+ final _kCodeBlockStyleMh = TextStyle (color: const HSLColor .fromAHSL (1 , 195 , 1 , 0.35 ).toColor ());
346
+ // .mi { color: hsl(195deg 100% 35%); }
347
+ final _kCodeBlockStyleMi = TextStyle (color: const HSLColor .fromAHSL (1 , 195 , 1 , 0.35 ).toColor ());
348
+ // .mo { color: hsl(195deg 100% 35%); }
349
+ final _kCodeBlockStyleMo = TextStyle (color: const HSLColor .fromAHSL (1 , 195 , 1 , 0.35 ).toColor ());
350
+ // .sb { color: hsl(86deg 57% 40%); }
351
+ final _kCodeBlockStyleSb = TextStyle (color: const HSLColor .fromAHSL (1 , 86 , 0.57 , 0.40 ).toColor ());
352
+ // .sc { color: hsl(86deg 57% 40%); }
353
+ final _kCodeBlockStyleSc = TextStyle (color: const HSLColor .fromAHSL (1 , 86 , 0.57 , 0.40 ).toColor ());
354
+ // .sd { color: hsl(86deg 57% 40%); font-style: italic; }
355
+ final _kCodeBlockStyleSd = TextStyle (color: const HSLColor .fromAHSL (1 , 86 , 0.57 , 0.40 ).toColor (), fontStyle: FontStyle .italic);
356
+ // .s2 { color: hsl(225deg 71% 33%); }
357
+ final _kCodeBlockStyleS2 = TextStyle (color: const HSLColor .fromAHSL (1 , 225 , 0.71 , 0.33 ).toColor ());
358
+ // .se { color: hsl(26deg 69% 43%); font-weight: bold; }
359
+ final _kCodeBlockStyleSe = TextStyle (color: const HSLColor .fromAHSL (1 , 26 , 0.69 , 0.43 ).toColor (), fontWeight: FontWeight .bold);
360
+ // .sh { color: hsl(86deg 57% 40%); }
361
+ final _kCodeBlockStyleSh = TextStyle (color: const HSLColor .fromAHSL (1 , 86 , 0.57 , 0.40 ).toColor ());
362
+ // .si { color: hsl(336deg 38% 56%); font-weight: bold; }
363
+ final _kCodeBlockStyleSi = TextStyle (color: const HSLColor .fromAHSL (1 , 336 , 0.38 , 0.56 ).toColor (), fontWeight: FontWeight .bold);
364
+ // .sx { color: hsl(120deg 100% 25%); }
365
+ final _kCodeBlockStyleSx = TextStyle (color: const HSLColor .fromAHSL (1 , 120 , 1 , 0.25 ).toColor ());
366
+ // .sr { color: hsl(189deg 54% 49%); }
367
+ final _kCodeBlockStyleSr = TextStyle (color: const HSLColor .fromAHSL (1 , 189 , 0.54 , 0.49 ).toColor ());
368
+ // .s1 { color: hsl(86deg 57% 40%); }
369
+ final _kCodeBlockStyleS1 = TextStyle (color: const HSLColor .fromAHSL (1 , 86 , 0.57 , 0.40 ).toColor ());
370
+ // .ss { color: hsl(241deg 68% 28%); }
371
+ final _kCodeBlockStyleSs = TextStyle (color: const HSLColor .fromAHSL (1 , 241 , 0.68 , 0.28 ).toColor ());
372
+ // .bp { color: hsl(120deg 100% 25%); }
373
+ final _kCodeBlockStyleBp = TextStyle (color: const HSLColor .fromAHSL (1 , 120 , 1 , 0.25 ).toColor ());
374
+ // .vc { color: hsl(241deg 68% 28%); }
375
+ final _kCodeBlockStyleVc = TextStyle (color: const HSLColor .fromAHSL (1 , 241 , 0.68 , 0.28 ).toColor ());
376
+ // .vg { color: hsl(241deg 68% 28%); }
377
+ final _kCodeBlockStyleVg = TextStyle (color: const HSLColor .fromAHSL (1 , 241 , 0.68 , 0.28 ).toColor ());
378
+ // .vi { color: hsl(241deg 68% 28%); }
379
+ final _kCodeBlockStyleVi = TextStyle (color: const HSLColor .fromAHSL (1 , 241 , 0.68 , 0.28 ).toColor ());
380
+ // .il { color: hsl(0deg 0% 40%); }
381
+ final _kCodeBlockStyleIl = TextStyle (color: const HSLColor .fromAHSL (1 , 0 , 0 , 0.40 ).toColor ());
382
+
251
383
class CodeBlock extends StatelessWidget {
252
384
const CodeBlock ({super .key, required this .node});
253
385
@@ -287,8 +419,74 @@ class CodeBlock extends StatelessWidget {
287
419
}
288
420
289
421
InlineSpan _buildNode (CodeBlockSpanNode node) {
290
- // TODO: generate text styles for each node based on token type
291
- return TextSpan (text: node.text);
422
+ final style = switch (node.tokenType) {
423
+ CodeBlockSpanToken .text => null , // styles not applied for Text token
424
+ CodeBlockSpanToken .highlightedLines => _kCodeBlockStyleHll,
425
+ CodeBlockSpanToken .comment => _kCodeBlockStyleC,
426
+ CodeBlockSpanToken .error => _kCodeBlockStyleErr,
427
+ CodeBlockSpanToken .keyword => _kCodeBlockStyleK,
428
+ CodeBlockSpanToken .operator => _kCodeBlockStyleO,
429
+ CodeBlockSpanToken .commentMultiline => _kCodeBlockStyleCm,
430
+ CodeBlockSpanToken .commentPreproc => _kCodeBlockStyleCp,
431
+ CodeBlockSpanToken .commentSingle => _kCodeBlockStyleC1,
432
+ CodeBlockSpanToken .commentSpecial => _kCodeBlockStyleCs,
433
+ CodeBlockSpanToken .genericDeleted => _kCodeBlockStyleGd,
434
+ CodeBlockSpanToken .genericEmph => _kCodeBlockStyleGe,
435
+ CodeBlockSpanToken .genericError => _kCodeBlockStyleGr,
436
+ CodeBlockSpanToken .genericHeading => _kCodeBlockStyleGh,
437
+ CodeBlockSpanToken .genericInserted => _kCodeBlockStyleGi,
438
+ CodeBlockSpanToken .genericOutput => _kCodeBlockStyleGo,
439
+ CodeBlockSpanToken .genericPrompt => _kCodeBlockStyleGp,
440
+ CodeBlockSpanToken .genericStrong => _kCodeBlockStyleGs,
441
+ CodeBlockSpanToken .genericSubheading => _kCodeBlockStyleGu,
442
+ CodeBlockSpanToken .genericTraceback => _kCodeBlockStyleGt,
443
+ CodeBlockSpanToken .keywordConstant => _kCodeBlockStyleKc,
444
+ CodeBlockSpanToken .keywordDeclaration => _kCodeBlockStyleKd,
445
+ CodeBlockSpanToken .keywordNamespace => _kCodeBlockStyleKn,
446
+ CodeBlockSpanToken .keywordPseudo => _kCodeBlockStyleKp,
447
+ CodeBlockSpanToken .keywordReserved => _kCodeBlockStyleKr,
448
+ CodeBlockSpanToken .keywordType => _kCodeBlockStyleKt,
449
+ CodeBlockSpanToken .number => _kCodeBlockStyleM,
450
+ CodeBlockSpanToken .string => _kCodeBlockStyleS,
451
+ CodeBlockSpanToken .nameAttribute => _kCodeBlockStyleNa,
452
+ CodeBlockSpanToken .nameBuiltin => _kCodeBlockStyleNb,
453
+ CodeBlockSpanToken .nameClass => _kCodeBlockStyleNc,
454
+ CodeBlockSpanToken .nameConstant => _kCodeBlockStyleNo,
455
+ CodeBlockSpanToken .nameDecorator => _kCodeBlockStyleNd,
456
+ CodeBlockSpanToken .nameEntity => _kCodeBlockStyleNi,
457
+ CodeBlockSpanToken .nameException => _kCodeBlockStyleNe,
458
+ CodeBlockSpanToken .nameFunction => _kCodeBlockStyleNf,
459
+ CodeBlockSpanToken .nameLabel => _kCodeBlockStyleNl,
460
+ CodeBlockSpanToken .nameNamespace => _kCodeBlockStyleNn,
461
+ CodeBlockSpanToken .nameTag => _kCodeBlockStyleNt,
462
+ CodeBlockSpanToken .nameVariable => _kCodeBlockStyleNv,
463
+ CodeBlockSpanToken .nameOther => _kCodeBlockStyleNx,
464
+ CodeBlockSpanToken .operatorWord => _kCodeBlockStyleOw,
465
+ CodeBlockSpanToken .whitespace => _kCodeBlockStyleW,
466
+ CodeBlockSpanToken .numberFloat => _kCodeBlockStyleMf,
467
+ CodeBlockSpanToken .numberHex => _kCodeBlockStyleMh,
468
+ CodeBlockSpanToken .numberInteger => _kCodeBlockStyleMi,
469
+ CodeBlockSpanToken .numberOct => _kCodeBlockStyleMo,
470
+ CodeBlockSpanToken .stringBacktick => _kCodeBlockStyleSb,
471
+ CodeBlockSpanToken .stringChar => _kCodeBlockStyleSc,
472
+ CodeBlockSpanToken .stringDoc => _kCodeBlockStyleSd,
473
+ CodeBlockSpanToken .stringDouble => _kCodeBlockStyleS2,
474
+ CodeBlockSpanToken .stringEscape => _kCodeBlockStyleSe,
475
+ CodeBlockSpanToken .stringHeredoc => _kCodeBlockStyleSh,
476
+ CodeBlockSpanToken .stringInterpol => _kCodeBlockStyleSi,
477
+ CodeBlockSpanToken .stringOther => _kCodeBlockStyleSx,
478
+ CodeBlockSpanToken .stringRegex => _kCodeBlockStyleSr,
479
+ CodeBlockSpanToken .stringSingle => _kCodeBlockStyleS1,
480
+ CodeBlockSpanToken .stringSymbol => _kCodeBlockStyleSs,
481
+ CodeBlockSpanToken .nameBuiltinPseudo => _kCodeBlockStyleBp,
482
+ CodeBlockSpanToken .nameVariableClass => _kCodeBlockStyleVc,
483
+ CodeBlockSpanToken .nameVariableGlobal => _kCodeBlockStyleVg,
484
+ CodeBlockSpanToken .nameVariableInstance => _kCodeBlockStyleVi,
485
+ CodeBlockSpanToken .numberIntegerLong => _kCodeBlockStyleIl,
486
+ _ => null , // not every token is styled
487
+ };
488
+
489
+ return TextSpan (text: node.text, style: style);
292
490
}
293
491
}
294
492
0 commit comments