Contains the CodeBrowser code without the test cases.
References:
ref | ==> | ref |
Functions:
∇ {hasMainMenu}←AddMainMenu(parms collect);html;refs
[1] refs←{1<⍴,⍵:↑⍵ ⋄ ⍉⍪⊃⍵}⊃,/parms GetSubNamespaces¨parms.refs
[2] refs←({(⍵⍳⍵)=⍳≢⍵}refs[;2])⌿refs ⍝ Get rid of (additional) refs
[3] hasMainMenu←0
[4] html←1 AddMainMenu_ refs collect
[5] :If 1≥+/∨/¨'<li>'∘⍷¨html
[6] html←''
[7] :EndIf
[8] :If 0≠≢html
[9] html←('<nav id="main">' '<p>Namespace structure:</p>'),html,(⊂'</nav>')
[10] WriteHTML html
[11] hasMainMenu←1
[12] :EndIf
[13] ⍝Done
∇
∇ html←level AddMainMenu_(refs collect);i;buff;noOf
[1] html←⊂'<ol>'
[2] i←1
[3] :Repeat
[4] :If ~0∊⍴refs
[5] html,←{'<li>'('<a href="#',(collect.remove RemoveLevels⍕⍵),'">',((⊃{⍺,'.',⍵}/⍕¨level),'. ',⍕⍵),'</a>')}refs[i;2]
[6] :If 0<noOf←{+/∧\1↓⍵[;1]>⊃⍵}(i-1)↓refs
[7] html,←(level,1)AddMainMenu_(noOf↑i↓refs)collect
[8] i←i+noOf+1
[9] :Else
[10] i+←1
[11] :EndIf
[12] :EndIf
[13] (¯1↑level)←1+¯1↑level
[14] :Until i>1⊃⍴refs
[15] html,←⊂'</ol>'
[16] ⍝Done
∇
∇ html←AddParameters parms;mat;toc;header;row
[1] html←''
[2] :If parms.showParms
[3] mat←parms.∆List
[4] toc←mat[;1]~¨' '
[5] mat⌿⍨←~toc∊⊂'refs' ⍝ Strictly speaking these are not parameters
[6] row←toc⍳⊂'info'
[7] mat[row;2]←⊂Max 2⊃mat[row;]
[8] row←toc⍳⊂'caption'
[9] mat[row;2]←⊂Max 2⊃mat[row;]
[10] row←toc⍳⊂'footer'
[11] mat[row;2]←⊂Max 2⊃mat[row;]
[12] html←({{'<tr>',⍵,'</tr>'}⊃,/{'<td>',(⍕⍵),'</td>'}¨⍵}¨↓mat)
[13] header←⊂'<tr><th>Name</th><th>Setting</th></tr>'
[14] html←('<div id="parameters">' '<hr>' '<h2 class="center">Parameters</h2>' '<table id="parms">'),header,(⊂'<tbody>'),html,'</tbody>' '</table>' '</div>'
[15] :EndIf
[16] ⍝Done
∇
∇ {r}←level CollectAplObjects(parms collect);buff;ref;For;level
[1] r←⍬
[2] :For ref :In parms.refs
[3] level CollectAplObjects_ ref parms collect
[4] :EndFor
[5] ⍝Done
∇
∇ {r}←level CollectAplObjects_(ref parms collect);EndIf;lists;refs
[1] r←⍬
[2] lists←level CreateToc ref parms collect
[3] level CollectAplObjects__ lists ref parms collect
[4] :If 0≠≢lists.containers
[5] :AndIf parms.recursive
[6] refs←ref.⍎¨lists.containers
[7] :AndIf 0<≢refs←(0<≢¨⍕¨refs)/refs
[8] ((⊂level),¨⍳⍴lists.containers){⍺ CollectAplObjects_ ⍵ parms collect}¨refs
[9] :EndIf
[10] ⍝Done
∇
∇ {r}←level CollectAplObjects__(lists ref parms collect);i;html;names;k;name;captions
[1] r←⍬
[2] ReportRefs ref
[3] html←''
[4] captions←'Functions:' 'Operators:' 'Scripts:' 'Variables:'
[5] :For i :In ⍳≢lists.(fns opr scripts variables)
[6] :If 0≠≢names←i⊃lists.(fns opr scripts variables)
[7] html,←⊂'<p class="type">',(i⊃captions),'</p>'
[8] :For k :In ⍳⍴names
[9] name←k⊃names
[10] html,←level CollectFnsAndOprAndScriptsAndVars ref name parms k collect
[11] :EndFor
[12] :EndIf
[13] :EndFor
[14] html,←⊂'<div id="',(GetBookmark_ID parms),'"></div>'
[15] IncrementBookMarkCounter parms
[16] r←WriteHTML html
∇
∇ r←level CollectFnsAndOpr(ref name parms collect i);body;no;caption;target
[1] r←''
[2] :If ¯3≠≡body←(⎕UCS 13)A.Split ref.⎕VR name
[3] body←ExchangeHtmlSpecialChars body
[4] r,←⊂'<div class="bookmarktarget" ',(collect MakeID(⍕ref),'.',name),'>'
[5] r,←⊂'<div id="',(GetBookmark_ID parms),'" class="code_block">'
[6] caption←MakeBreadCrumb collect.remove RemoveLevels⍕ref
[7] r,←⊂'<button title="Hide" class="accordion expanded">Hide</button>'
[8] target←'bookmark_',¯5↑'00000',⍕parms.bookmarkCounter-1
[9] r,←⊂'<button title="Brings previous object to the top" onClick="jump2bookmark(''',target,''')">Previous</button>'
[10] target←'bookmark_',¯5↑'00000',⍕parms.bookmarkCounter+1
[11] r,←⊂'<button title="Brings next object to the top" onClick="jump2bookmark(''',target,''')">Next</button>'
[12] r,←⊂'<p class="caption">',(⍕i),'. ',caption,'.',name,' (',(⍕¯1+≢body),' lines)</p>'
[13] r,←⊂'<div class="accordion-content">'
[14] (1⊃body)←'<pre><code>',1⊃body
[15] r,←body,⊂'</code></pre>'
[16] r,←'</div>' '</div>' '</div>'
[17] IncrementBookMarkCounter parms
[18] :EndIf
[19] ⍝Done
∇
∇ r←level CollectFnsAndOprAndScriptsAndVars(ref name parms i collect);body;no;caption
[1] r←''
[2] :Select ⊃ref.⎕NC name
[3] :Case 9
[4] r←level CollectScript ref name parms collect i
[5] :Case 2
[6] r←level CollectVariable ref name parms collect i
[7] :Else
[8] r←level CollectFnsAndOpr ref name parms collect i
[9] :EndSelect
[10] ⍝DoneColl
∇
∇ r←level CollectScript(ref name parms collect i);body;no;caption;target
[1] r←''
[2] :If 2=≡body←ref.⎕SRC ref.⍎name
[3] body←(,¨'<>&')⎕R'\<' '\>' '\&'⍠('Greedy' 0)⊣body
[4] no←⍕2+level
[5] r,←⊂'<div class="bookmarktarget" ',(collect MakeID(⍕ref),'.',name),'>'
[6] r,←⊂'<div id="',(GetBookmark_ID parms),'" class="code_block">'
[7] caption←MakeBreadCrumb collect.remove RemoveLevels⍕ref
[8] r,←⊂'<button title="Hide" class="accordion expanded">Hide</button>'
[9] target←'bookmark_',¯5↑'00000',⍕parms.bookmarkCounter-1
[10] r,←⊂'<button title="Brings previous object to the top" onClick="jump2bookmark(''',target,''')">Previous</button>'
[11] target←'bookmark_',¯5↑'00000',⍕parms.bookmarkCounter+1
[12] r,←⊂'<button title="Brings next object to the top" onClick="jump2bookmark(''',target,''')">Next</button>'
[13] r,←⊂'<p class="caption">',(⍕i),'. ',caption,'.',name,' (',(⍕≢body),' lines)</p>'
[14] r,←⊂'<div class="accordion-content">'
[15] body←({(3+⍴,⍕⍵){⍺↑'[',(⍕⍵),']'}¨¯1+⍳⍵}⍴body),¨body
[16] (1⊃body)←'<pre><code>',1⊃body
[17] r,←body,⊂'</code></pre>'
[18] r,←'</div>' '</div>' '</div>'
[19] IncrementBookMarkCounter parms
[20] :EndIf
[21] ⍝Done
∇
∇ r←level CollectVariable(ref name parms collect i);no;info;caption
[1] r←''
[2] no←⍕2+level
[3] r,←⊂'<div ',(collect MakeID(⍕ref),'.',name),'>'
[4] caption←MakeBreadCrumb collect.remove RemoveLevels⍕ref
[5] r,←⊂'<p class="caption">',(⍕i),'. ',caption,'.',name,'</p>'
[6] r,←⊂'</div>'
[7] :Trap 6
[8] info←'Rank: ',(⍕⍴⍴ref.⍎name),'; Shape: ',({0∊⍴⍵:'⍬' ⋄ ⍕⍵}⍴ref.⍎name),'; Depth: ',(⍕≡ref.⍎name),'; Data Representation: ',⍕⎕DR ref.⍎name
[9] r,←⊂'<pre><code>',info,'</code></pre>'
[10] :Else ⍝ This may well fail because the variable is now hidden (CodeBrowser on CodeBrowser)
[11] r←''
[12] :EndTrap
[13] ⍝Done
∇
∇ CompressCSS←{
[1] ⍝ Takes CSS and compresses it to a single line.
[2] ⍝ Along the way it...
[3] ⍝ * removes all comments
[4] ⍝ * removes any spaces around `;:{}`
[5] ⍝ * replaces <TAB> chars by spaces
[6] ⍝ * removes multiple spaces
[7] ⍝ Note that this method can have desastrous results when performed on non-valid CSS!\\
[8] ⍝ Throws an error in case something is not right with the CSS.
[9] css←⍵
[10] css←{(1↓⊃,/(⎕UCS 13),¨⍵)}⍣(1≠≡css)⊣css
[11] start←'/*'⍷css
[12] end←'*/'⍷css
[13] mask←~{⍵∨≠\⍵}css='"'
[14] 0=≡/+/¨mask∘/¨start end:'Cannot compress CSS: number of occurrences of /* and */ are different'⎕SIGNAL 11
[15] 0≠≢(∪⊃-/+\¨start end)~0 1:'Cannot compress CSS: Invalid nested comments'⎕SIGNAL 11
[16] start∧←mask
[17] end∧←mask
[18] bool←~{⍵∨≠\⍵}start∨end
[19] bool[1+⍸end]←0
[20] css←bool/css
[21] css←A.DMB css~⎕TC
[22] ((css=⎕UCS 9)/css)←' '
[23] mask←~{⍵∨≠\⍵}css='"'
[24] b1←mask\mask/⊃∨/' :' ' ;' ' {' ' }'⍷¨⊂css
[25] b2←mask\mask/⊃∨/': ' '; ' '{ ' '} '⍷¨⊂css
[26] b←~b1∨0,¯1↓b2
[27] '<style>',(b/css),'</style>'
[28] }
∇
∇ filename←CreateHtml parms;collect;WriteHTML;info
[1] parms.bookmarkCounter←1
[2] WriteHTML←parms.filename∘{0=≢⍵:r←⍬ ⋄ (⊂⍵)⎕NPUT ⍺ 2}
[3] WriteHeader parms
[4] WriteHTML'<h1>',(ExchangeHtmlSpecialChars parms.caption),'</h1>'
[5] :If 0≠≢parms.info
[6] info←ExchangeHtmlSpecialChars⍣(~parms.infoIsHTML)⊣parms.info
[7] :If 0 1∊⍨≡info
[8] :AndIf ~(⎕UCS 13)∊info
[9] WriteHTML(⊂'<div id="info">'),({'<p>',⍵,'</p>'}¨⊆info),⊂'</div>'
[10] :Else
[11] info←(⎕UCS 13)A.Split⍣((⎕UCS 13)∊info)⊣info
[12] WriteHTML(⊂'<div id="info">'),({({'<p>',⍵,'</p>'}⍵)}¨info),⊂'</div>'
[13] :EndIf
[14] :EndIf
[15] collect←⎕NS''
[16] collect.namespaces←⍬
[17] collect.remove←⌊/{+/'.'=⍵}¨namespaces
[18] :If parms.recursive
[19] collect.hasMainMenu←AddMainMenu parms collect
[20] :Else
[21] collect.hasMainMenu←0
[22] :EndIf
[23] WriteHTML'<div id="',(GetBookmark_ID parms),'"></div>'
[24] parms.bookmarkCounter+←1
[25] 1 CollectAplObjects parms collect
[26] WriteHTML AddFooter parms
[27] WriteHTML AddParameters parms
[28] WriteHTML InjectJavaScriptLate ⍬
[29] WriteHTML('</body>' '</html>')
[30] filename←parms.filename
[31] ⍝Done
∇
∇ {r}←CreateOrReplaceFile parms;errCounter;tno
[1] r←⍬
[2] :If ⎕NEXISTS parms.filename
[3] :Trap 19
[4] ⎕NDELETE parms.filename
[5] :Case 19
[6] ⎕NUNTIE((A.DTB↓⎕NNAMES)⍳⊂parms.filename)⊃⎕NNUMS
[7] ⎕NDELETE parms.filename
[8] :EndTrap
[9] :EndIf
[10] errCounter←0
[11] :Repeat
[12] :Trap 22
[13] ⍝ This causes sometimes an error that goes away
[14] ⍝ after a short delay. DropBox?!
[15] tno←parms.filename ⎕NCREATE 0
[16] :Else
[17] tno←0
[18] ⎕DL 0.2
[19] errCounter←errCounter+1
[20] :EndTrap
[21] :Until (tno<0)∨5<errCounter ⍝ Try max 5 times.
[22] 'Unable to create the HTML file'⎕SIGNAL 22/⍨tno=0
[23] ⎕NUNTIE tno
[24] ⍝Done
∇
∇ r←CreateParms path
[1] ⍝ If `path` is not empty it is assumed that this points to the CodeBrowser home directory of a user command folder.
[2] ⍝ | Name | Description | Options/flag |
[3] ⍝ |:-----------------|:------------|:-------------|
[4] ⍝ | `backgroundColorPrint` | Set this to 0 if you don't want background color when printing. | --- |
[5] ⍝ | `caption` | Defaults to the list of namespaces specified by the user. | `-caption |
[6] ⍝ | `cssfilename` | Location of the CSS file. | --- |
[7] ⍝ | `filename` | If not set this defaults to a temp file name. | `-filename` |
[8] ⍝ | `footer` | No default. Text string added to the bottom of the HTML file. | `-footer` |
[9] ⍝ | `ignore` | Use this to ignore, say, a help system etc.<<br>>Text vector with comma-separated fully qualified namespace names. | `-ignore` |
[10] ⍝ | `ignoreEmpty` | Boolean that defaults to 1 menaing that empty containers are ignored. | --- |
[11] ⍝ | `ignoreTatinPkgs`| Boolean that decided whether #._tatin (or ⎕SE._tatin) should be ignored |
[12] ⍝ | `info` | If not empty this is shown under the caption with ID="info". | `-info` |
[13] ⍝ | `infoIsHTML` | Boolean that defaults to 0, meaning that any `<` becomes `<`.<<br>>Typically used for HTML that was generated by the `MarkAPL` class. |
[14] ⍝ | `lang` | Specifies the language; defaults to "en". | `-lang` |
[15] ⍝ | `lines` | Number of lines to be displayed. Defaults to no restriction |
[16] ⍝ | `linkcssfile` | Boolean that defaults to 0 menaing that contents of `cssfile` is embedded. | --- |
[17] ⍝ | `namespaces` | Will be becomes the namespaces to be scanned. Is read-only.| --- |
[18] ⍝ | `printFontSize` | Base font size in pt. | `-pfs` |
[19] ⍝ | `processFunctions` | Boolean that defaults to 1. | `-obj=f` |
[20] ⍝ | `processGuiInstances | Boolean that defaults to 0. | `-obj=g` |
[21] ⍝ | `processOperators` | Boolean that defaults to 1. | `-obj=o` |
[22] ⍝ | `processScripts` | Boolean that defaults to 1. Regards classes, interfaces and scripted namespaces. | `-obj=s` |
[23] ⍝ | `processVars` | Boolean that defaults to 1. | `-obj=v` |
[24] ⍝ | `recursive` | Boolean that defaults to 1, meaning that sub-namespaces will be scanned as well. | `-r=1` |
[25] ⍝ | `showParms` | Boolean that defaults to 0. Specify 1 to append a table with parameters. | `-p` |
[26] ⍝ | `twoSidedPrint` | Boolean that defaults to 0. If 1 the left margin is always larger than the right one.| `-twosided` |
[27] ⍝ | `version` | Text vector with version number and version data. Is read-only| --- |
[28] ⍝ | `viewInBrowser` | Boolean that defaults to 0. Specify 1 for displaying the HTML in your default browser. | `-view` |
[29] r←⎕NS''
[30] r.backgroundColorPrint←1
[31] r.caption←¯1
[32] r.cssfilename←GetCssFilename path
[33] r.filename←''
[34] r.footer←''
[35] r.ignore←''
[36] r.ignoreEmpty←1
[37] r.ignoreTatinPkgs←1
[38] r.info←''
[39] r.infoIsHTML←0
[40] r.lang←'en'
[41] r.lines←¯1
[42] r.linkcssfile←0
[43] r.namespaces←''
[44] r.printFontSize←8
[45] r.processFunctions←1
[46] r.processGuiInstances←0
[47] r.processOperators←1
[48] r.processScripts←1
[49] r.processVars←1
[50] r.recursive←1
[51] r.showParms←0
[52] r.twoSidedPrint←0
[53] r.version←{(1⊃⍵),' ',(2⊃⍵),' from ',(3⊃⍵)}Version
[54] r.viewInBrowser←0
[55] r.⎕FX'r←∆List' 'r←{⍵,[1.5]⍎¨⍵}↓⎕nl 2' 'r←(~(r[;1]~¨'' '')∊''refs'' ''bookmarkCounter'')⌿r'
[56] ⍝Done
∇
∇ lists←level CreateToc(ref parms collect);lists;width;caption;flag;html;buff
[1] lists←⎕NS'' ⍝ All lists: functions, operators, non-scripted namespaces (containers)
[2] lists.(fns opr scripts variables containers)←⊂''
[3] :If collect.hasMainMenu
[4] caption←(FormatLevel level),MakeBreadCrumb collect.remove RemoveLevels⍕ref
[5] html←⊂caption{'<h3 id="',(collect.remove RemoveLevels ⍵),'">',⍺,'</h3>'}⍕ref
[6] :Else
[7] html←''
[8] :EndIf
[9] flag←1
[10] :If 0<≢↓ref.⎕NL 2 3 4 9
[11] width←⍕6⌈⌈0.8×⌈/≢¨↓ref.⎕NL 9,GetNameClasses parms
[12] (buff flag)←HandleContainers ref width flag lists parms collect
[13] html,←buff
[14] :If parms.processFunctions
[15] :AndIf 0≠≢lists.fns←' '~¨⍨↓ref.⎕NL 3
[16] :AndIf 0≠≢lists.fns←(3.3≠⊃∘ref.⎕NC¨⊂¨lists.fns)/lists.fns
[17] (html flag)←html OpenNavSub flag
[18] html,←CreateToc_ ref parms lists.fns'Function'collect width
[19] :EndIf
[20] :If parms.processOperators
[21] :AndIf 0≠≢lists.opr←' '~¨⍨↓ref.⎕NL 4
[22] :AndIf 0≠≢lists.opr←(4.3≠⊃∘ref.⎕NC¨⊂¨lists.opr)/lists.opr
[23] (html flag)←html OpenNavSub flag
[24] html,←CreateToc_ ref parms lists.opr'Operator'collect width
[25] :EndIf
[26] :If parms.processScripts
[27] :AndIf 0≠≢lists.scripts←ListScriptsIn ref
[28] :AndIf 0≠≢lists.scripts←(~(ref.{0∊⍴⊃,/⍵:⍵ ⋄ ⍎¨⍵}lists.scripts)∊parms.ignore)/lists.scripts
[29] (html flag)←html OpenNavSub flag
[30] html,←CreateToc_ ref parms lists.scripts'Script'collect width
[31] :EndIf
[32] :If parms.processVars
[33] :AndIf 0≠≢lists.variables←' '~¨⍨↓ref.⎕NL 2
[34] (html flag)←html OpenNavSub flag
[35] html,←CreateToc_ ref parms lists.variables'Variable'collect width
[36] :EndIf
[37] html,←(~flag)/⊂'</nav>'
[38] :EndIf
[39] ⍝ Collapsible: html,←⊂'</div>'
[40] {}WriteHTML html
[41] ⍝Done
∇
∇ html←CreateToc_(ref parms list title collect width)
[1] html←''
[2] html,←⊂'<div class="toclist">'
[3] html,←⊂'<p><b>',title,(((1<⍴list)/'s'),': ',⍕⊃⍴list),'</b></p>'
[4] html,←⊂'<div>'
[5] html,←(ref{'<div style="width:',width,'em;"><a ',(collect MakeBookmarkRef(⍕⍺),'.',{⍵↓⍨⍵⍳' '}⍵),'>',⍵}¨{(⍕¨⍳⍴⍵),¨'. '∘,¨⍵}list),¨⊂'</a></div>'
[6] html,←'</div>' '</div>'
[7] ⍝Done
∇
∇ ExchangeHtmlSpecialChars←{
[1] 11::(,¨'<>&')⎕R'\<' '\>' '\&'⍠('Greedy' 0)⊣↓⎕FMT ⍵
[2] (,¨'<>&')⎕R'\<' '\>' '\&'⍠('Greedy' 0)⊣⍵
[3] }
∇
∇ FormatDate←{
[1] date←⍵
[2] ' '=1↑0⍴date:date
[3] 10↑A.FormatDateTime date
[4] }
∇
∇ FormatLevel←{
[1] (⊃{⍺,'.',⍵}/⍕¨⍵),'. '
[2] }
∇
∇ r←GetBookmark_ID parms
[1] ⍝ Returns an ID that can be used as a bookmark ID.
[2] r←'bookmark_',¯5↑'00000',⍕parms.bookmarkCounter
[3] ⍝Done
∇
∇ css←GetCSS parms;against;bool;row;replaceBy
[1] css←⊃F.NGET(1⊃,parms.cssfilename)1
[2] against←'font-size: ',(⍕parms.printFontSize),'pt;'
[3] css←'font-size: *8pt;'⎕R against⊣css
[4] css←{'-webkit-print-color-adjust: *exact;'⎕R''⊣⍵}⍣(⊃~parms.backgroundColorPrint)⊣css
[5] :If 0≠parms.twoSidedPrint
[6] against←'@page :left {margin: 20mm 20mm 20mm 10mm;}'
[7] css←'@page :left *{margin: *20mm *20mm *20mm *20mm;}'⎕R against⊣css
[8] :EndIf
[9] :If 0<+/bool←∨/¨'.accordion-content'∘⍷¨css
[10] row←⍸bool
[11] replaceBy←'max-height: ',(⍕parms.lines),'em;'
[12] css[row]←replaceBy∘{replaceBy←⍺ ⋄ 'max-height: {0,}([1-9][0-9]){1,2}em;'⎕R replaceBy⍠('Greedy' 0)⊣⍵}¨css[row]
[13] :EndIf
[14] ⍝Done
∇
∇ GetCodeMirrorLib←{
[1] ⍝ NOT SUPPORTED (yet)
[2] parms←⍵
[3] 0=parms.codeMirrorLib:''
[4] r←''
[5] r,←⊂'<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.33.0/codemirror.js"></script>'
[6] r,←⊂'<link href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.33.0/codemirror.css" rel="stylesheet">'
[7] r,←⊂'<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.33.0/mode/apl/apl.js"></script>'
[8] r,←⊂'<style>'
[9] r,←⊂'.CodeMirror{height:auto; border: 1px solid #eee;}'
[10] r,←⊂'</style>'
[11] r,←⊂' <script>'
[12] r,←⊂'(function(){'
[13] r,←⊂'nodes=document.getElementsByTagName(''code'')'
[14] r,←⊂'Array.from(nodes).forEach(node=>{'
[15] r,←⊂' if(node.parentNode.tagName===''PRE''){'
[16] r,←⊂' let pre=node.parentNode;'
[17] r,←⊂' let ta=document.createElement("TEXTAREA");'
[18] r,←⊂' ta.value=node.innerText;'
[19] r,←⊂' pre.parentNode.replaceChild(ta,pre);'
[20] r,←⊂' CodeMirror.fromTextArea(ta);'
[21] r,←⊂' }'
[22] r,←⊂'})'
[23] r,←⊂'})();'
[24] r,←⊂'</script>'
[25] r
[26] }
∇
∇ r←GetCssFilename path;F
[1] F←##.FilesAndDirs
[2] :If 0=≢path
[3] :If 9=##.⎕NC'CiderConfig'
[4] r←##.CiderConfig.HOME,'/Files/codebrowser_styles.css'
[5] :ElseIf 9=##.⎕NC'TatinVars'
[6] r←##.TatinVars.HOME,'/Files/codebrowser_styles.css'
[7] :Else
[8] r←HOME,'/codebrowser_styles.css'
[9] :EndIf
[10] :Else
[11] ((path∊'/\')/path)←F.CurrentSep
[12] r←path,F.CurrentSep,'codebrowser_styles.css'
[13] :EndIf
∇
∇ r←GetNameClasses parms
[1] r←parms.(processVars processFunctions processOperators processScripts)/2 3 4 9
[2] ⍝Done
∇
∇ r←{y}GetSubNamespaces ref;list;level;bool
[1] level←0
[2] :If 0=⎕NC'y'
[3] ⎕SHADOW'parms'
[4] parms←CreateParms''
[5] :ElseIf 326=⎕DR y
[6] ⎕SHADOW'parms'
[7] parms←y
[8] :Else
[9] level←y
[10] :EndIf
[11] r←⊂level ref
[12] :If 0≠≢list←' '~¨⍨↓ref.⎕NL 9.1 9.2 ⍝ All namespaces
[13] :AndIf 0≠≢list←(ref.{((⍕⎕THIS),'.',⍵)≡⍕⍎⍵}¨list)/list ⍝ We are not interested in refs pointing elsewhere
[14] list←ref.⍎¨list ⍝ Make them refs
[15] list~←ref,{0∊⍴⊃,/⍵:⍵ ⋄ ⍎¨⍵}MassageNameLists parms.ignore ⍝ Remove any self references and those to be ignored
[16] :AndIf 0≠≢list
[17] :If parms.ignoreTatinPkgs
[18] :AndIf 0<≢parms.namespaces
[19] :AndIf ∧/parms.namespaces≢¨⊂'_tatin'
[20] list←(~(⍕¨list)∊'#._tatin' '⎕SE._tatin')/list ⍝ Remove Tatin packages
[21] :EndIf
[22] :AndIf 0≠≢list
[23] :AndIf 0≠≢list←(~'['∊¨⍕¨list)/list ⍝ Remove unnamed namespaces and instances
[24] :AndIf 0≠≢list←({16::1 ⋄ 0⊣⎕SRC ⍵}¨list)/list ⍝ Remove scripted ones
[25] :If 0∊bool←'Namespace'∘≡¨ref.{⍵ ⎕WG'Type'}¨list
[26] :If parms.processGuiInstances
[27] bool∨←(~bool)\ref.{⍵ ⎕WG'KeepOnClose'}¨(~bool)/list
[28] :EndIf
[29] list←bool/list
[30] :EndIf
[31] :AndIf 0≠≢list
[32] :If parms.ignoreEmpty
[33] list←({0≠≢⍵.⎕NL⍳16}¨list)/list
[34] :EndIf
[35] :AndIf 0≠≢list
[36] r←((⊂level,ref),⊃,/(1+level)GetSubNamespaces¨list)~⊂''
[37] :EndIf
[38] ⍝Done
∇
∇ (html flag)←HandleContainers(ref width flag lists parms collect);html;these;recursiveMsg
[1] html←''
[2] :If 0<≢lists.containers←' '~¨⍨↓ref.⎕NL 9
[3] :AndIf 0<≢lists.containers←({16::1 ⋄ 0⊣⎕SRC ⍵}¨ref.⍎¨lists.containers)/lists.containers
[4] :AndIf 0<≢lists.containers←(~(ref.⍎¨lists.containers)∊parms.ignore)/lists.containers
[5] :AndIf 0<≢lists.containers←(ref≠ref.⍎¨lists.containers)/lists.containers
[6] :AndIf 0<≢lists.containers←((~'['∊¨⍕¨ref.⍎¨lists.containers))/lists.containers
[7] :AndIf 0<≢lists.containers←(~(these←ref.⍎¨lists.containers)∊collect.namespaces)/lists.containers
[8] lists←RemoveGuiInstances lists ref parms
[9] :AndIf 0<≢lists.containers
[10] lists←RemoveEmptyContainers lists ref parms
[11] :AndIf 0<≢lists.containers
[12] lists←RemoveTatinPackages lists ref parms
[13] :AndIf 0<≢lists.containers
[14] collect.namespaces,←these
[15] flag←{0⊣html,←⊂'<nav class="sub">'}⍣1⊣1
[16] html,←⊂'<div class="toclist">'
[17] recursiveMsg←(~collect.hasMainMenu)/' (not scanned)'
[18] html,←⊂'<p><b>Sub namespace',((1<⍴lists.containers)/'s'),': ',(⍕⊃⍴lists.containers),'</b>',recursiveMsg,'</p>'
[19] html,←⊂'<div>'
[20] :If parms.recursive
[21] html,←⊃,/ref{(no name)←⍵ ⋄ ⊂'<div style="width:',width,'em;"><a ',(collect MakeBookmarkRef(⍕⍺),'.',name),'>',(⍕no),'. ',name,'</a></div>'}¨(⍳≢lists.containers),¨⊂¨lists.containers
[22] :Else
[23] html,←lists.containers{('<div style="width:',width,'em;">'),(⍕⍵),'. ',⍺,'</div>'}¨⍳≢lists.containers
[24] :EndIf
[25] html,←'</div>' '</div>'
[26] :EndIf
∇
∇ (msg en)←HandleParms(parms namespaces);DE
[1] ⍝ Returns either `'' 0` or an error message in `msg` and 11 in `en`.
[2] DE←11 ⍝ DOMAIN ERROR
[3] msg←en←⍬
[4] namespaces←'⎕se'⎕R'⎕SE'⊣namespaces
[5] :If ~∧/((,¨namespaces)∊,¨'#' '⎕SE')∨⊃¨9=⎕NC¨namespaces
[6] msg←'No namespace(s) specified'
[7] en←DE
[8] :Return
[9] :EndIf
[10] :Trap 0
[11] parms.refs←⍎¨namespaces
[12] :Else
[13] msg←'Something went wrong - check the namespace list'
[14] en←DE
[15] :Return
[16] :EndTrap
[17] :If 1≥|≡parms.cssfilename
[18] parms.cssfilename←A.DMB parms.cssfilename
[19] :If ∨/' ,'∊parms.cssfilename
[20] ((' '=parms.cssfilename)/parms.cssfilename)←','
[21] parms.cssfilename←','A.Split parms.cssfilename
[22] :EndIf
[23] parms.cssfilename←⊆parms.cssfilename
[24] :EndIf
[25] parms.filename{~0∊⍴⍺:⍺ ⋄ (¯4↓F.GetTempFilename''),'.html'}←⍬
[26] parms.caption{~(⊂⍺)∊¯1 '':⍺ ⋄ 1=⍴,⍵:⍕⍵ ⋄ ⊃,/{⍺,', ',⍵}/⍵}←namespaces
[27] CreateOrReplaceFile parms
[28] :Trap 0
[29] parms.ignore←{0∊⍴⊃,/⍵:⍵ ⋄ ⍎¨⍵}MassageNameLists parms.ignore
[30] :Else
[31] msg←'Something went wrong - check -ignore'
[32] en←DE
[33] :EndTrap
[34] :If '⋄'∊parms.info
[35] parms.info←'⋄'A.Split parms.info
[36] :EndIf
[37] :If ~(⊂parms.infoIsHTML)∊0 1
[38] msg←'"infoIsHTML" is not a Boolean'
[39] en←DE
[40] :EndIf
[41] :If ~(⊂parms.processGuiInstances)∊0 1
[42] msg←'"processGuiInstances" is not a Boolean'
[43] en←DE
[44] :EndIf
[45] :If ~(≡parms.info)∊0 1 2
[46] msg←'"info" is neither a text vector nor a vector of text vectors'
[47] en←DE
[48] :EndIf
[49] ⍝Done
∇
∇ {parms}←IncrementBookMarkCounter parms
[1] parms.bookmarkCounter+←1
[2] ⍝Done
∇
∇ {r}←Init dummy
[1] r←⍬
[2] A←##.APLTreeUtils2 ⋄ F←##.FilesAndDirs
[3] ⍝Done
∇
∇ {r}←InitializeUserCommand dummy
[1] ⍝ Propagate refs depending on circumstances
[2] r←⍬
[3] :If 0=⎕NC'A' ⍝ It's a Tatin package then
[4] :If '⎕'=⊃⊃⎕XSI
[5] A←⎕SE._CodeBrowser.APLSource.APLTreeUtils2
[6] F←⎕SE._CodeBrowser.APLSource.FilesAndDirs
[7] :Else
[8] A←##.APLTreeUtils2
[9] F←##.FilesAndDirs
[10] :EndIf
[11] :EndIf
[12] ⍝Done
∇
∇ html←InjectJavaScriptEarly dummy
[1] ⍝ This code needs to go into the <head>er of the HTML page.
[2] html←''
[3] html,←⊂'<script>'
[4] html,←⊂'function jump2bookmark(id){'
[5] html,←⊂' var obj = document.getElementById(id);'
[6] html,←⊂' obj.scrollIntoView({behavior: "smooth", block: "start"});'
[7] html,←⊂'}'
[8] html,←⊂'</script>'
∇
∇ html←InjectJavaScriptLate dummy
[1] ⍝ The transition does not work well on large objects (several hundred lines) at all.
[2] ⍝ May be one day CSS gets better options for this, or we implement a pure JavaScript solution?!
[3] ⍝ This code needs to go to the bottom of the HTML page!
[4] html←''
[5] html,←⊂'<script>'
[6] html,←⊂'var acc = document.getElementsByClassName("accordion");'
[7] html,←⊂'var i;'
[8] html,←⊂'for (i = 0; i < acc.length; i++) {'
[9] html,←⊂' acc[i].addEventListener("click", function() {'
[10] ⍝ html,←⊂'debugger;'
[11] html,←⊂' var content = lastSibling(this);'
[12] html,←⊂' if (this.classList.contains("expanded")) {'
[13] ⍝ We need to collapse it:
[14] html,←⊂' this.classList.add("collapsed");'
[15] html,←⊂' this.classList.remove("expanded");'
[16] ⍝html,←⊂' content.style.transition = "max-height 1s ease-in 0s";'
[17] html,←⊂' content.style.maxHeight = 0;'
[18] html,←⊂' this.innerHTML = "Show"' ⍝ "↕"'
[19] html,←⊂' this.setAttribute("title", "Show the code block");'
[20] html,←⊂' } else {'
[21] ⍝ We need to expanded it:
[22] ⍝html,←⊂' content.style.transition = "max-height 0.2s ease-out 0s";'
[23] html,←⊂' content.style.maxHeight = content.scrollHeight + "px";'
[24] html,←⊂' this.classList.add("expanded");'
[25] html,←⊂' this.classList.remove("collapsed");'
[26] html,←⊂' this.innerHTML = "Hide"'
[27] html,←⊂' this.setAttribute("title", "Hide the code block");'
[28] html,←⊂' } '
[29] html,←⊂' });'
[30] html,←⊂'}'
[31] html,←⊂'function lastSibling(node){'
[32] html,←⊂' var tempObj=node.parentNode.lastChild;'
[33] html,←⊂' while(tempObj.nodeType!=1 && tempObj.previousSibling!=null){'
[34] html,←⊂' tempObj=tempObj.previousSibling;'
[35] html,←⊂' }'
[36] html,←⊂' return (tempObj.nodeType==1)?tempObj:false;'
[37] html,←⊂'}'
[38] html,←⊂'</script>'
[39] ⍝Done
∇
∇ Install
[1] ⍝ Checks whether the packages required by CodeBrowser are already installed in the standard folder for
[2] ⍝ packages required by any Dyalog user command.
[3] ∘∘∘
∇
∇ ListScriptsIn←{
[1] l1←ref{0∊≢⍵:⍵ ⋄ ⍵/⍨⍺.{((⍕⎕THIS),'.',⍵)≡⍕⍎⍵}¨⍵}' '~¨⍨↓ref.⎕NL 9.4 9.5 ⍝ Class and interfaces
[2] l2←ref{0∊≢⍵:⍵ ⋄ ⍵/⍨⍺.{((⍕⎕THIS),'.',⍵)≡⍕⍎⍵}¨⍵}' '~¨⍨↓ref.⎕NL 9.1 ⍝ All namespaces
[3] l2←(ref.{0::0 ⋄ 1⊣⍴⎕SRC⍎⍵}¨l2)/l2
[4] 0∊⍴l2:l1
[5] {⍵[⍋↑⍵]}l1,l2
[6] }
∇
∇ r←collect MakeBookmarkRef path
[1] path←collect.remove RemoveLevels path
[2] r←'href="#',path,'"'
[3] ⍝Done
∇
∇ MakeBreadCrumb←{
[1] parts←'.'A.Split ⍵
[2] urls←{(⍳⍴⍵)↑¨⊂⍵}parts
[3] top←{'<a href="#',(⊃{⍺,'.',⍵}/⍵),'">'}¨urls
[4] r←top,¨parts
[5] ¯1↓⊃,/r,¨⊂'</a>.'
[6] }
∇
∇ r←collect MakeID ref
[1] ref←collect.remove RemoveLevels ref
[2] r←'id="',ref,'"'
[3] ⍝Done
∇
∇ MassageNameLists←{
[1] ⍝ (⊂'#.abc') ←→ MassageNameLists '#.abc'
[2] ⍝ ('#.abc' '#.x' '#.y') ←→ MassageNameLists '#.abc #.x , #.y'
[3] ⍝ ('#.abc' '#.x' '#.y') ←→ MassageNameLists #.abc #.x #.y'
[4] 1<|≡⍵:⍕¨⍵
[5] r←⍕,⍵
[6] ((','=r)/r)←' '
[7] ' 'A.Split A.DMB r
[8] }
∇
∇ Max←{
[1] ⍺←80
[2] ⍺>⍴⍵:⍵
[3] (⍺⍴⍵),'...'
[4] }
∇
∇ r←MoreHelp dummy
[1] {}⎕SE.UCMD']ADOC ⎕se._CodeBrowser'
[2] r←'Watch your default browser'
∇
∇ OpenInDefaultBrowser←{
[1] 6::0
[2] ⎕USING←'' 'System' 'System.Diagnostics,System.dll'
[3] proc←Process.Start,⊂⍵
[4] 1:proc←proc ⍝ was a NEW process started = True?
[5] }
∇
∇ r←Public
[1] r←'Run' 'CreateParms' 'Selfie' 'MoreHelp'
∇
∇ lists←RemoveEmptyContainers(lists ref parms);bool;list
[1] ⍝ Remove all empty containers unless parms.ignoreEmpty is 0.
[2] :If parms.ignoreEmpty
[3] list←ref.⍎¨lists.containers
[4] :If 0∊bool←{~0∊⍴⍵.⎕NL⍳16}¨list
[5] lists.containers←bool/lists.containers
[6] :EndIf
[7] :EndIf
∇
∇ lists←RemoveGuiInstances(lists ref parms);bool;list
[1] ⍝ Remove all GUI instances unless parms.processGuiInstances is 1.
[2] ⍝ Even then everything that does not carry `KeepOnClose←` is
[3] ⍝ removed
[4] list←ref.⍎¨lists.containers
[5] :If 0∊bool←'Namespace'∘≡¨list ⎕WG¨⊂'Type'
[6] :If parms.processGuiInstances
[7] bool∨←(~bool)\ref.{⍵ ⎕WG'KeepOnclose'}¨(~bool)/list
[8] :EndIf
[9] lists.containers←bool/lists.containers
[10] :EndIf
∇
∇ RemoveLevels←{
[1] noOf←⍺
[2] path←⍵
[3] (,'#')≡,path:path
[4] buff←+\'.'=⍵
[5] path←(+/∧\noOf>buff)↓path
[6] ('.'=1⍴path)↓path
[7] }
∇
∇ list←parent RemoveRefs list;bool
[1] ⍝ Remove scripts that are just references.
[2] :If 0<+/bool←9=parent.⎕NC list ⍝ Only those are potentially refs
[3] bool←bool∧bool\parent.{((⍕⎕THIS),'.',⍵)≡⍕⍎⍵}¨↓bool⌿list
[4] list←bool⌿list
[5] :EndIf
∇
∇ lists←RemoveTatinPackages(lists ref parms);bool
[1] ⍝ Remove all Tatin packages except when the user asks for them explicitly
[2] :If parms.ignoreTatinPkgs
[3] :AndIf 0=+/'⎕SE._tatin' '#._tatin'∊parms.namespaces
[4] lists.containers←(~lists.containers≡¨⊂'_tatin')/lists.containers
[5] :EndIf
∇
∇ {r}←ReportRefs ref;html;list
[1] r←⍬
[2] :If 0≠≢list←' '~¨⍨↓ref.⎕NL 9.1
[3] :AndIf 0≠≢list←(ref.{∊'['∊is←⍕⍎⍵:0 ⋄ ((⍕⎕THIS),'.',⍵)≢is}¨list)/list
[4] html←⊂'<p class="type">References:</p>'
[5] html,←⊂'<table class="refs">'
[6] html,←'<tr>'∘,¨(ref.{'<td>',⍵,'</td><td>==></td><td>',({0::⍵ ⋄ ⍕⍎}⍵),'</td>'}¨list),¨⊂'</tr>'
[7] html,←⊂'</table>'
[8] {}WriteHTML html
[9] :EndIf
[10] ⍝Done
∇
∇ filename←{parms}Run namespaces;refs
[1] ⍝ Collects the code and variables in the (non-scripted) namespaces listed in `namespaces` and
[2] ⍝ compiles an HTML page with the code in it.\\
[3] ⍝ `namespaces` must be a text vector with fully qualified namespace name(s). You can use either
[4] ⍝ a space or a comma as separator.\\
[5] ⍝ `parms` is optional. If provided it must be a parameter space, typically created with `CreateParms`.\\
[6] ⍝ Returns the name of the file the HTML is written to.\\
[7] ⍝ The HTML page contains the CSS and JavaScript needed and is therefore fully self-contained.
[8] ⍝ You should not attempt to view it in an outdated browser like IE9.
[9] ⎕IO←1 ⋄ ⎕ML←1
[10] Init ⍬
[11] namespaces←MassageNameLists namespaces
[12] parms←{0<⎕NC ⍵:⍎⍵ ⋄ CreateParms''}'parms'
[13] parms.namespaces←namespaces
[14] ⎕SIGNAL/HandleParms parms namespaces
[15] filename←CreateHtml parms
[16] :If parms.viewInBrowser
[17] {}A.GoToWebPage filename
[18] :EndIf
[19] parms.cssfilename←{0=≢⍵:⍵ ⋄ 0 1∊⍨≡⍵:⍵ ⋄ ⊃{⍺,', ',⍵}/⍵}parms.cssfilename
[20] ⍝Done
∇
∇ r←Selfie dummy;parms
[1] ⍝ Create an HTML document of CodeBrowser itself.
[2] parms←CreateParms''
[3] parms.caption←'CodeBrowser'
[4] parms.info←'Contains the CodeBrowser code without the test cases.'
[5] parms.showParms←1
[6] parms.footer←'Created by ',⎕AN,' on ',A.FormatDateTime ⎕TS
[7] parms.twoSidedPrint←1
[8] parms.filename←F.GetTempPath,'/',⎕AN,'_CodeBrowser_CodeReview.html'
[9] parms.viewInBrowser←1
[10] r←parms Run(⍕⎕THIS)
[11] ⍝Done
∇
∇ r←Version
[1] ⍝ See also `History`
[2] r←'CodeBrowser' '2.0.0+81' '2022-01-17'
∇
∇ {r}←WriteHeader parms;html;thisCssFile;filename
[1] html←⊂'<!DOCTYPE html>'
[2] html,←⊂'<html lang="',parms.lang,'">'
[3] html,←⊂'<head>'
[4] html,←⊂'<meta http-equiv="X-UA-Compatible" content="IE=edge" />'
[5] html,←⊂'<meta charset="utf-8">'
[6] html,←⊂'<title>',(ExchangeHtmlSpecialChars parms.caption),'</title>'
[7] :If parms.linkcssfile
[8] :For thisCssFile :In parms.cssfilename
[9] filename←F.EnforceSlash'expand'F.NormalizePath thisCssFile
[10] filename←':/'⎕R'|/'⊣filename
[11] html,←⊂'<link href="file://',filename,'" rel="stylesheet">'
[12] :EndFor
[13] :Else
[14] html,←⊂CompressCSS GetCSS parms
[15] :EndIf
[16] html,←InjectJavaScriptEarly ⍬
[17] ⍝html,←GetCodeMirrorLib parms ⍝ Not implemented yet ⍝TODO⍝
[18] html,←⊂'</head>'
[19] html,←⊂'<body>'
[20] r←WriteHTML html
[21] ⍝Done
∇
Variables:
Rank: 1; Shape: 83; Depth: 2; Data Representation: 326
Rank: 1; Shape: 18; Depth: 2; Data Representation: 326
Rank: 0; Shape: ⍬; Depth: 0; Data Representation: 83
Rank: 1; Shape: 1473; Depth: 2; Data Representation: 326
Rank: 0; Shape: ⍬; Depth: 0; Data Representation: 83
Rank: 1; Shape: 1; Depth: 2; Data Representation: 326
Rank: 1; Shape: 3; Depth: 2; Data Representation: 326
Functions:
∇ CreateParms←{⍺←⊣ ⋄ ⍺ ##.CreateParms ⍵}
∇
∇ MoreHelp←{⍺←⊣ ⋄ ⍺ ##.MoreHelp ⍵}
∇
∇ Run←{⍺←⊣ ⋄ ⍺ ##.Run ⍵}
∇
∇ Selfie←{⍺←⊣ ⋄ ⍺ ##.Selfie ⍵}
∇
Functions:
∇ {r}←{tellLink}CreateAPI flag;list1;list2
[1] ⍝ Creates cover functions for all API functions in ##.API from ##.Public.\\
[2] ⍝ If ⍺←1 then Link will be told.
[3] ⍝ Without ⍺ the user will be asked whether Link should be told.
[4] r←⍬
[5] tellLink←{0<⎕NC ⍵:⍎⍵ ⋄ ¯1}'tellLink'
[6] :If 0=##.⎕NC'API'
[7] 'API'##.⎕NS''
[8] :EndIf
[9] :If flag
[10] :If 0<≢list1←↓##.API.⎕NL⍳16
[11] ⎕SE.Link.Expunge¨(⊂(⍕⎕THIS),'.##.API.'),¨list1
[12] :EndIf
[13] list2←##.Public~'Methods' 'Public' 'GoToGitHub'
[14] ##.API.{⍎⍵,'←{⍺←⊣ ⋄ ⍺ ##.',⍵,' ⍵}'}¨list2
[15] :If (,1)≡,tellLink
[16] :OrIf 1 ##.U.YesOrNo'Tell Link?'
[17] r,←⎕SE.Link.Add¨##.API.((⊂(⍕⎕THIS),'.'),¨↓⎕NL 3)
[18] :EndIf
[19] :EndIf
∇
∇ {success}←ImportCode path;list
[1] ⍝ Takes a path and imports everyting found. Traps any errors but prints errors to the session for them.
[2] ⍝ Returns a scalar 0 in case their is nothing to import, otherwise a vector with 1 for success and 0
[3] ⍝ otherwise for every item found.
[4] success←0
[5] :If 0<≢list←⊃⎕NINFO⍠('Wildcard' 1)('Recurse' 2)⊣path
[6] success←{0::0,0/⎕←'Error fixing ',⍵,':',⍕⎕EN ⋄ 1⊣2 ⎕FIX'file://',⍵}¨list
[7] :EndIf
[8] ⍝Done
∇
Functions:
∇ AddPosnAndSize←{+⌿↑⍵.(Posn Size)}
∇
∇ (success msg)←CheckInput n;list;bool
[1] success←0
[2] msg←''
[3]
[4] :If 0∊⍴∊list←PolishNamespaceList n.namespaces.Text
[5] ShowInStatusbar'Nothing to scan?!'
[6] →SetFocusTo n.Scan n.namespaces
[7] :EndIf
[8] bool←list∊,¨'#' '⎕SE'
[9] :If 1∊bool←~{(⍵∊,¨'#' '⎕SE')∨9.1=⎕NC∘⊂¨⍵}list
[10] ShowInStatusbar'Scan: not a namespace: ',⊃{⍺,',',⍵}/bool/list
[11] →SetFocusTo n.Scan n.namespaces
[12] :EndIf
[13] n.namespaces.Text←⊃{⍺,', ',⍵}/list
[14]
[15] :If ~0∊⍴list←n.toBeIgnored.Text
[16] ((list=',')/list)←' '
[17] list←##.A.DMB list
[18] list←∪' '##.A.Split list
[19] :If 1∊bool←~{((,'#')∘≡¨⍵)∨9=⎕NC¨⍵}list
[20] ShowInStatusbar'To be ignored: not a namespace: ',⊃{⍺,',',⍵}/bool/list
[21] →SetFocusTo n.Scan n.toBeIgnored
[22] :EndIf
[23] n.toBeIgnored.Text←⊃{⍺,',',⍵}/list
[24] :EndIf
[25]
[26] :If ~0∊⍴n.filename.Text
[27] :AndIf 0=##.F.IsFile n.filename.Text
[28] :AndIf ~CreateNativeFile n.filename.Text
[29] ShowInStatusbar'HTML filename is invalid (not pointing to a file)'
[30] →SetFocusTo n.Parms n.filename
[31] :EndIf
[32]
[33] :If ~0∊⍴n.cssFilename.Text
[34] :AndIf 0=##.F.IsFile n.cssFilename.Text
[35] ShowInStatusbar'CSS filename is invalid (not pointing to a file)'
[36] →SetFocusTo n.Parms n.cssFilename
[37] :EndIf
[38]
[39] :If 0=+/n.(processFns processOpr processScripts processVars).State
[40] ShowInStatusbar'Nothing to be processed?!'
[41] →SetFocusTo n.Parms n.processFns
[42] :EndIf
[43]
[44] :If (0=n.lines.Value)∨n.lines.Value<¯1
[45] ShowInStatusbar'"Lines" must be either a positive integer or ¯1'
[46] →SetFocusTo n.Parms n.lines
[47] :EndIf
[48]
[49] success←1
[50] ⍝Done
∇
∇ {r}←CopyGuiToParms n
[1] r←⍬
[2] n.∆Parms.namespaces←n.namespaces.Text
[3] n.∆Parms.ignore←n.toBeIgnored.Text
[4] n.∆Parms.ignoreEmpty←n.ignoreEmptyNamespaces.State
[5] n.∆Parms.ignoreTatinPkgs←n.ignoreTatinPkgs.State
[6] n.∆Parms.recursive←n.recursive.State
[7] n.∆Parms.processGuiInstances←n.processGuiInstances.State
[8] n.∆Parms.filename←n.filename.Text
[9] n.∆Parms.cssfilename←MassageCssFilename n.cssFilename.Text
[10] n.∆Parms.linkcssfile←n.linkCssFile.State
[11] n.∆Parms.lang←n.lang.Text
[12] n.∆Parms.showParms←n.showParms.State
[13] n.∆Parms.viewInBrowser←n.viewInBrowser.State
[14] n.∆Parms.processFunctions←n.processFns.State
[15] n.∆Parms.processOperators←n.processOpr.State
[16] n.∆Parms.processScripts←n.processScripts.State
[17] n.∆Parms.processVars←n.processVars.State
[18] n.∆Parms.backgroundColorPrint←n.printBgrCol.State
[19] n.∆Parms.twoSidedPrint←n.twoSidedPrint.State
[20] n.∆Parms.printFontSize←⊃(//)⎕VFI n.fontSizeForPrint.Text
[21] n.∆Parms.caption←n.caption.Text
[22] n.∆Parms.footer←n.footer.Text
[23] n.∆Parms.info←,n.info.Text
[24] n.∆Parms.infoIsHTML←n.infoIsHtml.State
[25] n.∆Parms.lines←n.lines.Value
[26] ⍝Done
∇
∇ n←CreateButtons n;∆
[1] ∆←⊂'Button'
[2] ∆,←⊂'Style' 'Push'
[3] ∆,←⊂'Caption' '&Done'
[4] ∆,←⊂'Size'(⍬ 120)
[5] ∆,←⊂'TipObj'n.∆Tip
[6] ∆,←⊂'Tip'('Create the HTML page, close the GUI and' 'print the HTML filename to the session')
[7] ∆,←⊂'Attach'(4⍴'Bottom' 'Left')
[8] n.OK←⍎'ok'n.∆Form.⎕WC ∆
[9] n.∆Buttons←n.OK
[10] n.OK.Posn[1]←n.∆Form.Size[1]-n.OK.Size[1]+(⌊0.5×n.∆vgap)+n.StatusMsg.##.Size[1]
[11] n.OK.Posn[2]←n.∆hgap
[12]
[13] ∆←⊂'Button'
[14] ∆,←⊂'Style' 'Push'
[15] ∆,←⊂'Caption' 'Cancel'
[16] ∆,←⊂'Size'(⍬ 120)
[17] ∆,←⊂'Attach'(4⍴'Bottom' 'Left')
[18] ∆,←⊂'TipObj'n.∆Tip
[19] ∆,←⊂'Tip'('Close the GUI without taking any action')
[20] n.Cancel←⍎'cancel'n.∆Form.⎕WC ∆
[21] n.∆Buttons,←n.Cancel
[22] n.Cancel.Posn[1]←n.OK.Posn[1]
[23] n.Cancel.Posn[2]←n.∆hgap+2⊃AddPosnAndSize n.OK
[24]
[25] ∆←⊂'Button'
[26] ∆,←⊂'Style' 'Push'
[27] ∆,←⊂'Caption' '&Preview'
[28] ∆,←⊂'Size'(⍬ 120)
[29] ∆,←⊂'Attach'(4⍴'Bottom' 'Left')
[30] ∆,←⊂'TipObj'n.∆Tip
[31] ∆,←⊂'Tip'('Put what''s defined on display' 'with the default browser.')
[32] n.Preview←⍎'preview'n.∆Form.⎕WC ∆
[33] n.∆Buttons,←n.Preview
[34] n.Preview.Posn[1]←n.OK.Posn[1]
[35] n.Preview.Posn[2]←n.∆hgap+2⊃AddPosnAndSize n.Cancel
[36] n.Preview.onSelect←'OnPreview'
[37] ⍝Done
∇
∇ n←n CreateCaption parent;∆;ref
[1] ∆←⊂'Label'
[2] ∆,←⊂'Posn'(n.(∆vgap ∆hgap))
[3] ∆,←⊂'Caption' '&Caption:'
[4] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Left')
[5] ref←⍎'caption_label'parent.⎕WC ∆
[6]
[7] ∆←⊂'Edit'
[8] ∆,←⊂'Posn'(((⌈n.∆vgap÷2)+⊃↑+⌿⊃ref.(Posn Size)),n.∆hgap)
[9] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Right')
[10] ∆,←⊂'Size'(⍬(parent.Size[2]-2×n.∆hgap))
[11] ∆,←⊂'Text'({¯1≡⍵:'' ⋄ ⍵}n.∆Parms.caption)
[12] ∆,←⊂'TipObj'n.∆Tip
[13] ∆,←⊂'Tip'('Specify the overall caption.' 'If you leave this empty it will default to' 'the names of all namespaces to be scanned.')
[14] n.caption←⍎'caption'parent.⎕WC ∆
[15] ⍝Done
∇
∇ n←n CreateCssFilename(above parent);∆;ref
[1] ∆←⊂'Label'
[2] ∆,←⊂'Posn'((n.∆vgap+⊃+⌿↑above.(Posn Size)),n.∆hgap)
[3] ∆,←⊂'Caption' '&CSS filename:'
[4] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Left')
[5] ref←⍎'cssfile_label'parent.⎕WC ∆
[6]
[7] ∆←⊂'Edit'
[8] ∆,←⊂'Posn'(((2+⌈n.∆vgap÷2)+⊃↑+⌿⊃ref.(Posn Size)),n.∆hgap)
[9] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Right')
[10] ∆,←⊂'Size'(⍬(parent.Size[2]-2×n.∆hgap))
[11] ∆,←⊂'TipObj'n.∆Tip
[12] ∆,←⊂'Tip'('The name of the CSS file to be used.' 'Change this only if you have created your own CSS file.')
[13] ∆,←⊂'Text'n.∆Parms.cssfilename
[14] n.cssFilename←⍎'cssfile'parent.⎕WC ∆
[15]
[16] ∆←⊂'Button'
[17] ∆,←⊂'Style' 'Push'
[18] ∆,←⊂'Caption' '...'
[19] ∆,←⊂'Posn'((n.cssFilename.Posn[1])⍬)
[20] ∆,←⊂'Size'((n.cssFilename.Size[1])⍬)
[21] ∆,←⊂'TipObj'n.∆Tip
[22] ∆,←⊂'Tip'('Browse for the CSS file to be used')
[23] ∆,←⊂'Attach'('Top' 'Right' 'Top' 'Right')
[24] n.selectDirCssFile←⍎'selectDirFilename'parent.⎕WC ∆
[25] n.selectDirCssFile.onSelect←'OnBrowseForCssFile'
[26] n.selectDirCssFile.Posn[2]←n.TabCtrl.Size[2]-n.∆hgap+n.selectDirCssFile.Size[2]
[27] n.cssFilename.Size[2]-←2+n.selectDirCssFile.Size[2]
[28]
[29] ∆←⊂'Button'
[30] ∆,←⊂'Style' 'Check'
[31] ∆,←⊂'Caption' 'Link the CSS file rather than emebedd'
[32] ∆,←⊂'Posn'((2+n.∆vgap+⊃↑+⌿⊃n.cssFilename.(Posn Size)),n.∆hgap)
[33] ∆,←⊂'TipObj'n.∆Tip
[34] ∆,←⊂'Tip'('Linking can be very useful for changing the CSS')
[35] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Left')
[36] n.linkCssFile←⍎'linkCssFile'parent.⎕WC ∆
[37] ⍝Done
∇
∇ n←CreateFileBox parms;n;∆;path
[1] ⍝ Builds up a `FileBox` control which will remain invisible until it is `⎕DQ`ed.\\
[2] ⍝ Returns an `n` namepsace.
[3] n←⎕NS''
[4] ∆←''
[5] ∆,←⊂'Caption'parms.caption
[6] ∆,←⊂'Style' 'Single'
[7] ∆,←⊂'Filters'parms.filters
[8] ∆,←⊂'FileMode'parms.fileMode
[9] ∆,←⊂'Index'(parms.index-1)
[10] path←parms.path
[11] ((path='/')/path)←'\'
[12] ∆,←⊂'Directory'path
[13] :If 0∊⍴parms.file
[14] ∆,←⊂'File'(↑,/1↓⎕NPARTS path)
[15] :Else
[16] ∆,←⊂'File'(↑,/1↓⎕NPARTS parms.file)
[17] :EndIf
[18] n.∆Form←parms.parent.⎕NEW'FileBox'∆
[19] n.∆Form.⎕DF'[FileBox]'
[20] n.∆Form.onFileBoxOK←'OnSelectOkButtonInFileBox'
[21] n.∆Form.onFileBoxCancel←'OnSelectCancelButtonInFileBox'
[22] n.∆parms←parms
[23] n.∆result←''
[24] n.∆Form.n←n
[25] ⍝Done
∇
∇ r←filename CreateFileBoxParms n
[1] ⍝ Returns a parameter namespace with default settings:
[2] r←⎕NS''
[3] r.caption←''
[4] r.file←filename
[5] r.fileMode←'Read'
[6] r.filters←⊂'*.*' 'All files (*.*)'
[7] r.index←1
[8] r.parent←n.∆Form
[9] r.path←{0∊⍴⍵:##.F.PWD ⋄ ⍵}path
[10] ⍝Done
∇
∇ n←n CreateFilename parent;∆;ref
[1] ∆←⊂'Label'
[2] ∆,←⊂'Posn'(n.(∆vgap ∆hgap))
[3] ∆,←⊂'Caption' '&HTML filename:'
[4] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Left')
[5] ref←⍎'filename_label'parent.⎕WC ∆
[6]
[7] ∆←⊂'Edit'
[8] ∆,←⊂'Posn'((2+⊃↑+⌿↑ref.(Posn Size)),n.∆hgap)
[9] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Right')
[10] ∆,←⊂'Size'(⍬(parent.Size[2]-2×n.∆hgap))
[11] :If 0∊≢n.∆Parms.filename
[12] ∆,←⊂'Text'('html'##.F.GetTempFilename2'')
[13] :Else
[14] ∆,←⊂'Text'n.∆Parms.filename
[15] :EndIf
[16] ∆,←⊂'TipObj'n.∆Tip
[17] ∆,←⊂'Tip'('The name of the file the HTML will be saved in.' 'There is not default.')
[18] n.filename←⍎'footer'parent.⎕WC ∆
[19]
[20] ∆←⊂'Button'
[21] ∆,←⊂'Style' 'Push'
[22] ∆,←⊂'Caption' '...'
[23] ∆,←⊂'Posn'((n.filename.Posn[1])⍬)
[24] ∆,←⊂'Size'((n.filename.Size[1])⍬)
[25] ∆,←⊂'TipObj'n.∆Tip
[26] ∆,←⊂'Tip'('Browse for the file the HTML is going to be written to.')
[27] ∆,←⊂'Attach'('Top' 'Right' 'Top' 'Right')
[28] n.selectDirFilename←⍎'selectDirFilename'parent.⎕WC ∆
[29] n.selectDirFilename.onSelect←'OnBrowseForFilename'
[30] n.selectDirFilename.Posn[2]←n.TabCtrl.Size[2]-n.∆hgap+n.selectDirFilename.Size[2]
[31] n.filename.Size[2]-←2+n.selectDirFilename.Size[2]
[32] ⍝Done
∇
∇ n←CreateFonts n
[1] n.∆APL_Font←⍎'APLFont'n.∆Form.⎕WC'Font'('PName' 'APL385 Unicode')('Size' 18)
[2] n.∆STD_Font←⍎'STDFont'n.∆Form.⎕WC'Font'('PName' 'Verdana')('Size' 15)
[3] ⍝Done
∇
∇ n←CreateForm n;∆;ref;∆Form
[1] ∆←⊂'Form'
[2] ∆,←⊂'Caption'({(1⊃⍵),' version ',(2⊃⍵),' from ',(3⊃⍵)}##.Version)
[3] ∆,←⊂'Coord' 'Pixel'
[4] ∆,←⊂'Posn'(300 280)
[5] ∆,←⊂'Size'(565 900)
[6] n.∆Form←⍎'gui'⎕WC ∆
[7]
[8] ref←⍎'SB'n.∆Form.⎕WC⊂'Statusbar'
[9] n.StatusMsg←⍎'StatusMsg'ref.⎕WC'StatusField'('Coord' 'Prop')('Size'⍬ 99)
[10] n←CreateFonts n
[11] n.∆Form.FontObj←n.∆STD_Font
[12] n.∆Tip←'MyTip'n.∆Form.⎕WC⊂'TipField'
[13] ⍝Done
∇
∇ n←CreateGUI n;∆;size
[1] n←CreateForm n
[2] n←CreateTabs n
[3] n(CreateScanTabChildren)←parms.namespaces
[4] n←CreateParmsTabChildren n
[5] n←CreateButtons n
[6] n←CreateTextTabChildren n
[7] n.OK.onSelect←'OnOK'
[8] n.Cancel.onSelect←1
[9] n.∆Form.n←n
[10] 2 ⎕NQ n.Scan'Select'
[11] n.namespaces.SelText←2⍴1+⍴,n.namespaces.Text
[12] ⎕NQ n.namespaces'GotFocus'
[13] ⍝Done
∇
∇ n←n CreateIgnoreGuiInstances(parent above);∆
[1] ∆←⊂'Button'
[2] ∆,←⊂'Caption' 'Ignore &GUI instances'
[3] ∆,←⊂'Style' 'Check'
[4] ∆,←⊂'State'(~n.∆Parms.processGuiInstances)
[5] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'left')
[6] ∆,←⊂'TipObj'n.∆Tip
[7] ∆,←⊂'Tip'('GUI instances with' 'KeepOnClose←0' 'are ignored in any case')
[8] ∆,←⊂'Posn'((⊃+⌿↑above.(Posn Size)),n.∆hgap+2)
[9] n.processGuiInstances←⍎'processGuiInstances'parent.⎕WC ∆
[10] ⍝Done
∇
∇ n←n CreateInfo(parent above);∆;ref;tip
[1] ∆←⊂'Label'
[2] ∆,←⊂'Posn'((n.∆vgap+⊃+⌿↑above.(Posn Size)),n.∆hgap)
[3] ∆,←⊂'Caption' '&Info:'
[4] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Left')
[5] ref←⍎'info_label'parent.⎕WC ∆
[6]
[7] ∆←⊂'Edit'
[8] ∆,←⊂'Posn'((⊃+⌿↑ref.(Posn Size)),n.∆hgap)
[9] ∆,←⊂'Attach'('Top' 'Left' 'Bottom' 'Right')
[10] ∆,←⊂'Size'(⍬(parent.Size[2]-2×n.∆hgap))
[11] ∆,←⊂'Text'n.∆Parms.info
[12] ∆,←⊂'Style' 'Multi'
[13] ∆,←⊂'TipObj'n.∆Tip
[14] tip←⊂'"Info" goes right after the "Caption".'
[15] tip,←⊂'There is no default, so if you leave this'
[16] tip,←⊂'empty then there will be no "Info".'
[17] ∆,←⊂'Tip'tip
[18] n.info←⍎'info'parent.⎕WC ∆
[19] n.info.onKeyPress←'OnKeyPressInInfo'
[20]
[21] ∆←⊂'Button'
[22] ∆,←⊂'Style' 'Check'
[23] ∆,←⊂'Caption' '"Info" is &HTML'
[24] ∆,←⊂'TipObj'n.∆Tip
[25] tip←⊂'Use this in case you want "Info" to be left alone (normally "<" etc. would be translated).'
[26] tip,←⊂'This allows you to transform Markdown to HTML and then insert that HTML as "Info".'
[27] ∆,←⊂'Tip'tip
[28] ∆,←⊂'Posn'(((⌈n.∆vgap÷2)+⊃+⌿↑n.info.(Posn Size)),n.∆hgap)
[29] ∆,←⊂'State'n.∆Parms.infoIsHTML
[30] ∆,←⊂'Attach'(4⍴'Bottom' 'Left')
[31] n.infoIsHtml←⍎'infoIsHtml'parent.⎕WC ∆
[32] n.infoIsHtml.Posn[2]+←2
[33] ⍝Done
∇
∇ n←n CreateLang(parent above);∆;list
[1] ∆←⊂'Label'
[2] ∆,←⊂'Caption' '&Language:'
[3] ∆,←⊂'Posn'((n.∆vgap+⊃+⌿↑above.(Posn Size)),n.∆hgap)
[4] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[5] n.lang_label←⍎'lang_label'parent.⎕WC ∆
[6]
[7] ∆←⊂'Combo'
[8] ∆,←⊂'Style' 'DropEdit'
[9] ∆,←⊂'Posn'((⊃+⌿↑n.lang_label.(Posn Size)),n.∆hgap)
[10] ∆,←⊂'index' 1
[11] ∆,←⊂'Size'(21 50)
[12] list←'en' 'de' 'da' 'fr' 'it' 'es'
[13] ∆,←⊂'Items'list
[14] ∆,←⊂'TipObj'n.∆Tip
[15] ∆,←⊂'Tip'('This two-character code is used for setting the "lang" attribute of the <html> tag.')
[16] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[17] ∆,←⊂'SelItems'({b←(⍴⍵)⍴0 ⋄ b[1]←1 ⋄ b}list)
[18] n.lang←⍎'lang'parent.⎕WC ∆
[19] n.lang.onKeyPress←'OnKeyPressInLang'
[20] ⍝Done
∇
∇ n←n CreateLines(parent sibling);∆;ref
[1] ∆←⊂'Label'
[2] ∆,←⊂'Caption' '&L&ines:'
[3] ∆,←⊂'Posn'(sibling.Posn[1],n.∆vgap+2⊃+⌿↑sibling.(Posn Size))
[4] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[5] ref←⍎'lines_label'parent.⎕WC ∆
[6]
[7] ∆←⊂'Edit'
[8] ∆,←⊂'Posn'((⊃+⌿↑ref.(Posn Size)),ref.Posn[2])
[9] ∆,←⊂'FieldType' 'Numeric'
[10] ∆,←⊂'Size'(21 50)
[11] ∆,←⊂'Value'n.∆Parms.lines
[12] ∆,←⊂'TipObj'n.∆Tip
[13] ∆,←⊂'Tip'('How many lines are displayed per object.' '¯1 means "all lines".')
[14] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[15] n.lines←⍎'lines'parent.⎕WC ∆
[16] ⍝Done
∇
∇ n←n CreateNamespaces(parent namespaces);∆;ref
[1] ∆←⊂'Label'
[2] ∆,←⊂'Posn'n.(∆vgap ∆hgap)
[3] ∆,←⊂'Caption' '&Namespace(s) to be scanned:'
[4] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Left')
[5] ref←⍎'ns_label'parent.⎕WC ∆
[6]
[7] ∆←⊂'Edit'
[8] ∆,←⊂'Posn'(((2+⌈n.∆vgap÷2)+⊃↑+⌿⊃ref.(Posn Size)),n.∆hgap)
[9] ∆,←⊂'Font'n.∆APL_Font
[10] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Right')
[11] ∆,←⊂'Text'(⊃{⍺,', ',⍵}/{0∊≢⍵:'#' ⋄ ⍵}⊆⍕¨namespaces)
[12] ∆,←⊂'Size'(⍬(n.ScanSubForm.Size[2]-2×n.∆hgap))
[13] ∆,←⊂'FontObj'n.∆APL_Font
[14] ∆,←⊂'TipObj'n.∆Tip
[15] ∆,←⊂'Tip'('Specify all the namespaces to be scanned.' 'Use spaces or commata as separators.')
[16] n.namespaces←⍎'namespaces'parent.⎕WC ∆
[17] n.namespaces.Size[1]-←5
[18]
[19] ∆←⊂'Button'
[20] ∆,←⊂'Style' 'Check'
[21] ∆,←⊂'Caption' 'Process &recursively'
[22] ∆,←⊂'Posn'((n.∆hgap+⊃+⌿↑n.namespaces.(Posn Size)),n.∆vgap)
[23] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Right')
[24] ∆,←⊂'State'n.∆Parms.recursive
[25] ∆,←⊂'TipObj'n.∆Tip
[26] ⍝∆,←⊂'Tip'('')
[27] n.recursive←⍎'recursive'parent.⎕WC ∆
[28] ⍝Done
∇
∇ success←CreateNativeFile filename;tno
[1] ⍝ Tries to create native file with `filename` and returns 1 in case of success and 0 otherwise.
[2] :Trap 22
[3] tno←filename ⎕NCREATE 0
[4] ⎕NUNTIE tno
[5] success←1
[6] :Case 22
[7] success←0
[8] :EndTrap
∇
∇ n←n CreateOtherParms(parent above);∆;ref
[1] ∆←⊂'Button'
[2] ∆,←⊂'Style' 'Check'
[3] ∆,←⊂'Caption' '&Show parameters at the end of the document'
[4] ∆,←⊂'Posn'((n.∆vgap+⊃+⌿↑above.(Posn Size)),n.∆vgap)
[5] ∆,←⊂'State'n.∆Parms.showParms
[6] ∆,←⊂'TipObj'n.∆Tip
[7] ∆,←⊂'Tip'('Use this for documenting the parameters.' 'When printed the parameter go onto a separate page.')
[8] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[9] n.showParms←⍎'showParms'parent.⎕WC ∆
[10]
[11] ∆←⊂'Button'
[12] ∆,←⊂'Style' 'Check'
[13] ∆,←⊂'Caption' '&View resulting HTML page in default browser'
[14] ∆,←⊂'Posn'((⊃+⌿↑n.showParms.(Posn Size)),n.∆hgap)
[15] ∆,←⊂'State'n.∆Parms.viewInBrowser
[16] ∆,←⊂'TipObj'n.∆Tip
[17] ⍝ ∆,←⊂'Tip'('')
[18] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[19] n.viewInBrowser←⍎'viewInBrowser'parent.⎕WC ∆
[20] ⍝Done
∇
∇ n←CreateParmsTabChildren n;∆;ref
[1] n(CreateFilename)←n.ParmsSubForm
[2] n(CreateCssFilename)←n.filename n.ParmsSubForm
[3] n(CreateToBeProcessed)←n.ParmsSubForm n.linkCssFile
[4] n(CreatePrintParms)←n.processFns.## n.ParmsSubForm
[5] n(CreateLang)←n.ParmsSubForm n.processFns.##
[6] n(CreateLines)←n.ParmsSubForm n.lang_label
[7] n(CreateOtherParms)←n.ParmsSubForm n.lines
[8] ⍝Done
∇
∇ n←n CreatePrintParms(sibling parent);∆;ref;ref2;list
[1] ∆←⊂'Group'
[2] ∆,←⊂'Caption' ' P&rint parameters'
[3] ∆,←⊂'Posn'(sibling.Posn[1],n.∆hgap+2⊃+⌿↑sibling.(Posn Size))
[4] ∆,←⊂'Size'(135 300)
[5] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[6] ref←⍎'printParms_group'parent.⎕WC ∆
[7]
[8] ∆←⊂'Button'
[9] ∆,←⊂'Style' 'Check'
[10] ∆,←⊂'Caption' '&Use background colour for print'
[11] ∆,←⊂'TipObj'n.∆Tip
[12] ∆,←⊂'State'n.∆Parms.backgroundColorPrint
[13] ∆,←⊂'Tip'('By default when printing background colours are ignored.' 'For some browsers that default behaviour can be overwritten.')
[14] ∆,←⊂'Posn'(n.(2 1×∆vgap ∆hgap))
[15] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[16] n.printBgrCol←⍎'printBgrCol'ref.⎕WC ∆
[17]
[18] ∆←⊂'Button'
[19] ∆,←⊂'Style' 'Check'
[20] ∆,←⊂'Caption' '&Two-sided print'
[21] ∆,←⊂'State'n.∆Parms.twoSidedPrint
[22] ∆,←⊂'TipObj'n.∆Tip
[23] ∆,←⊂'Tip'('The left margin is different on odd and even pages then.')
[24] ∆,←⊂'Posn'((⊃+⌿↑n.printBgrCol.(Posn Size)),n.∆hgap)
[25] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[26] n.twoSidedPrint←⍎'twoSidedPrint'ref.⎕WC ∆
[27]
[28] ∆←⊂'Label'
[29] ∆,←⊂'Caption' '&Font size to be used for print:'
[30] ∆,←⊂'Posn'((n.∆vgap+⊃+⌿↑n.twoSidedPrint.(Posn Size)),n.∆hgap)
[31] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[32] ref2←⍎'fontsize_label'ref.⎕WC ∆
[33]
[34] ∆←⊂'Combo'
[35] ∆,←⊂'Style' 'Drop'
[36] ∆,←⊂'Posn'(ref2.Posn[1],ref2.Size[2]+n.∆hgap)
[37] ∆,←⊂'index' 1
[38] ∆,←⊂'Size'(21 40)
[39] list←'4' '5' '6' '7' '8' '9' '10' '11' '12' '16' '17' '18' '20' '22' '23' '24' '25' '27' '28' '29' '31'
[40] ∆,←⊂'Items'list
[41] ∆,←⊂'TipObj'n.∆Tip
[42] ⍝∆,←⊂'Tip' ('')
[43] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[44] ∆,←⊂'SelItems'(list{b←(⍴⍺)⍴0 ⋄ b[(⍎¨⍺)⍳⍵]←1 ⋄ b}n.∆Parms.printFontSize)
[45] n.fontSizeForPrint←⍎'fontSizeForPrint'ref.⎕WC ∆
[46] ⍝Done
∇
∇ n←n CreateScanTabChildren namespaces
[1] n(CreateNamespaces)←n.ScanSubForm namespaces
[2] n(CreateToBeIgnored)←n.ScanSubForm n.recursive
[3] n(CreateIgnoreGuiInstances)←n.ScanSubForm n.ignoreEmptyNamespaces
[4] n(CreateTatinPackages)←n.ScanSubForm n.processGuiInstances
[5] ⍝Done
∇
∇ n←CreateSubForms n;∆
[1] ∆←⊂'SubForm'
[2] ∆,←⊂'TabObj'n.Scan
[3] ∆,←⊂'Coord' 'Prop'
[4] ∆,←⊂'Posn'(0 0)
[5] ∆,←⊂'Size'(100 100)
[6] ∆,←⊂'EdgeStyle' 'Dialog'
[7] ∆,←⊂'Attach'('Top' 'Left' 'Bottom' 'Right')
[8] n.ScanSubForm←⍎'subformScan'n.TabCtrl.⎕WC ∆
[9] n.ScanSubForm.Coord←'Pixel'
[10]
[11] ∆←⊂'SubForm'
[12] ∆,←⊂'TabObj'n.Parms
[13] ∆,←⊂'Coord' 'Prop'
[14] ∆,←⊂'Posn'(0 0)
[15] ∆,←⊂'Size'(100 100)
[16] ∆,←⊂'EdgeStyle' 'Dialog'
[17] ∆,←⊂'Attach'('Top' 'Left' 'Bottom' 'Right')
[18] n.ParmsSubForm←⍎'subformParms'n.TabCtrl.⎕WC ∆
[19] n.ParmsSubForm.Coord←'Pixel'
[20]
[21] ∆←⊂'SubForm'
[22] ∆,←⊂'TabObj'n.Text
[23] ∆,←⊂'Coord' 'Prop'
[24] ∆,←⊂'Posn'(0 0)
[25] ∆,←⊂'Size'(100 100)
[26] ∆,←⊂'EdgeStyle' 'Dialog'
[27] ∆,←⊂'Attach'('Top' 'Left' 'Bottom' 'Right')
[28] n.TextSubForm←⍎'subformText'n.TabCtrl.⎕WC ∆
[29] n.TextSubForm.Coord←'Pixel'
[30] ⍝Done
∇
∇ n←CreateTabControlAndChildren n;∆
[1] ∆←⊂'TabControl'
[2] ∆,←⊂'Size'(n.∆Form.Size-70 20)
[3] ∆,←⊂'Posn'(0 10)
[4] ∆,←⊂'Attach'('Top' 'Left' 'Bottom' 'Right')
[5] n.TabCtrl←⍎'tabctrl'n.∆Form.⎕WC ∆
[6]
[7] ∆←⊂'TabButton'
[8] ∆,←⊂'Caption' 'Scan'
[9] n.Scan←⍎'tabbtnScan'n.TabCtrl.⎕WC ∆
[10]
[11] ∆←⊂'TabButton'
[12] ∆,←⊂'Caption' 'Parameters'
[13] n.Parms←⍎'tabbtnParms'n.TabCtrl.⎕WC ∆
[14]
[15] ∆←⊂'TabButton'
[16] ∆,←⊂'Caption' 'Text'
[17] n.Text←⍎'tabbtnText'n.TabCtrl.⎕WC ∆
[18] ⍝Done
∇
∇ n←CreateTabs n;∆
[1] n←CreateTabControlAndChildren n
[2] n←CreateSubForms n
[3] ⍝Done
∇
∇ n←n CreateTatinPackages(parent above);∆
[1] ∆←⊂'Button'
[2] ∆,←⊂'Style' 'Check'
[3] ∆,←⊂'Caption' 'Ignore &Tatin packages'
[4] ∆,←⊂'Posn'((⊃+⌿↑above.(Posn Size)),n.∆hgap)
[5] ∆,←⊂'State'n.∆Parms.ignoreTatinPkgs
[6] ∆,←⊂'TipObj'n.∆Tip
[7] ∆,←⊂'Tip'('Ignores (⎕SE|#)._tatin')
[8] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[9] n.ignoreTatinPkgs←⍎'ignoreTatinPkgs'parent.⎕WC ∆
[10] ⍝Done
∇
∇ n←CreateTextTabChildren n;∆;ref;list
[1] n(CreateCaption)←n.TextSubForm
[2] n(CreateFooter)←n.TextSubForm n.caption
[3] n(CreateInfo)←n.TextSubForm n.footer
[4] ⍝Done
∇
∇ n←n CreateToBeIgnored(parent above);∆;ref
[1] ∆←⊂'Label'
[2] ∆,←⊂'Posn'((n.∆vgap+⊃+⌿↑above.(Posn Size)),n.∆hgap)
[3] ∆,←⊂'Caption' 'To be ignored:'
[4] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Left')
[5] ref←⍎'ignored_label'parent.⎕WC ∆
[6]
[7] ∆←⊂'Edit'
[8] ∆,←⊂'Posn'(((2+⌈n.∆vgap÷2)+⊃↑+⌿⊃ref.(Posn Size)),n.∆hgap)
[9] ∆,←⊂'Font'n.∆APL_Font
[10] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'Right')
[11] ∆,←⊂'Size'(⍬(parent.Size[2]-2×n.∆hgap))
[12] ∆,←⊂'FontObj'n.∆APL_Font
[13] ∆,←⊂'TipObj'n.∆Tip
[14] ∆,←⊂'Tip'('Specify everything inside the namespaces to be scanned that you want to be ignored.' 'Specify fully qualified names. Use spaces or commata as separators.')
[15] n.toBeIgnored←⍎'tobeignored'parent.⎕WC ∆
[16] n.toBeIgnored.Size[1]-←5
[17]
[18] ∆←⊂'Button'
[19] ∆,←⊂'Caption' '&Ignore empty namespaces'
[20] ∆,←⊂'Style' 'Check'
[21] ∆,←⊂'State'n.∆Parms.ignoreEmpty
[22] ∆,←⊂'Attach'('Top' 'Left' 'Top' 'left')
[23] ∆,←⊂'Tip'('If this is not ticked empty namespaces will be listed')
[24] ∆,←⊂'Posn'(((⌈n.∆vgap÷2)+⊃+⌿↑n.toBeIgnored.(Posn Size)),n.∆hgap+2)
[25] n.ignoreEmptyNamespaces←⍎'ignoreEmpty'parent.⎕WC ∆
[26] ⍝Done
∇
∇ n←n CreateToBeProcessed(parent above);∆;ref
[1] ∆←⊂'Group'
[2] ∆,←⊂'Caption' ' &Process '
[3] ∆,←⊂'Posn'((n.∆vgap+⊃+⌿↑n.linkCssFile.(Posn Size)),n.∆hgap)
[4] ∆,←⊂'Size'(135 300)
[5] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[6] ∆,←⊂'TipObj'n.∆Tip
[7] ⍝ ∆,←⊂'Tip'('')
[8] ref←⍎'process_group'parent.⎕WC ∆
[9]
[10] ∆←⊂'Button'
[11] ∆,←⊂'Style' 'Check'
[12] ∆,←⊂'Caption' '&Functions'
[13] ∆,←⊂'Posn'n.(2 1×∆vgap ∆hgap)
[14] ∆,←⊂'State'n.∆Parms.processFunctions
[15] ∆,←⊂'TipObj'n.∆Tip
[16] ⍝ ∆,←⊂'Tip'('')
[17] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[18] n.processFns←⍎'processFns'ref.⎕WC ∆
[19]
[20] ∆←⊂'Button'
[21] ∆,←⊂'Style' 'Check'
[22] ∆,←⊂'Caption' '&Operators'
[23] ∆,←⊂'Posn'((⊃+⌿↑n.processFns.(Posn Size)),n.∆hgap)
[24] ∆,←⊂'State'n.∆Parms.processOperators
[25] ∆,←⊂'TipObj'n.∆Tip
[26] ⍝ ∆,←⊂'Tip'('')
[27] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[28] n.processOpr←⍎'processOpr'ref.⎕WC ∆
[29]
[30] ∆←⊂'Button'
[31] ∆,←⊂'Style' 'Check'
[32] ∆,←⊂'Caption' '&Scripts (classes, namespaces, interfaces)'
[33] ∆,←⊂'Posn'((⊃+⌿↑n.processOpr.(Posn Size)),n.∆hgap)
[34] ∆,←⊂'State'n.∆Parms.processScripts
[35] ∆,←⊂'TipObj'n.∆Tip
[36] ⍝ ∆,←⊂'Tip'('')
[37] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[38] n.processScripts←⍎'processScripts'ref.⎕WC ∆
[39]
[40] ∆←⊂'Button'
[41] ∆,←⊂'Style' 'Check'
[42] ∆,←⊂'Caption' '&Variables'
[43] ∆,←⊂'Posn'((⊃+⌿↑n.processScripts.(Posn Size)),n.∆hgap)
[44] ∆,←⊂'State'n.∆Parms.processVars
[45] ∆,←⊂'TipObj'n.∆Tip
[46] ⍝ ∆,←⊂'Tip'('')
[47] ∆,←⊂'Attach'(4⍴'Top' 'Left')
[48] n.processVars←⍎'processVars'ref.⎕WC ∆
[49] ⍝Done
∇
∇ {r}←DQ ref
[1] r←⎕DQ ref
[2] ⍝Done
∇
∇ GetRefTo_n←{
[1] 0<⍵.⎕NC'n':⍵.n
[2] ∇ ⍵.##
[3] }
∇
∇ n←Init dummy
[1] n←⎕NS''
[2] n.(∆vgap ∆hgap)←15
∇
∇ filename←MassageCssFilename filename
[1] ⍝ Forces `filename` to be an absolute path.
[2] :If (~':'∊filename)∧'//'≢2⍴filename ⍝ Not absolute?
[3] filename←'expand'##.F.NormalizePath filename
[4] :EndIf
[5] ⍝Done
∇
∇ OnBrowseForCssFile msg;n;parms;fb;res;path;filename;extension
[1] n←GetRefTo_n⊃msg
[2] (path filename extension)←⎕NPARTS n.cssFilename.Text
[3] filename←filename,extension
[4] parms←filename CreateFileBoxParms n
[5] :If 0∊⍴path
[6] parms.path←##.F.PWD
[7] :Else
[8] parms.path←path
[9] :EndIf
[10] parms.caption←'Read CSS file'
[11] parms.filters←⊂'*.css' 'CSS file'
[12] fb←CreateFileBox parms
[13] res←DQ fb.∆Form
[14] :If ~0∊⍴fb.∆result
[15] n.cssFilename.Text←fb.∆result
[16] :EndIf
[17] ⍝Done
∇
∇ OnBrowseForFilename msg;parms;fb;n;res;path;filename;extension
[1] n←GetRefTo_n⊃msg
[2] (path filename extension)←⎕NPARTS n.filename.Text
[3] filename←filename,extension
[4] parms←filename CreateFileBoxParms n
[5] :If 0∊⍴path
[6] parms.path←##.F.PWD
[7] :Else
[8] parms.path←path
[9] :EndIf
[10] parms←filename CreateFileBoxParms n
[11] parms.caption←'Save HTML file'
[12] parms.fileMode←'Write'
[13] parms.filters←('*.HTML' 'HTML files')('*.HTM' 'HTML files')
[14] fb←CreateFileBox parms
[15] res←DQ fb.∆Form
[16] :If ~0∊⍴fb.∆result
[17] n.filename.Text←fb.∆result
[18] :EndIf
[19] ⍝Done
∇
∇ OnKeyPressInInfo←{
[1] ⍵[4 5 6]≢0 9 2:1
[2] ⍝ Suppress Ctrl+Tab: that should change the current tab
[3] n←GetRefTo_n⊃⍵
[4] 0⊣⎕NQ n.TabCtrl.TabObj,1↓⍵
[5] }
∇
∇ OnKeyPressInLang←{
[1] 1≠⍴,3⊃⍵:1
[2] 2≥1+⍴,⍵[1].Text
[3] }
∇
∇ r←OnOK msg;n
[1] n←GetRefTo_n⊃msg
[2] (r msg)←CheckInput n
[3] :If r
[4] ShowInStatusbar'Processing...'
[5] n.∆Parms←n.∆Parms
[6] CopyGuiToParms n
[7] {}n.∆Parms ##.Run n.∆Parms.namespaces
[8] ⎕NQ n.∆Form'Close'
[9] :EndIf
[10] ⍝Done
∇
∇ OnPreview←{
[1] n←GetRefTo_n⊃⍵
[2] (r msg)←CheckInput n
[3] 0=r:0
[4] _←CopyGuiToParms n
[5] 0=≢n.∆Parms.filename:0
[6] _←n.∆Parms ##.Run n.∆Parms.namespaces
[7] _←##.A.GoToWebPage⍣(⊃~n.∆Parms.viewInBrowser)⊣n.∆Parms.filename
[8] 0
[9] }
∇
∇ OnSelectCancelButtonInFileBox←{
[1] n←GetRefTo_n⊃⍵
[2] n.∆result←''
[3] 1
[4] }
∇
∇ OnSelectOkButtonInFileBox←{
[1] n←GetRefTo_n⊃⍵
[2] n.∆result←n.∆Form.Directory,n.∆Form.File
[3] 1
[4] }
∇
∇ PolishNamespaceList←{
[1] ⍝ ⍵ is typically n.namespaces.Text
[2] list←⍵
[3] ((list=',')/list)←' '
[4] list←∪' '##.A.Split ##.A.DMB list
[5] '⎕se'⎕R'⎕SE'⊣list
[6] }
∇
∇ {r}←{parms}Run(namespaces homePath);∆;n
[1] ⍝ `namespaces` can be one of:
[2] ⍝ * Single ref
[3] ⍝ * Vector of refs
[4] ⍝ * Simple text vector
[5] ⍝ * Vector of text vectors
[6] ⍝ In case `homePath` is not empty it is assumed that `Run` is executed by the user command framework.
[7] r←⍬
[8] ##.Init ⍬
[9] :If 0=⎕NC'parms'
[10] parms←##.CreateParms homePath
[11] :EndIf
[12] parms.namespaces←namespaces
[13] n←Init ⍬
[14] n.∆Parms←parms
[15] n←CreateGUI n
[16] DQ n.∆Form
[17] :Trap 0 ⋄ ⎕NQ n.∆Form'Close' ⋄ :EndTrap
[18] ⍝Done
∇
∇ r←SetFocusTo(tab control)
[1] r←0
[2] ⎕NQ tab'Select'
[3] ⎕NQ control'GotFocus'
[4] ⍝Done
∇
∇ {r}←ShowInStatusbar msg
[1] n.StatusMsg.Text←msg
[2] ⍝Done
∇
Name | Setting |
---|---|
backgroundColorPrint | 1 |
caption | CodeBrowser |
cssfilename | C:/T/Projects/UserCommands/CodeBrowser/Files/codebrowser_styles.css |
filename | C:\Users\kai\AppData\Local\Temp\/kai_CodeBrowser_CodeReview.html |
footer | Created by kai on 2022-01-18 09:27:16 |
ignore | |
ignoreEmpty | 1 |
ignoreTatinPkgs | 1 |
info | Contains the CodeBrowser code without the test cases. |
infoIsHTML | 0 |
lang | en |
lines | ¯1 |
linkcssfile | 0 |
namespaces | #.CodeBrowser.CodeBrowser |
printFontSize | 8 |
processFunctions | 1 |
processGuiInstances | 0 |
processOperators | 1 |
processScripts | 1 |
processVars | 1 |
recursive | 1 |
showParms | 1 |
twoSidedPrint | 1 |
version | CodeBrowser 2.0.0+81 from 2022-01-17 |
viewInBrowser | 1 |