Project

General

Profile

Feature #24681 » 0001-Switch-syntax-highlighter-to-Rouge-from-CodeRay.patch

Go MAEDA, 2018-09-27 12:31

View differences:

Gemfile
5 5
end
6 6

  
7 7
gem "rails", "5.2.1"
8
gem "coderay", "~> 1.1.1"
8
gem "rouge", "~> 3.2.1"
9 9
gem "request_store", "1.0.5"
10 10
gem "mini_mime", "~> 1.0.1"
11 11
gem "actionpack-xml_parser"
lib/redmine/syntax_highlighting.rb
52 52
      end
53 53
    end
54 54

  
55
    module CodeRay
56
      require 'coderay'
55
    module Rouge
56
      require 'rouge'
57 57

  
58
      def self.retrieve_supported_languages
59
        ::CodeRay::Scanners.list +
60
        # Add CodeRay scanner aliases
61
        ::CodeRay::Scanners.plugin_hash.keys.map(&:to_sym) -
62
        # Remove internal CodeRay scanners
63
        %w(debug default raydebug scanner).map(&:to_sym)
64
      end
65
      private_class_method :retrieve_supported_languages
58
      # Customized formatter based on Rouge::Formatters::HTMLLinewise
59
      # Syntax highlighting is completed within each line.
60
      class CustomHTMLLinewise < ::Rouge::Formatter
61
        def initialize(formatter)
62
          @formatter = formatter
63
        end
66 64

  
67
      SUPPORTED_LANGUAGES = retrieve_supported_languages
65
        def stream(tokens, &b)
66
          token_lines(tokens) do |line|
67
            line.each do |tok, val|
68
              yield @formatter.span(tok, val)
69
            end
70
            yield "\n"
71
          end
72
        end
73
      end
68 74

  
69 75
      class << self
70 76
        # Highlights +text+ as the content of +filename+
71 77
        # Should not return line numbers nor outer pre tag
72 78
        def highlight_by_filename(text, filename)
73
          language = ::CodeRay::FileType[filename]
74
          language ? ::CodeRay.scan(text, language).html(:break_lines => true) : ERB::Util.h(text)
79
          lexer =::Rouge::Lexer.guess_by_filename(filename)
80
          formatter = ::Rouge::Formatters::HTML.new
81
          ::Rouge.highlight(text, lexer, CustomHTMLLinewise.new(formatter))
75 82
        end
76 83

  
77 84
        # Highlights +text+ using +language+ syntax
78 85
        # Should not return outer pre tag
79 86
        def highlight_by_language(text, language)
80
          ::CodeRay.scan(text, language).html(:wrap => :span)
87
          lexer =
88
            find_lexer(language.to_s.downcase) || ::Rouge::Lexers::PlainText
89
          ::Rouge.highlight(text, lexer, ::Rouge::Formatters::HTML)
81 90
        end
82 91

  
83 92
        def language_supported?(language)
84
          SUPPORTED_LANGUAGES.include?(language.to_s.downcase.to_sym)
85
        rescue
86
          false
93
          find_lexer(language.to_s.downcase) ? true : false
94
        end
95
        
96
        private
97
        # Alias names used by CodeRay and not supported by Rouge
98
        LANG_ALIASES = {
99
          'delphi' => 'pascal',
100
          'cplusplus' => 'cpp',
101
          'ecmascript' => 'javascript',
102
          'ecma_script' => 'javascript',
103
          'java_script' => 'javascript',
104
          'xhtml' => 'html'
105
        }
106

  
107
        def find_lexer(language)
108
          ::Rouge::Lexer.find(language) ||
109
            ::Rouge::Lexer.find(LANG_ALIASES[language])
87 110
        end
88 111
      end
89 112
    end
90 113
  end
91 114

  
92
  SyntaxHighlighting.highlighter = 'CodeRay'
115
  SyntaxHighlighting.highlighter = 'Rouge'
93 116
end
lib/redmine/wiki_formatting/textile/formatter.rb
125 125
                language = $1
126 126
                text = $2
127 127
                if Redmine::SyntaxHighlighting.language_supported?(language)
128
                  text.gsub!(/x%x%/, '&')
128 129
                  content = "<code class=\"#{language} syntaxhl\">" +
129 130
                    Redmine::SyntaxHighlighting.highlight_by_language(text, language)
130 131
                else
