Skip to content

Instantly share code, notes, and snippets.

@JensAyton
Created December 10, 2015 08:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JensAyton/f7a2bb8b259d008933cb to your computer and use it in GitHub Desktop.
Save JensAyton/f7a2bb8b259d008933cb to your computer and use it in GitHub Desktop.
Macro for pasting ANSI escape codes together, based on https://twitter.com/velartrill/status/674797360774569984. This version requires GCC/Clang extensions for handling zero-length macro __VA_ARGS__es, because I’m lazy, but it could be done without. Note that this is an awful idea because sooner or later you’ll want to output to a text file and …
#ifndef format_h
#define format_h
#define reset "0"
#define bold "1"
#define red "31"
#define format(first, ...) \
"\e[" first join_format_codes(__VA_ARGS__) "m"
#define prepend_joiner(s) \
";" s
#define join_format_codes(...) \
JATEMPLATE_MAP(prepend_joiner, __VA_ARGS__)
// Stuff I happened to have lying around follows.
#define JATEMPLATE_ARGUMENT_COUNT(...) \
JATEMPLATE_ARGUMENT_COUNT_INNER(_0, ##__VA_ARGS__, JATEMPLATE_ARGUMENT_COUNT_63_VALUES())
#define JATEMPLATE_ARGUMENT_COUNT_INNER(...) \
JATEMPLATE_ARGUMENT_COUNT_EXTRACT_64TH_ARG(__VA_ARGS__)
#define JATEMPLATE_ARGUMENT_COUNT_EXTRACT_64TH_ARG( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
#define JATEMPLATE_ARGUMENT_COUNT_63_VALUES() \
62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
#define JATEMPLATE_MAP(F, ...) \
JATEMPLATE_MAP_INNER(F, JATEMPLATE_ARGUMENT_COUNT(__VA_ARGS__), __VA_ARGS__)
#define JATEMPLATE_MAP_INNER(F, COUNTEXPR, ...) \
JATEMPLATE_MAP_INNER2(F, COUNTEXPR, __VA_ARGS__)
#define JATEMPLATE_MAP_INNER2(F, COUNT, ...) \
JATEMPLATE_MAP_INNER3(F, JATEMPLATE_MAP_IMPL_ ## COUNT, __VA_ARGS__)
#define JATEMPLATE_MAP_INNER3(F, IMPL, ...) \
IMPL(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_0(F, HEAD)
#define JATEMPLATE_MAP_IMPL_1(F, HEAD) F(HEAD)
#define JATEMPLATE_MAP_IMPL_2(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_1(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_3(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_2(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_4(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_3(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_5(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_4(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_6(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_5(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_7(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_6(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_8(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_7(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_9(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_8(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_10(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_9(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_11(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_10(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_12(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_11(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_13(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_12(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_14(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_13(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_15(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_14(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_16(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_15(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_17(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_16(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_18(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_17(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_19(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_18(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_20(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_19(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_21(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_20(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_22(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_21(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_23(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_22(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_24(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_23(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_25(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_24(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_26(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_25(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_27(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_26(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_28(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_27(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_29(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_28(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_30(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_29(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_31(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_30(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_32(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_31(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_33(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_32(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_34(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_33(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_35(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_34(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_36(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_35(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_37(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_36(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_38(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_37(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_39(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_38(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_40(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_39(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_41(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_40(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_42(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_41(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_43(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_42(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_44(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_43(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_45(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_44(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_46(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_45(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_47(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_46(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_48(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_47(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_49(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_48(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_50(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_49(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_51(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_50(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_52(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_51(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_53(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_52(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_54(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_53(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_55(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_54(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_56(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_55(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_57(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_56(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_58(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_57(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_59(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_58(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_60(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_59(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_61(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_60(F, __VA_ARGS__)
#define JATEMPLATE_MAP_IMPL_62(F, HEAD, ...) F(HEAD), JATEMPLATE_MAP_IMPL_61(F, __VA_ARGS__)
#endif /* format_h */
@JensAyton
Copy link
Author

Usage:

printf(format(bold, red) "Hi" format(reset) "\n");

@JensAyton
Copy link
Author

Additional macro hack to reduce namespace pollution (the example works unmodified, bold etc are valid only within format()):

#define format_hack_reset   "0"
#define format_hack_bold    "1"
#define format_hack_red     "31"

#define format(...) \
    format_hack_format(JATEMPLATE_MAP(format_hack_prepend_namespace, __VA_ARGS__))

#define format_hack_format(...) \
    format_hack_format_inner(__VA_ARGS__)

#define format_hack_format_inner(first, ...) \
    "\e[" first format_hack_join_format_codes(__VA_ARGS__) "m"

#define format_hack_prepend_joiner(s) \
    ";" s

#define format_hack_join_format_codes(...) \
    JATEMPLATE_MAP(format_hack_prepend_joiner, __VA_ARGS__)

#define format_hack_prepend_namespace(s) \
    format_hack_##s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment