Salida de Ruby coloreada al terminal [cerrado]

273

Usando Ruby, ¿cómo puedo realizar la coloración de texto de fondo y primer plano para la salida en el terminal?

Recuerdo que cuando programamos Pascal, todos escribíamos nuestros propios textcolor(…)procedimientos para que nuestros pequeños programas educativos se vieran más bonitos y presentadores.

¿Cómo haría para codificar un equivalente de eso en Ruby?

gmile
fuente
Entonces, ¿es imposible obtener el color "naranja" por ejemplo?
Matrix
Checkout github.com/kigster/colored2
Konstantin Gredeskoul

Respuestas:

379

¡Colorear es mi joya favorita! :-)

Echale un vistazo:

https://github.com/fazibear/colorize

Instalación:

gem install colorize

Uso:

require 'colorize'

puts "I am now red".red
puts "I am now blue".blue
puts "Testing".yellow
jaredmdobson
fuente
2
¿Alguien podría decirme si Colorize funciona en Cygwin Terminal? Traté de ejecutar el código anterior en Cygwin pero sale sin colores ...
jj_
55
Esto funcionará bien en un símbolo del sistema de Windows si instala la win32consolegema y require 'win32console'después colorize.
Ben
2
@Ben No lo he probado personalmente, pero desde Ruby 2.0 ya no deberías necesitar la win32consolegema. github.com/luislavena/win32console/issues/…
Dennis
1
¿Alguna forma de hacer que esto funcione con la consola de Sumblime Text?
nipponese
66
Esta gema tiene licencia bajo GPL, por lo que (creo) no se puede usar en software propietario. jonathannen.com/2013/07/07/license-your-gems.html
Andrei Botalov
249

Combinando las respuestas anteriores, puede implementar algo que funcione como el color de la gema sin necesidad de otra dependencia.

class String
  # colorization
  def colorize(color_code)
    "\e[#{color_code}m#{self}\e[0m"
  end

  def red
    colorize(31)
  end

  def green
    colorize(32)
  end

  def yellow
    colorize(33)
  end

  def blue
    colorize(34)
  end

  def pink
    colorize(35)
  end

  def light_blue
    colorize(36)
  end
end
Erik Skoglund
fuente
ah, buena edición Nick. Sí, por supuesto, no hay necesidad de pasar por alto. Estaba cansado cuando escribí esto :)
Erik Skoglund
¿Funcionará esto también en Windows?
Alp
Funciona en Windows si está utilizando ConEmu
Mike Glenn
1
Me gusta más que colorear, ya que esto solo cambia el color de primer plano. colorear parece cambiar siempre el color de fondo.
jlyonsmith
1
Sé que llego tarde a la fiesta, pero ¿no sería mejor usar un cierre aquí?
215

Como métodos de clase String (solo Unix):

class String
def black;          "\e[30m#{self}\e[0m" end
def red;            "\e[31m#{self}\e[0m" end
def green;          "\e[32m#{self}\e[0m" end
def brown;          "\e[33m#{self}\e[0m" end
def blue;           "\e[34m#{self}\e[0m" end
def magenta;        "\e[35m#{self}\e[0m" end
def cyan;           "\e[36m#{self}\e[0m" end
def gray;           "\e[37m#{self}\e[0m" end

def bg_black;       "\e[40m#{self}\e[0m" end
def bg_red;         "\e[41m#{self}\e[0m" end
def bg_green;       "\e[42m#{self}\e[0m" end
def bg_brown;       "\e[43m#{self}\e[0m" end
def bg_blue;        "\e[44m#{self}\e[0m" end
def bg_magenta;     "\e[45m#{self}\e[0m" end
def bg_cyan;        "\e[46m#{self}\e[0m" end
def bg_gray;        "\e[47m#{self}\e[0m" end

def bold;           "\e[1m#{self}\e[22m" end
def italic;         "\e[3m#{self}\e[23m" end
def underline;      "\e[4m#{self}\e[24m" end
def blink;          "\e[5m#{self}\e[25m" end
def reverse_color;  "\e[7m#{self}\e[27m" end
end

y uso:

puts "I'm back green".bg_green
puts "I'm red and back cyan".red.bg_cyan
puts "I'm bold and green and backround red".bold.green.bg_red

