Giter VIP home page Giter VIP logo

paint's Introduction

Ruby Paint

Paint creates terminal colors and effects for you. It combines the strengths of term-ansicolor, rainbow, and similar projects into a simple to use, however still flexible terminal colors gem with no core extensions by default.

Supported Rubies: 3.3, 3.2, 3.1, 3.0

Unsupported, but might still work: 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1, 2.0, 1.9

Features

  • No string extensions (suitable for library development)
  • Simple API
  • Faster than other terminal color gems (as of January 2024)
  • Supports true color or 256 colors (for capable terminals)
  • Allows you to set any terminal effects
  • Paint.mode: Fall-back modes for terminals with less colors, supported modes:
    • 0xFFFFFF (= 16777215) colors (true color)
    • 256 colors (palette)
    • 16 colors (only ANSI colors, combined with bright effect)
    • 8 colors (only ANSI colors)
    • 0 colors (no colors / deactivate)

Paint 2.0 | True Color Support

Starting with Paint 2.0, true color mode is the new default mode, since most major terminals now support 24bit colors. If it happens to not work in your setup:

  • Manually set Paint.mode = 256 at the beginning of your code
  • Please open a new issue so we can figure out how to blacklist the terminal used

Setup

Add to Gemfile:

gem 'paint'

and run bundle install.

In Ruby do:

require 'paint'

Usage

The only method you need is: Paint.[]

The first argument given to Paint.[] is the string to colorize (if the object is not a string, to_s will be called on it). The other arguments describe how to modify/colorize the string. Let's learn by example:

Paint['Ruby', :red]           # Sets ANSI color red
Paint['Ruby', :red, :bright]  # Also applies bright/bold effect
Paint['Ruby', :bright, :red]  # Does the same as above
Paint['Ruby', :red, :bright, :underline] # Effects can often be combined
Paint['Ruby', :red, :blue]    # The second color you define is for background
Paint['Ruby', nil, :blue]     # Pass a nil before a color to ignore foreground and only set background color
Paint['Ruby', [100, 255, 5]]  # You can define RGB colors. Depending on your terminal, this will create
                              # a "true color" or map to 256/16/8 colors.
Paint['Ruby', "gold", "snow"] # Paint supports rgb.txt color names, note that the arguments are strings
                              # (:yellow != "yellow")!
Paint['Ruby', "#123456"]      # HTML like definitions are possible
Paint['Ruby', "fff"]          # Another HTML hex definition
Paint['Ruby', :inverse]       # Swaps fore- and background
Paint['Ruby', :italic, :encircle, :rapid_blink, :overline] # Probably not supported effects
Paint['Ruby']                 # Don't pass any argument and the string will not be changed

When you pass multiple colors, the first one is taken as foreground color and the second one defines the background color, every following color will be ignored. To only change the background color, you have to pass a nil first. Effects can be passed in any order.

You can find more examples in the specs.

List of rgb.txt colors.

Windows Support

For ANSI support in Windows OS, you can use ansicon or ConEmu or WSL.

Paint.mode

You can choose between five ways to use Paint.[] by setting Paint.mode to one of the following:

  • 0xFFFFFF: Use 16777215 true colors
  • 256: Use the 256 colors palette
  • 16: Use the eight ANSI colors (combined with bright effect)
  • 8: Use the eight ANSI colors
  • 0: Don't colorize at all

Paint tries to automatically detect the proper value your terminal is capable of, please open an issue if Paint.detect_mode yields a wrong value for you.

Paint.detect_mode will return 0 if the NO_COLOR environment variable is set.

More Details About Terminal Colors and Effects

Terminal colors/effects get created by ANSI escape sequences. These are strings that look like this: \e[X;X;X;X;X]m where X are integers with some meaning. For example, 0 means reset, 31 means red foreground and 41 stands for red background. When you tell Paint to use one of the eight ANSI base colors as foreground color, it just inserts a number between 30 and 37 into the sequence. The following colors are available:

  • :black
  • :red
  • :green
  • :yellow
  • :blue
  • :magenta
  • :cyan
  • :white, :gray
  • (:default)

When combined with the :bright (= :bold) effect, the color in the terminal emulator often differs a little bit, thus it is possible to represent 16 colors.

Through special sequences it's also possible to set 256-colors, or even 16777215 colors, instead of only the 8 ANSI ones. However, this is not supported by all terminals. Paint automatically translates given RGB colors to a suitable color of the supported color spectrum.

