jekyll_pre 1.2.1 → 1.2.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c319e1e24db16309a2df595cd44df695cd239eba0c477af076a12fc25033e292
4
- data.tar.gz: edddecc3b1265d3741d4c7a5eac9cf6980f305541fa003f14f67d7a0165c3766
3
+ metadata.gz: 2e01bd13d91a64bf9b1dc9802cd11ef6c759985a30532daf8b3ace4618bfe634
4
+ data.tar.gz: 6d33733cf1f1d0267ba226dafd459807254fa10f5199f2b1358648f9f94ccc01
5
5
  SHA512:
6
- metadata.gz: 6cef3e92951e7d2f53107a8ade5dd04d52b8bc505fd4112bb0689a8bf7a245b6088c3e56238a211a73362c1ff6cf978ff3646ed289b667533e2495838f7127e4
7
- data.tar.gz: c5b8067ee37fe465aa697acc30bdb8e6d54b85c020da4fa80d788f978a72d729745c9b3556caa563edbb358d770b95e0e07e6bf0addf23aad0818c0cf2e4b00d
6
+ metadata.gz: 8e1f5e2a5cb3beb928cc2d8ad09fd1274aff0c5085ac1ee1f014456aaefaa78d5711c2bd9046e9418737b7bff7b53b2e4f54856e5dbbb8fcd1d4f193757db0fc
7
+ data.tar.gz: 22747b92ec65bb6568a648c98a2a24417fd970daa012632ec596deca2232b0e994dffa7017792083d797c1ee6b2bc86b01b4b496d84525786ddcfd06769ade64
data/.rubocop.yml CHANGED
@@ -1,6 +1,9 @@
1
1
  require:
2
- - rubocop-rspec
3
- - rubocop-rake
2
+ # - rubocop-jekyll
3
+ - rubocop-md
4
+ - rubocop-performance
5
+ - rubocop-rake
6
+ - rubocop-rspec
4
7
 
5
8
  AllCops:
6
9
  Exclude:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 1.2.3
2
+ * Added `cd` option to `exec` tag.
3
+
4
+ ## 1.2.2
5
+ * Added `exec` tag.
6
+ * Demarked CSS for the `exec`, `noselect`, and `pre` tags in `demo/assets/css/style.css`
7
+ within `/* Start of pre tag css */` and `/* End of pre tag css */`.
8
+
1
9
  ## 1.2.1
2
10
  * Updated to `jekyll_plugin_support` v0.5.1 so the `noselect` tag is more efficient.
3
11
 
