jekyll_pre 1.2.1 → 1.2.3

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