public/javascripts/jstoolbar/jstoolbar.js
453 453

  
454 454
/* Code highlighting menu */
455 455
jsToolBar.prototype.precodeMenu = function(fn){
456
  var codeRayLanguages = ["c", "clojure", "cpp", "css", "delphi", "diff", "erb", "go", "groovy", "haml", "html", "java", "javascript", "json", "lua", "php", "python", "ruby", "sass", "sql", "taskpaper", "text", "xml", "yaml"];
456
  var hlLanguages = ["c", "clojure", "cpp", "css", "diff", "erb", "go", "groovy", "haml", "html", "java", "javascript", "json", "lua", "pascal", "php", "python", "ruby", "sass", "sql", "text", "xml", "yaml"];
457 457
  var menu = $("<ul style='position:absolute;'></ul>");
458
  for (var i = 0; i < codeRayLanguages.length; i++) {
459
    $("<li></li>").text(codeRayLanguages[i]).appendTo(menu).mousedown(function(){
458
  for (var i = 0; i < hlLanguages.length; i++) {
459
    $("<li></li>").text(hlLanguages[i]).appendTo(menu).mousedown(function(){
460 460
      fn($(this).text());
461 461
    });
462 462
  }
public/stylesheets/application.css
1407 1407
.ui-datepicker-title select {width:70px !important; margin-top:-2px !important; margin-right:4px !important;}
1408 1408

  
1409 1409

  
1410
/************* CodeRay styles *************/
1411
.syntaxhl div {display: inline;}
1412
.syntaxhl .code pre { overflow: auto }
1413

  
1414
.syntaxhl .annotation { color:#007 }
1415
.syntaxhl .attribute-name { color:#b48 }
1416
.syntaxhl .attribute-value { color:#700 }
1417
.syntaxhl .binary { color:#549 }
1418
.syntaxhl .binary .char { color:#325 }
1419
.syntaxhl .binary .delimiter { color:#325 }
1420
.syntaxhl .char { color:#D20 }
1421
.syntaxhl .char .content { color:#D20 }
1422
.syntaxhl .char .delimiter { color:#710 }
1423
.syntaxhl .class { color:#B06; font-weight:bold }
1424
.syntaxhl .class-variable { color:#369 }
1425
.syntaxhl .color { color:#0A0 }
1426
.syntaxhl .comment { color:#777 }
1427
.syntaxhl .comment .char { color:#444 }
1428
.syntaxhl .comment .delimiter { color:#444 }
1429
.syntaxhl .constant { color:#036; font-weight:bold }
1430
.syntaxhl .decorator { color:#B0B }
1431
.syntaxhl .definition { color:#099; font-weight:bold }
1432
.syntaxhl .delimiter { color:black }
1433
.syntaxhl .directive { color:#088; font-weight:bold }
1434
.syntaxhl .docstring { color:#D42; }
1435
.syntaxhl .doctype { color:#34b }
1436
.syntaxhl .done { text-decoration: line-through; color: gray }
1437
.syntaxhl .entity { color:#800; font-weight:bold }
1438
.syntaxhl .error { color:#F00; background-color:#FAA }
1439
.syntaxhl .escape  { color:#666 }
1440
.syntaxhl .exception { color:#C00; font-weight:bold }
1441
.syntaxhl .float { color:#60E }
1442
.syntaxhl .function { color:#06B; font-weight:bold }
1443
.syntaxhl .function .delimiter { color:#059 }
1444
.syntaxhl .function .content { color:#037 }
1445
.syntaxhl .global-variable { color:#d70 }
1446
.syntaxhl .hex { color:#02b }
1447
.syntaxhl .id  { color:#33D; font-weight:bold }
1448
.syntaxhl .include { color:#B44; font-weight:bold }
1449
.syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black }
1450
.syntaxhl .inline-delimiter { font-weight: bold; color: #666 }
1451
.syntaxhl .instance-variable { color:#33B }
1452
.syntaxhl .integer  { color:#00D }
1453
.syntaxhl .imaginary { color:#f00 }
1454
.syntaxhl .important { color:#D00 }
1455
.syntaxhl .key { color: #606 }
1456
.syntaxhl .key .char { color: #60f }
1457
.syntaxhl .key .delimiter { color: #404 }
1458
.syntaxhl .keyword { color:#080; font-weight:bold }
1459
.syntaxhl .label { color:#970; font-weight:bold }
1460
.syntaxhl .local-variable { color:#950 }
1461
.syntaxhl .map .content { color:#808 }
1462
.syntaxhl .map .delimiter { color:#40A}
1463
.syntaxhl .map { background-color:hsla(200,100%,50%,0.06); }
1464
.syntaxhl .namespace { color:#707; font-weight:bold }
1465
.syntaxhl .octal { color:#40E }
1466
.syntaxhl .operator { }
1467
.syntaxhl .predefined { color:#369; font-weight:bold }
1468
.syntaxhl .predefined-constant { color:#069 }
1469
.syntaxhl .predefined-type { color:#0a8; font-weight:bold }
1470
.syntaxhl .preprocessor { color:#579 }
1471
.syntaxhl .pseudo-class { color:#00C; font-weight:bold }
1472
.syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); }
1473
.syntaxhl .regexp .content { color:#808 }
1474
.syntaxhl .regexp .delimiter { color:#404 }
1475
.syntaxhl .regexp .modifier { color:#C2C }
1476
.syntaxhl .reserved { color:#080; font-weight:bold }
1477
.syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); }
1478
.syntaxhl .shell .content { color:#2B2 }
1479
.syntaxhl .shell .delimiter { color:#161 }
1480
.syntaxhl .string { background-color:hsla(0,100%,50%,0.05); }
1481
.syntaxhl .string .char { color: #b0b }
1482
.syntaxhl .string .content { color: #D20 }
1483
.syntaxhl .string .delimiter { color: #710 }
1484
.syntaxhl .string .modifier { color: #E40 }
1485
.syntaxhl .symbol { color:#A60 }
1486
.syntaxhl .symbol .content { color:#A60 }
1487
.syntaxhl .symbol .delimiter { color:#740 }
1488
.syntaxhl .tag { color:#070; font-weight:bold }
1489
.syntaxhl .type { color:#339; font-weight:bold }
1490
.syntaxhl .value { color: #088 }
1491
.syntaxhl .variable { color:#037 }
1492

  
1493
.syntaxhl .insert { background: hsla(120,100%,50%,0.12) }
1494
.syntaxhl .delete { background: hsla(0,100%,50%,0.12) }
1495
.syntaxhl .change { color: #bbf; background: #007 }
1496
.syntaxhl .head { color: #f8f; background: #505 }
1497
.syntaxhl .head .filename { color: white; }
1498

  
1499
.syntaxhl .delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; }
1500
.syntaxhl .insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }
1501

  
1502
.syntaxhl .insert .insert { color: #0c0; background:transparent; font-weight:bold }
1503
.syntaxhl .delete .delete { color: #c00; background:transparent; font-weight:bold }
1504
.syntaxhl .change .change { color: #88f }
1505
.syntaxhl .head .head { color: #f4f }
1410
/************* Rouge styles *************/
1411
/* generated by: pygmentize -f html -a .syntaxhl -S colorful */
1412
.syntaxhl .hll { background-color: #ffffcc }
1413
.syntaxhl  { background: #fafafa; }
1414
.syntaxhl .c { color: #888888 } /* Comment */
1415
.syntaxhl .err { color: #FF0000; background-color: #FFAAAA } /* Error */
1416
.syntaxhl .k { color: #008800; font-weight: bold } /* Keyword */
1417
.syntaxhl .o { color: #333333 } /* Operator */
1418
.syntaxhl .ch { color: #888888 } /* Comment.Hashbang */
1419
.syntaxhl .cm { color: #888888 } /* Comment.Multiline */
1420
.syntaxhl .cp { color: #557799 } /* Comment.Preproc */
1421
.syntaxhl .cpf { color: #888888 } /* Comment.PreprocFile */
1422
.syntaxhl .c1 { color: #888888 } /* Comment.Single */
1423
.syntaxhl .cs { color: #cc0000; font-weight: bold } /* Comment.Special */
1424
.syntaxhl .gd { color: #A00000 } /* Generic.Deleted */
1425
.syntaxhl .ge { font-style: italic } /* Generic.Emph */
1426
.syntaxhl .gr { color: #FF0000 } /* Generic.Error */
1427
.syntaxhl .gh { color: #000080; font-weight: bold } /* Generic.Heading */
1428
.syntaxhl .gi { color: #00A000 } /* Generic.Inserted */
1429
.syntaxhl .go { color: #888888 } /* Generic.Output */
1430
.syntaxhl .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
1431
.syntaxhl .gs { font-weight: bold } /* Generic.Strong */
1432
.syntaxhl .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
1433
.syntaxhl .gt { color: #0044DD } /* Generic.Traceback */
1434
.syntaxhl .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
1435
.syntaxhl .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
1436
.syntaxhl .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
1437
.syntaxhl .kp { color: #003388; font-weight: bold } /* Keyword.Pseudo */
1438
.syntaxhl .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
1439
.syntaxhl .kt { color: #333399; font-weight: bold } /* Keyword.Type */
1440
.syntaxhl .m { color: #6600EE; font-weight: bold } /* Literal.Number */
1441
.syntaxhl .s { background-color: #fff0f0 } /* Literal.String */
1442
.syntaxhl .na { color: #0000CC } /* Name.Attribute */
1443
.syntaxhl .nb { color: #007020 } /* Name.Builtin */
1444
.syntaxhl .nc { color: #BB0066; font-weight: bold } /* Name.Class */
1445
.syntaxhl .no { color: #003366; font-weight: bold } /* Name.Constant */
1446
.syntaxhl .nd { color: #555555; font-weight: bold } /* Name.Decorator */
1447
.syntaxhl .ni { color: #880000; font-weight: bold } /* Name.Entity */
1448
.syntaxhl .ne { color: #FF0000; font-weight: bold } /* Name.Exception */
1449
.syntaxhl .nf { color: #0066BB; font-weight: bold } /* Name.Function */
1450
.syntaxhl .nl { color: #997700; font-weight: bold } /* Name.Label */
1451
.syntaxhl .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
1452
.syntaxhl .nt { color: #007700 } /* Name.Tag */
1453
.syntaxhl .nv { color: #996633 } /* Name.Variable */
1454
.syntaxhl .ow { color: #000000; font-weight: bold } /* Operator.Word */
1455
.syntaxhl .w { color: #bbbbbb } /* Text.Whitespace */
1456
.syntaxhl .mb { color: #6600EE; font-weight: bold } /* Literal.Number.Bin */
1457
.syntaxhl .mf { color: #6600EE; font-weight: bold } /* Literal.Number.Float */
1458
.syntaxhl .mh { color: #005588; font-weight: bold } /* Literal.Number.Hex */
1459
.syntaxhl .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
1460
.syntaxhl .mo { color: #4400EE; font-weight: bold } /* Literal.Number.Oct */
1461
.syntaxhl .sa { background-color: #fff0f0 } /* Literal.String.Affix */
1462
.syntaxhl .sb { background-color: #fff0f0 } /* Literal.String.Backtick */
1463
.syntaxhl .sc { color: #0044DD } /* Literal.String.Char */
1464
.syntaxhl .dl { background-color: #fff0f0 } /* Literal.String.Delimiter */
1465
.syntaxhl .sd { color: #DD4422 } /* Literal.String.Doc */
1466
.syntaxhl .s2 { background-color: #fff0f0 } /* Literal.String.Double */
1467
.syntaxhl .se { color: #666666; font-weight: bold; background-color: #fff0f0 } /* Literal.String.Escape */
1468
.syntaxhl .sh { background-color: #fff0f0 } /* Literal.String.Heredoc */
1469
.syntaxhl .si { background-color: #eeeeee } /* Literal.String.Interpol */
1470
.syntaxhl .sx { color: #DD2200; background-color: #fff0f0 } /* Literal.String.Other */
1471
.syntaxhl .sr { color: #000000; background-color: #fff0ff } /* Literal.String.Regex */
1472
.syntaxhl .s1 { background-color: #fff0f0 } /* Literal.String.Single */
1473
.syntaxhl .ss { color: #AA6600 } /* Literal.String.Symbol */
1474
.syntaxhl .bp { color: #007020 } /* Name.Builtin.Pseudo */
1475
.syntaxhl .fm { color: #0066BB; font-weight: bold } /* Name.Function.Magic */
1476
.syntaxhl .vc { color: #336699 } /* Name.Variable.Class */
1477
.syntaxhl .vg { color: #dd7700; font-weight: bold } /* Name.Variable.Global */
1478
.syntaxhl .vi { color: #3333BB } /* Name.Variable.Instance */
1479
.syntaxhl .vm { color: #996633 } /* Name.Variable.Magic */
1480
.syntaxhl .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
1506 1481

  
1507 1482
/***** Media print specific styles *****/
1508 1483
@media print {
public/stylesheets/rtl.css
373 373
/* Custom JQuery styles */
374 374
.ui-datepicker-title select {margin-left:4px !important; margin-right:0 !important;}
375 375

  
376
/************* CodeRay styles *************/
377
.syntaxhl .line-numbers {margin:0px 0px 0px 5px;}
378

  
379 376
/***** Media print specific styles *****/
380 377
@media print {
381 378
}
test/helpers/application_helper_test.rb
1094 1094

  
1095 1095
  def test_syntax_highlight
1096 1096
    raw = <<-RAW
1097
<pre><code class="ruby">
1098
# Some ruby code here
1097
<pre><code class="ECMA_script">
1098
/* Hello */
1099
document.write("Hello World!");
1099 1100
</code></pre>
1100 1101
RAW
1101 1102

  
1102 1103
    expected = <<-EXPECTED
1103
<pre><code class="ruby syntaxhl"><span class=\"CodeRay\"><span class="comment"># Some ruby code here</span></span>
1104
</code></pre>
1104
<pre><code class=\"ECMA_script syntaxhl\"><span class=\"cm\">/* Hello */</span><span class=\"nb\">document</span><span class=\"p\">.</span><span class=\"nx\">write</span><span class=\"p\">(</span><span class=\"s2\">\"Hello World!\"</span><span class=\"p\">);</span></code></pre>
1105 1105
EXPECTED
1106 1106

  
1107 1107
    assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
1108 1108
  end
1109 1109

  
1110
  def test_syntax_highlight_ampersand_in_textile
1111
    raw = <<-RAW
1112
<pre><code class="ruby">
1113
x = a & b
1114
</code></pre>
1115
RAW
1116

  
1117
    expected = <<-EXPECTED
1118
<pre><code class=\"ruby syntaxhl\"><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">&amp;</span> <span class=\"n\">b</span></code></pre>
1119
EXPECTED
1120

  
1121
    with_settings :text_formatting => 'textile' do
1122
      assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
1123
    end
1124
  end
1125

  
1110 1126
  def test_to_path_param
1111 1127
    assert_equal 'test1/test2', to_path_param('test1/test2')
1112 1128
    assert_equal 'test1/test2', to_path_param('/test1/test2/')
test/unit/lib/redmine/syntax_highlighting/coderay_test.rb
1
# Redmine - project management software
2
# Copyright (C) 2006-2017  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.expand_path('../../../../../test_helper', __FILE__)
19

  
20
class Redmine::SyntaxHighlighting::CodeRayTest < ActiveSupport::TestCase
21
  def test_retrieve_supported_languages_should_return_array_of_symbols
22
    assert_kind_of Array, Redmine::SyntaxHighlighting::CodeRay.send(:retrieve_supported_languages)
23
    assert_kind_of Symbol, Redmine::SyntaxHighlighting::CodeRay.send(:retrieve_supported_languages).first
24
  end
25

  
26
  def test_retrieve_supported_languages_should_return_array_of_symbols_holding_languages
27
    assert_includes Redmine::SyntaxHighlighting::CodeRay.send(:retrieve_supported_languages), :ruby
28
  end
29

  
30
  def test_retrieve_supported_languages_should_return_array_of_symbols_holding_languages_aliases
31
    assert_includes Redmine::SyntaxHighlighting::CodeRay.send(:retrieve_supported_languages), :javascript
32
  end
33

  
34
  def test_retrieve_supported_languages_should_return_array_of_symbols_not_holding_internal_languages
35
    refute_includes Redmine::SyntaxHighlighting::CodeRay.send(:retrieve_supported_languages), :default
36
  end
37
end
test/unit/lib/redmine/wiki_formatting/markdown_formatter_test.rb
66 66
~~~
67 67
STR
68 68
    assert_select_in @formatter.new(text).to_html, 'pre code.ruby.syntaxhl' do
69
      assert_select 'span.keyword', :text => 'def'
69
      assert_select 'span.k', :text => 'def'
70 70
    end
71 71
  end
72 72

  
test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb
547 547

  
548 548
  def test_should_allow_valid_language_class_attribute_on_code_tags
549 549
    # language name is double-quoted
550
    assert_html_output({"<code class=\"ruby\">test</code>" => "<code class=\"ruby syntaxhl\"><span class=\"CodeRay\">test</span></code>"}, false)
550
    assert_html_output({"<code class=\"ruby\">test</code>" => "<code class=\"ruby syntaxhl\"><span class=\"nb\">test</span></code>"}, false)
551 551
    # language name is single-quoted
552
    assert_html_output({"<code class='ruby'>test</code>" => "<code class=\"ruby syntaxhl\"><span class=\"CodeRay\">test</span></code>"}, false)
552
    assert_html_output({"<code class='ruby'>test</code>" => "<code class=\"ruby syntaxhl\"><span class=\"nb\">test</span></code>"}, false)
553 553
  end
554 554

  
555 555
  def test_should_not_allow_valid_language_class_attribute_on_non_code_offtags
(11-11/11)