jekyll-pseudocode-latex 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: edc827f76e4159ad63393e9c3cbbac8f9fac37847135d14855f68fd88c2e5e22
4
+ data.tar.gz: 759e33d237d4fbaa61c1f7a9b0b8b4a51092c66f323091dd129a81c5b8b8fd4b
5
+ SHA512:
6
+ metadata.gz: 210fe9e506dfdba43c09769af31d5538b1f5d8f577ef2d45804484114b702bd62887a2f7eca11e0ebabc7aaa435aed2e8b3172bedd831a3219362e3bcaa41dd0
7
+ data.tar.gz: e87a088f37cda6c87d73bc53e41b7cf92a11cb916abac772fb7e27f4cb81f4318c88d4341b476930470120922469d9e133d104b65436b4cea33b7a4bf7ece907
data/README.md ADDED
@@ -0,0 +1,218 @@
1
+ # Jekyll Pseudocode Plugin
2
+
3
+ A Jekyll plugin to render pseudocode blocks using a simplified syntax similar to LaTeX.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your Jekyll site's `Gemfile`:
8
+
9
+ ```ruby
10
+ gem "jekyll-pseudocode"
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```bash
22
+ gem install jekyll-pseudocode
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ 1. **Create a Pseudocode Block:**
28
+
29
+ Use the `pseudocode` tag in your Markdown files to create a pseudocode block. Here is an example:
30
+
31
+ ```markdown
32
+ ---
33
+ title: Quicksort Algorithm
34
+ ---
35
+
36
+ {% pseudocode %}
37
+ % This quicksort algorithm is extracted from Chapter 7, Introduction to Algorithms (3rd edition)
38
+ \begin{algorithm}
39
+ \caption{Quicksort}
40
+ \begin{algorithmic}
41
+ \PROCEDURE{Quicksort}{$A, p, r$}
42
+ \IF{$p < r$}
43
+ \STATE $q = $ \CALL{Partition}{$A, p, r$}
44
+ \STATE \CALL{Quicksort}{$A, p, q - 1$}
45
+ \STATE \CALL{Quicksort}{$A, q + 1, r$}
46
+ \ENDIF
47
+ \ENDPROCEDURE
48
+ \PROCEDURE{Partition}{$A, p, r$}
49
+ \STATE $x = A[r]$
50
+ \STATE $i = p - 1$
51
+ \FOR{$j = p$ \TO $r - 1$}
52
+ \IF{$A[j] < x$}
53
+ \STATE $i = i + 1$
54
+ \STATE exchange $A[i]$ with $A[j]$
55
+ \ENDIF
56
+ \ENDFOR
57
+ \STATE exchange $A[i]$ with $A[r]$
58
+ \ENDPROCEDURE
59
+ \end{algorithmic}
60
+ \end{algorithm}
61
+ {% endpseudocode %}
62
+ ```
63
+
64
+ 2. **Copy the CSS File:**
65
+
66
+ Ensure you have the CSS file in `assets/css/pseudocode.css` with the following content. You can copy it from the plugin repository:
67
+
68
+ ```css
69
+ .ps-root {
70
+ font-family: MJXZERO, MJXTEX;
71
+ font-size: 1em;
72
+ font-weight: 100;
73
+ -webkit-font-smoothing: antialiased !important;
74
+ }
75
+
76
+ .ps-root .ps-algorithm {
77
+ margin: .8em 0;
78
+ border-top: 3px solid #000;
79
+ border-bottom: 2px solid #000;
80
+ }
81
+
82
+ .ps-root .ps-algorithm.with-caption {
83
+ border-bottom: 2px solid #000;
84
+ }
85
+
86
+ .ps-root .ps-indent-1 {
87
+ margin-left: 1em;
88
+ }
89
+
90
+ .ps-root .ps-indent-2 {
91
+ margin-left: 2em;
92
+ }
93
+
94
+ .ps-root .ps-indent-3 {
95
+ margin-left: 3em;
96
+ }
97
+
98
+ .ps-root .ps-indent-4 {
99
+ margin-left: 4em;
100
+ }
101
+
102
+ .ps-root .ps-indent-5 {
103
+ margin-left: 5em;
104
+ }
105
+
106
+ .ps-root .ps-caption {
107
+ display: block;
108
+ border-bottom: 2px solid #000;
109
+ margin-top: 4px !important;
110
+ margin-bottom: 0.5em;
111
+ }
112
+
113
+ .ps-root .MathJax, .ps-root .MathJax_CHTML {
114
+ text-indent: 0;
115
+ font-size: 1em !important;
116
+ }
117
+
118
+ .ps-root .ps-line {
119
+ margin: 0;
120
+ padding: 0;
121
+ line-height: 1.2;
122
+ }
123
+
124
+ .ps-root .ps-funcname {
125
+ font-family: MJXZERO, MJXTEX;
126
+ font-weight: 400;
127
+ font-style: normal;
128
+ text-transform: none;
129
+ }
130
+
131
+ .ps-root .ps-keyword {
132
+ font-family: MJXZERO, MJXTEX;
133
+ font-weight: 700;
134
+ font-style: normal;
135
+ text-transform: none;
136
+ }
137
+
138
+ .ps-root .ps-comment {
139
+ font-family: MJXZERO, MJXTEX;
140
+ font-weight: 400;
141
+ font-style: normal;
142
+ text-transform: none;
143
+ }
144
+
145
+ .ps-root .ps-linenum {
146
+ font-size: .8em;
147
+ line-height: 1em;
148
+ width: 1.6em;
149
+ text-align: right;
150
+ display: inline-block;
151
+ position: relative;
152
+ padding-right: .3em;
153
+ }
154
+
155
+ .ps-root .ps-algorithmic.with-linenum .ps-line.ps-code {
156
+ text-indent: -1.6em;
157
+ }
158
+
159
+ .ps-root .ps-algorithmic.with-linenum .ps-line.ps-code > span {
160
+ text-indent: 0;
161
+ }
162
+
163
+ .ps-root .ps-algorithmic.with-scopelines .ps-block {
164
+ border-left-style: solid;
165
+ border-left-width: .1em;
166
+ padding-left: .6em;
167
+ }
168
+
169
+ .ps-root .ps-algorithmic.with-scopelines > .ps-block {
170
+ border-left: none;
171
+ }
172
+ ```
173
+
174
+ 3. **Update `_config.yml`:**
175
+
176
+ Add the following line to your `_config.yml` file to include the CSS file:
177
+
178
+ ```yaml
179
+ site-css:
180
+ - "/assets/css/pseudocode.css"
181
+ ```
182
+
183
+ 4. **Include the CSS and MathJax in Your Pages or Layouts:**
184
+
185
+ Add the following lines to the HTML of your pages or layouts to include the CSS and MathJax:
186
+
187
+ ```html
188
+ <link rel="stylesheet" href="assets/css/pseudocode.css">
189
+ <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
190
+ <script>
191
+ window.MathJax = {
192
+ tex: {
193
+ inlineMath: [['$', '$'], ['\\(', '\\)']]
194
+ },
195
+ svg: {
196
+ fontCache: 'global'
197
+ }
198
+ };
199
+
200
+ (function () {
201
+ var script = document.createElement('script');
202
+ script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js';
203
+ script.async = true;
204
+ document.head.appendChild(script);
205
+ })();
206
+ </script>
207
+ ```
208
+
209
+ 5. **Build and Serve Your Site:**
210
+
211
+ Rebuild and serve your Jekyll site to see the changes:
212
+
213
+ ```bash
214
+ bundle exec jekyll serve
215
+ ```
216
+
217
+ By following these instructions, you'll be able to use the Jekyll pseudocode plugin in your site. If you encounter any issues, please refer to the plugin repository for additional troubleshooting and support.
218
+ ```
@@ -0,0 +1,104 @@
1
+ .ps-root {
2
+ font-family: MJXZERO, MJXTEX;
3
+ font-size: 1em;
4
+ font-weight: 100;
5
+ -webkit-font-smoothing: antialiased !important;
6
+ }
7
+
8
+ .ps-root .ps-algorithm {
9
+ margin: .8em 0;
10
+ border-top: 3px solid #000;
11
+ border-bottom: 2px solid #000;
12
+ }
13
+
14
+ .ps-root .ps-algorithm.with-caption {
15
+ border-bottom: 2px solid #000;
16
+ }
17
+
18
+ .ps-root .ps-indent-1 {
19
+ margin-left: 1em;
20
+ }
21
+
22
+ .ps-root .ps-indent-2 {
23
+ margin-left: 2em;
24
+ }
25
+
26
+ .ps-root .ps-indent-3 {
27
+ margin-left: 3em;
28
+ }
29
+
30
+ .ps-root .ps-indent-4 {
31
+ margin-left: 4em;
32
+ }
33
+
34
+ .ps-root .ps-indent-5 {
35
+ margin-left: 5em;
36
+ }
37
+
38
+
39
+ .ps-root .ps-caption {
40
+ display: block;
41
+ border-bottom: 2px solid #000;
42
+ margin-top: 4px!important;
43
+ margin-bottom: 0.5em;
44
+ }
45
+
46
+ .ps-root .MathJax, .ps-root .MathJax_CHTML {
47
+ text-indent: 0;
48
+ font-size: 1em !important;
49
+ }
50
+
51
+ .ps-root .ps-line {
52
+ margin: 0;
53
+ padding: 0;
54
+ line-height: 1.2;
55
+ }
56
+
57
+ .ps-root .ps-funcname {
58
+ font-family: MJXZERO, MJXTEX;
59
+ font-weight: 400;
60
+ font-style: normal;
61
+ text-transform: none;
62
+ }
63
+
64
+ .ps-root .ps-keyword {
65
+ font-family: MJXZERO, MJXTEX;
66
+ font-weight: 700;
67
+ font-style: normal;
68
+ text-transform: none;
69
+ }
70
+
71
+ .ps-root .ps-comment {
72
+ font-family: MJXZERO, MJXTEX;
73
+ font-weight: 400;
74
+ font-style: normal;
75
+ text-transform: none;
76
+ }
77
+
78
+ .ps-root .ps-linenum {
79
+ font-size: .8em;
80
+ line-height: 1em;
81
+ width: 1.6em;
82
+ text-align: right;
83
+ display: inline-block;
84
+ position: relative;
85
+ padding-right: .3em;
86
+ }
87
+
88
+ .ps-root .ps-algorithmic.with-linenum .ps-line.ps-code {
89
+ text-indent: -1.6em;
90
+ }
91
+
92
+ .ps-root .ps-algorithmic.with-linenum .ps-line.ps-code > span {
93
+ text-indent: 0;
94
+ }
95
+
96
+ .ps-root .ps-algorithmic.with-scopelines .ps-block {
97
+ border-left-style: solid;
98
+ border-left-width: .1em;
99
+ padding-left: .6em;
100
+ }
101
+
102
+ .ps-root .ps-algorithmic.with-scopelines > .ps-block {
103
+ border-left: none;
104
+ }
@@ -0,0 +1,181 @@
1
+ require 'jekyll'
2
+ require 'liquid'
3
+ require 'rexml/document'
4
+
5
+ module Jekyll
6
+ class PseudocodeBlock < Liquid::Block
7
+ @@number = 0
8
+
9
+ def initialize(tag_name, text, tokens)
10
+ super
11
+ end
12
+
13
+ def render(context)
14
+ content = super
15
+ @@number += 1
16
+ content = process_pseudocode(content)
17
+ "<div class='ps-root'>#{content}</div>"
18
+ end
19
+
20
+ def process_pseudocode(content)
21
+ open_divs = []
22
+ indent_level = 0
23
+ content_lines = content.strip.split("\n")
24
+ html_lines = []
25
+
26
+ call_pattern = /\\CALL\{(.*?)\}\{(.*?)\}/
27
+
28
+ replace_calls = lambda do |statement|
29
+ statement.gsub(call_pattern) { |match| "<span class='ps-call'><span class='ps-funcname'>#{Regexp.last_match(1)}</span>(#{Regexp.last_match(2)})</span>" }
30
+ end
31
+
32
+ wrap_math_expressions = lambda do |statement|
33
+ statement.gsub(/\$(.*?)\$/, '<span class="arithmatex">\\(\1\\)</span>')
34
+ end
35
+
36
+ process_control_statement = lambda do |keyword, condition|
37
+ condition = wrap_math_expressions.call(condition)
38
+ additional_keyword = keyword == "if" ? "then" : "do"
39
+ if keyword == "for"
40
+ condition = condition.gsub(/\\TO/, '<span class="ps-keyword">to</span>')
41
+ end
42
+ "<div class='ps-#{keyword.downcase} ps-indent-#{indent_level}'><span class='ps-keyword'>#{keyword.downcase}</span> (#{condition}) <span class='ps-keyword'>#{additional_keyword}</span>"
43
+ end
44
+
45
+ content_lines.each do |line|
46
+ stripped_line = line.strip
47
+
48
+ case stripped_line
49
+ when /\\begin{algorithm}/
50
+ html_lines << "<div class='ps-algorithm'>"
51
+ open_divs << 'algorithm'
52
+ when /\\end{algorithm}/
53
+ if open_divs.last == 'algorithm'
54
+ html_lines << "</div>"
55
+ open_divs.pop
56
+ end
57
+ when /\\caption{(.*?)}/
58
+ caption = stripped_line.match(/\\caption{(.*?)}/)[1]
59
+ html_lines[-1] = "<div class='ps-algorithm with-caption'><div class='ps-caption'><span class='ps-keyword'>Algorithm #{@@number}</span> #{caption}</div>"
60
+ when /\\begin{algorithmic}/
61
+ html_lines << "<div class='ps-algorithmic'>"
62
+ open_divs << 'algorithmic'
63
+ when /\\end{algorithmic}/
64
+ if open_divs.last == 'algorithmic'
65
+ html_lines << "</div>"
66
+ open_divs.pop
67
+ end
68
+ when /\\PROCEDURE{(.*?)}{(.*?)}/
69
+ procedure_name = stripped_line.match(/\\PROCEDURE{(.*?)}{(.*?)}/)[1]
70
+ params = stripped_line.match(/\\PROCEDURE{(.*?)}{(.*?)}/)[2]
71
+ params = wrap_math_expressions.call(params)
72
+ html_lines << "<div class='ps-procedure ps-indent-#{indent_level}'><span class='ps-keyword'>procedure </span><span class='ps-funcname'>#{procedure_name}</span>(#{params})"
73
+ open_divs << 'procedure'
74
+ indent_level += 1
75
+ when /\\ENDPROCEDURE/
76
+ if open_divs.last == 'procedure'
77
+ indent_level -= 1
78
+ html_lines << "<div class='ps-keyword'>end procedure</div></div>"
79
+ open_divs.pop
80
+ end
81
+ when /\\IF{(.*?)}/
82
+ condition = stripped_line.match(/\\IF{(.*?)}/)[1]
83
+ statement = process_control_statement.call('if', condition)
84
+ html_lines << statement
85
+ open_divs << 'if'
86
+ indent_level += 1
87
+ when /\\ENDIF/
88
+ if open_divs.last == 'if'
89
+ indent_level -= 1
90
+ html_lines << "<div class='ps-keyword'>end if</div></div>"
91
+ open_divs.pop
92
+ end
93
+ when /\\FOR{(.*?)}/
94
+ loop = stripped_line.match(/\\FOR{(.*?)}/)[1]
95
+ statement = process_control_statement.call('for', loop)
96
+ html_lines << statement
97
+ open_divs << 'for'
98
+ indent_level += 1
99
+ when /\\ENDFOR/
100
+ if open_divs.last == 'for'
101
+ indent_level -= 1
102
+ html_lines << "<div class='ps-keyword'>end for</div></div>"
103
+ open_divs.pop
104
+ end
105
+ when /\\FOREACH{(.*?)}/
106
+ loop = stripped_line.match(/\\FOREACH{(.*?)}/)[1]
107
+ statement = "<div class='ps-foreach ps-indent-#{indent_level}'><span class='ps-keyword'>for each</span> (#{wrap_math_expressions.call(loop)}) <span class='ps-keyword'>do</span>"
108
+ html_lines << statement
109
+ open_divs << 'foreach'
110
+ indent_level += 1
111
+ when /\\ENDFOREACH/
112
+ if open_divs.last == 'foreach'
113
+ indent_level -= 1
114
+ html_lines << "<div class='ps-keyword'>end for each</div></div>"
115
+ open_divs.pop
116
+ end
117
+ when /\\WHILE{(.*?)}/
118
+ condition = stripped_line.match(/\\WHILE{(.*?)}/)[1]
119
+ statement = process_control_statement.call('while', condition)
120
+ html_lines << statement
121
+ open_divs << 'while'
122
+ indent_level += 1
123
+ when /\\ENDWHILE/
124
+ if open_divs.last == 'while'
125
+ indent_level -= 1
126
+ html_lines << "<div class='ps-keyword'>end while</div></div>"
127
+ open_divs.pop
128
+ end
129
+ when /\\REPEAT{(.*?)}/
130
+ condition = stripped_line.match(/\\REPEAT{(.*?)}/)[1]
131
+ statement = process_control_statement.call('repeat', condition)
132
+ html_lines << statement
133
+ open_divs << 'repeat'
134
+ indent_level += 1
135
+ when /\\ENDREPEAT/
136
+ if open_divs.last == 'repeat'
137
+ indent_level -= 1
138
+ html_lines << "<div class='ps-keyword'>end repeat</div></div>"
139
+ open_divs.pop
140
+ end
141
+ when /\\ELSEIF{(.*?)}/
142
+ condition = stripped_line.match(/\\ELSEIF{(.*?)}/)[1]
143
+ statement = process_control_statement.call('elseif', condition)
144
+ html_lines << statement
145
+ if open_divs.last == 'if'
146
+ open_divs.pop
147
+ open_divs << 'elseif'
148
+ end
149
+ when /\\ELSE/
150
+ html_lines << "<div class='ps-else ps-indent-#{indent_level}'><span class='ps-keyword'>else</span>"
151
+ if open_divs.last == 'if' || open_divs.last == 'elseif'
152
+ open_divs.pop
153
+ open_divs << 'else'
154
+ end
155
+ when /\\STATE{(.*?)}/
156
+ statement = stripped_line.match(/\\STATE{(.*?)}/)[1]
157
+ statement = replace_calls.call(statement)
158
+ statement = wrap_math_expressions.call(statement)
159
+ html_lines << "<div class='ps-state ps-indent-#{indent_level}'>#{statement}</div>"
160
+ when /\\STATE\s+(.*)/
161
+ statement = stripped_line.match(/\\STATE\s+(.*)/)[1]
162
+ statement = replace_calls.call(statement)
163
+ statement = wrap_math_expressions.call(statement)
164
+ html_lines << "<div class='ps-state ps-indent-#{indent_level}'>#{statement}</div>"
165
+ when /\\CALL{(.*?)}{(.*?)}/
166
+ call = stripped_line.match(/\\CALL{(.*?)}{(.*?)}/)[1]
167
+ params = stripped_line.match(/\\CALL{(.*?)}{(.*?)}/)[2]
168
+ html_lines << "<div class='ps-call ps-indent-#{indent_level}'><span class='ps-funcname'>#{call}</span>(#{params})</div>"
169
+ else
170
+ html_lines << "<div class='ps-line ps-indent-#{indent_level}'>#{replace_calls.call(wrap_math_expressions.call(stripped_line))}</div>"
171
+ end
172
+ end
173
+
174
+ open_divs.reverse_each { |div| html_lines << "</div>" }
175
+
176
+ html_lines.join("\n")
177
+ end
178
+ end
179
+ end
180
+
181
+ Liquid::Template.register_tag('pseudocode', Jekyll::PseudocodeBlock)
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-pseudocode-latex
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jules Topart
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-06-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ description: This plugin allows you to write pseudocode blocks in your Jekyll site
28
+ using a simplified syntax similar to LaTeX. Make sure to include MathJax
29
+ email:
30
+ - jules.topart@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - README.md
36
+ - assets/css/pseudo-code.css
37
+ - lib/jekyll/pseudocode.rb
38
+ homepage: https://github.com/JulesTopart/jekyll-pseudocode-latex
39
+ licenses:
40
+ - MIT
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.5.11
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: A Jekyll plugin to render pseudocode blocks using latex format from MathJax.
61
+ test_files: []