jektex 0.0.3 → 0.0.6

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: 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