jektex 0.0.3 → 0.0.6

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: daa553320105731fb20840fc40d211a73f576f6847b8b3de0019d72313ac0c97
4
- data.tar.gz: 4479c3dc694c196845460e4ed63263ad5bb900ed9b3a42fe68e4900001dfccda
3
+ metadata.gz: 476a24b916af7e71a30a60cd2476063fa2d627959060179104e8a41871c5d4ab
4
+ data.tar.gz: 93243e4af6fea3e355f0cc4401e990cdb107f77c717b7e63d4902a172b56a7d0
5
5
  SHA512:
6
- metadata.gz: 42333a3f6325918d8e1da7c6dd983c3f8404d10b2ae84449076ba768846793ec992af35e6962ebde5c3ae2619dfc2f4c3211370d9c75f6f6883707fbdf355c03
7
- data.tar.gz: 24849a110d4ac120fcccab47f357d0c74ae8f7d640dbcd21c7741dc7cf88096aaef6afe088b99a486fe9589e6f67afa13703f09f395ad5c157f6b3ee542c8672
6
+ metadata.gz: d0ae577416fec788441659e670f4e85c0b34c091c81f666ab1cd62f5a39b3500548efb4238f53d77f1ea0dd30bd3571f001aa418311dcf6786a70afbbd3d0e8c
7
+ data.tar.gz: a7feff881708ffb27bffb76c2f00146c0bb4f7f4a90fe341ea88f121f1442ace72294596112f8c139e9a5628f4f14f0022e2f18dabe5a7e15e56e985d31c9d73
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Gem Version](https://badge.fury.io/rb/jektex.svg)](https://rubygems.org/gems/jektex)
2
+
1
3
  # Jektex
2
4
  Jekyll plugin for blazing fast server side cached LaTeX rendering with support of macros.
3
5
  Enjoy comfort of latex and markdown without cluttering your site with bloated javascript.
@@ -13,14 +15,14 @@ Enjoy comfort of latex and markdown without cluttering your site with bloated ja
13
15
  - Does not interfere with Jekyll workflow and project structure
14
16
  - Marks invalid syntax in document
15
17
  - Prints location of invalid expression during rendering
16
- - Tags places within the rendered documents with syntax errors
18
+ - Highly configurable but still having sensible defaults
19
+ - Makes sure that cache does not contain expression rendered with outdated configuration
17
20
 
18
21
  ## Usage
19
22
 
20
23
  ### Notation
21
24
  **Inline formula**
22
25
  Put formula between two pairs of dolar signs (`$$`) inside of paragraph.
23
-
24
26
  ```latex
25
27
  Lorem ipsum dolor sit amet, consectetur $$e^{i\theta}=\cos(\theta)+i\sin(\theta)$$
26
28
  adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
@@ -43,31 +45,87 @@ display mode?
43
45
  This is how [kramdown](https://kramdown.gettalong.org/)(Jekyll's markdown parser) works
44
46
  so I decided to respect this convention. It makes this plugin more consistent and universal._
45
47
 
46
- ### Macros
47
- You can define global macros in your `_config.yml` file:
48
+ ### Config
49
+ Jektex si highly configurable from your `_config.yml` file
50
+
51
+ **Disabling cache**
52
+ You can disable caching with `disable_disk_cache = true` in `_config.yml`. Cache is
53
+ enabled by default. You can find more information on [Jekyll official website](https://jekyllrb.com/docs/configuration/options/).
54
+
55
+ **Setting cache location**
56
+ By default jektex cache will be saved in `.jekyll-cache` directory. This results in it's
57
+ deletion when you call `jekyll clean`. To prevent cache deletion or you just want to
58
+ change location of cache for another reason you can achieve that by specifying
59
+ `cache_dir` in `_config.yml`.
60
+ ```yaml
61
+ # Jektex cache dir location
62
+ jektex:
63
+ cache_dir: ".jektex-cache"
64
+ ```
65
+
66
+ **Ignore**
67
+ By default jektex tries to render LaTeX in all files not excluded by Jekyll. But
68
+ sometimes you get in situation when you do not want to render some files. For example
69
+ _RSS feed_ with excerpts containing LaTeX. As a solution jektex offers `ignore` option.
70
+ You can use conventional wild cards using `*`. For example:
71
+ ```yaml
72
+ # Jektex ignore files
73
+ jektex:
74
+ ignore: ["*.xml", "README.md", "_drafts/*" ]
75
+ ```
76
+
77
+ This example configuration ignores all `.xml` files, `README.md` and all files
78
+ in `_drafts` directory.
79
+
80
+ Another option for ignoring specific posts is setting `jektex` tag in front matter of
81
+ post to `false`. For example:
82
+ ```yaml
83
+ ---
84
+ title: "How Jektex works"
85
+ category: "Development"
86
+ jektex: false
87
+ layout: post
88
+ ---
89
+ ```
90
+
91
+ Setting `jektex` tag to `true` or not setting at all will result in jektex rendering LaTeX
92
+ expressions in that post.
48
93
 
94
+ **Macros**
95
+ You can define global macros like this:
49
96
  ```yaml
50
97
  # Jektex macros
51
- jektex-macros:
98
+ jektex:
99
+ macros:
52
100
  - ["\\Q", "\\mathbb{Q}"]
53
101
  - ["\\C", "\\mathbb{C}"]
54
102
  ```
103
+ And yes you have to escape backlash(`\`) with another backlash. This is caused by
104
+ [yaml definition](https://yaml.org/).
55
105
 
56
- ### Cache control
57
-
58
- **Clearing cache**
59
- To clear cached expressions you have to delete `.jektex-cache` directory in your
60
- project directory.
61
-
62
- **Disabling cache**
63
- You can disable caching with `disable_disk_cache = false` in `_config.yml`.
106
+ **Complete examples**
107
+ Recommended config:
108
+ ```yaml
109
+ jektex:
110
+ cache_dir: ".jektex-cache"
111
+ ignore: ["*.xml"]
112
+ macros:
113
+ - ["\\Q", "\\mathbb{Q}"]
114
+ - ["\\C", "\\mathbb{C}"]
115
+ ```
116
+ Having no configuration is equivalent to this:
117
+ ```yaml
118
+ jektex:
119
+ cache_dir: ".jekyll-cache"
120
+ ignore: []
121
+ macros: []
122
+ ```
64
123
 
65
124
  ## Installation
66
125
  This plugin is available as a [RubyGem](https://rubygems.org/gems/jektex).
67
126
 
68
127
  **Using bundler**
69
128
  Add `jektex` to your `Gemfile` like this:
70
-
71
129
  ```ruby
72
130
  group :jekyll_plugins do
73
131
  gem "jektex"
@@ -90,6 +148,9 @@ and do not forget to add `katex.min.css` to you html head:
90
148
  ```html
91
149
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css" integrity="sha384-MlJdn/WNKDGXveldHDdyRP1R4CTHr3FeuDNfhsLPYrq2t0UBkUdK2jyTnXPEK1NQ" crossorigin="anonymous">
92
150
  ```
93
- It is much better practice to download **css** file and loaded as an asset from your server directly.
151
+ It is much better practice to download [**css** file](https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css) and load it as an asset from your server directly.
94
152
  You can find more information on [KaTeX's website](https://katex.org/docs/browser.html).
95
153
 
154
+ ## Contributions and bug reports
155
+ Feel free to repost any bugs or even make feature request in [issues on official repository](https://github.com/yagarea/jektex/issues).
156
+ I am opened for pull requests as well.
data/lib/jektex/jektex.rb CHANGED
@@ -3,108 +3,148 @@ require 'digest'
3
3
  require 'htmlentities'
4
4
 
5
5
 
6
- PATH_TO_JS = __dir__ + "/katex.min.js"
7
- CACHE_DIR = "./.jektex-cache/"
6
+ PATH_TO_JS = File.join(__dir__, "/katex.min.js")
7
+ DEFAULT_CACHE_DIR = ".jekyll-cache"
8
8
  CACHE_FILE = "jektex-cache.marshal"
9
- PATH_TO_CACHE = CACHE_DIR + CACHE_FILE
10
9
  KATEX = ExecJS.compile(open(PATH_TO_JS).read)
11
10
  PARSE_ERROR_PLACEHOLDER = "<b style='color: red;'>PARSE ERROR</b>"
11
+ FRONT_MATTER_TAG = "jektex"
12
+ INDENT = " " * 13
13
+
12
14
  $global_macros = Hash.new
15
+ $updated_global_macros = Array.new
16
+
13
17
  $count_newly_generated_expressions = 0
18
+
19
+ $path_to_cache = File.join(DEFAULT_CACHE_DIR, CACHE_FILE)
14
20
  $cache = nil
15
21
  $disable_disk_cache = false
16
22
 
17
- def convert(page)
23
+ $ignored = Array.new
24
+
25
+ def get_list_of_updated_global_macros(current_macros, cached_global_macros)
26
+ return Array.new unless cached_global_macros || current_macros
27
+ return current_macros.keys unless cached_global_macros
28
+ return cached_global_macros.keys unless current_macros
29
+
30
+ macro_set = Set.new(cached_global_macros.keys + current_macros.keys)
31
+ macro_set.delete_if { |m| cached_global_macros[m] == current_macros[m] }
32
+ return macro_set.to_a
33
+ end
34
+
35
+ def is_ignored?(page)
36
+ return true if page.data[FRONT_MATTER_TAG] == "false"
37
+ return $ignored.any? { |patern| File.fnmatch?(patern, page.relative_path, File::FNM_DOTMATCH) }
38
+ end
39
+
40
+ def contains_updated_global_macro?(expression)
41
+ return $updated_global_macros.any? { |m| expression[m] }
42
+ end
43
+
44
+ def print_stats
45
+ print "#{INDENT}LaTeX: " \
46
+ "#{$count_newly_generated_expressions} expressions rendered " \
47
+ "(#{$cache.size} already cached)".ljust(72) + "\r"
48
+ $stdout.flush
49
+ end
50
+
51
+ def render(page)
52
+ # check if document is not set to be ignored
53
+ return page.output if !page.data || is_ignored?(page)
18
54
  # convert HTML entities back to characters
19
55
  post = HTMLEntities.new.decode(page.output.to_s)
20
- post = post.gsub(/(\\\()((.|\n)*?)(?<!\\)\\\)/) { |m| escape_method($1, $2, page.path) }
21
- post = post.gsub(/(\\\[)((.|\n)*?)(?<!\\)\\\]/) { |m| escape_method($1, $2, page.path) }
56
+ # render inline expressions
57
+ post = post.gsub(/(\\\()((.|\n)*?)(?<!\\)\\\)/) { |m| escape_method($1, $2, page.relative_path) }
58
+ # render display mode expressions
59
+ post = post.gsub(/(\\\[)((.|\n)*?)(?<!\\)\\\]/) { |m| escape_method($1, $2, page.relative_path) }
22
60
  return post
23
61
  end
24
62
 
25
- def escape_method( type, string, doc_path )
26
- @display = false
27
-
28
- # detect if expression is display view
29
- case type.downcase
30
- when /\(/
31
- @display = false
32
- else /\[/
33
- @display = true
34
- end
63
+ def escape_method( type, expression, doc_path )
64
+ # detect if expression is in display mode
65
+ is_in_display_mode? = type.downcase =~ /\[/
35
66
 
36
67
  # generate a hash from the math expression
37
- @expression_hash = Digest::SHA2.hexdigest(string) + @display.to_s
68
+ expression_hash = Digest::SHA2.hexdigest(string) + is_in_display_mode?.to_s
38
69
 
39
70
  # use it if it exists
40
- if($cache.has_key?(@expression_hash))
71
+ if($cache.has_key?(expression_hash) && !contains_updated_global_macro?(string))
72
+ # check if expressin conains updated macro
41
73
  $count_newly_generated_expressions += 1
42
74
  print_stats
43
- return $cache[@expression_hash]
75
+ return $cache[expression_hash]
44
76
 
45
77
  # else generate one and store it
46
78
  else
47
79
  # create the cache directory, if it doesn't exist
48
80
  begin
49
81
  # render using ExecJS
50
- @result = KATEX.call("katex.renderToString", string,
51
- {displayMode: @display, macros: $global_macros})
82
+ result = KATEX.call("katex.renderToString", expression,
83
+ {is_in_display_mode?Mode: is_in_display_mode?, macros: $global_macros})
52
84
  rescue SystemExit, Interrupt
53
85
  # save cache to disk
54
- File.open(PATH_TO_CACHE, "w"){|to_file| Marshal.dump($cache, to_file)}
55
- # this stops jekyll being immune to interupts and kill command
86
+ File.open($path_to_cache, "w"){|to_file| Marshal.dump($cache, to_file)}
87
+ # this stops jekyll being immune to interrupts and kill command
56
88
  raise
57
- rescue Exception => e
89
+ rescue ExecJS::ProgramError => pe
58
90
  # catch parse error
59
- puts "\e[31m " + e.message.gsub("ParseError: ", "") + "\n\t" + doc_path + "\e[0m"
91
+ puts "\e[31m " + pe.message.gsub("ParseError: ", "") + "\n\t" + doc_path + "\e[0m"
60
92
  return PARSE_ERROR_PLACEHOLDER
61
93
  end
62
94
  # save to cache
63
- $cache[@expression_hash] = @result
95
+ $cache[expression_hash] = @result
64
96
  # update count of newly generated expressions
65
97
  $count_newly_generated_expressions += 1
66
98
  print_stats
67
- return @result
99
+ return result
68
100
  end
69
101
  end
70
102
 
71
- def print_stats
72
- print " LaTeX: " +
73
- ($count_newly_generated_expressions).to_s +
74
- " expressions rendered (" + $cache.size.to_s +
75
- " already cached) \r"
76
- $stdout.flush
103
+ Jekyll::Hooks.register :pages, :post_render do |page|
104
+ page.output = render(page)
77
105
  end
78
106
 
79
- Jekyll::Hooks.register :pages, :post_render do |page|
80
- page.output = convert(page)
107
+ Jekyll::Hooks.register :documents, :post_render do |doc|
108
+ doc.output = render(doc)
81
109
  end
82
110
 
83
111
  Jekyll::Hooks.register :site, :after_init do |site|
84
- # load macros from config file
85
- if site.config["jektex-macros"] != nil
86
- for macro_definition in site.config["jektex-macros"]
87
- $global_macros[macro_definition[0]] = macro_definition[1]
88
- end
89
- end
90
- # print macro information
91
- if $global_macros.size == 0
92
- puts " LaTeX: no macros loaded"
112
+ # load jektex config from config file and if no config is defined make empty one
113
+ config = site.config["jektex"] || Hash.new
114
+
115
+ # check if there is defined custom cache location in config
116
+ $path_to_cache = File.join(config["cache_dir"].to_s, CACHE_FILE) if config.has_key?("cache_dir")
117
+
118
+ # load content of cache file if it exists
119
+ if File.exist?($path_to_cache)
120
+ $cache = File.open($path_to_cache, "r"){ |from_file| Marshal.load(from_file)}
93
121
  else
94
- puts " LaTeX: " + $global_macros.size.to_s + " macro" +
95
- ($global_macros.size == 1 ? "" : "s") + " loaded"
122
+ $cache = Hash.new
96
123
  end
97
124
 
98
- if site.config["disable_disk_cache"] != nil
99
- $disable_disk_cache = site.config["disable_disk_cache"]
125
+ # check if cache is disable in config
126
+ $disable_disk_cache = site.config["disable_disk_cache"] if site.config.has_key?("disable_disk_cache")
127
+
128
+ # load macros
129
+ if config.has_key?("macros")
130
+ for macro_definition in config["macros"]
131
+ $global_macros[macro_definition[0]] = macro_definition[1]
132
+ end
100
133
  end
101
134
 
102
- # load content of cache file if it exists
103
- if(File.exist?(PATH_TO_CACHE))
104
- $cache = File.open(PATH_TO_CACHE, "r"){|from_file| Marshal.load(from_file)}
135
+ # make list of updated macros
136
+ $updated_global_macros = get_list_of_updated_global_macros($global_macros, $cache["cached_global_macros"])
137
+ # print macro information
138
+ if $global_macros.empty?
139
+ puts "#{INDENT}LaTeX: no macros loaded"
105
140
  else
106
- $cache = Hash.new
141
+ puts "#{INDENT}LaTeX: #{$global_macros.size} macro" +
142
+ ($global_macros.size == 1 ? "" : "s") + " loaded" +
143
+ ($updated_global_macros.empty? ? "" : " (#{$updated_global_macros.size} updated)")
107
144
  end
145
+
146
+ # load list of ignored files
147
+ $ignored = config["ignore"] if config.has_key?("ignore")
108
148
  end
109
149
 
110
150
  Jekyll::Hooks.register :site, :after_reset do
@@ -116,9 +156,13 @@ Jekyll::Hooks.register :site, :post_write do
116
156
  # print new line to prevent overwriting previous output
117
157
  print "\n"
118
158
  # check if caching is enabled
119
- if $disable_disk_cache == false
159
+ if !$disable_disk_cache
160
+ # save global macros to cache
161
+ $cache["cached_global_macros"] = $global_macros
162
+ # create cache path
163
+ Pathname.new($path_to_cache).dirname.mkpath
120
164
  # save cache to disk
121
- Dir.mkdir(CACHE_DIR) unless File.exists?(CACHE_DIR)
122
- File.open(PATH_TO_CACHE, "w"){|to_file| Marshal.dump($cache, to_file)}
165
+ File.open($path_to_cache, "w"){|to_file| Marshal.dump($cache, to_file)}
123
166
  end
124
167
  end
168
+
@@ -1,3 +1,3 @@
1
1
  module Jektex
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.6"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jektex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Černý
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-18 00:00:00.000000000 Z
11
+ date: 2022-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: execjs
@@ -108,7 +108,7 @@ licenses:
108
108
  - GPL-3.0-or-later
109
109
  metadata:
110
110
  bug_tracker_uri: https://github.com/yagarea/jektex/issues
111
- documentation_uri: https://github.com/yagarea/jektex
111
+ documentation_uri: https://github.com/yagarea/jektex/blob/master/README.md
112
112
  homepage_uri: https://github.com/yagarea/jektex
113
113
  source_code_uri: https://github.com/yagarea/jektex
114
114
  changelog_uri: https://github.com/yagarea/jektex/blob/master/changelog.md