en mi consola:

ingrese la descripción de la imagen aquí

adicional:

def no_colors
  self.gsub /\e\[\d+m/, ""
end

elimina caracteres de formato

Nota

puts "\e[31m" # set format (red foreground)
puts "\e[0m"   # clear format
puts "green-#{"red".red}-green".green # will be green-red-normal, because of \e[0
Ivan Black
fuente
La negrita debe usar el código de escape 22 no 21:def bold; "\e[1m#{self}\e[22m" end
Kanat Bolazar
@KanatBolazar, algunos sistemas admiten 21 . Pero lo cambio a 22 por capacidad. Gracias.
Ivan Black
1
Esto es genial, lo puse en un inicializador en mi aplicación Rails. ¡Funciona de maravilla!
Fantásticos consejos. Tan fácil y sin dependencias. Muy muy bien hecho!
mraxus
1
En Windows 10 cmd.exe, puts "\e[0"no funciona para borrar el formato; puts "\e[0m"debe ser usado
Nnnes
41

Escribí un pequeño método para probar los modos básicos de color, basado en las respuestas de Erik Skoglund y otros.

#outputs color table to console, regular and bold modes
def colortable
  names = %w(black red green yellow blue pink cyan white default)
  fgcodes = (30..39).to_a - [38]

  s = ''
  reg  = "\e[%d;%dm%s\e[0m"
  bold = "\e[1;%d;%dm%s\e[0m"
  puts '                       color table with these background codes:'
  puts '          40       41       42       43       44       45       46       47       49'
  names.zip(fgcodes).each {|name,fg|
    s = "#{fg}"
    puts "%7s "%name + "#{reg}  #{bold}   "*9 % [fg,40,s,fg,40,s,  fg,41,s,fg,41,s,  fg,42,s,fg,42,s,  fg,43,s,fg,43,s,  
      fg,44,s,fg,44,s,  fg,45,s,fg,45,s,  fg,46,s,fg,46,s,  fg,47,s,fg,47,s,  fg,49,s,fg,49,s ]
  }
end

salida de ejemplo: ruby colortest

glacial
fuente
37

Puede usar secuencias de escape ANSI para hacer esto en la consola. Sé que esto funciona en Linux y OSX, no estoy seguro de si la consola de Windows (cmd) es compatible con ANSI.

Lo hice en Java, pero las ideas son las mismas.

//foreground color
public static final String BLACK_TEXT()   { return "\033[30m";}
public static final String RED_TEXT()     { return "\033[31m";}
public static final String GREEN_TEXT()   { return "\033[32m";}
public static final String BROWN_TEXT()   { return "\033[33m";}
public static final String BLUE_TEXT()    { return "\033[34m";}
public static final String MAGENTA_TEXT() { return "\033[35m";}
public static final String CYAN_TEXT()    { return "\033[36m";}
public static final String GRAY_TEXT()    { return "\033[37m";}

//background color
public static final String BLACK_BACK()   { return "\033[40m";}
public static final String RED_BACK()     { return "\033[41m";}
public static final String GREEN_BACK()   { return "\033[42m";}
public static final String BROWN_BACK()   { return "\033[43m";}
public static final String BLUE_BACK()    { return "\033[44m";}
public static final String MAGENTA_BACK() { return "\033[45m";}
public static final String CYAN_BACK()    { return "\033[46m";}
public static final String WHITE_BACK()   { return "\033[47m";}

//ANSI control chars
public static final String RESET_COLORS() { return "\033[0m";}
public static final String BOLD_ON()      { return "\033[1m";}
public static final String BLINK_ON()     { return "\033[5m";}
public static final String REVERSE_ON()   { return "\033[7m";}
public static final String BOLD_OFF()     { return "\033[22m";}
public static final String BLINK_OFF()    { return "\033[25m";}
public static final String REVERSE_OFF()  { return "\033[27m";}
Ryan Michela
fuente
77
Esto funciona y tiene la ventaja de no requerir una gema, lo que puede molestar a algunas personas.
ThomasW
3
La consola de Windows admite códigos ANSI.
Ben
16

Mientras que las otras respuestas harán el trabajo bien para la mayoría de las personas, debe mencionarse la forma "correcta" de Unix de hacerlo. Dado que todos los tipos de terminales de texto no son compatibles con estas secuencias, puede consultar la base de datos terminfo , una abstracción sobre las capacidades de varios terminales de texto. Esto puede parecer todo de interés histórico - terminales de software en uso hoy en día por lo general apoyar las secuencias ANSI - pero tiene (al menos) un efecto práctico: a veces es útil para poder establecer la variable de entorno TERMpara dumbevitar todo tal estilo, por ejemplo al guardar la salida en un archivo de texto. Además, se siente bien hacer las cosas bien . :-)

