[RFC] ColorD

Chad J chadjoan at __spam.is.bad__gmail.com
Tue Oct 23 05:47:21 PDT 2012


On 10/23/2012 03:51 AM, Jens Mueller wrote:
> Chad J wrote:
>> On 10/22/2012 03:47 AM, Jens Mueller wrote:
>>> Chad J wrote:
>>>> There is no weakness to this.  The only shred of a counterargument I
>>>> can think of is that it makes the format strings more difficult to
>>>> learn. Other than that, it is possible to detect the destination of
>>>> the formatter, so color codes will never end up in places where they
>>>> shouldn't.  A conservative approach to this should handle most
>>>> desires and never interfere with all the people with no interest in
>>>> color.
>>>>
>>>> On the upshot are the things I've mentioned:
>>>> - A format specifier is potentially more discoverable.
>>>> - A format specifier is more concise.  This keeps your lines from
>>>> wrapping.  They are probably too long already.
>>>
>>> Do you consider this
>>> writecf(Color.red, "something %s", "here")
>>> concise as well?
>>>
>>
>> The case is too easy.  You're formatting an entire line.
>
> Am I? I think it's not a line. But I see your point.
> You mean something like
> writec(Color.red, "red")
> writec(Color.blue, "blue")
> writec(Color.green, "green")
> is too verbose.
> You want something like
> writef("%CFred(red%)%CFblue(blue%)%CFgreeng(reen%)");
> Right?
>
>>>> - To cement the previous point: nesting requires a few extra
>>>> characters with a format specifier, rather than a couple extra
>>>> /lines/ for extra function calls.
>>>
>>> Don't understand this point. Can you give an example?
>>>
>>
>> Option A:
>>
>>      auto save = getConsoleState();
>>      scope (exit) setConsoleState(save);
>>      setConsoleColors(Fg.red, Bg.blue);
>>      writeln("Red text on blue background.");
>>
>> Option B:
>>
>>      writefln("%CFredBblu(Red text on blue background.%)");
>
> I see. Though I find the last line difficult to decipher (because there
> are no spaces).
>
>>>> - Calls to stateful console functions allow people to write bugs
>>>> like saving console state and then forgetting to restore it (or
>>>> throwing an exception and neglecting to restore from within a scope
>>>> guard).  Format specifiers do not have this problem.
>>>
>>> The same holds for
>>> writecf(Color.red, "something %s", "here")
>>>
>>
>> See my above example.  In that case the formatter no longer requires
>> even using the scope feature because there are no resources to clean
>> up.  The library handles that mess.
>>
>> Also statefulness is a pain to deal with.  Stack-like operation with
>> push/pop or bracketing constructs is usually much less troublesome
>> for this sort of thing.
>
> It'll be nice then if you can built something using format specifiers on
> top of a basic library.
>
>>>> - etc (I'm sure I'm forgetting one or two.)
>>>>
>>>> These are the reasons why my ideal language has color formatting
>>>> built into its I/O routines.
>>>
>>> Just wanted to point out that instead of that you can add writec*
>>> functions. I think the only thing is that these are less discoverable
>>> but they also work without formatting, e.g.
>>> writec(Color.red, "my text");
>>>
>>
>> The thing I found very difficult with other color formatting APIs
>> was formatting individual words or characters.  Entire lines are
>> easy-peasy stuff in any API.  Solving the entire-lines case won't
>> impress me. ;)
>
> I see your point now. But we should keep it simple.
>
>> Here's my more typical use case:
>>
>> writefln("The %CFred(widgetometer%) is a device for measuring");
>> writefln("widget effectiveness.  It is possible to ");
>> writefln("reconcile transcendental properties by hitting");
>> writefln("%CFblu(B%) for blue coefficients, %CFgrn(G%) for green");
>> writefln("coefficients, or %CFyel(Y%) for yellow coefficients.");
>> writefln("Here is a correspondence table:");
>> writefln("  %CFnue( %) | %CFblu( B %) %CFgrn( G %) %CFyel( Y %) ");
>> writefln("  %CFnue(-%)-+-%CFnue(---%)-%CFnue(---%)-%CFnue(---%)-");
>> writefln("  %CFblu(B%) | %CFblu(200%) %CFwht(330%) %CFwht(303%) ");
>> writefln("  %CFgrn(G%) | %CFwht(110%) %CFgrn(020%) %CFwht(033%) ");
>> writefln("  %CFyel(Y%) | %CFwht(101%) %CFwht(011%) %CFyel(002%) ");
>>
>> I realized that I wanted a "nue" color that has no effect but allows
>> me to align things effectively ;)
>>
>> Anyhow, please try to write the above example using any other style.
>> Interleaved function calls are particularly "fun"<g>
>
> I'm convinced. But I find that it difficult to read. Though that's a
> problem I usually have with format strings. Can these format strings be
> made easier to read. I mean
>
> writefln("The %CF(red)(widgetometer) is a device for measuring");
> or
> writefln("The %c(red,white)(widgetometer) is a device for measuring"); // for writing red on white
>
> is already easier to my eyes.
> I'd be happy to see it built on top.
>
> Jens

That's a reasonable suggestion.  The only thing that can't be solved is 
the trailing ) enclosing the text to be formatted.  That needs a % 
before it to prevent ambiguity with parentheses in the text itself.  So 
I could make your example:

 > writefln("The %c(red,white)(widgetometer%) is a device 
formeasuring"); // for writing red on white

I was also considering the possibility of separating layout and style by 
allowing some kind of style specification before the printing, with a 
limited formatting spec for using the styles:

stdout.addTermTextStyle("id=myStyle, fg=red, bg=white, dark, underline");

writefln("The %c(myStyle)(widgetometer%) is a device for measuring");


More information about the Digitalmars-d mailing list