1 /** 2 * Functions for raising errors. 3 * 4 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errors.d, _errors.d) 8 * Documentation: https://dlang.org/phobos/dmd_errors.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/errors.d 10 */ 11 12 module dmd.errors; 13 14 import core.stdc.stdarg; 15 import core.stdc.stdio; 16 import core.stdc.stdlib; 17 import core.stdc.string; 18 import dmd.globals; 19 import dmd.root.outbuffer; 20 import dmd.root.rmem; 21 import dmd.root.string; 22 import dmd.console; 23 24 nothrow: 25 26 /** 27 * Color highlighting to classify messages 28 */ 29 enum Classification 30 { 31 error = Color.brightRed, /// for errors 32 gagged = Color.brightBlue, /// for gagged errors 33 warning = Color.brightYellow, /// for warnings 34 deprecation = Color.brightCyan, /// for deprecations 35 tip = Color.brightGreen, /// for tip messages 36 } 37 38 /** 39 * Print an error message, increasing the global error count. 40 * Params: 41 * loc = location of error 42 * format = printf-style format specification 43 * ... = printf-style variadic arguments 44 */ 45 static if (__VERSION__ < 2092) 46 extern (C++) void error(const ref Loc loc, const(char)* format, ...) 47 { 48 va_list ap; 49 va_start(ap, format); 50 verror(loc, format, ap); 51 va_end(ap); 52 } 53 else 54 pragma(printf) extern (C++) void error(const ref Loc loc, const(char)* format, ...) 55 { 56 va_list ap; 57 va_start(ap, format); 58 verror(loc, format, ap); 59 va_end(ap); 60 } 61 62 /** 63 * Same as above, but takes a filename and line information arguments as separate parameters. 64 * Params: 65 * filename = source file of error 66 * linnum = line in the source file 67 * charnum = column number on the line 68 * format = printf-style format specification 69 * ... = printf-style variadic arguments 70 */ 71 static if (__VERSION__ < 2092) 72 extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...) 73 { 74 const loc = Loc(filename, linnum, charnum); 75 va_list ap; 76 va_start(ap, format); 77 verror(loc, format, ap); 78 va_end(ap); 79 } 80 else 81 pragma(printf) extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...) 82 { 83 const loc = Loc(filename, linnum, charnum); 84 va_list ap; 85 va_start(ap, format); 86 verror(loc, format, ap); 87 va_end(ap); 88 } 89 90 /** 91 * Print additional details about an error message. 92 * Doesn't increase the error count or print an additional error prefix. 93 * Params: 94 * loc = location of error 95 * format = printf-style format specification 96 * ... = printf-style variadic arguments 97 */ 98 static if (__VERSION__ < 2092) 99 extern (C++) void errorSupplemental(const ref Loc loc, const(char)* format, ...) 100 { 101 va_list ap; 102 va_start(ap, format); 103 verrorSupplemental(loc, format, ap); 104 va_end(ap); 105 } 106 else 107 pragma(printf) extern (C++) void errorSupplemental(const ref Loc loc, const(char)* format, ...) 108 { 109 va_list ap; 110 va_start(ap, format); 111 verrorSupplemental(loc, format, ap); 112 va_end(ap); 113 } 114 115 /** 116 * Print a warning message, increasing the global warning count. 117 * Params: 118 * loc = location of warning 119 * format = printf-style format specification 120 * ... = printf-style variadic arguments 121 */ 122 static if (__VERSION__ < 2092) 123 extern (C++) void warning(const ref Loc loc, const(char)* format, ...) 124 { 125 va_list ap; 126 va_start(ap, format); 127 vwarning(loc, format, ap); 128 va_end(ap); 129 } 130 else 131 pragma(printf) extern (C++) void warning(const ref Loc loc, const(char)* format, ...) 132 { 133 va_list ap; 134 va_start(ap, format); 135 vwarning(loc, format, ap); 136 va_end(ap); 137 } 138 139 /** 140 * Print additional details about a warning message. 141 * Doesn't increase the warning count or print an additional warning prefix. 142 * Params: 143 * loc = location of warning 144 * format = printf-style format specification 145 * ... = printf-style variadic arguments 146 */ 147 static if (__VERSION__ < 2092) 148 extern (C++) void warningSupplemental(const ref Loc loc, const(char)* format, ...) 149 { 150 va_list ap; 151 va_start(ap, format); 152 vwarningSupplemental(loc, format, ap); 153 va_end(ap); 154 } 155 else 156 pragma(printf) extern (C++) void warningSupplemental(const ref Loc loc, const(char)* format, ...) 157 { 158 va_list ap; 159 va_start(ap, format); 160 vwarningSupplemental(loc, format, ap); 161 va_end(ap); 162 } 163 164 /** 165 * Print a deprecation message, may increase the global warning or error count 166 * depending on whether deprecations are ignored. 167 * Params: 168 * loc = location of deprecation 169 * format = printf-style format specification 170 * ... = printf-style variadic arguments 171 */ 172 static if (__VERSION__ < 2092) 173 extern (C++) void deprecation(const ref Loc loc, const(char)* format, ...) 174 { 175 va_list ap; 176 va_start(ap, format); 177 vdeprecation(loc, format, ap); 178 va_end(ap); 179 } 180 else 181 pragma(printf) extern (C++) void deprecation(const ref Loc loc, const(char)* format, ...) 182 { 183 va_list ap; 184 va_start(ap, format); 185 vdeprecation(loc, format, ap); 186 va_end(ap); 187 } 188 189 /** 190 * Print additional details about a deprecation message. 191 * Doesn't increase the error count, or print an additional deprecation prefix. 192 * Params: 193 * loc = location of deprecation 194 * format = printf-style format specification 195 * ... = printf-style variadic arguments 196 */ 197 static if (__VERSION__ < 2092) 198 extern (C++) void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) 199 { 200 va_list ap; 201 va_start(ap, format); 202 vdeprecationSupplemental(loc, format, ap); 203 va_end(ap); 204 } 205 else 206 pragma(printf) extern (C++) void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) 207 { 208 va_list ap; 209 va_start(ap, format); 210 vdeprecationSupplemental(loc, format, ap); 211 va_end(ap); 212 } 213 214 /** 215 * Print a verbose message. 216 * Doesn't prefix or highlight messages. 217 * Params: 218 * loc = location of message 219 * format = printf-style format specification 220 * ... = printf-style variadic arguments 221 */ 222 static if (__VERSION__ < 2092) 223 extern (C++) void message(const ref Loc loc, const(char)* format, ...) 224 { 225 va_list ap; 226 va_start(ap, format); 227 vmessage(loc, format, ap); 228 va_end(ap); 229 } 230 else 231 pragma(printf) extern (C++) void message(const ref Loc loc, const(char)* format, ...) 232 { 233 va_list ap; 234 va_start(ap, format); 235 vmessage(loc, format, ap); 236 va_end(ap); 237 } 238 239 /** 240 * Same as above, but doesn't take a location argument. 241 * Params: 242 * format = printf-style format specification 243 * ... = printf-style variadic arguments 244 */ 245 static if (__VERSION__ < 2092) 246 extern (C++) void message(const(char)* format, ...) 247 { 248 va_list ap; 249 va_start(ap, format); 250 vmessage(Loc.initial, format, ap); 251 va_end(ap); 252 } 253 else 254 pragma(printf) extern (C++) void message(const(char)* format, ...) 255 { 256 va_list ap; 257 va_start(ap, format); 258 vmessage(Loc.initial, format, ap); 259 va_end(ap); 260 } 261 262 /** 263 * The type of the diagnostic handler 264 * see verrorPrint for arguments 265 * Returns: true if error handling is done, false to continue printing to stderr 266 */ 267 alias DiagnosticHandler = bool delegate(const ref Loc location, Color headerColor, const(char)* header, const(char)* messageFormat, va_list args, const(char)* prefix1, const(char)* prefix2); 268 269 /** 270 * The diagnostic handler. 271 * If non-null it will be called for every diagnostic message issued by the compiler. 272 * If it returns false, the message will be printed to stderr as usual. 273 */ 274 __gshared DiagnosticHandler diagnosticHandler; 275 276 /** 277 * Print a tip message with the prefix and highlighting. 278 * Params: 279 * format = printf-style format specification 280 * ... = printf-style variadic arguments 281 */ 282 static if (__VERSION__ < 2092) 283 extern (C++) void tip(const(char)* format, ...) 284 { 285 va_list ap; 286 va_start(ap, format); 287 vtip(format, ap); 288 va_end(ap); 289 } 290 else 291 pragma(printf) extern (C++) void tip(const(char)* format, ...) 292 { 293 va_list ap; 294 va_start(ap, format); 295 vtip(format, ap); 296 va_end(ap); 297 } 298 299 /** 300 * Just print to stderr, doesn't care about gagging. 301 * (format,ap) text within backticks gets syntax highlighted. 302 * Params: 303 * loc = location of error 304 * headerColor = color to set `header` output to 305 * header = title of error message 306 * format = printf-style format specification 307 * ap = printf-style variadic arguments 308 * p1 = additional message prefix 309 * p2 = additional message prefix 310 */ 311 private void verrorPrint(const ref Loc loc, Color headerColor, const(char)* header, 312 const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null) 313 { 314 if (diagnosticHandler && diagnosticHandler(loc, headerColor, header, format, ap, p1, p2)) 315 return; 316 317 if (global.params.showGaggedErrors && global.gag) 318 fprintf(stderr, "(spec:%d) ", global.gag); 319 Console* con = cast(Console*)global.console; 320 const p = loc.toChars(); 321 if (con) 322 con.setColorBright(true); 323 if (*p) 324 { 325 fprintf(stderr, "%s: ", p); 326 mem.xfree(cast(void*)p); 327 } 328 if (con) 329 con.setColor(headerColor); 330 fputs(header, stderr); 331 if (con) 332 con.resetColor(); 333 OutBuffer tmp; 334 if (p1) 335 { 336 tmp.writestring(p1); 337 tmp.writestring(" "); 338 } 339 if (p2) 340 { 341 tmp.writestring(p2); 342 tmp.writestring(" "); 343 } 344 tmp.vprintf(format, ap); 345 346 if (con && strchr(tmp.peekChars(), '`')) 347 { 348 colorSyntaxHighlight(tmp); 349 writeHighlights(con, tmp); 350 } 351 else 352 fputs(tmp.peekChars(), stderr); 353 fputc('\n', stderr); 354 355 if (global.params.printErrorContext && 356 // ignore invalid files 357 loc != Loc.initial && 358 // ignore mixins for now 359 !loc.filename.strstr(".d-mixin-") && 360 !global.params.mixinOut) 361 { 362 import dmd.filecache : FileCache; 363 auto fllines = FileCache.fileCache.addOrGetFile(loc.filename.toDString()); 364 365 if (loc.linnum - 1 < fllines.lines.length) 366 { 367 auto line = fllines.lines[loc.linnum - 1]; 368 if (loc.charnum < line.length) 369 { 370 fprintf(stderr, "%.*s\n", cast(int)line.length, line.ptr); 371 foreach (_; 1 .. loc.charnum) 372 fputc(' ', stderr); 373 374 fputc('^', stderr); 375 fputc('\n', stderr); 376 } 377 } 378 } 379 fflush(stderr); // ensure it gets written out in case of compiler aborts 380 } 381 382 /** 383 * Same as $(D error), but takes a va_list parameter, and optionally additional message prefixes. 384 * Params: 385 * loc = location of error 386 * format = printf-style format specification 387 * ap = printf-style variadic arguments 388 * p1 = additional message prefix 389 * p2 = additional message prefix 390 * header = title of error message 391 */ 392 extern (C++) void verror(const ref Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null, const(char)* header = "Error: ") 393 { 394 global.errors++; 395 if (!global.gag) 396 { 397 verrorPrint(loc, Classification.error, header, format, ap, p1, p2); 398 if (global.params.errorLimit && global.errors >= global.params.errorLimit) 399 fatal(); // moderate blizzard of cascading messages 400 } 401 else 402 { 403 if (global.params.showGaggedErrors) 404 verrorPrint(loc, Classification.gagged, header, format, ap, p1, p2); 405 global.gaggedErrors++; 406 } 407 } 408 409 /** 410 * Same as $(D errorSupplemental), but takes a va_list parameter. 411 * Params: 412 * loc = location of error 413 * format = printf-style format specification 414 * ap = printf-style variadic arguments 415 */ 416 static if (__VERSION__ < 2092) 417 extern (C++) void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap) 418 { 419 _verrorSupplemental(loc, format, ap); 420 } 421 else 422 pragma(printf) extern (C++) void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap) 423 { 424 _verrorSupplemental(loc, format, ap); 425 } 426 427 private void _verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap) 428 { 429 Color color; 430 if (global.gag) 431 { 432 if (!global.params.showGaggedErrors) 433 return; 434 color = Classification.gagged; 435 } 436 else 437 color = Classification.error; 438 verrorPrint(loc, color, " ", format, ap); 439 } 440 441 /** 442 * Same as $(D warning), but takes a va_list parameter. 443 * Params: 444 * loc = location of warning 445 * format = printf-style format specification 446 * ap = printf-style variadic arguments 447 */ 448 static if (__VERSION__ < 2092) 449 extern (C++) void vwarning(const ref Loc loc, const(char)* format, va_list ap) 450 { 451 _vwarning(loc, format, ap); 452 } 453 else 454 pragma(printf) extern (C++) void vwarning(const ref Loc loc, const(char)* format, va_list ap) 455 { 456 _vwarning(loc, format, ap); 457 } 458 459 private void _vwarning(const ref Loc loc, const(char)* format, va_list ap) 460 { 461 if (global.params.warnings != DiagnosticReporting.off) 462 { 463 if (!global.gag) 464 { 465 verrorPrint(loc, Classification.warning, "Warning: ", format, ap); 466 if (global.params.warnings == DiagnosticReporting.error) 467 global.warnings++; 468 } 469 else 470 { 471 global.gaggedWarnings++; 472 } 473 } 474 } 475 476 /** 477 * Same as $(D warningSupplemental), but takes a va_list parameter. 478 * Params: 479 * loc = location of warning 480 * format = printf-style format specification 481 * ap = printf-style variadic arguments 482 */ 483 static if (__VERSION__ < 2092) 484 extern (C++) void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap) 485 { 486 _vwarningSupplemental(loc, format, ap); 487 } 488 else 489 pragma(printf) extern (C++) void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap) 490 { 491 _vwarningSupplemental(loc, format, ap); 492 } 493 494 private void _vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap) 495 { 496 if (global.params.warnings != DiagnosticReporting.off && !global.gag) 497 verrorPrint(loc, Classification.warning, " ", format, ap); 498 } 499 500 /** 501 * Same as $(D deprecation), but takes a va_list parameter, and optionally additional message prefixes. 502 * Params: 503 * loc = location of deprecation 504 * format = printf-style format specification 505 * ap = printf-style variadic arguments 506 * p1 = additional message prefix 507 * p2 = additional message prefix 508 */ 509 extern (C++) void vdeprecation(const ref Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null) 510 { 511 __gshared const(char)* header = "Deprecation: "; 512 if (global.params.useDeprecated == DiagnosticReporting.error) 513 verror(loc, format, ap, p1, p2, header); 514 else if (global.params.useDeprecated == DiagnosticReporting.inform) 515 { 516 if (!global.gag) 517 { 518 verrorPrint(loc, Classification.deprecation, header, format, ap, p1, p2); 519 } 520 else 521 { 522 global.gaggedWarnings++; 523 } 524 } 525 } 526 527 /** 528 * Same as $(D message), but takes a va_list parameter. 529 * Params: 530 * loc = location of message 531 * format = printf-style format specification 532 * ap = printf-style variadic arguments 533 */ 534 static if (__VERSION__ < 2092) 535 extern (C++) void vmessage(const ref Loc loc, const(char)* format, va_list ap) 536 { 537 _vmessage(loc, format, ap); 538 } 539 else 540 pragma(printf) extern (C++) void vmessage(const ref Loc loc, const(char)* format, va_list ap) 541 { 542 _vmessage(loc, format, ap); 543 } 544 545 private void _vmessage(const ref Loc loc, const(char)* format, va_list ap) 546 { 547 const p = loc.toChars(); 548 if (*p) 549 { 550 fprintf(stdout, "%s: ", p); 551 mem.xfree(cast(void*)p); 552 } 553 OutBuffer tmp; 554 tmp.vprintf(format, ap); 555 fputs(tmp.peekChars(), stdout); 556 fputc('\n', stdout); 557 fflush(stdout); // ensure it gets written out in case of compiler aborts 558 } 559 560 /** 561 * Same as $(D tip), but takes a va_list parameter. 562 * Params: 563 * format = printf-style format specification 564 * ap = printf-style variadic arguments 565 */ 566 static if (__VERSION__ < 2092) 567 extern (C++) void vtip(const(char)* format, va_list ap) 568 { 569 _vtip(format, ap); 570 } 571 else 572 pragma(printf) extern (C++) void vtip(const(char)* format, va_list ap) 573 { 574 _vtip(format, ap); 575 } 576 private void _vtip(const(char)* format, va_list ap) 577 { 578 if (!global.gag) 579 { 580 Loc loc = Loc.init; 581 verrorPrint(loc, Classification.tip, " Tip: ", format, ap); 582 } 583 } 584 585 /** 586 * Same as $(D deprecationSupplemental), but takes a va_list parameter. 587 * Params: 588 * loc = location of deprecation 589 * format = printf-style format specification 590 * ap = printf-style variadic arguments 591 */ 592 static if (__VERSION__ < 2092) 593 extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap) 594 { 595 _vdeprecationSupplemental(loc, format, ap); 596 } 597 else 598 pragma(printf) extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap) 599 { 600 _vdeprecationSupplemental(loc, format, ap); 601 } 602 603 private void _vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap) 604 { 605 if (global.params.useDeprecated == DiagnosticReporting.error) 606 verrorSupplemental(loc, format, ap); 607 else if (global.params.useDeprecated == DiagnosticReporting.inform && !global.gag) 608 verrorPrint(loc, Classification.deprecation, " ", format, ap); 609 } 610 611 /** 612 * Call this after printing out fatal error messages to clean up and exit 613 * the compiler. 614 */ 615 extern (C++) void fatal() 616 { 617 version (none) 618 { 619 halt(); 620 } 621 exit(EXIT_FAILURE); 622 } 623 624 /** 625 * Try to stop forgetting to remove the breakpoints from 626 * release builds. 627 */ 628 extern (C++) void halt() 629 { 630 assert(0); 631 } 632 633 /** 634 * Scan characters in `buf`. Assume text enclosed by `...` 635 * is D source code, and color syntax highlight it. 636 * Modify contents of `buf` with highlighted result. 637 * Many parallels to ddoc.highlightText(). 638 * Params: 639 * buf = text containing `...` code to highlight 640 */ 641 private void colorSyntaxHighlight(ref OutBuffer buf) 642 { 643 //printf("colorSyntaxHighlight('%.*s')\n", cast(int)buf.length, buf.data); 644 bool inBacktick = false; 645 size_t iCodeStart = 0; 646 size_t offset = 0; 647 for (size_t i = offset; i < buf.length; ++i) 648 { 649 char c = buf[i]; 650 switch (c) 651 { 652 case '`': 653 if (inBacktick) 654 { 655 inBacktick = false; 656 OutBuffer codebuf; 657 codebuf.write(buf[iCodeStart + 1 .. i]); 658 codebuf.writeByte(0); 659 // escape the contents, but do not perform highlighting except for DDOC_PSYMBOL 660 colorHighlightCode(codebuf); 661 buf.remove(iCodeStart, i - iCodeStart + 1); // also trimming off the current ` 662 immutable pre = ""; 663 i = buf.insert(iCodeStart, pre); 664 i = buf.insert(i, codebuf[]); 665 i--; // point to the ending ) so when the for loop does i++, it will see the next character 666 break; 667 } 668 inBacktick = true; 669 iCodeStart = i; 670 break; 671 672 default: 673 break; 674 } 675 } 676 } 677 678 679 /** 680 * Embed these highlighting commands in the text stream. 681 * HIGHLIGHT.Escape indicates a Color follows. 682 */ 683 enum HIGHLIGHT : ubyte 684 { 685 Default = Color.black, // back to whatever the console is set at 686 Escape = '\xFF', // highlight Color follows 687 Identifier = Color.white, 688 Keyword = Color.white, 689 Literal = Color.white, 690 Comment = Color.darkGray, 691 Other = Color.cyan, // other tokens 692 } 693 694 /** 695 * Highlight code for CODE section. 696 * Rewrite the contents of `buf` with embedded highlights. 697 * Analogous to doc.highlightCode2() 698 */ 699 700 private void colorHighlightCode(ref OutBuffer buf) 701 { 702 import dmd.lexer; 703 import dmd.tokens; 704 import dmd.diagnostic : DefaultDiagnosticHandler; 705 706 __gshared int nested; 707 if (nested) 708 { 709 // Should never happen, but don't infinitely recurse if it does 710 --nested; 711 return; 712 } 713 ++nested; 714 715 auto gaggedErrorsSave = global.startGagging(); 716 auto diagnosticHandler = DefaultDiagnosticHandler(); 717 scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1, diagnosticHandler.diagnosticHandler); 718 OutBuffer res; 719 const(char)* lastp = cast(char*)buf[].ptr; 720 //printf("colorHighlightCode('%.*s')\n", cast(int)(buf.length - 1), buf.data); 721 res.reserve(buf.length); 722 res.writeByte(HIGHLIGHT.Escape); 723 res.writeByte(HIGHLIGHT.Other); 724 while (1) 725 { 726 Token tok; 727 lex.scan(&tok); 728 diagnosticHandler.report(); 729 res.writestring(lastp[0 .. tok.ptr - lastp]); 730 HIGHLIGHT highlight; 731 switch (tok.value) 732 { 733 case TOK.identifier: 734 highlight = HIGHLIGHT.Identifier; 735 break; 736 case TOK.comment: 737 highlight = HIGHLIGHT.Comment; 738 break; 739 case TOK.int32Literal: 740 .. 741 case TOK.dcharLiteral: 742 case TOK.string_: 743 highlight = HIGHLIGHT.Literal; 744 break; 745 default: 746 if (tok.isKeyword()) 747 highlight = HIGHLIGHT.Keyword; 748 break; 749 } 750 if (highlight != HIGHLIGHT.Default) 751 { 752 res.writeByte(HIGHLIGHT.Escape); 753 res.writeByte(highlight); 754 res.writestring(tok.ptr[0 .. lex.p - tok.ptr]); 755 res.writeByte(HIGHLIGHT.Escape); 756 res.writeByte(HIGHLIGHT.Other); 757 } 758 else 759 res.writestring(tok.ptr[0 .. lex.p - tok.ptr]); 760 if (tok.value == TOK.endOfFile) 761 break; 762 lastp = lex.p; 763 } 764 res.writeByte(HIGHLIGHT.Escape); 765 res.writeByte(HIGHLIGHT.Default); 766 //printf("res = '%.*s'\n", cast(int)buf.length, buf.data); 767 buf.setsize(0); 768 buf.write(&res); 769 global.endGagging(gaggedErrorsSave); 770 --nested; 771 } 772 773 /** 774 * Write the buffer contents with embedded highlights to stderr. 775 * Params: 776 * buf = highlighted text 777 */ 778 private void writeHighlights(Console* con, ref const OutBuffer buf) 779 { 780 bool colors; 781 scope (exit) 782 { 783 /* Do not mess up console if highlighting aborts 784 */ 785 if (colors) 786 con.resetColor(); 787 } 788 789 for (size_t i = 0; i < buf.length; ++i) 790 { 791 const c = buf[i]; 792 if (c == HIGHLIGHT.Escape) 793 { 794 const color = buf[++i]; 795 if (color == HIGHLIGHT.Default) 796 { 797 con.resetColor(); 798 colors = false; 799 } 800 else 801 if (color == Color.white) 802 { 803 con.resetColor(); 804 con.setColorBright(true); 805 colors = true; 806 } 807 else 808 { 809 con.setColor(cast(Color)color); 810 colors = true; 811 } 812 } 813 else 814 fputc(c, con.fp); 815 } 816 }