Puedes usar la gema ruby-terminfo . Necesita un poco de compilación de C para instalar; Pude instalarlo en mi sistema Ubuntu 14.10 con:

$ sudo apt-get install libncurses5-dev
$ gem install ruby-terminfo --user-install

Luego puede consultar la base de datos de esta manera (consulte la página del manual de terminfo para obtener una lista de los códigos disponibles):

require 'terminfo' 
TermInfo.control("bold")
puts "Bold text"
TermInfo.control("sgr0")
puts "Back to normal."
puts "And now some " + TermInfo.control_string("setaf", 1) + 
     "red" + TermInfo.control_string("sgr0") + " text."

Aquí hay una pequeña clase de envoltura que armé para hacer las cosas un poco más simples de usar.

require 'terminfo'

class Style
  def self.style() 
    @@singleton ||= Style.new
  end

  colors = %w{black red green yellow blue magenta cyan white}
  colors.each_with_index do |color, index|
    define_method(color) { get("setaf", index) }
    define_method("bg_" + color) { get("setab", index) }
  end

  def bold()  get("bold")  end
  def under() get("smul")  end
  def dim()   get("dim")   end
  def clear() get("sgr0")  end

  def get(*args)
    begin
      TermInfo.control_string(*args)
    rescue TermInfo::TermInfoError
      ""
    end
  end
end

Uso:

c = Style.style
C = c.clear
puts "#{c.red}Warning:#{C} this is #{c.bold}way#{C} #{c.bg_red}too much #{c.cyan + c.under}styling#{C}!"
puts "#{c.dim}(Don't you think?)#{C}"

Salida del script Ruby anterior

(editar) Finalmente, si prefiere no necesitar una gema, puede confiar en el tputprograma, como se describe aquí - Ejemplo de Ruby:

puts "Hi! " + `tput setaf 1` + "This is red!" + `tput sgr0`
skagedal
fuente
44
Mayor, mayor +1 para uso de tput. Ni siquiera puedo articular cuánta pérdida de cabello tputme ha salvado.
Pierce
14

Hice este método que podría ayudar. No es gran cosa pero funciona:

def colorize(text, color = "default", bgColor = "default")
    colors = {"default" => "38","black" => "30","red" => "31","green" => "32","brown" => "33", "blue" => "34", "purple" => "35",
     "cyan" => "36", "gray" => "37", "dark gray" => "1;30", "light red" => "1;31", "light green" => "1;32", "yellow" => "1;33",
      "light blue" => "1;34", "light purple" => "1;35", "light cyan" => "1;36", "white" => "1;37"}
    bgColors = {"default" => "0", "black" => "40", "red" => "41", "green" => "42", "brown" => "43", "blue" => "44",
     "purple" => "45", "cyan" => "46", "gray" => "47", "dark gray" => "100", "light red" => "101", "light green" => "102",
     "yellow" => "103", "light blue" => "104", "light purple" => "105", "light cyan" => "106", "white" => "107"}
    color_code = colors[color]
    bgColor_code = bgColors[bgColor]
    return "\033[#{bgColor_code};#{color_code}m#{text}\033[0m"
end

Aquí se explica cómo usarlo:

puts "#{colorize("Hello World")}"
puts "#{colorize("Hello World", "yellow")}"
puts "#{colorize("Hello World", "white","light red")}"

Las posibles mejoras podrían ser:

  • colorsy bgColorsse definen cada vez que se llama al método y no cambian.
  • Añadir otras opciones como bold, underline, dim, etc.

Este método no funciona p, como lo phace un inspecta su argumento. Por ejemplo:

p "#{colorize("Hello World")}"

mostrará "\ e [0; 38mHola Mundo \ e [0m"

