Fossil

Check-in Differences
Login

Check-in Differences

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Difference From 67060c509079a8b7 To d88444e265f3f78f

2020-09-17
23:44
pikchr command doc updates. (check-in: 82a0b517 user: stephan tags: trunk)
23:25
Removed some console.debug() output and fixed extraneous breaks which caused markdown_to_html() to stop afer processing a single tag. (check-in: 67060c50 user: stephan tags: trunk)
23:11
Renovated the pikchr click handling as discussed off-list with drh. (check-in: 938bb6c7 user: stephan tags: trunk)
21:09
Toggle Pikchr between SVG and source code using ctrl-click. Or if the Pikchr was created using the "toggle" tag, an plain old single-click will suffice. (check-in: d88444e2 user: drh tags: trunk)
19:31
Misuse of a potentially unsigned value, caught by clang. Only affected platforms where char is unsigned by default. (check-in: 5c92bbfc user: stephan tags: trunk)

Changes to src/default.css.

1386
1387
1388
1389
1390
1391
1392


1393
1394
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396







+
+


noscript > .error {
  /* Part of the style_emit_noscript_for_js_page() interface. */
  padding: 1em;
  font-size: 150%;
}
.pikchr-src { /* source code view for a pikchr (see fossil.pikchr.js) */
  box-sizing: border-box/*reduces UI shift*/;
  border-width: 1px;
  border-style: dotted;
  overflow: auto;
}

Changes to src/fossil.dom.js.

711
712
713
714
715
716
717
718
719


720
721
722
723
724
725
726
711
712
713
714
715
716
717


718
719
720
721
722
723
724
725
726







