Skip to content
Browse files

Merge branch 'release/0.1'

  • Loading branch information...
2 parents 0cbf085 + 42a0c4b commit eb4838bd3146e2fa72b33033d8e192404cb45858 @samwho committed May 1, 2012
View
2 .gitignore
@@ -0,0 +1,2 @@
+.rvmrc
+Gemfile.lock
View
4 .travis.yml
@@ -0,0 +1,4 @@
+rvm:
+ - 1.8.7
+ - 1.9.2
+ - 1.9.3
View
10 Gemfile
@@ -0,0 +1,10 @@
+source :rubygems
+
+group :test do
+ gem 'rspec'
+ gem 'rake'
+end
+
+group :development do
+ gem 'pry'
+end
View
18 LICENSE
@@ -0,0 +1,18 @@
+Copyright (C) 2012 Sam Rose
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
293 README.md
@@ -0,0 +1,293 @@
+This is a Ruby DSL for creating Vim color schemes. I personally found color
+schemes difficult to get working in both terminal and graphical interfaces, this
+DSL tries to remedy that by, for example, automatically filling in the value of
+guibg by looking at ctermbg.
+
+[![Build Status](https://secure.travis-ci.org/samwho/vimcolorscheme.png?branch=master)](http://travis-ci.org/samwho/vimcolorscheme)
+
+# Installation
+
+Installation is standard for a Ruby gem:
+
+ gem install vimcolorscheme
+
+# Usage
+
+Let's start by showing you a really small example:
+
+``` ruby
+require 'vimcolorscheme'
+
+scheme = VimColorScheme.new :scheme_name, :dark do
+
+end
+
+scheme.save_to_vim!
+```
+
+Here we're starting a new vim color scheme with the name of `:scheme_name`
+(which will be converted into a string later) and it's going to be a dark theme.
+
+At the end of this script we save the color scheme to our vim directory with the
+`save_to_vim!` method on the scheme object. This will write our color scheme to
+the file `~/.vim/colors/scheme_name.vim`. The exclamation mark means it will
+overwrite if a file with that name exists. You can omit the exclamation mark if
+you would rather be prompted.
+
+## Adding highlights
+
+Let's expand this example to actually do something useful: highlight!
+
+``` ruby
+require 'vimcolorscheme'
+
+scheme = VimColorScheme.new :scheme_name, :dark do
+ highlight :Normal do
+ guifg '#ffffff'
+ guibg '#000000'
+ end
+end
+
+scheme.save_to_vim!
+```
+
+The `highlight` method takes a name argument, which can be anything with a
+`to_s` method and a block, which gives us access to some really cool methods.
+
+There are methods for all of the following attributes: `gui`, `guifg`, `guibg`,
+`cterm`, `ctermfg`, and `ctermbg`. Calling them with no arguments will return
+their value, which is nil by default, and calling them with arguments will set
+their value.
+
+Let's have a look at what that outputs when we save the file as `vimscheme1.rb`
+and run it with:
+
+ ruby vimscheme1.rb
+
+And the output is:
+
+``` vim
+set background=dark
+
+highlight clear
+
+if exists('syntax_on')
+ syntax reset
+endif
+
+let g:colors_name = 'scheme_name'
+
+highlight Normal gui=NONE guifg=#ffffff guibg=#000000 cterm=NONE ctermfg=231
+ctermbg=16
+```
+
+The top part of the file is some obligatory boilerplate stuff such as setting
+the background to light or dark, clearing the current highlighting and syntax
+and setting the color scheme name inside of vim itself.
+
+The last line is what we're interested in. The highlight line. Notice how it
+has values for both the guifg _and_ ctermfg? Internally it works out what the
+closest match is for the color and sets it for you.
+
+You don't need to accept this automatic color defaulting if you don't want. To
+stop it happening, just explicitly set what you want the ctermfg attribute to
+be:
+
+``` ruby
+require 'vimcolorscheme'
+
+scheme = VimColorScheme.new :scheme_name, :dark do
+ highlight :Normal do
+ guifg '#ffffff'
+ guibg '#000000'
+
+ ctermfg :none
+ ctermbg :none
+ end
+end
+
+scheme.save_to_vim!
+```
+
+### What about bold and underline and stuff?
+
+Setting the gui and cterm elements works slightly differently. These methods
+take as many arguments you give them. Let's see an example:
+
+``` ruby
+require 'vimcolorscheme'
+
+scheme = VimColorScheme.new :scheme_name, :dark do
+ highlight :Normal do
+ guifg '#ffffff'
+ guibg '#000000'
+
+ ctermfg :none
+ ctermbg :none
+
+ gui :bold, :italic
+ end
+end
+
+scheme.save_to_vim!
+```
+
+And the corresponding output:
+
+``` vim
+set background=dark
+
+highlight clear
+
+if exists('syntax_on')
+ syntax reset
+endif
+
+let g:colors_name = 'scheme_name'
+
+highlight Normal gui=bold,italic guifg=#ffffff guibg=#000000 cterm=bold,italic
+ctermfg=NONE ctermbg=NONE
+```
+
+Notice how both `gui` _and_ `cterm` have been given bold and italic properties?
+This should hopefully make color scheme development simpler and more
+expressive by harnessing the power of Ruby.
+
+## Comments
+
+If you want to add comments into your resulting color scheme file that's
+possible too! Check this out:
+
+``` ruby
+require 'vimcolorscheme'
+
+scheme = VimColorScheme.new :scheme_name, :dark do
+ comment "author: Sam Rose <samwho@lbak.co.uk>"
+
+ highlight :Normal do
+ guifg '#ffffff'
+ guibg '#000000'
+
+ ctermfg :none
+ ctermbg :none
+
+ gui :bold, :italic
+ end
+end
+
+scheme.save_to_vim!
+```
+
+See that `comment` line near the top? That tells people that I authored this
+theme. Let's see what it looks like in the vim file:
+
+``` vim
+" author: Sam Rose <samwho@lbak.co.uk>
+
+set background=dark
+
+highlight clear
+
+if exists('syntax_on')
+ syntax reset
+endif
+
+let g:colors_name = 'scheme_name'
+
+highlight Normal gui=bold,italic guifg=#ffffff guibg=#000000 cterm=bold,italic
+ctermfg=NONE ctermbg=NONE
+```
+
+We now have a comment at the top! Sweet. The astute among you may be curious
+about the placement of the boilerplate code. Why isn't it above the comment?
+Comments at the start of a document are treated specially. Before the document
+is created, vimcolorscheme looks through what we've done and all comments that
+happen before anything else are placed at the very top of the file. In short,
+all comments that you create before you create anything else will end up at the
+very top of the file.
+
+### Block comments
+
+You can also insert comments using blocks. This following snippet of code is
+exactly the same as the last one:
+
+``` ruby
+require 'vimcolorscheme'
+
+scheme = VimColorScheme.new :scheme_name, :dark do
+ comment do
+ "author: Sam Rose <samwho@lbak.co.uk>"
+ end
+
+ highlight :Normal do
+ guifg '#ffffff'
+ guibg '#000000'
+
+ ctermfg :none
+ ctermbg :none
+
+ gui :bold, :italic
+ end
+end
+
+scheme.save_to_vim!
+```
+
+## Raw input
+
+This DSL isn't perfect. There are things you can't do. Because of this, the
+ability to implement raw strings into the document is present. With this we can
+do things such as define vim variable or insert if statements into our color
+scheme file. Example:
+
+``` ruby
+require 'vimcolorscheme'
+
+scheme = VimColorScheme.new :scheme_name, :dark do
+ comment do
+ "author: Sam Rose <samwho@lbak.co.uk>"
+ end
+
+ raw "if version < 700"
+ raw " finish"
+ raw "endif\n"
+
+ highlight :Normal do
+ guifg '#ffffff'
+ guibg '#000000'
+
+ ctermfg :none
+ ctermbg :none
+
+ gui :bold, :italic
+ end
+end
+
+scheme.save_to_vim!
+```
+
+Let's see what that gives us:
+
+``` vim
+" author: Sam Rose <samwho@lbak.co.uk>
+
+set background=dark
+
+highlight clear
+
+if exists('syntax_on')
+ syntax reset
+endif
+
+let g:colors_name = 'scheme_name'
+
+if version < 700
+ finish
+endif
+
+highlight Normal gui=bold,italic guifg=#ffffff guibg=#000000
+cterm=bold,italic ctermfg=NONE ctermbg=NONE
+```
+
+As expected, the if statement is just pasted in verbatim. It's not pretty, but
+it lets us do things the DSL wouldn't let us do "natively".
View
8 Rakefile
@@ -0,0 +1,8 @@
+require 'rspec/core/rake_task'
+
+task :default => [:test]
+
+desc "Run all tests"
+RSpec::Core::RakeTask.new(:test) do |t|
+ t.rspec_opts = '-cfs'
+end
View
20 examples/simple_theme.rb
@@ -0,0 +1,20 @@
+# In your code, this LOAD_PATH malarky won't be necessary because the gem will
+# already be on your load path. This is just here for my own testing purposes so
+# that I can test the examples against the latest code base.
+libdir = File.absolute_path(File.dirname(__FILE__)) + '/../lib'
+$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
+
+require 'vimcolorscheme'
+
+VimColorScheme.new :simple_theme, :dark do
+ highlight :Normal do
+ ctermfg 231
+ ctermbg :none
+ end
+
+ comment "Highlighting for a constant in Ruby."
+ highlight :rubyConstant do
+ guifg '#ff0000'
+ gui :bold
+ end
+end.save_to_vim!
View
27 examples/vimscheme1.rb
@@ -0,0 +1,27 @@
+# In your code, this LOAD_PATH malarky won't be necessary because the gem will
+# already be on your load path. This is just here for my own testing purposes so
+# that I can test the examples against the latest code base.
+libdir = File.absolute_path(File.dirname(__FILE__)) + '/../lib'
+$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
+
+require 'vimcolorscheme'
+
+scheme = VimColorScheme.new :scheme_name, :dark do
+ comment "author: Sam Rose <samwho@lbak.co.uk>"
+
+ raw "if version < 700"
+ raw " finish"
+ raw "endif\n"
+
+ highlight :Normal do
+ guifg '#ffffff'
+ guibg '#000000'
+
+ ctermfg :none
+ ctermbg :none
+
+ gui :bold, :italic
+ end
+end
+
+scheme.save_to_vim!
View
13 lib/vimcolorscheme.rb
@@ -0,0 +1,13 @@
+libdir = File.dirname(__FILE__)
+$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
+
+module VimColorScheme
+ ROOTDIR = File.expand_path(File.dirname(__FILE__) + '/..')
+end
+
+require 'vimcolorscheme/hex2term'
+require 'vimcolorscheme/highlight_node'
+require 'vimcolorscheme/comment_node'
+require 'vimcolorscheme/raw_node'
+require 'vimcolorscheme/document'
+require 'vimcolorscheme/base'
View
11 lib/vimcolorscheme/base.rb
@@ -0,0 +1,11 @@
+module VimColorScheme
+ module Base
+ def new name, lightordark, &block
+ @document = VimColorScheme::Document.new(name, lightordark)
+ @document.instance_eval(&block)
+ @document
+ end
+ end
+
+ extend Base
+end
View
15 lib/vimcolorscheme/comment_node.rb
@@ -0,0 +1,15 @@
+module VimColorScheme
+ class CommentNode
+ # Initializes the comment node with a comment string.
+ def initialize comment
+ @comment = comment
+ end
+
+ # Renders the comment node by splitting the string at newlines and then
+ # appending the " comment character at the start of each line and joining
+ # the result with newlines.
+ def to_s
+ @comment.split(/\n/).map { |str| str = '" ' + str }.join("\n") + "\n"
+ end
+ end
+end
View
149 lib/vimcolorscheme/document.rb
@@ -0,0 +1,149 @@
+module VimColorScheme
+ class Document
+ # Creates a new color scheme document. The user will never call this method
+ # themselves but an object of this class is what they will be working with
+ # through the DSL.
+ #
+ # This constructor takes the name of the color scheme, whether it is light
+ # or dark and an optional option hash as arguments.
+ def initialize name, lightordark, options = {}
+ @name = name
+ @lightordark = lightordark
+ @options = options
+ @nodes = []
+ end
+
+ # Creates a highlight node in the document. You need to give this method
+ # call a name and a clock. Here's a usage example:
+ #
+ # highlight :Normal do
+ # cterm :bold, :underline
+ # end
+ def highlight name, &block
+ @nodes << HighlightNode.new(name)
+ @nodes.last.instance_eval(&block)
+ end
+
+ # Creates a comment node in the document. It takes a single argument, which
+ # is the string that will be in the comment. You don't need to include the "
+ # comment character in the string, that will be done for you when the vim
+ # color scheme document is created.
+ #
+ # Example:
+ #
+ # comment "This is a comment!"
+ #
+ # Alternately, you can create a comment by returning a string from a block:
+ #
+ # comment do
+ # "This is a comment!"
+ # end
+ #
+ # Both examples above yield the same result.
+ def comment string = nil
+ if block_given?
+ @nodes << CommentNode.new(yield)
+ else
+ @nodes << CommentNode.new(string)
+ end
+ end
+
+ # Creates a raw node in the current document. Raw nodes are inteded for
+ # users that want to insert code into their vim color scheme that we don't
+ # currently have a native implementation for.
+ #
+ # Example:
+ #
+ # raw "let g:my_var = 'variable!'"
+ #
+ # You can also give raw a block that returns a string:
+ #
+ # raw do
+ # "let g:my_var = 'variable!'"
+ # end
+ #
+ # The two examples above are functionally the same. The strings that are
+ # passed to raw will be printed as-is into the vim color scheme file.
+ def raw string = nil
+ if block_given?
+ @nodes << RawNode.new(yield)
+ else
+ @nodes << RawNode.new(string)
+ end
+ end
+
+ # Saves this color scheme to a file. If the file exists, the user will be
+ # prompted as to whether or not they want to overwrite the file.
+ def save path
+ if File.exists?(path)
+ puts "#{path} already exists! Overwrite? y/n"
+ answer = gets
+ unless answer == 'n' or answer == 'N'
+ File.open(path, 'w') do |file|
+ file.write(to_s)
+ end
+ end
+ end
+ end
+
+ # Does exactly the same as the save method excpet it doesn't prompt the user
+ # if the file exists, it just goes ahead and overwrites it.
+ def save! path
+ File.open(path, 'w') do |file|
+ file.write(to_s)
+ end
+ end
+
+ # This method will save the color scheme into the user's ~/.vim/colors
+ # directory. If the scheme already exists, the user will be prompted asking
+ # if they want to overwrite it.
+ def save_to_vim
+ save(File.expand_path("~/.vim/colors/#{@name.to_s}.vim"))
+ end
+
+ # This method does exactly the same as the save_to_vim method but it will
+ # not ask if you want to overwrite a file if it exists already, it will just
+ # overwrite it.
+ def save_to_vim!
+ save!(File.expand_path("~/.vim/colors/#{@name.to_s}.vim"))
+ end
+
+ # This method converts the object into a valid vim color scheme document. It
+ # is what is used to create the color schemes at the end of the DSL block.
+ def to_s
+ result = ''
+
+ # If the document starts with comments, we want to print those at the top.
+ top_comments = @nodes.take_while { |node| node.is_a? CommentNode }
+ top_comments.each do |comment|
+ result += comment.to_s
+ end
+
+ # Vanity new lines ftw.
+ result += "\n"
+
+ # Pop the top comments off the node list.
+ top_comments.length.times do
+ @nodes.shift
+ end
+
+ if @lightordark == :dark
+ result += "set background=dark\n\n"
+ else
+ result += "set background=light\n\n"
+ end
+
+ result += "highlight clear\n\n"
+ result += "if exists('syntax_on')\n"
+ result += " syntax reset\n"
+ result += "endif\n\n"
+ result += "let g:colors_name = '#{@name.to_s}'\n\n"
+
+ @nodes.each do |node|
+ result += node.to_s
+ end
+
+ return result
+ end
+ end
+end
View
357 lib/vimcolorscheme/hex2term.rb
@@ -0,0 +1,357 @@
+module VimColorScheme
+ class Hex2Term
+ # This colour lookup table is taken from the following gist:
+ # https://gist.github.com/719710
+ SCLUT = {
+ # Primary 3-bit (8 colors). Unique representation!
+ '00' => '000000',
+ '01' => '800000',
+ '02' => '008000',
+ '03' => '808000',
+ '04' => '000080',
+ '05' => '800080',
+ '06' => '008080',
+ '07' => 'c0c0c0',
+
+ # Equivalent "bright" versions of original 8 colors.
+ '08' => '808080',
+ '09' => 'ff0000',
+ '10' => '00ff00',
+ '11' => 'ffff00',
+ '12' => '0000ff',
+ '13' => 'ff00ff',
+ '14' => '00ffff',
+ '15' => 'ffffff',
+
+ # Strictly ascending.
+ '16' => '000000',
+ '17' => '00005f',
+ '18' => '000087',
+ '19' => '0000af',
+ '20' => '0000d7',
+ '21' => '0000ff',
+ '22' => '005f00',
+ '23' => '005f5f',
+ '24' => '005f87',
+ '25' => '005faf',
+ '26' => '005fd7',
+ '27' => '005fff',
+ '28' => '008700',
+ '29' => '00875f',
+ '30' => '008787',
+ '31' => '0087af',
+ '32' => '0087d7',
+ '33' => '0087ff',
+ '34' => '00af00',
+ '35' => '00af5f',
+ '36' => '00af87',
+ '37' => '00afaf',
+ '38' => '00afd7',
+ '39' => '00afff',
+ '40' => '00d700',
+ '41' => '00d75f',
+ '42' => '00d787',
+ '43' => '00d7af',
+ '44' => '00d7d7',
+ '45' => '00d7ff',
+ '46' => '00ff00',
+ '47' => '00ff5f',
+ '48' => '00ff87',
+ '49' => '00ffaf',
+ '50' => '00ffd7',
+ '51' => '00ffff',
+ '52' => '5f0000',
+ '53' => '5f005f',
+ '54' => '5f0087',
+ '55' => '5f00af',
+ '56' => '5f00d7',
+ '57' => '5f00ff',
+ '58' => '5f5f00',
+ '59' => '5f5f5f',
+ '60' => '5f5f87',
+ '61' => '5f5faf',
+ '62' => '5f5fd7',
+ '63' => '5f5fff',
+ '64' => '5f8700',
+ '65' => '5f875f',
+ '66' => '5f8787',
+ '67' => '5f87af',
+ '68' => '5f87d7',
+ '69' => '5f87ff',
+ '70' => '5faf00',
+ '71' => '5faf5f',
+ '72' => '5faf87',
+ '73' => '5fafaf',
+ '74' => '5fafd7',
+ '75' => '5fafff',
+ '76' => '5fd700',
+ '77' => '5fd75f',
+ '78' => '5fd787',
+ '79' => '5fd7af',
+ '80' => '5fd7d7',
+ '81' => '5fd7ff',
+ '82' => '5fff00',
+ '83' => '5fff5f',
+ '84' => '5fff87',
+ '85' => '5fffaf',
+ '86' => '5fffd7',
+ '87' => '5fffff',
+ '88' => '870000',
+ '89' => '87005f',
+ '90' => '870087',
+ '91' => '8700af',
+ '92' => '8700d7',
+ '93' => '8700ff',
+ '94' => '875f00',
+ '95' => '875f5f',
+ '96' => '875f87',
+ '97' => '875faf',
+ '98' => '875fd7',
+ '99' => '875fff',
+ '100' => '878700',
+ '101' => '87875f',
+ '102' => '878787',
+ '103' => '8787af',
+ '104' => '8787d7',
+ '105' => '8787ff',
+ '106' => '87af00',
+ '107' => '87af5f',
+ '108' => '87af87',
+ '109' => '87afaf',
+ '110' => '87afd7',
+ '111' => '87afff',
+ '112' => '87d700',
+ '113' => '87d75f',
+ '114' => '87d787',
+ '115' => '87d7af',
+ '116' => '87d7d7',
+ '117' => '87d7ff',
+ '118' => '87ff00',
+ '119' => '87ff5f',
+ '120' => '87ff87',
+ '121' => '87ffaf',
+ '122' => '87ffd7',
+ '123' => '87ffff',
+ '124' => 'af0000',
+ '125' => 'af005f',
+ '126' => 'af0087',
+ '127' => 'af00af',
+ '128' => 'af00d7',
+ '129' => 'af00ff',
+ '130' => 'af5f00',
+ '131' => 'af5f5f',
+ '132' => 'af5f87',
+ '133' => 'af5faf',
+ '134' => 'af5fd7',
+ '135' => 'af5fff',
+ '136' => 'af8700',
+ '137' => 'af875f',
+ '138' => 'af8787',
+ '139' => 'af87af',
+ '140' => 'af87d7',
+ '141' => 'af87ff',
+ '142' => 'afaf00',
+ '143' => 'afaf5f',
+ '144' => 'afaf87',
+ '145' => 'afafaf',
+ '146' => 'afafd7',
+ '147' => 'afafff',
+ '148' => 'afd700',
+ '149' => 'afd75f',
+ '150' => 'afd787',
+ '151' => 'afd7af',
+ '152' => 'afd7d7',
+ '153' => 'afd7ff',
+ '154' => 'afff00',
+ '155' => 'afff5f',
+ '156' => 'afff87',
+ '157' => 'afffaf',
+ '158' => 'afffd7',
+ '159' => 'afffff',
+ '160' => 'd70000',
+ '161' => 'd7005f',
+ '162' => 'd70087',
+ '163' => 'd700af',
+ '164' => 'd700d7',
+ '165' => 'd700ff',
+ '166' => 'd75f00',
+ '167' => 'd75f5f',
+ '168' => 'd75f87',
+ '169' => 'd75faf',
+ '170' => 'd75fd7',
+ '171' => 'd75fff',
+ '172' => 'd78700',
+ '173' => 'd7875f',
+ '174' => 'd78787',
+ '175' => 'd787af',
+ '176' => 'd787d7',
+ '177' => 'd787ff',
+ '178' => 'd7af00',
+ '179' => 'd7af5f',
+ '180' => 'd7af87',
+ '181' => 'd7afaf',
+ '182' => 'd7afd7',
+ '183' => 'd7afff',
+ '184' => 'd7d700',
+ '185' => 'd7d75f',
+ '186' => 'd7d787',
+ '187' => 'd7d7af',
+ '188' => 'd7d7d7',
+ '189' => 'd7d7ff',
+ '190' => 'd7ff00',
+ '191' => 'd7ff5f',
+ '192' => 'd7ff87',
+ '193' => 'd7ffaf',
+ '194' => 'd7ffd7',
+ '195' => 'd7ffff',
+ '196' => 'ff0000',
+ '197' => 'ff005f',
+ '198' => 'ff0087',
+ '199' => 'ff00af',
+ '200' => 'ff00d7',
+ '201' => 'ff00ff',
+ '202' => 'ff5f00',
+ '203' => 'ff5f5f',
+ '204' => 'ff5f87',
+ '205' => 'ff5faf',
+ '206' => 'ff5fd7',
+ '207' => 'ff5fff',
+ '208' => 'ff8700',
+ '209' => 'ff875f',
+ '210' => 'ff8787',
+ '211' => 'ff87af',
+ '212' => 'ff87d7',
+ '213' => 'ff87ff',
+ '214' => 'ffaf00',
+ '215' => 'ffaf5f',
+ '216' => 'ffaf87',
+ '217' => 'ffafaf',
+ '218' => 'ffafd7',
+ '219' => 'ffafff',
+ '220' => 'ffd700',
+ '221' => 'ffd75f',
+ '222' => 'ffd787',
+ '223' => 'ffd7af',
+ '224' => 'ffd7d7',
+ '225' => 'ffd7ff',
+ '226' => 'ffff00',
+ '227' => 'ffff5f',
+ '228' => 'ffff87',
+ '229' => 'ffffaf',
+ '230' => 'ffffd7',
+ '231' => 'ffffff',
+
+ # Gr' => scale rang.
+ '232' => '080808',
+ '233' => '121212',
+ '234' => '1c1c1c',
+ '235' => '262626',
+ '236' => '303030',
+ '237' => '3a3a3a',
+ '238' => '444444',
+ '239' => '4e4e4e',
+ '240' => '585858',
+ '241' => '626262',
+ '242' => '6c6c6c',
+ '243' => '767676',
+ '244' => '808080',
+ '245' => '8a8a8a',
+ '246' => '949494',
+ '247' => '9e9e9e',
+ '248' => 'a8a8a8',
+ '249' => 'b2b2b2',
+ '250' => 'bcbcbc',
+ '251' => 'c6c6c6',
+ '252' => 'd0d0d0',
+ '253' => 'dadada',
+ '254' => 'e4e4e4',
+ '255' => 'eeeeee',
+ }
+
+ # Hex color lookup table. Essentially this is exactly the same as the short
+ # color lookup table but inverted. So k => v becomes v => k.
+ HCLUT = SCLUT.invert
+
+ # Takes either a short color value or a hexidecimal color value and converts
+ # it to the other format respectively.
+ #
+ # Example:
+ #
+ # convert(23)
+ # # => '005f5f'
+ #
+ # convert('#ffffff')
+ # # => '231'
+ def self.convert value
+ if value.to_s.length < 4 and value.to_s.to_i < 256
+ short2rb(value)
+ else
+ rgb2short(value)
+ end
+ end
+
+ # Takes a short color value (e.g. between 0 and 255) and returns the
+ # hexadecimal equivalent with a leading hash.
+ #
+ # Example:
+ #
+ # short2rb(231)
+ # # => '#ffffff'
+ def self.short2rb short
+ '#' + SCLUT[short.to_s]
+ end
+
+ # Takes an RGB hex value, with or without the leading hash, and converts it
+ # into one of 256 color values used by terminals.
+ #
+ # The method for doing it was borrowed with lots of love from this gist:
+ # https://gist.github.com/719710
+ #
+ # Example:
+ #
+ # rgb2short('#ffffff')
+ # # => '231'
+ def self.rgb2short rgb
+ rgb = strip_hash(rgb)
+ incs = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
+ parts = rgb.split(/(..)(..)(..)/).map { |part| part.to_i(16) }
+ res = []
+
+ # The above split will have an empty string at the start, this gets rid of
+ # it
+ parts.shift
+
+ parts.each do |part|
+ incs.each_cons(2) do |s, b|
+ if s <= part and part <= b
+ s1 = (s - part).abs
+ b1 = (b - part).abs
+
+ if s1 < b1
+ closest = s
+ else
+ closest = b
+ end
+
+ res << closest
+ break
+ end
+ end
+ end
+
+ key = res.map { |part| part.to_s(16).center(2, '0') }.join
+ HCLUT[key]
+ end
+
+ # Takes a string that may or may not have a hash at the start and returns a
+ # string that does not have a hash at the start.
+ #
+ # Example:
+ #
+ # strip_hash('#ffffff')
+ # # => 'ffffff'
+ def self.strip_hash hex
+ hex.delete '#'
+ end
+ end
+end
View
114 lib/vimcolorscheme/highlight_node.rb
@@ -0,0 +1,114 @@
+module VimColorScheme
+ class HighlightNode
+ def initialize name, options = {}
+ @name = name
+ @options = options
+ end
+
+ # Processes the values of a node. Basically, if there are values that have
+ # not been set, we try to guess them. So we convert gui colors to cterm
+ # colors if the cterm colors are not present and default to :none if that
+ # isn't possible and so on.
+ #
+ # This gets called in the to_s method so there's no need to call it
+ # explicitly.
+ def process
+ # Process colors. Set cterm if none, gui if none, based on their
+ # counterparts.
+ if !gui and cterm
+ gui(cterm)
+ end
+
+ if !guifg and ctermfg
+ guifg Hex2Term.convert(ctermfg)
+ end
+
+ if !guibg and ctermbg
+ guibg Hex2Term.convert(ctermbg)
+ end
+
+ if !cterm and gui
+ cterm(gui)
+ end
+
+ if !ctermfg and guifg
+ ctermfg Hex2Term.convert(guifg)
+ end
+
+ if !ctermbg and guibg
+ ctermbg Hex2Term.convert(guibg)
+ end
+
+ # Default things to none if they are nil or false.
+ gui :none unless gui
+ guifg :none unless guifg
+ guibg :none unless guibg
+ cterm :none unless cterm
+ ctermfg :none unless ctermfg
+ ctermbg :none unless ctermbg
+ end
+
+ # Converts the Node to a valid entry in a vim color scheme file.
+ def to_s
+ # Make sure the node has been processed before converting to string.
+ process
+
+ result = "highlight #{@name.to_s} "
+ result += "gui=#{attr_to_s(gui)} "
+ result += "guifg=#{attr_to_s(guifg)} "
+ result += "guibg=#{attr_to_s(guibg)} "
+ result += "cterm=#{attr_to_s(cterm)} "
+ result += "ctermfg=#{attr_to_s(ctermfg)} "
+ result += "ctermbg=#{attr_to_s(ctermbg)}\n"
+ end
+
+ # Converts an attribute to string. This accounts for cases such as :none and
+ # :reverse and returns the appropriate string.
+ def attr_to_s attribute
+ case attribute
+ when Array
+ attribute.map { |a| attr_to_s(a) }.join(',')
+ when :none
+ 'NONE'
+ when :reverse
+ 'REVERSE'
+ else
+ attribute
+ end
+ end
+
+ #
+ # The following are just default accessors for the various members of the
+ # options hash on this object.
+ #
+ def gui *args
+ @options[:gui] = args if args.length > 0
+ @options[:gui]
+ end
+
+ def guibg new_guibg = nil
+ @options[:guibg] = new_guibg if new_guibg
+ @options[:guibg]
+ end
+
+ def guifg new_guifg = nil
+ @options[:guifg] = new_guifg if new_guifg
+ @options[:guifg]
+ end
+
+ def cterm *args
+ @options[:cterm] = args if args.length > 0
+ @options[:cterm]
+ end
+
+ def ctermbg new_ctermbg = nil
+ @options[:ctermbg] = new_ctermbg if new_ctermbg
+ @options[:ctermbg]
+ end
+
+ def ctermfg new_ctermfg = nil
+ @options[:ctermfg] = new_ctermfg if new_ctermfg
+ @options[:ctermfg]
+ end
+ end
+end
View
15 lib/vimcolorscheme/raw_node.rb
@@ -0,0 +1,15 @@
+module VimColorScheme
+ class RawNode
+ # The raw node gets initialized with a string. This string will later just
+ # be printed as-is into the vim file.
+ def initialize raw
+ @raw = raw
+ end
+
+ # Just returns the value that was passed into the constructor of this
+ # object.
+ def to_s
+ @raw + "\n"
+ end
+ end
+end
View
92 spec/base_spec.rb
@@ -0,0 +1,92 @@
+require 'spec_helper'
+require 'fileutils'
+
+describe VimColorScheme::Base do
+ let :test_scheme do
+ VimColorScheme.new :test_scheme, :dark do
+ comment "This is a comment!"
+ comment do
+ "This is a block comment!"
+ end
+
+ highlight :Normal do
+ ctermfg '231'
+ ctermbg '31'
+ cterm :bold, :underline
+ end
+
+ raw "Some raw input."
+
+ raw do
+ "Some raw block input."
+ end
+ end.to_s
+ end
+
+ let :test_scheme_path do
+ VimColorScheme::ROOTDIR + '/spec/data/test_scheme.vim'
+ end
+
+ let :test_scheme_object do
+ VimColorScheme.new :test_scheme, :dark do
+ highlight :Normal do
+ ctermfg '231'
+ ctermbg '31'
+ cterm :bold, :underline
+ end
+ end
+ end
+
+ # Ensure that the test scheme file does not exists for each test.
+ after :each do
+ FileUtils.rm test_scheme_path if File.exists?(test_scheme_path)
+ end
+
+ it "should print out the color scheme name" do
+ test_scheme.should include("let g:colors_name = 'test_scheme'")
+ end
+
+ it "should set the background" do
+ test_scheme.should include("set background=dark")
+ end
+
+ it "should clear highlighting at the start" do
+ test_scheme.should include("highlight clear")
+ end
+
+ it "should check if syntax highlighting is on" do
+ test_scheme.should include("if exists('syntax_on')")
+ end
+
+ it "should set bold and underline style values" do
+ test_scheme.should include("cterm=bold,underline")
+ end
+
+ it 'should write to file with the save method' do
+ test_scheme_object.save!(test_scheme_path)
+
+ File.open(test_scheme_path) do |file|
+ file.read.should == test_scheme_object.to_s
+ end
+ end
+
+ it 'should render comments' do
+ test_scheme.should include('" This is a comment!' + "\n")
+ end
+
+ it 'should render block comments' do
+ test_scheme.should include('" This is a block comment!' + "\n")
+ end
+
+ it 'should render comments at the top... at the top' do
+ test_scheme.start_with?('" This is a comment!' + "\n").should be_true
+ end
+
+ it 'should render raw' do
+ test_scheme.should include("Some raw input.\n")
+ end
+
+ it 'should render raw blocks' do
+ test_scheme.should include("Some raw block input.\n")
+ end
+end
View
22 spec/comment_node_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe VimColorScheme::CommentNode do
+ let :single_line_comment do
+ comment = VimColorScheme::CommentNode.new "This is a comment!"
+ comment.to_s
+ end
+
+ let :multi_line_comment do
+ comment = VimColorScheme::CommentNode.new "This is.\nA multiline.\nComment."
+ comment.to_s
+ end
+
+ it 'should put the comment character on the front of a comment' do
+ single_line_comment.should == '" This is a comment!' + "\n"
+ end
+
+ it 'should render multiline comments properly' do
+ multi_line_comment.should == '" This is.' + "\n" + '" A multiline.' +
+ "\n" + '" Comment.' + "\n"
+ end
+end
View
0 spec/data/.include
No changes.
View
25 spec/hex2term_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe VimColorScheme::Hex2Term do
+ # Just a method to reduce clutter in this test. Delegates to the Hex2Term
+ # class in the ColorSchemeRb module.
+ def convert value
+ VimColorScheme::Hex2Term.convert value
+ end
+
+ it "correctly convert hex colors to term colors" do
+ convert('123456').should == '23'
+ convert('00af00').should == '34'
+ convert('odadd6').should == '38'
+
+ convert('231').should == '#ffffff'
+ convert(231).should == '#ffffff'
+ convert(23).should == '#005f5f'
+ end
+
+ it "correctly handle hex number with leading hashes" do
+ convert('#123456').should == '23'
+ convert('#00af00').should == '34'
+ convert('#odadd6').should == '38'
+ end
+end
View
77 spec/highlight_node_spec.rb
@@ -0,0 +1,77 @@
+require 'spec_helper'
+
+describe VimColorScheme::HighlightNode do
+ let :guinode do
+ temp = VimColorScheme::HighlightNode.new :Normal
+ temp.guifg '#00af00'
+ temp.guibg '#00afd7'
+ temp.gui :bold
+ temp.to_s
+ end
+
+ let :ctermnode do
+ temp = VimColorScheme::HighlightNode.new :Normal
+ temp.ctermfg '34'
+ temp.ctermbg '35'
+ temp.cterm :italic
+ temp.gui :none
+ temp.to_s
+ end
+
+ let :bothnode do
+ temp = VimColorScheme::HighlightNode.new :Normal
+ temp.ctermfg '34'
+ temp.ctermbg '35'
+ temp.guifg '#00af00'
+ temp.guibg '#00afd7'
+ temp.to_s
+ end
+
+ let :reversenode do
+ temp = VimColorScheme::HighlightNode.new :Normal
+ temp.gui :reverse
+ temp.to_s
+ end
+
+ it 'should start with the word highlight' do
+ guinode.start_with?('highlight').should be_true
+ bothnode.start_with?('highlight').should be_true
+ ctermnode.start_with?('highlight').should be_true
+ reversenode.start_with?('highlight').should be_true
+ end
+
+ it "should convert between gui and cterm colors correctly" do
+ guinode.should include('ctermfg=34')
+ guinode.should include('ctermbg=38')
+ end
+
+ it "should convert between cterm and gui colors correctly" do
+ ctermnode.should include('guifg=#00af00')
+ ctermnode.should include('guibg=#00af5f')
+ end
+
+ it 'should not convert colors if both are present' do
+ bothnode.should include('ctermfg=34')
+ bothnode.should include('ctermbg=35')
+ bothnode.should include('guifg=#00af00')
+ bothnode.should include('guibg=#00afd7')
+ end
+
+ it 'should correctly default nodes to none if no value is given' do
+ bothnode.should include('gui=NONE')
+ end
+
+ it 'should correctly convert :reverse values to REVERSE' do
+ reversenode.should include('gui=REVERSE')
+ end
+
+ it 'should set gui to bold and correctly mirror that in cterm' do
+ guinode.should include('gui=bold')
+ guinode.should include('cterm=bold')
+ end
+
+ it 'should set not mirror gui and cterm if coth are set' do
+ ctermnode.should include('cterm=italic')
+ ctermnode.should include('gui=NONE')
+ end
+end
View
12 spec/raw_node_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+describe VimColorScheme::RawNode do
+ let :raw_node do
+ raw = VimColorScheme::RawNode.new "Raw content."
+ raw.to_s
+ end
+
+ it 'should render content verbatim' do
+ raw_node.should == "Raw content.\n"
+ end
+end
View
1 spec/spec_helper.rb
@@ -0,0 +1 @@
+require File.dirname(__FILE__) + '/../lib/vimcolorscheme.rb'
View
16 vimcolorscheme.gemspec
@@ -0,0 +1,16 @@
+Gem::Specification.new do |s|
+ s.name = %q{vimcolorscheme}
+ s.version = "0.1"
+ s.date = %q{2012-05-01}
+ s.authors = ["Sam Rose"]
+ s.email = %q{samwho@lbak.co.uk}
+ s.summary = %q{A Ruby DSL for creating Vim color schemes}
+ s.homepage = %q{http://github.com/samwho/vimcolorscheme}
+ s.description = %q{Allows for creating of Vim color schemes using a nifty Ruby DSL}
+ s.required_ruby_version = '>= 1.8.7'
+ s.license = 'MIT'
+
+ # Add all files to the files parameter.
+ s.files = []
+ Dir["**/*.*"].each { |path| s.files.push path }
+end

0 comments on commit eb4838b

Please sign in to comment.
Something went wrong with that request. Please try again.