gollum-lib 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of gollum-lib might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Rakefile +4 -1
- data/gollum-lib.gemspec +31 -30
- data/lib/gollum-lib.rb +8 -8
- data/lib/gollum-lib/blob_entry.rb +5 -5
- data/lib/gollum-lib/committer.rb +11 -11
- data/lib/gollum-lib/file.rb +10 -9
- data/lib/gollum-lib/file_view.rb +33 -33
- data/lib/gollum-lib/filter.rb +3 -3
- data/lib/gollum-lib/filter/code.rb +30 -18
- data/lib/gollum-lib/filter/metadata.rb +5 -3
- data/lib/gollum-lib/filter/plain_text.rb +4 -3
- data/lib/gollum-lib/filter/remote_code.rb +20 -18
- data/lib/gollum-lib/filter/render.rb +4 -2
- data/lib/gollum-lib/filter/sanitize.rb +4 -2
- data/lib/gollum-lib/filter/tags.rb +36 -35
- data/lib/gollum-lib/filter/toc.rb +29 -13
- data/lib/gollum-lib/filter/wsd.rb +1 -1
- data/lib/gollum-lib/git_access.rb +11 -11
- data/lib/gollum-lib/gitcode.rb +13 -13
- data/lib/gollum-lib/grit_ext.rb +1 -1
- data/lib/gollum-lib/helpers.rb +2 -2
- data/lib/gollum-lib/markup.rb +81 -42
- data/lib/gollum-lib/markups.rb +1 -1
- data/lib/gollum-lib/page.rb +15 -15
- data/lib/gollum-lib/pagination.rb +1 -1
- data/lib/gollum-lib/sanitization.rb +74 -74
- data/lib/gollum-lib/wiki.rb +54 -54
- metadata +111 -103
@@ -28,20 +28,20 @@ class Gollum::Filter::Code < Gollum::Filter
|
|
28
28
|
lang = lang[1] unless lang.nil?
|
29
29
|
end
|
30
30
|
|
31
|
-
@map[id] = cached
|
32
|
-
|
33
|
-
|
31
|
+
@map[id] = cached ?
|
32
|
+
{ :output => cached } :
|
33
|
+
{ :lang => lang, :code => m_code, :indent => m_indent }
|
34
34
|
|
35
35
|
"#{m_indent}#{id}" # print the SHA1 ID with the proper indentation
|
36
36
|
end
|
37
37
|
|
38
38
|
data.gsub!(/^([ \t]*)``` ?([^\r\n]+)?\r?\n(.+?)\r?\n\1```[ \t]*\r?$/m) do
|
39
|
-
lang
|
40
|
-
id
|
41
|
-
cached
|
42
|
-
@map[id] = cached
|
43
|
-
|
44
|
-
|
39
|
+
lang = $2 ? $2.strip : nil
|
40
|
+
id = Digest::SHA1.hexdigest("#{lang}.#{$3}")
|
41
|
+
cached = @markup.check_cache(:code, id)
|
42
|
+
@map[id] = cached ?
|
43
|
+
{ :output => cached } :
|
44
|
+
{ :lang => lang, :code => $3, :indent => $1 }
|
45
45
|
"#{$1}#{id}" # print the SHA1 ID with the proper indentation
|
46
46
|
end
|
47
47
|
|
@@ -74,18 +74,30 @@ class Gollum::Filter::Code < Gollum::Filter
|
|
74
74
|
highlighted = []
|
75
75
|
blocks.each do |lang, code|
|
76
76
|
encoding = @markup.encoding || 'utf-8'
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
hl_code =
|
82
|
-
hl_code = "<pre class='highlight'><span class='err'>#{CGI.escapeHTML(hl_code)}</span></pre>"
|
77
|
+
|
78
|
+
if defined? Pygments
|
79
|
+
# treat unknown and bash as standard pre tags
|
80
|
+
if !lang || lang.downcase == 'bash'
|
81
|
+
hl_code = "<pre>#{code}</pre>"
|
83
82
|
else
|
84
|
-
|
83
|
+
# must set startinline to true for php to be highlighted without <?
|
84
|
+
hl_code = Pygments.highlight(code, :lexer => lang, :options => { :encoding => encoding.to_s, :startinline => true })
|
85
|
+
end
|
86
|
+
else # Rouge
|
87
|
+
begin
|
88
|
+
if Rouge::Lexer.find(lang).nil?
|
89
|
+
lexer = Rouge::Lexers::PlainText.new
|
90
|
+
formatter = Rouge::Formatters::HTML.new(:wrap => false)
|
91
|
+
hl_code = formatter.format(lexer.lex(code))
|
92
|
+
hl_code = "<pre class='highlight'><span class='err'>#{CGI.escapeHTML(hl_code)}</span></pre>"
|
93
|
+
else
|
94
|
+
hl_code = Rouge.highlight(code, lang, 'html')
|
95
|
+
end
|
96
|
+
rescue
|
97
|
+
hl_code = code
|
85
98
|
end
|
86
|
-
rescue
|
87
|
-
hl_code = code
|
88
99
|
end
|
100
|
+
|
89
101
|
highlighted << hl_code
|
90
102
|
end
|
91
103
|
|
@@ -16,12 +16,14 @@ class Gollum::Filter::Metadata < Gollum::Filter
|
|
16
16
|
# HTML elements before parsing each line.
|
17
17
|
$1.split("\n").each do |line|
|
18
18
|
line.gsub!(/<[^>]*>/, '')
|
19
|
-
k, v
|
19
|
+
k, v = line.split(':', 2)
|
20
20
|
@markup.metadata[k.strip] = (v ? v.strip : '') if k
|
21
21
|
end
|
22
22
|
''
|
23
23
|
end
|
24
24
|
end
|
25
|
-
|
26
|
-
def process(d)
|
25
|
+
|
26
|
+
def process(d)
|
27
|
+
d
|
28
|
+
end
|
27
29
|
end
|
@@ -16,7 +16,7 @@ class Gollum::Filter::RemoteCode < Gollum::Filter
|
|
16
16
|
return data if @markup.format == :txt
|
17
17
|
data.gsub /^[ \t]*``` ?([^:\n\r]+):((http)?[^`\n\r]+)```/ do
|
18
18
|
language = $1
|
19
|
-
uri
|
19
|
+
uri = $2
|
20
20
|
protocol = $3
|
21
21
|
|
22
22
|
# Detect local file
|
@@ -34,28 +34,30 @@ class Gollum::Filter::RemoteCode < Gollum::Filter
|
|
34
34
|
"```#{language}\n#{contents}\n```\n"
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
38
|
-
def process(d)
|
37
|
+
|
38
|
+
def process(d)
|
39
|
+
d
|
40
|
+
end
|
39
41
|
|
40
42
|
private
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
def req uri, cut = 1
|
45
|
+
uri = URI(uri)
|
46
|
+
return "Too many redirects or retries" if cut >= 10
|
47
|
+
http = Net::HTTP.new uri.host, uri.port
|
48
|
+
http.use_ssl = true
|
49
|
+
resp = http.get uri.path, {
|
48
50
|
'Accept' => 'text/plain',
|
49
51
|
'Cache-Control' => 'no-cache',
|
50
52
|
'Connection' => 'keep-alive',
|
51
53
|
'User-Agent' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0'
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
}
|
55
|
+
code = resp.code.to_i
|
56
|
+
return resp.body if code == 200
|
57
|
+
return "Not Found" if code == 404
|
58
|
+
return "Unhandled Response Code #{code}" unless code == 304 or not resp.header['location'].nil?
|
59
|
+
loc = URI.parse resp.header['location']
|
60
|
+
uri2 = loc.relative? ? (uri + loc) : loc # overloads (+)
|
61
|
+
req uri2, (cut + 1)
|
62
|
+
end
|
61
63
|
end
|
@@ -10,19 +10,19 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
10
10
|
"[[#{$2}]]#{$3}"
|
11
11
|
elsif $2.include?('][')
|
12
12
|
if $2[0..4] == 'file:'
|
13
|
-
pre
|
14
|
-
post
|
15
|
-
parts
|
13
|
+
pre = $1
|
14
|
+
post = $3
|
15
|
+
parts = $2.split('][')
|
16
16
|
parts[0][0..4] = ""
|
17
|
-
link
|
18
|
-
id
|
19
|
-
@map[id]
|
17
|
+
link = "#{parts[1]}|#{parts[0].sub(/\.org/, '')}"
|
18
|
+
id = Digest::SHA1.hexdigest(link)
|
19
|
+
@map[id] = link
|
20
20
|
"#{pre}#{id}#{post}"
|
21
21
|
else
|
22
22
|
$&
|
23
23
|
end
|
24
24
|
else
|
25
|
-
id
|
25
|
+
id = Digest::SHA1.hexdigest($2)
|
26
26
|
@map[id] = $2
|
27
27
|
"#{$1}#{id}#{$3}"
|
28
28
|
end
|
@@ -56,11 +56,12 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
56
56
|
# data - The String data (with placeholders).
|
57
57
|
# id - The String SHA1 hash.
|
58
58
|
PREFORMATTED_TAGS = %w(code tt)
|
59
|
+
|
59
60
|
def is_preformatted?(data, id)
|
60
|
-
doc
|
61
|
+
doc = Nokogiri::HTML::DocumentFragment.parse(data)
|
61
62
|
node = doc.search("[text()*='#{id}']").first
|
62
63
|
node && (PREFORMATTED_TAGS.include?(node.name) ||
|
63
|
-
|
64
|
+
node.ancestors.any? { |a| PREFORMATTED_TAGS.include?(a.name) })
|
64
65
|
end
|
65
66
|
|
66
67
|
# Process a single tag into its final HTML form.
|
@@ -84,7 +85,7 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
84
85
|
process_page_link_tag(tag)
|
85
86
|
end
|
86
87
|
end
|
87
|
-
|
88
|
+
|
88
89
|
# Attempt to process the tag as an include tag
|
89
90
|
#
|
90
91
|
# tag - The String tag contents (the stuff inside the double brackets).
|
@@ -94,8 +95,8 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
94
95
|
#
|
95
96
|
def process_include_tag(tag)
|
96
97
|
return unless /^include:/.match(tag)
|
97
|
-
page_name
|
98
|
-
resolved_page_name =
|
98
|
+
page_name = tag[8..-1]
|
99
|
+
resolved_page_name = ::File.expand_path(page_name, "/"+@markup.dir)
|
99
100
|
|
100
101
|
if @markup.include_levels > 0
|
101
102
|
page = find_page_from_name(resolved_page_name)
|
@@ -119,12 +120,12 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
119
120
|
parts = tag.split('|')
|
120
121
|
return if parts.size.zero?
|
121
122
|
|
122
|
-
name
|
123
|
-
path
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
123
|
+
name = parts[0].strip
|
124
|
+
path = if file = @markup.find_file(name)
|
125
|
+
::File.join @markup.wiki.base_path, file.path
|
126
|
+
elsif name =~ /^https?:\/\/.+(jpg|png|gif|svg|bmp)$/i
|
127
|
+
name
|
128
|
+
end
|
128
129
|
|
129
130
|
if path
|
130
131
|
opts = parse_image_tag_options(tag)
|
@@ -137,7 +138,7 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
137
138
|
align = opts['align']
|
138
139
|
if opts['float']
|
139
140
|
containered = true
|
140
|
-
align
|
141
|
+
align ||= 'left'
|
141
142
|
if %w{left right}.include?(align)
|
142
143
|
classes << "float-#{align}"
|
143
144
|
end
|
@@ -171,11 +172,11 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
171
172
|
if opts['frame'] || containered
|
172
173
|
classes << 'frame' if opts['frame']
|
173
174
|
%{<span class="#{classes.join(' ')}">} +
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
175
|
+
%{<span>} +
|
176
|
+
%{<img src="#{path}" #{attr_string}/>} +
|
177
|
+
(alt ? %{<span>#{alt}</span>} : '') +
|
178
|
+
%{</span>} +
|
179
|
+
%{</span>}
|
179
180
|
else
|
180
181
|
%{<img src="#{path}" #{attr_string}/>}
|
181
182
|
end
|
@@ -192,7 +193,7 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
192
193
|
# val - The String option value or true if it is a binary option.
|
193
194
|
def parse_image_tag_options(tag)
|
194
195
|
tag.split('|')[1..-1].inject({}) do |memo, attr|
|
195
|
-
parts
|
196
|
+
parts = attr.split('=').map { |x| x.strip }
|
196
197
|
memo[parts[0]] = (parts.size == 1 ? true : parts[1])
|
197
198
|
memo
|
198
199
|
end
|
@@ -209,15 +210,15 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
209
210
|
parts = tag.split('|')
|
210
211
|
return if parts.size.zero?
|
211
212
|
|
212
|
-
name
|
213
|
-
path
|
214
|
-
path
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
213
|
+
name = parts[0].strip
|
214
|
+
path = parts[1] && parts[1].strip
|
215
|
+
path = if path && file = @markup.find_file(path)
|
216
|
+
::File.join @markup.wiki.base_path, file.path
|
217
|
+
elsif path =~ %r{^https?://}
|
218
|
+
path
|
219
|
+
else
|
220
|
+
nil
|
221
|
+
end
|
221
222
|
|
222
223
|
if name && path && file
|
223
224
|
%{<a href="#{::File.join @markup.wiki.base_path, file.path}">#{name}</a>}
|
@@ -240,7 +241,7 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
240
241
|
parts.reverse! if @markup.format == :mediawiki
|
241
242
|
|
242
243
|
name, page_name = *parts.compact.map(&:strip)
|
243
|
-
cname
|
244
|
+
cname = @markup.wiki.page_class.cname(page_name || name)
|
244
245
|
|
245
246
|
if name =~ %r{^https?://} && page_name.nil?
|
246
247
|
%{<a href="#{name}">#{name}</a>}
|
@@ -1,31 +1,47 @@
|
|
1
1
|
# Inserts header anchors and creates TOC
|
2
2
|
class Gollum::Filter::TOC < Gollum::Filter
|
3
|
-
def extract(d)
|
4
|
-
|
3
|
+
def extract(d)
|
4
|
+
d
|
5
|
+
end
|
6
|
+
|
5
7
|
def process(data)
|
6
|
-
doc
|
7
|
-
toc
|
8
|
+
doc = Nokogiri::HTML::DocumentFragment.parse(data)
|
9
|
+
toc = nil
|
10
|
+
anchor_names = {}
|
11
|
+
|
8
12
|
doc.css('h1,h2,h3,h4,h5,h6').each do |h|
|
9
13
|
# must escape "
|
10
|
-
h_name
|
14
|
+
h_name = h.content.gsub(' ', '-').gsub('"', '%22')
|
15
|
+
|
16
|
+
# Ensure repeat anchors have a unique prefix or the
|
17
|
+
# toc will break
|
18
|
+
anchor_names[h_name] = 0 if anchor_names[h_name].nil?
|
19
|
+
anchor_names[h_name] += 1
|
20
|
+
|
21
|
+
anchor_prefix_number = anchor_names[h_name]
|
22
|
+
if anchor_prefix_number > 1
|
23
|
+
h_name = anchor_prefix_number.to_s + '-' + h_name
|
24
|
+
end
|
11
25
|
|
12
|
-
level = h.name.gsub(/[hH]/,'').to_i
|
26
|
+
level = h.name.gsub(/[hH]/, '').to_i
|
13
27
|
|
14
28
|
# Add anchors
|
15
|
-
|
29
|
+
anchor_element = %Q(<a class="anchor" id="#{h_name}" href="##{h_name}"><i class="fa fa-link"></i></a>)
|
30
|
+
# Add anchor element as the first child (before h.content)
|
31
|
+
h.children.before anchor_element
|
16
32
|
|
17
33
|
# Build TOC
|
18
|
-
toc
|
19
|
-
tail
|
34
|
+
toc ||= Nokogiri::XML::DocumentFragment.parse('<div class="toc"><div class="toc-title">Table of Contents</div></div>')
|
35
|
+
tail ||= toc.child
|
20
36
|
tail_level ||= 0
|
21
37
|
|
22
38
|
while tail_level < level
|
23
|
-
node
|
24
|
-
tail
|
39
|
+
node = Nokogiri::XML::Node.new('ul', doc)
|
40
|
+
tail = tail.add_child(node)
|
25
41
|
tail_level += 1
|
26
42
|
end
|
27
43
|
while tail_level > level
|
28
|
-
tail
|
44
|
+
tail = tail.parent
|
29
45
|
tail_level -= 1
|
30
46
|
end
|
31
47
|
node = Nokogiri::XML::Node.new('li', doc)
|
@@ -42,4 +58,4 @@ class Gollum::Filter::TOC < Gollum::Filter
|
|
42
58
|
toc.nil? ? '' : toc
|
43
59
|
end
|
44
60
|
end
|
45
|
-
end
|
61
|
+
end
|
@@ -16,7 +16,7 @@ class Gollum::Filter::WSD < Gollum::Filter
|
|
16
16
|
def extract(data)
|
17
17
|
return data if @markup.format == :txt
|
18
18
|
data.gsub(/^\{\{\{\{\{\{ ?(.+?)\r?\n(.+?)\r?\n\}\}\}\}\}\}\r?$/m) do
|
19
|
-
id
|
19
|
+
id = Digest::SHA1.hexdigest($2)
|
20
20
|
@map[id] = { :style => $1, :code => $2 }
|
21
21
|
id
|
22
22
|
end
|
@@ -12,7 +12,7 @@ module Gollum
|
|
12
12
|
# Returns this instance.
|
13
13
|
def initialize(path, page_file_dir = nil, bare = false)
|
14
14
|
@page_file_dir = page_file_dir
|
15
|
-
@path
|
15
|
+
@path = path
|
16
16
|
begin
|
17
17
|
@repo = Grit::Repo.new(path, { :is_bare => bare })
|
18
18
|
rescue Grit::InvalidGitRepositoryError
|
@@ -40,11 +40,11 @@ module Gollum
|
|
40
40
|
ref = ref.to_s
|
41
41
|
return if ref.empty?
|
42
42
|
sha =
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
if sha?(ref)
|
44
|
+
ref
|
45
|
+
else
|
46
|
+
get_cache(:ref, ref) { ref_to_sha!(ref) }
|
47
|
+
end.to_s
|
48
48
|
sha.empty? ? nil : sha
|
49
49
|
end
|
50
50
|
|
@@ -84,7 +84,7 @@ module Gollum
|
|
84
84
|
commit(sha)
|
85
85
|
else
|
86
86
|
if cm = commit!(ref)
|
87
|
-
set_cache(:ref,
|
87
|
+
set_cache(:ref, ref, cm.id)
|
88
88
|
set_cache(:commit, cm.id, cm)
|
89
89
|
end
|
90
90
|
end
|
@@ -163,11 +163,11 @@ module Gollum
|
|
163
163
|
#
|
164
164
|
# Returns an Array of BlobEntry instances.
|
165
165
|
def tree!(sha)
|
166
|
-
tree
|
166
|
+
tree = @repo.lstree(sha, { :recursive => true })
|
167
167
|
items = []
|
168
168
|
tree.each do |entry|
|
169
169
|
if entry[:type] == 'blob'
|
170
|
-
items << BlobEntry.new(entry[:sha], entry[:path], entry[:size], entry[:mode].to_i(8))
|
170
|
+
items << BlobEntry.new(entry[:sha], entry[:path], entry[:size], entry[:mode].to_i(8))
|
171
171
|
end
|
172
172
|
end
|
173
173
|
if dir = @page_file_dir
|
@@ -184,7 +184,7 @@ module Gollum
|
|
184
184
|
#
|
185
185
|
# Returns the String content of the Git object.
|
186
186
|
def cat_file!(sha)
|
187
|
-
@repo.git.cat_file({:p => true}, sha)
|
187
|
+
@repo.git.cat_file({ :p => true }, sha)
|
188
188
|
end
|
189
189
|
|
190
190
|
# Reads a Git commit.
|
@@ -244,7 +244,7 @@ module Gollum
|
|
244
244
|
def decode_git_path(path)
|
245
245
|
if path[0] == ?" && path[-1] == ?"
|
246
246
|
path = path[1...-1]
|
247
|
-
path.gsub!(/\\\d{3}/)
|
247
|
+
path.gsub!(/\\\d{3}/) { |m| m[1..-1].to_i(8).chr }
|
248
248
|
end
|
249
249
|
path.gsub!(/\\[rn"\\]/) { |m| eval(%("#{m.to_s}")) }
|
250
250
|
path
|