presently 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.
Files changed (215) hide show
  1. checksums.yaml +7 -0
  2. data/bin/presently +13 -0
  3. data/lib/presently/application.rb +104 -0
  4. data/lib/presently/clock.rb +77 -0
  5. data/lib/presently/display_view.rb +73 -0
  6. data/lib/presently/environment/application.rb +62 -0
  7. data/lib/presently/page.rb +38 -0
  8. data/lib/presently/page.xrb +31 -0
  9. data/lib/presently/presentation.rb +72 -0
  10. data/lib/presently/presentation_controller.rb +181 -0
  11. data/lib/presently/presenter_view.rb +264 -0
  12. data/lib/presently/slide.rb +148 -0
  13. data/lib/presently/slide_view.rb +92 -0
  14. data/lib/presently/state.rb +66 -0
  15. data/lib/presently/version.rb +9 -0
  16. data/lib/presently.rb +9 -0
  17. data/license.md +21 -0
  18. data/public/_components/@socketry/syntax/Syntax/CodeElement.js +337 -0
  19. data/public/_components/@socketry/syntax/Syntax/Errors.js +52 -0
  20. data/public/_components/@socketry/syntax/Syntax/Language/apache.js +49 -0
  21. data/public/_components/@socketry/syntax/Syntax/Language/applescript.js +157 -0
  22. data/public/_components/@socketry/syntax/Syntax/Language/assembly.js +42 -0
  23. data/public/_components/@socketry/syntax/Syntax/Language/bash-script.js +108 -0
  24. data/public/_components/@socketry/syntax/Syntax/Language/bash.js +32 -0
  25. data/public/_components/@socketry/syntax/Syntax/Language/basic.js +232 -0
  26. data/public/_components/@socketry/syntax/Syntax/Language/c++.js +1 -0
  27. data/public/_components/@socketry/syntax/Syntax/Language/c.js +1 -0
  28. data/public/_components/@socketry/syntax/Syntax/Language/clang.js +201 -0
  29. data/public/_components/@socketry/syntax/Syntax/Language/cpp.js +1 -0
  30. data/public/_components/@socketry/syntax/Syntax/Language/csharp.js +166 -0
  31. data/public/_components/@socketry/syntax/Syntax/Language/css.js +244 -0
  32. data/public/_components/@socketry/syntax/Syntax/Language/diff.js +24 -0
  33. data/public/_components/@socketry/syntax/Syntax/Language/go.js +135 -0
  34. data/public/_components/@socketry/syntax/Syntax/Language/haskell.js +110 -0
  35. data/public/_components/@socketry/syntax/Syntax/Language/html.js +69 -0
  36. data/public/_components/@socketry/syntax/Syntax/Language/io.js +68 -0
  37. data/public/_components/@socketry/syntax/Syntax/Language/java.js +134 -0
  38. data/public/_components/@socketry/syntax/Syntax/Language/javascript.js +89 -0
  39. data/public/_components/@socketry/syntax/Syntax/Language/json.js +36 -0
  40. data/public/_components/@socketry/syntax/Syntax/Language/lisp.js +38 -0
  41. data/public/_components/@socketry/syntax/Syntax/Language/lua.js +87 -0
  42. data/public/_components/@socketry/syntax/Syntax/Language/markdown.js +112 -0
  43. data/public/_components/@socketry/syntax/Syntax/Language/nginx.js +37 -0
  44. data/public/_components/@socketry/syntax/Syntax/Language/objective-c.js +1 -0
  45. data/public/_components/@socketry/syntax/Syntax/Language/ocaml.js +225 -0
  46. data/public/_components/@socketry/syntax/Syntax/Language/pascal.js +166 -0
  47. data/public/_components/@socketry/syntax/Syntax/Language/patch.js +2 -0
  48. data/public/_components/@socketry/syntax/Syntax/Language/perl5.js +317 -0
  49. data/public/_components/@socketry/syntax/Syntax/Language/php-script.js +112 -0
  50. data/public/_components/@socketry/syntax/Syntax/Language/php.js +18 -0
  51. data/public/_components/@socketry/syntax/Syntax/Language/plain.js +20 -0
  52. data/public/_components/@socketry/syntax/Syntax/Language/protobuf.js +77 -0
  53. data/public/_components/@socketry/syntax/Syntax/Language/python.js +208 -0
  54. data/public/_components/@socketry/syntax/Syntax/Language/ruby.js +124 -0
  55. data/public/_components/@socketry/syntax/Syntax/Language/scala.js +81 -0
  56. data/public/_components/@socketry/syntax/Syntax/Language/smalltalk.js +30 -0
  57. data/public/_components/@socketry/syntax/Syntax/Language/sql.js +865 -0
  58. data/public/_components/@socketry/syntax/Syntax/Language/super-collider.js +70 -0
  59. data/public/_components/@socketry/syntax/Syntax/Language/swift.js +176 -0
  60. data/public/_components/@socketry/syntax/Syntax/Language/xml.js +76 -0
  61. data/public/_components/@socketry/syntax/Syntax/Language/xrb.js +33 -0
  62. data/public/_components/@socketry/syntax/Syntax/Language/yaml.js +29 -0
  63. data/public/_components/@socketry/syntax/Syntax/Language.js +276 -0
  64. data/public/_components/@socketry/syntax/Syntax/Loader.js +78 -0
  65. data/public/_components/@socketry/syntax/Syntax/Match.js +546 -0
  66. data/public/_components/@socketry/syntax/Syntax/Rule.js +306 -0
  67. data/public/_components/@socketry/syntax/Syntax.js +356 -0
  68. data/public/_components/@socketry/syntax/bin/syntax-ast.js +42 -0
  69. data/public/_components/@socketry/syntax/examples/_template.html +53 -0
  70. data/public/_components/@socketry/syntax/examples/apache.html +72 -0
  71. data/public/_components/@socketry/syntax/examples/applescript.html +72 -0
  72. data/public/_components/@socketry/syntax/examples/assembly.html +74 -0
  73. data/public/_components/@socketry/syntax/examples/bash.html +90 -0
  74. data/public/_components/@socketry/syntax/examples/basic.html +87 -0
  75. data/public/_components/@socketry/syntax/examples/c.html +141 -0
  76. data/public/_components/@socketry/syntax/examples/clang.html +202 -0
  77. data/public/_components/@socketry/syntax/examples/csharp.html +110 -0
  78. data/public/_components/@socketry/syntax/examples/css-colors.html +179 -0
  79. data/public/_components/@socketry/syntax/examples/custom-theme.html +155 -0
  80. data/public/_components/@socketry/syntax/examples/diff.html +142 -0
  81. data/public/_components/@socketry/syntax/examples/examples.css +216 -0
  82. data/public/_components/@socketry/syntax/examples/go.html +413 -0
  83. data/public/_components/@socketry/syntax/examples/haskell.html +373 -0
  84. data/public/_components/@socketry/syntax/examples/html.html +316 -0
  85. data/public/_components/@socketry/syntax/examples/index.html +97 -0
  86. data/public/_components/@socketry/syntax/examples/io.html +552 -0
  87. data/public/_components/@socketry/syntax/examples/java.html +786 -0
  88. data/public/_components/@socketry/syntax/examples/javascript.html +199 -0
  89. data/public/_components/@socketry/syntax/examples/json.html +150 -0
  90. data/public/_components/@socketry/syntax/examples/lisp.html +476 -0
  91. data/public/_components/@socketry/syntax/examples/lua.html +737 -0
  92. data/public/_components/@socketry/syntax/examples/markdown.html +121 -0
  93. data/public/_components/@socketry/syntax/examples/mixed.html +306 -0
  94. data/public/_components/@socketry/syntax/examples/nginx.html +554 -0
  95. data/public/_components/@socketry/syntax/examples/ocaml.html +596 -0
  96. data/public/_components/@socketry/syntax/examples/pascal.html +762 -0
  97. data/public/_components/@socketry/syntax/examples/perl5.html +488 -0
  98. data/public/_components/@socketry/syntax/examples/php-script.html +142 -0
  99. data/public/_components/@socketry/syntax/examples/php.html +95 -0
  100. data/public/_components/@socketry/syntax/examples/plain.html +222 -0
  101. data/public/_components/@socketry/syntax/examples/protobuf.html +405 -0
  102. data/public/_components/@socketry/syntax/examples/python.html +82 -0
  103. data/public/_components/@socketry/syntax/examples/readme.md +79 -0
  104. data/public/_components/@socketry/syntax/examples/ruby.html +58 -0
  105. data/public/_components/@socketry/syntax/examples/scala.html +41 -0
  106. data/public/_components/@socketry/syntax/examples/smalltalk.html +436 -0
  107. data/public/_components/@socketry/syntax/examples/sql.html +373 -0
  108. data/public/_components/@socketry/syntax/examples/super-collider.html +55 -0
  109. data/public/_components/@socketry/syntax/examples/swift.html +176 -0
  110. data/public/_components/@socketry/syntax/examples/wrap-demo.html +103 -0
  111. data/public/_components/@socketry/syntax/examples/xml.html +112 -0
  112. data/public/_components/@socketry/syntax/examples/xrb.html +37 -0
  113. data/public/_components/@socketry/syntax/examples/yaml.html +72 -0
  114. data/public/_components/@socketry/syntax/license.md +21 -0
  115. data/public/_components/@socketry/syntax/package-lock.json +834 -0
  116. data/public/_components/@socketry/syntax/package.json +43 -0
  117. data/public/_components/@socketry/syntax/readme.md +162 -0
  118. data/public/_components/@socketry/syntax/test/Syntax/CodeElement.js +306 -0
  119. data/public/_components/@socketry/syntax/test/Syntax/ErrorHandling.js +85 -0
  120. data/public/_components/@socketry/syntax/test/Syntax/Language/apache.js +153 -0
  121. data/public/_components/@socketry/syntax/test/Syntax/Language/applescript.js +198 -0
  122. data/public/_components/@socketry/syntax/test/Syntax/Language/assembly.js +209 -0
  123. data/public/_components/@socketry/syntax/test/Syntax/Language/bash-script.js +225 -0
  124. data/public/_components/@socketry/syntax/test/Syntax/Language/bash.js +162 -0
  125. data/public/_components/@socketry/syntax/test/Syntax/Language/basic.js +265 -0
  126. data/public/_components/@socketry/syntax/test/Syntax/Language/clang.js +390 -0
  127. data/public/_components/@socketry/syntax/test/Syntax/Language/csharp.js +436 -0
  128. data/public/_components/@socketry/syntax/test/Syntax/Language/css.js +431 -0
  129. data/public/_components/@socketry/syntax/test/Syntax/Language/diff.js +206 -0
  130. data/public/_components/@socketry/syntax/test/Syntax/Language/go.js +386 -0
  131. data/public/_components/@socketry/syntax/test/Syntax/Language/haskell.js +454 -0
  132. data/public/_components/@socketry/syntax/test/Syntax/Language/html.js +111 -0
  133. data/public/_components/@socketry/syntax/test/Syntax/Language/io.js +229 -0
  134. data/public/_components/@socketry/syntax/test/Syntax/Language/java.js +362 -0
  135. data/public/_components/@socketry/syntax/test/Syntax/Language/javascript.js +101 -0
  136. data/public/_components/@socketry/syntax/test/Syntax/Language/json.js +101 -0
  137. data/public/_components/@socketry/syntax/test/Syntax/Language/lisp.js +224 -0
  138. data/public/_components/@socketry/syntax/test/Syntax/Language/lua.js +307 -0
  139. data/public/_components/@socketry/syntax/test/Syntax/Language/markdown.js +163 -0
  140. data/public/_components/@socketry/syntax/test/Syntax/Language/nginx.js +267 -0
  141. data/public/_components/@socketry/syntax/test/Syntax/Language/ocaml.js +299 -0
  142. data/public/_components/@socketry/syntax/test/Syntax/Language/pascal.js +311 -0
  143. data/public/_components/@socketry/syntax/test/Syntax/Language/perl5.js +333 -0
  144. data/public/_components/@socketry/syntax/test/Syntax/Language/php-script.js +197 -0
  145. data/public/_components/@socketry/syntax/test/Syntax/Language/php.js +92 -0
  146. data/public/_components/@socketry/syntax/test/Syntax/Language/plain.js +327 -0
  147. data/public/_components/@socketry/syntax/test/Syntax/Language/protobuf.js +294 -0
  148. data/public/_components/@socketry/syntax/test/Syntax/Language/python.js +213 -0
  149. data/public/_components/@socketry/syntax/test/Syntax/Language/ruby.js +70 -0
  150. data/public/_components/@socketry/syntax/test/Syntax/Language/scala.js +75 -0
  151. data/public/_components/@socketry/syntax/test/Syntax/Language/smalltalk.js +223 -0
  152. data/public/_components/@socketry/syntax/test/Syntax/Language/sql.js +281 -0
  153. data/public/_components/@socketry/syntax/test/Syntax/Language/super-collider.js +66 -0
  154. data/public/_components/@socketry/syntax/test/Syntax/Language/swift.js +71 -0
  155. data/public/_components/@socketry/syntax/test/Syntax/Language/xml.js +170 -0
  156. data/public/_components/@socketry/syntax/test/Syntax/Language/xrb.js +57 -0
  157. data/public/_components/@socketry/syntax/test/Syntax/Language/yaml.js +123 -0
  158. data/public/_components/@socketry/syntax/test/Syntax/Language.js +62 -0
  159. data/public/_components/@socketry/syntax/test/Syntax/Match.js +40 -0
  160. data/public/_components/@socketry/syntax/test/Syntax/Rule.js +251 -0
  161. data/public/_components/@socketry/syntax/test/Syntax.js +38 -0
  162. data/public/_components/@socketry/syntax/test/helpers/ast-matcher.js +90 -0
  163. data/public/_components/@socketry/syntax/themes/base/apache.css +1 -0
  164. data/public/_components/@socketry/syntax/themes/base/applescript.css +1 -0
  165. data/public/_components/@socketry/syntax/themes/base/assembly.css +1 -0
  166. data/public/_components/@socketry/syntax/themes/base/bash.css +1 -0
  167. data/public/_components/@socketry/syntax/themes/base/basic.css +1 -0
  168. data/public/_components/@socketry/syntax/themes/base/c.css +1 -0
  169. data/public/_components/@socketry/syntax/themes/base/clang.css +0 -0
  170. data/public/_components/@socketry/syntax/themes/base/csharp.css +1 -0
  171. data/public/_components/@socketry/syntax/themes/base/css.css +22 -0
  172. data/public/_components/@socketry/syntax/themes/base/diff.css +48 -0
  173. data/public/_components/@socketry/syntax/themes/base/go.css +1 -0
  174. data/public/_components/@socketry/syntax/themes/base/haskell.css +1 -0
  175. data/public/_components/@socketry/syntax/themes/base/html.css +1 -0
  176. data/public/_components/@socketry/syntax/themes/base/io.css +1 -0
  177. data/public/_components/@socketry/syntax/themes/base/java.css +1 -0
  178. data/public/_components/@socketry/syntax/themes/base/javascript.css +1 -0
  179. data/public/_components/@socketry/syntax/themes/base/json.css +41 -0
  180. data/public/_components/@socketry/syntax/themes/base/lisp.css +1 -0
  181. data/public/_components/@socketry/syntax/themes/base/lua.css +1 -0
  182. data/public/_components/@socketry/syntax/themes/base/markdown.css +16 -0
  183. data/public/_components/@socketry/syntax/themes/base/nginx.css +1 -0
  184. data/public/_components/@socketry/syntax/themes/base/ocaml.css +1 -0
  185. data/public/_components/@socketry/syntax/themes/base/pascal.css +1 -0
  186. data/public/_components/@socketry/syntax/themes/base/perl5.css +1 -0
  187. data/public/_components/@socketry/syntax/themes/base/php-script.css +1 -0
  188. data/public/_components/@socketry/syntax/themes/base/php.css +1 -0
  189. data/public/_components/@socketry/syntax/themes/base/plain.css +1 -0
  190. data/public/_components/@socketry/syntax/themes/base/protobuf.css +1 -0
  191. data/public/_components/@socketry/syntax/themes/base/python.css +1 -0
  192. data/public/_components/@socketry/syntax/themes/base/ruby.css +23 -0
  193. data/public/_components/@socketry/syntax/themes/base/scala.css +3 -0
  194. data/public/_components/@socketry/syntax/themes/base/smalltalk.css +1 -0
  195. data/public/_components/@socketry/syntax/themes/base/sql.css +1 -0
  196. data/public/_components/@socketry/syntax/themes/base/super-collider.css +33 -0
  197. data/public/_components/@socketry/syntax/themes/base/swift.css +1 -0
  198. data/public/_components/@socketry/syntax/themes/base/syntax.css +63 -0
  199. data/public/_components/@socketry/syntax/themes/base/xml.css +1 -0
  200. data/public/_components/@socketry/syntax/themes/base/xrb.css +29 -0
  201. data/public/_components/@socketry/syntax/themes/base/yaml.css +1 -0
  202. data/public/_components/@socketry/syntax/themes/theming.md +233 -0
  203. data/public/_components/@socketry/syntax/update-examples.js +135 -0
  204. data/public/_static/index.css +593 -0
  205. data/public/application.js +147 -0
  206. data/readme.md +69 -0
  207. data/releases.md +3 -0
  208. data/templates/code.xrb +12 -0
  209. data/templates/default.xrb +5 -0
  210. data/templates/image.xrb +8 -0
  211. data/templates/section.xrb +5 -0
  212. data/templates/title.xrb +8 -0
  213. data/templates/translation.xrb +8 -0
  214. data/templates/two_column.xrb +8 -0
  215. metadata +280 -0
