zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

bunt_ansi.ex (17665B)


      1 defmodule Bunt.ANSI.Sequence do
      2   @moduledoc false
      3 
      4   defmacro defalias(alias_name, original_name) do
      5     quote bind_quoted: [alias_name: alias_name, original_name: original_name] do
      6       def unquote(alias_name)() do
      7         unquote(original_name)()
      8       end
      9 
     10       defp format_sequence(unquote(alias_name)) do
     11         unquote(original_name)()
     12       end
     13     end
     14   end
     15 
     16   defmacro defsequence(name, code, prefix \\ "", terminator \\ "m") do
     17     quote bind_quoted: [name: name, code: code, prefix: prefix, terminator: terminator] do
     18       def unquote(name)() do
     19         "\e[#{unquote(prefix)}#{unquote(code)}#{unquote(terminator)}"
     20       end
     21 
     22       defp format_sequence(unquote(name)) do
     23         unquote(name)()
     24       end
     25     end
     26   end
     27 end
     28 
     29 defmodule Bunt.ANSI do
     30   @moduledoc """
     31   Functionality to render ANSI escape sequences.
     32 
     33   [ANSI escape sequences](https://en.wikipedia.org/wiki/ANSI_escape_code)
     34   are characters embedded in text used to control formatting, color, and
     35   other output options on video text terminals.
     36   """
     37 
     38   import Bunt.ANSI.Sequence
     39 
     40   @color_tuples [
     41     {nil, :color16, 16, {0, 0, 0}},
     42     {nil, :color17, 17, {0, 0, 95}},
     43     {"darkblue", :color18, 18, {0, 0, 135}},
     44     {nil, :color19, 19, {0, 0, 175}},
     45     {"mediumblue", :color20, 20, {0, 0, 215}},
     46     {nil, :color21, 21, {0, 0, 255}},
     47     {"darkgreen", :color22, 22, {0, 95, 0}},
     48     {"darkslategray", :color23, 23, {0, 95, 95}},
     49     {nil, :color24, 24, {0, 95, 135}},
     50     {nil, :color25, 25, {0, 95, 175}},
     51     {nil, :color26, 26, {0, 95, 215}},
     52     {nil, :color27, 27, {0, 95, 255}},
     53     {nil, :color28, 28, {0, 135, 0}},
     54     {nil, :color29, 29, {0, 135, 95}},
     55     {"darkcyan", :color30, 30, {0, 135, 135}},
     56     {nil, :color31, 31, {0, 135, 175}},
     57     {nil, :color32, 32, {0, 135, 215}},
     58     {nil, :color33, 33, {0, 135, 255}},
     59     {nil, :color34, 34, {0, 175, 0}},
     60     {nil, :color35, 35, {0, 175, 95}},
     61     {nil, :color36, 36, {0, 175, 135}},
     62     {nil, :color37, 37, {0, 175, 175}},
     63     {nil, :color38, 38, {0, 175, 215}},
     64     {"deepskyblue", :color39, 39, {0, 175, 255}},
     65     {nil, :color40, 40, {0, 215, 0}},
     66     {nil, :color41, 41, {0, 215, 95}},
     67     {nil, :color42, 42, {0, 215, 135}},
     68     {nil, :color43, 43, {0, 215, 175}},
     69     {nil, :color44, 44, {0, 215, 215}},
     70     {nil, :color45, 45, {0, 215, 255}},
     71     {nil, :color46, 46, {0, 255, 0}},
     72     {nil, :color47, 47, {0, 255, 95}},
     73     {"springgreen", :color48, 48, {0, 255, 135}},
     74     {nil, :color49, 49, {0, 255, 175}},
     75     {nil, :color50, 50, {0, 255, 215}},
     76     {"aqua", :color51, 51, {0, 255, 255}},
     77     {nil, :color52, 52, {95, 0, 0}},
     78     {nil, :color53, 53, {95, 0, 95}},
     79     {nil, :color54, 54, {95, 0, 135}},
     80     {nil, :color55, 55, {95, 0, 175}},
     81     {nil, :color56, 56, {95, 0, 215}},
     82     {nil, :color57, 57, {95, 0, 255}},
     83     {nil, :color58, 58, {95, 95, 0}},
     84     {"dimgray", :color59, 59, {95, 95, 95}},
     85     {nil, :color60, 60, {95, 95, 135}},
     86     {nil, :color61, 61, {95, 95, 175}},
     87     {nil, :color62, 62, {95, 95, 215}},
     88     {nil, :color63, 63, {95, 95, 255}},
     89     {nil, :color64, 64, {95, 135, 0}},
     90     {nil, :color65, 65, {95, 135, 95}},
     91     {nil, :color66, 66, {95, 135, 135}},
     92     {"steelblue", :color67, 67, {95, 135, 175}},
     93     {nil, :color68, 68, {95, 135, 215}},
     94     {nil, :color69, 69, {95, 135, 255}},
     95     {nil, :color70, 70, {95, 175, 0}},
     96     {nil, :color71, 71, {95, 175, 95}},
     97     {nil, :color72, 72, {95, 175, 135}},
     98     {nil, :color73, 73, {95, 175, 175}},
     99     {nil, :color74, 74, {95, 175, 215}},
    100     {nil, :color75, 75, {95, 175, 255}},
    101     {nil, :color76, 76, {95, 215, 0}},
    102     {nil, :color77, 77, {95, 215, 95}},
    103     {nil, :color78, 78, {95, 215, 135}},
    104     {nil, :color79, 79, {95, 215, 175}},
    105     {nil, :color80, 80, {95, 215, 215}},
    106     {nil, :color81, 81, {95, 215, 255}},
    107     {nil, :color82, 82, {95, 255, 0}},
    108     {nil, :color83, 83, {95, 255, 95}},
    109     {nil, :color84, 84, {95, 255, 135}},
    110     {nil, :color85, 85, {95, 255, 175}},
    111     {nil, :color86, 86, {95, 255, 215}},
    112     {nil, :color87, 87, {95, 255, 255}},
    113     {"darkred", :color88, 88, {135, 0, 0}},
    114     {nil, :color89, 89, {135, 0, 95}},
    115     {"darkmagenta", :color90, 90, {135, 0, 135}},
    116     {nil, :color91, 91, {135, 0, 175}},
    117     {nil, :color92, 92, {135, 0, 215}},
    118     {nil, :color93, 93, {135, 0, 255}},
    119     {nil, :color94, 94, {135, 95, 0}},
    120     {nil, :color95, 95, {135, 95, 95}},
    121     {nil, :color96, 96, {135, 95, 135}},
    122     {nil, :color97, 97, {135, 95, 175}},
    123     {nil, :color98, 98, {135, 95, 215}},
    124     {nil, :color99, 99, {135, 95, 255}},
    125     {"olive", :color100, 100, {135, 135, 0}},
    126     {nil, :color101, 101, {135, 135, 95}},
    127     {nil, :color102, 102, {135, 135, 135}},
    128     {nil, :color103, 103, {135, 135, 175}},
    129     {nil, :color104, 104, {135, 135, 215}},
    130     {nil, :color105, 105, {135, 135, 255}},
    131     {nil, :color106, 106, {135, 175, 0}},
    132     {nil, :color107, 107, {135, 175, 95}},
    133     {nil, :color108, 108, {135, 175, 135}},
    134     {nil, :color109, 109, {135, 175, 175}},
    135     {nil, :color110, 110, {135, 175, 215}},
    136     {nil, :color111, 111, {135, 175, 255}},
    137     {nil, :color112, 112, {135, 215, 0}},
    138     {nil, :color113, 113, {135, 215, 95}},
    139     {nil, :color114, 114, {135, 215, 135}},
    140     {nil, :color115, 115, {135, 215, 175}},
    141     {nil, :color116, 116, {135, 215, 215}},
    142     {nil, :color117, 117, {135, 215, 255}},
    143     {"chartreuse", :color118, 118, {135, 255, 0}},
    144     {nil, :color119, 119, {135, 255, 95}},
    145     {nil, :color120, 120, {135, 255, 135}},
    146     {nil, :color121, 121, {135, 255, 175}},
    147     {"aquamarine", :color122, 122, {135, 255, 215}},
    148     {nil, :color123, 123, {135, 255, 255}},
    149     {nil, :color124, 124, {175, 0, 0}},
    150     {nil, :color125, 125, {175, 0, 95}},
    151     {nil, :color126, 126, {175, 0, 135}},
    152     {nil, :color127, 127, {175, 0, 175}},
    153     {nil, :color128, 128, {175, 0, 215}},
    154     {nil, :color129, 129, {175, 0, 255}},
    155     {nil, :color130, 130, {175, 95, 0}},
    156     {nil, :color131, 131, {175, 95, 95}},
    157     {nil, :color132, 132, {175, 95, 135}},
    158     {nil, :color133, 133, {175, 95, 175}},
    159     {nil, :color134, 134, {175, 95, 215}},
    160     {nil, :color135, 135, {175, 95, 255}},
    161     {nil, :color136, 136, {175, 135, 0}},
    162     {nil, :color137, 137, {175, 135, 95}},
    163     {nil, :color138, 138, {175, 135, 135}},
    164     {nil, :color139, 139, {175, 135, 175}},
    165     {nil, :color140, 140, {175, 135, 215}},
    166     {nil, :color141, 141, {175, 135, 255}},
    167     {nil, :color142, 142, {175, 175, 0}},
    168     {nil, :color143, 143, {175, 175, 95}},
    169     {nil, :color144, 144, {175, 175, 135}},
    170     {nil, :color145, 145, {175, 175, 175}},
    171     {nil, :color146, 146, {175, 175, 215}},
    172     {nil, :color147, 147, {175, 175, 255}},
    173     {nil, :color148, 148, {175, 215, 0}},
    174     {nil, :color149, 149, {175, 215, 95}},
    175     {nil, :color150, 150, {175, 215, 135}},
    176     {nil, :color151, 151, {175, 215, 175}},
    177     {nil, :color152, 152, {175, 215, 215}},
    178     {nil, :color153, 153, {175, 215, 255}},
    179     {"greenyellow", :color154, 154, {175, 255, 0}},
    180     {nil, :color155, 155, {175, 255, 95}},
    181     {nil, :color156, 156, {175, 255, 135}},
    182     {nil, :color157, 157, {175, 255, 175}},
    183     {nil, :color158, 158, {175, 255, 215}},
    184     {nil, :color159, 159, {175, 255, 255}},
    185     {nil, :color160, 160, {215, 0, 0}},
    186     {nil, :color161, 161, {215, 0, 95}},
    187     {nil, :color162, 162, {215, 0, 135}},
    188     {nil, :color163, 163, {215, 0, 175}},
    189     {nil, :color164, 164, {215, 0, 215}},
    190     {nil, :color165, 165, {215, 0, 255}},
    191     {nil, :color166, 166, {215, 95, 0}},
    192     {nil, :color167, 167, {215, 95, 95}},
    193     {nil, :color168, 168, {215, 95, 135}},
    194     {nil, :color169, 169, {215, 95, 175}},
    195     {nil, :color170, 170, {215, 95, 215}},
    196     {nil, :color171, 171, {215, 95, 255}},
    197     {"chocolate", :color172, 172, {215, 135, 0}},
    198     {nil, :color173, 173, {215, 135, 95}},
    199     {nil, :color174, 174, {215, 135, 135}},
    200     {nil, :color175, 175, {215, 135, 175}},
    201     {nil, :color176, 176, {215, 135, 215}},
    202     {nil, :color177, 177, {215, 135, 255}},
    203     {"goldenrod", :color178, 178, {215, 175, 0}},
    204     {nil, :color179, 179, {215, 175, 95}},
    205     {nil, :color180, 180, {215, 175, 135}},
    206     {nil, :color181, 181, {215, 175, 175}},
    207     {nil, :color182, 182, {215, 175, 215}},
    208     {nil, :color183, 183, {215, 175, 255}},
    209     {nil, :color184, 184, {215, 215, 0}},
    210     {nil, :color185, 185, {215, 215, 95}},
    211     {nil, :color186, 186, {215, 215, 135}},
    212     {nil, :color187, 187, {215, 215, 175}},
    213     {"lightgray", :color188, 188, {215, 215, 215}},
    214     {nil, :color189, 189, {215, 215, 255}},
    215     {nil, :color190, 190, {215, 255, 0}},
    216     {nil, :color191, 191, {215, 255, 95}},
    217     {nil, :color192, 192, {215, 255, 135}},
    218     {nil, :color193, 193, {215, 255, 175}},
    219     {"beige", :color194, 194, {215, 255, 215}},
    220     {"lightcyan", :color195, 195, {215, 255, 255}},
    221     {nil, :color196, 196, {255, 0, 0}},
    222     {nil, :color197, 197, {255, 0, 95}},
    223     {nil, :color198, 198, {255, 0, 135}},
    224     {nil, :color199, 199, {255, 0, 175}},
    225     {nil, :color200, 200, {255, 0, 215}},
    226     {"fuchsia", :color201, 201, {255, 0, 255}},
    227     {"orangered", :color202, 202, {255, 95, 0}},
    228     {nil, :color203, 203, {255, 95, 95}},
    229     {nil, :color204, 204, {255, 95, 135}},
    230     {"hotpink", :color205, 205, {255, 95, 175}},
    231     {nil, :color206, 206, {255, 95, 215}},
    232     {nil, :color207, 207, {255, 95, 255}},
    233     {"darkorange", :color208, 208, {255, 135, 0}},
    234     {"coral", :color209, 209, {255, 135, 95}},
    235     {nil, :color210, 210, {255, 135, 135}},
    236     {nil, :color211, 211, {255, 135, 175}},
    237     {nil, :color212, 212, {255, 135, 215}},
    238     {nil, :color213, 213, {255, 135, 255}},
    239     {"orange", :color214, 214, {255, 175, 0}},
    240     {nil, :color215, 215, {255, 175, 95}},
    241     {nil, :color216, 216, {255, 175, 135}},
    242     {nil, :color217, 217, {255, 175, 175}},
    243     {nil, :color218, 218, {255, 175, 215}},
    244     {nil, :color219, 219, {255, 175, 255}},
    245     {"gold", :color220, 220, {255, 215, 0}},
    246     {nil, :color221, 221, {255, 215, 95}},
    247     {"khaki", :color222, 222, {255, 215, 135}},
    248     {"moccasin", :color223, 223, {255, 215, 175}},
    249     {"mistyrose", :color224, 224, {255, 215, 215}},
    250     {nil, :color225, 225, {255, 215, 255}},
    251     {nil, :color226, 226, {255, 255, 0}},
    252     {nil, :color227, 227, {255, 255, 95}},
    253     {nil, :color228, 228, {255, 255, 135}},
    254     {nil, :color229, 229, {255, 255, 175}},
    255     {"lightyellow", :color230, 230, {255, 255, 215}},
    256     {nil, :color231, 231, {255, 255, 255}},
    257     {nil, :color232, 232, {255, 255, 255}},
    258     {nil, :color233, 233, {255, 255, 255}},
    259     {nil, :color234, 234, {255, 255, 255}},
    260     {nil, :color235, 235, {255, 255, 255}},
    261     {nil, :color236, 236, {255, 255, 255}},
    262     {nil, :color237, 237, {255, 255, 255}},
    263     {nil, :color238, 238, {255, 255, 255}},
    264     {nil, :color239, 239, {255, 255, 255}},
    265     {nil, :color240, 240, {255, 255, 255}},
    266     {nil, :color241, 241, {255, 255, 255}},
    267     {nil, :color242, 242, {255, 255, 255}},
    268     {nil, :color243, 243, {255, 255, 255}},
    269     {nil, :color244, 244, {255, 255, 255}},
    270     {nil, :color245, 245, {255, 255, 255}},
    271     {nil, :color246, 246, {255, 255, 255}},
    272     {nil, :color247, 247, {255, 255, 255}},
    273     {nil, :color248, 248, {255, 255, 255}},
    274     {nil, :color249, 249, {255, 255, 255}},
    275     {nil, :color250, 250, {255, 255, 255}},
    276     {nil, :color251, 251, {255, 255, 255}},
    277     {nil, :color252, 252, {255, 255, 255}},
    278     {nil, :color253, 253, {255, 255, 255}},
    279     {nil, :color254, 254, {255, 255, 255}},
    280     {nil, :color255, 255, {255, 255, 255}}
    281   ]
    282 
    283   def color_tuples, do: @color_tuples
    284 
    285   for {name, color, code, _} <- @color_tuples do
    286     @doc "Sets foreground color to #{color}"
    287     defsequence(color, code, "38;5;")
    288 
    289     @doc "Sets background color to #{color}"
    290     defsequence(:"#{color}_background", code, "48;5;")
    291 
    292     if name do
    293       @doc "Sets foreground color to #{name}"
    294       defsequence(:"#{name}", code, "38;5;")
    295 
    296       @doc "Sets background color to #{name}"
    297       defsequence(:"#{name}_background", code, "48;5;")
    298     end
    299   end
    300 
    301   if Version.match?(System.version(), ">= 1.14.0-dev") do
    302     @color_aliases Application.compile_env(:bunt, :color_aliases, [])
    303   else
    304     function = :get_env
    305     @color_aliases apply(Application, function, [:bunt, :color_aliases, []])
    306   end
    307 
    308   def color_aliases, do: @color_aliases
    309 
    310   for {alias_name, original_name} <- @color_aliases do
    311     defalias(alias_name, original_name)
    312     defalias(:"#{alias_name}_background", :"#{original_name}_background")
    313   end
    314 
    315   @typep ansicode :: atom()
    316   @typep ansilist ::
    317            maybe_improper_list(
    318              char() | ansicode() | binary() | ansilist(),
    319              binary() | ansicode() | []
    320            )
    321   @type ansidata :: ansilist() | ansicode() | binary()
    322 
    323   @doc """
    324   Checks if ANSI coloring is supported and enabled on this machine.
    325 
    326   This function simply reads the configuration value for
    327   `:ansi_enabled` in the `:elixir` application. The value is by
    328   default `false` unless Elixir can detect during startup that
    329   both `stdout` and `stderr` are terminals.
    330   """
    331   @spec enabled? :: boolean
    332   def enabled? do
    333     Application.get_env(:elixir, :ansi_enabled, false)
    334   end
    335 
    336   @doc "Resets all attributes"
    337   defsequence(:reset, 0)
    338 
    339   @doc "Bright (increased intensity) or Bold"
    340   defsequence(:bright, 1)
    341 
    342   @doc "Faint (decreased intensity), not widely supported"
    343   defsequence(:faint, 2)
    344 
    345   @doc "Italic: on. Not widely supported. Sometimes treated as inverse"
    346   defsequence(:italic, 3)
    347 
    348   @doc "Underline: Single"
    349   defsequence(:underline, 4)
    350 
    351   @doc "Blink: Slow. Less than 150 per minute"
    352   defsequence(:blink_slow, 5)
    353 
    354   @doc "Blink: Rapid. MS-DOS ANSI.SYS; 150 per minute or more; not widely supported"
    355   defsequence(:blink_rapid, 6)
    356 
    357   @doc "Image: Negative. Swap foreground and background"
    358   defsequence(:inverse, 7)
    359 
    360   @doc "Image: Negative. Swap foreground and background"
    361   defsequence(:reverse, 7)
    362 
    363   @doc "Conceal. Not widely supported"
    364   defsequence(:conceal, 8)
    365 
    366   @doc "Crossed-out. Characters legible, but marked for deletion. Not widely supported"
    367   defsequence(:crossed_out, 9)
    368 
    369   @doc "Sets primary (default) font"
    370   defsequence(:primary_font, 10)
    371 
    372   for font_n <- [1, 2, 3, 4, 5, 6, 7, 8, 9] do
    373     @doc "Sets alternative font #{font_n}"
    374     defsequence(:"font_#{font_n}", font_n + 10)
    375   end
    376 
    377   @doc "Normal color or intensity"
    378   defsequence(:normal, 22)
    379 
    380   @doc "Not italic"
    381   defsequence(:not_italic, 23)
    382 
    383   @doc "Underline: None"
    384   defsequence(:no_underline, 24)
    385 
    386   @doc "Blink: off"
    387   defsequence(:blink_off, 25)
    388 
    389   colors = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white]
    390 
    391   for {color, code} <- Enum.with_index(colors) do
    392     @doc "Sets foreground color to #{color}"
    393     defsequence(color, code + 30)
    394 
    395     @doc "Sets background color to #{color}"
    396     defsequence(:"#{color}_background", code + 40)
    397   end
    398 
    399   @doc "Default text color"
    400   defsequence(:default_color, 39)
    401 
    402   @doc "Default background color"
    403   defsequence(:default_background, 49)
    404 
    405   @doc "Framed"
    406   defsequence(:framed, 51)
    407 
    408   @doc "Encircled"
    409   defsequence(:encircled, 52)
    410 
    411   @doc "Overlined"
    412   defsequence(:overlined, 53)
    413 
    414   @doc "Not framed or encircled"
    415   defsequence(:not_framed_encircled, 54)
    416 
    417   @doc "Not overlined"
    418   defsequence(:not_overlined, 55)
    419 
    420   @doc "Sends cursor home"
    421   defsequence(:home, "", "H")
    422 
    423   @doc "Clears screen"
    424   defsequence(:clear, "2", "J")
    425 
    426   @doc "Clears line"
    427   defsequence(:clear_line, "2", "K")
    428 
    429   defp format_sequence(other) do
    430     raise ArgumentError, "invalid ANSI sequence specification: #{other}"
    431   end
    432 
    433   @doc ~S"""
    434   Formats a chardata-like argument by converting named ANSI sequences into actual
    435   ANSI codes.
    436 
    437   The named sequences are represented by atoms.
    438 
    439   It will also append an `IO.ANSI.reset/0` to the chardata when a conversion is
    440   performed. If you don't want this behaviour, use `format_fragment/2`.
    441 
    442   An optional boolean parameter can be passed to enable or disable
    443   emitting actual ANSI codes. When `false`, no ANSI codes will emitted.
    444   By default checks if ANSI is enabled using the `enabled?/0` function.
    445 
    446   ## Examples
    447 
    448       iex> IO.ANSI.format(["Hello, ", :red, :bright, "world!"], true)
    449       [[[[[[], "Hello, "] | "\e[31m"] | "\e[1m"], "world!"] | "\e[0m"]
    450 
    451   """
    452   def format(chardata, emit \\ enabled?()) when is_boolean(emit) do
    453     do_format(chardata, [], [], emit, :maybe)
    454   end
    455 
    456   @doc ~S"""
    457   Formats a chardata-like argument by converting named ANSI sequences into actual
    458   ANSI codes.
    459 
    460   The named sequences are represented by atoms.
    461 
    462   An optional boolean parameter can be passed to enable or disable
    463   emitting actual ANSI codes. When `false`, no ANSI codes will emitted.
    464   By default checks if ANSI is enabled using the `enabled?/0` function.
    465 
    466   ## Examples
    467 
    468       iex> IO.ANSI.format_fragment([:bright, 'Word'], true)
    469       [[[[[[] | "\e[1m"], 87], 111], 114], 100]
    470 
    471   """
    472   def format_fragment(chardata, emit \\ enabled?()) when is_boolean(emit) do
    473     do_format(chardata, [], [], emit, false)
    474   end
    475 
    476   defp do_format([term | rest], rem, acc, emit, append_reset) do
    477     do_format(term, [rest | rem], acc, emit, append_reset)
    478   end
    479 
    480   defp do_format(term, rem, acc, true, append_reset) when is_atom(term) do
    481     do_format([], rem, [acc | format_sequence(term)], true, !!append_reset)
    482   end
    483 
    484   defp do_format(term, rem, acc, false, append_reset) when is_atom(term) do
    485     do_format([], rem, acc, false, append_reset)
    486   end
    487 
    488   defp do_format(term, rem, acc, emit, append_reset) when not is_list(term) do
    489     do_format([], rem, [acc | [term]], emit, append_reset)
    490   end
    491 
    492   defp do_format([], [next | rest], acc, emit, append_reset) do
    493     do_format(next, rest, acc, emit, append_reset)
    494   end
    495 
    496   defp do_format([], [], acc, true, true) do
    497     [acc | IO.ANSI.reset()]
    498   end
    499 
    500   defp do_format([], [], acc, _emit, _append_reset) do
    501     acc
    502   end
    503 end