When using the Paint.[] method, Paint wraps the given string between the calculated escape sequence and an reset sequence ("\e[0m"). You can get the raw escape sequence by using the Paint.color method.

Effects

See en.wikipedia.org/wiki/ANSI_escape_code for a more detailed discussion:

Often supported

0) :reset, :nothing
1) :bright, :bold
4) :underline
7) :inverse, :negative
8) :conceal, :hide
22) :clean
24) :underline_off
26) :inverse_off, :positive
27) :conceal_off, :show, :reveal

Not widely supported

2) :faint
3) :italic
5) :blink, :slow_blink
6) :rapid_blink
9) :crossed, :crossed_out
10) :default_font, :font0
11-19) :font1, :font2, :font3, :font4, :font5, :font6, :font7, :font8, :font9
20) :fraktur
21) :bright_off, :bold_off, :double_underline
23) :italic_off, :fraktur_off
25) :blink_off
29) :crossed_off, :crossed_out_off
51) :frame
52) :encircle
53) :overline
54) :frame_off, :encircle_off
55) :overline_off

Substitution & Nesting

From time to time, you might find yourself in a situation where you want to colorize a substring differently from the rest of the string. Paint supports this via a simple templating approach using the % method with an array argument. Use the %{var} notation within a string, and pass the template variables as a hash:

Paint%['Yellow string with a %{blue_text} in it', :yellow,
  blue_text: ["blue text", :blue]
]
# => "\e[33mYellow string with a \e[34mblue text\e[0m\e[33m in it\e[0m"

Please note that the resulting ASCII escape sequence can be quite verbose since it restores the parent context after the substitution.

Utilities

The Paint.random method generates a random ANSI color you can pass into Paint.[]:

Paint['Ruby', Paint.random]        # Get one of eight random ANSI foreground colors
Paint['Ruby', Paint.random(true)]  # Get one of eight random ANSI background colors

Another helper method is Paint.unpaint, which removes any ANSI colors:

Paint.unpaint( Paint['Ruby', :red, :bright] ).should == 'Ruby'

You can get a p like alternative for calling puts Paint.[]:

require 'paint/pa'
pa "Ruby", :red, :underline  # same as puts Paint["Ruby", :red, :underline]

Advanced Usage: Shortcuts

There is an extension gem available which allows you to define custom color definitions, which you can reuse later. See SHORTCUTS.md for documentation. This is completely optional.

J-_-L

Copyright (c) 2011-2024 Jan Lelis https://janlelis.com, released under the MIT license.

Thank you to rainbow and term-ansicolor for ideas and inspiration. Also, a lot of thanks to all the contributors!

paint's People

Contributors

alexwayfer avatar cybershadow avatar dependabot[bot] avatar edwardbetts avatar eizengan avatar janlelis avatar jdickey avatar korny avatar korun avatar mhaylock avatar noraj avatar olleolleolle avatar pgib avatar vaz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

paint's Issues

Gem.gunzip deprecation warning when bundling with Paint 2.0.1

Bundling a Gem or app which uses paint 2.0.1 produces the following deprecation warning:

NOTE: Gem.gunzip is deprecated; use Gem::Util.gunzip instead. It will be removed on or after 2018-12-01.
Gem.gunzip called from /Users/jeffdickey/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/paint-2.0.1/lib/paint/rgb_colors.rb:5.

"It should be an easy enough fix", he said, naively.

Weird gem install message

Hi there,

I just installed the gem and got an unreadable message during gem installation:

$ sudo gem install paint
Passwort: 
Fetching: paint-0.8.0.gem (100%)
         ��� info ����������������������������
 J-_-L � https://github.com/janlelis/paint �
         ��� usage ���������������������������
         � require 'paint'                   �
         � puts Paint['J-_-L', :red] # J-_-L �
         �������������������������������������
Successfully installed paint-0.8.0
1 gem installed
Installing ri documentation for paint-0.8.0...
Installing RDoc documentation for paint-0.8.0...

If this is intended, there should be at least some hint about that.

Valete,
Quintus

Can't load paint/pa under Rails Console

In my .irbrc file I have:
require 'paint/pa'

Using Ruby 2.3.1 and Rails 4.2.10 (as well as previous versions of both)

irb and rails console both load paint/pa and functions using Paint work properly.

Using Ruby 2.5.1 and Rails 5.2.1

