選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

syntax_highlighting.rb 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. # frozen_string_literal: true
  2. # Redmine - project management software
  3. # Copyright (C) 2006- Jean-Philippe Lang
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU General Public License
  7. # as published by the Free Software Foundation; either version 2
  8. # of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. module Redmine
  19. module SyntaxHighlighting
  20. class << self
  21. attr_reader :highlighter
  22. def highlighter=(name)
  23. if name.is_a?(Module)
  24. @highlighter = name
  25. else
  26. @highlighter = const_get(name)
  27. end
  28. end
  29. def highlight_by_filename(text, filename)
  30. highlighter.highlight_by_filename(text, filename)
  31. rescue
  32. ERB::Util.h(text)
  33. end
  34. def highlight_by_language(text, language)
  35. highlighter.highlight_by_language(text, language)
  36. rescue
  37. ERB::Util.h(text)
  38. end
  39. def language_supported?(language)
  40. if highlighter.respond_to? :language_supported?
  41. highlighter.language_supported? language
  42. else
  43. true
  44. end
  45. rescue
  46. false
  47. end
  48. def filename_supported?(filename)
  49. if highlighter.respond_to? :filename_supported?
  50. highlighter.filename_supported? filename
  51. else
  52. false
  53. end
  54. end
  55. end
  56. module Rouge
  57. require 'rouge'
  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. super()
  63. @formatter = formatter
  64. end
  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
  74. class << self
  75. # Highlights +text+ as the content of +filename+
  76. # Should not return line numbers nor outer pre tag
  77. def highlight_by_filename(text, filename)
  78. # TODO: Delete the following workaround for #30434 and
  79. # test_syntax_highlight_should_normalize_line_endings in
  80. # application_helper_test.rb when Rouge is improved to
  81. # handle CRLF properly.
  82. # See also: https://github.com/jneen/rouge/pull/1078
  83. text = text.gsub(/\r\n?/, "\n")
  84. lexer =::Rouge::Lexer.guess(:source => text, :filename => filename)
  85. formatter = ::Rouge::Formatters::HTML.new
  86. ::Rouge.highlight(text, lexer, CustomHTMLLinewise.new(formatter))
  87. end
  88. # Highlights +text+ using +language+ syntax
  89. # Should not return outer pre tag
  90. def highlight_by_language(text, language)
  91. lexer =
  92. find_lexer(language.to_s.downcase) || ::Rouge::Lexers::PlainText
  93. ::Rouge.highlight(text, lexer, ::Rouge::Formatters::HTML)
  94. end
  95. def language_supported?(language)
  96. find_lexer(language.to_s.downcase) ? true : false
  97. end
  98. def filename_supported?(filename)
  99. !::Rouge::Lexer.guesses(:filename => filename).empty?
  100. end
  101. private
  102. # Alias names used by CodeRay and not supported by Rouge
  103. LANG_ALIASES = {
  104. 'delphi' => 'pascal',
  105. 'cplusplus' => 'cpp',
  106. 'ecmascript' => 'javascript',
  107. 'ecma_script' => 'javascript',
  108. 'java_script' => 'javascript',
  109. 'xhtml' => 'html'
  110. }
  111. def find_lexer(language)
  112. ::Rouge::Lexer.find(language) ||
  113. ::Rouge::Lexer.find(LANG_ALIASES[language])
  114. end
  115. end
  116. end
  117. end
  118. SyntaxHighlighting.highlighter = 'Rouge'
  119. end