3

I'm working on a terminal program under Linux. I consider adding colorized output.

The task is not really hard, so I succeeded with the following:

[3]> (format t "~a[1;31mred text~a[0m" #\escape #\escape)
red text ; this text is really red and bold in terminal ;-)
NIL

But the code is ugly: I don't know how to put char #\escape (decimal value 27) into a string in 'inline' fashion. For example C++ code from this thread:

cout << "\033[1;31mbold red text\033[0m\n";

Here is #\Escape as \033 (octal). Is there something similar in Common Lisp?

My effort naïf doesn't work as intended:

[4]> (format t "#\escape1;31mred test#\escape[0m")
#escape1;31mred test#escape[0m
NIL
Community
  • 1
  • 1
Mark Karpov
  • 7,499
  • 2
  • 27
  • 62

1 Answers1

4

You can type the characters manually…

You don't have to do anything special to have the control characters (or other "unusual" characters) in your strings. You just need to be able to type them into the editor. How easy it will be will depend on your editor. In Emacs, and in at least some terminal emulators, you can press Ctrl-Q followed by another character to insert that character literally. Thus, you can press Ctrl-Q followed by Escape to insert a literal #\escape character. How it appears will depend on the terminal emulator or editor. In my terminal, the literal Escape character is displayed as ^[. Thus, I end up with:

(format t "^[[1;31mhello^[[0!")
;          **           **     
;         result of C-Q Esc

This gives me some red text, as in your example:

enter image description here

…or use a library to make it easier!

If you don't want your source to contain characters that might not be easily readable, you might look into something like Edi Weitz's CL-INTERPOL:

CL-INTERPOL is a library for Common Lisp which modifies the reader so that you can have interpolation within strings similar to Perl or Unix Shell scripts. It also provides various ways to insert arbitrary characters into literal strings even if your editor/IDE doesn't support them. Here's an example:

* (let ((a 42))
    #?"foo: \xC4\N{Latin capital letter U with diaeresis}\nbar: ${a}")
"foo: ÄÜ
bar: 42"

Using CL-INTERPOL, this becomes easy:

* (interpol:enable-interpol-syntax)

* (format t #?"\e[1;31mhello\e[0m!")
hello!                                ; there's color here, honest!
NIL
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • I like the idea and `^[` does not contain any special characters. I use Emacs so there is no problem. But is this portable? If I use now `^[` in my source code, will it be character with code 27 everywhere, for every end-user? In other words: `format` really prints `^[` and terminal recognizes it on its own or this combination of characters get converted to value `27` somehow? – Mark Karpov Aug 01 '14 at 20:09
  • I didn't type `^[`; I typed the escape character which is *displayed* in the terminal as `^[`. It's the literal byte for that character. Terminal control codes aren't necessarily universal, so "portable" might be misleading, and Common Lisp implementations don't have to use the same character encoding, but I think you should always end up with the same character. – Joshua Taylor Aug 01 '14 at 20:12
  • Hmm, I see now. Emacs prints out one byte as `^[`. So my source code contains byte 27 on that position. It's quite interesting how services like GitHub would display it;-) – Mark Karpov Aug 01 '14 at 20:16