Writing colored output to the console

The writefln function has a lot of formatting options for strings, but they always come out with the same default color. How can we create colored text output in D?

Getting ready

Download terminal.d from my Github repository to your project's directory.

How to do it…

Let's write colored output to the console by executing the following steps:

  1. Import terminal.
  2. Create an instance of Terminal with a linear output type.
  3. Set the foreground and background color with the terminal.color method.
  4. Write text with the terminal.write, terminal.writeln, terminal.writef, or terminal.writefln functions. They work the same way as the homonym functions in std.stdio.
  5. You can flush output with terminal.flush() if it isn't done soon enough automatically.
  6. Compile the program and terminal.d together with dmd yourfile.d terminal.d.

The following is the code:

import terminal;

void main() {
  auto terminal = Terminal(ConsoleOutputType.linear);
  terminal.color(Color.green, Color.red);
  terminal.writeln("Hello, world!");
}

Running the program will print Hello, world! in green text on a red background.

How it works…

Writing colored output is carried out differently on a Unix terminal than on the Windows console. On a Unix terminal, colors are set by printing an ANSI escape sequence to stdout, and it is the program's responsibility to set it back to normal before termination. On the Windows console, colors are changed with an API function, and the operating system will ensure the next program run sees a consistent state, so you do not have to clean it up manually.

The terminal.d module hides these implementation details behind a consistent interface, with the Terminal struct performing necessary cleanup work in its destructor.

Note

In an earlier draft of terminal.d, I used an array of delegates created in the constructor to roll back changes in the destructor. That was a mistake that led to random crashes because delegates have a hidden internal pointer to the object. Using internal pointers in D's structs invokes undefined behavior because the struct may move at any time without notice, leaving a dangling pointer to the old, now reused memory. While a list of cleanup delegates may look elegant like scope(exit), alas it is bug prone and should not be used with structs.

Terminal operates on a unique resource that is modified in its destructor, and it has a disabled postblit to statically prohibit copying the object. Similarly, the default construction is disabled to force the user to call the explicit constructor, giving Terminal a chance to run necessary initialization functions and gather information about the terminal's existing state at startup.

Otherwise, the implementation of Terminal is pretty unremarkable—it is just a wrapper for operating system and library functionality with its own buffering solution.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.142.2