-
-
Notifications
You must be signed in to change notification settings - Fork 24
/
generator.rb
121 lines (98 loc) · 3.26 KB
/
generator.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# frozen_string_literal: true
module JekyllTitlesFromHeadings
class Generator < Jekyll::Generator
attr_accessor :site
# rubocop:disable Lint/InterpolationCheck
TITLE_REGEX =
%r!
\A\s* # Beginning and whitespace
(?: # either
\#{1,3}\s+(.*) # atx-style header
| # or
(.*)\r?\n[-=]+\s* # Setex-style header
)$ # end of line
!x
# rubocop:enable Lint/InterpolationCheck
CONVERTER_CLASS = Jekyll::Converters::Markdown
STRIP_MARKUP_FILTERS = %i[
markdownify strip_html normalize_whitespace
].freeze
# Regex to strip extra markup still present after markdownify
# (footnotes at the moment).
EXTRA_MARKUP_REGEX = %r!\[\^[^\]]*\]!
CONFIG_KEY = "titles_from_headings".freeze
ENABLED_KEY = "enabled".freeze
STRIP_TITLE_KEY = "strip_title".freeze
COLLECTIONS_KEY = "collections".freeze
safe true
priority :lowest
def initialize(site)
@site = site
end
def generate(site)
@site = site
return if disabled?
documents = site.pages
documents = site.pages + site.docs_to_write if collections?
documents.each do |document|
next unless should_add_title?(document)
next if document.is_a?(Jekyll::StaticFile)
document.data["title"] = title_for(document)
strip_title!(document) if strip_title?(document)
end
end
def should_add_title?(document)
markdown?(document) && !title?(document)
end
def title?(document)
!inferred_title?(document) && !document.data["title"].nil?
end
def markdown?(document)
markdown_converter.matches(document.extname)
end
def markdown_converter
@markdown_converter ||= site.find_converter_instance(CONVERTER_CLASS)
end
def title_for(document)
return document.data["title"] if title?(document)
matches = document.content.match(TITLE_REGEX)
return strip_markup(matches[1] || matches[2]) if matches
document.data["title"] # If we cant match a title, we use the inferred one.
rescue ArgumentError => e
raise e unless e.to_s.start_with?("invalid byte sequence in UTF-8")
end
private
def strip_markup(string)
STRIP_MARKUP_FILTERS.reduce(string) do |memo, method|
filters.public_send(method, memo)
end.gsub(EXTRA_MARKUP_REGEX, "")
end
def option(key)
site.config[CONFIG_KEY] && site.config[CONFIG_KEY][key]
end
def disabled?
option(ENABLED_KEY) == false
end
def strip_title?(document)
if document.data.key?(STRIP_TITLE_KEY)
document.data[STRIP_TITLE_KEY] == true
else
option(STRIP_TITLE_KEY) == true
end
end
def collections?
option(COLLECTIONS_KEY) == true
end
# Documents (posts and collection items) have their title inferred from the filename.
# We want to override these titles, because they were not excplicitly set.
def inferred_title?(document)
document.is_a?(Jekyll::Document)
end
def strip_title!(document)
document.content.gsub!(TITLE_REGEX, "")
end
def filters
@filters ||= JekyllTitlesFromHeadings::Filters.new(site)
end
end
end