irb loads paint/pa and functions correctly

rails console throws this error message:

cannot load such file -- paint/pa

It seems that this is a Rails issue, maybe having to modifications of the irb load path.

Any insights on the issue and how to resolve?

All running under MacOS.

Performance

I added a benchmark task and implemented some performance boosts.

The following are benchmarks with Ruby 1.8.7; other Ruby engines behave similarly.

Currently: https://github.com/rubychan/paint

                                     user     system      total        real
cycle                            0.080000   0.000000   0.080000 (  0.076957)
term-ansicolor                   0.320000   0.000000   0.320000 (  0.319086)
rainbow                          0.830000   0.000000   0.830000 (  0.838637)
paint                            2.020000   0.020000   2.040000 (  2.043669)  *
term-ansicolor with background   0.730000   0.000000   0.730000 (  0.737908)
rainbow with background          1.790000   0.020000   1.810000 (  1.808856)
paint with background            2.750000   0.020000   2.770000 (  2.776894)  *

Improved: https://github.com/rubychan/paint/tree/murphy-speedups

                                     user     system      total        real
cycle                            0.070000   0.000000   0.070000 (  0.078598)
term-ansicolor                   0.310000   0.000000   0.310000 (  0.313784)
rainbow                          0.820000   0.010000   0.830000 (  0.821557)
paint                            0.320000   0.000000   0.320000 (  0.325781)  *
term-ansicolor with background   0.720000   0.000000   0.720000 (  0.723231)
rainbow with background          1.760000   0.010000   1.770000 (  1.773275)
paint with background            0.450000   0.000000   0.450000 (  0.455812)  *

cycle measures the base time for all benchmarks.

Broken benchmark

Hello!
I trying run benchmark, but term-ansicolor tests raises ArgumentError. O_o

$ ruby --version
ruby 2.0.0p481 (2014-05-08 revision 45883) [i686-linux]
$ bundle exec rake benchmark
Rehearsal ------------------------------------------------------------------
cycle                            0.030000   0.000000   0.030000 (  0.033609)
paint                            0.320000   0.000000   0.320000 (  0.311577)
term-ansicolor                 rake aborted!
ArgumentError: Bad number of arguments for RGB color definition, should be 3
/home/user/.rvm/gems/ruby-2.0.0-p481/gems/rainbow-1.1.4/lib/ansi_color.rb:53:in `code_from_rgb'
/home/user/.rvm/gems/ruby-2.0.0-p481/gems/rainbow-1.1.4/lib/ansi_color.rb:27:in `code'
/home/user/.rvm/gems/ruby-2.0.0-p481/gems/rainbow-1.1.4/lib/rainbow.rb:33:in `foreground'
(eval):2:in `blue'
/home/user/paint/Rakefile:89:in `block (4 levels) in <top (required)>'
/home/user/paint/Rakefile:88:in `times'
/home/user/paint/Rakefile:88:in `block (3 levels) in <top (required)>'
/home/user/paint/Rakefile:72:in `block in <top (required)>'
/home/user/.rvm/gems/ruby-2.0.0-p481/bin/ruby_executable_hooks:15:in `eval'
/home/user/.rvm/gems/ruby-2.0.0-p481/bin/ruby_executable_hooks:15:in `<main>'
Tasks: TOP => benchmark

Please lessen (or remove) the post install message.

I love your work, and I love giving you credit for the work but nothing is worse then having a production server that logs all stdout into a log file spam me with irrelevant messages and ascii boxes. I was wondering if you could at least remove the boxes and keep it to two simple lines or do something simple like rdoc.

NO_COLOR standard

Can be nice to implement this standard https://no-color.org/

All command-line software which outputs text with ANSI color added should check for the presence of a NO_COLOR environment variable that, when present (regardless of its value), prevents the addition of ANSI color.

require "rbconfig" missing

in paint/util.rb, RbConfig is accessed without a require "rbconfig", which makes programs fail with uninitialized constant Module::RbConfig unless they somehow preload rbconfig (eg when they use rubygems, or by ruby 1.9).

when a require "rbconfig" line is inserted as the first line of paint/util.rb, things work well again.

this came up in debian as http://bugs.debian.org/705751, and unless better suggestions come up in this issue thread, i'll include a patch to that effect in a new debian package release; please apply the change to the original paint as well.

a complete example:

