diff --git a/Gemfile b/Gemfile
index 8ac2f0b00..452797cb9 100644
--- a/Gemfile
+++ b/Gemfile
@@ -4,8 +4,9 @@ gem "redcarpet"
gem "activesupport"
gem "highline"
gem "rake"
-gem "coderay", :git => "git://github.com/dgeb/coderay.git", :branch => "handlebars"
+gem "coderay"
gem "middleman", '~> 3.0'
+gem "byebug"
gem "thin"
gem "rack"
gem "listen"
diff --git a/Gemfile.lock b/Gemfile.lock
index 151040176..405249871 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -7,13 +7,6 @@ GIT
nokogiri
swiftype (>= 0.0.4)
-GIT
- remote: git://github.com/dgeb/coderay.git
- revision: 1362fd4af63331aed51ce9907ad7295cea228874
- branch: handlebars
- specs:
- coderay (1.1.0.rc1)
-
GEM
remote: https://rubygems.org/
remote: https://rails-assets.org/
@@ -25,6 +18,9 @@ GEM
thread_safe (~> 0.1)
tzinfo (~> 1.1)
builder (3.2.2)
+ byebug (4.0.1)
+ columnize (= 0.9.0)
+ rb-readline (= 0.5.2)
capybara (2.4.4)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
@@ -35,10 +31,12 @@ GEM
timers (~> 4.0.0)
chunky_png (1.3.3)
cliver (0.3.2)
+ coderay (1.1.0)
coffee-script (2.3.0)
coffee-script-source
execjs
coffee-script-source (1.9.0)
+ columnize (0.9.0)
compass (1.0.3)
chunky_png (~> 1.2)
compass-core (~> 1.0.2)
@@ -142,6 +140,7 @@ GEM
rb-fsevent (0.9.4)
rb-inotify (0.9.5)
ffi (>= 0.5.0)
+ rb-readline (0.5.2)
redcarpet (3.2.2)
rspec (3.2.0)
rspec-core (~> 3.2.0)
@@ -202,8 +201,9 @@ PLATFORMS
DEPENDENCIES
activesupport
builder
+ byebug
capybara
- coderay!
+ coderay
hashie
highline
listen
diff --git a/lib/highlighter.rb b/lib/highlighter.rb
index e7f10e7e7..a52ac69bb 100644
--- a/lib/highlighter.rb
+++ b/lib/highlighter.rb
@@ -1,5 +1,13 @@
require "redcarpet"
+require "byebug"
require "coderay"
+require "nokogiri"
+
+class EmberEncoder < CodeRay::Encoders::Div
+ FILE_EXTENSION = 'ember.html'
+ register_for :ember
+
+end
module Highlighter
class MissingLanguageError < StandardError; end
@@ -17,47 +25,75 @@ def _highlight(string, language, class_name=nil)
raise MissingLanguageError, error_message if language.nil?
- language, file_name = _detect_language_and_filename(language)
+ language, file_name, changes = _detect_language_filename_and_changes(language)
result = %Q{
}
result += '
'
result += '
'
- result += _code_table(string, language, file_name)
+ result += _code_table(string, language, file_name, changes)
result += '
'
result += %Q{
}
result
end
- def _detect_language_and_filename(language)
-
+ def _detect_language_filename_and_changes(language)
file_name = nil
+ changes = []
+ changes_regex = /\{(.+)\}$/
bare_language_regex = /\A\w+\z/
+ if change_numbers = changes_regex.match(language)
+ language = language.sub(changes_regex, '')
+
+ changes = _parse_changes(change_numbers[1])
+ end
+
unless language =~ bare_language_regex
file_name = language
- language = case /\.(\w+)$/.match(language)[1]
- when 'hbs'
- 'handlebars'
- when 'js'
- 'javascript'
- when 'html'
- 'html'
- when 'css'
- 'css'
- when 'json'
- 'json'
- end
+ language = _determine_language(language)
+ end
+ [language, file_name, changes]
+ end
+
+ def _determine_language(language)
+ case /\.(\w+)$/.match(language)[1]
+ when 'hbs'
+ 'handlebars'
+ when 'js'
+ 'javascript'
+ when 'html'
+ 'html'
+ when 'css'
+ 'css'
+ when 'json'
+ 'json'
+ end
+ end
+
+ def _parse_changes(change_numbers)
+ changes = change_numbers.split(',').map do |change|
+ state = case change.slice(0)
+ when '+'
+ 'added'
+ when '-'
+ 'removed'
+ else
+ nil
+ end
+
+ [change.to_i.abs, state]
end
- [language, file_name]
end
- def _code_table(string, language, file_name)
+ def _code_table(string, language, file_name, changes)
code = CodeRay.scan(string, language)
- table = code.div css: :class,
+ # debugger
+ table = code.ember css: :class,
line_numbers: :table,
- line_number_anchors: false
+ line_number_anchors: false,
+ highlight_lines: [1,3]
if file_name.present?
@@ -71,7 +107,30 @@ def _code_table(string, language, file_name)
HEADER
end
- table
+ _highlight_lines(table, changes)
+ end
+
+ def _highlight_lines(table, highlights)
+ return table if highlights.empty?
+
+ table_xml = Nokogiri.XML(table)
+
+ numbers_node = table_xml.at_xpath('//td[@class="line-numbers"]/pre')
+ code_node = table_xml.at_xpath('//td[@class="code"]/pre')
+
+ numbers_contents = numbers_node.inner_html.split("\n")
+ code_contents = code_node.inner_html.split("\n")
+
+ highlights.each do |line_number, state|
+ index = line_number - 1
+ numbers_contents[index] = "#{numbers_contents[index]}"
+ code_contents[index] = "#{code_contents[index]}"
+ end
+
+ numbers_node.inner_html = numbers_contents.join("\n")
+ code_node.inner_html = code_contents.join("\n")
+
+ table_xml.to_xml
end
def highlight(language, class_name, &block)
diff --git a/source/stylesheets/highlight.css.scss b/source/stylesheets/highlight.css.scss
index 902e0cb3e..1a1d24ff8 100644
--- a/source/stylesheets/highlight.css.scss
+++ b/source/stylesheets/highlight.css.scss
@@ -4,12 +4,19 @@
$border-radius: 5px;
$blue: #1f58ce;
-$gray: #777777;
-$green: #007700;
+$gray: #545454;
+$textColor: #222;
+$green: #005f00;
+$orange: #8f4a2c;
+
+$highlight-yellow: #f8eec7;
+$highlight-green: #E8F4E5;
+$highlight-red: #ffecec;
body.guides .highlight {
@include border-radius($border-radius);
border: 1px solid #d1d1d1;
+ color: $textColor;
}
#content .highlight {
@@ -46,6 +53,45 @@ body.guides .highlight {
&.handlebars .ribbon {
@include hidpi('handlebars-ribbon', png);
}
+
+ .highlight-line {
+ display: inline-block;
+ margin: 0 -10px;
+ background-color: $highlight-yellow;
+ border-right: $highlight-yellow solid 5px;
+ border-left: $highlight-yellow solid 5px;
+ box-sizing: content-box;
+
+ &.added {
+ border-color: $highlight-green;
+ background-color: $highlight-green;
+ }
+
+ &.removed {
+ border-color: $highlight-red;
+ background-color: $highlight-red;
+ }
+ }
+
+ .code .highlight-line {
+ width: 613px;
+ margin: 0 -13px;
+ border-left-width: 13px;
+ border-right-width: 13px;
+ }
+
+ .line-numbers .highlight-line {
+ width: 28px;
+ border-right-color: darken($highlight-yellow, 20%);
+
+ &.added {
+ border-right-color: darken($highlight-green, 20%);
+ }
+
+ &.removed {
+ border-right-color: darken($highlight-red, 20%);
+ }
+ }
}
.CodeRay {
@@ -55,7 +101,7 @@ body.guides .highlight {
text-align: center;
border-right: 1px solid #d1d1d1;
background-color: #f6f6f6;
- color: #b4b4b4;
+ color: $gray;
@include border-top-left-radius($border-radius);
@include border-bottom-left-radius($border-radius);
}
@@ -71,7 +117,7 @@ body.guides .highlight {
}
.comment {
- color: $gray;
+ color: $green;
}
.attribute-name {
@@ -87,7 +133,7 @@ body.guides .highlight {
}
.keyword {
- color: #ce791f;
+ color: $orange;
}
.key, .function {
diff --git a/spec/highlighter_spec.rb b/spec/highlighter_spec.rb
index ca4d6b8ca..007252294 100644
--- a/spec/highlighter_spec.rb
+++ b/spec/highlighter_spec.rb
@@ -12,37 +12,65 @@ class HelperTester
Object.send :remove_const, :HelperTester
end
- describe '#_detect_language_and_filename' do
+ describe '#_detect_language_filename_and_changes' do
it 'returns bare languages and does not return a filename' do
- language, filename = HelperTester.new._detect_language_and_filename('javascript')
+ language, filename, changes = HelperTester.new._detect_language_filename_and_changes('javascript')
expect(language).to eq 'javascript'
expect(filename).to be_nil
+ expect(changes).to eq []
- language, filename = HelperTester.new._detect_language_and_filename('handlebars')
+ language, filename, changes = HelperTester.new._detect_language_filename_and_changes('handlebars')
expect(language).to eq 'handlebars'
expect(filename).to be_nil
+ expect(changes).to eq []
end
it 'returns the detected language and the filename from a filename' do
- language, filename = HelperTester.new._detect_language_and_filename('app/components/my-component.js')
+ language, filename, changes = HelperTester.new._detect_language_filename_and_changes('app/components/my-component.js')
expect(language).to eq 'javascript'
expect(filename).to eq 'app/components/my-component.js'
+ expect(changes).to eq []
- language, filename = HelperTester.new._detect_language_and_filename('app/templates/application.hbs')
+ language, filename, changes = HelperTester.new._detect_language_filename_and_changes('app/templates/application.hbs')
expect(language).to eq 'handlebars'
expect(filename).to eq 'app/templates/application.hbs'
+ expect(changes).to eq []
- language, filename = HelperTester.new._detect_language_and_filename('app/index.html')
+ language, filename, changes = HelperTester.new._detect_language_filename_and_changes('app/index.html')
expect(language).to eq 'html'
expect(filename).to eq 'app/index.html'
+ expect(changes).to eq []
- language, filename = HelperTester.new._detect_language_and_filename('app/styles/app.css')
+ language, filename, changes = HelperTester.new._detect_language_filename_and_changes('app/styles/app.css')
expect(language).to eq 'css'
expect(filename).to eq 'app/styles/app.css'
+ expect(changes).to eq []
- language, filename = HelperTester.new._detect_language_and_filename('bower.json')
+ language, filename, changes = HelperTester.new._detect_language_filename_and_changes('bower.json')
expect(language).to eq 'json'
expect(filename).to eq 'bower.json'
+ expect(changes).to eq []
+ end
+
+ it 'returns detected code changes' do
+ _, _, changes = HelperTester.new._detect_language_filename_and_changes('app/components/my-component.js{1,+3,4,-5,+6,-7}')
+
+ expect(changes).to eq [
+ [1, nil],
+ [3, 'added'],
+ [4, nil],
+ [5, 'removed'],
+ [6, 'added'],
+ [7, 'removed'],
+ ]
+
+ _, _, changes = HelperTester.new._detect_language_filename_and_changes('javascript{+2,3,-5}')
+
+ expect(changes).to eq [
+ [2, 'added'],
+ [3, nil],
+ [5, 'removed']
+ ]
end
end
@@ -82,6 +110,48 @@ class HelperTester
export default Ember.Component.extend() |
+OUTPUT
+ end
+
+ it 'returns a code block with a filename in the table when using a filename fence with highlighting' do
+ code_block = HelperTester.new._highlight("export default Ember.Component.extend()\nvar added;\nvar removed;",
+ 'app/components/my-foo.js{1,+2,-3}')
+ expect(code_block).to eq <<-OUTPUT.sub(/\n$/, '')
+
+OUTPUT
+ end
+
+ it 'returns a code block with a filename in the table when using a filename fence with highlighting' do
+ code_block = HelperTester.new._highlight("export default Ember.Component.extend()\nvar added;\nvar removed;",
+ 'javascript{1,+2,-3}')
+ expect(code_block).to eq <<-OUTPUT.sub(/\n$/, '')
+
OUTPUT
end
end