jekyll-docs 3.6.0 → 3.6.1

Sign up to get free protection for your applications and to get access to all the features.
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)