Skip to content

Commit

Permalink
[#2744] Highlight a line in the submissions page
Browse files Browse the repository at this point in the history
  • Loading branch information
Karlo Soriano committed Apr 24, 2016
1 parent f03d8a8 commit 605eb3f
Show file tree
Hide file tree
Showing 15 changed files with 186 additions and 48 deletions.
5 changes: 5 additions & 0 deletions frontend/app/js/scroll.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
$(function () {
var shiftWindow = function() { scrollBy(0, -50) };
if (location.hash) shiftWindow();
window.addEventListener("hashchange", shiftWindow);
});
3 changes: 2 additions & 1 deletion lib/exercism/syntax_highlighter.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'rouge'
require 'rouge/formatters/html_exercism'

module ExercismLib
class SyntaxHighlighter
Expand Down Expand Up @@ -36,7 +37,7 @@ def formatter
line_numbers: true
}

Rouge::Formatters::HTML.new(options)
Rouge::Formatters::HTMLExercism.new(options)
end

def normalize_language(language)
Expand Down
120 changes: 120 additions & 0 deletions lib/rouge/formatters/html_exercism.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
require 'cgi'

module Rouge
module Formatters
# Transforms a token stream into HTML output.
class HTMLExercism < Formatter
tag 'html'

# @option opts [String] :css_class ('highlight')
# @option opts [true/false] :line_numbers (false)
# @option opts [String] :line_numbers_id ('L')
# @option opts [Rouge::CSSTheme] :inline_theme (nil)
# @option opts [true/false] :wrap (true)
#
# Initialize with options.
#
# If `:inline_theme` is given, then instead of rendering the
# tokens as <span> tags with CSS classes, the styles according to
# the given theme will be inlined in "style" attributes. This is
# useful for formats in which stylesheets are not available.
#
# Content will be wrapped in a tag (`div` if tableized, `pre` if
# not) with the given `:css_class` unless `:wrap` is set to `false`.
def initialize(opts={})
@css_class = opts.fetch(:css_class, 'highlight')
@css_class = " class=#{@css_class.inspect}" if @css_class

@line_numbers = opts.fetch(:line_numbers, false)
@line_numbers_id = opts.fetch(:line_numbers_id, 'L')
@start_line = opts.fetch(:start_line, 1)
@inline_theme = opts.fetch(:inline_theme, nil)
@inline_theme = Theme.find(@inline_theme).new if @inline_theme.is_a? String

@wrap = opts.fetch(:wrap, true)
end

# @yield the html output.
def stream(tokens, &b)
if @line_numbers
stream_tableized(tokens, &b)
else
stream_untableized(tokens, &b)
end
end

private
def stream_untableized(tokens, &b)
yield "<pre#@css_class><code>" if @wrap
tokens.each{ |tok, val| span(tok, val, &b) }
yield "</code></pre>\n" if @wrap
end

def stream_tableized(tokens)
num_lines = 0
last_val = ''
formatted = ''

tokens.each do |tok, val|
last_val = val
num_lines += val.scan(/\n/).size
span(tok, val) { |str| formatted << str }
end

formatted = formatted.lines.map.with_index(1) do |line, index|
"<span id='#{@line_numbers_id}#{index}'>#{line}</span>"
end.join

# add an extra line for non-newline-terminated strings
if last_val[-1] != "\n"
num_lines += 1
span(Token::Tokens::Text::Whitespace, "\n") { |str| formatted << str }
end

# generate a string of newline-separated line numbers for the gutter>
numbers = %<<pre class="lineno">#{(@start_line..num_lines+@start_line-1)
.to_a.join("\n")}</pre>>

yield "<div#@css_class>" if @wrap
yield '<table style="border-spacing: 0"><tbody><tr>'

# the "gl" class applies the style for Generic.Lineno
yield '<td class="gutter gl" style="text-align: right">'
yield numbers
yield '</td>'

yield '<td class="code">'
yield '<pre>'
yield formatted
yield '</pre>'
yield '</td>'

yield "</tr></tbody></table>\n"
yield "</div>\n" if @wrap
end

TABLE_FOR_ESCAPE_HTML = {
'&' => '&amp;',
'<' => '&lt;',
'>' => '&gt;',
}

def span(tok, val)
val = val.gsub(/[&<>]/, TABLE_FOR_ESCAPE_HTML)
shortname = tok.shortname or raise "unknown token: #{tok.inspect} for #{val.inspect}"

if shortname.empty?
yield val
else
if @inline_theme
rules = @inline_theme.style_for(tok).rendered_rules

yield "<span style=\"#{rules.to_a.join(';')}\">#{val}</span>"
else
yield "<span class=\"#{shortname}\">#{val}</span>"
end
end
end
end
end
end
20 changes: 10 additions & 10 deletions public/css/application.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion public/css/base/components/inbox.css
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nav.inbox li{padding-left:50px}nav.inbox li a .total-count{color:#777;float:right}nav.inbox li .badge{position:absolute;top:0;left:0}
nav.inbox li{padding-left:50px}nav.inbox li a .total-count{color:#777;float:right}nav.inbox li .badge{position:absolute;top:10px;left:5px}
8 changes: 4 additions & 4 deletions public/css/base/import.css

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions public/css/font-awesome/font-awesome.css

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions public/css/layouts/footer.css

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions public/css/layouts/import.css

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions public/css/layouts/submission.css

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions public/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -30393,6 +30393,12 @@ $(function() {
});
});