Lo probé con puts, printy la gema Logger, y funciona bien.


Mejoré esto e hice una clase así colorsy bgColorsson constantes de clase y colorizees un método de clase:

EDITAR: Mejor estilo de código, constantes definidas en lugar de variables de clase, usando símbolos en lugar de cadenas, se agregaron más opciones como negrita, cursiva, etc.

class Colorizator
    COLOURS = { default: '38', black: '30', red: '31', green: '32', brown: '33', blue: '34', purple: '35',
                cyan: '36', gray: '37', dark_gray: '1;30', light_red: '1;31', light_green: '1;32', yellow: '1;33',
                light_blue: '1;34', light_purple: '1;35', light_cyan: '1;36', white: '1;37' }.freeze
    BG_COLOURS = { default: '0', black: '40', red: '41', green: '42', brown: '43', blue: '44',
                   purple: '45', cyan: '46', gray: '47', dark_gray: '100', light_red: '101', light_green: '102',
                   yellow: '103', light_blue: '104', light_purple: '105', light_cyan: '106', white: '107' }.freeze

    FONT_OPTIONS = { bold: '1', dim: '2', italic: '3', underline: '4', reverse: '7', hidden: '8' }.freeze

    def self.colorize(text, colour = :default, bg_colour = :default, **options)
        colour_code = COLOURS[colour]
        bg_colour_code = BG_COLOURS[bg_colour]
        font_options = options.select { |k, v| v && FONT_OPTIONS.key?(k) }.keys
        font_options = font_options.map { |e| FONT_OPTIONS[e] }.join(';').squeeze
        return "\e[#{bg_colour_code};#{font_options};#{colour_code}m#{text}\e[0m".squeeze(';')
    end
end

Puedes usarlo haciendo:

Colorizator.colorize "Hello World", :gray, :white
Colorizator.colorize "Hello World", :light_blue, bold: true
Colorizator.colorize "Hello World", :light_blue, :white, bold: true, underline: true
Redithion
fuente
13

Esto es lo que hice para que funcione sin necesidad de gemas:

def red(mytext) ; "\e[31m#{mytext}\e[0m" ; end
puts red("hello world")

Luego, solo el texto en las comillas está coloreado, y volverá a su programa programado regularmente.

suzyQ
fuente
3
No funciona para mi Entiendo exactamente:e[32mSOMETEXT
Oscar Godson
había un error tipográfico en el primer personaje de escape: debería ser en "\e(...)"lugar de"e\(...)"
artrópodo
12

Encontré algunos:

http://github.com/ssoroka/ansi/tree/master

Ejemplos:

puts ANSI.color(:red) { "hello there" }
puts ANSI.color(:green) + "Everything is green now" + ANSI.no_color

http://flori.github.com/term-ansicolor/

Ejemplos:

print red, bold, "red bold", reset, "\n"
print red(bold("red bold")), "\n"
print red { bold { "red bold" } }, "\n"

http://github.com/sickill/rainbow

Ejemplo:

puts "this is red".foreground(:red) + " and " + "this on yellow bg".background(:yellow) + " and " + "even bright underlined!".underline.bright

Si está en Windows, es posible que deba hacer una "instalación de gemas win32console" para habilitar la compatibilidad con los colores.

Además, el artículo Colorizing console Ruby-script output es útil si necesita crear su propia gema. Explica cómo agregar colores ANSI a las cadenas. Puede usar este conocimiento para envolverlo en alguna clase que extienda una cadena o algo así.

Pedro
fuente
8

Esto puede ayudarlo: salida rubí coloreada

ennuikiller
fuente
1
Y mejorando la muestra en este enlace, puede extender la clase String para que sea más fácil de usar ("Hello" .red):class String; def red; colorize(self, "\033[31m"); end; end
Adriano P
3

Encontré que las respuestas anteriores eran útiles, sin embargo, no se ajustaban a la factura si quería colorear algo como la salida del registro sin usar bibliotecas de terceros. Lo siguiente resolvió el problema para mí:

red = 31
green = 32
blue = 34

def color (color=blue)
  printf "\033[#{color}m";
  yield
  printf "\033[0m"
end

color { puts "this is blue" }
color(red) { logger.info "and this is red" }

¡Espero que ayude!

pmyjavec
fuente