@@ -0,0 +1,101 @@
1
+ import Syntax from '../../../Syntax.js';
2
+ import registerJSON from '../../../Syntax/Language/json.js';
3
+ import {strictEqual, ok} from 'node:assert';
4
+ import test from 'node:test';
5
+
6
+ async function getLanguage() {
7
+ const syntax = new Syntax();
8
+ registerJSON(syntax);
9
+ return await syntax.getLanguage('json');
10
+ }
11
+
12
+ function typesFrom(matches) {
13
+ return matches.map(m => m.expression.type);
14
+ }
15
+
16
+ test('JSON language can be registered', async () => {
17
+ const language = await getLanguage();
18
+ strictEqual(language.name, 'json');
19
+ });
20
+
21
+ test('JSON: true, false, null constants', async () => {
22
+ const language = await getLanguage();
23
+ const code = 'true false null';
24
+ const matches = await language.getMatches(Syntax.default, code);
25
+ const constants = matches.filter(m => m.expression.type === 'constant');
26
+ strictEqual(constants.length, 3);
27
+ });
28
+
29
+ test('JSON: integer numbers', async () => {
30
+ const language = await getLanguage();
31
+ const code = '0 42 -17 999';
32
+ const matches = await language.getMatches(Syntax.default, code);
33
+ const numbers = matches.filter(m => m.expression.type === 'constant' && /^-?\d/.test(m.value));
34
+ ok(numbers.length >= 4);
35
+ });
36
+
37
+ test('JSON: float numbers', async () => {
38
+ const language = await getLanguage();
39
+ const code = '3.14 -0.5 123.456';
40
+ const matches = await language.getMatches(Syntax.default, code);
41
+ const numbers = matches.filter(m => m.expression.type === 'constant' && m.value.includes('.'));
42
+ ok(numbers.length >= 3);
43
+ });
44
+
45
+ test('JSON: scientific notation', async () => {
46
+ const language = await getLanguage();
47
+ const code = '1e10 2.5e-3 -1.23E+5';
48
+ const matches = await language.getMatches(Syntax.default, code);
49
+ const numbers = matches.filter(m => m.expression.type === 'constant' && /e/i.test(m.value));
50
+ ok(numbers.length >= 3);
51
+ });
52
+
53
+ test('JSON: strings', async () => {
54
+ const language = await getLanguage();
55
+ const code = '"hello" "world" "with \\"escaped\\" quotes"';
56
+ const matches = await language.getMatches(Syntax.default, code);
57
+ const strings = matches.filter(m => m.expression.type === 'string');
58
+ ok(strings.length >= 3);
59
+ });
60
+
61
+ test('JSON: object keys', async () => {
62
+ const language = await getLanguage();
63
+ const code = '{"name": "value", "age": 42}';
64
+ const matches = await language.getMatches(Syntax.default, code);
65
+ const keys = matches.filter(m => m.expression.type === 'key');
66
+ ok(keys.length >= 2);
67
+ });
68
+
69
+ test('JSON: structural operators', async () => {
70
+ const language = await getLanguage();
71
+ const code = '{} [] , : ';
72
+ const matches = await language.getMatches(Syntax.default, code);
73
+ const operators = matches.filter(m => m.expression.type === 'operator');
74
+ ok(operators.length >= 4);
75
+ });
76
+
77
+ test('JSON: nested object', async () => {
78
+ const language = await getLanguage();
79
+ const code = '{"user": {"name": "John", "age": 30}}';
80
+ const matches = await language.getMatches(Syntax.default, code);
81
+ const keys = matches.filter(m => m.expression.type === 'key');
82
+ ok(keys.length >= 3);
83
+ });
84
+
85
+ test('JSON: array', async () => {
86
+ const language = await getLanguage();
87
+ const code = '[1, 2, "three", true, null]';
88
+ const matches = await language.getMatches(Syntax.default, code);
89
+ const types = typesFrom(matches);
90
+ ok(types.includes('constant'));
91
+ ok(types.includes('string'));
92
+ ok(types.includes('operator'));
93
+ });
94
+
95
+ test('JSON: complex structure', async () => {
96
+ const language = await getLanguage();
97
+ const code = '{"items": [{"id": 1, "active": true}, {"id": 2, "active": false}]}';
98
+ const matches = await language.getMatches(Syntax.default, code);
99
+ const keys = matches.filter(m => m.expression.type === 'key');
100
+ ok(keys.length >= 5);
101
+ });
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Tests for Lisp language syntax highlighting
3
+ */
4
+
5
+ import {test} from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import {JSDOM} from 'jsdom';
8
+ import Syntax from '../../../Syntax.js';
9
+
10
+ const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
11
+ global.window = dom.window;
12
+ global.document = dom.window.document;
13
+ global.HTMLElement = dom.window.HTMLElement;
14
+ global.customElements = dom.window.customElements;
15
+
16
+ const syntax = new Syntax();
17
+
18
+ test('Lisp language can be registered', async () => {
19
+ const language = await syntax.getResource('lisp');
20
+ assert.ok(language);
21
+ assert.equal(language.name, 'lisp');
22
+ });
23
+
24
+ test('Lisp can match parentheses operators', async () => {
25
+ const language = await syntax.getResource('lisp');
26
+ const matches = await language.getMatches(syntax, '(+ 1 2)');
27
+ const operators = matches.filter(m => m.type === 'operator');
28
+ assert.ok(operators.some(m => m.value === '('));
29
+ assert.ok(operators.some(m => m.value === ')'));
30
+ });
31
+
32
+ test('Lisp can match single semicolon comments', async () => {
33
+ const language = await syntax.getResource('lisp');
34
+ const matches = await language.getMatches(syntax, '; This is a comment');
35
+ const comments = matches.filter(m => m.type === 'comment');
36
+ assert.ok(comments.some(m => m.value === '; This is a comment'));
37
+ });
38
+
39
+ test('Lisp can match double semicolon comments', async () => {
40
+ const language = await syntax.getResource('lisp');
41
+ const matches = await language.getMatches(syntax, ';; This is a comment');
42
+ const comments = matches.filter(m => m.type === 'comment');
43
+ assert.ok(comments.some(m => m.value === ';; This is a comment'));
44
+ });
45
+
46
+ test('Lisp can match triple semicolon comments', async () => {
47
+ const language = await syntax.getResource('lisp');
48
+ const matches = await language.getMatches(syntax, ';;; Section header');
49
+ const comments = matches.filter(m => m.type === 'comment');
50
+ assert.ok(comments.some(m => m.value === ';;; Section header'));
51
+ });
52
+
53
+ test('Lisp can match decimal numbers', async () => {
54
+ const language = await syntax.getResource('lisp');
55
+ const matches = await language.getMatches(syntax, '(+ 42 3.14)');
56
+ const numbers = matches.filter(m => m.type === 'constant');
57
+ assert.ok(numbers.some(m => m.value === '42'));
58
+ assert.ok(numbers.some(m => m.value === '3.14'));
59
+ });
60
+
61
+ test('Lisp can match hexadecimal numbers', async () => {
62
+ const language = await syntax.getResource('lisp');
63
+ const matches = await language.getMatches(syntax, '0xFF 0x1A2B');
64
+ const numbers = matches.filter(m => m.type === 'constant');
65
+ assert.ok(numbers.some(m => m.value === '0xFF'));
66
+ assert.ok(numbers.some(m => m.value === '0x1A2B'));
67
+ });
68
+
69
+ test('Lisp can match hash constants', async () => {
70
+ const language = await syntax.getResource('lisp');
71
+ const matches = await language.getMatches(syntax, '#t #f #nil');
72
+ const constants = matches.filter(m => m.type === 'constant');
73
+ assert.ok(constants.some(m => m.value === '#t'));
74
+ assert.ok(constants.some(m => m.value === '#f'));
75
+ assert.ok(constants.some(m => m.value === '#nil'));
76
+ });
77
+
78
+ test('Lisp can match hash keywords', async () => {
79
+ const language = await syntax.getResource('lisp');
80
+ const matches = await language.getMatches(syntax, '#true #false');
81
+ const constants = matches.filter(m => m.type === 'constant');
82
+ assert.ok(constants.some(m => m.value === '#true'));
83
+ assert.ok(constants.some(m => m.value === '#false'));
84
+ });
85
+
86
+ test('Lisp can match function calls', async () => {
87
+ const language = await syntax.getResource('lisp');
88
+ const matches = await language.getMatches(syntax, '(defun factorial (n))');
89
+ const functions = matches.filter(m => m.type === 'function');
90
+ assert.ok(functions.some(m => m.value === 'defun'));
91
+ });
92
+
93
+ test('Lisp can match function names in expressions', async () => {
94
+ const language = await syntax.getResource('lisp');
95
+ const matches = await language.getMatches(syntax, '(+ 1 2)');
96
+ const functions = matches.filter(m => m.type === 'function');
97
+ assert.ok(functions.some(m => m.value === '+'));
98
+ });
99
+
100
+ test('Lisp can match built-in functions', async () => {
101
+ const language = await syntax.getResource('lisp');
102
+ const matches = await language.getMatches(syntax, '(list 1 2 3)');
103
+ const functions = matches.filter(m => m.type === 'function');
104
+ assert.ok(functions.some(m => m.value === 'list'));
105
+ });
106
+
107
+ test('Lisp can match special forms', async () => {
108
+ const language = await syntax.getResource('lisp');
109
+ const matches = await language.getMatches(syntax, '(if condition then else)');
110
+ const functions = matches.filter(m => m.type === 'function');
111
+ assert.ok(functions.some(m => m.value === 'if'));
112
+ });
113
+
114
+ test('Lisp can match lambda expressions', async () => {
115
+ const language = await syntax.getResource('lisp');
116
+ const matches = await language.getMatches(syntax, '(lambda (x) (* x x))');
117
+ const functions = matches.filter(m => m.type === 'function');
118
+ assert.ok(functions.some(m => m.value === 'lambda'));
119
+ });
120
+
121
+ test('Lisp can match double-quoted strings', async () => {
122
+ const language = await syntax.getResource('lisp');
123
+ const matches = await language.getMatches(syntax, '"Hello, World!"');
124
+ const strings = matches.filter(m => m.type === 'string');
125
+ assert.ok(strings.some(m => m.value === '"Hello, World!"'));
126
+ });
127
+
128
+ test('Lisp can match multi-line strings', async () => {
129
+ const language = await syntax.getResource('lisp');
130
+ const matches = await language.getMatches(syntax, '"Line 1\nLine 2"');
131
+ const strings = matches.filter(m => m.type === 'string');
132
+ assert.ok(strings.some(m => m.value.includes('Line 1')));
133
+ });
134
+
135
+ test('Lisp can match string escapes', async () => {
136
+ const language = await syntax.getResource('lisp');
137
+ const matches = await language.getMatches(syntax, '"Say \\"Hello\\""');
138
+ const strings = matches.filter(m => m.type === 'string');
139
+ assert.ok(strings.length > 0);
140
+ });
141
+
142
+ test('Lisp can match nested expressions', async () => {
143
+ const language = await syntax.getResource('lisp');
144
+ const matches = await language.getMatches(syntax, '(+ (* 2 3) (- 5 1))');
145
+ const operators = matches.filter(m => m.type === 'operator');
146
+ const openParens = operators.filter(m => m.value === '(');
147
+ const closeParens = operators.filter(m => m.value === ')');
148
+ assert.ok(openParens.length >= 3);
149
+ assert.ok(closeParens.length >= 3);
150
+ });
151
+
152
+ test('Lisp can match let bindings', async () => {
153
+ const language = await syntax.getResource('lisp');
154
+ const matches = await language.getMatches(
155
+ syntax,
156
+ '(let ((x 10) (y 20)) (+ x y))'
157
+ );
158
+ const functions = matches.filter(m => m.type === 'function');
159
+ assert.ok(functions.some(m => m.value === 'let'));
160
+ });
161
+
162
+ test('Lisp can match define statements', async () => {
163
+ const language = await syntax.getResource('lisp');
164
+ const matches = await language.getMatches(syntax, '(define x 42)');
165
+ const functions = matches.filter(m => m.type === 'function');
166
+ assert.ok(functions.some(m => m.value === 'define'));
167
+ });
168
+
169
+ test('Lisp can match setq assignments', async () => {
170
+ const language = await syntax.getResource('lisp');
171
+ const matches = await language.getMatches(syntax, '(setq x 100)');
172
+ const functions = matches.filter(m => m.type === 'function');
173
+ assert.ok(functions.some(m => m.value === 'setq'));
174
+ });
175
+
176
+ test('Lisp can process complete function definition', async () => {
177
+ const language = await syntax.getResource('lisp');
178
+ const code = `(defun factorial (n)
179
+ (if (<= n 1)
180
+ 1
181
+ (* n (factorial (- n 1)))))`;
182
+ const matches = await language.getMatches(syntax, code);
183
+ assert.ok(matches.length > 0);
184
+
185
+ const functions = matches.filter(m => m.type === 'function');
186
+ assert.ok(functions.some(m => m.value === 'defun'));
187
+ assert.ok(functions.some(m => m.value === 'if'));
188
+ assert.ok(functions.some(m => m.value === '<='));
189
+ assert.ok(functions.some(m => m.value === '*'));
190
+ assert.ok(functions.some(m => m.value === 'factorial'));
191
+ assert.ok(functions.some(m => m.value === '-'));
192
+ });
193
+
194
+ test('Lisp can process code with comments', async () => {
195
+ const language = await syntax.getResource('lisp');
196
+ const code = `; Calculate factorial
197
+ (defun factorial (n)
198
+ ;; Base case
199
+ (if (<= n 1)
200
+ 1 ; Return 1
201
+ (* n (factorial (- n 1)))))`;
202
+ const matches = await language.getMatches(syntax, code);
203
+
204
+ const comments = matches.filter(m => m.type === 'comment');
205
+ assert.ok(comments.some(m => m.value === '; Calculate factorial'));
206
+ assert.ok(comments.some(m => m.value === ';; Base case'));
207
+ assert.ok(comments.some(m => m.value === '; Return 1'));
208
+ });
209
+
210
+ test('Lisp can match quoted expressions', async () => {
211
+ const language = await syntax.getResource('lisp');
212
+ const matches = await language.getMatches(syntax, "'(1 2 3)");
213
+ // Quote is just part of the syntax, lists are in parentheses
214
+ const operators = matches.filter(m => m.type === 'operator');
215
+ assert.ok(operators.some(m => m.value === '('));
216
+ assert.ok(operators.some(m => m.value === ')'));
217
+ });
218
+
219
+ test('Lisp can match backquote and unquote', async () => {
220
+ const language = await syntax.getResource('lisp');
221
+ const matches = await language.getMatches(syntax, '`(1 ,x 3)');
222
+ // Backquote and comma are part of the expression syntax
223
+ assert.ok(matches.length > 0);
224
+ });
@@ -0,0 +1,307 @@
1
+ /**
2
+ * Tests for Lua language syntax highlighting
3
+ */
4
+
5
+ import {test} from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import {JSDOM} from 'jsdom';
8
+ import Syntax from '../../../Syntax.js';
9
+
10
+ const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
11
+ global.window = dom.window;
12
+ global.document = dom.window.document;
13
+ global.HTMLElement = dom.window.HTMLElement;
14
+ global.customElements = dom.window.customElements;
15
+
16
+ const syntax = new Syntax();
17
+
18
+ test('Lua language can be registered', async () => {
19
+ const language = await syntax.getResource('lua');
20
+ assert.ok(language);
21
+ assert.equal(language.name, 'lua');
22
+ });
23
+
24
+ test('Lua can match function keyword', async () => {
25
+ const language = await syntax.getResource('lua');
26
+ const matches = await language.getMatches(syntax, 'function test() end');
27
+ const keywords = matches.filter(m => m.type === 'keyword');
28
+ assert.ok(keywords.some(m => m.value === 'function'));
29
+ assert.ok(keywords.some(m => m.value === 'end'));
30
+ });
31
+
32
+ test('Lua can match local keyword', async () => {
33
+ const language = await syntax.getResource('lua');
34
+ const matches = await language.getMatches(syntax, 'local x = 10');
35
+ const keywords = matches.filter(m => m.type === 'keyword');
36
+ assert.ok(keywords.some(m => m.value === 'local'));
37
+ });
38
+
39
+ test('Lua can match control flow keywords', async () => {
40
+ const language = await syntax.getResource('lua');
41
+ const matches = await language.getMatches(
42
+ syntax,
43
+ 'if x > 0 then return true else return false end'
44
+ );
45
+ const keywords = matches.filter(m => m.type === 'keyword');
46
+ assert.ok(keywords.some(m => m.value === 'if'));
47
+ assert.ok(keywords.some(m => m.value === 'then'));
48
+ assert.ok(keywords.some(m => m.value === 'else'));
49
+ assert.ok(keywords.some(m => m.value === 'return'));
50
+ assert.ok(keywords.some(m => m.value === 'end'));
51
+ });
52
+
53
+ test('Lua can match elseif keyword', async () => {
54
+ const language = await syntax.getResource('lua');
55
+ const matches = await language.getMatches(
56
+ syntax,
57
+ 'if x > 0 then elseif x < 0 then else end'
58
+ );
59
+ const keywords = matches.filter(m => m.type === 'keyword');
60
+ assert.ok(keywords.some(m => m.value === 'elseif'));
61
+ });
62
+
63
+ test('Lua can match loop keywords', async () => {
64
+ const language = await syntax.getResource('lua');
65
+ const matches = await language.getMatches(
66
+ syntax,
67
+ 'for i = 1, 10 do end while true do break end'
68
+ );
69
+ const keywords = matches.filter(m => m.type === 'keyword');
70
+ assert.ok(keywords.some(m => m.value === 'for'));
71
+ assert.ok(keywords.some(m => m.value === 'while'));
72
+ assert.ok(keywords.some(m => m.value === 'do'));
73
+ assert.ok(keywords.some(m => m.value === 'break'));
74
+ });
75
+
76
+ test('Lua can match repeat until keywords', async () => {
77
+ const language = await syntax.getResource('lua');
78
+ const matches = await language.getMatches(
79
+ syntax,
80
+ 'repeat x = x + 1 until x > 10'
81
+ );
82
+ const keywords = matches.filter(m => m.type === 'keyword');
83
+ assert.ok(keywords.some(m => m.value === 'repeat'));
84
+ assert.ok(keywords.some(m => m.value === 'until'));
85
+ });
86
+
87
+ test('Lua can match in keyword', async () => {
88
+ const language = await syntax.getResource('lua');
89
+ const matches = await language.getMatches(
90
+ syntax,
91
+ 'for k, v in pairs(t) do end'
92
+ );
93
+ const keywords = matches.filter(m => m.type === 'keyword');
94
+ assert.ok(keywords.some(m => m.value === 'in'));
95
+ });
96
+
97
+ test('Lua can match logical keywords', async () => {
98
+ const language = await syntax.getResource('lua');
99
+ const matches = await language.getMatches(
100
+ syntax,
101
+ 'if x > 0 and y < 10 or not z then end'
102
+ );
103
+ const keywords = matches.filter(m => m.type === 'keyword');
104
+ assert.ok(keywords.some(m => m.value === 'and'));
105
+ assert.ok(keywords.some(m => m.value === 'or'));
106
+ assert.ok(keywords.some(m => m.value === 'not'));
107
+ });
108
+
109
+ test('Lua can match boolean constants', async () => {
110
+ const language = await syntax.getResource('lua');
111
+ const matches = await language.getMatches(syntax, 'x = true; y = false');
112
+ const constants = matches.filter(m => m.type === 'constant');
113
+ assert.ok(constants.some(m => m.value === 'true'));
114
+ assert.ok(constants.some(m => m.value === 'false'));
115
+ });
116
+
117
+ test('Lua can match nil constant', async () => {
118
+ const language = await syntax.getResource('lua');
119
+ const matches = await language.getMatches(syntax, 'x = nil');
120
+ const constants = matches.filter(m => m.type === 'constant');
121
+ assert.ok(constants.some(m => m.value === 'nil'));
122
+ });
123
+
124
+ test('Lua can match self constant', async () => {
125
+ const language = await syntax.getResource('lua');
126
+ const matches = await language.getMatches(
127
+ syntax,
128
+ 'function obj:method() self.value = 10 end'
129
+ );
130
+ const constants = matches.filter(m => m.type === 'constant');
131
+ assert.ok(constants.some(m => m.value === 'self'));
132
+ });
133
+
134
+ test('Lua can match arithmetic operators', async () => {
135
+ const language = await syntax.getResource('lua');
136
+ const matches = await language.getMatches(syntax, 'x + y - z * a / b % c ^ d');
137
+ const operators = matches.filter(m => m.type === 'operator');
138
+ assert.ok(operators.some(m => m.value === '+'));
139
+ assert.ok(operators.some(m => m.value === '-'));
140
+ assert.ok(operators.some(m => m.value === '*'));
141
+ assert.ok(operators.some(m => m.value === '/'));
142
+ assert.ok(operators.some(m => m.value === '%'));
143
+ assert.ok(operators.some(m => m.value === '^'));
144
+ });
145
+
146
+ test('Lua can match comparison operators', async () => {
147
+ const language = await syntax.getResource('lua');
148
+ const matches = await language.getMatches(
149
+ syntax,
150
+ 'if x == y or a ~= b or c < d or e > f then end'
151
+ );
152
+ const operators = matches.filter(m => m.type === 'operator');
153
+ assert.ok(operators.some(m => m.value === '=='));
154
+ assert.ok(operators.some(m => m.value === '~='));
155
+ assert.ok(operators.some(m => m.value === '<'));
156
+ assert.ok(operators.some(m => m.value === '>'));
157
+ });
158
+
159
+ test('Lua can match less/greater than or equal operators', async () => {
160
+ const language = await syntax.getResource('lua');
161
+ const matches = await language.getMatches(
162
+ syntax,
163
+ 'if x <= y and a >= b then end'
164
+ );
165
+ const operators = matches.filter(m => m.type === 'operator');
166
+ assert.ok(operators.some(m => m.value === '<='));
167
+ assert.ok(operators.some(m => m.value === '>='));
168
+ });
169
+
170
+ test('Lua can match concatenation operator', async () => {
171
+ const language = await syntax.getResource('lua');
172
+ const matches = await language.getMatches(
173
+ syntax,
174
+ 's = "Hello" .. " " .. "World"'
175
+ );
176
+ const operators = matches.filter(m => m.type === 'operator');
177
+ assert.ok(operators.some(m => m.value === '..'));
178
+ });
179
+
180
+ test('Lua can match length operator', async () => {
181
+ const language = await syntax.getResource('lua');
182
+ const matches = await language.getMatches(syntax, 'len = #table');
183
+ const operators = matches.filter(m => m.type === 'operator');
184
+ assert.ok(operators.some(m => m.value === '#'));
185
+ });
186
+
187
+ test('Lua can match assignment operator', async () => {
188
+ const language = await syntax.getResource('lua');
189
+ const matches = await language.getMatches(syntax, 'x = 10');
190
+ const operators = matches.filter(m => m.type === 'operator');
191
+ assert.ok(operators.some(m => m.value === '='));
192
+ });
193
+
194
+ test('Lua can match colon operator', async () => {
195
+ const language = await syntax.getResource('lua');
196
+ const matches = await language.getMatches(syntax, 'obj:method()');
197
+ const operators = matches.filter(m => m.type === 'operator');
198
+ assert.ok(operators.some(m => m.value === ':'));
199
+ });
200
+
201
+ test('Lua can match single-line comments', async () => {
202
+ const language = await syntax.getResource('lua');
203
+ const matches = await language.getMatches(
204
+ syntax,
205
+ '-- This is a comment\nx = 10'
206
+ );
207
+ const comments = matches.filter(m => m.type === 'comment');
208
+ assert.ok(comments.some(m => m.value === '-- This is a comment'));
209
+ });
210
+
211
+ test('Lua can match multi-line comments', async () => {
212
+ const language = await syntax.getResource('lua');
213
+ const matches = await language.getMatches(
214
+ syntax,
215
+ '--[[ This is a\nmulti-line comment ]]--'
216
+ );
217
+ const comments = matches.filter(m => m.type === 'comment');
218
+ assert.ok(comments.some(m => m.value.includes('multi-line')));
219
+ });
220
+
221
+ test('Lua can match single-quoted strings', async () => {
222
+ const language = await syntax.getResource('lua');
223
+ const matches = await language.getMatches(syntax, "s = 'Hello, World!'");
224
+ const strings = matches.filter(m => m.type === 'string');
225
+ assert.ok(strings.some(m => m.value === "'Hello, World!'"));
226
+ });
227
+
228
+ test('Lua can match double-quoted strings', async () => {
229
+ const language = await syntax.getResource('lua');
230
+ const matches = await language.getMatches(syntax, 's = "Hello, World!"');
231
+ const strings = matches.filter(m => m.type === 'string');
232
+ assert.ok(strings.some(m => m.value === '"Hello, World!"'));
233
+ });
234
+
235
+ test('Lua can match string escapes', async () => {
236
+ const language = await syntax.getResource('lua');
237
+ const matches = await language.getMatches(syntax, 's = "Line 1\\nLine 2"');
238
+ const strings = matches.filter(m => m.type === 'string');
239
+ assert.ok(strings.length > 0);
240
+ });
241
+
242
+ test('Lua can match decimal numbers', async () => {
243
+ const language = await syntax.getResource('lua');
244
+ const matches = await language.getMatches(syntax, 'x = 42; y = 3.14');
245
+ const numbers = matches.filter(m => m.type === 'constant');
246
+ assert.ok(numbers.some(m => m.value === '42'));
247
+ assert.ok(numbers.some(m => m.value === '3.14'));
248
+ });
249
+
250
+ test('Lua can match hexadecimal numbers', async () => {
251
+ const language = await syntax.getResource('lua');
252
+ const matches = await language.getMatches(syntax, 'color = 0xFF00AA');
253
+ const numbers = matches.filter(m => m.type === 'constant');
254
+ assert.ok(numbers.some(m => m.value === '0xFF00AA'));
255
+ });
256
+
257
+ test('Lua can match CamelCase types', async () => {
258
+ const language = await syntax.getResource('lua');
259
+ const matches = await language.getMatches(syntax, 'MyClass = {}');
260
+ const types = matches.filter(m => m.type === 'type');
261
+ assert.ok(types.some(m => m.value === 'MyClass'));
262
+ });
263
+
264
+ test('Lua can match function calls', async () => {
265
+ const language = await syntax.getResource('lua');
266
+ const matches = await language.getMatches(syntax, 'print("Hello")');
267
+ const functions = matches.filter(m => m.type === 'function');
268
+ assert.ok(functions.some(m => m.value === 'print'));
269
+ });
270
+
271
+ test('Lua can process complete function definition', async () => {
272
+ const language = await syntax.getResource('lua');
273
+ const code = `function factorial(n)
274
+ if n <= 1 then
275
+ return 1
276
+ else
277
+ return n * factorial(n - 1)
278
+ end
279
+ end`;
280
+ const matches = await language.getMatches(syntax, code);
281
+ assert.ok(matches.length > 0);
282
+
283
+ const keywords = matches.filter(m => m.type === 'keyword');
284
+ assert.ok(keywords.some(m => m.value === 'function'));
285
+ assert.ok(keywords.some(m => m.value === 'if'));
286
+ assert.ok(keywords.some(m => m.value === 'then'));
287
+ assert.ok(keywords.some(m => m.value === 'return'));
288
+ assert.ok(keywords.some(m => m.value === 'else'));
289
+ assert.ok(keywords.some(m => m.value === 'end'));
290
+ });
291
+
292
+ test('Lua can process table definition', async () => {
293
+ const language = await syntax.getResource('lua');
294
+ const code = `local person = {
295
+ name = "Alice",
296
+ age = 30,
297
+ greet = function(self)
298
+ print("Hello, " .. self.name)
299
+ end
300
+ }`;
301
+ const matches = await language.getMatches(syntax, code);
302
+ assert.ok(matches.length > 0);
303
+
304
+ const keywords = matches.filter(m => m.type === 'keyword');
305
+ assert.ok(keywords.some(m => m.value === 'local'));
306
+ assert.ok(keywords.some(m => m.value === 'function'));
307
+ });