├── VERSION ├── .rubocop.yml ├── lib ├── pry-theme │ ├── cli.rb │ ├── formattable.rb │ ├── colors │ │ ├── color8.rb │ │ ├── color256.rb │ │ └── color16.rb │ ├── color_table.rb │ ├── theme_list.rb │ ├── config.rb │ ├── when_started_hook.rb │ ├── term.rb │ ├── preview.rb │ ├── hex.rb │ ├── basic_editor.rb │ ├── definition.rb │ ├── declaration.rb │ ├── theme.rb │ ├── commands.rb │ ├── rgb.rb │ └── color.rb └── pry-theme.rb ├── .gitignore ├── screenshots ├── zenburn.png ├── solarized.png ├── tomorrow.png └── railscasts.png ├── Gemfile ├── .travis.yml ├── Rakefile ├── spec ├── helper.rb ├── term_spec.rb ├── config_spec.rb ├── hex_spec.rb ├── color_table.rb ├── rgb_spec.rb ├── commands_spec.rb ├── colors │ ├── color8_spec.rb │ ├── color16_spec.rb │ └── color256_spec.rb └── theme_spec.rb ├── pry-theme.gemspec ├── themes ├── pry-monochrome.prytheme.rb ├── pry-modern-8.prytheme.rb ├── monokai.prytheme.rb ├── pry-siberia-8.prytheme.rb ├── pry-classic-8.prytheme.rb ├── pry-love-8.prytheme.rb ├── pry-tepid-8.prytheme.rb ├── pry-zealand-8.prytheme.rb ├── tomorrow.prytheme.rb ├── zenburn.prytheme.rb ├── vim-default.prytheme.rb ├── pry-love-16.prytheme.rb ├── pry-modern-16.prytheme.rb ├── pry-siberia-16.prytheme.rb ├── solarized.prytheme.rb ├── pry-classic-16.prytheme.rb ├── pry-classic-256.prytheme.rb ├── github.prytheme.rb ├── pry-tepid-16.prytheme.rb ├── twilight.prytheme.rb ├── railscasts.prytheme.rb ├── pry-cold.prytheme.rb ├── pry-zealand-16.prytheme.rb ├── pry-modern-256.prytheme.rb └── vim-detailed.prytheme.rb ├── LICENSE ├── README.md ├── .rubocop_todo.yml └── CHANGELOG.md /VERSION: -------------------------------------------------------------------------------- 1 | 1.3.1 2 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: .rubocop_todo.yml 2 | -------------------------------------------------------------------------------- /lib/pry-theme/cli.rb: -------------------------------------------------------------------------------- 1 | require 'pry-theme' 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.gem 3 | Gemfile.lock 4 | .rbx/* 5 | -------------------------------------------------------------------------------- /screenshots/zenburn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyrylo/pry-theme/HEAD/screenshots/zenburn.png -------------------------------------------------------------------------------- /screenshots/solarized.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyrylo/pry-theme/HEAD/screenshots/solarized.png -------------------------------------------------------------------------------- /screenshots/tomorrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyrylo/pry-theme/HEAD/screenshots/tomorrow.png -------------------------------------------------------------------------------- /screenshots/railscasts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyrylo/pry-theme/HEAD/screenshots/railscasts.png -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | 4 | group :development, :test do 5 | gem 'pry', '~> 0.10' 6 | end 7 | 8 | group :development do 9 | gem 'rake', '~> 10.1' 10 | end 11 | 12 | group :test do 13 | gem 'bacon', '~> 1.2' 14 | end 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 2.0 3 | - 2.1 4 | - 2.2 5 | - 2.3 6 | - 2.4.0 7 | - ruby-head 8 | - jruby-9.1.5.0 9 | 10 | matrix: 11 | allow_failures: 12 | - rvm: ruby-head 13 | 14 | script: 15 | - rake spec 16 | 17 | branches: 18 | only: 19 | - master 20 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | def quiet 2 | ENV['VERBOSE'] ? '' : '-q' 3 | end 4 | 5 | def test_files 6 | paths = FileList['spec/**/*_spec.rb'] 7 | paths.shuffle!.join(' ') 8 | end 9 | 10 | desc "Run tests" 11 | task :spec do 12 | exec "bacon -Ispec #{ quiet } #{ test_files }" 13 | end 14 | 15 | task :default => :spec 16 | -------------------------------------------------------------------------------- /spec/helper.rb: -------------------------------------------------------------------------------- 1 | require 'bundler/setup' 2 | 3 | require 'pry' 4 | if Pry::VERSION < '0.11' 5 | require 'pry/test/helper' 6 | else 7 | require 'pry/testable' 8 | include Pry::Testable 9 | end 10 | 11 | Bundler.require :default, :test 12 | 13 | Pry.config.color = false 14 | Pry.config.hooks = Pry::Hooks.new 15 | Pry.config.pager = false 16 | Pry.config.theme = nil 17 | 18 | puts( 19 | "Ruby: #{RUBY_VERSION}; " + 20 | "Ruby Engine: #{defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'}; " + 21 | "Pry Theme: #{PryTheme::VERSION}" 22 | ) 23 | -------------------------------------------------------------------------------- /lib/pry-theme/formattable.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | module Formattable 3 | 4 | FORMATTING = { 5 | :bold => 1, 6 | :italic => 3, 7 | :underline => 4 8 | } 9 | 10 | def bold 11 | options[:bold] && FORMATTING[:bold] 12 | end 13 | def bold?; !!bold; end 14 | 15 | def italic 16 | options[:italic] && FORMATTING[:italic] 17 | end 18 | def italic?; !!italic; end 19 | 20 | def underline 21 | options[:underline] && FORMATTING[:underline] 22 | end 23 | def underline?; !!underline; end 24 | 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/pry-theme/colors/color8.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | class Color8 < Color 3 | 4 | def initialize(options = {}) 5 | super(8, options) 6 | end 7 | 8 | private 9 | 10 | def create_ansi_sequence(fg, bg) 11 | super(fg, bg, '39;49') 12 | end 13 | 14 | def build_fg_sequence 15 | [foreground] 16 | end 17 | 18 | def build_bg_sequence 19 | [background] 20 | end 21 | 22 | def find_from_integer(color_id) 23 | sorted_colors.each_with_index.to_a.rassoc(color_id).first.first 24 | end 25 | 26 | def build_effects_sequence 27 | [] 28 | end 29 | 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /pry-theme.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = 'pry-theme' 3 | s.version = File.read('VERSION') 4 | s.date = Time.now.strftime('%Y-%m-%d') 5 | s.summary = 'An easy way to customize Pry colors via theme files' 6 | s.description = 'The plugin enables color theme support for Pry.' 7 | s.author = 'Kyrylo Silin' 8 | s.email = 'silin@kyrylo.org' 9 | s.homepage = 'https://github.com/kyrylo/pry-theme' 10 | s.licenses = 'zlib' 11 | 12 | s.require_path = 'lib' 13 | s.files = `git ls-files`.split("\n") 14 | 15 | s.add_dependency 'coderay', '~> 1.1' 16 | end 17 | -------------------------------------------------------------------------------- /lib/pry-theme/colors/color256.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | class Color256 < PryTheme::Color 3 | 4 | include Formattable 5 | 6 | def initialize(options = {}) 7 | super(256, options) 8 | end 9 | 10 | private 11 | 12 | def create_ansi_sequence(fg, bg) 13 | super(fg, bg, '0') 14 | end 15 | 16 | def build_fg_sequence 17 | ['38', '5', foreground] 18 | end 19 | 20 | def build_bg_sequence 21 | ['48', '5', background] 22 | end 23 | 24 | def find_from_integer(color_id) 25 | pair = colors.find { |*term| term.first.flatten.include?(color_id) } 26 | pair.first if pair 27 | end 28 | 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/pry-theme/colors/color16.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | class Color16 < Color 3 | 4 | def initialize(options = {}) 5 | super(16, options) 6 | end 7 | 8 | private 9 | 10 | def create_ansi_sequence(fg, bg) 11 | super(fg, bg, '39;49') 12 | end 13 | 14 | def build_fg_sequence 15 | [foreground] 16 | end 17 | 18 | def build_bg_sequence 19 | [background] 20 | end 21 | 22 | def build_effects_sequence 23 | [] 24 | end 25 | 26 | def find_from_integer(color_id) 27 | sorted_colors.each_with_index.to_a.rassoc(color_id).first.first 28 | end 29 | 30 | def build_layer(layer) 31 | layer.join(';') 32 | end 33 | 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/term_spec.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | describe PryTheme::TERM do 4 | TERM = PryTheme::TERM 5 | 6 | it "represents itself as Integer" do 7 | TERM.new(23).to_i.should == 23 8 | end 9 | 10 | it "has color model parameter" do 11 | TERM.new(1).color_model.should == 256 12 | TERM.new(1, 16).color_model.should == 16 13 | end 14 | 15 | it "doesn't accept malformed arguments" do 16 | lambda { TERM.new(-23) }.should.raise ArgumentError 17 | lambda { TERM.new(256) }.should.raise ArgumentError 18 | lambda { TERM.new(25, 16) }.should.raise ArgumentError 19 | lambda { TERM.new(25, '16') }.should.raise TypeError 20 | lambda { TERM.new(:one) }.should.raise TypeError 21 | lambda { TERM.new('25') }.should.raise TypeError 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /themes/pry-monochrome.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-monochrome' do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'For people who hate colors' 4 | 5 | define_theme do 6 | class_ [:bold, :underline] 7 | comment [:italic] 8 | constant [:bold] 9 | error [:bold, :italic, :underline] 10 | global_variable [:bold] 11 | inline_delimiter [:bold] 12 | keyword [:bold] 13 | method [:underline] 14 | predefined_constant [:italic] 15 | symbol [:underline] 16 | 17 | regexp do 18 | delimiter [:bold] 19 | modifier [:italic] 20 | end 21 | 22 | shell do 23 | delimiter [:bold] 24 | end 25 | 26 | string do 27 | delimiter [:bold] 28 | end 29 | end 30 | end 31 | 32 | PryTheme::ThemeList.add_theme(t) 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2020 Kyrylo Silin 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 19 | 3. This notice may not be removed or altered from any source distribution. 20 | -------------------------------------------------------------------------------- /lib/pry-theme/color_table.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | class ColorTable 3 | 4 | class << self 5 | def t256 6 | ColorTable.new(256).table 7 | end 8 | 9 | def t16 10 | ColorTable.new(16).table 11 | end 12 | 13 | def t8 14 | ColorTable.new(8).table 15 | end 16 | 17 | def build_color_string(color, fg = nil) 18 | "%s%s\e[0m:%s%s\e[0m" % 19 | [color.to_ansi(true), fg || color.foreground, 20 | color.to_ansi, color.foreground(true)] 21 | end 22 | end 23 | 24 | def initialize(color_model) 25 | @color_model = color_model 26 | end 27 | 28 | def table 29 | colors = [] 30 | 0.upto(@color_model - 1) { |i| 31 | color = PryTheme.const_get(:"Color#@color_model").new( 32 | :from => :term, :foreground => i) 33 | colors << self.class.build_color_string(color, i) 34 | } 35 | Pry::Helpers.tablify_or_one_line("Color model #@color_model", colors) 36 | end 37 | 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/config_spec.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | describe PryTheme::Config do 4 | before do 5 | @token_colors = CodeRay::Encoders::Terminal::TOKEN_COLORS 6 | @old_key_token = @token_colors[:key] 7 | @token_colors[:key].should != @token_colors[:symbol] 8 | end 9 | 10 | after do 11 | CodeRay::Encoders::Terminal::TOKEN_COLORS[:key] = @old_key_token 12 | end 13 | 14 | describe "#apply" do 15 | describe ":paint_key_as_symbol is true" do 16 | before do 17 | PryTheme::Config.new(paint_key_as_symbol: true).apply 18 | end 19 | 20 | it "sets the key token to the value of the symbol token" do 21 | @token_colors[:key].should == @token_colors[:symbol] 22 | end 23 | end 24 | 25 | describe ":paint_key_as symbol is false" do 26 | before do 27 | PryTheme::Config.new(paint_key_as_symbol: false).apply 28 | end 29 | 30 | it "doesn't set the key token to the value of the symbol token" do 31 | @token_colors[:key].should != @token_colors[:symbol] 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /themes/pry-modern-8.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-modern-8', :color_model => 8 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'Simplied version of pry-modern-16' 4 | 5 | define_theme do 6 | class_ 'magenta' 7 | class_variable 'cyan' 8 | comment 'blue' 9 | constant 'blue' 10 | error 'black', 'white' 11 | float 'red' 12 | global_variable 'yellow' 13 | inline_delimiter 'green' 14 | instance_variable 'cyan' 15 | integer 'blue' 16 | keyword 'red' 17 | method 'yellow' 18 | predefined_constant 'cyan' 19 | symbol 'green' 20 | 21 | regexp do 22 | self_ 'red' 23 | char 'red' 24 | content 'magenta' 25 | delimiter 'red' 26 | modifier 'red' 27 | escape 'red' 28 | end 29 | 30 | shell do 31 | self_ 'green' 32 | char 'green' 33 | content 'green' 34 | delimiter 'green' 35 | escape 'green' 36 | end 37 | 38 | string do 39 | self_ 'green' 40 | char 'green' 41 | content 'green' 42 | delimiter 'green' 43 | escape 'green' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/monokai.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'monokai' do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description "Based on Wimer Hazenberg's theme" 4 | 5 | define_theme do 6 | class_ 'sky01' 7 | class_variable 'white' 8 | comment 'pale_mauve01' 9 | constant 'sky01' 10 | error 'crimson', [:italic] 11 | float 'amethyst01' 12 | global_variable 'white' 13 | inline_delimiter 'white' 14 | instance_variable 'white' 15 | integer 'amethyst01' 16 | keyword 'crimson' 17 | method 'lime01' 18 | predefined_constant 'sky01' 19 | symbol 'amethyst01' 20 | 21 | regexp do 22 | self_ 'flax' 23 | char 'white' 24 | content 'flax' 25 | delimiter 'flax' 26 | modifier 'flax' 27 | escape 'white' 28 | end 29 | 30 | shell do 31 | self_ 'flax' 32 | char 'white' 33 | content 'flax' 34 | delimiter 'flax' 35 | escape 'white' 36 | end 37 | 38 | string do 39 | self_ 'flax' 40 | char 'white' 41 | content 'flax' 42 | delimiter 'flax' 43 | escape 'white' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/pry-siberia-8.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-siberia-8', :color_model => 8 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'This one reminds me of the cold Siberia... (just a tad)' 4 | 5 | define_theme do 6 | class_ 'blue' 7 | class_variable 'blue' 8 | comment 'yellow' 9 | constant 'blue' 10 | error 'white', 'blue' 11 | float 'yellow' 12 | global_variable 'yellow' 13 | inline_delimiter 'green' 14 | instance_variable 'blue' 15 | integer 'yellow' 16 | keyword 'cyan' 17 | method 'cyan' 18 | predefined_constant 'cyan' 19 | symbol 'cyan' 20 | 21 | regexp do 22 | self_ 'blue' 23 | char 'cyan' 24 | content 'blue' 25 | delimiter 'cyan' 26 | modifier 'blue' 27 | escape 'blue' 28 | end 29 | 30 | shell do 31 | self_ 'blue' 32 | char 'cyan' 33 | content 'blue' 34 | delimiter 'cyan' 35 | escape 'cyan' 36 | end 37 | 38 | string do 39 | self_ 'blue' 40 | char 'cyan' 41 | content 'blue' 42 | delimiter 'cyan' 43 | escape 'cyan' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/pry-classic-8.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-classic-8', :color_model => 8 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'The default Pry Theme for terminals with poor color support' 4 | 5 | define_theme do 6 | class_ 'magenta' 7 | class_variable 'blue' 8 | comment 'blue' 9 | constant 'blue' 10 | error 'yellow', 'red' 11 | float 'magenta' 12 | global_variable 'green' 13 | inline_delimiter 'red' 14 | instance_variable 'blue' 15 | integer 'blue' 16 | keyword 'red' 17 | method 'blue' 18 | predefined_constant 'cyan' 19 | symbol 'green' 20 | 21 | regexp do 22 | self_ 'red' 23 | char 'red' 24 | content 'red' 25 | delimiter 'red' 26 | modifier 'magenta' 27 | escape 'red' 28 | end 29 | 30 | shell do 31 | self_ 'green' 32 | char 'green' 33 | content 'green' 34 | delimiter 'green' 35 | escape 'green' 36 | end 37 | 38 | string do 39 | self_ 'green' 40 | char 'green' 41 | content 'green' 42 | delimiter 'green' 43 | escape 'green' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/pry-love-8.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-love-8', :color_model => 8 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'Adds the love, expressed in 8 colors' 4 | 5 | define_theme do 6 | class_ 'magenta' 7 | class_variable 'red' 8 | comment 'cyan' 9 | constant 'magenta' 10 | error 'yellow', 'magenta' 11 | float 'magenta' 12 | global_variable 'red' 13 | inline_delimiter 'red' 14 | instance_variable 'red' 15 | integer 'magenta' 16 | keyword 'red' 17 | method 'green' 18 | predefined_constant 'magenta' 19 | symbol 'magenta' 20 | 21 | regexp do 22 | self_ 'yellow' 23 | char 'yellow' 24 | content 'yellow' 25 | delimiter 'red' 26 | modifier 'yellow' 27 | escape 'magenta' 28 | end 29 | 30 | shell do 31 | self_ 'yellow' 32 | char 'yellow' 33 | content 'yellow' 34 | delimiter 'red' 35 | escape 'magenta' 36 | end 37 | 38 | string do 39 | self_ 'yellow' 40 | char 'yellow' 41 | content 'yellow' 42 | delimiter 'red' 43 | escape 'magenta' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/pry-tepid-8.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-tepid-8', :color_model => 8 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'Warm colors with warm soul' 4 | 5 | define_theme do 6 | class_ 'magenta' 7 | class_variable 'magenta' 8 | comment 'green' 9 | constant 'magenta' 10 | error 'black', 'magenta' 11 | float 'green' 12 | global_variable 'green' 13 | inline_delimiter 'yellow' 14 | instance_variable 'magenta' 15 | integer 'green' 16 | keyword 'yellow' 17 | method 'yellow' 18 | predefined_constant 'yellow' 19 | symbol 'yellow' 20 | 21 | regexp do 22 | self_ 'magenta' 23 | char 'yellow' 24 | content 'magenta' 25 | delimiter 'magenta' 26 | modifier 'yellow' 27 | escape 'yellow' 28 | end 29 | 30 | shell do 31 | self_ 'magenta' 32 | char 'yellow' 33 | content 'magenta' 34 | delimiter 'yellow' 35 | escape 'yellow' 36 | end 37 | 38 | string do 39 | self_ 'magenta' 40 | char 'yellow' 41 | content 'magenta' 42 | delimiter 'yellow' 43 | escape 'yellow' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /lib/pry-theme/theme_list.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | module ThemeList 3 | 4 | extend self 5 | 6 | def themes 7 | @themes ||= [] 8 | end 9 | 10 | def add_theme(theme) 11 | themes << theme 12 | end 13 | 14 | def each(&block) 15 | themes.each(&block) 16 | end 17 | 18 | def current_theme 19 | themes.find { |theme| theme.active? } 20 | end 21 | 22 | def activate_theme(name) 23 | theme = themes.find { |t| t.name == name } 24 | 25 | if theme 26 | current_theme.disable if current_theme 27 | theme.activate 28 | true 29 | end 30 | end 31 | 32 | def activate_theme_intelligently 33 | if Pry::Helpers::Platform.windows? 34 | activate_theme('pry-classic-16') 35 | else 36 | case PryTheme.tput_colors 37 | when 256 then activate_theme('pry-classic-256') 38 | when 16 then activate_theme('pry-classic-16') 39 | else activate_theme('pry-classic-8') 40 | end 41 | end 42 | end 43 | 44 | def reload_theme(name, file) 45 | @themes.delete_if { |theme| theme.name == name } 46 | load file 47 | activate_theme(name) 48 | true 49 | end 50 | 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /themes/pry-zealand-8.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-zealand-8', :color_model => 8 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'Feel the presence of New Zealand in your terminal' 4 | 5 | define_theme do 6 | class_ 'yellow' 7 | class_variable 'yellow' 8 | comment 'magenta' 9 | constant 'yellow' 10 | error 'black', 'yellow' 11 | float 'magenta' 12 | global_variable 'magenta' 13 | inline_delimiter 'green' 14 | instance_variable 'yellow' 15 | integer 'magenta' 16 | keyword 'green' 17 | method 'green' 18 | predefined_constant 'green' 19 | symbol 'green' 20 | 21 | regexp do 22 | self_ 'yellow' 23 | char 'green' 24 | content 'yellow' 25 | delimiter 'yellow' 26 | modifier 'green' 27 | escape 'green' 28 | end 29 | 30 | shell do 31 | self_ 'yellow' 32 | char 'green' 33 | content 'yellow' 34 | delimiter 'green' 35 | escape 'green' 36 | end 37 | 38 | string do 39 | self_ 'yellow' 40 | char 'green' 41 | content 'yellow' 42 | delimiter 'green' 43 | escape 'green' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | 50 | -------------------------------------------------------------------------------- /themes/tomorrow.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'tomorrow' do 2 | author :name => 'John Mair' 3 | description 'A theme should not get in your way' 4 | 5 | define_theme do 6 | class_ 'gold' 7 | class_variable 'alizarin' 8 | comment 'gray03' 9 | constant 'gold' 10 | error 'tangerine', [:italic] 11 | float 'tangerine' 12 | global_variable 'alizarin' 13 | inline_delimiter 'heliotrope01' 14 | instance_variable 'alizarin' 15 | integer 'tangerine' 16 | keyword 'heliotrope03' 17 | method 'royal_blue05' 18 | predefined_constant 'tangerine' 19 | symbol 'old_gold' 20 | 21 | regexp do 22 | self_ 'alizarin' 23 | char 'heliotrope01' 24 | content 'old_gold' 25 | delimiter 'alizarin' 26 | modifier 'old_gold' 27 | escape 'heliotrope01' 28 | end 29 | 30 | shell do 31 | self_ 'gray02' 32 | char 'heliotrope01' 33 | content 'puce01' 34 | delimiter 'gray02' 35 | escape 'heliotrope01' 36 | end 37 | 38 | string do 39 | self_ 'old_gold' 40 | char 'heliotrope01' 41 | content 'old_gold' 42 | delimiter 'old_gold' 43 | escape 'heliotrope01' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/zenburn.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'zenburn' do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'A low-contrast color scheme' 4 | 5 | define_theme do 6 | class_ 'dark_peach', [:bold] 7 | class_variable 'dark_peach' 8 | comment 'swamp_green01' 9 | constant 'dark_peach', [:bold] 10 | error 'tenne', [:italic] 11 | float 'silver01' 12 | global_variable 'dark_peach' 13 | inline_delimiter 'gray02' 14 | instance_variable 'dark_peach' 15 | integer 'pale_blue01' 16 | keyword 'dark_salmon', [:bold] 17 | method 'corn02' 18 | predefined_constant 'dark_peach' 19 | symbol 'puce01', [:bold] 20 | 21 | regexp do 22 | self_ 'gray02' 23 | char 'gray02' 24 | content 'puce01' 25 | delimiter 'gray02' 26 | modifier 'gray02' 27 | escape 'gray02' 28 | end 29 | 30 | shell do 31 | self_ 'gray02' 32 | char 'gray02' 33 | content 'puce01' 34 | delimiter 'gray02' 35 | escape 'gray02' 36 | end 37 | 38 | string do 39 | self_ 'gray02' 40 | char 'gray02' 41 | content 'puce01' 42 | delimiter 'gray02' 43 | escape 'gray02' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/vim-default.prytheme.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | t = PryTheme.create :name => 'vim-default', :color_model => 8 do 4 | author :name => '☈king', :email => 'rking-pry-vimscheme@sharpsaw.org' 5 | description 'For those familiar with the default vim colorscheme' 6 | 7 | define_theme do 8 | class_ 'green' 9 | class_variable 'cyan' 10 | comment 'blue' 11 | constant 'green' 12 | error 'white', 'red' 13 | float 'red' 14 | global_variable 'cyan' 15 | inline_delimiter 'red' 16 | instance_variable 'cyan' 17 | integer 'red' 18 | keyword 'magenta' # some should be yellow. CodeRay's limited. 19 | method 'cyan' 20 | predefined_constant 'cyan' 21 | symbol 'red' 22 | 23 | regexp do 24 | self_ 'magenta' 25 | char 'red' 26 | content 'red' 27 | delimiter 'magenta' 28 | modifier 'magenta' 29 | escape 'red' 30 | end 31 | 32 | shell do 33 | self_ 'magenta' 34 | char 'red' 35 | content 'red' 36 | delimiter 'magenta' 37 | escape 'red' 38 | end 39 | 40 | string do 41 | self_ 'magenta' 42 | char 'red' 43 | content 'red' 44 | delimiter 'magenta' 45 | escape 'red' 46 | end 47 | end 48 | end 49 | 50 | PryTheme::ThemeList.add_theme(t) 51 | -------------------------------------------------------------------------------- /themes/pry-love-16.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-love-16', :color_model => 16 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'Adds the love, expressed in 16 colors' 4 | 5 | define_theme do 6 | class_ 'bright_magenta' 7 | class_variable 'red' 8 | comment 'cyan' 9 | constant 'bright_magenta' 10 | error 'bright_yellow', 'magenta' 11 | float 'magenta' 12 | global_variable 'red' 13 | inline_delimiter 'red' 14 | instance_variable 'red' 15 | integer 'magenta' 16 | keyword 'bright_red' 17 | method 'bright_green' 18 | predefined_constant 'magenta' 19 | symbol 'magenta' 20 | 21 | regexp do 22 | self_ 'yellow' 23 | char 'yellow' 24 | content 'yellow' 25 | delimiter 'bright_red' 26 | modifier 'bright_yellow' 27 | escape 'bright_magenta' 28 | end 29 | 30 | shell do 31 | self_ 'yellow' 32 | char 'yellow' 33 | content 'yellow' 34 | delimiter 'bright_red' 35 | escape 'bright_magenta' 36 | end 37 | 38 | string do 39 | self_ 'yellow' 40 | char 'yellow' 41 | content 'yellow' 42 | delimiter 'bright_red' 43 | escape 'bright_magenta' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/pry-modern-16.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-modern-16', :color_model => 16 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'Simplied version of pry-modern-256' 4 | 5 | define_theme do 6 | class_ 'bright_magenta' 7 | class_variable 'bright_cyan' 8 | comment 'blue' 9 | constant 'bright_blue' 10 | error 'black', 'white' 11 | float 'bright_red' 12 | global_variable 'bright_yellow' 13 | inline_delimiter 'bright_green' 14 | instance_variable 'bright_cyan' 15 | integer 'bright_blue' 16 | keyword 'bright_red' 17 | method 'bright_yellow' 18 | predefined_constant 'bright_cyan' 19 | symbol 'bright_green' 20 | 21 | regexp do 22 | self_ 'bright_red' 23 | char 'bright_red' 24 | content 'magenta' 25 | delimiter 'red' 26 | modifier 'red' 27 | escape 'red' 28 | end 29 | 30 | shell do 31 | self_ 'bright_green' 32 | char 'bright_green' 33 | content 'green' 34 | delimiter 'green' 35 | escape 'green' 36 | end 37 | 38 | string do 39 | self_ 'bright_green' 40 | char 'bright_green' 41 | content 'green' 42 | delimiter 'green' 43 | escape 'green' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/pry-siberia-16.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-siberia-16', :color_model => 16 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'This one reminds me of the cold Siberia...' 4 | 5 | define_theme do 6 | class_ 'bright_blue' 7 | class_variable 'bright_blue' 8 | comment 'yellow' 9 | constant 'bright_blue' 10 | error 'white', 'bright_blue' 11 | float 'bright_yellow' 12 | global_variable 'bright_yellow' 13 | inline_delimiter 'green' 14 | instance_variable 'bright_blue' 15 | integer 'bright_yellow' 16 | keyword 'cyan' 17 | method 'bright_cyan' 18 | predefined_constant 'bright_cyan' 19 | symbol 'cyan' 20 | 21 | regexp do 22 | self_ 'bright_blue' 23 | char 'bright_cyan' 24 | content 'bright_blue' 25 | delimiter 'blue' 26 | modifier 'cyan' 27 | escape 'cyan' 28 | end 29 | 30 | shell do 31 | self_ 'bright_blue' 32 | char 'bright_cyan' 33 | content 'bright_blue' 34 | delimiter 'cyan' 35 | escape 'cyan' 36 | end 37 | 38 | string do 39 | self_ 'bright_blue' 40 | char 'bright_cyan' 41 | content 'bright_blue' 42 | delimiter 'cyan' 43 | escape 'cyan' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/solarized.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'solarized' do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'Precision colors for machines and people' 4 | 5 | define_theme do 6 | class_ 'dark_goldenrod' 7 | class_variable 'azure01' 8 | comment 'wet_asphalt05' 9 | constant 'dark_goldenrod' 10 | error 'abdel_kerims_beard04' 11 | float 'robin_egg_blue01' 12 | global_variable 'azure01' 13 | inline_delimiter 'titian' 14 | instance_variable 'azure01' 15 | integer 'robin_egg_blue01' 16 | keyword 'gray03', [:bold] 17 | method 'azure01' 18 | predefined_constant 'azure01' 19 | symbol 'robin_egg_blue01' 20 | 21 | regexp do 22 | self_ 'olive_drab' 23 | char 'titian' 24 | content 'olive_drab' 25 | delimiter 'titian' 26 | modifier 'titian' 27 | escape 'titian' 28 | end 29 | 30 | shell do 31 | self_ 'titian' 32 | char 'titian' 33 | content 'robin_egg_blue01' 34 | delimiter 'titian' 35 | escape 'titian' 36 | end 37 | 38 | string do 39 | self_ 'titian' 40 | char 'titian' 41 | content 'robin_egg_blue01' 42 | delimiter 'titian' 43 | escape 'robin_egg_blue01' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/pry-classic-16.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-classic-16', :color_model => 16 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'The default Pry Theme for terminals with average color support' 4 | 5 | define_theme do 6 | class_ 'bright_magenta' 7 | class_variable 'bright_blue' 8 | comment 'blue' 9 | constant 'bright_blue' 10 | error 'bright_yellow', 'red' 11 | float 'bright_magenta' 12 | global_variable 'green' 13 | inline_delimiter 'red' 14 | instance_variable 'bright_blue' 15 | integer 'bright_blue' 16 | keyword 'bright_red' 17 | method 'bright_blue' 18 | predefined_constant 'bright_cyan' 19 | symbol 'bright_green' 20 | 21 | regexp do 22 | self_ 'red' 23 | char 'red' 24 | content 'red' 25 | delimiter 'bright_red' 26 | modifier 'bright_magenta' 27 | escape 'red' 28 | end 29 | 30 | shell do 31 | self_ 'green' 32 | char 'green' 33 | content 'bright_green' 34 | delimiter 'bright_green' 35 | escape 'green' 36 | end 37 | 38 | string do 39 | self_ 'green' 40 | char 'green' 41 | content 'bright_green' 42 | delimiter 'bright_green' 43 | escape 'green' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/pry-classic-256.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-classic-256' do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'The default Pry Theme' 4 | 5 | define_theme do 6 | class_ 'pale_red_violet03', [:bold] 7 | class_variable 'cerulean_grey02' 8 | comment 'wisteria02' 9 | constant 'blue' 10 | error 'yellow', 'red' 11 | float 'magenta' 12 | global_variable 'lime02' 13 | inline_delimiter 'red' 14 | instance_variable 'cerulean_grey02' 15 | integer 'blue' 16 | keyword 'red' 17 | method 'blue', [:bold] 18 | predefined_constant 'robin_egg_blue04' 19 | symbol 'green' 20 | 21 | regexp do 22 | self_ 'red' 23 | char 'pale_red_violet03' 24 | content 'eggplant02' 25 | delimiter 'red', [:bold] 26 | modifier 'magenta', [:underline] 27 | escape 'red' 28 | end 29 | 30 | shell do 31 | self_ 'green' 32 | char 'dark_spring_green' 33 | content 'green' 34 | delimiter 'green', [:bold] 35 | escape 'dark_spring_green' 36 | end 37 | 38 | string do 39 | self_ 'green' 40 | char 'dark_spring_green' 41 | content 'green' 42 | delimiter 'green', [:bold] 43 | escape 'dark_spring_green' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/github.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'github' do 2 | author :name => 'John Mair' 3 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 4 | description 'Based on GitHub theme' 5 | 6 | define_theme do 7 | class_ 'seroburomalinovyj01', [:bold] 8 | class_variable 'teal01' 9 | comment 'gray01' 10 | constant 'teal' 11 | error 'bismarck_furious', 'periwinkle' 12 | float 'teal01' 13 | global_variable 'teal01' 14 | inline_delimiter 'cerise01' 15 | instance_variable 'teal01' 16 | integer 'teal01' 17 | keyword 'black', [:bold] 18 | method 'maroon', [:bold] 19 | predefined_constant 'teal01' 20 | symbol 'violet_eggplant01' 21 | 22 | regexp do 23 | self_ 'toad_in_love01' 24 | char 'toad_in_love01' 25 | content 'toad_in_love01' 26 | delimiter 'toad_in_love01' 27 | modifier 'toad_in_love01' 28 | escape 'toad_in_love01' 29 | end 30 | 31 | shell do 32 | self_ 'cerise01' 33 | char 'cerise01' 34 | content 'cerise01' 35 | delimiter 'cerise01' 36 | escape 'cerise01' 37 | end 38 | 39 | string do 40 | self_ 'cerise01' 41 | char 'cerise01' 42 | content 'cerise01' 43 | delimiter 'cerise01' 44 | escape 'cerise01' 45 | end 46 | end 47 | end 48 | 49 | PryTheme::ThemeList.add_theme(t) 50 | -------------------------------------------------------------------------------- /themes/pry-tepid-16.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-tepid-16', :color_model => 16 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'Warm colors with warm soul' 4 | 5 | define_theme do 6 | class_ 'bright_magenta' 7 | class_variable 'bright_magenta' 8 | comment 'green' 9 | constant 'bright_magenta' 10 | error 'black', 'bright_magenta' 11 | float 'bright_green' 12 | global_variable 'bright_green' 13 | inline_delimiter 'yellow' 14 | instance_variable 'bright_magenta' 15 | integer 'bright_green' 16 | keyword 'yellow' 17 | method 'bright_yellow' 18 | predefined_constant 'bright_yellow' 19 | symbol 'yellow' 20 | 21 | regexp do 22 | self_ 'bright_magenta' 23 | char 'bright_yellow' 24 | content 'bright_magenta' 25 | delimiter 'magenta' 26 | modifier 'yellow' 27 | escape 'yellow' 28 | end 29 | 30 | shell do 31 | self_ 'bright_magenta' 32 | char 'bright_yellow' 33 | content 'bright_magenta' 34 | delimiter 'yellow' 35 | escape 'yellow' 36 | end 37 | 38 | string do 39 | self_ 'bright_magenta' 40 | char 'bright_yellow' 41 | content 'bright_magenta' 42 | delimiter 'yellow' 43 | escape 'yellow' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/twilight.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'twilight' do 2 | author :name => 'John Mair' 3 | description 'Based on Twilight from Emacs color-theme package' 4 | 5 | define_theme do 6 | class_ 'vert_de_peche' 7 | class_variable 'pale_cornflower_blue', [:bold] 8 | comment 'gray03' 9 | constant 'vert_de_peche' 10 | error 'tenne', [:italic] 11 | float 'silver01' 12 | global_variable 'pale_cornflower_blue' 13 | inline_delimiter 'pistachio01' 14 | instance_variable 'cornflower_blue02' 15 | integer 'pale_blue01' 16 | keyword 'brass02', [:bold] 17 | method 'ochre', [:bold] 18 | predefined_constant 'pale_cornflower_blue' 19 | symbol 'chestnut01' 20 | 21 | regexp do 22 | self_ 'moss_green' 23 | char 'pistachio01' 24 | content 'old_gold' 25 | delimiter 'moss_green' 26 | modifier 'pale_cornflower_blue' 27 | escape 'pistachio01' 28 | end 29 | 30 | shell do 31 | self_ 'moss_green' 32 | char 'pistachio01' 33 | content 'moss_green' 34 | delimiter 'moss_green' 35 | escape 'pistachio01' 36 | end 37 | 38 | string do 39 | self_ 'moss_green' 40 | char 'pistachio01' 41 | content 'moss_green' 42 | delimiter 'moss_green' 43 | escape 'pistachio01' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/railscasts.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'railscasts' do 2 | author :name => 'Ryan Fitzgerald' 3 | author :name => 'John Mair' 4 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 5 | description 'The famous RailsCasts theme' 6 | 7 | define_theme do 8 | class_ 'white' 9 | class_variable 'robin_egg_blue03' 10 | comment 'tan' 11 | constant 'white' 12 | error 'white', 'maroon' 13 | float 'asparagus' 14 | global_variable :bg => 'robin_egg_blue03' 15 | inline_delimiter 'emerald02' 16 | instance_variable 'robin_egg_blue03' 17 | integer 'asparagus' 18 | keyword 'international_orange' 19 | method 'mustard02' 20 | predefined_constant 'robin_egg_blue03' 21 | symbol 'cornflower_blue01' 22 | 23 | regexp do 24 | self_ 'asparagus' 25 | char 'orange' 26 | content 'asparagus' 27 | delimiter 'asparagus' 28 | modifier 'asparagus' 29 | escape 'emerald02' 30 | end 31 | 32 | shell do 33 | self_ 'asparagus' 34 | char 'orange' 35 | content 'asparagus' 36 | delimiter 'asparagus' 37 | escape 'emerald02' 38 | end 39 | 40 | string do 41 | self_ 'asparagus' 42 | char 'orange' 43 | content 'asparagus' 44 | delimiter 'asparagus' 45 | escape 'emerald02' 46 | end 47 | end 48 | end 49 | 50 | PryTheme::ThemeList.add_theme(t) 51 | -------------------------------------------------------------------------------- /themes/pry-cold.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-cold' do 2 | author :name => 'John Mair' 3 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 4 | description 'Based on Charcoalblack theme from Emacs' 5 | 6 | define_theme do 7 | class_ 'robin_egg_blue02', [:bold] 8 | class_variable 'pale_blue03', [:bold] 9 | comment 'light_grey03' 10 | constant 'robin_egg_blue02', [:bold] 11 | error 'robin_egg_blue02', [:bold, :italic] 12 | float 'silver01' 13 | global_variable 'robin_egg_blue02' 14 | inline_delimiter 'puce01' 15 | instance_variable 'pale_blue03' 16 | integer 'seroburomalinovyj01' 17 | keyword 'pale_blue03', [:bold] 18 | method 'royal_blue05' 19 | predefined_constant 'robin_egg_blue02', [:bold] 20 | symbol 'bluish03' 21 | 22 | regexp do 23 | self_ 'gray02' 24 | char 'white' 25 | content 'bluish03' 26 | delimiter 'gray02' 27 | modifier 'gray02' 28 | escape 'puce01' 29 | end 30 | 31 | shell do 32 | self_ 'gray02' 33 | char 'white' 34 | content 'puce01' 35 | delimiter 'gray02' 36 | escape 'puce01' 37 | end 38 | 39 | string do 40 | self_ 'bluish03' 41 | char 'white' 42 | content 'bluish03' 43 | delimiter 'bluish03' 44 | escape 'puce01' 45 | end 46 | end 47 | end 48 | 49 | PryTheme::ThemeList.add_theme(t) 50 | -------------------------------------------------------------------------------- /lib/pry-theme/config.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | # @since 1.1.0 3 | # @api private 4 | # 5 | # Does what the +Pry.config.theme_options+ hash orders. Currently, it 6 | # supports only boolean values. 7 | class Config 8 | # Responsible for actions that are defined in +theme_options+. 9 | class Executor 10 | # @note The method amends the default behaviour of CodeRay. 11 | # 12 | # Sets the colour of the key token to the colour of the symbol token (akin 13 | # to Pygments). 14 | # @example 15 | # {foo: 1, :bar => 2} 16 | # # ^ ^ 17 | # # | | 18 | # # key symbol 19 | # Without this patch keys and symbols have generally different colours. 20 | # It's impossible to set the colour of the key token, but with help of 21 | # this method you can make it look like a symbol. 22 | # @return [void] 23 | # @see https://github.com/kyrylo/pry-theme/issues/30 24 | def paint_key_as_symbol 25 | token_colors = CodeRay::Encoders::Terminal::TOKEN_COLORS 26 | token_colors[:key] = token_colors[:symbol] 27 | end 28 | end 29 | 30 | def initialize(options) 31 | @executor = Executor.new 32 | @options = options 33 | end 34 | 35 | def apply 36 | @options.each do |key, value| 37 | @executor.__send__(key) if value 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /themes/pry-zealand-16.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-zealand-16', :color_model => 16 do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'Feel the presence of green, ecologic and flourishing New Zealand in your terminal' 4 | 5 | define_theme do 6 | class_ 'bright_yellow' 7 | class_variable 'bright_yellow' 8 | comment 'magenta' 9 | constant 'bright_yellow' 10 | error 'black', 'bright_yellow' 11 | float 'bright_magenta' 12 | global_variable 'bright_magenta' 13 | inline_delimiter 'green' 14 | instance_variable 'bright_yellow' 15 | integer 'bright_magenta' 16 | keyword 'green' 17 | method 'bright_green' 18 | predefined_constant 'bright_green' 19 | symbol 'green' 20 | 21 | regexp do 22 | self_ 'bright_yellow' 23 | char 'bright_green' 24 | content 'bright_yellow' 25 | delimiter 'yellow' 26 | modifier 'green' 27 | escape 'green' 28 | end 29 | 30 | shell do 31 | self_ 'bright_yellow' 32 | char 'bright_green' 33 | content 'bright_yellow' 34 | delimiter 'green' 35 | escape 'green' 36 | end 37 | 38 | string do 39 | self_ 'bright_yellow' 40 | char 'bright_green' 41 | content 'bright_yellow' 42 | delimiter 'green' 43 | escape 'green' 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /themes/pry-modern-256.prytheme.rb: -------------------------------------------------------------------------------- 1 | t = PryTheme.create :name => 'pry-modern-256' do 2 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 3 | description 'Nifty version of pry-classic' 4 | 5 | define_theme do 6 | class_ 'fuchsia', [:bold] 7 | class_variable 'robin_egg_blue04' 8 | comment 'cerulean_grey01' 9 | constant 'klein_blue', [:bold, :underline] 10 | error 'cerulean_grey02' 11 | float 'dark_pink01', [:bold] 12 | global_variable 'gold' 13 | inline_delimiter 'malachite01', [:bold] 14 | instance_variable 'robin_egg_blue04' 15 | integer 'robin_egg_blue01', [:bold] 16 | keyword 'chestnut01', [:bold] 17 | method 'grass01', [:bold] 18 | predefined_constant 'cyan', [:bold] 19 | symbol 'malachite02', [:bold] 20 | 21 | regexp do 22 | self_ 'tangerine' 23 | char 'tangerine' 24 | content 'violaceous03' 25 | delimiter 'tangerine', [:bold] 26 | modifier 'dark_pink01', [:bold] 27 | escape 'malachite01', [:bold] 28 | end 29 | 30 | shell do 31 | self_ 'grass01' 32 | char 'grass01' 33 | content 'grass01' 34 | delimiter 'white' 35 | escape 'malachite01', [:bold] 36 | end 37 | 38 | string do 39 | self_ 'malachite01' 40 | char 'malachite01' 41 | content 'malachite01' 42 | delimiter 'malachite01', [:bold] 43 | escape 'malachite01', [:bold] 44 | end 45 | end 46 | end 47 | 48 | PryTheme::ThemeList.add_theme(t) 49 | -------------------------------------------------------------------------------- /spec/hex_spec.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | describe PryTheme::HEX do 4 | HEX = PryTheme::HEX 5 | 6 | it "accepts String with an octothorp as an argument" do 7 | lambda { HEX.new('#ffffff') }.should.not.raise 8 | lambda { HEX.new('#FFFFFF') }.should.not.raise 9 | end 10 | 11 | it "doesn't accept malformed arguments" do 12 | lambda { HEX.new('#fffffff') }.should.raise ArgumentError 13 | lambda { HEX.new('ffffff') }.should.raise ArgumentError 14 | lambda { HEX.new('dqwdqw') }.should.raise ArgumentError 15 | lambda { HEX.new(:boom) }.should.raise TypeError 16 | end 17 | 18 | it "converts itself to rgb" do 19 | HEX.new('#ffffff').to_rgb.to_a.should == [255, 255, 255] 20 | end 21 | 22 | it "converts itself to term 256" do 23 | HEX.new('#ffffff').to_term.to_i.should == 15 24 | HEX.new('#ffffff').to_term(256).to_i.should == 15 25 | end 26 | 27 | it "converts itself to term 256 and determines the nearest term colour" do 28 | HEX.new('#fefefe').to_term.to_i.should == 15 29 | HEX.new('#cecece').to_term.to_i.should == 189 30 | end 31 | 32 | it "converts itself to term 16" do 33 | HEX.new('#ffffff').to_term(16).to_i.should == 15 34 | end 35 | 36 | it "converts itself to term 16 and determines the nearest term colour" do 37 | HEX.new('#fefefe').to_term(16).to_i.should == 15 38 | HEX.new('#cecece').to_term(16).to_i.should == 11 39 | end 40 | 41 | it "converts itself to term 8" do 42 | HEX.new('#ffffff').to_term(8).to_i.should == 0 43 | end 44 | 45 | it "converts itself to term 8 and determines the nearest term colour" do 46 | HEX.new('#3a6e9c').to_term(8).to_i.should == 1 47 | end 48 | 49 | it "represents itself as String" do 50 | HEX.new('#ffffff').to_s.should == '#ffffff' 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /lib/pry-theme/when_started_hook.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | # This is a hook to Pry. It executes upon Pry's launch. The hook is 3 | # responsible for bootstrapping Pry Theme. 4 | class WhenStartedHook 5 | def call(_context, _options, pry_instance) 6 | recreate_user_themes_from_default_ones 7 | load_themes 8 | 9 | if File.exist?(theme_file) 10 | ThemeList.activate_theme(Pry.config.theme) 11 | else 12 | display_warning(pry_instance) if Pry.config.theme 13 | ThemeList.activate_theme_intelligently 14 | end 15 | 16 | apply_config 17 | end 18 | 19 | private 20 | 21 | def apply_config 22 | Pry.config.theme_options ||= {} 23 | PryTheme::Config.new(Pry.config.theme_options).apply 24 | end 25 | 26 | # Copy a default theme to theme directory, but only if it isn't there yet. 27 | def recreate_user_themes_from_default_ones 28 | FileUtils.mkdir_p(USER_THEMES_DIR) unless File.exist?(USER_THEMES_DIR) 29 | default_themes = Dir.entries(DEF_THEMES_DIR) - %w(. ..) 30 | 31 | default_themes.each do |theme| 32 | user_theme_path = File.join(USER_THEMES_DIR, theme) 33 | next if File.exist?(user_theme_path) 34 | def_theme_path = File.join(DEF_THEMES_DIR, theme) 35 | FileUtils.cp(def_theme_path, USER_THEMES_DIR) 36 | end 37 | end 38 | 39 | def load_themes 40 | user_themes = Dir[File.join(USER_THEMES_DIR, '*' + PT_EXT)] 41 | user_themes.each do |theme| 42 | require theme 43 | end 44 | end 45 | 46 | def theme_file 47 | File.join(USER_THEMES_DIR, Pry.config.theme.to_s + PT_EXT) 48 | end 49 | 50 | def display_warning(pry_instance) 51 | pry_instance.output.puts 'Pry Theme Warning: Pry.config.theme is set to ' \ 52 | "\"#{ Pry.config.theme }\". There's no such a theme in your system. " \ 53 | "All installed themes live inside #{ USER_THEMES_DIR }. Falling back " \ 54 | 'to the default theme for now.' 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/pry-theme/term.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | # @since 0.2.0 3 | # @api private 4 | # 5 | # Represents a terminal colour (not ANSI). Checks whether a number fits in its 6 | # colour model. 7 | class TERM 8 | 9 | # @return [Integer] the values are 8, 16 or 256 10 | attr_reader :color_model 11 | 12 | # @param [Integer] value 13 | # @param [Integer] color_model 14 | def initialize(value, color_model = 256) 15 | validate_attrs(value, color_model) 16 | @value = value 17 | @color_model = color_model 18 | end 19 | 20 | # @return [String] 21 | def inspect 22 | "(TERM-#{ @color_model }: #{ @value })" 23 | end 24 | 25 | # @return [Integer] 26 | def to_i 27 | @value 28 | end 29 | 30 | private 31 | 32 | # @param [Integer] value 33 | # @param [Integer] color_model 34 | # @raise [ArgumentError] if the +value+ isn't a valid Integer (not in 35 | # +color_model+ range) or provided incorrect +color_model+ 36 | # @raise [TypeError] if the +value+ or the +color_model+ isn't an Integer 37 | # at all 38 | # @return [void] 39 | def validate_attrs(value, color_model) 40 | integers = value.is_a?(Integer) && color_model.is_a?(Integer) 41 | correct_term = 42 | if integers 43 | case color_model 44 | when 256 then value.between?(0, 255) 45 | when 16 then value.between?(0, 15) 46 | when 8 then value.between?(0, 7) 47 | else raise ArgumentError, 48 | 'invalid color model for PryTheme::TERM#new(): ' \ 49 | "\"#{ color_model }\"" 50 | end 51 | end 52 | 53 | return true if integers && correct_term 54 | 55 | unless integers 56 | raise TypeError, "can't convert #{ value.class } into PryTheme::TERM" 57 | end 58 | 59 | unless correct_term 60 | raise ArgumentError, 61 | %|invalid TERM number for PryTheme::TERM#new(): "#{ value }"| 62 | end 63 | end 64 | 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /themes/vim-detailed.prytheme.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | t = PryTheme.create :name => 'vim-detailed' do 4 | author :name => '☈king', :email => 'rking-pry-vim-detailed@sharpsaw.org' 5 | description "Lil' pal of http://www.vim.org/scripts/script.php?script_id=4297" 6 | 7 | define_theme do 8 | class_ 'vert_de_pomme02' # (originally: green) 9 | class_variable 'bluish01', 'flea_belly' # Intentionally ugly as a warning 10 | comment 'wet_asphalt07' # (originally: blue) 11 | constant 'vert_de_pomme01' # (originally: green) 12 | error 'black', 'bismarck_furious' # (originally: white, red) 13 | float 'titian' # (originally: red) 14 | global_variable 'cerise01', 'black03' # Intentionally ugly as chastisement 15 | inline_delimiter 'pale_mauve02', [:italic] 16 | instance_variable 'light_blue02' # (originally: cyan) 17 | integer 'bismarck_furious' # (originally: red) 18 | keyword 'magenta' 19 | method 'royal_blue02', [:bold] # (originally: cyan) 20 | predefined_constant 'pale_mauve02' # (originally: cyan) 21 | symbol 'cornflower_blue02' # (originally: red) 22 | 23 | regexp do 24 | self_ 'maroon01' # (originally: magenta) 25 | char 'red', 'black03' # (originally: red) 26 | content 'red', 'black03' # (originally: red) 27 | delimiter 'maroon01' # (originally: magenta) 28 | modifier 'lilac01' # (originally: magenta) 29 | escape 'violet_eggplant', [:bold] 30 | end 31 | 32 | shell do 33 | self_ 'pale_mauve02' # (originally: red) 34 | char 'eggplant02', 'black03' 35 | content 'eggplant02' # (originally: red) 36 | delimiter 'bright_violet', 'black03' # (originally: magenta) 37 | escape 'eggplant02', [:bold] 38 | end 39 | 40 | string do 41 | self_ 'titian' # (originally: red) 42 | char 'violet_eggplant01', 'black03' 43 | content 'bismarck_furious', 'black03' 44 | delimiter 'azure01' # (originally: magenta) 45 | escape 'violet_eggplant01', 'black03' # (originally: red) 46 | end 47 | end 48 | end 49 | 50 | PryTheme::ThemeList.add_theme(t) 51 | -------------------------------------------------------------------------------- /lib/pry-theme/preview.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | class Preview 3 | 4 | def initialize(theme) 5 | @theme = theme 6 | end 7 | 8 | def short 9 | cur_theme = ThemeList.current_theme 10 | @theme.activate 11 | [header, description, '--', short_snippet].join("\n") 12 | ensure 13 | @theme.disable 14 | cur_theme.activate 15 | end 16 | 17 | def long 18 | long_snippet 19 | end 20 | 21 | def description 22 | @theme.description 23 | end 24 | 25 | def header 26 | Pry::Helpers::Text.bold("#{ @theme.name } / #{ @theme.color_model }") 27 | end 28 | 29 | def banner(msg) 30 | safe_width = 80 31 | delimiter = ('-' * safe_width) 32 | [delimiter, 33 | Pry::Helpers::Text.bold(msg.center(safe_width)), 34 | delimiter 35 | ].join("\n") + "\n" 36 | end 37 | 38 | private 39 | 40 | def short_snippet 41 | code = Pry::Helpers::CommandHelpers.unindent(<<-'CODE') 42 | 1: class Theme 43 | 2: def method 44 | 3: @ivar, @@cvar, lvar = 10_000, 400.00, "string" 45 | 4: end 46 | 5: end 47 | CODE 48 | Pry::Helpers::BaseHelpers.colorize_code(code) 49 | end 50 | 51 | def long_snippet 52 | code = Pry::Helpers::CommandHelpers.unindent(<<-CODE) 53 | # "#{ @theme.name }" theme. 54 | class PryTheme::ThisIsAClass 55 | def this_is_a_method 56 | THIS_IS_A_CONSTANT = :this_is_a_symbol 57 | this_is_a_local_var = "\#{this} \#@is a string.\\n" 58 | this_is_a_float = 10_000.00 59 | this_is_an_integer = 10_000 60 | 61 | # TRUE and FALSE are predefined constants. 62 | $this_is_a_global_variable = TRUE or FALSE 63 | 64 | @this_is_an_instance_variable = `echo '\#@hi \#{system} call\\n'` 65 | @@this_is_a_class_variable = @@@\\\\$ # An error. 66 | 67 | /[0-9]{1,3}this \#{is} a regexp\\w+/xi 68 | end 69 | end 70 | CODE 71 | Pry::Helpers::BaseHelpers.colorize_code(code) 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /spec/color_table.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | describe PryTheme::ColorTable do 4 | describe "::build_color_string" do 5 | before do 6 | @color256 = PryTheme::Color256.new(:foreground => 100, :background => 101) 7 | @color16 = PryTheme::Color16.new(:foreground => 9, :background => 10) 8 | @color8 = PryTheme::Color8.new(:foreground => 3, :background => 4) 9 | end 10 | 11 | it "builds a suitable (visually) for colour table (256) row" do 12 | output = PryTheme::ColorTable.build_color_string(@color256) 13 | output.should == 14 | "\e[7;38;5;100;48;5;101m100\e[0m:\e[38;5;100;48;5;101molive01\e[0m" 15 | end 16 | 17 | it "builds a suitable (visually) for colour table (16) row" do 18 | output = PryTheme::ColorTable.build_color_string(@color16) 19 | output.should == "\e[7;31;1;42m31;1\e[0m:\e[31;1;42mbright_red\e[0m" 20 | end 21 | 22 | it "builds a suitable (visually) for colour table (8) row" do 23 | output = PryTheme::ColorTable.build_color_string(@color8) 24 | output.should == "\e[7;33;44m33\e[0m:\e[33;44myellow\e[0m" 25 | end 26 | end 27 | 28 | describe "#table" do 29 | it "returns proper table for with 256 colours" do 30 | table = PryTheme::ColorTable.t256 31 | table.should =~ /Color model 256/ 32 | table.should =~ /\e\[7;38;5;147m147\e\[0m:\e\[38;5;147mwisteria02\e\[0m/ 33 | table.should =~ /\e\[7;38;5;24m24\e\[0m:\e\[38;5;24mcerulean_grey01\e\[0m/ 34 | table.should =~ /\e\[7;38;5;0m0\e\[0m:\e\[38;5;0mblack\e\[0m/ 35 | end 36 | 37 | it "returns proper table for with 16 colours" do 38 | table = PryTheme::ColorTable.t16 39 | table.should =~ /Color model 16/ 40 | table.should =~ /\n \e\[7;30m0\e\[0m:\e\[30mblack\e\[0m/ 41 | table.should =~ /\e\[7;35;1m13\e\[0m:\e\[35;1mbright_magenta\e\[0m/ 42 | table.should =~ /\e\[7;37;1m15\e\[0m:\e\[37;1mbright_white\e\[0m\n/ 43 | end 44 | 45 | it "returns proper table for with 8 colours" do 46 | table = PryTheme::ColorTable.t8 47 | table.should =~ /Color model 8/ 48 | table.should =~ /: \e\[7;30m0\e\[0m:\e\[30mblack\e\[0m/ 49 | table.should =~ /\e\[7;33m3\e\[0m:\e\[33myellow\e\[0m/ 50 | table.should =~ /\e\[7;37m7\e\[0m:\e\[37mwhite\e\[0m\n/ 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /lib/pry-theme/hex.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | # @since 0.2.0 3 | # @api private 4 | # 5 | # Represents a HEX colour. It's possible to convert a HEX instance into {TERM} 6 | # or {RGB} colours. However, this conversion is half-duplex (see {RGB}). This 7 | # class validates its input (you won't see malformed or nonexistent HEX 8 | # colours). 9 | # 10 | # @note Conversion to {TERM} relies on {RGB#to_term}, as a {HEX} instance 11 | # converts itself to {RGB} first, and only then to {TERM}. 12 | # @example Conversion to RGB 13 | # HEX.new('#ffffff').to_rgb #=> (RGB: 255, 255, 255) 14 | # @example Conversion to TERM 15 | # HEX.new('#ffffff').to_term(16) #=> (TERM-16: 15) 16 | # 17 | # # Approximation. 18 | # HEX.new('#fc33ea').to_term #=> (TERM-256: 207) 19 | class HEX 20 | 21 | # Represents a single HEX "digit". 22 | BYTE = /[A-F\d]{2}/i 23 | 24 | # A hex String must be prefixed with an octothorp. Use any letter case. 25 | PATTERN = /\A#(#{ BYTE }){3}\z/i 26 | 27 | # @param [String] value must be a valid hex number 28 | def initialize(value) 29 | validate_value(value) 30 | @value = value 31 | end 32 | 33 | # @return [String] 34 | def inspect 35 | "(HEX: #{ @value })" 36 | end 37 | 38 | # @example 39 | # HEX.new('#33aabb').to_s #=> "#33aabb" 40 | # @return [String] 41 | def to_s 42 | @value 43 | end 44 | 45 | # Converts `self` into {RGB}. 46 | # @return [RGB] 47 | def to_rgb 48 | RGB.new(@value[1..-1].scan(BYTE).map! { |b| b.to_i(16) }) 49 | end 50 | 51 | # Converts `self` into {TERM}. 52 | # @return [RGB] 53 | def to_term(color_model = 256) 54 | to_rgb.to_term(color_model) 55 | end 56 | 57 | private 58 | 59 | # Validates whether +value+ is a valid hex colour value. 60 | # 61 | # @param [String] value 62 | # @raise [TypeError] if +value+ isn't String 63 | # @raise [ArgumentError] if +value+ is malformed 64 | # @return [void] 65 | def validate_value(value) 66 | unless value.is_a?(String) 67 | raise TypeError, "can't convert #{ value.class } into PryTheme::HEX" 68 | end 69 | if value !~ PryTheme::HEX::PATTERN 70 | fail ArgumentError, %|invalid value for PryTheme::HEX#new(): "#{value}"| 71 | end 72 | true 73 | end 74 | 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/rgb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | describe PryTheme::RGB do 4 | RGB = PryTheme::RGB 5 | 6 | it "accepts Array as an argument" do 7 | lambda { RGB.new([0, 0, 0]) }.should.not.raise 8 | end 9 | 10 | it "doesn't accept malformed Arrays" do 11 | lambda { RGB.new([0, 0, 0, 0]) }.should.raise ArgumentError 12 | lambda { RGB.new([256, 256, 256]) }.should.raise ArgumentError 13 | lambda { RGB.new([:one, 256, 256]) }.should.raise ArgumentError 14 | end 15 | 16 | it "accepts String as an argument" do 17 | lambda { RGB.new('0, 0, 0') }.should.not.raise 18 | end 19 | 20 | it "doesn't accept malformed Strings" do 21 | lambda { RGB.new('0, 0, 0, 0') }.should.raise ArgumentError 22 | lambda { RGB.new('256, 256, 256') }.should.raise ArgumentError 23 | lambda { RGB.new('256, heaven, 256') }.should.raise ArgumentError 24 | end 25 | 26 | it "raises error if gibberish is given as an argument" do 27 | lambda { RGB.new('jeyenne') }.should.raise ArgumentError 28 | lambda { RGB.new(:jeyenne) }.should.raise TypeError 29 | end 30 | 31 | it "converts itself to term 256" do 32 | RGB.new([0, 0, 0]).to_term.to_i.should == 0 33 | RGB.new('255, 255, 255').to_term.to_i.should == 15 34 | end 35 | 36 | it "converts itself to term 256 and determines the nearest term colour" do 37 | RGB.new('21, 24, 205').to_term.to_i.should == 20 38 | RGB.new('210, 240, 20').to_term.to_i.should == 191 39 | end 40 | 41 | it "converts itself to term 16" do 42 | RGB.new([0, 0, 0]).to_term(16).to_i.should == 0 43 | RGB.new([255, 255, 255]).to_term(16).to_i.should == 15 44 | RGB.new([255, 0, 255]).to_term(16).to_i.should == 13 45 | end 46 | 47 | it "converts itself to and determines the nearest term colour" do 48 | RGB.new([0, 101, 69]).to_term(16).to_i.should == 1 49 | end 50 | 51 | it "converts itself to term 8" do 52 | RGB.new([0, 0, 0]).to_term(8).to_i.should == 0 53 | RGB.new([255, 255, 255]).to_term(8).to_i.should == 0 54 | RGB.new([255, 0, 255]).to_term(8).to_i.should == 0 55 | end 56 | 57 | it "converts itself to and determines the nearest term colour" do 58 | RGB.new([0, 101, 69]).to_term(16).to_i.should == 1 59 | RGB.new([122, 122, 122]).to_term(8).to_i.should == 3 60 | RGB.new([176, 127, 30]).to_term(8).to_i.should == 4 61 | end 62 | 63 | it "converts itself to hex" do 64 | RGB.new([0, 0, 0]).to_hex.to_s.should == '#000000' 65 | RGB.new([255, 255, 255]).to_hex.to_s.should == '#ffffff' 66 | end 67 | 68 | it "represents itself as a String" do 69 | RGB.new([0, 0, 0]).to_s.should == '0, 0, 0' 70 | RGB.new('0, 0, 0').to_s.should == '0, 0, 0' 71 | end 72 | 73 | it "represents itself as an Array" do 74 | RGB.new([0, 0, 0]).to_a.should == [0, 0, 0] 75 | RGB.new('0, 0, 0').to_a.should == [0, 0, 0] 76 | end 77 | 78 | it "represents itself in CSS format" do 79 | RGB.new([0, 0, 0]).to_css.should == 'rgb(0, 0, 0)' 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /lib/pry-theme/basic_editor.rb: -------------------------------------------------------------------------------- 1 | require 'etc' 2 | 3 | module PryTheme 4 | class BasicEditor 5 | 6 | class << self 7 | def edit(theme_name) 8 | editor = new(theme_name) 9 | editor.start_editing 10 | end 11 | end 12 | 13 | attr_reader :current_file, :output 14 | 15 | def initialize(filename) 16 | @filename = filename 17 | theme_path = themify(filename) 18 | 19 | @editor = Pry.config.editor 20 | @new_theme = false 21 | @output = Pry.output 22 | @current_file = File.open(theme_path, 'r+') 23 | rescue Errno::ENOENT 24 | @new_theme = true 25 | @current_file = File.open(theme_path, 'w') 26 | end 27 | 28 | def start_editing 29 | if @new_theme 30 | @output.puts 'Created a new theme.' 31 | @current_file.puts template 32 | @current_file.close 33 | end 34 | @output.puts "Opened in #{ @editor }: #{ themify(@filename) }" 35 | 36 | reload_theme! 37 | output_dashy_header("Current \"#@filename\"") 38 | 39 | Pry::Editor.invoke_editor(@current_file.path, 1) 40 | 41 | reload_theme! 42 | output_dashy_header("Edited \"#@filename\"") 43 | end 44 | 45 | private 46 | 47 | def reload_theme! 48 | ThemeList.reload_theme(@filename, @current_file) 49 | end 50 | 51 | def output_dashy_header(msg) 52 | preview = Preview.new(ThemeList.themes.find { |t| t.name == @filename }) 53 | Pry::Pager.page(preview.banner(msg) + preview.long) 54 | end 55 | 56 | def themify(filename) 57 | File.join(USER_THEMES_DIR, filename + PT_EXT) 58 | end 59 | 60 | def template 61 | Pry::Helpers::CommandHelpers.unindent(<<-TEMPLATE) 62 | t = PryTheme.create :name => '#{ @filename }' do 63 | author :name => '#{ Etc.getlogin || 'me' }', :email => 'user@hostname' 64 | description '#{ @filename } theme' 65 | 66 | # How the flip do I edit this?! 67 | # Help is there: https://github.com/kyrylo/pry-theme/wiki/Creating-a-New-Theme 68 | define_theme do 69 | class_ 70 | class_variable 71 | comment 72 | constant 73 | error 74 | float 75 | global_variable 76 | inline_delimiter 77 | instance_variable 78 | integer 79 | keyword 80 | method 81 | predefined_constant 82 | symbol 83 | 84 | regexp do 85 | self_ 86 | char 87 | content 88 | delimiter 89 | modifier 90 | escape 91 | end 92 | 93 | shell do 94 | self_ 95 | char 96 | content 97 | delimiter 98 | escape 99 | end 100 | 101 | string do 102 | self_ 103 | char 104 | content 105 | delimiter 106 | escape 107 | end 108 | end 109 | end 110 | 111 | PryTheme::ThemeList.add_theme(t) 112 | TEMPLATE 113 | end 114 | 115 | end 116 | end 117 | -------------------------------------------------------------------------------- /lib/pry-theme/definition.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | class Theme 3 | 4 | # @since 0.2.0 5 | # @api private 6 | module DynamicMethod 7 | def def_dynamic_methods(*dynamic_methods) 8 | dynamic_methods.each { |attr| 9 | define_method(attr) do |*args| 10 | name = :"@#{ attr }" 11 | if args.first 12 | decl = 13 | Color::Declaration.t(args, instance_variable_get(:@color_model)) 14 | instance_variable_set(name, decl) 15 | end 16 | instance_variable_get(name) 17 | end 18 | } 19 | end 20 | end 21 | 22 | # @since 0.2.0 23 | # @api private 24 | module DefaultAttrs 25 | def set_default_attrs(attrs) 26 | default_color = PryTheme.const_get(:"Color#{ @color_model }").new 27 | attrs.each do |attr| 28 | instance_variable_set(:"@#{ attr }", default_color.dup) 29 | end 30 | end 31 | 32 | def set_nested_attrs 33 | regexp { set_default_attrs(Definition::Regexp::ATTRS) } 34 | shell { set_default_attrs(Definition::Shell::ATTRS) } 35 | string { set_default_attrs(Definition::String::ATTRS) } 36 | end 37 | 38 | def method_missing(meth, *args, &block) 39 | raise PryTheme::ThemeError, %|unknown option "#{ meth }"| 40 | end 41 | end 42 | 43 | # @since 0.2.0 44 | # @api private 45 | # @todo: possibly, try to avoid duplication. 46 | class Definition 47 | extend DynamicMethod 48 | include DefaultAttrs 49 | 50 | ATTRS = [ 51 | :class_, :class_variable, :comment, :constant, :error, :float, 52 | :global_variable, :inline_delimiter, :instance_variable, :integer, 53 | :keyword, :method, :predefined_constant, :symbol 54 | ] 55 | 56 | def_dynamic_methods(*ATTRS) 57 | 58 | def initialize(color_model, &block) 59 | @color_model = color_model 60 | set_default_attrs(ATTRS) and set_nested_attrs 61 | instance_eval(&block) 62 | end 63 | 64 | def regexp(&block) 65 | @regexp = Definition::Regexp.new(@color_model, &block) if block_given? 66 | @regexp 67 | end 68 | 69 | def shell(&block) 70 | @shell = Definition::Shell.new(@color_model, &block) if block_given? 71 | @shell 72 | end 73 | 74 | def string(&block) 75 | @string = Definition::String.new(@color_model, &block) if block_given? 76 | @string 77 | end 78 | 79 | class Compound 80 | extend DynamicMethod 81 | include DefaultAttrs 82 | 83 | ATTRS = [:self_, :char, :content, :delimiter, :escape] 84 | 85 | def_dynamic_methods(*ATTRS) 86 | 87 | def initialize(color_model, &block) 88 | @color_model = color_model 89 | set_default_attrs(ATTRS) 90 | instance_eval(&block) 91 | end 92 | end 93 | 94 | class Regexp < Compound 95 | ATTRS = [:modifier] 96 | 97 | def_dynamic_methods(*ATTRS) 98 | 99 | def initialize(color_model, &block) 100 | @color_model = color_model 101 | set_default_attrs(ATTRS) 102 | super 103 | end 104 | end 105 | 106 | Shell = Class.new(Compound) 107 | String = Class.new(Compound) 108 | end 109 | 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /lib/pry-theme.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | require 'pry-theme/config' 4 | require 'pry-theme/theme_list' 5 | require 'pry-theme/when_started_hook' 6 | require 'pry-theme/hex' 7 | require 'pry-theme/rgb' 8 | require 'pry-theme/term' 9 | require 'pry-theme/formattable' 10 | require 'pry-theme/declaration' 11 | require 'pry-theme/definition' 12 | require 'pry-theme/theme' 13 | require 'pry-theme/preview' 14 | require 'pry-theme/color' 15 | require 'pry-theme/color_table' 16 | require 'pry-theme/basic_editor' 17 | require 'pry-theme/commands' 18 | 19 | Pry.config.hooks 20 | Pry.config.hooks 21 | .add_hook(:when_started, :pry_theme, PryTheme::WhenStartedHook.new) 22 | 23 | module PryTheme 24 | 25 | # The VERSION file must be in the root directory of the library. 26 | VERSION_FILE = File.expand_path('../../VERSION', __FILE__) 27 | 28 | VERSION = File.exist?(VERSION_FILE) ? 29 | File.read(VERSION_FILE).chomp : '(could not find VERSION file)' 30 | 31 | # The root path of Pry Theme source code. 32 | ROOT = File.expand_path(File.dirname(__FILE__)) 33 | 34 | # The path of the directory with Pry configuration files. 35 | CONFIG_DIR = File.join(ENV['HOME'], '.pry') 36 | 37 | # The path of the default Pry Theme themes. 38 | DEF_THEMES_DIR = File.join(ROOT, '..', 'themes') 39 | 40 | # The path where the user should keep their themes. 41 | USER_THEMES_DIR = File.join(CONFIG_DIR, 'themes') 42 | 43 | # Every Pry Theme file must end with this extension. 44 | PT_EXT = '.prytheme.rb' 45 | 46 | # Pry Theme Collection. 47 | PTC = 'https://api.github.com/repos/kyrylo/pry-theme-collection/contents/' 48 | 49 | # The default URL shortener (used for listing themes from PTC). 50 | SHORTENER = 'http://is.gd/create.php?format=simple&url=' 51 | 52 | # @since 0.2.0 53 | # @api public 54 | class << self 55 | # @see https://github.com/kyrylo/pry-theme/wiki/Creating-a-New-Theme 56 | # 57 | # Creates a new Pry Theme theme. 58 | # 59 | # @example 60 | # my_theme = PryTheme.create name: 'my-theme', color_model: 8 do 61 | # author name: 'John Doe', email: 'johndoe@example.com' 62 | # description 'My first theme' 63 | # 64 | # define_theme do 65 | # class_variable 'red' 66 | # integer 'black' 67 | # method 'white', 'red' 68 | # symbol bg: 'yellow' 69 | # 70 | # string do 71 | # content 'blue', 'black' 72 | # end 73 | # end 74 | # end 75 | # 76 | # my_theme.definition.class_variable.foreground(true) #=> "red" 77 | # my_theme.definition.string.content.background(true) #=> "black" 78 | # 79 | # @param [Hash] config 80 | # @option config [String] :name ('prytheme-\d+') The name of the theme. It 81 | # must be no longer than 18 characters 82 | # @option config [Integer] :color_model (256) The number of colours 83 | # available in the theme that is being created. Besides 256, valid 84 | # arguments are `8` and `16` 85 | def create(config = {}, &block) 86 | Theme.new(config, &block) 87 | end 88 | 89 | # @return [Integer] the number of supported terminal colours. Always equal 90 | # to 16 on Windows. 91 | def tput_colors 92 | `tput colors`.to_i 93 | rescue Errno::ENOENT 94 | 16 95 | end 96 | 97 | # @param [Integer] color 98 | # @return [Class] the class, which corresponds to the given +color+ 99 | def color_const(color) 100 | const_get(:"Color#{ color }") 101 | end 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /lib/pry-theme/declaration.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | class Color 3 | 4 | # @since 0.2.0 5 | # @api private 6 | class Declaration 7 | 8 | class << self 9 | def translate(decl, color_model) 10 | decl = Declaration.new(decl, color_model) 11 | decl.parse 12 | decl.to_color 13 | end 14 | alias_method :t, :translate 15 | end 16 | 17 | def initialize(color_decl, color_model) 18 | validate_effects(color_decl, color_model) 19 | 20 | @color_decl = color_decl 21 | @color_model = color_model 22 | @color_class = PryTheme.const_get(:"Color#{ color_model }") 23 | @effects = {} 24 | @parsed = false 25 | @fg = nil 26 | @bg = nil 27 | end 28 | 29 | def parse 30 | if @parsed 31 | return 32 | else 33 | case @color_decl.size 34 | when 3 then build_from_two_layers 35 | when 2 then build_from_two_args 36 | when 1 then build_from_arg 37 | end 38 | @parsed = true 39 | end 40 | end 41 | 42 | def to_color 43 | [:readable, :hex, :rgb, :term].each do |type| 44 | begin 45 | return @color_class.new({ 46 | :from => type, 47 | :foreground => @fg, 48 | :background => @bg 49 | }.merge!(@effects)) 50 | rescue ArgumentError, TypeError 51 | next 52 | end 53 | end 54 | raise PryTheme::ThemeError, 55 | %|malformed color declaration (#{ [@fg, @bg].compact.join(', ') })| 56 | end 57 | 58 | private 59 | 60 | def validate_effects(color_decl, color_model) 61 | incorrect_color_model = (color_model != 256) 62 | incorrect_declaration = (color_decl.any? do |decl| 63 | decl.is_a?(Array) && decl.all? { |elem| elem.is_a?(Symbol) } 64 | end) 65 | 66 | if incorrect_color_model && incorrect_declaration 67 | raise PryTheme::ThemeError, 68 | 'effects are available only for 256-color themes' 69 | end 70 | end 71 | 72 | def build_effects 73 | if @color_decl.any? 74 | @effects = @color_decl.shift.inject({}) { |h, k| h[k] = true; h } 75 | end 76 | end 77 | 78 | def build_from_two_layers 79 | @fg, @bg = 2.times.map { @color_decl.shift } 80 | build_effects 81 | end 82 | 83 | def build_from_two_args 84 | if decl_has_bg_key? 85 | @bg = @color_decl.first[:bg] 86 | @color_decl.shift 87 | else 88 | @fg = @color_decl.shift 89 | if @color_decl.last.is_a?(Array) 90 | @bg = @color_decl.shift if decl_contains_rgb? 91 | else 92 | @bg = @color_decl.shift 93 | end 94 | end 95 | build_effects 96 | end 97 | 98 | def build_from_arg 99 | f = @color_decl.first 100 | if decl_has_bg_key? 101 | @bg = f[:bg] 102 | @color_decl.shift 103 | elsif f.is_a?(String) || f.is_a?(Integer) 104 | @fg = @color_decl.shift 105 | else 106 | build_effects 107 | end 108 | end 109 | 110 | def decl_has_bg_key? 111 | f = @color_decl.first 112 | f.is_a?(Hash) && f.has_key?(:bg) 113 | end 114 | 115 | def decl_contains_rgb? 116 | l = @color_decl.last 117 | l.size == 3 && l.all? { |decl| decl.is_a?(Integer) } 118 | end 119 | 120 | end 121 | end 122 | end 123 | -------------------------------------------------------------------------------- /lib/pry-theme/theme.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | 3 | # Raised when something goes wrong with Pry Theme themes. It's a general 4 | # exception for everything that comes into collision in theme files. 5 | ThemeError = Class.new(StandardError) 6 | 7 | # @since 0.2.0 8 | # @api private 9 | # @see PryTheme::create 10 | # 11 | # Creates a new Pry Theme theme. This class is not meant for the direct 12 | # instantiation. Use {PryTheme::create} instead. 13 | class Theme 14 | 15 | DEFAULT_CONFIG = { 16 | :name => "prytheme-#{ rand(1_000_000_000) }", 17 | :color_model => 256, 18 | :author => 'Unknown Author', 19 | :description => '', 20 | } 21 | 22 | # Matches against valid theme name. It must start with a letter. The letter 23 | # case is not important. 24 | VALID_NAME = /\A[A-z][A-z0-9-]*\z/i 25 | 26 | # @return [Theme::Definition] the heart of every theme: the colour 27 | # definitions 28 | attr_reader :definition 29 | 30 | # @return [Boolean] whether this theme is a current theme 31 | attr_reader :active 32 | alias_method :active?, :active 33 | 34 | # @see PryTheme::create 35 | def initialize(config = {}, &block) 36 | @config = DEFAULT_CONFIG.merge(config) 37 | @authors = [{ :name => @config[:author] }] 38 | @default_author = true 39 | @active = false 40 | @definition = nil 41 | 42 | validate_config 43 | 44 | instance_eval(&block) 45 | end 46 | 47 | def author(options = nil) 48 | if options 49 | if options[:name].length > 32 50 | raise PryTheme::ThemeError, 51 | "author's name must be no longer than 32 characters" 52 | end 53 | 54 | if @default_author 55 | @default_author = false 56 | @authors[0] = options 57 | else 58 | @authors << options 59 | end 60 | end 61 | @authors 62 | end 63 | 64 | def description(text = nil) 65 | if text 66 | if text.length > 280 67 | raise PryTheme::ThemeError, 68 | "description must be no longer than 280 characters" 69 | end 70 | @config[:description] = text 71 | end 72 | @config[:description] 73 | end 74 | 75 | def define_theme(&block) 76 | @definition = Definition.new(color_model, &block) 77 | end 78 | 79 | def name 80 | @config[:name] 81 | end 82 | 83 | def color_model 84 | @config[:color_model] 85 | end 86 | 87 | def disable 88 | @active = false 89 | end 90 | 91 | def activate 92 | ::CodeRay::Encoders::Terminal::TOKEN_COLORS.merge!(to_coderay) 93 | @active = true 94 | end 95 | 96 | def to_coderay 97 | {}.tap do |coderay| 98 | @definition.class.instance_methods(false).each { |attr| 99 | attr = attr.to_sym 100 | val = @definition.__send__(attr) if @definition 101 | 102 | unless val.kind_of?(Color) 103 | coderay[attr] = {} 104 | ivars = val.instance_variables.delete_if { |v| v =~ /color_model/} 105 | ivars.each do |ivar| 106 | coderay[attr][ivar.to_s.chomp('_')[1..-1].to_sym] = 107 | val.instance_variable_get(ivar).to_ansi 108 | end 109 | else 110 | coderay[attr.to_s.chomp('_').to_sym] = val.to_ansi 111 | end 112 | } 113 | end 114 | end 115 | 116 | private 117 | 118 | def validate_config 119 | if name !~ VALID_NAME 120 | raise PryTheme::ThemeError, 'theme name must start with a letter' 121 | end 122 | 123 | if name.length > 18 124 | raise PryTheme::ThemeError, 125 | 'theme name must be no longer than 18 characters' 126 | end 127 | 128 | unless [256, 8, 16].include?(color_model) 129 | raise PryTheme::ThemeError, 130 | 'incorrect color model. Available values: 8, 16 or 256' 131 | end 132 | end 133 | 134 | end 135 | end 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Pry Theme][logo] 2 | 3 | ![Pry Theme version badge][ver-badge] [![Build Status][ci-badge]][ci-link] 4 | 5 | * Repository: [https://github.com/kyrylo/pry-theme/][pt] 6 | * Wiki: [https://github.com/kyrylo/pry-theme/wiki][wiki] 7 | 8 | Description 9 | ----------- 10 | 11 | Pry Theme is a plugin for [Pry][pry], which helps you to customise your Pry 12 | colors via `prytheme.rb` files. 13 | 14 | ![Railscasts](./screenshots/railscasts.png) 15 | ![Solarized](./screenshots/solarized.png) 16 | ![Tomorrow](./screenshots/tomorrow.png) 17 | ![Zenburn](./screenshots/zenburn.png) 18 | 19 | Installation 20 | ------------ 21 | 22 | All you need is to install the gem. The `pry-theme` plugin will be detected and 23 | used automatically. 24 | 25 | gem install pry-theme 26 | 27 | Synopsis 28 | -------- 29 | 30 | ### Theme files 31 | 32 | Theme file is nothing but a Ruby file, which has `.prytheme.rb` extension (for 33 | example, `beautiful.prytheme.rb`). In order to set up the desired theme, add the 34 | following line to your `.pryrc`: 35 | 36 | Pry.config.theme = "theme-name" 37 | 38 | The default theme is the one from the `pry-classic` family. It is dependent on 39 | your terminal capabilities. For example, if you're using Windows, your default 40 | theme will be `pry-classic-16`, since the Windows terminal can't support more 41 | than 16 colours. If you're using xterm or urxvt, then your default theme will be 42 | `pry-classic-256` (basically, you shouldn't notice it, because it resembles the 43 | default outlook of Pry, as though Pry Theme isn't present). This outlines the 44 | rule: the more colours your terminal supports, the more vivid version of 45 | `pry-classic` is used. 46 | 47 | Let's change it to something more neoteric: 48 | 49 | Pry.config.theme = "pry-modern-256" 50 | 51 | That's all! Launch your Pry and you will see the changes. 52 | 53 | ### CLI 54 | 55 | Pry Theme has a command-line interface available via Pry. Just launch Pry and 56 | start working with it. For example, you can _temporary_ change themes on the 57 | fly (only for the current session): 58 | 59 | [1] pry(main)> pry-theme try pry-classic-8 60 | 61 | This subcommand would switch your current theme to `pry-classic-8` theme. 62 | 63 | You can find [more information about CLI in Pry Theme Wiki][cli]. 64 | 65 | ### Managing themes 66 | 67 | Creating new themes isn't hard. [Check out Pry Theme Wiki article on that][new_theme]. 68 | 69 | Theme files must have `.prytheme.rb` extension. Check out [Pry Theme Collection][ptc] 70 | if you want to find some themes other than default ones. 71 | 72 | If you already have your theme stored somewhere on disk, just put it in the 73 | `$HOME/.pry/themes` directory. 74 | 75 | If you don't want to bother with routine operations, you can install a theme 76 | from the Collection with help of `pry-theme install ` subcommand. For 77 | example, you can want to install the xoria256 theme. Just execute 78 | `pry-theme install xoria256` and you're done. 79 | 80 | Oh, and don't forget to adjust your `.pryrc`! 81 | 82 | Limitations 83 | ----------- 84 | 85 | No limitations. Pry Theme will run everywhere where you can launch Pry. 86 | 87 | Credits 88 | ------- 89 | 90 | * Thanks to [banister][johndogg] for bringing the plugin in masses and 91 | contributing a bunch of themes; 92 | * Thanks to Karandashev for "Puzzle" font; 93 | * Thanks to Creatica for "Dited" font; 94 | * Thanks to [noprompt][noprompt] for a HEX to ANSI conversion Ruby 95 | implementation, which I borrowed from one of his projects. 96 | 97 | License 98 | ------- 99 | 100 | The project uses Zlib License. See LICENSE file for more information. 101 | 102 | [pt]: https://github.com/kyrylo/pry-theme/ "Home page" 103 | [ver-badge]: https://badge.fury.io/rb/pry-theme.png "Pry Theme version badge" 104 | [ci-badge]: https://travis-ci.org/kyrylo/pry-theme.png?branch=master "Build status" 105 | [ci-link]: https://travis-ci.org/kyrylo/pry-theme/ "Build history" 106 | [logo]: http://img-fotki.yandex.ru/get/5107/98991937.a/0_7c6c8_871a1842_orig "Pry Theme" 107 | [pry]: https://github.com/pry/pry/ "Pry's home page" 108 | [new_theme]: https://github.com/kyrylo/pry-theme/wiki/Creating-a-New-Theme 109 | [cli]: https://github.com/kyrylo/pry-theme/wiki/Pry-Theme-CLI 110 | [wiki]: https://github.com/kyrylo/pry-theme/wiki 111 | [ptc]: https://github.com/kyrylo/pry-theme-collection 112 | [johndogg]: https://github.com/banister/ "John Dogg" 113 | [noprompt]: https://github.com/noprompt/ "Joel Holdbrooks" 114 | -------------------------------------------------------------------------------- /spec/commands_spec.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | describe PryTheme::Command::PryTheme do 4 | before do 5 | theme = PryTheme.create(:name => 'wholesome'){} 6 | PryTheme::ThemeList.add_theme(theme) 7 | 8 | other_theme = PryTheme.create(:name => 'sick'){} 9 | PryTheme::ThemeList.add_theme(other_theme) 10 | end 11 | 12 | describe "empty callback" do 13 | it "outputs help" do 14 | pry_eval('pry-theme').should =~ /Usage: pry-theme/ 15 | end 16 | end 17 | 18 | describe "'current' subcommand" do 19 | it "displays current theme name" do 20 | PryTheme::ThemeList.activate_theme('wholesome') 21 | pry_eval('pry-theme current').should == "wholesome\n" 22 | end 23 | 24 | it "displays the short summary about current theme" do 25 | PryTheme::ThemeList.activate_theme('wholesome') 26 | 27 | pry_eval('pry-theme current --colors').should == 28 | Pry::Helpers::CommandHelpers.unindent(<<-'OUT') 29 | # "wholesome" theme. 30 | class PryTheme::ThisIsAClass 31 | def this_is_a_method 32 | THIS_IS_A_CONSTANT = :this_is_a_symbol 33 | this_is_a_local_var = "#{this} #@is a string.\n" 34 | this_is_a_float = 10_000.00 35 | this_is_an_integer = 10_000 36 | 37 | # TRUE and FALSE are predefined constants. 38 | $this_is_a_global_variable = TRUE or FALSE 39 | 40 | @this_is_an_instance_variable = `echo '#@hi #{system} call\n'` 41 | @@this_is_a_class_variable = @@@\\$ # An error. 42 | 43 | /[0-9]{1,3}this #{is} a regexp\w+/xi 44 | end 45 | end 46 | OUT 47 | end 48 | 49 | it "doesn't display anything" do 50 | pry_eval('pry-theme current --foo-bar').should == '' 51 | end 52 | end 53 | 54 | describe "'try' subcommand" do 55 | it "temporary switches to a theme" do 56 | pry_eval('pry-theme try sick').should == "Using \"sick\" theme\n" 57 | PryTheme::ThemeList.current_theme.name.should == 'sick' 58 | 59 | pry_eval('pry-theme try wholesome') 60 | .should == "Using \"wholesome\" theme\n" 61 | PryTheme::ThemeList.current_theme.name.should == 'wholesome' 62 | end 63 | 64 | it "displays error message if can't find the given theme" do 65 | cur = PryTheme::ThemeList.current_theme.name 66 | pry_eval('pry-theme try g-system') 67 | .should =~ /Cannot find "g-system" amongst themes in/ 68 | PryTheme::ThemeList.current_theme.name.should == cur 69 | end 70 | end 71 | 72 | describe "'list' subcommand" do 73 | it "lists currently installed themes" do 74 | pry_eval('pry-theme list').should =~ /class Theme/ 75 | pry_eval('pry-theme list').should =~ /sick/ 76 | end 77 | 78 | it "doesn't mangle current theme" do 79 | cur = PryTheme::ThemeList.current_theme 80 | pry_eval('pry-theme list') 81 | PryTheme::ThemeList.current_theme.should == cur 82 | end 83 | end 84 | 85 | describe "'colors' subcommand" do 86 | before { Pry.config.color = true } 87 | after { Pry.config.color = false } 88 | 89 | if ENV['TERM'] =~ /256color/ 90 | it "displays colours accordingly to the terminal color support" do 91 | table = pry_eval('pry-theme colors') 92 | table.should =~ /silver01/ 93 | table.should =~ /7;38;5;105/ 94 | end 95 | end 96 | 97 | describe "colours according to the chosen model" do 98 | it "displays the table of 256 colours" do 99 | table = pry_eval('pry-theme colors -m 256') 100 | table.should =~ /silver01/ 101 | table.should =~ /7;38;5;105/ 102 | table.should.not =~ /bright_red/ 103 | end 104 | 105 | it "displays the table of 16 colours" do 106 | table = pry_eval('pry-theme colors -m 16') 107 | table.should =~ /bright_red/ 108 | table.should =~ /7;31;1/ 109 | table.should.not =~ /silver01/ 110 | end 111 | 112 | it "displays the table of 8 colours" do 113 | table = pry_eval('pry-theme colors -m 8') 114 | table.should =~ /red/ 115 | table.should =~ /7;36/ 116 | table.should.not =~ /silver01/ 117 | table.should.not =~ /bright_red/ 118 | end 119 | end 120 | end 121 | 122 | describe "'convert' subcommand" do 123 | if ENV['TERM'] =~ /256color/ 124 | it "converts colours accordingly to the terminal color support" do 125 | pry_eval('pry-theme convert -t 124').should =~ /bismarck_furious/ 126 | end 127 | end 128 | 129 | it "warns when no switches given" do 130 | pry_eval('pry-theme convert').should =~ /You must provide the `-m`/ 131 | end 132 | 133 | it "warns on incorrect usage" do 134 | pry_eval('pry-theme convert dqwdwq').should =~ /You must provide the `-m`/ 135 | end 136 | 137 | describe "conversion from term" do 138 | if PryTheme.tput_colors == 256 139 | it "with implicit model" do 140 | pry_eval('pry-theme convert -t 124').should =~ /bismarck_furious/ 141 | end 142 | end 143 | 144 | it "with explicit color model 8" do 145 | pry_eval('pry-theme convert -m 8 -t 7').should =~ /white/ 146 | end 147 | 148 | it "with explicit color model 16" do 149 | pry_eval('pry-theme convert -m 16 -t 10').should =~ /bright_green/ 150 | end 151 | 152 | it "with explicit color model 256" do 153 | pry_eval('pry-theme convert -m 256 -t 124').should =~ /bismarck_furious/ 154 | end 155 | end 156 | 157 | describe "conversion from rgb" do 158 | if PryTheme.tput_colors == 256 159 | it "with implicit model" do 160 | pry_eval('pry-theme convert -r 124,0,11').should =~ /maroon01/ 161 | end 162 | end 163 | 164 | it "with explicit color model 8" do 165 | pry_eval('pry-theme convert -m 8 -r 124,0,11').should =~ /green/ 166 | end 167 | 168 | it "with explicit color model 16" do 169 | pry_eval('pry-theme convert -m 16 -r 124,0,11').should =~ /magenta/ 170 | end 171 | 172 | it "with explicit color model 256" do 173 | pry_eval('pry-theme convert -m 256 -r 124,0,11').should =~ /maroon01/ 174 | end 175 | end 176 | 177 | describe "conversion from hex" do 178 | if PryTheme.tput_colors == 256 179 | it "with implicit model" do 180 | pry_eval('pry-theme convert -h #ae3aff').should =~ /heliotrope02/ 181 | end 182 | end 183 | 184 | it "with explicit color model 8" do 185 | pry_eval('pry-theme convert -m 8 -h #ae3aff').should =~ /blue/ 186 | end 187 | 188 | it "with explicit color model 16" do 189 | pry_eval('pry-theme convert -m 16 -h #ae3aff').should =~ /bright_black/ 190 | end 191 | 192 | it "with explicit color model 256" do 193 | pry_eval('pry-theme convert -m 256 -h #ae3aff').should =~ /heliotrope02/ 194 | end 195 | end 196 | 197 | describe "displaying of error messages" do 198 | it "if colour model was specified without a colour" do 199 | pry_eval('pry-theme convert -m 8').should =~ /Provide a color value/ 200 | end 201 | 202 | it "if colour model is invalid" do 203 | pry_eval('pry-theme convert -m 23 -t 32') 204 | .should =~ /Unknown color model/ 205 | end 206 | end 207 | end 208 | end 209 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by `rubocop --auto-gen-config` 2 | # on 2014-06-14 18:01:49 +0300 using RuboCop version 0.23.0. 3 | # The point is for the user to remove these configuration records 4 | # one by one as the offenses are removed from the code base. 5 | # Note that changes in the inspected code, or installation of new 6 | # versions of RuboCop, may require this file to be generated again. 7 | 8 | # Offense count: 3 9 | Lint/AmbiguousOperator: 10 | Enabled: false 11 | 12 | # Offense count: 18 13 | Lint/AmbiguousRegexpLiteral: 14 | Enabled: false 15 | 16 | # Offense count: 44 17 | Lint/BlockAlignment: 18 | Enabled: false 19 | 20 | # Offense count: 1 21 | # Configuration parameters: AlignWith, SupportedStyles. 22 | Lint/EndAlignment: 23 | Enabled: false 24 | 25 | # Offense count: 1 26 | Lint/InvalidCharacterLiteral: 27 | Enabled: false 28 | 29 | # Offense count: 1 30 | Lint/ShadowingOuterLocalVariable: 31 | Enabled: false 32 | 33 | # Offense count: 3 34 | # Cop supports --auto-correct. 35 | Lint/StringConversionInInterpolation: 36 | Enabled: false 37 | 38 | # Offense count: 7 39 | # Cop supports --auto-correct. 40 | Lint/UnusedBlockArgument: 41 | Enabled: false 42 | 43 | # Offense count: 4 44 | # Cop supports --auto-correct. 45 | Lint/UnusedMethodArgument: 46 | Enabled: false 47 | 48 | # Offense count: 215 49 | Lint/Void: 50 | Enabled: false 51 | 52 | # Offense count: 1 53 | Style/AccessorMethodName: 54 | Enabled: false 55 | 56 | # Offense count: 16 57 | # Cop supports --auto-correct. 58 | # Configuration parameters: EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle, SupportedLastArgumentHashStyles. 59 | Style/AlignHash: 60 | Enabled: false 61 | 62 | # Offense count: 8 63 | # Cop supports --auto-correct. 64 | # Configuration parameters: EnforcedStyle, SupportedStyles. 65 | Style/AlignParameters: 66 | Enabled: false 67 | 68 | # Offense count: 1 69 | # Cop supports --auto-correct. 70 | Style/AndOr: 71 | Enabled: false 72 | 73 | # Offense count: 78 74 | # Cop supports --auto-correct. 75 | Style/Blocks: 76 | Enabled: false 77 | 78 | # Offense count: 1 79 | # Configuration parameters: EnforcedStyle, SupportedStyles. 80 | Style/ClassAndModuleChildren: 81 | Enabled: false 82 | 83 | # Offense count: 3 84 | # Configuration parameters: CountComments. 85 | Style/ClassLength: 86 | Max: 400 87 | 88 | # Offense count: 1 89 | Style/ClassVars: 90 | Enabled: false 91 | 92 | # Offense count: 1 93 | # Cop supports --auto-correct. 94 | # Configuration parameters: PreferredMethods. 95 | Style/CollectionMethods: 96 | Enabled: false 97 | 98 | # Offense count: 14 99 | # Cop supports --auto-correct. 100 | Style/CommentIndentation: 101 | Enabled: false 102 | 103 | # Offense count: 2 104 | Style/CyclomaticComplexity: 105 | Max: 10 106 | 107 | # Offense count: 2 108 | # Cop supports --auto-correct. 109 | Style/DeprecatedHashMethods: 110 | Enabled: false 111 | 112 | # Offense count: 15 113 | Style/Documentation: 114 | Enabled: false 115 | 116 | # Offense count: 37 117 | # Configuration parameters: EnforcedStyle, SupportedStyles. 118 | Style/DotPosition: 119 | Enabled: false 120 | 121 | # Offense count: 3 122 | Style/DoubleNegation: 123 | Enabled: false 124 | 125 | # Offense count: 1 126 | Style/EachWithObject: 127 | Enabled: false 128 | 129 | # Offense count: 3 130 | # Cop supports --auto-correct. 131 | # Configuration parameters: AllowAdjacentOneLineDefs. 132 | Style/EmptyLineBetweenDefs: 133 | Enabled: false 134 | 135 | # Offense count: 1 136 | # Cop supports --auto-correct. 137 | Style/EmptyLines: 138 | Enabled: false 139 | 140 | # Offense count: 32 141 | # Cop supports --auto-correct. 142 | Style/EmptyLinesAroundBody: 143 | Enabled: false 144 | 145 | # Offense count: 19 146 | # Configuration parameters: Exclude. 147 | Style/FileName: 148 | Enabled: false 149 | 150 | # Offense count: 1 151 | # Configuration parameters: EnforcedStyle, SupportedStyles. 152 | Style/For: 153 | Enabled: false 154 | 155 | # Offense count: 3 156 | # Configuration parameters: EnforcedStyle, SupportedStyles. 157 | Style/FormatString: 158 | Enabled: false 159 | 160 | # Offense count: 5 161 | # Configuration parameters: MinBodyLength. 162 | Style/GuardClause: 163 | Enabled: false 164 | 165 | # Offense count: 416 166 | # Cop supports --auto-correct. 167 | # Configuration parameters: EnforcedStyle, SupportedStyles. 168 | Style/HashSyntax: 169 | Enabled: false 170 | 171 | # Offense count: 1 172 | # Configuration parameters: MaxLineLength. 173 | Style/IfUnlessModifier: 174 | Enabled: false 175 | 176 | # Offense count: 3 177 | # Cop supports --auto-correct. 178 | Style/IndentationWidth: 179 | Enabled: false 180 | 181 | # Offense count: 36 182 | Style/Lambda: 183 | Enabled: false 184 | 185 | # Offense count: 26 186 | # Cop supports --auto-correct. 187 | Style/LeadingCommentSpace: 188 | Enabled: false 189 | 190 | # Offense count: 2 191 | # Cop supports --auto-correct. 192 | Style/LineEndConcatenation: 193 | Enabled: false 194 | 195 | # Offense count: 25 196 | Style/LineLength: 197 | Max: 80 198 | 199 | # Offense count: 20 200 | # Configuration parameters: CountComments. 201 | Style/MethodLength: 202 | Max: 45 203 | 204 | # Offense count: 1 205 | Style/ModuleFunction: 206 | Enabled: false 207 | 208 | # Offense count: 1 209 | Style/MultilineTernaryOperator: 210 | Enabled: false 211 | 212 | # Offense count: 1 213 | # Configuration parameters: EnforcedStyle, SupportedStyles. 214 | Style/Next: 215 | Enabled: false 216 | 217 | # Offense count: 11 218 | # Cop supports --auto-correct. 219 | # Configuration parameters: PreferredDelimiters. 220 | Style/PercentLiteralDelimiters: 221 | Enabled: false 222 | 223 | # Offense count: 2 224 | # Cop supports --auto-correct. 225 | # Configuration parameters: AllowAsExpressionSeparator. 226 | Style/Semicolon: 227 | Enabled: false 228 | 229 | # Offense count: 17 230 | # Cop supports --auto-correct. 231 | # Configuration parameters: EnforcedStyle, SupportedStyles. 232 | Style/SignalException: 233 | Enabled: false 234 | 235 | # Offense count: 1 236 | # Configuration parameters: Methods. 237 | Style/SingleLineBlockParams: 238 | Enabled: false 239 | 240 | # Offense count: 3 241 | # Cop supports --auto-correct. 242 | # Configuration parameters: AllowIfMethodIsEmpty. 243 | Style/SingleLineMethods: 244 | Enabled: false 245 | 246 | # Offense count: 1 247 | # Cop supports --auto-correct. 248 | Style/SpaceAfterColon: 249 | Enabled: false 250 | 251 | # Offense count: 2 252 | # Cop supports --auto-correct. 253 | Style/SpaceAroundOperators: 254 | Enabled: false 255 | 256 | # Offense count: 47 257 | # Cop supports --auto-correct. 258 | # Configuration parameters: EnforcedStyle, SupportedStyles. 259 | Style/SpaceBeforeBlockBraces: 260 | Enabled: false 261 | 262 | # Offense count: 4 263 | # Cop supports --auto-correct. 264 | # Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. 265 | Style/SpaceInsideBlockBraces: 266 | Enabled: false 267 | 268 | # Offense count: 79 269 | # Cop supports --auto-correct. 270 | Style/SpaceInsideBrackets: 271 | Enabled: false 272 | 273 | # Offense count: 6 274 | # Cop supports --auto-correct. 275 | # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SupportedStyles. 276 | Style/SpaceInsideHashLiteralBraces: 277 | Enabled: false 278 | 279 | # Offense count: 235 280 | # Cop supports --auto-correct. 281 | # Configuration parameters: EnforcedStyle, SupportedStyles. 282 | Style/StringLiterals: 283 | Enabled: false 284 | 285 | # Offense count: 1 286 | # Cop supports --auto-correct. 287 | # Configuration parameters: EnforcedStyle, SupportedStyles. 288 | Style/TrailingBlankLines: 289 | Enabled: false 290 | 291 | # Offense count: 11 292 | # Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. 293 | Style/TrailingComma: 294 | Enabled: false 295 | 296 | # Offense count: 1 297 | Style/UnlessElse: 298 | Enabled: false 299 | 300 | # Offense count: 3 301 | # Cop supports --auto-correct. 302 | Style/VariableInterpolation: 303 | Enabled: false 304 | -------------------------------------------------------------------------------- /spec/colors/color8_spec.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | describe PryTheme::Color8 do 4 | Color8 = PryTheme::Color8 5 | 6 | describe "foreground" do 7 | it "can be set" do 8 | color = Color8.new(:foreground => 'red') 9 | color.foreground(true).should == 'red' 10 | color.to_ansi.should == "\e[31m" 11 | end 12 | 13 | it "defaults to no colour at all" do 14 | color = Color8.new 15 | color.foreground(true).should == false 16 | color.to_ansi.should == "\e[39;49m" 17 | end 18 | 19 | it "raises error on invalid value" do 20 | lambda { Color8.new(:foreground => 'blah') }. 21 | should.raise(ArgumentError). 22 | message.should.match /invalid foreground value "blah"/ 23 | end 24 | end 25 | 26 | describe "background" do 27 | it "can be set" do 28 | color = Color8.new(:background => 'blue') 29 | color.background(true).should == 'blue' 30 | color.to_ansi.should == "\e[44m" 31 | end 32 | 33 | it "defaults to no colour at all" do 34 | color = Color8.new 35 | color.background(true).should == false 36 | color.to_ansi.should == "\e[39;49m" 37 | end 38 | 39 | it "raises error on invalid value" do 40 | lambda { Color8.new(:background => 'BLACK') }. 41 | should.raise(ArgumentError). 42 | message.should.match /invalid background value "BLACK"/ 43 | end 44 | end 45 | 46 | describe "foreground combined with background" do 47 | it "can be set" do 48 | color = Color8.new(:foreground => 'green', :background => 'red') 49 | color.foreground(true).should == 'green' 50 | color.background(true).should == 'red' 51 | color.to_ansi.should == "\e[32;41m" 52 | end 53 | end 54 | 55 | describe "effects" do 56 | it "can't be bold" do 57 | lambda { Color8.new(:bold => true).bold? }.should.raise(NoMethodError) 58 | end 59 | 60 | it "can't be italic" do 61 | lambda { Color8.new(:italic => true).italic? 62 | }.should.raise(NoMethodError) 63 | end 64 | 65 | it "can't be underlined" do 66 | lambda { Color8.new(:underline => true).underline? 67 | }.should.raise(NoMethodError) 68 | end 69 | end 70 | 71 | describe "argument types" do 72 | describe "readable" do 73 | it "works" do 74 | lambda { 75 | Color8.new( 76 | :from => :readable, 77 | :foreground => 'black', 78 | :background => 'white') 79 | }.should.not.raise 80 | end 81 | 82 | it "doesn't work with incorrect input" do 83 | lambda { 84 | Color8.new( 85 | :from => :readable, 86 | :foreground => '#222222', 87 | :background => [123, 11, 44]) 88 | }.should.raise(ArgumentError) 89 | end 90 | 91 | it "sets background and foreground properly" do 92 | color = Color8.new(:from => :readable, 93 | :foreground => 'black', 94 | :background => 'green') 95 | color.foreground.should == 30 96 | color.foreground(true).should == 'black' 97 | color.background.should == 42 98 | color.background(true).should == 'green' 99 | end 100 | 101 | it "sets foreground properly" do 102 | color = Color8.new(:from => :readable, :foreground => 'black') 103 | color.foreground.should == 30 104 | color.foreground(true).should == 'black' 105 | color.background.should == false 106 | color.background(true).should == false 107 | end 108 | 109 | it "sets background properly" do 110 | color = Color8.new(:from => :readable, :background => 'green') 111 | color.foreground.should == false 112 | color.foreground(true).should == false 113 | color.background.should == 42 114 | color.background(true).should == 'green' 115 | end 116 | end 117 | 118 | describe "hex" do 119 | it "works" do 120 | lambda { 121 | Color8.new( 122 | :from => :hex, 123 | :foreground => '#afaf11', 124 | :background => '#eaeaea') 125 | }.should.not.raise 126 | end 127 | 128 | it "doesn't work with incorrect input" do 129 | lambda { 130 | Color8.new( 131 | :from => :hex, 132 | :foreground => '#222222', 133 | :background => [123, 11, 44]) 134 | }.should.raise(TypeError) 135 | end 136 | 137 | it "sets background and foreground properly" do 138 | color = Color8.new(:from => :hex, 139 | :foreground => '#afaf11', 140 | :background => '#eaeaea') 141 | color.foreground.should == 34 142 | color.foreground(true).should == 'blue' 143 | color.background.should == 45 144 | color.background(true).should == 'magenta' 145 | end 146 | 147 | it "sets foreground properly" do 148 | color = Color8.new(:from => :hex, :foreground => '#afaf11') 149 | color.foreground.should == 34 150 | color.foreground(true).should == 'blue' 151 | color.background.should == false 152 | color.background(true).should == false 153 | end 154 | 155 | it "sets background properly" do 156 | color = Color8.new(:from => :hex, :background => '#eaeaea') 157 | color.foreground.should == false 158 | color.foreground(true).should == false 159 | color.background.should == 45 160 | color.background(true).should == 'magenta' 161 | end 162 | end 163 | 164 | describe "rgb" do 165 | it "works" do 166 | lambda { 167 | Color8.new( 168 | :from => :rgb, 169 | :foreground => '31, 125, 88', 170 | :background => [123, 11, 44]) 171 | }.should.not.raise(ArgumentError) 172 | end 173 | 174 | it "doesn't work with incorrect input" do 175 | lambda { 176 | Color8.new( 177 | :from => :rgb, 178 | :foreground => '#222222', 179 | :background => [123, 11, 44]) 180 | }.should.raise(ArgumentError) 181 | end 182 | 183 | it "sets background and foreground properly" do 184 | color = Color8.new(:from => :rgb, 185 | :foreground => '31, 31, 101', 186 | :background => '125, 101, 255') 187 | color.foreground.should == 30 188 | color.foreground(true).should == 'black' 189 | color.background.should == 43 190 | color.background(true).should == 'yellow' 191 | end 192 | 193 | it "sets foreground properly" do 194 | color = Color8.new(:from => :rgb, :foreground => '31, 31, 101') 195 | color.foreground.should == 30 196 | color.foreground(true).should == 'black' 197 | color.background.should == false 198 | color.background(true).should == false 199 | end 200 | 201 | it "sets background properly" do 202 | color = Color8.new(:from => :rgb, :background => '125, 101, 255') 203 | color.foreground.should == false 204 | color.foreground(true).should == false 205 | color.background.should == 43 206 | color.background(true).should == 'yellow' 207 | end 208 | end 209 | 210 | describe "term" do 211 | it "works" do 212 | lambda { 213 | Color8.new( 214 | :from => :term, 215 | :foreground => 1, 216 | :background => 7) 217 | }.should.not.raise(ArgumentError) 218 | end 219 | 220 | it "doesn't work with incorrect input" do 221 | lambda { 222 | Color8.new( 223 | :from => :term, 224 | :foreground => 33, 225 | :background => 42) 226 | }.should.raise(ArgumentError) 227 | end 228 | 229 | it "sets background and foreground properly" do 230 | color = Color8.new(:from => :term, :foreground => 0, :background => 7) 231 | color.foreground.should == 30 232 | color.foreground(true).should == 'black' 233 | color.background.should == 47 234 | color.background(true).should == 'white' 235 | end 236 | 237 | it "sets foreground properly" do 238 | color = Color8.new(:from => :term, :foreground => 0) 239 | color.foreground.should == 30 240 | color.foreground(true).should == 'black' 241 | color.background.should == false 242 | color.background(true).should == false 243 | end 244 | 245 | it "sets background properly" do 246 | color = Color8.new(:from => :term, :background => 7) 247 | color.foreground.should == false 248 | color.foreground(true).should == false 249 | color.background.should == 47 250 | color.background(true).should == 'white' 251 | end 252 | end 253 | end 254 | end 255 | -------------------------------------------------------------------------------- /spec/colors/color16_spec.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | describe PryTheme::Color16 do 4 | Color16 = PryTheme::Color16 5 | 6 | describe "foreground" do 7 | it "can be set" do 8 | color = Color16.new(:foreground => 'bright_red') 9 | color.foreground(true).should == 'bright_red' 10 | color.to_ansi.should == "\e[31;1m" 11 | 12 | color = Color16.new(:foreground => 'red') 13 | color.foreground(true).should == 'red' 14 | color.to_ansi.should == "\e[31m" 15 | end 16 | 17 | it "defaults to no colour at all" do 18 | color = Color16.new 19 | color.foreground(true).should == false 20 | color.to_ansi.should == "\e[39;49m" 21 | end 22 | 23 | it "raises error on invalid value" do 24 | lambda { Color16.new(:foreground => 'blah') }. 25 | should.raise(ArgumentError). 26 | message.should.match /invalid foreground value "blah"/ 27 | end 28 | end 29 | 30 | describe "background" do 31 | it "can be set" do 32 | color = Color16.new(:background => 'blue') 33 | color.background(true).should == 'blue' 34 | color.to_ansi.should == "\e[44m" 35 | end 36 | 37 | it "raises error on invalid value" do 38 | lambda { Color16.new(:background => 'blah') }. 39 | should.raise(ArgumentError). 40 | message.should.match /invalid background value "blah"/ 41 | end 42 | end 43 | 44 | describe "foreground combined with background" do 45 | it "can be set" do 46 | color = Color16.new( 47 | :foreground => 'bright_yellow', 48 | :background => 'bright_white') 49 | color.foreground(true).should == 'bright_yellow' 50 | color.background(true).should == 'bright_white' 51 | color.to_ansi.should == "\e[33;1;47m" 52 | end 53 | end 54 | 55 | describe "effects" do 56 | it "can't be bold" do 57 | lambda { Color16.new(:bold => true).bold? }.should.raise(NoMethodError) 58 | end 59 | 60 | it "can't be italic" do 61 | lambda { Color16.new(:italic => true).italic? 62 | }.should.raise(NoMethodError) 63 | end 64 | 65 | it "can't be underlined" do 66 | lambda { Color16.new(:underline => true).underline? 67 | }.should.raise(NoMethodError) 68 | end 69 | end 70 | 71 | describe "argument types" do 72 | describe "readable" do 73 | it "works" do 74 | lambda { 75 | Color16.new( 76 | :from => :readable, 77 | :foreground => 'yellow', 78 | :background => 'yellow') 79 | }.should.not.raise 80 | end 81 | 82 | it "doesn't work with incorrect input" do 83 | lambda { 84 | Color16.new( 85 | :from => :readable, 86 | :foreground => 'yellow', 87 | :background => '') 88 | }.should.raise(ArgumentError) 89 | end 90 | 91 | it "sets background and foreground properly" do 92 | color = Color16.new(:from => :readable, 93 | :foreground => 'bright_black', 94 | :background => 'green') 95 | color.foreground.should == '30;1' 96 | color.foreground(true).should == 'bright_black' 97 | color.background.should == 42 98 | color.background(true).should == 'green' 99 | end 100 | 101 | it "sets foreground properly" do 102 | color = Color16.new(:from => :readable, :foreground => 'bright_black') 103 | color.foreground.should == '30;1' 104 | color.foreground(true).should == 'bright_black' 105 | color.background.should == false 106 | color.background(true).should == false 107 | end 108 | 109 | it "sets background properly" do 110 | color = Color16.new(:from => :readable, :background => 'green') 111 | color.foreground.should == false 112 | color.foreground(true).should == false 113 | color.background.should == 42 114 | color.background(true).should == 'green' 115 | end 116 | end 117 | 118 | describe "hex" do 119 | it "works" do 120 | lambda { 121 | Color16.new( 122 | :from => :hex, 123 | :foreground => '#afaf11', 124 | :background => '#eaeaea') 125 | }.should.not.raise 126 | end 127 | 128 | it "doesn't work with incorrect input" do 129 | lambda { 130 | Color16.new( 131 | :from => :hex, 132 | :foreground => '#222222', 133 | :background => [123, 11, 44]) 134 | }.should.raise(TypeError) 135 | end 136 | 137 | it "sets background and foreground properly" do 138 | color = Color16.new(:from => :hex, 139 | :foreground => '#afaf11', 140 | :background => '#eaeaea') 141 | color.foreground.should == '30;1' 142 | color.foreground(true).should == 'bright_black' 143 | color.background.should == 43 144 | color.background(true).should == 'bright_yellow' 145 | end 146 | 147 | it "sets foreground properly" do 148 | color = Color16.new(:from => :hex, :foreground => '#afaf11') 149 | color.foreground.should == '30;1' 150 | color.foreground(true).should == 'bright_black' 151 | color.background.should == false 152 | color.background(true).should == false 153 | end 154 | 155 | it "sets background properly" do 156 | color = Color16.new(:from => :hex, :background => '#eaeaea') 157 | color.foreground.should == false 158 | color.foreground(true).should == false 159 | color.background.should == 43 160 | color.background(true).should == 'bright_yellow' 161 | end 162 | end 163 | 164 | describe "rgb" do 165 | it "works" do 166 | lambda { 167 | Color16.new( 168 | :from => :rgb, 169 | :foreground => '31, 125, 88', 170 | :background => [123, 11, 44]) 171 | }.should.not.raise(ArgumentError) 172 | end 173 | 174 | it "doesn't work with incorrect input" do 175 | lambda { 176 | Color16.new( 177 | :from => :rgb, 178 | :foreground => '#222222', 179 | :background => [123, 11, 44]) 180 | }.should.raise(ArgumentError) 181 | end 182 | 183 | it "sets background and foreground properly" do 184 | color = Color16.new(:from => :rgb, 185 | :foreground => '31, 31, 101', 186 | :background => '125, 101, 255') 187 | color.foreground.should == 31 188 | color.foreground(true).should == 'red' 189 | color.background.should == 46 190 | color.background(true).should == 'cyan' 191 | end 192 | 193 | it "sets foreground properly" do 194 | color = Color16.new(:from => :rgb, :foreground => '31, 31, 101') 195 | color.foreground.should == 31 196 | color.foreground(true).should == 'red' 197 | color.background.should == false 198 | color.background(true).should == false 199 | end 200 | 201 | it "sets background properly" do 202 | color = Color16.new(:from => :rgb, :background => '125, 101, 255') 203 | color.foreground.should == false 204 | color.foreground(true).should == false 205 | color.background.should == 46 206 | color.background(true).should == 'cyan' 207 | end 208 | end 209 | 210 | describe "term" do 211 | it "works" do 212 | lambda { 213 | Color16.new( 214 | :from => :term, 215 | :foreground => 10, 216 | :background => 7) 217 | }.should.not.raise(ArgumentError) 218 | end 219 | 220 | it "doesn't work with incorrect input" do 221 | lambda { 222 | Color16.new( 223 | :from => :term, 224 | :foreground => 10, 225 | :background => 'asd') 226 | }.should.raise(TypeError) 227 | end 228 | 229 | it "sets background and foreground properly" do 230 | color = Color16.new(:from => :term, :foreground => 4, :background => 8) 231 | color.foreground.should == 34 232 | color.foreground(true).should == 'blue' 233 | color.background.should == 40 234 | color.background(true).should == 'bright_black' 235 | end 236 | 237 | it "sets foreground properly" do 238 | color = Color16.new(:from => :term, :foreground => 4) 239 | color.foreground.should == 34 240 | color.foreground(true).should == 'blue' 241 | color.background.should == false 242 | color.background(true).should == false 243 | end 244 | 245 | it "sets background properly" do 246 | color = Color16.new(:from => :term, :background => 8) 247 | color.foreground.should == false 248 | color.foreground(true).should == false 249 | color.background.should == 40 250 | color.background(true).should == 'bright_black' 251 | end 252 | end 253 | end 254 | 255 | end 256 | -------------------------------------------------------------------------------- /lib/pry-theme/commands.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | module PryTheme 4 | Command = Class.new 5 | 6 | class Command::PryTheme < Pry::ClassCommand 7 | include Pry::Helpers::BaseHelpers 8 | include Pry::Helpers::CommandHelpers 9 | 10 | match 'pry-theme' 11 | description 'Manage your Pry themes.' 12 | 13 | banner <<-'BANNER' 14 | Usage: pry-theme [OPTIONS] [--help] 15 | 16 | The command comes from `pry-theme` plugin. It enbales color theme support for your 17 | Pry. Set up your favorite theme in `~/.pryrc` config file. For example, if you 18 | enjoy Zenburn theme, add the following line: `Pry.config.theme = 'zenburn'`. 19 | 20 | You can create your own themes with help of `edit` subcommand. More information 21 | can be found in the appropriate arcticle: http://is.gd/YPuTjM 22 | Tokens cheatsheet might come in handy, too: http://is.gd/D7GoVe 23 | 24 | pry-theme try pry-modern-256 # changes theme (lasts for current session only) 25 | pry-theme current # shows currently active theme name 26 | pry-theme current --colors # tests colors from the current theme 27 | pry-theme list # shows all installed themes as colorful snippets 28 | pry-theme list --remote # shows all themes from Pry Theme Collection 29 | pry-theme colors # shows the list of all color names 30 | pry-theme colors --model 8 # shows the list of colors according to 8 color model 31 | pry-theme install autumn # installs a theme from Pry Theme Collection 32 | pry-theme uninstall monokai # uninstalls a theme 33 | pry-theme convert -m 16 -t 3 # converts a single color to a term color 34 | pry-theme edit zenburn # opens Zenburn theme in `Pry.editor` 35 | BANNER 36 | 37 | def def_list(cmd) 38 | cmd.command :list do |opt| 39 | opt.description 'Show a list of all installed themes' 40 | 41 | opt.on :r, :remote, 'Show a list of all themes from Pry Theme Collection' 42 | 43 | opt.run do |opts, args| 44 | opts.present?(:r) ? show_remote_list : show_local_list 45 | end 46 | end 47 | end 48 | 49 | def def_colors(cmd) 50 | cmd.command :colors do |opt| 51 | opt.description 'Show all available colors' 52 | 53 | opt.on :m, :model=, 'Display colors according to the given color model' 54 | 55 | opt.run do |opts, args| 56 | if opts.present?(:m) 57 | display_colors(opts[:m].to_i) 58 | else 59 | display_colors(PryTheme.tput_colors) 60 | end 61 | end 62 | end 63 | end 64 | 65 | def def_try(cmd) 66 | cmd.command :try do |opt| 67 | opt.description 'Change theme on the fly (for the current session only)' 68 | 69 | opt.run do |opts, args| 70 | if PryTheme::ThemeList.activate_theme(args.first) 71 | output.puts %|Using "#{ args.first }" theme| 72 | elsif args.first 73 | output.puts %|Cannot find "#{args.first}" amongst themes in #{USER_THEMES_DIR}| 74 | end 75 | end 76 | end 77 | end 78 | 79 | def def_convert(cmd) 80 | cmd.command :convert do |opt| 81 | opt.description 'Convert the given color to proper terminal equivalent' 82 | 83 | opt.on :t, :term=, 'Show a terminal color' 84 | opt.on :h, :hex=, 'Convert from HEX' 85 | opt.on :r, :rgb=, 'Convert from RGB' 86 | opt.on :m, :model=, 'Convert accordingly to the given color model' 87 | 88 | opt.run do |opts, args| 89 | if color_model_option_only?(opts) 90 | output.puts 'Provide a color value to be converted' 91 | elsif color_model_option_and_other_one?(opts) || without_color_model?(opts) 92 | convert_color(opts, args) 93 | else 94 | output.puts 'You must provide the `-m` and one of the rest switches.' 95 | examples = [ 96 | 'pry-theme convert --model 8 --term 2', 97 | 'pry-theme convert --model 8 --rgb 103,104,0', 98 | 'pry-theme convert --model 16 --hex #EEAA00', 99 | 'pry-theme convert --model 16 --term 0', 100 | 'pry-theme convert --model 256 --term 255', 101 | 'pry-theme convert --model 256 --hex #EEAA00', 102 | ] 103 | output.puts "Example: #{ examples[rand(examples.size)] }" 104 | end 105 | end 106 | end 107 | end 108 | 109 | def def_uninstall(cmd) 110 | cmd.command :uninstall do |opt| 111 | opt.description 'Uninstall a theme' 112 | 113 | opt.run do |opts, args| 114 | args.each { |theme| 115 | begin 116 | FileUtils.rm(File.join(USER_THEMES_DIR, "#{ theme }.prytheme.rb")) 117 | output.puts %|Successfully uninstalled "#{ theme }"!| 118 | rescue 119 | output.puts %|Cannot find theme "#{ theme }"| 120 | end 121 | } 122 | end 123 | end 124 | end 125 | 126 | def def_install(cmd) 127 | cmd.command :install do |opt| 128 | opt.description 'Install a theme from Pry Theme Collection' 129 | 130 | opt.run do |opts, args| 131 | install_theme(args) 132 | end 133 | end 134 | end 135 | 136 | def def_current(cmd) 137 | cmd.command :current do |opt| 138 | opt.description 'Show information about currently active theme' 139 | 140 | opt.on :c, :colors, 'Display a painted code snippet' 141 | 142 | opt.run do |opts, args| 143 | 144 | if opts.present?(:c) 145 | _pry_.pager.page Preview.new(ThemeList.current_theme).long 146 | elsif args.empty? 147 | output.puts ThemeList.current_theme.name 148 | end 149 | end 150 | end 151 | end 152 | 153 | def def_edit(cmd) 154 | cmd.command :edit do |opt| 155 | opt.description 'Edit a theme definition' 156 | 157 | opt.run do |opts, args| 158 | BasicEditor.edit(args.first || ThemeList.current_theme.name) 159 | end 160 | end 161 | end 162 | 163 | def subcommands(cmd) 164 | [:def_list, :def_colors, :def_try, :def_edit, 165 | :def_uninstall, :def_install, :def_current, :def_convert, 166 | ].each { |m| __send__(m, cmd) } 167 | 168 | cmd.add_callback(:empty) do 169 | _pry_.pager.page opts.help 170 | end 171 | end 172 | 173 | def process 174 | # "There's no emptiness in the life of a warrior. Everything is filled to 175 | # the brim. Everything is filled to the brim, and everything is equal." 176 | end 177 | 178 | def complete(so_far) 179 | PryTheme::ThemeList.themes.map(&:name) 180 | end 181 | 182 | private 183 | 184 | def display_colors(color_model) 185 | case color_model 186 | when 256 then _pry_.pager.page(ColorTable.t256) 187 | when 16 then _pry_.pager.page(ColorTable.t16) 188 | when 8 then _pry_.pager.page(ColorTable.t8) 189 | end 190 | end 191 | 192 | def show_local_list 193 | previews = ThemeList.themes.map { |theme| Preview.new(theme).short } 194 | _pry_.pager.page(previews.join("\n")) 195 | end 196 | 197 | def show_remote_list 198 | output.puts 'Fetching the list of themes from Pry Theme Collection...' 199 | output.puts "#{windows?? '->':'→'} https://github.com/kyrylo/pry-theme-collection/" 200 | body = json_body(PryTheme::PTC) 201 | 202 | themes = body.map { |theme| 203 | unless installed?(theme) 204 | [theme['name'], theme['html_url']] 205 | end 206 | }.compact 207 | 208 | out = "--\n" 209 | themes.each.with_index(1) { |theme, i| 210 | out += "#{ i }. " 211 | out += theme.first + "\n" 212 | 213 | uri = URI.parse(PryTheme::SHORTENER + theme.last) 214 | http = Net::HTTP.new(uri.host, uri.port) 215 | response = http.request(Net::HTTP::Get.new(uri.request_uri)) 216 | 217 | out += response.body + "\n\n" 218 | } 219 | _pry_.pager.page(out.chomp) 220 | end 221 | 222 | def json_body(address) 223 | require 'net/https' 224 | require 'json' 225 | require 'base64' 226 | 227 | uri = URI.parse(address) 228 | http = Net::HTTP.new(uri.host, uri.port) 229 | http.use_ssl = true 230 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE if Pry::Helpers::Platform.windows? 231 | response = http.request(Net::HTTP::Get.new(uri.request_uri)) 232 | JSON.parse(response.body) 233 | end 234 | 235 | def install_theme(args) 236 | args.each { |theme| 237 | output.puts %|Installing "#{ theme }" from Pry Theme Collection...| 238 | body = json_body(PTC + "%s/%s#{ PT_EXT }" % [theme, theme]) 239 | 240 | if body['message'] 241 | output.puts %|Cannot find theme "#{ theme }"...| 242 | next 243 | end 244 | 245 | File.open(File.join(USER_THEMES_DIR, "#{theme}.prytheme.rb"), 'w') do |f| 246 | f.puts Base64.decode64(body['content']) 247 | end 248 | require File.join(USER_THEMES_DIR, "#{theme}.prytheme.rb") 249 | output.puts %|Successfully installed "#{ theme }"!| 250 | } 251 | end 252 | 253 | def convert_color(opts, args) 254 | color_model = (opts.present?(:m) ? opts[:m] : PryTheme.tput_colors) 255 | 256 | if opts.present?(:t) 257 | color = PryTheme.color_const(color_model).new( 258 | :from => :term, :foreground => opts[:t].to_i) 259 | elsif opts.present?(:h) 260 | color = PryTheme.color_const(color_model).new( 261 | :from => :hex, :foreground => opts[:h]) 262 | elsif opts.present?(:r) 263 | color = PryTheme.color_const(color_model).new( 264 | :from => :rgb, :foreground => opts[:r]) 265 | end 266 | output.puts ColorTable.build_color_string(color) 267 | rescue NameError 268 | output.puts %|Unknown color model "#{ opts[:m] }". Try 8, 16 or 256| 269 | end 270 | 271 | def color_model_option_only?(opts) 272 | opts[:m] && !(opts[:h] || opts[:r] || opts[:t]) 273 | end 274 | 275 | def color_model_option_and_other_one?(opts) 276 | opts[:m] && (opts[:h] || opts[:r] || opts[:t]) 277 | end 278 | 279 | def without_color_model?(opts) 280 | !opts[:m] && (opts[:h] || opts[:r] || opts[:t]) 281 | end 282 | 283 | def installed?(theme) 284 | theme['name'] == 'README.md' || 285 | ThemeList.themes.map(&:name).include?(theme['name']) 286 | end 287 | end 288 | 289 | Pry::Commands.add_command(PryTheme::Command::PryTheme) 290 | end 291 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Pry Theme changelog 2 | =================== 3 | 4 | ### master 5 | 6 | ### v1.3.1 (August 19, 2020) 7 | 8 | * Fixed ``NoMethodError: undefined method `windows?`` 9 | ([#62](https://github.com/kyrylo/pry-theme/pull/62)) 10 | 11 | ### v1.3.0 (January 26, 2019) 12 | 13 | * Fixed the "method BaseHelpers#windows? is deprecated" warning 14 | ([#55](https://github.com/kyrylo/pry-theme/pull/55)) 15 | 16 | ### v1.2.0 (January 16, 2016) 17 | 18 | * **IMPORTANT:** dropped support for Ruby <2.0 19 | ([#51](https://github.com/kyrylo/pry-theme/pull/51)) 20 | * Started depending on stock JSON library (no more dependency on the `json` gem) 21 | ([#49](https://github.com/kyrylo/pry-theme/pull/51)) 22 | * Fixed warnings on Ruby 2.4.0+ with regard to Fixnum 23 | ([#50](https://github.com/kyrylo/pry-theme/pull/51)) 24 | 25 | ### v1.1.3 (July 21, 2014) 26 | 27 | * Re-fixed broken behaviour of Pry. It's a temporary hack, to be removed on the 28 | new Pry release [→](https://github.com/kyrylo/pry-theme/issues/40) 29 | [→](https://github.com/kyrylo/pry-theme/issues/42) 30 | 31 | ### v1.1.2 (June 16, 2014) 32 | 33 | * Fixed broken behaviour when the Pry Rescue plugin isn't installed along with 34 | Pry Theme [→](https://github.com/kyrylo/pry-theme/issues/40) 35 | 36 | ### v1.1.1 (June 14, 2014) 37 | 38 | * Fixed error message when `theme_options` is not set at 39 | all. [→](https://github.com/kyrylo/pry-theme/issues/41) 40 | 41 | ### v1.1.0 (June 13, 2014) 42 | 43 | * Added `theme_options` config hash. It is a general config for Pry Theme 44 | * Added option that enables painting hash keys as symbols. 45 | [→](https://github.com/kyrylo/pry-theme/issues/30) 46 | 47 | ```ruby 48 | {foo: 1, :bar => 2} 49 | # ^ ^ 50 | # | | 51 | # key symbol 52 | ``` 53 | 54 | By default `foo` and `bar` have different colours. If you put this inside your 55 | `.pryrc`, then the key will have the same colour as the symbol. 56 | 57 | ```ruby 58 | Pry.config.theme_options = {:paint_key_as_symbol => true} 59 | ``` 60 | 61 | ### v1.0.3 (May 12, 2014) 62 | 63 | * Fixed error when Pry.config.theme is set to a theme that doesn't exist 64 | [→](https://github.com/kyrylo/pry-theme/issues/39) 65 | * Corrected README.md errors and confusing parts 66 | 67 | ### v1.0.2 (January 28, 2014) 68 | 69 | * Set stricter dependencies (namely, Pry Theme started demanding CodeRay v1.1.0 70 | or higher) 71 | 72 | ### v1.0.1 (November 18, 2013) 73 | 74 | * Fixed `pry-theme convert` and `pry-theme colors` 75 | 76 | ### v1.0.0 (November 13, 2013) 77 | 78 | * **IMPORTANT**: This version is incompatible with CodeRay 1.0.9 and lower 79 | * Fixed CodeRay 1.1.0 support 80 | 81 | ### v0.2.0 (March 26, 2013) 82 | 83 | * **HOT**: Added Windows support 84 | * **NOT SO HOT**: The plugin was rewritten from scratch 85 | * The plugin works everywhere where you can launch Pry 86 | * Improved `vim-detailed` theme 87 | * Added support for 16 colour themes 88 | * Introduced the new theme syntax 89 | * Lots of rewordings, improvements of help messages 90 | * Added fallback mode. It is useful when you are running Pry on poor terminals 91 | and trying to use a 256 colour theme. It is quite numpty, though. 92 | * Converted switches to subcommands 93 | * Added basic tab completion for installed themes 94 | * Added support for italic font. Does not work eveywhere. For example, I use 95 | urxvt and it does support italic fonts. 96 | * **NOT BAD**: Added a bunch of new themes 97 | 98 | * pry-monochrome 99 | * pry-modern-256 (old `pry-modern`) 100 | * pry-classic-256 (old `pry-classic`; default theme on 256 colour capable 101 | terminals) 102 | 103 | Including Windows friendly themes: 104 | 105 | * pry-classic-16 (default theme on Windows) 106 | * pry-classic-8 107 | * pry-zealand-16 (greenish) 108 | * pry-zealand-8 109 | * pry-love-16 (redish) 110 | * pry-love-8 111 | * pry-sibera-16 (bluish) 112 | * pry-sibera-8 113 | * pry-tepid-16 (yellowish) 114 | * pry-tepid-8 115 | * pry-modern-16 116 | * pry-modern-8 117 | * And probably something else. I could forget something! 118 | 119 | And do not forget to check out [the new CLI][cli]! 120 | 121 | ### v0.1.3 (September 21, 2012) 122 | 123 | * Improved integration with [pry-rescue][prescue] plugin. 124 | 125 | ### v0.1.2 (August 31, 2012) 126 | 127 | * Removed uninstaller. Actually, adding it, was a terrible idea. Remove theme 128 | files by hand, from now on. 129 | 130 | ### v0.1.1 (August 1, 2012) 131 | 132 | * Fixed bug in `--test` command not displaying current theme name; 133 | * Added new Pry Theme attributes: `escape`, `inline_delimiter` and `char`; 134 | * Amended output of `--test` command in order to reflect new attributes. 135 | 136 | ### v0.1.0 (July 23, 2012) 137 | 138 | * **HOT**: Boosted the load speed of the plugin: 139 | 140 | Before: 141 | ![Before](http://img-fotki.yandex.ru/get/6405/98991937.b/0_7f768_24d92170_orig) 142 | 143 | % time pry -e 'exit' 144 | 0.75s user 0.06s system 94% cpu 0.847 total 145 | 146 | After: 147 | ![After](http://img-fotki.yandex.ru/get/6400/98991937.b/0_7f767_7c1ad4e9_orig) 148 | 149 | % time pry -e 'exit' 150 | 0.69s user 0.04s system 94% cpu 0.773 total 151 | 152 | * **WARM**: added `--edit` command (`-e`). `-e` brings new experience in 153 | creating themes. With this command you can create and edit themes, both. For 154 | example, you can create a new theme like this: `pry-theme -e +my-theme`. Check 155 | out [a wiki entry][cli] for more information; 156 | 157 | * **TEPID**: improved `--color` command (`-c`). In this version `-c` can 158 | understand HEX, RGB, ANSI and human-readable colors. Interested in how to use 159 | it? Check out [Pry Theme CLI][cli] article in wiki; 160 | 161 | * Added [Pry Theme Cheatsheet][cheatsheet] to Pry Theme Wiki; 162 | * Fixed output for `--all-colors`, `--test`, `--list` and `--remote--list`. It 163 | was hard-coded to `$stdout`, so therefore, when it wasn't `$stdout`, 164 | information would be printed in the wrong place; 165 | * Fixed duplicate colors 86:aquamarine03 and 122:aquamarine03; 166 | * Fixed a bug when a user doesn't specify `Pry.config.theme` and tries to run 167 | `pry-theme -l`, which results in a TypeError; 168 | * Added two new 8-color default themes for a users with limited terminals: 169 | "vim-default" and "vim-detailed"; 170 | * Changed output for `--test`: it's more terse and concise now; 171 | * Changed output for `--list`, because the older one looked really silly; 172 | * Removed some spurious attributes for `.prytheme` files; 173 | * Fixed the name of theme "saturday". 174 | 175 | ### v0.0.10 (July 07, 2012) 176 | 177 | * Themes can use any color from 256-color palette as background color. Before 178 | this release you could use only 8 colors; 179 | * Changed command flag `--list --remote` to `--remote-list`. Now, to get a list 180 | of themes from Pry Theme Collection, you type `pry-theme -r` or 181 | `pry-theme --remote-list` instead of `pry-theme -lr`; 182 | * Limited theme descriptions to 80 characters; 183 | * Added "content" subparameter for "string" parameter (`.prytheme` syntax). 184 | * Changed the appearance of output from `pry-theme --all-colors` command, so it 185 | displays data in 3 columns instead of 1; 186 | * Changed some colors of Railscasts and Tomorrow themes; 187 | * Fixed bug when a user installs fresh gem and gets an improper warning, because 188 | `Pry.config.theme` is not defined. Added a proper notification message for 189 | such situations; 190 | * Renamed default theme `charcoal-black` to `pry-cold` (they are not the same). 191 | 192 | ### v0.0.9 (July 05, 2012) 193 | 194 | * **HOT**: Added `--install` flag. Now, you can easily install Pry themes from 195 | Pry Theme Collection via command line (`pry-theme -i nifty-theme`); 196 | * Added pager for long output. Try `pry-theme -a 256` and you will immediately 197 | notice the difference; 198 | * Added more informative output for `--list` flag; 199 | * Added a bunch of new default themes: solarized, zenburn, twilight, tomorrow, 200 | saturday, railscasts, monokai, github and charcoal-black; 201 | * Fixed wrong color name in 256-color palette (`pale_conflower_blue` → 202 | `pale_cornflower_blue`); 203 | * Fixed bug with respect to unwanted fall back to the `pry-classic` theme, 204 | when a user tries to switch to nonexistent theme; 205 | * Added a feature to `pry-theme` command: when a user invokes `pry-theme` 206 | command without arguments, it returns name of the current theme. 207 | 208 | ### v0.0.8 (July 02, 2012) 209 | 210 | * **IMPORTANT**: Changed directory where to store themes! Themes now live in 211 | `$HOME/.pry/themes` directory on Mac OS and GNU/Linux, both. Do not forget 212 | to delete or move your themes form the old path (On Mac OS it is 213 | `$HOME/Library/Application Support/pry-theme` and on GNU/Linux it is 214 | `$HOME/.pry/themes`). 215 | * On some operating systems Pry Theme was failing to detect correct config path. 216 | Fixed. 217 | * Fixed wrong behaviour, when uninstalling an unrelated gem. Pry Theme asked to 218 | uninstall themes every time you wanted to uninstall _any_ gem. 219 | * Fixed a typo in `pry-classic` theme, which was preventing to set `delimiter` 220 | parameter to a string. 221 | * Fixed wrong convertation of theme files. 222 | * Implemented `--list` (`-l`) option, which displays a list of all installed 223 | themes. 224 | 225 | ### v0.0.7 (June 30, 2012) 226 | 227 | * **HOTFIX**: v0.0.6 is broken (because of my inattentiveness). 228 | 229 | ### v0.0.6 (June 30, 2012) 230 | 231 | * Fixed bug when a `prytheme` attribute has no color value, but with attributes 232 | (for example, `symbol : (b)`); 233 | * Fixed bug when a `prytheme` has no color value at all (for example, 234 | `symbol : `); 235 | * Add basic checking for a valid color in `prytheme`. 236 | 237 | ### v0.0.5 (June 29, 2012) 238 | 239 | * No pre! 240 | * Added Ruby 1.8.7, JRuby and Ruby Enterprise Edition support; 241 | * Fixed 8-color themes bug. We could not even use them in the previous version; 242 | * Added `--test` command, which allows to "test" your theme visually; 243 | * Added uninstaller, which basically just asks a user if he or she wants to 244 | remove a directory with Pry themes (personally, I hate when software leave 245 | their crap); 246 | * Slightly improved `help` of `pry-theme` command; 247 | * Made theme attributes optional. Now, if you are not sure about some parameter 248 | in a Pry Theme, you can leave it empty. 249 | 250 | Last but not least: 251 | 252 | * Check out new Wiki! (https://github.com/kyrylo/pry-theme/wiki). 253 | 254 | ### v0.0.4.pre (June 28, 2012) 255 | 256 | * Added `--all-colors` and `--color` options for `pry-theme` command; 257 | * Improved used experience when working with `pry-theme`. 258 | 259 | ### v0.0.3.pre (June 26, 2012) 260 | 261 | * Added support for Mac OS and Windows (I believe so, at least). 262 | 263 | ### v0.0.2.pre (June 26, 2012) 264 | 265 | * Fixed bug with wrong detection of the root directory of the project. 266 | 267 | ### v0.0.1.pre (June 26, 2012) 268 | 269 | * Initial release. 270 | 271 | [cli]: https://github.com/kyrylo/pry-theme/wiki/Pry-Theme-CLI 272 | [cheatsheet]: https://github.com/kyrylo/pry-theme/wiki/Pry-Theme-Cheatsheet 273 | [prescue]: https://github.com/ConradIrwin/pry-rescue/ 274 | -------------------------------------------------------------------------------- /lib/pry-theme/rgb.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | # @since 0.2.0 3 | # @api private 4 | # 5 | # Represents an RGB colour. It's possible to convert an RGB instance into 6 | # {HEX} or {TERM} colours. However, this conversion is half-duplex. If an RGB 7 | # instance gets converted to {TERM} format, there is a high chance that it 8 | # will be approximated to fit in range of colour model (colour model can be 9 | # set via an argument of the conversion method). This class validates its 10 | # input (you won't see malformed of nonexistent RGB colours). 11 | # 12 | # @example Conversion to HEX 13 | # RGB.new([0, 0, 0]).to_hex #=> (HEX: #000000) 14 | # @example Conversion to TERM 15 | # RGB.new([0, 0, 0]).to_term(8) #=> (TERM-8: 0) 16 | # 17 | # # Approximation. 18 | # RGB.new([254, 244, 231]).to_term(8) #=> (TERM-8: 7) 19 | class RGB 20 | 21 | # 8 colours. For the standard GNU/Linux terminal emulator. 22 | LINUX = [ 23 | [ 0, 0, 0], [128, 0, 0], [ 0, 128, 0], 24 | [128, 128, 0], [ 0, 0, 128], [128, 0, 128], 25 | [ 0, 128, 128], [192, 192, 192] 26 | ] 27 | 28 | # 16 colours. For cmd.exe on Windows and other miserable terminals. 29 | SYSTEM = LINUX + [ 30 | [128, 128, 128], [255, 0, 0], [ 0, 255, 0], [255, 255, 0], 31 | [ 0, 0, 255], [255, 0, 255], [ 0, 255, 255], [255, 255, 255] 32 | ] 33 | 34 | # The next 216 colours. For men. 35 | COLORS = [ 36 | [ 0, 0, 0], [ 0, 0, 95], [ 0, 0, 135], [ 0, 0, 175], 37 | [ 0, 0, 215], [ 0, 0, 255], [ 0, 95, 0], [ 0, 95, 95], 38 | [ 0, 95, 135], [ 0, 95, 175], [ 0, 95, 215], [ 0, 95, 255], 39 | [ 0, 135, 0], [ 0, 135, 95], [ 0, 135, 135], [ 0, 135, 175], 40 | [ 0, 135, 215], [ 0, 135, 255], [ 0, 175, 0], [ 0, 175, 95], 41 | [ 0, 175, 135], [ 0, 175, 175], [ 0, 175, 215], [ 0, 175, 255], 42 | [ 0, 215, 0], [ 0, 215, 95], [ 0, 215, 135], [ 0, 215, 175], 43 | [ 0, 215, 215], [ 0, 215, 255], [ 0, 255, 0], [ 0, 255, 95], 44 | [ 0, 255, 135], [ 0, 255, 175], [ 0, 255, 215], [ 0, 255, 255], 45 | [ 95, 0, 0], [ 95, 0, 95], [ 95, 0, 135], [ 95, 0, 175], 46 | [ 95, 0, 215], [ 95, 0, 255], [ 95, 95, 0], [ 95, 95, 95], 47 | [ 95, 95, 135], [ 95, 95, 175], [ 95, 95, 215], [ 95, 95, 255], 48 | [ 95, 135, 0], [ 95, 135, 95], [ 95, 135, 135], [ 95, 135, 175], 49 | [ 95, 135, 215], [ 95, 135, 255], [ 95, 175, 0], [ 95, 175, 95], 50 | [ 95, 175, 135], [ 95, 175, 175], [ 95, 175, 215], [ 95, 175, 255], 51 | [ 95, 215, 0], [ 95, 215, 95], [ 95, 215, 135], [ 95, 215, 175], 52 | [ 95, 215, 215], [ 95, 215, 255], [ 95, 255, 0], [ 95, 255, 95], 53 | [ 95, 255, 135], [ 95, 255, 175], [ 95, 255, 215], [ 95, 255, 255], 54 | [135, 0, 0], [135, 0, 95], [135, 0, 135], [135, 0, 175], 55 | [135, 0, 215], [135, 0, 255], [135, 95, 0], [135, 95, 95], 56 | [135, 95, 135], [135, 95, 175], [135, 95, 215], [135, 95, 255], 57 | [135, 135, 0], [135, 135, 95], [135, 135, 135], [135, 135, 175], 58 | [135, 135, 215], [135, 135, 255], [135, 175, 0], [135, 175, 95], 59 | [135, 175, 135], [135, 175, 175], [135, 175, 215], [135, 175, 255], 60 | [135, 215, 0], [135, 215, 95], [135, 215, 135], [135, 215, 175], 61 | [135, 215, 215], [135, 215, 255], [135, 255, 0], [135, 255, 95], 62 | [135, 255, 135], [135, 255, 175], [135, 255, 215], [135, 255, 255], 63 | [175, 0, 0], [175, 0, 95], [175, 0, 135], [175, 0, 175], 64 | [175, 0, 215], [175, 0, 255], [175, 95, 0], [175, 95, 95], 65 | [175, 95, 135], [175, 95, 175], [175, 95, 215], [175, 95, 255], 66 | [175, 135, 0], [175, 135, 95], [175, 135, 135], [175, 135, 175], 67 | [175, 135, 215], [175, 135, 255], [175, 175, 0], [175, 175, 95], 68 | [175, 175, 135], [175, 175, 175], [175, 175, 215], [175, 175, 255], 69 | [175, 215, 0], [175, 215, 95], [175, 215, 135], [175, 215, 175], 70 | [175, 215, 215], [175, 215, 255], [175, 255, 0], [175, 255, 95], 71 | [175, 255, 135], [175, 255, 175], [175, 255, 215], [175, 255, 255], 72 | [215, 0, 0], [215, 0, 95], [215, 0, 135], [215, 0, 175], 73 | [215, 0, 215], [215, 0, 255], [215, 95, 0], [215, 95, 95], 74 | [215, 95, 135], [215, 95, 175], [215, 95, 215], [215, 95, 255], 75 | [215, 135, 0], [215, 135, 95], [215, 135, 135], [215, 135, 175], 76 | [215, 135, 215], [215, 135, 255], [215, 175, 0], [215, 175, 95], 77 | [215, 175, 135], [215, 175, 175], [215, 175, 175], [215, 175, 215], 78 | [215, 175, 255], [215, 215, 0], [215, 215, 95], [215, 215, 135], 79 | [215, 215, 175], [215, 215, 215], [215, 215, 255], [215, 255, 0], 80 | [215, 255, 95], [215, 255, 135], [215, 255, 175], [215, 255, 215], 81 | [215, 255, 255], [255, 0, 0], [255, 0, 95], [255, 0, 135], 82 | [255, 0, 175], [255, 0, 215], [255, 0, 255], [255, 95, 0], 83 | [255, 95, 95], [255, 95, 135], [255, 95, 175], [255, 95, 215], 84 | [255, 95, 255], [255, 135, 0], [255, 135, 95], [255, 135, 135], 85 | [255, 135, 175], [255, 135, 215], [255, 135, 255], [255, 175, 0], 86 | [255, 175, 95], [255, 175, 135], [255, 175, 175], [255, 175, 215], 87 | [255, 175, 255], [255, 215, 0], [255, 215, 95], [255, 215, 135], 88 | [255, 215, 175], [255, 215, 215], [255, 215, 255], [255, 255, 0], 89 | [255, 255, 95], [255, 255, 135], [255, 255, 175], [255, 255, 215] 90 | ] 91 | 92 | # The next 16 colours. For zen. 93 | GREYSCALE = (0x08..0xEE).step(0x0A).map { |v| [v] * 3 } 94 | 95 | # Combine everything into a full featured 256 colour RGB model. 96 | TABLE = SYSTEM + COLORS + GREYSCALE 97 | 98 | # The key points that are used to calculate the nearest match of an RGB. 99 | BYTEPOINTS_256 = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff] 100 | 101 | # @param [Array, String] value a String will be converted to Array 102 | # @raise [TypeError] if the +value+ is neither Array or String 103 | def initialize(value) 104 | @value = 105 | case value 106 | when Array 107 | validate_array(value) 108 | value 109 | when String 110 | validate_array(value = value.scan(/\d+/).map!(&:to_i)) 111 | value 112 | else 113 | raise TypeError, "can't convert #{ value.class } into PryTheme::RGB" 114 | end 115 | end 116 | 117 | # @return [String] 118 | def inspect 119 | "(RGB: #{ to_s })" 120 | end 121 | 122 | # Converts the RGB to a terminal colour equivalent. 123 | # 124 | # @note Accepts the following numbers: 256, 16, 8. 125 | # @param [Integer] color_model 126 | # @raise [ArgumentError] if +color_model+ parameter is incorrect 127 | # @return [TERM] a TERM representation of the RGB 128 | def to_term(color_model = 256) 129 | term = case color_model 130 | when 256 then PryTheme::RGB::TABLE.index(@value) 131 | when 16 then PryTheme::RGB::SYSTEM.index(@value) 132 | when 8 then PryTheme::RGB::LINUX.index(@value) 133 | else raise ArgumentError, 134 | "invalid value for PryTheme::HEX#to_term(): #{ @value }" 135 | end 136 | term = find_among_term_colors(term, color_model) if term.nil? 137 | PryTheme::TERM.new(term, color_model) 138 | end 139 | 140 | # Converts the RGB to a HEX colour equivalent. 141 | # @return [HEX] a HEX representation of the RGB 142 | def to_hex 143 | PryTheme::HEX.new("#%02x%02x%02x" % @value) 144 | end 145 | 146 | # @example 147 | # RGB.new([0, 12, 255]).to_s #=> "0, 12, 255" 148 | # @return [String] 149 | def to_s 150 | @value.join(', ') 151 | end 152 | 153 | # @example 154 | # RGB.new([0, 12, 255]).to_s #=> [0, 12, 255] 155 | # @return [Array] 156 | def to_a 157 | @value 158 | end 159 | 160 | # @example 161 | # RGB.new([0, 0, 0]).to_css #=> 'rgb(0, 0, 0)' 162 | # @return [String] 163 | def to_css 164 | "rgb(#{ to_s })" 165 | end 166 | 167 | private 168 | 169 | # Checks whether the +ary+ has correct number of elements and these elements 170 | # are valid RGB numbers. 171 | # 172 | # @param [Array] ary 173 | # @raise [ArgumentError] if the +ary+ is invalid 174 | # @return [void] 175 | def validate_array(ary) 176 | correct_size = ary.size.equal?(3) 177 | correct_vals = ary.all?{ |val| val.is_a?(Integer) && val.between?(0, 255) } 178 | return true if correct_size && correct_vals 179 | raise ArgumentError, 180 | %|invalid value for PryTheme::RGB#validate_array(): "#{ ary }"| 181 | end 182 | 183 | # Approximates the given +byte+ to a terminal colour value within range of 184 | # 256 colours. 185 | # 186 | # @param [Integer] byte a number between 0 and 255 187 | # @return [Integer] approximated number 188 | def nearest_term_256(byte) 189 | for i in 0..4 190 | lower, upper = BYTEPOINTS_256[i], BYTEPOINTS_256[i + 1] 191 | next unless byte.between?(lower, upper) 192 | 193 | distance_from_lower = (lower - byte).abs 194 | distance_from_upper = (upper - byte).abs 195 | closest = distance_from_lower < distance_from_upper ? lower : upper 196 | end 197 | closest 198 | end 199 | 200 | # The same as {#nearest_term_256}, but returns a number beteen 0 and 15. 201 | # 202 | # @note Oh, come on. At least it works! 203 | # @todo use more realistic algorithm. 204 | def nearest_term_16(byte) 205 | byte / 16 206 | end 207 | 208 | # The same as {#nearest_term_256}, but returns a number beteen 0 and 7. 209 | # 210 | # @note Oh, come on. At least it works! 211 | # @todo use more realistic algorithm. 212 | def nearest_term_8(byte) 213 | byte / 32 214 | end 215 | 216 | # Finds an approximated +term+ colour among the colour numbers within the 217 | # given +color_model+. 218 | # 219 | # @param [Integer] term a colour to be approximated 220 | # @param [Integer] color_model possible values {#to_term} 221 | # @return [Integer] approximated number, which fits in range of color_model 222 | def find_among_term_colors(term, color_model) 223 | rgb = @value.map { |byte| nearest_term_256(byte) } 224 | term = PryTheme::RGB::TABLE.index(rgb) 225 | approximate(term, color_model) 226 | end 227 | 228 | # Approximates +term+ in correspondence with +color_model+ 229 | # 230 | # @see #nearest_term_16 231 | # @see #nearest_term_8 232 | # @param [Integer] term a colour to be approximated 233 | # @param [Integer] color_model possible values {#to_term} 234 | # @return [Integer] approximated number, which fits in range of color_model 235 | def approximate(term, color_model) 236 | needs_approximation = (term > color_model - 1) 237 | 238 | if needs_approximation 239 | case color_model 240 | when 16 then nearest_term_16(term) 241 | when 8 then nearest_term_8(term) 242 | end 243 | else 244 | term 245 | end 246 | end 247 | 248 | end 249 | end 250 | -------------------------------------------------------------------------------- /spec/colors/color256_spec.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | describe PryTheme::Color256 do 4 | Color256 = PryTheme::Color256 5 | 6 | describe "foreground" do 7 | it "can be set" do 8 | color = Color256.new(:foreground => 'bright_violet') 9 | color.foreground(true).should == 'bright_violet' 10 | color.to_ansi.should == "\e[38;5;128m" 11 | end 12 | 13 | it "defaults to no colour at all" do 14 | color = Color256.new 15 | color.foreground(true).should == false 16 | color.to_ansi.should == "\e[0m" 17 | end 18 | 19 | it "raises error on invalid value" do 20 | lambda { Color256.new(:foreground => 'blah') }. 21 | should.raise(ArgumentError). 22 | message.should.match /invalid foreground value "blah"/ 23 | end 24 | 25 | describe "effects" do 26 | it "not used if there is a custom foreground" do 27 | color = Color256.new(:foreground => 'bright_violet') 28 | color.bold?.should == false 29 | color.underline?.should == false 30 | color.italic?.should == false 31 | color.to_ansi.should == "\e[38;5;128m" 32 | end 33 | 34 | it "uses bold" do 35 | color = Color256.new(:foreground => 'dark_pear', :bold => true) 36 | color.bold?.should == true 37 | color.underline?.should == false 38 | color.italic?.should == false 39 | color.to_ansi.should == "\e[38;5;178;1m" 40 | end 41 | 42 | it "uses underline" do 43 | color = Color256.new(:foreground => 'royal_blue03', :underline => true) 44 | color.bold?.should == false 45 | color.underline?.should == true 46 | color.italic?.should == false 47 | color.to_ansi.should == "\e[38;5;62;4m" 48 | end 49 | 50 | it "uses italic" do 51 | color = Color256.new(:foreground => 'cerise01', :italic => true) 52 | color.bold?.should == false 53 | color.underline?.should == false 54 | color.italic?.should == true 55 | color.to_ansi.should == "\e[38;5;161;3m" 56 | end 57 | 58 | it "combines everything" do 59 | color = Color256.new( 60 | :foreground => 'titian', 61 | :italic => true, 62 | :bold => true, 63 | :underline => true) 64 | color.bold?.should == true 65 | color.underline?.should == true 66 | color.italic?.should == true 67 | color.to_ansi.should == "\e[38;5;160;1;3;4m" 68 | end 69 | 70 | describe "with defaults" do 71 | it "not used for the default colours" do 72 | color = Color256.new 73 | color.bold?.should == false 74 | color.underline?.should == false 75 | color.italic?.should == false 76 | color.to_ansi.should == "\e[0m" 77 | end 78 | 79 | it "can be used without foreground" do 80 | color = Color256.new(:background => 'bistre', :bold => true) 81 | color.bold?.should == true 82 | color.underline?.should == false 83 | color.italic?.should == false 84 | color.to_ansi.should == "\e[48;5;235;1m" 85 | end 86 | 87 | it "can be used with the default colour" do 88 | color = Color256.new( 89 | :bold => true, 90 | :italic => true, 91 | :underline => true 92 | ) 93 | color.bold?.should == true 94 | color.underline?.should == true 95 | color.italic?.should == true 96 | color.to_ansi.should == "\e[1;3;4m" 97 | end 98 | end 99 | end 100 | end 101 | 102 | describe "background" do 103 | it "can be set" do 104 | color = Color256.new(:background => 'bright_violet') 105 | color.background(true).should == 'bright_violet' 106 | color.to_ansi.should == "\e[48;5;128m" 107 | end 108 | 109 | it "defaults to no colour at all" do 110 | color = Color256.new 111 | color.background(true).should == false 112 | color.to_ansi.should == "\e[0m" 113 | end 114 | 115 | it "raises error on invalid value" do 116 | lambda { Color256.new(:background => 'BLACK') }. 117 | should.raise(ArgumentError). 118 | message.should.match /invalid background value "BLACK"/ 119 | end 120 | end 121 | 122 | describe "foreground combined with background" do 123 | it "can be set" do 124 | color = Color256.new( 125 | :background => 'red_violet01', 126 | :foreground => 'pale_brown') 127 | color.foreground(true).should == 'pale_brown' 128 | color.background(true).should == 'red_violet01' 129 | color.to_ansi.should == "\e[38;5;137;48;5;126m" 130 | end 131 | 132 | it "can be set with effects" do 133 | color = Color256.new( 134 | :background => 'red_violet01', 135 | :foreground => 'pale_brown', 136 | :italic => true, 137 | :bold => true, 138 | :underline => true) 139 | color.to_ansi.should == "\e[38;5;137;1;3;4;48;5;126m" 140 | end 141 | end 142 | 143 | describe "argument types" do 144 | describe "readable" do 145 | it "works" do 146 | lambda { 147 | Color256.new( 148 | :from => :readable, 149 | :foreground => 'tan', 150 | :background => 'gold') 151 | }.should.not.raise 152 | end 153 | 154 | it "doesn't work with incorrect input" do 155 | lambda { 156 | Color256.new( 157 | :from => :readable, 158 | :foreground => '#222222', 159 | :background => [123, 11, 44]) 160 | }.should.raise(ArgumentError) 161 | end 162 | 163 | it "sets background and foreground properly" do 164 | color = Color256.new(:from => :readable, 165 | :foreground => 'dark_indigo', 166 | :background => 'klein_blue') 167 | color.foreground.should == 17 168 | color.foreground(true).should == 'dark_indigo' 169 | color.background.should == 32 170 | color.background(true).should == 'klein_blue' 171 | end 172 | 173 | it "sets foreground properly" do 174 | color = Color256.new(:from => :readable, :foreground => 'dark_indigo') 175 | color.foreground.should == 17 176 | color.foreground(true).should == 'dark_indigo' 177 | color.background.should == false 178 | color.background(true).should == false 179 | end 180 | 181 | it "sets background properly" do 182 | color = Color256.new(:from => :readable, :background => 'klein_blue') 183 | color.foreground.should == false 184 | color.foreground(true).should == false 185 | color.background.should == 32 186 | color.background(true).should == 'klein_blue' 187 | end 188 | end 189 | 190 | describe "hex" do 191 | it "works" do 192 | lambda { 193 | Color256.new( 194 | :from => :hex, 195 | :foreground => '#afaf11', 196 | :background => '#eaeaea') 197 | }.should.not.raise 198 | end 199 | 200 | it "doesn't work with incorrect input" do 201 | lambda { 202 | Color256.new( 203 | :from => :hex, 204 | :foreground => '#222222', 205 | :background => [123, 11, 44]) 206 | }.should.raise(TypeError) 207 | end 208 | 209 | it "sets background and foreground properly" do 210 | color = Color256.new(:from => :hex, 211 | :foreground => '#afaf11', 212 | :background => '#eaeaea') 213 | color.foreground.should == 142 214 | color.foreground(true).should == 'old_gold' 215 | color.background.should == 189 216 | color.background(true).should == 'periwinkle' 217 | end 218 | 219 | it "sets foreground properly" do 220 | color = Color256.new(:from => :hex, :foreground => '#afaf11') 221 | color.foreground.should == 142 222 | color.foreground(true).should == 'old_gold' 223 | color.background.should == false 224 | color.background(true).should == false 225 | end 226 | 227 | it "sets background properly" do 228 | color = Color256.new(:from => :hex, :background => '#eaeaea') 229 | color.foreground.should == false 230 | color.foreground(true).should == false 231 | color.background.should == 189 232 | color.background(true).should == 'periwinkle' 233 | end 234 | end 235 | 236 | describe "rgb" do 237 | it "works" do 238 | lambda { 239 | Color256.new( 240 | :from => :rgb, 241 | :foreground => '31, 125, 88', 242 | :background => [123, 11, 44]) 243 | }.should.not.raise(ArgumentError) 244 | end 245 | 246 | it "doesn't work with incorrect input" do 247 | lambda { 248 | Color256.new( 249 | :from => :rgb, 250 | :foreground => '#222222', 251 | :background => [123, 11, 44]) 252 | }.should.raise(ArgumentError) 253 | end 254 | 255 | it "sets background and foreground properly" do 256 | color = Color256.new(:from => :rgb, 257 | :foreground => '31, 31, 101', 258 | :background => '125, 101, 255') 259 | color.foreground.should == 17 260 | color.foreground(true).should == 'dark_indigo' 261 | color.background.should == 99 262 | color.background(true).should == 'heliotrope01' 263 | end 264 | 265 | it "sets foreground properly" do 266 | color = Color256.new(:from => :rgb, :foreground => '31, 31, 101') 267 | color.foreground.should == 17 268 | color.foreground(true).should == 'dark_indigo' 269 | color.background.should == false 270 | color.background(true).should == false 271 | end 272 | 273 | it "sets background properly" do 274 | color = Color256.new(:from => :rgb, :background => '125, 101, 255') 275 | color.foreground.should == false 276 | color.foreground(true).should == false 277 | color.background.should == 99 278 | color.background(true).should == 'heliotrope01' 279 | end 280 | end 281 | 282 | describe "term" do 283 | it "works" do 284 | lambda { 285 | Color256.new( 286 | :from => :term, 287 | :foreground => 31, 288 | :background => 123) 289 | }.should.not.raise(ArgumentError) 290 | end 291 | 292 | it "doesn't work with incorrect input" do 293 | lambda { 294 | Color256.new( 295 | :from => :term, 296 | :foreground => '#222222', 297 | :background => 'gray05') 298 | }.should.raise(TypeError) 299 | end 300 | 301 | it "sets background and foreground properly" do 302 | color = Color256.new( 303 | :from => :term, 304 | :foreground => 4, 305 | :background => 84 306 | ) 307 | color.foreground.should == 4 308 | color.foreground(true).should == 'navy_blue' 309 | color.background.should == 84 310 | color.background(true).should == 'spring_green03' 311 | end 312 | 313 | it "sets foreground properly" do 314 | color = Color256.new(:from => :term, :foreground => 4) 315 | color.foreground.should == 4 316 | color.foreground(true).should == 'navy_blue' 317 | color.background.should == false 318 | color.background(true).should == false 319 | end 320 | 321 | it "sets background properly" do 322 | color = Color256.new(:from => :term, :background => 84) 323 | color.foreground.should == false 324 | color.foreground(true).should == false 325 | color.background.should == 84 326 | color.background(true).should == 'spring_green03' 327 | end 328 | end 329 | end 330 | 331 | describe "#to_ansi" do 332 | before do 333 | @color = Color256.new(:from => :term, :background => 84) 334 | end 335 | 336 | it "converts a colour to an ANSI sequence" do 337 | @color.to_ansi.should == "\e[48;5;84m" 338 | end 339 | 340 | it "given `true` converts a colour to an inverted ANSI sequence" do 341 | @color.to_ansi(true).should == "\e[7;48;5;84m" 342 | end 343 | end 344 | 345 | end 346 | -------------------------------------------------------------------------------- /lib/pry-theme/color.rb: -------------------------------------------------------------------------------- 1 | module PryTheme 2 | class Color 3 | 4 | # Stores all possible colours for foregrounds and backgrounds, for 256, 16 5 | # and 8 colour palettes. 6 | @@colors = { 7 | :foreground => { 8 | 256 => { 9 | 'black' => [0, 16], 10 | 'maroon' => 1, 11 | 'toad_in_love' => 2, 12 | 'olive' => 3, 13 | 'navy_blue' => 4, 14 | 'violet_eggplant' => 5, 15 | 'teal' => 6, 16 | 'silver' => 7, 17 | 'gray' => [8, 244], 18 | 'red' => [9, 196], 19 | 'green' => [10, 46], 20 | 'yellow' => [11, 226], 21 | 'blue' => [12, 21], 22 | 'magenta' => [13, 201], 23 | 'cyan' => [14, 51], 24 | 'white' => [15, 231], 25 | 'dark_indigo' => 17, 26 | 'ultramarine01' => 18, 27 | 'ultramarine02' => 19, 28 | 'persian_blue01' => 20, 29 | 'dark_spring_green' => 22, 30 | 'dark_turquoise' => 23, 31 | 'cerulean_grey01' => 24, 32 | 'denim01' => 25, 33 | 'royal_blue01' => 26, 34 | 'royal_blue02' => 27, 35 | 'toad_in_love01' => 28, 36 | 'sea_green01' => 29, 37 | 'teal01' => 30, 38 | 'cerulean_grey02' => 31, 39 | 'klein_blue' => 32, 40 | 'azure01' => 33, 41 | 'vert_de_pomme01' => 34, 42 | 'jade01' => 35, 43 | 'jade02' => 36, 44 | 'robin_egg_blue01' => 37, 45 | 'bondi_blue' => 38, 46 | 'light_blue01' => 39, 47 | 'vert_de_pomme02' => 40, 48 | 'malachite01' => 41, 49 | 'emerald01' => 42, 50 | 'turquoise' => 43, 51 | 'robin_egg_blue02' => 44, 52 | 'electric01' => 45, 53 | 'spring_green01' => 47, 54 | 'spring_green02' => 48, 55 | 'mint_green01' => 49, 56 | 'aquamarine01' => 50, 57 | 'flea_belly' => 52, 58 | 'plum' => 53, 59 | 'indigo' => 54, 60 | 'purple01' => 55, 61 | 'violet01' => 56, 62 | 'persian_blue02' => 57, 63 | 'khaki01' => 58, 64 | 'wet_asphalt01' => 59, 65 | 'seroburomalinovyj01' => 60, 66 | 'denim02' => 61, 67 | 'royal_blue03' => 62, 68 | 'royal_blue04' => 63, 69 | 'olive_drab' => 64, 70 | 'fern_green' => 65, 71 | 'slate_gray' => 66, 72 | 'steel_blue' => 67, 73 | 'cornflower_blue01' => 68, 74 | 'azure02' => 69, 75 | 'grass01' => 70, 76 | 'emerald02' => 71, 77 | 'sea_green02' => 72, 78 | 'robin_egg_blue03' => 73, 79 | 'bluish01' => 74, 80 | 'light_blue02' => 75, 81 | 'vert_de_pomme03' => 76, 82 | 'pale_green01' => 77, 83 | 'emerald03' => 78, 84 | 'aquamarine02' => 79, 85 | 'robin_egg_blue04' => 80, 86 | 'sky01' => 81, 87 | 'bright_green' => 82, 88 | 'malachite02' => 83, 89 | 'spring_green03' => 84, 90 | 'chartreuse01' => 85, 91 | 'aquamarine03' => 86, 92 | 'cyan01' => 87, 93 | 'maroon01' => 88, 94 | 'eggplant01' => 89, 95 | 'violet_eggplant01' => 90, 96 | 'purple02' => 91, 97 | 'violet02' => 92, 98 | 'violet03' => 93, 99 | 'khaki02' => 94, 100 | 'pale_mauve01' => 95, 101 | 'seroburomalinovyj02' => 96, 102 | 'amethyst01' => 97, 103 | 'amethyst02' => 98, 104 | 'heliotrope01' => 99, 105 | 'olive01' => 100, 106 | 'dark_tan' => 101, 107 | 'gray01' => [102, 243], 108 | 'bluish02' => 103, 109 | 'cornflower_blue02' => 104, 110 | 'royal_blue05' => 105, 111 | 'grass02' => 106, 112 | 'asparagus' => 107, 113 | 'swamp_green01' => 108, 114 | 'light_grey01' => 109, 115 | 'bluish03' => 110, 116 | 'cornflower_blue03' => 111, 117 | 'green_yellow01' => 112, 118 | 'pale_green02' => 113, 119 | 'emerald04' => 114, 120 | 'celadon' => 115, 121 | 'pale_blue01' => 116, 122 | 'sky02' => 117, 123 | 'viridian' => 118, 124 | 'vert_de_pomme04' => 119, 125 | 'mint_green02' => 120, 126 | 'chartreuse02' => 121, 127 | 'aquamarine04' => 122, 128 | 'electric02' => 123, 129 | 'bismarck_furious' => 124, 130 | 'eggplant02' => 125, 131 | 'red_violet01' => 126, 132 | 'violet_eggplant02' => 127, 133 | 'bright_violet' => [128, 164], 134 | 'violet04' => 129, 135 | 'ochre' => 130, 136 | 'pale_mauve02' => 131, 137 | 'pale_red_violet01' => 132, 138 | 'orchid01' => 133, 139 | 'amethyst03' => 134, 140 | 'heliotrope02' => 135, 141 | 'dark_goldenrod' => 136, 142 | 'pale_brown' => 137, 143 | 'mountbatten_pink' => 138, 144 | 'lilac01' => 139, 145 | 'wisteria01' => 140, 146 | 'amethyst04' => 141, 147 | 'old_gold' => 142, 148 | 'brass01' => 143, 149 | 'swamp_green02' => 144, 150 | 'light_grey02' => 145, 151 | 'niagara' => 146, 152 | 'wisteria02' => 147, 153 | 'lime01' => 148, 154 | 'pistachio01' => 149, 155 | 'moss_green' => 150, 156 | 'dark_tea_green' => 151, 157 | 'pale_blue02' => 152, 158 | 'pale_cornflower_blue' => 153, 159 | 'green_yellow02' => 154, 160 | 'green_yellow03' => 155, 161 | 'pistachio02' => 156, 162 | 'chartreuse03' => 157, 163 | 'aquamarine05' => 158, 164 | 'pale_blue03' => 159, 165 | 'titian' => 160, 166 | 'cerise01' => 161, 167 | 'red_violet02' => 162, 168 | 'hot_pink01' => 163, 169 | 'magenta01' => 165, 170 | 'tenne' => 166, 171 | 'chestnut01' => 167, 172 | 'pale_red_violet02' => 168, 173 | 'orchid02' => 169, 174 | 'orchid03' => 170, 175 | 'heliotrope03' => 171, 176 | 'siena' => 172, 177 | 'dark_salmon' => 173, 178 | 'puce01' => 174, 179 | 'puce2' => 175, 180 | 'violaceous01' => 176, 181 | 'violaceous02' => 177, 182 | 'dark_pear' => 178, 183 | 'brass02' => 179, 184 | 'tan' => 180, 185 | 'pale_chestnut' => 181, 186 | 'lilac02' => 182, 187 | 'wisteria03' => 183, 188 | 'childs_surprise' => 184, 189 | 'vert_de_peche' => 185, 190 | 'flax' => 186, 191 | 'gray_tea_green' => 187, 192 | 'abdel_kerims_beard01' => 188, 193 | 'periwinkle' => 189, 194 | 'lime02' => 190, 195 | 'pistachio03' => 191, 196 | 'pistachio04' => 192, 197 | 'tea_green01' => 193, 198 | 'tea_green02' => 194, 199 | 'pang' => 195, 200 | 'crimson' => 197, 201 | 'cerise02' => 198, 202 | 'hot_pink02' => 199, 203 | 'hot_pink03' => 200, 204 | 'international_orange' => 202, 205 | 'alizarin' => 203, 206 | 'dark_pink01' => 204, 207 | 'dark_pink02' => 205, 208 | 'shocked_star' => 206, 209 | 'fuchsia' => 207, 210 | 'tangerine' => 208, 211 | 'salmon' => 209, 212 | 'chestnut02' => 210, 213 | 'pale_red_violet03' => 211, 214 | 'pale_magenta' => 212, 215 | 'violaceous03' => 213, 216 | 'orange' => 214, 217 | 'pink_orange' => 215, 218 | 'saumon' => 216, 219 | 'pink01' => 217, 220 | 'pink02' => 218, 221 | 'violaceous04' => 219, 222 | 'gold' => 220, 223 | 'mustard01' => 221, 224 | 'mustard02' => 222, 225 | 'dark_peach' => 223, 226 | 'pale_pink' => 224, 227 | 'thistle' => 225, 228 | 'corn01' => 227, 229 | 'corn02' => 228, 230 | 'perhydor' => 229, 231 | 'lemon_cream' => 230, 232 | 'black01' => 232, 233 | 'black02' => 233, 234 | 'black03' => 234, 235 | 'bistre' => 235, 236 | 'anthracite' => 236, 237 | 'wet_asphalt02' => 237, 238 | 'wet_asphalt03' => 238, 239 | 'wet_asphalt04' => 239, 240 | 'wet_asphalt05' => 240, 241 | 'wet_asphalt06' => 241, 242 | 'wet_asphalt07' => 242, 243 | 'gray02' => 245, 244 | 'gray03' => 246, 245 | 'gray04' => 247, 246 | 'gray05' => 248, 247 | 'light_grey03' => 249, 248 | 'light_grey04' => 250, 249 | 'silver01' => 251, 250 | 'abdel_kerims_beard02' => 252, 251 | 'abdel_kerims_beard03' => 253, 252 | 'abdel_kerims_beard04' => 254, 253 | 'seashell' => 255 254 | }, 255 | 16 => { 256 | 'black' => 30, 257 | 'red' => 31, 258 | 'green' => 32, 259 | 'yellow' => 33, 260 | 'blue' => 34, 261 | 'magenta' => 35, 262 | 'cyan' => 36, 263 | 'white' => 37, 264 | 'bright_black' => [30, 1], 265 | 'bright_red' => [31, 1], 266 | 'bright_green' => [32, 1], 267 | 'bright_yellow' => [33, 1], 268 | 'bright_blue' => [34, 1], 269 | 'bright_magenta' => [35, 1], 270 | 'bright_cyan' => [36, 1], 271 | 'bright_white' => [37, 1], 272 | }, 273 | 8 => { 274 | 'black' => 30, 275 | 'red' => 31, 276 | 'green' => 32, 277 | 'yellow' => 33, 278 | 'blue' => 34, 279 | 'magenta' => 35, 280 | 'cyan' => 36, 281 | 'white' => 37, 282 | } 283 | }, 284 | :background => { 285 | 16 => { 286 | 'black' => 40, 287 | 'red' => 41, 288 | 'green' => 42, 289 | 'yellow' => 43, 290 | 'blue' => 44, 291 | 'magenta' => 45, 292 | 'cyan' => 46, 293 | 'white' => 47, 294 | 'bright_black' => 40, 295 | 'bright_red' => 41, 296 | 'bright_green' => 42, 297 | 'bright_yellow' => 43, 298 | 'bright_blue' => 44, 299 | 'bright_magenta' => 45, 300 | 'bright_cyan' => 46, 301 | 'bright_white' => 47, 302 | }, 303 | } 304 | } 305 | @@colors[:background][256] = @@colors[:foreground][256] 306 | @@colors[:background][8] = @@colors[:background][16] 307 | 308 | # The default colour options Hash. 309 | OPTS = { 310 | :from => :readable, 311 | :foreground => false, 312 | :background => false, 313 | :bold => false, 314 | :italic => false, 315 | :underline => false, 316 | } 317 | 318 | attr_reader :color_model 319 | 320 | # @return [] 321 | attr_reader :options 322 | 323 | def initialize(color_model, options = {}) 324 | @options = OPTS.merge(options) 325 | @color_model = color_model 326 | set_layers 327 | end 328 | 329 | def foreground(readable = false) 330 | @readable_fg = find_color(:foreground) 331 | readable ? @readable_fg : layer_color(colors[@readable_fg]) 332 | end 333 | 334 | def background(readable = false) 335 | @readable_bg = find_color(:background) 336 | readable ? @readable_bg : layer_color(colors(:background)[@readable_bg]) 337 | end 338 | 339 | def to_ansi(inversion = false) 340 | ansi = create_ansi_sequence(foreground, background) 341 | escape(inversion ? ['7;', ansi].join('') : ansi) 342 | end 343 | 344 | private 345 | 346 | def set_layers 347 | foreground 348 | background 349 | end 350 | 351 | def escape(ansi) 352 | Array(ansi).map { |c| "\e[#{ c }m"}.join('') 353 | end 354 | 355 | def create_ansi_sequence(fg, bg, default_seq) 356 | (if fg && bg 357 | [[build_fg_sequence], [build_effects_sequence], [build_bg_sequence]].flatten 358 | elsif fg && !bg 359 | [[build_fg_sequence], [build_effects_sequence]].flatten 360 | elsif !fg && bg 361 | [[build_bg_sequence], [build_effects_sequence]].flatten 362 | else 363 | build_effects_sequence.tap { |sequence| 364 | sequence << default_seq if sequence.empty? 365 | } 366 | end).join(';') 367 | end 368 | 369 | def build_fg_sequence 370 | [foreground] 371 | end 372 | 373 | def build_effects_sequence 374 | [bold, italic, underline].delete_if { |e| e == false } 375 | end 376 | 377 | def build_bg_sequence 378 | [background] 379 | end 380 | 381 | def layer_color(layer) 382 | if layer 383 | layer.is_a?(Array) ? build_layer(layer) : layer 384 | else 385 | false 386 | end 387 | end 388 | 389 | def build_layer(layer) 390 | layer.first 391 | end 392 | 393 | def find_color(layer) 394 | case (color_id = cast_color(layer)) 395 | when String 396 | return color_id if colors.has_key?(color_id) 397 | when Integer 398 | color_id = find_from_integer(color_id) 399 | return color_id if color_id 400 | when false 401 | return color_id 402 | end 403 | 404 | raise ArgumentError, %|invalid #{ layer.to_s } value "#{ color_id }"| 405 | end 406 | 407 | def cast_color(layer) 408 | return false unless options[layer] 409 | 410 | case options[:from] 411 | when :readable 412 | options[layer] 413 | when :hex 414 | HEX.new(options[layer]).to_term(color_model).to_i 415 | when :rgb 416 | RGB.new(options[layer]).to_term(color_model).to_i 417 | when :term 418 | TERM.new(options[layer], color_model).to_i 419 | end 420 | end 421 | 422 | def colors(layer = :foreground) 423 | @@colors[layer][color_model] 424 | end 425 | 426 | def sorted_colors 427 | colors.sort_by { |k, v| v.is_a?(Array) ? v.first + 10 : v } 428 | end 429 | 430 | end 431 | end 432 | 433 | Dir[File.expand_path('../colors/*.rb', __FILE__)].each do |file| 434 | require file 435 | end 436 | -------------------------------------------------------------------------------- /spec/theme_spec.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | describe PryTheme::Theme do 4 | describe "name option" do 5 | it "defaults to some value if it's not specified" do 6 | theme = PryTheme.create{} 7 | theme.name.should =~ /prytheme-\d+/ 8 | end 9 | 10 | it "adds a theme name" do 11 | theme = PryTheme.create(:name => 'w00t'){} 12 | theme.name.should == 'w00t' 13 | end 14 | 15 | describe "validation" do 16 | it "ensures that the first character is a letter" do 17 | lambda { PryTheme.create(:name => '0ol'){} }. 18 | should.raise(PryTheme::ThemeError). 19 | message.should.match /must start with a letter/ 20 | end 21 | 22 | it "ensures that the the length is no longer than 18 characters" do 23 | long_n = 'x' * 19 24 | lambda { PryTheme.create(:name => long_n){} }. 25 | should.raise(PryTheme::ThemeError). 26 | message.should.match /no longer than 18 characters/ 27 | end 28 | end 29 | end 30 | 31 | describe "color model option" do 32 | it "defaults to some value if it's not specified" do 33 | theme = PryTheme.create{} 34 | theme.color_model.should == 256 35 | end 36 | 37 | it "adds color model" do 38 | theme = PryTheme.create(:color_model => 8){} 39 | theme.color_model.should == 8 40 | end 41 | 42 | describe "validation" do 43 | it "ensures that it's a correct number" do 44 | lambda { PryTheme.create(:name => 'w00t', :color_model => 255){} }. 45 | should.raise(PryTheme::ThemeError). 46 | message.should.match /incorrect color model/ 47 | end 48 | end 49 | end 50 | 51 | describe "#author" do 52 | it "defaults to some value if it's not specified" do 53 | theme = PryTheme.create{} 54 | theme.author.first[:name].should == 'Unknown Author' 55 | end 56 | 57 | it "adds an author" do 58 | theme = PryTheme.create{ author(:name => 'Kvitka', :email => 'kvi@t.ka') } 59 | theme.author.first[:name].should == 'Kvitka' 60 | theme.author.first[:email].should == 'kvi@t.ka' 61 | end 62 | 63 | it "adds multiple authors" do 64 | theme = PryTheme.create{ 65 | author(:name => 'Kvitka', :email => 'kvi@t.ka') 66 | author(:name => 'Cisyk', :email => 'ci@s.yk') } 67 | theme.author.first[:name].should == 'Kvitka' 68 | theme.author.first[:email].should == 'kvi@t.ka' 69 | theme.author.last[:name].should == 'Cisyk' 70 | theme.author.last[:email].should == 'ci@s.yk' 71 | end 72 | 73 | describe "validation" do 74 | it "ensures that the the length is no longer than 32 characters" do 75 | long_n = 'x' * 33 76 | lambda { PryTheme.create{ author(:name => long_n)} }. 77 | should.raise(PryTheme::ThemeError). 78 | message.should.match /no longer than 32 characters/ 79 | end 80 | end 81 | end 82 | 83 | describe "#description" do 84 | it "defaults to some value if it's not specified" do 85 | theme = PryTheme.create{} 86 | theme.description.should == '' 87 | 88 | end 89 | 90 | it "adds description" do 91 | theme = PryTheme.create{ description('wub wub') } 92 | theme.description.should == 'wub wub' 93 | end 94 | 95 | describe "validation" do 96 | it "ensures that the the length is no longer than 280 characters" do 97 | long_d = 'x' * 281 98 | lambda { PryTheme.create{ description(long_d)} }. 99 | should.raise(PryTheme::ThemeError). 100 | message.should.match /no longer than 280 characters/ 101 | end 102 | end 103 | end 104 | 105 | describe "definition" do 106 | describe "correct theme" do 107 | describe "with 8 colours" do 108 | it "sets foreground" do 109 | theme = PryTheme.create(:color_model => 8) { 110 | define_theme{ constant('blue') } } 111 | theme.definition.constant.foreground.should == 34 112 | theme.definition.constant.background.should == false 113 | end 114 | 115 | it "sets backround" do 116 | theme = PryTheme.create(:color_model => 8) { 117 | define_theme{ constant(:bg => 'blue') } } 118 | theme.definition.constant.foreground.should == false 119 | theme.definition.constant.background.should == 44 120 | end 121 | 122 | it "sets foreground and background" do 123 | theme = PryTheme.create(:color_model => 8) { 124 | define_theme{ symbol('blue', 'red') } } 125 | theme.definition.symbol.foreground.should == 34 126 | theme.definition.symbol.background.should == 41 127 | end 128 | 129 | it "defaults to proper colours" do 130 | theme = PryTheme.create(:color_model => 8){ define_theme{} } 131 | theme.definition.integer.to_ansi.should == "\e[39;49m" 132 | end 133 | end 134 | 135 | describe "with 16 colours" do 136 | it "sets foreground" do 137 | theme = PryTheme.create(:color_model => 16) { 138 | define_theme{ constant('bright_blue') } } 139 | theme.definition.constant.foreground.should == '34;1' 140 | theme.definition.constant.background.should == false 141 | end 142 | 143 | it "sets backround" do 144 | theme = PryTheme.create(:color_model => 16) { 145 | define_theme{ constant(:bg => 'bright_yellow') } } 146 | theme.definition.constant.foreground.should == false 147 | theme.definition.constant.background.should == 43 148 | end 149 | 150 | it "sets foreground and background" do 151 | theme = PryTheme.create(:color_model => 16) { 152 | define_theme{ symbol('blue', 'red') } } 153 | theme.definition.symbol.foreground.should == 34 154 | theme.definition.symbol.background.should == 41 155 | end 156 | 157 | it "defaults to proper colours" do 158 | theme = PryTheme.create(:color_model => 16){ define_theme{} } 159 | theme.definition.integer.to_ansi.should == "\e[39;49m" 160 | end 161 | end 162 | 163 | describe "with 256" do 164 | it "sets foreground" do 165 | theme = PryTheme.create(:color_model => 256) { 166 | define_theme{ constant('celadon') } } 167 | theme.definition.constant.foreground.should == 115 168 | theme.definition.constant.background.should == false 169 | end 170 | 171 | it "sets backround" do 172 | theme = PryTheme.create(:color_model => 256) { 173 | define_theme{ constant(:bg => 'viridian') } } 174 | theme.definition.constant.foreground.should == false 175 | theme.definition.constant.background.should == 118 176 | end 177 | 178 | it "sets foreground and background" do 179 | theme = PryTheme.create(:color_model => 256) { 180 | define_theme{ symbol('celadon', 'viridian') } } 181 | theme.definition.symbol.foreground.should == 115 182 | theme.definition.symbol.background.should == 118 183 | end 184 | 185 | it "defaults to proper colours" do 186 | theme = PryTheme.create(:color_model => 256){ define_theme{} } 187 | theme.definition.integer.to_ansi.should == "\e[0m" 188 | end 189 | 190 | describe "effects" do 191 | it "sets effects without layers" do 192 | theme = PryTheme.create(:color_model => 256) { 193 | define_theme{ symbol([:bold, :underline, :italic]) } } 194 | theme.definition.symbol.foreground.should == false 195 | theme.definition.symbol.background.should == false 196 | theme.definition.symbol.bold?.should == true 197 | theme.definition.symbol.underline?.should == true 198 | theme.definition.symbol.italic?.should == true 199 | end 200 | 201 | it "sets effects and foreground" do 202 | theme = PryTheme.create(:color_model => 256) { 203 | define_theme{ symbol('sky02', [:bold, :underline, :italic]) } } 204 | theme.definition.symbol.foreground.should == 117 205 | theme.definition.symbol.background.should == false 206 | theme.definition.symbol.bold?.should == true 207 | theme.definition.symbol.underline?.should == true 208 | theme.definition.symbol.italic?.should == true 209 | end 210 | 211 | it "sets effects and background" do 212 | theme = PryTheme.create(:color_model => 256) { 213 | define_theme{ 214 | symbol({:bg => 'olive01'}, [:bold, :underline, :italic]) } } 215 | theme.definition.symbol.foreground.should == false 216 | theme.definition.symbol.background.should == 100 217 | theme.definition.symbol.bold?.should == true 218 | theme.definition.symbol.underline?.should == true 219 | theme.definition.symbol.italic?.should == true 220 | end 221 | 222 | it "sets effects, foreground and background" do 223 | theme = PryTheme.create(:color_model => 256) { 224 | define_theme{ 225 | symbol('sky02', 'olive01', [:bold, :underline, :italic]) } } 226 | theme.definition.symbol.foreground.should == 117 227 | theme.definition.symbol.background.should == 100 228 | theme.definition.symbol.bold?.should == true 229 | theme.definition.symbol.underline?.should == true 230 | theme.definition.symbol.italic?.should == true 231 | end 232 | end 233 | end 234 | end 235 | 236 | describe "broken theme" do 237 | it "raises error when colour definition is malformed" do 238 | should.raise(PryTheme::ThemeError) { 239 | PryTheme.create{ define_theme { class_ 'wowzers' } } 240 | }.message.should =~ /malformed color declaration \(wowzers\)/ 241 | end 242 | 243 | describe "with 8 colours" do 244 | it "doesn't allow effects" do 245 | lambda { PryTheme.create(:color_model => 8) { 246 | define_theme{ constant('blue', [:bold]) } } }. 247 | should.raise(PryTheme::ThemeError). 248 | message.should.match /effects are available only for 256-color themes/ 249 | 250 | lambda { PryTheme.create(:color_model => 8) { 251 | define_theme{ constant({:fg => 'blue'}, [:bold]) } } }. 252 | should.raise(PryTheme::ThemeError). 253 | message.should.match /effects are available only for 256-color themes/ 254 | 255 | 256 | lambda { PryTheme.create(:color_model => 8) { 257 | define_theme{ constant([:bold]) } } }. 258 | should.raise(PryTheme::ThemeError). 259 | message.should.match /effects are available only for 256-color themes/ 260 | end 261 | end 262 | 263 | describe "with 16 colours" do 264 | it "doesn't allow effects" do 265 | lambda { PryTheme.create(:color_model => 16) { 266 | define_theme{ constant('blue', [:bold]) } } }. 267 | should.raise(PryTheme::ThemeError). 268 | message.should.match /effects are available only for 256-color themes/ 269 | 270 | lambda { PryTheme.create(:color_model => 16) { 271 | define_theme{ constant({:fg => 'blue'}, [:bold]) } } }. 272 | should.raise(PryTheme::ThemeError). 273 | message.should.match /effects are available only for 256-color themes/ 274 | 275 | lambda { PryTheme.create(:color_model => 16) { 276 | define_theme{ constant([:bold]) } } }. 277 | should.raise(PryTheme::ThemeError). 278 | message.should.match /effects are available only for 256-color themes/ 279 | end 280 | end 281 | 282 | describe "non-existent options" do 283 | it "raises error" do 284 | lambda { PryTheme.create { define_theme { klass 'red' } } }. 285 | should.raise(PryTheme::ThemeError). 286 | message.should.match /unknown option "klass"/ 287 | end 288 | end 289 | end 290 | end 291 | 292 | describe "nested definition" do 293 | it "doesn't conflict with other nested definitions" do 294 | theme = PryTheme.create(:color_model => 8) { 295 | define_theme{ 296 | regexp{ self_ 'blue' } 297 | string{ self_ 'green'; delimiter 'black' } } } 298 | theme.definition.regexp.self_.foreground(true).should == 'blue' 299 | theme.definition.string.self_.foreground(true).should == 'green' 300 | theme.definition.regexp.modifier.to_ansi.should == "\e[39;49m" 301 | theme.definition.string.delimiter.foreground(true).should == 'black' 302 | theme.definition.regexp.delimiter.to_ansi.should == "\e[39;49m" 303 | theme.definition.shell.delimiter.to_ansi.should == "\e[39;49m" 304 | end 305 | end 306 | 307 | describe "a wholesome theme" do 308 | it "works with all options :-)" do 309 | lambda { 310 | PryTheme.create(:name => 'wholesome', :color_model => 8) { 311 | author :name => 'Kyrylo Silin', :email => 'silin@kyrylo.org' 312 | description 'a kool theme!' 313 | define_theme { 314 | class_ 'magenta' 315 | class_variable 'cyan' 316 | comment 'blue' 317 | constant 'blue' 318 | error 'yellow', 'red' 319 | float 'magenta' 320 | global_variable :bg => 'green' 321 | inline_delimiter 'blue' 322 | instance_variable 'red' 323 | integer 'blue' 324 | keyword 'red' 325 | method 'blue' 326 | predefined_constant 'cyan' 327 | symbol 'green' 328 | regexp { 329 | self_ 'red' 330 | char 'magenta' 331 | content 'red' 332 | delimiter 'red' 333 | modifier 'magenta' 334 | escape 'magenta' } 335 | shell { 336 | self_ :bg => 'green' 337 | char 'magenta' 338 | content 'yellow' 339 | delimiter 'white' 340 | escape 'black' } 341 | string { 342 | self_ 'green' 343 | char 'white' 344 | content 'green' 345 | delimiter 'green' 346 | escape 'white' } } } 347 | }.should.not.raise 348 | end 349 | end 350 | 351 | describe "declaration type guessing" do 352 | it "guesses random colour types" do 353 | theme = PryTheme.create(:color_model => 8) { 354 | define_theme { 355 | class_ 'magenta' 356 | class_variable '#1188AA' 357 | comment 3 358 | constant 'blue' 359 | error [111, 111, 101], [31, 125, 255] 360 | float '0, 0, 125' 361 | global_variable :bg => 5 362 | inline_delimiter :bg => '#cabe99' 363 | string { 364 | content '#122122', '#FA4499' } } } 365 | d = theme.definition 366 | d.class_.foreground.should == 35 367 | d.class_variable.foreground.should == 30 368 | d.comment.foreground.should == 33 369 | d.constant.foreground.should == 34 370 | d.error.foreground.should == 31 371 | d.error.background.should == 41 372 | d.global_variable.foreground.should == false 373 | d.global_variable.background.should == 45 374 | d.inline_delimiter.foreground.should == false 375 | d.inline_delimiter.background.should == 45 376 | d.string.content.foreground.should == 30 377 | d.string.content.background.should == 46 378 | end 379 | 380 | #it "raises error if background and foreground aren't of the same type" do 381 | #lambda { PryTheme.create(:color_model => 8) { 382 | #define_theme { class_ 'magenta', '#123456' } } }. 383 | #should.raise(PryTheme::ThemeError). 384 | #message.should.match /foreground and background are not of the same type/ 385 | 386 | #lambda { PryTheme.create(:color_model => 8) { 387 | #define_theme { class_ '#123456', 'magenta' } } }. 388 | #should.raise(PryTheme::ThemeError). 389 | #message.should.match /foreground and background are not of the same type/ 390 | 391 | #lambda { PryTheme.create(:color_model => 8) { 392 | #define_theme { class_ '#123456', '31, 31, 31' } } }. 393 | #should.raise(PryTheme::ThemeError). 394 | #message.should.match /foreground and background are not of the same type/ 395 | 396 | #lambda { PryTheme.create(:color_model => 8) { 397 | #define_theme { class_ '31, 31, 31', '#123456' } } }. 398 | #should.raise(PryTheme::ThemeError). 399 | #message.should.match /foreground and background are not of the same type/ 400 | 401 | #lambda { PryTheme.create(:color_model => 8) { 402 | #define_theme { class_ '31, 31, 31', 'magenta' } } }. 403 | #should.raise(PryTheme::ThemeError). 404 | #message.should.match /foreground and background are not of the same type/ 405 | 406 | #lambda { PryTheme.create(:color_model => 8) { 407 | #define_theme { class_ 'magenta', '31, 31, 31' } } }. 408 | #should.raise(PryTheme::ThemeError). 409 | #message.should.match /foreground and background are not of the same type/ 410 | #end 411 | end 412 | 413 | describe "state" do 414 | it "can be active" do 415 | theme = PryTheme.create{} 416 | theme.activate 417 | theme.active?.should == true 418 | end 419 | 420 | it "can be disabled" do 421 | theme = PryTheme.create{} 422 | theme.activate 423 | theme.disable 424 | theme.active?.should == false 425 | end 426 | 427 | it "is inactive by default" do 428 | theme = PryTheme.create{} 429 | theme.active?.should == false 430 | end 431 | end 432 | 433 | describe "#to_coderay" do 434 | before do 435 | @coderay_hash = { 436 | :class => "\e[48;5;118m", 437 | :class_variable => "\e[0m", 438 | :comment => "\e[0m", 439 | :constant => "\e[0m", 440 | :error => "\e[0m", 441 | :float => "\e[0m", 442 | :global_variable => "\e[38;5;81;4m", 443 | :integer => "\e[38;5;64;48;5;208m", 444 | :inline_delimiter => "\e[0m", 445 | :instance_variable => "\e[0m", 446 | :keyword => "\e[0m", 447 | :method => "\e[0m", 448 | :predefined_constant => "\e[0m", 449 | :symbol => "\e[0m", 450 | :regexp => { 451 | :self => "\e[0m", 452 | :char => "\e[0m", 453 | :content => "\e[0m", 454 | :delimiter => "\e[0m", 455 | :modifier => "\e[38;5;148m", 456 | :escape => "\e[0m", 457 | }, 458 | :shell => { 459 | :self => "\e[0m", 460 | :char => "\e[0m", 461 | :content => "\e[0m", 462 | :delimiter => "\e[0m", 463 | :escape => "\e[0m", 464 | }, 465 | :string => { 466 | :self => "\e[38;5;186m", 467 | :char => "\e[0m", 468 | :content => "\e[0m", 469 | :delimiter => "\e[0m", 470 | :escape => "\e[0m", 471 | } 472 | } 473 | end 474 | 475 | it "represents theme definition as a hash" do 476 | theme = PryTheme.create{ 477 | define_theme{ 478 | class_(:bg => 'viridian') 479 | integer('olive_drab', 'tangerine') 480 | global_variable('sky01', [:underline]) 481 | string{ self_('flax') } 482 | regexp{ modifier('lime01') } } } 483 | theme.to_coderay.should == @coderay_hash 484 | end 485 | end 486 | end 487 | --------------------------------------------------------------------------------