jekyll-docs 3.6.0 → 3.6.1

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.
Files changed (253) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jekyll.rb +195 -0
  3. data/lib/jekyll/cleaner.rb +110 -0
  4. data/lib/jekyll/collection.rb +230 -0
  5. data/lib/jekyll/command.rb +78 -0
  6. data/lib/jekyll/commands/build.rb +102 -0
  7. data/lib/jekyll/commands/clean.rb +43 -0
  8. data/lib/jekyll/commands/doctor.rb +153 -0
  9. data/lib/jekyll/commands/help.rb +34 -0
  10. data/lib/jekyll/commands/new.rb +156 -0
  11. data/lib/jekyll/commands/new_theme.rb +40 -0
  12. data/lib/jekyll/commands/serve.rb +245 -0
  13. data/lib/jekyll/commands/serve/servlet.rb +62 -0
  14. data/lib/jekyll/configuration.rb +410 -0
  15. data/lib/jekyll/converter.rb +54 -0
  16. data/lib/jekyll/converters/identity.rb +23 -0
  17. data/lib/jekyll/converters/markdown.rb +104 -0
  18. data/lib/jekyll/converters/markdown/kramdown_parser.rb +123 -0
  19. data/lib/jekyll/converters/markdown/rdiscount_parser.rb +35 -0
  20. data/lib/jekyll/converters/markdown/redcarpet_parser.rb +108 -0
  21. data/lib/jekyll/converters/smartypants.rb +36 -0
  22. data/lib/jekyll/convertible.rb +251 -0
  23. data/lib/jekyll/deprecator.rb +52 -0
  24. data/lib/jekyll/document.rb +507 -0
  25. data/lib/jekyll/drops/collection_drop.rb +22 -0
  26. data/lib/jekyll/drops/document_drop.rb +69 -0
  27. data/lib/jekyll/drops/drop.rb +214 -0
  28. data/lib/jekyll/drops/excerpt_drop.rb +15 -0
  29. data/lib/jekyll/drops/jekyll_drop.rb +33 -0
  30. data/lib/jekyll/drops/site_drop.rb +47 -0
  31. data/lib/jekyll/drops/static_file_drop.rb +13 -0
  32. data/lib/jekyll/drops/unified_payload_drop.rb +25 -0
  33. data/lib/jekyll/drops/url_drop.rb +88 -0
  34. data/lib/jekyll/entry_filter.rb +123 -0
  35. data/lib/jekyll/errors.rb +20 -0
  36. data/lib/jekyll/excerpt.rb +126 -0
  37. data/lib/jekyll/external.rb +74 -0
  38. data/lib/jekyll/filters.rb +430 -0
  39. data/lib/jekyll/filters/grouping_filters.rb +65 -0
  40. data/lib/jekyll/filters/url_filters.rb +60 -0
  41. data/lib/jekyll/frontmatter_defaults.rb +197 -0
  42. data/lib/jekyll/generator.rb +5 -0
  43. data/lib/jekyll/hooks.rb +104 -0
  44. data/lib/jekyll/layout.rb +62 -0
  45. data/lib/jekyll/liquid_extensions.rb +24 -0
  46. data/lib/jekyll/liquid_renderer.rb +49 -0
  47. data/lib/jekyll/liquid_renderer/file.rb +56 -0
  48. data/lib/jekyll/liquid_renderer/table.rb +96 -0
  49. data/lib/jekyll/log_adapter.rb +147 -0
  50. data/lib/jekyll/mime.types +825 -0
  51. data/lib/jekyll/page.rb +187 -0
  52. data/lib/jekyll/plugin.rb +98 -0
  53. data/lib/jekyll/plugin_manager.rb +113 -0
  54. data/lib/jekyll/publisher.rb +23 -0
  55. data/lib/jekyll/reader.rb +134 -0
  56. data/lib/jekyll/readers/collection_reader.rb +22 -0
  57. data/lib/jekyll/readers/data_reader.rb +77 -0
  58. data/lib/jekyll/readers/layout_reader.rb +71 -0
  59. data/lib/jekyll/readers/page_reader.rb +25 -0
  60. data/lib/jekyll/readers/post_reader.rb +72 -0
  61. data/lib/jekyll/readers/static_file_reader.rb +25 -0
  62. data/lib/jekyll/readers/theme_assets_reader.rb +49 -0
  63. data/lib/jekyll/regenerator.rb +201 -0
  64. data/lib/jekyll/related_posts.rb +52 -0
  65. data/lib/jekyll/renderer.rb +269 -0
  66. data/lib/jekyll/site.rb +471 -0
  67. data/lib/jekyll/static_file.rb +162 -0
  68. data/lib/jekyll/stevenson.rb +61 -0
  69. data/lib/jekyll/tags/highlight.rb +141 -0
  70. data/lib/jekyll/tags/include.rb +215 -0
  71. data/lib/jekyll/tags/link.rb +37 -0
  72. data/lib/jekyll/tags/post_url.rb +103 -0
  73. data/lib/jekyll/theme.rb +68 -0
  74. data/lib/jekyll/theme_builder.rb +119 -0
  75. data/lib/jekyll/url.rb +161 -0
  76. data/lib/jekyll/utils.rb +337 -0
  77. data/lib/jekyll/utils/ansi.rb +59 -0
  78. data/lib/jekyll/utils/exec.rb +27 -0
  79. data/lib/jekyll/utils/platforms.rb +82 -0
  80. data/lib/jekyll/utils/rouge.rb +21 -0
  81. data/lib/jekyll/utils/win_tz.rb +75 -0
  82. data/lib/jekyll/version.rb +5 -0
  83. data/lib/site_template/404.html +24 -0
  84. data/lib/site_template/_config.yml +43 -0
  85. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +25 -0
  86. data/lib/site_template/about.md +18 -0
  87. data/lib/site_template/index.md +6 -0
  88. data/lib/theme_template/CODE_OF_CONDUCT.md.erb +74 -0
  89. data/lib/theme_template/Gemfile +4 -0
  90. data/lib/theme_template/LICENSE.txt.erb +21 -0
  91. data/lib/theme_template/README.md.erb +52 -0
  92. data/lib/theme_template/_layouts/default.html +1 -0
  93. data/lib/theme_template/_layouts/page.html +5 -0
  94. data/lib/theme_template/_layouts/post.html +5 -0
  95. data/lib/theme_template/example/_config.yml.erb +1 -0
  96. data/lib/theme_template/example/_post.md +12 -0
  97. data/lib/theme_template/example/index.html +14 -0
  98. data/lib/theme_template/example/style.scss +7 -0
  99. data/lib/theme_template/gitignore.erb +5 -0
  100. data/lib/theme_template/theme.gemspec.erb +19 -0
  101. metadata +103 -156
  102. data/lib/jekyll-docs.rb +0 -31
  103. data/site/404.html +0 -153
  104. data/site/CNAME +0 -1
  105. data/site/community/index.html +0 -299
  106. data/site/conduct/index.html +0 -10
  107. data/site/css/screen.css +0 -1
  108. data/site/docs/assets/index.html +0 -724
  109. data/site/docs/code_of_conduct/index.html +0 -730
  110. data/site/docs/collections/index.html +0 -1097
  111. data/site/docs/conduct/index.html +0 -744
  112. data/site/docs/configuration/index.html +0 -1403
  113. data/site/docs/continuous-integration/buddyworks/index.html +0 -726
  114. data/site/docs/continuous-integration/circleci/index.html +0 -757
  115. data/site/docs/continuous-integration/index.html +0 -681
  116. data/site/docs/continuous-integration/travis-ci/index.html +0 -891
  117. data/site/docs/contributing/index.html +0 -863
  118. data/site/docs/datafiles/index.html +0 -780
  119. data/site/docs/deployment-methods/index.html +0 -875
  120. data/site/docs/drafts/index.html +0 -636
  121. data/site/docs/extras/index.html +0 -689
  122. data/site/docs/frontmatter/index.html +0 -807
  123. data/site/docs/github-pages/index.html +0 -819
  124. data/site/docs/history/index.html +0 -3955
  125. data/site/docs/home/index.html +0 -644
  126. data/site/docs/includes/index.html +0 -800
  127. data/site/docs/index.html +0 -10
  128. data/site/docs/installation/index.html +0 -732
  129. data/site/docs/maintaining/affinity-team-captain/index.html +0 -706
  130. data/site/docs/maintaining/avoiding-burnout/index.html +0 -709
  131. data/site/docs/maintaining/becoming-a-maintainer/index.html +0 -717
  132. data/site/docs/maintaining/index.html +0 -713
  133. data/site/docs/maintaining/merging-a-pull-request/index.html +0 -747
  134. data/site/docs/maintaining/reviewing-a-pull-request/index.html +0 -725
  135. data/site/docs/maintaining/special-labels/index.html +0 -705
  136. data/site/docs/maintaining/triaging-an-issue/index.html +0 -735
  137. data/site/docs/migrations/index.html +0 -647
  138. data/site/docs/pages/index.html +0 -695
  139. data/site/docs/pagination/index.html +0 -870
  140. data/site/docs/permalinks/index.html +0 -1027
  141. data/site/docs/plugins/index.html +0 -1800
  142. data/site/docs/posts/index.html +0 -858
  143. data/site/docs/quickstart/index.html +0 -650
  144. data/site/docs/resources/index.html +0 -769
  145. data/site/docs/sites/index.html +0 -702
  146. data/site/docs/static-files/index.html +0 -720
  147. data/site/docs/structure/index.html +0 -822
  148. data/site/docs/templates/index.html +0 -1208
  149. data/site/docs/themes/index.html +0 -935
  150. data/site/docs/troubleshooting/index.html +0 -893
  151. data/site/docs/upgrading/0-to-2/index.html +0 -826
  152. data/site/docs/upgrading/2-to-3/index.html +0 -824
  153. data/site/docs/upgrading/index.html +0 -693
  154. data/site/docs/usage/index.html +0 -705
  155. data/site/docs/variables/index.html +0 -1048
  156. data/site/docs/windows/index.html +0 -799
  157. data/site/favicon.ico +0 -0
  158. data/site/feed.xml +0 -372
  159. data/site/fonts/FontAwesome.eot +0 -0
  160. data/site/fonts/FontAwesome.svg +0 -12
  161. data/site/fonts/FontAwesome.ttf +0 -0
  162. data/site/fonts/FontAwesome.woff +0 -0
  163. data/site/github.html +0 -10
  164. data/site/help/index.html +0 -244
  165. data/site/icomoon-selection.json +0 -96
  166. data/site/img/article-footer.png +0 -0
  167. data/site/img/footer-arrow.png +0 -0
  168. data/site/img/footer-logo.png +0 -0
  169. data/site/img/jekyll-sticker.jpg +0 -0
  170. data/site/img/jekylllayoutconcept.png +0 -0
  171. data/site/img/logo-2x.png +0 -0
  172. data/site/img/logo-rss.png +0 -0
  173. data/site/img/octojekyll.png +0 -0
  174. data/site/index.html +0 -267
  175. data/site/issues.html +0 -10
  176. data/site/js/html5shiv.min.js +0 -4
  177. data/site/js/respond.min.js +0 -5
  178. data/site/latest_version.txt +0 -1
  179. data/site/news/2013/05/05/jekyll-1-0-0-released/index.html +0 -570
  180. data/site/news/2013/05/08/jekyll-1-0-1-released/index.html +0 -570
  181. data/site/news/2013/05/12/jekyll-1-0-2-released/index.html +0 -571
  182. data/site/news/2013/06/07/jekyll-1-0-3-released/index.html +0 -568
  183. data/site/news/2013/07/14/jekyll-1-1-0-released/index.html +0 -570
  184. data/site/news/2013/07/24/jekyll-1-1-1-released/index.html +0 -569
  185. data/site/news/2013/07/25/jekyll-1-0-4-released/index.html +0 -565
  186. data/site/news/2013/07/25/jekyll-1-1-2-released/index.html +0 -565
  187. data/site/news/2013/09/06/jekyll-1-2-0-released/index.html +0 -572
  188. data/site/news/2013/09/14/jekyll-1-2-1-released/index.html +0 -566
  189. data/site/news/2013/10/28/jekyll-1-3-0-rc1-released/index.html +0 -564
  190. data/site/news/2013/11/04/jekyll-1-3-0-released/index.html +0 -599
  191. data/site/news/2013/11/26/jekyll-1-3-1-released/index.html +0 -568
  192. data/site/news/2013/12/07/jekyll-1-4-0-released/index.html +0 -583
  193. data/site/news/2013/12/09/jekyll-1-4-1-released/index.html +0 -565
  194. data/site/news/2013/12/16/jekyll-1-4-2-released/index.html +0 -564
  195. data/site/news/2014/01/13/jekyll-1-4-3-released/index.html +0 -573
  196. data/site/news/2014/03/24/jekyll-1-5-0-released/index.html +0 -564
  197. data/site/news/2014/03/27/jekyll-1-5-1-released/index.html +0 -569
  198. data/site/news/2014/05/06/jekyll-turns-2-0-0/index.html +0 -585
  199. data/site/news/2014/05/08/jekyll-2-0-3-released/index.html +0 -565
  200. data/site/news/2014/06/04/jekyll-stickers-1-dollar-stickermule/index.html +0 -567
  201. data/site/news/2014/06/28/jekyll-turns-21-i-mean-2-1-0/index.html +0 -582
  202. data/site/news/2014/07/01/jekyll-2-1-1-released/index.html +0 -579
  203. data/site/news/2014/07/29/jekyll-2-2-0-released/index.html +0 -568
  204. data/site/news/2014/08/10/jekyll-2-3-0-released/index.html +0 -588
  205. data/site/news/2014/09/09/jekyll-2-4-0-released/index.html +0 -574
  206. data/site/news/2014/11/05/jekylls-midlife-crisis-jekyll-turns-2-5-0/index.html +0 -597
  207. data/site/news/2014/11/09/jekyll-2-5-1-released/index.html +0 -575
  208. data/site/news/2014/11/12/jekyll-2-5-2-released/index.html +0 -565
  209. data/site/news/2014/12/17/alfredxing-welcome-to-jekyll-core/index.html +0 -572
  210. data/site/news/2014/12/22/jekyll-2-5-3-released/index.html +0 -567
  211. data/site/news/2015/01/20/jekyll-meet-and-greet/index.html +0 -568
  212. data/site/news/2015/01/24/jekyll-3-0-0-beta1-released/index.html +0 -588
  213. data/site/news/2015/02/26/introducing-jekyll-talk/index.html +0 -563
  214. data/site/news/2015/10/26/jekyll-3-0-released/index.html +0 -592
  215. data/site/news/2015/11/17/jekyll-3-0-1-released/index.html +0 -576
  216. data/site/news/2016/01/20/jekyll-3-0-2-released/index.html +0 -566
  217. data/site/news/2016/01/24/jekyll-3-1-0-released/index.html +0 -599
  218. data/site/news/2016/01/28/jekyll-3-1-1-released/index.html +0 -583
  219. data/site/news/2016/02/08/jekyll-3-0-3-released/index.html +0 -578
  220. data/site/news/2016/02/19/jekyll-3-1-2-released/index.html +0 -569
  221. data/site/news/2016/03/10/making-it-easier-to-contribute-to-jekyll/index.html +0 -565
  222. data/site/news/2016/04/19/jekyll-3-0-4-released/index.html +0 -571
  223. data/site/news/2016/04/19/jekyll-3-1-3-released/index.html +0 -566
  224. data/site/news/2016/04/26/jekyll-3-0-5-released/index.html +0 -572
  225. data/site/news/2016/05/18/jekyll-3-1-4-released/index.html +0 -576
  226. data/site/news/2016/05/18/jekyll-3-1-5-released/index.html +0 -564
  227. data/site/news/2016/05/19/jekyll-3-1-6-released/index.html +0 -566
  228. data/site/news/2016/06/03/update-on-jekyll-s-google-summer-of-code-projects/index.html +0 -567
  229. data/site/news/2016/07/26/jekyll-3-2-0-released/index.html +0 -676
  230. data/site/news/2016/08/02/jekyll-3-2-1-released/index.html +0 -571
  231. data/site/news/2016/08/24/jekyll-admin-initial-release/index.html +0 -566
  232. data/site/news/2016/10/06/jekyll-3-3-is-here/index.html +0 -645
  233. data/site/news/2016/11/14/jekyll-3-3-1-released/index.html +0 -569
  234. data/site/news/2017/01/18/jekyll-3-4-0-released/index.html +0 -592
  235. data/site/news/2017/03/02/jekyll-3-4-1-released/index.html +0 -649
  236. data/site/news/2017/03/09/jekyll-3-4-2-released/index.html +0 -598
  237. data/site/news/2017/03/21/jekyll-3-4-3-released/index.html +0 -594
  238. data/site/news/2017/06/15/jekyll-3-5-0-released/index.html +0 -589
  239. data/site/news/2017/07/17/jekyll-3-5-1-released/index.html +0 -569
  240. data/site/news/2017/08/12/jekyll-3-5-2-released/index.html +0 -573
  241. data/site/news/2017/09/21/jekyll-3-6-0-released/index.html +0 -565
  242. data/site/news/index.html +0 -3609
  243. data/site/news/releases/index.html +0 -3344
  244. data/site/philosophy.html +0 -46
  245. data/site/readme.md +0 -23
  246. data/site/robots.txt +0 -1
  247. data/site/sitemap.xml +0 -485
  248. data/site/tutorials/convert-site-to-jekyll/index.html +0 -793
  249. data/site/tutorials/custom-404-page/index.html +0 -358
  250. data/site/tutorials/home/index.html +0 -323
  251. data/site/tutorials/index.html +0 -10
  252. data/site/tutorials/navigation/index.html +0 -872
  253. data/site/tutorials/orderofinterpretation/index.html +0 -441
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ class StaticFile
5
+ extend Forwardable
6
+
7
+ attr_reader :relative_path, :extname, :name, :data
8
+
9
+ def_delegator :to_liquid, :to_json, :to_json
10
+
11
+ class << self
12
+ # The cache of last modification times [path] -> mtime.
13
+ def mtimes
14
+ @mtimes ||= {}
15
+ end
16
+
17
+ def reset_cache
18
+ @mtimes = nil
19
+ end
20
+ end
21
+
22
+ # Initialize a new StaticFile.
23
+ #
24
+ # site - The Site.
25
+ # base - The String path to the <source>.
26
+ # dir - The String path between <source> and the file.
27
+ # name - The String filename of the file.
28
+ # rubocop: disable ParameterLists
29
+ def initialize(site, base, dir, name, collection = nil)
30
+ @site = site
31
+ @base = base
32
+ @dir = dir
33
+ @name = name
34
+ @collection = collection
35
+ @relative_path = File.join(*[@dir, @name].compact)
36
+ @extname = File.extname(@name)
37
+ @data = @site.frontmatter_defaults.all(relative_path, type)
38
+ end
39
+ # rubocop: enable ParameterLists
40
+
41
+ # Returns source file path.
42
+ def path
43
+ File.join(*[@base, @dir, @name].compact)
44
+ end
45
+
46
+ # Obtain destination path.
47
+ #
48
+ # dest - The String path to the destination dir.
49
+ #
50
+ # Returns destination file path.
51
+ def destination(dest)
52
+ @site.in_dest_dir(*[dest, destination_rel_dir, @name].compact)
53
+ end
54
+
55
+ def destination_rel_dir
56
+ if @collection
57
+ File.dirname(url)
58
+ else
59
+ @dir
60
+ end
61
+ end
62
+
63
+ def modified_time
64
+ @modified_time ||= File.stat(path).mtime
65
+ end
66
+
67
+ # Returns last modification time for this file.
68
+ def mtime
69
+ modified_time.to_i
70
+ end
71
+
72
+ # Is source path modified?
73
+ #
74
+ # Returns true if modified since last write.
75
+ def modified?
76
+ self.class.mtimes[path] != mtime
77
+ end
78
+
79
+ # Whether to write the file to the filesystem
80
+ #
81
+ # Returns true unless the defaults for the destination path from
82
+ # _config.yml contain `published: false`.
83
+ def write?
84
+ defaults.fetch("published", true)
85
+ end
86
+
87
+ # Write the static file to the destination directory (if modified).
88
+ #
89
+ # dest - The String path to the destination dir.
90
+ #
91
+ # Returns false if the file was not modified since last time (no-op).
92
+ def write(dest)
93
+ dest_path = destination(dest)
94
+
95
+ return false if File.exist?(dest_path) && !modified?
96
+ self.class.mtimes[path] = mtime
97
+
98
+ FileUtils.mkdir_p(File.dirname(dest_path))
99
+ FileUtils.rm(dest_path) if File.exist?(dest_path)
100
+ copy_file(dest_path)
101
+
102
+ true
103
+ end
104
+
105
+ def to_liquid
106
+ @to_liquid ||= Drops::StaticFileDrop.new(self)
107
+ end
108
+
109
+ def basename
110
+ File.basename(name, extname)
111
+ end
112
+
113
+ def placeholders
114
+ {
115
+ :collection => @collection.label,
116
+ :path => relative_path[
117
+ @collection.relative_directory.size..relative_path.size],
118
+ :output_ext => "",
119
+ :name => "",
120
+ :title => "",
121
+ }
122
+ end
123
+
124
+ # Applies a similar URL-building technique as Jekyll::Document that takes
125
+ # the collection's URL template into account. The default URL template can
126
+ # be overriden in the collection's configuration in _config.yml.
127
+ def url
128
+ @url ||= if @collection.nil?
129
+ relative_path
130
+ else
131
+ ::Jekyll::URL.new({
132
+ :template => @collection.url_template,
133
+ :placeholders => placeholders,
134
+ })
135
+ end.to_s.gsub(%r!/$!, "")
136
+ end
137
+
138
+ # Returns the type of the collection if present, nil otherwise.
139
+ def type
140
+ @type ||= @collection.nil? ? nil : @collection.label.to_sym
141
+ end
142
+
143
+ # Returns the front matter defaults defined for the file's URL and/or type
144
+ # as defined in _config.yml.
145
+ def defaults
146
+ @defaults ||= @site.frontmatter_defaults.all url, type
147
+ end
148
+
149
+ private
150
+ def copy_file(dest_path)
151
+ if @site.safe || Jekyll.env == "production"
152
+ FileUtils.cp(path, dest_path)
153
+ else
154
+ FileUtils.copy_entry(path, dest_path)
155
+ end
156
+
157
+ unless File.symlink?(dest_path)
158
+ File.utime(self.class.mtimes[path], self.class.mtimes[path], dest_path)
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ class Stevenson < ::Logger
5
+ def initialize
6
+ @progname = nil
7
+ @level = DEBUG
8
+ @default_formatter = Formatter.new
9
+ @logdev = $stdout
10
+ @formatter = proc do |_, _, _, msg|
11
+ msg.to_s
12
+ end
13
+ end
14
+
15
+ def add(severity, message = nil, progname = nil)
16
+ severity ||= UNKNOWN
17
+ @logdev = logdevice(severity)
18
+
19
+ if @logdev.nil? || severity < @level
20
+ return true
21
+ end
22
+ progname ||= @progname
23
+ if message.nil?
24
+ if block_given?
25
+ message = yield
26
+ else
27
+ message = progname
28
+ progname = @progname
29
+ end
30
+ end
31
+ @logdev.puts(
32
+ format_message(format_severity(severity), Time.now, progname, message)
33
+ )
34
+ true
35
+ end
36
+
37
+ # Log a +WARN+ message
38
+ def warn(progname = nil, &block)
39
+ add(WARN, nil, progname.yellow, &block)
40
+ end
41
+
42
+ # Log an +ERROR+ message
43
+ def error(progname = nil, &block)
44
+ add(ERROR, nil, progname.red, &block)
45
+ end
46
+
47
+ def close
48
+ # No LogDevice in use
49
+ end
50
+
51
+ private
52
+
53
+ def logdevice(severity)
54
+ if severity > INFO
55
+ $stderr
56
+ else
57
+ $stdout
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Tags
5
+ class HighlightBlock < Liquid::Block
6
+ include Liquid::StandardFilters
7
+
8
+ # The regular expression syntax checker. Start with the language specifier.
9
+ # Follow that by zero or more space separated options that take one of three
10
+ # forms: name, name=value, or name="<quoted list>"
11
+ #
12
+ # <quoted list> is a space-separated list of numbers
13
+ SYNTAX = %r!^([a-zA-Z0-9.+#_-]+)((\s+\w+(=(\w+|"([0-9]+\s)*[0-9]+"))?)*)$!
14
+
15
+ def initialize(tag_name, markup, tokens)
16
+ super
17
+ if markup.strip =~ SYNTAX
18
+ @lang = Regexp.last_match(1).downcase
19
+ @highlight_options = parse_options(Regexp.last_match(2))
20
+ else
21
+ raise SyntaxError, <<-MSG
22
+ Syntax Error in tag 'highlight' while parsing the following markup:
23
+
24
+ #{markup}
25
+
26
+ Valid syntax: highlight <lang> [linenos]
27
+ MSG
28
+ end
29
+ end
30
+
31
+ def render(context)
32
+ prefix = context["highlighter_prefix"] || ""
33
+ suffix = context["highlighter_suffix"] || ""
34
+ code = super.to_s.gsub(%r!\A(\n|\r)+|(\n|\r)+\z!, "")
35
+
36
+ is_safe = !!context.registers[:site].safe
37
+
38
+ output =
39
+ case context.registers[:site].highlighter
40
+ when "pygments"
41
+ render_pygments(code, is_safe)
42
+ when "rouge"
43
+ render_rouge(code)
44
+ else
45
+ render_codehighlighter(code)
46
+ end
47
+
48
+ rendered_output = add_code_tag(output)
49
+ prefix + rendered_output + suffix
50
+ end
51
+
52
+ def sanitized_opts(opts, is_safe)
53
+ if is_safe
54
+ Hash[[
55
+ [:startinline, opts.fetch(:startinline, nil)],
56
+ [:hl_lines, opts.fetch(:hl_lines, nil)],
57
+ [:linenos, opts.fetch(:linenos, nil)],
58
+ [:encoding, opts.fetch(:encoding, "utf-8")],
59
+ [:cssclass, opts.fetch(:cssclass, nil)],
60
+ ].reject { |f| f.last.nil? }]
61
+ else
62
+ opts
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def parse_options(input)
69
+ options = {}
70
+ unless input.empty?
71
+ # Split along 3 possible forms -- key="<quoted list>", key=value, or key
72
+ input.scan(%r!(?:\w="[^"]*"|\w=\w|\w)+!) do |opt|
73
+ key, value = opt.split("=")
74
+ # If a quoted list, convert to array
75
+ if value && value.include?("\"")
76
+ value.delete!('"')
77
+ value = value.split
78
+ end
79
+ options[key.to_sym] = value || true
80
+ end
81
+ end
82
+ if options.key?(:linenos) && options[:linenos] == true
83
+ options[:linenos] = "inline"
84
+ end
85
+ options
86
+ end
87
+
88
+ def render_pygments(code, is_safe)
89
+ Jekyll::External.require_with_graceful_fail("pygments")
90
+
91
+ highlighted_code = Pygments.highlight(
92
+ code,
93
+ :lexer => @lang,
94
+ :options => sanitized_opts(@highlight_options, is_safe)
95
+ )
96
+
97
+ if highlighted_code.nil?
98
+ Jekyll.logger.error <<-MSG
99
+ There was an error highlighting your code:
100
+
101
+ #{code}
102
+
103
+ While attempting to convert the above code, Pygments.rb returned an unacceptable value.
104
+ This is usually a timeout problem solved by running `jekyll build` again.
105
+ MSG
106
+ raise ArgumentError, "Pygments.rb returned an unacceptable value "\
107
+ "when attempting to highlight some code."
108
+ end
109
+
110
+ highlighted_code.sub('<div class="highlight"><pre>', "").sub("</pre></div>", "")
111
+ end
112
+
113
+ def render_rouge(code)
114
+ formatter = Jekyll::Utils::Rouge.html_formatter(
115
+ :line_numbers => @highlight_options[:linenos],
116
+ :wrap => false,
117
+ :css_class => "highlight",
118
+ :gutter_class => "gutter",
119
+ :code_class => "code"
120
+ )
121
+ lexer = Rouge::Lexer.find_fancy(@lang, code) || Rouge::Lexers::PlainText
122
+ formatter.format(lexer.lex(code))
123
+ end
124
+
125
+ def render_codehighlighter(code)
126
+ h(code).strip
127
+ end
128
+
129
+ def add_code_tag(code)
130
+ code_attributes = [
131
+ "class=\"language-#{@lang.to_s.tr("+", "-")}\"",
132
+ "data-lang=\"#{@lang}\"",
133
+ ].join(" ")
134
+ "<figure class=\"highlight\"><pre><code #{code_attributes}>"\
135
+ "#{code.chomp}</code></pre></figure>"
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ Liquid::Template.register_tag("highlight", Jekyll::Tags::HighlightBlock)
@@ -0,0 +1,215 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Tags
5
+ class IncludeTagError < StandardError
6
+ attr_accessor :path
7
+
8
+ def initialize(msg, path)
9
+ super(msg)
10
+ @path = path
11
+ end
12
+ end
13
+
14
+ class IncludeTag < Liquid::Tag
15
+ VALID_SYNTAX = %r!
16
+ ([\w-]+)\s*=\s*
17
+ (?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))
18
+ !x
19
+ VARIABLE_SYNTAX = %r!
20
+ (?<variable>[^{]*(\{\{\s*[\w\-\.]+\s*(\|.*)?\}\}[^\s{}]*)+)
21
+ (?<params>.*)
22
+ !x
23
+
24
+ def initialize(tag_name, markup, tokens)
25
+ super
26
+ matched = markup.strip.match(VARIABLE_SYNTAX)
27
+ if matched
28
+ @file = matched["variable"].strip
29
+ @params = matched["params"].strip
30
+ else
31
+ @file, @params = markup.strip.split(%r!\s+!, 2)
32
+ end
33
+ validate_params if @params
34
+ @tag_name = tag_name
35
+ end
36
+
37
+ def syntax_example
38
+ "{% #{@tag_name} file.ext param='value' param2='value' %}"
39
+ end
40
+
41
+ def parse_params(context)
42
+ params = {}
43
+ markup = @params
44
+
45
+ while (match = VALID_SYNTAX.match(markup))
46
+ markup = markup[match.end(0)..-1]
47
+
48
+ value = if match[2]
49
+ match[2].gsub(%r!\\"!, '"')
50
+ elsif match[3]
51
+ match[3].gsub(%r!\\'!, "'")
52
+ elsif match[4]
53
+ context[match[4]]
54
+ end
55
+
56
+ params[match[1]] = value
57
+ end
58
+ params
59
+ end
60
+
61
+ def validate_file_name(file)
62
+ if file !~ %r!^[a-zA-Z0-9_/\.-]+$! || file =~ %r!\./! || file =~ %r!/\.!
63
+ raise ArgumentError, <<-MSG
64
+ Invalid syntax for include tag. File contains invalid characters or sequences:
65
+
66
+ #{file}
67
+
68
+ Valid syntax:
69
+
70
+ #{syntax_example}
71
+
72
+ MSG
73
+ end
74
+ end
75
+
76
+ def validate_params
77
+ full_valid_syntax = %r!\A\s*(?:#{VALID_SYNTAX}(?=\s|\z)\s*)*\z!
78
+ unless @params =~ full_valid_syntax
79
+ raise ArgumentError, <<-MSG
80
+ Invalid syntax for include tag:
81
+
82
+ #{@params}
83
+
84
+ Valid syntax:
85
+
86
+ #{syntax_example}
87
+
88
+ MSG
89
+ end
90
+ end
91
+
92
+ # Grab file read opts in the context
93
+ def file_read_opts(context)
94
+ context.registers[:site].file_read_opts
95
+ end
96
+
97
+ # Render the variable if required
98
+ def render_variable(context)
99
+ if @file.match(VARIABLE_SYNTAX)
100
+ partial = context.registers[:site]
101
+ .liquid_renderer
102
+ .file("(variable)")
103
+ .parse(@file)
104
+ partial.render!(context)
105
+ end
106
+ end
107
+
108
+ def tag_includes_dirs(context)
109
+ context.registers[:site].includes_load_paths.freeze
110
+ end
111
+
112
+ def locate_include_file(context, file, safe)
113
+ includes_dirs = tag_includes_dirs(context)
114
+ includes_dirs.each do |dir|
115
+ path = File.join(dir.to_s, file.to_s)
116
+ return path if valid_include_file?(path, dir.to_s, safe)
117
+ end
118
+ raise IOError, "Could not locate the included file '#{file}' in any of "\
119
+ "#{includes_dirs}. Ensure it exists in one of those directories and, "\
120
+ "if it is a symlink, does not point outside your site source."
121
+ end
122
+
123
+ def render(context)
124
+ site = context.registers[:site]
125
+
126
+ file = render_variable(context) || @file
127
+ validate_file_name(file)
128
+
129
+ path = locate_include_file(context, file, site.safe)
130
+ return unless path
131
+
132
+ add_include_to_dependency(site, path, context)
133
+
134
+ partial = load_cached_partial(path, context)
135
+
136
+ context.stack do
137
+ context["include"] = parse_params(context) if @params
138
+ begin
139
+ partial.render!(context)
140
+ rescue Liquid::Error => e
141
+ e.template_name = path
142
+ e.markup_context = "included " if e.markup_context.nil?
143
+ raise e
144
+ end
145
+ end
146
+ end
147
+
148
+ def add_include_to_dependency(site, path, context)
149
+ if context.registers[:page] && context.registers[:page].key?("path")
150
+ site.regenerator.add_dependency(
151
+ site.in_source_dir(context.registers[:page]["path"]),
152
+ path
153
+ )
154
+ end
155
+ end
156
+
157
+ def load_cached_partial(path, context)
158
+ context.registers[:cached_partials] ||= {}
159
+ cached_partial = context.registers[:cached_partials]
160
+
161
+ if cached_partial.key?(path)
162
+ cached_partial[path]
163
+ else
164
+ unparsed_file = context.registers[:site]
165
+ .liquid_renderer
166
+ .file(path)
167
+ begin
168
+ cached_partial[path] = unparsed_file.parse(read_file(path, context))
169
+ rescue Liquid::Error => e
170
+ e.template_name = path
171
+ e.markup_context = "included " if e.markup_context.nil?
172
+ raise e
173
+ end
174
+ end
175
+ end
176
+
177
+ def valid_include_file?(path, dir, safe)
178
+ !outside_site_source?(path, dir, safe) && File.file?(path)
179
+ end
180
+
181
+ def outside_site_source?(path, dir, safe)
182
+ safe && !realpath_prefixed_with?(path, dir)
183
+ end
184
+
185
+ def realpath_prefixed_with?(path, dir)
186
+ File.exist?(path) && File.realpath(path).start_with?(dir)
187
+ rescue
188
+ false
189
+ end
190
+
191
+ # This method allows to modify the file content by inheriting from the class.
192
+ def read_file(file, context)
193
+ File.read(file, file_read_opts(context))
194
+ end
195
+ end
196
+
197
+ class IncludeRelativeTag < IncludeTag
198
+ def tag_includes_dirs(context)
199
+ Array(page_path(context)).freeze
200
+ end
201
+
202
+ def page_path(context)
203
+ if context.registers[:page].nil?
204
+ context.registers[:site].source
205
+ else
206
+ current_doc_dir = File.dirname(context.registers[:page]["path"])
207
+ context.registers[:site].in_source_dir current_doc_dir
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
213
+
214
+ Liquid::Template.register_tag("include", Jekyll::Tags::IncludeTag)
215
+ Liquid::Template.register_tag("include_relative", Jekyll::Tags::IncludeRelativeTag)