@@ -1,27 +1,31 | |||
|
1 | 1 | <div class="contextual"> |
|
2 | 2 | <%= link_to(l(:label_page_index), {:action => 'special', :page => 'Page_index'}, :class => 'icon icon-index') %> |
|
3 | 3 | </div> |
|
4 | 4 | |
|
5 | 5 | <h2><%= @page.pretty_title %></h2> |
|
6 | 6 | |
|
7 | 7 | <% form_for :content, @content, :url => {:action => 'edit', :page => @page.title}, :html => {:id => 'wiki_form'} do |f| %> |
|
8 | 8 | <%= f.hidden_field :version %> |
|
9 | 9 | <%= error_messages_for 'content' %> |
|
10 | 10 | <div class="contextual"> |
|
11 | 11 | <%= l(:setting_text_formatting) %>: |
|
12 | 12 | <%= link_to l(:label_help), {:controller => 'help', :ctrl => 'wiki', :page => 'syntax' }, |
|
13 | 13 | :onclick => "window.open('#{ url_for :controller => 'help', :ctrl => 'wiki', :page => 'syntax' }', '', 'resizable=yes, location=no, width=300, height=500, menubar=no, status=no, scrollbars=yes'); return false;" %> |
|
14 | 14 | </div> |
|
15 | 15 | <p><%= f.text_area :text, :cols => 100, :rows => 25, :class => 'wiki-edit' %></p> |
|
16 | 16 | <p><label><%= l(:field_comments) %></label><br /><%= f.text_field :comments, :size => 120 %></p> |
|
17 | 17 | <p><%= submit_tag l(:button_save) %> |
|
18 | 18 | <%= link_to_remote l(:label_preview), |
|
19 | 19 | { :url => { :controller => 'wiki', :action => 'preview', :id => @project, :page => @page.title }, |
|
20 | 20 | :method => 'post', |
|
21 | 21 | :update => 'preview', |
|
22 | 22 | :with => "Form.serialize('wiki_form')" |
|
23 | 23 | } %></p> |
|
24 | 24 | <%= wikitoolbar_for 'content_text' %> |
|
25 | 25 | <% end %> |
|
26 | 26 | |
|
27 | 27 | <div id="preview" class="wiki"></div> |
|
28 | ||
|
29 | <% content_for :header_tags do %> | |
|
30 | <%= stylesheet_link_tag 'scm' %> | |
|
31 | <% end %> |
@@ -1,39 +1,43 | |||
|
1 | 1 | <div class="contextual"> |
|
2 | 2 | <%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :page => @page.title}, :class => 'icon icon-edit') if @content.version == @page.content.version %> |
|
3 | 3 | <%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :page => @page.title}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %> |
|
4 | 4 | <%= link_to_if_authorized(l(:button_rollback), {:action => 'edit', :page => @page.title, :version => @content.version }, :class => 'icon icon-cancel') if @content.version < @page.content.version %> |
|
5 | 5 | <%= link_to(l(:label_history), {:action => 'history', :page => @page.title}, :class => 'icon icon-history') %> |
|
6 | 6 | <%= link_to(l(:label_page_index), {:action => 'special', :page => 'Page_index'}, :class => 'icon icon-index') %> |
|
7 | 7 | </div> |
|
8 | 8 | |
|
9 | 9 | <% if @content.version != @page.content.version %> |
|
10 | 10 | <p> |
|
11 | 11 | <%= link_to(('« ' + l(:label_previous)), :action => 'index', :page => @page.title, :version => (@content.version - 1)) + " - " if @content.version > 1 %> |
|
12 | 12 | <%= "#{l(:label_version)} #{@content.version}/#{@page.content.version}" %> |
|
13 | 13 | <%= '(' + link_to('diff', :controller => 'wiki', :action => 'diff', :page => @page.title, :version => @content.version) + ')' if @content.version > 1 %> - |
|
14 | 14 | <%= link_to((l(:label_next) + ' »'), :action => 'index', :page => @page.title, :version => (@content.version + 1)) + " - " if @content.version < @page.content.version %> |
|
15 | 15 | <%= link_to(l(:label_current_version), :action => 'index', :page => @page.title) %> |
|
16 | 16 | <br /> |
|
17 | 17 | <em><%= @content.author ? @content.author.name : "anonyme" %>, <%= format_time(@content.updated_on) %> </em><br /> |
|
18 | 18 | <%=h @content.comments %> |
|
19 | 19 | </p> |
|
20 | 20 | <hr /> |
|
21 | 21 | <% end %> |
|
22 | 22 | |
|
23 | 23 | <%= render(:partial => "wiki/content", :locals => {:content => @content}) %> |
|
24 | 24 | |
|
25 | 25 | <%= link_to_attachments @page.attachments, :delete_url => (authorize_for('wiki', 'destroy_attachment') ? {:controller => 'wiki', :action => 'destroy_attachment', :page => @page.title} : nil) %> |
|
26 | 26 | |
|
27 | 27 | <div class="contextual"> |
|
28 | 28 | <%= l(:label_export_to) %> |
|
29 | 29 | <%= link_to 'HTML', {:export => 'html', :version => @content.version}, :class => 'icon icon-html' %>, |
|
30 | 30 | <%= link_to 'TXT', {:export => 'txt', :version => @content.version}, :class => 'icon icon-txt' %> |
|
31 | 31 | </div> |
|
32 | 32 | |
|
33 | 33 | <% if authorize_for('wiki', 'add_attachment') %> |
|
34 | 34 | <p><%= toggle_link l(:label_attachment_new), "add_attachment_form" %></p> |
|
35 | 35 | <% form_tag({ :controller => 'wiki', :action => 'add_attachment', :page => @page.title }, :multipart => true, :class => "tabular", :id => "add_attachment_form", :style => "display:none;") do %> |
|
36 | 36 | <%= render :partial => 'attachments/form' %> |
|
37 | 37 | <%= submit_tag l(:button_add) %> |
|
38 | 38 | <% end %> |
|
39 | 39 | <% end %> |
|
40 | ||
|
41 | <% content_for :header_tags do %> | |
|
42 | <%= stylesheet_link_tag 'scm' %> | |
|
43 | <% end %> |
@@ -1,79 +1,95 | |||
|
1 | 1 | require 'redcloth' |
|
2 | require 'coderay' | |
|
2 | 3 | |
|
3 | 4 | module Redmine |
|
4 | 5 | module WikiFormatting |
|
5 | 6 | |
|
6 | 7 | private |
|
7 | 8 | |
|
8 | 9 | class TextileFormatter < RedCloth |
|
9 | 10 | RULES = [:inline_auto_link, :inline_auto_mailto, :textile ] |
|
10 | 11 | |
|
11 | 12 | def initialize(*args) |
|
12 | 13 | super |
|
13 | 14 | self.hard_breaks=true |
|
14 | 15 | end |
|
15 | 16 | |
|
16 | 17 | def to_html |
|
17 | 18 | super(*RULES).to_s |
|
18 | 19 | end |
|
19 | 20 | |
|
20 | 21 | private |
|
21 | 22 | |
|
22 | 23 | # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet. |
|
23 | 24 | # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a> |
|
24 | 25 | def hard_break( text ) |
|
25 | 26 | text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks |
|
26 | 27 | end |
|
27 | 28 | |
|
29 | # Patch to add code highlighting support to RedCloth | |
|
30 | def smooth_offtags( text ) | |
|
31 | unless @pre_list.empty? | |
|
32 | ## replace <pre> content | |
|
33 | text.gsub!(/<redpre#(\d+)>/) do | |
|
34 | content = @pre_list[$1.to_i] | |
|
35 | if content.match(/<code\s+class="(\w+)">\s?(.+)/m) | |
|
36 | content = "<code class=\"#{$1} CodeRay\">" + | |
|
37 | CodeRay.scan($2, $1).html(:escape => false, :line_numbers => :inline) | |
|
38 | end | |
|
39 | content | |
|
40 | end | |
|
41 | end | |
|
42 | end | |
|
43 | ||
|
28 | 44 | AUTO_LINK_RE = %r{ |
|
29 | 45 | ( # leading text |
|
30 | 46 | <\w+.*?>| # leading HTML tag, or |
|
31 | 47 | [^=<>!:'"/]| # leading punctuation, or |
|
32 | 48 | ^ # beginning of line |
|
33 | 49 | ) |
|
34 | 50 | ( |
|
35 | 51 | (?:https?://)| # protocol spec, or |
|
36 | 52 | (?:www\.) # www.* |
|
37 | 53 | ) |
|
38 | 54 | ( |
|
39 | 55 | [-\w]+ # subdomain or domain |
|
40 | 56 | (?:\.[-\w]+)* # remaining subdomains or domain |
|
41 | 57 | (?::\d+)? # port |
|
42 | 58 | (?:/(?:(?:[~\w\+%-]|(?:[,.;:][^\s$]))+)?)* # path |
|
43 | 59 | (?:\?[\w\+%&=.;-]+)? # query string |
|
44 | 60 | (?:\#[\w\-]*)? # trailing anchor |
|
45 | 61 | ) |
|
46 | 62 | ([[:punct:]]|\s|<|$) # trailing text |
|
47 | 63 | }x unless const_defined?(:AUTO_LINK_RE) |
|
48 | 64 | |
|
49 | 65 | # Turns all urls into clickable links (code from Rails). |
|
50 | 66 | def inline_auto_link(text) |
|
51 | 67 | text.gsub!(AUTO_LINK_RE) do |
|
52 | 68 | all, a, b, c, d = $&, $1, $2, $3, $4 |
|
53 | 69 | if a =~ /<a\s/i || a =~ /![<>=]?/ |
|
54 | 70 | # don't replace URL's that are already linked |
|
55 | 71 | # and URL's prefixed with ! !> !< != (textile images) |
|
56 | 72 | all |
|
57 | 73 | else |
|
58 | 74 | text = b + c |
|
59 | 75 | %(#{a}<a href="#{b=="www."?"http://www.":b}#{c}">#{text}</a>#{d}) |
|
60 | 76 | end |
|
61 | 77 | end |
|
62 | 78 | end |
|
63 | 79 | |
|
64 | 80 | # Turns all email addresses into clickable links (code from Rails). |
|
65 | 81 | def inline_auto_mailto(text) |
|
66 | 82 | text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do |
|
67 | 83 | text = $1 |
|
68 | 84 | %{<a href="mailto:#{$1}" class="email">#{text}</a>} |
|
69 | 85 | end |
|
70 | 86 | end |
|
71 | 87 | end |
|
72 | 88 | |
|
73 | 89 | public |
|
74 | 90 | |
|
75 | 91 | def self.to_html(text, options = {}) |
|
76 | 92 | TextileFormatter.new(text).to_html |
|
77 | 93 | end |
|
78 | 94 | end |
|
79 | 95 | end |
@@ -1,123 +1,123 | |||
|
1 | 1 | |
|
2 | 2 | div.action_M { background: #fd8 } |
|
3 | 3 | div.action_D { background: #f88 } |
|
4 | 4 | div.action_A { background: #bfb } |
|
5 | 5 | |
|
6 | 6 | |
|
7 | 7 | tr.spacing { |
|
8 | 8 | border: 1px solid #d7d7d7; |
|
9 | 9 | } |
|
10 | 10 | |
|
11 | 11 | .line-num { |
|
12 | 12 | border: 1px solid #d7d7d7; |
|
13 | 13 | font-size: 0.8em; |
|
14 | 14 | text-align: right; |
|
15 | 15 | width: 3em; |
|
16 | 16 | padding-right: 3px; |
|
17 | 17 | } |
|
18 | 18 | |
|
19 | 19 | .line-code { |
|
20 | 20 | font-size: 1.4em; |
|
21 | 21 | } |
|
22 | 22 | |
|
23 | 23 | table.list thead th.list-filename { |
|
24 | 24 | background-color: #ddc; |
|
25 | 25 | font-weight: bolder; |
|
26 | 26 | text-align: left; |
|
27 | 27 | } |
|
28 | 28 | |
|
29 | 29 | |
|
30 | 30 | /************* Coderay styles *************/ |
|
31 | 31 | |
|
32 | .CodeRay { | |
|
32 | table.CodeRay { | |
|
33 | 33 | background-color: #fafafa; |
|
34 | 34 | } |
|
35 | 35 | .CodeRay pre { margin: 0px } |
|
36 | 36 | |
|
37 | 37 | span.CodeRay { white-space: pre; border: 0px; padding: 2px } |
|
38 | 38 | |
|
39 | 39 | .CodeRay .no { padding: 0px 4px } |
|
40 | 40 | .CodeRay .code { width: 100% } |
|
41 | 41 | |
|
42 | 42 | ol.CodeRay { font-size: 10pt } |
|
43 | 43 | ol.CodeRay li { white-space: pre } |
|
44 | 44 | |
|
45 | 45 | .CodeRay .code pre { overflow: auto } |
|
46 | 46 | |
|
47 | 47 | .CodeRay .debug { color:white ! important; background:blue ! important; } |
|
48 | 48 | |
|
49 | 49 | .CodeRay .af { color:#00C } |
|
50 | 50 | .CodeRay .an { color:#007 } |
|
51 | 51 | .CodeRay .av { color:#700 } |
|
52 | 52 | .CodeRay .aw { color:#C00 } |
|
53 | 53 | .CodeRay .bi { color:#509; font-weight:bold } |
|
54 | 54 | .CodeRay .c { color:#666; } |
|
55 | 55 | |
|
56 | 56 | .CodeRay .ch { color:#04D } |
|
57 | 57 | .CodeRay .ch .k { color:#04D } |
|
58 | 58 | .CodeRay .ch .dl { color:#039 } |
|
59 | 59 | |
|
60 | 60 | .CodeRay .cl { color:#B06; font-weight:bold } |
|
61 | 61 | .CodeRay .co { color:#036; font-weight:bold } |
|
62 | 62 | .CodeRay .cr { color:#0A0 } |
|
63 | 63 | .CodeRay .cv { color:#369 } |
|
64 | 64 | .CodeRay .df { color:#099; font-weight:bold } |
|
65 | 65 | .CodeRay .di { color:#088; font-weight:bold } |
|
66 | 66 | .CodeRay .dl { color:black } |
|
67 | 67 | .CodeRay .do { color:#970 } |
|
68 | 68 | .CodeRay .ds { color:#D42; font-weight:bold } |
|
69 | 69 | .CodeRay .e { color:#666; font-weight:bold } |
|
70 | 70 | .CodeRay .en { color:#800; font-weight:bold } |
|
71 | 71 | .CodeRay .er { color:#F00; background-color:#FAA } |
|
72 | 72 | .CodeRay .ex { color:#F00; font-weight:bold } |
|
73 | 73 | .CodeRay .fl { color:#60E; font-weight:bold } |
|
74 | 74 | .CodeRay .fu { color:#06B; font-weight:bold } |
|
75 | 75 | .CodeRay .gv { color:#d70; font-weight:bold } |
|
76 | 76 | .CodeRay .hx { color:#058; font-weight:bold } |
|
77 | 77 | .CodeRay .i { color:#00D; font-weight:bold } |
|
78 | 78 | .CodeRay .ic { color:#B44; font-weight:bold } |
|
79 | 79 | |
|
80 | 80 | .CodeRay .il { background: #eee } |
|
81 | 81 | .CodeRay .il .il { background: #ddd } |
|
82 | 82 | .CodeRay .il .il .il { background: #ccc } |
|
83 | 83 | .CodeRay .il .idl { font-weight: bold; color: #888 } |
|
84 | 84 | |
|
85 | 85 | .CodeRay .in { color:#B2B; font-weight:bold } |
|
86 | 86 | .CodeRay .iv { color:#33B } |
|
87 | 87 | .CodeRay .la { color:#970; font-weight:bold } |
|
88 | 88 | .CodeRay .lv { color:#963 } |
|
89 | 89 | .CodeRay .oc { color:#40E; font-weight:bold } |
|
90 | 90 | .CodeRay .of { color:#000; font-weight:bold } |
|
91 | 91 | .CodeRay .op { } |
|
92 | 92 | .CodeRay .pc { color:#038; font-weight:bold } |
|
93 | 93 | .CodeRay .pd { color:#369; font-weight:bold } |
|
94 | 94 | .CodeRay .pp { color:#579 } |
|
95 | 95 | .CodeRay .pt { color:#339; font-weight:bold } |
|
96 | 96 | .CodeRay .r { color:#080; font-weight:bold } |
|
97 | 97 | |
|
98 | 98 | .CodeRay .rx { background-color:#fff0ff } |
|
99 | 99 | .CodeRay .rx .k { color:#808 } |
|
100 | 100 | .CodeRay .rx .dl { color:#404 } |
|
101 | 101 | .CodeRay .rx .mod { color:#C2C } |
|
102 | 102 | .CodeRay .rx .fu { color:#404; font-weight: bold } |
|
103 | 103 | |
|
104 | 104 | .CodeRay .s { background-color:#fff0f0 } |
|
105 | 105 | .CodeRay .s .s { background-color:#ffe0e0 } |
|
106 | 106 | .CodeRay .s .s .s { background-color:#ffd0d0 } |
|
107 | 107 | .CodeRay .s .k { color:#D20 } |
|
108 | 108 | .CodeRay .s .dl { color:#710 } |
|
109 | 109 | |
|
110 | 110 | .CodeRay .sh { background-color:#f0fff0 } |
|
111 | 111 | .CodeRay .sh .k { color:#2B2 } |
|
112 | 112 | .CodeRay .sh .dl { color:#161 } |
|
113 | 113 | |
|
114 | 114 | .CodeRay .sy { color:#A60 } |
|
115 | 115 | .CodeRay .sy .k { color:#A60 } |
|
116 | 116 | .CodeRay .sy .dl { color:#630 } |
|
117 | 117 | |
|
118 | 118 | .CodeRay .ta { color:#070 } |
|
119 | 119 | .CodeRay .tf { color:#070; font-weight:bold } |
|
120 | 120 | .CodeRay .ts { color:#D70; font-weight:bold } |
|
121 | 121 | .CodeRay .ty { color:#339; font-weight:bold } |
|
122 | 122 | .CodeRay .v { color:#036 } |
|
123 | 123 | .CodeRay .xt { color:#444 } |
@@ -1,262 +1,268 | |||
|
1 | 1 | require "set" |
|
2 | 2 | |
|
3 | 3 | module CodeRay |
|
4 | 4 | module Encoders |
|
5 | 5 | |
|
6 | 6 | # = HTML Encoder |
|
7 | 7 | # |
|
8 | 8 | # This is CodeRay's most important highlighter: |
|
9 | 9 | # It provides save, fast XHTML generation and CSS support. |
|
10 | 10 | # |
|
11 | 11 | # == Usage |
|
12 | 12 | # |
|
13 | 13 | # require 'coderay' |
|
14 | 14 | # puts CodeRay.scan('Some /code/', :ruby).html #-> a HTML page |
|
15 | 15 | # puts CodeRay.scan('Some /code/', :ruby).html(:wrap => :span) |
|
16 | 16 | # #-> <span class="CodeRay"><span class="co">Some</span> /code/</span> |
|
17 | 17 | # puts CodeRay.scan('Some /code/', :ruby).span #-> the same |
|
18 | 18 | # |
|
19 | 19 | # puts CodeRay.scan('Some code', :ruby).html( |
|
20 | 20 | # :wrap => nil, |
|
21 | 21 | # :line_numbers => :inline, |
|
22 | 22 | # :css => :style |
|
23 | 23 | # ) |
|
24 | 24 | # #-> <span class="no">1</span> <span style="color:#036; font-weight:bold;">Some</span> code |
|
25 | 25 | # |
|
26 | 26 | # == Options |
|
27 | 27 | # |
|
28 | # === :escape | |
|
29 | # Escape html entities | |
|
30 | # Default: true | |
|
31 | # | |
|
28 | 32 | # === :tab_width |
|
29 | 33 | # Convert \t characters to +n+ spaces (a number.) |
|
30 | 34 | # Default: 8 |
|
31 | 35 | # |
|
32 | 36 | # === :css |
|
33 | 37 | # How to include the styles; can be :class or :style. |
|
34 | 38 | # |
|
35 | 39 | # Default: :class |
|
36 | 40 | # |
|
37 | 41 | # === :wrap |
|
38 | 42 | # Wrap in :page, :div, :span or nil. |
|
39 | 43 | # |
|
40 | 44 | # You can also use Encoders::Div and Encoders::Span. |
|
41 | 45 | # |
|
42 | 46 | # Default: nil |
|
43 | 47 | # |
|
44 | 48 | # === :line_numbers |
|
45 | 49 | # Include line numbers in :table, :inline, :list or nil (no line numbers) |
|
46 | 50 | # |
|
47 | 51 | # Default: nil |
|
48 | 52 | # |
|
49 | 53 | # === :line_number_start |
|
50 | 54 | # Where to start with line number counting. |
|
51 | 55 | # |
|
52 | 56 | # Default: 1 |
|
53 | 57 | # |
|
54 | 58 | # === :bold_every |
|
55 | 59 | # Make every +n+-th number appear bold. |
|
56 | 60 | # |
|
57 | 61 | # Default: 10 |
|
58 | 62 | # |
|
59 | 63 | # === :hint |
|
60 | 64 | # Include some information into the output using the title attribute. |
|
61 | 65 | # Can be :info (show token type on mouse-over), :info_long (with full path) |
|
62 | 66 | # or :debug (via inspect). |
|
63 | 67 | # |
|
64 | 68 | # Default: false |
|
65 | 69 | class HTML < Encoder |
|
66 | 70 | |
|
67 | 71 | include Streamable |
|
68 | 72 | register_for :html |
|
69 | 73 | |
|
70 | 74 | FILE_EXTENSION = 'html' |
|
71 | 75 | |
|
72 | 76 | DEFAULT_OPTIONS = { |
|
77 | :escape => true, | |
|
73 | 78 | :tab_width => 8, |
|
74 | 79 | |
|
75 | 80 | :level => :xhtml, |
|
76 | 81 | :css => :class, |
|
77 | 82 | |
|
78 | 83 | :style => :cycnus, |
|
79 | 84 | |
|
80 | 85 | :wrap => nil, |
|
81 | 86 | |
|
82 | 87 | :line_numbers => nil, |
|
83 | 88 | :line_number_start => 1, |
|
84 | 89 | :bold_every => 10, |
|
85 | 90 | |
|
86 | 91 | :hint => false, |
|
87 | 92 | } |
|
88 | 93 | |
|
89 | 94 | helper :output, :css |
|
90 | 95 | |
|
91 | 96 | attr_reader :css |
|
92 | 97 | |
|
93 | 98 | protected |
|
94 | 99 | |
|
95 | 100 | HTML_ESCAPE = { #:nodoc: |
|
96 | 101 | '&' => '&', |
|
97 | 102 | '"' => '"', |
|
98 | 103 | '>' => '>', |
|
99 | 104 | '<' => '<', |
|
100 | 105 | } |
|
101 | 106 | |
|
102 | 107 | # This was to prevent illegal HTML. |
|
103 | 108 | # Strange chars should still be avoided in codes. |
|
104 | 109 | evil_chars = Array(0x00...0x20) - [?\n, ?\t, ?\s] |
|
105 | 110 | evil_chars.each { |i| HTML_ESCAPE[i.chr] = ' ' } |
|
106 | 111 | #ansi_chars = Array(0x7f..0xff) |
|
107 | 112 | #ansi_chars.each { |i| HTML_ESCAPE[i.chr] = '&#%d;' % i } |
|
108 | 113 | # \x9 (\t) and \xA (\n) not included |
|
109 | 114 | #HTML_ESCAPE_PATTERN = /[\t&"><\0-\x8\xB-\x1f\x7f-\xff]/ |
|
110 | 115 | HTML_ESCAPE_PATTERN = /[\t"&><\0-\x8\xB-\x1f]/ |
|
111 | 116 | |
|
112 | 117 | TOKEN_KIND_TO_INFO = Hash.new { |h, kind| |
|
113 | 118 | h[kind] = |
|
114 | 119 | case kind |
|
115 | 120 | when :pre_constant |
|
116 | 121 | 'Predefined constant' |
|
117 | 122 | else |
|
118 | 123 | kind.to_s.gsub(/_/, ' ').gsub(/\b\w/) { $&.capitalize } |
|
119 | 124 | end |
|
120 | 125 | } |
|
121 | 126 | |
|
122 | 127 | TRANSPARENT_TOKEN_KINDS = [ |
|
123 | 128 | :delimiter, :modifier, :content, :escape, :inline_delimiter, |
|
124 | 129 | ].to_set |
|
125 | 130 | |
|
126 | 131 | # Generate a hint about the given +classes+ in a +hint+ style. |
|
127 | 132 | # |
|
128 | 133 | # +hint+ may be :info, :info_long or :debug. |
|
129 | 134 | def self.token_path_to_hint hint, classes |
|
130 | 135 | title = |
|
131 | 136 | case hint |
|
132 | 137 | when :info |
|
133 | 138 | TOKEN_KIND_TO_INFO[classes.first] |
|
134 | 139 | when :info_long |
|
135 | 140 | classes.reverse.map { |kind| TOKEN_KIND_TO_INFO[kind] }.join('/') |
|
136 | 141 | when :debug |
|
137 | 142 | classes.inspect |
|
138 | 143 | end |
|
139 | 144 | " title=\"#{title}\"" |
|
140 | 145 | end |
|
141 | 146 | |
|
142 | 147 | def setup options |
|
143 | 148 | super |
|
144 | 149 | |
|
145 | 150 | @HTML_ESCAPE = HTML_ESCAPE.dup |
|
146 | 151 | @HTML_ESCAPE["\t"] = ' ' * options[:tab_width] |
|
147 | 152 | |
|
153 | @escape = options[:escape] | |
|
148 | 154 | @opened = [nil] |
|
149 | 155 | @css = CSS.new options[:style] |
|
150 | 156 | |
|
151 | 157 | hint = options[:hint] |
|
152 | 158 | if hint and not [:debug, :info, :info_long].include? hint |
|
153 | 159 | raise ArgumentError, "Unknown value %p for :hint; \ |
|
154 | 160 | expected :info, :debug, false, or nil." % hint |
|
155 | 161 | end |
|
156 | 162 | |
|
157 | 163 | case options[:css] |
|
158 | 164 | |
|
159 | 165 | when :class |
|
160 | 166 | @css_style = Hash.new do |h, k| |
|
161 | 167 | c = Tokens::ClassOfKind[k.first] |
|
162 | 168 | if c == :NO_HIGHLIGHT and not hint |
|
163 | 169 | h[k.dup] = false |
|
164 | 170 | else |
|
165 | 171 | title = if hint |
|
166 | 172 | HTML.token_path_to_hint(hint, k[1..-1] << k.first) |
|
167 | 173 | else |
|
168 | 174 | '' |
|
169 | 175 | end |
|
170 | 176 | if c == :NO_HIGHLIGHT |
|
171 | 177 | h[k.dup] = '<span%s>' % [title] |
|
172 | 178 | else |
|
173 | 179 | h[k.dup] = '<span%s class="%s">' % [title, c] |
|
174 | 180 | end |
|
175 | 181 | end |
|
176 | 182 | end |
|
177 | 183 | |
|
178 | 184 | when :style |
|
179 | 185 | @css_style = Hash.new do |h, k| |
|
180 | 186 | if k.is_a? ::Array |
|
181 | 187 | styles = k.dup |
|
182 | 188 | else |
|
183 | 189 | styles = [k] |
|
184 | 190 | end |
|
185 | 191 | type = styles.first |
|
186 | 192 | classes = styles.map { |c| Tokens::ClassOfKind[c] } |
|
187 | 193 | if classes.first == :NO_HIGHLIGHT and not hint |
|
188 | 194 | h[k] = false |
|
189 | 195 | else |
|
190 | 196 | styles.shift if TRANSPARENT_TOKEN_KINDS.include? styles.first |
|
191 | 197 | title = HTML.token_path_to_hint hint, styles |
|
192 | 198 | style = @css[*classes] |
|
193 | 199 | h[k] = |
|
194 | 200 | if style |
|
195 | 201 | '<span%s style="%s">' % [title, style] |
|
196 | 202 | else |
|
197 | 203 | false |
|
198 | 204 | end |
|
199 | 205 | end |
|
200 | 206 | end |
|
201 | 207 | |
|
202 | 208 | else |
|
203 | 209 | raise ArgumentError, "Unknown value %p for :css." % options[:css] |
|
204 | 210 | |
|
205 | 211 | end |
|
206 | 212 | end |
|
207 | 213 | |
|
208 | 214 | def finish options |
|
209 | 215 | not_needed = @opened.shift |
|
210 | 216 | @out << '</span>' * @opened.size |
|
211 | 217 | unless @opened.empty? |
|
212 | 218 | warn '%d tokens still open: %p' % [@opened.size, @opened] |
|
213 | 219 | end |
|
214 | 220 | |
|
215 | 221 | @out.extend Output |
|
216 | 222 | @out.css = @css |
|
217 | 223 | @out.numerize! options[:line_numbers], options |
|
218 | 224 | @out.wrap! options[:wrap] |
|
219 | 225 | |
|
220 | 226 | super |
|
221 | 227 | end |
|
222 | 228 | |
|
223 | 229 | def token text, type |
|
224 | 230 | if text.is_a? ::String |
|
225 | if text =~ /#{HTML_ESCAPE_PATTERN}/o | |
|
231 | if @escape && (text =~ /#{HTML_ESCAPE_PATTERN}/o) | |
|
226 | 232 | text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] } |
|
227 | 233 | end |
|
228 | 234 | @opened[0] = type |
|
229 | 235 | if style = @css_style[@opened] |
|
230 | 236 | @out << style << text << '</span>' |
|
231 | 237 | else |
|
232 | 238 | @out << text |
|
233 | 239 | end |
|
234 | 240 | else |
|
235 | 241 | case text |
|
236 | 242 | when :open |
|
237 | 243 | @opened[0] = type |
|
238 | 244 | @out << (@css_style[@opened] || '<span>') |
|
239 | 245 | @opened << type |
|
240 | 246 | when :close |
|
241 | 247 | if @opened.empty? |
|
242 | 248 | # nothing to close |
|
243 | 249 | else |
|
244 | 250 | if $DEBUG and (@opened.size == 1 or @opened.last != type) |
|
245 | 251 | raise 'Malformed token stream: Trying to close a token (%p) \ |
|
246 | 252 | that is not open. Open are: %p.' % [type, @opened[1..-1]] |
|
247 | 253 | end |
|
248 | 254 | @out << '</span>' |
|
249 | 255 | @opened.pop |
|
250 | 256 | end |
|
251 | 257 | when nil |
|
252 | 258 | raise 'Token with nil as text was given: %p' % [[text, type]] |
|
253 | 259 | else |
|
254 | 260 | raise 'unknown token kind: %p' % text |
|
255 | 261 | end |
|
256 | 262 | end |
|
257 | 263 | end |
|
258 | 264 | |
|
259 | 265 | end |
|
260 | 266 | |
|
261 | 267 | end |
|
262 | 268 | end |
General Comments 0
You need to be logged in to leave comments.
Login now