-
-
+
+







  };

  /**
     Parses a string as HTML.

     Usages:

     Array (htmlString)
     DOMElement (DOMElement target, htmlString)
     (htmlString)
     (DOMElement target, htmlString)

     The first form parses the string as HTML and returns an Array of
     all elements parsed from it. If string is falsy then it returns
     an empty array.

     The second form parses the HTML string and appends all elements
     to the given target element using dom.append(), then returns the

Changes to src/fossil.page.pikchrshow.js.

320
321
322
323
324
325
326
327

328
329
330
331
332
333
334
335
336
337
320
321
322
323
324
325
326

327
328
329

330
331
332
333
334
335
336







-
+


-







    D.enable(this.e.previewModeToggle, this.e.markupAlignRadios);
    let label, svg;
    switch(this.previewMode){
    case 0:
      label = "SVG";
      f.showMarkupAlignment(false);
      D.parseHtml(D.clearElement(preTgt), P.response.raw);
      svg = preTgt.querySelector('svg.pikchr');
      svg = f.getSvgNode(this.response.raw);
      if(svg){ /*for copy button*/
        this.e.taPreviewText.value = svg.outerHTML;
        F.pikchr.addSrcView(svg);
      }
      break;
    case 1:
      label = "Markdown";
      f.showMarkupAlignment(true);
      this.e.taPreviewText.value = [
        '```pikchr'+f.getMarkupAlignmentClass(),

Changes to src/fossil.pikchr.js.

1
2

3

4











































































5

6

7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
24
25









26
27
28



29


30
31




32
33
34
35
36
37
38
39
40
41
42
43
44
45



46
47
48


49
50
51
52
53
54
55
56


57
58
59
60
61



62
63
64

65
66
67
68
69
70
71

72
73


74

75
76
77
78
79
80
81
82
83
84
85






















































































86

87
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

83

84
85
86

87
88
89
90
91
92
93
94
95
96





97
98
99
100
101
102
103
104
105
106


107
108
109

110
111
112
113
114
115
116
117
118
119
120
121
122





123



124
125
126



127
128








129
130


131
132

133
134
135
136
137

138
139
140
141
142
143
144
145
146


147
148

149
150
151









152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240


+
-
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
-
+
-



-
+









-
-
-
-
-
+
+
+
+
+
+
+
+
+

-
-
+
+
+
-
+
+


+
+
+
+





-
-
-
-
-

-
-
-
+
+
+
-
-
-
+
+
-
-
-
-
-
-
-
-
+
+
-
-


-
+
+
+


-
+







+
-
-
+
+
-
+


-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+

(function(F/*window.fossil object*/){
  "use strict";

  const D = F.dom, P = F.pikchr = {};
  const D = F.dom;

  const P = F.pikchr = {
  };

  ////////////////////////////////////////////////////////////////////////
  // Install an app-specific stylesheet, just for development, after which
  // it will be moved into default.css
  (function(){
    const head = document.head || document.querySelector('head'),
          styleTag = document.createElement('style'),
          wh = '1cm' /* fixed width/height of buttons */,
          styleCSS = `
.pikchr-button-bar {
  position: absolute;
  position: absolute;
  top: 0;
  left: 0;
  display: inline-flex;
  flex-direction: column;
}
.pikchr-src-button {
  min-height: ${wh}; max-height: ${wh};
  min-width: ${wh}; max-width: ${wh};
  font-size: ${wh};
  border: 1px solid black;
  background-color: rgba(255,255,0,0.7);
  border-radius: 0.25cm;
  z-index: 50;
  cursor: pointer;
  text-align: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transform-origin: center;
  transition: transform 250ms linear;
  padding: 0; margin: 0;
/* MIT-licensed SVG from: https://github.com/leungwensen/svg-icon/blob/master/dist/svg/ant/code.svg */
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg viewBox='0 0 1195 1195' \
xmlns='http:/\x2fwww.w3.org/2000/svg'%3e%3cpath d='M321.333 440q-9-10-22.5-10t-22.5 \
10l-182 181q-9 9-9 22.5t9 22.5l182 182q9 10 22.5 10t22.5-10q10-9 10-22.5t-10-22.5l-159-159 \
159-159q10-10 10-23t-10-22zm552 0q9-10 22.5-10t22.5 10l182 181q9 9 9 22.5t-9 \
22.5l-182 182q-9 10-22.5 10t-22.5-10q-10-9-10-22.5t10-22.5l159-159-159-159q-10-10-10-23t10-22zm-97-180q12 \
6 16 19t-2 24l-371 704q-7 12-19.5 16t-24.5-2q-11-7-15-19.5t2-24.5l371-703q6-12 \
18.5-16t24.5 2z'/%3e%3c/svg%3e");
  background-size: contain;
}
.pikchr-src-button.src-active {
  transform: scaleX(-1);
/* MIT-licensed SVG from: https://github.com/leungwensen/svg-icon/blob/master/dist/svg/ant/picture.svg */
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg viewBox='0 0 1195 1195' \
xmlns='http:/\x2fwww.w3.org/2000/svg'%3e%3cpath d='M1045.333 192h-896q-26 0-45 \
19t-19 45v768q0 26 19 45t45 19h896q26 0 45-19t19-45V256q0-26-19-45t-45-19zm-896 \
64h896v714l-236-348q-7-12-21-14t-25 7l-154 125-174-243q-10-14-28-13t-26 17l-232 \
448V256zm855 768h-822l231-447 184 255 179-145zm-182-642q13 0 22.5 9.5t9.5 22.5-9.5 \
22.5-22.5 9.5-22.5-9.5-9.5-22.5 9.5-22.5 22.5-9.5zm0-64q-40 0-68 28t-28 68 28 68 68 \
28 68-28 28-68-28-68-68-28z'/%3e%3c/svg%3e");
}
textarea.pikchr-src-text {
  box-sizing: border-box/*reduces UI shift*/;
}
.pikchr-copy-button {
  min-width: ${wh}; max-width: ${wh};
  min-height: ${wh}; max-height: ${wh};
  display: inline-block;
}
.pikchr-button-bar > .pikchr-src-button,
.pikchr-button-bar > .pikchr-copy-button {
  margin-bottom: 0.3em;
}
`;
    head.appendChild(styleTag);
    /* Adapted from https://stackoverflow.com/a/524721 */
    styleTag.type = 'text/css';
    D.append(styleTag, styleCSS);
  })();

  /**
     Sets up a "view source" button on one or more pikchr-created SVG
     Initializes pikchr-rendered elements with the ability to
     image elements.
     toggle between their SVG and source code.

     The first argument may be any of:

     - A single SVG.pikchr element.
     - A single SVG element.

     - A collection (with a forEach method) of such elements.

     - A CSS selector string for one or more such elements.

     - An array of such strings.

     Passing no value is equivalent to passing 'svg.pikchr'.

     For each SVG in the resulting set, this function sets up event
     handlers which allow the user to toggle the SVG between image and
     source code modes. The image will switch modes in response to
     cltr-click and, if its *parent* element has the "toggle" CSS
     class, it will also switch modes in response to single-click.
     For each SVG in the resulting set, this function does the
     following:

     - It sets the "position" value of the element's *parent* node to
     "relative", as that is necessary for what follows.

     - It creates a small pseudo-button, adding it to the SVG
     element's parent node, styled to hover in one of the element's
     corners.

     If the parent element has the "source" CSS class, the image
     starts off with its source code visible and the image hidden,
     - That button, when tapped, toggles the SVG on and off
     while revealing or hiding a readonly textarea element
     which contains the source code for that pikchr SVG
     instead of the default of the other way around.
     (which pikchr has helpfully embedded in the SVG's
     metadata).

     Returns this object.

     The 2nd argument is intended to be a plain options object, but it
     is currently unused, as it's not yet clear what we can/should
     make configurable.

     Each element will only be processed once by this routine, even if
     it is passed to this function multiple times. Each processed
     element gets a "data" attribute set to it to indicate that it was
     already dealt with.

     This code expects the following structure around the SVGs, and
     will not process any which don't match this:

     <DIV><SVG.pikchr></SVG><PRE.pikchr-src></PRE></DIV>
  */
  P.addSrcView = function f(svg){
    if(!f.hasOwnProperty('parentClick')){
      f.parentClick = function(ev){
  P.addSrcView = function f(svg,opt){
    if(!f.hasOwnProperty('bodyClick')){
      f.bodyClick = function(){
        if(ev.ctrlKey || this.classList.contains('toggle')){
          this._childs.forEach((e)=>e.classList.toggle('hidden'));
        }
        D.addClass(document.querySelectorAll('.pikchr-button-bar'), 'hidden');
      };
        /* For the sake of small pics, we have to eliminate the
           parent element's max-width... */
        const src = this._childs[1];
        if(src.classList.contains('hidden')){
          this.style.maxWidth = this.dataset.origMaxWidth;
        }else{
          this.style.maxWidth = "unset";
        }
      document.body.addEventListener('click', f.bodyClick, false);
    }
      };
    };
    if(!svg) svg = 'svg.pikchr';
    if('string' === typeof svg){
      document.querySelectorAll(svg).forEach((e)=>f.call(this, e));
      document.querySelectorAll(svg).forEach(
        (e)=>f.call(this, e, opt)
      );
      return this;
    }else if(svg.forEach){
      svg.forEach((e)=>f.call(this, e));
      svg.forEach((e)=>f.call(this, e, opt));
      return this;
    }
    if(svg.dataset.pikchrProcessed){
      return this;
    }
    svg.dataset.pikchrProcessed = 1;
    const parent = svg.parentNode;
    parent.style.position = 'relative' /* REQUIRED for btn placement */;
    const srcView = svg.nextElementSibling;
    if(!srcView || !srcView.classList.contains('pikchr-src')){
    const srcView = parent.querySelector('.pikchr-src');
    if(!srcView){
      /* Without this element, there's nothing for us to do here. */
      console.warn("No pikchr source node found in",parent);
      return this;
    }
    parent.dataset.origMaxWidth = parent.style.maxWidth;
    parent._childs = [svg, srcView];
    D.addClass(srcView, 'hidden');
    D.removeClass(svg, 'hidden');
    parent.addEventListener('click', f.parentClick, false);
    if(parent.classList.contains('source')){
      /* Start off in source-view mode via a very fake click event */
      f.parentClick.call(parent, {ctrlKey:true});
    }
    const buttonBar = D.addClass(D.span(), 'pikchr-button-bar');
    const btnFlip = D.append(
      D.addClass(D.span(), 'pikchr-src-button'),
    );
    const btnCopy = F.copyButton(D.span(), {
      cssClass: ['copy-button', 'pikchr-copy-button'],
      extractText: ()=>(srcView.classList.contains('hidden') ? svg.outerHTML : srcView.value),
      oncopy: ()=>D.flashOnce(btnCopy, ()=>btnFlip.click())
      // ^^^ after copying and flashing, flip back to SVG mode. */
    });
    D.append(buttonBar, btnFlip, btnCopy);
    // not yet sure which options we can/should support:
    // opt = F.mergeLastWins({},opt);
    D.addClass(srcView, 'hidden')/*should already be so, but just in case*/;
    D.append(parent, D.addClass(buttonBar, 'hidden'));

    parent.addEventListener('click', function f(ev){
      ev.preventDefault();
      ev.stopPropagation();
      D.toggleClass(buttonBar, 'hidden');
    }, false);

    /** Show the mode-switch buttons only in source view, and switch to
        source view if the SVG is tapped. This allows easy switching to
        source view while also keeping the buttons out of the way in
        SVG mode and giving the user the option of select/copy in the
        source mode via normal text-selection approaches. */
    svg.addEventListener('click', function(ev){
      D.removeClass(buttonBar, 'hidden');
      btnFlip.click();
    }, false);

    /** Toggle the source/SVG view on click. */
    btnFlip.addEventListener('click', function f(ev){
      ev.preventDefault();
      ev.stopPropagation();
      if(!f.hasOwnProperty('origMaxWidth')){
        f.origMaxWidth = parent.style.maxWidth;
      }
      const svgStyle = window.getComputedStyle(svg);
      srcView.style.minWidth = svgStyle.width;
      srcView.style.minHeight = svgStyle.height;
      /* ^^^ The SVG wrapper/parent element has a max-width, so the
         textarea will be too small on tiny images and won't be
         enlargable. */
      if(0){
        /* We seem to have a fundamental incompatibility with how we
           really want to position srcView at the same pos/size as the
           svg and how that interacts with centered items.
           Until/unless this can be solved, we have to decide between
           the lesser of two evils:

           1) This option. Small images have uselessly tiny source
           view which cannot be enlarged because the parent element
           has a width and/or max-width. width/max-width are important
           for center alignment via the margin:auto trick.

           2) Center-aligned images shift all the way to the left when
           the source view is visible, then back to the center when
           source view is hidden. Source views are resizable and may
           even grow a bit automatically for tiny images.
        */
        if(srcView.classList.contains('hidden')){/*initial state*/
          parent.style.width = f.origMaxWidth;
          parent.style.maxWidth = 'unset';
        }else{/*srcView is active*/
          parent.style.maxWidth = f.origMaxWidth;
          parent.style.width = 'unset';
        }
      }else if(1){
        /* Option #2: gives us good results for non-centered items but
           not for centered. We apparently have no(?) reliable way of
           distinguishing centered from left/indented pikchrs here
           unless we add a CSS class to mark them as such in the
           pikchr-to-wiki-image code. */
        if(srcView.classList.contains('hidden')){/*initial state*/
          parent.style.width = 'unset';
          parent.style.maxWidth = 'unset';
        }else{/*srcView is active*/
          parent.style.maxWidth = f.origMaxWidth;
          parent.style.width = 'unset';
        }
      }
      btnFlip.classList.toggle('src-active');
      D.toggleClass([svg, srcView, buttonBar], 'hidden');
    }, false);
  };
  
})(window.fossil);

Changes to src/markdown_html.c.

340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355














356
357


358
359


360
361


362
363


364
365
366
367
368
369
370
371
372















373
374
375
376

















377
378
379
380
381
382
383
340
341
342
343
344
345
346









347
348
349
350
351
352
353
354
355
356
357
358
359
360


361
362


363
364


365
366


367
368









369
370
371
372
373
374
375
376
377
378
379
380
381
382
383




384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407







-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







** text and insert the result in place of the original.
*/
void pikchr_to_html(
  Blob *ob,                     /* Write the generated SVG here */
  const char *zSrc, int nSrc,   /* The Pikchr source text */
  const char *zArg, int nArg    /* Addition arguments */
){
  int pikFlags = PIKCHR_PROCESS_NONCE
    | PIKCHR_PROCESS_DIV
    | PIKCHR_PROCESS_SRC_HIDDEN;
  Blob bSrc = empty_blob;

  while( nArg>0 ){
    int i;
    for(i=0; i<nArg && !fossil_isspace(zArg[i]); i++){}
    if( i==6 && strncmp(zArg, "center", 6)==0 ){
  int w = 0, h = 0;
  char *zIn = fossil_strndup(zSrc, nSrc);
  char *zOut = pikchr(zIn, "pikchr", 0, &w, &h);
  if( w>0 && h>0 ){
    static int nSvg = 0;
    const char *zSafeNonce = safe_html_nonce(1);
    const char *zCss = "";
    const char *zClickOk = "e.ctrlKey";
    blob_append(ob, zSafeNonce, -1);
    blob_append_char(ob, '\n');
    while( nArg>0 ){
      int i;
      for(i=0; i<nArg && !fossil_isspace(zArg[i]); i++){}
      if( i==6 && strncmp(zArg, "center", 6)==0 ){
      pikFlags |= PIKCHR_PROCESS_DIV_CENTER;
    }else if( i==6 && strncmp(zArg, "indent", 6)==0 ){
        zCss = "display:block;margin:auto;";
      }else if( i==6 && strncmp(zArg, "indent", 6)==0 ){
      pikFlags |= PIKCHR_PROCESS_DIV_INDENT;
    }else if( i==10 && strncmp(zArg, "float-left", 10)==0 ){
        zCss = "margin-left:4em;";
      }else if( i==10 && strncmp(zArg, "float-left", 10)==0 ){
      pikFlags |= PIKCHR_PROCESS_DIV_FLOAT_LEFT;
    }else if( i==11 && strncmp(zArg, "float-right", 11)==0 ){
        zCss = "float:left;padding=4em;";
      }else if( i==11 && strncmp(zArg, "float-right", 11)==0 ){
      pikFlags |= PIKCHR_PROCESS_DIV_FLOAT_RIGHT;
    }else if( i==6 && strncmp(zArg, "toggle", 6)==0 ){
        zCss = "float:right;padding=4em;";
      }else if( i==6 && strncmp(zArg, "toggle", 6)==0 ){
      pikFlags |= PIKCHR_PROCESS_DIV_TOGGLE;
    }else if( i==6 && strncmp(zArg, "source", 6)==0 ){
      pikFlags |= PIKCHR_PROCESS_DIV_SOURCE;
    }
    while( i<nArg && fossil_isspace(zArg[i]) ){ i++; }
    zArg += i;
    nArg -= i;
  }
  blob_append(&bSrc, zSrc, nSrc)
        zClickOk = "1";
      }
      while( i<nArg && fossil_isspace(zArg[i]) ){ i++; }
      zArg += i;
      nArg -= i;
    }
    blob_appendf(ob, "<div id='svgid-%d'>\n", ++nSvg);
    blob_appendf(ob, "<div class='pikchr-svg'");
    blob_appendf(ob, " style='max-width:%dpx;%s'>\n", w, zCss);
    blob_append(ob, zOut, -1);
    blob_appendf(ob, "</div>\n");
    blob_appendf(ob, "<pre class='hidden'><code>"
                     "%s</code></pre>\n", zIn);
    blob_appendf(ob, "</div>\n");
    blob_appendf(ob,
    /*have to dup input to ensure a NUL-terminated source string */;
  pikchr_process(blob_str(&bSrc), pikFlags, 0, ob);
  blob_reset(&bSrc);
}
      "<script nonce='%s'>\n"
      "document.getElementById('svgid-%d').onclick=function(e){\n"
      "  if(%s){\n"
      "    for(var c of this.children){c.classList.toggle('hidden');}\n"
      "  }\n"
      "}\n"
      "</script>\n",
      style_nonce(), nSvg, zClickOk);
    blob_appendf(ob, "%s\n", zSafeNonce);
  }else{
    blob_appendf(ob, "<pre>\n%s\n</pre>\n", zOut);
  }
  fossil_free(zIn);
  free(zOut);
}



/* Invoked for `...` blocks where there are nSep grave accents in a
** row that serve as the delimiter.  According to CommonMark:
**
**   *  https://spec.commonmark.org/0.29/#fenced-code-blocks
**   *  https://spec.commonmark.org/0.29/#code-spans
**

Changes to src/pikchrshow.c.

31
32
33
34
35
36
37
38
39
40
41
42
43

44
45
46
47
48




49
50
51
52
53
54
55
56
57
58
59
60
61

62
63
64
65
66
67


68
69
70
71
72
73
74
75
76
77
78
79

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

97
98
99
100
101
102



103
104
105
106

107
108
109
110
111
112

113
114
115

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
31
32
33
34
35
36
37


38
39
40

41





42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

58
59
60
61
62


63
64
65
66
67
68
69
70
71
72
73
74
75

76












77
78
79
80

81


82



83
84
85
86
87
88

89


90
91
92

93
94
95

96
97
98
99
100
101
102
103
104
105


106
107
108
109
110
111
112







-
-



-
+
-
-
-
-
-
+
+
+
+












-
+




-
-
+
+











-
+
-
-
-
-
-
-
-
-
-
-
-
-




-
+
-
-

-
-
-
+
+
+



-
+
-
-



-
+


-
+









-
-







#define PIKCHR_PROCESS_SRC        0x10
#define PIKCHR_PROCESS_SRC_HIDDEN 0x20
#define PIKCHR_PROCESS_DIV        0x40
#define PIKCHR_PROCESS_DIV_INDENT      0x0100
#define PIKCHR_PROCESS_DIV_CENTER      0x0200
#define PIKCHR_PROCESS_DIV_FLOAT_LEFT  0x0400
#define PIKCHR_PROCESS_DIV_FLOAT_RIGHT 0x0800
#define PIKCHR_PROCESS_DIV_TOGGLE      0x1000
#define PIKCHR_PROCESS_DIV_SOURCE      0x2000
#endif

/*
** Processes a pikchr script, optionally with embedded TH1, and
** Processes a pikchr script, optionally with embedded TH1. zIn is the
** produces HTML code for it. zIn is the NUL-terminated input
** script. pikFlags may be a bitmask of any of the PIKCHR_PROCESS_xxx
** flags documented below. thFlags may be a bitmask of any of the
** TH_INIT_xxx and/or TH_R2B_xxx flags. Output is sent to pOut,
** appending to it without modifying any prior contents.
** input script. pikFlags may be a bitmask of any of the
** PIKCHR_PROCESS_xxx flags (see below). thFlags may be a bitmask of
** any of the TH_INIT_xxx and/or TH_R2B_xxx flags. Output is sent to
** pOut, appending to it without modifying any prior contents.
**
** Returns 0 on success, 1 if TH1 processing failed, or 2 if pikchr
** processing failed. In either case, the error message (if any) from
** TH1 or pikchr will be appended to pOut.
**
** pikFlags flag descriptions:
**
** - PIKCHR_PROCESS_TH1 means to run zIn through TH1, using the TH1
** init flags specified in the 3rd argument. If thFlags is non-0 then
** this flag is assumed even if it is not specified.
**
** - PIKCHR_PROCESS_TH1_NOSVG means that processing stops after the
** TH1 eval step, thus the output will be (presumably) a
** TH1 step, thus the output will be (presumably) a
** TH1-generated/processed pikchr script (or whatever else the TH1
** outputs). If this flag is set, PIKCHR_PROCESS_TH1 is assumed even
** if it is not specified.
**
** All of the remaining flags listed below are ignored if
** PIKCHR_PROCESS_TH1_NOSVG is specified!
** The remaining flags listed below are ignored if
** PIKCHR_PROCESS_TH1_NOSVG is specified:
**
** - PIKCHR_PROCESS_DIV: if set, the SVG result is wrapped in a DIV
** element which specifies a max-width style value based on the SVG's
** calculated size. This flag has multiple mutually exclusive forms:
**
**  - PIKCHR_PROCESS_DIV uses default element alignment.
**  - PIKCHR_PROCESS_DIV_INDENT indents the div.
**  - PIKCHR_PROCESS_DIV_CENTER centers the div.
**  - PIKCHR_PROCESS_DIV_FLOAT_LEFT floats the div left.
**  - PIKCHR_PROCESS_DIV_FLOAT_RIGHT floats the div right.
**
** If more than one is specified, which one is used is undefined. Those
** If more than one is specified, which one is used is undefined.
** flags may be OR'd with one or both of the following:
**
**  - PIKCHR_PROCESS_DIV_TOGGLE: adds the 'toggle' CSS class to the
**    outer DIV so that event-handler code can install different
**    toggling behaviour than the default. Default is ctrl-click, but
**    this flag enables single-click toggling for the element.
**
**  - PIKCHR_PROCESS_DIV_SOURCE: adds the 'source' CSS class to the
**    outer DIV, which is a hint to the client-side renderer (see
**    fossil.pikchr.js) that the pikchr should initially be rendered
**    in source code form mode (the default is to hide the source and
**    show the SVG).
**
** - PIKCHR_PROCESS_NONCE: if set, the resulting SVG/DIV are wrapped
** in "safe nonce" comments, which are a fossil-internal mechanism
** which prevents the wiki/markdown processors from re-processing this
** output. This is necessary when calling this routine in the context
** output.
** of wiki/embedded doc processing, but not (e.g.) when fetching
** an image for /pikchrpage.
**
** - PIKCHR_PROCESS_SRC: if set, a new PRE.pikchr-src element is
** injected adjacent to the SVG element which contains the
** HTML-escaped content of the input script.
** - PIKCHR_PROCESS_SRC: if set, a new TEXTAREA.pikchr-src element is injected
** adjacet to the SVG element which contains the HTML-escaped content of
** the input script.
**
** - PIKCHR_PROCESS_SRC_HIDDEN: exactly like PIKCHR_PROCESS_SRC but
** the .pikchr-src tag also gets the CSS class 'hidden' (which, in
** fossil's default CSS, will hide that element). This is almost
** fossil's default CSS, will hide that element).
** always what client code will want to do if it includes the source
** at all.
**
** - PIKCHR_PROCESS_ERR_PRE: if set and pikchr() fails, the resulting
** error report is wrapped in a PRE element, else it is retained
** as-is (intended only for console output).
** as-is (intended for console output).
*/
int pikchr_process(const char * zIn, int pikFlags, int thFlags,
                   Blob * pOut){
                    Blob * pOut){
  Blob bIn = empty_blob;
  int isErr = 0;

  if(!(PIKCHR_PROCESS_DIV & pikFlags)
     /* If any DIV_xxx flags are set, set DIV */
     && (PIKCHR_PROCESS_DIV_INDENT
         | PIKCHR_PROCESS_DIV_CENTER
         | PIKCHR_PROCESS_DIV_FLOAT_RIGHT
         | PIKCHR_PROCESS_DIV_FLOAT_LEFT
         | PIKCHR_PROCESS_DIV_SOURCE
         | PIKCHR_PROCESS_DIV_TOGGLE
         ) & pikFlags){
    pikFlags |= PIKCHR_PROCESS_DIV;
  }
  if(!(PIKCHR_PROCESS_TH1 & pikFlags)
     /* If any TH1_xxx flags are set, set TH1 */
     && (PIKCHR_PROCESS_TH1_NOSVG & pikFlags || thFlags!=0)){
    pikFlags |= PIKCHR_PROCESS_TH1;
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183

184
185
186
187
188
189
190
191

192
193


194
195
196
197
198
199
200
130
131
132
133
134
135
136


137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153







154



155
156
157
158
159
160


161
162
163
164
165
166
167
168
169







-
-

















-
-
-
-
-
-
-
+
-
-
-





+
-
-
+
+







    }else{
      int w = 0, h = 0;
      const char * zContent = blob_str(&bIn);
      char *zOut;

      zOut = pikchr(zContent, "pikchr", 0, &w, &h);
      if( w>0 && h>0 ){
        const char * zClassToggle = "";
        const char * zClassSource = "";
        const char *zNonce = (PIKCHR_PROCESS_NONCE & pikFlags)
          ? safe_html_nonce(1) : 0;
        if(zNonce){
          blob_append(pOut, zNonce, -1);
        }
        if(PIKCHR_PROCESS_DIV & pikFlags){
          Blob css = empty_blob;
          blob_appendf(&css, "max-width:%dpx;", w);
          if(PIKCHR_PROCESS_DIV_CENTER & pikFlags){
            blob_append(&css, "display:block;margin-auto;", -1);
          }else if(PIKCHR_PROCESS_DIV_INDENT & pikFlags){
            blob_append(&css, "margin-left:4em", -1);
          }else if(PIKCHR_PROCESS_DIV_FLOAT_LEFT & pikFlags){
            blob_append(&css, "float:left;padding=4em;", -1);
          }else if(PIKCHR_PROCESS_DIV_FLOAT_RIGHT & pikFlags){
            blob_append(&css, "float:right;padding=4em;", -1);
          }
          if(PIKCHR_PROCESS_DIV_TOGGLE & pikFlags){
            zClassToggle = " toggle";
          }
          if(PIKCHR_PROCESS_DIV_SOURCE & pikFlags){
            zClassSource = " source";
          }
          blob_appendf(pOut,"<div class=\"pikchr-svg%s%s\" "
          blob_appendf(pOut,"<div class=\"pikchr\" style=\"%b\">\n", &css);
                       "style=\"%b\">\n",
                       zClassToggle/*safe-for-%s*/,
                       zClassSource/*safe-for-%s*/, &css);
          blob_reset(&css);
        }
        blob_append(pOut, zOut, -1);
        if((PIKCHR_PROCESS_SRC & pikFlags)
           || (PIKCHR_PROCESS_SRC_HIDDEN & pikFlags)){
          blob_appendf(pOut, "<textarea rows='10' readonly "
          blob_appendf(pOut, "<pre class='pikchr-src%s'>"
                       "%h</pre>\n",
                       "class='pikchr-src%s'>"
                       "%h</textarea>\n",
                       (PIKCHR_PROCESS_SRC_HIDDEN & pikFlags)
                       ? " hidden" : "",
                       blob_str(&bIn));
        }
        if(PIKCHR_PROCESS_DIV & pikFlags){
          blob_append(pOut, "</div>\n", 7);
        }
386
387
388
389
390
391
392
393

394
395
396
397
398
399
400
355
356
357
358
359
360
361

362
363
364
365
366
367
368
369







-
+







**
**    -div-center Like -div but centers the div.
**
**    -div-left   Like -div but floats the div left.
**
**    -div-right  Like -div but floats the div right.
**
**    -src       Stores the input pikchr's source code in the output as
**    -svg-src   Stores the input pikchr's source code in the output as
**               a separate element adjacent to the SVG one. The
**               source element initially has the "hidden" CSS class.
**
**    -th        Process the input using TH1 before passing it to pikchr.
**
**    -th-novar  Disable $var and $<var> TH1 processing. Use this if the
**               pikchr script uses '$' for its own purposes and that
428
429
430
431
432
433
434
435

436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
397
398
399
400
401
402
403

404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421






422
423
424
425
426
427
428







-
+

















-
-
-
-
-
-







  Blob bIn = empty_blob;
  Blob bOut = empty_blob;
  const char * zInfile = "-";
  const char * zOutfile = "-";
  const int fTh1 = find_option("th",0,0)!=0;
  const int fNosvg = find_option("th-nosvg",0,0)!=0;
  int isErr = 0;
  int pikFlags = find_option("src",0,0)!=0
  int pikFlags = find_option("svg-src",0,0)!=0
    ? PIKCHR_PROCESS_SRC_HIDDEN : 0;
  u32 fThFlags = TH_INIT_NO_ENCODE
    | (find_option("th-novar",0,0)!=0 ? TH_R2B_NO_VARS : 0);

  Th_InitTraceLog()/*processes -th-trace flag*/;

  if(find_option("div",0,0)!=0){
    pikFlags |= PIKCHR_PROCESS_DIV;
  }else if(find_option("div-indent",0,0)!=0){
    pikFlags |= PIKCHR_PROCESS_DIV_INDENT;
  }else if(find_option("div-center",0,0)!=0){
    pikFlags |= PIKCHR_PROCESS_DIV_CENTER;
  }else if(find_option("div-float-left",0,0)!=0){
    pikFlags |= PIKCHR_PROCESS_DIV_FLOAT_LEFT;
  }else if(find_option("div-float-right",0,0)!=0){
    pikFlags |= PIKCHR_PROCESS_DIV_FLOAT_RIGHT;
  }
  if(find_option("div-toggle",0,0)!=0){
    pikFlags |= PIKCHR_PROCESS_DIV_TOGGLE;
  }
  if(find_option("div-source",0,0)!=0){
    pikFlags |= PIKCHR_PROCESS_DIV_SOURCE;
  }

  verify_all_options();
  if(g.argc>4){
    usage("?INFILE? ?OUTFILE?");
  }
  if(g.argc>2){
    zInfile = g.argv[2];