$ irb1.8
irb(main):001:0> require "paint"
=> true
irb(main):002:0> Paint['Ruby', :red]
NameError: uninitialized constant Module::RbConfig
        from /usr/lib/ruby/vendor_ruby/paint/util.rb:38:in `detect_mode'
        from /usr/lib/ruby/vendor_ruby/paint.rb:164:in `mode'
        from /usr/lib/ruby/vendor_ruby/paint.rb:87:in `[]'
        from (irb):2
        from :0

CSS colors should accept upper case hex

This just bit me:

puts Paint['Ruby', "#4183c4"]
=> Ruby (in nice GitHub blue)

puts Paint['Ruby', "#4183C4"]
=> Ruby (black)

Otherwise, it works perfectly :)

Windows CI build stops at `cinst` not being a command, in Ruby 3.0

From a CI run:

Run cinst ansicon
cinst: D:\a\_temp\d1a0e82b-8211-4346-a1a2-1fbf8a380653.ps1:2
Line |
   2 |  cinst ansicon
     |  ~~~~~
     | The term 'cinst' is not recognized as a name of a cmdlet, function, script file, or executable program. Check
     | the spelling of the name, or if a path was included, verify that the path is correct and try again.

JRuby 1.9-mode installation error

I'm getting this error when bundling paint 0.8.5 under jruby-19mode on Travis CI:

Psych::SyntaxError: (<unknown>): 'reader' unacceptable character '�' (0x94) special characters are not allowed

in "'reader'", position 2965 at line 0 column 0
An error occurred while installing paint (0.8.5), and Bundler cannot continue.
Make sure that `gem install paint -v '0.8.5'` succeeds before bundling.

The command "bundle install" failed and exited with 5 during install.

Your build has been stopped.

Issue with nesting and modifiers not being terminated

Hi! Nice gem you have created, I really appreciate the nesting capability. I did notice that if you have a nested variable, modifiers don't get correctly terminated. e.g.

irb(main):025:1* Paint%['Yellow string with a %{blue_text} in it', :yellow,
irb(main):026:1*   blue_text: ["blue text", :blue, :underline]
irb(main):027:0> ]
=> "\e[33mYellow string with a \e[34;4mblue text\e[33m in it\e[0m"

Renders like this:

image

It would be nice if the underline was terminated at the end of the nested part. I am guessing that'd require something like this in the output:

 "\e[33mYellow string with a \e[34;4mblue text\e[33;24m in it\e[0m"

Not a huge deal, I can just not use nesting with modifiers, but thought it was worth mentioning. Thank you!

Output still includes "NOTHING" escape sequence when mode is 0

As the title says, I've tried setting Paint.mode to 0 when my application is not on a TTY and I'm finding that the output still includes the reset sequence ("\e[0m"). This appears to be because the code uses the constant NOTHING regardless of the current mode.

Based on the documentation, my interpretation of mode 0 is that it should completely disable any colorization and so this sequence should also be omitted?

Unable to bundle install because of bundle is locked to paint (0.8.7)

bundle install
Error: Your bundle is locked to paint (0.8.7), but that version could not be found in any of the sources listed in your Gemfile. If you haven't changed
sources, that means the author of paint (0.8.7) has removed it. You'll need to update your bundle to a version other than paint (0.8.7) that hasn't
been removed in order to install.

bundle update paint
Error: Fetching gem metadata from https://rubygems.org/...........
Resolving dependencies...
Bundler could not find compatible versions for gem "paint":
In Gemfile:
paint (> 2.0)
restclient was resolved to 0.10.0, which depends on
paint (
> 0.8)

Paint % [...] fails with frozen template

With frozen_string_literal: true pragma, templating fails.

Paint % ["%{f}(%{x})", :blue, f: "f", x: ["x", :gray]]

fails with:

paint-2.2.1/lib/paint.rb:28:in `gsub!': can't modify frozen String: "%{f}(%{x})" (FrozenError)

Steps to reproduce:

ruby --enable=frozen-string-literal \
  -r paint \
  -e 'puts(Paint % ["%{f}(%{x})", :blue, f: "f", x: ["x", :gray]])'

Expected behaviour:

Work normally, as in:

ruby -r paint \
  -e 'puts(Paint % ["%{f}(%{x})", :blue, f: "f", x: ["x", :gray]])'

image


Workaround

Unfreeze template:

Paint % [+"%{f}(%{x})", ...]

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.