Fossil SCM

Extended the pikchr wasm binding to make use of all of the pikchr() arguments and return more info in pikchr-worker's result. Fixed shift-enter behavior.

stephan 2022-06-06 23:53 pikchrshow-wasm
Commit 1dc34c9b61433ef9128c65c954de1eecdcd1510d05defb63de2e2ff40b056454
--- extsrc/pikchr-module.js
+++ extsrc/pikchr-module.js
@@ -109,10 +109,76 @@
109109
var noExitRuntime = Module["noExitRuntime"] || true;
110110
111111
if (typeof WebAssembly != "object") {
112112
abort("no native wasm support detected");
113113
}
114
+
115
+function setValue(ptr, value, type = "i8", noSafe) {
116
+ if (type.endsWith("*")) type = "i32";
117
+ switch (type) {
118
+ case "i1":
119
+ HEAP8[ptr >> 0] = value;
120
+ break;
121
+
122
+ case "i8":
123
+ HEAP8[ptr >> 0] = value;
124
+ break;
125
+
126
+ case "i16":
127
+ HEAP16[ptr >> 1] = value;
128
+ break;
129
+
130
+ case "i32":
131
+ HEAP32[ptr >> 2] = value;
132
+ break;
133
+
134
+ case "i64":
135
+ tempI64 = [ value >>> 0, (tempDouble = value, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0) ],
136
+ HEAP32[ptr >> 2] = tempI64[0], HEAP32[ptr + 4 >> 2] = tempI64[1];
137
+ break;
138
+
139
+ case "float":
140
+ HEAPF32[ptr >> 2] = value;
141
+ break;
142
+
143
+ case "double":
144
+ HEAPF64[ptr >> 3] = value;
145
+ break;
146
+
147
+ default:
148
+ abort("invalid type for setValue: " + type);
149
+ }
150
+}
151
+
152
+function getValue(ptr, type = "i8", noSafe) {
153
+ if (type.endsWith("*")) type = "i32";
154
+ switch (type) {
155
+ case "i1":
156
+ return HEAP8[ptr >> 0];
157
+
158
+ case "i8":
159
+ return HEAP8[ptr >> 0];
160
+
161
+ case "i16":
162
+ return HEAP16[ptr >> 1];
163
+
164
+ case "i32":
165
+ return HEAP32[ptr >> 2];
166
+
167
+ case "i64":
168
+ return HEAP32[ptr >> 2];
169
+
170
+ case "float":
171
+ return HEAPF32[ptr >> 2];
172
+
173
+ case "double":
174
+ return Number(HEAPF64[ptr >> 3]);
175
+
176
+ default:
177
+ abort("invalid type for getValue: " + type);
178
+ }
179
+}
114180
115181
var wasmMemory;
116182
117183
var ABORT = false;
118184
@@ -482,10 +548,14 @@
482548
}
483549
}
484550
instantiateAsync().catch(readyPromiseReject);
485551
return {};
486552
}
553
+
554
+var tempDouble;
555
+
556
+var tempI64;
487557
488558
function callRuntimeCallbacks(callbacks) {
489559
while (callbacks.length > 0) {
490560
var callback = callbacks.shift();
491561
if (typeof callback == "function") {
@@ -555,10 +625,18 @@
555625
return (stackAlloc = Module["stackAlloc"] = Module["asm"]["j"]).apply(null, arguments);
556626
};
557627
558628
Module["cwrap"] = cwrap;
559629
630
+Module["setValue"] = setValue;
631
+
632
+Module["getValue"] = getValue;
633
+
634
+Module["stackSave"] = stackSave;
635
+
636
+Module["stackRestore"] = stackRestore;
637
+
560638
var calledRun;
561639
562640
function ExitStatus(status) {
563641
this.name = "ExitStatus";
564642
this.message = "Program terminated with exit(" + status + ")";
565643
--- extsrc/pikchr-module.js
+++ extsrc/pikchr-module.js
@@ -109,10 +109,76 @@
109 var noExitRuntime = Module["noExitRuntime"] || true;
110
111 if (typeof WebAssembly != "object") {
112 abort("no native wasm support detected");
113 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
115 var wasmMemory;
116
117 var ABORT = false;
118
@@ -482,10 +548,14 @@
482 }
483 }
484 instantiateAsync().catch(readyPromiseReject);
485 return {};
486 }
 
 
 
 
487
488 function callRuntimeCallbacks(callbacks) {
489 while (callbacks.length > 0) {
490 var callback = callbacks.shift();
491 if (typeof callback == "function") {
@@ -555,10 +625,18 @@
555 return (stackAlloc = Module["stackAlloc"] = Module["asm"]["j"]).apply(null, arguments);
556 };
557
558 Module["cwrap"] = cwrap;
559
 
 
 
 
 
 
 
 
560 var calledRun;
561
562 function ExitStatus(status) {
563 this.name = "ExitStatus";
564 this.message = "Program terminated with exit(" + status + ")";
565
--- extsrc/pikchr-module.js
+++ extsrc/pikchr-module.js
@@ -109,10 +109,76 @@
109 var noExitRuntime = Module["noExitRuntime"] || true;
110
111 if (typeof WebAssembly != "object") {
112 abort("no native wasm support detected");
113 }
114
115 function setValue(ptr, value, type = "i8", noSafe) {
116 if (type.endsWith("*")) type = "i32";
117 switch (type) {
118 case "i1":
119 HEAP8[ptr >> 0] = value;
120 break;
121
122 case "i8":
123 HEAP8[ptr >> 0] = value;
124 break;
125
126 case "i16":
127 HEAP16[ptr >> 1] = value;
128 break;
129
130 case "i32":
131 HEAP32[ptr >> 2] = value;
132 break;
133
134 case "i64":
135 tempI64 = [ value >>> 0, (tempDouble = value, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0) ],
136 HEAP32[ptr >> 2] = tempI64[0], HEAP32[ptr + 4 >> 2] = tempI64[1];
137 break;
138
139 case "float":
140 HEAPF32[ptr >> 2] = value;
141 break;
142
143 case "double":
144 HEAPF64[ptr >> 3] = value;
145 break;
146
147 default:
148 abort("invalid type for setValue: " + type);
149 }
150 }
151
152 function getValue(ptr, type = "i8", noSafe) {
153 if (type.endsWith("*")) type = "i32";
154 switch (type) {
155 case "i1":
156 return HEAP8[ptr >> 0];
157
158 case "i8":
159 return HEAP8[ptr >> 0];
160
161 case "i16":
162 return HEAP16[ptr >> 1];
163
164 case "i32":
165 return HEAP32[ptr >> 2];
166
167 case "i64":
168 return HEAP32[ptr >> 2];
169
170 case "float":
171 return HEAPF32[ptr >> 2];
172
173 case "double":
174 return Number(HEAPF64[ptr >> 3]);
175
176 default:
177 abort("invalid type for getValue: " + type);
178 }
179 }
180
181 var wasmMemory;
182
183 var ABORT = false;
184
@@ -482,10 +548,14 @@
548 }
549 }
550 instantiateAsync().catch(readyPromiseReject);
551 return {};
552 }
553
554 var tempDouble;
555
556 var tempI64;
557
558 function callRuntimeCallbacks(callbacks) {
559 while (callbacks.length > 0) {
560 var callback = callbacks.shift();
561 if (typeof callback == "function") {
@@ -555,10 +625,18 @@
625 return (stackAlloc = Module["stackAlloc"] = Module["asm"]["j"]).apply(null, arguments);
626 };
627
628 Module["cwrap"] = cwrap;
629
630 Module["setValue"] = setValue;
631
632 Module["getValue"] = getValue;
633
634 Module["stackSave"] = stackSave;
635
636 Module["stackRestore"] = stackRestore;
637
638 var calledRun;
639
640 function ExitStatus(status) {
641 this.name = "ExitStatus";
642 this.message = "Program terminated with exit(" + status + ")";
643
--- extsrc/pikchr-worker.js
+++ extsrc/pikchr-worker.js
@@ -25,10 +25,20 @@
2525
'type'-dependent value.
2626
2727
The 'type' values expected by each side of the main/worker
2828
connection vary. The types are described below but subject to
2929
change at any time as this experiment evolves.
30
+
31
+ Main-to-Worker message types:
32
+
33
+ - pikchr: data=pikchr-format text to render or an object:
34
+
35
+ {
36
+ pikchr: source code for the pikchr,
37
+ darkMode: boolean true to adjust colors for a dark color scheme,
38
+ cssClass: CSS class name to add to the SVG
39
+ }
3040
3141
Workers-to-Main types
3242
3343
- stdout, stderr: indicate stdout/stderr output from the wasm
3444
layer. The data property is the string of the output, noting
@@ -52,19 +62,20 @@
5262
the module loading is complete, a message with a text value of
5363
null is posted.
5464
5565
- pikchr:
5666
57
- {type: 'pikchr', data:{
58
- text: input text,
59
- pikchr: rendered result (SVG on success, HTML on error),
60
- isError: bool, true if .pikchr holds an error report
61
- }
62
-
63
- Main-to-Worker message types:
64
-
65
- - pikchr: data=pikchr-format text to render.
67
+ {type: 'pikchr',
68
+ data:{
69
+ pikchr: input text,
70
+ result: rendered result (SVG on success, HTML on error),
71
+ isError: bool, true if .pikchr holds an error report,
72
+ flags: integer: flags used to configure the pikchr rendering,
73
+ width: if !isError, width (pixels) of the SVG,
74
+ height: if !isError, height (pixels) of the SVG
75
+ }
76
+ }
6677
6778
*/
6879
6980
"use strict";
7081
(function(){
@@ -99,41 +110,61 @@
99110
self.onmessage = function f(ev){
100111
ev = ev.data;
101112
switch(ev.type){
102113
/**
103114
Runs the given text through pikchr and emits a 'pikchr'
104
- message with the result:
105
-
106
- {type:'pikchr', data:{
107
- pikchr: input text,
108
- result: result text,
109
- isError: true if result holds an error
110
- }}
115
+ message result (output format documented above).
111116
112117
Fires a working/start event before it starts and
113118
working/end event when it finishes.
114119
*/
115120
case 'pikchr':
116121
if(pikchrModule.isDead){
117122
stderr("wasm module has exit()ed. Cannot pikchr.");
118123
return;
119124
}
120
- if(!f._) f._ = pikchrModule.cwrap('pikchr', 'string', ['string']);
125
+ if(!f._){
126
+ f._ = pikchrModule.cwrap('pikchr', 'string', [
127
+ 'string'/*script*/, 'string'/*CSS class*/, 'number'/*flags*/,
128
+ 'number'/*output: SVG width*/, 'number'/*output: SVG height*/
129
+ ]);
130
+ }
121131
wMsg('working','start');
132
+ const stack = pikchrModule.stackSave();
122133
try {
134
+ const pnWidth = pikchrModule.stackAlloc(4),
135
+ pnHeight = pikchrModule.stackAlloc(4);
136
+ let script = '', flags = 0, cssClass = null;
137
+ if('string'===typeof ev.data){
138
+ script = ev.data;
139
+ }else if(ev.data && 'object'===typeof ev.data){
140
+ script = ev.data.pikchr;
141
+ flags = ev.data.darkMode ? 0x02 : 0;
142
+ if(ev.data.cssClass) cssClass = ev.data.cssClass;
143
+ }
144
+ pikchrModule.setValue(pnWidth, 0, "i32");
145
+ pikchrModule.setValue(pnHeight, 0, "i32");
123146
const msg = {
124
- pikchr: ev.data,
125
- result: (f._(ev.data) || "").trim()
147
+ pikchr: script,
148
+ result: (f._(script, cssClass, flags, pnWidth, pnHeight) || "").trim(),
149
+ flags: flags
126150
};
127151
msg.isError = !!(msg.result && msg.result.startsWith('<div'));
152
+ if(msg.isError){
153
+ msg.width = msg.height = null;
154
+ }else{
155
+ msg.width = pikchrModule.getValue(pnWidth, "i32");
156
+ msg.height = pikchrModule.getValue(pnHeight, "i32");
157
+ }
128158
wMsg('pikchr', msg);
129159
} finally {
160
+ pikchrModule.stackRestore(stack);
130161
wMsg('working','end');
131162
}
132163
return;
133164
};
134
- console.warn("Unknown fiddle-worker message type:",ev);
165
+ console.warn("Unknown pikchr-worker message type:",ev);
135166
};
136167
137168
/**
138169
emscripten module for use with build mode -sMODULARIZE.
139170
*/
@@ -176,11 +207,10 @@
176207
});
177208
}
178209
};
179210
180211
importScripts('pikchr-module.js');
181
- //console.error("initPikchrModule =",initPikchrModule);
182212
/**
183213
initPikchrModule() is installed via pikchr-module.js due to
184214
building with:
185215
186216
emcc ... -sMODULARIZE=1 -sEXPORT_NAME=initPikchrModule
187217
--- extsrc/pikchr-worker.js
+++ extsrc/pikchr-worker.js
@@ -25,10 +25,20 @@
25 'type'-dependent value.
26
27 The 'type' values expected by each side of the main/worker
28 connection vary. The types are described below but subject to
29 change at any time as this experiment evolves.
 
 
 
 
 
 
 
 
 
 
30
31 Workers-to-Main types
32
33 - stdout, stderr: indicate stdout/stderr output from the wasm
34 layer. The data property is the string of the output, noting
@@ -52,19 +62,20 @@
52 the module loading is complete, a message with a text value of
53 null is posted.
54
55 - pikchr:
56
57 {type: 'pikchr', data:{
58 text: input text,
59 pikchr: rendered result (SVG on success, HTML on error),
60 isError: bool, true if .pikchr holds an error report
61 }
62
63 Main-to-Worker message types:
64
65 - pikchr: data=pikchr-format text to render.
 
66
67 */
68
69 "use strict";
70 (function(){
@@ -99,41 +110,61 @@
99 self.onmessage = function f(ev){
100 ev = ev.data;
101 switch(ev.type){
102 /**
103 Runs the given text through pikchr and emits a 'pikchr'
104 message with the result:
105
106 {type:'pikchr', data:{
107 pikchr: input text,
108 result: result text,
109 isError: true if result holds an error
110 }}
111
112 Fires a working/start event before it starts and
113 working/end event when it finishes.
114 */
115 case 'pikchr':
116 if(pikchrModule.isDead){
117 stderr("wasm module has exit()ed. Cannot pikchr.");
118 return;
119 }
120 if(!f._) f._ = pikchrModule.cwrap('pikchr', 'string', ['string']);
 
 
 
 
 
121 wMsg('working','start');
 
122 try {
 
 
 
 
 
 
 
 
 
 
 
 
123 const msg = {
124 pikchr: ev.data,
125 result: (f._(ev.data) || "").trim()
 
126 };
127 msg.isError = !!(msg.result && msg.result.startsWith('<div'));
 
 
 
 
 
 
128 wMsg('pikchr', msg);
129 } finally {
 
130 wMsg('working','end');
131 }
132 return;
133 };
134 console.warn("Unknown fiddle-worker message type:",ev);
135 };
136
137 /**
138 emscripten module for use with build mode -sMODULARIZE.
139 */
@@ -176,11 +207,10 @@
176 });
177 }
178 };
179
180 importScripts('pikchr-module.js');
181 //console.error("initPikchrModule =",initPikchrModule);
182 /**
183 initPikchrModule() is installed via pikchr-module.js due to
184 building with:
185
186 emcc ... -sMODULARIZE=1 -sEXPORT_NAME=initPikchrModule
187
--- extsrc/pikchr-worker.js
+++ extsrc/pikchr-worker.js
@@ -25,10 +25,20 @@
25 'type'-dependent value.
26
27 The 'type' values expected by each side of the main/worker
28 connection vary. The types are described below but subject to
29 change at any time as this experiment evolves.
30
31 Main-to-Worker message types:
32
33 - pikchr: data=pikchr-format text to render or an object:
34
35 {
36 pikchr: source code for the pikchr,
37 darkMode: boolean true to adjust colors for a dark color scheme,
38 cssClass: CSS class name to add to the SVG
39 }
40
41 Workers-to-Main types
42
43 - stdout, stderr: indicate stdout/stderr output from the wasm
44 layer. The data property is the string of the output, noting
@@ -52,19 +62,20 @@
62 the module loading is complete, a message with a text value of
63 null is posted.
64
65 - pikchr:
66
67 {type: 'pikchr',
68 data:{
69 pikchr: input text,
70 result: rendered result (SVG on success, HTML on error),
71 isError: bool, true if .pikchr holds an error report,
72 flags: integer: flags used to configure the pikchr rendering,
73 width: if !isError, width (pixels) of the SVG,
74 height: if !isError, height (pixels) of the SVG
75 }
76 }
77
78 */
79
80 "use strict";
81 (function(){
@@ -99,41 +110,61 @@
110 self.onmessage = function f(ev){
111 ev = ev.data;
112 switch(ev.type){
113 /**
114 Runs the given text through pikchr and emits a 'pikchr'
115 message result (output format documented above).
 
 
 
 
 
 
116
117 Fires a working/start event before it starts and
118 working/end event when it finishes.
119 */
120 case 'pikchr':
121 if(pikchrModule.isDead){
122 stderr("wasm module has exit()ed. Cannot pikchr.");
123 return;
124 }
125 if(!f._){
126 f._ = pikchrModule.cwrap('pikchr', 'string', [
127 'string'/*script*/, 'string'/*CSS class*/, 'number'/*flags*/,
128 'number'/*output: SVG width*/, 'number'/*output: SVG height*/
129 ]);
130 }
131 wMsg('working','start');
132 const stack = pikchrModule.stackSave();
133 try {
134 const pnWidth = pikchrModule.stackAlloc(4),
135 pnHeight = pikchrModule.stackAlloc(4);
136 let script = '', flags = 0, cssClass = null;
137 if('string'===typeof ev.data){
138 script = ev.data;
139 }else if(ev.data && 'object'===typeof ev.data){
140 script = ev.data.pikchr;
141 flags = ev.data.darkMode ? 0x02 : 0;
142 if(ev.data.cssClass) cssClass = ev.data.cssClass;
143 }
144 pikchrModule.setValue(pnWidth, 0, "i32");
145 pikchrModule.setValue(pnHeight, 0, "i32");
146 const msg = {
147 pikchr: script,
148 result: (f._(script, cssClass, flags, pnWidth, pnHeight) || "").trim(),
149 flags: flags
150 };
151 msg.isError = !!(msg.result && msg.result.startsWith('<div'));
152 if(msg.isError){
153 msg.width = msg.height = null;
154 }else{
155 msg.width = pikchrModule.getValue(pnWidth, "i32");
156 msg.height = pikchrModule.getValue(pnHeight, "i32");
157 }
158 wMsg('pikchr', msg);
159 } finally {
160 pikchrModule.stackRestore(stack);
161 wMsg('working','end');
162 }
163 return;
164 };
165 console.warn("Unknown pikchr-worker message type:",ev);
166 };
167
168 /**
169 emscripten module for use with build mode -sMODULARIZE.
170 */
@@ -176,11 +207,10 @@
207 });
208 }
209 };
210
211 importScripts('pikchr-module.js');
 
