trmnl_preview 0.5.4 → 0.5.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 +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +25 -15
- data/lib/trmnlp/api_client.rb +17 -3
- data/lib/trmnlp/cli.rb +3 -1
- data/lib/trmnlp/commands/login.rb +3 -1
- data/lib/trmnlp/commands/pull.rb +4 -4
- data/lib/trmnlp/commands/push.rb +18 -12
- data/lib/trmnlp/config/app.rb +5 -1
- data/lib/trmnlp/config/plugin.rb +8 -7
- data/lib/trmnlp/version.rb +1 -1
- data/templates/init/bin/trmnlp +31 -0
- data/web/public/highlight/highlight.min.js +315 -0
- data/web/public/highlight/styles/atom-one-dark.min.css +1 -0
- data/web/public/index.css +20 -2
- data/web/public/trmnl-component.js +1 -1
- data/web/views/index.erb +6 -1
- metadata +5 -3
- data/templates/init/bin/dev +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: abf6757d447adc5c12e7eed3baa049bc80757bc536f0da60af8ccb624d4216d4
|
4
|
+
data.tar.gz: a533ae492f2ea9b71a55130977a88988ec3767c1393b2ebbbf618364a5a0f53b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a88985299e6c183a0ee61fa609f117dffad48b42e1abdd4c2ea8303051725f44fc411870d9b5999d0ce7b1f78e6923d10974cf79ea79787ed61212eed36c3aa4
|
7
|
+
data.tar.gz: bbdd8ac78d326b086eb56c8a66cf2aaf96096e1beb879ee951cda37b6f699cf14fc5d796fac34d4711b20c8d750075f38c1110d2829d0ebe1ed0d5fafa44c9c3
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.5.6
|
4
|
+
|
5
|
+
- Fixed bug that left blank plugins on server after upload failed
|
6
|
+
- Fixed bug creating upload.zip after previous upload had failed
|
7
|
+
- Added support to read API key fromk `TRMNL_API_KEY` environment variable (@andi4000)
|
8
|
+
- Fixed `init` command in Docker container (@jbarreiros)
|
9
|
+
- Automatically remove ephemeral Docker container after exit (@andi4000)
|
10
|
+
|
11
|
+
## 0.5.5
|
12
|
+
|
13
|
+
- Added dark mode (@stephenyeargin)
|
14
|
+
- Added override for `polling_url` in project config (@heroheman)
|
15
|
+
- Reworked `bin/dev` into more generic `bin/trmnlp`
|
16
|
+
- Fixed pull, push, and clone commands on Windows (@eugenio)
|
17
|
+
|
3
18
|
## 0.5.4
|
4
19
|
|
5
20
|
- Added `shared.liquid` file to template (@mariovisic)
|
data/README.md
CHANGED
@@ -31,11 +31,11 @@ This is the structure of a plugin project:
|
|
31
31
|
You can start building a plugin locally, then `push` it to the TRMNL server for display on your device.
|
32
32
|
|
33
33
|
```sh
|
34
|
-
trmnlp init my_plugin # generate
|
35
|
-
cd my_plugin
|
36
|
-
trmnlp serve
|
37
|
-
trmnlp login
|
38
|
-
trmnlp push
|
34
|
+
trmnlp init [my_plugin] # generate
|
35
|
+
cd [my_plugin]
|
36
|
+
trmnlp serve # develop locally
|
37
|
+
trmnlp login # authenticate
|
38
|
+
trmnlp push # upload
|
39
39
|
```
|
40
40
|
|
41
41
|
## Modifying an Existing Plugin
|
@@ -43,16 +43,26 @@ trmnlp push # upload
|
|
43
43
|
If you have built a plugin with the web-based editor, you can `clone` it, work on it locally, and `push` changes back to the server.
|
44
44
|
|
45
45
|
```sh
|
46
|
-
trmnlp login
|
47
|
-
trmnlp clone my_plugin [id] # first download
|
48
|
-
cd my_plugin
|
49
|
-
trmnlp serve
|
50
|
-
trmnlp push
|
46
|
+
trmnlp login # authenticate
|
47
|
+
trmnlp clone [my_plugin] [id] # first download
|
48
|
+
cd [my_plugin]
|
49
|
+
trmnlp serve # develop locally
|
50
|
+
trmnlp push # upload
|
51
51
|
```
|
52
52
|
|
53
|
+
## Authentication
|
54
|
+
|
55
|
+
The `trmnlp login` command saves your API key to `~/.config/trmnlp/config.yml`.
|
56
|
+
|
57
|
+
If an environment variable is more convenient (for example in a CI/CD pipeline), you can set `$TRMNL_API_KEY` instead.
|
58
|
+
|
53
59
|
## Running trmnlp
|
54
60
|
|
55
|
-
|
61
|
+
The `bin/trmnlp` script is provided as a convenience. It will use the local Ruby gem if available, falling back to the `trmnl/trmnlp` Docker image.
|
62
|
+
|
63
|
+
You can modify the `bin/trmnlp` script to set up environment variables (plugin secrets, etc.) before running the server.
|
64
|
+
|
65
|
+
### Installing via RubyGems
|
56
66
|
|
57
67
|
Prerequisites:
|
58
68
|
|
@@ -66,13 +76,13 @@ gem install trmnl_preview
|
|
66
76
|
trmnlp serve
|
67
77
|
```
|
68
78
|
|
69
|
-
###
|
79
|
+
### Installing via Docker
|
70
80
|
|
71
81
|
```sh
|
72
82
|
docker run \
|
73
|
-
|
74
|
-
|
75
|
-
trmnl/trmnlp
|
83
|
+
--publish 4567:4567 \
|
84
|
+
--volume ".:/plugin" \
|
85
|
+
trmnl/trmnlp serve
|
76
86
|
```
|
77
87
|
|
78
88
|
## `.trmnlp.yml` Reference - Project Config
|
data/lib/trmnlp/api_client.rb
CHANGED
@@ -18,20 +18,24 @@ module TRMNLP
|
|
18
18
|
temp_file.write(response.body)
|
19
19
|
temp_file.rewind
|
20
20
|
|
21
|
-
# return the
|
22
|
-
|
21
|
+
# return the temp file IO
|
22
|
+
temp_file
|
23
23
|
else
|
24
24
|
raise Error, "failed to download plugin settings archive: #{response.status} #{response.body}"
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def post_plugin_setting_archive(id, path)
|
29
|
+
filepart = Faraday::Multipart::FilePart.new(path, 'application/zip')
|
30
|
+
|
29
31
|
payload = {
|
30
|
-
file:
|
32
|
+
file: filepart
|
31
33
|
}
|
32
34
|
|
33
35
|
response = conn.post("plugin_settings/#{id}/archive", payload)
|
34
36
|
|
37
|
+
filepart.close
|
38
|
+
|
35
39
|
if response.status == 200
|
36
40
|
JSON.parse(response.body)
|
37
41
|
else
|
@@ -49,6 +53,16 @@ module TRMNLP
|
|
49
53
|
end
|
50
54
|
end
|
51
55
|
|
56
|
+
def delete_plugin_setting(id)
|
57
|
+
response = conn.delete("plugin_settings/#{id}")
|
58
|
+
|
59
|
+
if response.status == 204
|
60
|
+
true
|
61
|
+
else
|
62
|
+
raise Error, "failed to delete plugin setting: #{response.status} #{response.body}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
52
66
|
private
|
53
67
|
|
54
68
|
attr_reader :config
|
data/lib/trmnlp/cli.rb
CHANGED
@@ -14,6 +14,8 @@ module TRMNLP
|
|
14
14
|
|
15
15
|
def self.exit_on_failure? = true
|
16
16
|
|
17
|
+
def self.default_bind = File.exist?('/.dockerenv') ? '0.0.0.0' : '127.0.0.1'
|
18
|
+
|
17
19
|
desc 'build', 'Generate static HTML files'
|
18
20
|
def build
|
19
21
|
Commands::Build.new(options).call
|
@@ -52,7 +54,7 @@ module TRMNLP
|
|
52
54
|
end
|
53
55
|
|
54
56
|
desc 'serve', 'Start a local dev server'
|
55
|
-
method_option :bind, type: :string, default:
|
57
|
+
method_option :bind, type: :string, default: default_bind, aliases: '-b', desc: 'Bind address'
|
56
58
|
method_option :port, type: :numeric, default: 4567, aliases: '-p', desc: 'Port number'
|
57
59
|
def serve
|
58
60
|
Commands::Serve.new(options).call
|
@@ -6,7 +6,9 @@ module TRMNLP
|
|
6
6
|
def call
|
7
7
|
if config.app.logged_in?
|
8
8
|
anonymous_key = config.app.api_key[0..10] + '*' * (config.app.api_key.length - 11)
|
9
|
-
output "Currently authenticated as: #{anonymous_key}"
|
9
|
+
output "Currently authenticated as: #{anonymous_key}"
|
10
|
+
confirm = prompt("You are already authenticated. Do you want to re-authenticate? (y/N): ")
|
11
|
+
return unless confirm.strip.downcase == 'y'
|
10
12
|
end
|
11
13
|
|
12
14
|
output "Please visit #{config.app.account_uri} to grab your API key, then paste it here."
|
data/lib/trmnlp/commands/pull.rb
CHANGED
@@ -19,11 +19,11 @@ module TRMNLP
|
|
19
19
|
end
|
20
20
|
|
21
21
|
api = APIClient.new(config)
|
22
|
-
|
22
|
+
tempfile = api.get_plugin_setting_archive(plugin_settings_id)
|
23
23
|
size = 0
|
24
24
|
|
25
25
|
begin
|
26
|
-
Zip::File.open(
|
26
|
+
Zip::File.open(tempfile.path) do |zip_file|
|
27
27
|
zip_file.each do |entry|
|
28
28
|
dest_path = paths.src_dir.join(entry.name)
|
29
29
|
dest_path.dirname.mkpath
|
@@ -31,9 +31,9 @@ module TRMNLP
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
size = File.size(
|
34
|
+
size = File.size(tempfile.path)
|
35
35
|
ensure
|
36
|
-
|
36
|
+
tempfile.close
|
37
37
|
end
|
38
38
|
|
39
39
|
puts "Downloaded plugin (#{size} bytes)"
|
data/lib/trmnlp/commands/push.rb
CHANGED
@@ -11,6 +11,7 @@ module TRMNLP
|
|
11
11
|
authenticate!
|
12
12
|
|
13
13
|
is_new = false
|
14
|
+
zip_path = 'upload.zip'
|
14
15
|
|
15
16
|
api = APIClient.new(config)
|
16
17
|
|
@@ -27,20 +28,16 @@ module TRMNLP
|
|
27
28
|
raise Error, 'aborting' unless answer == 'y' || answer == 'yes'
|
28
29
|
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
Zip::File.open(temp_file.path, Zip::File::CREATE) do |zip_file|
|
34
|
-
paths.src_files.each do |file|
|
35
|
-
zip_file.add(File.basename(file), file)
|
36
|
-
end
|
31
|
+
Zip::File.open(zip_path, Zip::File::CREATE) do |zip_file|
|
32
|
+
paths.src_files.each do |file|
|
33
|
+
zip_file.add(File.basename(file), file)
|
37
34
|
end
|
38
|
-
|
39
|
-
response = api.post_plugin_setting_archive(plugin_settings_id, temp_file.path)
|
40
|
-
paths.plugin_config.write(response.dig('data', 'settings_yaml'))
|
41
|
-
|
42
|
-
size = File.size(temp_file.path)
|
43
35
|
end
|
36
|
+
|
37
|
+
response = api.post_plugin_setting_archive(plugin_settings_id, zip_path)
|
38
|
+
paths.plugin_config.write(response.dig('data', 'settings_yaml'))
|
39
|
+
|
40
|
+
size = File.size(zip_path)
|
44
41
|
|
45
42
|
output <<~HEREDOC
|
46
43
|
Uploaded plugin (#{size} bytes)
|
@@ -55,6 +52,15 @@ module TRMNLP
|
|
55
52
|
#{config.app.playlists_uri}
|
56
53
|
HEREDOC
|
57
54
|
end
|
55
|
+
rescue
|
56
|
+
if is_new && plugin_settings_id
|
57
|
+
output 'Error during creation, cleaning up...'
|
58
|
+
api.delete_plugin_setting(plugin_settings_id)
|
59
|
+
end
|
60
|
+
|
61
|
+
raise
|
62
|
+
ensure
|
63
|
+
File.delete(zip_path) if File.exist?(zip_path)
|
58
64
|
end
|
59
65
|
end
|
60
66
|
end
|
data/lib/trmnlp/config/app.rb
CHANGED
@@ -17,7 +17,11 @@ module TRMNLP
|
|
17
17
|
def logged_in? = api_key && !api_key.empty?
|
18
18
|
def logged_out? = !logged_in?
|
19
19
|
|
20
|
-
def api_key
|
20
|
+
def api_key
|
21
|
+
env_api_key = ENV['TRMNL_API_KEY']
|
22
|
+
return env_api_key if env_api_key && !env_api_key.empty?
|
23
|
+
@config['api_key']
|
24
|
+
end
|
21
25
|
|
22
26
|
def api_key=(key)
|
23
27
|
@config['api_key'] = key
|
data/lib/trmnlp/config/plugin.rb
CHANGED
@@ -3,9 +3,9 @@ require 'yaml'
|
|
3
3
|
module TRMNLP
|
4
4
|
class Config
|
5
5
|
class Plugin
|
6
|
-
def initialize(paths,
|
6
|
+
def initialize(paths, project_config)
|
7
7
|
@paths = paths
|
8
|
-
@
|
8
|
+
@project_config = project_config
|
9
9
|
reload!
|
10
10
|
end
|
11
11
|
|
@@ -23,11 +23,12 @@ module TRMNLP
|
|
23
23
|
def static? = strategy == 'static'
|
24
24
|
|
25
25
|
def polling_urls
|
26
|
-
|
26
|
+
# allow project-level config to override
|
27
|
+
urls = project_config.user_data_overrides.dig('trmnl', 'plugin_settings', 'polling_url') || @config['polling_url']
|
27
28
|
|
28
|
-
|
29
|
+
return [] if urls.nil?
|
29
30
|
|
30
|
-
urls.map { |url| with_custom_fields(url) }
|
31
|
+
urls.strip.split("\n").map { |url| with_custom_fields(url.strip) }
|
31
32
|
end
|
32
33
|
|
33
34
|
def polling_url_text = polling_urls.join("\r\n") # for {{ trmnl }}
|
@@ -56,9 +57,9 @@ module TRMNLP
|
|
56
57
|
|
57
58
|
private
|
58
59
|
|
59
|
-
attr_reader :paths, :
|
60
|
+
attr_reader :paths, :project_config
|
60
61
|
|
61
|
-
def with_custom_fields(value) =
|
62
|
+
def with_custom_fields(value) = project_config.with_custom_fields(value)
|
62
63
|
|
63
64
|
# copied from TRMNL core
|
64
65
|
def string_to_hash(str, delimiter: '=')
|
data/lib/trmnlp/version.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
#! /bin/bash
|
2
|
+
#
|
3
|
+
# This script was automatically generated by `trmnlp init` but it's yours to modify!
|
4
|
+
# Use this opportunity to set up environment variables, install dependencies, etc.
|
5
|
+
#
|
6
|
+
|
7
|
+
if command -v trmnlp &> /dev/null
|
8
|
+
then
|
9
|
+
trmnlp "$@"
|
10
|
+
exit
|
11
|
+
fi
|
12
|
+
|
13
|
+
if command -v docker &> /dev/null
|
14
|
+
then
|
15
|
+
docker run \
|
16
|
+
--rm \
|
17
|
+
--publish 4567:4567 \
|
18
|
+
--volume "$(pwd):/plugin" \
|
19
|
+
trmnl/trmnlp "$@"
|
20
|
+
exit
|
21
|
+
fi
|
22
|
+
|
23
|
+
echo "Install the trmnl_preview gem:
|
24
|
+
|
25
|
+
gem install trmnl_preview
|
26
|
+
|
27
|
+
Or install Docker:
|
28
|
+
|
29
|
+
https://docs.docker.com/get-docker/"
|
30
|
+
|
31
|
+
exit 1
|
@@ -0,0 +1,315 @@
|
|
1
|
+
/*!
|
2
|
+
Highlight.js v11.11.1 (git: 08cb242e7d)
|
3
|
+
(c) 2006-2025 Josh Goebel <hello@joshgoebel.com> and other contributors
|
4
|
+
License: BSD-3-Clause
|
5
|
+
*/
|
6
|
+
var hljs=function(){"use strict";function e(t){
|
7
|
+
return t instanceof Map?t.clear=t.delete=t.set=()=>{
|
8
|
+
throw Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=()=>{
|
9
|
+
throw Error("set is read-only")
|
10
|
+
}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((n=>{
|
11
|
+
const i=t[n],s=typeof i;"object"!==s&&"function"!==s||Object.isFrozen(i)||e(i)
|
12
|
+
})),t}class t{constructor(e){
|
13
|
+
void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
|
14
|
+
ignoreMatch(){this.isMatchIgnored=!0}}function n(e){
|
15
|
+
return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")
|
16
|
+
}function i(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t]
|
17
|
+
;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const s=e=>!!e.scope
|
18
|
+
;class r{constructor(e,t){
|
19
|
+
this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){
|
20
|
+
this.buffer+=n(e)}openNode(e){if(!s(e))return;const t=((e,{prefix:t})=>{
|
21
|
+
if(e.startsWith("language:"))return e.replace("language:","language-")
|
22
|
+
;if(e.includes(".")){const n=e.split(".")
|
23
|
+
;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ")
|
24
|
+
}return`${t}${e}`})(e.scope,{prefix:this.classPrefix});this.span(t)}
|
25
|
+
closeNode(e){s(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){
|
26
|
+
this.buffer+=`<span class="${e}">`}}const o=(e={})=>{const t={children:[]}
|
27
|
+
;return Object.assign(t,e),t};class a{constructor(){
|
28
|
+
this.rootNode=o(),this.stack=[this.rootNode]}get top(){
|
29
|
+
return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
|
30
|
+
this.top.children.push(e)}openNode(e){const t=o({scope:e})
|
31
|
+
;this.add(t),this.stack.push(t)}closeNode(){
|
32
|
+
if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
|
33
|
+
for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
|
34
|
+
walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){
|
35
|
+
return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t),
|
36
|
+
t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){
|
37
|
+
"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
|
38
|
+
a._collapse(e)})))}}class c extends a{constructor(e){super(),this.options=e}
|
39
|
+
addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){
|
40
|
+
this.closeNode()}__addSublanguage(e,t){const n=e.root
|
41
|
+
;t&&(n.scope="language:"+t),this.add(n)}toHTML(){
|
42
|
+
return new r(this,this.options).value()}finalize(){
|
43
|
+
return this.closeAllNodes(),!0}}function l(e){
|
44
|
+
return e?"string"==typeof e?e:e.source:null}function g(e){return h("(?=",e,")")}
|
45
|
+
function u(e){return h("(?:",e,")*")}function d(e){return h("(?:",e,")?")}
|
46
|
+
function h(...e){return e.map((e=>l(e))).join("")}function f(...e){const t=(e=>{
|
47
|
+
const t=e[e.length-1]
|
48
|
+
;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{}
|
49
|
+
})(e);return"("+(t.capture?"":"?:")+e.map((e=>l(e))).join("|")+")"}
|
50
|
+
function p(e){return RegExp(e.toString()+"|").exec("").length-1}
|
51
|
+
const b=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
|
52
|
+
;function m(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n
|
53
|
+
;let i=l(e),s="";for(;i.length>0;){const e=b.exec(i);if(!e){s+=i;break}
|
54
|
+
s+=i.substring(0,e.index),
|
55
|
+
i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?s+="\\"+(Number(e[1])+t):(s+=e[0],
|
56
|
+
"("===e[0]&&n++)}return s})).map((e=>`(${e})`)).join(t)}
|
57
|
+
const E="[a-zA-Z]\\w*",x="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",_="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",O={
|
58
|
+
begin:"\\\\[\\s\\S]",relevance:0},v={scope:"string",begin:"'",end:"'",
|
59
|
+
illegal:"\\n",contains:[O]},k={scope:"string",begin:'"',end:'"',illegal:"\\n",
|
60
|
+
contains:[O]},N=(e,t,n={})=>{const s=i({scope:"comment",begin:e,end:t,
|
61
|
+
contains:[]},n);s.contains.push({scope:"doctag",
|
62
|
+
begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
|
63
|
+
end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
|
64
|
+
;const r=f("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
|
65
|
+
;return s.contains.push({begin:h(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),s
|
66
|
+
},S=N("//","$"),M=N("/\\*","\\*/"),R=N("#","$");var j=Object.freeze({
|
67
|
+
__proto__:null,APOS_STRING_MODE:v,BACKSLASH_ESCAPE:O,BINARY_NUMBER_MODE:{
|
68
|
+
scope:"number",begin:w,relevance:0},BINARY_NUMBER_RE:w,COMMENT:N,
|
69
|
+
C_BLOCK_COMMENT_MODE:M,C_LINE_COMMENT_MODE:S,C_NUMBER_MODE:{scope:"number",
|
70
|
+
begin:_,relevance:0},C_NUMBER_RE:_,END_SAME_AS_BEGIN:e=>Object.assign(e,{
|
71
|
+
"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{
|
72
|
+
t.data._beginMatch!==e[1]&&t.ignoreMatch()}}),HASH_COMMENT_MODE:R,IDENT_RE:E,
|
73
|
+
MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+x,relevance:0},
|
74
|
+
NUMBER_MODE:{scope:"number",begin:y,relevance:0},NUMBER_RE:y,
|
75
|
+
PHRASAL_WORDS_MODE:{
|
76
|
+
begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
|
77
|
+
},QUOTE_STRING_MODE:k,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/,
|
78
|
+
end:/\/[gimuy]*/,contains:[O,{begin:/\[/,end:/\]/,relevance:0,contains:[O]}]},
|
79
|
+
RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
|
80
|
+
SHEBANG:(e={})=>{const t=/^#![ ]*\//
|
81
|
+
;return e.binary&&(e.begin=h(t,/.*\b/,e.binary,/\b.*/)),i({scope:"meta",begin:t,
|
82
|
+
end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)},
|
83
|
+
TITLE_MODE:{scope:"title",begin:E,relevance:0},UNDERSCORE_IDENT_RE:x,
|
84
|
+
UNDERSCORE_TITLE_MODE:{scope:"title",begin:x,relevance:0}});function A(e,t){
|
85
|
+
"."===e.input[e.index-1]&&t.ignoreMatch()}function I(e,t){
|
86
|
+
void 0!==e.className&&(e.scope=e.className,delete e.className)}function T(e,t){
|
87
|
+
t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
|
88
|
+
e.__beforeBegin=A,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
|
89
|
+
void 0===e.relevance&&(e.relevance=0))}function L(e,t){
|
90
|
+
Array.isArray(e.illegal)&&(e.illegal=f(...e.illegal))}function B(e,t){
|
91
|
+
if(e.match){
|
92
|
+
if(e.begin||e.end)throw Error("begin & end are not supported with match")
|
93
|
+
;e.begin=e.match,delete e.match}}function P(e,t){
|
94
|
+
void 0===e.relevance&&(e.relevance=1)}const D=(e,t)=>{if(!e.beforeMatch)return
|
95
|
+
;if(e.starts)throw Error("beforeMatch cannot be used with starts")
|
96
|
+
;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t]
|
97
|
+
})),e.keywords=n.keywords,e.begin=h(n.beforeMatch,g(n.begin)),e.starts={
|
98
|
+
relevance:0,contains:[Object.assign(n,{endsParent:!0})]
|
99
|
+
},e.relevance=0,delete n.beforeMatch
|
100
|
+
},H=["of","and","for","in","not","or","if","then","parent","list","value"]
|
101
|
+
;function C(e,t,n="keyword"){const i=Object.create(null)
|
102
|
+
;return"string"==typeof e?s(n,e.split(" ")):Array.isArray(e)?s(n,e):Object.keys(e).forEach((n=>{
|
103
|
+
Object.assign(i,C(e[n],t,n))})),i;function s(e,n){
|
104
|
+
t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|")
|
105
|
+
;i[n[0]]=[e,$(n[0],n[1])]}))}}function $(e,t){
|
106
|
+
return t?Number(t):(e=>H.includes(e.toLowerCase()))(e)?0:1}const U={},z=e=>{
|
107
|
+
console.error(e)},W=(e,...t)=>{console.log("WARN: "+e,...t)},X=(e,t)=>{
|
108
|
+
U[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),U[`${e}/${t}`]=!0)
|
109
|
+
},G=Error();function K(e,t,{key:n}){let i=0;const s=e[n],r={},o={}
|
110
|
+
;for(let e=1;e<=t.length;e++)o[e+i]=s[e],r[e+i]=!0,i+=p(t[e-1])
|
111
|
+
;e[n]=o,e[n]._emit=r,e[n]._multi=!0}function F(e){(e=>{
|
112
|
+
e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
|
113
|
+
delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
|
114
|
+
_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
|
115
|
+
}),(e=>{if(Array.isArray(e.begin)){
|
116
|
+
if(e.skip||e.excludeBegin||e.returnBegin)throw z("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
|
117
|
+
G
|
118
|
+
;if("object"!=typeof e.beginScope||null===e.beginScope)throw z("beginScope must be object"),
|
119
|
+
G;K(e,e.begin,{key:"beginScope"}),e.begin=m(e.begin,{joinWith:""})}})(e),(e=>{
|
120
|
+
if(Array.isArray(e.end)){
|
121
|
+
if(e.skip||e.excludeEnd||e.returnEnd)throw z("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
|
122
|
+
G
|
123
|
+
;if("object"!=typeof e.endScope||null===e.endScope)throw z("endScope must be object"),
|
124
|
+
G;K(e,e.end,{key:"endScope"}),e.end=m(e.end,{joinWith:""})}})(e)}function Z(e){
|
125
|
+
function t(t,n){
|
126
|
+
return RegExp(l(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":""))
|
127
|
+
}class n{constructor(){
|
128
|
+
this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
|
129
|
+
addRule(e,t){
|
130
|
+
t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]),
|
131
|
+
this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
|
132
|
+
;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(m(e,{joinWith:"|"
|
133
|
+
}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
|
134
|
+
;const t=this.matcherRe.exec(e);if(!t)return null
|
135
|
+
;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n]
|
136
|
+
;return t.splice(0,n),Object.assign(t,i)}}class s{constructor(){
|
137
|
+
this.rules=[],this.multiRegexes=[],
|
138
|
+
this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
|
139
|
+
if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n
|
140
|
+
;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))),
|
141
|
+
t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){
|
142
|
+
return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){
|
143
|
+
this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){
|
144
|
+
const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex
|
145
|
+
;let n=t.exec(e)
|
146
|
+
;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{
|
147
|
+
const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)}
|
148
|
+
return n&&(this.regexIndex+=n.position+1,
|
149
|
+
this.regexIndex===this.count&&this.considerAll()),n}}
|
150
|
+
if(e.compilerExtensions||(e.compilerExtensions=[]),
|
151
|
+
e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
|
152
|
+
;return e.classNameAliases=i(e.classNameAliases||{}),function n(r,o){const a=r
|
153
|
+
;if(r.isCompiled)return a
|
154
|
+
;[I,B,F,D].forEach((e=>e(r,o))),e.compilerExtensions.forEach((e=>e(r,o))),
|
155
|
+
r.__beforeBegin=null,[T,L,P].forEach((e=>e(r,o))),r.isCompiled=!0;let c=null
|
156
|
+
;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords),
|
157
|
+
c=r.keywords.$pattern,
|
158
|
+
delete r.keywords.$pattern),c=c||/\w+/,r.keywords&&(r.keywords=C(r.keywords,e.case_insensitive)),
|
159
|
+
a.keywordPatternRe=t(c,!0),
|
160
|
+
o&&(r.begin||(r.begin=/\B|\b/),a.beginRe=t(a.begin),r.end||r.endsWithParent||(r.end=/\B|\b/),
|
161
|
+
r.end&&(a.endRe=t(a.end)),
|
162
|
+
a.terminatorEnd=l(a.end)||"",r.endsWithParent&&o.terminatorEnd&&(a.terminatorEnd+=(r.end?"|":"")+o.terminatorEnd)),
|
163
|
+
r.illegal&&(a.illegalRe=t(r.illegal)),
|
164
|
+
r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>i(e,{
|
165
|
+
variants:null},t)))),e.cachedVariants?e.cachedVariants:V(e)?i(e,{
|
166
|
+
starts:e.starts?i(e.starts):null
|
167
|
+
}):Object.isFrozen(e)?i(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{n(e,a)
|
168
|
+
})),r.starts&&n(r.starts,o),a.matcher=(e=>{const t=new s
|
169
|
+
;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin"
|
170
|
+
}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end"
|
171
|
+
}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function V(e){
|
172
|
+
return!!e&&(e.endsWithParent||V(e.starts))}class q extends Error{
|
173
|
+
constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}}
|
174
|
+
const J=n,Y=i,Q=Symbol("nomatch"),ee=n=>{
|
175
|
+
const i=Object.create(null),s=Object.create(null),r=[];let o=!0
|
176
|
+
;const a="Could not find the language '{}', did you forget to load/include a language module?",l={
|
177
|
+
disableAutodetect:!0,name:"Plain text",contains:[]};let p={
|
178
|
+
ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
|
179
|
+
languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
|
180
|
+
cssSelector:"pre code",languages:null,__emitter:c};function b(e){
|
181
|
+
return p.noHighlightRe.test(e)}function m(e,t,n){let i="",s=""
|
182
|
+
;"object"==typeof t?(i=e,
|
183
|
+
n=t.ignoreIllegals,s=t.language):(X("10.7.0","highlight(lang, code, ...args) has been deprecated."),
|
184
|
+
X("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
|
185
|
+
s=e,i=t),void 0===n&&(n=!0);const r={code:i,language:s};N("before:highlight",r)
|
186
|
+
;const o=r.result?r.result:E(r.language,r.code,n)
|
187
|
+
;return o.code=r.code,N("after:highlight",o),o}function E(e,n,s,r){
|
188
|
+
const c=Object.create(null);function l(){if(!N.keywords)return void M.addText(R)
|
189
|
+
;let e=0;N.keywordPatternRe.lastIndex=0;let t=N.keywordPatternRe.exec(R),n=""
|
190
|
+
;for(;t;){n+=R.substring(e,t.index)
|
191
|
+
;const s=w.case_insensitive?t[0].toLowerCase():t[0],r=(i=s,N.keywords[i]);if(r){
|
192
|
+
const[e,i]=r
|
193
|
+
;if(M.addText(n),n="",c[s]=(c[s]||0)+1,c[s]<=7&&(j+=i),e.startsWith("_"))n+=t[0];else{
|
194
|
+
const n=w.classNameAliases[e]||e;u(t[0],n)}}else n+=t[0]
|
195
|
+
;e=N.keywordPatternRe.lastIndex,t=N.keywordPatternRe.exec(R)}var i
|
196
|
+
;n+=R.substring(e),M.addText(n)}function g(){null!=N.subLanguage?(()=>{
|
197
|
+
if(""===R)return;let e=null;if("string"==typeof N.subLanguage){
|
198
|
+
if(!i[N.subLanguage])return void M.addText(R)
|
199
|
+
;e=E(N.subLanguage,R,!0,S[N.subLanguage]),S[N.subLanguage]=e._top
|
200
|
+
}else e=x(R,N.subLanguage.length?N.subLanguage:null)
|
201
|
+
;N.relevance>0&&(j+=e.relevance),M.__addSublanguage(e._emitter,e.language)
|
202
|
+
})():l(),R=""}function u(e,t){
|
203
|
+
""!==e&&(M.startScope(t),M.addText(e),M.endScope())}function d(e,t){let n=1
|
204
|
+
;const i=t.length-1;for(;n<=i;){if(!e._emit[n]){n++;continue}
|
205
|
+
const i=w.classNameAliases[e[n]]||e[n],s=t[n];i?u(s,i):(R=s,l(),R=""),n++}}
|
206
|
+
function h(e,t){
|
207
|
+
return e.scope&&"string"==typeof e.scope&&M.openNode(w.classNameAliases[e.scope]||e.scope),
|
208
|
+
e.beginScope&&(e.beginScope._wrap?(u(R,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
|
209
|
+
R=""):e.beginScope._multi&&(d(e.beginScope,t),R="")),N=Object.create(e,{parent:{
|
210
|
+
value:N}}),N}function f(e,n,i){let s=((e,t)=>{const n=e&&e.exec(t)
|
211
|
+
;return n&&0===n.index})(e.endRe,i);if(s){if(e["on:end"]){const i=new t(e)
|
212
|
+
;e["on:end"](n,i),i.isMatchIgnored&&(s=!1)}if(s){
|
213
|
+
for(;e.endsParent&&e.parent;)e=e.parent;return e}}
|
214
|
+
if(e.endsWithParent)return f(e.parent,n,i)}function b(e){
|
215
|
+
return 0===N.matcher.regexIndex?(R+=e[0],1):(T=!0,0)}function m(e){
|
216
|
+
const t=e[0],i=n.substring(e.index),s=f(N,e,i);if(!s)return Q;const r=N
|
217
|
+
;N.endScope&&N.endScope._wrap?(g(),
|
218
|
+
u(t,N.endScope._wrap)):N.endScope&&N.endScope._multi?(g(),
|
219
|
+
d(N.endScope,e)):r.skip?R+=t:(r.returnEnd||r.excludeEnd||(R+=t),
|
220
|
+
g(),r.excludeEnd&&(R=t));do{
|
221
|
+
N.scope&&M.closeNode(),N.skip||N.subLanguage||(j+=N.relevance),N=N.parent
|
222
|
+
}while(N!==s.parent);return s.starts&&h(s.starts,e),r.returnEnd?0:t.length}
|
223
|
+
let y={};function _(i,r){const a=r&&r[0];if(R+=i,null==a)return g(),0
|
224
|
+
;if("begin"===y.type&&"end"===r.type&&y.index===r.index&&""===a){
|
225
|
+
if(R+=n.slice(r.index,r.index+1),!o){const t=Error(`0 width match regex (${e})`)
|
226
|
+
;throw t.languageName=e,t.badRule=y.rule,t}return 1}
|
227
|
+
if(y=r,"begin"===r.type)return(e=>{
|
228
|
+
const n=e[0],i=e.rule,s=new t(i),r=[i.__beforeBegin,i["on:begin"]]
|
229
|
+
;for(const t of r)if(t&&(t(e,s),s.isMatchIgnored))return b(n)
|
230
|
+
;return i.skip?R+=n:(i.excludeBegin&&(R+=n),
|
231
|
+
g(),i.returnBegin||i.excludeBegin||(R=n)),h(i,e),i.returnBegin?0:n.length})(r)
|
232
|
+
;if("illegal"===r.type&&!s){
|
233
|
+
const e=Error('Illegal lexeme "'+a+'" for mode "'+(N.scope||"<unnamed>")+'"')
|
234
|
+
;throw e.mode=N,e}if("end"===r.type){const e=m(r);if(e!==Q)return e}
|
235
|
+
if("illegal"===r.type&&""===a)return R+="\n",1
|
236
|
+
;if(I>1e5&&I>3*r.index)throw Error("potential infinite loop, way more iterations than matches")
|
237
|
+
;return R+=a,a.length}const w=O(e)
|
238
|
+
;if(!w)throw z(a.replace("{}",e)),Error('Unknown language: "'+e+'"')
|
239
|
+
;const v=Z(w);let k="",N=r||v;const S={},M=new p.__emitter(p);(()=>{const e=[]
|
240
|
+
;for(let t=N;t!==w;t=t.parent)t.scope&&e.unshift(t.scope)
|
241
|
+
;e.forEach((e=>M.openNode(e)))})();let R="",j=0,A=0,I=0,T=!1;try{
|
242
|
+
if(w.__emitTokens)w.__emitTokens(n,M);else{for(N.matcher.considerAll();;){
|
243
|
+
I++,T?T=!1:N.matcher.considerAll(),N.matcher.lastIndex=A
|
244
|
+
;const e=N.matcher.exec(n);if(!e)break;const t=_(n.substring(A,e.index),e)
|
245
|
+
;A=e.index+t}_(n.substring(A))}return M.finalize(),k=M.toHTML(),{language:e,
|
246
|
+
value:k,relevance:j,illegal:!1,_emitter:M,_top:N}}catch(t){
|
247
|
+
if(t.message&&t.message.includes("Illegal"))return{language:e,value:J(n),
|
248
|
+
illegal:!0,relevance:0,_illegalBy:{message:t.message,index:A,
|
249
|
+
context:n.slice(A-100,A+100),mode:t.mode,resultSoFar:k},_emitter:M};if(o)return{
|
250
|
+
language:e,value:J(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:N}
|
251
|
+
;throw t}}function x(e,t){t=t||p.languages||Object.keys(i);const n=(e=>{
|
252
|
+
const t={value:J(e),illegal:!1,relevance:0,_top:l,_emitter:new p.__emitter(p)}
|
253
|
+
;return t._emitter.addText(e),t})(e),s=t.filter(O).filter(k).map((t=>E(t,e,!1)))
|
254
|
+
;s.unshift(n);const r=s.sort(((e,t)=>{
|
255
|
+
if(e.relevance!==t.relevance)return t.relevance-e.relevance
|
256
|
+
;if(e.language&&t.language){if(O(e.language).supersetOf===t.language)return 1
|
257
|
+
;if(O(t.language).supersetOf===e.language)return-1}return 0})),[o,a]=r,c=o
|
258
|
+
;return c.secondBest=a,c}function y(e){let t=null;const n=(e=>{
|
259
|
+
let t=e.className+" ";t+=e.parentNode?e.parentNode.className:""
|
260
|
+
;const n=p.languageDetectRe.exec(t);if(n){const t=O(n[1])
|
261
|
+
;return t||(W(a.replace("{}",n[1])),
|
262
|
+
W("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"}
|
263
|
+
return t.split(/\s+/).find((e=>b(e)||O(e)))})(e);if(b(n))return
|
264
|
+
;if(N("before:highlightElement",{el:e,language:n
|
265
|
+
}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e)
|
266
|
+
;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),
|
267
|
+
console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),
|
268
|
+
console.warn("The element with unescaped HTML:"),
|
269
|
+
console.warn(e)),p.throwUnescapedHTML))throw new q("One of your code blocks includes unescaped HTML.",e.innerHTML)
|
270
|
+
;t=e;const i=t.textContent,r=n?m(i,{language:n,ignoreIllegals:!0}):x(i)
|
271
|
+
;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,t,n)=>{const i=t&&s[t]||n
|
272
|
+
;e.classList.add("hljs"),e.classList.add("language-"+i)
|
273
|
+
})(e,n,r.language),e.result={language:r.language,re:r.relevance,
|
274
|
+
relevance:r.relevance},r.secondBest&&(e.secondBest={
|
275
|
+
language:r.secondBest.language,relevance:r.secondBest.relevance
|
276
|
+
}),N("after:highlightElement",{el:e,result:r,text:i})}let _=!1;function w(){
|
277
|
+
if("loading"===document.readyState)return _||window.addEventListener("DOMContentLoaded",(()=>{
|
278
|
+
w()}),!1),void(_=!0);document.querySelectorAll(p.cssSelector).forEach(y)}
|
279
|
+
function O(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}
|
280
|
+
function v(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
|
281
|
+
s[e.toLowerCase()]=t}))}function k(e){const t=O(e)
|
282
|
+
;return t&&!t.disableAutodetect}function N(e,t){const n=e;r.forEach((e=>{
|
283
|
+
e[n]&&e[n](t)}))}Object.assign(n,{highlight:m,highlightAuto:x,highlightAll:w,
|
284
|
+
highlightElement:y,
|
285
|
+
highlightBlock:e=>(X("10.7.0","highlightBlock will be removed entirely in v12.0"),
|
286
|
+
X("10.7.0","Please use highlightElement now."),y(e)),configure:e=>{p=Y(p,e)},
|
287
|
+
initHighlighting:()=>{
|
288
|
+
w(),X("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},
|
289
|
+
initHighlightingOnLoad:()=>{
|
290
|
+
w(),X("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")
|
291
|
+
},registerLanguage:(e,t)=>{let s=null;try{s=t(n)}catch(t){
|
292
|
+
if(z("Language definition for '{}' could not be registered.".replace("{}",e)),
|
293
|
+
!o)throw t;z(t),s=l}
|
294
|
+
s.name||(s.name=e),i[e]=s,s.rawDefinition=t.bind(null,n),s.aliases&&v(s.aliases,{
|
295
|
+
languageName:e})},unregisterLanguage:e=>{delete i[e]
|
296
|
+
;for(const t of Object.keys(s))s[t]===e&&delete s[t]},
|
297
|
+
listLanguages:()=>Object.keys(i),getLanguage:O,registerAliases:v,
|
298
|
+
autoDetection:k,inherit:Y,addPlugin:e=>{(e=>{
|
299
|
+
e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{
|
300
|
+
e["before:highlightBlock"](Object.assign({block:t.el},t))
|
301
|
+
}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{
|
302
|
+
e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),r.push(e)},
|
303
|
+
removePlugin:e=>{const t=r.indexOf(e);-1!==t&&r.splice(t,1)}}),n.debugMode=()=>{
|
304
|
+
o=!1},n.safeMode=()=>{o=!0},n.versionString="11.11.1",n.regex={concat:h,
|
305
|
+
lookahead:g,either:f,optional:d,anyNumberOfTimes:u}
|
306
|
+
;for(const t in j)"object"==typeof j[t]&&e(j[t]);return Object.assign(n,j),n
|
307
|
+
},te=ee({});return te.newInstance=()=>ee({}),te}()
|
308
|
+
;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);/*! `json` grammar compiled for Highlight.js 11.11.1 */
|
309
|
+
(()=>{var e=(()=>{"use strict";return e=>{const a=["true","false","null"],s={
|
310
|
+
scope:"literal",beginKeywords:a.join(" ")};return{name:"JSON",aliases:["jsonc"],
|
311
|
+
keywords:{literal:a},contains:[{className:"attr",
|
312
|
+
begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{match:/[{}[\],:]/,
|
313
|
+
className:"punctuation",relevance:0
|
314
|
+
},e.QUOTE_STRING_MODE,s,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],
|
315
|
+
illegal:"\\S"}}})();hljs.registerLanguage("json",e)})();
|
@@ -0,0 +1 @@
|
|
1
|
+
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}
|
data/web/public/index.css
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
body {
|
2
2
|
font-family: sans-serif;
|
3
3
|
margin: 10px;
|
4
|
+
background-color: #eaebef;
|
4
5
|
}
|
5
6
|
|
6
7
|
main {
|
@@ -19,7 +20,7 @@ menu {
|
|
19
20
|
|
20
21
|
menu a {
|
21
22
|
padding: 0.5em 1em;
|
22
|
-
background: #
|
23
|
+
background: #c7cbd5;
|
23
24
|
border-radius: 0.5em;
|
24
25
|
display: inline-block;
|
25
26
|
text-decoration: none;
|
@@ -35,9 +36,10 @@ menu a.active {
|
|
35
36
|
color: white;
|
36
37
|
}
|
37
38
|
|
38
|
-
pre {
|
39
|
+
pre > code {
|
39
40
|
max-width: 950px;
|
40
41
|
overflow-x: scroll;
|
42
|
+
border-radius: 0.5em;
|
41
43
|
}
|
42
44
|
|
43
45
|
.spinner {
|
@@ -57,3 +59,19 @@ pre {
|
|
57
59
|
transform: rotate(360deg);
|
58
60
|
}
|
59
61
|
}
|
62
|
+
|
63
|
+
@media (prefers-color-scheme: dark) {
|
64
|
+
body {
|
65
|
+
background-color: #191b21;
|
66
|
+
color: #ffffff;
|
67
|
+
}
|
68
|
+
|
69
|
+
menu a {
|
70
|
+
background-color: #262932;
|
71
|
+
color: #b1b6c4;
|
72
|
+
}
|
73
|
+
|
74
|
+
menu a:hover {
|
75
|
+
background-color: #2f333e;
|
76
|
+
}
|
77
|
+
}
|
@@ -204,7 +204,7 @@
|
|
204
204
|
|
205
205
|
|
206
206
|
|
207
|
-
<foreignobject class="node" x="36" y="34" width="
|
207
|
+
<foreignobject class="node" x="36" y="34" width="830" height="520"
|
208
208
|
style="transform:scale(0.98); position: relative; border-radius: 12px; opacity: 0.9; mix-blend-mode: darken;">
|
209
209
|
<div id="${contentWrapperId}"
|
210
210
|
style="position: static; width: 100%; height: 100%; max-width: 100%; max-height: 100%;">
|
data/web/views/index.erb
CHANGED
@@ -11,6 +11,11 @@
|
|
11
11
|
<link rel="stylesheet" href="/index.css">
|
12
12
|
<script src="/trmnl-component.js" defer></script>
|
13
13
|
<script src="/index.js"></script>
|
14
|
+
|
15
|
+
<!-- Highlight.js for syntax highlighting -->
|
16
|
+
<link rel="stylesheet" href="/highlight/styles/atom-one-dark.min.css">
|
17
|
+
<script src="/highlight/highlight.min.js"></script>
|
18
|
+
<script>hljs.highlightAll();</script>
|
14
19
|
</head>
|
15
20
|
<body>
|
16
21
|
<main>
|
@@ -41,7 +46,7 @@
|
|
41
46
|
|
42
47
|
<trmnl-frame>Rendering…</trmnl-frame>
|
43
48
|
|
44
|
-
<pre id="user-data"><%= @user_data %></pre>
|
49
|
+
<pre id="user-data"><code><%= @user_data %></code></pre>
|
45
50
|
</main>
|
46
51
|
</body>
|
47
52
|
</html>
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trmnl_preview
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rockwell Schrock
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-07-10 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: sinatra
|
@@ -286,7 +286,7 @@ files:
|
|
286
286
|
- lib/trmnlp/screen_generator.rb
|
287
287
|
- lib/trmnlp/version.rb
|
288
288
|
- templates/init/.trmnlp.yml
|
289
|
-
- templates/init/bin/
|
289
|
+
- templates/init/bin/trmnlp
|
290
290
|
- templates/init/src/full.liquid
|
291
291
|
- templates/init/src/half_horizontal.liquid
|
292
292
|
- templates/init/src/half_vertical.liquid
|
@@ -294,6 +294,8 @@ files:
|
|
294
294
|
- templates/init/src/settings.yml
|
295
295
|
- templates/init/src/shared.liquid
|
296
296
|
- trmnl_preview.gemspec
|
297
|
+
- web/public/highlight/highlight.min.js
|
298
|
+
- web/public/highlight/styles/atom-one-dark.min.css
|
297
299
|
- web/public/index.css
|
298
300
|
- web/public/index.js
|
299
301
|
- web/public/trmnl-component.js
|
data/templates/init/bin/dev
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
#! /bin/bash
|
2
|
-
|
3
|
-
if command -v trmnlp &> /dev/null
|
4
|
-
then
|
5
|
-
echo "Starting trmnlp..."
|
6
|
-
trmnlp serve
|
7
|
-
exit
|
8
|
-
fi
|
9
|
-
|
10
|
-
if command -v docker &> /dev/null
|
11
|
-
then
|
12
|
-
echo "Running trmnl/trmnlp container..."
|
13
|
-
docker run -p 4567:4567 -v .:/plugin trmnl/trmnlp
|
14
|
-
exit
|
15
|
-
fi
|
16
|
-
|
17
|
-
echo "Install the trmnl_preview gem:
|
18
|
-
|
19
|
-
gem install trmnl_preview
|
20
|
-
|
21
|
-
Or install Docker:
|
22
|
-
|
23
|
-
https://docs.docker.com/get-docker/"
|
24
|
-
|
25
|
-
exit 1
|