$(function () {
var shiftWindow = function() { scrollBy(0, -50) };
if (location.hash) shiftWindow();
window.addEventListener("hashchange", shiftWindow);
});

$(".track-activity-chart").each(function(index, element) {
var stats = $(element).data('stats');
var data = {
Expand Down
4 changes: 4 additions & 0 deletions public/sass/layouts/submission.scss
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@
.highlight {
padding: 5px 0px;
}

:target {
background: #f8eec7;
}
}
}
.submission-like-button {
Expand Down
30 changes: 16 additions & 14 deletions test/exercism/converts_markdown_to_html_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ def test_markdown_code_with_ampersands
expected = %q{<div class="highlight plaintext">
<table style="border-spacing: 0;"><tbody><tr>
<td class="gutter gl" style="text-align: right;"><pre class="lineno">1</pre></td>
<td class="code"><pre>big &amp;&amp; strong
</pre></td>
<td class="code"><pre><span id="L1">big &amp;&amp; strong
</span></pre></td>
</tr></tbody></table>
</div>}
assert_converts_to(input, expected)
Expand Down Expand Up @@ -67,10 +67,12 @@ def test_markdown_code_with_javascript_and_double_braces
3
4
5</pre></td>
<td class="code"><pre> var refill = 99
, template = "{{current}} of beer on the wall, {{current}} of beer.\n" +
"{{action}}, {{remaining}} of beer on the wall.\n";
</pre></td>
<td class="code"><pre><span id="L1"> var refill = 99
</span><span id="L2"> , template = \"{{current}} of beer on the wall, {{current}} of beer.
</span><span id="L3">" +
</span><span id="L4"> \"{{action}}, {{remaining}} of beer on the wall.
</span><span id="L5">";
</span></pre></td>
</tr></tbody></table>
</div>}

Expand All @@ -97,10 +99,10 @@ class Foobar
<td class="gutter gl" style="text-align: right;"><pre class="lineno">1
2
3</pre></td>
<td class="code"><pre>class Foobar
foos.each { |foo| foo.bar &gt; 10 }
end
</pre></td>
<td class="code"><pre><span id="L1">class Foobar
</span><span id="L2"> foos.each { |foo| foo.bar &gt; 10 }
</span><span id="L3">end
</span></pre></td>
</tr></tbody></table>
</div>
Expand All @@ -124,10 +126,10 @@ def test_markdown_with_clojure_code
<td class="gutter gl" style="text-align: right;"><pre class="lineno">1
2
3</pre></td>
<td class="code"><pre><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">to-rna</span><span class="w">
</span><span class="p">[</span><span class="n">dna-string</span><span class="p">]</span><span class="w">
</span><span class="p">(</span><span class="nf">clojure.string/replace</span><span class="w"> </span><span class="n">dna-string</span><span class="w"> </span><span class="sc">\T</span><span class="w"> </span><span class="sc">\U</span><span class="p">))</span><span class="w">
</span></pre></td>
<td class="code"><pre><span id="L1"><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">to-rna</span><span class="w">
</span><span id="L2"> </span><span class="p">[</span><span class="n">dna-string</span><span class="p">]</span><span class="w">
</span><span id="L3"> </span><span class="p">(</span><span class="nf">clojure.string/replace</span><span class="w"> </span><span class="n">dna-string</span><span class="w"> </span><span class="sc">\T</span><span class="w"> </span><span class="sc">\U</span><span class="p">))</span><span class="w">
</span><span id="L4"></span></span></pre></td>
</tr></tbody></table>
</div>}
assert_converts_to(input, expected)
Expand Down
4 changes: 2 additions & 2 deletions test/fixtures/approvals/markdown_double_braces.approved.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="highlight json">
<table style="border-spacing: 0;"><tbody><tr>
<td class="gutter gl" style="text-align: right;"><pre class="lineno">1</pre></td>
<td class="code"><pre><span class="p">{</span><span class="err">{x:</span><span class="w"> </span><span class="err">y</span><span class="p">}</span><span class="err">}</span><span class="w">
</span></pre></td>
<td class="code"><pre><span id="L1"><span class="p">{</span><span class="err">{x:</span><span class="w"> </span><span class="err">y</span><span class="p">}</span><span class="err">}</span><span class="w">
</span><span id="L2"></span></span></pre></td>
</tr></tbody></table>
</div>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="highlight plaintext">
<table style="border-spacing: 0;"><tbody><tr>
<td class="gutter gl" style="text-align: right;"><pre class="lineno">1</pre></td>
<td class="code"><pre>x{{current}}y
</pre></td>
<td class="code"><pre><span id="L1">x{{current}}y
</span></pre></td>
</tr></tbody></table>
</div>

0 comments on commit 605eb3f

Please sign in to comment.