212 /**
213 initPikchrModule() is installed via pikchr-module.js due to
214 building with:
215
216 emcc ... -sMODULARIZE=1 -sEXPORT_NAME=initPikchrModule
217
--- src/fossil.page.pikchrshowasm.js
+++ src/fossil.page.pikchrshowasm.js
@@ -281,11 +281,14 @@
281281
/**
282282
Submits the current input text to pikchr and renders the
283283
result. */
284284
PS.render = function f(txt){
285285
preStartWork();
286
- this.wMsg('pikchr',txt);
286
+ this.wMsg('pikchr',{
287
+ pikchr: txt,
288
+ darkMode: !!window.fossil.config.skin.isDark
289
+ });
287290
};
288291
289292
const eOut = E('#pikchr-output');
290293
const eOutWrapper = E('#pikchr-output-wrapper');
291294
PS.addMsgHandler('pikchr', function(ev){
@@ -441,11 +444,11 @@
441444
f._ = text;
442445
PS._isDirty = false;
443446
PS.render(text || '');
444447
}, 800, false);
445448
446
- taInput.addEventListener('keyup',function f(ev){
449
+ taInput.addEventListener('keydown',function f(ev){
447450
if((ev.ctrlKey || ev.shiftKey) && 13 === ev.keyCode){
448451
// Ctrl-enter and shift-enter both run the current input
449452
PS._isDirty = false/*prevent a pending debounce from re-rendering*/;
450453
ev.preventDefault();
451454
ev.stopPropagation();
452455
--- src/fossil.page.pikchrshowasm.js
+++ src/fossil.page.pikchrshowasm.js
@@ -281,11 +281,14 @@
281 /**
282 Submits the current input text to pikchr and renders the
283 result. */
284 PS.render = function f(txt){
285 preStartWork();
286 this.wMsg('pikchr',txt);
 
 
 
287 };
288
289 const eOut = E('#pikchr-output');
290 const eOutWrapper = E('#pikchr-output-wrapper');
291 PS.addMsgHandler('pikchr', function(ev){
@@ -441,11 +444,11 @@
441 f._ = text;
442 PS._isDirty = false;
443 PS.render(text || '');
444 }, 800, false);
445
446 taInput.addEventListener('keyup',function f(ev){
447 if((ev.ctrlKey || ev.shiftKey) && 13 === ev.keyCode){
448 // Ctrl-enter and shift-enter both run the current input
449 PS._isDirty = false/*prevent a pending debounce from re-rendering*/;
450 ev.preventDefault();
451 ev.stopPropagation();
452
--- src/fossil.page.pikchrshowasm.js
+++ src/fossil.page.pikchrshowasm.js
@@ -281,11 +281,14 @@
281 /**
282 Submits the current input text to pikchr and renders the
283 result. */
284 PS.render = function f(txt){
285 preStartWork();
286 this.wMsg('pikchr',{
287 pikchr: txt,
288 darkMode: !!window.fossil.config.skin.isDark
289 });
290 };
291
292 const eOut = E('#pikchr-output');
293 const eOutWrapper = E('#pikchr-output-wrapper');
294 PS.addMsgHandler('pikchr', function(ev){
@@ -441,11 +444,11 @@
444 f._ = text;
445 PS._isDirty = false;
446 PS.render(text || '');
447 }, 800, false);
448
449 taInput.addEventListener('keydown',function f(ev){
450 if((ev.ctrlKey || ev.shiftKey) && 13 === ev.keyCode){
451 // Ctrl-enter and shift-enter both run the current input
452 PS._isDirty = false/*prevent a pending debounce from re-rendering*/;
453 ev.preventDefault();
454 ev.stopPropagation();
455
--- src/style.pikchrshow.css
+++ src/style.pikchrshow.css
@@ -187,9 +187,5 @@
187187
flex-direction: column-reverse;
188188
}
189189
#view-split > .fieldset.options {
190190
margin-top: 0.5em;
191191
}
192
-body.fossil-dark-style #pikchr-output svg {
193
- /* Flip the colors to approximate a dark theme look */
194
- filter: invert(1) hue-rotate(180deg);
195
-}
196192
--- src/style.pikchrshow.css
+++ src/style.pikchrshow.css
@@ -187,9 +187,5 @@
187 flex-direction: column-reverse;
188 }
189 #view-split > .fieldset.options {
190 margin-top: 0.5em;
191 }
192 body.fossil-dark-style #pikchr-output svg {
193 /* Flip the colors to approximate a dark theme look */
194 filter: invert(1) hue-rotate(180deg);
195 }
196
--- src/style.pikchrshow.css
+++ src/style.pikchrshow.css
@@ -187,9 +187,5 @@
187 flex-direction: column-reverse;
188 }
189 #view-split > .fieldset.options {
190 margin-top: 0.5em;
191 }
 
 
 
 
192

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button