data/README.md CHANGED
@@ -2,11 +2,11 @@ Jekyll_pre
2
2
  [![Gem Version](https://badge.fury.io/rb/jekyll_pre.svg)](https://badge.fury.io/rb/jekyll_pre)
3
3
  ===========
4
4
 
5
- This Jekyll plugin provides 2 new Liquid tags that work together:
5
+ This Jekyll plugin provides 3 new Liquid tags that work together:
6
6
 
7
- * A `pre` block tag that can optionally display a copy button.
7
+ * A `pre` block tag that can be displayed various ways.
8
8
  ```
9
- {% pre [Options] [headline words] %}
9
+ {% pre [Options] [free text label] %}
10
10
  Contents of pre tag
11
11
  {% endpre %}
12
12
  ```
@@ -24,37 +24,41 @@ This Jekyll plugin provides 2 new Liquid tags that work together:
24
24
  - {% pre This is a label %}<br>Contents of pre tag<br>{% endpre %}
25
25
  - `number` &ndash; Number the lines
26
26
  - `shell` &ndash; Equivalent to `label='Shell'`
27
- - `style` &ndash; Apply CSS styles
27
+ - `style` &ndash; Apply inline CSS styles
28
28
 
29
29
  The generated &lt;pre>&lt;/pre> tag has an `data-lt-active="false"` attribute, so [LanguageTool](https://forum.languagetool.org/t/avoid-spell-check-on-certain-html-inputs-manually/3944) does not check the spelling or grammar of the contents.
30
+
30
31
  * A `noselect` tag that can renders HTML content passed to it unselectable,
31
32
  and generates a <code>$</code> prompt if no content is provided.
32
33
  ```
33
34
  {% pre %}
34
- {% noselect [optional text string, defaults to $]%}Contents of pre tag
35
+ {% noselect [optional text string, defaults to $]%}Command
36
+ {% noselect unselectable output goes here %}
35
37
  {% endpre %}
36
38
  ```
37
39
 
38
- ## CSS
39
- Below are the CSS declarations that I defined pertaining to the pre and noselect tags that produced the above images:
40
- ```css
41
- .maxOneScreenHigh {
42
- max-height: 500px;
43
- }
40
+ * An `exec` tag that executes shell commands and incorporates the command and its output into the content of the `pre` tag.
41
+ Output data is escaped, whitespace is condensed, and wrapped in the same `unselectable` class as does `unselectable`.
42
+ ```
43
+ {% exec [Options] [shell command] %}
44
+ ```
45
+ `Options` are:
44
46
 
45
- .numbered_line,
46
- .unselectable.numbered_line,
47
- .numbered_line.unselectable {
48
- color: #5fb25f;
49
- }
47
+ - `cd="relative/or/absolute/directory"` - Change to specified directory before executing shell command.
48
+ Environment variables in the directory path will be expanded.
49
+ - `no_escape` – Do not HTML escape the result of running the shell command.
50
+ - `no_strip` – Do not remove leading and trailing whitespace from the result.
51
+ - `die_if_nonzero` – Set `false` to treat non-zero return codes as non-fatal.
52
+ Instead of terminating Jekyll with an error message,
53
+ the message will be displayed as an error by the Jekyll logger,
54
+ and a red message will appear in place of the result on the web page.
55
+ - `die_if_error` – Set `false` to treat exceptions generated by this plugin as non-fatal.
56
+ Instead of terminating Jekyll with an error message, the message will be displayed as an error by the Jekyll logger.
50
57
 
51
- .unselectable {
52
- color: #7922f9;
53
- -moz-user-select: none;
54
- -khtml-user-select: none;
55
- user-select: none;
56
- }
57
- ```
58
+
59
+ ## CSS
60
+ See [`demo/assets/css/style.css`](demo/assets/css/style.css) for the CSS declarations,
61
+ between `/* Start of pre tag css */` and `/* End of pre tag css */`.
58
62
 
59
63
 
60
64
  ## Additional Information
@@ -77,6 +81,7 @@ And then execute:
77
81
 
78
82
 
79
83
  ## Usage
84
+ The following examples are rendered on [my website](https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html#jekyll_pre).
80
85
 
81
86
  ### Example 1
82
87
  This example does not generate a copy button and does not demonstrate `noselect`.
@@ -148,20 +153,70 @@ Which renders as:
148
153
  ![example 4](images/usage4example.png)
149
154
 
150
155
 
151
- ### CSS
152
- Here are the CSS declarations that I defined pertaining to the `pre` and `noselect` tags that produced the above images:
156
+ ### Example 5
157
+ A regular expression can be passed to the `highlight` option.
158
+ This causes text that matches the regex pattern to be wrapped within a &lt;span class="bg_yellow">&lt;/span> tag.
159
+
160
+ The CSS stylesheet used for this page contains the following:
153
161
 
154
162
  ```css
155
- .maxOneScreenHigh {
156
- max-height: 500px;
163
+ .bg_yellow {
164
+ background-color: yellow;
165
+ padding: 2px;
157
166
  }
167
+ ```
158
168
 
159
- .unselectable {
160
- color: #7922f9;
161
- -moz-user-select: none;
162
- -khtml-user-select: none;
163
- user-select: none;
164
- }
169
+ This example demonstrates highlighting text that matches a regular expression. Regular expressions match against lines, which are delimited via newlines (\n).
170
+
171
+ ```
172
+ {% pre copyButton highlight="Line 2" %}
173
+ Line 1
174
+ Line 2
175
+ Line 3
176
+ Line 4
177
+ Line 5
178
+ Line 6
179
+ Line 7
180
+ {% endpre %}
181
+ ```
182
+
183
+
184
+ ### Example 6
185
+ Regular expressions match against lines, which are delimited via newlines (`\n`).
186
+ Thus to match an entire line that contains a phrase, specify the regex as `.*phrase.*`.
187
+ The following matches 3 possible phrases (`2`, `4` or `6`), then selects the entire line if matched.
188
+
189
+ ```
190
+ {% pre copyButton highlight=".*(2|4|6).*" %}
191
+ Line 1
192
+ Line 2
193
+ Line 3
194
+ Line 4
195
+ Line 5
196
+ Line 6
197
+ Line 7
198
+ {% endpre %}
199
+ ```
200
+
201
+
202
+ ### Example 7
203
+ This example floats an image to the right.
204
+ The `jekyll_pre plugin`’s `clear` option moves the generated HTML below the image.
205
+
206
+ ```
207
+ &lt;img src="jekyll.webp" style="float: right; width: 100px; height: auto;">
208
+ {% pre clear copyButton label='Clear example' %}
209
+ Using clear, copyButton and label parameters
210
+ {% endpre %}
211
+ ```
212
+
213
+ ### Example 8
214
+ The following executes `ls -alF /` and displays the output.
215
+
216
+ ```
217
+ {% pre clear copyButton label='Exec without error' %}
218
+ {% noselect %}{% exec die_if_nonzero=false ls -alF / %}
219
+ {% endpre %}
165
220
  ```
166
221
 
167
222
 
@@ -205,11 +260,7 @@ A test website is provided in the `demo` directory.
205
260
 
206
261
  ### Build and Install Locally
207
262
  To build and install this gem onto your local machine, run:
208
- ```shell
209
- $ rake install:local
210
- ```
211
263
 
212
- The following also does the same thing:
213
264
  ```shell
214
265
  $ bundle exec rake install
215
266
  ```
data/lib/exec_tag.rb ADDED
@@ -0,0 +1,89 @@
1
+ require 'jekyll_plugin_support'
2
+ require_relative 'jekyll_pre/version'
3
+
4
+ module ExecTag
5
+ class ExecTag < JekyllSupport::JekyllTag
6
+ include JekyllPreVersion
7
+
8
+ def render_impl
9
+ parse_args
10
+ command = @helper.remaining_markup
11
+ response = run_command(command)
12
+ response = if @child_status.success?
13
+ compress(response)
14
+ else
15
+ handle_error(command)
16
+ end
17
+
18
+ <<~END_OUTPUT
19
+ #{Rack::Utils.escape_html(command)}
20
+ <span class='unselectable'>#{response}</span>
21
+ END_OUTPUT
22
+ rescue PreError => e
23
+ raise PreError, e.message, []
24
+ rescue StandardError => e
25
+ msg = remove_html_tags(e.message) + " from executing '#{command}' on line #{@line_number} (after front matter) of #{@page['path']}"
26
+ raise PreError, msg.red, [] if die_if_error
27
+ end
28
+
29
+ private
30
+
31
+ def compress(response)
32
+ result = response.chomp
33
+ result = result.strip unless @no_strip
34
+ result = result.gsub('\n\n', '<br>\n')
35
+ result = Rack::Utils.escape_html(result) unless @no_escape
36
+ result
37
+ end
38
+
39
+ def die(msg)
40
+ msg_no_html = remove_html_tags(msg)
41
+ @logger.error("#{@page['path']} - #{msg_no_html}")
42
+ raise PreError, "#{@page['path']} - #{msg_no_html.red}", []
43
+ end
44
+
45
+ def handle_error(command)
46
+ msg0 = "Error: executing '#{command}'"
47
+ msg0 += " in directory '#{@cd}'" if @cd
48
+ msg = <<~END_MSG
49
+ #{msg0} on line #{@line_number} (after front matter) of #{@page['path']} returned error code #{@child_status.exitstatus}
50
+ END_MSG
51
+ raise PreError, msg.red, [] if @die_if_nonzero
52
+
53
+ @logger.error { msg }
54
+ "<span class='error'>Error code #{@child_status.exitstatus}</span>"
55
+ end
56
+
57
+ def parse_args
58
+ @cd = @helper.parameter_specified? 'cd'
59
+ @cd = JekyllPluginHelper.expand_env(@cd) if @cd
60
+
61
+ @no_escape = @helper.parameter_specified? 'no_escape'
62
+ @no_strip = @helper.parameter_specified? 'no_strip'
63
+ @die_if_nonzero = @helper.parameter_specified?('die_if_nonzero') # Implies die_if_error
64
+ @die_if_error = @helper.parameter_specified?('die_if_error') | @die_if_nonzero
65
+ end
66
+
67
+ # References @cd
68
+ # Defines @child_status
69
+ # @return result of running command
70
+ # @param command [String] Shell command to execute
71
+ def run_command(command)
72
+ result = if @cd
73
+ Dir.chdir(@cd) do
74
+ `#{command}`
75
+ end
76
+ else
77
+ `#{command}`
78
+ end
79
+ @child_status = $CHILD_STATUS
80
+ result
81
+ end
82
+
83
+ JekyllPluginHelper.register(self, 'exec')
84
+ end
85
+
86
+ def remove_html_tags(string)
87
+ string.gsub(/<[^>]*>/, '')
88
+ end
89
+ end
@@ -1,3 +1,3 @@
1
1
  module JekyllPreVersion
2
- VERSION = '1.2.1'.freeze
2
+ VERSION = '1.2.3'.freeze
3
3
  end
data/lib/jekyll_pre.rb CHANGED
@@ -1,98 +1,17 @@
1
- require 'liquid'
2
- require 'jekyll_plugin_logger'
3
- require 'jekyll_plugin_support'
4
- require_relative 'jekyll_pre/version'
5
-
6
1
  module JekyllPluginPreName
7
2
  PLUGIN_NAME = 'jekyll_pre'.freeze
8
3
  end
9
4
 
10
- class PreTagBlock < JekyllSupport::JekyllBlock
11
- @@prefix = "<button class='copyBtn' data-clipboard-target="
12
- @@suffix = " title='Copy to clipboard'><img src='/assets/images/clippy.svg' " \
13
- "alt='Copy to clipboard' style='width: 13px'></button>"
14
-
15
- def self.highlight(content, pattern)
16
- content.gsub(Regexp.new(pattern), "<span class='bg_yellow'>\\0</span>")
17
- end
18
-
19
- def self.make_copy_button(pre_id)
20
- "#{@@prefix}'##{pre_id}'#{@@suffix}"
21
- end
22
-
23
- def self.make_pre(make_copy_button, number_lines, label, dark, highlight_pattern, css_class, style, clear, content) # rubocop:disable Metrics/ParameterLists
24
- pre_clear = label_clear = ''
25
- if clear
26
- if label.to_s.empty?
27
- pre_clear = ' clear'
28
- else
29
- label_clear = ' clear'
30
- end
31
- end
32
- css_class = css_class ? " #{css_class}" : ''
33
- style = style ? " style='#{style}'" : ''
34
- dark_label = ' darkLabel' if dark
35
- label = if label.to_s.empty?
36
- ''
37
- elsif label.to_s.downcase.strip == 'shell'
38
- "<div class='codeLabel unselectable#{dark_label}#{label_clear}' data-lt-active='false'>Shell</div>"
39
- else
40
- "<div class='codeLabel unselectable#{dark_label}#{label_clear}' data-lt-active='false'>#{label}</div>"
41
- end
42
- pre_id = "id#{SecureRandom.hex(6)}"
43
- copy_button = make_copy_button ? PreTagBlock.make_copy_button(pre_id) : ''
44
- content = PreTagBlock.highlight(content, highlight_pattern) if highlight_pattern
45
- content = PreTagBlock.number_content(content) if number_lines
46
-
47
- classes = "maxOneScreenHigh copyContainer#{dark}#{pre_clear}#{css_class}"
48
- pre_content = "#{copy_button}#{content.strip}"
49
- "#{label}<pre data-lt-active='false' class='#{classes}'#{style} id='#{pre_id}'>#{pre_content}</pre>"
50
- end
5
+ require_relative './exec_tag'
6
+ require_relative './noselect_tag'
7
+ require_relative './pre_tag_block'
51
8
 
52
- def self.number_content(content)
53
- lines = content.split("\n")
54
- digits = lines.length.to_s.length
55
- i = 0
56
- numbered_content = lines.map do |line|
57
- i += 1
58
- number = i.to_s.rjust(digits, ' ')
59
- "<span class='unselectable numbered_line'> #{number}: </span>#{line}"
60
- end
61
- result = numbered_content.join("\n")
62
- result += "\n" unless result.end_with?("\n")
63
- result
64
- end
65
-
66
- def render_impl(text)
67
- text.strip!
68
-
69
- @clear = @helper.parameter_specified? 'clear'
70
- @class = @helper.parameter_specified? 'class'
71
- @highlight = @helper.parameter_specified? 'highlight'
72
- @make_copy_button = @helper.parameter_specified? 'copyButton'
73
- @number_lines = @helper.parameter_specified? 'number'
74
- @dark = ' dark' if @helper.parameter_specified? 'dark'
75
- @style = @helper.parameter_specified? 'style'
76
- @label = @helper.parameter_specified? 'label'
77
-
78
- # If a label was specified, use it, otherwise concatenate any dangling parameters and use that as the label
79
- @label ||= @helper.argv.join(' ')
80
-
81
- @logger.debug { "@make_copy_button = '#{@make_copy_button}'; @label = '#{@label}'" }
82
- self.class.make_pre(@make_copy_button, @number_lines, @label, @dark, @highlight, @class, @style, @clear, text)
83
- end
84
- end
9
+ PreError = Class.new(Liquid::Error)
85
10
 
86
- # """\\{% noselect %} or \\{% noselect this all gets copied.
87
- # Also, space before the closing percent is signficant %}"""
88
- class UnselectableTag < JekyllSupport::JekyllTagNoArgParsing
89
- def render_impl
90
- text = @argument_string
91
- text = '$ ' if text.nil? || text.empty?
92
- "<span class='unselectable'>#{text}</span>"
93
- end
11
+ module JekyllPreModule
12
+ include NoSelectTag
13
+ include PreTagBlock
14
+ include ExecTag
94
15
  end
95
16
 
96
17
  PluginMetaLogger.instance.info { "Loaded #{JekyllPluginPreName::PLUGIN_NAME} v#{JekyllPreVersion::VERSION} plugin." }
97
- Liquid::Template.register_tag('pre', PreTagBlock)
98
- Liquid::Template.register_tag('noselect', UnselectableTag)
@@ -0,0 +1,18 @@
1
+ require 'jekyll_plugin_support'
2
+ require_relative 'jekyll_pre/version'
3
+
4
+ module NoSelectTag
5
+ # """\\{% noselect %} or \\{% noselect this all gets copied.
6
+ # Also, space before the closing percent is signficant %}"""
7
+ class NoSelectTag < JekyllSupport::JekyllTagNoArgParsing
8
+ include JekyllPreVersion
9
+
10
+ def render_impl
11
+ text = @argument_string
12
+ text = '$ ' if text.nil? || text.empty?
13
+ "<span class='unselectable'>#{text}</span>"
14
+ end
15
+
16
+ JekyllPluginHelper.register(self, 'noselect')
17
+ end
18
+ end
@@ -0,0 +1,84 @@
1
+ require 'jekyll_plugin_support'
2
+ require_relative 'jekyll_pre/version'
3
+
4
+ module PreTagBlock
5
+ class PreTagBlock < JekyllSupport::JekyllBlock
6
+ include JekyllPreVersion
7
+
8
+ @@prefix = "<button class='copyBtn' data-clipboard-target="
9
+ @@suffix = " title='Copy to clipboard'><img src='/assets/images/clippy.svg' " \
10
+ "alt='Copy to clipboard' style='width: 13px'></button>"
11
+
12
+ def self.highlight(content, pattern)
13
+ content.gsub(Regexp.new(pattern), "<span class='bg_yellow'>\\0</span>")
14
+ end
15
+
16
+ def self.make_copy_button(pre_id)
17
+ "#{@@prefix}'##{pre_id}'#{@@suffix}"
18
+ end
19
+
20
+ def self.make_pre(make_copy_button, number_lines, label, dark, highlight_pattern, css_class, style, clear, content) # rubocop:disable Metrics/ParameterLists
21
+ pre_clear = label_clear = ''
22
+ if clear
23
+ if label.to_s.empty?
24
+ pre_clear = ' clear'
25
+ else
26
+ label_clear = ' clear'
27
+ end
28
+ end
29
+ css_class = css_class ? " #{css_class}" : ''
30
+ style = style ? " style='#{style}'" : ''
31
+ dark_label = ' darkLabel' if dark
32
+ label = if label.to_s.empty?
33
+ ''
34
+ elsif label.to_s.downcase.strip == 'shell'
35
+ "<div class='codeLabel unselectable#{dark_label}#{label_clear}' data-lt-active='false'>Shell</div>"
36
+ else
37
+ "<div class='codeLabel unselectable#{dark_label}#{label_clear}' data-lt-active='false'>#{label}</div>"
38
+ end
39
+ pre_id = "id#{SecureRandom.hex(6)}"
40
+ copy_button = make_copy_button ? PreTagBlock.make_copy_button(pre_id) : ''
41
+ content = PreTagBlock.highlight(content, highlight_pattern) if highlight_pattern
42
+ content = PreTagBlock.number_content(content) if number_lines
43
+
44
+ classes = "maxOneScreenHigh copyContainer#{dark}#{pre_clear}#{css_class}"
45
+ pre_content = "#{copy_button}#{content.strip}"
46
+ "#{label}<pre data-lt-active='false' class='#{classes}'#{style} id='#{pre_id}'>#{pre_content}</pre>"
47
+ end
48
+
49
+ def self.number_content(content)
50
+ lines = content.split("\n")
51
+ digits = lines.length.to_s.length
52
+ i = 0
53
+ numbered_content = lines.map do |line|
54
+ i += 1
55
+ number = i.to_s.rjust(digits, ' ')
56
+ "<span class='unselectable numbered_line'> #{number}: </span>#{line}"
57
+ end
58
+ result = numbered_content.join("\n")
59
+ result += "\n" unless result.end_with?("\n")
60
+ result
61
+ end
62
+
63
+ def render_impl(text)
64
+ text.strip!
65
+
66
+ @clear = @helper.parameter_specified? 'clear'
67
+ @class = @helper.parameter_specified? 'class'
68
+ @highlight = @helper.parameter_specified? 'highlight'
69
+ @make_copy_button = @helper.parameter_specified? 'copyButton'
70
+ @number_lines = @helper.parameter_specified? 'number'
71
+ @dark = ' dark' if @helper.parameter_specified? 'dark'
72
+ @style = @helper.parameter_specified? 'style'
73
+ @label = @helper.parameter_specified? 'label'
74
+
75
+ # If a label was specified, use it, otherwise concatenate any dangling parameters and use that as the label
76
+ @label ||= @helper.argv.join(' ')
77
+
78
+ @logger.debug { "@make_copy_button = '#{@make_copy_button}'; @label = '#{@label}'" }
79
+ self.class.make_pre(@make_copy_button, @number_lines, @label, @dark, @highlight, @class, @style, @clear, text)
80
+ end
81
+
82
+ JekyllPluginHelper.register(self, 'pre')
83
+ end
84
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll_pre
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Slinn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-02-17 00:00:00.000000000 Z
11
+ date: 2023-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
@@ -54,8 +54,11 @@ files:
54
54
  - README.md
55
55
  - Rakefile
56
56
  - jekyll_pre.gemspec
57
+ - lib/exec_tag.rb
57
58
  - lib/jekyll_pre.rb
58
59
  - lib/jekyll_pre/version.rb
60
+ - lib/noselect_tag.rb
61
+ - lib/pre_tag_block.rb
59
62
  - spec/pre_spec.rb
60
63
  - spec/spec_helper.rb
61
64
  - spec/status_persistence.txt